[Ocfs2-tools-devel] Patch of backup superblocks for ocfs2-tools.

tao.ma tao.ma at oracle.com
Wed Nov 29 00:50:56 PST 2006


Hi all,
     I implemented the backup superblock operations for ocfs2.
     Thanks joel for your advice about ocfs2_open and i_blkno in backup 
superblock now points to its own location so that it works ok.


-------------- next part --------------
ocfs2-tools: Add backup superblock for ocfs2.

mkfs.ocfs2: add backup superblock and '-n' to display backup blocks' location.

tunefs.ocfs2: add '-b' option to add backup superblocks for an old ocfs2 volume.

fsck.ocfs2: add '-r' option for superblock recovery.

debugfs.ocfs2: add '-s' option for the user to opening a fs
		using a backup superblock.

Index: fsck.ocfs2/fsck.c
===================================================================
--- fsck.ocfs2/fsck.c	(revision 1267)
+++ fsck.ocfs2/fsck.c	(working copy)
@@ -66,6 +66,8 @@
 #include "problem.h"
 #include "util.h"
 
+#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
+
 int verbose = 0;
 
 static char *whoami = "fsck.ocfs2";
@@ -74,13 +76,14 @@ static void print_usage(void)
 {
 	fprintf(stderr,
 		"Usage: fsck.ocfs2 [ -fGnuvVy ] [ -b superblock block ]\n"
-		"		    [ -B block size ] device\n"
+		"		    [ -B block size ] [-r num] device\n"
 		"\n"
 		"Critical flags for emergency repair:\n" 
 		" -n		Check but don't change the file system\n"
 		" -y		Answer 'yes' to all repair questions\n"
 		" -f		Force checking even if file system is clean\n"
 		" -F		Ignore cluster locking (dangerous!)\n"
+		" -r		restore backup superblock(very dangerous!)\n"
 		"\n"
 		"Less critical flags:\n"
 		" -b superblock	Treat given block as the super block\n"
@@ -191,6 +194,34 @@ static errcode_t write_out_superblock(o2
 	return ocfs2_write_super(ost->ost_fs);
 }
 
+static errcode_t update_backup_sb(o2fsck_state *ost)
+{
+	errcode_t ret;
+	struct ocfs2_dinode *di = ost->ost_fs->fs_super;
+	struct ocfs2_super_block *sb = OCFS2_RAW_SB(di);
+	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+
+	if (!(sb->s_feature_compat & OCFS2_FEATURE_COMPAT_BACKUP_SB))
+		return 0;
+
+	ret = ocfs2_get_backup_sb_offset(ost->ost_fs,
+					 blocks, ARRAY_LEN(blocks));
+	if (ret) {
+		com_err(whoami, ret,
+			"while getting backup superblock's offset.");
+		goto bail;
+	}
+
+	ret = ocfs2_set_backup_sb(ost->ost_fs, blocks, ARRAY_LEN(blocks));
+	if (ret) {
+		com_err(whoami, ret, "while backuping superblock.");
+		goto bail;
+	}
+
+bail:
+	return ret;
+}
+
 static void scale_time(time_t secs, unsigned *scaled, char **units)
 {
 	if (secs < 60) {
@@ -410,12 +441,60 @@ out:
 	return ret;
 }
 
+static errcode_t recover_backup_sb(o2fsck_state *ost, char* device, int sb_num)
+{
+	errcode_t ret;
+	uint64_t offsets[OCFS2_MAX_BACKUP_SUPERBLOCKS], blksize, sb;
+	ocfs2_filesys *fs = NULL;
+
+	if (sb_num < 1 || sb_num > OCFS2_MAX_BACKUP_SUPERBLOCKS)
+		return -1;
+ 	
+	ret = ocfs2_get_backup_sb_offset(NULL, offsets, ARRAY_LEN(offsets));
+	if (ret)
+		goto bail;
+
+	/* iterate all the blocksize to get the right one. */
+	for (blksize = OCFS2_MIN_BLOCKSIZE;
+		blksize <= OCFS2_MAX_BLOCKSIZE;	blksize <<= 1) {
+		sb = offsets[sb_num - 1] / blksize;
+		ret = ocfs2_open(device, OCFS2_FLAG_RW, sb, blksize, &fs);
+		if (!ret)
+			break;
+	}
+
+	if (ret)
+		goto bail;
+
+	/* recover the backup information to superblock. */
+	if (prompt(ost, PN, PR_RECOVER_BACKUP_SUPERBLOCK,
+	    	   "Recover superblock information from backup block"
+		   "#%"PRIu64"?", sb)) {
+		fs->fs_super->i_blkno = OCFS2_SUPER_BLOCK_BLKNO;
+		ret = ocfs2_write_super(fs);
+		if (ret)
+			goto bail;
+	}
+
+	/* no matter whether the user recover the superblock or not here, 
+	 * we should return 0 in case the superblock can be opened
+	 * without the recovery.
+	 */
+	ret = 0;
+
+bail:
+	if (fs)
+		ocfs2_close(fs);
+	return ret;
+}
+
 int main(int argc, char **argv)
 {
 	char *filename;
 	int64_t blkno, blksize;
 	o2fsck_state _ost, *ost = &_ost;
 	int c, open_flags = OCFS2_FLAG_RW | OCFS2_FLAG_STRICT_COMPAT_CHECK;
+	int sb_num = 0;
 	int fsck_mask = FSCK_OK;
 	errcode_t ret;
 
@@ -434,7 +513,7 @@ int main(int argc, char **argv)
 	setlinebuf(stderr);
 	setlinebuf(stdout);
 
-	while((c = getopt(argc, argv, "b:B:fFGnuvVy")) != EOF) {
+	while((c = getopt(argc, argv, "b:B:fFGnuvVyr:")) != EOF) {
 		switch (c) {
 			case 'b':
 				blkno = read_number(optarg);
@@ -496,6 +575,10 @@ int main(int argc, char **argv)
 				version();
 				break;
 
+			case 'r':
+				sb_num = read_number(optarg);
+				break;
+
 			default:
 				fsck_mask |= FSCK_USAGE;
 				print_usage();
@@ -531,6 +614,17 @@ int main(int argc, char **argv)
 
 	filename = argv[optind];
 
+	/* recover superblock should be called at first. */
+	if (sb_num) {
+		ret = recover_backup_sb(ost, filename, sb_num);
+		if (ret) {
+			com_err(whoami, ret, "recover superblock failed.\n");
+			fsck_mask |= FSCK_ERROR;
+			goto out;
+		}
+
+	}
+
 	ret = open_and_check(ost, filename, open_flags, blkno, blksize);
 	if (ret) {
 		fsck_mask |= FSCK_ERROR;
@@ -639,6 +733,12 @@ done:
 		if (ret)
 			com_err(whoami, ret, "while writing back the "
 				"superblock");
+		else {
+			ret = update_backup_sb(ost);
+			if (ret)
+				com_err(whoami, ret, 
+					"while backing superblock.");
+		}
 	}
 
 unlock:
Index: fsck.ocfs2/pass1.c
===================================================================
--- fsck.ocfs2/pass1.c	(revision 1267)
+++ fsck.ocfs2/pass1.c	(working copy)
@@ -1005,6 +1005,8 @@ static void write_cluster_alloc(o2fsck_s
 	errcode_t ret;
 	uint64_t blkno, last_cbit, cbit, cbit_found;
 	struct ocfs2_cluster_group_sizes cgs;
+	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS], *backup = NULL, bpc;
+	struct ocfs2_super_block *super = OCFS2_RAW_SB(ost->ost_fs->fs_super);
 
 	ocfs2_calc_cluster_groups(ost->ost_fs->fs_clusters,
 				  ost->ost_fs->fs_blocksize, &cgs);
@@ -1033,6 +1035,21 @@ static void write_cluster_alloc(o2fsck_s
 		goto out;
 	}
 
+	/* handle the condition of backup superblock. */
+	memset(&blocks, 0, sizeof(blocks));
+	bpc = ost->ost_fs->fs_clustersize / ost->ost_fs->fs_blocksize;
+	if (super->s_feature_compat & OCFS2_FEATURE_COMPAT_BACKUP_SB) {
+		ret = ocfs2_get_backup_sb_offset(ost->ost_fs, blocks, 
+					 sizeof(blocks) / sizeof(blocks[0]));
+		if (ret) {
+			/* Here we just output a warning and continue. */
+			com_err(whoami, ret, "while get backup superblock "
+				"offset");
+		}
+		else
+			backup = blocks;
+	}
+
 	/* we walk our found blocks bitmap to find clusters that we think
 	 * are in use.  each time we find a block in a cluster we skip ahead
 	 * to the first block of the next cluster when looking for the next.
@@ -1044,6 +1061,10 @@ static void write_cluster_alloc(o2fsck_s
 	 * we special case the number of clusters as the cluster offset which
 	 * indicates that the rest of the bits to the end of the bitmap
 	 * should be clear.
+	 *
+	 * we should take backup superblock as a special case since it doesn't
+	 * belong to any inode. So it shouldn't be exist in
+	 * ost->ost_allocated_clusters.
 	 */
 	for (last_cbit = 0, cbit = 0;
 	     cbit < ost->ost_fs->fs_clusters; 
@@ -1069,7 +1090,12 @@ static void write_cluster_alloc(o2fsck_s
 
 		/* clear set bits that should have been clear up to cbit */
 		while (cbit_found < cbit) {
-			force_cluster_bit(ost, ci, cbit_found, 0);
+			/* check the backup superblock */
+			if (backup && *backup &&
+				cbit_found == *backup / bpc)
+					backup++;
+			else
+				force_cluster_bit(ost, ci, cbit_found, 0);
 			cbit_found++;
 			ret = ocfs2_bitmap_find_next_set(ci->ci_chains, cbit_found, 
 							 &cbit_found);
Index: fsck.ocfs2/fsck.ocfs2.checks.8.in
===================================================================
--- fsck.ocfs2/fsck.ocfs2.checks.8.in	(revision 1267)
+++ fsck.ocfs2/fsck.ocfs2.checks.8.in	(working copy)
@@ -648,6 +648,12 @@ to finish the job of truncating and remo
 Answering yes removes the file data associated with the inode and frees
 the inode.
 
+.SS "RECOVER_BACKUP_SUPERBLOCK"
+A ocfs2 volume has many backup superblocks. User can recover the superblock 
+when it is corrupted.
+
+Answering yes will copy the backup block to the superblock location.
+
 .SH "SEE ALSO"
 .BR fsck.ocfs2(8)
 
Index: libocfs2/backup_sb.c
===================================================================
--- libocfs2/backup_sb.c	(revision 0)
+++ libocfs2/backup_sb.c	(revision 0)
@@ -0,0 +1,192 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * backup_sb.c
+ *
+ * Backup superblocks for an OCFS2 volume.
+ *
+ * Copyright (C) 2006 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.
+ * 
+ * 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 <errno.h>
+#include "ocfs2.h"
+
+/* The byte offset of the first backup block will be 1G.
+ * The following will be 4G, 16G, 256G and 1T.
+ */
+#define START_OFFSET	1 << 30
+
+#undef min
+#define min(a,b)	((a) < (b) ? (a) : (b))
+
+/* In case we don't have fs_blocksize, we will return
+ * byte offsets and let the caller calculate them by itself.
+ */
+int ocfs2_get_backup_sb_offset(ocfs2_filesys *fs, 
+			       uint64_t *offsets, size_t len)
+{
+	size_t i;
+	uint64_t blkno, byteoff = START_OFFSET;
+	uint32_t blocksize;
+	
+	memset(offsets, 0, sizeof(uint64_t) * len);
+	len = min(len, OCFS2_MAX_BACKUP_SUPERBLOCKS);
+
+	if (fs)
+		blocksize = fs->fs_blocksize;
+	else
+		blocksize = 1;
+
+	for (i = 0; i < len; i++) {
+		blkno = byteoff / blocksize;
+		if (fs && fs->fs_blocks <= blkno)
+			break;
+	
+		offsets[i] = blkno;
+		byteoff = byteoff << 2;
+	}
+	return 0;
+}
+
+/* verify the blocks and return the length of the blocks. */
+static errcode_t verify_block_allocation(ocfs2_bitmap *bitmap, uint32_t bpc,
+					 uint64_t *blocks, size_t *len)
+{
+	size_t i;
+	errcode_t ret;
+	int val;
+
+	for (i = 0; i < *len; i++, blocks++) {
+		if (!*blocks)
+			break;
+
+		ret = ocfs2_bitmap_test(bitmap, *blocks / bpc, &val);
+		if (ret)
+			goto bail;
+
+		if (val) {
+			ret = ENOSPC;
+			goto bail;
+		}
+	}
+	*len = i;
+	ret = 0;
+	
+bail:
+	return ret;
+}
+
+/* 
+ * This function will backup superblock in the given blocks.
+ * And add the compat flag to superblock if needed.
+ */
+errcode_t ocfs2_set_backup_sb(ocfs2_filesys *fs, uint64_t *blocks, size_t len)
+{
+	size_t i;
+	errcode_t ret = 0;
+	char *buf = NULL;
+	uint64_t bm_blk, sb_blk, *blkno = blocks;
+	int val;
+	uint32_t compat;
+	struct ocfs2_dinode *di = NULL;
+	struct ocfs2_super_block *sb = NULL;
+	uint32_t bpc = fs->fs_clustersize / fs->fs_blocksize;
+
+	if (!len || !blocks || !*blocks)
+		goto bail;
+	len = min(len, OCFS2_MAX_BACKUP_SUPERBLOCKS);
+
+	if (!fs->fs_cluster_alloc) {
+		ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE,
+						0, &bm_blk);
+		if (ret)
+			goto bail;
+
+		ret = ocfs2_read_cached_inode(fs, bm_blk, &fs->fs_cluster_alloc);
+		if (ret)
+			goto bail;
+
+		ret = ocfs2_load_chain_allocator(fs, fs->fs_cluster_alloc);
+		if (ret)
+			goto bail;
+	}
+
+	if (!(OCFS2_RAW_SB(fs->fs_super)->s_feature_compat &
+				OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+		ret = verify_block_allocation(fs->fs_cluster_alloc->ci_chains,
+						    bpc, blocks, &len);
+		if (ret)
+			goto bail;
+	}
+
+	/* we get the superblock information from the disk. */
+	sb_blk = fs->fs_super->i_blkno;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto bail;
+
+	ret = io_read_block(fs->fs_io, sb_blk, 1, buf);
+	if (ret)
+		goto bail;	
+
+	di = (struct ocfs2_dinode *)buf;
+	sb = OCFS2_RAW_SB(di);
+
+	compat = le32_to_cpu(sb->s_feature_compat);
+
+	if (!(compat & OCFS2_FEATURE_COMPAT_BACKUP_SB))
+		sb->s_feature_compat |=
+				 cpu_to_le32(OCFS2_FEATURE_COMPAT_BACKUP_SB);
+
+	for (i = 0; i < len; i++, blkno++) {
+		di->i_blkno = cpu_to_le32(*blkno);
+		ret = io_write_block(fs->fs_io, *blkno, 1, buf);
+		if (ret)
+			goto bail;
+	}
+
+	blkno = blocks;
+	for (i = 0; i < len; i++, blkno++)
+		ocfs2_bitmap_set(fs->fs_cluster_alloc->ci_chains,
+				 *blkno / bpc, &val);
+
+	ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc);
+	if (ret)
+		goto bail;
+
+	/* write the compat flag back to the superblock if unset. */
+	if (!(compat & OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+		di->i_blkno = cpu_to_le32(OCFS2_SUPER_BLOCK_BLKNO);
+		ret = io_write_block(fs->fs_io, sb_blk, 1, buf);
+		if (ret)
+			goto bail;
+	}
+
+	/* make fs hold the same information as that on the disk. */
+	OCFS2_RAW_SB(fs->fs_super)->s_feature_compat |= 
+					OCFS2_FEATURE_COMPAT_BACKUP_SB;
+bail:
+	if (buf)
+		ocfs2_free(&buf);
+	if (fs->fs_cluster_alloc) {
+		ocfs2_free_cached_inode(fs, fs->fs_cluster_alloc);
+		fs->fs_cluster_alloc = NULL;
+	}
+	return ret;
+}
Index: libocfs2/Makefile
===================================================================
--- libocfs2/Makefile	(revision 1267)
+++ libocfs2/Makefile	(working copy)
@@ -80,7 +80,8 @@ CFILES = 		\
 	truncate.c	\
 	unix_io.c	\
 	unlink.c	\
-	lockid.c
+	lockid.c	\
+	backup_sb.c
 
 HFILES =				\
 	include/bitmap.h		\
Index: libocfs2/include/ocfs2.h
===================================================================
--- libocfs2/include/ocfs2.h	(revision 1267)
+++ libocfs2/include/ocfs2.h	(working copy)
@@ -79,7 +79,8 @@
 
 #define OCFS2_LIB_FEATURE_RO_COMPAT_SUPP	OCFS2_FEATURE_RO_COMPAT_SUPP
 
-#define OCFS2_LIB_FEATURE_COMPAT_SUPP		OCFS2_FEATURE_COMPAT_SUPP
+#define OCFS2_LIB_FEATURE_COMPAT_SUPP		(OCFS2_FEATURE_COMPAT_SUPP |	\
+						 OCFS2_FEATURE_COMPAT_BACKUP_SB)	
 
 /* Flags for the ocfs2_filesys structure */
 #define OCFS2_FLAG_RO			0x00
@@ -178,6 +179,9 @@
 #define OCFS2_CHB_WAITING	2
 #define OCFS2_CHB_COMPLETE	3
 
+/* the max backup superblock nums */
+#define OCFS2_MAX_BACKUP_SUPERBLOCKS	6
+
 typedef void (*ocfs2_chb_notify)(int state, char *progress, void *data);
 
 typedef struct _ocfs2_filesys ocfs2_filesys;
@@ -608,6 +612,20 @@ errcode_t ocfs2_encode_lockres(enum ocfs
 errcode_t ocfs2_decode_lockres(char *lockres, int len, enum ocfs2_lock_type *type,
 			       uint64_t *blkno, uint32_t *generation);
 
+/* get the blkno according to the file system info.
+ * The unused ones, depending on the volume size, are zeroed. 
+ */
+int ocfs2_get_backup_sb_offset(ocfs2_filesys *fs, 
+			       uint64_t *blocks, size_t len);
+
+/* This function will get the superblock pointed to by fs and copy it to
+ * the blocks. But first it will ensure all the appropriate clusters are free.
+ * If not, it will error out with ENOSPC. If free, it will set bits for all 
+ * the clusters, zero the full cluster and write the backup sb. 
+ * In case of updating, it will override the backup blocks with the newest
+ * superblock information.
+ */
+errcode_t ocfs2_set_backup_sb(ocfs2_filesys *fs, uint64_t *blocks, size_t len);
 
 /* 
  * ${foo}_to_${bar} is a floor function.  blocks_to_clusters will
Index: libocfs2/include/ocfs2_fs.h
===================================================================
--- libocfs2/include/ocfs2_fs.h	(revision 1267)
+++ libocfs2/include/ocfs2_fs.h	(working copy)
@@ -103,6 +103,12 @@
  */
 #define OCFS2_FEATURE_INCOMPAT_RESIZE_INPROG    0x0004
 
+/* 
+ * backup superblock flag is used to indicate that this volume
+ * has backup superblocks.
+ */
+#define OCFS2_FEATURE_COMPAT_BACKUP_SB		0x0008
+
 /*
  * Flags on ocfs2_dinode.i_flags
  */
Index: mkfs.ocfs2/mkfs.c
===================================================================
--- mkfs.ocfs2/mkfs.c	(revision 1267)
+++ mkfs.ocfs2/mkfs.c	(working copy)
@@ -84,6 +84,7 @@ static AllocGroup * initialize_alloc_gro
 					   uint16_t bpc);
 static void create_lost_found_dir(State *s);
 static void format_journals(State *s);
+static void format_backup_sb(State *s);
 
 extern char *optarg;
 extern int optind, opterr, optopt;
@@ -438,6 +439,14 @@ main(int argc, char **argv)
 	if (!s->quiet)
 		printf("done\n");
 
+	if (!s->quiet)
+		printf("Writing backup superblock: ");
+
+	format_backup_sb(s);
+
+	if (!s->quiet)
+		printf("done\n");
+
 	if (!s->hb_dev) {
 		/* These routines use libocfs2 to do their work. We
 		 * don't share an ocfs2_filesys context between the
@@ -503,6 +512,7 @@ get_state(int argc, char **argv)
 	State *s;
 	int c;
 	int verbose = 0, quiet = 0, force = 0, xtool = 0, hb_dev = 0;
+	int backup = 0;
 	int show_version = 0;
 	char *device_name;
 	int ret;
@@ -521,6 +531,7 @@ get_state(int argc, char **argv)
 		{ "journal-options", 0, 0, 'J'},
 		{ "heartbeat-device", 0, 0, 'H'},
 		{ "force", 0, 0, 'F'},
+		{ "num-backup", 0, 0, 'n'},
 		{ 0, 0, 0, 0}
 	};
 
@@ -530,8 +541,8 @@ get_state(int argc, char **argv)
 		progname = strdup("mkfs.ocfs2");
 
 	while (1) {
-		c = getopt_long(argc, argv, "b:C:L:N:J:vqVFHxT:", long_options, 
-				NULL);
+		c = getopt_long(argc, argv, "b:C:L:N:J:vqVFHxT:n",
+				long_options, NULL);
 
 		if (c == -1)
 			break;
@@ -637,6 +648,10 @@ get_state(int argc, char **argv)
 			parse_fs_type_opts(progname, optarg, &fs_type);
 			break;
 
+		case 'n':
+			backup = 1;
+			break;
+
 		default:
 			usage(progname);
 			break;
@@ -697,6 +712,8 @@ get_state(int argc, char **argv)
 
 	s->hb_dev = hb_dev;
 
+	s->backup = backup;
+
 	s->fs_type = fs_type;
 
 	return s;
@@ -810,7 +827,7 @@ usage(const char *progname)
 {
 	fprintf(stderr, "Usage: %s [-b block-size] [-C cluster-size] "
 			"[-N number-of-node-slots] [-T filesystem-type]\n"
-			"\t[-L volume-label] [-J journal-options] [-HFqvV] "
+			"\t[-L volume-label] [-J journal-options] [-HFqvVn] "
 			"device [blocks-count]\n",
 			progname);
 	exit(0);
@@ -2222,3 +2239,44 @@ error:
 	clear_both_ends(s);
 	exit(1);
 }
+
+static void format_backup_sb(State *s)
+{
+	errcode_t ret;
+	ocfs2_filesys *fs = NULL;
+	size_t i;
+	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+
+	ret = ocfs2_open(s->device_name, OCFS2_FLAG_RW, 0, 0, &fs);
+	if (ret) {
+		com_err(s->progname, ret,
+			"while opening file system for backup superblock.");
+		goto error;
+	}
+
+#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
+	ret = ocfs2_get_backup_sb_offset(fs, blocks, ARRAY_LEN(blocks));
+	if (ret) {
+		com_err(s->progname, ret, 
+			"while getting backup superblock's offset.");
+		goto error;
+	}
+
+	ret = ocfs2_set_backup_sb(fs, blocks, ARRAY_LEN(blocks));
+	if (ret) {
+		com_err(s->progname, ret, "while backuping superblock.");
+		goto error;
+	}
+
+	if (s->backup) {
+		for (i = 0; i < ARRAY_LEN(blocks) && blocks[i]; i++)
+			printf(" %"PRIu64" ", blocks[i] * fs->fs_blocksize);
+	}
+
+	ocfs2_close(fs);
+	return;
+
+error:
+	clear_both_ends(s);
+	exit(1);
+}
Index: mkfs.ocfs2/mkfs.h
===================================================================
--- mkfs.ocfs2/mkfs.h	(revision 1267)
+++ mkfs.ocfs2/mkfs.h	(working copy)
@@ -197,6 +197,7 @@ struct _State {
 	int force;
 	int prompt;
 	int hb_dev;
+	int backup;
 
 	uint32_t blocksize;
 	uint32_t blocksize_bits;
Index: tunefs.ocfs2/tunefs.c
===================================================================
--- tunefs.ocfs2/tunefs.c	(revision 1267)
+++ tunefs.ocfs2/tunefs.c	(working copy)
@@ -64,6 +64,8 @@
 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
 #endif
 
+#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
+
 typedef struct _ocfs2_tune_opts {
 	uint16_t num_slots;
 	uint64_t num_blocks;
@@ -75,6 +77,7 @@ typedef struct _ocfs2_tune_opts {
 	int verbose;
 	int quiet;
 	int prompt;
+	int backup_sb;
 	time_t tune_time;
 	int fd;
 } ocfs2_tune_opts;
@@ -88,7 +91,7 @@ static void usage(const char *progname)
 {
 	fprintf(stderr, "usage: %s [-N number-of-node-slots] "
 			"[-L volume-label]\n"
-			"\t[-J journal-options] [-qSUvV] "
+			"\t[-J journal-options] [-b] [-qSUvV] "
 			"device [blocks-count]\n",
 			progname);
 	exit(0);
@@ -247,6 +250,7 @@ static void get_options(int argc, char *
 		{ "journal-options", 0, 0, 'J'},
 		{ "volume-size", 0, 0, 'S'},
 		{ "uuid-reset", 0, 0, 'U'},
+		{ "backup-sb", 0, 0, 'b'},
 		{ 0, 0, 0, 0}
 	};
 
@@ -258,7 +262,7 @@ static void get_options(int argc, char *
 	opts.prompt = 1;
 
 	while (1) {
-		c = getopt_long(argc, argv, "L:N:J:SUvqVx", long_options,
+		c = getopt_long(argc, argv, "L:N:J:SUvqVxb", long_options,
 				NULL);
 
 		if (c == -1)
@@ -324,6 +328,10 @@ static void get_options(int argc, char *
 			opts.prompt = 0;
 			break;
 
+		case 'b':
+			opts.backup_sb =  1;
+			break;
+
 		default:
 			usage(opts.progname);
 			break;
@@ -751,6 +759,85 @@ bail:
 	return ret;
 }
 
+static inline errcode_t load_chain_allocator(ocfs2_filesys *fs,
+					     ocfs2_cached_inode** inode)
+{
+	errcode_t ret;
+	uint64_t blkno;
+
+	ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE,
+					0, &blkno);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_read_cached_inode(fs, blkno, inode);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_load_chain_allocator(fs, *inode);
+
+bail:
+	return ret;
+}
+
+static errcode_t backup_sb_check(ocfs2_filesys *fs)
+{
+	errcode_t ret;
+	int i, val, failed = 0;
+	ocfs2_cached_inode *chain_alloc = NULL;
+	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+	uint32_t bpc = fs->fs_clustersize / fs->fs_blocksize;
+	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
+
+	/* if the compat flag is set, just return. */
+	if (super->s_feature_compat & OCFS2_FEATURE_COMPAT_BACKUP_SB) {
+		com_err(opts.progname, 0,
+			"This volume already has backup superblocks");
+		return -1;
+	}
+
+	ret = ocfs2_get_backup_sb_offset(fs, blocks, ARRAY_LEN(blocks));
+	if (ret)
+		goto bail;
+
+	ret = load_chain_allocator(fs, &chain_alloc);
+	if (ret)
+		goto bail;
+
+	for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
+		if (!blocks[i])
+			break;
+
+		ret = ocfs2_bitmap_test(chain_alloc->ci_chains,
+					blocks[i] / bpc, &val);
+		if (ret)
+			goto bail;
+
+		if (val) {
+			com_err(opts.progname, 0, "block %"PRIu64
+				" is already allocated.", blocks[i]);
+			/* in order to verify all the block in the 'blocks',
+			 * we don't stop the loop here.
+			 */
+			failed = 1;
+		}
+	}
+
+	if (failed) {
+		ret = ENOSPC;
+		com_err(opts.progname, 0, "backup blocks check failed.");
+		com_err(opts.progname, 0, "Run debugfs.ocfs2 and use command"
+			" 'icheck' to detect the block's owner.");
+		com_err(opts.progname,0, "Please delete (after backing up them)"
+			" the files and try again.");
+	}
+
+	if (chain_alloc)
+		ocfs2_free_cached_inode(fs, chain_alloc);
+bail:
+	return ret;
+} 
+
 static void update_volume_label(ocfs2_filesys *fs, int *changed)
 {
   	memset (OCFS2_RAW_SB(fs->fs_super)->s_label, 0,
@@ -1092,6 +1179,27 @@ bail:
 	return ret;
 }
 
+static errcode_t update_backup_sb(ocfs2_filesys *fs)
+{
+	errcode_t ret;
+	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+	
+	ret = ocfs2_get_backup_sb_offset(fs, blocks, ARRAY_LEN(blocks));
+	if (ret) {
+		com_err(opts.progname, ret, "while getting backup superblock's offset.");
+		goto bail;
+	}
+
+	ret = ocfs2_set_backup_sb(fs, blocks, ARRAY_LEN(blocks));
+	if (ret) {
+		com_err(opts.progname, ret, "while backuping superblock.");
+		goto bail;
+	}
+
+bail:
+	return ret;
+}
+
 int main(int argc, char **argv)
 {
 	errcode_t ret = 0;
@@ -1185,6 +1293,14 @@ int main(int argc, char **argv)
 		}
 	}
 
+	/* check whether the block for backup superblock are used. */
+	if (opts.backup_sb) {
+		if (backup_sb_check(fs))
+			goto unlock;
+		else
+			printf("Adding backup superblock for the volume\n");
+	}
+
 	/* validate volume label */
 	if (opts.vol_label) {
 		printf("Changing volume label from %s to %s\n",
@@ -1247,7 +1363,7 @@ int main(int argc, char **argv)
 	}
 
 	if (!opts.vol_label && !opts.vol_uuid && !opts.num_slots &&
-	    !opts.jrnl_size && !opts.num_blocks) {
+	    !opts.jrnl_size && !opts.num_blocks && !opts.backup_sb) {
 		com_err(opts.progname, 0, "Nothing to do. Exiting.");
 		goto unlock;
 	}
@@ -1337,6 +1453,31 @@ int main(int argc, char **argv)
 		}
 		block_signals(SIG_UNBLOCK);
 		printf("Wrote Superblock\n");
+
+		/* superblock's information has changed.
+		 * we need to synchronize the backup blocks if needed.
+		 */
+		if (OCFS2_RAW_SB(fs->fs_super)->s_feature_compat &
+					OCFS2_FEATURE_COMPAT_BACKUP_SB) {
+			ret = update_backup_sb(fs);
+			if (ret) {
+				printf("warning, superblock changed and "
+					"failed to synchronsize the backup "
+					"blocks.");
+			}
+			else
+				printf("Updated backup superblock.\n");
+		}
+	}
+
+	if (opts.backup_sb) {
+		ret = update_backup_sb(fs);
+		if (ret) {
+			com_err(opts.progname, ret,
+				"while backuping superblock");
+			goto unlock;
+		}
+		printf("Backuped Superblock.\n");
 	}
 
 unlock:
Index: debugfs.ocfs2/commands.c
===================================================================
--- debugfs.ocfs2/commands.c	(revision 1267)
+++ debugfs.ocfs2/commands.c	(working copy)
@@ -293,6 +293,70 @@ static int process_inodestr_args(char **
 }
 
 /*
+ * process_open_args
+ *
+ */
+static int process_open_args(char **args, 
+			     uint64_t *superblock, uint64_t *blocksize)
+{
+	errcode_t ret;
+	long s;
+	char *ptr;
+	int ind = 2;
+	ocfs2_filesys *fs = NULL;
+	uint64_t byte_off[OCFS2_MAX_BACKUP_SUPERBLOCKS], sb, blksize;
+
+	*superblock = 0;
+	*blocksize = 0;
+
+	if (!args[ind])
+		return 0;
+
+	if (args[ind] && !strcmp(args[ind], "-s"))
+		ind++;
+	else
+		return -1;
+
+	if(!args[ind])
+		return -1;
+		
+	s = strtol(args[ind], &ptr, 0);
+
+	if (s < 1 || s > OCFS2_MAX_BACKUP_SUPERBLOCKS) {
+		fprintf (stderr, "num exceeds limit\n");
+		return -1;
+	}
+
+
+	ret = ocfs2_get_backup_sb_offset(NULL, byte_off,
+			 sizeof(byte_off) / sizeof(byte_off[0]));
+	if (ret)
+		goto bail;
+
+	/* iterate all the blocksize and get the right one. */
+	for (blksize = OCFS2_MIN_BLOCKSIZE;
+		blksize <= OCFS2_MAX_BLOCKSIZE;	blksize <<= 1) {
+		sb = byte_off[s-1] / blksize;
+		ret = ocfs2_open(args[1], OCFS2_FLAG_RO, sb, blksize, &fs);
+		if (!ret)
+			break;
+	}
+
+	if (ret) {
+		com_err(args[0],ret, "Can't open device by the num\n");
+		goto bail;
+	}
+
+	*superblock = sb;
+	*blocksize = blksize;
+
+	if (fs)
+		ocfs2_close(fs);
+bail:
+	return ret;
+}
+	
+/*
  * get_slotnum()
  *
  */
@@ -473,18 +537,19 @@ static void do_open (char **args)
 	char sysfile[SYSTEM_FILE_NAME_MAX];
 	int i;
 	struct ocfs2_super_block *sb;
+	uint64_t superblock, block_size;
 
 	if (gbls.device)
 		do_close (NULL);
 
-	if (dev == NULL) {
-		fprintf (stderr, "usage: %s <device>\n", args[0]);
+	if (dev == NULL || process_open_args(args, &superblock, &block_size)) {
+		fprintf (stderr, "usage: %s <device> [-s num]\n", args[0]);
 		return ;
 	}
 
 	flags = gbls.allow_write ? OCFS2_FLAG_RW : OCFS2_FLAG_RO;
         flags |= OCFS2_FLAG_HEARTBEAT_DEV_OK;
-	ret = ocfs2_open(dev, flags, 0, 0, &gbls.fs);
+	ret = ocfs2_open(dev, flags, superblock, block_size, &gbls.fs);
 	if (ret) {
 		gbls.fs = NULL;
 		com_err(args[0], ret, "while opening context for device %s",
@@ -684,7 +749,7 @@ static void do_help (char **args)
 	printf ("logdump <slot#>\t\t\t\tPrints journal file for the node slot\n");
 	printf ("ls [-l] <filespec>\t\t\tList directory\n");
 	printf ("ncheck <block#> ...\t\t\tList all pathnames of the inode(s)/lockname(s)\n");
-	printf ("open <device>\t\t\t\tOpen a device\n");
+	printf ("open <device> [-s num]\t\t\t\tOpen a device\n");
 	printf ("quit, q\t\t\t\t\tExit the program\n");
 	printf ("rdump [-v] <filespec> <outdir>\t\tRecursively dumps from src to a dir on a mounted filesystem\n");
 	printf ("slotmap\t\t\t\t\tShow slot map\n");
Index: debugfs.ocfs2/include/main.h
===================================================================
--- debugfs.ocfs2/include/main.h	(revision 1267)
+++ debugfs.ocfs2/include/main.h	(working copy)
@@ -88,6 +88,7 @@ typedef struct _dbgfs_glbs {
 typedef struct _dbgfs_opts {
 	int allow_write;
 	int no_prompt;
+	int sb_num;
 	char *cmd_file;
 	char *one_cmd;
 	char *device;
Index: debugfs.ocfs2/main.c
===================================================================
--- debugfs.ocfs2/main.c	(revision 1267)
+++ debugfs.ocfs2/main.c	(working copy)
@@ -51,9 +51,10 @@ static void usage (char *progname)
 	g_print ("usage: %s -l [<logentry> ... [allow|off|deny]] ...\n", progname);
 	g_print ("usage: %s -d, --decode <lockres>\n", progname);
 	g_print ("usage: %s -e, --encode <lock type> <block num> <generation>\n", progname);
-	g_print ("usage: %s [-f cmdfile] [-R request] [-V] [-w] [-n] [-?] [device]\n", progname);
+	g_print ("usage: %s [-f cmdfile] [-R request] [-s block] [-V] [-w] [-n] [-?] [device]\n", progname);
 	g_print ("\t-f, --file <cmdfile>\tExecute commands in cmdfile\n");
 	g_print ("\t-R, --request <command>\tExecute a single command\n");
+	g_print ("\t-s, --superblock <num>\tOpen the device using another superblock\n");
 	g_print ("\t-w, --write\t\tOpen in read-write mode instead of the default of read-only\n");
 	g_print ("\t-V, --version\t\tShow version\n");
 	g_print ("\t-n, --noprompt\t\tHide prompt\n");
@@ -188,6 +189,7 @@ static void process_encode_lockres(int a
 static void get_options(int argc, char **argv, dbgfs_opts *opts)
 {
 	int c;
+	char *ptr = NULL;
 	static struct option long_options[] = {
 		{ "file", 1, 0, 'f' },
 		{ "request", 1, 0, 'R' },
@@ -198,6 +200,7 @@ static void get_options(int argc, char *
 		{ "noprompt", 0, 0, 'n' },
 		{ "decode", 0, 0, 'd' },
 		{ "encode", 0, 0, 'e' },
+		{ "superblock", 0, 0, 's' },
 		{ 0, 0, 0, 0}
 	};
 
@@ -205,7 +208,7 @@ static void get_options(int argc, char *
 		if (decodemode || encodemode || logmode)
 			break;
 
-		c = getopt_long(argc, argv, "lf:R:deV?wn", long_options, NULL);
+		c = getopt_long(argc, argv, "lf:R:deV?wns:", long_options, NULL);
 		if (c == -1)
 			break;
 
@@ -257,6 +260,10 @@ static void get_options(int argc, char *
 			exit(0);
 			break;
 
+		case 's':
+			opts->sb_num = strtol(optarg, &ptr, 0);
+			break; 
+			
 		default:
 			usage(gbls.progname);
 			break;
@@ -476,7 +483,10 @@ int main (int argc, char **argv)
 		gbls.interactive++;
 
 	if (opts.device) {
-		line = g_strdup_printf ("open %s", opts.device);
+		if (opts.sb_num)
+			line = g_strdup_printf ("open %s -s %d", opts.device, opts.sb_num);
+		else
+			line = g_strdup_printf ("open %s", opts.device);
 		do_command (line);
 		g_free (line);
 	}


More information about the Ocfs2-tools-devel mailing list