需要帮助理解read_write.c

时间:2016-12-11 07:53:26

标签: c linux io linux-kernel ubuntu-16.04

您好我希望有人可以帮我理解 read_write.c 内核文件的读取部分,当我看到它时,我真的不明白。

考虑到有几个调用read函数的实例,我无法确定哪个部分实际上正在读取文件。我问,因为我必须知道在哪里修改它以及如何进行赋值我必须修改读取的输出而不实际修改文件。

顺便说一句,我使用的是kernel.org版本4.9中最新版本的Linux内核,感谢所有的帮助。以下是我认为正在进行阅读的地方。

typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);

const struct file_operations generic_ro_fops = {
.llseek     = generic_file_llseek,
.read_iter  = generic_file_read_iter,
.mmap       = generic_file_readonly_mmap,
.splice_read    = generic_file_splice_read,
};

static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter   *iter,
    loff_t *ppos, iter_fn_t fn, int flags)
{
    struct kiocb kiocb;
    ssize_t ret;

    if (flags & ~(RWF_HIPRI | RWF_DSYNC | RWF_SYNC))
        return -EOPNOTSUPP;

        init_sync_kiocb(&kiocb, filp);
    if (flags & RWF_HIPRI)
        kiocb.ki_flags |= IOCB_HIPRI;
    if (flags & RWF_DSYNC)
        kiocb.ki_flags |= IOCB_DSYNC;
    if (flags & RWF_SYNC)
        kiocb.ki_flags |= (IOCB_DSYNC | IOCB_SYNC);
        kiocb.ki_pos = *ppos;

    ret = fn(&kiocb, iter);
    BUG_ON(ret == -EIOCBQUEUED);
    *ppos = kiocb.ki_pos;
    return ret;
}

ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
              unsigned long nr_segs, unsigned long fast_segs,
              struct iovec *fast_pointer,
              struct iovec **ret_pointer)
{
    unsigned long seg;
    ssize_t ret;
    struct iovec *iov = fast_pointer;

    /*
     * SuS says "The readv() function *may* fail if the iovcnt argument
     * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
     * traditionally returned zero for zero segments, so...
     */
    if (nr_segs == 0) {
        ret = 0;
        goto out;
    }

    /*
     * First get the "struct iovec" from user memory and
     * verify all the pointers
     */
    if (nr_segs > UIO_MAXIOV) {
        ret = -EINVAL;
        goto out;
    }
    if (nr_segs > fast_segs) {
        iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
        printk(KERN_DEBUG "Hello from read_write.c\n");
        printk(KERN_DEBUG "Inside the copy check uvector method\n");
        if (iov == NULL) {
            ret = -ENOMEM;
            goto out;
    }
    }
    if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
        ret = -EFAULT;
        goto out;
    }

    /*
     * According to the Single Unix Specification we should return EINVAL
     * if an element length is < 0 when cast to ssize_t or if the
     * total length would overflow the ssize_t return value of the
     * system call.
     *
     * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the
     * overflow case.
     */
     ret = 0;
     for (seg = 0; seg < nr_segs; seg++) {
        void __user *buf = iov[seg].iov_base;
        ssize_t len = (ssize_t)iov[seg].iov_len;

        /* see if we we're about to use an invalid len or if
         * it's about to overflow ssize_t */
        if (len < 0) {
            ret = -EINVAL;
            goto out;
        }
        if (type >= 0
            && unlikely(!access_ok(vrfy_dir(type), buf, len))) {
            ret = -EFAULT;
            goto out;
        }
        if (len > MAX_RW_COUNT - ret) {
            len = MAX_RW_COUNT - ret;
            iov[seg].iov_len = len;
        }
        ret += len;
    }
out:
    *ret_pointer = iov;
    return ret;
}


/* Do it by hand, with file-ops */
static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
    loff_t *ppos, io_fn_t fn, int flags)
{
    ssize_t ret = 0;

    if (flags & ~RWF_HIPRI)
        return -EOPNOTSUPP;

    while (iov_iter_count(iter)) {
            struct iovec iovec = iov_iter_iovec(iter);
            ssize_t nr;

            nr = fn(filp, iovec.iov_base, iovec.iov_len, ppos);

            if (nr < 0) {
                if (!ret)
                    ret = nr;
                break;
            }
            ret += nr;
            if (nr != iovec.iov_len)
                break;
            iov_iter_advance(iter, nr);
        }

        return ret;
}

static ssize_t do_readv_writev(int type, struct file *file,
                               const struct iovec __user * uvector,
                               unsigned long nr_segs, loff_t *pos,
                               int flags)
{
    size_t tot_len;
    struct iovec iovstack[UIO_FASTIOV];
    struct iovec *iov = iovstack;
    struct iov_iter iter;
    ssize_t ret;
    io_fn_t fn;
    iter_fn_t iter_fn;

    ret = import_iovec(type, uvector, nr_segs,
                       ARRAY_SIZE(iovstack), &iov, &iter);
    if (ret < 0)
        return ret;

    tot_len = iov_iter_count(&iter);
    if (!tot_len)
        goto out;
    ret = rw_verify_area(type, file, pos, tot_len);
    if (ret < 0)
        goto out;

    if (type == READ) {
        fn = file->f_op->read;
        iter_fn = file->f_op->read_iter;
    } else {
        fn = (io_fn_t)file->f_op->write;
        iter_fn = file->f_op->write_iter;
        file_start_write(file);
    }

    if (iter_fn)
        ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags);
    else
        ret = do_loop_readv_writev(file, &iter, pos, fn, flags);

    if (type != READ)
        file_end_write(file);

    out:
        kfree(iov);
        if ((ret + (type == READ)) > 0) {
            if (type == READ)
                fsnotify_access(file);
            else
                fsnotify_modify(file);
        }
        return ret;
}

ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
                  unsigned long vlen, loff_t *pos, int flags)
{
    if (!(file->f_mode & FMODE_READ))
        return -EBADF;
    if (!(file->f_mode & FMODE_CAN_READ))
        return -EINVAL;

    return do_readv_writev(READ, file, vec, vlen, pos, flags);
}

EXPORT_SYMBOL(vfs_readv);
static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec,
                        unsigned long vlen, int flags)
{
    struct fd f = fdget_pos(fd);
    ssize_t ret = -EBADF;

    if (f.file) {
        loff_t pos = file_pos_read(f.file);
        ret = vfs_readv(f.file, vec, vlen, &pos, flags);
        if (ret >= 0)
            file_pos_write(f.file, pos);
        fdput_pos(f);
    }

    if (ret > 0)
        add_rchar(current, ret);
    inc_syscr(current);
    return ret;
}

static ssize_t do_preadv(unsigned long fd, const struct iovec __user *vec,
                         unsigned long vlen, loff_t pos, int flags)
{
    struct fd f;
    ssize_t ret = -EBADF;

    if (pos < 0)
        return -EINVAL;

    f = fdget(fd);
    if (f.file) {
        ret = -ESPIPE;
        if (f.file->f_mode & FMODE_PREAD)
            ret = vfs_readv(f.file, vec, vlen, &pos, flags);
        fdput(f);
    }

    if (ret > 0)
        add_rchar(current, ret);
    inc_syscr(current);
    return ret;
}


static ssize_t compat_do_readv_writev(int type, struct file *file,
               const struct compat_iovec __user *uvector,
               unsigned long nr_segs, loff_t *pos,
               int flags)
{
    compat_ssize_t tot_len;
    struct iovec iovstack[UIO_FASTIOV];
    struct iovec *iov = iovstack;
    struct iov_iter iter;
    ssize_t ret;
    io_fn_t fn;
    iter_fn_t iter_fn;

    ret = compat_import_iovec(type, uvector, nr_segs,
              UIO_FASTIOV, &iov, &iter);
    if (ret < 0)
        return ret;

    tot_len = iov_iter_count(&iter);
    if (!tot_len)
        goto out;
        ret = rw_verify_area(type, file, pos, tot_len);
    if (ret < 0)
        goto out;

    if (type == READ) {
        fn = file->f_op->read;
        iter_fn = file->f_op->read_iter;
    } else {
            fn = (io_fn_t)file->f_op->write;
            iter_fn = file->f_op->write_iter;
            file_start_write(file);
    }

    if (iter_fn)
        ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags);
    else
        ret = do_loop_readv_writev(file, &iter, pos, fn, flags);

    if (type != READ)
        file_end_write(file);

    out:
        kfree(iov);
        if ((ret + (type == READ)) > 0) {
            if (type == READ)
                fsnotify_access(file);
            else
                fsnotify_modify(file);
        }
        return ret;
}

static size_t compat_readv(struct file *file,
           const struct compat_iovec __user *vec,
           unsigned long vlen, loff_t *pos, int flags)
{
    ssize_t ret = -EBADF;

    if (!(file->f_mode & FMODE_READ))
       goto out;

    ret = -EINVAL;
    if (!(file->f_mode & FMODE_CAN_READ))
        goto out;

    ret = compat_do_readv_writev(READ, file, vec, vlen, pos, flags);

     out:
        if (ret > 0)
            add_rchar(current, ret);
        inc_syscr(current);
        return ret;
}

static size_t do_compat_readv(compat_ulong_t fd,
             const struct compat_iovec __user *vec,
             compat_ulong_t vlen, int flags)
{
    struct fd f = fdget_pos(fd);
    ssize_t ret;
    loff_t pos;

    if (!f.file)
        return -EBADF;
    pos = f.file->f_pos;
    ret = compat_readv(f.file, vec, vlen, &pos, flags);
    if (ret >= 0)
        f.file->f_pos = pos;
    fdput_pos(f);
    return ret;

}

COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
        const struct compat_iovec __user *,vec,
        compat_ulong_t, vlen)
{
    return do_compat_readv(fd, vec, vlen, 0);
}

static long do_compat_preadv64(unsigned long fd,
              const struct compat_iovec __user *vec,
              unsigned long vlen, loff_t pos, int flags)
{
    struct fd f;
    ssize_t ret;

    if (pos < 0)
        return -EINVAL;
    f = fdget(fd);
    if (!f.file)
        return -EBADF;
    ret = -ESPIPE;
        if (f.file->f_mode & FMODE_PREAD)
            ret = compat_readv(f.file, vec, vlen, &pos, flags);
        fdput(f);
        return ret;
}

1 个答案:

答案 0 :(得分:2)

除格式错误外,您可以轻松看到var mainForm = new formOne(); Application.Run(mainForm); do_readv都调用do_preadv。在这些功能中,没有任何迹象表明他们自己做了一些阅读。

您还可以看到vfs_readv没有阅读,只能拨打vfs_readv

实际阅读在这里完成:

do_readv_writev

嗯,这不是实际的阅读,但它是你可以从你的代码片段中获得的最接近阅读。 这些功能会发生什么,更重要的是,if (type == READ) { fn = file->f_op->read; iter_fn = file->f_op->read_iter; } ... if (iter_fn) ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags); else ret = do_loop_readv_writev(file, &iter, pos, fn, flags); iter_fn中存储的内容在您的代码中不可见。

我不是Linux专家,可以告诉你更多细节。