[Ocfs2-tools-devel] Add --no-backup-super in backup superblock
patches and resend them.
tao.ma
tao.ma at oracle.com
Wed Jan 10 19:09:39 PST 2007
-------------- next part --------------
Index: ocfs2-tools/debugfs.ocfs2/commands.c
===================================================================
--- ocfs2-tools.orig/debugfs.ocfs2/commands.c 2007-01-09 09:10:54.000000000 -0500
+++ ocfs2-tools/debugfs.ocfs2/commands.c 2007-01-09 09:15:02.000000000 -0500
@@ -294,6 +294,99 @@
return i;
}
+/* open the device, read the block from the device and get the
+ * blocksize from the offset of the ocfs2_super_block.
+ */
+static errcode_t get_blocksize(char* dev, uint64_t offset, uint64_t *blocksize)
+{
+ errcode_t ret;
+ uint64_t blkno;
+ uint32_t blocksize_bits;
+ char *buf = NULL;
+ io_channel* channel = NULL;
+ struct ocfs2_dinode *di = NULL;
+
+ ret = io_open(dev, OCFS2_FLAG_RO, &channel);
+ if (ret)
+ goto bail;
+
+ /* since ocfs2_super_block inode can be stored in OCFS2_MIN_BLOCKSIZE,
+ * so here we just use the minimum block size and read the information
+ * in the specific offset.
+ */
+ ret = io_set_blksize(channel, OCFS2_MIN_BLOCKSIZE);
+ if (ret)
+ goto bail;
+
+ ret = ocfs2_malloc_block(channel, &buf);
+ if (ret)
+ goto bail;
+
+ blkno = offset / OCFS2_MIN_BLOCKSIZE;
+ ret = io_read_block(channel, blkno, 1, buf);
+ if (ret)
+ goto bail;
+
+ di = (struct ocfs2_dinode *)buf;
+ blocksize_bits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
+ *blocksize = 1ULL << blocksize_bits;
+bail:
+ if (buf)
+ ocfs2_free(&buf);
+ if (channel)
+ io_close(channel);
+ return ret;
+}
+/*
+ * process_open_args
+ *
+ */
+static int process_open_args(char **args,
+ uint64_t *superblock, uint64_t *blocksize)
+{
+ errcode_t ret = 0;
+ uint32_t s;
+ char *ptr;
+ uint64_t byte_off[OCFS2_MAX_BACKUP_SUPERBLOCKS], blksize;
+ int num, ind = 2;
+
+ if (!args[ind])
+ return 0;
+
+ if (args[ind] && !strcmp(args[ind], "-s"))
+ ind++;
+ else
+ return -1;
+
+ if(!args[ind])
+ return -1;
+
+ num = ocfs2_get_backup_super_offset(NULL,
+ byte_off, ARRAY_SIZE(byte_off));
+ if (!num)
+ return -1;
+
+ s = strtoul(args[ind], &ptr, 0);
+ if (s < 1 || s > num) {
+ fprintf (stderr, "Backup super block is outside of valid range"
+ "(between 1 and %d)\n", num);
+ return -1;
+ }
+
+ ret = get_blocksize(args[1], byte_off[s-1], &blksize);
+ if (ret) {
+ com_err(args[0],ret, "Can't get the blocksize from the device"
+ " by the num %u\n", s);
+ goto bail;
+ }
+
+ *blocksize = blksize;
+ *superblock = byte_off[s-1]/blksize;
+ ret = 0;
+bail:
+ return ret;
+}
+
/*
* get_slotnum()
*
@@ -475,18 +568,19 @@
char sysfile[SYSTEM_FILE_NAME_MAX];
int i;
struct ocfs2_super_block *sb;
+ uint64_t superblock = 0, block_size = 0;
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",
@@ -687,7 +781,7 @@
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 backup#]\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: ocfs2-tools/debugfs.ocfs2/include/main.h
===================================================================
--- ocfs2-tools.orig/debugfs.ocfs2/include/main.h 2007-01-09 09:10:54.000000000 -0500
+++ ocfs2-tools/debugfs.ocfs2/include/main.h 2007-01-09 09:15:02.000000000 -0500
@@ -88,6 +88,7 @@
typedef struct _dbgfs_opts {
int allow_write;
int no_prompt;
+ uint32_t sb_num;
char *cmd_file;
char *one_cmd;
char *device;
Index: ocfs2-tools/debugfs.ocfs2/main.c
===================================================================
--- ocfs2-tools.orig/debugfs.ocfs2/main.c 2007-01-09 09:10:54.000000000 -0500
+++ ocfs2-tools/debugfs.ocfs2/main.c 2007-01-09 09:15:02.000000000 -0500
@@ -51,9 +51,10 @@
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 backup#] [-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 <backup#>\tOpen the device using a backup 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 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 @@
{ "noprompt", 0, 0, 'n' },
{ "decode", 0, 0, 'd' },
{ "encode", 0, 0, 'e' },
+ { "superblock", 0, 0, 's' },
{ 0, 0, 0, 0}
};
@@ -205,7 +208,7 @@
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 @@
exit(0);
break;
+ case 's':
+ opts->sb_num = strtoul(optarg, &ptr, 0);
+ break;
+
default:
usage(gbls.progname);
break;
@@ -476,7 +483,10 @@
gbls.interactive++;
if (opts.device) {
- line = g_strdup_printf ("open %s", opts.device);
+ if (opts.sb_num)
+ line = g_strdup_printf ("open %s -s %u", opts.device, opts.sb_num);
+ else
+ line = g_strdup_printf ("open %s", opts.device);
do_command (line);
g_free (line);
}
-------------- next part --------------
Index: ocfs2-tools/fsck.ocfs2/pass1.c
===================================================================
--- ocfs2-tools.orig/fsck.ocfs2/pass1.c 2007-01-09 09:10:49.000000000 -0500
+++ ocfs2-tools/fsck.ocfs2/pass1.c 2007-01-09 09:15:02.000000000 -0500
@@ -1023,6 +1023,18 @@
return ret;
}
+static inline int bit_in_backup_super(uint64_t bit,
+ uint32_t *clusters, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (bit == clusters[i])
+ return 1;
+ }
+ return 0;
+}
+
/* once we've iterated all the inodes we should have the current working
* set of which blocks we think are in use. we use this to derive the set
* of clusters that should be allocated in the cluster chain allocators. we
@@ -1033,6 +1045,9 @@
errcode_t ret;
uint64_t blkno, last_cbit, cbit, cbit_found;
struct ocfs2_cluster_group_sizes cgs;
+ uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+ uint32_t clusters[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+ int backup_super = 0, num = 0, i;
ocfs2_calc_cluster_groups(ost->ost_fs->fs_clusters,
ost->ost_fs->fs_blocksize, &cgs);
@@ -1061,6 +1076,22 @@
goto out;
}
+ /* handle the condition of backup superblock. */
+ memset(&blocks, 0, sizeof(blocks));
+ memset(&clusters, 0, sizeof(clusters));
+ if (OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(ost->ost_fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+ num = ocfs2_get_backup_super_offset(ost->ost_fs, blocks,
+ ARRAY_SIZE(blocks));
+ if (num) {
+ backup_super = 1;
+ for (i = 0; i < num; i++)
+ clusters[i] =
+ ocfs2_blocks_to_clusters(ost->ost_fs,
+ blocks[i]);
+ }
+ }
+
/* 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.
@@ -1072,6 +1103,10 @@
* 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;
@@ -1097,7 +1132,13 @@
/* clear set bits that should have been clear up to cbit */
while (cbit_found < cbit) {
- force_cluster_bit(ost, ci, cbit_found, 0);
+ /* check whether the volume has backup blocks
+ * and if yes, check whether the cluster contains
+ * one of the backup blocks.
+ */
+ if (!backup_super ||
+ !bit_in_backup_super(cbit_found, clusters, num))
+ force_cluster_bit(ost, ci, cbit_found, 0);
cbit_found++;
ret = ocfs2_bitmap_find_next_set(ci->ci_chains, cbit_found,
&cbit_found);
Index: ocfs2-tools/fsck.ocfs2/fsck.c
===================================================================
--- ocfs2-tools.orig/fsck.ocfs2/fsck.c 2007-01-09 09:10:49.000000000 -0500
+++ ocfs2-tools/fsck.ocfs2/fsck.c 2007-01-09 09:15:02.000000000 -0500
@@ -74,13 +74,14 @@
{
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 +192,32 @@
return ocfs2_write_super(ost->ost_fs);
}
+static errcode_t update_backup_super(o2fsck_state *ost)
+{
+ errcode_t ret;
+ int num;
+ 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 (!OCFS2_HAS_COMPAT_FEATURE(sb, OCFS2_FEATURE_COMPAT_BACKUP_SB))
+ return 0;
+
+ num = ocfs2_get_backup_super_offset(ost->ost_fs,
+ blocks, ARRAY_SIZE(blocks));
+ if (!num)
+ return 0;
+
+ ret = ocfs2_refresh_backup_super(ost->ost_fs, blocks, num);
+ if (ret) {
+ com_err(whoami, ret, "while refreshing backup superblocks.");
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
+
static void scale_time(time_t secs, unsigned *scaled, char **units)
{
if (secs < 60) {
@@ -410,12 +437,63 @@
return ret;
}
+static errcode_t recover_backup_super(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;
+
+ ocfs2_get_backup_super_offset(NULL, offsets, ARRAY_SIZE(offsets));
+
+ /* 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;
+ /* Here we just give the possible value of block num and
+ * block size to ocfs2_open and this function will check
+ * them and return '0' if they meet the right one.
+ */
+ 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 above,
+ * 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 +512,7 @@
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 +574,10 @@
version();
break;
+ case 'r':
+ sb_num = read_number(optarg);
+ break;
+
default:
fsck_mask |= FSCK_USAGE;
print_usage();
@@ -523,6 +605,17 @@
filename = argv[optind];
+ /* recover superblock should be called at first. */
+ if (sb_num) {
+ ret = recover_backup_super(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;
@@ -638,6 +731,12 @@
if (ret)
com_err(whoami, ret, "while writing back the "
"superblock");
+ else {
+ ret = update_backup_super(ost);
+ if (ret)
+ com_err(whoami, ret,
+ "while updating backup superblock.");
+ }
}
unlock:
Index: ocfs2-tools/fsck.ocfs2/fsck.ocfs2.checks.8.in
===================================================================
--- ocfs2-tools.orig/fsck.ocfs2/fsck.ocfs2.checks.8.in 2007-01-09 09:10:49.000000000 -0500
+++ ocfs2-tools/fsck.ocfs2/fsck.ocfs2.checks.8.in 2007-01-09 09:15:02.000000000 -0500
@@ -648,6 +648,12 @@
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)
-------------- next part --------------
Index: ocfs2-tools/libocfs2/Makefile
===================================================================
--- ocfs2-tools.orig/libocfs2/Makefile 2007-01-09 09:10:52.000000000 -0500
+++ ocfs2-tools/libocfs2/Makefile 2007-01-09 09:15:02.000000000 -0500
@@ -80,7 +80,8 @@
truncate.c \
unix_io.c \
unlink.c \
- lockid.c
+ lockid.c \
+ backup_super.c
HFILES = \
include/bitmap.h \
Index: ocfs2-tools/libocfs2/openfs.c
===================================================================
--- ocfs2-tools.orig/libocfs2/openfs.c 2007-01-09 09:10:52.000000000 -0500
+++ ocfs2-tools/libocfs2/openfs.c 2007-01-09 09:15:02.000000000 -0500
@@ -129,6 +129,42 @@
return ret;
}
+errcode_t ocfs2_write_backup_super(ocfs2_filesys *fs, uint64_t blkno)
+{
+ errcode_t ret;
+ char *buf = NULL;
+ struct ocfs2_dinode *di;
+
+ if (!(fs->fs_flags & OCFS2_FLAG_RW))
+ return OCFS2_ET_RO_FILESYS;
+
+ ret = ocfs2_malloc_block(fs->fs_io, &buf);
+ if (ret)
+ goto out_blk;
+
+ memcpy(buf, (char *)fs->fs_super, fs->fs_blocksize);
+ di = (struct ocfs2_dinode *)buf;
+
+ ret = OCFS2_ET_BAD_MAGIC;
+ if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE,
+ strlen(OCFS2_SUPER_BLOCK_SIGNATURE)))
+ goto out_blk;
+
+ di->i_blkno = blkno;
+ OCFS2_SET_COMPAT_FEATURE(OCFS2_RAW_SB(di),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB);
+ ret = ocfs2_write_inode(fs, blkno, buf);
+ if (ret)
+ goto out_blk;
+
+ ret = 0;
+
+out_blk:
+ if (buf)
+ ocfs2_free(&buf);
+ return ret;
+}
+
int ocfs2_mount_local(ocfs2_filesys *fs)
{
return OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat &
Index: ocfs2-tools/libocfs2/include/ocfs2.h
===================================================================
--- ocfs2-tools.orig/libocfs2/include/ocfs2.h 2007-01-09 09:10:51.000000000 -0500
+++ ocfs2-tools/libocfs2/include/ocfs2.h 2007-01-09 09:15:02.000000000 -0500
@@ -613,6 +613,29 @@
errcode_t ocfs2_decode_lockres(char *lockres, int len, enum ocfs2_lock_type *type,
uint64_t *blkno, uint32_t *generation);
+/* write the superblock at the specific block. */
+errcode_t ocfs2_write_backup_super(ocfs2_filesys *fs, uint64_t blkno);
+
+/* Get the blkno according to the file system info.
+ * The unused ones, depending on the volume size, are zeroed.
+ * Return the length of the block array.
+ */
+int ocfs2_get_backup_super_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 clusters 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_super(ocfs2_filesys *fs,
+ uint64_t *blocks, size_t len);
+
+/* Refresh the backup superblock inoformation. */
+errcode_t ocfs2_refresh_backup_super(ocfs2_filesys *fs,
+ uint64_t *blocks, size_t len);
/*
* ${foo}_to_${bar} is a floor function. blocks_to_clusters will
@@ -728,4 +751,6 @@
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
+/* lifted from the kernel. include/linux/kernel.h */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif /* _FILESYS_H */
Index: ocfs2-tools/libocfs2/backup_super.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ ocfs2-tools/libocfs2/backup_super.c 2007-01-09 09:15:02.000000000 -0500
@@ -0,0 +1,165 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * backup_super.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"
+
+/* 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_super_offset(ocfs2_filesys *fs,
+ uint64_t *offsets, size_t len)
+{
+ size_t i;
+ uint64_t blkno;
+ uint32_t blocksize;
+
+ memset(offsets, 0, sizeof(uint64_t) * len);
+ len = ocfs2_min(len, (size_t)OCFS2_MAX_BACKUP_SUPERBLOCKS);
+
+ if (fs)
+ blocksize = fs->fs_blocksize;
+ else
+ blocksize = 1;
+
+ for (i = 0; i < len; i++) {
+ blkno = ocfs2_backup_super_blkno(blocksize, i);
+ if (fs && fs->fs_blocks <= blkno)
+ break;
+
+ offsets[i] = blkno;
+ }
+ return i;
+}
+
+static inline errcode_t check_cluster(ocfs2_bitmap *bitmap, uint64_t bit)
+{
+ errcode_t ret;
+ int val;
+
+ ret = ocfs2_bitmap_test(bitmap, bit, &val);
+ if (ret)
+ goto bail;
+
+ if (val) {
+ ret = ENOSPC;
+ goto bail;
+ }
+
+ ret = 0;
+bail:
+ return ret;
+}
+
+errcode_t ocfs2_set_backup_super(ocfs2_filesys *fs,
+ uint64_t *blocks, size_t len)
+{
+ size_t i;
+ errcode_t ret = 0;
+ char *buf = NULL;
+ uint64_t bm_blk, *blkno = blocks;
+ int val;
+ uint32_t cluster, bpc = fs->fs_clustersize / fs->fs_blocksize;
+
+ if (!len || !blocks || !*blocks)
+ goto bail;
+ len = ocfs2_min(len,(size_t)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_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+ /* check all the blkno to see whether it is used. */
+ for (i = 0; i < len; i++, blkno++) {
+ ret = check_cluster(fs->fs_cluster_alloc->ci_chains,
+ ocfs2_blocks_to_clusters(fs, *blkno));
+ if (ret)
+ goto bail;
+ }
+ }
+
+ ret = ocfs2_malloc_blocks(fs->fs_io, bpc, &buf);
+ if (ret)
+ goto bail;
+ memset(buf, 0, fs->fs_clustersize);
+
+ /* zero all the clusters at first */
+ blkno = blocks;
+ for (i = 0; i < len; i++, blkno++) {
+ cluster = ocfs2_blocks_to_clusters(fs, *blkno);
+ ret = io_write_block(fs->fs_io, cluster*bpc, bpc, buf);
+ if (ret)
+ goto bail;
+ }
+
+ ret = ocfs2_refresh_backup_super(fs, blocks, len);
+ if (ret)
+ goto bail;
+
+ blkno = blocks;
+ for (i = 0; i < len; i++, blkno++)
+ ocfs2_bitmap_set(fs->fs_cluster_alloc->ci_chains,
+ ocfs2_blocks_to_clusters(fs, *blkno), &val);
+
+ ret = ocfs2_write_chain_allocator(fs, fs->fs_cluster_alloc);
+
+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;
+}
+
+errcode_t ocfs2_refresh_backup_super(ocfs2_filesys *fs,
+ uint64_t *blocks, size_t len)
+{
+ errcode_t ret = 0;
+ size_t i;
+
+ for (i = 0; i < len; i++, blocks++) {
+ ret = ocfs2_write_backup_super(fs, *blocks);
+ if (ret)
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
Index: ocfs2-tools/libocfs2/include/ocfs2_fs.h
===================================================================
--- ocfs2-tools.orig/libocfs2/include/ocfs2_fs.h 2007-01-09 09:10:51.000000000 -0500
+++ ocfs2-tools/libocfs2/include/ocfs2_fs.h 2007-01-09 09:15:02.000000000 -0500
@@ -85,7 +85,7 @@
#define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
OCFS2_SB(sb)->s_feature_incompat &= ~(mask)
-#define OCFS2_FEATURE_COMPAT_SUPP 0
+#define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB
#define OCFS2_FEATURE_INCOMPAT_SUPP OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT
#define OCFS2_FEATURE_RO_COMPAT_SUPP 0
@@ -110,6 +110,20 @@
#define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC 0x0010
/*
+ * backup superblock flag is used to indicate that this volume
+ * has backup superblocks.
+ */
+#define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001
+
+/* The byte offset of the first backup block will be 1G.
+ * The following will be 4G, 16G, 64G, 256G and 1T.
+ */
+#define OCFS2_BACKUP_SB_START 1 << 30
+
+/* the max backup superblock nums */
+#define OCFS2_MAX_BACKUP_SUPERBLOCKS 6
+
+/*
* Flags on ocfs2_dinode.i_flags
*/
#define OCFS2_VALID_FL (0x00000001) /* Inode is valid */
@@ -631,6 +645,19 @@
return size / sizeof(struct ocfs2_truncate_rec);
}
+
+static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index)
+{
+ uint64_t offset = OCFS2_BACKUP_SB_START;
+
+ if (index >= 0 && index < OCFS2_MAX_BACKUP_SUPERBLOCKS) {
+ offset <<= (2 * index);
+ offset /= blocksize;
+ return offset;
+ }
+
+ return 0;
+}
#endif /* __KERNEL__ */
-------------- next part --------------
Index: ocfs2-tools/mkfs.ocfs2/mkfs.c
===================================================================
--- ocfs2-tools.orig/mkfs.ocfs2/mkfs.c 2007-01-09 09:10:53.000000000 -0500
+++ ocfs2-tools/mkfs.ocfs2/mkfs.c 2007-01-09 09:15:02.000000000 -0500
@@ -84,6 +84,7 @@
uint16_t bpc);
static void create_lost_found_dir(State *s);
static void format_journals(State *s);
+static int format_backup_super(State *s);
extern char *optarg;
extern int optind, opterr, optopt;
@@ -113,6 +114,10 @@
{NULL, FS_DEFAULT},
};
+enum {
+ BACKUP_SUPER_OPTION = CHAR_MAX + 1,
+};
+
static uint64_t align_bytes_to_clusters_ceil(State *s,
uint64_t bytes)
{
@@ -438,6 +443,15 @@
if (!s->quiet)
printf("done\n");
+ if (!s->no_backup_super) {
+ if (!s->quiet)
+ printf("Writing backup superblock: ");
+
+ num = format_backup_super(s);
+ if (!s->quiet)
+ printf("%d block(s)\n", num);
+ }
+
if (!s->hb_dev) {
/* These routines use libocfs2 to do their work. We
* don't share an ocfs2_filesys context between the
@@ -510,6 +524,7 @@
uint64_t journal_size_in_bytes = 0;
enum ocfs2_fs_types fs_type = FS_DEFAULT;
int mount = 0;
+ int no_backup_super = 0;
static struct option long_options[] = {
{ "block-size", 1, 0, 'b' },
@@ -523,6 +538,7 @@
{ "heartbeat-device", 0, 0, 'H'},
{ "force", 0, 0, 'F'},
{ "mount", 1, 0, 'M'},
+ { "no-backup-super", 0, 0, BACKUP_SUPER_OPTION },
{ 0, 0, 0, 0}
};
@@ -653,6 +669,10 @@
parse_fs_type_opts(progname, optarg, &fs_type);
break;
+ case BACKUP_SUPER_OPTION:
+ no_backup_super = 1;
+ break;
+
default:
usage(progname);
break;
@@ -717,6 +737,8 @@
s->mount = mount;
+ s->no_backup_super = no_backup_super;
+
return s;
}
@@ -829,7 +851,7 @@
fprintf(stderr, "usage: %s [-b block-size] [-C cluster-size] "
"[-J journal-options]\n\t\t[-L volume-label] [-M mount-type] "
"[-N number-of-node-slots]\n\t\t[-T filesystem-type] [-HFqvV] "
- "device [blocks-count]\n", progname);
+ "[--no-backup-super] device [blocks-count]\n", progname);
exit(0);
}
@@ -2245,3 +2267,42 @@
clear_both_ends(s);
exit(1);
}
+
+static int format_backup_super(State *s)
+{
+ errcode_t ret;
+ ocfs2_filesys *fs = NULL;
+ size_t len;
+ 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;
+ }
+
+ len = ocfs2_get_backup_super_offset(fs, blocks, ARRAY_SIZE(blocks));
+
+ ret = ocfs2_set_backup_super(fs, blocks, len);
+ if (ret) {
+ com_err(s->progname, ret, "while backing up superblock.");
+ goto error;
+ }
+
+ OCFS2_SET_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB);
+
+ ret = ocfs2_write_super(fs);
+ if (ret) {
+ com_err(s->progname, ret, "while updating superblock.");
+ goto error;
+ }
+
+ ocfs2_close(fs);
+ return len;
+
+error:
+ clear_both_ends(s);
+ exit(1);
+}
-------------- next part --------------
Index: ocfs2-tools/tunefs.ocfs2/tunefs.c
===================================================================
--- ocfs2-tools.orig/tunefs.ocfs2/tunefs.c 2007-01-09 09:10:53.000000000 -0500
+++ ocfs2-tools/tunefs.ocfs2/tunefs.c 2007-01-09 09:15:02.000000000 -0500
@@ -69,6 +69,10 @@
#define MOUNT_LOCAL_STR "local"
#define MOUNT_CLUSTER_STR "cluster"
+enum {
+ BACKUP_SUPER_OPTION = CHAR_MAX + 1,
+};
+
typedef struct _ocfs2_tune_opts {
uint16_t num_slots;
uint64_t num_blocks;
@@ -81,6 +85,7 @@
int verbose;
int quiet;
int prompt;
+ int backup_super;
time_t tune_time;
int fd;
} ocfs2_tune_opts;
@@ -253,6 +258,7 @@
{ "volume-size", 0, 0, 'S'},
{ "uuid-reset", 0, 0, 'U'},
{ "mount", 1, 0, 'M' },
+ { "backup-super", 0, 0, BACKUP_SUPER_OPTION },
{ 0, 0, 0, 0}
};
@@ -264,7 +270,7 @@
opts.prompt = 1;
while (1) {
- c = getopt_long(argc, argv, "L:N:J:M:SUvqVx", long_options,
+ c = getopt_long(argc, argv, "L:N:J:M:SUvqVxb", long_options,
NULL);
if (c == -1)
@@ -344,12 +350,27 @@
opts.prompt = 0;
break;
+ case BACKUP_SUPER_OPTION:
+ opts.backup_super = 1;
+ break;
+
default:
usage(opts.progname);
break;
}
}
+ /* we don't allow backup_super to be coexist with other tunefs
+ * options to keep things simple.
+ */
+ if (opts.backup_super &&
+ (opts.vol_label || opts.num_slots ||
+ opts.mount || opts.jrnl_size || resize)) {
+ com_err(opts.progname, 0, "Cannot backup superblock"
+ " along with other tasks");
+ exit(1);
+ }
+
if (!opts.quiet || show_version)
version(opts.progname);
@@ -784,6 +805,82 @@
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_super_check(ocfs2_filesys *fs)
+{
+ errcode_t ret;
+ int i, num, val, failed = 0;
+ ocfs2_cached_inode *chain_alloc = NULL;
+ uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+ struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
+
+ /* if the compat flag is set, just return. */
+ if (OCFS2_HAS_COMPAT_FEATURE(super, OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+ com_err(opts.progname, 0,
+ "Volume has been enabled for Backup superblock");
+ return -1;
+ }
+
+ num = ocfs2_get_backup_super_offset(fs, blocks, ARRAY_SIZE(blocks));
+ if (!num) {
+ com_err(opts.progname, 0,
+ "Volume is too small to hold backup superblocks");
+ return -1;
+ }
+
+ ret = load_chain_allocator(fs, &chain_alloc);
+ if (ret)
+ goto bail;
+
+ for (i = 0; i < num; i++) {
+ ret = ocfs2_bitmap_test(chain_alloc->ci_chains,
+ ocfs2_blocks_to_clusters(fs, blocks[i]),
+ &val);
+ if (ret)
+ goto bail;
+
+ if (val) {
+ com_err(opts.progname, 0, "block %"PRIu64
+ " is in use.", 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, "Cannot enable backup superblock as "
+ "backup blocks are in use");
+ }
+
+ 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,
@@ -1141,6 +1238,56 @@
return ret;
}
+static errcode_t refresh_backup_super(ocfs2_filesys *fs)
+{
+ errcode_t ret;
+ int num;
+ uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+
+ num = ocfs2_get_backup_super_offset(fs, blocks, ARRAY_SIZE(blocks));
+ if (!num)
+ return 0;
+
+ ret = ocfs2_refresh_backup_super(fs, blocks, num);
+
+ return ret;
+}
+
+static errcode_t update_backup_super(ocfs2_filesys *fs, uint64_t newblocks)
+{
+ errcode_t ret;
+ int num, i;
+ uint64_t *new_backup_super, blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];
+ uint64_t startblk = fs->fs_blocks - newblocks;
+
+ num = ocfs2_get_backup_super_offset(fs, blocks, ARRAY_SIZE(blocks));
+ if (!num)
+ return 0;
+
+ if (newblocks) {
+ for (i = 0; i < num; i++) {
+ if (blocks[i] >= startblk)
+ break;
+ }
+
+ if (!(num - i))
+ return 0;
+
+ new_backup_super = &blocks[i];
+ num -= i;
+ } else
+ new_backup_super = blocks;
+
+ ret = ocfs2_set_backup_super(fs, new_backup_super, num);
+ if (ret) {
+ com_err(opts.progname, ret, "while backing up superblock.");
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
+
int main(int argc, char **argv)
{
errcode_t ret = 0;
@@ -1153,6 +1300,7 @@
int upd_blocks = 0;
int upd_mount = 0;
int upd_incompat = 0;
+ int upd_backup_super = 0;
char *tmpstr;
uint16_t tmp;
uint64_t def_jrnl_size = 0;
@@ -1230,7 +1378,8 @@
/* 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) {
+ if (opts.num_blocks || opts.num_slots || opts.jrnl_size ||
+ opts.backup_super) {
if (global_bitmap_check(fs)) {
com_err(opts.progname, 0, "Global bitmap check failed. "
"Run fsck.ocfs2 -f <device>.");
@@ -1238,6 +1387,14 @@
}
}
+ /* check whether the block for backup superblock are used. */
+ if (opts.backup_super) {
+ if (backup_super_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",
@@ -1312,7 +1469,8 @@
}
if (!opts.vol_label && !opts.vol_uuid && !opts.num_slots &&
- !opts.jrnl_size && !opts.num_blocks && !opts.mount) {
+ !opts.jrnl_size && !opts.num_blocks && !opts.mount &&
+ !opts.backup_super) {
com_err(opts.progname, 0, "Nothing to do. Exiting.");
goto unlock;
}
@@ -1399,9 +1557,31 @@
printf("Resized volume\n");
}
+ /* update the backup superblock. */
+ if (opts.backup_super ||
+ (opts.num_blocks &&
+ OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB))) {
+ block_signals(SIG_BLOCK);
+ ret = update_backup_super(fs, opts.num_blocks);
+ block_signals(SIG_UNBLOCK);
+ if (ret) {
+ com_err(opts.progname, ret,
+ "while backuping superblock");
+ goto unlock;
+ }
+ OCFS2_SET_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB);
+
+ if (opts.backup_super) {
+ printf("Backed up Superblock.\n");
+ upd_backup_super = 1;
+ }
+ }
+
/* write superblock */
if (upd_label || upd_uuid || upd_slots || upd_blocks || upd_incompat ||
- upd_mount) {
+ upd_mount || upd_backup_super) {
block_signals(SIG_BLOCK);
ret = ocfs2_write_super(fs);
if (ret) {
@@ -1410,6 +1590,34 @@
}
block_signals(SIG_UNBLOCK);
printf("Wrote Superblock\n");
+
+ /* superblock's information has changed.
+ * We need to synchronize the backup blocks if needed.
+ * We also have to admit that if upd_backup_super is set,
+ * there is no need to refresh the backups since they are
+ * written above by update_backup_super.
+ */
+ if (!upd_backup_super &&
+ OCFS2_HAS_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
+ block_signals(SIG_BLOCK);
+ ret = refresh_backup_super(fs);
+ block_signals(SIG_UNBLOCK);
+ if (ret) {
+ printf("Unable to refresh backup superblocks. "
+ "Please run fsck.ocfs2 before running "
+ "tunefs.ocfs2 to re-enable "
+ "backup superblocks.");
+ /* If this happens, we should remove the backup
+ * super compat flag in the superblock and let
+ * fsck reclaim the space before running tunefs
+ * again to set it.
+ */
+ OCFS2_CLEAR_COMPAT_FEATURE(
+ OCFS2_RAW_SB(fs->fs_super),
+ OCFS2_FEATURE_COMPAT_BACKUP_SB);
+ }
+ }
}
unlock:
-------------- next part --------------
backup_libocfs2_4.patch
backup_mkfs_4.patch
backup_fsck_4.patch
backup_tunefs_4.patch
backup_debugfs_4.patch
More information about the Ocfs2-tools-devel
mailing list