aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/file.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2018-06-24 15:04:04 +0100
committerAndreas Gruenbacher <agruenba@redhat.com>2018-07-02 16:27:17 +0100
commit64bc06bb32ee9cf458f432097113c8b495d75757 (patch)
treec87afdeaf0cd1c34ad4cf57c64a9a2c4678d84da /fs/gfs2/file.c
parentgfs2: Further iomap cleanups (diff)
downloadlinux-dev-64bc06bb32ee9cf458f432097113c8b495d75757.tar.xz
linux-dev-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.c44
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,