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; }
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 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 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; }
static errcode_t remove_slots(ocfs2_filesys *fs, int num_slots) { errcode_t ret; uint16_t old_num = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; uint16_t removed_slot = old_num - 1; struct tools_progress *prog = NULL; ret = remove_slot_check(fs, num_slots); if (ret) goto bail; /* We have seven steps in removing each slot */ prog = tools_progress_start("Removing slots", "rmslots", (old_num - num_slots) * 7); if (!prog) { ret = TUNEFS_ET_NO_MEMORY; goto bail; } /* This is cleared up in update_slot_count() if everything works */ ret = tunefs_set_in_progress(fs, OCFS2_TUNEFS_INPROG_REMOVE_SLOT); if (ret) goto bail; /* we will remove the slots once at a time so that fsck.ocfs2 can work * well and we can continue our work easily in case of any panic. */ while (removed_slot >= num_slots) { /* Link the specified extent alloc file to others. */ ret = relink_system_alloc(fs, removed_slot, num_slots, EXTENT_ALLOC_SYSTEM_INODE); if (ret) goto bail; tools_progress_step(prog, 1); /* Link the specified inode alloc file to others. */ ret = relink_system_alloc(fs, removed_slot, num_slots, INODE_ALLOC_SYSTEM_INODE); if (ret) goto bail; tools_progress_step(prog, 1); /* Truncate the orphan dir to release its clusters * to the global bitmap. */ ret = truncate_orphan_dir(fs, removed_slot); if (ret) goto bail; tools_progress_step(prog, 1); /* empty the content of journal and truncate its clusters. */ ret = empty_and_truncate_journal(fs, removed_slot); if (ret) goto bail; tools_progress_step(prog, 1); /* Now, we decrease the max_slots first and then remove the * slots for the reason that: * * 1. ocfs2_lock_down_clusters needs to lock all the journal * files. so if we delete the journal entry first and fail * to decrease the max_slots, the whole cluster can't be * locked any more due to the loss of journals. * * 2. Now all the resources except the inodes are freed * so it is safe to decrease the slots first, and if any * panic happens after we decrease the slots, we can ignore * them, and actually if we want to increase the slot in the * future, we can reuse these inodes. */ /* The slot number is updated in the super block.*/ OCFS2_RAW_SB(fs->fs_super)->s_max_slots--; ret = ocfs2_write_primary_super(fs); if (ret) goto bail; tools_progress_step(prog, 1); /* The extra system dir entries should be removed. */ ret = remove_slot_entry(fs, removed_slot); if (ret) goto bail; tools_progress_step(prog, 1); /* Decrease the i_links_count in system file directory * since the orphan_dir is removed. */ ret = decrease_link_count(fs, fs->fs_sysdir_blkno); if (ret) goto bail; tools_progress_step(prog, 1); removed_slot--; } bail: if (prog) tools_progress_stop(prog); return ret; }
static errcode_t add_slots(ocfs2_filesys *fs, int num_slots) { errcode_t ret; uint16_t old_num = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; char fname[OCFS2_MAX_FILENAME_LEN]; uint64_t blkno; int i, j, max_slots; int ftype; struct tools_progress *prog = NULL; if (ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super))) { ret = TUNEFS_ET_TOO_MANY_SLOTS_EXTENDED; max_slots = INT16_MAX; } else { ret = TUNEFS_ET_TOO_MANY_SLOTS_OLD; max_slots = OCFS2_MAX_SLOTS; } if (num_slots > max_slots) goto bail; prog = tools_progress_start("Adding slots", "addslots", (NUM_SYSTEM_INODES - OCFS2_LAST_GLOBAL_SYSTEM_INODE - 1) * (num_slots - old_num)); if (!prog) { ret = TUNEFS_ET_NO_MEMORY; goto bail; } ret = 0; for (i = OCFS2_LAST_GLOBAL_SYSTEM_INODE + 1; i < NUM_SYSTEM_INODES; ++i) { for (j = old_num; j < num_slots; ++j) { ocfs2_sprintf_system_inode_name(fname, OCFS2_MAX_FILENAME_LEN, i, j); verbosef(VL_APP, "Creating system file \"%s\"\n", fname); /* Goto next if file already exists */ 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); tools_progress_step(prog, 1); continue; } /* create inode for system file */ ret = ocfs2_new_system_inode(fs, &blkno, ocfs2_system_inodes[i].si_mode, ocfs2_system_inodes[i].si_iflags); if (ret) { verbosef(VL_APP, "%s while creating inode for " "system file \"%s\"\n", error_message(ret), fname); goto bail; } ftype = (S_ISDIR(ocfs2_system_inodes[i].si_mode) ? OCFS2_FT_DIR : OCFS2_FT_REG_FILE); /* if dir, alloc space to it */ if (ftype == OCFS2_FT_DIR) { ret = ocfs2_init_dir(fs, blkno, fs->fs_sysdir_blkno); if (ret) { verbosef(VL_APP, "%s while initializing " "directory \"%s\"\n", error_message(ret), fname); goto bail; } } /* Add the inode to the system dir */ ret = ocfs2_link(fs, fs->fs_sysdir_blkno, fname, blkno, ftype); if (ret) { verbosef(VL_APP, "%s while linking inode %"PRIu64" " "as \"%s\" in the system " "directory\n", error_message(ret), blkno, fname); goto bail; } verbosef(VL_APP, "System file \"%s\" created\n", fname); tools_progress_step(prog, 1); } } bail: if (prog) tools_progress_stop(prog); return ret; }