From: Felix Lee Date: Tue, 19 Sep 2023 22:33:34 +0000 (+0800) Subject: fix typos until manage proc file with standard filesystem section X-Git-Url: https://www.ivnss.com/gitweb/?a=commitdiff_plain;h=87dd27e13f11a8c797bedfe90c63748154926701;p=lkmpgcn fix typos until manage proc file with standard filesystem section --- diff --git a/lkmpg_cn.tex b/lkmpg_cn.tex index b32fb7c..2e9a02c 100644 --- a/lkmpg_cn.tex +++ b/lkmpg_cn.tex @@ -869,7 +869,7 @@ int main(void) \section{用户空间相对于内核空间} \label{sec:user_kernl_space} 内核就是对资源的访问,无论所讨论的资源是否恰好是一个显卡,一个硬盘或甚至内存。% -程序通常竟争相同的资源。当我刚刚保存此文档时,updatedb 开始更新本地数据库。我的% +程序通常竞争相同的资源。当我刚刚保存此文档时,updatedb 开始更新本地数据库。我的% vim 会话与 updatedb 两者同时使用硬盘驱动。内核需要保持事件的有序性,并且不让用% 户随时访问资源。为此,一个 CPU 可以运行于不同的模式。每种模式都提供不同程度的自% 由度,让你可以在系统上执行你想要的操作。Intel 80386 构架有\,4\,种这样的模式,称% @@ -1238,8 +1238,8 @@ cat /proc/devices 告诉用户该操作是不被支持的。如果你看不到我们如何处理读入缓冲区的数据,请不要担% 心;我们对此没做太多的事情。我们只是读入数据并打印一条消息来确认我们收到了它。 -在多线程环境,没有任何保护,对于相同内存地址的并发访问可能导致竟争情况,并且不% -能保持性能。在内核模块中,由于多个实例访问共享资源,可能产生并发竟争的问题。我% +在多线程环境,没有任何保护,对于相同内存地址的并发访问可能导致竞争情况,并且不% +能保持性能。在内核模块中,由于多个实例访问共享资源,可能产生并发竞争的问题。我% 们用原子化 Compare-And-Swap (CAS) 来保持状态,原子化的 \cpp|CDEV_NOT_USED| 与原% 子化的 \cpp|CDEV_EXCLUSIVE_OPEN| 来决定当前文件是否被其它人打开或没有被打开。% CAS 用一个希望的值比较一个内存位置的内容,只有两者相同时,才能更改那个内存位置% @@ -1261,27 +1261,27 @@ CAS 用一个希望的值比较一个内存位置的内容,只有两者相同 \chapter{/proc文件系统} \label{sec:procfs} 在 Linux 中,内核和模块有一个额外的机制来向进程发送信息,这个机制就是 % -\verb|/proc/modules|。最初设计它的意图是允许轻松访问有关进程的信息(因此得名),现% -在它被内核的每一个需要报告的有趣部分所使用,例如 \verb|/proc/modules| 提供模块% -列表, \verb|/proc/meminfo| 它收集内存使用的信息。 +\verb|/proc/modules|。最初设计它的意图,是允许轻松访问有关进程的信息(因此得名),% +现在它被内核每一个需要报告的有趣部分所使用,例如 \verb|/proc/modules| 提供模块% +列表, \verb|/proc/meminfo| 收集内存使用的信息。 使用 proc 文件系统的方法与设备驱动程序使用方法非常相似,使用 \verb|proc| 文件所% -需的所有信息创建一个数据结构,包括指向任可处理函数的指针(在我们的例子中只有一个,% -当有人试从 \verb|/proc| 文件中读取时调用的函数)。然后,\cpp|init_module| 向内核% -注册该结构,并且 \cpp|cleanup_module| 注销该结构。 +需的所有信息创建一个数据结构,包括指向任何可处理函数的指针(在我们的例子中只有一% +个,当有人尝试从 \verb|/proc| 文件中读取时,调用的函数)。然后,\cpp|init_module| % +向内核注册该结构,并且 \cpp|cleanup_module| 注销该结构。 正常的文件系统位于一个磁盘,而不是只在内存(它是 \verb|/proc| 的位置),并且在这种% -情况下,index-node(简称 inode)数字是一个指向该文件的 inode 位于的磁盘位置的指针。% +情况下,index-node(简称 inode)数字是一个指向该文件的 inode 位于磁盘位置的指针。% inode 包含关于该文件的信息,例如文件的许可权限,以及指向磁盘位置或可以找到文件% -数据的位置指针。 +数据位置的指针。 -因为在文件被打开或关闭时,我们不会被调用,\cpp|try_module_get| 与 \cpp|module_put| % -所以对我们来说,在模块中没有地方来被放置。如果文件已被打开,并且之后模块被移除% +因为在文件被打开或关闭时,我们不会被调用,所以 \cpp|try_module_get| 与 % +\cpp|module_put| 对我们来说没有地方在模块中放置。如果文件已被打开,然后模块被移除% 了,则无法避免不良后果。 -这里有一个如何使用 \verb|/proc| 文件的简单示例。这是针对 \verb|/proc| 文件系统的% -HelloWorld。过程分三步:在函数 \cpp|init_module| 中 \verb|/proc/helloworld| 文件% -被创建,当在回调函数 \cpp|procfile_read| 读文件 \verb|/proc/helloworld| 时,返回% +这里有一个如何使用 \verb|/proc| 文件的简单示例。这是针对 \verb|/proc| 文件系统的 % +HelloWorld。这里有三部分:在函数 \cpp|init_module| 中 \verb|/proc/helloworld| 文件% +被创建,当用回调函数 \cpp|procfile_read| 读文件 \verb|/proc/helloworld| 时,返回% 一个值(与一个缓冲),并在 \cpp|cleanup_module| 函数中删除 \verb|/proc/helloworld| % 文件。 @@ -1289,11 +1289,11 @@ HelloWorld。过程分三步:在函数 \cpp|init_module| 中 \verb|/proc/hello 返回值是一个 \cpp|struct proc_dir_entry|,并且文件 \verb|/proc/helloworld| 的配% 置将使用它(例如,该文件的拥有者)。一个空返回值意味着创建过程失败。 -每次文件 \verb|/proc/helloworld| 被读取,\cpp|procfile_read| 函数会被调用。这个% -函数的两个参数非常重要:缓存(第二个参数)与偏移量(第四个参数)。缓存的内容将被返回% -到应用,其内容会被读取(例如,\cpp|cat| 命令)。偏移量的值是在文件中位于的当前位置。% -如果函数返回值不为空,那么这个函数会再次被调用。因此,细心使用这个函数,如果它决% -不返回零,读函数被没完没了的被调用。 +每次文件 \verb|/proc/helloworld| 被读取,\cpp|procfile_read| 函数都会被调用。这% +个函数的两个参数非常重要:缓存(第二个参数)与偏移量(第四个参数)。缓存的内容将被% +返回到应用,其内容会被读取(例如,\cpp|cat| 命令)。偏移量的值是在文件中位于的当% +前位置。如果函数返回值不为空,那么这个函数会再次被调用。因此,仔细地使用这个函% +数,如果它决不返回零,读函数被没完没了的被调用。 \begin{verbatim} $ cat /proc/helloworld @@ -1307,33 +1307,32 @@ HelloWorld! \cpp|proc_ops| 结构在 Linux v5.6+ 中的 \src{include/linux/proc\_fs.h} 文件中被% 定义。在旧的内核中,它用 \cpp|file_operations| 在 \verb|/proc| 文件系统中用于定% 制挂钩,但它存在一些在 VFS 中不需要的结构成员,且每次 VFS 扩展 \cpp|file_operations| % -集,\verb|/proc| 变得臃肿。另一方面,这种结构不仅节省了空间,还节省了一些操作,% -从而提高了性能。例如,\verb|/proc| 中永不消失的文件可以设置 \cpp|proc_flag| 作为% -\cpp|PROC_ENTRY_PERMANENT| 在每个打开/读取/关闭序列中保存两个原子操作,一个分配,% -一个释放。 +数据集合,\verb|/proc| 代码变得臃肿。另一方面,这种结构不仅节省了空间,还节省了% +一些操作,从而提高了性能。例如,\verb|/proc| 中永不消失的文件可以设置 \cpp|proc_flag| % +作为 \cpp|PROC_ENTRY_PERMANENT| 在每个打开/读取/关闭序列中保存两个原子操作,一% +个分配,一个释放。 \section{读与写一个/proc文件} \label{sec:read_write_procfs} 我们已经看过一个对 \verb|/proc| 文件非常简单的示例,该示例只是读取 % \verb|/proc/helloworld| 文件。也可能写入一个 \verb|/proc| 文件。其工作与读的方% 法相同,当 \verb|/proc| 文件被写入时,一个函数被调用,但在这里与读操作有少许不% -同,数据来自用户,因此你必段从用户户向内核空间输入数据(用 \cpp|copy_from_user| % +同,数据来自用户,因此你必须从用户空间向内核空间输入数据(用 \cpp|copy_from_user| % 或 \cpp|get_user|)。 - 用 \cpp|copy_from_user| 或 \cpp|get_user| 的原因是 Linux 内存(在 Intel 架构,有% 些其它处理器上可能是不同的) 被分段。这意味着一个指针,本身,在内存中并不引用唯% -一的位置。而仅用内存段中位置,并且你需要知首它是哪个内存段后,才能使用它。对内% -核来说,内核有一个内存段,每个进程也有一个内存段。 +一的位置,而引用内存段中一个位置,并且你需要知道该内存位置是哪个内存段后,才能% +使用它。对内核来说,只有一个内存段,且每个进程也拥有一个内存段。 进程唯一可以访问的内存段是它自己的内存段,因此在编写作为进程运行的常规程序时,% -无需担心段问题。当你编写内核模块时,通常需要访问内核内存段,即由系统自动处理。% -然而,当内存缓冲区的内容需要在当前运行的进程和内核之间传递时,内核函数会收到一% -个指向进程段中的内存缓冲区的指针。\cpp|put_user| 与 \cpp|get_user| 宏允许你去% -访问那些内存。这些函数只处理一个字符,用 \cpp|copy_to_user| 与 \cpp|copy_from_user| % -你可以处理几个字符。由于缓冲区(在读或写函数中)位于内核空间,因此对于写函数,你% -需要导入数据,因为它来自用户空间,但对于读函数,则不需要导入数据,因为数据已经% -在内核空间中。 +无需担心内存分段问题。当你编写内核模块时,通常需要访问内核内存段,即由系统自动% +处理。然而,当内存缓冲区的内容需要在当前运行的进程和内核之间传递时,内核函数会% +收到一个指向进程段中的内存缓冲区的指针。\cpp|put_user| 与 \cpp|get_user| 宏允% +许你去访问那些内存。这些函数只处理一个字符,用 \cpp|copy_to_user| 与 % +\cpp|copy_from_user| 你可以处理几个字符。由于缓冲区(在读或写函数中)位于内核空% +间,因此对于 write 函数,你需要导入数据,因为它来自用户空间,但对于 read 函数,% +则不需要导入数据,因为数据已经在内核空间中。 \samplec{examples/procfs2.c} @@ -1554,7 +1553,7 @@ ioctl 数字在头文件中,通常通过一个宏调用(\cpp|_IO|,\cpp|__IOR 收到其它人的不同 ioctl,或如果他们收到你的 ioctl,你将知道有地方出错了。更多信息,% 查看内核源代码树中 \src{Documentation/userspace-api/ioctl/ioctl-number.rst}。 -另外,我们需要小心对共享资源的并发访问,将导致竟争条件产生。解决方法是使用原子 % +另外,我们需要小心对共享资源的并发访问,将导致竞争条件产生。解决方法是使用原子 % Compare-And-Swap (CAS),我们在 \ref{sec:chardev_c} 中提到了它,用它来强制执行% 独占访问。