diff options
author | Jens Axboe <axboe@kernel.dk> | 2013-04-20 21:27:25 -0700 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-04-21 19:29:59 -0600 |
commit | a5615e59e31d70c3c2f70f177edf1c6a5b98aa5f (patch) | |
tree | b88235788c3c2afe5f646c3fc72b748e0a575569 | |
parent | d16681b307ff5fd259043de36187f175ddf43d9a (diff) |
fs: only inc/dec inode->i_dio_count for file systemsaio-dio
We don't need truncate protection for block devices, so add a flag
bypassing this cache line dirtying for every IO.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | fs/block_dev.c | 3 | ||||
-rw-r--r-- | fs/direct-io.c | 13 | ||||
-rw-r--r-- | fs/inode.c | 7 | ||||
-rw-r--r-- | include/linux/fs.h | 4 |
4 files changed, 22 insertions, 5 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index aae187a7f94a..00a6f9efce51 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -164,7 +164,8 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, struct inode *inode = file->f_mapping->host; return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset, - nr_segs, blkdev_get_block, NULL, NULL, 0); + nr_segs, blkdev_get_block, NULL, NULL, + DIO_IGNORE_TRUNCATE); } int __sync_blockdev(struct block_device *bdev, int wait) diff --git a/fs/direct-io.c b/fs/direct-io.c index 9e639f0edf5c..f66555cdf203 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -266,7 +266,11 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is dio->end_io(dio->iocb, offset, transferred, dio->private, ret, is_async); } else { - inode_dio_done(dio->inode); + if (dio->flags & DIO_IGNORE_TRUNCATE) + __inode_dio_done(dio->inode); + else + inode_dio_done(dio->inode); + if (is_async) aio_complete(dio->iocb, ret, 0); } @@ -1125,9 +1129,12 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } /* - * Will be decremented at I/O completion time. + * Will be decremented at I/O completion time. For a block device + * we don't need to protect against truncate, so don't increment + * the inode direct IO count. */ - atomic_inc(&inode->i_dio_count); + if (!(dio->flags & DIO_IGNORE_TRUNCATE)) + atomic_inc(&inode->i_dio_count); /* * For file extending writes updating i_size before data diff --git a/fs/inode.c b/fs/inode.c index a898b3d43ccf..6878ba8979ff 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1883,6 +1883,11 @@ void inode_dio_wait(struct inode *inode) } EXPORT_SYMBOL(inode_dio_wait); +void __inode_dio_done(struct inode *inode) +{ + wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); +} + /* * inode_dio_done - signal finish of a direct I/O requests * @inode: inode the direct I/O happens on @@ -1893,6 +1898,6 @@ EXPORT_SYMBOL(inode_dio_wait); void inode_dio_done(struct inode *inode) { if (atomic_dec_and_test(&inode->i_dio_count)) - wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); + __inode_dio_done(inode); } EXPORT_SYMBOL(inode_dio_done); diff --git a/include/linux/fs.h b/include/linux/fs.h index 2c28271ab9d4..db36094768ea 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2433,6 +2433,9 @@ enum { /* filesystem does not support filling holes */ DIO_SKIP_HOLES = 0x02, + + /* inode/fs/bdev does not need truncate protection */ + DIO_IGNORE_TRUNCATE = 0x04, }; void dio_end_io(struct bio *bio, int error); @@ -2453,6 +2456,7 @@ static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb, #endif void inode_dio_wait(struct inode *inode); +void __inode_dio_done(struct inode *inode); void inode_dio_done(struct inode *inode); extern const struct file_operations generic_ro_fops; |