[Ocfs2-tools-devel] [PATCH 8/9] ocfs2-tools: add xattr support in fsck.ocfs2

Tiger Yang tiger.yang at oracle.com
Fri Dec 19 01:42:05 PST 2008


This patch will check all extended attributes related with each inode,
It will check xattr extent tree in index block and xattr's value tree,
mark all xattr block/cluster as used.

Signed-off-by: Tiger Yang <tiger.yang at oracle.com>
---
 fsck.ocfs2/Makefile         |    3 +-
 fsck.ocfs2/extent.c         |   17 +---
 fsck.ocfs2/include/extent.h |   13 +++
 fsck.ocfs2/include/xattr.h  |   26 +++++
 fsck.ocfs2/pass1.c          |    4 +
 fsck.ocfs2/xattr.c          |  249 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 296 insertions(+), 16 deletions(-)
 create mode 100644 fsck.ocfs2/include/xattr.h
 create mode 100644 fsck.ocfs2/xattr.c

diff --git a/fsck.ocfs2/Makefile b/fsck.ocfs2/Makefile
index d9d0862..9249cb5 100644
--- a/fsck.ocfs2/Makefile
+++ b/fsck.ocfs2/Makefile
@@ -31,7 +31,8 @@ CFILES =	fsck.c		\
 		problem.c 	\
 		slot_recovery.c \
 		strings.c 	\
-		util.c
+		util.c		\
+		xattr.c
 
 HFILES = 	include/fsck.h		\
 		include/dirblocks.h	\
diff --git a/fsck.ocfs2/extent.c b/fsck.ocfs2/extent.c
index 665704d..5f6639c 100644
--- a/fsck.ocfs2/extent.c
+++ b/fsck.ocfs2/extent.c
@@ -46,19 +46,6 @@
 
 static const char *whoami = "extent.c";
 
-struct extent_info {
-	uint64_t	ei_max_size;
-	uint64_t	ei_clusters;
-	uint64_t	ei_last_eb_blk;
-	uint16_t	ei_expected_depth;
-	unsigned	ei_expect_depth:1;
-};
-
-static errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
-			  struct ocfs2_dinode *di,
-			  struct ocfs2_extent_list *el,
-			  uint16_t max_recs, int *changed);
-
 static errcode_t check_eb(o2fsck_state *ost, struct extent_info *ei,
 			  struct ocfs2_dinode *di, uint64_t blkno,
 			  int *is_valid)
@@ -233,7 +220,7 @@ out:
 	return ret;
 }
 
-static errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
+errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
 			  struct ocfs2_dinode *di,
 			  struct ocfs2_extent_list *el,
 			  uint16_t max_recs, int *changed)
@@ -373,4 +360,4 @@ errcode_t o2fsck_check_extents(o2fsck_state *ost,
 		o2fsck_write_inode(ost, di->i_blkno, di);
 
 	return ret;
-}	
+}
diff --git a/fsck.ocfs2/include/extent.h b/fsck.ocfs2/include/extent.h
index 6fff28b..1266b7f 100644
--- a/fsck.ocfs2/include/extent.h
+++ b/fsck.ocfs2/include/extent.h
@@ -22,8 +22,21 @@
 
 #include "fsck.h"
 
+struct extent_info {
+	uint64_t	ei_max_size;
+	uint64_t	ei_clusters;
+	uint64_t	ei_last_eb_blk;
+	uint16_t	ei_expected_depth;
+	unsigned	ei_expect_depth:1;
+};
+
 errcode_t o2fsck_check_extents(o2fsck_state *ost,
                                struct ocfs2_dinode *di);
 
+errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
+			  struct ocfs2_dinode *di,
+			  struct ocfs2_extent_list *el,
+			  uint16_t max_recs, int *changed);
+
 #endif /* __O2FSCK_EXTENT_H__ */
 
diff --git a/fsck.ocfs2/include/xattr.h b/fsck.ocfs2/include/xattr.h
new file mode 100644
index 0000000..382e3b6
--- /dev/null
+++ b/fsck.ocfs2/include/xattr.h
@@ -0,0 +1,26 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.h
+ *
+ * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#ifndef __O2FSCK_XATTR_H__
+#define __O2FSCK_XATTR_H__
+
+#include "fsck.h"
+
+errcode_t o2fsck_check_xattr(o2fsck_state *ost,
+			     struct ocfs2_dinode *di);
+
+#endif /* __O2FSCK_XATTR_H__ */
+
diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index 209f8ff..6f385f6 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -65,6 +65,7 @@
 #include "pass1.h"
 #include "problem.h"
 #include "util.h"
+#include "xattr.h"
 
 static const char *whoami = "pass1";
 
@@ -1385,6 +1386,9 @@ errcode_t o2fsck_pass1(o2fsck_state *ost)
 								  blkno, di);
 					if (ret)
 						goto out;
+					ret = o2fsck_check_xattr(ost, di);
+					if (ret)
+						goto out;
 				}
 
 				valid = di->i_flags & OCFS2_VALID_FL;
diff --git a/fsck.ocfs2/xattr.c b/fsck.ocfs2/xattr.c
new file mode 100644
index 0000000..76e8fea
--- /dev/null
+++ b/fsck.ocfs2/xattr.c
@@ -0,0 +1,249 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.c
+ *
+ * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <string.h>
+#include <inttypes.h>
+
+#include "ocfs2/byteorder.h"
+#include "ocfs2/ocfs2.h"
+
+#include "xattr.h"
+#include "extent.h"
+#include "fsck.h"
+#include "problem.h"
+#include "util.h"
+
+static const char *whoami = "xattr.c";
+
+static errcode_t check_xattr(o2fsck_state *ost,
+			     struct ocfs2_dinode *di,
+			     struct ocfs2_xattr_header *xh,
+			     int *changed)
+{
+	int i;
+	struct extent_info ei = {0, };
+	errcode_t ret = 0;
+
+	for (i = 0 ; i < xh->xh_count; i++) {
+		int change = 0;
+		struct ocfs2_xattr_entry *xe = &xh->xh_entries[i];
+
+		if (!ocfs2_xattr_is_local(xe)) {
+			struct ocfs2_xattr_value_root *xv =
+				(struct ocfs2_xattr_value_root *)
+				((void *)xh + xe->xe_name_offset +
+				OCFS2_XATTR_SIZE(xe->xe_name_len));
+			struct ocfs2_extent_list *el = &xv->xr_list;
+			ret = check_el(ost, &ei, di, el, 1, &change);
+			if (ret)
+				return ret;
+			if (change)
+				*changed = 1;
+		}
+	}
+
+	return ret;
+}
+
+static errcode_t ocfs2_check_xattr_buckets(o2fsck_state *ost,
+					   struct ocfs2_dinode *di,
+					   uint64_t blkno,
+					   uint32_t clusters)
+{
+	int i;
+	errcode_t ret = 0;
+	char *bucket = NULL;
+	struct ocfs2_xattr_header *xh;
+	int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(ost->ost_fs);
+	uint32_t bpc = ocfs2_xattr_buckets_per_cluster(ost->ost_fs);
+	uint32_t num_buckets = clusters * bpc;
+
+	ret = ocfs2_malloc_blocks(ost->ost_fs->fs_io, blk_per_bucket, &bucket);
+	if (ret) {
+		com_err(whoami, ret, "while allocating room to read bucket "
+			"of xattr data");
+		goto out;
+	}
+
+	for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+		int changed = 0;
+
+		ret = io_read_block(ost->ost_fs->fs_io, blkno,
+				    blk_per_bucket, bucket);
+		if (ret) {
+			com_err(whoami, ret, "while reading blocks of xattr "
+				"bucket");
+			goto out;
+		}
+
+		xh = (struct ocfs2_xattr_header *)bucket;
+		ocfs2_swap_xattr_header(xh);
+		ocfs2_swap_xattr_entries_to_cpu(xh);
+		/*
+		 * The real bucket num in this series of blocks is stored
+		 * in the 1st bucket.
+		 */
+		if (i == 0)
+			num_buckets = xh->xh_num_buckets;
+
+		ret = check_xattr(ost, di, xh, &changed);
+		if (ret)
+			break;
+		if (changed) {
+			ocfs2_swap_xattr_entries_from_cpu(xh);
+			ocfs2_swap_xattr_header(xh);
+			io_write_block(ost->ost_fs->fs_io, blkno,
+				       blk_per_bucket, bucket);
+		}
+	}
+out:
+	if (bucket)
+		ocfs2_free(&bucket);
+
+	return ret;
+}
+
+static errcode_t o2fsck_check_xattr_index_block(o2fsck_state *ost,
+						struct ocfs2_dinode *di,
+						struct ocfs2_xattr_block *xb,
+						int *changed)
+{
+	struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+	errcode_t ret = 0;
+	uint32_t name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+	uint64_t p_blkno = 0;
+	struct extent_info ei = {0, };
+
+	if (!el->l_next_free_rec)
+		return 0;
+
+	ret = check_el(ost, &ei, di, el,
+		ocfs2_extent_recs_per_xattr_block(ost->ost_fs->fs_blocksize),
+		changed);
+	if (ret)
+		return ret;
+
+	while (name_hash > 0) {
+		ret = ocfs2_xattr_get_rec(ost->ost_fs, xb, name_hash, &p_blkno,
+					  &e_cpos, &num_clusters);
+		if (ret) {
+			com_err(whoami, ret, "while getting bucket record "
+				"of xattr data.");
+			goto out;
+		}
+
+		ret = ocfs2_check_xattr_buckets(ost, di, p_blkno,
+						num_clusters);
+		if (ret) {
+			com_err(whoami, ret, "while iterating buckets "
+				"of xattr data.");
+			goto out;
+		}
+
+		if (e_cpos == 0)
+			break;
+
+		name_hash = e_cpos - 1;
+	}
+
+out:
+	return ret;
+}
+
+static errcode_t o2fsck_check_xattr_block(o2fsck_state *ost,
+					  struct ocfs2_dinode *di)
+{
+	errcode_t ret;
+	char *blk = NULL;
+	struct ocfs2_xattr_block *xb = NULL;
+	int changed = 0;
+
+	ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &blk);
+	if (ret) {
+		com_err(whoami, ret, "while allocating room to read block "
+			"of xattr.");
+		return ret;
+	}
+
+	ret = ocfs2_read_xattr_block(ost->ost_fs, di->i_xattr_loc, blk);
+	if (ret) {
+		com_err(whoami, ret, "while reading externel block of xattr.");
+		return ret;
+	}
+
+	xb = (struct ocfs2_xattr_block *)blk;
+
+	if (!(xb->xb_flags & OCFS2_XATTR_INDEXED)) {
+		struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header;
+
+		ret = check_xattr(ost, di, xh, &changed);
+	} else
+		ret = o2fsck_check_xattr_index_block(ost, di, xb, &changed);
+
+	if (changed)
+		ocfs2_write_xattr_block(ost->ost_fs, di->i_xattr_loc, blk);
+
+	if (blk)
+		ocfs2_free(&blk);
+
+	return ret;
+}
+
+static errcode_t o2fsck_check_xattr_ibody(o2fsck_state *ost,
+					  struct ocfs2_dinode *di)
+{
+	errcode_t ret;
+	struct ocfs2_xattr_header *xh = NULL;
+	int changed = 0;
+
+	xh = (struct ocfs2_xattr_header *)
+		 ((void *)di + ost->ost_fs->fs_blocksize -
+		  di->i_xattr_inline_size);
+
+	ocfs2_swap_xattr_header(xh);
+	ocfs2_swap_xattr_entries_to_cpu(xh);
+
+	ret = check_xattr(ost, di, xh, &changed);
+
+	if (changed) {
+		ocfs2_swap_xattr_entries_from_cpu(xh);
+		ocfs2_swap_xattr_header(xh);
+		o2fsck_write_inode(ost, di->i_blkno, di);
+	}
+	return ret;
+}
+
+/*
+ * o2fsck_check_xattr
+ *
+ * Check extended attribute in inode block or external block.
+ */
+errcode_t o2fsck_check_xattr(o2fsck_state *ost,
+			     struct ocfs2_dinode *di)
+{
+	errcode_t ret = 0;
+
+	if (!(di->i_dyn_features & OCFS2_HAS_XATTR_FL))
+		return 0;
+
+	if (di->i_dyn_features & OCFS2_INLINE_XATTR_FL)
+		ret = o2fsck_check_xattr_ibody(ost, di);
+
+	if (!ret && di->i_xattr_loc)
+		ret = o2fsck_check_xattr_block(ost, di);
+
+	return ret;
+}
-- 
1.5.4.1




More information about the Ocfs2-tools-devel mailing list