diff -urN -x xfs_ialloc_btree.h.orig -x xfs_trans.c.orig -x Entries.Log -x Entries linux-2.6-xfs.orig/fs/xfs/xfs_alloc_btree.c linux-2.6-xfs/fs/xfs/xfs_alloc_btree.c --- linux-2.6-xfs.orig/fs/xfs/xfs_alloc_btree.c 2005-01-14 13:57:33.000000000 +0200 +++ linux-2.6-xfs/fs/xfs/xfs_alloc_btree.c 2005-09-06 02:01:39.024407208 +0300 @@ -1773,6 +1773,82 @@ */ /* + * Compute the size (in blocks) of the btree in the given level/block number + */ +int /* error */ +xfs_alloc_btsize( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* current level */ + xfs_agblock_t agbno, /* a.g. relative btree block number */ + int *result)/* pointer to variable to be incremented */ +{ + xfs_agnumber_t agno; + xfs_alloc_block_t *block=NULL; /* current btree block */ + int error; /* error return value */ + int ptrno; /* current key number */ + xfs_daddr_t d; /* disk address of btree block */ + xfs_buf_t *bp; /* buffer pointer for btree block */ + + XFS_STATS_INC(xs_abt_lookup); + + if(level == 0) { /* level == 0 means no childs and thus one block usage */ + (*result)++; + return 0; + } + + { + xfs_agf_t *agf; /* a.g. freespace header */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + agno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + } + + + d = XFS_AGB_TO_DADDR(cur->bc_mp, agno, agbno); + printk("btsize agno=%d agbno=%d diskaddr=%lld level=%d result=%d\n", agno, agbno, d, level, *result); + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, agno, + agbno, 0, &bp, XFS_ALLOC_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + + /* + * Iterate over each child in this non-leaf block + */ + for (ptrno = 0; ptrno < INT_GET(block->bb_numrecs, ARCH_CONVERT); ptrno++) { + xfs_alloc_ptr_t *child; + xfs_agblock_t newbno; + + child = XFS_ALLOC_PTR_ADDR(block, ptrno + 1, cur); + newbno = INT_GET(*child, ARCH_CONVERT); + + printk("\twill enter ptrno=%d (of %d) agbno=%d\n", ptrno, INT_GET(block->bb_numrecs, ARCH_CONVERT), newbno); + + if((error = xfs_alloc_btsize(cur, level - 1, newbno, result))) + return error; + + } + (*result)++; + return 0; +} + +/* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ diff -urN -x xfs_ialloc_btree.h.orig -x xfs_trans.c.orig -x Entries.Log -x Entries linux-2.6-xfs.orig/fs/xfs/xfs_alloc_btree.h linux-2.6-xfs/fs/xfs/xfs_alloc_btree.h --- linux-2.6-xfs.orig/fs/xfs/xfs_alloc_btree.h 2003-06-27 21:04:26.000000000 +0300 +++ linux-2.6-xfs/fs/xfs/xfs_alloc_btree.h 2005-09-06 02:01:39.025407056 +0300 @@ -164,6 +164,16 @@ */ /* + * Compute the size (in blocks) of the btree in the given level/block number + */ +int /* error */ +xfs_alloc_btsize( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* current level */ + xfs_agblock_t agbno, /* a.g. relative btree block number */ + int *result); /* pointer to variable to be incremented */ + +/* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ diff -urN -x xfs_ialloc_btree.h.orig -x xfs_trans.c.orig -x Entries.Log -x Entries linux-2.6-xfs.orig/fs/xfs/xfs_fsops.c linux-2.6-xfs/fs/xfs/xfs_fsops.c --- linux-2.6-xfs.orig/fs/xfs/xfs_fsops.c 2005-05-18 12:18:24.000000000 +0300 +++ linux-2.6-xfs/fs/xfs/xfs_fsops.c 2005-09-06 02:01:39.026406904 +0300 @@ -66,6 +66,8 @@ * File system operations */ +static int xfs_shrink_data_private(xfs_mount_t *mp, xfs_growfs_data_t *in); + int xfs_fs_geometry( xfs_mount_t *mp, @@ -153,7 +155,9 @@ nb = in->newblocks; pct = in->imaxpct; - if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100) + if (nb < mp->m_sb.sb_dblocks) + return xfs_shrink_data_private(mp, in); + if (pct < 0 || pct > 100) return XFS_ERROR(EINVAL); dpct = pct - mp->m_sb.sb_imax_pct; error = xfs_read_buf(mp, mp->m_ddev_targp, @@ -416,6 +420,318 @@ } static int +xfs_shrink_data_private( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_data_t *in) /* growfs data input struct */ +{ + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_agnumber_t agno; + xfs_buf_t *bp; + int dpct; + int error; + xfs_agnumber_t nagcount; /* new number of a.g. */ + xfs_agnumber_t nagimax = 0; + xfs_rfsblock_t nb, nb_mod; + xfs_rfsblock_t new; + xfs_rfsblock_t nfree; + xfs_agnumber_t oagcount; + int pct; + xfs_sb_t *sbp; + xfs_trans_t *tp; + xfs_alloc_arg_t allocarg; + long icount = 0; /* sum of total inode count deleted by shrink */ + long ifree = 0; /* sum of free inode count deleted by shrink */ + long inofree = 0; /* space used by inodes and inode btree */ + + nb = in->newblocks; + pct = in->imaxpct; + if (nb > mp->m_sb.sb_dblocks || pct < 0 || pct > 100) + return XFS_ERROR(EINVAL); + dpct = pct - mp->m_sb.sb_imax_pct; + error = xfs_read_buf(mp, mp->m_ddev_targp, + XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1), + XFS_FSS_TO_BB(mp, 1), 0, &bp); + if (error) + return error; + ASSERT(bp); + xfs_buf_relse(bp); + + new = nb; /* use new as a temporary here */ + nb_mod = do_div(new, mp->m_sb.sb_agblocks); + printk("Cur ag=%d, cur blocks=%d\n", mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks); + nagcount = new + (nb_mod != 0); + printk("New ag=%d, new blocks=%d, nb_mod=%d\n", new, nb, nb_mod); + if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { + printk("nb_mod (%d) < XFS_MIN_AG_BLOCKS (%d)\n", nb_mod, XFS_MIN_AG_BLOCKS); + nagcount--; + nb = nagcount * mp->m_sb.sb_agblocks; + printk("ne2 ag=%d, ne2 blocks=%d\n", nagcount, nb); + if (nb >= mp->m_sb.sb_dblocks) + return XFS_ERROR(EINVAL); + } + printk("Will resize from %d to %d, delta is %d\n", mp->m_sb.sb_dblocks, nb, mp->m_sb.sb_dblocks - nb); + /* Check to see if we trip over the log section */ + printk("logstart=%ld logblocks=%ld\n", mp->m_sb.sb_logstart, mp->m_sb.sb_logblocks); + if (nb < mp->m_sb.sb_logstart + mp->m_sb.sb_logblocks) + return XFS_ERROR(EINVAL); + new = nb - mp->m_sb.sb_dblocks; + oagcount = mp->m_sb.sb_agcount; + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); + printk("reserving %d\n", XFS_GROWFS_SPACE_RES(mp) + (-new)); + if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp) + (-new), + XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + return error; + } + + nfree = 0; + for(agno = oagcount - 1; agno >= nagcount; agno--) { + xfs_extlen_t usedblks; /* total used blocks in this a.g. */ + xfs_extlen_t freeblks; /* free blocks in this a.g. */ + xfs_extlen_t metaused; /* blocks used by metadata */ + xfs_agblock_t aglen; + xfs_btree_cur_t *cur; /* cursor used for btree iteration */ + xfs_extlen_t sizeibt; /* blocks used by inode btree */ + xfs_extlen_t sizeino; /* blocks used by inode chunks */ + xfs_extlen_t sizebno; /* blocks used by by-number btree */ + xfs_extlen_t sizecnt; /* blocks used by by-count btree */ + printk("doing agno=%d\n", agno); + + /* + * Check the inodes and get ino btree usage + */ + error = xfs_ialloc_read_agi(mp, tp, agno, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agi = XFS_BUF_TO_AGI(bp); + /* This a.g. has inodes in use, can't shrink */ + if(INT_GET(agi->agi_count, ARCH_CONVERT) != INT_GET(agi->agi_freecount, ARCH_CONVERT)) { + printk("agi %d has %d inodes in use\n", agno, INT_GET(agi->agi_count, ARCH_CONVERT) - INT_GET(agi->agi_freecount, ARCH_CONVERT)); + error = XFS_ERROR(ENOSPC); + goto error0; + } + /* Record the number of inodes (total and free) + * to substract from the superblock + */ + icount -= INT_GET(agi->agi_count, ARCH_CONVERT); + ifree -= INT_GET(agi->agi_freecount, ARCH_CONVERT); + + /* Compute the number of blocks used by inode chunks + * in this a.g. + */ + cur = xfs_btree_init_cursor(mp, tp, bp, agno, XFS_BTNUM_INO, NULL, 0); + sizeibt = sizeino = 0; + error = xfs_inobtsize(cur, cur->bc_nlevels - 1, INT_GET(agi->agi_root, ARCH_CONVERT), &sizeibt, &sizeino); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + if(error) { + goto error0; + } + printk("agi %d shows %d block in use by ino btree, %d blocks by inodes\n", agno, sizeibt, sizeino); + + /* Compute number of blocks used by the freelist and free btrees in this a.g. */ + error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agf = XFS_BUF_TO_AGF(bp); + + freeblks = INT_GET(agf->agf_freeblks, ARCH_CONVERT); + printk("Usage: %d prealloc, %d flcount\n", XFS_PREALLOC_BLOCKS(mp), INT_GET(agf->agf_flcount, ARCH_CONVERT)); + /* BNO btree processing */ + sizebno = 0; + cur = xfs_btree_init_cursor(mp, tp, bp, agno, XFS_BTNUM_BNO, NULL, 0); + error = xfs_alloc_btsize(cur, cur->bc_nlevels - 1, INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), &sizebno); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + if(error) { + goto error0; + } + printk("agf %d shows %d block in use by bno btree\n", agno, sizebno); + /* CNT btree processing */ + sizecnt = 0; + cur = xfs_btree_init_cursor(mp, tp, bp, agno, XFS_BTNUM_CNT, NULL, 0); + error = xfs_alloc_btsize(cur, cur->bc_nlevels - 1, INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), &sizecnt); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + if(error) { + goto error0; + } + printk("agf %d shows %d block in use by cnt btree\n", agno, sizecnt); + + /* Done gathering data, check sizes */ + /* We don't add here the sizebno and sizecnt since + * it appears they are not computed as 'used' space + */ + metaused = sizeino + sizeibt - 1; + + usedblks = XFS_PREALLOC_BLOCKS(mp) + \ + INT_GET(agf->agf_flcount, ARCH_CONVERT) + \ + metaused + sizebno - 1 + sizecnt - 1; + aglen = INT_GET(agf->agf_length, ARCH_CONVERT); + printk("agno=%d agf_length=%d computed used=%d known free=%d\n", agno, aglen, usedblks, INT_GET(agf->agf_freeblks, ARCH_CONVERT)); + if(usedblks + freeblks != aglen) { + printk("agno %d is not free (%d blocks allocated)\n", agno, aglen-usedblks-freeblks); + error = XFS_ERROR(ENOSPC); + goto error0; + } + new += aglen; + printk("will lower with %d\n", aglen - XFS_PREALLOC_BLOCKS(mp) - metaused); + nfree -= aglen - XFS_PREALLOC_BLOCKS(mp); + /* add not substract because previously these were counted as used + * think of it as first free'ing the inodes and the inode btree + * and then chopping all the other blocks from the fdblocks + */ + inofree += metaused; + } + /* + * There are new blocks in the old last a.g. + */ + if (new) { + printk("Shrinking last a.g. with %d blocks\n", new); + memset(&allocarg, 0, sizeof(allocarg)); + error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agf = XFS_BUF_TO_AGF(bp); + allocarg.tp = tp; + allocarg.mp = mp; + allocarg.agbp = bp; + allocarg.agno = agno; + allocarg.agbno = INT_GET(agf->agf_length, ARCH_CONVERT) + new; + allocarg.fsbno = XFS_AGB_TO_FSB(mp, agno, allocarg.agbno); + allocarg.minlen = -new; + allocarg.maxlen = -new; + allocarg.prod = -new; + allocarg.mod = 0; + allocarg.minleft = 0; + allocarg.total = -new; + allocarg.type = XFS_ALLOCTYPE_THIS_BNO; + allocarg.alignment = 1; + printk("agf_free before=%d\n", INT_GET(agf->agf_freeblks, ARCH_CONVERT)); + error = xfs_alloc_vextent(&allocarg); + if (error) { + printk("error in alloc extent\n"); + goto error0; + } + if(allocarg.agbno == NULLAGBLOCK) { + error = XFS_ERROR(ENOSPC); + goto error0; + } + printk("agf_free after=%d\n", INT_GET(agf->agf_freeblks, ARCH_CONVERT)); + //nfree += new; /* + because new is already negative */ + /* + * Change the agi length. + */ + error = xfs_ialloc_read_agi(mp, tp, agno, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agi = XFS_BUF_TO_AGI(bp); + INT_MOD(agi->agi_length, ARCH_CONVERT, new); + printk("agno=%d agi_length=%ld\n", agno, INT_GET(agi->agi_length, ARCH_CONVERT)); + + xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); + /* + * Change agf length. + */ + INT_MOD(agf->agf_length, ARCH_CONVERT, new); + printk("agno=%d agf_length=%ld\n", agno, INT_GET(agf->agf_length, ARCH_CONVERT)); + ASSERT(INT_GET(agf->agf_length, ARCH_CONVERT) == + INT_GET(agi->agi_length, ARCH_CONVERT)); + } + printk("nfree value: %d, oagcount=%d, nagcount=%d\n", nfree, oagcount, nagcount); + xfs_trans_agblocks_delta(tp, nfree); + xfs_trans_agblocks_delta(tp, inofree); + + if (nagcount < oagcount) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); + if (nb < mp->m_sb.sb_dblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, + nb - mp->m_sb.sb_dblocks); + if (nfree) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree); + if (inofree) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, inofree); + if (icount) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, icount); + if (ifree) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, ifree); + if (dpct) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); + error = xfs_trans_commit(tp, 0, NULL); + if (error) { + return error; + } + /* Free memory if the number of a.g. has changed */ + if (nagcount < oagcount) { + down_write(&mp->m_peraglock); + for (agno = nagcount; agno < oagcount; agno++) + if (mp->m_perag[agno].pagb_list) + kmem_free(mp->m_perag[agno].pagb_list, + sizeof(xfs_perag_busy_t) * + XFS_PAGB_NUM_SLOTS); + + mp->m_perag = kmem_realloc(mp->m_perag, + sizeof(xfs_perag_t) * nagcount, + sizeof(xfs_perag_t) * oagcount, + KM_SLEEP); + /* FIXME: here we could instead just lower + * nagimax to nagcount; is it better this way? + */ + mp->m_flags |= XFS_MOUNT_32BITINODES; + nagimax = xfs_initialize_perag(mp, nagcount); + up_write(&mp->m_peraglock); + } + + /* New allocation groups fully initialized, so update mount struct */ + if (nagimax) + mp->m_maxagi = nagimax; + if (mp->m_sb.sb_imax_pct) { + __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; + do_div(icount, 100); + mp->m_maxicount = icount << mp->m_sb.sb_inopblog; + } else + mp->m_maxicount = 0; + for (agno = 1; agno < nagcount; agno++) { + error = xfs_read_buf(mp, mp->m_ddev_targp, + XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), + XFS_FSS_TO_BB(mp, 1), 0, &bp); + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, + "error %d reading secondary superblock for ag %d", + error, agno); + break; + } + sbp = XFS_BUF_TO_SBP(bp); + xfs_xlatesb(sbp, &mp->m_sb, -1, XFS_SB_ALL_BITS); + /* + * If we get an error writing out the alternate superblocks, + * just issue a warning and continue. The real work is + * already done and committed. + */ + if (!(error = xfs_bwrite(mp, bp))) { + continue; + } else { + xfs_fs_cmn_err(CE_WARN, mp, + "write error %d updating secondary superblock for ag %d", + error, agno); + break; /* no point in continuing */ + } + } + return 0; + + error0: + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return error; +} + + +static int xfs_growfs_log_private( xfs_mount_t *mp, /* mount point for filesystem */ xfs_growfs_log_t *in) /* growfs log input struct */ diff -urN -x xfs_ialloc_btree.h.orig -x xfs_trans.c.orig -x Entries.Log -x Entries linux-2.6-xfs.orig/fs/xfs/xfs_ialloc_btree.c linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.c --- linux-2.6-xfs.orig/fs/xfs/xfs_ialloc_btree.c 2005-01-13 00:38:29.000000000 +0200 +++ linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.c 2005-09-06 02:01:39.029406448 +0300 @@ -1672,6 +1672,95 @@ */ /* + * Compute the size (in blocks) of the btree in the given level/block number + */ +int /* error */ +xfs_inobtsize( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* current level */ + xfs_agblock_t agbno, /* a.g. relative btree block number */ + int *btsize,/* pointer to btree size, to be incremented */ + int *inosize) /* pointer to inode blocks, to be incremented */ +{ + xfs_agnumber_t agno; + xfs_alloc_block_t *block=NULL; /* current btree block */ + int error; /* error return value */ + int ptrno; /* current key number */ + xfs_daddr_t d; /* disk address of btree block */ + xfs_buf_t *bp; /* buffer pointer for btree block */ + + { + xfs_agi_t *agi; /* a.g. inode header */ + + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + } + + + d = XFS_AGB_TO_DADDR(cur->bc_mp, agno, agbno); + printk("inobtsize agno=%d agbno=%d diskaddr=%lld level=%d bt=%d ino=%d\n", agno, agbno, d, level, *btsize, *inosize); + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, agno, + agbno, 0, &bp, XFS_INO_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_INOBT_BLOCK(bp); + + if(level == 0) { + printk("numrecs=%d\n", INT_GET(block->bb_numrecs, ARCH_CONVERT)); + for( ptrno = 0; ptrno < INT_GET(block->bb_numrecs, ARCH_CONVERT); ptrno++) { + xfs_inobt_rec_t *rec; + xfs_agino_t istart, istop; + xfs_agblock_t bstart, bstop; + + rec = XFS_INOBT_REC_ADDR(block, ptrno + 1, cur); + istart = INT_GET(rec->ir_startino, ARCH_CONVERT); + istop = istart + XFS_INODES_PER_CHUNK - 1; + bstart = XFS_AGINO_TO_AGBNO(cur->bc_mp, istart); + bstop = XFS_AGINO_TO_AGBNO(cur->bc_mp, istop); + printk("level0, recno %d, start inode %d, stop inode %d, start block %d, stop block %d, used blocks %d\n", + ptrno, istart, istop, bstart, bstop, bstop - bstart + 1); + (*inosize) += bstop - bstart + 1; + } + (*btsize)++; + return 0; + } + + /* + * Iterate over each child in this non-leaf block + */ + for (ptrno = 0; ptrno < INT_GET(block->bb_numrecs, ARCH_CONVERT); ptrno++) { + xfs_inobt_ptr_t *ptr; + xfs_agblock_t newbno; + + ptr = XFS_INOBT_PTR_ADDR(block, ptrno + 1, cur); + newbno = INT_GET(*ptr, ARCH_CONVERT); + printk("\twill enter ptrno=%d (of %d) agbno=%d\n", ptrno, INT_GET(block->bb_numrecs, ARCH_CONVERT), newbno); + + if((error = xfs_inobtsize(cur, level - 1, newbno, btsize, inosize))) + return error; + + } + (*btsize)++; + return 0; +} + +/* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ diff -urN -x xfs_ialloc_btree.h.orig -x xfs_trans.c.orig -x Entries.Log -x Entries linux-2.6-xfs.orig/fs/xfs/xfs_ialloc_btree.h linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.h --- linux-2.6-xfs.orig/fs/xfs/xfs_ialloc_btree.h 2005-06-07 17:39:14.000000000 +0300 +++ linux-2.6-xfs/fs/xfs/xfs_ialloc_btree.h 2005-09-06 02:01:39.040404776 +0300 @@ -219,6 +219,17 @@ */ /* + * Compute the size (in blocks) of the btree in the given level/block number + */ +int /* error */ +xfs_inobtsize( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, + xfs_agblock_t agbno, /* a.g. relative btree block number */ + int *btsize,/* pointer to btree size, to be incremented */ + int *inosize); /* pointer to inode blocks, to be incremented */ + +/* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ diff -urN -x xfs_ialloc_btree.h.orig -x xfs_trans.c.orig -x Entries.Log -x Entries linux-2.6-xfs.orig/fs/xfs/xfs_trans.c linux-2.6-xfs/fs/xfs/xfs_trans.c --- linux-2.6-xfs.orig/fs/xfs/xfs_trans.c 2005-07-13 06:43:58.000000000 +0300 +++ linux-2.6-xfs/fs/xfs/xfs_trans.c 2005-09-06 02:01:39.041404624 +0300 @@ -396,11 +396,9 @@ tp->t_res_frextents_delta += delta; break; case XFS_TRANS_SB_DBLOCKS: - ASSERT(delta > 0); tp->t_dblocks_delta += delta; break; case XFS_TRANS_SB_AGCOUNT: - ASSERT(delta > 0); tp->t_agcount_delta += delta; break; case XFS_TRANS_SB_IMAXPCT: