日期:2014-05-16 浏览次数:20641 次
linux内核中的文件描述符(六)--fd的分配--expand_files
Kernel version:2.6.14
CPU architecture:ARM920T
Author:ce123(http://blog.csdn.net/ce123)
我们先贴出expand_files函数的源码:
int expand_files(struct files_struct *files, int nr) { int err, expand = 0; struct fdtable *fdt; fdt = files_fdtable(files); if (nr >= fdt->max_fdset || nr >= fdt->max_fds) { //我们在前面的文章中已经分析过,初始时max_fdset = 1024,max_fds = 32 if (fdt->max_fdset >= NR_OPEN || //#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */ fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) { err = -EMFILE; //max_fdset和max_fds都不能大于 NR_OPEN,否则返回 -EMFILE,即打开太多的文件 goto out; } expand = 1; if ((err = expand_fdtable(files, nr)))//真正进行扩展 goto out; } err = expand; out: return err; }
expand_files函数进行一些检查后调用expand_fdtable进行文件描述符表的扩展,下面分析expand_fdtable函数。
static int expand_fdtable(struct files_struct *files, int nr) __releases(files->file_lock) __acquires(files->file_lock) { int error = 0; struct fdtable *fdt; struct fdtable *nfdt = NULL; spin_unlock(&files->file_lock); nfdt = alloc_fdtable(nr);//根据nr重新创建一个新的fdtable if (!nfdt) { error = -ENOMEM; spin_lock(&files->file_lock); goto out; } spin_lock(&files->file_lock); fdt = files_fdtable(files); /* * Check again since another task may have expanded the * fd table while we dropped the lock */ if (nr >= fdt->max_fds || nr >= fdt->max_fdset) { //nr值必须大于max_fds和max_fdset值,这里再次进行检查是防止另一个进程进行了expand copy_fdtable(nfdt, fdt); //将旧的fdtable中的内容拷贝至新的fdtable } else { /* Somebody expanded while we dropped file_lock */ spin_unlock(&files->file_lock); __free_fdtable(nfdt); spin_lock(&files->file_lock); goto out; } rcu_assign_pointer(files->fdt, nfdt);//用新的fdtable替换旧的fdtable free_fdtable(fdt);//释放旧的fdtable out: return error; }我们再来看一下扩展文件描述符表的关键函数alloc_fdtable,其定义如下:
static struct fdtable *alloc_fdtable(int nr) { struct fdtable *fdt = NULL; int nfds = 0; fd_set *new_openset = NULL, *new_execset = NULL; struct file **new_fds; fdt = kmalloc(sizeof(*fdt), GFP_KERNEL); if (!fdt) goto out; memset(fdt, 0, sizeof(*fdt)); nfds = __FD_SETSIZE; //#define __FD_SETSIZE 1024 // #define PAGE_SHIFT 12 // #define PAGE_SIZE (1UL <<