cluster: RHEL55 - GFS kernel panic, suid + nfsd with posix ACLs enabled

Bob Peterson rpeterso at fedoraproject.org
Mon Dec 7 19:10:14 UTC 2009


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=a07e555da106a5cbc72302c822971a67661eccba
Commit:        a07e555da106a5cbc72302c822971a67661eccba
Parent:        6a5f12eea4e117b3ed50016e737fc4847ccbd634
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Mon Dec 7 12:28:11 2009 -0600
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Mon Dec 7 12:28:11 2009 -0600

GFS kernel panic, suid + nfsd with posix ACLs enabled

This patch ensures that the transaction started to do the write
has enough spare blocks that it can do the eattr changes.  It
also prevents a situation where two transactions were started.

rhbz#513885
---
 gfs-kernel/src/gfs/eattr.c    |  107 ++++++++++++++++++++---------------------
 gfs-kernel/src/gfs/ops_file.c |    5 +-
 2 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/gfs-kernel/src/gfs/eattr.c b/gfs-kernel/src/gfs/eattr.c
index 8024262..57de82b 100644
--- a/gfs-kernel/src/gfs/eattr.c
+++ b/gfs-kernel/src/gfs/eattr.c
@@ -1559,56 +1559,49 @@ gfs_ea_remove(struct gfs_inode *ip, struct gfs_ea_request *er)
  * Returns: errno
  */
 
-int
-gfs_ea_acl_init(struct gfs_inode *ip, struct gfs_ea_request *er)
+int gfs_ea_acl_init(struct gfs_inode *ip, struct gfs_ea_request *er)
 {
+	struct buffer_head *bh;
+	struct gfs_ea_header *ea;
+	unsigned int size;
+	struct buffer_head *dibh;
 	int error;
 
 	if (!ip->i_di.di_eattr)
 		return ea_init_i(ip, er, NULL);
 
-	{
-		struct buffer_head *bh;
-		struct gfs_ea_header *ea;
-		unsigned int size;
-
-		ea_calc_size(ip->i_sbd, er, &size);
+	ea_calc_size(ip->i_sbd, er, &size);
 
-		error = gfs_dread(ip->i_gl, ip->i_di.di_eattr,
+	error = gfs_dread(ip->i_gl, ip->i_di.di_eattr,
 				  DIO_START | DIO_WAIT, &bh);
-		if (error)
-			return error;
-
-		if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_EA)) {
-			brelse(bh);
-			return -EIO;
-		}
+	if (error)
+		return error;
 
-		ea = GFS_EA_BH2FIRST(bh);
-		if (GFS_EA_REC_LEN(ea) - GFS_EA_SIZE(ea) >= size) {
-			ea = ea_split_ea(ea);
-			ea_write(ip, ea, er);
-			brelse(bh);
-			return 0;
-		}
+	if (gfs_metatype_check(ip->i_sbd, bh, GFS_METATYPE_EA)) {
+		brelse(bh);
+		return -EIO;
+	}
 
+	ea = GFS_EA_BH2FIRST(bh);
+	if (GFS_EA_REC_LEN(ea) - GFS_EA_SIZE(ea) >= size) {
+		ea = ea_split_ea(ea);
+		ea_write(ip, ea, er);
 		brelse(bh);
+		return 0;
 	}
 
+	brelse(bh);
+
 	error = ea_set_block(ip, er, NULL);
 	gfs_assert_withdraw(ip->i_sbd, error != -ENOSPC);
 	if (error)
 		return error;
 
-	{
-		struct buffer_head *dibh;
-		error = gfs_get_inode_buffer(ip, &dibh);
-		if (error)
-			return error;
-		gfs_dinode_out(&ip->i_di, dibh->b_data);
-		brelse(dibh);
-	}
-
+	error = gfs_get_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+	gfs_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
 	return error;
 }
 
@@ -1621,10 +1614,9 @@ gfs_ea_acl_init(struct gfs_inode *ip, struct gfs_ea_request *er)
  * Returns: errno
  */
 
-static int
-ea_acl_chmod_unstuffed(struct gfs_inode *ip,
-		       struct gfs_ea_header *ea,
-		       char *data)
+static int ea_acl_chmod_unstuffed(struct gfs_inode *ip,
+				  struct gfs_ea_header *ea, char *data,
+				  int *trans)
 {
 	struct gfs_sbd *sdp = ip->i_sbd;
 	struct buffer_head **bh;
@@ -1638,9 +1630,12 @@ ea_acl_chmod_unstuffed(struct gfs_inode *ip,
 	if (!bh)
 		return -ENOMEM;
 
-	error = gfs_trans_begin(sdp, 1 + nptrs, 0);
-	if (error)
-		goto out;
+	if (get_transaction == NULL) {
+		error = gfs_trans_begin(sdp, 1 + nptrs, 0);
+		if (error)
+			goto out;
+		*trans = 1;
+	}
 
 	for (x = 0; x < nptrs; x++) {
 		error = gfs_dread(ip->i_gl, gfs64_to_cpu(*dataptrs),
@@ -1680,15 +1675,14 @@ ea_acl_chmod_unstuffed(struct gfs_inode *ip,
 		brelse(bh[x]);
 	}
 
- out:
+out:
 	kfree(bh);
-
 	return error;
 
- fail:
+fail:
 	gfs_trans_end(sdp);
+	*trans = 0;
 	kfree(bh);
-
 	return error;
 }
 
@@ -1702,24 +1696,28 @@ ea_acl_chmod_unstuffed(struct gfs_inode *ip,
  * Returns: errno
  */
 
-int
-gfs_ea_acl_chmod(struct gfs_inode *ip, struct gfs_ea_location *el,
-		 struct iattr *attr, char *data)
+int gfs_ea_acl_chmod(struct gfs_inode *ip, struct gfs_ea_location *el,
+		     struct iattr *attr, char *data)
 {
+	struct gfs_sbd *sdp = ip->i_sbd;
 	struct buffer_head *dibh;
 	int error;
+	int trans = 0;
 
 	if (GFS_EA_IS_STUFFED(el->el_ea)) {
-		error = gfs_trans_begin(ip->i_sbd, 2, 0);
-		if (error)
-			return error;
+		if (get_transaction == NULL) {
+			error = gfs_trans_begin(ip->i_sbd, 2, 0);
+			if (error)
+				return error;
+			trans = 1;
+		}
 
 		gfs_trans_add_bh(ip->i_gl, el->el_bh);
-		memcpy(GFS_EA2DATA(el->el_ea),
-		       data,
+		memcpy(GFS_EA2DATA(el->el_ea), data,
 		       GFS_EA_DATA_LEN(el->el_ea));
-	} else
-		error = ea_acl_chmod_unstuffed(ip, el->el_ea, data);
+	} else {
+		error = ea_acl_chmod_unstuffed(ip, el->el_ea, data, &trans);
+	}
 
 	if (error)
 		return error;
@@ -1734,7 +1732,8 @@ gfs_ea_acl_chmod(struct gfs_inode *ip, struct gfs_ea_location *el,
 		brelse(dibh);
 	}
 
-	gfs_trans_end(ip->i_sbd);
+	if (trans)
+		gfs_trans_end(ip->i_sbd);
 
 	return error;
 }
diff --git a/gfs-kernel/src/gfs/ops_file.c b/gfs-kernel/src/gfs/ops_file.c
index bd68583..148fb67 100644
--- a/gfs-kernel/src/gfs/ops_file.c
+++ b/gfs-kernel/src/gfs/ops_file.c
@@ -800,6 +800,7 @@ do_do_write_buf(struct file *file, char *buf, size_t size, loff_t *offset,
 	int alloc_required, journaled;
 	ssize_t count;
 	int error;
+	unsigned int posix = sdp->sd_args.ar_posix_acls ? 4 : 0;
 
 	journaled = gfs_is_jdata(ip);
 
@@ -837,7 +838,7 @@ do_do_write_buf(struct file *file, char *buf, size_t size, loff_t *offset,
 
 		error = gfs_trans_begin(sdp,
 					1 + al->al_rgd->rd_ri.ri_length +
-					ind_blocks +
+					ind_blocks + posix +
 					((journaled) ? data_blocks : 0), 1);
 		if (error)
 			goto fail_ipres;
@@ -845,7 +846,7 @@ do_do_write_buf(struct file *file, char *buf, size_t size, loff_t *offset,
 		/* Trans may require:
 		   A modified dinode. */
 
-		error = gfs_trans_begin(sdp,
+		error = gfs_trans_begin(sdp, posix +
 					1 + ((journaled) ? data_blocks : 0), 0);
 		if (error)
 			goto fail_ipres;


More information about the cluster-commits mailing list