Ext2文件系统—路径名查找—1--挂载、follow_dotdot、follow_mount、lookup_mnt详解

本文深入解析了Linux VFS中的vfsmount结构及其在文件系统挂载过程中的作用,并详细介绍了路径查找过程中涉及的关键函数及数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、vfsmount


对于文件系统的挂载,最重要的是理解vfsmount结构,它表示了文件系统的挂载信息。其结构如下所示。

struct vfsmount {
struct list_head mnt_hash;
struct vfsmount *mnt_parent;/* fs we are mounted on */
struct dentry *mnt_mountpoint;/* dentry of mountpoint */
struct dentry *mnt_root;/* root of the mounted tree */
struct super_block *mnt_sb;/* pointer to superblock */
struct list_head mnt_mounts;/* list of children, anchored here */
struct list_head mnt_child;/* and going through their mnt_child */
... ...
}

需要特别注意的是mnt_mountpoint、mnt_root和mnt_parent。mnt_mountpoint表示文件系统的挂载点,也就是文件系统在挂在时指定的目录。mnt_root表示文件系统本身的根目录,也就是节点号为2的索引节点所对应的目录。好,现在我们来详细分析啥叫安装。


所谓安装,就是从一个存储设备上读入超级块,在内存中建立起一个super_block结构,再进而将此设备上的根目录与文件系统中已经存在的一个空白目录挂上钩。注意区别系统根目录具体文件系统根目录。系统根目录的目录名是“/”,它只存在于内存中;而具体文件系统的根目录是没有目录名的,它存在于磁盘中,一般是节点号为2的索引节点对应的目录。系统在初始化时要将一个存储设备作为整个系统的“根设备”,它的根目录就成为整个文件系统的总根,也就是“/”。注意挂载都是将设备根目录挂在已存在的目录上。也就是说,根设备的根目录是挂载在系统总根“/”上的,其它设备根目录是挂载在其余已存在文件系统空目录上的。


举个例子。比如,我们将某个挂载硬盘分区mount -t vfat /dev/hda2 /mnt/d。实际上就是新建一个vfsmount结构作为连接件,vfsmount->mnt_sb = /dev/hda2的超级块结构;vfsmount->mntroot = /dev/hda2的"根"目录的dentry;vfsmount->mnt_mountpoint = /mnt/d的dentry; vfsmount->mnt_parent = /mnt/d所属的文件系统的vfsmount。并且把这个新建的vfsmount连入一个全局的hash表mount_hashtable中。


2、路径查找——>follow_dotdot


在路径查找中有个结构经常看到,那就是 struct nameidata nd;这个数据结构是临时性的,只用来返回搜索的结果。成功返回时,其中的指针dentry指向所找到的dentry结构,而在该dentry结构中则有指向相应的inode结构。指针mnt则指向一个vfsmount数据结构,记录着文件系统的安装点、文件系统的根目录等安装信息。


在linux文件系统路径查找中,有一个函数 __link_path_walk->follow_dotdot ,代码如下:

static __always_inline void follow_dotdot(struct nameidata *nd)
{
struct fs_struct *fs = current->fs;
while(1) {
struct vfsmount *parent;
struct dentry *old = nd->path.dentry;
                read_lock(&fs->lock);
if (nd->path.dentry == fs->root.dentry &&
   nd->path.mnt == fs->root.mnt) {
                        read_unlock(&fs->lock);
break;
}
                read_unlock(&fs->lock);
spin_lock(&dcache_lock);
if (nd->path.dentry != nd->path.mnt->mnt_root) {
nd->path.dentry = dget(nd->path.dentry->d_parent);
spin_unlock(&dcache_lock);
dput(old);
break;
}
spin_unlock(&dcache_lock);
spin_lock(&vfsmount_lock);
parent = nd->path.mnt->mnt_parent;
if (parent == nd->path.mnt) {
spin_unlock(&vfsmount_lock);
break;
}
mntget(parent);
nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);
spin_unlock(&vfsmount_lock);
dput(old);
mntput(nd->path.mnt);
nd->path.mnt = parent;
}
follow_mount(&nd->path.mnt, &nd->path.dentry);
}

这个函数完成的功能是,对于路径中的当前分量,如果当前节点名是“..”,那就要往上跑到当前已经到达的节点nd->dentry的父目录中去。代码分三种情况进行讨论。


第一个if (nd->path.dentry == fs->root.dentry &&nd->path.mnt == fs->root.mnt) 表示,已到达节点nd->dentry就是本进程的根节点,这是不能再往上跑了,所以保持nd->不变。


第二个if (nd->path.dentry != nd->path.mnt->mnt_root) 表示,已到达节点nd->dentry并不是所在设备的根目录,也就意味着当前到达节点与其父目录节点在同一个设备上。因此直接把父目录节点d_parent作为当前dentry返回则可。


剩下第三种情况则是,已到达节点nd->dentry就是其所在设备上的根节点,往上跑一层就要跑到另一个设备上去了。而这里的if (parent == nd->path.mnt)是另外说明的特殊情况,即当前设备是系统根设备,则无法再往上跑到另一个设备中去了,因为已经到达“/”,所以直接返回。每个已安装的存储设备,包括根设备,都一个vfsmount结构,结构中有个指针mnt_parent指向其“父设备”,但是根设备的这个指针则指向自己,因为它再没有“父设备”了,而另一个指针mnt_mountpoint 则指向代表着安装点(一定是个目录)的dentry结构。若不是这种情况,那就要往上跑一层就要跑到另一个设备上。从文件系统的角度看,安装点与所安装设备的根目录是等价的,因为设备就是把它的根目录与安装点挂载挂钩而实现安装的。所以这种情况并不break,而要接着循环,就是要再往上一层跑到安装点的上一层目录中(而不是安装点本身)。


3、路径查找——>follow_mount、lookup_mnt


这两个函数我花了蛮久理解。后来发现其实很简单,就是说,如果当前找到的某个目录的dentry是被mount了的,那么就要一直顺着往下,找到mount在该目录的文件系统的,最底层一个,根目录的dentry结构


在文件系统挂载后,代表此设备的vfsmount 变量(假设是mnt)会通过其中的mnt_hash连接到它的挂载目录所对应的dentry结构d_mounted指向的链表中。因此可以通过判断d_mounted是否为零来检测此dentry是否被mount。下面分析这两个函数。

struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, int dir)
{
struct list_head *head = mount_hashtable + hash(mnt, dentry);
struct list_head *tmp = head;
struct vfsmount *p, *found = NULL;
for (;;) {
tmp = dir ? tmp->next : tmp->prev;
p = NULL;
if (tmp == head)
break;
p = list_entry(tmp, struct vfsmount, mnt_hash);
if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
found = p;
break;
}
}
return found;
}

它从 mount_hashtable表中去寻找相应的vfsmount结构。注意if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) 。其实mount在当前目录下的文件系统根目录,其mnt_mountpoint所对应的dentry所指向的inode是同一个,因为都是同一个挂载目录,inode只有一个。但是不同路径打开的dentry不一样所以要通过p->mnt_mountpoint == dentry来保证。而p->mnt_parent == mnt 很重要,它表示找的文件系统的根目录是直接mount在当前目录下的。所以在follow_mount函数中是一个循环,不断找到当前dentry直接mount下的根目录,直至最底层一个根目录。


因此follow_mount函数功能很明显,它把nd->dentry和nd->mnt更新为相应已安装文件系统的安装点和安装系统对象的地址;然后重复整个操作(几个文件系统可以安装在同一个安装点上)。
















可以读写Ext2,以Ext2方式挂载Ext3文件系统(不支持Ext3日志),不支持中文! It provides Windows NT4.0/2000/XP/2003/Vista/2008 with full access to Linux Ext2 volumes (read access andwrite access). This may be useful if you have installed both Windows and Linux as a dual boot environment on your computer. What features are supported? Complete reading and writing access to files and directories of volumes with theExt2 orExt3 file system. Supports features which are specific to the I/O-system of Windows: Byte Range Locks, Directory Notfication (so the Explorer updates the view of a directory on changes within that directory), Oplocks (so SMB clients are able to cache the content of files). Allows Windows to run with paging files on Ext2 volumes. UTF-8 encoded file names are supported. The driver treats files with file names that start with a dot "." character ashidden. Supports GPT disks if the Windows version used also does. Supports use of the Windows mountvol utility to create or delete drive letters for Ext2 volumes (except on Windows NT 4.0). See also section"Can drive letters also be configured from scripts?". What features are *not* supported? Inodes that are larger than 128 bytes are not supported. Access rights are not maintained. All users can access all the directories and files of an Ext2 volume. If a new file or directory is created, it inherits all the permissions, the GID and the UID from the directory where it has been created. There is one exception to this rule: a file (but not a directory) the driver has created always has cleared "x" permissions, it inherits the "r" and the "w" permissions only. See also section"What limitations arise from not maintaining access rights?". The driver does not allow accessing special files at Ext2 volumes, the access will be always denied. (Special files are sockets, soft links, block devices, character devices and pipes.) Alternate 8.3-DOS names are not supported (just because there is no place to store them in an Ext2 file system). This can prevent legacy DOS applications, executed by the NTVDM of Windows, from accessing some files or directories. Currently the driver does not implement defragging support. So defragmentation applications will neither show fragmentation information nor defragment any Ext2 volume. This software does not achieve booting a Windows operating system from an Ext2 volume. LVM volumes are not supported, so it is not possible to access them.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值