ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,struct block_device *bdev, const struct iovec *iov, loff_t offset,unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,int dio_lock_type) {int seg;size_t size;unsigned long addr;unsigned blkbits = inode->i_blkbits;unsigned bdev_blkbits = 0;unsigned blocksize_mask = (1 << blkbits) - 1;ssize_t retval = -EINVAL;loff_t end = offset;struct dio *dio;int release_i_mutex = 0;int acquire_i_mutex = 0;if (rw & WRITE)rw = WRITE_SYNC;if (bdev)bdev_blkbits = blksize_bits(bdev_hardsect_size(bdev));if (offset & blocksize_mask) {if (bdev)blkbits = bdev_blkbits;blocksize_mask = (1 << blkbits) - 1;if (offset & blocksize_mask)goto out;}for (seg = 0; seg < nr_segs; seg++) {addr = (unsigned long)iov[seg].iov_base;size = iov[seg].iov_len;end += size;if ((addr & blocksize_mask) || (size & blocksize_mask)) {if (bdev)blkbits = bdev_blkbits;blocksize_mask = (1 << blkbits) - 1;if ((addr & blocksize_mask) || (size & blocksize_mask))goto out;}}dio = kmalloc(sizeof(*dio), GFP_KERNEL);retval = -ENOMEM;if (!dio)goto out;dio->lock_type = dio_lock_type;if (dio_lock_type != DIO_NO_LOCKING) {if (rw == READ && end > offset) {struct address_space *mapping;mapping = iocb->ki_filp->f_mapping;if (dio_lock_type != DIO_OWN_LOCKING) {mutex_lock(&inode->i_mutex);release_i_mutex = 1;}retval = filemap_write_and_wait_range(mapping, offset,end - 1);if (retval) {kfree(dio);goto out;}if (dio_lock_type == DIO_OWN_LOCKING) {mutex_unlock(&inode->i_mutex);acquire_i_mutex = 1;}}if (dio_lock_type == DIO_LOCKING)down_read_non_owner(&inode->i_alloc_sem);}dio->is_async = !is_sync_kiocb(iocb) && !((rw & WRITE) &&(end > i_size_read(inode)));retval = direct_io_worker(rw, iocb, inode, iov, offset,nr_segs, blkbits, get_block, end_io, dio);if (rw == READ && dio_lock_type == DIO_LOCKING)release_i_mutex = 0;out:if (release_i_mutex)mutex_unlock(&inode->i_mutex);else if (acquire_i_mutex)mutex_lock(&inode->i_mutex);return retval; }该函数将要读或者要写的数据进行拆分,并检查缓冲区对齐的情况 。本文在前边介绍 open() 函数的时候指出,使用直接 I/O 读写数据的时候必须要注意缓冲区对齐的问题,从上边的代码可以看出,缓冲区对齐的检查是在 __blockdev_direct_IO() 函数里边进行的 。用户地址空间的缓冲区可以通过 iov 数组中的 iovec 描述符确定 。直接 I/O 的读操作或者写操作都是同步进行的,也就是说,函数 __blockdev_direct_IO() 会一直等到所有的 I/O 操作都结束才会返回,因此,一旦应用程序 read() 系统调用返回,应用程序就可以访问用户地址空间中含有相应数据的缓冲区 。但是,这种方法在应用程序读操作完成之前不能关闭应用程序,这将会导致关闭应用程序缓慢 。
直接I/O 优点最大的优点就是减少操作系统缓冲区和用户地址空间的拷贝次数 。降低了CPU的开销,和内存带宽 。对于某些应用程序来说简直是福音,将会大大提高性能 。
直接I/O 缺点直接IO并不总能让人如意 。直接IO的开销也很大,应用程序没有控制好读写,将会导致磁盘读写的效率低下 。磁盘的读写是通过磁头的切换到不同的磁道上读取和写入数据,如果需要写入数据在磁盘位置相隔比较远,就会导致寻道的时间大大增加,写入读取的效率大大降低 。
总结直接IO方式确实能够减少CPU的使用率以及内存带宽的占用,但是有时候也会造成性能的影响 。所以在使用直接IO之前一定要清楚它的原理,只有在各项都清晰的情况下,才考虑使用 。本人只是介绍了原理,如想深入,建议参考内核相关文档 。
推荐阅读
- Sql中Left Join、Right Join、Inner Join的区别
- 这些 Linux 指令你都掌握了吗
- phpstudy使用说明教程
- 在一个千万级的数据库查寻中,如何提高查询效率?
- 西红柿炒鸡蛋
- 恋爱中发现女朋友与前男友同居过 女友和前男友同居
- 中国版“苏格兰蛋”
- 美研签证拒签案例 美国拒签中国留学生
- 金骏眉制作流程 金骏眉制作工艺图
- 秋分时节谨防阴虚火旺 中医建议早睡早起
