[Ocfs2-tools-devel] [PATCH] libocfs2: Prevent endian swapping from scribbling over memory v2.

Joel Becker Joel.Becker at oracle.com
Wed Jun 3 16:18:36 PDT 2009


[ Fixed a missing byte limit with ocfs2_swap_inline_dir() ]

Some ocfs2 disk structures, such as our btree extent lists, are variable
in size.  They live inside another disk structure, and one of their
fields describes how big they are.  When we read the structure into RAM
and swap it to the local CPU, we rely on that field to make sure we only
swap what is necessary.

However, if that field gets corrupted, our endian swapping code will
happily keep scribbling past the end of the block buffer until it his
the corrupted limit or segfaults.  If you're lucky, it segfaults.

This change modifies all the impacted swapping functions.  They now take
the ocfs2_filesys as an argument so that they know the blocksize.  A new
function, ocfs2_swap_barrier(), is introduced.  It uses the
ocfs2_filesys and the current location in the block buffer to determine
when the swapping code is about to walk off the end.

Some of our list structures can live inside multiple containing
blocks.  Those swap functions require an additional argument, the
address of the containing object.  That way, ocfs2_swap_barrier() knows
what address to start at.

This is ocfs2 bugzilla #1109.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 debugfs.ocfs2/dump.c             |    6 +-
 debugfs.ocfs2/find_block_inode.c |    2 +-
 extras/find_dup_extents.c        |    2 +-
 fsck.ocfs2/pass1.c               |    2 +-
 include/ocfs2/ocfs2.h            |   57 ++++++++++++++---
 libocfs2/extents.c               |   31 ++++++---
 libocfs2/inode.c                 |   55 +++++++++++-----
 libocfs2/openfs.c                |    4 +-
 libocfs2/xattr.c                 |  128 ++++++++++++++++++++++++++++----------
 mkfs.ocfs2/mkfs.c                |   13 +++-
 tunefs.ocfs2/libocfs2ne.c        |    2 +-
 11 files changed, 221 insertions(+), 81 deletions(-)

diff --git a/debugfs.ocfs2/dump.c b/debugfs.ocfs2/dump.c
index 4c1157c..17f58e9 100644
--- a/debugfs.ocfs2/dump.c
+++ b/debugfs.ocfs2/dump.c
@@ -682,14 +682,14 @@ void dump_jbd_metadata (FILE *out, enum dump_block_type type, char *buf,
 	switch (type) {
 	case DUMP_BLOCK_INODE:
 		fprintf(out, "Inode\n");
-		ocfs2_swap_inode_to_cpu((struct ocfs2_dinode *)buf,
-					gbls.fs->fs_blocksize);
+		ocfs2_swap_inode_to_cpu(gbls.fs, (struct ocfs2_dinode *)buf);
 		dump_inode (out, (struct ocfs2_dinode *)buf);
 		fprintf (out, "\n");
 		break;
 	case DUMP_BLOCK_EXTENT_BLOCK:
 		fprintf(out, "Extent\n");
-		ocfs2_swap_extent_block_to_cpu((struct ocfs2_extent_block *)buf);
+		ocfs2_swap_extent_block_to_cpu(gbls.fs,
+					       (struct ocfs2_extent_block *)buf);
 		dump_extent_block (out, (struct ocfs2_extent_block *)buf);
 		fprintf (out, "\n");
 		break;
diff --git a/debugfs.ocfs2/find_block_inode.c b/debugfs.ocfs2/find_block_inode.c
index 1291afb..293ce09 100644
--- a/debugfs.ocfs2/find_block_inode.c
+++ b/debugfs.ocfs2/find_block_inode.c
@@ -378,7 +378,7 @@ errcode_t find_block_inode(ocfs2_filesys *fs, uint64_t *blkno, int count,
 			   strlen(OCFS2_INODE_SIGNATURE)))
 			continue;
 
-		ocfs2_swap_inode_to_cpu(di, fs->fs_blocksize);
+		ocfs2_swap_inode_to_cpu(fs, di);
 
 		if (di->i_fs_generation != fs->fs_super->i_fs_generation)
 			continue;
diff --git a/extras/find_dup_extents.c b/extras/find_dup_extents.c
index 9263891..1f8fdcc 100644
--- a/extras/find_dup_extents.c
+++ b/extras/find_dup_extents.c
@@ -184,7 +184,7 @@ static errcode_t run_scan(struct walk_extents *we, int test)
 				   strlen(OCFS2_INODE_SIGNATURE)))
 				continue;
 
-			ocfs2_swap_inode_to_cpu(di, we->fs->fs_blocksize);
+			ocfs2_swap_inode_to_cpu(we->fs, di);
 
 			if (!(di->i_flags & OCFS2_VALID_FL))
 				continue;
diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index 15880bc..4aeba8c 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -1377,7 +1377,7 @@ errcode_t o2fsck_pass1(o2fsck_state *ost)
 		if (!memcmp(di->i_signature, OCFS2_INODE_SIGNATURE,
 			    strlen(OCFS2_INODE_SIGNATURE))) {
 
-			ocfs2_swap_inode_to_cpu(di, fs->fs_blocksize);
+			ocfs2_swap_inode_to_cpu(fs, di);
 
 			 /* We only consider inodes whose generations don't
 			  * match if the user has asked us to */
diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 4dbbf43..fca35d7 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -251,8 +251,8 @@ errcode_t ocfs2_flush(ocfs2_filesys *fs);
 errcode_t ocfs2_close(ocfs2_filesys *fs);
 void ocfs2_freefs(ocfs2_filesys *fs);
 
-void ocfs2_swap_inode_from_cpu(struct ocfs2_dinode *di, size_t blocksize);
-void ocfs2_swap_inode_to_cpu(struct ocfs2_dinode *di, size_t blocksize);
+void ocfs2_swap_inode_from_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di);
+void ocfs2_swap_inode_to_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di);
 errcode_t ocfs2_read_inode(ocfs2_filesys *fs, uint64_t blkno,
 			   char *inode_buf);
 errcode_t ocfs2_write_inode(ocfs2_filesys *fs, uint64_t blkno,
@@ -266,8 +266,17 @@ errcode_t ocfs2_write_cached_inode(ocfs2_filesys *fs,
 errcode_t ocfs2_free_cached_inode(ocfs2_filesys *fs,
 				  ocfs2_cached_inode *cinode);
 
-void ocfs2_swap_extent_list_from_cpu(struct ocfs2_extent_list *el);
-void ocfs2_swap_extent_list_to_cpu(struct ocfs2_extent_list *el);
+/*
+ * obj is the object containing the extent list.  eg, if you are swapping
+ * an inode's extent list, you're passing 'di' for the obj and
+ * '&di->id2.i_list' for the el.  obj is needed to make sure the
+ * byte swapping code doesn't walk off the end of the buffer in the
+ * presence of corruption.
+ */
+void ocfs2_swap_extent_list_from_cpu(ocfs2_filesys *fs, void *obj,
+				     struct ocfs2_extent_list *el);
+void ocfs2_swap_extent_list_to_cpu(ocfs2_filesys *fs, void *obj,
+				   struct ocfs2_extent_list *el);
 errcode_t ocfs2_extent_map_get_blocks(ocfs2_cached_inode *cinode,
 				      uint64_t v_blkno, int count,
 				      uint64_t *p_blkno,
@@ -298,8 +307,10 @@ extern size_t ocfs2_journal_tag_bytes(journal_superblock_t *jsb);
 extern uint64_t ocfs2_journal_tag_block(journal_block_tag_t *tag,
 					size_t tag_bytes);
 
-void ocfs2_swap_extent_block_to_cpu(struct ocfs2_extent_block *eb);
-void ocfs2_swap_extent_block_from_cpu(struct ocfs2_extent_block *eb);
+void ocfs2_swap_extent_block_to_cpu(ocfs2_filesys *fs,
+				    struct ocfs2_extent_block *eb);
+void ocfs2_swap_extent_block_from_cpu(ocfs2_filesys *fs,
+				      struct ocfs2_extent_block *eb);
 errcode_t ocfs2_read_extent_block(ocfs2_filesys *fs, uint64_t blkno,
        				  char *eb_buf);
 errcode_t ocfs2_read_extent_block_nocheck(ocfs2_filesys *fs, uint64_t blkno,
@@ -974,6 +985,27 @@ static inline int ocfs2_support_xattr(struct ocfs2_super_block *osb)
 }
 
 /*
+ * When we're swapping some of our disk structures, a garbage count
+ * can send us past the edge of a block buffer.  This function guards
+ * against that.  It returns true if the element would walk off then end
+ * of the block buffer.
+ */
+static inline int ocfs2_swap_barrier(ocfs2_filesys *fs, void *block_buffer,
+				     void *element, size_t element_size)
+{
+	char *limit, *end;
+
+	limit = block_buffer;
+	limit += fs->fs_blocksize;
+
+	end = element;
+	end += element_size;
+
+	return end > limit;
+}
+
+
+/*
  * shamelessly lifted from the kernel
  *
  * min()/max() macros that also do
@@ -1098,10 +1130,15 @@ int ocfs2_xattr_find_leaf(ocfs2_filesys *fs, struct ocfs2_xattr_block *xb,
 			  uint32_t cpos, char **leaf_buf);
 uint16_t ocfs2_xattr_buckets_per_cluster(ocfs2_filesys *fs);
 uint16_t ocfs2_blocks_per_xattr_bucket(ocfs2_filesys *fs);
-void ocfs2_swap_xattrs_to_cpu(struct ocfs2_xattr_header *xh);
-void ocfs2_swap_xattrs_from_cpu(struct ocfs2_xattr_header *xh);
-void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb);
-void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb);
+/* See ocfs2_swap_extent_list() for a discussion of obj */
+void ocfs2_swap_xattrs_to_cpu(ocfs2_filesys *fs, void *obj,
+			      struct ocfs2_xattr_header *xh);
+void ocfs2_swap_xattrs_from_cpu(ocfs2_filesys *fs, void *obj,
+				struct ocfs2_xattr_header *xh);
+void ocfs2_swap_xattr_block_to_cpu(ocfs2_filesys *fs,
+				   struct ocfs2_xattr_block *xb);
+void ocfs2_swap_xattr_block_from_cpu(ocfs2_filesys *fs,
+				     struct ocfs2_xattr_block *xb);
 errcode_t ocfs2_read_xattr_block(ocfs2_filesys *fs,
 				 uint64_t blkno,
 				 char *xb_buf);
diff --git a/libocfs2/extents.c b/libocfs2/extents.c
index 4b6808a..ee7ef93 100644
--- a/libocfs2/extents.c
+++ b/libocfs2/extents.c
@@ -42,13 +42,18 @@ static void ocfs2_swap_extent_list_primary(struct ocfs2_extent_list *el)
 	el->l_next_free_rec = bswap_16(el->l_next_free_rec);
 }
 
-static void ocfs2_swap_extent_list_secondary(struct ocfs2_extent_list *el)
+static void ocfs2_swap_extent_list_secondary(ocfs2_filesys *fs, void *obj,
+					     struct ocfs2_extent_list *el)
 {
 	uint16_t i;
 
 	for(i = 0; i < el->l_next_free_rec; i++) {
 		struct ocfs2_extent_rec *rec = &el->l_recs[i];
 
+		if (ocfs2_swap_barrier(fs, obj, rec,
+				       sizeof(struct ocfs2_extent_rec)))
+			break;
+
 		rec->e_cpos = bswap_32(rec->e_cpos);
 		if (el->l_tree_depth)
 			rec->e_int_clusters = bswap_32(rec->e_int_clusters);
@@ -58,21 +63,23 @@ static void ocfs2_swap_extent_list_secondary(struct ocfs2_extent_list *el)
 	}
 }
 
-void ocfs2_swap_extent_list_from_cpu(struct ocfs2_extent_list *el)
+void ocfs2_swap_extent_list_from_cpu(ocfs2_filesys *fs, void *obj,
+				     struct ocfs2_extent_list *el)
 {
 	if (cpu_is_little_endian)
 		return;
 
-	ocfs2_swap_extent_list_secondary(el);
+	ocfs2_swap_extent_list_secondary(fs, obj, el);
 	ocfs2_swap_extent_list_primary(el);
 }
-void ocfs2_swap_extent_list_to_cpu(struct ocfs2_extent_list *el)
+void ocfs2_swap_extent_list_to_cpu(ocfs2_filesys *fs, void *obj,
+				   struct ocfs2_extent_list *el)
 {
 	if (cpu_is_little_endian)
 		return;
 
 	ocfs2_swap_extent_list_primary(el);
-	ocfs2_swap_extent_list_secondary(el);
+	ocfs2_swap_extent_list_secondary(fs, obj, el);
 }
 
 static void ocfs2_swap_extent_block_header(struct ocfs2_extent_block *eb)
@@ -85,22 +92,24 @@ static void ocfs2_swap_extent_block_header(struct ocfs2_extent_block *eb)
 	eb->h_next_leaf_blk = bswap_64(eb->h_next_leaf_blk);
 }
 
-void ocfs2_swap_extent_block_from_cpu(struct ocfs2_extent_block *eb)
+void ocfs2_swap_extent_block_from_cpu(ocfs2_filesys *fs,
+				      struct ocfs2_extent_block *eb)
 {
 	if (cpu_is_little_endian)
 		return;
 
 	ocfs2_swap_extent_block_header(eb);
-	ocfs2_swap_extent_list_from_cpu(&eb->h_list);
+	ocfs2_swap_extent_list_from_cpu(fs, eb, &eb->h_list);
 }
 
-void ocfs2_swap_extent_block_to_cpu(struct ocfs2_extent_block *eb)
+void ocfs2_swap_extent_block_to_cpu(ocfs2_filesys *fs,
+				    struct ocfs2_extent_block *eb)
 {
 	if (cpu_is_little_endian)
 		return;
 
 	ocfs2_swap_extent_block_header(eb);
-	ocfs2_swap_extent_list_to_cpu(&eb->h_list);
+	ocfs2_swap_extent_list_to_cpu(fs, eb, &eb->h_list);
 }
 
 errcode_t ocfs2_read_extent_block_nocheck(ocfs2_filesys *fs,
@@ -138,7 +147,7 @@ errcode_t ocfs2_read_extent_block_nocheck(ocfs2_filesys *fs,
 	memcpy(eb_buf, blk, fs->fs_blocksize);
 
 	eb = (struct ocfs2_extent_block *) eb_buf;
-	ocfs2_swap_extent_block_to_cpu(eb);
+	ocfs2_swap_extent_block_to_cpu(fs, eb);
 
 out:
 	ocfs2_free(&blk);
@@ -182,7 +191,7 @@ errcode_t ocfs2_write_extent_block(ocfs2_filesys *fs, uint64_t blkno,
 	memcpy(blk, eb_buf, fs->fs_blocksize);
 
 	eb = (struct ocfs2_extent_block *) blk;
-	ocfs2_swap_extent_block_from_cpu(eb);
+	ocfs2_swap_extent_block_from_cpu(fs, eb);
 
 	ocfs2_compute_meta_ecc(fs, blk, &eb->h_check);
 	ret = io_write_block(fs->fs_io, blkno, 1, blk);
diff --git a/libocfs2/inode.c b/libocfs2/inode.c
index e786f5e..1abda69 100644
--- a/libocfs2/inode.c
+++ b/libocfs2/inode.c
@@ -63,7 +63,7 @@ out_buf:
 	return ret;
 }
 
-static void ocfs2_swap_inode_third(struct ocfs2_dinode *di)
+static void ocfs2_swap_inode_third(ocfs2_filesys *fs, struct ocfs2_dinode *di)
 {
 
 	if (di->i_flags & OCFS2_CHAIN_FL) {
@@ -73,6 +73,10 @@ static void ocfs2_swap_inode_third(struct ocfs2_dinode *di)
 		for (i = 0; i < cl->cl_next_free_rec; i++) {
 			struct ocfs2_chain_rec *rec = &cl->cl_recs[i];
 
+			if (ocfs2_swap_barrier(fs, di, rec,
+					       sizeof(struct ocfs2_chain_rec)))
+				break;
+
 			rec->c_free  = bswap_32(rec->c_free);
 			rec->c_total = bswap_32(rec->c_total);
 			rec->c_blkno = bswap_64(rec->c_blkno);
@@ -86,6 +90,10 @@ static void ocfs2_swap_inode_third(struct ocfs2_dinode *di)
 			struct ocfs2_truncate_rec *rec =
 				&tl->tl_recs[i];
 
+			if (ocfs2_swap_barrier(fs, di, rec,
+					     sizeof(struct ocfs2_truncate_rec)))
+				break;
+
 			rec->t_start    = bswap_32(rec->t_start);
 			rec->t_clusters = bswap_32(rec->t_clusters);
 		}
@@ -202,11 +210,22 @@ static int has_extents(struct ocfs2_dinode *di)
 	return 1;
 }
 
-static inline void ocfs2_swap_inline_dir(struct ocfs2_dinode *di,
-					 int to_cpu)
+static inline void ocfs2_swap_inline_dir(ocfs2_filesys *fs,
+					 struct ocfs2_dinode *di, int to_cpu)
 {
 	void *de_buf = di->id2.i_data.id_data;
 	uint64_t bytes = di->id2.i_data.id_count;
+	int max_inline = ocfs2_max_inline_data(fs->fs_blocksize);
+
+	if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL)
+		max_inline -= di->i_xattr_inline_size;
+
+	/* Just in case i_xattr_inline_size is garbage */
+	if (max_inline < 0)
+		max_inline = 0;
+
+	if (bytes > max_inline)
+	    bytes = max_inline;
 
 	if (to_cpu)
 		ocfs2_swap_dir_entries_to_cpu(de_buf, bytes);
@@ -214,41 +233,43 @@ static inline void ocfs2_swap_inline_dir(struct ocfs2_dinode *di,
 		ocfs2_swap_dir_entries_from_cpu(de_buf, bytes);
 }
 
-void ocfs2_swap_inode_from_cpu(struct ocfs2_dinode *di, size_t blocksize)
+void ocfs2_swap_inode_from_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di)
 {
 	if (cpu_is_little_endian)
 		return;
 
 	if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) {
 		struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)
-			((void *)di + blocksize - di->i_xattr_inline_size);
-		ocfs2_swap_xattrs_from_cpu(xh);
+			((void *)di + fs->fs_blocksize -
+			 di->i_xattr_inline_size);
+		ocfs2_swap_xattrs_from_cpu(fs, di, xh);
 	}
 	if (has_extents(di))
-		ocfs2_swap_extent_list_from_cpu(&di->id2.i_list);
+		ocfs2_swap_extent_list_from_cpu(fs, di, &di->id2.i_list);
 	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL && S_ISDIR(di->i_mode))
-		ocfs2_swap_inline_dir(di, 0);
-	ocfs2_swap_inode_third(di);
+		ocfs2_swap_inline_dir(fs, di, 0);
+	ocfs2_swap_inode_third(fs, di);
 	ocfs2_swap_inode_second(di);
 	ocfs2_swap_inode_first(di);
 }
 
-void ocfs2_swap_inode_to_cpu(struct ocfs2_dinode *di, size_t blocksize)
+void ocfs2_swap_inode_to_cpu(ocfs2_filesys *fs, struct ocfs2_dinode *di)
 {
 	if (cpu_is_little_endian)
 		return;
 
 	ocfs2_swap_inode_first(di);
 	ocfs2_swap_inode_second(di);
-	ocfs2_swap_inode_third(di);
+	ocfs2_swap_inode_third(fs, di);
 	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL && S_ISDIR(di->i_mode))
-		ocfs2_swap_inline_dir(di, 1);
+		ocfs2_swap_inline_dir(fs, di, 1);
 	if (has_extents(di))
-		ocfs2_swap_extent_list_to_cpu(&di->id2.i_list);
+		ocfs2_swap_extent_list_to_cpu(fs, di, &di->id2.i_list);
 	if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL) {
 		struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)
-			((void *)di + blocksize - di->i_xattr_inline_size);
-		ocfs2_swap_xattrs_to_cpu(xh);
+			((void *)di + fs->fs_blocksize -
+			 di->i_xattr_inline_size);
+		ocfs2_swap_xattrs_to_cpu(fs, di, xh);
 	}
 }
 
@@ -284,7 +305,7 @@ errcode_t ocfs2_read_inode(ocfs2_filesys *fs, uint64_t blkno,
 	memcpy(inode_buf, blk, fs->fs_blocksize);
 
 	di = (struct ocfs2_dinode *) inode_buf;
-	ocfs2_swap_inode_to_cpu(di, fs->fs_blocksize);
+	ocfs2_swap_inode_to_cpu(fs, di);
 
 	ret = 0;
 out:
@@ -314,7 +335,7 @@ errcode_t ocfs2_write_inode(ocfs2_filesys *fs, uint64_t blkno,
 	memcpy(blk, inode_buf, fs->fs_blocksize);
 
 	di = (struct ocfs2_dinode *)blk;
-	ocfs2_swap_inode_from_cpu(di, fs->fs_blocksize);
+	ocfs2_swap_inode_from_cpu(fs, di);
 
 	ocfs2_compute_meta_ecc(fs, blk, &di->i_check);
 	ret = io_write_block(fs->fs_io, blkno, 1, blk);
diff --git a/libocfs2/openfs.c b/libocfs2/openfs.c
index 538d859..156ea47 100644
--- a/libocfs2/openfs.c
+++ b/libocfs2/openfs.c
@@ -137,7 +137,7 @@ errcode_t ocfs2_read_super(ocfs2_filesys *fs, uint64_t superblock, char *sb)
 	orig_blocksize = fs->fs_blocksize;
 	fs->fs_super = (struct ocfs2_dinode *)swapblk;
 	fs->fs_blocksize = blocksize;
-	ocfs2_swap_inode_to_cpu(fs->fs_super, fs->fs_blocksize);
+	ocfs2_swap_inode_to_cpu(fs, fs->fs_super);
 
 	ret = ocfs2_validate_meta_ecc(fs, blk, &di->i_check);
 
@@ -148,7 +148,7 @@ errcode_t ocfs2_read_super(ocfs2_filesys *fs, uint64_t superblock, char *sb)
 	if (ret)
 		goto out_blk;
 
-	ocfs2_swap_inode_to_cpu(di, fs->fs_blocksize);
+	ocfs2_swap_inode_to_cpu(fs, di);
 	if (!sb)
 		fs->fs_super = di;
 	else {
diff --git a/libocfs2/xattr.c b/libocfs2/xattr.c
index bffdfd9..275d058 100644
--- a/libocfs2/xattr.c
+++ b/libocfs2/xattr.c
@@ -106,9 +106,26 @@ static void ocfs2_swap_xattr_header(struct ocfs2_xattr_header *xh)
 	xh->xh_num_buckets	= bswap_16(xh->xh_num_buckets);
 }
 
-static void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh)
+/*
+ * The swap barriers for xattrs are the hardest.  The ocfs2_xattr_header
+ * can be at the start of a bucket, inside an xattr block, or at the end
+ * of an inode.  Thus, we need to pass obj for the containing object.
+ * On top of that, buckets are always 4K, regardless of blocksize.  Thus,
+ * we take objsize as an argument and fake the ocfs2_filesys we pass to
+ * ocfs2_swap_barrier().
+ *
+ * Much of this is internal to xattr.c, thankfully.  The callers of the
+ * pubic ocfs2_swap_xattr*() APIs don't have to worry about objsize!
+ */
+static void ocfs2_swap_xattr_entries_to_cpu(ocfs2_filesys *fs, void *obj,
+					    size_t objsize,
+					    struct ocfs2_xattr_header *xh)
 {
 	uint16_t i;
+	char *value;
+	ocfs2_filesys fake_fs = {
+		.fs_blocksize = objsize,
+	};
 
 	if (cpu_is_little_endian)
 		return;
@@ -116,23 +133,40 @@ static void ocfs2_swap_xattr_entries_to_cpu(struct ocfs2_xattr_header *xh)
 	for (i = 0; i < xh->xh_count; i++) {
 		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
 
+		if (ocfs2_swap_barrier(&fake_fs, obj, xe,
+				       sizeof(struct ocfs2_xattr_entry)))
+			break;
+
 		ocfs2_swap_xattr_entry(xe);
 
+		value = (char *)xh + xe->xe_name_offset +
+			OCFS2_XATTR_SIZE(xe->xe_name_len);
+
 		if (!ocfs2_xattr_is_local(xe)) {
 			struct ocfs2_xattr_value_root *xr =
-				(struct ocfs2_xattr_value_root *)
-				((char *)xh + xe->xe_name_offset +
-				OCFS2_XATTR_SIZE(xe->xe_name_len));
+				(struct ocfs2_xattr_value_root *)value;
+
+			if (ocfs2_swap_barrier(&fake_fs, obj, xr,
+					       OCFS2_XATTR_ROOT_SIZE))
+				break;
 
 			ocfs2_swap_xattr_value_root(xr);
-			ocfs2_swap_extent_list_to_cpu(&xr->xr_list);
-		}
+			ocfs2_swap_extent_list_to_cpu(fs, xh, &xr->xr_list);
+		} else if (ocfs2_swap_barrier(&fake_fs, obj, value,
+					      xe->xe_value_size))
+			break;
 	}
 }
 
-static void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh)
+static void ocfs2_swap_xattr_entries_from_cpu(ocfs2_filesys *fs, void *obj,
+					      size_t objsize,
+					      struct ocfs2_xattr_header *xh)
 {
 	uint16_t i;
+	char *value;
+	ocfs2_filesys fake_fs = {
+		.fs_blocksize = objsize,
+	};
 
 	if (cpu_is_little_endian)
 		return;
@@ -140,56 +174,86 @@ static void ocfs2_swap_xattr_entries_from_cpu(struct ocfs2_xattr_header *xh)
 	for (i = 0; i < xh->xh_count; i++) {
 		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
 
+		if (ocfs2_swap_barrier(&fake_fs, obj, xe,
+				       sizeof(struct ocfs2_xattr_entry)))
+			break;
+
+		value = (char *)xh + xe->xe_name_offset +
+			OCFS2_XATTR_SIZE(xe->xe_name_len);
+
 		if (!ocfs2_xattr_is_local(xe)) {
 			struct ocfs2_xattr_value_root *xr =
-				(struct ocfs2_xattr_value_root *)
-				((char *)xh + xe->xe_name_offset +
-				OCFS2_XATTR_SIZE(xe->xe_name_len));
+				(struct ocfs2_xattr_value_root *)value;
+
+			if (ocfs2_swap_barrier(&fake_fs, obj, xr,
+					       OCFS2_XATTR_ROOT_SIZE))
+				break;
 
-			ocfs2_swap_extent_list_from_cpu(&xr->xr_list);
+			ocfs2_swap_extent_list_from_cpu(fs, xh, &xr->xr_list);
 			ocfs2_swap_xattr_value_root(xr);
-		}
+		} else if (ocfs2_swap_barrier(&fake_fs, obj, value,
+					      xe->xe_value_size))
+			break;
+
 		ocfs2_swap_xattr_entry(xe);
 	}
 }
 
-void ocfs2_swap_xattrs_to_cpu(struct ocfs2_xattr_header *xh)
+static void __ocfs2_swap_xattrs_to_cpu(ocfs2_filesys *fs, void *obj,
+				       size_t objsize,
+				       struct ocfs2_xattr_header *xh)
 {
 	ocfs2_swap_xattr_header(xh);
-	ocfs2_swap_xattr_entries_to_cpu(xh);
+	ocfs2_swap_xattr_entries_to_cpu(fs, obj, objsize, xh);
+}
+
+void ocfs2_swap_xattrs_to_cpu(ocfs2_filesys *fs, void *obj,
+			      struct ocfs2_xattr_header *xh)
+{
+	return __ocfs2_swap_xattrs_to_cpu(fs, obj, fs->fs_blocksize, xh);
 }
 
-void ocfs2_swap_xattrs_from_cpu(struct ocfs2_xattr_header *xh)
+static void __ocfs2_swap_xattrs_from_cpu(ocfs2_filesys *fs, void *obj,
+					 size_t objsize,
+					 struct ocfs2_xattr_header *xh)
 {
-	ocfs2_swap_xattr_entries_from_cpu(xh);
+	ocfs2_swap_xattr_entries_from_cpu(fs, obj, objsize, xh);
 	ocfs2_swap_xattr_header(xh);
 }
 
-void ocfs2_swap_xattr_block_to_cpu(struct ocfs2_xattr_block *xb)
+void ocfs2_swap_xattrs_from_cpu(ocfs2_filesys *fs, void *obj,
+				struct ocfs2_xattr_header *xh)
+{
+	return __ocfs2_swap_xattrs_from_cpu(fs, obj, fs->fs_blocksize, xh);
+}
+
+void ocfs2_swap_xattr_block_to_cpu(ocfs2_filesys *fs,
+				   struct ocfs2_xattr_block *xb)
 {
 	if (cpu_is_little_endian)
 		return;
 
 	ocfs2_swap_xattr_block_header(xb);
-	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
-		ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header);
-		ocfs2_swap_xattr_entries_to_cpu(&xb->xb_attrs.xb_header);
-	} else {
+	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED))
+		ocfs2_swap_xattrs_to_cpu(fs, xb, &xb->xb_attrs.xb_header);
+	else {
 		ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root);
-		ocfs2_swap_extent_list_to_cpu(&xb->xb_attrs.xb_root.xt_list);
+		ocfs2_swap_extent_list_to_cpu(fs, xb,
+					      &xb->xb_attrs.xb_root.xt_list);
 	}
 }
 
-void ocfs2_swap_xattr_block_from_cpu(struct ocfs2_xattr_block *xb)
+void ocfs2_swap_xattr_block_from_cpu(ocfs2_filesys *fs,
+				     struct ocfs2_xattr_block *xb)
 {
 	if (cpu_is_little_endian)
 		return;
 
-	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
-		ocfs2_swap_xattr_entries_from_cpu(&xb->xb_attrs.xb_header);
-		ocfs2_swap_xattr_header(&xb->xb_attrs.xb_header);
-	} else {
-		ocfs2_swap_extent_list_from_cpu(&xb->xb_attrs.xb_root.xt_list);
+	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED))
+		ocfs2_swap_xattrs_from_cpu(fs, xb, &xb->xb_attrs.xb_header);
+	else {
+		ocfs2_swap_extent_list_from_cpu(fs, xb,
+						&xb->xb_attrs.xb_root.xt_list);
 		ocfs2_swap_xattr_tree_root(&xb->xb_attrs.xb_root);
 	}
 
@@ -230,7 +294,7 @@ errcode_t ocfs2_read_xattr_block(ocfs2_filesys *fs,
 
 	memcpy(xb_buf, blk, fs->fs_blocksize);
 	xb = (struct ocfs2_xattr_block *)xb_buf;
-	ocfs2_swap_xattr_block_to_cpu(xb);
+	ocfs2_swap_xattr_block_to_cpu(fs, xb);
 out:
 	ocfs2_free(&blk);
 	return ret;
@@ -258,7 +322,7 @@ errcode_t ocfs2_write_xattr_block(ocfs2_filesys *fs,
 	memcpy(blk, xb_buf, fs->fs_blocksize);
 
 	xb = (struct ocfs2_xattr_block *)blk;
-	ocfs2_swap_xattr_block_from_cpu(xb);
+	ocfs2_swap_xattr_block_from_cpu(fs, xb);
 
 	ocfs2_compute_meta_ecc(fs, blk, &xb->xb_check);
 	ret = io_write_block(fs->fs_io, blkno, 1, blk);
@@ -395,7 +459,7 @@ errcode_t ocfs2_read_xattr_bucket(ocfs2_filesys *fs,
 
 	memcpy(bucket_buf, bucket, OCFS2_XATTR_BUCKET_SIZE);
 	xh = (struct ocfs2_xattr_header *)bucket_buf;
-	ocfs2_swap_xattrs_to_cpu(xh);
+	__ocfs2_swap_xattrs_to_cpu(fs, xh, OCFS2_XATTR_BUCKET_SIZE, xh);
 out:
 	ocfs2_free(&bucket);
 	return ret;
@@ -425,7 +489,7 @@ errcode_t ocfs2_write_xattr_bucket(ocfs2_filesys *fs,
 	memcpy(bucket, bucket_buf, OCFS2_XATTR_BUCKET_SIZE);
 
 	xh = (struct ocfs2_xattr_header *)bucket;
-	ocfs2_swap_xattrs_from_cpu(xh);
+	__ocfs2_swap_xattrs_from_cpu(fs, xh, OCFS2_XATTR_BUCKET_SIZE, xh);
 
 	if (ocfs2_meta_ecc(OCFS2_RAW_SB(fs->fs_super)))
 		ocfs2_block_check_compute(bucket, OCFS2_XATTR_BUCKET_SIZE,
diff --git a/mkfs.ocfs2/mkfs.c b/mkfs.ocfs2/mkfs.c
index 048f70f..d6151cf 100644
--- a/mkfs.ocfs2/mkfs.c
+++ b/mkfs.ocfs2/mkfs.c
@@ -1945,6 +1945,15 @@ check_32bit_blocks(State *s)
 	exit(1);
 }
 
+static void mkfs_swap_inode_from_cpu(State *s, struct ocfs2_dinode *di)
+{
+	ocfs2_filesys fake_fs;
+	char super_buf[OCFS2_MAX_BLOCKSIZE];
+
+	fill_fake_fs(s, &fake_fs, super_buf);
+	ocfs2_swap_inode_from_cpu(&fake_fs, di);
+}
+
 static void
 format_superblock(State *s, SystemFileDiskRecord *rec,
 		  SystemFileDiskRecord *root_rec, SystemFileDiskRecord *sys_rec)
@@ -2025,7 +2034,7 @@ format_superblock(State *s, SystemFileDiskRecord *rec,
 	strcpy((char *)di->id2.i_super.s_label, s->vol_label);
 	memcpy(di->id2.i_super.s_uuid, s->uuid, 16);
 
-	ocfs2_swap_inode_from_cpu(di, s->blocksize);
+	mkfs_swap_inode_from_cpu(s, di);
 	mkfs_compute_meta_ecc(s, di, &di->i_check);
 	do_pwrite(s, di, s->blocksize, super_off);
 	free(di);
@@ -2191,7 +2200,7 @@ format_file(State *s, SystemFileDiskRecord *rec)
 	}
 
 write_out:
-	ocfs2_swap_inode_from_cpu(di, s->blocksize);
+	mkfs_swap_inode_from_cpu(s, di);
 	mkfs_compute_meta_ecc(s, di, &di->i_check);
 	do_pwrite(s, di, s->blocksize, rec->fe_off);
 	free(di);
diff --git a/tunefs.ocfs2/libocfs2ne.c b/tunefs.ocfs2/libocfs2ne.c
index c5362db..6f89175 100644
--- a/tunefs.ocfs2/libocfs2ne.c
+++ b/tunefs.ocfs2/libocfs2ne.c
@@ -498,7 +498,7 @@ static errcode_t tunefs_validate_inode(ocfs2_filesys *fs,
 		    strlen(OCFS2_INODE_SIGNATURE)))
 		return OCFS2_ET_BAD_INODE_MAGIC;
 
-	ocfs2_swap_inode_to_cpu(di, fs->fs_blocksize);
+	ocfs2_swap_inode_to_cpu(fs, di);
 
 	if (di->i_fs_generation != fs->fs_super->i_fs_generation)
 		return OCFS2_ET_INODE_NOT_VALID;
-- 
1.6.3.1

-- 

"There is shadow under this red rock.
 (Come in under the shadow of this red rock)
 And I will show you something different from either
 Your shadow at morning striding behind you
 Or your shadow at evening rising to meet you.
 I will show you fear in a handful of dust."

Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127



More information about the Ocfs2-tools-devel mailing list