博客:blog.focus-linux.net linuxfocus.blog.chinaunix.net
本文的copyleft归[email protected]所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
======================================================================================================
继续昨天的学习。
昨天学习alloc_fd时,还有一个函数expand_files没有进入跟踪。
int expand_files(struct files_struct *files, int nr)
{
struct fdtable *fdt;
fdt = files_fdtable(files);
/*
* N.B. For clone tasks sharing a files structure, this test
* will limit the total number of files that can be opened.
*/
/* 检查是否超过当前进程限定的最大可打开文件数 */
if (nr >= rlimit(RLIMIT_NOFILE))
return -EMFILE;
/* Do we need to expand? */
/*
如果nr小于max_fds,即目前的文件表的个数已经超过了nr, 所以无需扩展。
这也说明,文件表只会增大,不会减小。
*/
if (nr fdt->max_fds)
return 0;
/* Can we expand? */
检查是否超过了系统限定的最大可打开文件数
注意前面的检查为当前进程的打开文件数,此处的检查为系统可打开的文件数——所有进程
if (nr >= sysctl_nr_open)
/* All good, so we try */
/* 真正去做expand*/
return expand_fdtable(files, nr);
}
进入expand_fdtable
static int expand_fdtable(struct files_struct *files, int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
struct fdtable *new_fdt, *cur_fdt;
spin_unlock(&files->file_lock);
/* 申请新的文件表 */
new_fdt = alloc_fdtable(nr);
spin_lock(&files->file_lock);
if (!new_fdt)
return -ENOMEM;
* extremely unlikely race - sysctl_nr_open decreased between the check in
* caller and alloc_fdtable(). Cheaper to catch it here...
/* 如注释所示,由于竞争,有可能在申请nr个数的新文件表时,修改了sysctl_nr_open,导致新的文件表个数 小于我们所需要的。所以,这里需要对new_fdt->max_fds和nr进行判断。如果小于nr,那么expand失败 */
if (unlikely(new_fdt->max_fds = nr)) {
__free_fdtable(new_fdt);
}
* Check again since another task may have expanded the fd table while
* we dropped the lock
cur_fdt = files_fdtable(files);
/* 如注释所示,有可能另外一个进程已经扩展了文件表,所以这里再次判断 */
if (nr >= cur_fdt->max_fds) {
/* 复制文件表 */
/* Continue as planned */
copy_fdtable(new_fdt, cur_fdt);
rcu_assign_pointer(files->fdt, new_fdt);
/*
对于文件表结构struct files_struct,其成员变量fd_array为一个大小为NR_OPEN_DEFAULT的数 组。这是一种常用的技巧。一般来说,进程的打开的文件不会太多,所以可以直接使用一个比较小的数组,这 样可以提高效率避免二次分配,同时由于数组较小,并不会太浪费空间。当文件个数超过数组大小的时候,再 重新申请内存。*/
if (cur_fdt->max_fds > NR_OPEN_DEFAULT)
free_fdtable(cur_fdt);
} else {
/* Somebody else expanded, so undo our attempt */
return 1;
expand_files结束之后,alloc_fd也学习完了,即宏get_unused_fd_flags也就结束了,那么我们就再次回到了函数sock_alloc_file,继续学习其调用的其它函数。