From: Bob Peterson <rpeterso@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [GFS2 PATCH V2] gfs2: Implement special writepage for ail start operations
Date: Thu, 3 Jan 2019 15:13:10 -0500 (EST) [thread overview]
Message-ID: <651444781.59235487.1546546390205.JavaMail.zimbra@redhat.com> (raw)
In-Reply-To: <315229117.59037280.1546463577284.JavaMail.zimbra@redhat.com>
Hi,
Here's a rework of my previously posted patch based on Steve
Whitehouse's suggestions. This one's quite a bit simpler.
Also note that since gfs2_write_full_page was only ever called
with gfs2_get_block_noalloc, it's not necessary to pass in the
get_block function, so that parameter is now removed.
This version has now passed more than 425 iterations of the
failing test on rhel7, 350 iterations of the failing test on
rhel8, and dozens of iterations on an upstream kernel.
Regards,
Bob Peterson
---
gfs2: Implement special writepage for ail start operations
This patch fixes the hangs that result from doing certain jdata I/O,
primarily xfstests/269.
It implements a special new version of start_writepage that can
distinguish between writing pages from an ail sync operation, as
opposed to writes done on behalf of an inode write operation.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
fs/gfs2/aops.c | 11 +++++------
fs/gfs2/aops.h | 4 ++++
fs/gfs2/log.c | 40 +++++++++++++++++++++++++++++++++-------
fs/gfs2/log.h | 3 ++-
fs/gfs2/super.c | 2 +-
5 files changed, 45 insertions(+), 15 deletions(-)
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 05dd78f4b2b3..c5fb08eb9bb8 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -141,8 +141,7 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
/* This is the same as calling block_write_full_page, but it also
* writes pages outside of i_size
*/
-static int gfs2_write_full_page(struct page *page, get_block_t *get_block,
- struct writeback_control *wbc)
+int gfs2_write_full_page(struct page *page, struct writeback_control *wbc)
{
struct inode * const inode = page->mapping->host;
loff_t i_size = i_size_read(inode);
@@ -160,8 +159,8 @@ static int gfs2_write_full_page(struct page *page, get_block_t *get_block,
if (page->index == end_index && offset)
zero_user_segment(page, offset, PAGE_SIZE);
- return __block_write_full_page(inode, page, get_block, wbc,
- end_buffer_async_write);
+ return __block_write_full_page(inode, page, gfs2_get_block_noalloc,
+ wbc, end_buffer_async_write);
}
/**
@@ -189,7 +188,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w
}
gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize);
}
- return gfs2_write_full_page(page, gfs2_get_block_noalloc, wbc);
+ return gfs2_write_full_page(page, wbc);
}
/**
@@ -201,7 +200,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w
*
*/
-static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
+int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
diff --git a/fs/gfs2/aops.h b/fs/gfs2/aops.h
index fa8e5d0144dd..2b9f27b6c729 100644
--- a/fs/gfs2/aops.h
+++ b/fs/gfs2/aops.h
@@ -15,5 +15,9 @@ extern int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
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);
+extern int gfs2_jdata_writepage(struct page *page,
+ struct writeback_control *wbc);
+extern int gfs2_write_full_page(struct page *page,
+ struct writeback_control *wbc);
#endif /* __AOPS_DOT_H__ */
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 5bfaf381921a..787dba1db9a8 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -23,6 +23,7 @@
#include <linux/writeback.h>
#include <linux/list_sort.h>
+#include "aops.h"
#include "gfs2.h"
#include "incore.h"
#include "bmap.h"
@@ -82,18 +83,40 @@ static void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
brelse(bd->bd_bh);
}
+/*
+ * Function used by generic_writepages to call the real writepage
+ * function and set the mapping flags on error
+ */
+static int start_writepage(struct page *page, struct writeback_control *wbc,
+ void *data)
+{
+ struct address_space *mapping = page->mapping;
+ int ail_start = *(int *)data;
+ int ret;
+
+ if (ail_start)
+ ret = gfs2_write_full_page(page, wbc);
+ else
+ ret = mapping->a_ops->writepage(page, wbc);
+
+ mapping_set_error(mapping, ret);
+ return ret;
+}
+
/**
* gfs2_ail1_start_one - Start I/O on a part of the AIL
* @sdp: the filesystem
* @wbc: The writeback control structure
- * @ai: The ail structure
+ * @tr: the transaction
+ * @withdraw: this is set if we need to withdraw due to io errors
+ * @start: True if called from gfs2_ail1_start
*
*/
static int gfs2_ail1_start_one(struct gfs2_sbd *sdp,
struct writeback_control *wbc,
- struct gfs2_trans *tr,
- bool *withdraw)
+ struct gfs2_trans *tr, bool *withdraw,
+ int ail_start)
__releases(&sdp->sd_ail_lock)
__acquires(&sdp->sd_ail_lock)
{
@@ -128,7 +151,8 @@ __acquires(&sdp->sd_ail_lock)
if (!mapping)
continue;
spin_unlock(&sdp->sd_ail_lock);
- generic_writepages(mapping, wbc);
+ write_cache_pages(mapping, wbc, start_writepage,
+ &ail_start);
spin_lock(&sdp->sd_ail_lock);
if (wbc->nr_to_write <= 0)
break;
@@ -143,12 +167,14 @@ __acquires(&sdp->sd_ail_lock)
* gfs2_ail1_flush - start writeback of some ail1 entries
* @sdp: The super block
* @wbc: The writeback control structure
+ * @start: true if this was called from an ail1_start
*
* Writes back some ail1 entries, according to the limits in the
* writeback control structure
*/
-void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc)
+void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc,
+ int start)
{
struct list_head *head = &sdp->sd_ail1_list;
struct gfs2_trans *tr;
@@ -162,7 +188,7 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc)
list_for_each_entry_reverse(tr, head, tr_list) {
if (wbc->nr_to_write <= 0)
break;
- if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw))
+ if (gfs2_ail1_start_one(sdp, wbc, tr, &withdraw, start))
goto restart;
}
spin_unlock(&sdp->sd_ail_lock);
@@ -186,7 +212,7 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp)
.range_end = LLONG_MAX,
};
- return gfs2_ail1_flush(sdp, &wbc);
+ return gfs2_ail1_flush(sdp, &wbc, 1);
}
/**
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
index 1bc9bd444b28..3ebad7e505e4 100644
--- a/fs/gfs2/log.h
+++ b/fs/gfs2/log.h
@@ -74,7 +74,8 @@ extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
u32 type);
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
-extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc);
+extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc,
+ int start);
extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
extern int gfs2_logd(void *data);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index d4b11c903971..31e7948c3c0c 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -762,7 +762,7 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
GFS2_LOG_HEAD_FLUSH_NORMAL |
GFS2_LFC_WRITE_INODE);
if (bdi->wb.dirty_exceeded)
- gfs2_ail1_flush(sdp, wbc);
+ gfs2_ail1_flush(sdp, wbc, 0);
else
filemap_fdatawrite(metamapping);
if (flush_all)
prev parent reply other threads:[~2019-01-03 20:13 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <198879026.59035628.1546462911860.JavaMail.zimbra@redhat.com>
2019-01-02 21:12 ` [Cluster-devel] [GFS2 PATCH] gfs2: Implement special writepage for ail start operations Bob Peterson
2019-01-03 9:09 ` Steven Whitehouse
2019-01-03 20:13 ` Bob Peterson [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=651444781.59235487.1546546390205.JavaMail.zimbra@redhat.com \
--to=rpeterso@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).