如第一节第四部分所述,代表IO请求的io_struct结构体保存了用户提供的缓冲区地址所对应的物理地址,处理异步IO请求时应该使用这个物理地址。但是真正使用物理地址的时候,可能需要通过kmap函数将其转换成内核地址。执行转换的代码如下:
其中pio是一个io_struct结构体指针,代表一个异步IO请求。io_struct结构体的vec_cnt字段指示有多少个iovec结构体元素;vec_idx是当前正在处理的iovec结构体的序号;vec_offset表示对于当前iovec结构体,已经传输的字节数。pio->pg_array[pio->vec_idx]是用户缓冲区地址pio->iov_array[pio->vec_idx].iov_base(进程地址空间)对应的物理地址,kmap将其转换成内核地址。
真正将数据写入用户缓冲区的代码如下:
这里要区分是同步操作还是异步操作。对于同步操作(即执行aio_read/aio_write时设备资源可用,立即进行的IO操作),使用copy_to_user()函数将内核空间中的数据复制到用户空间中。对于异步操作,直接使用memcpy将设备缓冲区里的数据复制到目标地址。因为设备缓冲区在内核空间中,而目标地址是从用户缓冲区地址对应的物理地址转换而来的内核地址,所以可以直接使用memcpy进行复制。
执行读取操作的代码与写入操作的代码是类似的。