diff options
author | S. Wendy Cheng <wcheng@redhat.com> | 2007-01-18 15:56:34 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2007-02-05 13:36:15 -0500 |
commit | 5509826f1e548d14bb888c1cb6e3bbf23f855770 (patch) | |
tree | 20915fb965f5895f3a41361bdb6182ae10db242c /fs/gfs2/ops_inode.c | |
parent | e1d5b18ae92d0bbfe66dc2b4bab65006d32c5f7d (diff) |
[GFS2] Fix change nlink deadlock
Bugzilla 215088
Fix deadlock in gfs2_change_nlink() while installing RHEL5 into GFS2
partition. The gfs2_rename() apparently needs block allocation for the
new name (into the directory) where it requires rg locks. At the same
time, while updating the nlink count for the replaced file,
gfs2_change_nlink() tries to return the inode meta-data back to resource
group where it needs rg locks too. Our logic doesn't allow process to
acquire these locks recursively by the same process (RHEL installer)
that results a BUG call. This only happens within rename code path and
only if the destination file exists before the rename operation.
Signed-off-by: S. Wendy Cheng <wcheng@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_inode.c')
-rw-r--r-- | fs/gfs2/ops_inode.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 636dda4c7d38..919e8947e710 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -553,6 +553,7 @@ 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; | ||
556 | 557 | ||
557 | if (ndentry->d_inode) { | 558 | if (ndentry->d_inode) { |
558 | nip = GFS2_I(ndentry->d_inode); | 559 | nip = GFS2_I(ndentry->d_inode); |
@@ -684,12 +685,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
684 | error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + | 685 | error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + |
685 | al->al_rgd->rd_ri.ri_length + | 686 | al->al_rgd->rd_ri.ri_length + |
686 | 4 * RES_DINODE + 4 * RES_LEAF + | 687 | 4 * RES_DINODE + 4 * RES_LEAF + |
687 | RES_STATFS + RES_QUOTA, 0); | 688 | RES_STATFS + RES_QUOTA + 1, 0); |
688 | if (error) | 689 | if (error) |
689 | goto out_ipreserv; | 690 | goto out_ipreserv; |
690 | } else { | 691 | } else { |
691 | error = gfs2_trans_begin(sdp, 4 * RES_DINODE + | 692 | error = gfs2_trans_begin(sdp, 4 * RES_DINODE + |
692 | 5 * RES_LEAF, 0); | 693 | 5 * RES_LEAF + 1, 0); |
693 | if (error) | 694 | if (error) |
694 | goto out_gunlock; | 695 | goto out_gunlock; |
695 | } | 696 | } |
@@ -703,7 +704,25 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
703 | error = gfs2_dir_del(ndip, &ndentry->d_name); | 704 | error = gfs2_dir_del(ndip, &ndentry->d_name); |
704 | if (error) | 705 | if (error) |
705 | goto out_end_trans; | 706 | goto out_end_trans; |
706 | error = gfs2_change_nlink(nip, -1); | 707 | error = gfs2_change_nlink_i(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 | } | ||
707 | } | 726 | } |
708 | if (error) | 727 | if (error) |
709 | goto out_end_trans; | 728 | goto out_end_trans; |