linux内核库aio调研

时间:2024-04-05 09:18:29

背景介绍

图 1. 基本 Linux I/O 模型的简单矩阵

linux内核库aio调研

两种头文件:

原生的AIO_ABI方法 /usr/include/linux/aio_abi.h /usr/include/aio.h
通过无名信号量signal机制来判断是否IO完成。
表 1. AIO 接口 API

API 函数 说明
aio_read 请求异步读操作
aio_error 检查异步请求的状态
aio_return 获得完成的异步请求的返回状态
aio_write 请求异步写操作
aio_suspend 挂起调用进程,直到一个或多个异步请求已经完成(或失败)
aio_cancel 取消异步 I/O 请求
lio_listio 发起一系列 I/O 操作

集成的libaio方法 /usr/include/libaio.h
libaio不是centos原生的支持,需要手动安装开发库 离线或yum等安装
iocb数据结构:
linux内核库aio调研
linux内核库aio调研

iocb数据结构:它支持单个的io操作(io_iocb_common),也支持成批的IO处理(io_iocb_vector),还支持基于polling 模式(linux按键驱动)。

struct iocb在内核中又对应到struct kiocb结构。
linux内核库aio调研

便于调用,还封装好了多个常用的inline函数 (宏定义) ,宏定义都是操作struct iocb的结构体:

1、static inline void io_set_callback(struct iocb *iocb, io_callback_t cb)
2、static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
3、static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
4、static inline void io_prep_preadv(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset)
5、static inline void io_prep_pwritev(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset)
6、static inline void io_prep_poll(struct iocb *iocb, int fd, int events)
7、static inline int io_poll(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd, int events)
8、static inline void io_prep_fsync(struct iocb *iocb, int fd)
9、static inline int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)
10、static inline void io_prep_fdsync(struct iocb *iocb, int fd)
11、static inline int io_fdsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)
12、static inline void io_set_eventfd(struct iocb *iocb, int eventfd)

libaio主要用event 来实现异步:一个IO初始化的时候对应一个io event, 每完成一个IO就产生一个event, 因此IO 请求提交之后,随时检查返回的io event的数量,就知道哪些IO已经完成。

5 个系统调用:(man手册)

extern int io_setup(int maxevents, io_context_t *ctxp);
extern int io_destroy(io_context_t ctx);
extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]);
extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt);
extern int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);

1、int io_setup(unsigned nr_events, aio_context_t *ctx_idp);
nr_events: nr_events确认最大的异步IO请求数,即io_event数量;
ctx_idp: AIO上下文句柄的指针 , 0

ERRORS
       EAGAIN The specified nr_events  exceeds  the  user's  limit  of  available  events,  as  defined  in  /proc/sys/fs/aio-max-nr.
       EFAULT An invalid pointer is passed for ctx_idp.
       EINVAL ctx_idp  is  not  initialized, or the specified nr_events exceeds internal limits.  nr_events should be greater than 0.
       ENOMEM Insufficient kernel resources are available.
       ENOSYS io_setup() is not implemented on this architecture.

2、int io_submit(aio_context_t ctx_id, long nr, struct iocb **iocbpp);
ctx_id:IO上下文句柄,内核通过它进行查找;
nr:iocb数组的大小;
iocbpp: 每个iocb描述一个异步IO请求;

ERRORS
       EAGAIN Insufficient resources are available to queue any iocbs.
       EBADF  The file descriptor specified in the first iocb is invalid.
       EFAULT One of the data structures points to invalid data.
       EINVAL The AIO context specified by ctx_id is invalid.  nr is less than 0.  The iocb  at  *iocbpp[0] is not properly initialized, or the operation specified is invalid for the file descriptor in the iocb.
       ENOSYS io_submit() is not implemented on this architecture.

3、int io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
ctx_id :AIO上下文句柄;
min_nr:至少收集min_nr个已经完成的IO请求才返回;
nr:最多收集nr个已经完成的IO请求;
timeout:等待的时间
events:由应用层分配,内核将完成的io_event拷贝到该缓冲区,所以,events数组要保证至少有nr个io_event。

ERRORS
       EFAULT Either events or timeout is an invalid pointer.
       EINVAL ctx_id is invalid.  min_nr is out of range or nr is out of range.
       EINTR  Interrupted by a signal handler; see signal(7).
       ENOSYS io_getevents() is not implemented on this architecture.

int io_destroy(aio_context_t ctx_id);

ERRORS
       EFAULT The context pointed to is invalid.
       EINVAL The AIO context specified by ctx_id is invalid.
       ENOSYS io_destroy() is not implemented on this architecture.

int io_cancel(aio_context_t ctx_id, struct iocb *iocb, struct io_event *result);

在使用AIO时,需要通过系统调用io_getevents获取已经完成的IO事件,而系统调用io_getevents是阻塞的,所以有2种方式:(1)使用多线程,用专门的线程调用io_getevents;(2)对于单线程程序,可以通过epoll来使用AIO.
DL采用线程调用的方式。

aio-nr&aio-max-nr:

aio-nr是指定的事件数的运行总和
io_setup系统调用所有当前活动的aio上下文。如果aio-nr
到达aio-max-nr然后io_setup将失败并使用EAGAIN。注意
提高aio-max-nr不会导致预分配或重新调整大小
任何内核数据结构。

• /proc/sys/fs/aio-nr 文件提供了系统范围异步 I/O 请求现在的数目。
• /proc/sys/fs/aio-max-nr 文件是所允许的并发请求的最大个数
https://docs.oracle.com/cd/E11882_01/install.112/e24326/toc.htm#BHCCADGD
linux内核库aio调研

65536
1048576

1、可以临时修改内核参数aio-max-nr

echo > /proc/sys/fs/aio-max-nr 1048576

2、永久修改内核参数aio-max-nr,需要在/etc/sysctl.conf加上下面这句
fs.aio-max-nr = 1048576

用下列命令使参数生效
#/sbin/sysctl -p

File_max怎么产生的?(和系统内存有关)
https://serverfault.com/questions/716578/default-value-of-proc-sys-fs-file-max
linux内核库aio调研
linux内核库aio调研
linux内核库aio调研