static void zero_log(xfs_mount_t *mp) { int error; xlog_t log; xfs_daddr_t head_blk, tail_blk; dev_t logdev = (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev; memset(&log, 0, sizeof(log)); if (!x.logdev) x.logdev = x.ddev; x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); log.l_dev = logdev; log.l_logsize = BBTOB(x.logBBsize); log.l_logBBsize = x.logBBsize; log.l_logBBstart = x.logBBstart; log.l_mp = mp; if (xfs_sb_version_hassector(&mp->m_sb)) { log.l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; ASSERT(log.l_sectbb_log <= mp->m_sectbb_log); /* for larger sector sizes, must have v2 or external log */ ASSERT(log.l_sectbb_log == 0 || log.l_logBBstart == 0 || xfs_sb_version_haslogv2(&mp->m_sb)); ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); } log.l_sectbb_mask = (1 << log.l_sectbb_log) - 1; if ((error = xlog_find_tail(&log, &head_blk, &tail_blk))) { do_warn(_("zero_log: cannot find log head/tail " "(xlog_find_tail=%d), zeroing it anyway\n"), error); } else { if (verbose) { do_warn(_("zero_log: head block %lld tail block %lld\n"), head_blk, tail_blk); } if (head_blk != tail_blk) { if (zap_log) { do_warn(_( "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "destroyed because the -L option was used.\n")); } else { do_warn(_( "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running xfs_repair. If you are unable to mount the filesystem, then use\n" "the -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n")); exit(2); } } } libxfs_log_clear(logdev, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), &mp->m_sb.sb_uuid, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, mp->m_sb.sb_logsunit, XLOG_FMT); }
static char * version_string( xfs_sb_t *sbp) { static char s[1024]; if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1) strcpy(s, "V1"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2) strcpy(s, "V2"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3) strcpy(s, "V3"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) strcpy(s, "V4"); else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) strcpy(s, "V5"); /* * We assume the state of these features now, so macros don't exist for * them any more. */ if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT) strcat(s, ",NLINK"); if (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) strcat(s, ",SHARED"); if (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT) strcat(s, ",DIRV2"); if (xfs_sb_version_hasattr(sbp)) strcat(s, ",ATTR"); if (xfs_sb_version_hasquota(sbp)) strcat(s, ",QUOTA"); if (xfs_sb_version_hasalign(sbp)) strcat(s, ",ALIGN"); if (xfs_sb_version_hasdalign(sbp)) strcat(s, ",DALIGN"); if (xfs_sb_version_haslogv2(sbp)) strcat(s, ",LOGV2"); if (xfs_sb_version_hasextflgbit(sbp)) strcat(s, ",EXTFLG"); if (xfs_sb_version_hassector(sbp)) strcat(s, ",SECTOR"); if (xfs_sb_version_hasasciici(sbp)) strcat(s, ",ASCII_CI"); if (xfs_sb_version_hasmorebits(sbp)) strcat(s, ",MOREBITS"); if (xfs_sb_version_hasattr2(sbp)) strcat(s, ",ATTR2"); if (xfs_sb_version_haslazysbcount(sbp)) strcat(s, ",LAZYSBCOUNT"); if (xfs_sb_version_hasprojid32bit(sbp)) strcat(s, ",PROJID32BIT"); if (xfs_sb_version_hascrc(sbp)) strcat(s, ",CRC"); if (xfs_sb_version_hasftype(sbp)) strcat(s, ",FTYPE"); if (xfs_sb_version_hasfinobt(sbp)) strcat(s, ",FINOBT"); if (xfs_sb_version_hassparseinodes(sbp)) strcat(s, ",SPARSE_INODES"); if (xfs_sb_version_hasmetauuid(sbp)) strcat(s, ",META_UUID"); return s; }
/* * Possible fields that may have been set at mkfs time, * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog. * The quota inode fields in the secondaries should be zero. * Likewise, the sb_flags and sb_shared_vn should also be * zero and the shared version bit should be cleared for * current mkfs's. * * And everything else in the buffer beyond either sb_width, * sb_dirblklog (v2 dirs), or sb_logsectsize can be zeroed. * * Note: contrary to the name, this routine is called for all * superblocks, not just the secondary superblocks. */ static int secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb, xfs_agnumber_t i) { int do_bzero; int size; char *ip; int rval; rval = do_bzero = 0; /* * mkfs's that stamped a feature bit besides the ones in the mask * (e.g. were pre-6.5 beta) could leave garbage in the secondary * superblock sectors. Anything stamping the shared fs bit or better * into the secondaries is ok and should generate clean secondary * superblock sectors. so only run the zero check on the * potentially garbaged secondaries. */ if (pre_65_beta || (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) == 0 || sb->sb_versionnum < XFS_SB_VERSION_4) { /* * Check for garbage beyond the last field. * Use field addresses instead so this code will still * work against older filesystems when the superblock * gets rev'ed again with new fields appended. */ if (xfs_sb_version_hasmorebits(sb)) size = (__psint_t)&sb->sb_features2 + sizeof(sb->sb_features2) - (__psint_t)sb; else if (xfs_sb_version_haslogv2(sb)) size = (__psint_t)&sb->sb_logsunit + sizeof(sb->sb_logsunit) - (__psint_t)sb; else if (xfs_sb_version_hassector(sb)) size = (__psint_t)&sb->sb_logsectsize + sizeof(sb->sb_logsectsize) - (__psint_t)sb; else if (xfs_sb_version_hasdirv2(sb)) size = (__psint_t)&sb->sb_dirblklog + sizeof(sb->sb_dirblklog) - (__psint_t)sb; else size = (__psint_t)&sb->sb_width + sizeof(sb->sb_width) - (__psint_t)sb; for (ip = (char *)((__psint_t)sb + size); ip < (char *)((__psint_t)sb + mp->m_sb.sb_sectsize); ip++) { if (*ip) { do_bzero = 1; break; } } if (do_bzero) { rval |= XR_AG_SB_SEC; if (!no_modify) { do_warn( _("zeroing unused portion of %s superblock (AG #%u)\n"), !i ? _("primary") : _("secondary"), i); memset((void *)((__psint_t)sb + size), 0, mp->m_sb.sb_sectsize - size); } else do_warn( _("would zero unused portion of %s superblock (AG #%u)\n"), !i ? _("primary") : _("secondary"), i); } } /* * now look for the fields we can manipulate directly. * if we did a zero and that zero could have included * the field in question, just silently reset it. otherwise, * complain. * * for now, just zero the flags field since only * the readonly flag is used */ if (sb->sb_flags) { if (!no_modify) sb->sb_flags = 0; if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn(_("bad flags field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } /* * quota inodes and flags in secondary superblocks * are never set by mkfs. However, they could be set * in a secondary if a fs with quotas was growfs'ed since * growfs copies the new primary into the secondaries. */ if (sb->sb_inprogress == 1 && sb->sb_uquotino) { if (!no_modify) sb->sb_uquotino = 0; if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn( _("non-null user quota inode field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (sb->sb_inprogress == 1 && sb->sb_gquotino) { if (!no_modify) sb->sb_gquotino = 0; if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn( _("non-null group quota inode field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (sb->sb_inprogress == 1 && sb->sb_qflags) { if (!no_modify) sb->sb_qflags = 0; if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn(_("non-null quota flags in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } /* * if the secondaries agree on a stripe unit/width or inode * alignment, those fields ought to be valid since they are * written at mkfs time (and the corresponding sb version bits * are set). */ if (!xfs_sb_version_hasshared(sb) && sb->sb_shared_vn != 0) { if (!no_modify) sb->sb_shared_vn = 0; if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn( _("bad shared version number in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (!xfs_sb_version_hasalign(sb) && sb->sb_inoalignmt != 0) { if (!no_modify) sb->sb_inoalignmt = 0; if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn( _("bad inode alignment field in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (!xfs_sb_version_hasdalign(sb) && (sb->sb_unit != 0 || sb->sb_width != 0)) { if (!no_modify) sb->sb_unit = sb->sb_width = 0; if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn( _("bad stripe unit/width fields in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } if (!xfs_sb_version_hassector(sb) && (sb->sb_sectsize != BBSIZE || sb->sb_sectlog != BBSHIFT || sb->sb_logsectsize != 0 || sb->sb_logsectlog != 0)) { if (!no_modify) { sb->sb_sectsize = BBSIZE; sb->sb_sectlog = BBSHIFT; sb->sb_logsectsize = 0; sb->sb_logsectlog = 0; } if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) { rval |= XR_AG_SB; do_warn( _("bad log/data device sector size fields in superblock %d\n"), i); } else rval |= XR_AG_SB_SEC; } return(rval); }
int verify_sb(xfs_sb_t *sb, int is_primary_sb) { __uint32_t bsize; xfs_extlen_t align; int i; /* check magic number and version number */ if (sb->sb_magicnum != XFS_SB_MAGIC) return(XR_BAD_MAGIC); if (!xfs_sb_good_version(sb)) return(XR_BAD_VERSION); /* does sb think mkfs really finished ? */ if (is_primary_sb && sb->sb_inprogress == 1) return(XR_BAD_INPROGRESS); /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */ if (sb->sb_blocksize == 0) return(XR_BAD_BLOCKSIZE); bsize = 1; for (i = 0; bsize < sb->sb_blocksize && i < sizeof(sb->sb_blocksize) * NBBY; i++) bsize <<= 1; if (i < XFS_MIN_BLOCKSIZE_LOG || i > XFS_MAX_BLOCKSIZE_LOG) return(XR_BAD_BLOCKSIZE); /* check sb blocksize field against sb blocklog field */ if (i != sb->sb_blocklog) return(XR_BAD_BLOCKLOG); /* sanity check ag count, size fields against data size field */ if (sb->sb_dblocks == 0 || sb->sb_dblocks > ((__uint64_t)sb->sb_agcount * sb->sb_agblocks) || sb->sb_dblocks < ((__uint64_t)(sb->sb_agcount - 1) * sb->sb_agblocks + XFS_MIN_AG_BLOCKS)) return(XR_BAD_FS_SIZE_DATA); if (sb->sb_agblklog != (__uint8_t)libxfs_log2_roundup(sb->sb_agblocks)) return(XR_BAD_FS_SIZE_DATA); if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE || sb->sb_inodesize > XFS_DINODE_MAX_SIZE || sb->sb_inopblock != howmany(sb->sb_blocksize,sb->sb_inodesize)) return(XR_BAD_INO_SIZE_DATA); /* check to make sure sectorsize is legal 2^N, 9 <= N <= 15 */ if (sb->sb_sectsize == 0) return(XR_BAD_SECT_SIZE_DATA); bsize = 1; for (i = 0; bsize < sb->sb_sectsize && i < sizeof(sb->sb_sectsize) * NBBY; i++) { bsize <<= 1; } if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG) return(XR_BAD_SECT_SIZE_DATA); /* check sb sectorsize field against sb sectlog field */ if (i != sb->sb_sectlog) return(XR_BAD_SECT_SIZE_DATA); if (xfs_sb_version_hassector(sb)) { /* check to make sure log sector is legal 2^N, 9 <= N <= 15 */ if (sb->sb_logsectsize == 0) return(XR_BAD_SECT_SIZE_DATA); bsize = 1; for (i = 0; bsize < sb->sb_logsectsize && i < sizeof(sb->sb_logsectsize) * NBBY; i++) { bsize <<= 1; } if (i < XFS_MIN_SECTORSIZE_LOG || i > XFS_MAX_SECTORSIZE_LOG) return(XR_BAD_SECT_SIZE_DATA); /* check sb log sectorsize field against sb log sectlog field */ if (i != sb->sb_logsectlog) return(XR_BAD_SECT_SIZE_DATA); } /* * real-time extent size is always set */ if (sb->sb_rextsize * sb->sb_blocksize > XFS_MAX_RTEXTSIZE) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rextsize * sb->sb_blocksize < XFS_MIN_RTEXTSIZE) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rblocks == 0) { if (sb->sb_rextents != 0) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rbmblocks != 0) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rextslog != 0) return(XR_BAD_RT_GEO_DATA); if (sb->sb_frextents != 0) return(XR_BAD_RT_GEO_DATA); } else { /* * if we have a real-time partition, sanity-check geometry */ if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rextslog != libxfs_highbit32((unsigned int)sb->sb_rextents)) return(XR_BAD_RT_GEO_DATA); if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents, NBBY * sb->sb_blocksize)) return(XR_BAD_RT_GEO_DATA); } /* * verify correctness of inode alignment if it's there */ if (xfs_sb_version_hasalign(sb)) { align = calc_ino_align(sb); if (align != sb->sb_inoalignmt) return(XR_BAD_INO_ALIGN); } /* * verify max. % of inodes (sb_imax_pct) */ if (sb->sb_imax_pct > 100) return(XR_BAD_INO_MAX_PCT); /* * verify stripe alignment fields if present */ if (xfs_sb_version_hasdalign(sb)) { if ((!sb->sb_unit && sb->sb_width) || (sb->sb_unit && sb->sb_agblocks % sb->sb_unit)) return(XR_BAD_SB_UNIT); if ((sb->sb_unit && !sb->sb_width) || (sb->sb_width && sb->sb_unit && sb->sb_width % sb->sb_unit)) return(XR_BAD_SB_WIDTH); } /* * if shared bit is set, verify that the version number is sane */ if (xfs_sb_version_hasshared(sb)) { if (sb->sb_shared_vn > XFS_SB_MAX_SHARED_VN) return(XR_BAD_SVN); } /* * mkfs's that stamped a feature bit besides the ones in the * mask below could leave garbage in the secondary superblock * sectors. Anything stamping the shared fs bit or better into * the secondaries is ok and should generate clean secondary * superblock sectors. * * check primary and clean secondary superblocks more strictly */ if (is_primary_sb || sb->sb_versionnum & XR_PART_SECSB_VNMASK) { /* * return errors if shared vn or alignment fields * are set without their feature bits being set */ if ((!pre_65_beta && (sb->sb_versionnum & XR_PART_SECSB_VNMASK)) || (pre_65_beta && (sb->sb_versionnum & XR_ALPHA_SECSB_VNMASK))) { /* * shared version # and inode alignment fields * should be valid */ if (sb->sb_shared_vn && !xfs_sb_version_hasshared(sb)) return(XR_BAD_SVN); if (sb->sb_inoalignmt && !xfs_sb_version_hasalign(sb)) return(XR_BAD_INO_ALIGN); } if ((!pre_65_beta && (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK)) || (pre_65_beta && (sb->sb_versionnum & XFS_SB_VERSION_DALIGNBIT))) { /* * stripe alignment values should be valid */ if (sb->sb_unit && !xfs_sb_version_hasdalign(sb)) return(XR_BAD_SB_UNIT); if (sb->sb_width && !xfs_sb_version_hasdalign(sb)) return(XR_BAD_SB_WIDTH); } #if 0 /* * checks involving later superblock fields get added here... */ if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) { } #endif } return(XR_OK); }
static void zero_log( struct xfs_mount *mp) { int error; xfs_daddr_t head_blk; xfs_daddr_t tail_blk; struct xlog *log = mp->m_log; memset(log, 0, sizeof(struct xlog)); x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart); x.lbsize = BBSIZE; if (xfs_sb_version_hassector(&mp->m_sb)) x.lbsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT); log->l_dev = mp->m_logdev_targp; log->l_logBBsize = x.logBBsize; log->l_logBBstart = x.logBBstart; log->l_sectBBsize = BTOBB(x.lbsize); log->l_mp = mp; if (xfs_sb_version_hassector(&mp->m_sb)) { log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; ASSERT(log->l_sectbb_log <= mp->m_sectbb_log); /* for larger sector sizes, must have v2 or external log */ ASSERT(log->l_sectbb_log == 0 || log->l_logBBstart == 0 || xfs_sb_version_haslogv2(&mp->m_sb)); ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT); } log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1; /* * Find the log head and tail and alert the user to the situation if the * log appears corrupted or contains data. In either case, we do not * proceed past this point unless the user explicitly requests to zap * the log. */ error = xlog_find_tail(log, &head_blk, &tail_blk); if (error) { do_warn( _("zero_log: cannot find log head/tail (xlog_find_tail=%d)\n"), error); if (!no_modify && !zap_log) do_error(_( "ERROR: The log head and/or tail cannot be discovered. Attempt to mount the\n" "filesystem to replay the log or use the -L option to destroy the log and\n" "attempt a repair.\n")); } else { if (verbose) { do_warn( _("zero_log: head block %" PRId64 " tail block %" PRId64 "\n"), head_blk, tail_blk); } if (!no_modify && head_blk != tail_blk) { if (zap_log) { do_warn(_( "ALERT: The filesystem has valuable metadata changes in a log which is being\n" "destroyed because the -L option was used.\n")); } else { do_warn(_( "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" "be replayed. Mount the filesystem to replay the log, and unmount it before\n" "re-running xfs_repair. If you are unable to mount the filesystem, then use\n" "the -L option to destroy the log and attempt a repair.\n" "Note that destroying the log may cause corruption -- please attempt a mount\n" "of the filesystem before doing this.\n")); exit(2); } } } /* * Only clear the log when explicitly requested. Doing so is unnecessary * unless something is wrong. Further, this resets the current LSN of * the filesystem and creates more work for repair of v5 superblock * filesystems. */ if (!no_modify && zap_log) { libxfs_log_clear(log->l_dev, NULL, XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), &mp->m_sb.sb_uuid, xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1, mp->m_sb.sb_logsunit, XLOG_FMT, XLOG_INIT_CYCLE, true); /* update the log data structure with new state */ error = xlog_find_tail(log, &head_blk, &tail_blk); if (error || head_blk != tail_blk) do_error(_("failed to clear log")); } /* * Finally, seed the max LSN from the current state of the log if this * is a v5 filesystem. */ if (xfs_sb_version_hascrc(&mp->m_sb)) libxfs_max_lsn = log->l_last_sync_lsn; }