了解file_operations的loff_t*offp

Dr.*_*all 21 c linux kernel linux-device-driver linux-kernel

我正在设计一个只读取和写入字符缓冲区的设备驱动程序.然而,我的问题是file_operations结构read和结构中的两个功能write.我真的不明白究竟loff_t *offp是什么.我知道对于*offp文件偏移的读取和写入操作都意味着文件的当前读/写位置,但是我甚至不确定写入或读取设备文件意味着什么.

从我收集的内容来看,这就是我写作和从我的设备中读取的方式是我创建了一个代表我所称的设备的结构,my_char_struct如下所示.

struct my_char_structure{
    struct cdev my_cdev;
    struct semaphore sem;
    char *data;
    ssize_t data_size;
    unsigned int access_key;
    unsigned long size;
};
Run Code Online (Sandbox Code Playgroud)

这是一个静态结构,在我的驱动程序是insmod这样的时候初始化并指向它.

static dev_t dev_num;
static struct my_char_structure Dev;

int start_mod(void){
    //Because we are dealing with a fictitious device, I want
    //the driver to create my two devices with arbitrarily 
    //assigned major numbers.
    struct my_char_structure *my_dev = &Dev;
    int err;

    alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME);

    sema_init(&(my_dev->sem),1);

    cdev_init(&(my_dev->my_cdev), &fops);
    my_dev->my_cdev.owner = THIS_MODULE;
    my_dev->my_cdev.ops = &fops;// fops is my file operations struct

    err = cdev_add(&my_dev->my_cdev, dev_num, COUNT);
    if(err<0)
        printk(KERN_ALERT "There was an error %d.",err);
    printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num));

    return 0;   
}

module_init(start_mod);
Run Code Online (Sandbox Code Playgroud)

当我的设备打开时,我只是指向文件打开以指向我在此期间设置的静态结构module_init(start_mod)......

int dev_open(struct inode *in_node, struct file *filp){
    static struct my_char_structure *my_dev;
    my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev);
    printk(KERN_ALERT "The device number is %d",iminor(in_node));
    if(!my_dev)
        printk(KERN_ALERT "something didn't work. my_dev not initialized.");
    filp->private_data = my_dev;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的读写方法所做的是修改我用开放文件指出的初始结构Dev.无论copy_to_user我的结构是什么,用户认为已经写入设备的内容以及copy_from_user用户认为他们正在编写的内容.但是除了改变我的初始结构Dev之外,文件位置或偏移的想法没有意义,除非它指向内核中针对某些任意结构或类型的缓冲内存的指针.这是我对文件偏移的唯一解释......这是正确的吗?这就是loff_t *offp这里所说的吗?

write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
Run Code Online (Sandbox Code Playgroud)

(鉴于我的理解是正确的)当调用某些file_operation(例如读/写)并且我没有*offp亲自设置时,loff_t*offp最初设置为什么?

如果在最后一个file_operation中,offp = some_arbitrary_address(因为我告诉过它),那么当再次调用此操作时,offp将被设置为什么?

如果我正在运行其他file_opens操作会发生什么,它会设置为最后一个file_operation将其保留为什么,还是会保留一个使用了file_open操作的选项卡,并将*offp替换为file_open所拥有的操作?

当设备本身甚至不存储文件应该存储的信息时,char设备的概念对我来说太抽象了,而是它保存信息的驱动程序.我希望我已经解释了我的模糊性,并且我将清除任何我看似模棱两可的东西.

tor*_*rek 20

"参数loff_t"是统一的疯狂多样性"长偏移量",即寻求位置off_t,off64_t等,使驾驶者可以只使用参数loff_t,而不是担心.

当你进入驱动程序时,指针本身指向用户提供的偏移量(假设它的用户代码执行驱动程序访问 - 技术上内核可以提供它自己的,但是用户案例是要考虑的)通过lseekllseeklseek64等,然后由通常的读出和写入操作.考虑常规磁盘文件的情况:当您第一次访问open该文件时,您(作为用户)获取内核以提供跟踪文件中当前位置的数据结构,以便在您readwrite某些字节时,接下来readwrite从你离开的地方开始接送.

此外,如果您dup是文件描述符,或者通过(例如)执行等效操作fork并且exec在运行一系列命令方面,那么搜索位置将由所有继承进程共享.因此,在shell提示符下,命令:

(prog1; prog2; prog3) > outputfile
Run Code Online (Sandbox Code Playgroud)

创建一个输出文件,然后dup将描述符prog2写入三个程序,以便写入的输出在输出之后立即进入文件prog1,并且输出来自prog3其他两个 - 所有因为所有三个独立的进程共享相同的底层内核数据结构内部相同loff_t.

这同样适用于设备驱动程序文件.当您调用读写函数时,您会收到用户提供的"当前偏移量",您可以(并且应该)根据需要更新它...假设有任何需要(例如,您希望为用户提供常规文件的外观,包括读取和写入时搜索偏移量移动的事实.如果设备具有搜索偏移的某些逻辑应用,则可以在此处使用.

当然,设备驱动程序还有很多,这就是为什么有关于这些东西(qv)的完整书籍章节的原因.:-)

  • 是.(大概你的意思是`*offp + = nbytes`.)你正在改变的变量实际上是一个内核空间的东西,但它*代表*用户的搜索偏移量.(或者,在某些情况下,偏移提供给`pread`或`pwrite`调用,甚至是其他东西,但最常见的是用户的'lseek`偏移.)你称之为"奇怪的内核抽象",是什么使`(prog1; prog2)>输出`工作.顺便说一句,在*BSD内核中,有一个名为`uiomove`的函数可以自动更新"用户I/O偏移"; Linux只是走了另一条路. (2认同)