Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1299

kernel-2.6.18-238.el5.src.rpm

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;