我们再来看一下扩展文件描述符表的关键函数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 << PAGE_SHIFT) /* Expand to the max in easy steps */ do { if (nfds < (PAGE_SIZE * 8))//dfds = 1024 nfds = 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值,此时这个值为32k
nfds = 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 < 256 if (nfds < 256) nfds = 256;//nfds = 256(32->256->1024) //无法超过1024,因为在最开始的就进行了检查,一定要小于current->signal->rlim[RLIMIT_NOFILE].rlim_cur) else #endif if (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_fds fdt->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内核中的文件描述符(一)——基础知识简介
Linux内核中的文件描述符(二)——socket和文件描述符
Linux内核中的文件描述符(三)——fd的回收
Linux内核中的文件描述符(四)——fd的分配--get_unused_fd
Linux内核中的文件描述符(五)——fd的分配--locate_fd