[Ocfs2-tools-devel] [PATCH] libocfs2: Add ocfs2_feature_foreach()

Joel Becker Joel.Becker at oracle.com
Mon Jul 21 19:52:23 PDT 2008


The ocfs2_parse_feature() function will include dependent features when
used.  For example, if you ask it to parse "unwritten", it will return a
feature set that includes both unwritten extents and sparse files,
because unwritten extents depends on sparse files.  The same is true in
reverse.  If you ask it "nosparse", it will return a reverse set that
includes sparse files and every thing that depends on it.

However, the caller has no way of knowing which feature needs to be
added or removed first.  A naively ordered program might try to add
unwritten extents before sparse files.  That will fail.

We introduce ocfs2_feature_foreach() and
ocfs2_feature_reverse_foreach().  These functions take a feature set and
iterate over it, calling a supplied callback once per feature.  The
former function does it in "set" order, the latter obviously in "clear"
or reverse order.

This depends on the previous patch "Clearing features should clear their
dependencies".

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 include/ocfs2/ocfs2.h     |   15 ++++++
 libocfs2/feature_string.c |  110 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 119 insertions(+), 6 deletions(-)

diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 7c21d28..53449bf 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -644,6 +644,21 @@ errcode_t ocfs2_merge_feature_flags_with_level(ocfs2_fs_options *dest,
 					       ocfs2_fs_options *feature_set,
 					       ocfs2_fs_options *reverse_set);
 
+/*
+ * Get a callback with each feature in feature_set in order.  This will
+ * calculate the dependencies of each feature in feature_set, then call func
+ * once per feature, with only that feature passed to func.
+ */
+void ocfs2_feature_foreach(ocfs2_fs_options *feature_set,
+			   int (*func)(ocfs2_fs_options *feature,
+				       void *user_data),
+			   void *user_data);
+/* The reverse function.  It will call the features in reverse order. */
+void ocfs2_feature_reverse_foreach(ocfs2_fs_options *reverse_set,
+				   int (*func)(ocfs2_fs_options *feature,
+					       void *user_data),
+				   void *user_data);
+
 
 /* These are deprecated names - don't use them */
 int ocfs2_get_backup_super_offset(ocfs2_filesys *fs,
diff --git a/libocfs2/feature_string.c b/libocfs2/feature_string.c
index 56380e2..d7bee33 100644
--- a/libocfs2/feature_string.c
+++ b/libocfs2/feature_string.c
@@ -144,6 +144,16 @@ static int check_feature_flags(ocfs2_fs_options *fs_flags,
 	return ret;
 }
 
+static int feature_match(ocfs2_fs_options *a, ocfs2_fs_options *b)
+{
+	if ((a->opt_compat & b->opt_compat) ||
+	    (a->opt_incompat & b->opt_incompat) ||
+	    (a->opt_ro_compat & b->opt_ro_compat))
+		return 1;
+
+	return 0;
+}
+
 /*
  * If we are asked to clear a feature, we also need to clear any other
  * features that depend on it.
@@ -153,12 +163,8 @@ static void ocfs2_feature_clear_deps(ocfs2_fs_options *reverse_set)
 	int i;
 
 	for(i = 0; ocfs2_supported_features[i].ff_str; i++) {
-		if ((reverse_set->opt_compat &
-			ocfs2_supported_features[i].ff_flags.opt_compat) ||
-		    (reverse_set->opt_incompat &
-			ocfs2_supported_features[i].ff_flags.opt_incompat) ||
-		    (reverse_set->opt_ro_compat &
-			ocfs2_supported_features[i].ff_flags.opt_ro_compat)) {
+		if (feature_match(reverse_set,
+				  &ocfs2_supported_features[i].ff_flags)) {
 			merge_features(reverse_set,
 				       ocfs2_supported_features[i].ff_own_flags);
 		}
@@ -265,6 +271,71 @@ errcode_t ocfs2_parse_feature(const char *opts,
 	return 0;
 }
 
+static int compare_feature_forward(const void *pa, const void *pb)
+{
+	int ia = *(int *)pa;
+	int ib = *(int *)pb;
+	struct fs_feature_flags *fa = &ocfs2_supported_features[ia];
+	struct fs_feature_flags *fb = &ocfs2_supported_features[ib];
+
+	if (feature_match(&fb->ff_flags,
+			  &fa->ff_own_flags))
+		return -1;
+	if (feature_match(&fa->ff_flags,
+			  &fb->ff_own_flags))
+		return 1;
+	return 0;
+}
+
+static int compare_feature_backward(const void *pa, const void *pb)
+{
+	return compare_feature_forward(pb, pa);
+}
+
+static void __feature_foreach(int reverse, ocfs2_fs_options *feature_set,
+			      int (*func)(ocfs2_fs_options *feature,
+					  void *user_data),
+			      void *user_data)
+{
+	int i, index;
+	int num_features = sizeof(ocfs2_supported_features) /
+		sizeof(ocfs2_supported_features[0]);
+	int indices[num_features];
+
+	index = 0;
+	for (i = 0; ocfs2_supported_features[i].ff_str; i++) {
+		if (feature_match(feature_set,
+				  &ocfs2_supported_features[i].ff_own_flags)) {
+			indices[index] = i;
+			index++;
+		}
+	}
+
+	qsort(indices, index, sizeof(indices[0]),
+	      reverse ? compare_feature_backward : compare_feature_forward);
+
+	for (i = 0; i < index; i++) {
+		if (func(&ocfs2_supported_features[indices[i]].ff_own_flags,
+			 user_data))
+			break;
+	}
+}
+
+void ocfs2_feature_foreach(ocfs2_fs_options *feature_set,
+			   int (*func)(ocfs2_fs_options *feature,
+				       void *user_data),
+			   void *user_data)
+{
+	__feature_foreach(0, feature_set, func, user_data);
+}
+
+void ocfs2_feature_reverse_foreach(ocfs2_fs_options *reverse_set,
+				   int (*func)(ocfs2_fs_options *feature,
+					       void *user_data),
+				   void *user_data)
+{
+	__feature_foreach(1, reverse_set, func, user_data);
+}
 
 #ifdef DEBUG_EXE
 
@@ -299,6 +370,30 @@ static void print_features(char *desc, ocfs2_fs_options *feature_set)
 		    ocfs2_supported_features[i].ff_own_flags.opt_incompat)
 			fprintf(stdout, " %s",
 				ocfs2_supported_features[i].ff_str);
+	fprintf(stdout, "\n");
+}
+
+static int p_feature(ocfs2_fs_options *feature_set, void *user_data)
+{
+	int i;
+
+	for (i = 0; ocfs2_supported_features[i].ff_str; i++) {
+		if (feature_match(feature_set,
+				  &ocfs2_supported_features[i].ff_own_flags))
+			fprintf(stdout, " %s",
+				ocfs2_supported_features[i].ff_str);
+	}
+
+	return 0;
+}
+
+static void print_order(int reverse, ocfs2_fs_options *feature_set)
+{
+	fprintf(stdout, "In this order:");
+	if (reverse)
+		ocfs2_feature_reverse_foreach(feature_set, p_feature, NULL);
+	else
+		ocfs2_feature_foreach(feature_set, p_feature, NULL);
 	fprintf(stdout, "\n\n");
 }
 
@@ -367,10 +462,13 @@ int main(int argc, char *argv[])
 
 	print_features("\nmkfs.ocfs2 would set these features",
 		       &mkfs_features);
+	print_order(0, &mkfs_features);
 	print_features("tunefs.ocfs2 would set these features",
 		       &set_features);
+	print_order(0, &set_features);
 	print_features("tunefs.ocfs2 would clear these features",
 		       &clear_features);
+	print_order(1, &clear_features);
 
 	return 0;
 }
-- 
1.5.6.2

-- 

Life's Little Instruction Book #274

	"Leave everything a little better than you found it."

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