static int do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features) { xfs_sb_t tsb; if (!get_sb(agno, &tsb)) return 0; if (xfs_sb_has_mismatched_features2(&tsb)) { dbprintf(_("Superblock has mismatched features2 fields, " "skipping modification\n")); return 0; } if ((version & XFS_SB_VERSION_LOGV2BIT) && !xfs_sb_version_haslogv2(&tsb)) { tsb.sb_logsunit = 1; } tsb.sb_versionnum = version; tsb.sb_features2 = features; tsb.sb_bad_features2 = features; libxfs_sb_to_disk(iocur_top->data, &tsb); write_cur(); return 1; }
static uuid_t * do_uuid(xfs_agnumber_t agno, uuid_t *uuid) { xfs_sb_t tsb; static uuid_t uu; if (!get_sb(agno, &tsb)) return NULL; if (!uuid) { /* get uuid */ memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); pop_cur(); return &uu; } /* set uuid */ if (!xfs_sb_version_hascrc(&tsb)) goto write; /* * If we have CRCs, and this UUID differs from that stamped in the * metadata, set the incompat flag and copy the old one to the * metadata-specific location. * * If we are setting the user-visible UUID back to match the metadata * UUID, clear the metadata-specific location and the incompat flag. */ if (!xfs_sb_version_hasmetauuid(&tsb) && !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) { mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID; tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID; memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t)); } else if (xfs_sb_version_hasmetauuid(&tsb) && uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) { memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t)); /* Write those zeros now; it's ignored once we clear the flag */ libxfs_sb_to_disk(iocur_top->data, &tsb); mp->m_sb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID; tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID; } write: memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); libxfs_sb_to_disk(iocur_top->data, &tsb); write_cur(); return uuid; }
static uuid_t * do_uuid(xfs_agnumber_t agno, uuid_t *uuid) { xfs_sb_t tsb; static uuid_t uu; if (!get_sb(agno, &tsb)) return NULL; if (!uuid) { /* get uuid */ memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); pop_cur(); return &uu; } /* set uuid */ memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_UUID); write_cur(); return uuid; }
static char * do_label(xfs_agnumber_t agno, char *label) { size_t len; xfs_sb_t tsb; static char lbl[sizeof(tsb.sb_fname) + 1]; if (!get_sb(agno, &tsb)) return NULL; memset(&lbl[0], 0, sizeof(lbl)); if (!label) { /* get label */ pop_cur(); memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); return &lbl[0]; } /* set label */ if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { if (!warned++) dbprintf("warning: truncating label from %lld to %lld " "characters\n", (long long)len, (long long)sizeof(tsb.sb_fname)); len = sizeof(tsb.sb_fname); } if ( len == 2 && (strcmp(label, "\"\"") == 0 || strcmp(label, "''") == 0 || strcmp(label, "--") == 0) ) label[0] = label[1] = '\0'; memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); memcpy(&tsb.sb_fname, label, len); memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_FNAME); write_cur(); return &lbl[0]; }
static char * do_label(xfs_agnumber_t agno, char *label) { size_t len; xfs_sb_t tsb; static char lbl[sizeof(tsb.sb_fname) + 1]; if (!get_sb(agno, &tsb)) return NULL; memset(&lbl[0], 0, sizeof(lbl)); if (!label) { /* get label */ pop_cur(); memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); return &lbl[0]; } /* set label */ if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { if (agno == 0) dbprintf(_("%s: truncating label length from %d to %d\n"), progname, (int)len, (int)sizeof(tsb.sb_fname)); len = sizeof(tsb.sb_fname); } if ( len == 2 && (strcmp(label, "\"\"") == 0 || strcmp(label, "''") == 0 || strcmp(label, "--") == 0) ) label[0] = label[1] = '\0'; memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); memcpy(&tsb.sb_fname, label, len); memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); libxfs_sb_to_disk(iocur_top->data, &tsb); write_cur(); return &lbl[0]; }
static int uuid_f( int argc, char **argv) { char bp[40]; xfs_agnumber_t agno; uuid_t uu; uuid_t *uup = NULL; if (argc != 1 && argc != 2) { dbprintf(_("invalid parameters\n")); return 0; } if (argc == 2) { /* WRITE UUID */ if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) { dbprintf(_("%s: not in expert mode, writing disabled\n"), progname); return 0; } if (!strcasecmp(argv[1], "generate")) { platform_uuid_generate(&uu); } else if (!strcasecmp(argv[1], "nil")) { platform_uuid_clear(&uu); } else if (!strcasecmp(argv[1], "rewrite")) { uup = do_uuid(0, NULL); if (!uup) { dbprintf(_("failed to read UUID from AG 0\n")); return 0; } memcpy(&uu, uup, sizeof(uuid_t)); platform_uuid_unparse(&uu, bp); dbprintf(_("old UUID = %s\n"), bp); } else if (!strcasecmp(argv[1], "restore")) { xfs_sb_t tsb; if (!get_sb(0, &tsb)) return 0; /* Not set; nothing to do. Success! */ if (!xfs_sb_version_hasmetauuid(&tsb)) return 0; memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t)); } else { if (platform_uuid_parse(argv[1], &uu)) { dbprintf(_("invalid UUID\n")); return 0; } } /* clear the log (setting uuid) if it's not dirty */ if (!sb_logzero(&uu)) return 0; dbprintf(_("writing all SBs\n")); for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) if (!do_uuid(agno, &uu)) { dbprintf(_("failed to set UUID in AG %d\n"), agno); break; } platform_uuid_unparse(&uu, bp); dbprintf(_("new UUID = %s\n"), bp); return 0; } else { /* READ+CHECK UUID */ for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { uup = do_uuid(agno, NULL); if (!uup) { dbprintf(_("failed to read UUID from AG %d\n"), agno); return 0; } if (agno) { if (memcmp(&uu, uup, sizeof(uuid_t))) { dbprintf(_("warning: UUID in AG %d " "differs to the primary SB\n"), agno); break; } } else { memcpy(&uu, uup, sizeof(uuid_t)); } } if (mp->m_sb.sb_logstart) { if (x.logdev && x.logdev != x.ddev) dbprintf(_("warning - external log specified " "for FS with an internal log\n")); } else if (!x.logdev || (x.logdev == x.ddev)) { dbprintf(_("warning - no external log specified " "for FS with an external log\n")); } platform_uuid_unparse(&uu, bp); dbprintf(_("UUID = %s\n"), bp); } return 0; }
/* * the way to verify that a primary sb is consistent with the * filesystem is find the secondaries given the info in the * primary and compare the geometries in the secondaries against * the geometry indicated by the primary. * * returns 1 if bad, 0 if ok */ int verify_set_primary_sb(xfs_sb_t *rsb, int sb_index, int *sb_modified) { xfs_off_t off; fs_geometry_t geo; xfs_sb_t *sb; fs_geo_list_t *list; fs_geo_list_t *current; char *checked; xfs_agnumber_t agno; int num_sbs; int skip; int size; int num_ok; int retval; int round; /* * select the number of secondaries to try for */ num_sbs = MIN(NUM_SBS, rsb->sb_agcount); skip = howmany(num_sbs, rsb->sb_agcount); /* * We haven't been able to validate the sector size yet properly * (e.g. in the case of repairing an image in a file), so we need to * take into account sector mismatches and so use the maximum possible * sector size rather than the sector size in @rsb. */ size = NUM_AGH_SECTS * (1 << (XFS_MAX_SECTORSIZE_LOG)); retval = 0; list = NULL; num_ok = 0; *sb_modified = 0; sb = (xfs_sb_t *) alloc_ag_buf(size); checked = calloc(rsb->sb_agcount, sizeof(char)); if (!checked) { do_error(_("calloc failed in verify_set_primary_sb\n")); exit(1); } /* * put the primary sb geometry info onto the geometry list */ checked[sb_index] = 1; get_sb_geometry(&geo, rsb); list = add_geo(list, &geo, sb_index); /* * grab N secondaries. check them off as we get them * so we only process each one once */ for (round = 0; round < skip; round++) { for (agno = round; agno < rsb->sb_agcount; agno += skip) { if (checked[agno]) continue; off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog; checked[agno] = 1; if (get_sb(sb, off, size, agno) == XR_EOF) { retval = 1; goto out; } if (verify_sb(sb, 0) == XR_OK) { /* * save away geometry info. * don't bother checking the sb * against the agi/agf as the odds * of the sb being corrupted in a way * that it is internally consistent * but not consistent with the rest * of the filesystem is really really low. */ get_sb_geometry(&geo, sb); list = add_geo(list, &geo, agno); num_ok++; } } } /* * see if we have enough superblocks to bother with */ if (num_ok < num_sbs / 2) return(XR_INSUFF_SEC_SB); current = get_best_geo(list); /* * check that enough sbs agree that we're willing to * go with this geometry. if not, print out the * geometry and a message about the force option. */ switch (num_sbs) { case 2: /* * If we only have two allocation groups, and the superblock * in the second allocation group differs from the primary * superblock we can't verify the geometry information. * Warn the user about this situation and get out unless * explicitly overridden. */ if (current->refs != 2) { if (!force_geo) { do_warn( _("Only two AGs detected and they do not match - " "cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n")); exit(1); } } goto out_free_list; case 1: /* * If we only have a single allocation group there is no * secondary superblock that we can use to verify the geometry * information. Warn the user about this situation and get * out unless explicitly overridden. */ if (!force_geo) { do_warn( _("Only one AG detected - " "cannot validate filesystem geometry.\n" "Use the -o force_geometry option to proceed.\n")); exit(1); } goto out_free_list; default: /* * at least half of the probed superblocks have * to agree. if they don't, this fs is probably * too far gone anyway considering the fact that * XFS normally doesn't alter the secondary superblocks. */ if (current->refs < num_sbs / 2) { do_warn( _("Not enough matching superblocks - cannot proceed.\n")); exit(1); } } /* * set the geometry into primary superblock if necessary. */ if (current->index != sb_index) { *sb_modified = 1; off = (xfs_off_t)current->index * current->geo.sb_agblocks * current->geo.sb_blocksize; if (get_sb(sb, off, current->geo.sb_sectsize, current->index) != XR_OK) do_error(_("could not read superblock\n")); copy_sb(sb, rsb); /* * turn off inprogress bit since this is the primary. * also save away values that we need to ensure are * consistent in the other secondaries. */ rsb->sb_inprogress = 0; sb_inoalignmt = sb->sb_inoalignmt; sb_unit = sb->sb_unit; sb_width = sb->sb_width; } out_free_list: free_geo(list); out: free(sb); free(checked); return(retval); }
/* ARGSUSED */ void phase1(xfs_mount_t *mp) { xfs_sb_t *sb; char *ag_bp; int rval; do_log(_("Phase 1 - find and verify superblock...\n")); primary_sb_modified = 0; need_root_inode = 0; need_root_dotdot = 0; need_rbmino = 0; need_rsumino = 0; lost_quotas = 0; /* * get AG 0 into ag header buf */ ag_bp = alloc_ag_buf(MAX_SECTSIZE); sb = (xfs_sb_t *) ag_bp; if (get_sb(sb, 0LL, MAX_SECTSIZE, 0) == XR_EOF) do_error(_("error reading primary superblock\n")); /* * is this really an sb, verify internal consistency */ if ((rval = verify_sb(sb, 1)) != XR_OK) { do_warn(_("bad primary superblock - %s !!!\n"), err_string(rval)); if (!find_secondary_sb(sb)) no_sb(); primary_sb_modified = 1; } else if ((rval = verify_set_primary_sb(sb, 0, &primary_sb_modified)) != XR_OK) { do_warn(_("couldn't verify primary superblock - %s !!!\n"), err_string(rval)); if (!find_secondary_sb(sb)) no_sb(); primary_sb_modified = 1; } /* * Check bad_features2 and make sure features2 the same as * bad_features (ORing the two together). Leave bad_features2 * set so older kernels can still use it and not mount unsupported * filesystems when it reads bad_features2. */ if (sb->sb_bad_features2 != 0 && sb->sb_bad_features2 != sb->sb_features2) { sb->sb_features2 |= sb->sb_bad_features2; sb->sb_bad_features2 = sb->sb_features2; primary_sb_modified = 1; do_warn(_("superblock has a features2 mismatch, correcting\n")); } /* * apply any version changes or conversions after the primary * superblock has been verified or repaired * * Send output to stdout as do_log and everything else in repair * is sent to stderr and there is no "quiet" option. xfs_admin * will filter stderr but not stdout. This situation must be improved. */ if (convert_lazy_count) { if (lazy_count && !xfs_sb_version_haslazysbcount(sb)) { sb->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; sb->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; sb->sb_bad_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; primary_sb_modified = 1; printf(_("Enabling lazy-counters\n")); } else if (!lazy_count && xfs_sb_version_haslazysbcount(sb)) { sb->sb_features2 &= ~XFS_SB_VERSION2_LAZYSBCOUNTBIT; sb->sb_bad_features2 &= ~XFS_SB_VERSION2_LAZYSBCOUNTBIT; printf(_("Disabling lazy-counters\n")); primary_sb_modified = 1; } else { printf(_("Lazy-counters are already %s\n"), lazy_count ? _("enabled") : _("disabled")); exit(0); /* no conversion required, exit */ } } if (primary_sb_modified) { if (!no_modify) { do_warn(_("writing modified primary superblock\n")); write_primary_sb(sb, sb->sb_sectsize); } else { do_warn(_("would write modified primary superblock\n")); } } /* * misc. global var initialization */ sb_ifree = sb_icount = sb_fdblocks = sb_frextents = 0; free(sb); }