/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * feature_backup_super.c * * ocfs2 tune utility to enable and disable the backup superblock feature. * * Copyright (C) 2004, 2008 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. */ #include #include #include #include #include "ocfs2/ocfs2.h" #include "libocfs2ne.h" static errcode_t empty_backup_supers(ocfs2_filesys *fs) { errcode_t ret; int num; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; num = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); if (!num) return 0; ret = ocfs2_clear_backup_super_list(fs, blocks, num); if (ret) tcom_err(ret, "while freeing backup superblock locations"); return ret; } static errcode_t fill_backup_supers(ocfs2_filesys *fs) { errcode_t ret; int num; uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS]; num = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); ret = ocfs2_set_backup_super_list(fs, blocks, num); if (ret) tcom_err(ret, "while backing up the superblock"); return ret; } static int disable_backup_super(ocfs2_filesys *fs, int flags) { errcode_t err = 0; struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); struct tools_progress *prog; if (!OCFS2_HAS_COMPAT_FEATURE(super, OCFS2_FEATURE_COMPAT_BACKUP_SB)) { verbosef(VL_APP, "Backup superblock feature is not enabled; " "nothing to disable\n"); goto out; } if (!tools_interact("Disable the backup superblock feature on " "device \"%s\"? ", fs->fs_devname)) goto out; prog = tools_progress_start("Disable backup-super", "nobackup-super", 1); if (!prog) { err = TUNEFS_ET_NO_MEMORY; tcom_err(err, "while initializing the progress display"); goto out; } tunefs_block_signals(); err = empty_backup_supers(fs); if (!err) { super->s_feature_compat &= ~OCFS2_FEATURE_COMPAT_BACKUP_SB; err = ocfs2_write_super(fs); if (err) tcom_err(err, "while writing out the superblock\n" "Unable to disable the backup superblock " "feature on device \"%s\"", fs->fs_devname); } tunefs_unblock_signals(); tools_progress_step(prog, 1); tools_progress_stop(prog); out: return err; } static errcode_t load_global_bitmap(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 check_backup_offsets(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]; num = ocfs2_get_backup_super_offsets(fs, blocks, ARRAY_SIZE(blocks)); if (!num) { ret = 1; errorf("Volume on device \"%s\" is too small to contain " "backup superblocks\n", fs->fs_devname); goto bail; } ret = load_global_bitmap(fs, &chain_alloc); if (ret) { tcom_err(ret, "while loading the global bitmap"); 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) { tcom_err(ret, "looking up backup superblock locations " "in the global bitmap"); goto bail; } if (val) { verbosef(VL_APP, "Backup superblock location %d at block " "%"PRIu64" is in use\n", i, blocks[i]); /* in order to verify all the block in the 'blocks', * we don't stop the loop here. */ failed = 1; } } if (failed) { ret = 1; errorf("One or more backup superblock locations are " "already in use\n"); } else ret = 0; if (chain_alloc) ocfs2_free_cached_inode(fs, chain_alloc); bail: return ret; } static int enable_backup_super(ocfs2_filesys *fs, int flags) { errcode_t err = 0; struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); struct tools_progress *prog; if (OCFS2_HAS_COMPAT_FEATURE(super, OCFS2_FEATURE_COMPAT_BACKUP_SB)) { verbosef(VL_APP, "Backup superblock feature is already enabled; " "nothing to enable\n"); goto out; } if (!tools_interact("Enable the backup superblock feature on " "device \"%s\"? ", fs->fs_devname)) goto out; prog = tools_progress_start("Enable backup-super", "backup-super", 2); if (!prog) { err = TUNEFS_ET_NO_MEMORY; tcom_err(err, "while initializing the progress display"); goto out; } tunefs_block_signals(); err = check_backup_offsets(fs); tools_progress_step(prog, 1); if (!err) err = fill_backup_supers(fs); if (!err) { super->s_feature_compat |= OCFS2_FEATURE_COMPAT_BACKUP_SB; err = ocfs2_write_super(fs); if (err) tcom_err(err, "while writing out the superblock\n"); } tunefs_unblock_signals(); tools_progress_step(prog, 1); tools_progress_stop(prog); if (err) errorf("Unable to enable the backup superblock feature on " "device \"%s\"\n", fs->fs_devname); out: return err; } DEFINE_TUNEFS_FEATURE_COMPAT(backup_super, OCFS2_FEATURE_COMPAT_BACKUP_SB, TUNEFS_FLAG_RW | TUNEFS_FLAG_ALLOCATION, enable_backup_super, disable_backup_super); #ifdef DEBUG_EXE int main(int argc, char *argv[]) { return tunefs_feature_main(argc, argv, &backup_super_feature); } #endif