aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/glops.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-11-23 10:51:34 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2006-11-30 10:36:42 -0500
commitb004157ab5b374a498a5874cda68c389219d23e7 (patch)
tree1e7d7d5c62f3e12cc453e763bbff139b47458be4 /fs/gfs2/glops.c
parentae619320b22f8e0b2bbe4a3a5ac2f9ccf08d7ec2 (diff)
downloadkernel_samsung_smdk4412-b004157ab5b374a498a5874cda68c389219d23e7.zip
kernel_samsung_smdk4412-b004157ab5b374a498a5874cda68c389219d23e7.tar.gz
kernel_samsung_smdk4412-b004157ab5b374a498a5874cda68c389219d23e7.tar.bz2
[GFS2] Fix journal flush problem
This fixes a bug which resulted in poor performance due to flushing the journal too often. The code path in question was via the inode_go_sync() function in glops.c. The solution is not to flush the journal immediately when inodes are ejected from memory, but batch up the work for glockd to deal with later on. This means that glocks may now live on beyond the end of the lifetime of their inodes (but not very much longer in the normal case). Also fixed in this patch is a bug (which was hidden by the bug mentioned above) in calculation of the number of free journal blocks. The gfs2_logd process has been altered to be more responsive to the journal filling up. We now wake it up when the number of uncommitted journal blocks has reached the threshold level rather than trying to flush directly at the end of each transaction. This again means doing fewer, but larger, log flushes in general. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/glops.c')
-rw-r--r--fs/gfs2/glops.c93
1 files changed, 24 insertions, 69 deletions
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 60561ca..b068d10 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -107,70 +107,6 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
}
/**
- * gfs2_page_inval - Invalidate all pages associated with a glock
- * @gl: the glock
- *
- */
-
-static void gfs2_page_inval(struct gfs2_glock *gl)
-{
- struct gfs2_inode *ip;
- struct inode *inode;
-
- ip = gl->gl_object;
- inode = &ip->i_inode;
- if (!ip || !S_ISREG(inode->i_mode))
- return;
-
- truncate_inode_pages(inode->i_mapping, 0);
- gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages);
- clear_bit(GIF_PAGED, &ip->i_flags);
-}
-
-/**
- * gfs2_page_wait - Wait for writeback of data
- * @gl: the glock
- *
- * Syncs data (not metadata) for a regular file.
- * No-op for all other types.
- */
-
-static void gfs2_page_wait(struct gfs2_glock *gl)
-{
- struct gfs2_inode *ip = gl->gl_object;
- struct inode *inode = &ip->i_inode;
- struct address_space *mapping = inode->i_mapping;
- int error;
-
- if (!S_ISREG(inode->i_mode))
- return;
-
- error = filemap_fdatawait(mapping);
-
- /* Put back any errors cleared by filemap_fdatawait()
- so they can be caught by someone who can pass them
- up to user space. */
-
- if (error == -ENOSPC)
- set_bit(AS_ENOSPC, &mapping->flags);
- else if (error)
- set_bit(AS_EIO, &mapping->flags);
-
-}
-
-static void gfs2_page_writeback(struct gfs2_glock *gl)
-{
- struct gfs2_inode *ip = gl->gl_object;
- struct inode *inode = &ip->i_inode;
- struct address_space *mapping = inode->i_mapping;
-
- if (!S_ISREG(inode->i_mode))
- return;
-
- filemap_fdatawrite(mapping);
-}
-
-/**
* meta_go_sync - sync out the metadata for this glock
* @gl: the glock
*
@@ -264,11 +200,24 @@ static void inode_go_drop_th(struct gfs2_glock *gl)
static void inode_go_sync(struct gfs2_glock *gl)
{
+ struct gfs2_inode *ip = gl->gl_object;
+
+ if (ip && !S_ISREG(ip->i_inode.i_mode))
+ ip = NULL;
+
if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
- gfs2_page_writeback(gl);
gfs2_log_flush(gl->gl_sbd, gl);
+ if (ip)
+ filemap_fdatawrite(ip->i_inode.i_mapping);
gfs2_meta_sync(gl);
- gfs2_page_wait(gl);
+ if (ip) {
+ struct address_space *mapping = ip->i_inode.i_mapping;
+ int error = filemap_fdatawait(mapping);
+ if (error == -ENOSPC)
+ set_bit(AS_ENOSPC, &mapping->flags);
+ else if (error)
+ set_bit(AS_EIO, &mapping->flags);
+ }
clear_bit(GLF_DIRTY, &gl->gl_flags);
gfs2_ail_empty_gl(gl);
}
@@ -283,14 +232,20 @@ static void inode_go_sync(struct gfs2_glock *gl)
static void inode_go_inval(struct gfs2_glock *gl, int flags)
{
+ struct gfs2_inode *ip = gl->gl_object;
int meta = (flags & DIO_METADATA);
if (meta) {
- struct gfs2_inode *ip = gl->gl_object;
gfs2_meta_inval(gl);
- set_bit(GIF_INVALID, &ip->i_flags);
+ if (ip)
+ set_bit(GIF_INVALID, &ip->i_flags);
+ }
+
+ if (ip && S_ISREG(ip->i_inode.i_mode)) {
+ truncate_inode_pages(ip->i_inode.i_mapping, 0);
+ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !ip->i_inode.i_mapping->nrpages);
+ clear_bit(GIF_PAGED, &ip->i_flags);
}
- gfs2_page_inval(gl);
}
/**