• linux内核中网络文件系统的注册初始化


    针对内核3.9

    系统开启时,会使用init/main.c,然后再里面调用kernel_init(),在里面会再调用do_basic_setup(),调用do_initcalls(),调用do_one_initcall(),这个函数会去把注册了所有需要初始化的系统调用一一初始化。而网络模块由于全部都是基于socket在进行,所以,相关网络模块,在do_one_initcall()中会通过core_init()调用sock_init()来把网络文件系统登记在整个linux的文件系统中。其中core_init()非常重要,负责在内核初始化阶段把这些需要初始化的函数集中放在一个section里然后之后一个一个的进行处理。代码为:

    286 #define core_initcall(fn)               module_init(fn)

    297 #define module_init(initfn)                                     

    298         static inline initcall_t __inittest(void)               

    299         { return initfn; }                                      

    300         int init_module(void) __attribute__((alias(#initfn)));

    Sock_init的过程在2.63.9的内核中变化较大,代码如下:

     static int __init sock_init(void)

    2602 {

    2603         int err;

    2604         /*

    2605          *      Initialize the network sysctl infrastructure.

    2606          */

    2607         err = net_sysctl_init();

    2608         if (err)

    2609                 goto out;

    2610 

    2611         /*

    2612          *      Initialize skbuff SLAB cache

    2613          */

    2614         skb_init();

    2615 

    2616         /*

    2617          *      Initialize the protocols module.

    2618          */

    2619 

    2620         init_inodecache();

    2621 

    2622         err = register_filesystem(&sock_fs_type);

    2623         if (err)

    2624                 goto out_fs;

    2625         sock_mnt = kern_mount(&sock_fs_type);

    2626         if (IS_ERR(sock_mnt)) {

    2627                 err = PTR_ERR(sock_mnt);

    2628                 goto out_mount;

    2629         }

    然后一句一句地进行分析,我们知道sysctl设置和显示在/proc/sys目录中的内核参数.能用sysctl来设置或重新设置连网功能,如IP转发、IP碎片去除及源路由检查等。2607行调用net_sysctl_init()来对其进行初始化,我们来看怎么初始化的。

     83 static struct ctl_table_header *net_header;

     84 __init int net_sysctl_init(void)

     85 {

     86         static struct ctl_table empty[1];

     87         int ret = -ENOMEM;

     92         net_header = register_sysctl("net", empty);

     93         if (!net_header)

     94                 goto out;

     95         ret = register_pernet_subsys(&sysctl_pernet_ops);

     96         if (ret)

     97                 goto out;

     98         register_sysctl_root(&net_sysctl_root);

     99 out:

    100         return ret;

    101 }

    首先调用register_sysctl()进行把新的sysctl注册到ctl表中去,然后调用register_pernet_subsys()利用超级块操作表注册块设备表(此处由于我还没有学习过文件系统所以没懂),最后调用register_sysctl_root(),这个函数实际上什么都没有,官方给的注释是为了避免局限性把这个系统所在位置注册为空,说实话,没怎么懂,还望指教。

    回到sock_init(void)中,skb_init()是为了初始化slab,不关心。然后是init_inodecache(),这个函数负责对inode进行处理,大概是要创建一块用于socket相关的inode的调整缓存,以方便之后对inode进行创建和释放。

    然后是 register_filesystem(struct file_system_type * fs),负责socket文件系统注册到内核中。代码如下:

     69 int register_filesystem(struct file_system_type * fs)

     70 {

     71         int res = 0;

     72         struct file_system_type ** p;

     73 

     74         BUG_ON(strchr(fs->name, '.'));

     75         if (fs->next)

     76                 return -EBUSY;

     77         write_lock(&file_systems_lock);

     78         p = find_filesystem(fs->name, strlen(fs->name));

     79         if (*p)

     80                 res = -EBUSY;

     81         else

     82                 *p = fs;

     83         write_unlock(&file_systems_lock);

     84         return res;

     85 }

    可以看到这里实际上是把一个新的文件系统注册到file_system_type这个全局变量的链表里,这里涉及到file_system_type这个数据结构,其中核心部分如下:

    1802 struct file_system_type {

    1803         const char *name;

    1804         int fs_flags;

    1811         struct dentry *(*mount) (struct file_system_type *, int,

    1812                        const char *, void *);

    1813         void (*kill_sb) (struct super_block *);

    1814         struct module *owner;

    1815         struct file_system_type * next;

    1826 };

    其中struct dentry *(*mount) (struct file_system_type *, int,const char *, void *);是一个函数指针(也可以理解成钩子函数),负责指明哪个函数来处理,比如此处需要用到的sock_fs_type,就通过mount来规定使用sockfs_mount来进行注册。

    326 static struct file_system_type sock_fs_type = {

    327         .name =         "sockfs",

    328         .mount =        sockfs_mount,

    329         .kill_sb =      kill_anon_super,

    330 };

    再回到sock_init(void)最后使用sock_mnt = kern_mount(&sock_fs_type);来把网络文件系统安装上。实际上是调用vfs_kern_mount(),大概是在虚拟文件系统下进行内存分配之类的工作,没看懂。

    这里有一个非常优美的地方,在最后调用kern_mount(&sock_fs_type)时,会利用到sock_fs_type数据结构里的钩子函数sockfs_mount,然后继续调用mount_pseudo()执行实际上的安装,该函数是与文件系统相关的,是后面能执行socket等函数的先决条件。其中涉及文件系统,暂不讨论。

     

     

  • 相关阅读:
    oracle_dblink配置
    Data Pump(数据抽取)介绍
    亲测 logminer挖掘
    基础命令
    锁_rac环境kill锁表会话后出现killed状态(解决)
    ASM磁盘组空间不足--ORA-15041:DISGROUP DATA space exhausted (生产库案例)
    where子句的具体含义
    Oracle常用脚本——通过RMAN配置RAC环境的分布式磁带机
    如何创建动态的多维数组且内存空间连续
    Hibernate级联删除
  • 原文地址:https://www.cnblogs.com/hyd-desert-camel/p/3536345.html
Copyright © 2020-2023  润新知