From: Steven Whitehouse <swhiteho@redhat.com> Date: Wed, 9 Dec 2009 14:11:59 -0500 Subject: [gfs2] fix rename locking issue Message-id: <1260367919.14393.38.camel@localhost.localdomain> Patchwork-id: 21821 O-Subject: [RHEL 5.5] GFS2: Fix rename locking issue (bz #538484) Bugzilla: 538484 RH-Acked-by: Robert S Peterson <rpeterso@redhat.com> This patch fixes a bug relating to locking order in rename. The problem was that the check for whether an allocation would be required in order to insert a new directory entry was being carried out in all cases. If the rename resulted in an inode being unlinked then (i) we know that there is enough space in the directory since we are about to free some space and (ii) we therefore don't ever need to allocate any blocks so we don't need the resource group lock. This fixes (a very tricky to reproduce) issue where the an inode was being unlinked as a result of a rename, and due to the directory being full at the time that the time at which we did the gfs2_diradd_alloc_required() it returned true, and that the rgrp which was later locked during the reservation phase happened to be the same rgrp in which the inode to be unlinked was sitting. The person who hit this has tried this patch and been running with it for a week with no further problems. The same patch will be added to the upstream GFS2 -fixes tree shortly. This fixes bz: #538484 Signed-off-by: Don Zickus <dzickus@redhat.com> diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 5c4243d..585f330 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -611,7 +611,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct gfs2_rgrpd *nrgd; unsigned int num_gh; int dir_rename = 0; - int alloc_required; + int alloc_required = 0; unsigned int x; int error; @@ -729,7 +729,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_gunlock; } - alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); + if (nip == NULL) + alloc_required = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); + error = alloc_required; if (error < 0) goto out_gunlock; error = 0;