【问题标题】:How the getcwd is implemented in the kernel (library)?getcwd 如何在内核(库)中实现?
【发布时间】:2015-03-30 07:42:24
【问题描述】:

一个进程可以做

chdir("/to/some/where");

当来自另一个外壳时

mv /to/some/where /now/different/path/

第一个过程

print getcwd(); 
#prints /now/different/path/

getcwd 是如何实现的? (在最低级别,例如在内核级别,inode ...)。

我知道常见的(基于 inode 的)文件系统是如何工作的,例如包含目录的内容(条目名称和相应的 inode 编号)。

编辑

问题可能含糊不清 - 试图完善它。一种可能的情况(据我们所知)

  1. 内核知道给定进程(和他的线程)的CWD 的inode - 例如。索引节点号1000
  2. 读取 inode(获取需要读取的块)
  3. 读取相应的块(例如打开目录)
  4. 读取目录条目(条目名称和 inode 编号)
  5. 获取..父目录的inode号(例如900)和.(当前目录)的inode号
  6. 读取得到的父目录的内容
  • 上一个目录的name(对于inode 1000
  • 父目录的inode号
  1. 继续5. - 直到到达根 inode。

也就是说,getcwd 用于

/some/very/very/very/deep/directory/level

需要更多原始 IO 操作(需要读取更多目录条目)

/tmp

整个getcwd 是由两个读数完成的?

这是正确的吗?还是完全以另一种方式完成?

【问题讨论】:

  • 什么操作系统的内核?我猜您说的是 Unix 的各种变体之一,但是……如果您说的是 Linux,您是否考虑过查看源代码告诉您的内容?
  • @T.J.Crowder 我对概念层面的回答很感兴趣,当然主要是类 unix 系统,(linux,freebsd)但是如果 Windows 用另一种(已知)方式来做这件事 - 会很好知道如何... ;) 试图在数百万行内核源代码中找到它是如何在许多系统调用中实现的,对我来说可能很难。如果你知道答案,是不是太“难”告诉我? ;)
  • 很高兴知道这个问题有什么问题,我如何在这个主题上展示更多的研究工作,例如我可以做些什么来改善这个问题以避免投票。 ;)
  • 避免投票?在正确的地方询问。 SO是针对编程问题的-这个问题与编程无关,而是因为您要求概念级别-例如什么是“编程”——我回答了。
  • 这个问题一点也不含糊。我希望答案涵盖问题的所有可能变化的整个集合/卷,而不仅仅是一个荒谬的具体(因此实际上无用)案例。机器人人通常要求后一种情况,因为他们不会思考,需要对记忆的知识进行简单的模式匹配。他们不能返回公式,因为他们不明白,但必须返回他们记住的列表。

标签: c directory kernel pwd


【解决方案1】:

首先,你问错地方了。这个问题更多是关于操作系统的,所以unix.stackexchange是更好的地方。

无论如何,对于某些古老的 UNIX 实现(例如 BSD 2.8)或类似的实现,您提出的解决方案是正确。可以按照您的描述完成路径名解析。

但是,出现了许多问题 - 其中很少:

  • 正如你所说 - 太复杂的路径名解析(是的,更深的目录需要更多的 IO)
  • 取决于只存在一个ROOT目录的前提。从引入 per process 根目录的 BSD 4.2 来看,情况并非如此 - 允许 chroot 系统调用 - 允许将根设置为任何目录而不显示进程的真实路径。 (最酷的 FreeBSD 功能之一是 jails - 取决于此)(而且古代 linux 只有一个根 - 只有在 0.96c 中引入了 VFS - 虚拟文件系统层)
  • 和权限问题 - 例如当
#shell1
$ mkdir -p /tmp/some
$ cd /tmp/some

第二个外壳

$ su
# mkdir -p /tmp/my
# chmod 700 /tmp/my
# mv /tmp/some /tmp/my/

/tmp/my 目录对于第一个进程不可读。所以,它无法确定路径,那么它应该如何处理文件呢?所以,再次在 shell1 中:

$ pwd
/tmp/some #the original
$ echo $CWD
/tmp/some
$ /bin/pwd
pwd: .: Permission denied

但是,你仍然可以做例子

$ touch bob #works

例如系统允许您在“当前”目录中工作,而不会让您知道您在哪里。 (在这两种情况下,例如在 chroot 和第二种情况下);)

这意味着每个进程都将当前工作目录存储在他的表中:

  • 设备号(例如 hdd1 或 hdd2)
  • 设备上的 inode 编号

  • 内核维护另一个全局表(在 linux 中称为 dentry(目录条目)),其中内核维护每个进程的“inode”->“路径”映射,每个打开的文件描述符,以及 indode 缓存(在内核本身维护的 linux 中,BSD:vnod 驱动程序的作业)等等。

例如当某个进程要求输入节点 X 的路径名时,内核搜索 dentry 表,如果找到条目 - 立即返回,如果没有 - 调用 lookup 进程,路径名解析

当例如发生重命名时,内核搜索dentry 表,如果找到条目并根据需要进行更改。

以上所有内容极其简化,如您所见,以上所有内容高度依赖于操作系统,通用基础由 POSIX 定义 - 但发生在后面(例如实现) - 你需要真正阅读内核和/或谷歌的源代码:

  • linux 目录
  • linux vfs
  • freebsd vnode
  • 路径名解析

等等。

Ps:对于挑剔者,:) - 正如我所说 - 一切都过于简单,所以如果你想要更正并添加更多细节 - 编辑答案 - 我将其转换为“社区 wiki 答案”。

【讨论】:

    【解决方案2】:

    在 Linux(或 *BSD-s)等当前 POSIX 内核中,当前工作目录(作为内核 inode)是process 状态的一部分。所以内核进程描述符(可能是Linux上的一些struct task_struct)包含或引用该cwd。那么getcwd 就是“简单地”一个系统调用来查询它。

    内核索引节点(对于打开的文件描述符,包括工作目录)与文件系统相关,与磁盘索引节点不同。

    当然,恶在细节!

    【讨论】:

    • 这意味着,如果另一个进程将目录移动到另一个地方,内核(在重命名时)会在他的表中搜索每个进程(和线程)并更改状态?
    • 编辑了问题 - inode 不包含 name,也不包含 path
    • 内核 inode(用于打开的文件描述符,包括当前工作目录)不是磁盘 inode。
    • 例如kernel inodesfilesystem inodes 不同,它们包含给定 kernel inode 的完整路径名。当any 进程进行文件操作时,例如rename (mv),内核搜索这个kernel inode table 并将存储的path 更改为每个打开的描述符的新值,给定的inode 有什么意义? (如果您可以编辑 evil details 的答案,那就太好了。:)
    • 你需要阅读几本关于 Unix 内部原理和操作系统原理的整本书。我没有时间向你解释。
    猜你喜欢
    • 2020-06-07
    • 2020-10-22
    • 2011-05-13
    • 2018-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    相关资源
    最近更新 更多