Linux中seq_file的应用
2016-06-28 14:09
471 查看
seq_file和seq_operations结构体定义在include/linux/seq_file.h:
seq_printf和seq_vprintf均定义在fs/seq_file.c文件中:
int seq_vprintf(struct seq_file *m, const char *f, va_list args)
{
int len;
if (m->count < m->size) {
len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
if (m->count + len < m->size) {
m->count += len;
return 0;
}
}
seq_set_overflow(m);
return -1;
}
EXPORT_SYMBOL(seq_vprintf);
int seq_printf(struct seq_file *m, const char *f, ...)
{
int ret;
va_list args;
va_start(args, f);
ret = seq_vprintf(m, f, args);
va_end(args);
return ret;
}
EXPORT_SYMBOL(seq_printf);debugfs_dump_info_open函数调用single_open来初始化seq_operations中的start,stop,next,show函数指针。
*data = m->private;获得驱动的数据结构地址。
struct seq_file { char *buf; size_t size; size_t from; size_t count; size_t pad_until; loff_t index; loff_t read_pos; u64 version; struct mutex lock; const struct seq_operations *op; int poll_event; #ifdef CONFIG_USER_NS struct user_namespace *user_ns; #endif void *private; }; struct seq_operations { void * (*start) (struct seq_file *m, loff_t *pos); void (*stop) (struct seq_file *m, void *v); void * (*next) (struct seq_file *m, void *v, loff_t *pos); int (*show) (struct seq_file *m, void *v); };要使用seq_file接口,首先需要定义一个file_operations结构体,以实现open方法:
static const struct file_operations debug_dump_info_fops = { .owner = THIS_MODULE, .open = debugfs_dump_info_open, .read = seq_read, .release = single_release, };debugfs_dump_info_open定义:
static int debugfs_dump_info_open(struct inode *inode, struct file *file) { return single_open(file, msg21xx_debug_dump_info, inode->i_private); }inode->i_private中保存了驱动的私有数据结构地址,msg21xx_debug_dump_info函数就是seq_file的show方法,内核在设计上,seq_file的代码不会在start和stop调用之间执行其他的非原子操作,内核在调用start之后,马上就会调用stop,所以在start方法中获取信号量或者自旋锁是安全的,在调用start和stop之间,内核会调用show方法即msg21xx_debug_dump_info将实际的数据输出到用户空间,msg21xx_debug_dump_info调用seq_printf函数将data->ts_info指向的数据输出到m所指向的buf中,seq_printf会调用seq_vprintf,seq_vprintf调用vsnprintf将数据输出到buf中。
static int msg21xx_debug_dump_info(struct seq_file *m, void *v) { struct msg21xx_ts_data *data = m->private; seq_printf(m, "%s\n", data->ts_info); return 0; }
seq_printf和seq_vprintf均定义在fs/seq_file.c文件中:
int seq_vprintf(struct seq_file *m, const char *f, va_list args)
{
int len;
if (m->count < m->size) {
len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
if (m->count + len < m->size) {
m->count += len;
return 0;
}
}
seq_set_overflow(m);
return -1;
}
EXPORT_SYMBOL(seq_vprintf);
int seq_printf(struct seq_file *m, const char *f, ...)
{
int ret;
va_list args;
va_start(args, f);
ret = seq_vprintf(m, f, args);
va_end(args);
return ret;
}
EXPORT_SYMBOL(seq_printf);debugfs_dump_info_open函数调用single_open来初始化seq_operations中的start,stop,next,show函数指针。
int single_open(struct file *file, int (*show)(struct seq_file *, void *), void *data) { struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL); int res = -ENOMEM; if (op) { op->start = single_start; op->next = single_next; op->stop = single_stop; op->show = show; res = seq_open(file, op); if (!res) ((struct seq_file *)file->private_data)->private = data; else kfree(op); } return res; }seq_open中分配seq_file结构体,通过file->private_data = p;将file的private_data指针指向分配的seq_file结构,再通过single_open函数中的((struct seq_file *)file->private_data)->private = data;将驱动的私有数据结构的地址赋值给seq_file结构的private指针,这样一来,在msg21xx_debug_dump_info函数中,就可以通过struct msg21xx_ts_data
*data = m->private;获得驱动的数据结构地址。
/** * seq_open - initialize sequential file * @file: file we initialize * @op: method table describing the sequence * * seq_open() sets @file, associating it with a sequence described * by @op. @op->start() sets the iterator up and returns the first * element of sequence. @op->stop() shuts it down. @op->next() * returns the next element of sequence. @op->show() prints element * into the buffer. In case of error ->start() and ->next() return * ERR_PTR(error). In the end of sequence they return %NULL. ->show() * returns 0 in case of success and negative number in case of error. * Returning SEQ_SKIP means "discard this element and move on". */ int seq_open(struct file *file, const struct seq_operations *op) { struct seq_file *p = file->private_data; if (!p) { p = kmalloc(sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM; file->private_data = p; } memset(p, 0, sizeof(*p)); mutex_init(&p->lock); p->op = op; #ifdef CONFIG_USER_NS p->user_ns = file->f_cred->user_ns; #endif /* * Wrappers around seq_open(e.g. swaps_open) need to be * aware of this. If they set f_version themselves, they * should call seq_open first and then set f_version. */ file->f_version = 0; /* * seq_files support lseek() and pread(). They do not implement * write() at all, but we clear FMODE_PWRITE here for historical * reasons. * * If a client of seq_files a) implements file.write() and b) wishes to * support pwrite() then that client will need to implement its own * file.open() which calls seq_open() and then sets FMODE_PWRITE. */ file->f_mode &= ~FMODE_PWRITE; return 0; }最后只需调用debugfs_create_file完成所有的工作,并将驱动的私有数据结构指针传递到struct inode结构的inode->i_private。
temp = debugfs_create_file("dump_info", S_IRUSR | S_IWUSR, data->dir, data, &debug_dump_info_fops); if (temp == NULL || IS_ERR(temp)) { pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp)); err = PTR_ERR(temp); goto free_debug_dir; }
相关文章推荐
- centos7安装最新版git及免密码登录配置
- linux 常用命令
- linux mysql rpm 安装
- 视频驱动程序
- Linux安装nslookup
- Windows向Linux(ubuntu)传输文件
- 基于S3C2410平台移植Linux 2.6内核指南
- 初学CentOS——'服务'的启动管理与chkconfig用法
- vmware里centos不能上网 的问题
- 使用Linux raw socket时需要注意的一些问题
- linux局域网中,通过主机名进行通信
- Linux 错误收集
- 使用live555 在linux下搭建 rtsp server
- 一天一条Linux指令-ls
- linux与windows共享
- 自由主义教皇 Linus Torvalds 语录(待排版)
- Linux下DNS服务器搭建详解
- Linux /bin, /sbin, /usr/bin, /usr/sbin 区别
- GDB arm-linux交叉编译移植和使用方法(特别是对于正在运行的程序或者段错误的程序进行分析)
- Linux设备模型(热插拔、mdev 与 firmware)