在学习linux 字符驱动的时候会有这样的困惑
比如我们实现一个字符驱动的读函数,如下
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) {
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data;
...
if (copy_to_user(buf, dev->mem +p, count)) {
ret = -EFAULT;
} else {
*ppos += count;
ret = count;
printk(KERN_INFO "read %u byte(s) from %lu\n", count, p);
}
return ret;
}
为什么在成功拷贝到用户态数据之后,需要更新*ppos这个指针的数据,而不是filp->f_pos的数据
从语意上来讲应该是一致的,都是表示用户读位置的指针,为什么要费劲多传一个ppos过来,还需要内核代码对这个值去修改呢,我们自己直接修改filp中的数据不好吗?
这么做的原因是“时机”
系统要求我们更新*ppos,给系统一个机会去选择。
系统可以直接选择将ppos指向 &filp->f_pos, 也可以选择指向一个临时区域,后者拥有更大的灵活性。
比如由于某种情况不能正确返回到用户态,或者不能立即返回,这时内核临时保存这个读文件之后的偏移,filp存储的信息还是用户读之前的样子,这是符合语意的,因为用户这时确实还未读到数据,我们不能提前更新filp。
内核会在一个合适的时机将*ppos中的数据写回给filp->f_pos。
详细的讨论请参考下面的stackoverflow的链接