【问题标题】:Access data from proc file within kernel module从内核模块中的 proc 文件访问数据
【发布时间】:2013-08-31 15:22:31
【问题描述】:

我需要访问 Android 内核模块中的一些 proc 文件。 基本上我需要 cat 命令中显示的信息,例如cat /proc/uptime。但是我需要以编程方式进行。

我尝试使用proc_fs 函数,但这对我来说有点模糊,通常示例是创建一个 proc 文件然后读取它,就是这样。我需要实际使用 proc 文件中的数据。

我也尝试了好的fopen,但它似乎不适用于模块。

我该怎么做?我真的是这方面的新手。 我正在开发金鱼 Android 内核。

谢谢。

【问题讨论】:

  • 您是否尝试过像阅读普通文件一样阅读 /proc/foo ?全部阅读然后解析它。顺便说一句,“linux-kernel”将是这个问题的更好标签。
  • 我试过了,不行。感谢您的提示。
  • 为什么有人想在内核上下文中使用 proc fs,他们用于用户空间,为什么不直接使用数据结构和全局从 proc 获取信息的地方。

标签: android linux-kernel kernel kernel-module procfile


【解决方案1】:

Procfs 是一个内存文件系统。它是用户空间获取信息并将(配置)信息放入内核数据结构的接口。换句话说,procfs 使用户空间能够按照内核数据结构在运行时的存在方式进行交互和查看它们。

因此,/proc 中的任何文件意味着要从内核或内核模块中读取。为什么要这样做?在像 Linux 这样的单片内核中,您可以直接通过另一个子系统或通过预定义的函数访问内核中一个子系统的数据结构。

以下函数调用可能会有所帮助:

struct timespec uptime;

do_posix_clock_monotonic_gettime(&uptime);

你可以参考下面链接中的 /proc/uptime 实现,它本质上是一个seq_file

http://lxr.free-electrons.com/source/fs/proc/uptime.c

【讨论】:

  • 我的目标实际上是估计给定进程的 cpu 使用率。我按照这个公认的答案stackoverflow.com/a/16736599/1132848 进入了 proc 文件,但我想我明白了主要思想。谢谢
【解决方案2】:

我正在回答最初的问题,内核模块如何访问procfs 中的文件。

内核模块如何访问特殊文件系统中的文件

我发现以下是有用的参考: https://elixir.bootlin.com/linux/latest/source/fs/proc/proc_sysctl.c#L1790

我认为它是从内核命令行设置sysctl 值。顺序似乎如下:

A.挂载procfs 文件系统

  1. proc_fs_type = get_fs_type("proc");
  2. *proc_mnt = kern_mount(proc_fs_type);

B.在相对于 procfs 根目录的路径打开文件

  1. file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);

C.读/写文件

  1. int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id)
  2. wret = kernel_write(file, val, len, &pos);

D.关闭文件

  1. err = filp_close(file, NULL);

D.清理文件系统挂载

  1. kern_unmount(proc_mnt);
  2. put_filesystem(proc_fs_type);

内核模块应该访问特殊文件系统中的文件

是的,procfs 主要为用户空间提供对内核级数据的读/写访问。由于内核模块在内核中运行,如果存在允许模块访问此类数据的更直接的 API 调用序列,则首选使用此类 API,因为它可能更清洁、更少代码和更高效。

但是,动态加载的内核模块不能(干净)直接访问内核中的所有符号(或数据结构)。

内核模块只能访问以下函数和变量

  • 完全定义在一个头文件中,可以包含在内核模块源代码中

  • 或通过/include/asm-generic/export.h 中的宏之一显式暴露给内核模块:

    • EXPORT_SYMBOL
    • EXPORT_SYMBOL_GPL
    • EXPORT_DATA_SYMBOL
    • EXPORT_DATA_SYMBOL_GPL

内核模块需要访问未通过此类EXPORTED API 公开但可通过procfs 或任何其他特殊文件系统中的文件访问的数据的情况似乎是从内核模块访问此类文件的合法情况。

作为一般设计原则,我的理解是内核旨在实现机制而不强制执行特定策略。任何以强制用户空间可以访问数据但内核模块不能访问的策略的方式实现的功能都是设计不佳的。

内核模块代码按照设计运行在与内核其余部分相同的特权级别。没有万无一失的方法可以拒绝内核模块访问内核的任何其他部分可以访问的任何数据。任何此类尝试都可以通过漂亮丑陋的 hack 来规避。

作为一个极端的例子,在 x86 机器上,内核模块可以使用内联汇编来直接访问控制寄存器、遍历页表,并使用它想要的任何内存区域。中断和异常处理程序也是如此。

【讨论】:

    【解决方案3】:

    我用 top 来完成这个,因为它实际上给出了 CPU %。我使用的代码如下

    Process process = Runtime.getRuntime().exec("top -n 1");
                    //Get the output of top so that it can be read
                    BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));
                    String line;
                    //Read every line of the output of top that contains data
                    while (((line = bufferedReader.readLine()) != null)) {
                        //Break the line into parts.  Any number of spaces greater than 0 defines a new element
                        numbersC = line.split("[ ]+");              
                        if (i > 6) {  
                            //Some lines start with a space, so their indices are different than others
                            if (numbersC[0].equals("")){
                                //If name contains the string com.android, then it is a process that we want to take values for
                                if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android".toLowerCase())){
                                    //Add the name of the process to the Name arraylist, excluding the com.android. part
                                    Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
                                    //Add the CPU value of the process to the CPU arraylist, without the % at the end
                                    CPU.add(Long.parseLong(numbersC[3].replace("%", "")));  
                                }
                            }
                            else {
                                //This is basically the same as above, except with different index values, as there is no leading space in the numbers array
                                if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android.".toLowerCase())){ 
                                    Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
                                    CPU.add(Long.parseLong(numbersC[2].replace("%", "")));
                                }
                            }
                        }
                        i++;
                    }
    

    【讨论】:

    • 这不是对所提问题的回答(它试图在内核中获取此信息),原因有三个。首先,您使用的是top,与直接读取 /proc 条目相比,它基本上是间接的。其次,您正在用 java 编写,它不在内核上下文中运行。第三,基本问题是 /proc (如已接受的答案中所述)和 top 都不打算在内核上下文中使用。
    猜你喜欢
    • 2014-02-16
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多