aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorRussell Cattelan <cattelan@redhat.com>2007-01-29 18:13:44 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2007-02-05 13:38:17 -0500
commitddee76089cc9bcbd8ae9ec6c26e726a8ab2fe675 (patch)
treecf08d003789a2be0f109d3d5f255137fd36360f5 /fs/gfs2/inode.c
parent61be084efcc4451934257350281962595418a33c (diff)
[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:
280 return error; 280 return error;
281} 281}
282 282
283static int gfs2_change_nlink_i(struct gfs2_inode *ip)
284{
285 struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
286 struct gfs2_inode *rindex = GFS2_I(sdp->sd_rindex);
287 struct gfs2_glock *ri_gl = rindex->i_gl;
288 struct gfs2_rgrpd *rgd;
289 struct gfs2_holder ri_gh, rg_gh;
290 int existing, error;
291
292 /* if we come from rename path, we could have the lock already */
293 existing = gfs2_glock_is_locked_by_me(ri_gl);
294 if (!existing) {
295 error = gfs2_rindex_hold(sdp, &ri_gh);
296 if (error)
297 goto out;
298 }
299
300 /* find the matching rgd */
301 error = -EIO;
302 rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
303 if (!rgd)
304 goto out_norgrp;
305
306 /*
307 * Eventually we may want to move rgd(s) to a linked list
308 * and piggyback the free logic into one of gfs2 daemons
309 * to gain some performance.
310 */
311 if (!rgd->rd_gl || !gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
312 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
313 if (error)
314 goto out_norgrp;
315
316 gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
317 gfs2_glock_dq_uninit(&rg_gh);
318 }
319
320out_norgrp:
321 if (!existing)
322 gfs2_glock_dq_uninit(&ri_gh);
323out:
324 return error;
325}
326
327/** 283/**
328 * gfs2_change_nlink - Change nlink count on inode 284 * gfs2_change_nlink - Change nlink count on inode
329 * @ip: The GFS2 inode 285 * @ip: The GFS2 inode
@@ -365,7 +321,7 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
365 mark_inode_dirty(&ip->i_inode); 321 mark_inode_dirty(&ip->i_inode);
366 322
367 if (ip->i_inode.i_nlink == 0) 323 if (ip->i_inode.i_nlink == 0)
368 error = gfs2_change_nlink_i(ip); 324 gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
369 325
370 return error; 326 return error;
371} 327}