The difficult part of the chapter is over, and I’ll quickly detail the lseek method, which is useful and easy to implement. Note that the prototype of the method changed slightly in 2.1.0, as detailed in Section 17.2.1, in Chapter 17.
I’ve already stated that if the lseek method is missing from
the device’s operations, the default implementation in the kernel
acknowledges seeks from the beginning of file and from the current
position, by modifying filp->f_pos
.
If seeking relative to the end-of-file makes sense for your device, you should offer your own method, which will look like the following code:
int scull_lseek (struct inode *inode, struct file *filp, off_t off, int whence) { Scull_Dev *dev = filp->private_data; long 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. For the lseek system call to work
correctly, however, the read and write calls must
cooperate by updating filp->f_pos
whenever data is
transferred; they should also use the f_pos
field to
locate the data they transfer. The implementation of
scull includes these features, as shown in
Section 3.7 in Chapter 3.
While the implementation shown above 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 doesn’t make sense. If this is the case, you can’t just refrain from declaring the lseek operation, because the default method allows seeking. Instead, you should use the following code:
int scull_p_lseek (struct inode *inode, struct file *filp, off_t off, int whence) { return -ESPIPE; /* unseekable */ }
The function just shown comes from the scullpipe device,
which isn’t seekable; the error code is translated to ``Illegal
seek,'' though the symbolic name means ``is a pipe.'' Since the
position-indicator filp->f_pos
is meaningless for
non-seekable devices, neither read nor write needs to
update it during data transfer.
18.191.84.32