diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:57:51 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:57:51 -0400 |
commit | d4b3a4b7dd62f2e111d4d0afa9ef3f9b6cd955c0 (patch) | |
tree | cd0b5a46d81fa9d9b0253c489f64ad698e3a0fa9 /fs | |
parent | 4b22a57188d87e873346b73c227607715be96399 (diff) |
[XFS] move xfs_bmbt_killroot to common code
xfs_bmbt_killroot is a mostly generic implementation of moving from a real
block based root to an inode based root. So move it to xfs_btree.c where
it can use all the nice infrastructure there and make it pointer size
agnostic
The new name for it is xfs_btree_kill_iroot, following the old naming but
making it clear we're dealing with the root in inode case here, and to
avoid confusion with xfs_btree_new_root which is used for the not inode
rooted case. I've also added a comment describing what it does and why
it's named the way it is.
SGI-PV: 985583
SGI-Modid: xfs-linux-melb:xfs-kern:32203a
Signed-off-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: Bill O'Donnell <billodo@sgi.com>
Signed-off-by: David Chinner <david@fromorbit.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 32 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 116 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.c | 112 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 17 |
5 files changed, 185 insertions, 94 deletions
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index 818adca77fc6..f124ddd91c08 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
@@ -834,6 +834,37 @@ xfs_allocbt_alloc_block( | |||
834 | return 0; | 834 | return 0; |
835 | } | 835 | } |
836 | 836 | ||
837 | STATIC int | ||
838 | xfs_allocbt_free_block( | ||
839 | struct xfs_btree_cur *cur, | ||
840 | struct xfs_buf *bp) | ||
841 | { | ||
842 | struct xfs_buf *agbp = cur->bc_private.a.agbp; | ||
843 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); | ||
844 | xfs_agblock_t bno; | ||
845 | int error; | ||
846 | |||
847 | bno = XFS_DADDR_TO_AGBNO(cur->bc_mp, XFS_BUF_ADDR(bp)); | ||
848 | error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); | ||
849 | if (error) | ||
850 | return error; | ||
851 | |||
852 | /* | ||
853 | * Since blocks move to the free list without the coordination used in | ||
854 | * xfs_bmap_finish, we can't allow block to be available for | ||
855 | * reallocation and non-transaction writing (user data) until we know | ||
856 | * that the transaction that moved it to the free list is permanently | ||
857 | * on disk. We track the blocks by declaring these blocks as "busy"; | ||
858 | * the busy list is maintained on a per-ag basis and each transaction | ||
859 | * records which entries should be removed when the iclog commits to | ||
860 | * disk. If a busy block is allocated, the iclog is pushed up to the | ||
861 | * LSN that freed the block. | ||
862 | */ | ||
863 | xfs_alloc_mark_busy(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1); | ||
864 | xfs_trans_agbtree_delta(cur->bc_tp, -1); | ||
865 | return 0; | ||
866 | } | ||
867 | |||
837 | /* | 868 | /* |
838 | * Update the longest extent in the AGF | 869 | * Update the longest extent in the AGF |
839 | */ | 870 | */ |
@@ -1025,6 +1056,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = { | |||
1025 | .dup_cursor = xfs_allocbt_dup_cursor, | 1056 | .dup_cursor = xfs_allocbt_dup_cursor, |
1026 | .set_root = xfs_allocbt_set_root, | 1057 | .set_root = xfs_allocbt_set_root, |
1027 | .alloc_block = xfs_allocbt_alloc_block, | 1058 | .alloc_block = xfs_allocbt_alloc_block, |
1059 | .free_block = xfs_allocbt_free_block, | ||
1028 | .update_lastrec = xfs_allocbt_update_lastrec, | 1060 | .update_lastrec = xfs_allocbt_update_lastrec, |
1029 | .get_maxrecs = xfs_allocbt_get_maxrecs, | 1061 | .get_maxrecs = xfs_allocbt_get_maxrecs, |
1030 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, | 1062 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 2b15df32b7d2..6b7774ebc26a 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -49,7 +49,6 @@ | |||
49 | */ | 49 | */ |
50 | 50 | ||
51 | 51 | ||
52 | STATIC int xfs_bmbt_killroot(xfs_btree_cur_t *); | ||
53 | STATIC void xfs_bmbt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); | 52 | STATIC void xfs_bmbt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
54 | STATIC void xfs_bmbt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); | 53 | STATIC void xfs_bmbt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
55 | 54 | ||
@@ -194,7 +193,7 @@ xfs_bmbt_delrec( | |||
194 | if (level == cur->bc_nlevels - 1) { | 193 | if (level == cur->bc_nlevels - 1) { |
195 | xfs_iroot_realloc(cur->bc_private.b.ip, -1, | 194 | xfs_iroot_realloc(cur->bc_private.b.ip, -1, |
196 | cur->bc_private.b.whichfork); | 195 | cur->bc_private.b.whichfork); |
197 | if ((error = xfs_bmbt_killroot(cur))) { | 196 | if ((error = xfs_btree_kill_iroot(cur))) { |
198 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 197 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
199 | goto error0; | 198 | goto error0; |
200 | } | 199 | } |
@@ -228,7 +227,7 @@ xfs_bmbt_delrec( | |||
228 | */ | 227 | */ |
229 | if (lbno == NULLFSBLOCK && rbno == NULLFSBLOCK && | 228 | if (lbno == NULLFSBLOCK && rbno == NULLFSBLOCK && |
230 | level == cur->bc_nlevels - 2) { | 229 | level == cur->bc_nlevels - 2) { |
231 | if ((error = xfs_bmbt_killroot(cur))) { | 230 | if ((error = xfs_btree_kill_iroot(cur))) { |
232 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 231 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
233 | goto error0; | 232 | goto error0; |
234 | } | 233 | } |
@@ -456,97 +455,6 @@ error0: | |||
456 | return error; | 455 | return error; |
457 | } | 456 | } |
458 | 457 | ||
459 | STATIC int | ||
460 | xfs_bmbt_killroot( | ||
461 | xfs_btree_cur_t *cur) | ||
462 | { | ||
463 | xfs_bmbt_block_t *block; | ||
464 | xfs_bmbt_block_t *cblock; | ||
465 | xfs_buf_t *cbp; | ||
466 | xfs_bmbt_key_t *ckp; | ||
467 | xfs_bmbt_ptr_t *cpp; | ||
468 | #ifdef DEBUG | ||
469 | int error; | ||
470 | #endif | ||
471 | int i; | ||
472 | xfs_bmbt_key_t *kp; | ||
473 | xfs_inode_t *ip; | ||
474 | xfs_ifork_t *ifp; | ||
475 | int level; | ||
476 | xfs_bmbt_ptr_t *pp; | ||
477 | |||
478 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | ||
479 | level = cur->bc_nlevels - 1; | ||
480 | ASSERT(level >= 1); | ||
481 | /* | ||
482 | * Don't deal with the root block needs to be a leaf case. | ||
483 | * We're just going to turn the thing back into extents anyway. | ||
484 | */ | ||
485 | if (level == 1) { | ||
486 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
487 | return 0; | ||
488 | } | ||
489 | block = xfs_bmbt_get_block(cur, level, &cbp); | ||
490 | /* | ||
491 | * Give up if the root has multiple children. | ||
492 | */ | ||
493 | if (be16_to_cpu(block->bb_numrecs) != 1) { | ||
494 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
495 | return 0; | ||
496 | } | ||
497 | /* | ||
498 | * Only do this if the next level will fit. | ||
499 | * Then the data must be copied up to the inode, | ||
500 | * instead of freeing the root you free the next level. | ||
501 | */ | ||
502 | cbp = cur->bc_bufs[level - 1]; | ||
503 | cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); | ||
504 | if (be16_to_cpu(cblock->bb_numrecs) > XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { | ||
505 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
506 | return 0; | ||
507 | } | ||
508 | ASSERT(be64_to_cpu(cblock->bb_leftsib) == NULLDFSBNO); | ||
509 | ASSERT(be64_to_cpu(cblock->bb_rightsib) == NULLDFSBNO); | ||
510 | ip = cur->bc_private.b.ip; | ||
511 | ifp = XFS_IFORK_PTR(ip, cur->bc_private.b.whichfork); | ||
512 | ASSERT(XFS_BMAP_BLOCK_IMAXRECS(level, cur) == | ||
513 | XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes)); | ||
514 | i = (int)(be16_to_cpu(cblock->bb_numrecs) - XFS_BMAP_BLOCK_IMAXRECS(level, cur)); | ||
515 | if (i) { | ||
516 | xfs_iroot_realloc(ip, i, cur->bc_private.b.whichfork); | ||
517 | block = ifp->if_broot; | ||
518 | } | ||
519 | be16_add_cpu(&block->bb_numrecs, i); | ||
520 | ASSERT(block->bb_numrecs == cblock->bb_numrecs); | ||
521 | kp = XFS_BMAP_KEY_IADDR(block, 1, cur); | ||
522 | ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); | ||
523 | memcpy(kp, ckp, be16_to_cpu(block->bb_numrecs) * sizeof(*kp)); | ||
524 | pp = XFS_BMAP_PTR_IADDR(block, 1, cur); | ||
525 | cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); | ||
526 | #ifdef DEBUG | ||
527 | for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) { | ||
528 | if ((error = xfs_btree_check_lptr_disk(cur, cpp[i], level - 1))) { | ||
529 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
530 | return error; | ||
531 | } | ||
532 | } | ||
533 | #endif | ||
534 | memcpy(pp, cpp, be16_to_cpu(block->bb_numrecs) * sizeof(*pp)); | ||
535 | xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1, | ||
536 | cur->bc_private.b.flist, cur->bc_mp); | ||
537 | ip->i_d.di_nblocks--; | ||
538 | XFS_TRANS_MOD_DQUOT_BYINO(cur->bc_mp, cur->bc_tp, ip, | ||
539 | XFS_TRANS_DQ_BCOUNT, -1L); | ||
540 | xfs_trans_binval(cur->bc_tp, cbp); | ||
541 | cur->bc_bufs[level - 1] = NULL; | ||
542 | be16_add_cpu(&block->bb_level, -1); | ||
543 | xfs_trans_log_inode(cur->bc_tp, ip, | ||
544 | XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); | ||
545 | cur->bc_nlevels--; | ||
546 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | /* | 458 | /* |
551 | * Log key values from the btree block. | 459 | * Log key values from the btree block. |
552 | */ | 460 | */ |
@@ -1299,6 +1207,25 @@ xfs_bmbt_alloc_block( | |||
1299 | } | 1207 | } |
1300 | 1208 | ||
1301 | STATIC int | 1209 | STATIC int |
1210 | xfs_bmbt_free_block( | ||
1211 | struct xfs_btree_cur *cur, | ||
1212 | struct xfs_buf *bp) | ||
1213 | { | ||
1214 | struct xfs_mount *mp = cur->bc_mp; | ||
1215 | struct xfs_inode *ip = cur->bc_private.b.ip; | ||
1216 | struct xfs_trans *tp = cur->bc_tp; | ||
1217 | xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); | ||
1218 | |||
1219 | xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp); | ||
1220 | ip->i_d.di_nblocks--; | ||
1221 | |||
1222 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
1223 | XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); | ||
1224 | xfs_trans_binval(tp, bp); | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | STATIC int | ||
1302 | xfs_bmbt_get_maxrecs( | 1229 | xfs_bmbt_get_maxrecs( |
1303 | struct xfs_btree_cur *cur, | 1230 | struct xfs_btree_cur *cur, |
1304 | int level) | 1231 | int level) |
@@ -1460,6 +1387,7 @@ static const struct xfs_btree_ops xfs_bmbt_ops = { | |||
1460 | .dup_cursor = xfs_bmbt_dup_cursor, | 1387 | .dup_cursor = xfs_bmbt_dup_cursor, |
1461 | .update_cursor = xfs_bmbt_update_cursor, | 1388 | .update_cursor = xfs_bmbt_update_cursor, |
1462 | .alloc_block = xfs_bmbt_alloc_block, | 1389 | .alloc_block = xfs_bmbt_alloc_block, |
1390 | .free_block = xfs_bmbt_free_block, | ||
1463 | .get_maxrecs = xfs_bmbt_get_maxrecs, | 1391 | .get_maxrecs = xfs_bmbt_get_maxrecs, |
1464 | .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, | 1392 | .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, |
1465 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, | 1393 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 36477aae77df..75a8a7b00dfb 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -3059,3 +3059,115 @@ error0: | |||
3059 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | 3059 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); |
3060 | return error; | 3060 | return error; |
3061 | } | 3061 | } |
3062 | |||
3063 | /* | ||
3064 | * Try to merge a non-leaf block back into the inode root. | ||
3065 | * | ||
3066 | * Note: the killroot names comes from the fact that we're effectively | ||
3067 | * killing the old root block. But because we can't just delete the | ||
3068 | * inode we have to copy the single block it was pointing to into the | ||
3069 | * inode. | ||
3070 | */ | ||
3071 | int | ||
3072 | xfs_btree_kill_iroot( | ||
3073 | struct xfs_btree_cur *cur) | ||
3074 | { | ||
3075 | int whichfork = cur->bc_private.b.whichfork; | ||
3076 | struct xfs_inode *ip = cur->bc_private.b.ip; | ||
3077 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); | ||
3078 | struct xfs_btree_block *block; | ||
3079 | struct xfs_btree_block *cblock; | ||
3080 | union xfs_btree_key *kp; | ||
3081 | union xfs_btree_key *ckp; | ||
3082 | union xfs_btree_ptr *pp; | ||
3083 | union xfs_btree_ptr *cpp; | ||
3084 | struct xfs_buf *cbp; | ||
3085 | int level; | ||
3086 | int index; | ||
3087 | int numrecs; | ||
3088 | #ifdef DEBUG | ||
3089 | union xfs_btree_ptr ptr; | ||
3090 | int i; | ||
3091 | #endif | ||
3092 | |||
3093 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
3094 | |||
3095 | ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); | ||
3096 | ASSERT(cur->bc_nlevels > 1); | ||
3097 | |||
3098 | /* | ||
3099 | * Don't deal with the root block needs to be a leaf case. | ||
3100 | * We're just going to turn the thing back into extents anyway. | ||
3101 | */ | ||
3102 | level = cur->bc_nlevels - 1; | ||
3103 | if (level == 1) | ||
3104 | goto out0; | ||
3105 | |||
3106 | /* | ||
3107 | * Give up if the root has multiple children. | ||
3108 | */ | ||
3109 | block = xfs_btree_get_iroot(cur); | ||
3110 | if (xfs_btree_get_numrecs(block) != 1) | ||
3111 | goto out0; | ||
3112 | |||
3113 | cblock = xfs_btree_get_block(cur, level - 1, &cbp); | ||
3114 | numrecs = xfs_btree_get_numrecs(cblock); | ||
3115 | |||
3116 | /* | ||
3117 | * Only do this if the next level will fit. | ||
3118 | * Then the data must be copied up to the inode, | ||
3119 | * instead of freeing the root you free the next level. | ||
3120 | */ | ||
3121 | if (numrecs > cur->bc_ops->get_dmaxrecs(cur, level)) | ||
3122 | goto out0; | ||
3123 | |||
3124 | XFS_BTREE_STATS_INC(cur, killroot); | ||
3125 | |||
3126 | #ifdef DEBUG | ||
3127 | xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); | ||
3128 | ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); | ||
3129 | xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); | ||
3130 | ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); | ||
3131 | #endif | ||
3132 | |||
3133 | index = numrecs - cur->bc_ops->get_maxrecs(cur, level); | ||
3134 | if (index) { | ||
3135 | xfs_iroot_realloc(cur->bc_private.b.ip, index, | ||
3136 | cur->bc_private.b.whichfork); | ||
3137 | block = (struct xfs_btree_block *)ifp->if_broot; | ||
3138 | } | ||
3139 | |||
3140 | be16_add_cpu(&block->bb_numrecs, index); | ||
3141 | ASSERT(block->bb_numrecs == cblock->bb_numrecs); | ||
3142 | |||
3143 | kp = xfs_btree_key_addr(cur, 1, block); | ||
3144 | ckp = xfs_btree_key_addr(cur, 1, cblock); | ||
3145 | xfs_btree_copy_keys(cur, kp, ckp, numrecs); | ||
3146 | |||
3147 | pp = xfs_btree_ptr_addr(cur, 1, block); | ||
3148 | cpp = xfs_btree_ptr_addr(cur, 1, cblock); | ||
3149 | #ifdef DEBUG | ||
3150 | for (i = 0; i < numrecs; i++) { | ||
3151 | int error; | ||
3152 | |||
3153 | error = xfs_btree_check_ptr(cur, cpp, i, level - 1); | ||
3154 | if (error) { | ||
3155 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
3156 | return error; | ||
3157 | } | ||
3158 | } | ||
3159 | #endif | ||
3160 | xfs_btree_copy_ptrs(cur, pp, cpp, numrecs); | ||
3161 | |||
3162 | cur->bc_ops->free_block(cur, cbp); | ||
3163 | XFS_BTREE_STATS_INC(cur, free); | ||
3164 | |||
3165 | cur->bc_bufs[level - 1] = NULL; | ||
3166 | be16_add_cpu(&block->bb_level, -1); | ||
3167 | xfs_trans_log_inode(cur->bc_tp, ip, | ||
3168 | XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); | ||
3169 | cur->bc_nlevels--; | ||
3170 | out0: | ||
3171 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
3172 | return 0; | ||
3173 | } | ||
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 6f03871f5995..ff2552febba7 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
@@ -198,6 +198,7 @@ struct xfs_btree_ops { | |||
198 | union xfs_btree_ptr *start_bno, | 198 | union xfs_btree_ptr *start_bno, |
199 | union xfs_btree_ptr *new_bno, | 199 | union xfs_btree_ptr *new_bno, |
200 | int length, int *stat); | 200 | int length, int *stat); |
201 | int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); | ||
201 | 202 | ||
202 | /* update last record information */ | 203 | /* update last record information */ |
203 | void (*update_lastrec)(struct xfs_btree_cur *cur, | 204 | void (*update_lastrec)(struct xfs_btree_cur *cur, |
@@ -559,6 +560,7 @@ int xfs_btree_split(struct xfs_btree_cur *, int, union xfs_btree_ptr *, | |||
559 | union xfs_btree_key *, struct xfs_btree_cur **, int *); | 560 | union xfs_btree_key *, struct xfs_btree_cur **, int *); |
560 | int xfs_btree_new_root(struct xfs_btree_cur *, int *); | 561 | int xfs_btree_new_root(struct xfs_btree_cur *, int *); |
561 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); | 562 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); |
563 | int xfs_btree_kill_iroot(struct xfs_btree_cur *); | ||
562 | int xfs_btree_insert(struct xfs_btree_cur *, int *); | 564 | int xfs_btree_insert(struct xfs_btree_cur *, int *); |
563 | 565 | ||
564 | /* | 566 | /* |
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 8f66e2720566..90f1d4ee7720 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
@@ -754,6 +754,22 @@ xfs_inobt_alloc_block( | |||
754 | return 0; | 754 | return 0; |
755 | } | 755 | } |
756 | 756 | ||
757 | STATIC int | ||
758 | xfs_inobt_free_block( | ||
759 | struct xfs_btree_cur *cur, | ||
760 | struct xfs_buf *bp) | ||
761 | { | ||
762 | xfs_fsblock_t fsbno; | ||
763 | int error; | ||
764 | |||
765 | fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)); | ||
766 | error = xfs_free_extent(cur->bc_tp, fsbno, 1); | ||
767 | if (error) | ||
768 | return error; | ||
769 | |||
770 | xfs_trans_binval(cur->bc_tp, bp); | ||
771 | return error; | ||
772 | } | ||
757 | 773 | ||
758 | STATIC int | 774 | STATIC int |
759 | xfs_inobt_get_maxrecs( | 775 | xfs_inobt_get_maxrecs( |
@@ -886,6 +902,7 @@ static const struct xfs_btree_ops xfs_inobt_ops = { | |||
886 | .dup_cursor = xfs_inobt_dup_cursor, | 902 | .dup_cursor = xfs_inobt_dup_cursor, |
887 | .set_root = xfs_inobt_set_root, | 903 | .set_root = xfs_inobt_set_root, |
888 | .alloc_block = xfs_inobt_alloc_block, | 904 | .alloc_block = xfs_inobt_alloc_block, |
905 | .free_block = xfs_inobt_free_block, | ||
889 | .get_maxrecs = xfs_inobt_get_maxrecs, | 906 | .get_maxrecs = xfs_inobt_get_maxrecs, |
890 | .init_key_from_rec = xfs_inobt_init_key_from_rec, | 907 | .init_key_from_rec = xfs_inobt_init_key_from_rec, |
891 | .init_rec_from_key = xfs_inobt_init_rec_from_key, | 908 | .init_rec_from_key = xfs_inobt_init_rec_from_key, |