使用ssize_t(* read)函数代替seq_file实现

时间:2016-01-14 20:13:50

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

我在proc下创建了一个文件来读取字符串,但是我没有使用seq_file实现,而是可以使用file_operations中的ssize_t(* read)方法读取它。这种方法有误吗?

有谁能解释一下我在使用seq_file实现的哪些情况下更好?

    ssize_t my_proc_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
    {
      printk(KERN_INFO "loff_t *offset = %lld\n", *offset);
      printk(KERN_INFO "count = %lu\n", count);

      /* comment below two lines and check what happens. If we don't return
         0 it means there is still some data and read is called repeatedly. */
      if((int)*offset >= ARRAY_LEN)
        return 0;
      *offset += ARRAY_LEN;

  return sprintf(buffer, "%s\n", param);
}

同样在输出中我总是算数是131072,为什么会这样?

[ 7317.855146] loff_t *offset = 131073
[ 7317.855149] count = 131072

1 个答案:

答案 0 :(得分:1)

seq_file对于文件很有用,内容不会存储在某个地方,但是当用户需要时,动态生成。它可以使用单个格式字符串生成(如问题帖子中的%s\n),也可以组合不同或相同类型的块。

使用seq_file功能时,代码编写器不会为要读入的缓冲区大小,当前文件的偏移量以及使用__user访问copy_to_user()数据而烦恼。相反,他专注于生成文件的内容,就好像它是一些无限大小的流。其他所有内容都由seq_file机制自动处理。

例如,给出的例子可以使用seq_file实现,如下所示:

int param_show(struct seq_file *m, void *v)
{
    (void)v; /* Unused */
    seq_printf(m, "%s\n", param); /* Just generate content of the "file" */
    return 0;
}

int my_proc_open(struct inode *inode, struct file *filp)
{
    return single_open(filp, &param_show, NULL);
}

const struct file_operations my_proc_ops = {
    .owner = THIS_MODULE,
    .open = &my_proc_open,
    .read = &seq_read
};

为了进行比较,直接实现了相同的读取功能:

ssize_t my_proc_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
{
    ssize_t ret;
    size_t param_len = strlen(param);

    /* Write to buffer everything except terminating '\n' */
    ret = simple_read_from_buffer(buffer, count, offset, param, param_len);
    /* But processing of additional '\n' is much more complex */
    if (ret >= 0 && ret < (ssize_t)count && *offset == param_len) {
        char ch = '\n';
        int err = put_user(buffer + ret, &ch); /* Try to append '\n' */

        if (!err) {
            /* Success */
            ++ret;
            ++(*offset);
        } else if (!ret) {
            /* Fail and nothing has been read before */
            ret = err;
        }
    }

    return ret;
}

const struct file_operations my_proc_ops = {
    .owner = THIS_MODULE,
    .read = &my_proc_read
};

正如我们所看到的,虽然阅读params的预备内容是单行(使用帮助simple_read_from_buffer),但应该生成的其他\n ,使实施更加困难。

seq_file的缺点在于其性能:.show函数中生成的内容未缓存,因此每个后续的read()系统调用都需要再次调用.show。此外,为了生成文件的内容,使用内部缓冲区,并且应该在堆中分配此缓冲区。

但在大多数情况下,动态生成的文件很少和/或很少读取和/或性能不高。所以seq_file适用于几乎所有情况下的此类文件。