[Ocfs2-tools-devel] [PATCH 5/9] fsck.ocfs2: Implement Pass 1C, scanning for inode names.

Joel Becker joel.becker at oracle.com
Thu Jul 30 12:25:03 PDT 2009


Pass 1C scans the directory tree to provide names for any inode owning
multiply-claimed clusters.  This allows Pass 1D to print readable names
when asking questions.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 fsck.ocfs2/pass1b.c |  279 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 257 insertions(+), 22 deletions(-)

diff --git a/fsck.ocfs2/pass1b.c b/fsck.ocfs2/pass1b.c
index e353d21..4ad655f 100644
--- a/fsck.ocfs2/pass1b.c
+++ b/fsck.ocfs2/pass1b.c
@@ -32,7 +32,12 @@
  * this inode for each addition cluster it used to share.
  *
  * Pass 1C walks the directory tree and gives names to each inode.  This
- * is so the user can see the name of the file they are fixing.
+ * is so the user can see the name of the file they are fixing.  The pass
+ * does a depth-first traversal of the tree.  For every inode in the
+ * rbtree of duplicates it finds, it stores the path for it.  It will
+ * ignore errors in the directory tree, because we haven't fixed it yet.
+ * When reporting to the user, inodes without names will just get their
+ * inode number printed.
  *
  * Pass 1D does the actual fixing.  Each inode with duplicate clusters can
  * cloned to an entirely new file or deleted.  Regardless of the choice,
@@ -71,6 +76,9 @@ struct dup_inode {
 	/* The block number of this inode */
 	uint64_t	di_ino;
 
+	/* The path to this inode */
+	char		*di_path;
+
 	/*
 	 * i_flags from the inode.  We need to refuse deletion of
 	 * system files, and chain allocators are even worse.
@@ -111,6 +119,8 @@ struct dup_context {
 
 	/* Inodes that own them */
 	struct rb_root	dup_inodes;
+	/* How many there are */
+	uint64_t	dup_inode_count;
 };
 
 /* See if the cluster rbtree has the given cluster.  */
@@ -200,6 +210,7 @@ static void dup_inode_insert(struct dup_context *dct,
 
 	rb_link_node(&insert_di->di_node, parent, p);
 	rb_insert_color(&insert_di->di_node, &dct->dup_inodes);
+	dct->dup_inode_count++;
 }
 
 /*
@@ -282,6 +293,40 @@ out:
 	return ret;
 }
 
+static void o2fsck_empty_dup_context(struct dup_context *dct)
+{
+	struct dup_cluster *dc;
+	struct dup_inode *di;
+	struct dup_cluster_owner *dco;
+	struct rb_node *node;
+	struct list_head *p, *next;
+
+	while ((node = rb_first(&dct->dup_clusters)) != NULL) {
+		dc = rb_entry(node, struct dup_cluster, dc_node);
+
+		list_for_each_safe(p, next, &dc->dc_owners) {
+			dco = list_entry(p, struct dup_cluster_owner,
+					 dco_list);
+			list_del(&dco->dco_list);
+			ocfs2_free(&dco);
+		}
+
+		rb_erase(&dc->dc_node, &dct->dup_clusters);
+		ocfs2_free(&dc);
+	}
+
+	while ((node = rb_first(&dct->dup_inodes)) != NULL) {
+		di = rb_entry(node, struct dup_inode, di_node);
+		rb_erase(&di->di_node, &dct->dup_inodes);
+		ocfs2_free(&di);
+	}
+}
+
+
+/*
+ * Pass 1B
+ */
+
 struct process_extents_context {
 	o2fsck_state *ost;
 	struct dup_context *dct;
@@ -694,35 +739,227 @@ out:
 	return ret;
 }
 
-static void o2fsck_empty_dup_context(struct dup_context *dct)
+
+/*
+ * Pass 1C
+ */
+
+struct dir_to_scan {
+	struct list_head ts_list;
+	uint64_t ts_ino;
+	char *ts_path;
+};
+
+struct dir_scan_context {
+	o2fsck_state *ds_ost;
+	struct dup_context *ds_dct;
+
+	/* Inodes we still have to find */
+	int64_t ds_inodes_left;
+
+	/* Subdirs that are pending */
+	struct list_head ds_paths;
+
+	/* The cwd's path and ino */
+	uint64_t ds_ino;
+	char *ds_cwd;
+	int ds_cwdlen;
+};
+
+static void pass1c_warn(errcode_t ret)
 {
-	struct dup_cluster *dc;
-	struct dup_inode *di;
-	struct dup_cluster_owner *dco;
-	struct rb_node *node;
-	struct list_head *p, *next;
+	static int warned = 0;
 
-	while ((node = rb_first(&dct->dup_clusters)) != NULL) {
-		dc = rb_entry(node, struct dup_cluster, dc_node);
+	if (warned)
+		return;
 
-		list_for_each_safe(p, next, &dc->dc_owners) {
-			dco = list_entry(p, struct dup_cluster_owner,
-					 dco_list);
-			list_del(&dco->dco_list);
-			ocfs2_free(&dco);
-		}
+	warned = 1;
+	com_err(whoami, ret,
+		"while finding path names in Pass 1c.  The pass will "
+		"continue, but some inodes may be described by "
+		"inode number instead of name.");
+}
 
-		rb_erase(&dc->dc_node, &dct->dup_clusters);
-		ocfs2_free(&dc);
+static char *de_to_path(struct dir_scan_context *scan,
+			struct ocfs2_dir_entry *de)
+{
+	/* The 2 is for the path separator and the null */
+	int copied, pathlen = scan->ds_cwdlen + de->name_len + 2;
+	char *path = NULL;
+	/* We start with an empty cwd as we add '/' or '//' */
+	const char *cwdstr = scan->ds_cwdlen ? scan->ds_cwd : "";
+	const char *sep = "/";
+
+	/* Don't repeat '/' */
+	if (scan->ds_cwdlen &&
+	    (scan->ds_cwd[scan->ds_cwdlen - 1] == '/'))
+		sep = "";
+	if (de->name_len && (de->name[0] == '/'))
+		sep = "";
+
+	if (!ocfs2_malloc0(sizeof(char) * pathlen, &path)) {
+		copied = snprintf(path, pathlen, "%s%s%.*s",
+				  cwdstr, sep, de->name_len, de->name);
+		assert(copied < pathlen);
 	}
 
-	while ((node = rb_first(&dct->dup_inodes)) != NULL) {
+	return path;
+}
+
+static void push_dir(struct dir_scan_context *scan,
+		     struct ocfs2_dir_entry *de)
+{
+	errcode_t ret;
+	struct dir_to_scan *ts = NULL;
+
+	ret = ocfs2_malloc0(sizeof(struct dir_to_scan), &ts);
+	if (ret)
+		goto warn;
+
+	ts->ts_ino = de->inode;
+	ts->ts_path = de_to_path(scan, de);
+	if (!ts->ts_path) {
+		ret = OCFS2_ET_NO_MEMORY;
+		goto warn;
+	}
+
+	list_add(&ts->ts_list, &scan->ds_paths);
+	return;
+
+warn:
+	if (ts)
+		ocfs2_free(&ts);
+	pass1c_warn(ret);
+}
+
+static void set_next_cwd(struct dir_scan_context *scan)
+{
+	struct dir_to_scan *ts;
+
+	if (scan->ds_cwd)
+		ocfs2_free(&scan->ds_cwd);
+
+	ts = list_entry(scan->ds_paths.next, struct dir_to_scan, ts_list);
+	list_del(&ts->ts_list);
+
+	/* Steal the string from ts */
+	scan->ds_cwd = ts->ts_path;
+	scan->ds_cwdlen = strlen(scan->ds_cwd);
+	scan->ds_ino = ts->ts_ino;
+
+	ocfs2_free(&ts);
+}
+
+static void name_inode(struct dir_scan_context *scan,
+		       struct ocfs2_dir_entry *de)
+{
+	struct dup_inode *di = dup_inode_lookup(scan->ds_dct, de->inode);
+
+	if (!di || di->di_path)
+		return;
+
+	scan->ds_inodes_left--;
+
+	di->di_path = de_to_path(scan, de);
+	if (!di->di_path)
+		pass1c_warn(OCFS2_ET_NO_MEMORY);
+}
+
+static int walk_iterate(struct ocfs2_dir_entry *de, int offset,
+			int blocksize, char *buf, void *priv_data)
+{
+	struct dir_scan_context *scan = priv_data;
+
+	/* Directories are checked when they're traversed */
+	if (de->file_type == OCFS2_FT_DIR)
+		push_dir(scan, de);
+	else
+		name_inode(scan, de);
+
+	return scan->ds_inodes_left ? 0 : OCFS2_DIRENT_ABORT;
+}
+
+static void walk_cwd(struct dir_scan_context *scan)
+{
+	errcode_t ret;
+	struct ocfs2_dir_entry de;
+
+	memcpy(de.name, scan->ds_cwd, scan->ds_cwdlen);
+	de.name_len = scan->ds_cwdlen;
+	name_inode(scan, &de);
+
+	ret = ocfs2_dir_iterate(scan->ds_ost->ost_fs, scan->ds_ino,
+				OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL,
+				walk_iterate, scan);
+	if (ret)
+		pass1c_warn(ret);
+}
+
+static errcode_t o2fsck_pass1c(o2fsck_state *ost, struct dup_context *dct)
+{
+	errcode_t ret;
+	struct dir_scan_context scan = {
+		.ds_ost = ost,
+		.ds_dct = dct,
+		.ds_inodes_left = dct->dup_inode_count,
+	};
+
+	whoami = "pass1c";
+	printf("Pass 1c: Scanning directories to name the inode owning "
+	       "multiply-claimed clusters\n");
+
+	INIT_LIST_HEAD(&scan.ds_paths);
+	push_dir(&scan, &(struct ocfs2_dir_entry){
+		 .name = "/",
+		 .name_len = 1,
+		 .file_type = OCFS2_FT_DIR,
+		 .inode = ost->ost_fs->fs_root_blkno,
+		 });
+	push_dir(&scan, &(struct ocfs2_dir_entry){
+		 .name = "//",
+		 .name_len = 2,
+		 .file_type = OCFS2_FT_DIR,
+		 .inode = ost->ost_fs->fs_sysdir_blkno,
+		 });
+
+	while (scan.ds_inodes_left && !list_empty(&scan.ds_paths)) {
+		set_next_cwd(&scan);
+		walk_cwd(&scan);
+	}
+
+	return ret;
+}
+
+
+/*
+ * Pass 1D
+ */
+
+static void print_inode_path(struct dup_inode *di)
+{
+	if (di->di_path)
+		fprintf(stdout, "%s\n", di->di_path);
+	else
+		fprintf(stdout, "<%"PRIu64">\n", di->di_ino);
+}
+
+static errcode_t o2fsck_pass1d(o2fsck_state *ost, struct dup_context *dct)
+{
+	struct dup_inode *di;
+	struct rb_node *node = rb_first(&dct->dup_inodes);
+
+	for (node = rb_first(&dct->dup_inodes); node; node = rb_next(node)) {
 		di = rb_entry(node, struct dup_inode, di_node);
-		rb_erase(&di->di_node, &dct->dup_inodes);
-		ocfs2_free(&di);
+		print_inode_path(di);
 	}
+
+	return 0;
 }
 
+
+/*
+ * Exported call
+ */
 errcode_t ocfs2_pass1_dups(o2fsck_state *ost)
 {
 	errcode_t ret;
@@ -732,12 +969,10 @@ errcode_t ocfs2_pass1_dups(o2fsck_state *ost)
 	};
 
 	ret = o2fsck_pass1b(ost, &dct);
-#if 0
 	if (!ret)
 		ret = o2fsck_pass1c(ost, &dct);
 	if (!ret)
 		ret = o2fsck_pass1d(ost, &dct);
-#endif
 
 	o2fsck_empty_dup_context(&dct);
 	return ret;
-- 
1.6.3.3




More information about the Ocfs2-tools-devel mailing list