天天看点

TCP/IP源码学习(48)——socket与VFS的关联(2)

作者:[email protected]

博客: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,继续学习其调用的其它函数。

继续阅读