Commit 64bc06bb authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

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: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: default avatarBob Peterson <rpeterso@redhat.com>
parent d505a96a
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <trace/events/writeback.h> #include <trace/events/writeback.h>
#include <linux/sched/signal.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -36,10 +37,11 @@ ...@@ -36,10 +37,11 @@
#include "super.h" #include "super.h"
#include "util.h" #include "util.h"
#include "glops.h" #include "glops.h"
#include "aops.h"
static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page, void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
unsigned int from, unsigned int len) unsigned int from, unsigned int len)
{ {
struct buffer_head *head = page_buffers(page); struct buffer_head *head = page_buffers(page);
unsigned int bsize = head->b_size; unsigned int bsize = head->b_size;
...@@ -462,7 +464,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping, ...@@ -462,7 +464,7 @@ static int gfs2_jdata_writepages(struct address_space *mapping,
* Returns: errno * Returns: errno
*/ */
static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
{ {
struct buffer_head *dibh; struct buffer_head *dibh;
u64 dsize = i_size_read(&ip->i_inode); u64 dsize = i_size_read(&ip->i_inode);
...@@ -776,7 +778,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, ...@@ -776,7 +778,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
* adjust_fs_space - Adjusts the free space available due to gfs2_grow * adjust_fs_space - Adjusts the free space available due to gfs2_grow
* @inode: the rindex inode * @inode: the rindex inode
*/ */
static void adjust_fs_space(struct inode *inode) void adjust_fs_space(struct inode *inode)
{ {
struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
...@@ -822,11 +824,11 @@ static void adjust_fs_space(struct inode *inode) ...@@ -822,11 +824,11 @@ static void adjust_fs_space(struct inode *inode)
* This copies the data from the page into the inode block after * This copies the data from the page into the inode block after
* the inode data structure itself. * the inode data structure itself.
* *
* Returns: errno * Returns: copied bytes or errno
*/ */
static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
loff_t pos, unsigned copied, loff_t pos, unsigned copied,
struct page *page) struct page *page)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
u64 to = pos + copied; u64 to = pos + copied;
...@@ -865,7 +867,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, ...@@ -865,7 +867,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
* The main write_end function for GFS2. We just put our locking around the VFS * The main write_end function for GFS2. We just put our locking around the VFS
* provided functions. * provided functions.
* *
* Returns: errno * Returns: copied bytes or errno
*/ */
static int gfs2_write_end(struct file *file, struct address_space *mapping, static int gfs2_write_end(struct file *file, struct address_space *mapping,
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*/
#ifndef __AOPS_DOT_H__
#define __AOPS_DOT_H__
#include "incore.h"
extern int stuffed_readpage(struct gfs2_inode *ip, struct page *page);
extern int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
loff_t pos, unsigned copied,
struct page *page);
extern void adjust_fs_space(struct inode *inode);
extern void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
unsigned int from, unsigned int len);
#endif /* __AOPS_DOT_H__ */
This diff is collapsed.
...@@ -26,10 +26,12 @@ ...@@ -26,10 +26,12 @@
#include <linux/dlm.h> #include <linux/dlm.h>
#include <linux/dlm_plock.h> #include <linux/dlm_plock.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/backing-dev.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
#include "bmap.h" #include "bmap.h"
#include "aops.h"
#include "dir.h" #include "dir.h"
#include "glock.h" #include "glock.h"
#include "glops.h" #include "glops.h"
...@@ -691,9 +693,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end, ...@@ -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 * gfs2_file_write_iter - Perform a write to a file
* @iocb: The io context * @iocb: The io context
* @iov: The data to write * @from: The data to write
* @nr_segs: Number of @iov segments
* @pos: The file position
* *
* We have to do a lock/unlock here to refresh the inode size for * 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 * 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, ...@@ -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) static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct gfs2_inode *ip = GFS2_I(file_inode(file)); struct inode *inode = file_inode(file);
int ret; struct gfs2_inode *ip = GFS2_I(inode);
ssize_t ret;
ret = gfs2_rsqa_alloc(ip); ret = gfs2_rsqa_alloc(ip);
if (ret) if (ret)
...@@ -723,7 +724,38 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -723,7 +724,38 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
gfs2_glock_dq_uninit(&gh); 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, static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment