Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=292c8c14cace19c94c6abe25506310239daf949e
Commit:     292c8c14cace19c94c6abe25506310239daf949e
Parent:     c97bfe4351771675963e02f34d31e206fd2d7150
Author:     Abhijith Das <[EMAIL PROTECTED]>
AuthorDate: Thu Nov 29 14:13:54 2007 -0600
Committer:  Steven Whitehouse <[EMAIL PROTECTED]>
CommitDate: Fri Jan 25 08:08:18 2008 +0000

    [GFS2] patch to check for recursive lock requests in gfs2_rename code path
    
    A certain scenario in the rename code path triggers a kernel BUG()
    because it accidentally does recursive locking The first lock is
    requested to unlink an already existing inode (replacing a file) and the
    second lock is requested when the destination directory needs to alloc
    some space. It is rare that these two
    events happen during the same rename call, and even more rare that these
    two instances try to lock the same rgrp. It is, however, possible.
    https://bugzilla.redhat.com/show_bug.cgi?id=404711
    
    Signed-off-by: Abhijith Das <[EMAIL PROTECTED]>
    Signed-off-by: Steven Whitehouse <[EMAIL PROTECTED]>
---
 fs/gfs2/rgrp.c |   33 +++++++++++++++++++++++++--------
 1 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 09848aa..e0ee195 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -1063,22 +1063,30 @@ static struct inode *get_local_rgrp(struct gfs2_inode 
*ip, u64 *last_unlinked)
        int flags = LM_FLAG_TRY;
        int skipped = 0;
        int loops = 0;
-       int error;
+       int error, rg_locked;
 
        /* Try recently successful rgrps */
 
        rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
 
        while (rgd) {
-               error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
-                                          LM_FLAG_TRY, &al->al_rgd_gh);
+               rg_locked = 0;
+
+               if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
+                       rg_locked = 1;
+                       error = 0;
+               } else {
+                       error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
+                                                  LM_FLAG_TRY, &al->al_rgd_gh);
+               }
                switch (error) {
                case 0:
                        if (try_rgrp_fit(rgd, al))
                                goto out;
                        if (rgd->rd_flags & GFS2_RDF_CHECK)
                                inode = try_rgrp_unlink(rgd, last_unlinked);
-                       gfs2_glock_dq_uninit(&al->al_rgd_gh);
+                       if (!rg_locked)
+                               gfs2_glock_dq_uninit(&al->al_rgd_gh);
                        if (inode)
                                return inode;
                        rgd = recent_rgrp_next(rgd, 1);
@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode 
*ip, u64 *last_unlinked)
        begin = rgd = forward_rgrp_get(sdp);
 
        for (;;) {
-               error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
-                                         &al->al_rgd_gh);
+               rg_locked = 0;
+
+               if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
+                       rg_locked = 1;
+                       error = 0;
+               } else {
+                       error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 
flags,
+                                                  &al->al_rgd_gh);
+               }
                switch (error) {
                case 0:
                        if (try_rgrp_fit(rgd, al))
                                goto out;
                        if (rgd->rd_flags & GFS2_RDF_CHECK)
                                inode = try_rgrp_unlink(rgd, last_unlinked);
-                       gfs2_glock_dq_uninit(&al->al_rgd_gh);
+                       if (!rg_locked)
+                               gfs2_glock_dq_uninit(&al->al_rgd_gh);
                        if (inode)
                                return inode;
                        break;
@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
                             al->al_line);
 
        al->al_rgd = NULL;
-       gfs2_glock_dq_uninit(&al->al_rgd_gh);
+       if (al->al_rgd_gh.gh_gl)
+               gfs2_glock_dq_uninit(&al->al_rgd_gh);
        if (ip != GFS2_I(sdp->sd_rindex))
                gfs2_glock_dq_uninit(&al->al_ri_gh);
 }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to