直接IO路径分析

直接IO路径

下图,是在O_DIRECT打开模式下,对文件进行进行读写的函数调用图。

 

函数generic_file_aio_read进行IO类型判别,如果是直接IO

对块设备文件,会走blkdev_direct_IO分支,代码如下:

清单 1. 函数 blkdev_direct_IO()

static ssize_t

blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,

                        loff_t offset, unsigned long nr_segs)

{

        struct file *file = iocb->ki_filp;

        struct inode *inode = file->f_mapping->host;

        return blockdev_direct_IO_no_locking_newtrunc(rwiocbinode,

                                I_BDEV(inode), iovoffsetnr_segs,

                                blkdev_get_blocksNULL);

}

它只是简单取出文件对象和索引节点结构,索引节点同时是其地址空间的owner,然后,调用blockdev_direct_IO_no_locking_newtrunc. 而blockdev_direct_IO_no_locking_newtrunc只是一个封装函数,它立即调用 __blockdev_direct_IO_newtrunc.

清单 2 函数 blkdev_direct_IO_no_locking_newtrunc()

static inline ssize_t blockdev_direct_IO_no_locking_newtrunc(int rw, struct kiocb *iocb,

        struct inode *inode, struct block_device *bdev, const struct iovec *iov,

        loff_t offset, unsigned long nr_segsget_block_t get_block,

        dio_iodone_t end_io)

{

        return __blockdev_direct_IO_newtrunc(rwiocbinodebdeviovoffset,

                                nr_segsget_blockend_ioNULL, 0);

}

对普通文件,会走blockdev_direct_IO_newtrunc,代码如下:

清单 2 函数 blkdev_direct_IO_newtrunc()

static inline ssize_t blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb,

        struct inode *inode, struct block_device *bdev, const struct iovec *iov,

        loff_t offset, unsigned long nr_segsget_block_t get_block,

        dio_iodone_t end_io)

{

        return __blockdev_direct_IO_newtrunc(rwiocbinodebdeviovoffset,

                                    nr_segsget_blockend_ioNULL,

                                    DIO_LOCKING | DIO_SKIP_HOLES);

}

到这一步可以看出,对普通文件和块设备文件的直接IO,到最后都会调用__blockdev_direct_IO_newtrunc,其差别在于有没加锁,可以看它的最后一个参数是不同的,即对普通文件的DIO要加锁,避免多个进程在同一时刻对文件写,而块设备文件则没有加以限制,而是交由底层的设备驱动进行处理,底层的写操作会以串行方式执行。

__blockdev_direct_IO_newtrunc函数,代码如下,主要完成这样几个任务

1)检查各个段的内存边界,不能出现跨页的段

2)检查,如果有锁,即是对普通文件的DIO,则调用filemap_write_and_wait_range,将相应位置可能存在的page cache废弃掉或刷回磁盘(避免产生不一致),然后调用direct_io_worker来处理请求

清单 3 函数 __blkdev_direct_IO_newtrunc()

ssize_t

__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,

        struct block_device *bdev, const struct iovec *iovloff_t offset

        unsigned long nr_segsget_block_t get_blockdio_iodone_t end_io,

        dio_submit_t submit_io, int flags)

{

        if (dio->flags & DIO_LOCKING) {

                ...

                mutex_lock(&inode->i_mutex);

                retval=filemap_write_and_wait_range(mapping,offset, end-1);

                ...

        }

        retval = direct_io_worker(rwiocbinodeiovoffset,nr_segsblkbitsget_block

                             end_iosubmit_iodio);

        ...

}

direct_io_worker,一次可能包含多个读操作,对于其中的每一个,调用do_direct_IO.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值