[Ocfs2-tools-devel] [PATCH 3/5] Add "Set sparse flag" to
ocfs2-tools, take 1
Tao Ma
tao.ma at oracle.com
Wed Oct 17 02:26:14 PDT 2007
"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 | 59 ++++++++++++++++
tunefs.ocfs2/sparse_file.c | 137 +++++++++++++++++++++++++++++++++++++
tunefs.ocfs2/tunefs.c | 61 +++++++++++++++--
tunefs.ocfs2/tunefs.h | 8 ++
7 files changed, 269 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 6ee68a4..6be6347 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..77fb89a
--- /dev/null
+++ b/tunefs.ocfs2/features.c
@@ -0,0 +1,59 @@
+/*
+ * 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 = 0;
+
+ if ((opts.set_feature.incompat &
+ OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) &&
+ ocfs2_sparse_alloc(OCFS2_RAW_SB(fs->fs_super)))
+ ret = 1;
+
+ 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 4877408..3499ae4 100644
--- a/tunefs.ocfs2/sparse_file.c
+++ b/tunefs.ocfs2/sparse_file.c
@@ -463,3 +463,140 @@ bail:
ocfs2_free(&buf);
return ret;
}
+
+static errcode_t fill_file_end(ocfs2_filesys *fs, struct ocfs2_dinode *di)
+{
+ errcode_t ret = 0;
+ char *buf = NULL, *data_buf = NULL;;
+ struct ocfs2_extent_rec *rec = NULL;
+ struct ocfs2_extent_list *el = NULL;
+ struct ocfs2_extent_block *eb = NULL;
+ uint64_t blkno, len_in_blk, last_cluster_start;
+ uint16_t offset, blk_off, bpc = fs->fs_clustersize / fs->fs_blocksize;
+
+ ret = ocfs2_malloc_block(fs->fs_io, &data_buf);
+ if (ret)
+ goto bail;
+
+ el = &di->id2.i_list;
+ if (el->l_tree_depth > 0) {
+ ret = ocfs2_malloc_block(fs->fs_io, &buf);
+ if (ret)
+ goto bail;
+
+ ret = ocfs2_read_extent_block(fs, di->i_last_eb_blk, buf);
+ if (ret)
+ goto bail;
+
+ eb = (struct ocfs2_extent_block *)buf;
+ el = &eb->h_list;
+ }
+
+ if (!el->l_next_free_rec)
+ goto bail;
+
+ rec = &el->l_recs[el->l_next_free_rec - 1];
+
+ offset = di->i_size % fs->fs_blocksize;
+ len_in_blk = (di->i_size + fs->fs_blocksize - 1) / fs->fs_blocksize;
+ blk_off = len_in_blk % bpc;
+
+ /*
+ * Although in a non-sparse file system a extent record doesn't have
+ * the extent flag, 2-bytes are still enough to store the length of
+ * the extent record. And the disk storage of OCFS2 is little endian,
+ * so we can use e_leaf_cluster here safely.
+ */
+ last_cluster_start = rec->e_blkno + (rec->e_leaf_clusters - 1) * bpc;
+ blkno = last_cluster_start + blk_off - 1;
+
+ /* first emtpy the extra byte in the last used block. */
+ ret = io_read_block(fs->fs_io, blkno, 1,data_buf);
+ if (ret)
+ goto bail;
+
+ memset(data_buf + offset, 0, fs->fs_blocksize - offset);
+ ret = io_write_block(fs->fs_io, blkno, 1, data_buf);
+ if (ret)
+ goto bail;
+
+ /* Then empty the extra blocks in the last cluster. */
+ memset(data_buf, 0, fs->fs_blocksize);
+ while (++blkno % bpc != 0) {
+ ret = io_write_block(fs->fs_io, blkno, 1, data_buf);
+ if (ret)
+ goto bail;
+ }
+
+bail:
+ if (data_buf)
+ ocfs2_free(&data_buf);
+ if (buf)
+ ocfs2_free(&buf);
+
+ return ret;
+}
+
+errcode_t set_sparse_file_flag(ocfs2_filesys *fs, char *progname)
+{
+ errcode_t ret;
+ uint64_t blkno;
+ char *buf;
+ struct ocfs2_dinode *di;
+ ocfs2_inode_scan *scan;
+ struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
+
+ 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");
+ goto out_close_scan;
+ }
+ 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_SYSTEM_FL)
+ continue;
+
+ if (S_ISREG(di->i_mode)) {
+ if (!(di->i_size % fs->fs_clustersize))
+ continue;
+
+ ret = fill_file_end(fs, di);
+ if (ret)
+ goto out_close_scan;
+ }
+ }
+
+ OCFS2_SET_INCOMPAT_FEATURE(super, OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC);
+
+out_close_scan:
+ ocfs2_close_inode_scan(scan);
+out_free:
+ ocfs2_free(&buf);
+
+out:
+ return ret;
+}
diff --git a/tunefs.ocfs2/tunefs.c b/tunefs.ocfs2/tunefs.c
index ed0a18f..035f69d 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;
@@ -1383,6 +1413,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 ||
@@ -1478,7 +1518,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;
}
@@ -1595,6 +1635,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 &&
@@ -1619,7 +1670,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