8.12 代码:路径名

路径名查找涉及一系列对dirlookup的调用,每个路径组件调用一个。Nameikernel/fs.c:661)计算path并返回相应的inode。函数nameiparent是一个变体:它在最后一个元素之前停止,返回父目录的inode并将最后一个元素复制到name中。两者都调用通用函数namex来完成实际工作。

Namexkernel/fs.c:626)首先决定路径计算的开始位置。如果路径以斜线开始,则计算从根目录开始;否则,从当前目录开始(kernel/fs.c:630-633)。然后,它使用skipelem依次考察路径的每个元素(kernel/fs.c:635)。循环的每次迭代都必须在当前索引结点ip中查找name。迭代首先给ip上锁并检查它是否是一个目录。如果不是,则查找失败(kernel/fs.c:636-640)(锁定ip是必要的,不是因为ip->type可以被更改,而是因为在ilock运行之前,ip->type不能保证已从磁盘加载。)如果调用是nameiparent,并且这是最后一个路径元素,则根据nameiparent的定义,循环会提前停止;最后一个路径元素已经复制到name中,因此namex只需返回解锁的ipkernel/fs.c:641-645)。最后,循环将使用dirlookup查找路径元素,并通过设置ip = nextkernel/fs.c:646-651)为下一次迭代做准备。当循环用完路径元素时,它返回ip

namex过程可能需要很长时间才能完成:它可能涉及多个磁盘操作来读取路径名中所遍历目录的索引节点和目录块(如果它们不在buffer cache中)。Xv6经过精心设计,如果一个内核线程对namex的调用在磁盘I/O上阻塞,另一个查找不同路径名的内核线程可以同时进行。Namex分别锁定路径中的每个目录,以便在不同目录中进行并行查找。

这种并发性带来了一些挑战。例如,当一个内核线程正在查找路径名时,另一个内核线程可能正在通过取消目录链接来更改目录树。一个潜在的风险是,查找可能正在搜索已被另一个内核线程删除且其块已被重新用于另一个目录或文件的目录。

Xv6避免了这种竞争。例如,在namex中执行dirlookup时,lookup线程持有目录上的锁,dirlookup返回使用iget获得的inode。Iget增加索引节点的引用计数。只有在从dirlookup接收inode之后,namex才会释放目录上的锁。现在,另一个线程可以从目录中取消inode的链接,但是xv6还不会删除inode,因为inode的引用计数仍然大于零。

另一个风险是死锁。例如,查找“.”时,next指向与ip相同的inode。在释放ip上的锁之前锁定next将导致死锁。为了避免这种死锁,namex在获得下一个目录的锁之前解锁该目录。这里我们再次看到为什么igetilock之间的分离很重要。

copyright by duguosheng all right reserved,powered by Gitbook该文件修订时间: 2021-08-19 14:13:16

results matching ""

    No results matching ""