The Kernel Newbie Corner: Kernel Debugging with proc "Sequence" Files--Part 2

时间:2022-09-28 13:37:29

转载:https://www.linux.com/learn/linux-career-center/39972-kernel-debugging-with-proc-qsequenceq-files-part-2-of-3

This week, we'll pick up where we left off last week and continue discussing simple kernel and module debugging using seq_file-based proc files. And given the amount of material left to cover, we'll spend this week finishing off the issues related to the simpler, non-sequence proc files, and leave the complicated topic of sequenced writes for a final Part 3 next week, so this will be a relatively short column.

(The archive of all previous "Kernel Newbie Corner" articles can be found here.)

This is ongoing content from the Linux Foundation training program. If you want more content, please consider signing up for one of these classes.

A Quick Recap

As a refresher, let's consider a simple loadable module that represents a solution to last week's exercise and creates the proc file /proc/hz that, when read, displays the kernel tick rate (a value that shouldn't change no matter how many times you display it):

 #include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h> static int
hz_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", HZ);
return 0;
} static int
hz_open(struct inode *inode, struct file *file)
{
return single_open(file, hz_show, NULL);
} static const struct file_operations hz_fops = {
.owner = THIS_MODULE,
.open = hz_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
}; static int __init
hz_init(void)
{
printk(KERN_INFO "Loading hz module, HZ = %d.\n", HZ);
proc_create("hz", 0, NULL, &hz_fops);
return 0;
} static void __exit
hz_exit(void)
{
remove_proc_entry("hz", NULL);
printk(KERN_INFO "Unloading hz module.\n");
} module_init(hz_init);
module_exit(hz_exit); MODULE_LICENSE("GPL");

Some quick observations about the above:

  • Even though we're continuing to use the seq_file implementation of proc files which supports sequenced writes, we're still showing examples that print so little output that we can use the simpler, "single" variation designed to print all of the output we care about in a single operation. This will change when we finally get to Part 3 next week.
  • In case you hadn't figured it out yet, the kernel tick rate is available via the global kernel macro HZ, which is all we need to print.
  • Even though we're using printk() to generate some syslog messages upon module entry and exit, those calls are clearly not essential for proper operation of our proc file and, in many cases, proc files like this won't generate any log messages unless something goes wrong.
  • We're so confident that nothing can go wrong with our module that we're not even bothering to check return codes in our module entry routine. That's not actually lazy--if you recall, even some of the kernel routines take the same shortcut.

And now that we're all back up to speed, where do we go from here?

What Exactly Can We "Print" From Our proc File?

Notice above how you generate the output from your proc file--with a fairly self-explanatory call to seq_printf(). But there are a number of output primitives you can use for that output, all declared in the kernel header file include/linux/seq_file.h, which you can combine any way you want to produce that output:

 int seq_printf(struct seq_file *, const char *, ...)
int seq_putc(struct seq_file *m, char c);
int seq_puts(struct seq_file *m, const char *s);
int seq_write(struct seq_file *seq, const void *data, size_t len);
int seq_escape(struct seq_file *, const char *, const char *);
int seq_path(struct seq_file *, struct path *, char *);
int seq_dentry(struct seq_file *, struct dentry *, char *);
int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
char *esc);

The purpose of the first few should be obvious, and you can see the actual implementation and explanations of all of them in the corresponding kernel source file fs/seq_file.c. What's curious is that not all of those output primitives are exported to make them available to modules. The seq_path() function is exported, while the functionally similar seq_path_root() and seq_dentry() functions are not. And for extra confusion, the routine that they are all based on in that same source file, mangle_path() is exported. Does anyone else find that a bit odd?

In any event, it should be clear how you can generate your proc file output with any combination of printing strings, characters, or arbitrary sequences of bytes with any of the above.

Finally, make sure you consider exactly what format you want your proc file output to have. You might be tempted to spruce up the output with labels and headings, but that's just going to get in the way if you want to feed that output into another program. Your best bet is to keep things simple, and generate raw output data, then decide what to do with it from there.

Creating Hierarchical proc Files

Finally, rather than cluttering up the /proc directory with your personal proc files at the top level, you can create a subdirectory and keep multiple proc files in the same place. Here's the relevant snippets from a modified HZ module that creates the file /proc/rday/hz:

 #include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h> static struct proc_dir_entry* rday_dir; // pointer to new dir ... snip ... static int __init
hz_init(void)
{
rday_dir = proc_mkdir("rday", NULL);
proc_create("hz", 0, rday_dir, &hz_fops);
return 0;
} static void __exit
hz_exit(void)
{
remove_proc_entry("hz", rday_dir);
remove_proc_entry("rday", NULL);
}

Note what's changed here. Rather than create my HZ proc file under the (default location of) /proc, I first have to create (and save a global reference to) a new directory called "rday", underneath which I'll create my file. Conversely, if I do it this way, I have to make sure I undo those operations in the reverse order when I unload the module, as you can see above in the exit routine. Simple, no? There's just one new complication.

It's quite possible to write a module that creates a number of useful proc files but, at that point, you might consider actually checking return codes while creating all of your files and directories in case something goes wrong. As you've seen, if you're creating a single file, you can generally cheat and assume it's going to work. But if it gets more complicated, it might be time to start examining return codes, as in:

 static struct proc_dir_entry* rday_dir;

 static int __init
hz_init(void)
{
int retval = 0;
struct proc_dir_entry* hz_file; rday_dir = proc_mkdir("rday", NULL);
if (rday_dir == NULL) { // directory creation failed
retval = -ENOMEM;
goto out;
} hz_file = proc_create("hz", 0, rday_dir, &hz_fops);
if (hz_file == NULL) { // file creation failed
retval = -ENOMEM;
goto badfile;
} return 0; badfile:
remove_proc_entry("rday", NULL);
out:
return retval;
}

Recall from an earlier column that, if things go badly during your module entry routine, it's your responsibility to undo everything you did, and return all claimed resources back to the kernel.

Exercise for the reader: For a more complicated example that creates a number of files and symbolic links, see the file Documentation/DocBook/procfs_example.c in the kernel source tree. That example doesn't actually use the seq_file implementation of proc files, but it is a good example of how much error-checking can be done in a single loadable module.

Next week: Finishing things off with actual sequenced writing.

The Kernel Newbie Corner: Kernel Debugging with proc "Sequence" Files--Part 2的更多相关文章

  1. The Kernel Newbie Corner&colon; Kernel Debugging with proc &quot&semi;Sequence&quot&semi; Files--Part 3

    转载:https://www.linux.com/learn/linux-career-center/44184-the-kernel-newbie-corner-kernel-debugging-w ...

  2. The Kernel Newbie Corner&colon; Kernel Debugging Using proc &quot&semi;Sequence&quot&semi; Files--Part 1

    转载:https://www.linux.com/learn/linux-career-center/37985-the-kernel-newbie-corner-kernel-debugging-u ...

  3. Kernel Methods &lpar;5&rpar; Kernel PCA

    先看一眼PCA与KPCA的可视化区别: 在PCA算法是怎么跟协方差矩阵/特征值/特征向量勾搭起来的?里已经推导过PCA算法的小半部分原理. 本文假设你已经知道了PCA算法的基本原理和步骤. 从原始输入 ...

  4. Kernel Methods &lpar;2&rpar; Kernel function

    几个重要的问题 现在已经知道了kernel function的定义, 以及使用kernel后可以将非线性问题转换成一个线性问题. 在使用kernel 方法时, 如果稍微思考一下的话, 就会遇到以下几个 ...

  5. Debugging Information in Separate Files

    [Debugging Information in Separate Files] gdb allows you to put a program's debugging information in ...

  6. Kernel Methods &lpar;4&rpar; Kernel SVM

    (本文假设你已经知道了hard margin SVM的基本知识.) 如果要为Kernel methods找一个最好搭档, 那肯定是SVM. SVM从90年代开始流行, 直至2012年被deep lea ...

  7. Kernel Methods &lpar;3&rpar; Kernel Linear Regression

    Linear Regression 线性回归应该算得上是最简单的一种机器学习算法了吧. 它的问题定义为: 给定训练数据集\(D\), 由\(m\)个二元组\(x_i, y_i\)组成, 其中: \(x ...

  8. Linux Kernel sys&lowbar;call&lowbar;table、Kernel Symbols Export Table Generation Principle、Difference Between System Calls Entrance In 32bit、64bit Linux

    目录 . sys_call_table:系统调用表 . 内核符号导出表:Kernel-Symbol-Table . Linux 32bit.64bit环境下系统调用入口的异同 . Linux 32bi ...

  9. Jordan Lecture Note-12&colon; Kernel典型相关分析&lpar;Kernel Canonical Correlation Analysis&comma; KCCA&rpar;&period;

    Kernel典型相关分析 (一)KCCA 同样,我们可以引入Kernel函数,通过非线性的坐标变换达到之前CCA所寻求的目标.首先,假设映射$\Phi_X: x\rightarrow \Phi_X(x ...

随机推荐

  1. PSP&lpar;11&period;16~11&period;23&rpar;

    18号 类别c 内容c 开始时间s 结束e 中断I 净时间T 看书 构建之法 9:00 10:00 0 60m 看书 查资料 10:00 11:15 5 70m 个人 写博客 13:30 14:55 ...

  2. &dollar;&lpar;function&lpar;&rpar;&lbrace;&rcub;&rpar;和&dollar;&lpar;document&rpar;&period;ready&lpar;function&lpar;&rpar;&lbrace;&rcub;&rpar; 的用法

    当文档载入完毕就执行,以下几种效果是等价的:1. $(function(){ //这个就是jQuery ready()的简写,即下2的简写 // do something }); 2. $(docum ...

  3. iOS开发--&lowbar;weak typeof&lpar;self&rpar; weakSelf &equals; self

    _weak typeof(self) weakSelf = self;  (一)内存管理原则  1.默认strong,可选weak.strong下不管成员变量还是property,每次使用指针指向一个 ...

  4. Intellij idea生成Hibernate实体类

    反向生成基于注解的Hibernate实体类 1. 为项目添加Hibernate支持 2. 在IDE右边找到database,然后按照步骤添加数据. 3. 保存后.在主面板左侧有persistence, ...

  5. SpaceSyntax【空间句法】之DepthMapX学习:唠叨(目录)

    最近花大力气学习了空间句法这一理论,以及其相关软件DepthMapX. 我觉得吧,你要是能搜索到这理论,这一软件名,这篇博客,那我甚至都不用介绍这软件是干什么用的——好吧,还是会说一下的. 虽然不知道 ...

  6. list内含有元组或字典

    a=[(")] for k,v,i in a: print(k,v,i) 结果: 1 21 12 2 31 32 list里含元组,可以用这种遍历输出挨个元素 但list里含字典时,这样就只 ...

  7. Java中线程池的实现原理-求职必备

    jdk1.5引入Executor线程池框架,通过它把任务的提交和执行进行解耦,只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行.被哪个线程执行,以及什么时候执行. 初始化线程池(4种) ...

  8. 为python安装matplotlib模块

    matplotlib是python中强大的画图模块. 首先确保已经安装python,然后用pip来安装matplotlib模块. 进入到cmd窗口下,执行python -m pip install - ...

  9. 笔记--Wcf全面解析(上)---(1)

    using System; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using ...

  10. 使用HTTPS与SSL来保证安全性

    原文链接:https://developer.android.com/training/articles/security-ssl.html SSL,安全套接层(TSL),是一个常见的用来加密客户端和 ...