/* * Invalidate buffers for per-AG btree blocks we're dumping. This function * is not intended for use with file data repairs; we have bunmapi for that. */ int xrep_invalidate_blocks( struct xfs_scrub *sc, struct xfs_bitmap *bitmap) { struct xfs_bitmap_range *bmr; struct xfs_bitmap_range *n; struct xfs_buf *bp; xfs_fsblock_t fsbno; /* * For each block in each extent, see if there's an incore buffer for * exactly that block; if so, invalidate it. The buffer cache only * lets us look for one buffer at a time, so we have to look one block * at a time. Avoid invalidating AG headers and post-EOFS blocks * because we never own those; and if we can't TRYLOCK the buffer we * assume it's owned by someone else. */ for_each_xfs_bitmap_block(fsbno, bmr, n, bitmap) { /* Skip AG headers and post-EOFS blocks */ if (!xfs_verify_fsbno(sc->mp, fsbno)) continue; bp = xfs_buf_incore(sc->mp->m_ddev_targp, XFS_FSB_TO_DADDR(sc->mp, fsbno), XFS_FSB_TO_BB(sc->mp, 1), XBF_TRYLOCK); if (bp) { xfs_trans_bjoin(sc->tp, bp); xfs_trans_binval(sc->tp, bp); } } return 0; }
/* * Indiscriminately delete the entire attribute fork * * Recurse (gasp!) through the attribute nodes until we find leaves. * We're doing a depth-first traversal in order to invalidate everything. */ int xfs_attr3_root_inactive( struct xfs_trans **trans, struct xfs_inode *dp) { struct xfs_da_blkinfo *info; struct xfs_buf *bp; xfs_daddr_t blkno; int error; /* * Read block 0 to see what we have to work with. * We only get here if we have extents, since we remove * the extents in reverse order the extent containing * block 0 must still be there. */ error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK); if (error) return error; blkno = bp->b_bn; /* * Invalidate the tree, even if the "tree" is only a single leaf block. * This is a depth-first traversal! */ info = bp->b_addr; switch (info->magic) { case cpu_to_be16(XFS_DA_NODE_MAGIC): case cpu_to_be16(XFS_DA3_NODE_MAGIC): error = xfs_attr3_node_inactive(trans, dp, bp, 1); break; case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): error = xfs_attr3_leaf_inactive(trans, dp, bp); break; default: error = -EIO; xfs_trans_brelse(*trans, bp); break; } if (error) return error; /* * Invalidate the incore copy of the root block. */ error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK); if (error) return error; xfs_trans_binval(*trans, bp); /* remove from cache */ /* * Commit the invalidate and start the next transaction. */ error = xfs_trans_roll(trans, dp); return error; }
/* * Free a symlink that has blocks associated with it. */ STATIC int xfs_inactive_symlink_rmt( struct xfs_inode *ip) { xfs_buf_t *bp; int committed; int done; int error; xfs_fsblock_t first_block; xfs_bmap_free_t free_list; int i; xfs_mount_t *mp; xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS]; int nmaps; int size; xfs_trans_t *tp; mp = ip->i_mount; ASSERT(ip->i_df.if_flags & XFS_IFEXTENTS); /* * We're freeing a symlink that has some * blocks allocated to it. Free the * blocks here. We know that we've got * either 1 or 2 extents and that we can * free them all in one bunmapi call. */ ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0); if (error) { xfs_trans_cancel(tp, 0); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); /* * Lock the inode, fix the size, and join it to the transaction. * Hold it so in the normal path, we still have it locked for * the second transaction. In the error paths we need it * held so the cancel won't rele it, see below. */ size = (int)ip->i_d.di_size; ip->i_d.di_size = 0; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); /* * Find the block(s) so we can inval and unmap them. */ done = 0; xfs_bmap_init(&free_list, &first_block); nmaps = ARRAY_SIZE(mval); error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size), mval, &nmaps, 0); if (error) goto error_trans_cancel; /* * Invalidate the block(s). No validation is done. */ for (i = 0; i < nmaps; i++) { bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); if (!bp) { error = ENOMEM; goto error_bmap_cancel; } xfs_trans_binval(tp, bp); } /* * Unmap the dead block(s) to the free_list. */ error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, &first_block, &free_list, &done); if (error) goto error_bmap_cancel; ASSERT(done); /* * Commit the first transaction. This logs the EFI and the inode. */ error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) goto error_bmap_cancel; /* * The transaction must have been committed, since there were * actually extents freed by xfs_bunmapi. See xfs_bmap_finish. * The new tp has the extent freeing and EFDs. */ ASSERT(committed); /* * The first xact was committed, so add the inode to the new one. * Mark it dirty so it will be logged and moved forward in the log as * part of every commit. */ xfs_trans_ijoin(tp, ip, 0); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); /* * Commit the transaction containing extent freeing and EFDs. */ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); if (error) { ASSERT(XFS_FORCED_SHUTDOWN(mp)); goto error_unlock; } /* * Remove the memory for extent descriptions (just bookkeeping). */ if (ip->i_df.if_bytes) xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK); ASSERT(ip->i_df.if_bytes == 0); xfs_iunlock(ip, XFS_ILOCK_EXCL); return 0; error_bmap_cancel: xfs_bmap_cancel(&free_list); error_trans_cancel: xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); error_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; }
/* * Remove the given block from the directory. * This routine is used for data and free blocks, leaf/node are done * by xfs_da_shrink_inode. */ int xfs_dir2_shrink_inode( xfs_da_args_t *args, xfs_dir2_db_t db, struct xfs_buf *bp) { xfs_fileoff_t bno; /* directory file offset */ xfs_dablk_t da; /* directory file offset */ int done; /* bunmap is finished */ xfs_inode_t *dp; int error; xfs_mount_t *mp; xfs_trans_t *tp; trace_xfs_dir2_shrink_inode(args, db); dp = args->dp; mp = dp->i_mount; tp = args->trans; da = xfs_dir2_db_to_da(args->geo, db); /* * Unmap the fsblock(s). */ if ((error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, &done))) { /* * ENOSPC actually can happen if we're in a removename with * no space reservation, and the resulting block removal * would cause a bmap btree split or conversion from extents * to btree. This can only happen for un-fragmented * directory blocks, since you need to be punching out * the middle of an extent. * In this case we need to leave the block in the file, * and not binval it. * So the block has to be in a consistent empty state * and appropriately logged. * We don't free up the buffer, the caller can tell it * hasn't happened since it got an error back. */ return error; } ASSERT(done); /* * Invalidate the buffer from the transaction. */ xfs_trans_binval(tp, bp); /* * If it's not a data block, we're done. */ if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)) return 0; /* * If the block isn't the last one in the directory, we're done. */ if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0)) return 0; bno = da; if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { /* * This can't really happen unless there's kernel corruption. */ return error; } if (db == args->geo->datablk) ASSERT(bno == 0); else ASSERT(bno > 0); /* * Set the size to the new last block. */ dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); return 0; }
/* * Look at all the extents for this logical region, * invalidate any buffers that are incore/in transactions. */ STATIC int xfs_attr3_leaf_freextent( struct xfs_trans **trans, struct xfs_inode *dp, xfs_dablk_t blkno, int blkcnt) { struct xfs_bmbt_irec map; struct xfs_buf *bp; xfs_dablk_t tblkno; xfs_daddr_t dblkno; int tblkcnt; int dblkcnt; int nmap; int error; /* * Roll through the "value", invalidating the attribute value's * blocks. */ tblkno = blkno; tblkcnt = blkcnt; while (tblkcnt > 0) { /* * Try to remember where we decided to put the value. */ nmap = 1; error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); if (error) { return error; } ASSERT(nmap == 1); ASSERT(map.br_startblock != DELAYSTARTBLOCK); /* * If it's a hole, these are already unmapped * so there's nothing to invalidate. */ if (map.br_startblock != HOLESTARTBLOCK) { dblkno = XFS_FSB_TO_DADDR(dp->i_mount, map.br_startblock); dblkcnt = XFS_FSB_TO_BB(dp->i_mount, map.br_blockcount); bp = xfs_trans_get_buf(*trans, dp->i_mount->m_ddev_targp, dblkno, dblkcnt, 0); if (!bp) return -ENOMEM; xfs_trans_binval(*trans, bp); /* * Roll to next transaction. */ error = xfs_trans_roll(trans, dp); if (error) return error; } tblkno += map.br_blockcount; tblkcnt -= map.br_blockcount; } return 0; }
/* * Recurse (gasp!) through the attribute nodes until we find leaves. * We're doing a depth-first traversal in order to invalidate everything. */ STATIC int xfs_attr3_node_inactive( struct xfs_trans **trans, struct xfs_inode *dp, struct xfs_buf *bp, int level) { xfs_da_blkinfo_t *info; xfs_da_intnode_t *node; xfs_dablk_t child_fsb; xfs_daddr_t parent_blkno, child_blkno; int error, i; struct xfs_buf *child_bp; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr ichdr; /* * Since this code is recursive (gasp!) we must protect ourselves. */ if (level > XFS_DA_NODE_MAXDEPTH) { xfs_trans_brelse(*trans, bp); /* no locks for later trans */ return -EIO; } node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&ichdr, node); parent_blkno = bp->b_bn; if (!ichdr.count) { xfs_trans_brelse(*trans, bp); return 0; } btree = dp->d_ops->node_tree_p(node); child_fsb = be32_to_cpu(btree[0].before); xfs_trans_brelse(*trans, bp); /* no locks for later trans */ /* * If this is the node level just above the leaves, simply loop * over the leaves removing all of them. If this is higher up * in the tree, recurse downward. */ for (i = 0; i < ichdr.count; i++) { /* * Read the subsidiary block to see what we have to work with. * Don't do this in a transaction. This is a depth-first * traversal of the tree so we may deal with many blocks * before we come back to this one. */ error = xfs_da3_node_read(*trans, dp, child_fsb, -2, &child_bp, XFS_ATTR_FORK); if (error) return error; if (child_bp) { /* save for re-read later */ child_blkno = XFS_BUF_ADDR(child_bp); /* * Invalidate the subtree, however we have to. */ info = child_bp->b_addr; switch (info->magic) { case cpu_to_be16(XFS_DA_NODE_MAGIC): case cpu_to_be16(XFS_DA3_NODE_MAGIC): error = xfs_attr3_node_inactive(trans, dp, child_bp, level + 1); break; case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): error = xfs_attr3_leaf_inactive(trans, dp, child_bp); break; default: error = -EIO; xfs_trans_brelse(*trans, child_bp); break; } if (error) return error; /* * Remove the subsidiary block from the cache * and from the log. */ error = xfs_da_get_buf(*trans, dp, 0, child_blkno, &child_bp, XFS_ATTR_FORK); if (error) return error; xfs_trans_binval(*trans, child_bp); } /* * If we're not done, re-read the parent to get the next * child block number. */ if (i + 1 < ichdr.count) { error = xfs_da3_node_read(*trans, dp, 0, parent_blkno, &bp, XFS_ATTR_FORK); if (error) return error; child_fsb = be32_to_cpu(btree[i + 1].before); xfs_trans_brelse(*trans, bp); } /* * Atomically commit the whole invalidate stuff. */ error = xfs_trans_roll(trans, dp); if (error) return error; } return 0; }