为什么io_prep_pwritev将nbytes设置为iovcnt?

问题描述 投票:0回答:1

在 libaio 中,

io_prep_pwritev
宏准备命令并设置 iocb 结构。
iocb.c.u.nbytes
不是应该是字节数吗?在
io_prep_pwritev
中,它被设置为iovcnt,这似乎不正确。这是为什么?

https://kernel.googlesource.com/pub/scm/fs/ext2/xfstests-bld/+/ac7997c9b0f905383e8675a766efc8c8305ce1f1/libaio/src/libaio.h#203

c linux asynchronous aio
1个回答
0
投票

这是正确的,但看起来很奇怪。 PWRITE 和 PWRITEV 共享相同的 ABI。 对于 PWRITE,它按照您期望的方式工作,将

buf
设置为数据缓冲区,将
nbytes
设置为字节数:

static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
{
        memset(iocb, 0, sizeof(*iocb));
        iocb->aio_fildes = fd;
        iocb->aio_lio_opcode = IO_CMD_PWRITE;
        iocb->aio_reqprio = 0;
        iocb->u.c.buf = buf;
        iocb->u.c.nbytes = count;
        iocb->u.c.offset = offset;
}

但对于 PWRITEV,它重新调整了 ABI 参数的用途,以将 iovec 数组及其长度传递到内核中。

static inline void io_prep_pwritev(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset)
{
        memset(iocb, 0, sizeof(*iocb));
        iocb->aio_fildes = fd;
        iocb->aio_lio_opcode = IO_CMD_PWRITEV;
        iocb->aio_reqprio = 0;
        iocb->u.c.buf = (void *)iov;
        iocb->u.c.nbytes = iovcnt;
        iocb->u.c.offset = offset;
}

然后,在

fs/aio.c
的内核内部,切换I/O操作是否为
vectored
。 在非向量情况下,它将参数解码为单个缓冲区指针和字节数。 在向量情况下,它调用
lib/iov_iter.c:import_iovec
buf
nbytes
参数解码为 iovec 以及 iovec 的长度。

这里是解码操作码的地方,注意指示

vectored
操作的布尔值:

    switch (iocb->aio_lio_opcode) {
    case IOCB_CMD_PREAD:
        return aio_read(&req->rw, iocb, false, compat);
    case IOCB_CMD_PWRITE:
        return aio_write(&req->rw, iocb, false, compat);
    case IOCB_CMD_PREADV:
        return aio_read(&req->rw, iocb, true, compat);
    case IOCB_CMD_PWRITEV:
        return aio_write(&req->rw, iocb, true, compat);
    case IOCB_CMD_FSYNC:
        return aio_fsync(&req->fsync, iocb, false);
    case IOCB_CMD_FDSYNC:
        return aio_fsync(&req->fsync, iocb, true);
    case IOCB_CMD_POLL:
        return aio_poll(req, iocb);
    default:
        pr_debug("invalid aio operation %d\n", iocb->aio_lio_opcode);
        return -EINVAL;
    }

并且,这是它处理解码参数的地方:

static ssize_t aio_setup_rw(int rw, const struct iocb *iocb,
        struct iovec **iovec, bool vectored, bool compat,
        struct iov_iter *iter)
{
    void __user *buf = (void __user *)(uintptr_t)iocb->aio_buf;
    size_t len = iocb->aio_nbytes;

    if (!vectored) {
        ssize_t ret = import_single_range(rw, buf, len, *iovec, iter);
        *iovec = NULL;
        return ret;
    }
#ifdef CONFIG_COMPAT
    if (compat)
        return compat_import_iovec(rw, buf, len, UIO_FASTIOV, iovec,
                iter);
#endif
    return import_iovec(rw, buf, len, UIO_FASTIOV, iovec, iter);
}
© www.soinside.com 2019 - 2024. All rights reserved.