linux内核中的文件描述符(六)–fd的分配–expand

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 = 32if (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重新创建一个新的fdtableif (!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值,这里再次进行检查是防止另一个进程进行了expandcopy_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);//释放旧的fdtableout: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_SETSIZE1024          //  #define PAGE_SHIFT12          //  #define PAGE_SIZE(1UL << PAGE_SHIFT)  /* Expand to the max in easy steps */  do {if (nfds < (PAGE_SIZE * 8))//dfds = 1024nfds = PAGE_SIZE * 8;else {nfds = nfds * 2;if (nfds > NR_OPEN)nfds = NR_OPEN;}} while (nfds <= nr);//第一次expand时,nr应该等于32  new_openset = alloc_fdset(nfds);//分配打开文件位图  new_execset = alloc_fdset(nfds);  if (!new_openset || !new_execset)  goto out;fdt->open_fds = new_openset;fdt->close_on_exec = new_execset;fdt->max_fdset = nfds;//更新max_fdset值,此时这个值为32knfds = NR_OPEN_DEFAULT;//nfds = 32/* * Expand to the max in easy steps, and keep expanding it until * we have enough for the requested fd array size. */do {#if NR_OPEN_DEFAULT < 256if (nfds < 256)nfds = 256;//nfds = 256(32->256->1024)//无法超过1024,因为在最开始的就进行了检查,一定要小于current->signal->rlim[RLIMIT_NOFILE].rlim_cur)else#endifif (nfds < (PAGE_SIZE / sizeof(struct file *)))nfds = PAGE_SIZE / sizeof(struct file *);else {nfds = nfds * 2;if (nfds > NR_OPEN)nfds = NR_OPEN;  }} while (nfds <= nr);new_fds = alloc_fd_array(nfds);//分配文件描述符数组if (!new_fds)goto out;fdt->fd = new_fds;fdt->max_fds = nfds;//更新max_fdsfdt->free_files = NULL;return fdt;out:  if (new_openset)  free_fdset(new_openset, nfds);  if (new_execset)  free_fdset(new_execset, nfds);kfree(fdt);return NULL;}

alloc_fd_array和alloc_fdset采用kmalloc或者vmalloc进行内存分配。人生就是一次充满未知的旅行,在乎的是沿途的风景,

linux内核中的文件描述符(六)–fd的分配–expand

相关文章:

你感兴趣的文章:

标签云: