Return Linux 内核序列 'show' 例程的值
Return value of Linux kernel sequence 'show' routine
我正在尝试理解 Linux 内核中的序列文件。恕我直言,它们是一个被误解的野兽,考虑到这一点,我从 web 编译了一个现成的内核模块。我在这里复制(修改后的)代码以便于访问:
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
static int limit = 10; //default value, it can be changed here or
module_param(limit, int, S_IRUGO); //transfered as a module parameter
static int* even_ptr; //we will work with dynamic memory
/**
* start
*/
static void *ct_seq_start(struct seq_file *s, loff_t *pos) {
printk(KERN_INFO "Entering start(), pos = %Ld, seq-file pos = %lu.\n", *pos, s->count);
if ((*pos) >= limit) { // are we done?
printk(KERN_INFO "Apparently, we're done.\n");
return NULL;
}
//Allocate an integer to hold our increasing even value
even_ptr = kmalloc(sizeof(int), GFP_KERNEL);
if (!even_ptr) // fatal kernel allocation error
return NULL;
printk(KERN_INFO "In start(), even_ptr = 0x%pX.\n", even_ptr);
*even_ptr = (*pos)*2;
return even_ptr;
}
/**
* show
*/
static int ct_seq_show(struct seq_file *s, void *v) {
printk(KERN_INFO "In show(), even = %d.\n", *(int*)v);
seq_printf(s, "The current value of the even number is %d\n", *(int*)v);
// return (*(int *)v); // <-- Instead of a customary 'zero' I return the value of 'v' which is the actual even number that we are printing to the kernel log as well as the seq file
return 0;
}
/**
* next
*/
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) {
printk(KERN_INFO "In next(), v = 0x%pX, *(int*)v=%d, pos=%Ld, seq-file pos=%lu.\n", v, *(int*)v, *pos, s->count);
(*pos)++; //increase my position counter
if (*pos >= limit) //are we done?
return NULL;
*(int*)v += 2; //to the next even value
return v;
}
/**
* stop
*/
static void ct_seq_stop(struct seq_file *s, void *v) {
printk(KERN_INFO "Entering stop().\n");
if (v)
printk(KERN_INFO "v is %pX.\n", v);
else
printk(KERN_INFO "v is null.\n");
printk(KERN_INFO "In stop(), even_ptr = %pX.\n", even_ptr);
if (even_ptr) {
printk(KERN_INFO "Freeing and clearing even_ptr.\n");
kfree(even_ptr);
even_ptr = NULL;
} else
printk(KERN_INFO "even_ptr is already null.\n");
}
/**
* This structure gathers functions which control the sequential reading
*/
static struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
.show = ct_seq_show
};
/**
* This function is called when a file from /proc is opened
*/
static int ct_open(struct inode *inode, struct file *file) {
return seq_open(file, &ct_seq_ops);
};
/**
* This structure gathers functions for a /proc-file operations
*/
static struct file_operations ct_file_ops = {
.owner = THIS_MODULE,
.open = ct_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
/**
* This function is called when this module is loaded into the kernel
*/
static int __init ct_init(void) {
proc_create("evens", 0, NULL, &ct_file_ops);
return 0;
}
/**
* This function is called when this module is removed from the kernel
*/
static void __exit ct_exit(void) {
remove_proc_entry("evens", NULL);
}
module_init(ct_init);
module_exit(ct_exit);
MODULE_LICENSE("GPL");
我的内核日志显示:
Jun 30 19:10:22 mintab kernel: [ 8213.539959] Entering start(), pos = 0, seq-file pos = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539960] In start(), even_ptr = 0xffff9241772a8000.
Jun 30 19:10:22 mintab kernel: [ 8213.539960] In show(), even = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539962] In next(), v = 0xffff9241772a8000, *(int*)v=0, pos=0, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539962] In show(), even = 2.
Jun 30 19:10:22 mintab kernel: [ 8213.539963] In next(), v = 0xffff9241772a8000, *(int*)v=2, pos=1, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539963] In show(), even = 4.
Jun 30 19:10:22 mintab kernel: [ 8213.539964] In next(), v = 0xffff9241772a8000, *(int*)v=4, pos=2, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539964] In show(), even = 6.
Jun 30 19:10:22 mintab kernel: [ 8213.539965] In next(), v = 0xffff9241772a8000, *(int*)v=6, pos=3, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539965] In show(), even = 8.
Jun 30 19:10:22 mintab kernel: [ 8213.539966] In next(), v = 0xffff9241772a8000, *(int*)v=8, pos=4, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539966] In show(), even = 10.
Jun 30 19:10:22 mintab kernel: [ 8213.539967] In next(), v = 0xffff9241772a8000, *(int*)v=10, pos=5, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539967] In show(), even = 12.
Jun 30 19:10:22 mintab kernel: [ 8213.539968] In next(), v = 0xffff9241772a8000, *(int*)v=12, pos=6, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539969] In show(), even = 14.
Jun 30 19:10:22 mintab kernel: [ 8213.539969] In next(), v = 0xffff9241772a8000, *(int*)v=14, pos=7, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539970] In show(), even = 16.
Jun 30 19:10:22 mintab kernel: [ 8213.539970] In next(), v = 0xffff9241772a8000, *(int*)v=16, pos=8, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539971] In show(), even = 18.
Jun 30 19:10:22 mintab kernel: [ 8213.539971] In next(), v = 0xffff9241772a8000, *(int*)v=18, pos=9, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539972] Entering stop().
Jun 30 19:10:22 mintab kernel: [ 8213.539972] v is null.
Jun 30 19:10:22 mintab kernel: [ 8213.539972] In stop(), even_ptr = ffff9241772a8000.
Jun 30 19:10:22 mintab kernel: [ 8213.539973] Freeing and clearing even_ptr.
Jun 30 19:10:22 mintab kernel: [ 8213.539996] Entering start(), pos = 10, seq-file pos = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539996] Apparently, we're done.
Jun 30 19:10:22 mintab kernel: [ 8213.539997] Entering stop().
Jun 30 19:10:22 mintab kernel: [ 8213.539997] v is null.
Jun 30 19:10:22 mintab kernel: [ 8213.539997] In stop(), even_ptr = (null).
Jun 30 19:10:22 mintab kernel: [ 8213.539998] even_ptr is already null.
并且proc文件只给出如下输出然后就停止了:
偶数当前值为0
我假设 'show' 例程必须 return 0 才能被认为对底层 seq 文件生态系统没有错误。但是,一个小的正整数不表示相同吗?或者他们以其他方式使用??
UPDATE1:正如我们的朋友 Tsyvarev 的 所提到的,它被明确要求从 show 例程中 return 0,因为其他任何事情都被认为是失败的,因此相应地恢复。话虽如此,谁能解释一下为什么我们在用完所有数字后再次输入开始并且v
最终是NULL
?我特别想知道我们为什么要这样做?
Jul 1 11:16:59 mintab kernel: [31765.915542] v is null.
Jul 1 11:16:59 mintab kernel: [31765.915542] In stop(), even_ptr = ffff9c7df619b340.
Jul 1 11:16:59 mintab kernel: [31765.915542] Freeing and clearing even_ptr.
Jul 1 11:16:59 mintab kernel: [31765.915551] Entering start(), pos = 200, seq-file pos = 0.
Jul 1 11:16:59 mintab kernel: [31765.915551] Apparently, we're done.
Jul 1 11:16:59 mintab kernel: [31765.915552] Entering stop().
Jul 1 11:16:59 mintab kernel: [31765.915552] v is null.
Jul 1 11:16:59 mintab kernel: [31765.915553] In stop(), even_ptr = (null).
此外,欢迎提供更多链接,以更详细和(希望)更简单地解释序列文件机制。
内核文档中描述了顺序文件,位于 Documentation/filesystems/seq_file.txt 下。根据文档,show
函数应该 return:
- 0 成功
- -失败时的 ERR(负错误代码)
- SEQ_SKIP 用于丢弃当前项目的任何输出
当前实施将 show
的任何正 return 值视为 SEQ_SKIP:
// (from traverse() function in fs/seq_file.c)
// ...
error = m->op->show(m, p);
if (error < 0) // <-- negative return value is an error indicator
break;
if (unlikely(error)) { // <-- this is for positive return values
error = 0; // <-- as if 'show' returns 0...
m->count = 0; // <-- ... but with output dropped
}
所以,想要报show
成功,只需return0.
我正在尝试理解 Linux 内核中的序列文件。恕我直言,它们是一个被误解的野兽,考虑到这一点,我从 web 编译了一个现成的内核模块。我在这里复制(修改后的)代码以便于访问:
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
static int limit = 10; //default value, it can be changed here or
module_param(limit, int, S_IRUGO); //transfered as a module parameter
static int* even_ptr; //we will work with dynamic memory
/**
* start
*/
static void *ct_seq_start(struct seq_file *s, loff_t *pos) {
printk(KERN_INFO "Entering start(), pos = %Ld, seq-file pos = %lu.\n", *pos, s->count);
if ((*pos) >= limit) { // are we done?
printk(KERN_INFO "Apparently, we're done.\n");
return NULL;
}
//Allocate an integer to hold our increasing even value
even_ptr = kmalloc(sizeof(int), GFP_KERNEL);
if (!even_ptr) // fatal kernel allocation error
return NULL;
printk(KERN_INFO "In start(), even_ptr = 0x%pX.\n", even_ptr);
*even_ptr = (*pos)*2;
return even_ptr;
}
/**
* show
*/
static int ct_seq_show(struct seq_file *s, void *v) {
printk(KERN_INFO "In show(), even = %d.\n", *(int*)v);
seq_printf(s, "The current value of the even number is %d\n", *(int*)v);
// return (*(int *)v); // <-- Instead of a customary 'zero' I return the value of 'v' which is the actual even number that we are printing to the kernel log as well as the seq file
return 0;
}
/**
* next
*/
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) {
printk(KERN_INFO "In next(), v = 0x%pX, *(int*)v=%d, pos=%Ld, seq-file pos=%lu.\n", v, *(int*)v, *pos, s->count);
(*pos)++; //increase my position counter
if (*pos >= limit) //are we done?
return NULL;
*(int*)v += 2; //to the next even value
return v;
}
/**
* stop
*/
static void ct_seq_stop(struct seq_file *s, void *v) {
printk(KERN_INFO "Entering stop().\n");
if (v)
printk(KERN_INFO "v is %pX.\n", v);
else
printk(KERN_INFO "v is null.\n");
printk(KERN_INFO "In stop(), even_ptr = %pX.\n", even_ptr);
if (even_ptr) {
printk(KERN_INFO "Freeing and clearing even_ptr.\n");
kfree(even_ptr);
even_ptr = NULL;
} else
printk(KERN_INFO "even_ptr is already null.\n");
}
/**
* This structure gathers functions which control the sequential reading
*/
static struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
.show = ct_seq_show
};
/**
* This function is called when a file from /proc is opened
*/
static int ct_open(struct inode *inode, struct file *file) {
return seq_open(file, &ct_seq_ops);
};
/**
* This structure gathers functions for a /proc-file operations
*/
static struct file_operations ct_file_ops = {
.owner = THIS_MODULE,
.open = ct_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
/**
* This function is called when this module is loaded into the kernel
*/
static int __init ct_init(void) {
proc_create("evens", 0, NULL, &ct_file_ops);
return 0;
}
/**
* This function is called when this module is removed from the kernel
*/
static void __exit ct_exit(void) {
remove_proc_entry("evens", NULL);
}
module_init(ct_init);
module_exit(ct_exit);
MODULE_LICENSE("GPL");
我的内核日志显示:
Jun 30 19:10:22 mintab kernel: [ 8213.539959] Entering start(), pos = 0, seq-file pos = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539960] In start(), even_ptr = 0xffff9241772a8000.
Jun 30 19:10:22 mintab kernel: [ 8213.539960] In show(), even = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539962] In next(), v = 0xffff9241772a8000, *(int*)v=0, pos=0, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539962] In show(), even = 2.
Jun 30 19:10:22 mintab kernel: [ 8213.539963] In next(), v = 0xffff9241772a8000, *(int*)v=2, pos=1, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539963] In show(), even = 4.
Jun 30 19:10:22 mintab kernel: [ 8213.539964] In next(), v = 0xffff9241772a8000, *(int*)v=4, pos=2, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539964] In show(), even = 6.
Jun 30 19:10:22 mintab kernel: [ 8213.539965] In next(), v = 0xffff9241772a8000, *(int*)v=6, pos=3, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539965] In show(), even = 8.
Jun 30 19:10:22 mintab kernel: [ 8213.539966] In next(), v = 0xffff9241772a8000, *(int*)v=8, pos=4, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539966] In show(), even = 10.
Jun 30 19:10:22 mintab kernel: [ 8213.539967] In next(), v = 0xffff9241772a8000, *(int*)v=10, pos=5, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539967] In show(), even = 12.
Jun 30 19:10:22 mintab kernel: [ 8213.539968] In next(), v = 0xffff9241772a8000, *(int*)v=12, pos=6, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539969] In show(), even = 14.
Jun 30 19:10:22 mintab kernel: [ 8213.539969] In next(), v = 0xffff9241772a8000, *(int*)v=14, pos=7, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539970] In show(), even = 16.
Jun 30 19:10:22 mintab kernel: [ 8213.539970] In next(), v = 0xffff9241772a8000, *(int*)v=16, pos=8, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539971] In show(), even = 18.
Jun 30 19:10:22 mintab kernel: [ 8213.539971] In next(), v = 0xffff9241772a8000, *(int*)v=18, pos=9, seq-file pos=42.
Jun 30 19:10:22 mintab kernel: [ 8213.539972] Entering stop().
Jun 30 19:10:22 mintab kernel: [ 8213.539972] v is null.
Jun 30 19:10:22 mintab kernel: [ 8213.539972] In stop(), even_ptr = ffff9241772a8000.
Jun 30 19:10:22 mintab kernel: [ 8213.539973] Freeing and clearing even_ptr.
Jun 30 19:10:22 mintab kernel: [ 8213.539996] Entering start(), pos = 10, seq-file pos = 0.
Jun 30 19:10:22 mintab kernel: [ 8213.539996] Apparently, we're done.
Jun 30 19:10:22 mintab kernel: [ 8213.539997] Entering stop().
Jun 30 19:10:22 mintab kernel: [ 8213.539997] v is null.
Jun 30 19:10:22 mintab kernel: [ 8213.539997] In stop(), even_ptr = (null).
Jun 30 19:10:22 mintab kernel: [ 8213.539998] even_ptr is already null.
并且proc文件只给出如下输出然后就停止了: 偶数当前值为0
我假设 'show' 例程必须 return 0 才能被认为对底层 seq 文件生态系统没有错误。但是,一个小的正整数不表示相同吗?或者他们以其他方式使用??
UPDATE1:正如我们的朋友 Tsyvarev 的 v
最终是NULL
?我特别想知道我们为什么要这样做?
Jul 1 11:16:59 mintab kernel: [31765.915542] v is null.
Jul 1 11:16:59 mintab kernel: [31765.915542] In stop(), even_ptr = ffff9c7df619b340.
Jul 1 11:16:59 mintab kernel: [31765.915542] Freeing and clearing even_ptr.
Jul 1 11:16:59 mintab kernel: [31765.915551] Entering start(), pos = 200, seq-file pos = 0.
Jul 1 11:16:59 mintab kernel: [31765.915551] Apparently, we're done.
Jul 1 11:16:59 mintab kernel: [31765.915552] Entering stop().
Jul 1 11:16:59 mintab kernel: [31765.915552] v is null.
Jul 1 11:16:59 mintab kernel: [31765.915553] In stop(), even_ptr = (null).
此外,欢迎提供更多链接,以更详细和(希望)更简单地解释序列文件机制。
内核文档中描述了顺序文件,位于 Documentation/filesystems/seq_file.txt 下。根据文档,show
函数应该 return:
- 0 成功
- -失败时的 ERR(负错误代码)
- SEQ_SKIP 用于丢弃当前项目的任何输出
当前实施将 show
的任何正 return 值视为 SEQ_SKIP:
// (from traverse() function in fs/seq_file.c)
// ...
error = m->op->show(m, p);
if (error < 0) // <-- negative return value is an error indicator
break;
if (unlikely(error)) { // <-- this is for positive return values
error = 0; // <-- as if 'show' returns 0...
m->count = 0; // <-- ... but with output dropped
}
所以,想要报show
成功,只需return0.