【问题标题】:Writable seq_file in Linux KernelLinux内核中的可写seq_file
【发布时间】:2020-01-01 16:58:48
【问题描述】:

我正在对seq_files 进行一些实验,但对此有些困惑。

我从seq_file.c分析了常用函数的实现,通过seq_printf实现判断struct seq_file的内部char *buf完全用于存储格式化字符串以复制到seq_read中的用户。但是seq_file.c中定义了seq_write函数,可以写入缓冲区。

问题: 是否可以重用struct seq_file 的内部缓冲区并将其用于写入来自用户的数据或仅用于数据格式化?

我目前使用另一个缓冲区来写入数据,struct seq_file 仅用于数据格式化:

static char buf[4096];    
static char *limit = buf;

void *pfsw_seq_start(struct seq_file *m, loff_t *pos){
    if(*pos >= limit - buf) {
        return NULL;
    }
    char *data = buf + *pos;
    *pos = limit - buf;
    return data;
}

void pfsw_seq_stop(struct seq_file *m, void *v){ }

void *pfsw_seq_next(struct seq_file *m, void *v, loff_t *pos){ return NULL; }

int pfsw_seq_show(struct seq_file *m, void *v){
    seq_printf(m, "Data: %s\n", (char *) v);
    return 0;
}

ssize_t pfsw_seq_write(struct file *filp, const char __user * user_data, size_t sz, loff_t *off){
    if(*off < 0 || *off > sizeof buf){
        return -EINVAL;
    }
    size_t space_left_from_off = sizeof buf - (size_t) *off;
    size_t bytes_to_write = space_left_from_off <= sz ? space_left_from_off : sz;
    if(copy_from_user(buf + *off, user_data, bytes_to_write)){
        return -EAGAIN;
    }
    *off += bytes_to_write;
    if(*off > limit - buf){
        limit = buf + *off;
    }
    return bytes_to_write;
}

所以我将struct file_operations定义为

static const struct seq_operations seq_ops = {
    .start = pfsw_seq_start,
    .stop  = pfsw_seq_stop,
    .next  = pfsw_seq_next,
    .show  = pfsw_seq_show
};

int pfsw_seq_open(struct inode *ino, struct file *filp){ 
    return seq_open(filp, &seq_ops);
}

static const struct file_operations fops = {
    .open = pfsw_seq_open,
    .read = seq_read,
    .write = pfsw_seq_write,
    .release = seq_release,
};

【问题讨论】:

  • 如果你需要一个临时缓冲区,我想你可以,但你为什么不能直接复制到数据需要去的地方?
  • @stark 例如,如果某个大对象是由用单独的writes 编写的小块组装而成的。然后它会去其他地方。
  • @0andriy 我真正感到困惑的是,使用procfs 进行这样的写作是否很常见。为较新内核开发的模块是否应该切换到sysfs
  • 对不起,我没有很好地阅读这个问题。为什么首先需要使用 seq_file?
  • @0andriy 嗯...那么有什么替代方案?

标签: c linux linux-kernel linux-device-driver


【解决方案1】:

您要找的助手是simple_write_to_buffer

给定一个指向缓冲区的指针及其可用大小,帮助程序处理传递给.write 函数的所有参数:

ssize_t pfsw_write(struct file *filp, const char __user * user_data, size_t sz, loff_t *off)
{
    // This performs the most work.
    ssize_t res = simple_write_to_buffer(buf, sizeof(buf), off, user_data, sz);

    // Optionally, you may update the buffer's actual size.
    // NOTE: In the simple form this doesn't work with **concurrent** writing.

    if ((res > 0) && *off > buf_size) {
      buf_size = *off;
    }

    return res;
}

simple_write_to_buffer 助手的“对”是simple_read_from_buffer。该助手可用于实现.read 方法:

ssize_t pfsw_read(struct file filp*, char __user * user_data, size_t sz, loff_t *off)
{
    // Here the helper does the whole work.
    //
    // 'buf_size' could be 'sizeof(buf)' in case of the buffer of the fixed size.
    // Alternatively, you need to take care about concurrency;
    // see the comments in the 'pfsw_write' function.
    return simple_read_from_buffer(buf, buf_size, off, user_data, sz);
}

子系统seq_file用于实现读取文件(.read功能)。

虽然seq_read.read 函数的实际实现,但seq_write 只是.show.show 函数的助手@。

查看my answer 获取有关seq_file 和写入文件的相关问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 2012-09-27
    • 1970-01-01
    相关资源
    最近更新 更多