Poster of Linux kernelThe best gift for a Linux geek
 Linux kernel map 
⇦ prev ⇱ home next ⇨

6.5. Seeking a Device

One of the last things we need to cover in this chapter is the llseek method, which is useful (for some devices) and easy to implement.

6.5.1. The llseek Implementation

The llseek method implements the lseek and llseek system calls. We have already stated that if the llseek method is missing from the device's operations, the default implementation in the kernel performs seeks by modifying filp->f_pos, the current reading/writing position within the file. Please note that for the lseek system call to work correctly, the read and write methods must cooperate by using and updating the offset item they receive as an argument.

You may need to provide your own llseek method if the seek operation corresponds to a physical operation on the device. A simple example can be seen in the scull driver:

loff_t scull_llseek(struct file *filp, loff_t off, int whence)
{
    struct scull_dev *dev = filp->private_data;
    loff_t newpos;

    switch(whence) {
      case 0: /* SEEK_SET */
        newpos = off;
        break;

      case 1: /* SEEK_CUR */
        newpos = filp->f_pos + off;
        break;

      case 2: /* SEEK_END */
        newpos = dev->size + off;
        break;

      default: /* can't happen */
        return -EINVAL;
    }
    if (newpos < 0) return -EINVAL;
    filp->f_pos = newpos;
    return newpos;
}

The only device-specific operation here is retrieving the file length from the device. In scull the read and write methods cooperate as needed, as shown in Chapter 3.

Although the implementation just shown makes sense for scull, which handles a well-defined data area, most devices offer a data flow rather than a data area (just think about the serial ports or the keyboard), and seeking those devices does not make sense. If this is the case for your device, you can't just refrain from declaring the llseek operation, because the default method allows seeking. Instead, you should inform the kernel that your device does not support llseek by calling nonseekable_open in your open method:

int nonseekable_open(struct inode *inode; struct file *filp);

This call marks the given filp as being nonseekable; the kernel never allows an lseek call on such a file to succeed. By marking the file in this way, you can also be assured that no attempts will be made to seek the file by way of the pread and pwrite system calls.

For completeness, you should also set the llseek method in your file_operations structure to the special helper function no_llseek, which is defined in <linux/fs.h>.

    ⇦ prev ⇱ home next ⇨
    Poster of Linux kernelThe best gift for a Linux geek