[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