summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorS. Wendy Cheng <wcheng@redhat.com>2007-01-18 22:07:03 +0100
committerSteven Whitehouse <swhiteho@redhat.com>2007-02-05 19:36:31 +0100
commit87d21e07f3880b8d489f0b4a639deb1362101838 (patch)
tree20b41fc6dad45363b81a9e44daf5b278f532f183 /fs/gfs2/inode.c
parent[GFS2] BZ 217008 fsfuzzer fix. (diff)
downloadlinux-87d21e07f3880b8d489f0b4a639deb1362101838.tar.xz
linux-87d21e07f3880b8d489f0b4a639deb1362101838.zip
[GFS2] Fix gfs2_rename deadlock
Second round of gfs2_rename lock re-ordering to allow Anaconda adding root partition on top of gfs2. Previous to this patch the recursive lock detector in glock.c can be triggered due to attempting to lock the rgrp twice. This fixes it by checking to see whether the rgrp is already locked. This fixes Red Hat bugzilla #221237 Signed-off-by: S. Wendy Cheng <wcheng@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r--fs/gfs2/inode.c50
1 files changed, 31 insertions, 19 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index bab338f6b610..58c2ce785fed 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -281,13 +281,13 @@ out:
}
/**
- * gfs2_change_nlink_i - Change nlink count on inode
+ * gfs2_change_nlink - Change nlink count on inode
* @ip: The GFS2 inode
* @diff: The change in the nlink count required
*
* Returns: errno
*/
-int gfs2_change_nlink_i(struct gfs2_inode *ip, int diff)
+int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
{
struct buffer_head *dibh;
u32 nlink;
@@ -320,40 +320,52 @@ int gfs2_change_nlink_i(struct gfs2_inode *ip, int diff)
brelse(dibh);
mark_inode_dirty(&ip->i_inode);
+ if (ip->i_inode.i_nlink == 0)
+ error = gfs2_change_nlink_i(ip);
+
return error;
}
-int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
+int gfs2_change_nlink_i(struct gfs2_inode *ip)
{
struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
- int error;
-
- /* update the nlink */
- error = gfs2_change_nlink_i(ip, diff);
- if (error)
- return error;
-
- /* return meta data block back to rg */
- if (ip->i_inode.i_nlink == 0) {
- struct gfs2_rgrpd *rgd;
- struct gfs2_holder ri_gh, rg_gh;
+ struct gfs2_inode *rindex = GFS2_I(sdp->sd_rindex);
+ struct gfs2_glock *ri_gl = rindex->i_gl;
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_holder ri_gh, rg_gh;
+ int existing, error;
+ /* if we come from rename path, we could have the lock already */
+ existing = gfs2_glock_is_locked_by_me(ri_gl);
+ if (!existing) {
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
goto out;
- error = -EIO;
- rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
- if (!rgd)
- goto out_norgrp;
+ }
+
+ /* find the matching rgd */
+ error = -EIO;
+ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+ if (!rgd)
+ goto out_norgrp;
+
+ /*
+ * Eventually we may want to move rgd(s) to a linked list
+ * and piggyback the free logic into one of gfs2 daemons
+ * to gain some performance.
+ */
+ if (!rgd->rd_gl || !gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
if (error)
goto out_norgrp;
gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
gfs2_glock_dq_uninit(&rg_gh);
+ }
+
out_norgrp:
+ if (!existing)
gfs2_glock_dq_uninit(&ri_gh);
- }
out:
return error;
}