cluster: RHEL56 - gfs2_convert: gfs2_convert doesn't convert indirectly-pointed extended attributes correctly

Abhijith Das adas at fedoraproject.org
Fri Apr 30 15:49:14 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=4e102cbef05a8d57b063b56346ca439cd580c924
Commit:        4e102cbef05a8d57b063b56346ca439cd580c924
Parent:        7a9640a8e3c1c3430f5705affdc38772f0f4a1ab
Author:        Abhijith Das <adas at redhat.com>
AuthorDate:    Fri Apr 30 10:47:09 2010 -0500
Committer:     Abhijith Das <adas at redhat.com>
CommitterDate: Fri Apr 30 10:47:09 2010 -0500

gfs2_convert: gfs2_convert doesn't convert indirectly-pointed extended attributes correctly

When the extended attributes for a file don't fit
in one fs block, the dinode->di_eattr block becomes
an indirect block that contains pointers to blocks
that actually contain the xattrs. The gfs1 indirect
block header is different (larger) than that of gfs2
and this causes an incorrect conversion. The
resulting gfs2 filesystem cannot display the xattrs
because of leading nulls in the indirect block. This
patch adjusts this correctly.

Resolves: rhbz#576040
Signed-off-by: Abhi Das <adas at redhat.com>
---
 gfs2/convert/gfs2_convert.c |   45 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 0379d33..f28aac4 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -948,6 +948,45 @@ static int fix_cdpn_symlink(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, s
 
 	return ret;
 }
+
+/*
+ * fix_xattr -
+ * Extended attributes can be either direct (in the ip->i_di.di_eattr block) or
+ * then can be at a maximum of 1 indirect level. Multiple levels of indirection
+ * are not supported. If the di_eattr block contains extended attribute data,
+ * i.e block type = GFS_METATYPE_EA, we ignore it.
+ * If the di_eattr block contains block pointers to extended attributes we need
+ * to fix the header. gfs1 uses gfs_indirect as the header which is 64 bytes
+ * bigger than gfs2_meta_header that gfs2 uses.
+ */
+static int fix_xattr(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct gfs2_inode *ip)
+{
+	int ret = 0, len, old_hdr_sz, new_hdr_sz;
+	struct gfs2_buffer_head *eabh;
+	char *buf;
+
+	/* Read in the i_di.di_eattr block */
+	eabh = bread(sbp, ip->i_di.di_eattr);
+        if (!gfs2_check_meta(eabh, GFS_METATYPE_IN)) {/* if it is an indirect block */
+		len = sbp->bsize - sizeof(struct gfs_indirect);
+		buf = malloc(len);
+		if (!buf) {
+			log_crit("Error: out of memory.\n");
+			return -1;
+		}
+		old_hdr_sz = sizeof(struct gfs_indirect);
+		new_hdr_sz = sizeof(struct gfs2_meta_header);
+		memcpy(buf, eabh->b_data + old_hdr_sz, sbp->bsize - old_hdr_sz);
+		memset(eabh->b_data + new_hdr_sz, 0, sbp->bsize - new_hdr_sz);
+		memcpy(eabh->b_data + new_hdr_sz, buf, len);
+		free(buf);
+		bmodified(eabh);
+	}
+        brelse(eabh);
+
+	return ret;
+}
+
 /* ------------------------------------------------------------------------- */
 /* adjust_inode - change an inode from gfs1 to gfs2                          */
 /*                                                                           */
@@ -1039,6 +1078,12 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
 			if (ret)
 				return -1;
 		}
+		/* Check for extended attributes */
+		if (inode->i_di.di_eattr) {
+			ret = fix_xattr(sbp, bh, inode);
+			if (ret)
+				return -1;
+		}
 	}
 	
 	bmodified(inode->i_bh);


More information about the cluster-commits mailing list