/*
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_btree.h"
#include "xfs_btree_trace.h"
#include "xfs_ialloc.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
/*
* Prototypes for internal functions.
*/
STATIC void xfs_alloc_log_block(xfs_trans_t *, xfs_buf_t *, int);
STATIC void xfs_alloc_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int);
STATIC void xfs_alloc_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
STATIC void xfs_alloc_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
/*
* Internal functions.
*/
/*
* Single level of the xfs_alloc_delete record deletion routine.
* Delete record pointed to by cur/level.
* Remove the record from its block then rebalance the tree.
* Return 0 for error, 1 for done, 2 to go on to the next level.
*/
STATIC int /* error */
xfs_alloc_delrec(
xfs_btree_cur_t *cur, /* btree cursor */
int level, /* level removing record from */
int *stat) /* fail/done/go-on */
{
xfs_agf_t *agf; /* allocation group freelist header */
xfs_alloc_block_t *block; /* btree block record/key lives in */
xfs_agblock_t bno; /* btree block number */
xfs_buf_t *bp; /* buffer for block */
int error; /* error return value */
int i; /* loop index */
xfs_alloc_key_t key; /* kp points here if block is level 0 */
xfs_agblock_t lbno; /* left block's block number */
xfs_buf_t *lbp; /* left block's buffer pointer */
xfs_alloc_block_t *left; /* left btree block */
xfs_alloc_key_t *lkp=NULL; /* left block key pointer */
xfs_alloc_ptr_t *lpp=NULL; /* left block address pointer */
int lrecs=0; /* number of records in left block */
xfs_alloc_rec_t *lrp; /* left block record pointer */
xfs_mount_t *mp; /* mount structure */
int ptr; /* index in btree block for this rec */
xfs_agblock_t rbno; /* right block's block number */
xfs_buf_t *rbp; /* right block's buffer pointer */
xfs_alloc_block_t *right; /* right btree block */
xfs_alloc_key_t *rkp; /* right block key pointer */
xfs_alloc_ptr_t *rpp; /* right block address pointer */
int rrecs=0; /* number of records in right block */
int numrecs;
xfs_alloc_rec_t *rrp; /* right block record pointer */
xfs_btree_cur_t *tcur; /* temporary btree cursor */
/*
* Get the index of the entry being deleted, check for nothing there.
*/
ptr = cur->bc_ptrs[level];
if (ptr == 0) {
*stat = 0;
return 0;
}
/*
* Get the buffer & block containing the record or key/ptr.
*/
bp = cur->bc_bufs[level];
block = XFS_BUF_TO_ALLOC_BLOCK(bp);
#ifdef DEBUG
if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
return error;
#endif
/*
* Fail if we're off the end of the block.
*/
numrecs = be16_to_cpu(block->bb_numrecs);
if (ptr > numrecs) {
*stat = 0;
return 0;
}
XFS_STATS_INC(xs_abt_delrec);
/*
* It's a nonleaf. Excise the key and ptr being deleted, by
* sliding the entries past them down one.
* Log the changed areas of the block.
*/
if (level > 0) {
lkp = XFS_ALLOC_KEY_ADDR(block, 1, cur);
lpp = XFS_ALLOC_PTR_ADDR(block, 1, cur);
#ifdef DEBUG
for (i = ptr; i < numrecs; i++) {
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(lpp[i]), level)))
return error;
}
#endif
if (ptr < numrecs) {
memmove(&lkp[ptr - 1],