[Ocfs2-tools-devel] [PATCH 5/7] Add "Set sparse flag" to ocfs2-tools, take 3

Tao Ma tao.ma at oracle.com
Sun Nov 4 23:47:08 PST 2007


Change from V2 to V3:
1. Add OCFS2_VALID_FL check in iterate_all_regular.
2. Add i_cluster check in set_func so that if we have modified
   the file in ocfs2_zero_tail_and_truncate, we will save the
   new cluster size.

"Set sparse" is used when we want to add "sparse" features for an
old-formatted OCFS2 volume. Now the user can use
"--fs-features=sparse" to add this feature to those volumes and
enable the new "sparse" feature.

Signed-off-by: Tao Ma <tao.ma at oracle.com>
---
 libocfs2/include/feature_string.h |    8 ---
 libocfs2/include/ocfs2.h          |    8 +++
 tunefs.ocfs2/Makefile             |    2 +-
 tunefs.ocfs2/features.c           |   66 ++++++++++++++++++++++++
 tunefs.ocfs2/sparse_file.c        |  101 +++++++++++++++++++++++++++++++++++++
 tunefs.ocfs2/tunefs.c             |   61 ++++++++++++++++++++--
 tunefs.ocfs2/tunefs.h             |    8 +++
 7 files changed, 240 insertions(+), 14 deletions(-)
 create mode 100644 tunefs.ocfs2/features.c

diff --git a/libocfs2/include/feature_string.h b/libocfs2/include/feature_string.h
index b8e860d..49156a7 100644
--- a/libocfs2/include/feature_string.h
+++ b/libocfs2/include/feature_string.h
@@ -28,14 +28,6 @@
 
 #include <ocfs2.h>
 
-typedef struct _fs_options fs_options;
-
-struct _fs_options {
-	uint32_t compat;
-	uint32_t incompat;
-	uint32_t ro_compat;
-};
-
 struct fs_feature_flags {
 	const char *ff_str;
 	/* this flag is the feature's own flag. */
diff --git a/libocfs2/include/ocfs2.h b/libocfs2/include/ocfs2.h
index 9fd0b83..748fdae 100644
--- a/libocfs2/include/ocfs2.h
+++ b/libocfs2/include/ocfs2.h
@@ -200,6 +200,14 @@ struct _ocfs2_devices {
 	uint8_t *node_nums;		/* list of mounted nodes */
 };
 
+typedef struct _fs_options fs_options;
+
+struct _fs_options {
+	uint32_t compat;
+	uint32_t incompat;
+	uint32_t ro_compat;
+};
+
 errcode_t ocfs2_malloc(unsigned long size, void *ptr);
 errcode_t ocfs2_malloc0(unsigned long size, void *ptr);
 errcode_t ocfs2_free(void *ptr);
diff --git a/tunefs.ocfs2/Makefile b/tunefs.ocfs2/Makefile
index d41f961..e6b4427 100644
--- a/tunefs.ocfs2/Makefile
+++ b/tunefs.ocfs2/Makefile
@@ -31,7 +31,7 @@ DEFINES = -DOCFS2_FLAT_INCLUDES -DVERSION=\"$(VERSION)\" -DO2DLM_FLAT_INCLUDES -
 
 MANS = tunefs.ocfs2.8
 
-CFILES = tunefs.c query.c remove_slot.c sparse_file.c
+CFILES = tunefs.c query.c remove_slot.c sparse_file.c features.c
 HFILES = tunefs.h
 
 OBJS = $(subst .c,.o,$(CFILES))
diff --git a/tunefs.ocfs2/features.c b/tunefs.ocfs2/features.c
new file mode 100644
index 0000000..e42e08b
--- /dev/null
+++ b/tunefs.ocfs2/features.c
@@ -0,0 +1,66 @@
+/*
+ * features.c
+ *
+ * source file for adding or removing features for tunefs.
+ *
+ * Copyright (C) 2007 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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+#include <ocfs2.h>
+
+#include <assert.h>
+
+#include <tunefs.h>
+
+extern ocfs2_tune_opts opts;
+
+/*
+ * Check whether we can add or remove a feature.
+ *
+ * Currently, we only handle "sparse files".
+ * More feature check may be added if we want to
+ * support more options in tunefs.ocfs2.
+ */
+errcode_t feature_check(ocfs2_filesys *fs)
+{
+	errcode_t ret = 1;
+
+	if (opts.set_feature.ro_compat != 0 ||
+	    opts.set_feature.compat != 0 ||
+	    opts.clear_feature.ro_compat != 0 ||
+	    opts.clear_feature.compat != 0)
+		goto bail;
+
+	if ((opts.set_feature.incompat ==
+	     OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) &&
+	     !ocfs2_sparse_alloc(OCFS2_RAW_SB(fs->fs_super)))
+		ret = 0;
+
+bail:
+	return ret;
+}
+
+errcode_t update_feature(ocfs2_filesys *fs)
+{
+	errcode_t ret = 0;
+
+	if (opts.set_feature.incompat & OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
+		ret = set_sparse_file_flag(fs, opts.progname);
+
+	return ret;
+}
diff --git a/tunefs.ocfs2/sparse_file.c b/tunefs.ocfs2/sparse_file.c
index 040014c..82dc257 100644
--- a/tunefs.ocfs2/sparse_file.c
+++ b/tunefs.ocfs2/sparse_file.c
@@ -400,3 +400,104 @@ bail:
 	empty_multi_link_files(&ctxt);
 	return ret;
 }
+
+static errcode_t iterate_all_regular(ocfs2_filesys *fs, char *progname,
+				     errcode_t (*func)(ocfs2_filesys *fs,
+						struct ocfs2_dinode *di))
+{
+	errcode_t ret;
+	uint64_t blkno;
+	char *buf;
+	struct ocfs2_dinode *di;
+	ocfs2_inode_scan *scan;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto out;
+
+	di = (struct ocfs2_dinode *)buf;
+
+	ret = ocfs2_open_inode_scan(fs, &scan);
+	if (ret) {
+		com_err(progname, ret, "while opening inode scan");
+		goto out_free;
+	}
+
+	for(;;) {
+		ret = ocfs2_get_next_inode(scan, &blkno, buf);
+		if (ret) {
+			com_err(progname, ret,
+				"while getting next inode");
+			break;
+		}
+		if (blkno == 0)
+			break;
+
+		if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE,
+			    strlen(OCFS2_INODE_SIGNATURE)))
+			continue;
+
+		ocfs2_swap_inode_to_cpu(di);
+
+		if (di->i_fs_generation != fs->fs_super->i_fs_generation)
+			continue;
+
+		if (!(di->i_flags & OCFS2_VALID_FL))
+			continue;
+
+		if (di->i_flags & OCFS2_SYSTEM_FL)
+			continue;
+
+		if (S_ISREG(di->i_mode) && func) {
+			ret = func(fs, di);
+			if (ret)
+				break;
+		}
+	}
+
+	ocfs2_close_inode_scan(scan);
+out_free:
+	ocfs2_free(&buf);
+
+out:
+	return ret;
+}
+
+static errcode_t set_func(ocfs2_filesys *fs, struct ocfs2_dinode *di)
+{
+	errcode_t ret;
+	uint32_t new_clusters;
+	ocfs2_cached_inode *ci = NULL;
+
+	ret = ocfs2_read_cached_inode(fs, di->i_blkno, &ci);
+	if (ret)
+		goto out;
+
+	ret = ocfs2_zero_tail_and_truncate(fs, ci, di->i_size, &new_clusters);
+
+	if (new_clusters != ci->ci_inode->i_clusters) {
+		ci->ci_inode->i_clusters = new_clusters;
+		ret = ocfs2_write_cached_inode(fs, ci);
+	}
+
+	if (ci)
+		ocfs2_free_cached_inode(fs, ci);
+out:
+	return ret;
+}
+
+errcode_t set_sparse_file_flag(ocfs2_filesys *fs, char *progname)
+{
+	errcode_t ret;
+	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
+
+	ret = iterate_all_regular(fs, progname, set_func);
+
+	if (ret)
+		goto bail;
+
+	OCFS2_SET_INCOMPAT_FEATURE(super, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC);
+
+bail:
+	return ret;
+}
diff --git a/tunefs.ocfs2/tunefs.c b/tunefs.ocfs2/tunefs.c
index 5e8dff9..8121565 100644
--- a/tunefs.ocfs2/tunefs.c
+++ b/tunefs.ocfs2/tunefs.c
@@ -24,6 +24,7 @@
  */
 
 #include <tunefs.h>
+#include <feature_string.h>
 
 ocfs2_tune_opts opts;
 ocfs2_filesys *fs_gbl = NULL;
@@ -35,7 +36,7 @@ static void usage(const char *progname)
 	fprintf(stderr, "usage: %s [-J journal-options] [-L volume-label]\n"
 			"\t\t[-M mount-type] [-N number-of-node-slots] [-Q query-fmt]\n"
 			"\t\t[-qSUvV] [--backup-super] [--list-sparse]\n"
-			"\t\tdevice [blocks-count]\n",
+			"\t\t[--fs-features=[no]sparse,...]] device [blocks-count]\n",
 			progname);
 	exit(0);
 }
@@ -183,6 +184,7 @@ static void get_options(int argc, char **argv)
 	int show_version = 0;
 	int uuid = 0;
 	char *dummy;
+	errcode_t ret = 0;
 
 	static struct option long_options[] = {
 		{ "label", 1, 0, 'L' },
@@ -197,6 +199,7 @@ static void get_options(int argc, char **argv)
 		{ "mount", 1, 0, 'M' },
 		{ "backup-super", 0, 0, BACKUP_SUPER_OPTION },
 		{ "list-sparse", 0, 0, LIST_SPARSE_FILES },
+		{ "fs-features=", 1, 0, FEATURES_OPTION },
 		{ 0, 0, 0, 0}
 	};
 
@@ -299,6 +302,18 @@ static void get_options(int argc, char **argv)
 			opts.list_sparse = 1;
 			break;
 
+		case FEATURES_OPTION:
+			ret = parse_feature(optarg,
+					    &opts.set_feature,
+					    &opts.clear_feature);
+			if (ret) {
+				com_err(opts.progname, ret,
+					"when parsing --fs-features string");
+				exit(1);
+			}
+			opts.feature_string = strdup(optarg);
+			break;
+
 		default:
 			usage(opts.progname);
 			break;
@@ -311,7 +326,7 @@ static void get_options(int argc, char **argv)
 	if (opts.backup_super &&
 	    (opts.vol_label || opts.num_slots ||
 	     opts.mount || opts.jrnl_size || resize ||
-	     opts.list_sparse)) {
+	     opts.list_sparse || opts.feature_string)) {
 		com_err(opts.progname, 0, "Cannot backup superblock"
 			" along with other tasks");
 		exit(1);
@@ -332,12 +347,26 @@ static void get_options(int argc, char **argv)
 	 */
 	if (opts.list_sparse &&
 	    (opts.vol_label || opts.num_slots ||
-	     opts.mount || opts.jrnl_size || resize || opts.backup_super)) {
+	     opts.mount || opts.jrnl_size || resize || opts.backup_super ||
+	     opts.feature_string)) {
 		com_err(opts.progname, 0, "Cannot list sparse files"
 			" along with other tasks");
 		exit(1);
 	}
 
+	/*
+	 * We don't allow feature-modifation to be coexist with other tunefs
+	 * options to keep things simple.
+	 */
+	if (opts.feature_string &&
+	    (opts.vol_label || opts.num_slots ||
+	     opts.mount || opts.jrnl_size || resize || opts.backup_super ||
+	     opts.list_sparse)) {
+		com_err(opts.progname, 0, "Cannot modify fs features"
+			" along with other tasks");
+		exit(1);
+	}
+
 	if (show_version)
 		exit(0);
 
@@ -1274,6 +1303,7 @@ int main(int argc, char **argv)
 	int upd_mount = 0;
 	int upd_incompat = 0;
 	int upd_backup_super = 0;
+	int upd_feature = 0;
 	char *tmpstr;
 	uint16_t max_slots;
 	uint64_t def_jrnl_size = 0;
@@ -1391,6 +1421,16 @@ int main(int argc, char **argv)
 		printf("List all the sparse files in the volume\n");
 	}
 
+	if (opts.feature_string) {
+		if (feature_check(fs)) {
+			com_err(opts.progname, 0,
+				"feature check failed. ");
+			goto unlock;
+		}
+		printf("Modify feature \"%s\" for the volume\n",
+			opts.feature_string);
+	}
+
 	/* If operation requires touching the global bitmap, ensure it is good */
 	/* This is to handle failed resize */
 	if (opts.num_blocks || opts.num_slots || opts.jrnl_size ||
@@ -1486,7 +1526,7 @@ int main(int argc, char **argv)
 
 	if (!opts.vol_label && !opts.vol_uuid && !opts.num_slots &&
 	    !opts.jrnl_size && !opts.num_blocks && !opts.mount &&
-	    !opts.backup_super && !opts.list_sparse) {
+	    !opts.backup_super && !opts.list_sparse && !opts.feature_string) {
 		com_err(opts.progname, 0, "Nothing to do. Exiting.");
 		goto unlock;
 	}
@@ -1603,6 +1643,17 @@ int main(int argc, char **argv)
 		}
 	}
 
+	/* change the feature in the super block.*/
+	if (opts.feature_string) {
+		ret = update_feature(fs);
+		if (ret) {
+			com_err(opts.progname, ret,
+				"while updating feature in super block");
+			goto unlock;
+		}
+		upd_feature = 1;
+	}
+
 	/* update the backup superblock. */
 	if (opts.backup_super ||
 	    (opts.num_blocks &&
@@ -1627,7 +1678,7 @@ int main(int argc, char **argv)
 
 	/* write superblock */
 	if (upd_label || upd_uuid || upd_slots || upd_blocks || upd_incompat ||
-	    upd_mount || upd_backup_super) {
+	    upd_mount || upd_backup_super || upd_feature) {
 		block_signals(SIG_BLOCK);
 		ret = ocfs2_write_super(fs);
 		if (ret) {
diff --git a/tunefs.ocfs2/tunefs.h b/tunefs.ocfs2/tunefs.h
index 4415703..4216b4b 100644
--- a/tunefs.ocfs2/tunefs.h
+++ b/tunefs.ocfs2/tunefs.h
@@ -74,6 +74,7 @@
 enum {
 	BACKUP_SUPER_OPTION = CHAR_MAX + 1,
 	LIST_SPARSE_FILES,
+	FEATURES_OPTION,
 };
 
 typedef struct _ocfs2_tune_opts {
@@ -91,6 +92,9 @@ typedef struct _ocfs2_tune_opts {
 	int prompt;
 	int backup_super;
 	int list_sparse;
+	fs_options set_feature;
+	fs_options clear_feature;
+	char *feature_string;
 	time_t tune_time;
 	int fd;
 } ocfs2_tune_opts;
@@ -101,4 +105,8 @@ errcode_t remove_slots(ocfs2_filesys *fs);
 errcode_t remove_slot_check(ocfs2_filesys *fs);
 
 errcode_t list_sparse(ocfs2_filesys *fs);
+errcode_t set_sparse_file_flag(ocfs2_filesys *fs, char *progname);
+
+errcode_t feature_check(ocfs2_filesys *fs);
+errcode_t update_feature(ocfs2_filesys *fs);
 #endif /* _TUNEFS_H */
-- 
1.5.3.2.g4f337



More information about the Ocfs2-tools-devel mailing list