本文主要对Linux分析网络文件系统的注册和挂载过程
一、简介Linux中";万物皆文件",socket在Linux中对应的文件系统称为Sockfs,每创建一个socket,就在sockfs同时创建了一个特殊的文件sockfs在文件系统中inode,该inode目前唯一的标志socket的通信。
本文的重点是sockfs在文件系统的注册和挂载过程中,将在未来进行socket详细分析和记录底层来龙去脉。
二、三核心结构体1、struct file_system_type
file_system_type结构体代表Linux各种内核文件系统,每个文件系统都必须有自己的file_system_type用于描述具体文件系统的类型,如ext4对应的ext4_fs_type,struct file_system_type如结构体所示:
struct file_system_type{const char *name; ///文件系统名称int fs_flags;#define FS_REQUIRES_DEV 1 #define FS_BINARY_MOUNTDATA 2#define FS_HAS_SUBTYPE 4#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */struct dentry *(*mount) (struct file_system_type *, int,const char *, void *); ////挂载本文件系统时使用的回调函数void (*kill_sb) (struct super_block *); ///释放超级块函数指针struct module *owner;//指向实现本文件系统的模块,通常为THIS_MODULE宏struct file_system_type * next;///指向文件系统类型链表的下一个文件系统类型struct hlist_head fs_supers;struct lock_class_key s_lock_key;struct lock_class_key s_umount_key;struct lock_class_key s_vfs_rename_key;struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];struct lock_class_key i_lock_key;struct lock_class_key i_mutex_key;struct lock_class_key i_mutex_dir_key;};
如struct file_system_type * next结构成员,所有文件系统file_system_type结构形成链表,在fs/filesystem.c文件系统的全局变量
/* fs/filesystem.c*/static struct file_system_type *file_systems;
在Linux内核中sock_fs_type结构定义代表sockfs网络文件系统,如下所示:
static struct file_system_type sock_fs_type ={.name = "sockfs",.mount = sockfs_mount,.kill_sb = kill_anon_super,};
2、struct vfsmount与struct mount
安装文件系统时,会有一个vfsmount结构和mount被创建,mount代表文件系统的安装实例,在旧的核心版本中mount和vfsmount的成员都在vfsmount里,现在Linux内核将vfsmount改作mount并将结构体mount中mnt_root, mnt_sb, mnt_flags成员移到vfsmount在结构体中。这样使得vfsmount在许多情况下,内容更简洁,只需要传递vfsmount而已。struct 路由知识 vfsmount如下:
struct vfsmount{struct dentry *mnt_root; ///指向文件系统的根dentrystruct super_block *mnt_sb; // 超级块对象指向文件系统int mnt_flags; // 本文件系统的挂载标志}
对于每一个mount有一个文件系统vfsmount结构表示,sockfs安装时的vfsmount定义如下:
static struct vfsmount *sock_mnt __read_mostly;
struct mount如下:
struct mount{struct hlist_node mnt_hash; /* 链表用于链接全局已挂载的文件系统 */struct mount *mnt_parent; /* 文件系统指向本文件系统的挂载点,即父文件系统 */ struct dentry *mnt_mountpoint; /* 指向本文件系统的挂载点dentry */struct vfsmount mnt; /* 指向本文件系统vfsmount实例 */union{struct rcu_head mnt_rcu;struct llist_node mnt_llist;};#ifdef CONFIG_SMPstruct mnt_pcp __percpu *mnt_pcp;#elseint mnt_count;int mnt_writers;#endifstruct list_head mnt_mounts; /* 本文件系统下所有子文件系统链表的表头,以下节点都是mnt_child */struct list_head mnt_child; /* 链接到被该文件系统挂起的父文件系统mnt_mounts上 */struct list_head mnt_instance; /* 路由网 链接到sb->s_mounts上的一个mount实例 */const char *mnt_devname; /* 设备名,如/dev/sdb1 */struct list_head mnt_list; /* 链接到进程namespace在已经挂载的文件系统中,表头是mnt_namespace的list域 */ struct list_head mnt_expire; /* 链接到文件系统专有的过期链表,如NFS, CIFS等 */struct list_head mnt_share; /* 链接到共享挂载的循环链表 */struct list_head mnt_slave_list;/* 本文件系统slave mount链表的表头 */struct list_head mnt_slave; /* 连接到master文件系统的mnt_slave_list */struct mount *mnt_master; /* 指向本文件系统master文件系统,slave is on master->mnt_slave_list */struct mnt_namespace *mnt_ns; /* 该文件系统的过程指向name space */struct mountpoint *mnt_mp; /* where is it mounted */struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */struct list_head mnt_umounting; /* list entry for umount propagation */#ifdef CONFIG_FSNOTIFYstruct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;__u32 mnt_fsnotify_mask;#endifint mnt_id; /* mount identifier */int mnt_group_id; /* peer group 路由知识 identifier */int mnt_expiry_mark; /* true if marked for expiry */struct hlist_head mnt_pins;struct fs_pin mnt_umount;struct dentry *mnt_ex_mountpoint;}
更多Linux内核视频文章免费收到后台私信【内核大礼包】自行获取。
三、sockfs注册文件系统
Linux当核心初始化时,执行sock_init()函数登记sockfs,sock_init()函数如下:
static int __init sock_init(void){...err = register_filesystem(&sock_fs_type);////注册网络文件系统...sock_mnt = kern_mount(&sock_fs_type);/////装网络文件系统...}
注册函数:
int register_filesystem(struct file_system_type * fs){int res = 0;struct file_system_type ** p;BUG_ON(strchr(fs->name, '.'));if (fs->next)return -EBUSY;write_lock(&file_systems_lock);p = find_filesystem(fs->name, strlen(fs->name)); //找出它是否存在if (*p)res = -EBUSY;else*p = fs; //将filesystem静态变量指向fswrite_unlock(&file_systems_lock);return res;}
注册函数中的find函数如下,for循环开始file_systems变量是上述注册文件系统使用的全局变量指针,strncmp去比较file_system_type的第一项name(文件系统名称)是否与要注册的文件系统名称相同,如果返回相同的P指向相同的名称file_system_type结构指针,如果找不到,指向NULL。
static struct file_system_type **find_filesystem(const char *name, unsigned len){struct file_system_type **p;for (p = &file_systems; *p; p = &(*p)->next)if (strncmp((*p)->name, name, len) == 0 &&!(*p)->name[len])break;return p;}
}{