【问题标题】:File operation in drivers and struct declaration驱动程序中的文件操作和结构声明
【发布时间】:2020-12-06 10:28:18
【问题描述】:

我试图弄清楚基本内核驱动程序背后的代码是如何工作的。

我有以下结构:

    static struct file_operations fops =
{
   .open = dev_open,
   .read = dev_read,
   .write = dev_write,
   .release = dev_release,
};

而我的 dev_open 函数定义为:

static int     dev_open(struct inode *, struct file *);

现在我也熟悉了,打开设备文件的原型是在 linux/fs.h 中定义的:

http://lxr.linux.no/linux+v3.10/include/linux/fs.h#L1517

这是该链接中的特定行:

int (*open) (struct inode *, struct file *);

现在我的问题是.open = dev_open,int (*open) (struct inode *, struct file *); 之间的关系是什么 这是在 linux/fs.h 中定义的?是否将dev_open的地址传递给linux/fs.h中定义的函数指针int (*open)?一定有某种关系,或者将 struct fops 定义为“文件操作”类型有什么意义?

在这里提出并回答了一个类似的问题,但我觉得我的问题被遗漏了: File operations in drivers

谢谢

【问题讨论】:

  • int (*open) (struct inode *, struct file *); 行为struct file_operations 定义了一个字段。字段名称为open,字段类型为指向函数的指针,对应接受2个参数(类型为struct inode*struct file*)并返回int。跨度>
  • 知道成员初始化器.open = dev_open 的含义与.open = &dev_open 完全相同可能会有所帮助。 C 对函数上的一元 *& 运算符有奇怪的规则。在这两种情况下,fops.open 都被初始化为指向 dev_open 函数。
  • struct file_operations 中,open 成员需要显式声明为函数指针int (*open)(struct inode *, struct file *);。结构或联合类型的成员可以具有“指向函数的指针”类型,但不能具有“函数”类型,因此不能将open 成员声明为int open(struct inode *. struct file *);

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


【解决方案1】:

我认为这个问题更多是关于 C 而不是 Linux 内核。

结构或联合类型的成员不能具有函数类型,但它们可以具有指向函数的指针类型。例如,在 Linux 内核中,struct file_operations 的成员 open 需要使用 函数指针 类型声明:int (*open)(struct inode *, struct file *);。将成员声明为int open(struct inode *, struct file *); 是错误的。

在Linux内核代码中的这个变量定义中:

static struct file_operations fops =
{
   .open = dev_open,
   .read = dev_read,
   .write = dev_write,
   .release = dev_release,
};

顺便说一句,上面的 owner 成员通常应该像这样初始化:

   .owner = THIS_MODULE,

表达式dev_opendev_readdev_writedev_release函数指示符,它们被用作赋值表达式来初始化fops 的成员.函数指示符是具有 function 类型的表达式。除非它是sizeof_Alignof 或一元& 运算符的操作数,否则函数指示符将转换为指向函数的指针 类型。因此,上述变量foo的定义完全等价于:

static struct file_operations fops =
{
   .open = &dev_open,
   .read = &dev_read,
   .write = &dev_write,
   .release = &dev_release,
};

(别忘了也初始化.owner = THIS_MODULE,。)

在那里,函数指示符一元&运算符的操作数,因此不会隐式转换为指向函数的指针类型,但&运算符是将它们显式地转换为 指向函数的指针 类型。

经过fops的上述初始化,rc = fops.open(inode, file);间接调用dev_open(inode, file)并将返回值赋给rc。有时您可能会看到这是用旧样式编写的:rc = (*fops.open)(inode, file);。他们都做同样的事情。函数调用运算符() 的操作数实际上始终是一个指向函数的指针。对于rc = (*fops.open)(inode, file);fops.open 有一个指向函数的指针 类型。 (*fops.open)fops.open 取消引用到 function 类型,但由于 (*fops.open)函数指示符,它被隐式转换回 函数指针 在函数调用之前键入。类似地,在直接调用rc = dev_open(inode, file); 中,dev_open 是一个函数指示符,因此具有 function 类型,但在函数调用。

【讨论】:

  • 我相信我的困惑在于等式的左侧。 .open = dev_open.(*open)(struct inode *, struct file *)=dev_open 的缩写,是真的吗?
  • @programmer25 不,.(*open)(struct inode *, struct file *)=dev_open 是无效的语法。 open 成员已经有一个类型。它只需要使用兼容类型的值进行初始化(或分配)。 open 成员的类型为int (*)(struct inode *, struct file *)(一个指向函数的指针 类型)。 dev_open 的类型为 int (struct inode *, struct file *)(一个 function 类型),但被转换为 int (*)(struct inode *, struct file *)(一个与 open 成员匹配的 函数指针 类型),所以是与open 成员兼容。
猜你喜欢
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-10
  • 2020-01-05
  • 1970-01-01
  • 2020-11-09
相关资源
最近更新 更多