blob: 60f5db5d6dfa1d32877fd17453dbef4efca95498 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2001,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"
Nathan Scotta844f452005-11-02 14:38:42 +110027#include "xfs_dir2.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "xfs_btree.h"
38#include "xfs_ialloc.h"
39#include "xfs_alloc.h"
40#include "xfs_error.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042STATIC void xfs_inobt_log_block(xfs_trans_t *, xfs_buf_t *, int);
43STATIC void xfs_inobt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int);
44STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
45STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047STATIC int xfs_inobt_split(xfs_btree_cur_t *, int, xfs_agblock_t *,
48 xfs_inobt_key_t *, xfs_btree_cur_t **, int *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 * Single level of the xfs_inobt_delete record deletion routine.
52 * Delete record pointed to by cur/level.
53 * Remove the record from its block then rebalance the tree.
54 * Return 0 for error, 1 for done, 2 to go on to the next level.
55 */
56STATIC int /* error */
57xfs_inobt_delrec(
58 xfs_btree_cur_t *cur, /* btree cursor */
59 int level, /* level removing record from */
60 int *stat) /* fail/done/go-on */
61{
62 xfs_buf_t *agbp; /* buffer for a.g. inode header */
63 xfs_mount_t *mp; /* mount structure */
64 xfs_agi_t *agi; /* allocation group inode header */
65 xfs_inobt_block_t *block; /* btree block record/key lives in */
66 xfs_agblock_t bno; /* btree block number */
67 xfs_buf_t *bp; /* buffer for block */
68 int error; /* error return value */
69 int i; /* loop index */
70 xfs_inobt_key_t key; /* kp points here if block is level 0 */
71 xfs_inobt_key_t *kp = NULL; /* pointer to btree keys */
72 xfs_agblock_t lbno; /* left block's block number */
73 xfs_buf_t *lbp; /* left block's buffer pointer */
74 xfs_inobt_block_t *left; /* left btree block */
75 xfs_inobt_key_t *lkp; /* left block key pointer */
76 xfs_inobt_ptr_t *lpp; /* left block address pointer */
77 int lrecs = 0; /* number of records in left block */
78 xfs_inobt_rec_t *lrp; /* left block record pointer */
79 xfs_inobt_ptr_t *pp = NULL; /* pointer to btree addresses */
80 int ptr; /* index in btree block for this rec */
81 xfs_agblock_t rbno; /* right block's block number */
82 xfs_buf_t *rbp; /* right block's buffer pointer */
83 xfs_inobt_block_t *right; /* right btree block */
84 xfs_inobt_key_t *rkp; /* right block key pointer */
85 xfs_inobt_rec_t *rp; /* pointer to btree records */
86 xfs_inobt_ptr_t *rpp; /* right block address pointer */
87 int rrecs = 0; /* number of records in right block */
88 int numrecs;
89 xfs_inobt_rec_t *rrp; /* right block record pointer */
90 xfs_btree_cur_t *tcur; /* temporary btree cursor */
91
92 mp = cur->bc_mp;
93
94 /*
95 * Get the index of the entry being deleted, check for nothing there.
96 */
97 ptr = cur->bc_ptrs[level];
98 if (ptr == 0) {
99 *stat = 0;
100 return 0;
101 }
102
103 /*
104 * Get the buffer & block containing the record or key/ptr.
105 */
106 bp = cur->bc_bufs[level];
107 block = XFS_BUF_TO_INOBT_BLOCK(bp);
108#ifdef DEBUG
109 if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
110 return error;
111#endif
112 /*
113 * Fail if we're off the end of the block.
114 */
115
Christoph Hellwig16259e72005-11-02 15:11:25 +1100116 numrecs = be16_to_cpu(block->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 if (ptr > numrecs) {
118 *stat = 0;
119 return 0;
120 }
121 /*
122 * It's a nonleaf. Excise the key and ptr being deleted, by
123 * sliding the entries past them down one.
124 * Log the changed areas of the block.
125 */
126 if (level > 0) {
127 kp = XFS_INOBT_KEY_ADDR(block, 1, cur);
128 pp = XFS_INOBT_PTR_ADDR(block, 1, cur);
129#ifdef DEBUG
130 for (i = ptr; i < numrecs; i++) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100131 if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i]), level)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 return error;
133 }
134#endif
135 if (ptr < numrecs) {
136 memmove(&kp[ptr - 1], &kp[ptr],
137 (numrecs - ptr) * sizeof(*kp));
138 memmove(&pp[ptr - 1], &pp[ptr],
139 (numrecs - ptr) * sizeof(*kp));
140 xfs_inobt_log_keys(cur, bp, ptr, numrecs - 1);
141 xfs_inobt_log_ptrs(cur, bp, ptr, numrecs - 1);
142 }
143 }
144 /*
145 * It's a leaf. Excise the record being deleted, by sliding the
146 * entries past it down one. Log the changed areas of the block.
147 */
148 else {
149 rp = XFS_INOBT_REC_ADDR(block, 1, cur);
150 if (ptr < numrecs) {
151 memmove(&rp[ptr - 1], &rp[ptr],
152 (numrecs - ptr) * sizeof(*rp));
153 xfs_inobt_log_recs(cur, bp, ptr, numrecs - 1);
154 }
155 /*
156 * If it's the first record in the block, we'll need a key
157 * structure to pass up to the next level (updkey).
158 */
159 if (ptr == 1) {
160 key.ir_startino = rp->ir_startino;
161 kp = &key;
162 }
163 }
164 /*
165 * Decrement and log the number of entries in the block.
166 */
167 numrecs--;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100168 block->bb_numrecs = cpu_to_be16(numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
170 /*
171 * Is this the root level? If so, we're almost done.
172 */
173 if (level == cur->bc_nlevels - 1) {
174 /*
175 * If this is the root level,
176 * and there's only one entry left,
177 * and it's NOT the leaf level,
178 * then we can get rid of this level.
179 */
180 if (numrecs == 1 && level > 0) {
Christoph Hellwig169d6222008-08-13 16:25:27 +1000181 agbp = cur->bc_private.a.agbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 agi = XFS_BUF_TO_AGI(agbp);
183 /*
184 * pp is still set to the first pointer in the block.
185 * Make it the new root of the btree.
186 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100187 bno = be32_to_cpu(agi->agi_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 agi->agi_root = *pp;
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800189 be32_add_cpu(&agi->agi_level, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 /*
191 * Free the block.
192 */
193 if ((error = xfs_free_extent(cur->bc_tp,
Christoph Hellwig169d6222008-08-13 16:25:27 +1000194 XFS_AGB_TO_FSB(mp, cur->bc_private.a.agno, bno), 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 return error;
196 xfs_trans_binval(cur->bc_tp, bp);
197 xfs_ialloc_log_agi(cur->bc_tp, agbp,
198 XFS_AGI_ROOT | XFS_AGI_LEVEL);
199 /*
200 * Update the cursor so there's one fewer level.
201 */
202 cur->bc_bufs[level] = NULL;
203 cur->bc_nlevels--;
204 } else if (level > 0 &&
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100205 (error = xfs_btree_decrement(cur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return error;
207 *stat = 1;
208 return 0;
209 }
210 /*
211 * If we deleted the leftmost entry in the block, update the
212 * key values above us in the tree.
213 */
Christoph Hellwig38bb7422008-10-30 16:56:22 +1100214 if (ptr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)kp, level + 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 return error;
216 /*
217 * If the number of records remaining in the block is at least
218 * the minimum, we're done.
219 */
220 if (numrecs >= XFS_INOBT_BLOCK_MINRECS(level, cur)) {
221 if (level > 0 &&
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100222 (error = xfs_btree_decrement(cur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 return error;
224 *stat = 1;
225 return 0;
226 }
227 /*
228 * Otherwise, we have to move some records around to keep the
229 * tree balanced. Look at the left and right sibling blocks to
230 * see if we can re-balance by moving only one record.
231 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100232 rbno = be32_to_cpu(block->bb_rightsib);
233 lbno = be32_to_cpu(block->bb_leftsib);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 bno = NULLAGBLOCK;
235 ASSERT(rbno != NULLAGBLOCK || lbno != NULLAGBLOCK);
236 /*
237 * Duplicate the cursor so our btree manipulations here won't
238 * disrupt the next level up.
239 */
240 if ((error = xfs_btree_dup_cursor(cur, &tcur)))
241 return error;
242 /*
243 * If there's a right sibling, see if it's ok to shift an entry
244 * out of it.
245 */
246 if (rbno != NULLAGBLOCK) {
247 /*
248 * Move the temp cursor to the last entry in the next block.
249 * Actually any entry but the first would suffice.
250 */
251 i = xfs_btree_lastrec(tcur, level);
252 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
Christoph Hellwig637aa502008-10-30 16:55:45 +1100253 if ((error = xfs_btree_increment(tcur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 goto error0;
255 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
256 i = xfs_btree_lastrec(tcur, level);
257 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
258 /*
259 * Grab a pointer to the block.
260 */
261 rbp = tcur->bc_bufs[level];
262 right = XFS_BUF_TO_INOBT_BLOCK(rbp);
263#ifdef DEBUG
264 if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
265 goto error0;
266#endif
267 /*
268 * Grab the current block number, for future use.
269 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100270 bno = be32_to_cpu(right->bb_leftsib);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /*
272 * If right block is full enough so that removing one entry
273 * won't make it too empty, and left-shifting an entry out
274 * of right to us works, we're done.
275 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100276 if (be16_to_cpu(right->bb_numrecs) - 1 >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 XFS_INOBT_BLOCK_MINRECS(level, cur)) {
Christoph Hellwig687b8902008-10-30 16:56:53 +1100278 if ((error = xfs_btree_lshift(tcur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 goto error0;
280 if (i) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100281 ASSERT(be16_to_cpu(block->bb_numrecs) >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 XFS_INOBT_BLOCK_MINRECS(level, cur));
283 xfs_btree_del_cursor(tcur,
284 XFS_BTREE_NOERROR);
285 if (level > 0 &&
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100286 (error = xfs_btree_decrement(cur, level,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 &i)))
288 return error;
289 *stat = 1;
290 return 0;
291 }
292 }
293 /*
294 * Otherwise, grab the number of records in right for
295 * future reference, and fix up the temp cursor to point
296 * to our block again (last record).
297 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100298 rrecs = be16_to_cpu(right->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 if (lbno != NULLAGBLOCK) {
300 xfs_btree_firstrec(tcur, level);
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100301 if ((error = xfs_btree_decrement(tcur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 goto error0;
303 }
304 }
305 /*
306 * If there's a left sibling, see if it's ok to shift an entry
307 * out of it.
308 */
309 if (lbno != NULLAGBLOCK) {
310 /*
311 * Move the temp cursor to the first entry in the
312 * previous block.
313 */
314 xfs_btree_firstrec(tcur, level);
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100315 if ((error = xfs_btree_decrement(tcur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 goto error0;
317 xfs_btree_firstrec(tcur, level);
318 /*
319 * Grab a pointer to the block.
320 */
321 lbp = tcur->bc_bufs[level];
322 left = XFS_BUF_TO_INOBT_BLOCK(lbp);
323#ifdef DEBUG
324 if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
325 goto error0;
326#endif
327 /*
328 * Grab the current block number, for future use.
329 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100330 bno = be32_to_cpu(left->bb_rightsib);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 /*
332 * If left block is full enough so that removing one entry
333 * won't make it too empty, and right-shifting an entry out
334 * of left to us works, we're done.
335 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100336 if (be16_to_cpu(left->bb_numrecs) - 1 >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 XFS_INOBT_BLOCK_MINRECS(level, cur)) {
Christoph Hellwig9eaead52008-10-30 16:56:43 +1100338 if ((error = xfs_btree_rshift(tcur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 goto error0;
340 if (i) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100341 ASSERT(be16_to_cpu(block->bb_numrecs) >=
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 XFS_INOBT_BLOCK_MINRECS(level, cur));
343 xfs_btree_del_cursor(tcur,
344 XFS_BTREE_NOERROR);
345 if (level == 0)
346 cur->bc_ptrs[0]++;
347 *stat = 1;
348 return 0;
349 }
350 }
351 /*
352 * Otherwise, grab the number of records in right for
353 * future reference.
354 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100355 lrecs = be16_to_cpu(left->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357 /*
358 * Delete the temp cursor, we're done with it.
359 */
360 xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
361 /*
362 * If here, we need to do a join to keep the tree balanced.
363 */
364 ASSERT(bno != NULLAGBLOCK);
365 /*
366 * See if we can join with the left neighbor block.
367 */
368 if (lbno != NULLAGBLOCK &&
369 lrecs + numrecs <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
370 /*
371 * Set "right" to be the starting block,
372 * "left" to be the left neighbor.
373 */
374 rbno = bno;
375 right = block;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100376 rrecs = be16_to_cpu(right->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 rbp = bp;
378 if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
Christoph Hellwig169d6222008-08-13 16:25:27 +1000379 cur->bc_private.a.agno, lbno, 0, &lbp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 XFS_INO_BTREE_REF)))
381 return error;
382 left = XFS_BUF_TO_INOBT_BLOCK(lbp);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100383 lrecs = be16_to_cpu(left->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
385 return error;
386 }
387 /*
388 * If that won't work, see if we can join with the right neighbor block.
389 */
390 else if (rbno != NULLAGBLOCK &&
391 rrecs + numrecs <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
392 /*
393 * Set "left" to be the starting block,
394 * "right" to be the right neighbor.
395 */
396 lbno = bno;
397 left = block;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100398 lrecs = be16_to_cpu(left->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 lbp = bp;
400 if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
Christoph Hellwig169d6222008-08-13 16:25:27 +1000401 cur->bc_private.a.agno, rbno, 0, &rbp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 XFS_INO_BTREE_REF)))
403 return error;
404 right = XFS_BUF_TO_INOBT_BLOCK(rbp);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100405 rrecs = be16_to_cpu(right->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
407 return error;
408 }
409 /*
410 * Otherwise, we can't fix the imbalance.
411 * Just return. This is probably a logic error, but it's not fatal.
412 */
413 else {
Christoph Hellwig8df4da42008-10-30 16:55:58 +1100414 if (level > 0 && (error = xfs_btree_decrement(cur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return error;
416 *stat = 1;
417 return 0;
418 }
419 /*
420 * We're now going to join "left" and "right" by moving all the stuff
421 * in "right" to "left" and deleting "right".
422 */
423 if (level > 0) {
424 /*
425 * It's a non-leaf. Move keys and pointers.
426 */
427 lkp = XFS_INOBT_KEY_ADDR(left, lrecs + 1, cur);
428 lpp = XFS_INOBT_PTR_ADDR(left, lrecs + 1, cur);
429 rkp = XFS_INOBT_KEY_ADDR(right, 1, cur);
430 rpp = XFS_INOBT_PTR_ADDR(right, 1, cur);
431#ifdef DEBUG
432 for (i = 0; i < rrecs; i++) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100433 if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i]), level)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return error;
435 }
436#endif
437 memcpy(lkp, rkp, rrecs * sizeof(*lkp));
438 memcpy(lpp, rpp, rrecs * sizeof(*lpp));
439 xfs_inobt_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs);
440 xfs_inobt_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs);
441 } else {
442 /*
443 * It's a leaf. Move records.
444 */
445 lrp = XFS_INOBT_REC_ADDR(left, lrecs + 1, cur);
446 rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
447 memcpy(lrp, rrp, rrecs * sizeof(*lrp));
448 xfs_inobt_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs);
449 }
450 /*
451 * If we joined with the left neighbor, set the buffer in the
452 * cursor to the left block, and fix up the index.
453 */
454 if (bp != lbp) {
455 xfs_btree_setbuf(cur, level, lbp);
456 cur->bc_ptrs[level] += lrecs;
457 }
458 /*
459 * If we joined with the right neighbor and there's a level above
460 * us, increment the cursor at that level.
461 */
462 else if (level + 1 < cur->bc_nlevels &&
Christoph Hellwig637aa502008-10-30 16:55:45 +1100463 (error = xfs_btree_increment(cur, level + 1, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 return error;
465 /*
466 * Fix up the number of records in the surviving block.
467 */
468 lrecs += rrecs;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100469 left->bb_numrecs = cpu_to_be16(lrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 /*
471 * Fix up the right block pointer in the surviving block, and log it.
472 */
473 left->bb_rightsib = right->bb_rightsib;
474 xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);
475 /*
476 * If there is a right sibling now, make it point to the
477 * remaining block.
478 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100479 if (be32_to_cpu(left->bb_rightsib) != NULLAGBLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 xfs_inobt_block_t *rrblock;
481 xfs_buf_t *rrbp;
482
483 if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
Christoph Hellwig169d6222008-08-13 16:25:27 +1000484 cur->bc_private.a.agno, be32_to_cpu(left->bb_rightsib), 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 &rrbp, XFS_INO_BTREE_REF)))
486 return error;
487 rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp);
488 if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)))
489 return error;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100490 rrblock->bb_leftsib = cpu_to_be32(lbno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 xfs_inobt_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB);
492 }
493 /*
494 * Free the deleting block.
495 */
496 if ((error = xfs_free_extent(cur->bc_tp, XFS_AGB_TO_FSB(mp,
Christoph Hellwig169d6222008-08-13 16:25:27 +1000497 cur->bc_private.a.agno, rbno), 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return error;
499 xfs_trans_binval(cur->bc_tp, rbp);
500 /*
501 * Readjust the ptr at this level if it's not a leaf, since it's
502 * still pointing at the deletion point, which makes the cursor
503 * inconsistent. If this makes the ptr 0, the caller fixes it up.
504 * We can't use decrement because it would change the next level up.
505 */
506 if (level > 0)
507 cur->bc_ptrs[level]--;
508 /*
509 * Return value means the next level up has something to do.
510 */
511 *stat = 2;
512 return 0;
513
514error0:
515 xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
516 return error;
517}
518
519/*
520 * Insert one record/level. Return information to the caller
521 * allowing the next level up to proceed if necessary.
522 */
523STATIC int /* error */
524xfs_inobt_insrec(
525 xfs_btree_cur_t *cur, /* btree cursor */
526 int level, /* level to insert record at */
527 xfs_agblock_t *bnop, /* i/o: block number inserted */
528 xfs_inobt_rec_t *recp, /* i/o: record data inserted */
529 xfs_btree_cur_t **curp, /* output: new cursor replacing cur */
530 int *stat) /* success/failure */
531{
532 xfs_inobt_block_t *block; /* btree block record/key lives in */
533 xfs_buf_t *bp; /* buffer for block */
534 int error; /* error return value */
535 int i; /* loop index */
536 xfs_inobt_key_t key; /* key value being inserted */
537 xfs_inobt_key_t *kp=NULL; /* pointer to btree keys */
538 xfs_agblock_t nbno; /* block number of allocated block */
539 xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */
540 xfs_inobt_key_t nkey; /* new key value, from split */
541 xfs_inobt_rec_t nrec; /* new record value, for caller */
542 int numrecs;
543 int optr; /* old ptr value */
544 xfs_inobt_ptr_t *pp; /* pointer to btree addresses */
545 int ptr; /* index in btree block for this rec */
546 xfs_inobt_rec_t *rp=NULL; /* pointer to btree records */
547
548 /*
Christoph Hellwig5bde1ba2005-11-02 15:06:18 +1100549 * GCC doesn't understand the (arguably complex) control flow in
550 * this function and complains about uninitialized structure fields
551 * without this.
552 */
553 memset(&nrec, 0, sizeof(nrec));
554
555 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 * If we made it to the root level, allocate a new root block
557 * and we're done.
558 */
559 if (level >= cur->bc_nlevels) {
560 error = xfs_inobt_newroot(cur, &i);
561 *bnop = NULLAGBLOCK;
562 *stat = i;
563 return error;
564 }
565 /*
566 * Make a key out of the record data to be inserted, and save it.
567 */
Christoph Hellwig61a25842006-09-28 10:57:04 +1000568 key.ir_startino = recp->ir_startino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 optr = ptr = cur->bc_ptrs[level];
570 /*
571 * If we're off the left edge, return failure.
572 */
573 if (ptr == 0) {
574 *stat = 0;
575 return 0;
576 }
577 /*
578 * Get pointers to the btree buffer and block.
579 */
580 bp = cur->bc_bufs[level];
581 block = XFS_BUF_TO_INOBT_BLOCK(bp);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100582 numrecs = be16_to_cpu(block->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583#ifdef DEBUG
584 if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
585 return error;
586 /*
587 * Check that the new entry is being inserted in the right place.
588 */
589 if (ptr <= numrecs) {
590 if (level == 0) {
591 rp = XFS_INOBT_REC_ADDR(block, ptr, cur);
592 xfs_btree_check_rec(cur->bc_btnum, recp, rp);
593 } else {
594 kp = XFS_INOBT_KEY_ADDR(block, ptr, cur);
595 xfs_btree_check_key(cur->bc_btnum, &key, kp);
596 }
597 }
598#endif
599 nbno = NULLAGBLOCK;
Nathan Scott1121b212006-09-28 10:58:40 +1000600 ncur = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 /*
602 * If the block is full, we can't insert the new entry until we
603 * make the block un-full.
604 */
605 if (numrecs == XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
606 /*
607 * First, try shifting an entry to the right neighbor.
608 */
Christoph Hellwig9eaead52008-10-30 16:56:43 +1100609 if ((error = xfs_btree_rshift(cur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 return error;
611 if (i) {
612 /* nothing */
613 }
614 /*
615 * Next, try shifting an entry to the left neighbor.
616 */
617 else {
Christoph Hellwig687b8902008-10-30 16:56:53 +1100618 if ((error = xfs_btree_lshift(cur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return error;
620 if (i) {
621 optr = ptr = cur->bc_ptrs[level];
622 } else {
623 /*
624 * Next, try splitting the current block
625 * in half. If this works we have to
626 * re-set our variables because
627 * we could be in a different block now.
628 */
629 if ((error = xfs_inobt_split(cur, level, &nbno,
630 &nkey, &ncur, &i)))
631 return error;
632 if (i) {
633 bp = cur->bc_bufs[level];
634 block = XFS_BUF_TO_INOBT_BLOCK(bp);
635#ifdef DEBUG
636 if ((error = xfs_btree_check_sblock(cur,
637 block, level, bp)))
638 return error;
639#endif
640 ptr = cur->bc_ptrs[level];
Christoph Hellwig61a25842006-09-28 10:57:04 +1000641 nrec.ir_startino = nkey.ir_startino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 } else {
643 /*
644 * Otherwise the insert fails.
645 */
646 *stat = 0;
647 return 0;
648 }
649 }
650 }
651 }
652 /*
653 * At this point we know there's room for our new entry in the block
654 * we're pointing at.
655 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100656 numrecs = be16_to_cpu(block->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (level > 0) {
658 /*
659 * It's a non-leaf entry. Make a hole for the new data
660 * in the key and ptr regions of the block.
661 */
662 kp = XFS_INOBT_KEY_ADDR(block, 1, cur);
663 pp = XFS_INOBT_PTR_ADDR(block, 1, cur);
664#ifdef DEBUG
665 for (i = numrecs; i >= ptr; i--) {
Christoph Hellwig16259e72005-11-02 15:11:25 +1100666 if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return error;
668 }
669#endif
670 memmove(&kp[ptr], &kp[ptr - 1],
671 (numrecs - ptr + 1) * sizeof(*kp));
672 memmove(&pp[ptr], &pp[ptr - 1],
673 (numrecs - ptr + 1) * sizeof(*pp));
674 /*
675 * Now stuff the new data in, bump numrecs and log the new data.
676 */
677#ifdef DEBUG
678 if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
679 return error;
680#endif
Christoph Hellwigc38e5e82006-09-28 10:57:17 +1000681 kp[ptr - 1] = key;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100682 pp[ptr - 1] = cpu_to_be32(*bnop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 numrecs++;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100684 block->bb_numrecs = cpu_to_be16(numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 xfs_inobt_log_keys(cur, bp, ptr, numrecs);
686 xfs_inobt_log_ptrs(cur, bp, ptr, numrecs);
687 } else {
688 /*
689 * It's a leaf entry. Make a hole for the new record.
690 */
691 rp = XFS_INOBT_REC_ADDR(block, 1, cur);
692 memmove(&rp[ptr], &rp[ptr - 1],
693 (numrecs - ptr + 1) * sizeof(*rp));
694 /*
695 * Now stuff the new record in, bump numrecs
696 * and log the new data.
697 */
Christoph Hellwigc38e5e82006-09-28 10:57:17 +1000698 rp[ptr - 1] = *recp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 numrecs++;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100700 block->bb_numrecs = cpu_to_be16(numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 xfs_inobt_log_recs(cur, bp, ptr, numrecs);
702 }
703 /*
704 * Log the new number of records in the btree header.
705 */
706 xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
707#ifdef DEBUG
708 /*
709 * Check that the key/record is in the right place, now.
710 */
711 if (ptr < numrecs) {
712 if (level == 0)
713 xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,
714 rp + ptr);
715 else
716 xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,
717 kp + ptr);
718 }
719#endif
720 /*
721 * If we inserted at the start of a block, update the parents' keys.
722 */
Christoph Hellwig38bb7422008-10-30 16:56:22 +1100723 if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return error;
725 /*
726 * Return the new block number, if any.
727 * If there is one, give back a record value and a cursor too.
728 */
729 *bnop = nbno;
730 if (nbno != NULLAGBLOCK) {
Christoph Hellwigc38e5e82006-09-28 10:57:17 +1000731 *recp = nrec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 *curp = ncur;
733 }
734 *stat = 1;
735 return 0;
736}
737
738/*
739 * Log header fields from a btree block.
740 */
741STATIC void
742xfs_inobt_log_block(
743 xfs_trans_t *tp, /* transaction pointer */
744 xfs_buf_t *bp, /* buffer containing btree block */
745 int fields) /* mask of fields: XFS_BB_... */
746{
747 int first; /* first byte offset logged */
748 int last; /* last byte offset logged */
749 static const short offsets[] = { /* table of offsets */
750 offsetof(xfs_inobt_block_t, bb_magic),
751 offsetof(xfs_inobt_block_t, bb_level),
752 offsetof(xfs_inobt_block_t, bb_numrecs),
753 offsetof(xfs_inobt_block_t, bb_leftsib),
754 offsetof(xfs_inobt_block_t, bb_rightsib),
755 sizeof(xfs_inobt_block_t)
756 };
757
758 xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last);
759 xfs_trans_log_buf(tp, bp, first, last);
760}
761
762/*
763 * Log keys from a btree block (nonleaf).
764 */
765STATIC void
766xfs_inobt_log_keys(
767 xfs_btree_cur_t *cur, /* btree cursor */
768 xfs_buf_t *bp, /* buffer containing btree block */
769 int kfirst, /* index of first key to log */
770 int klast) /* index of last key to log */
771{
772 xfs_inobt_block_t *block; /* btree block to log from */
773 int first; /* first byte offset logged */
774 xfs_inobt_key_t *kp; /* key pointer in btree block */
775 int last; /* last byte offset logged */
776
777 block = XFS_BUF_TO_INOBT_BLOCK(bp);
778 kp = XFS_INOBT_KEY_ADDR(block, 1, cur);
779 first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block);
780 last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block);
781 xfs_trans_log_buf(cur->bc_tp, bp, first, last);
782}
783
784/*
785 * Log block pointer fields from a btree block (nonleaf).
786 */
787STATIC void
788xfs_inobt_log_ptrs(
789 xfs_btree_cur_t *cur, /* btree cursor */
790 xfs_buf_t *bp, /* buffer containing btree block */
791 int pfirst, /* index of first pointer to log */
792 int plast) /* index of last pointer to log */
793{
794 xfs_inobt_block_t *block; /* btree block to log from */
795 int first; /* first byte offset logged */
796 int last; /* last byte offset logged */
797 xfs_inobt_ptr_t *pp; /* block-pointer pointer in btree blk */
798
799 block = XFS_BUF_TO_INOBT_BLOCK(bp);
800 pp = XFS_INOBT_PTR_ADDR(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(cur->bc_tp, bp, first, last);
804}
805
806/*
807 * Log records from a btree block (leaf).
808 */
809STATIC void
810xfs_inobt_log_recs(
811 xfs_btree_cur_t *cur, /* btree cursor */
812 xfs_buf_t *bp, /* buffer containing btree block */
813 int rfirst, /* index of first record to log */
814 int rlast) /* index of last record to log */
815{
816 xfs_inobt_block_t *block; /* btree block to log from */
817 int first; /* first byte offset logged */
818 int last; /* last byte offset logged */
819 xfs_inobt_rec_t *rp; /* record pointer for btree block */
820
821 block = XFS_BUF_TO_INOBT_BLOCK(bp);
822 rp = XFS_INOBT_REC_ADDR(block, 1, cur);
823 first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block);
824 last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block);
825 xfs_trans_log_buf(cur->bc_tp, bp, first, last);
826}
827
828/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Allocate a new root block, fill it in.
830 */
831STATIC int /* error */
832xfs_inobt_newroot(
833 xfs_btree_cur_t *cur, /* btree cursor */
834 int *stat) /* success/failure */
835{
836 xfs_agi_t *agi; /* a.g. inode header */
837 xfs_alloc_arg_t args; /* allocation argument structure */
838 xfs_inobt_block_t *block; /* one half of the old root block */
839 xfs_buf_t *bp; /* buffer containing block */
840 int error; /* error return value */
841 xfs_inobt_key_t *kp; /* btree key pointer */
842 xfs_agblock_t lbno; /* left block number */
843 xfs_buf_t *lbp; /* left buffer pointer */
844 xfs_inobt_block_t *left; /* left btree block */
845 xfs_buf_t *nbp; /* new (root) buffer */
846 xfs_inobt_block_t *new; /* new (root) btree block */
847 int nptr; /* new value for key index, 1 or 2 */
848 xfs_inobt_ptr_t *pp; /* btree address pointer */
849 xfs_agblock_t rbno; /* right block number */
850 xfs_buf_t *rbp; /* right buffer pointer */
851 xfs_inobt_block_t *right; /* right btree block */
852 xfs_inobt_rec_t *rp; /* btree record pointer */
853
854 ASSERT(cur->bc_nlevels < XFS_IN_MAXLEVELS(cur->bc_mp));
855
856 /*
857 * Get a block & a buffer.
858 */
Christoph Hellwig169d6222008-08-13 16:25:27 +1000859 agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 args.tp = cur->bc_tp;
861 args.mp = cur->bc_mp;
Christoph Hellwig169d6222008-08-13 16:25:27 +1000862 args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno,
Christoph Hellwig16259e72005-11-02 15:11:25 +1100863 be32_to_cpu(agi->agi_root));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 args.mod = args.minleft = args.alignment = args.total = args.wasdel =
865 args.isfl = args.userdata = args.minalignslop = 0;
866 args.minlen = args.maxlen = args.prod = 1;
867 args.type = XFS_ALLOCTYPE_NEAR_BNO;
868 if ((error = xfs_alloc_vextent(&args)))
869 return error;
870 /*
871 * None available, we fail.
872 */
873 if (args.fsbno == NULLFSBLOCK) {
874 *stat = 0;
875 return 0;
876 }
877 ASSERT(args.len == 1);
878 nbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0);
879 new = XFS_BUF_TO_INOBT_BLOCK(nbp);
880 /*
881 * Set the root data in the a.g. inode structure.
882 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100883 agi->agi_root = cpu_to_be32(args.agbno);
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800884 be32_add_cpu(&agi->agi_level, 1);
Christoph Hellwig169d6222008-08-13 16:25:27 +1000885 xfs_ialloc_log_agi(args.tp, cur->bc_private.a.agbp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 XFS_AGI_ROOT | XFS_AGI_LEVEL);
887 /*
888 * At the previous root level there are now two blocks: the old
889 * root, and the new block generated when it was split.
890 * We don't know which one the cursor is pointing at, so we
891 * set up variables "left" and "right" for each case.
892 */
893 bp = cur->bc_bufs[cur->bc_nlevels - 1];
894 block = XFS_BUF_TO_INOBT_BLOCK(bp);
895#ifdef DEBUG
896 if ((error = xfs_btree_check_sblock(cur, block, cur->bc_nlevels - 1, bp)))
897 return error;
898#endif
Christoph Hellwig16259e72005-11-02 15:11:25 +1100899 if (be32_to_cpu(block->bb_rightsib) != NULLAGBLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /*
901 * Our block is left, pick up the right block.
902 */
903 lbp = bp;
904 lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp));
905 left = block;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100906 rbno = be32_to_cpu(left->bb_rightsib);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno,
908 rbno, 0, &rbp, XFS_INO_BTREE_REF)))
909 return error;
910 bp = rbp;
911 right = XFS_BUF_TO_INOBT_BLOCK(rbp);
912 if ((error = xfs_btree_check_sblock(cur, right,
913 cur->bc_nlevels - 1, rbp)))
914 return error;
915 nptr = 1;
916 } else {
917 /*
918 * Our block is right, pick up the left block.
919 */
920 rbp = bp;
921 rbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(rbp));
922 right = block;
Christoph Hellwig16259e72005-11-02 15:11:25 +1100923 lbno = be32_to_cpu(right->bb_leftsib);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno,
925 lbno, 0, &lbp, XFS_INO_BTREE_REF)))
926 return error;
927 bp = lbp;
928 left = XFS_BUF_TO_INOBT_BLOCK(lbp);
929 if ((error = xfs_btree_check_sblock(cur, left,
930 cur->bc_nlevels - 1, lbp)))
931 return error;
932 nptr = 2;
933 }
934 /*
935 * Fill in the new block's btree header and log it.
936 */
Christoph Hellwig16259e72005-11-02 15:11:25 +1100937 new->bb_magic = cpu_to_be32(xfs_magics[cur->bc_btnum]);
938 new->bb_level = cpu_to_be16(cur->bc_nlevels);
939 new->bb_numrecs = cpu_to_be16(2);
940 new->bb_leftsib = cpu_to_be32(NULLAGBLOCK);
941 new->bb_rightsib = cpu_to_be32(NULLAGBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 xfs_inobt_log_block(args.tp, nbp, XFS_BB_ALL_BITS);
943 ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK);
944 /*
945 * Fill in the key data in the new root.
946 */
947 kp = XFS_INOBT_KEY_ADDR(new, 1, cur);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100948 if (be16_to_cpu(left->bb_level) > 0) {
Christoph Hellwigc38e5e82006-09-28 10:57:17 +1000949 kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur);
950 kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 } else {
952 rp = XFS_INOBT_REC_ADDR(left, 1, cur);
Christoph Hellwig61a25842006-09-28 10:57:04 +1000953 kp[0].ir_startino = rp->ir_startino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 rp = XFS_INOBT_REC_ADDR(right, 1, cur);
Christoph Hellwig61a25842006-09-28 10:57:04 +1000955 kp[1].ir_startino = rp->ir_startino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 xfs_inobt_log_keys(cur, nbp, 1, 2);
958 /*
959 * Fill in the pointer data in the new root.
960 */
961 pp = XFS_INOBT_PTR_ADDR(new, 1, cur);
Christoph Hellwig16259e72005-11-02 15:11:25 +1100962 pp[0] = cpu_to_be32(lbno);
963 pp[1] = cpu_to_be32(rbno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 xfs_inobt_log_ptrs(cur, nbp, 1, 2);
965 /*
966 * Fix up the cursor.
967 */
968 xfs_btree_setbuf(cur, cur->bc_nlevels, nbp);
969 cur->bc_ptrs[cur->bc_nlevels] = nptr;
970 cur->bc_nlevels++;
971 *stat = 1;
972 return 0;
973}
974
975/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 * Split cur/level block in half.
977 * Return new block number and its first record (to be inserted into parent).
978 */
979STATIC int /* error */
980xfs_inobt_split(
981 xfs_btree_cur_t *cur, /* btree cursor */
982 int level, /* level to split */
983 xfs_agblock_t *bnop, /* output: block number allocated */
984 xfs_inobt_key_t *keyp, /* output: first key of new block */
985 xfs_btree_cur_t **curp, /* output: new cursor */
986 int *stat) /* success/failure */
987{
988 xfs_alloc_arg_t args; /* allocation argument structure */
989 int error; /* error return value */
990 int i; /* loop index/record number */
991 xfs_agblock_t lbno; /* left (current) block number */
992 xfs_buf_t *lbp; /* buffer for left block */
993 xfs_inobt_block_t *left; /* left (current) btree block */
994 xfs_inobt_key_t *lkp; /* left btree key pointer */
995 xfs_inobt_ptr_t *lpp; /* left btree address pointer */
996 xfs_inobt_rec_t *lrp; /* left btree record pointer */
997 xfs_buf_t *rbp; /* buffer for right block */
998 xfs_inobt_block_t *right; /* right (new) btree block */
999 xfs_inobt_key_t *rkp; /* right btree key pointer */
1000 xfs_inobt_ptr_t *rpp; /* right btree address pointer */
1001 xfs_inobt_rec_t *rrp; /* right btree record pointer */
1002
1003 /*
1004 * Set up left block (current one).
1005 */
1006 lbp = cur->bc_bufs[level];
1007 args.tp = cur->bc_tp;
1008 args.mp = cur->bc_mp;
1009 lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp));
1010 /*
1011 * Allocate the new block.
1012 * If we can't do it, we're toast. Give up.
1013 */
Christoph Hellwig169d6222008-08-13 16:25:27 +10001014 args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, lbno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 args.mod = args.minleft = args.alignment = args.total = args.wasdel =
1016 args.isfl = args.userdata = args.minalignslop = 0;
1017 args.minlen = args.maxlen = args.prod = 1;
1018 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1019 if ((error = xfs_alloc_vextent(&args)))
1020 return error;
1021 if (args.fsbno == NULLFSBLOCK) {
1022 *stat = 0;
1023 return 0;
1024 }
1025 ASSERT(args.len == 1);
1026 rbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0);
1027 /*
1028 * Set up the new block as "right".
1029 */
1030 right = XFS_BUF_TO_INOBT_BLOCK(rbp);
1031 /*
1032 * "Left" is the current (according to the cursor) block.
1033 */
1034 left = XFS_BUF_TO_INOBT_BLOCK(lbp);
1035#ifdef DEBUG
1036 if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
1037 return error;
1038#endif
1039 /*
1040 * Fill in the btree header for the new block.
1041 */
Christoph Hellwig16259e72005-11-02 15:11:25 +11001042 right->bb_magic = cpu_to_be32(xfs_magics[cur->bc_btnum]);
1043 right->bb_level = left->bb_level;
1044 right->bb_numrecs = cpu_to_be16(be16_to_cpu(left->bb_numrecs) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 /*
1046 * Make sure that if there's an odd number of entries now, that
1047 * each new block will have the same number of entries.
1048 */
Christoph Hellwig16259e72005-11-02 15:11:25 +11001049 if ((be16_to_cpu(left->bb_numrecs) & 1) &&
1050 cur->bc_ptrs[level] <= be16_to_cpu(right->bb_numrecs) + 1)
Marcin Slusarz413d57c2008-02-13 15:03:29 -08001051 be16_add_cpu(&right->bb_numrecs, 1);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001052 i = be16_to_cpu(left->bb_numrecs) - be16_to_cpu(right->bb_numrecs) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /*
1054 * For non-leaf blocks, copy keys and addresses over to the new block.
1055 */
1056 if (level > 0) {
1057 lkp = XFS_INOBT_KEY_ADDR(left, i, cur);
1058 lpp = XFS_INOBT_PTR_ADDR(left, i, cur);
1059 rkp = XFS_INOBT_KEY_ADDR(right, 1, cur);
1060 rpp = XFS_INOBT_PTR_ADDR(right, 1, cur);
1061#ifdef DEBUG
Christoph Hellwig16259e72005-11-02 15:11:25 +11001062 for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {
1063 if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(lpp[i]), level)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return error;
1065 }
1066#endif
Christoph Hellwig16259e72005-11-02 15:11:25 +11001067 memcpy(rkp, lkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp));
1068 memcpy(rpp, lpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
1069 xfs_inobt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
1070 xfs_inobt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 *keyp = *rkp;
1072 }
1073 /*
1074 * For leaf blocks, copy records over to the new block.
1075 */
1076 else {
1077 lrp = XFS_INOBT_REC_ADDR(left, i, cur);
1078 rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001079 memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
1080 xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
Christoph Hellwig61a25842006-09-28 10:57:04 +10001081 keyp->ir_startino = rrp->ir_startino;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083 /*
1084 * Find the left block number by looking in the buffer.
1085 * Adjust numrecs, sibling pointers.
1086 */
Marcin Slusarz413d57c2008-02-13 15:03:29 -08001087 be16_add_cpu(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs)));
Christoph Hellwig16259e72005-11-02 15:11:25 +11001088 right->bb_rightsib = left->bb_rightsib;
1089 left->bb_rightsib = cpu_to_be32(args.agbno);
1090 right->bb_leftsib = cpu_to_be32(lbno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 xfs_inobt_log_block(args.tp, rbp, XFS_BB_ALL_BITS);
1092 xfs_inobt_log_block(args.tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);
1093 /*
1094 * If there's a block to the new block's right, make that block
1095 * point back to right instead of to left.
1096 */
Christoph Hellwig16259e72005-11-02 15:11:25 +11001097 if (be32_to_cpu(right->bb_rightsib) != NULLAGBLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 xfs_inobt_block_t *rrblock; /* rr btree block */
1099 xfs_buf_t *rrbp; /* buffer for rrblock */
1100
1101 if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno,
Christoph Hellwig16259e72005-11-02 15:11:25 +11001102 be32_to_cpu(right->bb_rightsib), 0, &rrbp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 XFS_INO_BTREE_REF)))
1104 return error;
1105 rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp);
1106 if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)))
1107 return error;
Christoph Hellwig16259e72005-11-02 15:11:25 +11001108 rrblock->bb_leftsib = cpu_to_be32(args.agbno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 xfs_inobt_log_block(args.tp, rrbp, XFS_BB_LEFTSIB);
1110 }
1111 /*
1112 * If the cursor is really in the right block, move it there.
1113 * If it's just pointing past the last entry in left, then we'll
1114 * insert there, so don't change anything in that case.
1115 */
Christoph Hellwig16259e72005-11-02 15:11:25 +11001116 if (cur->bc_ptrs[level] > be16_to_cpu(left->bb_numrecs) + 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 xfs_btree_setbuf(cur, level, rbp);
Christoph Hellwig16259e72005-11-02 15:11:25 +11001118 cur->bc_ptrs[level] -= be16_to_cpu(left->bb_numrecs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
1120 /*
1121 * If there are more levels, we'll need another cursor which refers
1122 * the right block, no matter where this cursor was.
1123 */
1124 if (level + 1 < cur->bc_nlevels) {
1125 if ((error = xfs_btree_dup_cursor(cur, curp)))
1126 return error;
1127 (*curp)->bc_ptrs[level + 1]++;
1128 }
1129 *bnop = args.agbno;
1130 *stat = 1;
1131 return 0;
1132}
1133
1134/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 * Externally visible routines.
1136 */
1137
1138/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 * Delete the record pointed to by cur.
1140 * The cursor refers to the place where the record was (could be inserted)
1141 * when the operation returns.
1142 */
1143int /* error */
1144xfs_inobt_delete(
1145 xfs_btree_cur_t *cur, /* btree cursor */
1146 int *stat) /* success/failure */
1147{
1148 int error;
1149 int i; /* result code */
1150 int level; /* btree level */
1151
1152 /*
1153 * Go up the tree, starting at leaf level.
1154 * If 2 is returned then a join was done; go to the next level.
1155 * Otherwise we are done.
1156 */
1157 for (level = 0, i = 2; i == 2; level++) {
1158 if ((error = xfs_inobt_delrec(cur, level, &i)))
1159 return error;
1160 }
1161 if (i == 0) {
1162 for (level = 1; level < cur->bc_nlevels; level++) {
1163 if (cur->bc_ptrs[level] == 0) {
Christoph Hellwig8df4da42008-10-30 16:55:58 +11001164 if ((error = xfs_btree_decrement(cur, level, &i)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 return error;
1166 break;
1167 }
1168 }
1169 }
1170 *stat = i;
1171 return 0;
1172}
1173
1174
1175/*
1176 * Get the data from the pointed-to record.
1177 */
1178int /* error */
1179xfs_inobt_get_rec(
1180 xfs_btree_cur_t *cur, /* btree cursor */
1181 xfs_agino_t *ino, /* output: starting inode of chunk */
1182 __int32_t *fcnt, /* output: number of free inodes */
1183 xfs_inofree_t *free, /* output: free inode mask */
1184 int *stat) /* output: success/failure */
1185{
1186 xfs_inobt_block_t *block; /* btree block */
1187 xfs_buf_t *bp; /* buffer containing btree block */
1188#ifdef DEBUG
1189 int error; /* error return value */
1190#endif
1191 int ptr; /* record number */
1192 xfs_inobt_rec_t *rec; /* record data */
1193
1194 bp = cur->bc_bufs[0];
1195 ptr = cur->bc_ptrs[0];
1196 block = XFS_BUF_TO_INOBT_BLOCK(bp);
1197#ifdef DEBUG
1198 if ((error = xfs_btree_check_sblock(cur, block, 0, bp)))
1199 return error;
1200#endif
1201 /*
1202 * Off the right end or left end, return failure.
1203 */
Christoph Hellwig16259e72005-11-02 15:11:25 +11001204 if (ptr > be16_to_cpu(block->bb_numrecs) || ptr <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 *stat = 0;
1206 return 0;
1207 }
1208 /*
1209 * Point to the record and extract its data.
1210 */
1211 rec = XFS_INOBT_REC_ADDR(block, ptr, cur);
Christoph Hellwig61a25842006-09-28 10:57:04 +10001212 *ino = be32_to_cpu(rec->ir_startino);
1213 *fcnt = be32_to_cpu(rec->ir_freecount);
1214 *free = be64_to_cpu(rec->ir_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 *stat = 1;
1216 return 0;
1217}
1218
1219/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 * Insert the current record at the point referenced by cur.
1221 * The cursor may be inconsistent on return if splits have been done.
1222 */
1223int /* error */
1224xfs_inobt_insert(
1225 xfs_btree_cur_t *cur, /* btree cursor */
1226 int *stat) /* success/failure */
1227{
1228 int error; /* error return value */
1229 int i; /* result value, 0 for failure */
1230 int level; /* current level number in btree */
1231 xfs_agblock_t nbno; /* new block number (split result) */
1232 xfs_btree_cur_t *ncur; /* new cursor (split result) */
1233 xfs_inobt_rec_t nrec; /* record being inserted this level */
1234 xfs_btree_cur_t *pcur; /* previous level's cursor */
1235
1236 level = 0;
1237 nbno = NULLAGBLOCK;
Christoph Hellwig61a25842006-09-28 10:57:04 +10001238 nrec.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
1239 nrec.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
1240 nrec.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
Nathan Scott1121b212006-09-28 10:58:40 +10001241 ncur = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 pcur = cur;
1243 /*
1244 * Loop going up the tree, starting at the leaf level.
1245 * Stop when we don't get a split block, that must mean that
1246 * the insert is finished with this level.
1247 */
1248 do {
1249 /*
1250 * Insert nrec/nbno into this level of the tree.
1251 * Note if we fail, nbno will be null.
1252 */
1253 if ((error = xfs_inobt_insrec(pcur, level++, &nbno, &nrec, &ncur,
1254 &i))) {
1255 if (pcur != cur)
1256 xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
1257 return error;
1258 }
1259 /*
1260 * See if the cursor we just used is trash.
1261 * Can't trash the caller's cursor, but otherwise we should
1262 * if ncur is a new cursor or we're about to be done.
1263 */
1264 if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) {
1265 cur->bc_nlevels = pcur->bc_nlevels;
1266 xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
1267 }
1268 /*
1269 * If we got a new cursor, switch to it.
1270 */
1271 if (ncur) {
1272 pcur = ncur;
Nathan Scott1121b212006-09-28 10:58:40 +10001273 ncur = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 }
1275 } while (nbno != NULLAGBLOCK);
1276 *stat = i;
1277 return 0;
1278}
1279
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001280STATIC struct xfs_btree_cur *
1281xfs_inobt_dup_cursor(
1282 struct xfs_btree_cur *cur)
1283{
1284 return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
1285 cur->bc_private.a.agbp, cur->bc_private.a.agno);
1286}
1287
Christoph Hellwigce5e42d2008-10-30 16:55:23 +11001288STATIC int
1289xfs_inobt_get_maxrecs(
1290 struct xfs_btree_cur *cur,
1291 int level)
1292{
1293 return cur->bc_mp->m_inobt_mxr[level != 0];
1294}
1295
Christoph Hellwigfe033cc2008-10-30 16:56:09 +11001296STATIC void
1297xfs_inobt_init_key_from_rec(
1298 union xfs_btree_key *key,
1299 union xfs_btree_rec *rec)
1300{
1301 key->inobt.ir_startino = rec->inobt.ir_startino;
1302}
1303
1304/*
1305 * intial value of ptr for lookup
1306 */
1307STATIC void
1308xfs_inobt_init_ptr_from_cur(
1309 struct xfs_btree_cur *cur,
1310 union xfs_btree_ptr *ptr)
1311{
1312 struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
1313
1314 ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
1315
1316 ptr->s = agi->agi_root;
1317}
1318
1319STATIC __int64_t
1320xfs_inobt_key_diff(
1321 struct xfs_btree_cur *cur,
1322 union xfs_btree_key *key)
1323{
1324 return (__int64_t)be32_to_cpu(key->inobt.ir_startino) -
1325 cur->bc_rec.i.ir_startino;
1326}
1327
Christoph Hellwig8c4ed632008-10-30 16:55:13 +11001328#ifdef XFS_BTREE_TRACE
1329ktrace_t *xfs_inobt_trace_buf;
1330
1331STATIC void
1332xfs_inobt_trace_enter(
1333 struct xfs_btree_cur *cur,
1334 const char *func,
1335 char *s,
1336 int type,
1337 int line,
1338 __psunsigned_t a0,
1339 __psunsigned_t a1,
1340 __psunsigned_t a2,
1341 __psunsigned_t a3,
1342 __psunsigned_t a4,
1343 __psunsigned_t a5,
1344 __psunsigned_t a6,
1345 __psunsigned_t a7,
1346 __psunsigned_t a8,
1347 __psunsigned_t a9,
1348 __psunsigned_t a10)
1349{
1350 ktrace_enter(xfs_inobt_trace_buf, (void *)(__psint_t)type,
1351 (void *)func, (void *)s, NULL, (void *)cur,
1352 (void *)a0, (void *)a1, (void *)a2, (void *)a3,
1353 (void *)a4, (void *)a5, (void *)a6, (void *)a7,
1354 (void *)a8, (void *)a9, (void *)a10);
1355}
1356
1357STATIC void
1358xfs_inobt_trace_cursor(
1359 struct xfs_btree_cur *cur,
1360 __uint32_t *s0,
1361 __uint64_t *l0,
1362 __uint64_t *l1)
1363{
1364 *s0 = cur->bc_private.a.agno;
1365 *l0 = cur->bc_rec.i.ir_startino;
1366 *l1 = cur->bc_rec.i.ir_free;
1367}
1368
1369STATIC void
1370xfs_inobt_trace_key(
1371 struct xfs_btree_cur *cur,
1372 union xfs_btree_key *key,
1373 __uint64_t *l0,
1374 __uint64_t *l1)
1375{
1376 *l0 = be32_to_cpu(key->inobt.ir_startino);
1377 *l1 = 0;
1378}
1379
1380STATIC void
1381xfs_inobt_trace_record(
1382 struct xfs_btree_cur *cur,
1383 union xfs_btree_rec *rec,
1384 __uint64_t *l0,
1385 __uint64_t *l1,
1386 __uint64_t *l2)
1387{
1388 *l0 = be32_to_cpu(rec->inobt.ir_startino);
1389 *l1 = be32_to_cpu(rec->inobt.ir_freecount);
1390 *l2 = be64_to_cpu(rec->inobt.ir_free);
1391}
1392#endif /* XFS_BTREE_TRACE */
1393
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001394static const struct xfs_btree_ops xfs_inobt_ops = {
Christoph Hellwig65f1eae2008-10-30 16:55:34 +11001395 .rec_len = sizeof(xfs_inobt_rec_t),
1396 .key_len = sizeof(xfs_inobt_key_t),
1397
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001398 .dup_cursor = xfs_inobt_dup_cursor,
Christoph Hellwigce5e42d2008-10-30 16:55:23 +11001399 .get_maxrecs = xfs_inobt_get_maxrecs,
Christoph Hellwigfe033cc2008-10-30 16:56:09 +11001400 .init_key_from_rec = xfs_inobt_init_key_from_rec,
1401 .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur,
1402 .key_diff = xfs_inobt_key_diff,
Christoph Hellwig8c4ed632008-10-30 16:55:13 +11001403
1404#ifdef XFS_BTREE_TRACE
1405 .trace_enter = xfs_inobt_trace_enter,
1406 .trace_cursor = xfs_inobt_trace_cursor,
1407 .trace_key = xfs_inobt_trace_key,
1408 .trace_record = xfs_inobt_trace_record,
1409#endif
Christoph Hellwig561f7d12008-10-30 16:53:59 +11001410};
1411
1412/*
1413 * Allocate a new inode btree cursor.
1414 */
1415struct xfs_btree_cur * /* new inode btree cursor */
1416xfs_inobt_init_cursor(
1417 struct xfs_mount *mp, /* file system mount point */
1418 struct xfs_trans *tp, /* transaction pointer */
1419 struct xfs_buf *agbp, /* buffer for agi structure */
1420 xfs_agnumber_t agno) /* allocation group number */
1421{
1422 struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
1423 struct xfs_btree_cur *cur;
1424
1425 cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
1426
1427 cur->bc_tp = tp;
1428 cur->bc_mp = mp;
1429 cur->bc_nlevels = be32_to_cpu(agi->agi_level);
1430 cur->bc_btnum = XFS_BTNUM_INO;
1431 cur->bc_blocklog = mp->m_sb.sb_blocklog;
1432
1433 cur->bc_ops = &xfs_inobt_ops;
1434
1435 cur->bc_private.a.agbp = agbp;
1436 cur->bc_private.a.agno = agno;
1437
1438 return cur;
1439}