在内核模块中访问proc文件中的数据

5
我需要在Android内核模块中访问一些proc文件。基本上,我需要像“cat /proc/uptime”命令中显示的信息。但是我需要以编程方式执行此操作。
我尝试使用proc_fs函数进行操作,但对我来说有点模糊,通常示例是创建一个proc文件,然后读取它,就这样。我需要实际使用proc文件中的数据。
我也尝试了好用的fopen,但似乎在模块中不起作用。
我应该怎么做呢?我真的很新手。 我正在goldfish Android内核上工作。
谢谢。

你尝试过像读取普通文件一样读取/proc/foo吗?将其全部读入,然后解析它。顺便说一句,'linux-kernel' 是这个问题更好的标签。 - Peter L.
我尝试了,不起作用。感谢你的提示。 - douglasd3
为什么任何人想在内核上下文中使用proc fs,它们是为用户空间设计的。您为什么不直接使用数据结构和全局变量,从而proc获取信息呢? - Pradeep Goswami
3个回答

5

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使用率。我通过遵循这个被接受的答案https://dev59.com/i2Qn5IYBdhLWcg3wkH7U#16736599来进入proc文件。但我认为我已经掌握了主要思路。谢谢。 - douglasd3

1
我在回答原问题,即内核模块如何访问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或任何其他特殊文件系统中的文件访问数据的情况似乎是合法的。

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

内核模块代码按设计原则与内核的其余部分在同一特权级别上运行。没有绝对可靠的方法来拒绝内核模块访问任何其他部分的内核可以访问的数据。任何此类尝试都可以用美丽而丑陋的黑客技巧规避。

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

-1

我使用了 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 - Chris Stratton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接