errcode_t o2cbtool_init_cluster_stack(void) { errcode_t ret; const char *stack = NULL; verbosef(VL_DEBUG, "Initializing cluster stack\n"); ret = o2cb_init(); if (ret) { tcom_err(ret, "while initializing the cluster"); goto bail; } ret = o2cb_get_stack_name(&stack); if (ret) { tcom_err(ret, "while determining the current cluster stack"); goto bail; } if (strcmp(stack, stackname)) { ret = -1; errorf("This tool supports the '%s' stack, but the '%s' " "stack is in use.\n", stackname, stack); } bail: return ret; }
static errcode_t create_system_file(ocfs2_filesys *fs, int type, int node) { char fname[OCFS2_MAX_FILENAME_LEN]; uint64_t blkno; errcode_t ret; ocfs2_sprintf_system_inode_name(fname, sizeof(fname), type, node); ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname, strlen(fname), NULL, &blkno); if (!ret) { verbosef(VL_APP, "System file \"%s\" already exists!\n", fname); return 0; } ret = ocfs2_new_system_inode(fs, &blkno, ocfs2_system_inodes[type].si_mode, ocfs2_system_inodes[type].si_iflags); if (ret) { tcom_err(ret, "while creating system file \"%s\"", fname); return ret; } ret = ocfs2_link(fs, fs->fs_sysdir_blkno, fname, blkno, OCFS2_FT_REG_FILE); if (ret) { tcom_err(ret, "while linking file \"%s\" in the system " "directory", fname); return ret; } return 0; }
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 remove_quota_files_iterate(struct ocfs2_dir_entry *dirent, uint64_t blocknr, int offset, int blocksize, char *buf, void *priv_data) { struct remove_quota_files_ctxt *ctxt = priv_data; char dname[OCFS2_MAX_FILENAME_LEN]; char wname[OCFS2_MAX_FILENAME_LEN]; errcode_t ret; int tail, i; int ret_flags = 0; strncpy(dname, dirent->name, dirent->name_len); dname[dirent->name_len] = 0; /* Check whether entry is quota file of type we want - i.e. matching * aquota.user:[0-9][0-9][0-9][0-9] or aquota.user for type == USRQUOTA * and similarly for type == GRPQUOTA */ strcpy(wname, "aquota."); strcat(wname, type2name(ctxt->type)); tail = strlen(wname); if (strncmp(dname, wname, tail)) return 0; if (dname[tail] == ':') { /* May be local file? */ tail++; for (i = 0; i < 4; i++) if (dname[tail + i] < '0' || dname[tail + i] > '9') return 0; if (dname[tail + i]) return 0; } else if (dname[tail]) /* May be global file? */ return 0; verbosef(VL_APP, "Deleting quota file %s\n", dname); ret = ocfs2_truncate(ctxt->fs, dirent->inode, 0); if (ret) { tcom_err(ret, "while truncating quota file \"%s\"", dname); ret_flags |= OCFS2_DIRENT_ERROR; ctxt->err = ret; goto out; } ret = ocfs2_delete_inode(ctxt->fs, dirent->inode); if (ret) { tcom_err(ret, "while deleting quota file \"%s\"", dname); ret_flags |= OCFS2_DIRENT_ERROR; ctxt->err = ret; } else { dirent->inode = 0; ret_flags |= OCFS2_DIRENT_CHANGED; } out: return ret_flags; }
int main(int argc, char **argv) { errcode_t ret; struct o2cb_command *cmd; O2CBConfig *oc_config = NULL; setbuf(stdout, NULL); setbuf(stderr, NULL); initialize_o2cb_error_table(); tools_setup_argv0(argv[0]); parse_options(argc, argv, &cmd); ret = o2cb_config_load(cmd->o_config_file, &oc_config); if (ret) { tcom_err(ret, "while loading cluster configuration " "file '%s'", cmd->o_config_file); goto bail; } cmd->o_config = oc_config; cmd->o_modified = 0; cmd->o_print_usage = 1; ret = -1; if (!cmd->o_action) { errorf("Command '%s' has not been implemented\n", cmd->o_name); goto bail; } ret = cmd->o_action(cmd); if (cmd->o_print_usage) errorf("usage: %s %s\n", cmd->o_name, cmd->o_usage); if (ret || !cmd->o_modified) goto bail; ret = o2cb_config_store(oc_config, cmd->o_config_file); if (ret) tcom_err(ret, "while storing the cluster configuration in " "file '%s'", cmd->o_config_file); bail: if (oc_config) o2cb_config_free(oc_config); ret = ret ? 1 : 0; return ret; }
static int features_parse_option(struct tunefs_operation *op, char *arg) { int rc = 1; errcode_t err; struct feature_op_state *state = NULL; struct check_supported_context ctxt = { .sc_string = arg, }; if (!arg) { errorf("No features specified\n"); goto out; } err = ocfs2_malloc0(sizeof(struct feature_op_state), &state); if (err) { tcom_err(err, "while processing feature options"); goto out; } state->fo_op = op; err = ocfs2_parse_feature(arg, &state->fo_feature_set, &state->fo_reverse_set); if (err) { tcom_err(err, "while parsing feature options \"%s\"", arg); goto out; } ctxt.sc_state = state; ctxt.sc_action = FEATURE_ENABLE; ocfs2_feature_foreach(&state->fo_feature_set, check_supported_func, &ctxt); if (ctxt.sc_error) goto out; ctxt.sc_action = FEATURE_DISABLE; ocfs2_feature_reverse_foreach(&state->fo_reverse_set, check_supported_func, &ctxt); if (ctxt.sc_error) goto out; rc = 0; out: if (!rc) op->to_private = state; else if (state) ocfs2_free(&state); return rc; }
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; }
/* * When creating printf fields for ourselves, we need to avoid the * standard specifiers. All lowercase specifiers are reserved by C99. * Reserved uppercase specifiers are: E, F, G, A, C, S, X, L */ static int query_run(struct tunefs_operation *op, ocfs2_filesys *fs, int flags) { char *queryfmt = op->to_private; char *fmt; fmt = process_escapes(queryfmt); if (!fmt) { tcom_err(TUNEFS_ET_NO_MEMORY, "while escaping the query format"); return 1; } register_printf_function('B', handle_blocksize, handle_arginfo); register_printf_function('T', handle_clustersize, handle_arginfo); register_printf_function('N', handle_numslots, handle_arginfo); register_printf_function('R', handle_rootdir, handle_arginfo); register_printf_function('Y', handle_sysdir, handle_arginfo); register_printf_function('P', handle_clustergroup, handle_arginfo); register_printf_function('V', handle_label, handle_arginfo); register_printf_function('U', handle_uuid, handle_arginfo); register_printf_function('M', handle_compat, handle_arginfo); register_printf_function('H', handle_incompat, handle_arginfo); register_printf_function('O', handle_ro_compat, handle_arginfo); query_fs = fs; fprintf(stdout, fmt); query_fs = NULL; ocfs2_free(&fmt); return 0; }
static int set_journal_block64_run(struct tunefs_operation *op, ocfs2_filesys *fs, int flags) { errcode_t err; int rc = 0; ocfs2_fs_options mask, options; struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); memset(&mask, 0, sizeof(ocfs2_fs_options)); memset(&options, 0, sizeof(ocfs2_fs_options)); mask.opt_incompat |= JBD2_FEATURE_INCOMPAT_64BIT; options.opt_incompat |= JBD2_FEATURE_INCOMPAT_64BIT; if (!tools_interact("Enable block64 journal feature on device \"%s\"? ", fs->fs_devname)) goto out; tunefs_block_signals(); super->s_feature_compat |= OCFS2_FEATURE_COMPAT_JBD2_SB; err = ocfs2_write_super(fs); if (!err) err = tunefs_set_journal_size(fs, 0, mask, options); tunefs_unblock_signals(); if (err) { rc = 1; tcom_err(err, "; unable to enable block64 journal feature on " "device \"%s\"", fs->fs_devname); } out: return rc; }
static void tunefs_inprog_flag_in_str(uint32_t flag, char *buf, size_t len) { errcode_t err; err = ocfs2_snprint_tunefs_flags(buf, len, flag); if (err) tcom_err(err, "while processing inprog flags"); }
static void ro_compat_flag_in_str(uint32_t flag, char *buf, size_t len) { errcode_t err; ocfs2_fs_options flags = { .opt_ro_compat = flag, }; err = ocfs2_snprint_feature_flags(buf, len, &flags); if (err) tcom_err(err, "while processing feature flags"); }
static int run_feature_func(ocfs2_fs_options *feature, void *user_data) { errcode_t err; struct run_features_context *ctxt = user_data; struct tunefs_feature *feat = find_feature(feature); err = tunefs_feature_run(ctxt->rc_fs, feat); if (err && (err != TUNEFS_ET_OPERATION_FAILED)) tcom_err(err, "while toggling feature \"%s\"", feat->tf_name); return err; }
static int disable_grpquota(ocfs2_filesys *fs, int flags) { errcode_t ret; struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); struct tools_progress *prog = NULL; if (!OCFS2_HAS_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { verbosef(VL_APP, "Group quotas are already disabled; " "nothing to disable\n"); return 0; } if (!tools_interact("Disable group quota feature on device " "\"%s\"? ", fs->fs_devname)) return 0; prog = tools_progress_start("Disabling user quota", "nousrquota", 2); if (!prog) { ret = TUNEFS_ET_NO_MEMORY; tcom_err(ret, "while initializing progress display"); return ret; } tunefs_block_signals(); ret = remove_quota_files(fs, GRPQUOTA, prog); if (ret) { tcom_err(ret, "while removing group quota files"); goto bail; } OCFS2_CLEAR_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA); ret = ocfs2_write_super(fs); tools_progress_step(prog, 1); bail: tools_progress_stop(prog); tunefs_unblock_signals(); 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 set_journal_block32_run(struct tunefs_operation *op, ocfs2_filesys *fs, int flags) { errcode_t err; int rc = 0; ocfs2_fs_options mask, options; if (fs->fs_blocks > UINT32_MAX) { tcom_err(TUNEFS_ET_OPERATION_FAILED, "; cannot enable block32 journal feature on " "device \"%s\" having more that %u blocks", fs->fs_devname, UINT32_MAX); rc = 1; goto out; } memset(&mask, 0, sizeof(ocfs2_fs_options)); memset(&options, 0, sizeof(ocfs2_fs_options)); mask.opt_incompat |= JBD2_FEATURE_INCOMPAT_64BIT; if (!tools_interact("Enable block32 journal feature on device \"%s\" ?", fs->fs_devname)) goto out; tunefs_block_signals(); err = tunefs_set_journal_size(fs, 0, mask, options); tunefs_unblock_signals(); if (err) { rc = 1; tcom_err(err, "; unable to enable block32 journal feature on " "device \"%s\"", fs->fs_devname); } out: return rc; }
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 int cloned_volume_run(struct tunefs_operation *op, ocfs2_filesys *fs, int flags) { errcode_t err; int rc = 0; char *new_label = op->to_private; err = cloned_volume(fs, new_label); if (err) { tcom_err(err, "- unable to update the uuid and label on " "device \"%s\"", fs->fs_devname); rc = 1; } return rc; }
static int set_slot_count_run(struct tunefs_operation *op, ocfs2_filesys *fs, int flags) { errcode_t err; int rc = 0; int num_slots = (int)(unsigned long)op->to_private; err = update_slot_count(fs, num_slots); if (err) { tcom_err(err, "- unable to update the number of slots on device " "\"%s\"", fs->fs_devname); rc = 1; } return rc; }
static errcode_t cloned_volume(ocfs2_filesys *fs, const char *new_label) { errcode_t err; struct tools_progress *prog; if (!tools_interact_critical( "Updating the UUID and label on cloned volume \"%s\".\n" "DANGER: THIS WILL MODIFY THE UUID WITHOUT ACCESSING THE " "CLUSTER SOFTWARE. YOU MUST BE ABSOLUTELY SURE THAT NO " "OTHER NODE IS USING THIS FILESYSTEM BEFORE MODIFYING " "ITS UUID.\n" "Update the UUID and label? ", fs->fs_devname)) return 0; prog = tools_progress_start("Cloning volume", "cloning", 3); if (!prog) { err = TUNEFS_ET_NO_MEMORY; tcom_err(err, "while initializing the progress display"); goto out; } update_volume_uuid(fs); tools_progress_step(prog, 1); update_volume_label(fs, new_label); tools_progress_step(prog, 1); tunefs_block_signals(); err = ocfs2_write_super(fs); tunefs_unblock_signals(); tools_progress_step(prog, 1); tools_progress_stop(prog); out: return err; }
static int update_sync_interval(ocfs2_filesys *fs, int type, unsigned long syncms) { errcode_t err; struct tools_progress *prog; int feature = (type == USRQUOTA) ? OCFS2_FEATURE_RO_COMPAT_USRQUOTA : OCFS2_FEATURE_RO_COMPAT_GRPQUOTA; struct ocfs2_global_disk_dqinfo *qinfo; if (!OCFS2_HAS_RO_COMPAT_FEATURE(OCFS2_RAW_SB(fs->fs_super), feature)) { errorf("The %s quota is not enabled on device \"%s\"\n", type2name(type), fs->fs_devname); return 1; } err = ocfs2_init_fs_quota_info(fs, type); if (err) { tcom_err(err, "while looking up %s quota file on device " "\"%s\"", type2name(type), fs->fs_devname); return 1; } err = ocfs2_read_global_quota_info(fs, type); if (err) { tcom_err(err, "while reading %s quota info on device \"%s\"", type2name(type), fs->fs_devname); return 1; } qinfo = &fs->qinfo[type].qi_info; if (qinfo->dqi_syncms == syncms) { verbosef(VL_APP, "Device \"%s\" already has interval %lu set; " "nothing to do\n", fs->fs_devname, syncms); return 0; } if (!tools_interact("Change quota syncing interval on device \"%s\" " "from %lu to %lu? ", fs->fs_devname, (unsigned long)qinfo->dqi_syncms, syncms)) return 0; prog = tools_progress_start("Setting syncing interval", "interval", 1); if (!prog) { tcom_err(err, "while initializing the progress display"); return 1; } tunefs_block_signals(); qinfo->dqi_syncms = syncms; err = ocfs2_write_global_quota_info(fs, type); tunefs_unblock_signals(); tools_progress_step(prog, 1); tools_progress_stop(prog); if (err) { tcom_err(err, "- unable to update %s quota syncing interval on " "device \"%s\"", type2name(type), fs->fs_devname); return 1; } return 0; }
static errcode_t create_quota_files(ocfs2_filesys *fs, int type, struct tools_progress *prog) { ocfs2_quota_hash *hash; errcode_t ret; int num_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; int i; int local_type = (type == USRQUOTA) ? LOCAL_USER_QUOTA_SYSTEM_INODE : LOCAL_GROUP_QUOTA_SYSTEM_INODE; int global_type = (type == USRQUOTA) ? USER_QUOTA_SYSTEM_INODE : GROUP_QUOTA_SYSTEM_INODE; verbosef(VL_APP, "Creating %s quota system files\n", type2name(type)); ret = create_system_file(fs, global_type, 0); if (ret) return ret; for (i = 0; i < num_slots; i++) { ret = create_system_file(fs, local_type, i); if (ret) return ret; } tools_progress_step(prog, 1); verbosef(VL_APP, "Initializing global %s quota file\n", type2name(type)); ret = ocfs2_init_fs_quota_info(fs, type); if (ret) { tcom_err(ret, "while looking up global %s quota file", type2name(type)); return ret; } fs->qinfo[type].flags = OCFS2_QF_INFO_LOADED; fs->qinfo[type].qi_info.dqi_syncms = OCFS2_DEF_QUOTA_SYNC; fs->qinfo[type].qi_info.dqi_bgrace = OCFS2_DEF_BLOCK_GRACE; fs->qinfo[type].qi_info.dqi_igrace = OCFS2_DEF_INODE_GRACE; ret = ocfs2_init_global_quota_file(fs, type); if (ret) { tcom_err(ret, "while initilizing global %s quota files", type2name(type)); return ret; } tools_progress_step(prog, 1); verbosef(VL_APP, "Initializing local %s quota files\n", type2name(type)); ret = ocfs2_init_local_quota_files(fs, type); if (ret) { tcom_err(ret, "while initilizing local %s quota files", type2name(type)); return ret; } tools_progress_step(prog, 1); verbosef(VL_APP, "Computing %s quota usage\n", type2name(type)); ret = ocfs2_new_quota_hash(&hash); if (ret) { tcom_err(ret, "while creating quota hash"); return ret; } if (type == USRQUOTA) ret = ocfs2_compute_quota_usage(fs, hash, NULL); else ret = ocfs2_compute_quota_usage(fs, NULL, hash); if (ret) { tcom_err(ret, "while scanning filesystem to gather " "quota usage"); return ret; } tools_progress_step(prog, 1); verbosef(VL_APP, "Write %s quotas to file\n", type2name(type)); ret = ocfs2_write_release_dquots(fs, type, hash); if (ret) { tcom_err(ret, "while writing %s quota usage to disk", type2name(type)); return ret; } tools_progress_step(prog, 1); ret = ocfs2_free_quota_hash(hash); if (ret) tcom_err(ret, "while freeing quota hash"); return ret; }
static errcode_t remove_quota_files(ocfs2_filesys *fs, int type, struct tools_progress *prog) { struct remove_quota_files_ctxt ctxt = { .fs = fs, .type = type, .err = 0, }; ocfs2_dir_iterate(fs, fs->fs_sysdir_blkno, OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL, remove_quota_files_iterate, &ctxt); tools_progress_step(prog, 1); return ctxt.err; } static int enable_usrquota(ocfs2_filesys *fs, int flags) { struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); errcode_t ret; struct tools_progress *prog = NULL; if (OCFS2_HAS_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { verbosef(VL_APP, "User quotas are already enabled; " "nothing to enable\n"); return 0; } if (!tools_interact("Enable user quota feature on device " "\"%s\"? ", fs->fs_devname)) return 0; prog = tools_progress_start("Enabling user quota", "usrquota", 6); if (!prog) { ret = TUNEFS_ET_NO_MEMORY; tcom_err(ret, "while initializing progress display"); return ret; } tunefs_block_signals(); ret = create_quota_files(fs, USRQUOTA, prog); if (ret) { tcom_err(ret, "while creating user quota files"); goto bail; } OCFS2_SET_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_USRQUOTA); ret = ocfs2_write_super(fs); tools_progress_step(prog, 1); bail: tunefs_unblock_signals(); tools_progress_stop(prog); return ret; } static int disable_usrquota(ocfs2_filesys *fs, int flags) { errcode_t ret; struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); struct tools_progress *prog = NULL; if (!OCFS2_HAS_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { verbosef(VL_APP, "User quotas are already disabled; " "nothing to disable\n"); return 0; } if (!tools_interact("Disable user quota feature on device " "\"%s\"? ", fs->fs_devname)) return 0; prog = tools_progress_start("Disabling user quota", "nousrquota", 2); if (!prog) { ret = TUNEFS_ET_NO_MEMORY; tcom_err(ret, "while initializing progress display"); return ret; } tunefs_block_signals(); ret = remove_quota_files(fs, USRQUOTA, prog); if (ret) { tcom_err(ret, "while removing user quota files"); goto bail; } OCFS2_CLEAR_RO_COMPAT_FEATURE(super, OCFS2_FEATURE_RO_COMPAT_USRQUOTA); ret = ocfs2_write_super(fs); tools_progress_step(prog, 1); bail: tunefs_unblock_signals(); tools_progress_stop(prog); return ret; }