diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2018-06-24 16:04:04 +0200 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2018-07-02 17:27:17 +0200 |
commit | 64bc06bb32ee9cf458f432097113c8b495d75757 (patch) | |
tree | c87afdeaf0cd1c34ad4cf57c64a9a2c4678d84da /fs/gfs2/file.c | |
parent | gfs2: Further iomap cleanups (diff) | |
download | linux-64bc06bb32ee9cf458f432097113c8b495d75757.tar.xz linux-64bc06bb32ee9cf458f432097113c8b495d75757.zip |
gfs2: iomap buffered write support
With the traditional page-based writes, blocks are allocated separately
for each page written to. With iomap writes, we can allocate a lot more
blocks at once, with a fraction of the allocation overhead for each
page.
Split calculating the number of blocks that can be allocated at a given
position (gfs2_alloc_size) off from gfs2_iomap_alloc: that size
determines the number of blocks to allocate and reserve in the journal.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2/file.c')
-rw-r--r-- | fs/gfs2/file.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 6f6bbfbff13d..16dd395479a5 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -26,10 +26,12 @@ #include <linux/dlm.h> #include <linux/dlm_plock.h> #include <linux/delay.h> +#include <linux/backing-dev.h> #include "gfs2.h" #include "incore.h" #include "bmap.h" +#include "aops.h" #include "dir.h" #include "glock.h" #include "glops.h" @@ -691,9 +693,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end, /** * gfs2_file_write_iter - Perform a write to a file * @iocb: The io context - * @iov: The data to write - * @nr_segs: Number of @iov segments - * @pos: The file position + * @from: The data to write * * We have to do a lock/unlock here to refresh the inode size for * O_APPEND writes, otherwise we can land up writing at the wrong @@ -705,8 +705,9 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end, static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; - struct gfs2_inode *ip = GFS2_I(file_inode(file)); - int ret; + struct inode *inode = file_inode(file); + struct gfs2_inode *ip = GFS2_I(inode); + ssize_t ret; ret = gfs2_rsqa_alloc(ip); if (ret) @@ -723,7 +724,38 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) gfs2_glock_dq_uninit(&gh); } - return generic_file_write_iter(iocb, from); + if (iocb->ki_flags & IOCB_DIRECT) + return generic_file_write_iter(iocb, from); + + inode_lock(inode); + ret = generic_write_checks(iocb, from); + if (ret <= 0) + goto out; + + /* We can write back this queue in page reclaim */ + current->backing_dev_info = inode_to_bdi(inode); + + ret = file_remove_privs(file); + if (ret) + goto out2; + + ret = file_update_time(file); + if (ret) + goto out2; + + ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); + +out2: + current->backing_dev_info = NULL; +out: + inode_unlock(inode); + if (likely(ret > 0)) { + iocb->ki_pos += ret; + + /* Handle various SYNC-type writes */ + ret = generic_write_sync(iocb, ret); + } + return ret; } static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, |