preadシステムコール
サンプル
#include <stdio.h> #include <fcntl.h> void disp(char* read, char *buf, int len) { buf[len] = 0; printf("%-15s:%s\n", read, buf); } void main(void) { int fd; char buf[6]; fd = open("babakaka", O_RDONLY); read(fd, buf, 1); disp("read1", buf, 1); pread(fd, buf, 1, 5); disp("pread pos 5", buf, 1); read(fd, buf, 1); disp("read2 ", buf, 1); pread(fd, buf, 1, 3); disp("pread pos 3", buf, 1); read(fd, buf, 1); disp("read3 ", buf, 1); }
[root@localhost north]# echo 0123456789 > babakaka [root@localhost north]# ./pread.out read1 :0 pread pos 5 :5 read2 :1 pread pos 3 :3 read3 :2readはvfs_read()でfile->f_posを位置として読み出し、読み出した位置のposをfile->f_pos=posとします。
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret; } static inline loff_t file_pos_read(struct file *file) { return file->f_pos; } static inline void file_pos_write(struct file *file, loff_t pos) { file->f_pos = pos; }preadは引数のposアドレスでvfs_read()をコールされ、file->f_posの参照/更新はありません。
SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf, size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PREAD) ret = vfs_read(file, buf, count, &pos); fput_light(file, fput_needed); } return ret; } ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read)) return -EINVAL; if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) return -EFAULT; ret = rw_verify_area(READ, file, pos, count); if (ret >= 0) { count = ret; if (file->f_op->read) ret = file->f_op->read(file, buf, count, pos); else ret = do_sync_read(file, buf, count, pos); if (ret > 0) { fsnotify_access(file); add_rchar(current, ret); } inc_syscr(current); } return ret; } ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { struct iovec iov = { .iov_base = buf, .iov_len = len }; struct kiocb kiocb; ssize_t ret; init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; kiocb.ki_left = len; kiocb.ki_nbytes = len; for (;;) { ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos); if (ret != -EIOCBRETRY) break; wait_on_retry_sync_kiocb(&kiocb); } if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); *ppos = kiocb.ki_pos; return ret; }