blob: e7539263457fb429122a32d65398b5aa7184e431 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Nathan Scott7b718762005-11-02 14:58:39 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * published by the Free Software Foundation.
8 *
Nathan Scott7b718762005-11-02 14:58:39 +11009 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Nathan Scott7b718762005-11-02 14:58:39 +110014 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110019#include "xfs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "xfs_types.h"
Nathan Scotta844f452005-11-02 14:38:42 +110021#include "xfs_bit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "xfs_log.h"
Nathan Scotta844f452005-11-02 14:38:42 +110023#include "xfs_inum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include "xfs_trans.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include "xfs_dir2.h"
28#include "xfs_dmapi.h"
29#include "xfs_mount.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include "xfs_bmap_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110031#include "xfs_alloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_ialloc_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110033#include "xfs_dir2_sf.h"
34#include "xfs_attr_sf.h"
35#include "xfs_dinode.h"
36#include "xfs_inode.h"
37#include "xfs_inode_item.h"
38#include "xfs_alloc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "xfs_btree.h"
Christoph Hellwig8c4ed632008-10-30 16:55:13 +110040#include "xfs_btree_trace.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "xfs_ialloc.h"
42#include "xfs_itable.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include "xfs_bmap.h"
44#include "xfs_error.h"
45#include "xfs_quota.h"
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047/*
48 * Prototypes for internal btree functions.
49 */
50
51
52STATIC int xfs_bmbt_killroot(xfs_btree_cur_t *);
53STATIC void xfs_bmbt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int);
54STATIC void xfs_bmbt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#undef EXIT
Christoph Hellwig8c4ed632008-10-30 16:55:13 +110057
58#define ENTRY XBT_ENTRY
59#define ERROR XBT_ERROR
60#define EXIT XBT_EXIT
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62/*
Christoph Hellwig8c4ed632008-10-30 16:55:13 +110063 * Keep the XFS_BMBT_TRACE_ names around for now until all code using them
64 * is converted to be generic and thus switches to the XFS_BTREE_TRACE_ names.
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 */
Christoph Hellwig8c4ed632008-10-30 16:55:13 +110066#define XFS_BMBT_TRACE_ARGBI(c,b,i) \
67 XFS_BTREE_TRACE_ARGBI(c,b,i)
68#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) \
69 XFS_BTREE_TRACE_ARGBII(c,b,i,j)
70#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) \
71 XFS_BTREE_TRACE_ARGFFFI(c,o,b,i,j)
72#define XFS_BMBT_TRACE_ARGI(c,i) \
73 XFS_BTREE_TRACE_ARGI(c,i)
74#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s) \
75 XFS_BTREE_TRACE_ARGIPK(c,i,(union xfs_btree_ptr)f,s)
76#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \
77 XFS_BTREE_TRACE_ARGIPR(c,i, \
78 (union xfs_btree_ptr)f, (union xfs_btree_rec *)r)
79#define XFS_BMBT_TRACE_ARGIK(c,i,k) \
80 XFS_BTREE_TRACE_ARGIK(c,i,(union xfs_btree_key *)k)
81#define XFS_BMBT_TRACE_CURSOR(c,s) \
82 XFS_BTREE_TRACE_CURSOR(c,s)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84
85/*
86 * Internal functions.
87 */
88
89/*
90 * Delete record pointed to by cur/level.
91 */
92STATIC int /* error */
93xfs_bmbt_delrec(
94 xfs_btree_cur_t *cur,
95 int level,
96 int *stat) /* success/failure */
97{
98 xfs_bmbt_block_t *block; /* bmap btree block */
99 xfs_fsblock_t bno; /* fs-relative block number */
100 xfs_buf_t *bp; /* buffer for block */
101 int error; /* error return value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 int i; /* loop counter */
103 int j; /* temp state */
104 xfs_bmbt_key_t key; /* bmap btree key */
105 xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */
106 xfs_fsblock_t lbno; /* left sibling block number */
107 xfs_buf_t *lbp; /* left buffer pointer */
108 xfs_bmbt_block_t *left; /* left btree block */
109 xfs_bmbt_key_t *lkp; /* left btree key */
110 xfs_bmbt_ptr_t *lpp; /* left address pointer */
111 int lrecs=0; /* left record count */
112 xfs_bmbt_rec_t *lrp; /* left record pointer */
113 xfs_mount_t *mp; /* file system mount point */
114 xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */
115 int ptr; /* key/record index */
116 xfs_fsblock_t rbno; /* right sibling block number */
117 xfs_buf_t *rbp; /* right buffer pointer */
118 xfs_bmbt_block_t *right; /* right btree block */
119 xfs_bmbt_key_t *rkp; /* right btree key */
120 xfs_bmbt_rec_t *rp; /* pointer to bmap btree rec */
121 xfs_bmbt_ptr_t *rpp; /* right address pointer */
122 xfs_bmbt_block_t *rrblock; /* right-right btree block */
123 xfs_buf_t *rrbp; /* right-right buffer pointer */
124 int rrecs=0; /* right record count */
125 xfs_bmbt_rec_t *rrp; /* right record pointer */
126 xfs_btree_cur_t *tcur; /* temporary btree cursor */
127 int numrecs; /* temporary numrec count */
128 int numlrecs, numrrecs;
129
130 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
131 XFS_BMBT_TRACE_ARGI(cur, level);
132 ptr = cur->bc_ptrs[level];
Nathan Scott1121b212006-09-28 10:58:40 +1000133 tcur = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 if (ptr == 0) {
135 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
136 *stat = 0;
137 return 0;
138 }
139 block = xfs_bmbt_get_block(cur, level, &bp);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100140 numrecs = be16_to_cpu(block->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141#ifdef DEBUG
142 if ((error = xfs_btree_check_lblock(cur, block, level, bp))) {
143 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
144 goto error0;
145 }
146#endif
147 if (ptr > numrecs) {
148 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
149 *stat = 0;
150 return 0;
151 }
152 XFS_STATS_INC(xs_bmbt_delrec);
153 if (level > 0) {
154 kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
155 pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
156#ifdef DEBUG
157 for (i = ptr; i < numrecs; i++) {
Christoph Hellwigb113bcb2006-09-28 10:57:42 +1000158 if ((error = xfs_btree_check_lptr_disk(cur, pp[i], level))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
160 goto error0;
161 }
162 }
163#endif
164 if (ptr < numrecs) {
165 memmove(&kp[ptr - 1], &kp[ptr],
166 (numrecs - ptr) * sizeof(*kp));
Christoph Hellwigd580ef62007-08-16 16:23:11 +1000167 memmove(&pp[ptr - 1], &pp[ptr],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 (numrecs - ptr) * sizeof(*pp));
169 xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs - 1);
170 xfs_bmbt_log_keys(cur, bp, ptr, numrecs - 1);
171 }
172 } else {
173 rp = XFS_BMAP_REC_IADDR(block, 1, cur);
174 if (ptr < numrecs) {
175 memmove(&rp[ptr - 1], &rp[ptr],
176 (numrecs - ptr) * sizeof(*rp));
177 xfs_bmbt_log_recs(cur, bp, ptr, numrecs - 1);
178 }
179 if (ptr == 1) {
Christoph Hellwig8801bb92006-09-28 10:58:17 +1000180 key.br_startoff =
181 cpu_to_be64(xfs_bmbt_disk_get_startoff(rp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 kp = &key;
183 }
184 }
185 numrecs--;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100186 block->bb_numrecs = cpu_to_be16(numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS);
188 /*
189 * We're at the root level.
190 * First, shrink the root block in-memory.
191 * Try to get rid of the next level down.
192 * If we can't then there's nothing left to do.
193 */
194 if (level == cur->bc_nlevels - 1) {
195 xfs_iroot_realloc(cur->bc_private.b.ip, -1,
196 cur->bc_private.b.whichfork);
197 if ((error = xfs_bmbt_killroot(cur))) {
198 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
199 goto error0;
200 }
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100201 if (level > 0 && (error = xfs_btree_decrement(cur, level, &j))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
203 goto error0;
204 }
205 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
206 *stat = 1;
207 return 0;
208 }
Christoph Hellwig38bb7422008-10-30 16:56:22 +1100209 if (ptr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)kp, level + 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
211 goto error0;
212 }
213 if (numrecs >= XFS_BMAP_BLOCK_IMINRECS(level, cur)) {
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100214 if (level > 0 && (error = xfs_btree_decrement(cur, level, &j))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
216 goto error0;
217 }
218 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
219 *stat = 1;
220 return 0;
221 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100222 rbno = be64_to_cpu(block->bb_rightsib);
223 lbno = be64_to_cpu(block->bb_leftsib);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 /*
225 * One child of root, need to get a chance to copy its contents
226 * into the root and delete it. Can't go up to next level,
227 * there's nothing to delete there.
228 */
229 if (lbno == NULLFSBLOCK && rbno == NULLFSBLOCK &&
230 level == cur->bc_nlevels - 2) {
231 if ((error = xfs_bmbt_killroot(cur))) {
232 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
233 goto error0;
234 }
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100235 if (level > 0 && (error = xfs_btree_decrement(cur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
237 goto error0;
238 }
239 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
240 *stat = 1;
241 return 0;
242 }
243 ASSERT(rbno != NULLFSBLOCK || lbno != NULLFSBLOCK);
244 if ((error = xfs_btree_dup_cursor(cur, &tcur))) {
245 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
246 goto error0;
247 }
248 bno = NULLFSBLOCK;
249 if (rbno != NULLFSBLOCK) {
250 i = xfs_btree_lastrec(tcur, level);
251 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
Christoph Hellwig637aa502008-10-30 16:55:45 +1100252 if ((error = xfs_btree_increment(tcur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
254 goto error0;
255 }
256 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
257 i = xfs_btree_lastrec(tcur, level);
258 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
259 rbp = tcur->bc_bufs[level];
260 right = XFS_BUF_TO_BMBT_BLOCK(rbp);
261#ifdef DEBUG
262 if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) {
263 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
264 goto error0;
265 }
266#endif
Christoph Hellwig16259e72005-11-02 15:11:25 +1100267 bno = be64_to_cpu(right->bb_leftsib);
268 if (be16_to_cpu(right->bb_numrecs) - 1 >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 XFS_BMAP_BLOCK_IMINRECS(level, cur)) {
Christoph Hellwig687b8902008-10-30 16:56:53 +1100270 if ((error = xfs_btree_lshift(tcur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
272 goto error0;
273 }
274 if (i) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100275 ASSERT(be16_to_cpu(block->bb_numrecs) >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 XFS_BMAP_BLOCK_IMINRECS(level, tcur));
277 xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
278 tcur = NULL;
279 if (level > 0) {
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100280 if ((error = xfs_btree_decrement(cur,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 level, &i))) {
282 XFS_BMBT_TRACE_CURSOR(cur,
283 ERROR);
284 goto error0;
285 }
286 }
287 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
288 *stat = 1;
289 return 0;
290 }
291 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100292 rrecs = be16_to_cpu(right->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if (lbno != NULLFSBLOCK) {
294 i = xfs_btree_firstrec(tcur, level);
295 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100296 if ((error = xfs_btree_decrement(tcur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
298 goto error0;
299 }
300 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
301 }
302 }
303 if (lbno != NULLFSBLOCK) {
304 i = xfs_btree_firstrec(tcur, level);
305 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
306 /*
307 * decrement to last in block
308 */
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100309 if ((error = xfs_btree_decrement(tcur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
311 goto error0;
312 }
313 i = xfs_btree_firstrec(tcur, level);
314 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
315 lbp = tcur->bc_bufs[level];
316 left = XFS_BUF_TO_BMBT_BLOCK(lbp);
317#ifdef DEBUG
318 if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) {
319 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
320 goto error0;
321 }
322#endif
Christoph Hellwig16259e72005-11-02 15:11:25 +1100323 bno = be64_to_cpu(left->bb_rightsib);
324 if (be16_to_cpu(left->bb_numrecs) - 1 >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 XFS_BMAP_BLOCK_IMINRECS(level, cur)) {
Christoph Hellwig9eaead52008-10-30 16:56:43 +1100326 if ((error = xfs_btree_rshift(tcur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
328 goto error0;
329 }
330 if (i) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100331 ASSERT(be16_to_cpu(block->bb_numrecs) >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 XFS_BMAP_BLOCK_IMINRECS(level, tcur));
333 xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
334 tcur = NULL;
335 if (level == 0)
336 cur->bc_ptrs[0]++;
337 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
338 *stat = 1;
339 return 0;
340 }
341 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100342 lrecs = be16_to_cpu(left->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
344 xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
345 tcur = NULL;
346 mp = cur->bc_mp;
347 ASSERT(bno != NULLFSBLOCK);
348 if (lbno != NULLFSBLOCK &&
Christoph Hellwig16259e72005-11-02 15:11:25 +1100349 lrecs + be16_to_cpu(block->bb_numrecs) <= XFS_BMAP_BLOCK_IMAXRECS(level, cur)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 rbno = bno;
351 right = block;
352 rbp = bp;
353 if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, lbno, 0, &lbp,
354 XFS_BMAP_BTREE_REF))) {
355 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
356 goto error0;
357 }
358 left = XFS_BUF_TO_BMBT_BLOCK(lbp);
359 if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) {
360 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
361 goto error0;
362 }
363 } else if (rbno != NULLFSBLOCK &&
Christoph Hellwig16259e72005-11-02 15:11:25 +1100364 rrecs + be16_to_cpu(block->bb_numrecs) <=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 XFS_BMAP_BLOCK_IMAXRECS(level, cur)) {
366 lbno = bno;
367 left = block;
368 lbp = bp;
369 if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, rbno, 0, &rbp,
370 XFS_BMAP_BTREE_REF))) {
371 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
372 goto error0;
373 }
374 right = XFS_BUF_TO_BMBT_BLOCK(rbp);
375 if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) {
376 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
377 goto error0;
378 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100379 lrecs = be16_to_cpu(left->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 } else {
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100381 if (level > 0 && (error = xfs_btree_decrement(cur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
383 goto error0;
384 }
385 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
386 *stat = 1;
387 return 0;
388 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100389 numlrecs = be16_to_cpu(left->bb_numrecs);
390 numrrecs = be16_to_cpu(right->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (level > 0) {
392 lkp = XFS_BMAP_KEY_IADDR(left, numlrecs + 1, cur);
393 lpp = XFS_BMAP_PTR_IADDR(left, numlrecs + 1, cur);
394 rkp = XFS_BMAP_KEY_IADDR(right, 1, cur);
395 rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
396#ifdef DEBUG
397 for (i = 0; i < numrrecs; i++) {
Christoph Hellwigb113bcb2006-09-28 10:57:42 +1000398 if ((error = xfs_btree_check_lptr_disk(cur, rpp[i], level))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
400 goto error0;
401 }
402 }
403#endif
404 memcpy(lkp, rkp, numrrecs * sizeof(*lkp));
405 memcpy(lpp, rpp, numrrecs * sizeof(*lpp));
406 xfs_bmbt_log_keys(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
407 xfs_bmbt_log_ptrs(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
408 } else {
409 lrp = XFS_BMAP_REC_IADDR(left, numlrecs + 1, cur);
410 rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
411 memcpy(lrp, rrp, numrrecs * sizeof(*lrp));
412 xfs_bmbt_log_recs(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
413 }
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800414 be16_add_cpu(&left->bb_numrecs, numrrecs);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100415 left->bb_rightsib = right->bb_rightsib;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100417 if (be64_to_cpu(left->bb_rightsib) != NULLDFSBNO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if ((error = xfs_btree_read_bufl(mp, cur->bc_tp,
Christoph Hellwig16259e72005-11-02 15:11:25 +1100419 be64_to_cpu(left->bb_rightsib),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 0, &rrbp, XFS_BMAP_BTREE_REF))) {
421 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
422 goto error0;
423 }
424 rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp);
425 if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) {
426 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
427 goto error0;
428 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100429 rrblock->bb_leftsib = cpu_to_be64(lbno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB);
431 }
432 xfs_bmap_add_free(XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(rbp)), 1,
433 cur->bc_private.b.flist, mp);
434 cur->bc_private.b.ip->i_d.di_nblocks--;
435 xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
436 XFS_TRANS_MOD_DQUOT_BYINO(mp, cur->bc_tp, cur->bc_private.b.ip,
437 XFS_TRANS_DQ_BCOUNT, -1L);
438 xfs_trans_binval(cur->bc_tp, rbp);
439 if (bp != lbp) {
440 cur->bc_bufs[level] = lbp;
441 cur->bc_ptrs[level] += lrecs;
442 cur->bc_ra[level] = 0;
Christoph Hellwig637aa502008-10-30 16:55:45 +1100443 } else if ((error = xfs_btree_increment(cur, level + 1, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
445 goto error0;
446 }
447 if (level > 0)
448 cur->bc_ptrs[level]--;
449 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
450 *stat = 2;
451 return 0;
452
453error0:
454 if (tcur)
455 xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
456 return error;
457}
458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459/*
460 * Insert one record/level. Return information to the caller
461 * allowing the next level up to proceed if necessary.
462 */
463STATIC int /* error */
464xfs_bmbt_insrec(
465 xfs_btree_cur_t *cur,
466 int level,
467 xfs_fsblock_t *bnop,
468 xfs_bmbt_rec_t *recp,
469 xfs_btree_cur_t **curp,
470 int *stat) /* no-go/done/continue */
471{
472 xfs_bmbt_block_t *block; /* bmap btree block */
473 xfs_buf_t *bp; /* buffer for block */
474 int error; /* error return value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 int i; /* loop index */
476 xfs_bmbt_key_t key; /* bmap btree key */
477 xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */
478 int logflags; /* inode logging flags */
479 xfs_fsblock_t nbno; /* new block number */
480 struct xfs_btree_cur *ncur; /* new btree cursor */
Christoph Hellwig8801bb92006-09-28 10:58:17 +1000481 __uint64_t startoff; /* new btree key value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 xfs_bmbt_rec_t nrec; /* new record count */
483 int optr; /* old key/record index */
484 xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */
485 int ptr; /* key/record index */
486 xfs_bmbt_rec_t *rp=NULL; /* pointer to bmap btree rec */
487 int numrecs;
488
489 ASSERT(level < cur->bc_nlevels);
490 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
491 XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp);
Nathan Scott1121b212006-09-28 10:58:40 +1000492 ncur = NULL;
Christoph Hellwig8801bb92006-09-28 10:58:17 +1000493 key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(recp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 optr = ptr = cur->bc_ptrs[level];
495 if (ptr == 0) {
496 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
497 *stat = 0;
498 return 0;
499 }
500 XFS_STATS_INC(xs_bmbt_insrec);
501 block = xfs_bmbt_get_block(cur, level, &bp);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100502 numrecs = be16_to_cpu(block->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503#ifdef DEBUG
504 if ((error = xfs_btree_check_lblock(cur, block, level, bp))) {
505 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
506 return error;
507 }
508 if (ptr <= numrecs) {
509 if (level == 0) {
510 rp = XFS_BMAP_REC_IADDR(block, ptr, cur);
511 xfs_btree_check_rec(XFS_BTNUM_BMAP, recp, rp);
512 } else {
513 kp = XFS_BMAP_KEY_IADDR(block, ptr, cur);
514 xfs_btree_check_key(XFS_BTNUM_BMAP, &key, kp);
515 }
516 }
517#endif
518 nbno = NULLFSBLOCK;
519 if (numrecs == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) {
520 if (numrecs < XFS_BMAP_BLOCK_DMAXRECS(level, cur)) {
521 /*
522 * A root block, that can be made bigger.
523 */
524 xfs_iroot_realloc(cur->bc_private.b.ip, 1,
525 cur->bc_private.b.whichfork);
526 block = xfs_bmbt_get_block(cur, level, &bp);
527 } else if (level == cur->bc_nlevels - 1) {
528 if ((error = xfs_bmbt_newroot(cur, &logflags, stat)) ||
529 *stat == 0) {
530 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
531 return error;
532 }
533 xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
534 logflags);
535 block = xfs_bmbt_get_block(cur, level, &bp);
536 } else {
Christoph Hellwig9eaead52008-10-30 16:56:43 +1100537 if ((error = xfs_btree_rshift(cur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
539 return error;
540 }
541 if (i) {
542 /* nothing */
543 } else {
Christoph Hellwig687b8902008-10-30 16:56:53 +1100544 if ((error = xfs_btree_lshift(cur, level, &i))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
546 return error;
547 }
548 if (i) {
549 optr = ptr = cur->bc_ptrs[level];
550 } else {
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +1100551 union xfs_btree_ptr bno = { .l = cpu_to_be64(nbno) };
552 union xfs_btree_key skey;
553 if ((error = xfs_btree_split(cur, level,
554 &bno, &skey, &ncur,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 &i))) {
556 XFS_BMBT_TRACE_CURSOR(cur,
557 ERROR);
558 return error;
559 }
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +1100560 nbno = be64_to_cpu(bno.l);
561 startoff = be64_to_cpu(skey.bmbt.br_startoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (i) {
563 block = xfs_bmbt_get_block(
564 cur, level, &bp);
565#ifdef DEBUG
566 if ((error =
567 xfs_btree_check_lblock(cur,
568 block, level, bp))) {
569 XFS_BMBT_TRACE_CURSOR(
570 cur, ERROR);
571 return error;
572 }
573#endif
574 ptr = cur->bc_ptrs[level];
575 xfs_bmbt_disk_set_allf(&nrec,
Christoph Hellwig8801bb92006-09-28 10:58:17 +1000576 startoff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 XFS_EXT_NORM);
578 } else {
579 XFS_BMBT_TRACE_CURSOR(cur,
580 EXIT);
581 *stat = 0;
582 return 0;
583 }
584 }
585 }
586 }
587 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100588 numrecs = be16_to_cpu(block->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 if (level > 0) {
590 kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
591 pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
592#ifdef DEBUG
593 for (i = numrecs; i >= ptr; i--) {
Christoph Hellwigb113bcb2006-09-28 10:57:42 +1000594 if ((error = xfs_btree_check_lptr_disk(cur, pp[i - 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 level))) {
596 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
597 return error;
598 }
599 }
600#endif
601 memmove(&kp[ptr], &kp[ptr - 1],
602 (numrecs - ptr + 1) * sizeof(*kp));
Christoph Hellwigd580ef62007-08-16 16:23:11 +1000603 memmove(&pp[ptr], &pp[ptr - 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 (numrecs - ptr + 1) * sizeof(*pp));
605#ifdef DEBUG
Christoph Hellwig576039c2006-09-28 10:58:06 +1000606 if ((error = xfs_btree_check_lptr(cur, *bnop, level))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
608 return error;
609 }
610#endif
611 kp[ptr - 1] = key;
Christoph Hellwig576039c2006-09-28 10:58:06 +1000612 pp[ptr - 1] = cpu_to_be64(*bnop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 numrecs++;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100614 block->bb_numrecs = cpu_to_be16(numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 xfs_bmbt_log_keys(cur, bp, ptr, numrecs);
616 xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs);
617 } else {
618 rp = XFS_BMAP_REC_IADDR(block, 1, cur);
619 memmove(&rp[ptr], &rp[ptr - 1],
620 (numrecs - ptr + 1) * sizeof(*rp));
621 rp[ptr - 1] = *recp;
622 numrecs++;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100623 block->bb_numrecs = cpu_to_be16(numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 xfs_bmbt_log_recs(cur, bp, ptr, numrecs);
625 }
626 xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS);
627#ifdef DEBUG
628 if (ptr < numrecs) {
629 if (level == 0)
630 xfs_btree_check_rec(XFS_BTNUM_BMAP, rp + ptr - 1,
631 rp + ptr);
632 else
633 xfs_btree_check_key(XFS_BTNUM_BMAP, kp + ptr - 1,
634 kp + ptr);
635 }
636#endif
Christoph Hellwig38bb7422008-10-30 16:56:22 +1100637 if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
639 return error;
640 }
641 *bnop = nbno;
642 if (nbno != NULLFSBLOCK) {
643 *recp = nrec;
644 *curp = ncur;
645 }
646 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
647 *stat = 1;
648 return 0;
649}
650
651STATIC int
652xfs_bmbt_killroot(
653 xfs_btree_cur_t *cur)
654{
655 xfs_bmbt_block_t *block;
656 xfs_bmbt_block_t *cblock;
657 xfs_buf_t *cbp;
658 xfs_bmbt_key_t *ckp;
659 xfs_bmbt_ptr_t *cpp;
660#ifdef DEBUG
661 int error;
662#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 int i;
664 xfs_bmbt_key_t *kp;
665 xfs_inode_t *ip;
666 xfs_ifork_t *ifp;
667 int level;
668 xfs_bmbt_ptr_t *pp;
669
670 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
671 level = cur->bc_nlevels - 1;
672 ASSERT(level >= 1);
673 /*
674 * Don't deal with the root block needs to be a leaf case.
675 * We're just going to turn the thing back into extents anyway.
676 */
677 if (level == 1) {
678 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
679 return 0;
680 }
681 block = xfs_bmbt_get_block(cur, level, &cbp);
682 /*
683 * Give up if the root has multiple children.
684 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100685 if (be16_to_cpu(block->bb_numrecs) != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
687 return 0;
688 }
689 /*
690 * Only do this if the next level will fit.
691 * Then the data must be copied up to the inode,
692 * instead of freeing the root you free the next level.
693 */
694 cbp = cur->bc_bufs[level - 1];
695 cblock = XFS_BUF_TO_BMBT_BLOCK(cbp);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100696 if (be16_to_cpu(cblock->bb_numrecs) > XFS_BMAP_BLOCK_DMAXRECS(level, cur)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
698 return 0;
699 }
Christoph Hellwig16259e72005-11-02 15:11:25 +1100700 ASSERT(be64_to_cpu(cblock->bb_leftsib) == NULLDFSBNO);
701 ASSERT(be64_to_cpu(cblock->bb_rightsib) == NULLDFSBNO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 ip = cur->bc_private.b.ip;
703 ifp = XFS_IFORK_PTR(ip, cur->bc_private.b.whichfork);
704 ASSERT(XFS_BMAP_BLOCK_IMAXRECS(level, cur) ==
705 XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes));
Christoph Hellwig16259e72005-11-02 15:11:25 +1100706 i = (int)(be16_to_cpu(cblock->bb_numrecs) - XFS_BMAP_BLOCK_IMAXRECS(level, cur));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 if (i) {
708 xfs_iroot_realloc(ip, i, cur->bc_private.b.whichfork);
709 block = ifp->if_broot;
710 }
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800711 be16_add_cpu(&block->bb_numrecs, i);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100712 ASSERT(block->bb_numrecs == cblock->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
714 ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100715 memcpy(kp, ckp, be16_to_cpu(block->bb_numrecs) * sizeof(*kp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
717 cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
718#ifdef DEBUG
Christoph Hellwig16259e72005-11-02 15:11:25 +1100719 for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
Christoph Hellwigb113bcb2006-09-28 10:57:42 +1000720 if ((error = xfs_btree_check_lptr_disk(cur, cpp[i], level - 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
722 return error;
723 }
724 }
725#endif
Christoph Hellwig16259e72005-11-02 15:11:25 +1100726 memcpy(pp, cpp, be16_to_cpu(block->bb_numrecs) * sizeof(*pp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1,
728 cur->bc_private.b.flist, cur->bc_mp);
729 ip->i_d.di_nblocks--;
730 XFS_TRANS_MOD_DQUOT_BYINO(cur->bc_mp, cur->bc_tp, ip,
731 XFS_TRANS_DQ_BCOUNT, -1L);
732 xfs_trans_binval(cur->bc_tp, cbp);
733 cur->bc_bufs[level - 1] = NULL;
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800734 be16_add_cpu(&block->bb_level, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 xfs_trans_log_inode(cur->bc_tp, ip,
736 XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork));
737 cur->bc_nlevels--;
738 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
739 return 0;
740}
741
742/*
743 * Log key values from the btree block.
744 */
745STATIC void
746xfs_bmbt_log_keys(
747 xfs_btree_cur_t *cur,
748 xfs_buf_t *bp,
749 int kfirst,
750 int klast)
751{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 xfs_trans_t *tp;
753
754 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
755 XFS_BMBT_TRACE_ARGBII(cur, bp, kfirst, klast);
756 tp = cur->bc_tp;
757 if (bp) {
758 xfs_bmbt_block_t *block;
759 int first;
760 xfs_bmbt_key_t *kp;
761 int last;
762
763 block = XFS_BUF_TO_BMBT_BLOCK(bp);
764 kp = XFS_BMAP_KEY_DADDR(block, 1, cur);
765 first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block);
766 last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block);
767 xfs_trans_log_buf(tp, bp, first, last);
768 } else {
769 xfs_inode_t *ip;
770
771 ip = cur->bc_private.b.ip;
772 xfs_trans_log_inode(tp, ip,
773 XFS_ILOG_FBROOT(cur->bc_private.b.whichfork));
774 }
775 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
776}
777
778/*
779 * Log pointer values from the btree block.
780 */
781STATIC void
782xfs_bmbt_log_ptrs(
783 xfs_btree_cur_t *cur,
784 xfs_buf_t *bp,
785 int pfirst,
786 int plast)
787{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 xfs_trans_t *tp;
789
790 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
791 XFS_BMBT_TRACE_ARGBII(cur, bp, pfirst, plast);
792 tp = cur->bc_tp;
793 if (bp) {
794 xfs_bmbt_block_t *block;
795 int first;
796 int last;
797 xfs_bmbt_ptr_t *pp;
798
799 block = XFS_BUF_TO_BMBT_BLOCK(bp);
800 pp = XFS_BMAP_PTR_DADDR(block, 1, cur);
801 first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block);
802 last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block);
803 xfs_trans_log_buf(tp, bp, first, last);
804 } else {
805 xfs_inode_t *ip;
806
807 ip = cur->bc_private.b.ip;
808 xfs_trans_log_inode(tp, ip,
809 XFS_ILOG_FBROOT(cur->bc_private.b.whichfork));
810 }
811 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
812}
813
814/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 * Determine the extent state.
816 */
817/* ARGSUSED */
818STATIC xfs_exntst_t
819xfs_extent_state(
820 xfs_filblks_t blks,
821 int extent_flag)
822{
823 if (extent_flag) {
824 ASSERT(blks != 0); /* saved for DMIG */
825 return XFS_EXT_UNWRITTEN;
826 }
827 return XFS_EXT_NORM;
828}
829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830/*
831 * Convert on-disk form of btree root to in-memory form.
832 */
833void
834xfs_bmdr_to_bmbt(
835 xfs_bmdr_block_t *dblock,
836 int dblocklen,
837 xfs_bmbt_block_t *rblock,
838 int rblocklen)
839{
840 int dmxr;
841 xfs_bmbt_key_t *fkp;
Christoph Hellwig576039c2006-09-28 10:58:06 +1000842 __be64 *fpp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 xfs_bmbt_key_t *tkp;
Christoph Hellwig576039c2006-09-28 10:58:06 +1000844 __be64 *tpp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Christoph Hellwig16259e72005-11-02 15:11:25 +1100846 rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
847 rblock->bb_level = dblock->bb_level;
848 ASSERT(be16_to_cpu(rblock->bb_level) > 0);
849 rblock->bb_numrecs = dblock->bb_numrecs;
850 rblock->bb_leftsib = cpu_to_be64(NULLDFSBNO);
851 rblock->bb_rightsib = cpu_to_be64(NULLDFSBNO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0);
Eric Sandeen2c36dde2007-02-10 18:37:33 +1100853 fkp = XFS_BTREE_KEY_ADDR(xfs_bmdr, dblock, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 tkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen);
Eric Sandeen2c36dde2007-02-10 18:37:33 +1100855 fpp = XFS_BTREE_PTR_ADDR(xfs_bmdr, dblock, 1, dmxr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100857 dmxr = be16_to_cpu(dblock->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
Christoph Hellwig576039c2006-09-28 10:58:06 +1000859 memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
861
862/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 * Delete the record pointed to by cur.
864 */
865int /* error */
866xfs_bmbt_delete(
867 xfs_btree_cur_t *cur,
868 int *stat) /* success/failure */
869{
870 int error; /* error return value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 int i;
872 int level;
873
874 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
875 for (level = 0, i = 2; i == 2; level++) {
876 if ((error = xfs_bmbt_delrec(cur, level, &i))) {
877 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
878 return error;
879 }
880 }
881 if (i == 0) {
882 for (level = 1; level < cur->bc_nlevels; level++) {
883 if (cur->bc_ptrs[level] == 0) {
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100884 if ((error = xfs_btree_decrement(cur, level,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 &i))) {
886 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
887 return error;
888 }
889 break;
890 }
891 }
892 }
893 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
894 *stat = i;
895 return 0;
896}
897
898/*
899 * Convert a compressed bmap extent record to an uncompressed form.
900 * This code must be in sync with the routines xfs_bmbt_get_startoff,
901 * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state.
902 */
903
David Chinner7989cb82007-02-10 18:34:56 +1100904STATIC_INLINE void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905__xfs_bmbt_get_all(
906 __uint64_t l0,
907 __uint64_t l1,
908 xfs_bmbt_irec_t *s)
909{
910 int ext_flag;
911 xfs_exntst_t st;
912
913 ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN));
914 s->br_startoff = ((xfs_fileoff_t)l0 &
915 XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
916#if XFS_BIG_BLKNOS
917 s->br_startblock = (((xfs_fsblock_t)l0 & XFS_MASK64LO(9)) << 43) |
918 (((xfs_fsblock_t)l1) >> 21);
919#else
920#ifdef DEBUG
921 {
922 xfs_dfsbno_t b;
923
924 b = (((xfs_dfsbno_t)l0 & XFS_MASK64LO(9)) << 43) |
925 (((xfs_dfsbno_t)l1) >> 21);
926 ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b));
927 s->br_startblock = (xfs_fsblock_t)b;
928 }
929#else /* !DEBUG */
930 s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)l1) >> 21);
931#endif /* DEBUG */
932#endif /* XFS_BIG_BLKNOS */
933 s->br_blockcount = (xfs_filblks_t)(l1 & XFS_MASK64LO(21));
934 /* This is xfs_extent_state() in-line */
935 if (ext_flag) {
936 ASSERT(s->br_blockcount != 0); /* saved for DMIG */
937 st = XFS_EXT_UNWRITTEN;
938 } else
939 st = XFS_EXT_NORM;
940 s->br_state = st;
941}
942
943void
944xfs_bmbt_get_all(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +1000945 xfs_bmbt_rec_host_t *r,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 xfs_bmbt_irec_t *s)
947{
948 __xfs_bmbt_get_all(r->l0, r->l1, s);
949}
950
951/*
952 * Get the block pointer for the given level of the cursor.
953 * Fill in the buffer pointer, if applicable.
954 */
955xfs_bmbt_block_t *
956xfs_bmbt_get_block(
957 xfs_btree_cur_t *cur,
958 int level,
959 xfs_buf_t **bpp)
960{
961 xfs_ifork_t *ifp;
962 xfs_bmbt_block_t *rval;
963
964 if (level < cur->bc_nlevels - 1) {
965 *bpp = cur->bc_bufs[level];
966 rval = XFS_BUF_TO_BMBT_BLOCK(*bpp);
967 } else {
968 *bpp = NULL;
969 ifp = XFS_IFORK_PTR(cur->bc_private.b.ip,
970 cur->bc_private.b.whichfork);
971 rval = ifp->if_broot;
972 }
973 return rval;
974}
975
976/*
977 * Extract the blockcount field from an in memory bmap extent record.
978 */
979xfs_filblks_t
980xfs_bmbt_get_blockcount(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +1000981 xfs_bmbt_rec_host_t *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
983 return (xfs_filblks_t)(r->l1 & XFS_MASK64LO(21));
984}
985
986/*
987 * Extract the startblock field from an in memory bmap extent record.
988 */
989xfs_fsblock_t
990xfs_bmbt_get_startblock(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +1000991 xfs_bmbt_rec_host_t *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992{
993#if XFS_BIG_BLKNOS
994 return (((xfs_fsblock_t)r->l0 & XFS_MASK64LO(9)) << 43) |
995 (((xfs_fsblock_t)r->l1) >> 21);
996#else
997#ifdef DEBUG
998 xfs_dfsbno_t b;
999
1000 b = (((xfs_dfsbno_t)r->l0 & XFS_MASK64LO(9)) << 43) |
1001 (((xfs_dfsbno_t)r->l1) >> 21);
1002 ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b));
1003 return (xfs_fsblock_t)b;
1004#else /* !DEBUG */
1005 return (xfs_fsblock_t)(((xfs_dfsbno_t)r->l1) >> 21);
1006#endif /* DEBUG */
1007#endif /* XFS_BIG_BLKNOS */
1008}
1009
1010/*
1011 * Extract the startoff field from an in memory bmap extent record.
1012 */
1013xfs_fileoff_t
1014xfs_bmbt_get_startoff(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001015 xfs_bmbt_rec_host_t *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016{
1017 return ((xfs_fileoff_t)r->l0 &
1018 XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
1019}
1020
1021xfs_exntst_t
1022xfs_bmbt_get_state(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001023 xfs_bmbt_rec_host_t *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 int ext_flag;
1026
1027 ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN));
1028 return xfs_extent_state(xfs_bmbt_get_blockcount(r),
1029 ext_flag);
1030}
1031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032/* Endian flipping versions of the bmbt extraction functions */
1033void
1034xfs_bmbt_disk_get_all(
1035 xfs_bmbt_rec_t *r,
1036 xfs_bmbt_irec_t *s)
1037{
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001038 __xfs_bmbt_get_all(be64_to_cpu(r->l0), be64_to_cpu(r->l1), s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039}
1040
1041/*
1042 * Extract the blockcount field from an on disk bmap extent record.
1043 */
1044xfs_filblks_t
1045xfs_bmbt_disk_get_blockcount(
1046 xfs_bmbt_rec_t *r)
1047{
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001048 return (xfs_filblks_t)(be64_to_cpu(r->l1) & XFS_MASK64LO(21));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049}
1050
1051/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 * Extract the startoff field from a disk format bmap extent record.
1053 */
1054xfs_fileoff_t
1055xfs_bmbt_disk_get_startoff(
1056 xfs_bmbt_rec_t *r)
1057{
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001058 return ((xfs_fileoff_t)be64_to_cpu(r->l0) &
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
1060}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 * Insert the current record at the point referenced by cur.
David Chinner59a33f92008-03-27 18:00:45 +11001064 *
1065 * A multi-level split of the tree on insert will invalidate the original
Lachlan McIlroyddea2d52008-06-23 13:25:53 +10001066 * cursor. All callers of this function should assume that the cursor is
1067 * no longer valid and revalidate it.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 */
1069int /* error */
1070xfs_bmbt_insert(
1071 xfs_btree_cur_t *cur,
1072 int *stat) /* success/failure */
1073{
1074 int error; /* error return value */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 int i;
1076 int level;
1077 xfs_fsblock_t nbno;
1078 xfs_btree_cur_t *ncur;
1079 xfs_bmbt_rec_t nrec;
1080 xfs_btree_cur_t *pcur;
1081
1082 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
1083 level = 0;
1084 nbno = NULLFSBLOCK;
1085 xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
Nathan Scott1121b212006-09-28 10:58:40 +10001086 ncur = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 pcur = cur;
1088 do {
1089 if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur,
1090 &i))) {
1091 if (pcur != cur)
1092 xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
Lachlan McIlroyddea2d52008-06-23 13:25:53 +10001093 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
1094 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
1097 if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) {
1098 cur->bc_nlevels = pcur->bc_nlevels;
1099 cur->bc_private.b.allocated +=
1100 pcur->bc_private.b.allocated;
1101 pcur->bc_private.b.allocated = 0;
1102 ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) ||
Eric Sandeen71ddabb2007-11-23 16:29:42 +11001103 XFS_IS_REALTIME_INODE(cur->bc_private.b.ip));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 cur->bc_private.b.firstblock =
1105 pcur->bc_private.b.firstblock;
1106 ASSERT(cur->bc_private.b.flist ==
1107 pcur->bc_private.b.flist);
1108 xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
1109 }
1110 if (ncur) {
1111 pcur = ncur;
Nathan Scott1121b212006-09-28 10:58:40 +10001112 ncur = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
1114 } while (nbno != NULLFSBLOCK);
1115 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
1116 *stat = i;
1117 return 0;
1118error0:
1119 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
1120 return error;
1121}
1122
1123/*
1124 * Log fields from the btree block header.
1125 */
1126void
1127xfs_bmbt_log_block(
1128 xfs_btree_cur_t *cur,
1129 xfs_buf_t *bp,
1130 int fields)
1131{
1132 int first;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 int last;
1134 xfs_trans_t *tp;
1135 static const short offsets[] = {
1136 offsetof(xfs_bmbt_block_t, bb_magic),
1137 offsetof(xfs_bmbt_block_t, bb_level),
1138 offsetof(xfs_bmbt_block_t, bb_numrecs),
1139 offsetof(xfs_bmbt_block_t, bb_leftsib),
1140 offsetof(xfs_bmbt_block_t, bb_rightsib),
1141 sizeof(xfs_bmbt_block_t)
1142 };
1143
1144 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
1145 XFS_BMBT_TRACE_ARGBI(cur, bp, fields);
1146 tp = cur->bc_tp;
1147 if (bp) {
1148 xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first,
1149 &last);
1150 xfs_trans_log_buf(tp, bp, first, last);
1151 } else
1152 xfs_trans_log_inode(tp, cur->bc_private.b.ip,
1153 XFS_ILOG_FBROOT(cur->bc_private.b.whichfork));
1154 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
1155}
1156
1157/*
1158 * Log record values from the btree block.
1159 */
1160void
1161xfs_bmbt_log_recs(
1162 xfs_btree_cur_t *cur,
1163 xfs_buf_t *bp,
1164 int rfirst,
1165 int rlast)
1166{
1167 xfs_bmbt_block_t *block;
1168 int first;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 int last;
1170 xfs_bmbt_rec_t *rp;
1171 xfs_trans_t *tp;
1172
1173 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
1174 XFS_BMBT_TRACE_ARGBII(cur, bp, rfirst, rlast);
1175 ASSERT(bp);
1176 tp = cur->bc_tp;
1177 block = XFS_BUF_TO_BMBT_BLOCK(bp);
1178 rp = XFS_BMAP_REC_DADDR(block, 1, cur);
1179 first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block);
1180 last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block);
1181 xfs_trans_log_buf(tp, bp, first, last);
1182 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
1183}
1184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185/*
1186 * Give the bmap btree a new root block. Copy the old broot contents
1187 * down into a real block and make the broot point to it.
1188 */
1189int /* error */
1190xfs_bmbt_newroot(
1191 xfs_btree_cur_t *cur, /* btree cursor */
1192 int *logflags, /* logging flags for inode */
1193 int *stat) /* return status - 0 fail */
1194{
1195 xfs_alloc_arg_t args; /* allocation arguments */
1196 xfs_bmbt_block_t *block; /* bmap btree block */
1197 xfs_buf_t *bp; /* buffer for block */
1198 xfs_bmbt_block_t *cblock; /* child btree block */
1199 xfs_bmbt_key_t *ckp; /* child key pointer */
1200 xfs_bmbt_ptr_t *cpp; /* child ptr pointer */
1201 int error; /* error return code */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202#ifdef DEBUG
1203 int i; /* loop counter */
1204#endif
1205 xfs_bmbt_key_t *kp; /* pointer to bmap btree key */
1206 int level; /* btree level */
1207 xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */
1208
1209 XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
1210 level = cur->bc_nlevels - 1;
1211 block = xfs_bmbt_get_block(cur, level, &bp);
1212 /*
1213 * Copy the root into a real block.
1214 */
1215 args.mp = cur->bc_mp;
1216 pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
1217 args.tp = cur->bc_tp;
1218 args.fsbno = cur->bc_private.b.firstblock;
1219 args.mod = args.minleft = args.alignment = args.total = args.isfl =
1220 args.userdata = args.minalignslop = 0;
1221 args.minlen = args.maxlen = args.prod = 1;
1222 args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL;
Yingping Lud210a282006-06-09 14:55:18 +10001223 args.firstblock = args.fsbno;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 if (args.fsbno == NULLFSBLOCK) {
1225#ifdef DEBUG
Christoph Hellwigb113bcb2006-09-28 10:57:42 +10001226 if ((error = xfs_btree_check_lptr_disk(cur, *pp, level))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
1228 return error;
1229 }
1230#endif
Christoph Hellwig576039c2006-09-28 10:58:06 +10001231 args.fsbno = be64_to_cpu(*pp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 args.type = XFS_ALLOCTYPE_START_BNO;
Lachlan McIlroyb877e3d2008-06-27 13:33:03 +10001233 } else if (cur->bc_private.b.flist->xbf_low)
1234 args.type = XFS_ALLOCTYPE_START_BNO;
1235 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1237 if ((error = xfs_alloc_vextent(&args))) {
1238 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
1239 return error;
1240 }
1241 if (args.fsbno == NULLFSBLOCK) {
1242 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
1243 *stat = 0;
1244 return 0;
1245 }
1246 ASSERT(args.len == 1);
1247 cur->bc_private.b.firstblock = args.fsbno;
1248 cur->bc_private.b.allocated++;
1249 cur->bc_private.b.ip->i_d.di_nblocks++;
1250 XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
1251 XFS_TRANS_DQ_BCOUNT, 1L);
1252 bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0);
1253 cblock = XFS_BUF_TO_BMBT_BLOCK(bp);
1254 *cblock = *block;
Marcin Slusarz413d57c2008-02-13 15:03:29 -08001255 be16_add_cpu(&block->bb_level, 1);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001256 block->bb_numrecs = cpu_to_be16(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 cur->bc_nlevels++;
1258 cur->bc_ptrs[level + 1] = 1;
1259 kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
1260 ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001261 memcpy(ckp, kp, be16_to_cpu(cblock->bb_numrecs) * sizeof(*kp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
1263#ifdef DEBUG
Christoph Hellwig16259e72005-11-02 15:11:25 +11001264 for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
Christoph Hellwigb113bcb2006-09-28 10:57:42 +10001265 if ((error = xfs_btree_check_lptr_disk(cur, pp[i], level))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
1267 return error;
1268 }
1269 }
1270#endif
Christoph Hellwig16259e72005-11-02 15:11:25 +11001271 memcpy(cpp, pp, be16_to_cpu(cblock->bb_numrecs) * sizeof(*pp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272#ifdef DEBUG
Christoph Hellwig576039c2006-09-28 10:58:06 +10001273 if ((error = xfs_btree_check_lptr(cur, args.fsbno, level))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 XFS_BMBT_TRACE_CURSOR(cur, ERROR);
1275 return error;
1276 }
1277#endif
Christoph Hellwig576039c2006-09-28 10:58:06 +10001278 *pp = cpu_to_be64(args.fsbno);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001279 xfs_iroot_realloc(cur->bc_private.b.ip, 1 - be16_to_cpu(cblock->bb_numrecs),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 cur->bc_private.b.whichfork);
1281 xfs_btree_setbuf(cur, level, bp);
1282 /*
1283 * Do all this logging at the end so that
1284 * the root is at the right level.
1285 */
1286 xfs_bmbt_log_block(cur, bp, XFS_BB_ALL_BITS);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001287 xfs_bmbt_log_keys(cur, bp, 1, be16_to_cpu(cblock->bb_numrecs));
1288 xfs_bmbt_log_ptrs(cur, bp, 1, be16_to_cpu(cblock->bb_numrecs));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 XFS_BMBT_TRACE_CURSOR(cur, EXIT);
1290 *logflags |=
1291 XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork);
1292 *stat = 1;
1293 return 0;
1294}
1295
1296/*
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001297 * Set all the fields in a bmap extent record from the arguments.
1298 */
1299void
1300xfs_bmbt_set_allf(
1301 xfs_bmbt_rec_host_t *r,
1302 xfs_fileoff_t startoff,
1303 xfs_fsblock_t startblock,
1304 xfs_filblks_t blockcount,
1305 xfs_exntst_t state)
1306{
1307 int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1;
1308
1309 ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN);
1310 ASSERT((startoff & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0);
1311 ASSERT((blockcount & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0);
1312
1313#if XFS_BIG_BLKNOS
1314 ASSERT((startblock & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0);
1315
1316 r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
1317 ((xfs_bmbt_rec_base_t)startoff << 9) |
1318 ((xfs_bmbt_rec_base_t)startblock >> 43);
1319 r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) |
1320 ((xfs_bmbt_rec_base_t)blockcount &
1321 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
1322#else /* !XFS_BIG_BLKNOS */
Michal Piotrowskiddc6d3b2007-08-23 16:20:10 +10001323 if (ISNULLSTARTBLOCK(startblock)) {
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001324 r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
1325 ((xfs_bmbt_rec_base_t)startoff << 9) |
1326 (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
1327 r->l1 = XFS_MASK64HI(11) |
1328 ((xfs_bmbt_rec_base_t)startblock << 21) |
1329 ((xfs_bmbt_rec_base_t)blockcount &
1330 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
1331 } else {
1332 r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
1333 ((xfs_bmbt_rec_base_t)startoff << 9);
1334 r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) |
1335 ((xfs_bmbt_rec_base_t)blockcount &
1336 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
1337 }
1338#endif /* XFS_BIG_BLKNOS */
1339}
1340
1341/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 * Set all the fields in a bmap extent record from the uncompressed form.
1343 */
1344void
1345xfs_bmbt_set_all(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001346 xfs_bmbt_rec_host_t *r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 xfs_bmbt_irec_t *s)
1348{
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001349 xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock,
1350 s->br_blockcount, s->br_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351}
1352
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354/*
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001355 * Set all the fields in a disk format bmap extent record from the arguments.
1356 */
1357void
1358xfs_bmbt_disk_set_allf(
1359 xfs_bmbt_rec_t *r,
1360 xfs_fileoff_t startoff,
1361 xfs_fsblock_t startblock,
1362 xfs_filblks_t blockcount,
1363 xfs_exntst_t state)
1364{
1365 int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1;
1366
1367 ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN);
1368 ASSERT((startoff & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0);
1369 ASSERT((blockcount & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0);
1370
1371#if XFS_BIG_BLKNOS
1372 ASSERT((startblock & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0);
1373
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001374 r->l0 = cpu_to_be64(
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001375 ((xfs_bmbt_rec_base_t)extent_flag << 63) |
1376 ((xfs_bmbt_rec_base_t)startoff << 9) |
1377 ((xfs_bmbt_rec_base_t)startblock >> 43));
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001378 r->l1 = cpu_to_be64(
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001379 ((xfs_bmbt_rec_base_t)startblock << 21) |
1380 ((xfs_bmbt_rec_base_t)blockcount &
1381 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
1382#else /* !XFS_BIG_BLKNOS */
Michal Piotrowskiddc6d3b2007-08-23 16:20:10 +10001383 if (ISNULLSTARTBLOCK(startblock)) {
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001384 r->l0 = cpu_to_be64(
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001385 ((xfs_bmbt_rec_base_t)extent_flag << 63) |
1386 ((xfs_bmbt_rec_base_t)startoff << 9) |
1387 (xfs_bmbt_rec_base_t)XFS_MASK64LO(9));
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001388 r->l1 = cpu_to_be64(XFS_MASK64HI(11) |
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001389 ((xfs_bmbt_rec_base_t)startblock << 21) |
1390 ((xfs_bmbt_rec_base_t)blockcount &
1391 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
1392 } else {
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001393 r->l0 = cpu_to_be64(
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001394 ((xfs_bmbt_rec_base_t)extent_flag << 63) |
1395 ((xfs_bmbt_rec_base_t)startoff << 9));
Christoph Hellwigcd8b0a92007-08-16 16:24:15 +10001396 r->l1 = cpu_to_be64(
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001397 ((xfs_bmbt_rec_base_t)startblock << 21) |
1398 ((xfs_bmbt_rec_base_t)blockcount &
1399 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
1400 }
1401#endif /* XFS_BIG_BLKNOS */
1402}
1403
1404/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 * Set all the fields in a bmap extent record from the uncompressed form.
1406 */
1407void
1408xfs_bmbt_disk_set_all(
1409 xfs_bmbt_rec_t *r,
1410 xfs_bmbt_irec_t *s)
1411{
Christoph Hellwig8cba4342007-08-16 16:23:53 +10001412 xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock,
1413 s->br_blockcount, s->br_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416/*
1417 * Set the blockcount field in a bmap extent record.
1418 */
1419void
1420xfs_bmbt_set_blockcount(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001421 xfs_bmbt_rec_host_t *r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 xfs_filblks_t v)
1423{
1424 ASSERT((v & XFS_MASK64HI(43)) == 0);
1425 r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) |
1426 (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21));
1427}
1428
1429/*
1430 * Set the startblock field in a bmap extent record.
1431 */
1432void
1433xfs_bmbt_set_startblock(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001434 xfs_bmbt_rec_host_t *r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 xfs_fsblock_t v)
1436{
1437#if XFS_BIG_BLKNOS
1438 ASSERT((v & XFS_MASK64HI(12)) == 0);
1439 r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) |
1440 (xfs_bmbt_rec_base_t)(v >> 43);
1441 r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) |
1442 (xfs_bmbt_rec_base_t)(v << 21);
1443#else /* !XFS_BIG_BLKNOS */
1444 if (ISNULLSTARTBLOCK(v)) {
1445 r->l0 |= (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
1446 r->l1 = (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) |
1447 ((xfs_bmbt_rec_base_t)v << 21) |
1448 (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
1449 } else {
1450 r->l0 &= ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
1451 r->l1 = ((xfs_bmbt_rec_base_t)v << 21) |
1452 (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
1453 }
1454#endif /* XFS_BIG_BLKNOS */
1455}
1456
1457/*
1458 * Set the startoff field in a bmap extent record.
1459 */
1460void
1461xfs_bmbt_set_startoff(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001462 xfs_bmbt_rec_host_t *r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 xfs_fileoff_t v)
1464{
1465 ASSERT((v & XFS_MASK64HI(9)) == 0);
1466 r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) |
1467 ((xfs_bmbt_rec_base_t)v << 9) |
1468 (r->l0 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9));
1469}
1470
1471/*
1472 * Set the extent state field in a bmap extent record.
1473 */
1474void
1475xfs_bmbt_set_state(
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001476 xfs_bmbt_rec_host_t *r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 xfs_exntst_t v)
1478{
1479 ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN);
1480 if (v == XFS_EXT_NORM)
1481 r->l0 &= XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN);
1482 else
1483 r->l0 |= XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN);
1484}
1485
1486/*
1487 * Convert in-memory form of btree root to on-disk form.
1488 */
1489void
1490xfs_bmbt_to_bmdr(
1491 xfs_bmbt_block_t *rblock,
1492 int rblocklen,
1493 xfs_bmdr_block_t *dblock,
1494 int dblocklen)
1495{
1496 int dmxr;
1497 xfs_bmbt_key_t *fkp;
Christoph Hellwig576039c2006-09-28 10:58:06 +10001498 __be64 *fpp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 xfs_bmbt_key_t *tkp;
Christoph Hellwig576039c2006-09-28 10:58:06 +10001500 __be64 *tpp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Christoph Hellwig16259e72005-11-02 15:11:25 +11001502 ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_MAGIC);
1503 ASSERT(be64_to_cpu(rblock->bb_leftsib) == NULLDFSBNO);
1504 ASSERT(be64_to_cpu(rblock->bb_rightsib) == NULLDFSBNO);
1505 ASSERT(be16_to_cpu(rblock->bb_level) > 0);
1506 dblock->bb_level = rblock->bb_level;
1507 dblock->bb_numrecs = rblock->bb_numrecs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0);
1509 fkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen);
Eric Sandeen2c36dde2007-02-10 18:37:33 +11001510 tkp = XFS_BTREE_KEY_ADDR(xfs_bmdr, dblock, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
Eric Sandeen2c36dde2007-02-10 18:37:33 +11001512 tpp = XFS_BTREE_PTR_ADDR(xfs_bmdr, dblock, 1, dmxr);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001513 dmxr = be16_to_cpu(dblock->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
Christoph Hellwig576039c2006-09-28 10:58:06 +10001515 memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516}
1517
1518/*
Mandy Kirkconnell4eea22f2006-03-14 13:29:52 +11001519 * Check extent records, which have just been read, for
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 * any bit in the extent flag field. ASSERT on debug
1521 * kernels, as this condition should not occur.
1522 * Return an error condition (1) if any flags found,
1523 * otherwise return 0.
1524 */
1525
1526int
1527xfs_check_nostate_extents(
Mandy Kirkconnell4eea22f2006-03-14 13:29:52 +11001528 xfs_ifork_t *ifp,
1529 xfs_extnum_t idx,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 xfs_extnum_t num)
1531{
Mandy Kirkconnell4eea22f2006-03-14 13:29:52 +11001532 for (; num > 0; num--, idx++) {
Christoph Hellwiga6f64d42007-08-16 16:23:40 +10001533 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 if ((ep->l0 >>
1535 (64 - BMBT_EXNTFLAG_BITLEN)) != 0) {
1536 ASSERT(0);
1537 return 1;
1538 }
1539 }
1540 return 0;
1541}
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001542
1543
1544STATIC struct xfs_btree_cur *
1545xfs_bmbt_dup_cursor(
1546 struct xfs_btree_cur *cur)
1547{
1548 struct xfs_btree_cur *new;
1549
1550 new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp,
1551 cur->bc_private.b.ip, cur->bc_private.b.whichfork);
1552
1553 /*
1554 * Copy the firstblock, flist, and flags values,
1555 * since init cursor doesn't get them.
1556 */
1557 new->bc_private.b.firstblock = cur->bc_private.b.firstblock;
1558 new->bc_private.b.flist = cur->bc_private.b.flist;
1559 new->bc_private.b.flags = cur->bc_private.b.flags;
1560
1561 return new;
1562}
1563
Christoph Hellwigce5e42d2008-10-30 16:55:23 +11001564STATIC int
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +11001565xfs_bmbt_alloc_block(
1566 struct xfs_btree_cur *cur,
1567 union xfs_btree_ptr *start,
1568 union xfs_btree_ptr *new,
1569 int length,
1570 int *stat)
1571{
1572 xfs_alloc_arg_t args; /* block allocation args */
1573 int error; /* error return value */
1574
1575 memset(&args, 0, sizeof(args));
1576 args.tp = cur->bc_tp;
1577 args.mp = cur->bc_mp;
1578 args.fsbno = cur->bc_private.b.firstblock;
1579 args.firstblock = args.fsbno;
1580
1581 if (args.fsbno == NULLFSBLOCK) {
1582 args.fsbno = be64_to_cpu(start->l);
1583 args.type = XFS_ALLOCTYPE_START_BNO;
1584 /*
1585 * Make sure there is sufficient room left in the AG to
1586 * complete a full tree split for an extent insert. If
1587 * we are converting the middle part of an extent then
1588 * we may need space for two tree splits.
1589 *
1590 * We are relying on the caller to make the correct block
1591 * reservation for this operation to succeed. If the
1592 * reservation amount is insufficient then we may fail a
1593 * block allocation here and corrupt the filesystem.
1594 */
1595 args.minleft = xfs_trans_get_block_res(args.tp);
1596 } else if (cur->bc_private.b.flist->xbf_low) {
1597 args.type = XFS_ALLOCTYPE_START_BNO;
1598 } else {
1599 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1600 }
1601
1602 args.minlen = args.maxlen = args.prod = 1;
1603 args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL;
1604 if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) {
1605 error = XFS_ERROR(ENOSPC);
1606 goto error0;
1607 }
1608 error = xfs_alloc_vextent(&args);
1609 if (error)
1610 goto error0;
1611
1612 if (args.fsbno == NULLFSBLOCK && args.minleft) {
1613 /*
1614 * Could not find an AG with enough free space to satisfy
1615 * a full btree split. Try again without minleft and if
1616 * successful activate the lowspace algorithm.
1617 */
1618 args.fsbno = 0;
1619 args.type = XFS_ALLOCTYPE_FIRST_AG;
1620 args.minleft = 0;
1621 error = xfs_alloc_vextent(&args);
1622 if (error)
1623 goto error0;
1624 cur->bc_private.b.flist->xbf_low = 1;
1625 }
1626 if (args.fsbno == NULLFSBLOCK) {
1627 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1628 *stat = 0;
1629 return 0;
1630 }
1631 ASSERT(args.len == 1);
1632 cur->bc_private.b.firstblock = args.fsbno;
1633 cur->bc_private.b.allocated++;
1634 cur->bc_private.b.ip->i_d.di_nblocks++;
1635 xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE);
1636 XFS_TRANS_MOD_DQUOT_BYINO(args.mp, args.tp, cur->bc_private.b.ip,
1637 XFS_TRANS_DQ_BCOUNT, 1L);
1638
1639 new->l = cpu_to_be64(args.fsbno);
1640
1641 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1642 *stat = 1;
1643 return 0;
1644
1645 error0:
1646 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
1647 return error;
1648}
1649
1650STATIC int
Christoph Hellwigce5e42d2008-10-30 16:55:23 +11001651xfs_bmbt_get_maxrecs(
1652 struct xfs_btree_cur *cur,
1653 int level)
1654{
1655 return XFS_BMAP_BLOCK_IMAXRECS(level, cur);
1656}
1657
Christoph Hellwigfe033cc2008-10-30 16:56:09 +11001658STATIC void
1659xfs_bmbt_init_key_from_rec(
1660 union xfs_btree_key *key,
1661 union xfs_btree_rec *rec)
1662{
1663 key->bmbt.br_startoff =
1664 cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt));
1665}
1666
1667STATIC void
1668xfs_bmbt_init_ptr_from_cur(
1669 struct xfs_btree_cur *cur,
1670 union xfs_btree_ptr *ptr)
1671{
1672 ptr->l = 0;
1673}
1674
1675STATIC __int64_t
1676xfs_bmbt_key_diff(
1677 struct xfs_btree_cur *cur,
1678 union xfs_btree_key *key)
1679{
1680 return (__int64_t)be64_to_cpu(key->bmbt.br_startoff) -
1681 cur->bc_rec.b.br_startoff;
1682}
1683
Christoph Hellwig8c4ed632008-10-30 16:55:13 +11001684#ifdef XFS_BTREE_TRACE
1685ktrace_t *xfs_bmbt_trace_buf;
1686
1687STATIC void
1688xfs_bmbt_trace_enter(
1689 struct xfs_btree_cur *cur,
1690 const char *func,
1691 char *s,
1692 int type,
1693 int line,
1694 __psunsigned_t a0,
1695 __psunsigned_t a1,
1696 __psunsigned_t a2,
1697 __psunsigned_t a3,
1698 __psunsigned_t a4,
1699 __psunsigned_t a5,
1700 __psunsigned_t a6,
1701 __psunsigned_t a7,
1702 __psunsigned_t a8,
1703 __psunsigned_t a9,
1704 __psunsigned_t a10)
1705{
1706 struct xfs_inode *ip = cur->bc_private.b.ip;
1707 int whichfork = cur->bc_private.b.whichfork;
1708
1709 ktrace_enter(xfs_bmbt_trace_buf,
1710 (void *)((__psint_t)type | (whichfork << 8) | (line << 16)),
1711 (void *)func, (void *)s, (void *)ip, (void *)cur,
1712 (void *)a0, (void *)a1, (void *)a2, (void *)a3,
1713 (void *)a4, (void *)a5, (void *)a6, (void *)a7,
1714 (void *)a8, (void *)a9, (void *)a10);
1715 ktrace_enter(ip->i_btrace,
1716 (void *)((__psint_t)type | (whichfork << 8) | (line << 16)),
1717 (void *)func, (void *)s, (void *)ip, (void *)cur,
1718 (void *)a0, (void *)a1, (void *)a2, (void *)a3,
1719 (void *)a4, (void *)a5, (void *)a6, (void *)a7,
1720 (void *)a8, (void *)a9, (void *)a10);
1721}
1722
1723STATIC void
1724xfs_bmbt_trace_cursor(
1725 struct xfs_btree_cur *cur,
1726 __uint32_t *s0,
1727 __uint64_t *l0,
1728 __uint64_t *l1)
1729{
1730 struct xfs_bmbt_rec_host r;
1731
1732 xfs_bmbt_set_all(&r, &cur->bc_rec.b);
1733
1734 *s0 = (cur->bc_nlevels << 24) |
1735 (cur->bc_private.b.flags << 16) |
1736 cur->bc_private.b.allocated;
1737 *l0 = r.l0;
1738 *l1 = r.l1;
1739}
1740
1741STATIC void
1742xfs_bmbt_trace_key(
1743 struct xfs_btree_cur *cur,
1744 union xfs_btree_key *key,
1745 __uint64_t *l0,
1746 __uint64_t *l1)
1747{
1748 *l0 = be64_to_cpu(key->bmbt.br_startoff);
1749 *l1 = 0;
1750}
1751
1752STATIC void
1753xfs_bmbt_trace_record(
1754 struct xfs_btree_cur *cur,
1755 union xfs_btree_rec *rec,
1756 __uint64_t *l0,
1757 __uint64_t *l1,
1758 __uint64_t *l2)
1759{
1760 struct xfs_bmbt_irec irec;
1761
1762 xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
1763 *l0 = irec.br_startoff;
1764 *l1 = irec.br_startblock;
1765 *l2 = irec.br_blockcount;
1766}
1767#endif /* XFS_BTREE_TRACE */
1768
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001769static const struct xfs_btree_ops xfs_bmbt_ops = {
Christoph Hellwig65f1eae2008-10-30 16:55:34 +11001770 .rec_len = sizeof(xfs_bmbt_rec_t),
1771 .key_len = sizeof(xfs_bmbt_key_t),
1772
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001773 .dup_cursor = xfs_bmbt_dup_cursor,
Christoph Hellwigf5eb8e72008-10-30 16:57:03 +11001774 .alloc_block = xfs_bmbt_alloc_block,
Christoph Hellwigce5e42d2008-10-30 16:55:23 +11001775 .get_maxrecs = xfs_bmbt_get_maxrecs,
Christoph Hellwigfe033cc2008-10-30 16:56:09 +11001776 .init_key_from_rec = xfs_bmbt_init_key_from_rec,
1777 .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur,
1778 .key_diff = xfs_bmbt_key_diff,
Christoph Hellwig8c4ed632008-10-30 16:55:13 +11001779
1780#ifdef XFS_BTREE_TRACE
1781 .trace_enter = xfs_bmbt_trace_enter,
1782 .trace_cursor = xfs_bmbt_trace_cursor,
1783 .trace_key = xfs_bmbt_trace_key,
1784 .trace_record = xfs_bmbt_trace_record,
1785#endif
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001786};
1787
1788/*
1789 * Allocate a new bmap btree cursor.
1790 */
1791struct xfs_btree_cur * /* new bmap btree cursor */
1792xfs_bmbt_init_cursor(
1793 struct xfs_mount *mp, /* file system mount point */
1794 struct xfs_trans *tp, /* transaction pointer */
1795 struct xfs_inode *ip, /* inode owning the btree */
1796 int whichfork) /* data or attr fork */
1797{
1798 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
1799 struct xfs_btree_cur *cur;
1800
1801 cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
1802
1803 cur->bc_tp = tp;
1804 cur->bc_mp = mp;
1805 cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
1806 cur->bc_btnum = XFS_BTNUM_BMAP;
1807 cur->bc_blocklog = mp->m_sb.sb_blocklog;
1808
1809 cur->bc_ops = &xfs_bmbt_ops;
Christoph Hellwige99ab902008-10-30 16:54:33 +11001810 cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE;
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001811
1812 cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
1813 cur->bc_private.b.ip = ip;
1814 cur->bc_private.b.firstblock = NULLFSBLOCK;
1815 cur->bc_private.b.flist = NULL;
1816 cur->bc_private.b.allocated = 0;
1817 cur->bc_private.b.flags = 0;
1818 cur->bc_private.b.whichfork = whichfork;
1819
1820 return cur;
1821}