[Ocfs2-tools-devel] [PATCH] inline/xattr: Let ocfs2_file_write handle inline xattr properly.

Tao Ma tao.ma at oracle.com
Mon Jan 4 01:00:22 PST 2010


The kernel now supports both inline data and inline xattr, so
we'd better support them also in user space. But now the user
space libocfs2 still use the old ocfs2_max_inline_data, and
we can easily corrupt a file's inline xattr with following steps:

1. create an empty file by touch.
2. set some xattrs in the file which will resides inside inode.
3. write a user space program and call ocfs2_file_write like this:
	memset(buf, 0, 3800);
        ret = ocfs2_file_write(ci, buf, 3800, 0, &wrote);

In case of bs=4k, the max inline data count without xattr is
3896, so the xattrs we set in step 2 is cleared by ocfs2_file_write.
This patch is try to resolve this bug.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fsck.ocfs2/pass1.c              |    9 ++-------
 fswreck/inode.c                 |    3 ++-
 include/ocfs2-kernel/ocfs2_fs.h |   17 +++++++++--------
 libocfs2/alloc.c                |   21 +++++++++++++++------
 libocfs2/fileio.c               |    3 ++-
 libocfs2/inode.c                |    5 +----
 mkfs.ocfs2/mkfs.c               |   15 ++++++++++-----
 7 files changed, 41 insertions(+), 32 deletions(-)

diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index db4225b..4f0ad8c 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -871,13 +871,8 @@ size_cluster_check:
 	 * less than the max inline data size.
 	 */
 	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
-		uint16_t max_inline;
-
-		if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL)
-			max_inline = ocfs2_max_inline_data(fs->fs_blocksize) -
-				     di->i_xattr_inline_size;
-		else
-			max_inline = ocfs2_max_inline_data(fs->fs_blocksize);
+		uint16_t max_inline =
+			ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di);
 
 		/* id_count is check first. */
 		if (di->id2.i_data.id_count != max_inline &&
diff --git a/fswreck/inode.c b/fswreck/inode.c
index afd4284..fafd0d0 100644
--- a/fswreck/inode.c
+++ b/fswreck/inode.c
@@ -350,7 +350,8 @@ void mess_up_inline_inode(ocfs2_filesys *fs, enum fsck_type type, uint64_t blkno
 			FSWRK_COM_FATAL(progname, ret);
 
 		di = (struct ocfs2_dinode *)buf;
-		max_inline_sz = ocfs2_max_inline_data(fs->fs_blocksize);
+		max_inline_sz =
+			ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di);
 
 		if (!(di->i_dyn_features & OCFS2_INLINE_DATA_FL))
 			di->i_dyn_features |= OCFS2_INLINE_DATA_FL;
diff --git a/include/ocfs2-kernel/ocfs2_fs.h b/include/ocfs2-kernel/ocfs2_fs.h
index 1650315..37eea20 100644
--- a/include/ocfs2-kernel/ocfs2_fs.h
+++ b/include/ocfs2-kernel/ocfs2_fs.h
@@ -1074,12 +1074,6 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
 		 offsetof(struct ocfs2_dinode, id2.i_symlink);
 }
 
-static inline int ocfs2_max_inline_data(struct super_block *sb)
-{
-	return sb->s_blocksize -
-		offsetof(struct ocfs2_dinode, id2.i_data.id_data);
-}
-
 static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb,
 						   struct ocfs2_dinode *di)
 {
@@ -1202,9 +1196,16 @@ static inline int ocfs2_fast_symlink_chars(int blocksize)
 	return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink);
 }
 
-static inline int ocfs2_max_inline_data(int blocksize)
+static inline int ocfs2_max_inline_data_with_xattr(int blocksize,
+						   struct ocfs2_dinode *di)
 {
-	return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+	if (di && (di->i_dyn_features & OCFS2_INLINE_XATTR_FL))
+		return blocksize -
+			offsetof(struct ocfs2_dinode, id2.i_data.id_data) -
+			di->i_xattr_inline_size;
+	else
+		return blocksize -
+			offsetof(struct ocfs2_dinode, id2.i_data.id_data);
 }
 
 static inline int ocfs2_extent_recs_per_inode(int blocksize)
diff --git a/libocfs2/alloc.c b/libocfs2/alloc.c
index e076bc5..18c6e0e 100644
--- a/libocfs2/alloc.c
+++ b/libocfs2/alloc.c
@@ -120,16 +120,24 @@ static int ocfs2_clusters_per_group(int block_size, int cluster_size_bits)
 	return (megabytes << ONE_MB_SHIFT) >> cluster_size_bits;
 }
 
-static inline void ocfs2_zero_dinode_id2(int blocksize,
-					 struct ocfs2_dinode *di)
+static void ocfs2_zero_dinode_id2_with_xattr(int blocksize,
+					     struct ocfs2_dinode *di)
 {
-	memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+	unsigned int xattrsize = di->i_xattr_inline_size;
+
+	if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL)
+		memset(&di->id2, 0, blocksize -
+				    offsetof(struct ocfs2_dinode, id2) -
+				    xattrsize);
+	else
+		memset(&di->id2, 0, blocksize -
+				    offsetof(struct ocfs2_dinode, id2));
 }
 
 void ocfs2_dinode_new_extent_list(ocfs2_filesys *fs,
 				  struct ocfs2_dinode *di)
 {
-	ocfs2_zero_dinode_id2(fs->fs_blocksize, di);
+	ocfs2_zero_dinode_id2_with_xattr(fs->fs_blocksize, di);
 
 	di->id2.i_list.l_tree_depth = 0;
 	di->id2.i_list.l_next_free_rec = 0;
@@ -140,9 +148,10 @@ void ocfs2_set_inode_data_inline(ocfs2_filesys *fs, struct ocfs2_dinode *di)
 {
 	struct ocfs2_inline_data *idata = &di->id2.i_data;
 
-	ocfs2_zero_dinode_id2(fs->fs_blocksize, di);
+	ocfs2_zero_dinode_id2_with_xattr(fs->fs_blocksize, di);
 
-	idata->id_count = ocfs2_max_inline_data(fs->fs_blocksize);
+	idata->id_count =
+		ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di);
 
 	di->i_dyn_features |= OCFS2_INLINE_DATA_FL;
 }
diff --git a/libocfs2/fileio.c b/libocfs2/fileio.c
index c4664ec..f10f8be 100644
--- a/libocfs2/fileio.c
+++ b/libocfs2/fileio.c
@@ -583,7 +583,8 @@ static errcode_t ocfs2_try_to_write_inline_data(ocfs2_cached_inode *ci,
 		goto out;
 	}
 
-	if (di->i_clusters > 0 || end > ocfs2_max_inline_data(fs->fs_blocksize))
+	if (di->i_clusters > 0 ||
+	    end > ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di))
 		return OCFS2_ET_CANNOT_INLINE_DATA;
 
 	ocfs2_set_inode_data_inline(fs, ci->ci_inode);
diff --git a/libocfs2/inode.c b/libocfs2/inode.c
index 1abda69..40dd6cc 100644
--- a/libocfs2/inode.c
+++ b/libocfs2/inode.c
@@ -215,10 +215,7 @@ static inline void ocfs2_swap_inline_dir(ocfs2_filesys *fs,
 {
 	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;
+	int max_inline = ocfs2_max_inline_data_with_xattr(fs->fs_blocksize, di);
 
 	/* Just in case i_xattr_inline_size is garbage */
 	if (max_inline < 0)
diff --git a/mkfs.ocfs2/mkfs.c b/mkfs.ocfs2/mkfs.c
index c2105af..19f5411 100644
--- a/mkfs.ocfs2/mkfs.c
+++ b/mkfs.ocfs2/mkfs.c
@@ -570,7 +570,8 @@ main(int argc, char **argv)
 	add_entry_to_directory(s, root_dir, "..", root_dir_rec.fe_off, OCFS2_FT_DIR);
 
 	need = system_dir_bytes_needed(s);
-	if (!s->inline_data || need > ocfs2_max_inline_data(s->blocksize)) {
+	if (!s->inline_data ||
+	    need > ocfs2_max_inline_data_with_xattr(s->blocksize, NULL)) {
 		need = system_dir_blocks_needed(s) << s->blocksize_bits;
 		alloc_bytes_from_bitmap(s, need, s->global_bm,
 					&system_dir_rec.extent_off,
@@ -2308,21 +2309,25 @@ format_file(State *s, SystemFileDiskRecord *rec)
 			(struct ocfs2_dir_entry *)(dir->buf + dir->last_off);
 		int dir_len = dir->last_off + OCFS2_DIR_REC_LEN(de->name_len);
 
-		if (dir_len > ocfs2_max_inline_data(s->blocksize)) {
+		if (dir_len >
+		    ocfs2_max_inline_data_with_xattr(s->blocksize, di)) {
 			com_err(s->progname, 0,
 				"Inline a dir which shouldn't be inline.\n");
 			clear_both_ends(s);
 			exit(1);
 		}
 		de->rec_len -= s->blocksize -
-			       ocfs2_max_inline_data(s->blocksize);
+			       ocfs2_max_inline_data_with_xattr(s->blocksize,
+								di);
 		memset(&di->id2, 0,
 		       s->blocksize - offsetof(struct ocfs2_dinode, id2));
 
-		di->id2.i_data.id_count = ocfs2_max_inline_data(s->blocksize);
+		di->id2.i_data.id_count =
+			ocfs2_max_inline_data_with_xattr(s->blocksize, di);
 		memcpy(di->id2.i_data.id_data, dir->buf, dir_len);
 		di->i_dyn_features |= OCFS2_INLINE_DATA_FL;
-		di->i_size = ocfs2_max_inline_data(s->blocksize);
+		di->i_size = ocfs2_max_inline_data_with_xattr(s->blocksize,
+							      di);
 	}
 
 write_out:
-- 
1.5.5




More information about the Ocfs2-tools-devel mailing list