[Ocfs2-tools-devel] [PATCH 08/11] fsck.ocfs2 now know inline data.

Tao Ma tao.ma at oracle.com
Thu Jul 24 23:32:51 PDT 2008


Hi Joel,
	the new patch. Please review it. Thanks.

Add the check for id_count and also remove INLINE_DATA_FL when
the volume doesn't support it.

fsck.ocfs2 will only check i_size and i_clusters for inline data.
As for directory check, inline directory will also be checked.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 fsck.ocfs2/fsck.ocfs2.checks.8.in |   12 ++++++
 fsck.ocfs2/pass1.c                |   71 +++++++++++++++++++++++++++++++++++-
 fsck.ocfs2/pass2.c                |   52 ++++++++++++++++++++-------
 3 files changed, 119 insertions(+), 16 deletions(-)

diff --git a/fsck.ocfs2/fsck.ocfs2.checks.8.in b/fsck.ocfs2/fsck.ocfs2.checks.8.in
index 3d3246a..1bca839 100644
--- a/fsck.ocfs2/fsck.ocfs2.checks.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.checks.8.in
@@ -691,6 +691,18 @@ Answering yes reconfigures the filesystem to use the current cluster stack.
 DANGER: YOU MUST BE ABSOLUTELY SURE THAT NO OTHER NODE IS USING THIS FILESYSTEM
 BEFORE CONTINUING.  OTHERWISE, YOU CAN CORRUPT THE FILESYSTEM AND LOSE DATA.
 
+.SS "INLINE_DATA_FLAG_INVALID"
+Inline file can only exist in a volume with inline supported, Fsck has found
+that a file in a non-inline volume has inline flag set.
+
+Answering yes remove this flag from the file.
+
+.SS "INLINE_DATA_COUNT_INVALID"
+For an inline file, there is a limit for id2.id_data.id_count. Fsck has found
+that this value isn't right.
+
+Answering yes change this value to the right number.
+
 .SH "SEE ALSO"
 .BR fsck.ocfs2(8)
 
diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index bef2863..1458f20 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -497,6 +497,16 @@ static void o2fsck_verify_inode_fields(ocfs2_filesys *fs,
 		o2fsck_write_inode(ost, blkno, di);
 	}
 
+	if ((di->i_dyn_features & OCFS2_INLINE_DATA_FL) &&
+	    !ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super)) &&
+	    prompt(ost, PY, PR_INLINE_DATA_FLAG_INVALID,
+		   "Inode %"PRIu64" has inline flag set but the volume "
+		   "doesn't support it. Clear it?", (uint64_t)di->i_blkno)) {
+
+		di->i_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+		o2fsck_write_inode(ost, blkno, di);
+	}
+
 	if (S_ISDIR(di->i_mode)) {
 		ocfs2_bitmap_set(ost->ost_dir_inodes, blkno, NULL);
 		o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 0, 0,
@@ -767,6 +777,24 @@ static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost,
 	    (S_ISLNK(di->i_mode) && di->i_clusters == 0))
 		return 0;
 
+	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
+		/*
+		 * We add i_blkno as the dir block, so when the dir's
+		 * inode_no is the same as dir_block_no, we can tell
+		 * that this dir is inlinded and help us in the following
+		 * directory check.
+		 */
+		if (S_ISDIR(di->i_mode)) {
+			ret = o2fsck_add_dir_block(&ost->ost_dirblocks,
+						   di->i_blkno,
+						   di->i_blkno, 0);
+			if (ret)
+				return ret;
+		}
+
+		goto size_cluster_check;
+	}
+
 	ret = o2fsck_check_extents(ost, di);
 	if (ret == 0)
 		ret = ocfs2_block_iterate_inode(fs, di,
@@ -816,6 +844,7 @@ static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost,
 		goto out;	
 	}
 
+size_cluster_check:
 	/*
 	 * i_size and i_cluster mean quite different between a non-sparse
 	 * and sparse file system.
@@ -831,9 +860,47 @@ static errcode_t o2fsck_check_blocks(ocfs2_filesys *fs, o2fsck_state *ost,
 	 * end of the visible cluster end. It is also reasonable for a file
 	 * which has no allocated blocks but any number of byte sizes,
 	 * so we don't need to check its size either.
+	 *
+	 * In an inline file, i_clusters should be zero and i_size should be
+	 * less than the max inline data size.
 	 */
-	if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat &
-	    OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) {
+	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
+		uint16_t max_inline = ocfs2_max_inline_data(fs->fs_blocksize);
+
+		/* id_count is check first. */
+		if (di->id2.i_data.id_count != max_inline &&
+		    prompt(ost, PY, PR_INLINE_DATA_COUNT_INVALID,
+			   "Inode %"PRIu64" is inline file and its id_count "
+			   "is %u which should be %u. Correct this "
+			   "count?", (uint64_t)di->i_blkno,
+			   di->id2.i_data.id_count, max_inline)) {
+			di->id2.i_data.id_count = max_inline;
+			o2fsck_write_inode(ost, blkno, di);
+		}
+
+		/* i_size is checked for symlinks elsewhere */
+		if (di->i_size > max_inline &&
+		    prompt(ost, PY, PR_INODE_SIZE, "Inode %"PRIu64
+			   "has a size of %"PRIu64" which exceeds the max "
+			   "inline data size %u. "
+			   "Correct the file size?",
+			   (uint64_t)di->i_blkno, (uint64_t)di->i_size,
+			   max_inline)) {
+			di->i_size = max_inline;
+			o2fsck_write_inode(ost, blkno, di);
+		}
+
+		if (di->i_clusters > 0 &&
+		    prompt(ost, PY, PR_INODE_CLUSTERS,
+			   "Inode %"PRIu64" has %"PRIu32" clusters but it has "
+			   "inline data flag set. "
+			   "Correct the number of clusters?",
+			   (uint64_t)di->i_blkno, di->i_clusters)) {
+			di->i_clusters = 0;
+			o2fsck_write_inode(ost, blkno, di);
+		}
+	} else if (OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat &
+		   OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) {
 		if (vb.vb_num_blocks > 0) {
 			expected = ocfs2_blocks_to_clusters(fs,
 							 vb.vb_last_block + 1);
diff --git a/fsck.ocfs2/pass2.c b/fsck.ocfs2/pass2.c
index 5f1696d..c53c264 100644
--- a/fsck.ocfs2/pass2.c
+++ b/fsck.ocfs2/pass2.c
@@ -83,12 +83,19 @@ static int dirent_has_dots(struct ocfs2_dir_entry *dirent, int num_dots)
 	return dirent->name[0] == '.';
 }
 
-static int expected_dots(o2fsck_dirblock_entry *dbe, int offset)
+static int expected_dots(o2fsck_state *ost,
+			 o2fsck_dirblock_entry *dbe,
+			 int offset)
 {
+	int inline_off = offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+
 	if (dbe->e_blkcount == 0) {
-		if (offset == 0)
+		if (offset == 0 ||
+		    (dbe->e_ino == dbe->e_blkno && offset == inline_off))
 			return 1;
-		if (offset == OCFS2_DIR_REC_LEN(1))
+		if (offset == OCFS2_DIR_REC_LEN(1) ||
+		    (dbe->e_ino == dbe->e_blkno &&
+		     offset == inline_off + OCFS2_DIR_REC_LEN(1)))
 			return 2;
 	}
 
@@ -99,7 +106,7 @@ static errcode_t fix_dirent_dots(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
 				 struct ocfs2_dir_entry *dirent, int offset, 
 				 int left, unsigned int *flags)
 {
-	int expect_dots = expected_dots(dbe, offset);
+	int expect_dots = expected_dots(ost, dbe, offset);
 	int changed_len = 0;
 	struct ocfs2_dir_entry *next;
 	uint16_t new_len;
@@ -432,7 +439,7 @@ static errcode_t fix_dirent_linkage(o2fsck_state *ost,
 				    int offset,
 				    unsigned int *flags)
 {
-	int expect_dots = expected_dots(dbe, offset);
+	int expect_dots = expected_dots(ost, dbe, offset);
 	o2fsck_dir_parent *dp;
 	errcode_t ret = 0;
 	int is_dir;
@@ -637,14 +644,25 @@ static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe,
 	verbosef("dir block %"PRIu64" block offs %"PRIu64" in ino\n",
 		 dbe->e_blkno, dbe->e_blkcount);
 
-	if (dbe->e_blkcount >= ocfs2_blocks_in_bytes(dd->fs, di->i_size))
-		goto out;
+	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
+		if (dbe->e_ino != dbe->e_blkno)
+			goto out;
 
- 	ret = ocfs2_read_dir_block(dd->fs, dbe->e_blkno, dd->dirblock_buf);
-	if (ret && ret != OCFS2_ET_DIR_CORRUPTED) {
-		com_err(whoami, ret, "while reading dir block %"PRIu64,
-			dbe->e_blkno);
-		goto out;
+		memcpy(dd->dirblock_buf, dd->inoblock_buf,
+		       dd->fs->fs_blocksize);
+		offset = offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+	} else {
+		if (dbe->e_blkcount >= ocfs2_blocks_in_bytes(dd->fs,
+							     di->i_size))
+			goto out;
+
+		ret = ocfs2_read_dir_block(dd->fs, dbe->e_blkno,
+					   dd->dirblock_buf);
+		if (ret && ret != OCFS2_ET_DIR_CORRUPTED) {
+			com_err(whoami, ret, "while reading dir block %"PRIu64,
+				dbe->e_blkno);
+			goto out;
+		}
 	}
 
 	while (offset < dd->fs->fs_blocksize) {
@@ -735,8 +753,14 @@ next:
 	}
 
 	if (ret_flags & OCFS2_DIRENT_CHANGED) {
-		ret = ocfs2_write_dir_block(dd->fs, dbe->e_blkno,
-					    dd->dirblock_buf);
+		if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
+			memcpy(dd->inoblock_buf, dd->dirblock_buf,
+			       dd->fs->fs_blocksize);
+			ret = ocfs2_write_inode(dd->fs, dbe->e_ino,
+						dd->dirblock_buf);
+		} else
+			ret = ocfs2_write_dir_block(dd->fs, dbe->e_blkno,
+						    dd->dirblock_buf);
 		if (ret) {
 			com_err(whoami, ret, "while writing dir block %"PRIu64,
 				dbe->e_blkno);
-- 
1.5.4.GIT




More information about the Ocfs2-tools-devel mailing list