static errcode_t update_slot_count(ocfs2_filesys *fs, int num_slots) { errcode_t ret = 0; int orig_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots; if (num_slots == orig_slots) { verbosef(VL_APP, "Device \"%s\" already has %d node slots; " "nothing to do\n", fs->fs_devname, num_slots); goto out; } if (!tools_interact("Change the number of node slots on device " "\"%s\" from %d to %d? ", fs->fs_devname, orig_slots, num_slots)) goto out; tunefs_block_signals(); if (num_slots > orig_slots) ret = add_slots(fs, num_slots); else ret = remove_slots(fs, num_slots); if (ret) goto out_unblock; OCFS2_RAW_SB(fs->fs_super)->s_max_slots = num_slots; if (num_slots > orig_slots) { /* Grow the new journals to match the first slot */ verbosef(VL_APP, "Allocating space for the new journals\n"); ret = tunefs_set_journal_size(fs, 0); if (!ret) verbosef(VL_APP, "Journal space allocated\n"); else { verbosef(VL_APP, "%s while trying to size the new journals\n", error_message(ret)); goto out_unblock; } } ret = ocfs2_format_slot_map(fs); if (ret) goto out_unblock; if (num_slots < orig_slots) { ret = tunefs_clear_in_progress(fs, OCFS2_TUNEFS_INPROG_REMOVE_SLOT); if (ret) goto out_unblock; } ret = ocfs2_write_super(fs); out_unblock: tunefs_unblock_signals(); out: return ret; }
int main(int argc, char **argv) { char *filename; int64_t blkno, blksize; o2fsck_state *ost = &_ost; int c, open_flags = OCFS2_FLAG_RW | OCFS2_FLAG_STRICT_COMPAT_CHECK; int sb_num = 0; int fsck_mask = FSCK_OK; int slot_recover_err = 0; errcode_t ret; int mount_flags; int proceed = 1; memset(ost, 0, sizeof(o2fsck_state)); ost->ost_ask = 1; ost->ost_dirblocks.db_root = RB_ROOT; ost->ost_dir_parents = RB_ROOT; ost->ost_refcount_trees = RB_ROOT; /* These mean "autodetect" */ blksize = 0; blkno = 0; initialize_ocfs_error_table(); initialize_o2dl_error_table(); initialize_o2cb_error_table(); setlinebuf(stderr); setlinebuf(stdout); tools_progress_disable(); while ((c = getopt(argc, argv, "b:B:DfFGnupavVytPr:")) != EOF) { switch (c) { case 'b': blkno = read_number(optarg); if (blkno < OCFS2_SUPER_BLOCK_BLKNO) { fprintf(stderr, "Invalid blkno: %s\n", optarg); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } break; case 'B': blksize = read_number(optarg); if (blksize < OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blksize: %s\n", optarg); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } break; case 'D': ost->ost_compress_dirs = 1; break; case 'F': ost->ost_skip_o2cb = 1; break; case 'f': ost->ost_force = 1; break; case 'G': ost->ost_fix_fs_gen = 1; break; case 'n': open_flags &= ~OCFS2_FLAG_RW; open_flags |= OCFS2_FLAG_RO; /* Fall through */ case 'a': case 'p': /* * Like extN, -a maps to -p, which is * 'preen'. This means only fix things * that don't require human interaction. * Unlike extN, this is only journal * replay for now. To make it smarter, * ost->ost_answer needs to learn a * new mode. */ ost->ost_ask = 0; ost->ost_answer = 0; break; case 'P': tools_progress_enable(); break; case 'y': ost->ost_ask = 0; ost->ost_answer = 1; break; case 'u': open_flags |= OCFS2_FLAG_BUFFERED; break; case 'v': verbose = 1; break; case 'V': print_version(); exit(FSCK_USAGE); break; case 'r': sb_num = read_number(optarg); break; case 't': if (ost->ost_show_stats) ost->ost_show_extended_stats = 1; ost->ost_show_stats = 1; break; default: fsck_mask |= FSCK_USAGE; print_usage(); goto out; break; } } if (!(open_flags & OCFS2_FLAG_RW) && ost->ost_compress_dirs) { fprintf(stderr, "Compress directories (-D) incompatible with read-only mode\n"); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } if (blksize % OCFS2_MIN_BLOCKSIZE) { fprintf(stderr, "Invalid blocksize: %"PRId64"\n", blksize); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } if (optind >= argc) { fprintf(stderr, "Missing filename\n"); fsck_mask |= FSCK_USAGE; print_usage(); goto out; } filename = argv[optind]; print_version(); ret = ocfs2_check_if_mounted(filename, &mount_flags); if (ret) { com_err(whoami, ret, "while determining whether %s is mounted.", filename); fsck_mask |= FSCK_ERROR; goto out; } if (mount_flags & (OCFS2_MF_MOUNTED | OCFS2_MF_BUSY)) { if (!(open_flags & OCFS2_FLAG_RW)) fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 (read-" "only) on a mounted filesystem may detect " "invalid errors.\n\n"); else fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 on a " "mounted filesystem may cause SEVERE " "filesystem damage.\n\n"); proceed = 0; } if (proceed && ost->ost_skip_o2cb) { fprintf(stdout, "\nWARNING!!! You have disabled the cluster check. " "Continue only if you\nare absolutely sure that NO " "node has this filesystem mounted or is\notherwise " "accessing it. If unsure, do NOT continue.\n\n"); proceed = 0; } if (!proceed) { fprintf(stdout, "Do you really want to continue (y/N): "); if (toupper(getchar()) != 'Y') { printf("Aborting operation.\n"); fsck_mask |= FSCK_CANCELED; goto out; } } if (signal(SIGTERM, handle_signal) == SIG_ERR) { com_err(whoami, 0, "Could not set SIGTERM"); exit(1); } if (signal(SIGINT, handle_signal) == SIG_ERR) { com_err(whoami, 0, "Could not set SIGINT"); exit(1); } /* 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; goto out; } if (open_flags & OCFS2_FLAG_RW && !ost->ost_skip_o2cb && !ocfs2_mount_local(ost->ost_fs)) { ret = o2cb_init(); if (ret) { com_err(whoami, ret, "while initializing the cluster"); goto close; } block_signals(SIG_BLOCK); ret = ocfs2_initialize_dlm(ost->ost_fs, whoami); if (ret == O2CB_ET_INVALID_STACK_NAME || ret == O2CB_ET_INVALID_CLUSTER_NAME || ret == O2CB_ET_INVALID_HEARTBEAT_MODE) { block_signals(SIG_UNBLOCK); ret = recover_cluster_info(ost); if (ret) { com_err(whoami, ret, "while recovering cluster information"); goto close; } block_signals(SIG_BLOCK); ret = ocfs2_initialize_dlm(ost->ost_fs, whoami); } if (ret) { block_signals(SIG_UNBLOCK); com_err(whoami, ret, "while initializing the DLM"); goto close; } ret = ocfs2_lock_down_cluster(ost->ost_fs); if (ret) { block_signals(SIG_UNBLOCK); com_err(whoami, ret, "while locking down the cluster"); goto close; } cluster_locked = 1; block_signals(SIG_UNBLOCK); } printf("Checking OCFS2 filesystem in %s:\n", filename); printf(" Label: "); print_label(ost); printf(" UUID: "); print_uuid(ost); printf(" Number of blocks: %"PRIu64"\n", ost->ost_fs->fs_blocks); printf(" Block size: %u\n", ost->ost_fs->fs_blocksize); printf(" Number of clusters: %"PRIu32"\n", ost->ost_fs->fs_clusters); printf(" Cluster size: %u\n", ost->ost_fs->fs_clustersize); printf(" Number of slots: %u\n\n", OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_slots); /* Let's get enough of a cache to replay the journals */ o2fsck_init_cache(ost, O2FSCK_CACHE_MODE_JOURNAL); if (open_flags & OCFS2_FLAG_RW) { ret = o2fsck_check_journals(ost); if (ret) { printf("fsck saw unrecoverable errors in the journal " "files and will not continue.\n"); goto unlock; } } ret = maybe_replay_journals(ost, filename, open_flags, blkno, blksize); if (ret) { printf("fsck encountered unrecoverable errors while " "replaying the journals and will not continue\n"); fsck_mask |= FSCK_ERROR; goto unlock; } /* Grow the cache */ o2fsck_init_cache(ost, O2FSCK_CACHE_MODE_FULL); /* allocate all this junk after we've replayed the journal and the * sb should be stable */ if (o2fsck_state_init(ost->ost_fs, ost)) { fprintf(stderr, "error allocating run-time state, exiting..\n"); fsck_mask |= FSCK_ERROR; goto unlock; } ret = o2fsck_slot_recovery(ost); if (ret) { printf("fsck encountered errors while recovering slot " "information, check forced.\n"); slot_recover_err = 1; ost->ost_force = 1; } if (fs_is_clean(ost, filename)) { fsck_mask = FSCK_OK; goto clear_dirty_flag; } #if 0 o2fsck_mark_block_used(ost, 0); o2fsck_mark_block_used(ost, 1); o2fsck_mark_block_used(ost, OCFS2_SUPER_BLOCK_BLKNO); #endif mark_magical_clusters(ost); /* XXX we don't use the bad blocks inode, do we? */ /* XXX for now it is assumed that errors returned from a pass * are fatal. these can be fixed over time. */ ret = o2fsck_pass0(ost); if (ret) { com_err(whoami, ret, "while performing pass 0"); goto done; } ret = o2fsck_pass1(ost); if (ret) { com_err(whoami, ret, "while performing pass 1"); goto done; } ret = o2fsck_pass2(ost); if (ret) { com_err(whoami, ret, "while performing pass 2"); goto done; } ret = o2fsck_pass3(ost); if (ret) { com_err(whoami, ret, "while performing pass 3"); goto done; } ret = o2fsck_pass4(ost); if (ret) { com_err(whoami, ret, "while performing pass 4"); goto done; } ret = o2fsck_pass5(ost); if (ret) { com_err(whoami, ret, "while performing pass 5"); goto done; } done: if (ret) fsck_mask |= FSCK_ERROR; else { fsck_mask = FSCK_OK; ost->ost_saw_error = 0; printf("All passes succeeded.\n\n"); o2fsck_print_resource_track(NULL, ost, &ost->ost_rt, ost->ost_fs->fs_io); show_stats(ost); } clear_dirty_flag: if (ost->ost_fs->fs_flags & OCFS2_FLAG_RW) { ret = write_out_superblock(ost); if (ret) com_err(whoami, ret, "while writing back the " "superblock(s)"); if (fsck_mask == FSCK_OK) { if (slot_recover_err) { ret = o2fsck_slot_recovery(ost); if (ret) { com_err(whoami, ret, "while doing slot " "recovery."); goto unlock; } } ret = o2fsck_clear_journal_flags(ost); if (ret) { com_err(whoami, ret, "while clear dirty " "journal flag."); goto unlock; } ret = ocfs2_format_slot_map(ost->ost_fs); if (ret) com_err(whoami, ret, "while format slot " "map."); } } unlock: block_signals(SIG_BLOCK); if (ost->ost_fs->fs_dlm_ctxt) ocfs2_release_cluster(ost->ost_fs); cluster_locked = 0; block_signals(SIG_UNBLOCK); close: block_signals(SIG_BLOCK); if (ost->ost_fs->fs_dlm_ctxt) ocfs2_shutdown_dlm(ost->ost_fs, whoami); block_signals(SIG_UNBLOCK); ret = ocfs2_close(ost->ost_fs); if (ret) { com_err(whoami, ret, "while closing file \"%s\"", filename); /* XXX I wonder about this error.. */ fsck_mask |= FSCK_ERROR; } out: return fsck_mask; }