cluster: STABLE3 - gfs2_convert: Doesn't convert indirectly-pointed extended attributes correctly

Abhijith Das adas at fedoraproject.org
Wed Apr 7 17:08:24 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=e5e6b8a3620349e57dc1264dff3c0c613994c5fd
Commit:        e5e6b8a3620349e57dc1264dff3c0c613994c5fd
Parent:        410bdc8b5f565d26ffd8c26ce8b6b9393704bb72
Author:        Abhijith Das <adas at redhat.com>
AuthorDate:    Wed Apr 7 12:04:34 2010 -0500
Committer:     Abhijith Das <adas at redhat.com>
CommitterDate: Wed Apr 7 12:04:34 2010 -0500

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#579626
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 a3e57fd..6543903 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -937,6 +937,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                          */
 /*                                                                           */
@@ -1028,6 +1067,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