cluster-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
* [Cluster-devel] [PATCH] GFS2: kernel changes to support new gfs2_grow command (Try 3)
@ 2007-05-08 20:43 David Teigland
  0 siblings, 0 replies; 14+ messages in thread
From: David Teigland @ 2007-05-08 20:43 UTC (permalink / raw)
  To: cluster-devel.redhat.com

On Tue, May 08, 2007 at 09:56:05AM -0500, Robert Peterson wrote:
> David Teigland wrote:
> >On Wed, May 02, 2007 at 08:57:08PM -0500, Robert Peterson wrote:
> >>@@ -447,7 +479,12 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
> >>	u64 junk = ip->i_di.di_size;
> >>	int error;
> >>
> >>-	if (do_div(junk, sizeof(struct gfs2_rindex))) {
> >>+	/* If someone is holding the rindex file with a glock, they must
> >>+	   be updating it, in which case we may have partial entries.
> >>+	   In this case, we ignore the partials. */
> >>+	if (!gfs2_glock_is_held_excl(ip->i_gl) &&
> >>+	    !gfs2_glock_is_held_shrd(ip->i_gl) &&
> >>+	    do_div(junk, sizeof(struct gfs2_rindex))) {
> >>		gfs2_consist_inode(ip);
> >>		return -EIO;
> >>	}
> >
> >So the use of glock_is_held _is_ part of an assertion, not part of an
> >algorithm which I was worried about before.  We should only ever get to
> >this spot with a shared glock, right? (rindex_hold takes it).  So a plain
> >old assertion that the glock is shared at the beginning would be ok, but
> >this particular check doesn't make sense to me.
> 
> For the sake of completeness, I retested without this change to make
> sure it was also still necessary.  It was.  The problem is that
> we can now call gfs2_ri_update while there are still partial rindex 
> entries.  This can happen when we need to allocate a new page to the
> rindex, which calls gfs2_inplace_reserve_i, which eventually gets to 
> gfs2_check_rindex_version.  Without the change, you get:

+       else if (!sdp->sd_rgrps) /* We may not have the rindex read in, so: */
+               error = gfs2_check_rindex_version(sdp);

This is a very special exception; instead of using this more general
purpose function (gfs2_check_rindex_version) for the purpose of reading in
the rgrps, and then being required to add the further special case checks
up above -- I suggest using a new function here that just reads in the
rgrps without the checks above that you've had to modify.

The path I see us going down here is adding a special-case-exception in
one spot, then finding that it's not quite right, so adding another
special-case-exception on top of it ... and so on.  It becomes a house of
cards very quickly that way.

Dave



^ permalink raw reply	[flat|nested] 14+ messages in thread
* [Cluster-devel] [PATCH] GFS2: kernel changes to support new gfs2_grow command (Try 3)
@ 2007-05-08 20:42 David Teigland
  0 siblings, 0 replies; 14+ messages in thread
From: David Teigland @ 2007-05-08 20:42 UTC (permalink / raw)
  To: cluster-devel.redhat.com

On Tue, May 08, 2007 at 03:24:41PM +0100, Steven Whitehouse wrote:
> > Well, I retested this code path and found that this code is still 
> > necessary  (unless I should somehow be doing this a different way).
> > Without the code, the gfs2_rindex_hold tries to add a holder,
> > but there's already a holder due to the meta_fs.  Under the right 
> > conditions, you get:
> > 
> > original: gfs2_prepare_write+0x49/0x237 [gfs2]
> > new: gfs2_rindex_hold+0x2b/0x52a [gfs2]
> 
> I agree that this change is needed, its how we've solved the same
> problem elsewhere and it looks ok to me,

OK, I see, it's because we removed the ability for a process to have two
holders on the same glock from gfs2.  I'm assuming that the glock taken
for writing is released after inplace_release().

Dave



^ permalink raw reply	[flat|nested] 14+ messages in thread
* [Cluster-devel] [PATCH] GFS2: kernel changes to support new gfs2_grow command (Try 3)
@ 2007-05-03  1:57 Robert Peterson
  2007-05-04 16:47 ` David Teigland
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Robert Peterson @ 2007-05-03  1:57 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Hi All,

This is another revision of my gfs2 kernel patch that allows 
gfs2_grow to function properly.  

Steve Whitehouse expressed some concerns about the previous
patch and I restructured it based on his comments.
The previous patch was doing the statfs_change at file close time,
under its own transaction.  The current patch does the statfs_change
inside the gfs2_commit_write function, which keeps it under the
umbrella of the inode transaction.

I can't call ri_update to re-read the rindex file during the 
transaction because the transaction may have outstanding unwritten
buffers attached to the rgrps that would be otherwise blown away.
So instead, I created a new function, gfs2_ri_total, that will
re-read the rindex file just to total the file system space
for the sake of the statfs_change.  The ri_update will happen
later, when gfs2 realizes the version number has changed, as it
happened before my patch.

Since the statfs_change is happening at write_commit time and there
may be multiple writes to the rindex file for one grow operation.
So one consequence of this restructuring is that instead of getting
one kernel message to indicate the change, you may see several.
For example, before when you did a gfs2_grow, you'd get a single
message like:

GFS2: File system extended by 247876 blocks (968MB)

Now you get something like:

GFS2: File system extended by 207896 blocks (812MB)
GFS2: File system extended by 39980 blocks (156MB)

This version has also been successfully run against the hours-long 
"gfs2_fsck_hellfire" test that does several gfs2_grow and gfs2_fsck
while interjecting file system damage.  It does this repeatedly
under a variety Resource Group conditions.  

Regards,

Bob Peterson
Red Hat Cluster Suite

Signed-off-By: Bob Peterson <rpeterso@redhat.com>
-- 
 fs/gfs2/ops_address.c |   39 +++++++++++++++++-
 fs/gfs2/ops_address.h |    5 ++-
 fs/gfs2/rgrp.c        |  106 ++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 129 insertions(+), 21 deletions(-)

diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 30c1562..41f153d 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -450,6 +450,40 @@ out_uninit:
 }
 
 /**
+ * adjust_fs_space - Adjusts the free space available due to gfs2_grow
+ * @inode: the rindex inode
+ */
+static void adjust_fs_space(struct inode *inode)
+{
+	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+	struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
+	struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
+	__u64 fs_total, new_free, new_free_readable;
+	const char *stg_abbrev = " KMGTPEE";
+	int factor;
+
+	/* Total up the file system space, according to the latest rindex. */
+	fs_total = gfs2_ri_total(sdp);
+
+	spin_lock(&sdp->sd_statfs_spin);
+	if (fs_total > (m_sc->sc_total + l_sc->sc_total))
+		new_free = fs_total - (m_sc->sc_total + l_sc->sc_total);
+	else
+		new_free = 0;
+	spin_unlock(&sdp->sd_statfs_spin);
+	new_free_readable = new_free * sdp->sd_sb.sb_bsize;
+	for (factor = 0; factor < 7; factor++)
+		if (new_free_readable > 1024)
+			new_free_readable /= 1024;
+		else
+			break;
+	printk(KERN_WARNING "GFS2: File system extended by %llu "
+	       "blocks (%llu%cB)\n", new_free, new_free_readable,
+	       stg_abbrev[factor]);
+	gfs2_statfs_change(sdp, new_free, new_free, 0);
+}
+
+/**
  * gfs2_commit_write - Commit write to a file
  * @file: The file to write to
  * @page: The page containing the data
@@ -511,6 +545,9 @@ static int gfs2_commit_write(struct file *file, struct page *page,
 		di->di_size = cpu_to_be64(inode->i_size);
 	}
 
+	if (inode == sdp->sd_rindex)
+		adjust_fs_space(inode);
+
 	brelse(dibh);
 	gfs2_trans_end(sdp);
 	if (al->al_requested) {
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
index 35aaee4..d770ff3 100644
--- a/fs/gfs2/ops_address.h
+++ b/fs/gfs2/ops_address.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -18,5 +18,8 @@ extern const struct address_space_operations gfs2_file_aops;
 extern int gfs2_get_block(struct inode *inode, sector_t lblock,
 			  struct buffer_head *bh_result, int create);
 extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
+extern __u64 gfs2_ri_total(struct gfs2_sbd *sdp);
+extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
+			       s64 dinodes);
 
 #endif /* __OPS_ADDRESS_DOT_H__ */
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 1727f50..dfb997d 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
@@ -431,6 +431,38 @@ static int compute_bitstructs(struct gfs2_rgrpd *rgd)
 }
 
 /**
+ * gfs2_ri_total - Total up the file system space, according to the rindex.
+ *
+ */
+__u64 gfs2_ri_total(struct gfs2_sbd *sdp)
+{
+	__u64 total_data = 0;	
+	struct inode *inode = sdp->sd_rindex;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_rindex_host ri;
+	char buf[sizeof(struct gfs2_rindex)];
+	struct file_ra_state ra_state;
+	int error, rgrps;
+
+	mutex_lock(&sdp->sd_rindex_mutex);
+	file_ra_state_init(&ra_state, inode->i_mapping);
+	for (rgrps = 0;; rgrps++) {
+		loff_t pos = rgrps * sizeof(struct gfs2_rindex);
+
+		if (pos + sizeof(struct gfs2_rindex) >= ip->i_di.di_size)
+			break;
+		error = gfs2_internal_read(ip, &ra_state, buf, &pos,
+					   sizeof(struct gfs2_rindex));
+		if (error != sizeof(struct gfs2_rindex))
+			break;
+		gfs2_rindex_in(&ri, buf);
+		total_data += ri.ri_data;
+	}
+	mutex_unlock(&sdp->sd_rindex_mutex);
+	return total_data;
+}
+
+/**
  * gfs2_ri_update - Pull in a new resource index from the disk
  * @gl: The glock covering the rindex inode
  *
@@ -447,7 +479,12 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
 	u64 junk = ip->i_di.di_size;
 	int error;
 
-	if (do_div(junk, sizeof(struct gfs2_rindex))) {
+	/* If someone is holding the rindex file with a glock, they must
+	   be updating it, in which case we may have partial entries.
+	   In this case, we ignore the partials. */
+	if (!gfs2_glock_is_held_excl(ip->i_gl) &&
+	    !gfs2_glock_is_held_shrd(ip->i_gl) &&
+	    do_div(junk, sizeof(struct gfs2_rindex))) {
 		gfs2_consist_inode(ip);
 		return -EIO;
 	}
@@ -457,6 +494,9 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
 	file_ra_state_init(&ra_state, inode->i_mapping);
 	for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {
 		loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
+
+		if (pos + sizeof(struct gfs2_rindex) >= ip->i_di.di_size)
+			break;
 		error = gfs2_internal_read(ip, &ra_state, buf, &pos,
 					    sizeof(struct gfs2_rindex));
 		if (!error)
@@ -502,6 +542,35 @@ fail:
 }
 
 /**
+ * gfs2_check_rindex_version - Check the rindex version number and resync
+ *                        if necessary.
+ * @sdp: The GFS2 superblock
+ *
+ * This makes sure that we're using the latest copy of the resource index
+ * special file, which might have been updated if someone expanded the
+ * filesystem (via gfs2_grow utility), which adds new resource groups.
+ *
+ */
+
+static int gfs2_check_rindex_version(struct gfs2_sbd *sdp)
+{
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
+	struct gfs2_glock *gl = ip->i_gl;
+	int error = 0;
+
+	gfs2_assert(sdp, gfs2_glock_is_locked_by_me(gl));
+	/* Read new copy from disk if we don't have the latest */
+	if (sdp->sd_rindex_vn != gl->gl_vn) {
+		mutex_lock(&sdp->sd_rindex_mutex);
+		if (sdp->sd_rindex_vn != gl->gl_vn)
+			error = gfs2_ri_update(ip);
+		mutex_unlock(&sdp->sd_rindex_mutex);
+	}
+
+	return error;
+}
+
+/**
  * gfs2_rindex_hold - Grab a lock on the rindex
  * @sdp: The GFS2 superblock
  * @ri_gh: the glock holder
@@ -526,20 +595,11 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
 	int error;
 
 	error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
-	if (error)
-		return error;
-
-	/* Read new copy from disk if we don't have the latest */
-	if (sdp->sd_rindex_vn != gl->gl_vn) {
-		mutex_lock(&sdp->sd_rindex_mutex);
-		if (sdp->sd_rindex_vn != gl->gl_vn) {
-			error = gfs2_ri_update(ip);
-			if (error)
-				gfs2_glock_dq_uninit(ri_gh);
-		}
-		mutex_unlock(&sdp->sd_rindex_mutex);
+	if (!error) {
+		error = gfs2_check_rindex_version(sdp);
+		if (error)
+			gfs2_glock_dq_uninit(ri_gh);
 	}
-
 	return error;
 }
 
@@ -978,18 +1038,25 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 	struct gfs2_alloc *al = &ip->i_alloc;
-	int error;
+	int error = 0;
 
 	if (gfs2_assert_warn(sdp, al->al_requested))
 		return -EINVAL;
 
-	error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+	/* We need to hold the rindex unless the inode we're using is
+	   the rindex itself, in which case it's already held. */
+	if (ip != GFS2_I(sdp->sd_rindex))
+		error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+	else if (!sdp->sd_rgrps) /* We may not have the rindex read in, so: */
+		error = gfs2_check_rindex_version(sdp);
+
 	if (error)
 		return error;
 
 	error = get_local_rgrp(ip);
 	if (error) {
-		gfs2_glock_dq_uninit(&al->al_ri_gh);
+		if (ip != GFS2_I(sdp->sd_rindex))
+			gfs2_glock_dq_uninit(&al->al_ri_gh);
 		return error;
 	}
 
@@ -1019,7 +1086,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
 
 	al->al_rgd = NULL;
 	gfs2_glock_dq_uninit(&al->al_rgd_gh);
-	gfs2_glock_dq_uninit(&al->al_ri_gh);
+	if (ip != GFS2_I(sdp->sd_rindex))
+		gfs2_glock_dq_uninit(&al->al_ri_gh);
 }
 
 /**



^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2007-05-08 20:43 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-08 20:43 [Cluster-devel] [PATCH] GFS2: kernel changes to support new gfs2_grow command (Try 3) David Teigland
  -- strict thread matches above, loose matches on Subject: below --
2007-05-08 20:42 David Teigland
2007-05-03  1:57 Robert Peterson
2007-05-04 16:47 ` David Teigland
2007-05-04 21:35   ` Robert Peterson
2007-05-04 22:16     ` David Teigland
2007-05-04 19:37 ` David Teigland
2007-05-04 21:37   ` Robert Peterson
2007-05-08 14:56   ` Robert Peterson
2007-05-04 20:23 ` David Teigland
2007-05-04 21:48   ` Robert Peterson
2007-05-04 22:04     ` David Teigland
2007-05-08 14:17     ` Robert Peterson
2007-05-08 14:24       ` Steven Whitehouse

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).