#define libxfs_dinode_to_disk xfs_dinode_to_disk
void xfs_dinode_from_disk(struct xfs_icdinode *,
struct xfs_dinode *);
+#define libxfs_dinode_calc_crc xfs_dinode_calc_crc
#define libxfs_idata_realloc xfs_idata_realloc
#define libxfs_idestroy_fork xfs_idestroy_fork
#define libxfs_sb_from_disk xfs_sb_from_disk
#define libxfs_sb_to_disk xfs_sb_to_disk
+/* xfs_symlink.h */
+#define libxfs_symlink_blocks xfs_symlink_blocks
+#define libxfs_symlink_hdr_ok xfs_symlink_hdr_ok
+
/* xfs_rtalloc.c */
int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t);
*/
#define XFS_ALLOC_BLOCK_LEN(mp) \
(xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
- XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \
+ XFS_BTREE_SBLOCK_CRC_LEN : \
XFS_BTREE_SBLOCK_LEN)
/*
*/
#define XFS_BMBT_BLOCK_LEN(mp) \
(xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
- XFS_BTREE_LBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \
+ XFS_BTREE_LBLOCK_CRC_LEN : \
XFS_BTREE_LBLOCK_LEN)
#define XFS_BMBT_REC_ADDR(mp, block, index) \
#define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */
#define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */
-#define XFS_BTREE_CRCBLOCK_ADD 32 /* size of blkno + crc + uuid */
+
+/* sizes of CRC enabled btree blocks */
+#define XFS_BTREE_SBLOCK_CRC_LEN (XFS_BTREE_SBLOCK_LEN + 40)
+#define XFS_BTREE_LBLOCK_CRC_LEN (XFS_BTREE_LBLOCK_LEN + 48)
#define XFS_BTREE_SBLOCK_CRC_OFF \
offsetof(struct xfs_btree_block, bb_u.s.bb_crc)
*/
#define XFS_INOBT_BLOCK_LEN(mp) \
(xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
- XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD : \
+ XFS_BTREE_SBLOCK_CRC_LEN : \
XFS_BTREE_SBLOCK_LEN)
/*
sizeof(struct xfs_dsymlink_hdr) : 0))
int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
+bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
+ uint32_t size, struct xfs_buf *bp);
extern const struct xfs_buf_ops xfs_symlink_buf_ops;
} else
bp = kmem_zone_zalloc(xfs_buf_zone, 0);
pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex);
+ bp->b_ops = NULL;
return bp;
}
}
}
+ /*
+ * clear any pre-existing error status on the buffer. This can occur if
+ * the buffer is corrupt on disk and the repair process doesn't clear
+ * the error before fixing and writing it back.
+ */
+ bp->b_error = 0;
if (bp->b_ops) {
bp->b_ops->verify_write(bp);
- if (bp->b_error)
+ if (bp->b_error) {
+ fprintf(stderr,
+ _("%s: write verifer failed on bno 0x%llx/0x%x\n"),
+ __func__, (long long)bp->b_bn, bp->b_bcount);
return bp->b_error;
+ }
}
if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) {
int
libxfs_writebuf(xfs_buf_t *bp, int flags)
{
+#ifdef IO_DEBUG
+ printf("%lx: %s: dirty blkno=%llu(%llu)\n",
+ pthread_self(), __FUNCTION__,
+ (long long)LIBXFS_BBTOOFF64(bp->b_bn),
+ (long long)bp->b_bn);
+#endif
bp->b_flags |= (LIBXFS_B_DIRTY | flags);
libxfs_putbuf(bp);
return 0;
#define IHOLD(ip) ((void) 0)
/* stop unused var warnings by assigning mp to itself */
-#define XFS_CORRUPTION_ERROR(e,l,mp,m) do { (mp) = (mp); } while (0)
-#define XFS_ERROR_REPORT(e,l,mp) do { (mp) = (mp); } while (0)
+#define XFS_CORRUPTION_ERROR(e,l,mp,m) do { \
+ (mp) = (mp); \
+ cmn_err(CE_ALERT, "%s: XFS_CORRUPTION_ERROR", (e)); \
+} while (0)
+
+#define XFS_ERROR_REPORT(e,l,mp) do { \
+ (mp) = (mp); \
+ cmn_err(CE_ALERT, "%s: XFS_ERROR_REPORT", (e)); \
+} while (0)
+
#define XFS_QM_DQATTACH(mp,ip,flags) 0
#define XFS_ERROR(e) (e)
#define XFS_ERRLEVEL_LOW 1
struct xfs_agf *agf = XFS_BUF_TO_AGF(bp);
if (xfs_sb_version_hascrc(&mp->m_sb) &&
- !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_uuid))
+ !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
+ char uu[64], uu2[64];
+ platform_uuid_unparse(&agf->agf_uuid, uu);
+ platform_uuid_unparse(&mp->m_sb.sb_uuid, uu2);
+
return false;
+ }
if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
*/
static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur)
{
- size_t len;
-
- if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
- len = XFS_BTREE_LBLOCK_LEN;
- else
- len = XFS_BTREE_SBLOCK_LEN;
+ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+ if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS)
+ return XFS_BTREE_LBLOCK_CRC_LEN;
+ return XFS_BTREE_LBLOCK_LEN;
+ }
if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS)
- len += XFS_BTREE_CRCBLOCK_ADD;
-
- return len;
+ return XFS_BTREE_SBLOCK_CRC_LEN;
+ return XFS_BTREE_SBLOCK_LEN;
}
/*
offsetof(struct xfs_btree_block, bb_u.s.bb_uuid),
offsetof(struct xfs_btree_block, bb_u.s.bb_owner),
offsetof(struct xfs_btree_block, bb_u.s.bb_crc),
- XFS_BTREE_SBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD
+ XFS_BTREE_SBLOCK_CRC_LEN
};
static const short loffsets[] = { /* table of offsets (long) */
offsetof(struct xfs_btree_block, bb_magic),
offsetof(struct xfs_btree_block, bb_u.l.bb_owner),
offsetof(struct xfs_btree_block, bb_u.l.bb_crc),
offsetof(struct xfs_btree_block, bb_u.l.bb_pad),
- XFS_BTREE_LBLOCK_LEN + XFS_BTREE_CRCBLOCK_ADD
+ XFS_BTREE_LBLOCK_CRC_LEN
};
XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
#include "protos.h"
#include "err_protos.h"
+/*
+ * XXX (dgc): What is the point of all the check and repair here when phase 5
+ * recreates the AGF/AGI/AGFL completely from scratch?
+ */
+
static int
verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i)
{
/* don't check freespace btrees -- will be checked by caller */
- return(retval);
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
+ return retval;
+
+ if (platform_uuid_compare(&agf->agf_uuid, &mp->m_sb.sb_uuid)) {
+ char uu[64];
+
+ retval = XR_AG_AGF;
+ platform_uuid_unparse(&agf->agf_uuid, uu);
+ do_warn(_("bad uuid %s for agf %d\n"), uu, i);
+
+ if (!no_modify)
+ platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+ }
+ return retval;
}
static int
/* don't check inode btree -- will be checked by caller */
- return(retval);
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
+ return retval;
+
+ if (platform_uuid_compare(&agi->agi_uuid, &mp->m_sb.sb_uuid)) {
+ char uu[64];
+
+ retval = XR_AG_AGI;
+ platform_uuid_unparse(&agi->agi_uuid, uu);
+ do_warn(_("bad uuid %s for agi %d\n"), uu, agno);
+
+ if (!no_modify)
+ platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+ }
+
+ return retval;
}
/*
bplist[bp_index] = libxfs_readbuf(mp->m_dev,
XFS_AGB_TO_DADDR(mp, agno, agbno),
XFS_FSB_TO_BB(mp, blks_per_cluster), 0,
- NULL);
+ &xfs_inode_buf_ops);
if (!bplist[bp_index]) {
do_warn(_("cannot read inode %" PRIu64 ", disk block %" PRId64 ", cnt %d\n"),
XFS_AGINO_TO_INO(mp, agno, first_irec->ino_startnum),
extra_attr_check, &isa_dir, &parent);
ASSERT(is_used != 3);
- if (ino_dirty)
+ if (ino_dirty) {
dirty = 1;
+ libxfs_dinode_calc_crc(mp, dino);
+ }
+
/*
* XXX - if we want to try and keep
* track of whether we need to bang on
}
static int
-clear_dinode_core(xfs_dinode_t *dinoc, xfs_ino_t ino_num)
+clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
{
int dirty = 0;
+ int i;
- if (be16_to_cpu(dinoc->di_magic) != XFS_DINODE_MAGIC) {
- dirty = 1;
-
- if (no_modify)
- return(1);
+#define __dirty_no_modify_ret(dirty) \
+ ({ (dirty) = 1; if (no_modify) return 1; })
+ if (be16_to_cpu(dinoc->di_magic) != XFS_DINODE_MAGIC) {
+ __dirty_no_modify_ret(dirty);
dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
}
if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) ||
(!fs_inode_nlink && dinoc->di_version > 1)) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
- dinoc->di_version = (fs_inode_nlink) ? 2 : 1;
+ __dirty_no_modify_ret(dirty);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ dinoc->di_version = 3;
+ else
+ dinoc->di_version = (fs_inode_nlink) ? 2 : 1;
}
if (be16_to_cpu(dinoc->di_mode) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_mode = 0;
}
if (be16_to_cpu(dinoc->di_flags) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_flags = 0;
}
if (be32_to_cpu(dinoc->di_dmevmask) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_dmevmask = 0;
}
if (dinoc->di_forkoff != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_forkoff = 0;
}
if (dinoc->di_format != XFS_DINODE_FMT_EXTENTS) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_format = XFS_DINODE_FMT_EXTENTS;
}
if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
}
if (be64_to_cpu(dinoc->di_size) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_size = 0;
}
if (be64_to_cpu(dinoc->di_nblocks) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_nblocks = 0;
}
if (be16_to_cpu(dinoc->di_onlink) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_onlink = 0;
}
if (be32_to_cpu(dinoc->di_nextents) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_nextents = 0;
}
if (be16_to_cpu(dinoc->di_anextents) != 0) {
- dirty = 1;
-
- if (no_modify)
- return(1);
-
+ __dirty_no_modify_ret(dirty);
dinoc->di_anextents = 0;
}
if (dinoc->di_version > 1 &&
be32_to_cpu(dinoc->di_nlink) != 0) {
- dirty = 1;
+ __dirty_no_modify_ret(dirty);
+ dinoc->di_nlink = 0;
+ }
- if (no_modify)
- return(1);
+ /* we are done for version 1/2 inodes */
+ if (dinoc->di_version < 3)
+ return dirty;
- dinoc->di_nlink = 0;
+ if (be64_to_cpu(dinoc->di_ino) != ino_num) {
+ __dirty_no_modify_ret(dirty);
+ dinoc->di_ino = cpu_to_be64(ino_num);
}
- return(dirty);
+ if (platform_uuid_compare(&dinoc->di_uuid, &mp->m_sb.sb_uuid)) {
+ __dirty_no_modify_ret(dirty);
+ platform_uuid_copy(&dinoc->di_uuid, &mp->m_sb.sb_uuid);
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (dinoc->di_pad[i] != 0) {
+ __dirty_no_modify_ret(dirty);
+ memset(dinoc->di_pad, 0, 16);
+ break;
+ }
+ }
+
+ if (be64_to_cpu(dinoc->di_flags2) != 0) {
+ __dirty_no_modify_ret(dirty);
+ dinoc->di_flags2 = 0;
+ }
+
+ if (be64_to_cpu(dinoc->di_lsn) != 0) {
+ __dirty_no_modify_ret(dirty);
+ dinoc->di_lsn = 0;
+ }
+
+ if (be64_to_cpu(dinoc->di_changecount) != 0) {
+ __dirty_no_modify_ret(dirty);
+ dinoc->di_changecount = 0;
+ }
+
+ return dirty;
}
static int
{
int dirty;
- dirty = clear_dinode_core(dino, ino_num);
+ dirty = clear_dinode_core(mp, dino, ino_num);
dirty += clear_dinode_unlinked(mp, dino);
/* and clear the forks */
int level;
int numrecs;
bmap_cursor_t cursor;
+ __uint64_t magic;
dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
lino = XFS_AGINO_TO_INO(mp, agno, ino);
else
forkname = _("attr");
+ magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_BMAP_CRC_MAGIC
+ : XFS_BMAP_MAGIC;
+
level = be16_to_cpu(dib->bb_level);
numrecs = be16_to_cpu(dib->bb_numrecs);
return(1);
}
- if (scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type,
+ if (scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt, type,
whichfork, lino, tot, nex, blkmapp, &cursor,
- 1, check_dups))
+ 1, check_dups, magic, &xfs_bmbt_buf_ops))
return(1);
/*
* fix key (offset) mismatches between the keys in root
return(1);
}
+
buf_data = (char *)XFS_BUF_PTR(bp);
- size = MIN(be64_to_cpu(dino->di_size) - amountdone,
- XFS_FSB_TO_BB(mp, 1) * BBSIZE);
+ size = MIN(be64_to_cpu(dino->di_size) - amountdone,
+ XFS_SYMLINK_BUF_SPACE(mp,
+ mp->m_sb.sb_blocksize));
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!libxfs_symlink_hdr_ok(mp, lino, amountdone,
+ size, bp)) {
+ do_warn(
+_("bad symlink header ino %" PRIu64 ", file block %d, disk block %" PRIu64 "\n"),
+ lino, i, fsbno);
+ return(1);
+ }
+ buf_data += sizeof(struct xfs_dsymlink_hdr);
+ }
memmove(cptr, buf_data, size);
cptr += size;
amountdone += size;
}
if (!XFS_DINODE_GOOD_VERSION(dino->di_version) ||
- (!fs_inode_nlink && dino->di_version > 1)) {
+ (!fs_inode_nlink && dino->di_version > 1) ||
+ (xfs_sb_version_hascrc(&mp->m_sb) && dino->di_version < 3) ) {
retval = 1;
if (!uncertain)
do_warn(_("bad version number 0x%x on inode %" PRIu64 "%c"),
if (!verify_mode) {
if (!no_modify) {
do_warn(_(" resetting version number\n"));
- dino->di_version = (fs_inode_nlink) ? 2 : 1;
+ dino->di_version =
+ xfs_sb_version_hascrc(&mp->m_sb) ? 3 :
+ (fs_inode_nlink) ? 2 : 1;
*dirty = 1;
} else
do_warn(_(" would reset version number\n"));
}
}
+ /*
+ * We don't bother checking the CRC here - we cannot guarantee that when
+ * we are called here that the inode has not already been modified in
+ * memory and hence invalidated the CRC.
+ */
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (be64_to_cpu(dino->di_ino) != lino) {
+ if (!uncertain)
+ do_warn(
+_("inode identifier %llu mismatch on inode %" PRIu64 "\n"),
+ be64_to_cpu(dino->di_ino), lino);
+ if (verify_mode)
+ return 1;
+ goto clear_bad_out;
+ }
+ if (platform_uuid_compare(&dino->di_uuid, &mp->m_sb.sb_uuid)) {
+ if (!uncertain)
+ do_warn(
+ _("UUID mismatch on inode %" PRIu64 "\n"), lino);
+ if (verify_mode)
+ return 1;
+ goto clear_bad_out;
+ }
+ }
+
/*
* blow out of here if the inode size is < 0
*/
ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT);
}
log.l_sectbb_mask = (1 << log.l_sectbb_log) - 1;
+ log.l_sectBBsize = 1 << mp->m_sb.sb_logsectlog;
if ((error = xlog_find_tail(&log, &head_blk, &tail_blk))) {
do_warn(_("zero_log: cannot find log head/tail "
xfs_alloc_ptr_t *bt_ptr;
xfs_agblock_t agbno;
bt_stat_level_t *lptr;
+ __uint32_t crc_magic;
+
+ if (magic == XFS_ABTB_MAGIC)
+ crc_magic = XFS_ABTB_CRC_MAGIC;
+ else
+ crc_magic = XFS_ABTC_CRC_MAGIC;
level++;
/*
* initialize block header
*/
+ lptr->buf_p->b_ops = &xfs_allocbt_buf_ops;
bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ xfs_btree_init_block(mp, lptr->buf_p, crc_magic, level,
+ 0, agno, XFS_BTREE_CRC_BLOCKS);
+ else
+ xfs_btree_init_block(mp, lptr->buf_p, magic, level,
+ 0, agno, 0);
- bt_hdr->bb_magic = cpu_to_be32(magic);
- bt_hdr->bb_level = cpu_to_be16(level);
bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno);
- bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
- bt_hdr->bb_numrecs = 0;
/*
* propagate extent record for first extent in new block up
extent_tree_node_t *ext_ptr;
bt_stat_level_t *lptr;
xfs_extlen_t freeblks;
+ __uint32_t crc_magic;
#ifdef XR_BLD_FREE_TRACE
fprintf(stderr, "in build_freespace_tree, agno = %d\n", agno);
freeblks = 0;
ASSERT(level > 0);
+ if (magic == XFS_ABTB_MAGIC)
+ crc_magic = XFS_ABTB_CRC_MAGIC;
+ else
+ crc_magic = XFS_ABTC_CRC_MAGIC;
/*
* initialize the first block on each btree level
/*
* initialize block header
*/
+ lptr->buf_p->b_ops = &xfs_allocbt_buf_ops;
bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
-
- bt_hdr->bb_magic = cpu_to_be32(magic);
- bt_hdr->bb_level = cpu_to_be16(i);
- bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
- bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
- bt_hdr->bb_numrecs = 0;
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ xfs_btree_init_block(mp, lptr->buf_p, crc_magic, i,
+ 0, agno, XFS_BTREE_CRC_BLOCKS);
+ else
+ xfs_btree_init_block(mp, lptr->buf_p, magic, i,
+ 0, agno, 0);
}
/*
* run along leaf, setting up records. as we have to switch
/*
* block initialization, lay in block header
*/
+ lptr->buf_p->b_ops = &xfs_allocbt_buf_ops;
bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ xfs_btree_init_block(mp, lptr->buf_p, crc_magic, 0,
+ 0, agno, XFS_BTREE_CRC_BLOCKS);
+ else
+ xfs_btree_init_block(mp, lptr->buf_p, magic, 0,
+ 0, agno, 0);
- bt_hdr->bb_magic = cpu_to_be32(magic);
- bt_hdr->bb_level = 0;
bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno);
- bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb +
(lptr->modulo > 0));
#ifdef XR_BLD_FREE_TRACE
/*
* initialize block header
*/
+ lptr->buf_p->b_ops = &xfs_inobt_buf_ops;
bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_CRC_MAGIC,
+ level, 0, agno,
+ XFS_BTREE_CRC_BLOCKS);
+ else
+ xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC,
+ level, 0, agno, 0);
- bt_hdr->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
- bt_hdr->bb_level = cpu_to_be16(level);
bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno);
- bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
- bt_hdr->bb_numrecs = 0;
+
/*
* propagate extent record for first extent in new block up
*/
*bt_ptr = cpu_to_be32(btree_curs->level[level-1].agbno);
}
+/*
+ * XXX: yet more code that can be shared with mkfs, growfs.
+ */
static void
build_agi(xfs_mount_t *mp, xfs_agnumber_t agno,
bt_status_t *btree_curs, xfs_agino_t first_agino,
agi_buf = libxfs_getbuf(mp->m_dev,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
mp->m_sb.sb_sectsize/BBSIZE);
+ agi_buf->b_ops = &xfs_agi_buf_ops;
agi = XFS_BUF_TO_AGI(agi_buf);
memset(agi, 0, mp->m_sb.sb_sectsize);
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++)
agi->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ platform_uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
+
libxfs_writebuf(agi_buf, 0);
}
/*
* initialize block header
*/
+
+ lptr->buf_p->b_ops = &xfs_inobt_buf_ops;
bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
-
- bt_hdr->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
- bt_hdr->bb_level = cpu_to_be16(i);
- bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
- bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
- bt_hdr->bb_numrecs = 0;
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_CRC_MAGIC,
+ i, 0, agno,
+ XFS_BTREE_CRC_BLOCKS);
+ else
+ xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC,
+ i, 0, agno, 0);
}
+
/*
* run along leaf, setting up records. as we have to switch
* blocks, call the prop_ino_cursor routine to set up the new
/*
* block initialization, lay in block header
*/
+ lptr->buf_p->b_ops = &xfs_inobt_buf_ops;
bt_hdr = XFS_BUF_TO_BLOCK(lptr->buf_p);
memset(bt_hdr, 0, mp->m_sb.sb_blocksize);
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_CRC_MAGIC,
+ 0, 0, agno,
+ XFS_BTREE_CRC_BLOCKS);
+ else
+ xfs_btree_init_block(mp, lptr->buf_p, XFS_IBT_MAGIC,
+ 0, 0, agno, 0);
- bt_hdr->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
- bt_hdr->bb_level = 0;
bt_hdr->bb_u.s.bb_leftsib = cpu_to_be32(lptr->prev_agbno);
- bt_hdr->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
bt_hdr->bb_numrecs = cpu_to_be16(lptr->num_recs_pb +
(lptr->modulo > 0));
/*
* build both the agf and the agfl for an agno given both
- * btree cursors
+ * btree cursors.
+ *
+ * XXX: yet more common code that can be shared with mkfs/growfs.
*/
static void
build_agf_agfl(xfs_mount_t *mp,
agf_buf = libxfs_getbuf(mp->m_dev,
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
mp->m_sb.sb_sectsize/BBSIZE);
+ agf_buf->b_ops = &xfs_agf_buf_ops;
agf = XFS_BUF_TO_AGF(agf_buf);
memset(agf, 0, mp->m_sb.sb_sectsize);
XFS_BTNUM_CNT);
#endif
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ platform_uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
+
+ /* initialise the AGFL, then fill it if there are blocks left over. */
+ agfl_buf = libxfs_getbuf(mp->m_dev,
+ XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
+ mp->m_sb.sb_sectsize/BBSIZE);
+ agfl_buf->b_ops = &xfs_agfl_buf_ops;
+ agfl = XFS_BUF_TO_AGFL(agfl_buf);
+
+ /* setting to 0xff results in initialisation to NULLAGBLOCK */
+ memset(agfl, 0xff, mp->m_sb.sb_sectsize);
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
+ agfl->agfl_seqno = cpu_to_be32(agno);
+ platform_uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
+ for (i = 0; i < XFS_AGFL_SIZE(mp); i++)
+ agfl->agfl_bno[i] = cpu_to_be32(NULLAGBLOCK);
+ }
+ freelist = XFS_BUF_TO_AGFL_BNO(mp, agfl_buf);
+
/*
* do we have left-over blocks in the btree cursors that should
* be used to fill the AGFL?
*/
if (bno_bt->num_free_blocks > 0 || bcnt_bt->num_free_blocks > 0) {
/*
- * yes - grab the AGFL buffer
- */
- agfl_buf = libxfs_getbuf(mp->m_dev,
- XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
- mp->m_sb.sb_sectsize/BBSIZE);
- agfl = XFS_BUF_TO_AGFL(agfl_buf);
- freelist = XFS_BUF_TO_AGFL_BNO(mp, agfl_buf);
- memset(agfl, 0, mp->m_sb.sb_sectsize);
- /*
- * ok, now grab as many blocks as we can
+ * yes, now grab as many blocks as we can
*/
i = j = 0;
while (bno_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE(mp)) {
fprintf(stderr, "writing agfl for ag %u\n", agno);
#endif
- libxfs_writebuf(agfl_buf, 0);
} else {
agf->agf_flfirst = 0;
agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
agf->agf_flcount = 0;
}
+ libxfs_writebuf(agfl_buf, 0);
+
ext_ptr = findbiggest_bcnt_extent(agno);
agf->agf_longest = cpu_to_be32((ext_ptr != NULL) ?
ext_ptr->ex_blockcount : 0);
libxfs_writebuf(agf_buf, 0);
+ /*
+ * now fix up the free list appropriately
+ * XXX: code lifted from mkfs, should be shared.
+ */
+ {
+ xfs_alloc_arg_t args;
+ xfs_trans_t *tp;
+
+ memset(&args, 0, sizeof(args));
+ args.tp = tp = libxfs_trans_alloc(mp, 0);
+ args.mp = mp;
+ args.agno = agno;
+ args.alignment = 1;
+ args.pag = xfs_perag_get(mp,agno);
+ libxfs_trans_reserve(tp, XFS_MIN_FREELIST(agf, mp), 0, 0, 0, 0);
+ libxfs_alloc_fix_freelist(&args, 0);
+ xfs_perag_put(args.pag);
+ libxfs_trans_commit(tp, 0);
+ }
+
#ifdef XR_BLD_FREE_TRACE
fprintf(stderr, "wrote agf for ag %u, error = %d\n", agno, error);
#endif
int rc;
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dbno),
- XFS_FSB_TO_BB(mp, 1), 0, NULL);
+ XFS_FSB_TO_BB(mp, 1), 0, &xfs_bmbt_buf_ops);
if (!bp)
return 0;
int hasdir = 0;
int isadir;
+ bp->b_ops = &xfs_inode_buf_ops;
+ bp->b_ops->verify_read(bp);
+ if (bp->b_error)
+ return;
+
for (icnt = 0; icnt < (XFS_BUF_COUNT(bp) >> mp->m_sb.sb_inodelog); icnt++) {
dino = xfs_make_iptr(mp, bp, icnt);
__uint64_t ifreecount;
};
-static void
-scanfunc_allocbt(
- struct xfs_btree_block *block,
- int level,
- xfs_agblock_t bno,
- xfs_agnumber_t agno,
- int suspect,
- int isroot,
- __uint32_t magic,
- struct aghdr_cnts *agcnts);
-
void
set_mp(xfs_mount_t *mpp)
{
xfs_agnumber_t agno,
int suspect,
int isroot,
+ __uint32_t magic,
void *priv),
int isroot,
- void *priv)
+ __uint32_t magic,
+ void *priv,
+ const struct xfs_buf_ops *ops)
{
xfs_buf_t *bp;
bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, root),
- XFS_FSB_TO_BB(mp, 1), 0, NULL);
+ XFS_FSB_TO_BB(mp, 1), 0, ops);
if (!bp) {
do_error(_("can't read btree block %d/%d\n"), agno, root);
return;
}
(*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, root, agno, suspect,
- isroot, priv);
+ isroot, magic, priv);
libxfs_putbuf(bp);
}
bmap_cursor_t *bm_cursor,
int isroot,
int check_dups,
- int *dirty),
+ int *dirty,
+ __uint64_t magic),
int type,
int whichfork,
xfs_ino_t ino,
blkmap_t **blkmapp,
bmap_cursor_t *bm_cursor,
int isroot,
- int check_dups)
+ int check_dups,
+ __uint64_t magic,
+ const struct xfs_buf_ops *ops)
{
xfs_buf_t *bp;
int err;
int dirty = 0;
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, root),
- XFS_FSB_TO_BB(mp, 1), 0, NULL);
+ XFS_FSB_TO_BB(mp, 1), 0, ops);
if (!bp) {
do_error(_("can't read btree block %d/%d\n"),
XFS_FSB_TO_AGNO(mp, root),
}
err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1,
type, whichfork, root, ino, tot, nex, blkmapp,
- bm_cursor, isroot, check_dups, &dirty);
+ bm_cursor, isroot, check_dups, &dirty,
+ magic);
ASSERT(dirty == 0 || (dirty && !no_modify));
}
int
-scanfunc_bmap(
+scan_bmapbt(
struct xfs_btree_block *block,
int level,
int type,
bmap_cursor_t *bm_cursor,
int isroot,
int check_dups,
- int *dirty)
+ int *dirty,
+ __uint64_t magic)
{
int i;
int err;
* another inode are claiming the same block but that's
* highly unlikely.
*/
- if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC) {
+ if (be32_to_cpu(block->bb_magic) != magic) {
do_warn(
_("bad magic # %#x in inode %" PRIu64 " (%s fork) bmbt block %" PRIu64 "\n"),
be32_to_cpu(block->bb_magic), ino, forkname, bno);
return(1);
}
+ if (magic == XFS_BMAP_CRC_MAGIC) {
+ /* verify owner */
+ if (be64_to_cpu(block->bb_u.l.bb_owner) != ino) {
+ do_warn(
+_("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
+ ino, be64_to_cpu(block->bb_u.l.bb_owner), bno);
+ return(1);
+ }
+ }
+
if (check_dups == 0) {
/*
* check sibling pointers. if bad we have a conflict
return(1);
}
- err = scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap,
+ err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt,
type, whichfork, ino, tot, nex, blkmapp,
- bm_cursor, 0, check_dups);
+ bm_cursor, 0, check_dups, magic,
+ &xfs_bmbt_buf_ops);
if (err)
return(1);
}
static void
-scanfunc_bno(
- struct xfs_btree_block *block,
- int level,
- xfs_agblock_t bno,
- xfs_agnumber_t agno,
- int suspect,
- int isroot,
- void *agcnts)
-{
- return scanfunc_allocbt(block, level, bno, agno,
- suspect, isroot, XFS_ABTB_MAGIC, agcnts);
-}
-
-static void
-scanfunc_cnt(
- struct xfs_btree_block *block,
- int level,
- xfs_agblock_t bno,
- xfs_agnumber_t agno,
- int suspect,
- int isroot,
- void *agcnts)
-{
- return scanfunc_allocbt(block, level, bno, agno,
- suspect, isroot, XFS_ABTC_MAGIC, agcnts);
-}
-
-static void
-scanfunc_allocbt(
+scan_allocbt(
struct xfs_btree_block *block,
int level,
xfs_agblock_t bno,
int suspect,
int isroot,
__uint32_t magic,
- struct aghdr_cnts *agcnts)
+ void *priv)
{
+ struct aghdr_cnts *agcnts = priv;
const char *name;
int i;
xfs_alloc_ptr_t *pp;
xfs_extlen_t lastcount = 0;
xfs_agblock_t lastblock = 0;
- assert(magic == XFS_ABTB_MAGIC || magic == XFS_ABTC_MAGIC);
-
- name = (magic == XFS_ABTB_MAGIC) ? "bno" : "cnt";
+ switch (magic) {
+ case XFS_ABTB_CRC_MAGIC:
+ case XFS_ABTB_MAGIC:
+ name = "bno";
+ break;
+ case XFS_ABTC_CRC_MAGIC:
+ case XFS_ABTC_MAGIC:
+ name = "cnt";
+ break;
+ default:
+ assert(0);
+ break;
+ }
if (be32_to_cpu(block->bb_magic) != magic) {
do_warn(_("bad magic # %#x in bt%s block %d/%d\n"),
continue;
}
- if (magic == XFS_ABTB_MAGIC) {
+ if (magic == XFS_ABTB_MAGIC ||
+ magic == XFS_ABTB_CRC_MAGIC) {
if (b <= lastblock) {
do_warn(_(
"out-of-order bno btree record %d (%u %u) block %u/%u\n"),
* no warning messages -- we'll catch
* FREE1 blocks later
*/
- if (magic == XFS_ABTC_MAGIC) {
+ if (magic == XFS_ABTC_MAGIC ||
+ magic == XFS_ABTC_CRC_MAGIC) {
set_bmap_ext(agno, b, blen,
XR_E_FREE);
break;
* as possible.
*/
if (bno != 0 && verify_agbno(mp, agno, bno)) {
- scan_sbtree(bno, level, agno, suspect,
- (magic == XFS_ABTB_MAGIC) ?
- scanfunc_bno : scanfunc_cnt, 0,
- (void *)agcnts);
+ switch (magic) {
+ case XFS_ABTB_CRC_MAGIC:
+ case XFS_ABTB_MAGIC:
+ scan_sbtree(bno, level, agno, suspect,
+ scan_allocbt, 0, magic, priv,
+ &xfs_allocbt_buf_ops);
+ break;
+ case XFS_ABTC_CRC_MAGIC:
+ case XFS_ABTC_MAGIC:
+ scan_sbtree(bno, level, agno, suspect,
+ scan_allocbt, 0, magic, priv,
+ &xfs_allocbt_buf_ops);
+ break;
+ }
}
}
}
* that we aren't sure about go into the uncertain list.
*/
static void
-scanfunc_ino(
+scan_inobt(
struct xfs_btree_block *block,
int level,
xfs_agblock_t bno,
xfs_agnumber_t agno,
int suspect,
int isroot,
+ __uint32_t magic,
void *priv)
{
struct aghdr_cnts *agcnts = priv;
hdr_errors = 0;
- if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC) {
+ if (be32_to_cpu(block->bb_magic) != magic) {
do_warn(_("bad magic # %#x in inobt block %d/%d\n"),
be32_to_cpu(block->bb_magic), agno, bno);
hdr_errors++;
if (be32_to_cpu(pp[i]) != 0 && verify_agbno(mp, agno,
be32_to_cpu(pp[i])))
scan_sbtree(be32_to_cpu(pp[i]), level, agno,
- suspect, scanfunc_ino, 0, priv);
+ suspect, scan_inobt, 0, magic, priv,
+ &xfs_inobt_buf_ops);
}
}
struct aghdr_cnts *agcnts)
{
xfs_agblock_t bno;
+ __uint32_t magic;
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC
+ : XFS_ABTB_MAGIC;
scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
- agno, 0, scanfunc_bno, 1, agcnts);
+ agno, 0, scan_allocbt, 1, magic, agcnts,
+ &xfs_allocbt_buf_ops);
} else {
do_warn(_("bad agbno %u for btbno root, agno %d\n"),
bno, agno);
bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTC_CRC_MAGIC
+ : XFS_ABTC_MAGIC;
scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
- agno, 0, scanfunc_cnt, 1, agcnts);
+ agno, 0, scan_allocbt, 1, magic, agcnts,
+ &xfs_allocbt_buf_ops);
} else {
do_warn(_("bad agbno %u for btbcnt root, agno %d\n"),
bno, agno);
{
xfs_agblock_t bno;
int i;
+ __uint32_t magic;
bno = be32_to_cpu(agi->agi_root);
if (bno != 0 && verify_agbno(mp, agno, bno)) {
+ magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC
+ : XFS_IBT_MAGIC;
scan_sbtree(bno, be32_to_cpu(agi->agi_level),
- agno, 0, scanfunc_ino, 1, agcnts);
+ agno, 0, scan_inobt, 1, magic, agcnts,
+ &xfs_inobt_buf_ops);
} else {
do_warn(_("bad agbno %u for inobt root, agno %d\n"),
be32_to_cpu(agi->agi_root), agno);
bmap_cursor_t *bm_cursor,
int isroot,
int check_dups,
- int *dirty),
+ int *dirty,
+ __uint64_t magic),
int type,
int whichfork,
xfs_ino_t ino,
struct blkmap **blkmapp,
bmap_cursor_t *bm_cursor,
int isroot,
- int check_dups);
+ int check_dups,
+ __uint64_t magic,
+ const struct xfs_buf_ops *ops);
-int scanfunc_bmap(
+int scan_bmapbt(
struct xfs_btree_block *block,
int level,
int type,
bmap_cursor_t *bm_cursor,
int isroot,
int check_dups,
- int *dirty);
+ int *dirty,
+ __uint64_t magic);
void
scan_ags(
return(1);
}
- if (XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_4) {
+ if (XFS_SB_VERSION_NUM(sb) >= XFS_SB_VERSION_4) {
if (!fs_sb_feature_bits_allowed) {
if (!no_modify) {
do_warn(
glob_agcount = mp->m_sb.sb_agcount;
chunks_pblock = mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK;
- max_symlink_blocks = howmany(MAXPATHLEN - 1, mp->m_sb.sb_blocksize);
+ max_symlink_blocks = libxfs_symlink_blocks(mp, MAXPATHLEN);
inodes_per_cluster = MAX(mp->m_sb.sb_inopblock,
XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);