虚拟文件系统之文件系统的安装与卸载

努力成为linux kernel hacker的人李万鹏原创作品,为梦而战。转载请标明出处

http://blog.csdn.net/woshixingaaa/archive/2011/05/14/6420104.aspx

安装普通文件系统
mount系统调用被用来安装一个普通的文件系统;它的服务例程是sys_mount()。这个函数首先把参数的值拷贝到临时内核缓冲区,也就是位于内核栈的这个函数的那些局部变量。获取大内核锁,并调用do_mount()函数。

它调用do_kern_mount函数,给它传递的参数为文件系统类型,安装标志以及块设备名。
do_kern_mount返回一个新的安装文件系统描述符的地址。

do_add_mount实现的基本功能:
1)获得当前进程的写信号量namespace_sem,因为函数要更改namespace结构。
2)do_kern_mount()函数可能让当前进程睡眠;同时,另一个进程可能在完全相同的安装点上安装文件系统或者甚至更改根文件系统(current->namespace->root)。验证在该文件系统安装点上最近安装的文件系统是否仍指向当前的namespace;如果不是,则释放读/写信号量并返回一个错误码。
3)如果要安装的文件系统已经被安装在由系统调用的参数所指定的安装点上,或该安装点是一个符号链接,则释放读/写信号量并返回一个错误码。
4)初始化由do_kern_mount()分配的新安装文件系统对象的mnt_flags字段的标志。
5)调用graft_tree()把新安装的文件系统对象插入到namespace链表,散列表及父文件系统的子链表中。
6)释放namespace_sem读/写信号量并返回
这里说明一下真正实现文件系统安装的是do_add_mount函数,而不是do_kern_mount函数。do_kern_mount函数只是得到一个vfsmount,并初始化超级块之类的。真正的挂载在do_add_mount函数中调用的graft_tree,graft_tree调用的attach_recursive_mnt,attach_recursive_mnt调mnt_set_mountpoint(dest_mnt,dest_dentry,source_mnt)完成的:

分配超级块对象
文件系统对象的get_sb方法通常是由单行函数实现,例如在Ext2文件系统中该方法的实现如下:

get_sb_bdev()VFS函数分配并初始化一个新的适合于磁盘的文件系统的超级块;它接受ext2_fill_super()函数的地址,该函数从Ext2磁盘分区读取磁盘超级块。

安装文件系统
安装文件系统分两个阶段:
1.内核安装特殊rootfs文件系统,该文件系统仅提供一个作为初始安装点的空目录。
2.内核在空目录上安装实际根文件系统。
阶段一:安装rootfs文件系统
第一阶段由init_rootfs()和init_mount_tree()函数完成的,它们在系统初始化过程中完成。

1.调用do_kern_mount函数,把字符串"rootfs"作为文件系统类型参数传递给它,并把该函数返回的新安装文件系统描述符的地址保存在mnt局部变量中。do_kern_mount()最终调用rootfs文件系统的get_sb方法,也即rootfs_get_sb()函数:

get_sb_nodev()函数执行如下步骤:

a.调用sget()函数分配新的超级块,传递set_anon_super()函数的地址作为参数。接下来,用合适的方式设置超级块的s_dev字段:主设备号为0,次设备号不同于其他已安装的特殊文件系统的次设备号。
b.将flags参数的值拷贝到超级块的s_flags字段中。
c.调用ram_fill_super()函数分配索引节点和对应的目录项对象,并填充超级块字段值。由于rootfs是一种特殊文件系统,没有磁盘超级块,因此只需执行两个超级块操作。
d.返回新超级块的地址。
2.为进程0的命名空间分配一个namespace对象,并将新分配的已安装文件系统描述符插入到namespace的链表中。
3.将系统中每个进程的namespace字段设置为namespace对象的地址;同时初始化引用计数器namespace->count(缺省情况下,所有进程共享同一个初始namespace)。
4.将进程0的根目录和当前工作目录设置为根文件系统。
阶段二:安装实际根文件系统
prepare_namespace()函数执行如下:


卸载文件系统
umount()系统调用用来卸载一个文件系统。

该函数执行如下操作:
1.调用user_path()查找安装点路径名;该函数把返回的查找结果存放在nameidata类型的局部变量nd中。
2.如果查找的最终目录不是文件系统的安装点,则设置retval返回码为-EINVAL并跑到第6步。这种检查是通过验证path.mnt->mnt_root进行的。
3.如果要卸载的文件系统还没有安装在命名空间中,则设置retval返回码为-EINVAL并跳到第6步,这种检查是通过验在path.mnt上调用check_mnt()函数进行的。
4.如果用户不具有卸载文件系统的特权,则设置retval返回码为-EPERM并跳到第6步。
5.调用do_umount(),传递给他的参数为path.mnt和flags。
a.从已安装文件系统对象的mnt_sb字段检查超级块对象的sb的地址。
b.如果用户要求强制拆卸操作,则调用umount_begin超级块操作中断任何正在进行的安装操作。
c.如果要卸载的文件系统是根文件系统,且用户并不要求真正的把它卸载下来,则调用do_remount_sb()重新安装根文件系统为只读并终止。
d.为进行写操作而获取当前进程的namespace_sem读/写信号量和vfsmount_lock自旋锁。
e.如果已安装文件系统不包含任何子安装文件系统的安装点,或者用户要求强制卸载文件系统,则调用umount_tree()卸载文件系统(及其所有子文件系统);
f.释放vfsmount_lock自旋锁和当前进程的namespace_sem读/写信号量。
6.减少相应文件系统根目录的目录项对象和已安装文件系统描述符的引用计数器的值;这些计数器值由path_lookup()增加。
7.返回retval的值。

你可能感兴趣的:(linux,Security,F#,Blog,UP)