在 libaio 中,
io_prep_pwritev
宏准备命令并设置 iocb 结构。 iocb.c.u.nbytes
不是应该是字节数吗?在io_prep_pwritev
中,它被设置为iovcnt,这似乎不正确。这是为什么?
这是正确的,但看起来很奇怪。 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);
}