Commit 9ff8ec32 authored by Steven Whitehouse's avatar Steven Whitehouse

[GFS2] Split gfs2_writepage into three cases

This patch splits gfs2_writepage into separate functions for each of
the three cases: writeback, ordered and journalled. As a result
it becomes a lot easier to see what each one is doing. The common
code is moved into gfs2_writepage_common.

This fixes a performance bug where we were doing more work than
strictly required in the ordered write case.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 5561093e
...@@ -556,6 +556,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) ...@@ -556,6 +556,7 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
lock_buffer(bd->bd_bh); lock_buffer(bd->bd_bh);
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
if (tr) {
if (!list_empty(&bd->bd_list_tr)) if (!list_empty(&bd->bd_list_tr))
goto out; goto out;
tr->tr_touched = 1; tr->tr_touched = 1;
...@@ -563,9 +564,11 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) ...@@ -563,9 +564,11 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
tr->tr_num_buf++; tr->tr_num_buf++;
list_add(&bd->bd_list_tr, &tr->tr_list_buf); list_add(&bd->bd_list_tr, &tr->tr_list_buf);
} }
}
if (!list_empty(&le->le_list)) if (!list_empty(&le->le_list))
goto out; goto out;
if (tr)
__glock_lo_add(sdp, &bd->bd_gl->gl_le); __glock_lo_add(sdp, &bd->bd_gl->gl_le);
if (gfs2_is_jdata(ip)) { if (gfs2_is_jdata(ip)) {
gfs2_pin(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh);
......
...@@ -103,16 +103,15 @@ static int gfs2_get_block_direct(struct inode *inode, sector_t lblock, ...@@ -103,16 +103,15 @@ static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
} }
/** /**
* gfs2_writepage - Write complete page * gfs2_writepage_common - Common bits of writepage
* @page: Page to write * @page: The page to be written
* * @wbc: The writeback control
* Returns: errno
* *
* Some of this is copied from block_write_full_page() although we still * Returns: 1 if writepage is ok, otherwise an error code or zero if no error.
* call it to do most of the work.
*/ */
static int gfs2_writepage(struct page *page, struct writeback_control *wbc) static int gfs2_writepage_common(struct page *page,
struct writeback_control *wbc)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
...@@ -120,23 +119,94 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) ...@@ -120,23 +119,94 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
loff_t i_size = i_size_read(inode); loff_t i_size = i_size_read(inode);
pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
unsigned offset; unsigned offset;
int error; int ret = -EIO;
int done_trans = 0;
if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) { if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl)))
unlock_page(page); goto out;
return -EIO; ret = 0;
}
if (current->journal_info) if (current->journal_info)
goto out_ignore; goto redirty;
/* Is the page fully outside i_size? (truncate in progress) */ /* Is the page fully outside i_size? (truncate in progress) */
offset = i_size & (PAGE_CACHE_SIZE-1); offset = i_size & (PAGE_CACHE_SIZE-1);
if (page->index > end_index || (page->index == end_index && !offset)) { if (page->index > end_index || (page->index == end_index && !offset)) {
page->mapping->a_ops->invalidatepage(page, 0); page->mapping->a_ops->invalidatepage(page, 0);
goto out;
}
return 1;
redirty:
redirty_page_for_writepage(wbc, page);
out:
unlock_page(page); unlock_page(page);
return 0; /* don't care */ return 0;
}
/**
* gfs2_writeback_writepage - Write page for writeback mappings
* @page: The page
* @wbc: The writeback control
*
*/
static int gfs2_writeback_writepage(struct page *page,
struct writeback_control *wbc)
{
int ret;
ret = gfs2_writepage_common(page, wbc);
if (ret <= 0)
return ret;
ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
if (ret == -EAGAIN)
ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
return ret;
}
/**
* gfs2_ordered_writepage - Write page for ordered data files
* @page: The page to write
* @wbc: The writeback control
*
*/
static int gfs2_ordered_writepage(struct page *page,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
int ret;
ret = gfs2_writepage_common(page, wbc);
if (ret <= 0)
return ret;
if (!page_has_buffers(page)) {
create_empty_buffers(page, inode->i_sb->s_blocksize,
(1 << BH_Dirty)|(1 << BH_Uptodate));
} }
gfs2_page_add_databufs(ip, page, 0, inode->i_sb->s_blocksize-1);
return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
}
/**
* gfs2_jdata_writepage - Write complete page
* @page: Page to write
*
* Returns: errno
*
*/
static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
int error;
int done_trans = 0;
error = gfs2_writepage_common(page, wbc);
if (error <= 0)
return error;
if (PageChecked(page)) { if (PageChecked(page)) {
error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
...@@ -838,7 +908,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) ...@@ -838,7 +908,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
} }
static const struct address_space_operations gfs2_writeback_aops = { static const struct address_space_operations gfs2_writeback_aops = {
.writepage = gfs2_writepage, .writepage = gfs2_writeback_writepage,
.writepages = gfs2_writeback_writepages, .writepages = gfs2_writeback_writepages,
.readpage = gfs2_readpage, .readpage = gfs2_readpage,
.readpages = gfs2_readpages, .readpages = gfs2_readpages,
...@@ -852,7 +922,7 @@ static const struct address_space_operations gfs2_writeback_aops = { ...@@ -852,7 +922,7 @@ static const struct address_space_operations gfs2_writeback_aops = {
}; };
static const struct address_space_operations gfs2_ordered_aops = { static const struct address_space_operations gfs2_ordered_aops = {
.writepage = gfs2_writepage, .writepage = gfs2_ordered_writepage,
.readpage = gfs2_readpage, .readpage = gfs2_readpage,
.readpages = gfs2_readpages, .readpages = gfs2_readpages,
.sync_page = block_sync_page, .sync_page = block_sync_page,
...@@ -866,7 +936,7 @@ static const struct address_space_operations gfs2_ordered_aops = { ...@@ -866,7 +936,7 @@ static const struct address_space_operations gfs2_ordered_aops = {
}; };
static const struct address_space_operations gfs2_jdata_aops = { static const struct address_space_operations gfs2_jdata_aops = {
.writepage = gfs2_writepage, .writepage = gfs2_jdata_writepage,
.readpage = gfs2_readpage, .readpage = gfs2_readpage,
.readpages = gfs2_readpages, .readpages = gfs2_readpages,
.sync_page = block_sync_page, .sync_page = block_sync_page,
......
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