llseek主要用来操作文件的指针.其实质是内核依赖filp->f_ops执行文件的定位.
1.原型:
llseek(struct file *filp, loff_t off, int whence);
各参数意义如下:
filp:用户空间打开的设备文件描述符;
off:偏移量;
whence:基址.一共有三个标识:SEEK_SET、SEEK_CUR和SEEK_END.这三个标识一般和off配合使用.如下:
SEEK_SET:off即为新的读写位置;
SEEK_CUR:当前读写位置后增加off个偏移量;
SEEK_END:将读写位置指向文件尾后再增加off个偏移量.
如下:
static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
{
loff_t newpos;
switch(whence) {
case 0: /* SEEK_SET */
newpos = offset;
break;
case 1: /* SEEK_CUR */
newpos = filp->f_pos + offset;
break;
case 2: /* SEEK_END */
newpos = MEMDEV_SIZE -1 + offset;
break;
default: /* can't happen */
return -EINVAL;
}
if ((newpos<0) || (newpos>MEMDEV_SIZE))
return -EINVAL;
filp->f_pos = newpos;
return newpos;
}
2.llseek对write/read的影响:
当实现了llseek系统调用,在进行读写时,必须对文件位置指针进行"校准".如:
read:
static ssize_t mem_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 mem_dev *dev = filp->private_data;
if (p >= MEMDEV_SIZE)
return 0;
if (count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p;
if (copy_to_user(buf, (void*)(dev->data + p), count))
{
ret = - EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
}
return ret;
}
write:
static ssize_t mem_write(struct file *filp, c