1

我试图弄清楚驱动程序中的文件操作是如何工作的。我知道有几个文件操作,但是这些操作的函数是用几个参数调用的,而操作本身是没有任何定义的。

所以如果我有这个 -

static const struct file_operations proc_myled_operations = { 
     .open = proc_myled_open, 
     .read = seq_read, 
     .write = proc_myled_write, 
     .llseek = seq_lseek, 
     .release = single_release 
 };

现在我知道内核级驱动程序只能作为来自用户应用程序的文件进行访问。这是一个嵌入式系统,所以我有一些 LED,我可以通过写入它们的内存映射寄存器来打开它们。

因此,当我打开一个 LED 时,将执行 .write 或“proc_myled_write”调用,我可以通过使用 fopen 打开此文件然后使用 fputs 写入它来执行此操作。但是如果 .write 被映射为“proc_myled_write 并且这个函数有这样的参数 -

static ssize_t proc_myled_write(struct file *file, const char __user * buf, 
size_t count, loff_t * ppos)

争论会发生什么?没有对带有这些参数的上述函数的函数调用。我已经在几个驱动程序中看到了这一点。我只使用了这个,因为它是一个简单的例子。文件操作如何映射到这些函数?例如,用户空间中的“写入”如何跟踪驱动程序中的写入?

谢谢你。

4

2 回答 2

5

当您说“没有带有这些参数的上述函数的函数调用”时,我不确定您的意思。

这些函数的原型在其自身的声明中struct file_operations定义。

这是结构声明的前几行:

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ...

虽然声明中未命名参数,但您可以清楚地看到该write()函数声明了 4 个参数,这些参数与您在问题中提到的类型相匹配。

当您将函数分配给相应的字段 ( proc_myled_operations.write = proc_myled_write) 时,您只需将指针传递给模块中声明和定义的写入函数。指向函数本身的指针不需要参数。


好的,所以您的问题实际上是:“用户空间系统调用最终如何调用模块中的 write 函数?” 好问题!我建议编辑您的问题,以使未来的读者更清楚。

好吧,让我们看看我是否可以按照纸上的线索。我发现这个文档给了我查看write()系统调用代码的起始位置。它非常非常古老,但是,内核中并非所有内容都发生了变化!我们从fs/read_write.cwrite()中的系统调用声明开始我们的旅程:

SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
            size_t, count)

它使用文件描述符fdstruct file您注册字符驱动程序时创建。然后它获取文件中的当前位置并调用vfs_write().

ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)

在这个函数中,请参见以下行

ret = file->f_op->write(file, buf, count, pos);

就在那里!

为了消除对 的 类型的任何疑问file->f_op,我们看一下的定义struct file并查看以下f_op字段的定义:

    const struct file_operations    *f_op;

所以一定是struct file_operations你注册司机时传入的。呸!

如果您好奇的话,希望所有这些链接都能向您展示如何跟踪其他系统调用。

于 2013-07-15T22:10:06.793 回答
1

@Maverick,在内核中编写原型或签名是ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)。从用户空间应用程序中,您将发出open , write系统调用来打开/关闭 LED。在用户空间中写入系统调用签名是int write(int fd, const char *buf, size_t count)。所以当你从用户空间调用 write 时,传递的 fd(文件描述符)到达虚拟文件系统(vfs) ,维护打开文件描述符表(OFDT)的链表,因此根据fd,OFDT 有一个指针filp(文件指针)指向打开的文件例如:设备节点“/dev/xxx”或任何其他文件。其余的buf 和 count是从用户空间传递到内核空间的相同参数。最后loff_t *fpos进入图片,如果你想寻找文件ex:在打开的文件上使用 lseek 或 fseek,如果寻找那么文件指针(loff_t fpos)位置会相应地改变。希望我清除了您的疑问:-)

于 2013-07-16T02:41:08.523 回答