aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Marzinski <bmarzins@redhat.com>2016-06-27 10:58:40 -0400
committerBob Peterson <rpeterso@redhat.com>2016-06-27 10:58:40 -0400
commitb4bba38909c21689de21355e84259cb7b38f25ac (patch)
tree3892b8d2e5b06b8db6e0d3ec7533b958c25bbdb9
parent6df9f9a253c7dc9f8ed18bf89d762de350a31813 (diff)
fs: export __block_write_full_page
gfs2 needs to be able to skip the check to see if a page is outside of the file size when writing it out. gfs2 can get into a situation where it needs to flush its in-memory log to disk while a truncate is in progress. If the file being trucated has data journaling enabled, it is possible that there are data blocks in the log that are past the end of the file. gfs can't finish the log flush without either writing these blocks out or revoking them. Otherwise, if the node crashed, it could overwrite subsequent changes made by other nodes in the cluster when it's journal was replayed. Unfortunately, there is no way to add log entries to the log during a flush. So gfs2 simply writes out the page instead. This situation can only occur when the truncate code still has the file locked exclusively, and hasn't marked this block as free in the metadata (which happens later in truc_dealloc). After gfs2 writes this page out, the truncation code will shortly invalidate it and write out any revokes if necessary. In order to make this work, gfs2 needs to be able to skip the check for writes outside the file size. Since the check exists in block_write_full_page, this patch exports __block_write_full_page, which doesn't have the check. Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
-rw-r--r--fs/buffer.c3
-rw-r--r--include/linux/buffer_head.h3
2 files changed, 5 insertions, 1 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 754813a6962b..6c15012a75d9 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1687,7 +1687,7 @@ static struct buffer_head *create_page_buffers(struct page *page, struct inode *
1687 * WB_SYNC_ALL, the writes are posted using WRITE_SYNC; this 1687 * WB_SYNC_ALL, the writes are posted using WRITE_SYNC; this
1688 * causes the writes to be flagged as synchronous writes. 1688 * causes the writes to be flagged as synchronous writes.
1689 */ 1689 */
1690static int __block_write_full_page(struct inode *inode, struct page *page, 1690int __block_write_full_page(struct inode *inode, struct page *page,
1691 get_block_t *get_block, struct writeback_control *wbc, 1691 get_block_t *get_block, struct writeback_control *wbc,
1692 bh_end_io_t *handler) 1692 bh_end_io_t *handler)
1693{ 1693{
@@ -1848,6 +1848,7 @@ recover:
1848 unlock_page(page); 1848 unlock_page(page);
1849 goto done; 1849 goto done;
1850} 1850}
1851EXPORT_SYMBOL(__block_write_full_page);
1851 1852
1852/* 1853/*
1853 * If a page has any new buffers, zero them out here, and mark them uptodate 1854 * If a page has any new buffers, zero them out here, and mark them uptodate
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index d48daa3f6f20..7e14e545c4b6 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -208,6 +208,9 @@ void block_invalidatepage(struct page *page, unsigned int offset,
208 unsigned int length); 208 unsigned int length);
209int block_write_full_page(struct page *page, get_block_t *get_block, 209int block_write_full_page(struct page *page, get_block_t *get_block,
210 struct writeback_control *wbc); 210 struct writeback_control *wbc);
211int __block_write_full_page(struct inode *inode, struct page *page,
212 get_block_t *get_block, struct writeback_control *wbc,
213 bh_end_io_t *handler);
211int block_read_full_page(struct page*, get_block_t*); 214int block_read_full_page(struct page*, get_block_t*);
212int block_is_partially_uptodate(struct page *page, unsigned long from, 215int block_is_partially_uptodate(struct page *page, unsigned long from,
213 unsigned long count); 216 unsigned long count);