summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorRussell Cattelan <cattelan@redhat.com>2007-01-29 17:13:44 -0600
committerSteven Whitehouse <swhiteho@redhat.com>2007-02-05 13:38:17 -0500
commitddee76089cc9bcbd8ae9ec6c26e726a8ab2fe675 (patch)
treecf08d003789a2be0f109d3d5f255137fd36360f5 /fs/gfs2/inode.c
parent61be084efcc4451934257350281962595418a33c (diff)
downloadlinux-ddee76089cc9bcbd8ae9ec6c26e726a8ab2fe675.tar.bz2
[GFS2] Fix unlink deadlocks
Move the glock acquisition to outside of the transactions. Lock odering must be preserved in order to prevent ABBA deadlocks. The current gfs2_change_nlink code would tries to grab the glock after having started a transaction and thus is holding the log lock. This is inconsistent with other code paths in gfs that grab the resource group glock prior to staring a tranactions. One problem with this fix is that the resource group lock is always grabbed now even if the inode still has ref count and can not be marked for unlink. Signed-off-by: Russell Cattelan <cattelan@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r--fs/gfs2/inode.c46
1 files changed, 1 insertions, 45 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 88fcfb4f5c4d..0d6831a40565 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -280,50 +280,6 @@ out:
return error;
}
-static int gfs2_change_nlink_i(struct gfs2_inode *ip)
-{
- struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
- 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;
- }
-
- /* 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;
-}
-
/**
* gfs2_change_nlink - Change nlink count on inode
* @ip: The GFS2 inode
@@ -365,7 +321,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
mark_inode_dirty(&ip->i_inode);
if (ip->i_inode.i_nlink == 0)
- error = gfs2_change_nlink_i(ip);
+ gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
return error;
}