aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorS. Wendy Cheng <wcheng@redhat.com>2007-01-18 16:07:03 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2007-02-05 13:36:31 -0500
commit87d21e07f3880b8d489f0b4a639deb1362101838 (patch)
tree20b41fc6dad45363b81a9e44daf5b278f532f183
parent6c93fd1e578669364e026a0d44c669b871e2a8c4 (diff)
[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>
-rw-r--r--fs/gfs2/inode.c50
-rw-r--r--fs/gfs2/inode.h2
-rw-r--r--fs/gfs2/ops_inode.c25
3 files changed, 35 insertions, 42 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:
281} 281}
282 282
283/** 283/**
284 * gfs2_change_nlink_i - Change nlink count on inode 284 * gfs2_change_nlink - Change nlink count on inode
285 * @ip: The GFS2 inode 285 * @ip: The GFS2 inode
286 * @diff: The change in the nlink count required 286 * @diff: The change in the nlink count required
287 * 287 *
288 * Returns: errno 288 * Returns: errno
289 */ 289 */
290int gfs2_change_nlink_i(struct gfs2_inode *ip, int diff) 290int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
291{ 291{
292 struct buffer_head *dibh; 292 struct buffer_head *dibh;
293 u32 nlink; 293 u32 nlink;
@@ -320,40 +320,52 @@ int gfs2_change_nlink_i(struct gfs2_inode *ip, int diff)
320 brelse(dibh); 320 brelse(dibh);
321 mark_inode_dirty(&ip->i_inode); 321 mark_inode_dirty(&ip->i_inode);
322 322
323 if (ip->i_inode.i_nlink == 0)
324 error = gfs2_change_nlink_i(ip);
325
323 return error; 326 return error;
324} 327}
325 328
326int gfs2_change_nlink(struct gfs2_inode *ip, int diff) 329int gfs2_change_nlink_i(struct gfs2_inode *ip)
327{ 330{
328 struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info; 331 struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
329 int error; 332 struct gfs2_inode *rindex = GFS2_I(sdp->sd_rindex);
330 333 struct gfs2_glock *ri_gl = rindex->i_gl;
331 /* update the nlink */ 334 struct gfs2_rgrpd *rgd;
332 error = gfs2_change_nlink_i(ip, diff); 335 struct gfs2_holder ri_gh, rg_gh;
333 if (error) 336 int existing, error;
334 return error;
335
336 /* return meta data block back to rg */
337 if (ip->i_inode.i_nlink == 0) {
338 struct gfs2_rgrpd *rgd;
339 struct gfs2_holder ri_gh, rg_gh;
340 337
338 /* if we come from rename path, we could have the lock already */
339 existing = gfs2_glock_is_locked_by_me(ri_gl);
340 if (!existing) {
341 error = gfs2_rindex_hold(sdp, &ri_gh); 341 error = gfs2_rindex_hold(sdp, &ri_gh);
342 if (error) 342 if (error)
343 goto out; 343 goto out;
344 error = -EIO; 344 }
345 rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); 345
346 if (!rgd) 346 /* find the matching rgd */
347 goto out_norgrp; 347 error = -EIO;
348 rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
349 if (!rgd)
350 goto out_norgrp;
351
352 /*
353 * Eventually we may want to move rgd(s) to a linked list
354 * and piggyback the free logic into one of gfs2 daemons
355 * to gain some performance.
356 */
357 if (!rgd->rd_gl || !gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
348 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh); 358 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
349 if (error) 359 if (error)
350 goto out_norgrp; 360 goto out_norgrp;
351 361
352 gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ 362 gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
353 gfs2_glock_dq_uninit(&rg_gh); 363 gfs2_glock_dq_uninit(&rg_gh);
364 }
365
354out_norgrp: 366out_norgrp:
367 if (!existing)
355 gfs2_glock_dq_uninit(&ri_gh); 368 gfs2_glock_dq_uninit(&ri_gh);
356 }
357out: 369out:
358 return error; 370 return error;
359} 371}
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 85c67cb568d1..cee281b5326b 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -40,7 +40,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip);
40 40
41int gfs2_dinode_dealloc(struct gfs2_inode *inode); 41int gfs2_dinode_dealloc(struct gfs2_inode *inode);
42int gfs2_change_nlink(struct gfs2_inode *ip, int diff); 42int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
43int gfs2_change_nlink_i(struct gfs2_inode *ip, int diff); 43int gfs2_change_nlink_i(struct gfs2_inode *ip);
44struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, 44struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
45 int is_root, struct nameidata *nd); 45 int is_root, struct nameidata *nd);
46struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, 46struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 919e8947e710..b2a12f44f59d 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -553,7 +553,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
553 int alloc_required; 553 int alloc_required;
554 unsigned int x; 554 unsigned int x;
555 int error; 555 int error;
556 struct gfs2_rgrpd *rgd;
557 556
558 if (ndentry->d_inode) { 557 if (ndentry->d_inode) {
559 nip = GFS2_I(ndentry->d_inode); 558 nip = GFS2_I(ndentry->d_inode);
@@ -685,12 +684,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
685 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + 684 error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
686 al->al_rgd->rd_ri.ri_length + 685 al->al_rgd->rd_ri.ri_length +
687 4 * RES_DINODE + 4 * RES_LEAF + 686 4 * RES_DINODE + 4 * RES_LEAF +
688 RES_STATFS + RES_QUOTA + 1, 0); 687 RES_STATFS + RES_QUOTA + 4, 0);
689 if (error) 688 if (error)
690 goto out_ipreserv; 689 goto out_ipreserv;
691 } else { 690 } else {
692 error = gfs2_trans_begin(sdp, 4 * RES_DINODE + 691 error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
693 5 * RES_LEAF + 1, 0); 692 5 * RES_LEAF + 4, 0);
694 if (error) 693 if (error)
695 goto out_gunlock; 694 goto out_gunlock;
696 } 695 }
@@ -704,25 +703,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
704 error = gfs2_dir_del(ndip, &ndentry->d_name); 703 error = gfs2_dir_del(ndip, &ndentry->d_name);
705 if (error) 704 if (error)
706 goto out_end_trans; 705 goto out_end_trans;
707 error = gfs2_change_nlink_i(nip, -1); 706 error = gfs2_change_nlink(nip, -1);
708 if ((!error) && (nip->i_inode.i_nlink == 0)) {
709 error = -EIO;
710 rgd = gfs2_blk2rgrpd(sdp, nip->i_num.no_addr);
711 if (rgd) {
712 struct gfs2_holder nlink_rg_gh;
713 if (rgd != nip->i_alloc.al_rgd)
714 error = gfs2_glock_nq_init(
715 rgd->rd_gl, LM_ST_EXCLUSIVE,
716 0, &nlink_rg_gh);
717 else
718 error = 0;
719 if (!error) {
720 gfs2_unlink_di(&nip->i_inode);
721 if (rgd != nip->i_alloc.al_rgd)
722 gfs2_glock_dq_uninit(&nlink_rg_gh);
723 }
724 }
725 }
726 } 707 }
727 if (error) 708 if (error)
728 goto out_end_trans; 709 goto out_end_trans;