Gitweb:
http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 3ec446ad397ab64d614e5f5a5cbca81f548cd78d
Parent: 56b6aa902c70fcdc78edf58352d850f62f1e67be
Author: Abhijith Das <adas(a)redhat.com>
AuthorDate: Wed Apr 7 12:04:34 2010 -0500
Committer: Abhijith Das <adas(a)redhat.com>
CommitterDate: Tue Apr 20 10:37:16 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(a)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 324342d..3f72b51 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -941,6 +941,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 */
/* */
@@ -1032,6 +1071,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);