diff options
| author | Jaegeuk Kim <jaegeuk@kernel.org> | 2016-02-03 13:09:09 -0800 |
|---|---|---|
| committer | Mister Oyster <oysterized@gmail.com> | 2017-04-13 12:32:59 +0200 |
| commit | 73f2dda2b305a0ed110e87c22fb9ce54821d18ef (patch) | |
| tree | 9a5a46a521aa2d84e69a7ab5be239e4c50233206 | |
| parent | 7b6e7175f6294a5512117d47e42c391eff51a115 (diff) | |
f2fs: move dio preallocation into f2fs_file_write_iter
This patch moves preallocation code for direct IOs into f2fs_file_write_iter.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Conflicts:
fs/f2fs/data.c
fs/f2fs/file.c
| -rw-r--r-- | fs/f2fs/data.c | 38 | ||||
| -rw-r--r-- | fs/f2fs/f2fs.h | 12 | ||||
| -rw-r--r-- | fs/f2fs/file.c | 32 |
3 files changed, 59 insertions, 23 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index fdd545ae6..7164e80ca 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -565,16 +565,24 @@ alloc: return 0; } -static int __allocate_data_blocks(struct inode *inode, loff_t offset, - size_t count) +ssize_t f2fs_preallocate_blocks(struct kiocb *iocb, size_t count) { + struct inode *inode = file_inode(iocb->ki_filp); struct f2fs_map_blocks map; + ssize_t ret = 0; - map.m_lblk = F2FS_BYTES_TO_BLK(offset); + map.m_lblk = F2FS_BYTES_TO_BLK(iocb->ki_pos); map.m_len = F2FS_BYTES_TO_BLK(count); map.m_next_pgofs = NULL; - return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_DIO); + if (iocb->ki_filp->f_flags & O_DIRECT && + !(f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))) { + ret = f2fs_convert_inline_inode(inode); + if (ret) + return ret; + ret = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO); + } + return ret; } /* @@ -671,7 +679,8 @@ next_block: map->m_len = 1; } else if ((map->m_pblk != NEW_ADDR && blkaddr == (map->m_pblk + ofs)) || - (map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR)) { + (map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR) || + flag == F2FS_GET_BLOCK_PRE_DIO) { ofs++; map->m_len++; } else { @@ -1643,35 +1652,20 @@ static ssize_t f2fs_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 address_space *mapping = file->f_mapping; + struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; size_t count = iov_length(iov, nr_segs); int err; - /* we don't need to use inline_data strictly */ - err = f2fs_convert_inline_inode(inode); + err = check_direct_IO(inode, rw, iov, offset, nr_segs); if (err) return err; if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) return 0; - err = check_direct_IO(inode, rw, iov, offset, nr_segs); - if (err) - return err; - - trace_f2fs_direct_IO_enter(inode, offset, count, rw); - - if (rw & WRITE) { - err = __allocate_data_blocks(inode, offset, count); - if (err) - goto out; - } - err = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, get_data_block_dio); -out: if (err < 0 && (rw & WRITE)) f2fs_write_failed(mapping, offset + count); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 455706e3f..5e73eff7b 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -105,6 +105,16 @@ static inline bool f2fs_crc_valid(__u32 blk_crc, void *buf, size_t buf_size) return f2fs_crc32(buf, buf_size) == blk_crc; } +static inline void inode_lock(struct inode *inode) +{ + mutex_lock(&inode->i_mutex); +} + +static inline void inode_unlock(struct inode *inode) +{ + mutex_unlock(&inode->i_mutex); +} + /** * wq_has_sleeper - check if there are any waiting processes * @wq: wait queue head @@ -411,6 +421,7 @@ struct f2fs_map_blocks { #define F2FS_GET_BLOCK_DIO 1 #define F2FS_GET_BLOCK_FIEMAP 2 #define F2FS_GET_BLOCK_BMAP 3 +#define F2FS_GET_BLOCK_PRE_DIO 4 /* * i_advise uses FADVISE_XXX_BIT. We can add additional hints later. @@ -1934,6 +1945,7 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *); void set_data_blkaddr(struct dnode_of_data *); int reserve_new_block(struct dnode_of_data *); int f2fs_get_block(struct dnode_of_data *, pgoff_t); +ssize_t f2fs_preallocate_blocks(struct kiocb *, size_t); int f2fs_reserve_block(struct dnode_of_data *, pgoff_t); struct page *get_read_data_page(struct inode *, pgoff_t, int, bool); struct page *find_data_page(struct inode *, pgoff_t); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 9302c2a74..c1cb8c70f 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -21,6 +21,7 @@ #include <linux/mount.h> #include <linux/pagevec.h> #include <linux/random.h> +#include <linux/aio.h> #include "f2fs.h" #include "node.h" @@ -1892,6 +1893,35 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } +static ssize_t f2fs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); + ssize_t ret; + + if (f2fs_encrypted_inode(inode) && + !f2fs_has_encryption_key(inode) && + f2fs_get_encryption_info(inode)) + return -EACCES; + + inode_lock(inode); + ret = f2fs_preallocate_blocks(iocb, iov_length(iov, nr_segs)); + if (!ret) + ret = __generic_file_aio_write(iocb, iov, nr_segs, + &iocb->ki_pos); + inode_unlock(inode); + + if (ret > 0 || ret == -EIOCBQUEUED) { + ssize_t err; + + err = generic_write_sync(file, iocb->ki_pos - ret, ret); + if (err < 0 && ret > 0) + ret = err; + } + return ret; +} + #ifdef CONFIG_COMPAT long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1930,7 +1960,7 @@ const struct file_operations f2fs_file_operations = { .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .aio_write = f2fs_file_aio_write, .open = f2fs_file_open, .release = f2fs_release_file, .mmap = f2fs_file_mmap, |
