/* * Check that the holemask and freemask of a hypothetical inode cluster match * what's actually on disk. If sparse inodes are enabled, the cluster does * not actually have to map to inodes if the corresponding holemask bit is set. * * @cluster_base is the first inode in the cluster within the @irec. */ STATIC int xchk_iallocbt_check_cluster( struct xchk_btree *bs, struct xfs_inobt_rec_incore *irec, unsigned int cluster_base) { struct xfs_imap imap; struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_dinode *dip; struct xfs_buf *cluster_bp; unsigned int nr_inodes; xfs_agnumber_t agno = bs->cur->bc_private.a.agno; xfs_agblock_t agbno; unsigned int cluster_index; uint16_t cluster_mask = 0; uint16_t ir_holemask; int error = 0; nr_inodes = min_t(unsigned int, XFS_INODES_PER_CHUNK, mp->m_inodes_per_cluster); /* Map this inode cluster */ agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino + cluster_base); /* Compute a bitmask for this cluster that can be used for holemask. */ for (cluster_index = 0; cluster_index < nr_inodes; cluster_index += XFS_INODES_PER_HOLEMASK_BIT) cluster_mask |= XFS_INOBT_MASK((cluster_base + cluster_index) / XFS_INODES_PER_HOLEMASK_BIT); /* * Map the first inode of this cluster to a buffer and offset. * Be careful about inobt records that don't align with the start of * the inode buffer when block sizes are large enough to hold multiple * inode chunks. When this happens, cluster_base will be zero but * ir_startino can be large enough to make im_boffset nonzero. */ ir_holemask = (irec->ir_holemask & cluster_mask); imap.im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno); imap.im_len = XFS_FSB_TO_BB(mp, mp->m_blocks_per_cluster); imap.im_boffset = XFS_INO_TO_OFFSET(mp, irec->ir_startino); if (imap.im_boffset != 0 && cluster_base != 0) { ASSERT(imap.im_boffset == 0 || cluster_base == 0); xchk_btree_set_corrupt(bs->sc, bs->cur, 0); return 0; } trace_xchk_iallocbt_check_cluster(mp, agno, irec->ir_startino, imap.im_blkno, imap.im_len, cluster_base, nr_inodes, cluster_mask, ir_holemask, XFS_INO_TO_OFFSET(mp, irec->ir_startino + cluster_base)); /* The whole cluster must be a hole or not a hole. */ if (ir_holemask != cluster_mask && ir_holemask != 0) { xchk_btree_set_corrupt(bs->sc, bs->cur, 0); return 0; } /* If any part of this is a hole, skip it. */ if (ir_holemask) { xchk_xref_is_not_owned_by(bs->sc, agbno, mp->m_blocks_per_cluster, &XFS_RMAP_OINFO_INODES); return 0; } xchk_xref_is_owned_by(bs->sc, agbno, mp->m_blocks_per_cluster, &XFS_RMAP_OINFO_INODES); /* Grab the inode cluster buffer. */ error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &cluster_bp, 0, 0); if (!xchk_btree_xref_process_error(bs->sc, bs->cur, 0, &error)) return error; /* Check free status of each inode within this cluster. */ for (cluster_index = 0; cluster_index < nr_inodes; cluster_index++) { struct xfs_dinode *dip; if (imap.im_boffset >= BBTOB(cluster_bp->b_length)) { xchk_btree_set_corrupt(bs->sc, bs->cur, 0); break; } dip = xfs_buf_offset(cluster_bp, imap.im_boffset); error = xchk_iallocbt_check_cluster_ifree(bs, irec, cluster_base + cluster_index, dip); if (error) break; imap.im_boffset += mp->m_sb.sb_inodesize; } xfs_trans_brelse(bs->cur->bc_tp, cluster_bp); return error; }
/* * Read the disk inode attributes into the in-core inode structure. * * For version 5 superblocks, if we are initialising a new inode and we are not * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new * inode core with a random generation number. If we are keeping inodes around, * we need to read the inode cluster to get the existing generation number off * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode * format) then log recovery is dependent on the di_flushiter field being * initialised from the current on-disk value and hence we must also read the * inode off disk. */ int xfs_iread( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *ip, uint iget_flags) { xfs_buf_t *bp; xfs_dinode_t *dip; int error; /* * Fill in the location information in the in-core inode. */ error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); if (error) return error; /* shortcut IO on inode allocation if possible */ if ((iget_flags & XFS_IGET_CREATE) && xfs_sb_version_hascrc(&mp->m_sb) && !(mp->m_flags & XFS_MOUNT_IKEEP)) { /* initialise the on-disk inode core */ memset(&ip->i_d, 0, sizeof(ip->i_d)); ip->i_d.di_magic = XFS_DINODE_MAGIC; ip->i_d.di_gen = prandom_u32(); if (xfs_sb_version_hascrc(&mp->m_sb)) { ip->i_d.di_version = 3; ip->i_d.di_ino = ip->i_ino; uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid); } else ip->i_d.di_version = 2; return 0; } /* * Get pointers to the on-disk inode and the buffer containing it. */ error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); if (error) return error; /* even unallocated inodes are verified */ if (!xfs_dinode_verify(mp, ip, dip)) { xfs_alert(mp, "%s: validation failed for inode %lld failed", __func__, ip->i_ino); XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip); error = -EFSCORRUPTED; goto out_brelse; } /* * If the on-disk inode is already linked to a directory * entry, copy all of the inode into the in-core inode. * xfs_iformat_fork() handles copying in the inode format * specific information. * Otherwise, just get the truly permanent information. */ if (dip->di_mode) { xfs_dinode_from_disk(&ip->i_d, dip); error = xfs_iformat_fork(ip, dip); if (error) { #ifdef DEBUG xfs_alert(mp, "%s: xfs_iformat() returned error %d", __func__, error); #endif /* DEBUG */ goto out_brelse; } } else { /* * Partial initialisation of the in-core inode. Just the bits * that xfs_ialloc won't overwrite or relies on being correct. */ ip->i_d.di_magic = be16_to_cpu(dip->di_magic); ip->i_d.di_version = dip->di_version; ip->i_d.di_gen = be32_to_cpu(dip->di_gen); ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); if (dip->di_version == 3) { ip->i_d.di_ino = be64_to_cpu(dip->di_ino); uuid_copy(&ip->i_d.di_uuid, &dip->di_uuid); } /* * Make sure to pull in the mode here as well in * case the inode is released without being used. * This ensures that xfs_inactive() will see that * the inode is already free and not try to mess * with the uninitialized part of it. */ ip->i_d.di_mode = 0; } /* * Automatically convert version 1 inode formats in memory to version 2 * inode format. If the inode is modified, it will get logged and * rewritten as a version 2 inode. We can do this because we set the * superblock feature bit for v2 inodes unconditionally during mount * and it means the reast of the code can assume the inode version is 2 * or higher. */ if (ip->i_d.di_version == 1) { ip->i_d.di_version = 2; memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); ip->i_d.di_nlink = ip->i_d.di_onlink; ip->i_d.di_onlink = 0; xfs_set_projid(ip, 0); } ip->i_delayed_blks = 0; /* * Mark the buffer containing the inode as something to keep * around for a while. This helps to keep recently accessed * meta-data in-core longer. */ xfs_buf_set_ref(bp, XFS_INO_REF); /* * Use xfs_trans_brelse() to release the buffer containing the on-disk * inode, because it was acquired with xfs_trans_read_buf() in * xfs_imap_to_bp() above. If tp is NULL, this is just a normal * brelse(). If we're within a transaction, then xfs_trans_brelse() * will only release the buffer if it is not dirty within the * transaction. It will be OK to release the buffer in this case, * because inodes on disk are never destroyed and we will be locking the * new in-core inode before putting it in the cache where other * processes can find it. Thus we don't have to worry about the inode * being changed just because we released the buffer. */ out_brelse: xfs_trans_brelse(tp, bp); return error; }
/* * Read the disk inode attributes into the in-core inode structure. * * For version 5 superblocks, if we are initialising a new inode and we are not * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new * inode core with a random generation number. If we are keeping inodes around, * we need to read the inode cluster to get the existing generation number off * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode * format) then log recovery is dependent on the di_flushiter field being * initialised from the current on-disk value and hence we must also read the * inode off disk. */ int xfs_iread( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *ip, uint iget_flags) { xfs_buf_t *bp; xfs_dinode_t *dip; xfs_failaddr_t fa; int error; /* * Fill in the location information in the in-core inode. */ error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); if (error) return error; /* shortcut IO on inode allocation if possible */ if ((iget_flags & XFS_IGET_CREATE) && xfs_sb_version_hascrc(&mp->m_sb) && !(mp->m_flags & XFS_MOUNT_IKEEP)) { /* initialise the on-disk inode core */ memset(&ip->i_d, 0, sizeof(ip->i_d)); VFS_I(ip)->i_generation = prandom_u32(); ip->i_d.di_version = 3; return 0; } /* * Get pointers to the on-disk inode and the buffer containing it. */ error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); if (error) return error; /* even unallocated inodes are verified */ fa = xfs_dinode_verify(mp, ip->i_ino, dip); if (fa) { xfs_inode_verifier_error(ip, -EFSCORRUPTED, "dinode", dip, sizeof(*dip), fa); error = -EFSCORRUPTED; goto out_brelse; } /* * If the on-disk inode is already linked to a directory * entry, copy all of the inode into the in-core inode. * xfs_iformat_fork() handles copying in the inode format * specific information. * Otherwise, just get the truly permanent information. */ if (dip->di_mode) { xfs_inode_from_disk(ip, dip); error = xfs_iformat_fork(ip, dip); if (error) { #ifdef DEBUG xfs_alert(mp, "%s: xfs_iformat() returned error %d", __func__, error); #endif /* DEBUG */ goto out_brelse; } } else { /* * Partial initialisation of the in-core inode. Just the bits * that xfs_ialloc won't overwrite or relies on being correct. */ ip->i_d.di_version = dip->di_version; VFS_I(ip)->i_generation = be32_to_cpu(dip->di_gen); ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); /* * Make sure to pull in the mode here as well in * case the inode is released without being used. * This ensures that xfs_inactive() will see that * the inode is already free and not try to mess * with the uninitialized part of it. */ VFS_I(ip)->i_mode = 0; } ASSERT(ip->i_d.di_version >= 2); ip->i_delayed_blks = 0; /* * Mark the buffer containing the inode as something to keep * around for a while. This helps to keep recently accessed * meta-data in-core longer. */ xfs_buf_set_ref(bp, XFS_INO_REF); /* * Use xfs_trans_brelse() to release the buffer containing the on-disk * inode, because it was acquired with xfs_trans_read_buf() in * xfs_imap_to_bp() above. If tp is NULL, this is just a normal * brelse(). If we're within a transaction, then xfs_trans_brelse() * will only release the buffer if it is not dirty within the * transaction. It will be OK to release the buffer in this case, * because inodes on disk are never destroyed and we will be locking the * new in-core inode before putting it in the cache where other * processes can find it. Thus we don't have to worry about the inode * being changed just because we released the buffer. */ out_brelse: xfs_trans_brelse(tp, bp); return error; }
/* Make sure the free mask is consistent with what the inodes think. */ STATIC int xfs_scrub_iallocbt_check_freemask( struct xfs_scrub_btree *bs, struct xfs_inobt_rec_incore *irec) { struct xfs_owner_info oinfo; struct xfs_imap imap; struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_dinode *dip; struct xfs_buf *bp; xfs_ino_t fsino; xfs_agino_t nr_inodes; xfs_agino_t agino; xfs_agino_t chunkino; xfs_agino_t clusterino; xfs_agblock_t agbno; int blks_per_cluster; uint16_t holemask; uint16_t ir_holemask; int error = 0; /* Make sure the freemask matches the inode records. */ blks_per_cluster = xfs_icluster_size_fsb(mp); nr_inodes = XFS_OFFBNO_TO_AGINO(mp, blks_per_cluster, 0); xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_INODES); for (agino = irec->ir_startino; agino < irec->ir_startino + XFS_INODES_PER_CHUNK; agino += blks_per_cluster * mp->m_sb.sb_inopblock) { fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino); chunkino = agino - irec->ir_startino; agbno = XFS_AGINO_TO_AGBNO(mp, agino); /* Compute the holemask mask for this cluster. */ for (clusterino = 0, holemask = 0; clusterino < nr_inodes; clusterino += XFS_INODES_PER_HOLEMASK_BIT) holemask |= XFS_INOBT_MASK((chunkino + clusterino) / XFS_INODES_PER_HOLEMASK_BIT); /* The whole cluster must be a hole or not a hole. */ ir_holemask = (irec->ir_holemask & holemask); if (ir_holemask != holemask && ir_holemask != 0) { xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0); continue; } /* If any part of this is a hole, skip it. */ if (ir_holemask) continue; /* Grab the inode cluster buffer. */ imap.im_blkno = XFS_AGB_TO_DADDR(mp, bs->cur->bc_private.a.agno, agbno); imap.im_len = XFS_FSB_TO_BB(mp, blks_per_cluster); imap.im_boffset = 0; error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap, &dip, &bp, 0, 0); if (!xfs_scrub_btree_process_error(bs->sc, bs->cur, 0, &error)) continue; /* Which inodes are free? */ for (clusterino = 0; clusterino < nr_inodes; clusterino++) { error = xfs_scrub_iallocbt_check_cluster_freemask(bs, fsino, chunkino, clusterino, irec, bp); if (error) { xfs_trans_brelse(bs->cur->bc_tp, bp); return error; } } xfs_trans_brelse(bs->cur->bc_tp, bp); } return error; }