無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

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          :2
readは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;
}

追記

ユーザ空間のアドレスを参照する場合、copy_from_user()でカーネル空間にコピーして参照しますが、システムコール実データ引数はカーネル空間のスタックにpushされるため、そのアドレスはプロセス空間のカーネルアドレスとなります。

最終更新 2016/11/27 14:05:24 - north
(2015/01/19 22:13:37 作成)