preadシステムコール
Rev.2を表示中。最新版はこちら。
preadシステムコールはファイルの指定位置から読み込み、ファイルの読み込み位置を更新しません。以下のサンプルでreadで読み込むと、01234/56789/NULLとなります。manによると、 他のスレッドによるファイルオフセットの変更の影響を受けることなく、 複数のスレッドが同じファイルディスクリプタに対して入出力を行うことができる。と言うことですが、また、再読込みはキャッシュから読み込まれるため、巨大なファイルデータをわざわざバッファに読み込んで、処理するのでなく、ファイルその物をデータバッファの如く取り扱うといった利用も可能となります。
#include <stdio.h> #include <fcntl.h> void main(void) { int fd, i; char buf[6]; fd = open("hoge", O_RDONLY); for (i = 0; i < 5; i++) { pread(fd, buf, 5, 0); buf[5] = 0; printf("%s\n", buf); } pread(fd, buf, 5, 5); buf[5] = 0; printf("%s\n", buf); }
[root@localhost lkm]# echo 0123456789 > hoge [root@localhost lkm]# ./a.out 01234 01234 01234 01234 01234 56789readは、file_pos_read()を読込み位置に、file_pos_write()で読込んだ位置をfile->f_posとしますが、preadは引数をそのまま読込み位置とし、file->f_posを更新しないだけです。pwriteについても同じです。openしたファイルはFMODE_PREADF/MODE_PWRITEが設定されており、FMODE_PREADF/MODE_PWRITEはカーネル内でリセットされるフラグです。
sql_fileはMODE_PWRITEがリセットされます。objectがリスト管理されていて、飛び越えたobjectを書き込む場合、リストする親が存在してなく、当該のobjectを登録する事ができないからです。
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; } 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 void file_pos_write(struct file *file, loff_t pos) { file->f_pos = pos; }