From: Robert S Peterson <rpeterso@redhat.com> Date: Fri, 1 Oct 2010 13:28:37 -0400 Subject: [fs] gfs2: fix fatal filesystem consistency error Message-id: <299895110.226651285939717540.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com> Patchwork-id: 28533 O-Subject: [RHEL5.6 PATCH TRY #2] GFS2 fatal: filesystem consistency error - bz #529914 Bugzilla: 529914 RH-Acked-by: Steven Whitehouse <swhiteho@redhat.com> RH-Acked-by: Benjamin Marzinski <bmarzins@redhat.com> RH-Acked-by: Abhijith Das <adas@redhat.com> Hi, Based on feedback from Steve Whitehouse, I have reworked this patch. This is the revised patch: This patch fixes a bug whereby a rename operation shortly after mount of a GFS2 file system caused the file system to withdraw from the mount and flag a consistency error. This is a kludge that circumvents the problem for 5.6, but for upstream I am planning a more proper fix that will be more of a design change, and therefore beyond the scope and time-frame of 5.6. The upstream and RHEL6 patch will be tracked with bug #638657. The code was tested on system roth-02 with a scenario that reliably recreated the problem before the patch. This fixes bug #529914. Regards, Bob Peterson Red Hat GFS Signed-off-by: Bob Peterson <rpeterso@redhat.com> -- fs/gfs2/ops_inode.c | 11 ++++++++--- fs/gfs2/rgrp.c | 22 +++++++++++++--------- fs/gfs2/rgrp.h | 6 ++++-- 3 files changed, 25 insertions(+), 14 deletions(-) Signed-off-by: Jarod Wilson <jarod@redhat.com> diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 585f330..7b4613f 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -607,7 +607,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct gfs2_inode *ip = GFS2_I(odentry->d_inode); struct gfs2_inode *nip = NULL; struct gfs2_sbd *sdp = GFS2_SB(odir); - struct gfs2_holder ghs[5], r_gh; + struct gfs2_holder ghs[5], r_gh, ri_gh; struct gfs2_rgrpd *nrgd; unsigned int num_gh; int dir_rename = 0; @@ -621,7 +621,11 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, return 0; } - /* Make sure we aren't trying to move a dirctory into it's subdir */ + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + return error; + + /* Make sure we aren't trying to move a directory into its subdir */ if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) { dir_rename = 1; @@ -749,7 +753,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, al->al_requested = sdp->sd_max_dirres; - error = gfs2_inplace_reserve(ndip); + error = gfs2_inplace_reserve_ri(ndip); if (error) goto out_gunlock_q; @@ -834,6 +838,7 @@ out_gunlock_r: if (dir_rename) gfs2_glock_dq_uninit(&r_gh); out: + gfs2_glock_dq_uninit(&ri_gh); return error; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index ca2800e..8da06d7 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1201,7 +1201,8 @@ out: * Returns: errno */ -int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) +int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, + char *file, unsigned int line) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = ip->i_alloc; @@ -1212,12 +1213,15 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) return -EINVAL; try_again: - /* 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_ri_update_special(ip); + if (hold_rindex) { + /* 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_ri_update_special(ip); + } if (error) return error; @@ -1228,7 +1232,7 @@ try_again: try to free it, and try the allocation again. */ error = get_local_rgrp(ip, &unlinked, &last_unlinked); if (error) { - if (ip != GFS2_I(sdp->sd_rindex)) + if (hold_rindex && ip != GFS2_I(sdp->sd_rindex)) gfs2_glock_dq_uninit(&al->al_ri_gh); if (error != -EAGAIN) return error; @@ -1270,7 +1274,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip) al->al_rgd = NULL; if (al->al_rgd_gh.gh_gl) gfs2_glock_dq_uninit(&al->al_rgd_gh); - if (ip != GFS2_I(sdp->sd_rindex)) + if (ip != GFS2_I(sdp->sd_rindex) && al->al_ri_gh.gh_gl) gfs2_glock_dq_uninit(&al->al_ri_gh); } diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 83a4554..56c266f 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -37,10 +37,12 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip) ip->i_alloc = NULL; } -int gfs2_inplace_reserve_i(struct gfs2_inode *ip, +int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, char *file, unsigned int line); #define gfs2_inplace_reserve(ip) \ -gfs2_inplace_reserve_i((ip), __FILE__, __LINE__) + gfs2_inplace_reserve_i((ip), 1, __FILE__, __LINE__) +#define gfs2_inplace_reserve_ri(ip) \ + gfs2_inplace_reserve_i((ip), 0, __FILE__, __LINE__) void gfs2_inplace_release(struct gfs2_inode *ip);