xfs_da_btree.c 70.8 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2
/*
3
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4
 * Copyright (c) 2013 Red Hat, Inc.
5
 * All Rights Reserved.
Linus Torvalds's avatar
Linus Torvalds committed
6 7
 */
#include "xfs.h"
8
#include "xfs_fs.h"
9
#include "xfs_shared.h"
10 11 12
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
13
#include "xfs_bit.h"
Linus Torvalds's avatar
Linus Torvalds committed
14
#include "xfs_mount.h"
15
#include "xfs_da_format.h"
16
#include "xfs_da_btree.h"
17
#include "xfs_dir2.h"
18
#include "xfs_dir2_priv.h"
Linus Torvalds's avatar
Linus Torvalds committed
19
#include "xfs_inode.h"
20
#include "xfs_trans.h"
21 22
#include "xfs_inode_item.h"
#include "xfs_alloc.h"
Linus Torvalds's avatar
Linus Torvalds committed
23 24 25 26
#include "xfs_bmap.h"
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
#include "xfs_error.h"
27
#include "xfs_trace.h"
28 29
#include "xfs_cksum.h"
#include "xfs_buf_item.h"
30
#include "xfs_log.h"
Linus Torvalds's avatar
Linus Torvalds committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44

/*
 * xfs_da_btree.c
 *
 * Routines to implement directories as Btrees of hashed names.
 */

/*========================================================================
 * Function prototypes for the kernel.
 *========================================================================*/

/*
 * Routines used for growing the Btree.
 */
45
STATIC int xfs_da3_root_split(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
46 47
					    xfs_da_state_blk_t *existing_root,
					    xfs_da_state_blk_t *new_child);
48
STATIC int xfs_da3_node_split(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
49 50 51 52 53
					    xfs_da_state_blk_t *existing_blk,
					    xfs_da_state_blk_t *split_blk,
					    xfs_da_state_blk_t *blk_to_add,
					    int treelevel,
					    int *result);
54
STATIC void xfs_da3_node_rebalance(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
55 56
					 xfs_da_state_blk_t *node_blk_1,
					 xfs_da_state_blk_t *node_blk_2);
57
STATIC void xfs_da3_node_add(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
58 59 60 61 62 63
				   xfs_da_state_blk_t *old_node_blk,
				   xfs_da_state_blk_t *new_node_blk);

/*
 * Routines used for shrinking the Btree.
 */
64
STATIC int xfs_da3_root_join(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
65
					   xfs_da_state_blk_t *root_blk);
66 67
STATIC int xfs_da3_node_toosmall(xfs_da_state_t *state, int *retval);
STATIC void xfs_da3_node_remove(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
68
					      xfs_da_state_blk_t *drop_blk);
69
STATIC void xfs_da3_node_unbalance(xfs_da_state_t *state,
Linus Torvalds's avatar
Linus Torvalds committed
70 71 72 73 74 75
					 xfs_da_state_blk_t *src_node_blk,
					 xfs_da_state_blk_t *dst_node_blk);

/*
 * Utility routines.
 */
76
STATIC int	xfs_da3_blk_unlink(xfs_da_state_t *state,
77 78
				  xfs_da_state_blk_t *drop_blk,
				  xfs_da_state_blk_t *save_blk);
Linus Torvalds's avatar
Linus Torvalds committed
79

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

kmem_zone_t *xfs_da_state_zone;	/* anchor for state struct zone */

/*
 * Allocate a dir-state structure.
 * We don't put them on the stack since they're large.
 */
xfs_da_state_t *
xfs_da_state_alloc(void)
{
	return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS);
}

/*
 * Kill the altpath contents of a da-state structure.
 */
STATIC void
xfs_da_state_kill_altpath(xfs_da_state_t *state)
{
	int	i;

	for (i = 0; i < state->altpath.active; i++)
		state->altpath.blk[i].bp = NULL;
	state->altpath.active = 0;
}

/*
 * Free a da-state structure.
 */
void
xfs_da_state_free(xfs_da_state_t *state)
{
	xfs_da_state_kill_altpath(state);
#ifdef DEBUG
	memset((char *)state, 0, sizeof(*state));
#endif /* DEBUG */
	kmem_zone_free(xfs_da_state_zone, state);
}

119
static xfs_failaddr_t
120
xfs_da3_node_verify(
121 122 123
	struct xfs_buf		*bp)
{
	struct xfs_mount	*mp = bp->b_target->bt_mount;
124 125
	struct xfs_da_intnode	*hdr = bp->b_addr;
	struct xfs_da3_icnode_hdr ichdr;
126 127 128
	const struct xfs_dir_ops *ops;

	ops = xfs_dir_get_ops(mp, NULL);
129

130
	ops->node_hdr_from_disk(&ichdr, hdr);
131 132 133 134 135

	if (xfs_sb_version_hascrc(&mp->m_sb)) {
		struct xfs_da3_node_hdr *hdr3 = bp->b_addr;

		if (ichdr.magic != XFS_DA3_NODE_MAGIC)
136
			return __this_address;
137

138
		if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid))
139
			return __this_address;
140
		if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
141
			return __this_address;
142
		if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
143
			return __this_address;
144 145
	} else {
		if (ichdr.magic != XFS_DA_NODE_MAGIC)
146
			return __this_address;
147
	}
148
	if (ichdr.level == 0)
149
		return __this_address;
150
	if (ichdr.level > XFS_DA_NODE_MAXDEPTH)
151
		return __this_address;
152
	if (ichdr.count == 0)
153
		return __this_address;
154 155 156 157 158

	/*
	 * we don't know if the node is for and attribute or directory tree,
	 * so only fail if the count is outside both bounds
	 */
159 160
	if (ichdr.count > mp->m_dir_geo->node_ents &&
	    ichdr.count > mp->m_attr_geo->node_ents)
161
		return __this_address;
162 163

	/* XXX: hash order check? */
164

165
	return NULL;
166 167 168
}

static void
169
xfs_da3_node_write_verify(
170 171
	struct xfs_buf	*bp)
{
172
	struct xfs_mount	*mp = bp->b_target->bt_mount;
173
	struct xfs_buf_log_item	*bip = bp->b_log_item;
174
	struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
175
	xfs_failaddr_t		fa;
176

177 178 179
	fa = xfs_da3_node_verify(bp);
	if (fa) {
		xfs_verifier_error(bp, -EFSCORRUPTED, fa);
180 181 182 183 184 185 186 187 188
		return;
	}

	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return;

	if (bip)
		hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn);

189
	xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF);
190 191
}

192 193 194 195 196 197
/*
 * leaf/node format detection on trees is sketchy, so a node read can be done on
 * leaf level blocks when detection identifies the tree as a node format tree
 * incorrectly. In this case, we need to swap the verifier to match the correct
 * format of the block being read.
 */
198
static void
199
xfs_da3_node_read_verify(
200 201 202
	struct xfs_buf		*bp)
{
	struct xfs_da_blkinfo	*info = bp->b_addr;
203
	xfs_failaddr_t		fa;
204 205

	switch (be16_to_cpu(info->magic)) {
206
		case XFS_DA3_NODE_MAGIC:
207
			if (!xfs_buf_verify_cksum(bp, XFS_DA3_NODE_CRC_OFF)) {
208 209
				xfs_verifier_error(bp, -EFSBADCRC,
						__this_address);
210
				break;
211
			}
212
			/* fall through */
213
		case XFS_DA_NODE_MAGIC:
214 215 216
			fa = xfs_da3_node_verify(bp);
			if (fa)
				xfs_verifier_error(bp, -EFSCORRUPTED, fa);
217
			return;
218
		case XFS_ATTR_LEAF_MAGIC:
219
		case XFS_ATTR3_LEAF_MAGIC:
220
			bp->b_ops = &xfs_attr3_leaf_buf_ops;
221
			bp->b_ops->verify_read(bp);
222 223
			return;
		case XFS_DIR2_LEAFN_MAGIC:
224 225
		case XFS_DIR3_LEAFN_MAGIC:
			bp->b_ops = &xfs_dir3_leafn_buf_ops;
226
			bp->b_ops->verify_read(bp);
227 228
			return;
		default:
229
			xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
230 231 232 233
			break;
	}
}

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/* Verify the structure of a da3 block. */
static xfs_failaddr_t
xfs_da3_node_verify_struct(
	struct xfs_buf		*bp)
{
	struct xfs_da_blkinfo	*info = bp->b_addr;

	switch (be16_to_cpu(info->magic)) {
	case XFS_DA3_NODE_MAGIC:
	case XFS_DA_NODE_MAGIC:
		return xfs_da3_node_verify(bp);
	case XFS_ATTR_LEAF_MAGIC:
	case XFS_ATTR3_LEAF_MAGIC:
		bp->b_ops = &xfs_attr3_leaf_buf_ops;
		return bp->b_ops->verify_struct(bp);
	case XFS_DIR2_LEAFN_MAGIC:
	case XFS_DIR3_LEAFN_MAGIC:
		bp->b_ops = &xfs_dir3_leafn_buf_ops;
		return bp->b_ops->verify_struct(bp);
	default:
		return __this_address;
	}
}

258
const struct xfs_buf_ops xfs_da3_node_buf_ops = {
259
	.name = "xfs_da3_node",
260 261
	.verify_read = xfs_da3_node_read_verify,
	.verify_write = xfs_da3_node_write_verify,
262
	.verify_struct = xfs_da3_node_verify_struct,
263 264
};

265
int
266
xfs_da3_node_read(
267 268 269 270 271 272 273
	struct xfs_trans	*tp,
	struct xfs_inode	*dp,
	xfs_dablk_t		bno,
	xfs_daddr_t		mappedbno,
	struct xfs_buf		**bpp,
	int			which_fork)
{
274 275 276
	int			err;

	err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
277
					which_fork, &xfs_da3_node_buf_ops);
278
	if (!err && tp && *bpp) {
279 280 281 282 283
		struct xfs_da_blkinfo	*info = (*bpp)->b_addr;
		int			type;

		switch (be16_to_cpu(info->magic)) {
		case XFS_DA_NODE_MAGIC:
284
		case XFS_DA3_NODE_MAGIC:
285
			type = XFS_BLFT_DA_NODE_BUF;
286 287 288
			break;
		case XFS_ATTR_LEAF_MAGIC:
		case XFS_ATTR3_LEAF_MAGIC:
289
			type = XFS_BLFT_ATTR_LEAF_BUF;
290 291 292
			break;
		case XFS_DIR2_LEAFN_MAGIC:
		case XFS_DIR3_LEAFN_MAGIC:
293
			type = XFS_BLFT_DIR_LEAFN_BUF;
294 295
			break;
		default:
296
			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
297
					tp->t_mountp, info, sizeof(*info));
298 299 300
			xfs_trans_brelse(tp, *bpp);
			*bpp = NULL;
			return -EFSCORRUPTED;
301 302 303 304
		}
		xfs_trans_buf_set_type(tp, *bpp, type);
	}
	return err;
305 306
}

Linus Torvalds's avatar
Linus Torvalds committed
307 308 309 310 311 312 313 314
/*========================================================================
 * Routines used for growing the Btree.
 *========================================================================*/

/*
 * Create the initial contents of an intermediate node.
 */
int
315 316 317 318 319 320
xfs_da3_node_create(
	struct xfs_da_args	*args,
	xfs_dablk_t		blkno,
	int			level,
	struct xfs_buf		**bpp,
	int			whichfork)
Linus Torvalds's avatar
Linus Torvalds committed
321
{
322 323 324 325 326 327
	struct xfs_da_intnode	*node;
	struct xfs_trans	*tp = args->trans;
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_da3_icnode_hdr ichdr = {0};
	struct xfs_buf		*bp;
	int			error;
328
	struct xfs_inode	*dp = args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
329

330
	trace_xfs_da_node_create(args);
331
	ASSERT(level <= XFS_DA_NODE_MAXDEPTH);
332

333
	error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
334
	if (error)
Eric Sandeen's avatar
Eric Sandeen committed
335
		return error;
336
	bp->b_ops = &xfs_da3_node_buf_ops;
337
	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
338
	node = bp->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
339

340 341 342
	if (xfs_sb_version_hascrc(&mp->m_sb)) {
		struct xfs_da3_node_hdr *hdr3 = bp->b_addr;

343
		memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr));
344 345 346
		ichdr.magic = XFS_DA3_NODE_MAGIC;
		hdr3->info.blkno = cpu_to_be64(bp->b_bn);
		hdr3->info.owner = cpu_to_be64(args->dp->i_ino);
347
		uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid);
348 349 350 351 352
	} else {
		ichdr.magic = XFS_DA_NODE_MAGIC;
	}
	ichdr.level = level;

353
	dp->d_ops->node_hdr_to_disk(node, &ichdr);
354
	xfs_trans_log_buf(tp, bp,
355
		XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size));
Linus Torvalds's avatar
Linus Torvalds committed
356 357

	*bpp = bp;
Eric Sandeen's avatar
Eric Sandeen committed
358
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
359 360 361 362 363 364 365
}

/*
 * Split a leaf node, rebalance, then possibly split
 * intermediate nodes, rebalance, etc.
 */
int							/* error */
366 367
xfs_da3_split(
	struct xfs_da_state	*state)
Linus Torvalds's avatar
Linus Torvalds committed
368
{
369 370 371 372 373
	struct xfs_da_state_blk	*oldblk;
	struct xfs_da_state_blk	*newblk;
	struct xfs_da_state_blk	*addblk;
	struct xfs_da_intnode	*node;
	int			max;
374
	int			action = 0;
375 376
	int			error;
	int			i;
Linus Torvalds's avatar
Linus Torvalds committed
377

378 379
	trace_xfs_da_split(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
380 381 382 383 384 385 386 387 388
	/*
	 * Walk back up the tree splitting/inserting/adjusting as necessary.
	 * If we need to insert and there isn't room, split the node, then
	 * decide which fragment to insert the new block from below into.
	 * Note that we may split the root this way, but we need more fixup.
	 */
	max = state->path.active - 1;
	ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH));
	ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC ||
389
	       state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC);
Linus Torvalds's avatar
Linus Torvalds committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403

	addblk = &state->path.blk[max];		/* initial dummy value */
	for (i = max; (i >= 0) && addblk; state->path.active--, i--) {
		oldblk = &state->path.blk[i];
		newblk = &state->altpath.blk[i];

		/*
		 * If a leaf node then
		 *     Allocate a new leaf node, then rebalance across them.
		 * else if an intermediate node then
		 *     We split on the last layer, must we split the node?
		 */
		switch (oldblk->magic) {
		case XFS_ATTR_LEAF_MAGIC:
404
			error = xfs_attr3_leaf_split(state, oldblk, newblk);
405
			if ((error != 0) && (error != -ENOSPC)) {
Eric Sandeen's avatar
Eric Sandeen committed
406
				return error;	/* GROT: attr is inconsistent */
Linus Torvalds's avatar
Linus Torvalds committed
407 408 409 410 411 412
			}
			if (!error) {
				addblk = newblk;
				break;
			}
			/*
413 414 415
			 * Entry wouldn't fit, split the leaf again. The new
			 * extrablk will be consumed by xfs_da3_node_split if
			 * the node is split.
Linus Torvalds's avatar
Linus Torvalds committed
416 417 418 419
			 */
			state->extravalid = 1;
			if (state->inleaf) {
				state->extraafter = 0;	/* before newblk */
420
				trace_xfs_attr_leaf_split_before(state->args);
421
				error = xfs_attr3_leaf_split(state, oldblk,
Linus Torvalds's avatar
Linus Torvalds committed
422 423 424
							    &state->extrablk);
			} else {
				state->extraafter = 1;	/* after newblk */
425
				trace_xfs_attr_leaf_split_after(state->args);
426
				error = xfs_attr3_leaf_split(state, newblk,
Linus Torvalds's avatar
Linus Torvalds committed
427 428 429
							    &state->extrablk);
			}
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
430
				return error;	/* GROT: attr inconsistent */
Linus Torvalds's avatar
Linus Torvalds committed
431 432 433 434 435 436 437 438 439
			addblk = newblk;
			break;
		case XFS_DIR2_LEAFN_MAGIC:
			error = xfs_dir2_leafn_split(state, oldblk, newblk);
			if (error)
				return error;
			addblk = newblk;
			break;
		case XFS_DA_NODE_MAGIC:
440
			error = xfs_da3_node_split(state, oldblk, newblk, addblk,
Linus Torvalds's avatar
Linus Torvalds committed
441 442 443
							 max - i, &action);
			addblk->bp = NULL;
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
444
				return error;	/* GROT: dir is inconsistent */
Linus Torvalds's avatar
Linus Torvalds committed
445 446 447 448 449 450 451 452 453 454 455 456 457
			/*
			 * Record the newly split block for the next time thru?
			 */
			if (action)
				addblk = newblk;
			else
				addblk = NULL;
			break;
		}

		/*
		 * Update the btree to show the new hashval for this child.
		 */
458
		xfs_da3_fixhashpath(state, &state->path);
Linus Torvalds's avatar
Linus Torvalds committed
459 460
	}
	if (!addblk)
Eric Sandeen's avatar
Eric Sandeen committed
461
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
462

463 464 465 466 467 468 469 470
	/*
	 * xfs_da3_node_split() should have consumed any extra blocks we added
	 * during a double leaf split in the attr fork. This is guaranteed as
	 * we can't be here if the attr fork only has a single leaf block.
	 */
	ASSERT(state->extravalid == 0 ||
	       state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC);

Linus Torvalds's avatar
Linus Torvalds committed
471 472 473 474 475
	/*
	 * Split the root node.
	 */
	ASSERT(state->path.active == 0);
	oldblk = &state->path.blk[0];
476
	error = xfs_da3_root_split(state, oldblk, addblk);
Linus Torvalds's avatar
Linus Torvalds committed
477 478
	if (error) {
		addblk->bp = NULL;
Eric Sandeen's avatar
Eric Sandeen committed
479
		return error;	/* GROT: dir is inconsistent */
Linus Torvalds's avatar
Linus Torvalds committed
480 481 482
	}

	/*
483 484 485 486
	 * Update pointers to the node which used to be block 0 and just got
	 * bumped because of the addition of a new root node.  Note that the
	 * original block 0 could be at any position in the list of blocks in
	 * the tree.
487
	 *
488 489 490 491
	 * Note: the magic numbers and sibling pointers are in the same physical
	 * place for both v2 and v3 headers (by design). Hence it doesn't matter
	 * which version of the xfs_da_intnode structure we use here as the
	 * result will be the same using either structure.
Linus Torvalds's avatar
Linus Torvalds committed
492
	 */
493
	node = oldblk->bp->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
494
	if (node->hdr.info.forw) {
495 496
		ASSERT(be32_to_cpu(node->hdr.info.forw) == addblk->blkno);
		node = addblk->bp->b_addr;
497
		node->hdr.info.back = cpu_to_be32(oldblk->blkno);
498 499 500
		xfs_trans_log_buf(state->args->trans, addblk->bp,
				  XFS_DA_LOGRANGE(node, &node->hdr.info,
				  sizeof(node->hdr.info)));
Linus Torvalds's avatar
Linus Torvalds committed
501
	}
502
	node = oldblk->bp->b_addr;
503
	if (node->hdr.info.back) {
504 505
		ASSERT(be32_to_cpu(node->hdr.info.back) == addblk->blkno);
		node = addblk->bp->b_addr;
506
		node->hdr.info.forw = cpu_to_be32(oldblk->blkno);
507 508 509
		xfs_trans_log_buf(state->args->trans, addblk->bp,
				  XFS_DA_LOGRANGE(node, &node->hdr.info,
				  sizeof(node->hdr.info)));
Linus Torvalds's avatar
Linus Torvalds committed
510 511
	}
	addblk->bp = NULL;
Eric Sandeen's avatar
Eric Sandeen committed
512
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
513 514 515 516 517 518 519 520
}

/*
 * Split the root.  We have to create a new root and point to the two
 * parts (the split old root) that we just created.  Copy block zero to
 * the EOF, extending the inode in process.
 */
STATIC int						/* error */
521 522 523 524
xfs_da3_root_split(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*blk1,
	struct xfs_da_state_blk	*blk2)
Linus Torvalds's avatar
Linus Torvalds committed
525
{
526 527 528 529 530 531 532 533 534 535 536 537 538
	struct xfs_da_intnode	*node;
	struct xfs_da_intnode	*oldroot;
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr nodehdr;
	struct xfs_da_args	*args;
	struct xfs_buf		*bp;
	struct xfs_inode	*dp;
	struct xfs_trans	*tp;
	struct xfs_dir2_leaf	*leaf;
	xfs_dablk_t		blkno;
	int			level;
	int			error;
	int			size;
Linus Torvalds's avatar
Linus Torvalds committed
539

540 541
	trace_xfs_da_root_split(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
542 543 544 545 546 547 548
	/*
	 * Copy the existing (incorrect) block from the root node position
	 * to a free space somewhere.
	 */
	args = state->args;
	error = xfs_da_grow_inode(args, &blkno);
	if (error)
549 550
		return error;

Linus Torvalds's avatar
Linus Torvalds committed
551 552 553 554
	dp = args->dp;
	tp = args->trans;
	error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork);
	if (error)
555
		return error;
556 557
	node = bp->b_addr;
	oldroot = blk1->bp->b_addr;
558 559
	if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
	    oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) {
560
		struct xfs_da3_icnode_hdr icnodehdr;
561

562
		dp->d_ops->node_hdr_from_disk(&icnodehdr, oldroot);
563
		btree = dp->d_ops->node_tree_p(oldroot);
564 565
		size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot);
		level = icnodehdr.level;
566 567 568 569 570

		/*
		 * we are about to copy oldroot to bp, so set up the type
		 * of bp while we know exactly what it will be.
		 */
571
		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF);
Linus Torvalds's avatar
Linus Torvalds committed
572
	} else {
573 574 575
		struct xfs_dir3_icleaf_hdr leafhdr;
		struct xfs_dir2_leaf_entry *ents;

Linus Torvalds's avatar
Linus Torvalds committed
576
		leaf = (xfs_dir2_leaf_t *)oldroot;
577
		dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
578
		ents = dp->d_ops->leaf_ents_p(leaf);
579 580 581 582

		ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
		       leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
		size = (int)((char *)&ents[leafhdr.count] - (char *)leaf);
583
		level = 0;
584 585 586 587 588

		/*
		 * we are about to copy oldroot to bp, so set up the type
		 * of bp while we know exactly what it will be.
		 */
589
		xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF);
Linus Torvalds's avatar
Linus Torvalds committed
590
	}
591 592 593 594 595 596 597

	/*
	 * we can copy most of the information in the node from one block to
	 * another, but for CRC enabled headers we have to make sure that the
	 * block specific identifiers are kept intact. We update the buffer
	 * directly for this.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
598
	memcpy(node, oldroot, size);
599 600 601 602 603 604
	if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) ||
	    oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
		struct xfs_da3_intnode *node3 = (struct xfs_da3_intnode *)node;

		node3->hdr.info.blkno = cpu_to_be64(bp->b_bn);
	}
605
	xfs_trans_log_buf(tp, bp, 0, size - 1);
606

607
	bp->b_ops = blk1->bp->b_ops;
608
	xfs_trans_buf_copy_type(bp, blk1->bp);
Linus Torvalds's avatar
Linus Torvalds committed
609 610 611 612 613 614
	blk1->bp = bp;
	blk1->blkno = blkno;

	/*
	 * Set up the new root node.
	 */
615
	error = xfs_da3_node_create(args,
616
		(args->whichfork == XFS_DATA_FORK) ? args->geo->leafblk : 0,
617
		level + 1, &bp, args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
618
	if (error)
619 620
		return error;

621
	node = bp->b_addr;
622
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
623
	btree = dp->d_ops->node_tree_p(node);
624 625 626 627 628
	btree[0].hashval = cpu_to_be32(blk1->hashval);
	btree[0].before = cpu_to_be32(blk1->blkno);
	btree[1].hashval = cpu_to_be32(blk2->hashval);
	btree[1].before = cpu_to_be32(blk2->blkno);
	nodehdr.count = 2;
629
	dp->d_ops->node_hdr_to_disk(node, &nodehdr);
Linus Torvalds's avatar
Linus Torvalds committed
630 631

#ifdef DEBUG
632 633
	if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
	    oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
634 635 636 637
		ASSERT(blk1->blkno >= args->geo->leafblk &&
		       blk1->blkno < args->geo->freeblk);
		ASSERT(blk2->blkno >= args->geo->leafblk &&
		       blk2->blkno < args->geo->freeblk);
Linus Torvalds's avatar
Linus Torvalds committed
638 639 640 641
	}
#endif

	/* Header is already logged by xfs_da_node_create */
642
	xfs_trans_log_buf(tp, bp,
643
		XFS_DA_LOGRANGE(node, btree, sizeof(xfs_da_node_entry_t) * 2));
Linus Torvalds's avatar
Linus Torvalds committed
644

645
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
646 647 648 649 650 651
}

/*
 * Split the node, rebalance, then add the new entry.
 */
STATIC int						/* error */
652 653 654 655 656 657 658
xfs_da3_node_split(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*oldblk,
	struct xfs_da_state_blk	*newblk,
	struct xfs_da_state_blk	*addblk,
	int			treelevel,
	int			*result)
Linus Torvalds's avatar
Linus Torvalds committed
659
{
660 661 662 663 664 665
	struct xfs_da_intnode	*node;
	struct xfs_da3_icnode_hdr nodehdr;
	xfs_dablk_t		blkno;
	int			newcount;
	int			error;
	int			useextra;
666
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
667

668 669
	trace_xfs_da_node_split(state->args);

670
	node = oldblk->bp->b_addr;
671
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
Linus Torvalds's avatar
Linus Torvalds committed
672 673

	/*
674
	 * With V2 dirs the extra block is data or freespace.
Linus Torvalds's avatar
Linus Torvalds committed
675
	 */
676
	useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK;
Linus Torvalds's avatar
Linus Torvalds committed
677 678 679 680
	newcount = 1 + useextra;
	/*
	 * Do we have to split the node?
	 */
681
	if (nodehdr.count + newcount > state->args->geo->node_ents) {
Linus Torvalds's avatar
Linus Torvalds committed
682 683 684 685 686 687
		/*
		 * Allocate a new node, add to the doubly linked chain of
		 * nodes, then move some of our excess entries into it.
		 */
		error = xfs_da_grow_inode(state->args, &blkno);
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
688
			return error;	/* GROT: dir is inconsistent */
Linus Torvalds's avatar
Linus Torvalds committed
689

690
		error = xfs_da3_node_create(state->args, blkno, treelevel,
Linus Torvalds's avatar
Linus Torvalds committed
691 692
					   &newblk->bp, state->args->whichfork);
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
693
			return error;	/* GROT: dir is inconsistent */
Linus Torvalds's avatar
Linus Torvalds committed
694 695
		newblk->blkno = blkno;
		newblk->magic = XFS_DA_NODE_MAGIC;
696 697
		xfs_da3_node_rebalance(state, oldblk, newblk);
		error = xfs_da3_blk_link(state, oldblk, newblk);
Linus Torvalds's avatar
Linus Torvalds committed
698
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
699
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
700 701 702 703 704 705 706 707 708
		*result = 1;
	} else {
		*result = 0;
	}

	/*
	 * Insert the new entry(s) into the correct block
	 * (updating last hashval in the process).
	 *
709
	 * xfs_da3_node_add() inserts BEFORE the given index,
Linus Torvalds's avatar
Linus Torvalds committed
710 711 712 713 714 715 716
	 * and as a result of using node_lookup_int() we always
	 * point to a valid entry (not after one), but a split
	 * operation always results in a new block whose hashvals
	 * FOLLOW the current block.
	 *
	 * If we had double-split op below us, then add the extra block too.
	 */
717
	node = oldblk->bp->b_addr;
718
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
719
	if (oldblk->index <= nodehdr.count) {
Linus Torvalds's avatar
Linus Torvalds committed
720
		oldblk->index++;
721
		xfs_da3_node_add(state, oldblk, addblk);
Linus Torvalds's avatar
Linus Torvalds committed
722 723 724
		if (useextra) {
			if (state->extraafter)
				oldblk->index++;
725
			xfs_da3_node_add(state, oldblk, &state->extrablk);
Linus Torvalds's avatar
Linus Torvalds committed
726 727 728 729
			state->extravalid = 0;
		}
	} else {
		newblk->index++;
730
		xfs_da3_node_add(state, newblk, addblk);
Linus Torvalds's avatar
Linus Torvalds committed
731 732 733
		if (useextra) {
			if (state->extraafter)
				newblk->index++;
734
			xfs_da3_node_add(state, newblk, &state->extrablk);
Linus Torvalds's avatar
Linus Torvalds committed
735 736 737 738
			state->extravalid = 0;
		}
	}

Eric Sandeen's avatar
Eric Sandeen committed
739
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
740 741 742 743 744 745 746 747 748
}

/*
 * Balance the btree elements between two intermediate nodes,
 * usually one full and one empty.
 *
 * NOTE: if blk2 is empty, then it will get the upper half of blk1.
 */
STATIC void
749 750 751 752
xfs_da3_node_rebalance(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*blk1,
	struct xfs_da_state_blk	*blk2)
Linus Torvalds's avatar
Linus Torvalds committed
753
{
754 755 756 757 758 759 760 761 762 763 764 765 766
	struct xfs_da_intnode	*node1;
	struct xfs_da_intnode	*node2;
	struct xfs_da_intnode	*tmpnode;
	struct xfs_da_node_entry *btree1;
	struct xfs_da_node_entry *btree2;
	struct xfs_da_node_entry *btree_s;
	struct xfs_da_node_entry *btree_d;
	struct xfs_da3_icnode_hdr nodehdr1;
	struct xfs_da3_icnode_hdr nodehdr2;
	struct xfs_trans	*tp;
	int			count;
	int			tmp;
	int			swap = 0;
767
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
768

769 770
	trace_xfs_da_node_rebalance(state->args);

771 772
	node1 = blk1->bp->b_addr;
	node2 = blk2->bp->b_addr;
773 774
	dp->d_ops->node_hdr_from_disk(&nodehdr1, node1);
	dp->d_ops->node_hdr_from_disk(&nodehdr2, node2);
775 776
	btree1 = dp->d_ops->node_tree_p(node1);
	btree2 = dp->d_ops->node_tree_p(node2);
777

Linus Torvalds's avatar
Linus Torvalds committed
778 779 780 781
	/*
	 * Figure out how many entries need to move, and in which direction.
	 * Swap the nodes around if that makes it simpler.
	 */
782 783 784 785
	if (nodehdr1.count > 0 && nodehdr2.count > 0 &&
	    ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) ||
	     (be32_to_cpu(btree2[nodehdr2.count - 1].hashval) <
			be32_to_cpu(btree1[nodehdr1.count - 1].hashval)))) {
Linus Torvalds's avatar
Linus Torvalds committed
786 787 788
		tmpnode = node1;
		node1 = node2;
		node2 = tmpnode;
789 790
		dp->d_ops->node_hdr_from_disk(&nodehdr1, node1);
		dp->d_ops->node_hdr_from_disk(&nodehdr2, node2);
791 792
		btree1 = dp->d_ops->node_tree_p(node1);
		btree2 = dp->d_ops->node_tree_p(node2);
793
		swap = 1;
Linus Torvalds's avatar
Linus Torvalds committed
794
	}
795 796

	count = (nodehdr1.count - nodehdr2.count) / 2;
Linus Torvalds's avatar
Linus Torvalds committed
797 798 799 800 801 802 803 804 805 806
	if (count == 0)
		return;
	tp = state->args->trans;
	/*
	 * Two cases: high-to-low and low-to-high.
	 */
	if (count > 0) {
		/*
		 * Move elements in node2 up to make a hole.
		 */
807 808
		tmp = nodehdr2.count;
		if (tmp > 0) {
Linus Torvalds's avatar
Linus Torvalds committed
809
			tmp *= (uint)sizeof(xfs_da_node_entry_t);
810 811
			btree_s = &btree2[0];
			btree_d = &btree2[count];
Linus Torvalds's avatar
Linus Torvalds committed
812 813 814 815 816 817 818
			memmove(btree_d, btree_s, tmp);
		}

		/*
		 * Move the req'd B-tree elements from high in node1 to
		 * low in node2.
		 */
819
		nodehdr2.count += count;
Linus Torvalds's avatar
Linus Torvalds committed
820
		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
821 822
		btree_s = &btree1[nodehdr1.count - count];
		btree_d = &btree2[0];
Linus Torvalds's avatar
Linus Torvalds committed
823
		memcpy(btree_d, btree_s, tmp);
824
		nodehdr1.count -= count;
Linus Torvalds's avatar
Linus Torvalds committed
825 826 827 828 829 830 831
	} else {
		/*
		 * Move the req'd B-tree elements from low in node2 to
		 * high in node1.
		 */
		count = -count;
		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
832 833
		btree_s = &btree2[0];
		btree_d = &btree1[nodehdr1.count];
Linus Torvalds's avatar
Linus Torvalds committed
834
		memcpy(btree_d, btree_s, tmp);
835 836
		nodehdr1.count += count;

837
		xfs_trans_log_buf(tp, blk1->bp,
Linus Torvalds's avatar
Linus Torvalds committed
838 839 840 841 842
			XFS_DA_LOGRANGE(node1, btree_d, tmp));

		/*
		 * Move elements in node2 down to fill the hole.
		 */
843
		tmp  = nodehdr2.count - count;
Linus Torvalds's avatar
Linus Torvalds committed
844
		tmp *= (uint)sizeof(xfs_da_node_entry_t);
845 846
		btree_s = &btree2[count];
		btree_d = &btree2[0];
Linus Torvalds's avatar
Linus Torvalds committed
847
		memmove(btree_d, btree_s, tmp);
848
		nodehdr2.count -= count;
Linus Torvalds's avatar
Linus Torvalds committed
849 850 851 852 853
	}

	/*
	 * Log header of node 1 and all current bits of node 2.
	 */
854
	dp->d_ops->node_hdr_to_disk(node1, &nodehdr1);
855
	xfs_trans_log_buf(tp, blk1->bp,
856
		XFS_DA_LOGRANGE(node1, &node1->hdr, dp->d_ops->node_hdr_size));
857

858
	dp->d_ops->node_hdr_to_disk(node2, &nodehdr2);
859
	xfs_trans_log_buf(tp, blk2->bp,
Linus Torvalds's avatar
Linus Torvalds committed
860
		XFS_DA_LOGRANGE(node2, &node2->hdr,
861
				dp->d_ops->node_hdr_size +
862
				(sizeof(btree2[0]) * nodehdr2.count)));
Linus Torvalds's avatar
Linus Torvalds committed
863 864 865 866 867

	/*
	 * Record the last hashval from each block for upward propagation.
	 * (note: don't use the swapped node pointers)
	 */
868 869 870
	if (swap) {
		node1 = blk1->bp->b_addr;
		node2 = blk2->bp->b_addr;
871 872
		dp->d_ops->node_hdr_from_disk(&nodehdr1, node1);
		dp->d_ops->node_hdr_from_disk(&nodehdr2, node2);
873 874
		btree1 = dp->d_ops->node_tree_p(node1);
		btree2 = dp->d_ops->node_tree_p(node2);
875 876 877
	}
	blk1->hashval = be32_to_cpu(btree1[nodehdr1.count - 1].hashval);
	blk2->hashval = be32_to_cpu(btree2[nodehdr2.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
878 879 880 881

	/*
	 * Adjust the expected index for insertion.
	 */
882 883 884
	if (blk1->index >= nodehdr1.count) {
		blk2->index = blk1->index - nodehdr1.count;
		blk1->index = nodehdr1.count + 1;	/* make it invalid */
Linus Torvalds's avatar
Linus Torvalds committed
885 886 887 888 889 890 891
	}
}

/*
 * Add a new entry to an intermediate node.
 */
STATIC void
892 893 894 895
xfs_da3_node_add(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*oldblk,
	struct xfs_da_state_blk	*newblk)
Linus Torvalds's avatar
Linus Torvalds committed
896
{
897 898 899 900
	struct xfs_da_intnode	*node;
	struct xfs_da3_icnode_hdr nodehdr;
	struct xfs_da_node_entry *btree;
	int			tmp;
901
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
902

903 904
	trace_xfs_da_node_add(state->args);

905
	node = oldblk->bp->b_addr;
906
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
907
	btree = dp->d_ops->node_tree_p(node);
908 909

	ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count);
Linus Torvalds's avatar
Linus Torvalds committed
910
	ASSERT(newblk->blkno != 0);
911
	if (state->args->whichfork == XFS_DATA_FORK)
912 913
		ASSERT(newblk->blkno >= state->args->geo->leafblk &&
		       newblk->blkno < state->args->geo->freeblk);
Linus Torvalds's avatar
Linus Torvalds committed
914 915 916 917 918

	/*
	 * We may need to make some room before we insert the new node.
	 */
	tmp = 0;
919 920 921
	if (oldblk->index < nodehdr.count) {
		tmp = (nodehdr.count - oldblk->index) * (uint)sizeof(*btree);
		memmove(&btree[oldblk->index + 1], &btree[oldblk->index], tmp);
Linus Torvalds's avatar
Linus Torvalds committed
922
	}
923 924
	btree[oldblk->index].hashval = cpu_to_be32(newblk->hashval);
	btree[oldblk->index].before = cpu_to_be32(newblk->blkno);
925
	xfs_trans_log_buf(state->args->trans, oldblk->bp,
926 927 928 929
		XFS_DA_LOGRANGE(node, &btree[oldblk->index],
				tmp + sizeof(*btree)));

	nodehdr.count += 1;
930
	dp->d_ops->node_hdr_to_disk(node, &nodehdr);
931
	xfs_trans_log_buf(state->args->trans, oldblk->bp,
932
		XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size));
Linus Torvalds's avatar
Linus Torvalds committed
933 934 935 936

	/*
	 * Copy the last hash value from the oldblk to propagate upwards.
	 */
937
	oldblk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
938 939 940 941 942 943 944 945 946 947 948
}

/*========================================================================
 * Routines used for shrinking the Btree.
 *========================================================================*/

/*
 * Deallocate an empty leaf node, remove it from its parent,
 * possibly deallocating that block, etc...
 */
int
949 950
xfs_da3_join(
	struct xfs_da_state	*state)
Linus Torvalds's avatar
Linus Torvalds committed
951
{
952 953 954 955
	struct xfs_da_state_blk	*drop_blk;
	struct xfs_da_state_blk	*save_blk;
	int			action = 0;
	int			error;
Linus Torvalds's avatar
Linus Torvalds committed
956

957 958
	trace_xfs_da_join(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
959 960 961 962
	drop_blk = &state->path.blk[ state->path.active-1 ];
	save_blk = &state->altpath.blk[ state->path.active-1 ];
	ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC);
	ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC ||
963
	       drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
Linus Torvalds's avatar
Linus Torvalds committed
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978

	/*
	 * Walk back up the tree joining/deallocating as necessary.
	 * When we stop dropping blocks, break out.
	 */
	for (  ; state->path.active >= 2; drop_blk--, save_blk--,
		 state->path.active--) {
		/*
		 * See if we can combine the block with a neighbor.
		 *   (action == 0) => no options, just leave
		 *   (action == 1) => coalesce, then unlink
		 *   (action == 2) => block empty, unlink it
		 */
		switch (drop_blk->magic) {
		case XFS_ATTR_LEAF_MAGIC:
979
			error = xfs_attr3_leaf_toosmall(state, &action);
Linus Torvalds's avatar
Linus Torvalds committed
980
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
981
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
982
			if (action == 0)
Eric Sandeen's avatar
Eric Sandeen committed
983
				return 0;
984
			xfs_attr3_leaf_unbalance(state, drop_blk, save_blk);
Linus Torvalds's avatar
Linus Torvalds committed
985 986 987 988 989 990 991 992 993 994 995 996 997 998
			break;
		case XFS_DIR2_LEAFN_MAGIC:
			error = xfs_dir2_leafn_toosmall(state, &action);
			if (error)
				return error;
			if (action == 0)
				return 0;
			xfs_dir2_leafn_unbalance(state, drop_blk, save_blk);
			break;
		case XFS_DA_NODE_MAGIC:
			/*
			 * Remove the offending node, fixup hashvals,
			 * check for a toosmall neighbor.
			 */
999 1000 1001
			xfs_da3_node_remove(state, drop_blk);
			xfs_da3_fixhashpath(state, &state->path);
			error = xfs_da3_node_toosmall(state, &action);
Linus Torvalds's avatar
Linus Torvalds committed
1002
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1003
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
1004 1005
			if (action == 0)
				return 0;
1006
			xfs_da3_node_unbalance(state, drop_blk, save_blk);
Linus Torvalds's avatar
Linus Torvalds committed
1007 1008
			break;
		}
1009 1010
		xfs_da3_fixhashpath(state, &state->altpath);
		error = xfs_da3_blk_unlink(state, drop_blk, save_blk);
Linus Torvalds's avatar
Linus Torvalds committed
1011 1012
		xfs_da_state_kill_altpath(state);
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1013
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
1014 1015 1016 1017
		error = xfs_da_shrink_inode(state->args, drop_blk->blkno,
							 drop_blk->bp);
		drop_blk->bp = NULL;
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1018
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
1019 1020 1021 1022 1023 1024
	}
	/*
	 * We joined all the way to the top.  If it turns out that
	 * we only have one entry in the root, make the child block
	 * the new root.
	 */
1025 1026 1027
	xfs_da3_node_remove(state, drop_blk);
	xfs_da3_fixhashpath(state, &state->path);
	error = xfs_da3_root_join(state, &state->path.blk[0]);
Eric Sandeen's avatar
Eric Sandeen committed
1028
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
1029 1030
}

1031 1032 1033 1034 1035 1036 1037 1038
#ifdef	DEBUG
static void
xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level)
{
	__be16	magic = blkinfo->magic;

	if (level == 1) {
		ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
1039
		       magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) ||
1040 1041
		       magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) ||
		       magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC));
1042 1043 1044 1045
	} else {
		ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
		       magic == cpu_to_be16(XFS_DA3_NODE_MAGIC));
	}
1046 1047 1048 1049 1050 1051 1052
	ASSERT(!blkinfo->forw);
	ASSERT(!blkinfo->back);
}
#else	/* !DEBUG */
#define	xfs_da_blkinfo_onlychild_validate(blkinfo, level)
#endif	/* !DEBUG */

Linus Torvalds's avatar
Linus Torvalds committed
1053 1054 1055 1056 1057
/*
 * We have only one entry in the root.  Copy the only remaining child of
 * the old root to block 0 as the new root node.
 */
STATIC int
1058 1059 1060
xfs_da3_root_join(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*root_blk)
Linus Torvalds's avatar
Linus Torvalds committed
1061
{
1062 1063 1064 1065 1066 1067 1068
	struct xfs_da_intnode	*oldroot;
	struct xfs_da_args	*args;
	xfs_dablk_t		child;
	struct xfs_buf		*bp;
	struct xfs_da3_icnode_hdr oldroothdr;
	struct xfs_da_node_entry *btree;
	int			error;
1069
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1070

1071 1072
	trace_xfs_da_root_join(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
1073
	ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
1074 1075

	args = state->args;
1076
	oldroot = root_blk->bp->b_addr;
1077
	dp->d_ops->node_hdr_from_disk(&oldroothdr, oldroot);
1078 1079
	ASSERT(oldroothdr.forw == 0);
	ASSERT(oldroothdr.back == 0);
Linus Torvalds's avatar
Linus Torvalds committed
1080 1081 1082 1083

	/*
	 * If the root has more than one child, then don't do anything.
	 */
1084 1085
	if (oldroothdr.count > 1)
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1086 1087 1088 1089 1090

	/*
	 * Read in the (only) child block, then copy those bytes into
	 * the root block's buffer and free the original child block.
	 */
1091
	btree = dp->d_ops->node_tree_p(oldroot);
1092
	child = be32_to_cpu(btree[0].before);
Linus Torvalds's avatar
Linus Torvalds committed
1093
	ASSERT(child != 0);
1094
	error = xfs_da3_node_read(args->trans, dp, child, -1, &bp,
1095
					     args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1096
	if (error)
1097 1098
		return error;
	xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);
1099

1100 1101 1102
	/*
	 * This could be copying a leaf back into the root block in the case of
	 * there only being a single leaf block left in the tree. Hence we have
1103
	 * to update the b_ops pointer as well to match the buffer type change
1104 1105
	 * that could occur. For dir3 blocks we also need to update the block
	 * number in the buffer header.
1106
	 */
1107
	memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize);
1108
	root_blk->bp->b_ops = bp->b_ops;
1109
	xfs_trans_buf_copy_type(root_blk->bp, bp);
1110 1111 1112 1113
	if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) {
		struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr;
		da3->blkno = cpu_to_be64(root_blk->bp->b_bn);
	}
1114 1115
	xfs_trans_log_buf(args->trans, root_blk->bp, 0,
			  args->geo->blksize - 1);
Linus Torvalds's avatar
Linus Torvalds committed
1116
	error = xfs_da_shrink_inode(args, child, bp);
Eric Sandeen's avatar
Eric Sandeen committed
1117
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
}

/*
 * Check a node block and its neighbors to see if the block should be
 * collapsed into one or the other neighbor.  Always keep the block
 * with the smaller block number.
 * If the current block is over 50% full, don't try to join it, return 0.
 * If the block is empty, fill in the state structure and return 2.
 * If it can be collapsed, fill in the state structure and return 1.
 * If nothing can be done, return 0.
 */
STATIC int
1130 1131 1132
xfs_da3_node_toosmall(
	struct xfs_da_state	*state,
	int			*action)
Linus Torvalds's avatar
Linus Torvalds committed
1133
{
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
	struct xfs_da_intnode	*node;
	struct xfs_da_state_blk	*blk;
	struct xfs_da_blkinfo	*info;
	xfs_dablk_t		blkno;
	struct xfs_buf		*bp;
	struct xfs_da3_icnode_hdr nodehdr;
	int			count;
	int			forward;
	int			error;
	int			retval;
	int			i;
1145
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1146

1147 1148
	trace_xfs_da_node_toosmall(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
1149 1150 1151 1152 1153 1154
	/*
	 * Check for the degenerate case of the block being over 50% full.
	 * If so, it's not worth even looking to see if we might be able
	 * to coalesce with a sibling.
	 */
	blk = &state->path.blk[ state->path.active-1 ];
1155
	info = blk->bp->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
1156
	node = (xfs_da_intnode_t *)info;
1157
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1158
	if (nodehdr.count > (state->args->geo->node_ents >> 1)) {
Linus Torvalds's avatar
Linus Torvalds committed
1159
		*action = 0;	/* blk over 50%, don't try to join */
Eric Sandeen's avatar
Eric Sandeen committed
1160
		return 0;	/* blk over 50%, don't try to join */
Linus Torvalds's avatar
Linus Torvalds committed
1161 1162 1163 1164 1165
	}

	/*
	 * Check for the degenerate case of the block being empty.
	 * If the block is empty, we'll simply delete it, no need to
1166
	 * coalesce it with a sibling block.  We choose (arbitrarily)
Linus Torvalds's avatar
Linus Torvalds committed
1167 1168
	 * to merge with the forward block unless it is NULL.
	 */
1169
	if (nodehdr.count == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
1170 1171 1172 1173
		/*
		 * Make altpath point to the block we want to keep and
		 * path point to the block we want to drop (this one).
		 */
1174
		forward = (info->forw != 0);
Linus Torvalds's avatar
Linus Torvalds committed
1175
		memcpy(&state->altpath, &state->path, sizeof(state->path));
1176
		error = xfs_da3_path_shift(state, &state->altpath, forward,
Linus Torvalds's avatar
Linus Torvalds committed
1177 1178
						 0, &retval);
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1179
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
1180 1181 1182 1183 1184
		if (retval) {
			*action = 0;
		} else {
			*action = 2;
		}
Eric Sandeen's avatar
Eric Sandeen committed
1185
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1186 1187 1188 1189 1190 1191 1192 1193 1194
	}

	/*
	 * Examine each sibling block to see if we can coalesce with
	 * at least 25% free space to spare.  We need to figure out
	 * whether to merge with the forward or the backward block.
	 * We prefer coalescing with the lower numbered sibling so as
	 * to shrink a directory over time.
	 */
1195 1196
	count  = state->args->geo->node_ents;
	count -= state->args->geo->node_ents >> 2;
1197 1198
	count -= nodehdr.count;

Linus Torvalds's avatar
Linus Torvalds committed
1199
	/* start with smaller blk num */
1200
	forward = nodehdr.forw < nodehdr.back;
Linus Torvalds's avatar
Linus Torvalds committed
1201
	for (i = 0; i < 2; forward = !forward, i++) {
1202
		struct xfs_da3_icnode_hdr thdr;
Linus Torvalds's avatar
Linus Torvalds committed
1203
		if (forward)
1204
			blkno = nodehdr.forw;
Linus Torvalds's avatar
Linus Torvalds committed
1205
		else
1206
			blkno = nodehdr.back;
Linus Torvalds's avatar
Linus Torvalds committed
1207 1208
		if (blkno == 0)
			continue;
1209
		error = xfs_da3_node_read(state->args->trans, dp,
1210
					blkno, -1, &bp, state->args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1211
		if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1212
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
1213

1214
		node = bp->b_addr;
1215
		dp->d_ops->node_hdr_from_disk(&thdr, node);
1216
		xfs_trans_brelse(state->args->trans, bp);
1217

1218
		if (count - thdr.count >= 0)
Linus Torvalds's avatar
Linus Torvalds committed
1219 1220 1221 1222
			break;	/* fits with at least 25% to spare */
	}
	if (i >= 2) {
		*action = 0;
1223
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1224 1225 1226 1227 1228 1229 1230 1231
	}

	/*
	 * Make altpath point to the block we want to keep (the lower
	 * numbered block) and path point to the block we want to drop.
	 */
	memcpy(&state->altpath, &state->path, sizeof(state->path));
	if (blkno < blk->blkno) {
1232
		error = xfs_da3_path_shift(state, &state->altpath, forward,
Linus Torvalds's avatar
Linus Torvalds committed
1233 1234
						 0, &retval);
	} else {
1235
		error = xfs_da3_path_shift(state, &state->path, forward,
Linus Torvalds's avatar
Linus Torvalds committed
1236
						 0, &retval);
1237 1238 1239 1240 1241 1242
	}
	if (error)
		return error;
	if (retval) {
		*action = 0;
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1243 1244
	}
	*action = 1;
1245 1246 1247 1248 1249 1250 1251 1252
	return 0;
}

/*
 * Pick up the last hashvalue from an intermediate node.
 */
STATIC uint
xfs_da3_node_lasthash(
1253
	struct xfs_inode	*dp,
1254 1255 1256 1257 1258 1259 1260 1261
	struct xfs_buf		*bp,
	int			*count)
{
	struct xfs_da_intnode	 *node;
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr nodehdr;

	node = bp->b_addr;
1262
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1263 1264 1265 1266
	if (count)
		*count = nodehdr.count;
	if (!nodehdr.count)
		return 0;
1267
	btree = dp->d_ops->node_tree_p(node);
1268
	return be32_to_cpu(btree[nodehdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
1269 1270 1271 1272 1273 1274 1275
}

/*
 * Walk back up the tree adjusting hash values as necessary,
 * when we stop making changes, return.
 */
void
1276 1277 1278
xfs_da3_fixhashpath(
	struct xfs_da_state	*state,
	struct xfs_da_state_path *path)
Linus Torvalds's avatar
Linus Torvalds committed
1279
{
1280 1281 1282 1283 1284 1285
	struct xfs_da_state_blk	*blk;
	struct xfs_da_intnode	*node;
	struct xfs_da_node_entry *btree;
	xfs_dahash_t		lasthash=0;
	int			level;
	int			count;
1286
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1287

1288 1289
	trace_xfs_da_fixhashpath(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
1290 1291 1292 1293 1294 1295 1296 1297 1298
	level = path->active-1;
	blk = &path->blk[ level ];
	switch (blk->magic) {
	case XFS_ATTR_LEAF_MAGIC:
		lasthash = xfs_attr_leaf_lasthash(blk->bp, &count);
		if (count == 0)
			return;
		break;
	case XFS_DIR2_LEAFN_MAGIC:
1299
		lasthash = xfs_dir2_leaf_lasthash(dp, blk->bp, &count);
Linus Torvalds's avatar
Linus Torvalds committed
1300 1301 1302 1303
		if (count == 0)
			return;
		break;
	case XFS_DA_NODE_MAGIC:
1304
		lasthash = xfs_da3_node_lasthash(dp, blk->bp, &count);
Linus Torvalds's avatar
Linus Torvalds committed
1305 1306 1307 1308 1309
		if (count == 0)
			return;
		break;
	}
	for (blk--, level--; level >= 0; blk--, level--) {
1310 1311
		struct xfs_da3_icnode_hdr nodehdr;

1312
		node = blk->bp->b_addr;
1313
		dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1314
		btree = dp->d_ops->node_tree_p(node);
1315
		if (be32_to_cpu(btree[blk->index].hashval) == lasthash)
Linus Torvalds's avatar
Linus Torvalds committed
1316 1317
			break;
		blk->hashval = lasthash;
1318
		btree[blk->index].hashval = cpu_to_be32(lasthash);
1319
		xfs_trans_log_buf(state->args->trans, blk->bp,
1320 1321
				  XFS_DA_LOGRANGE(node, &btree[blk->index],
						  sizeof(*btree)));
Linus Torvalds's avatar
Linus Torvalds committed
1322

1323
		lasthash = be32_to_cpu(btree[nodehdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
1324 1325 1326 1327 1328 1329 1330
	}
}

/*
 * Remove an entry from an intermediate node.
 */
STATIC void
1331 1332 1333
xfs_da3_node_remove(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*drop_blk)
Linus Torvalds's avatar
Linus Torvalds committed
1334
{
1335 1336 1337 1338 1339
	struct xfs_da_intnode	*node;
	struct xfs_da3_icnode_hdr nodehdr;
	struct xfs_da_node_entry *btree;
	int			index;
	int			tmp;
1340
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1341

1342 1343
	trace_xfs_da_node_remove(state->args);

1344
	node = drop_blk->bp->b_addr;
1345
	dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1346
	ASSERT(drop_blk->index < nodehdr.count);
Linus Torvalds's avatar
Linus Torvalds committed
1347 1348 1349 1350 1351
	ASSERT(drop_blk->index >= 0);

	/*
	 * Copy over the offending entry, or just zero it out.
	 */
1352
	index = drop_blk->index;
1353
	btree = dp->d_ops->node_tree_p(node);
1354 1355
	if (index < nodehdr.count - 1) {
		tmp  = nodehdr.count - index - 1;
Linus Torvalds's avatar
Linus Torvalds committed
1356
		tmp *= (uint)sizeof(xfs_da_node_entry_t);
1357
		memmove(&btree[index], &btree[index + 1], tmp);
1358
		xfs_trans_log_buf(state->args->trans, drop_blk->bp,
1359 1360
		    XFS_DA_LOGRANGE(node, &btree[index], tmp));
		index = nodehdr.count - 1;
Linus Torvalds's avatar
Linus Torvalds committed
1361
	}
1362
	memset(&btree[index], 0, sizeof(xfs_da_node_entry_t));
1363
	xfs_trans_log_buf(state->args->trans, drop_blk->bp,
1364 1365
	    XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index])));
	nodehdr.count -= 1;
1366
	dp->d_ops->node_hdr_to_disk(node, &nodehdr);
1367
	xfs_trans_log_buf(state->args->trans, drop_blk->bp,
1368
	    XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size));
Linus Torvalds's avatar
Linus Torvalds committed
1369 1370 1371 1372

	/*
	 * Copy the last hash value from the block to propagate upwards.
	 */
1373
	drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
1374 1375 1376
}

/*
1377
 * Unbalance the elements between two intermediate nodes,
Linus Torvalds's avatar
Linus Torvalds committed
1378 1379 1380
 * move all Btree elements from one node into another.
 */
STATIC void
1381 1382 1383 1384
xfs_da3_node_unbalance(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*drop_blk,
	struct xfs_da_state_blk	*save_blk)
Linus Torvalds's avatar
Linus Torvalds committed
1385
{
1386 1387 1388 1389 1390 1391 1392 1393 1394
	struct xfs_da_intnode	*drop_node;
	struct xfs_da_intnode	*save_node;
	struct xfs_da_node_entry *drop_btree;
	struct xfs_da_node_entry *save_btree;
	struct xfs_da3_icnode_hdr drop_hdr;
	struct xfs_da3_icnode_hdr save_hdr;
	struct xfs_trans	*tp;
	int			sindex;
	int			tmp;
1395
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1396

1397 1398
	trace_xfs_da_node_unbalance(state->args);

1399 1400
	drop_node = drop_blk->bp->b_addr;
	save_node = save_blk->bp->b_addr;
1401 1402
	dp->d_ops->node_hdr_from_disk(&drop_hdr, drop_node);
	dp->d_ops->node_hdr_from_disk(&save_hdr, save_node);
1403 1404
	drop_btree = dp->d_ops->node_tree_p(drop_node);
	save_btree = dp->d_ops->node_tree_p(save_node);
Linus Torvalds's avatar
Linus Torvalds committed
1405 1406 1407 1408 1409 1410
	tp = state->args->trans;

	/*
	 * If the dying block has lower hashvals, then move all the
	 * elements in the remaining block up to make a hole.
	 */
1411 1412 1413 1414 1415 1416 1417 1418 1419
	if ((be32_to_cpu(drop_btree[0].hashval) <
			be32_to_cpu(save_btree[0].hashval)) ||
	    (be32_to_cpu(drop_btree[drop_hdr.count - 1].hashval) <
			be32_to_cpu(save_btree[save_hdr.count - 1].hashval))) {
		/* XXX: check this - is memmove dst correct? */
		tmp = save_hdr.count * sizeof(xfs_da_node_entry_t);
		memmove(&save_btree[drop_hdr.count], &save_btree[0], tmp);

		sindex = 0;
1420
		xfs_trans_log_buf(tp, save_blk->bp,
1421 1422 1423
			XFS_DA_LOGRANGE(save_node, &save_btree[0],
				(save_hdr.count + drop_hdr.count) *
						sizeof(xfs_da_node_entry_t)));
Linus Torvalds's avatar
Linus Torvalds committed
1424
	} else {
1425
		sindex = save_hdr.count;
1426
		xfs_trans_log_buf(tp, save_blk->bp,
1427 1428
			XFS_DA_LOGRANGE(save_node, &save_btree[sindex],
				drop_hdr.count * sizeof(xfs_da_node_entry_t)));
Linus Torvalds's avatar
Linus Torvalds committed
1429 1430 1431 1432 1433
	}

	/*
	 * Move all the B-tree elements from drop_blk to save_blk.
	 */
1434 1435 1436
	tmp = drop_hdr.count * (uint)sizeof(xfs_da_node_entry_t);
	memcpy(&save_btree[sindex], &drop_btree[0], tmp);
	save_hdr.count += drop_hdr.count;
Linus Torvalds's avatar
Linus Torvalds committed
1437

1438
	dp->d_ops->node_hdr_to_disk(save_node, &save_hdr);
1439
	xfs_trans_log_buf(tp, save_blk->bp,
Linus Torvalds's avatar
Linus Torvalds committed
1440
		XFS_DA_LOGRANGE(save_node, &save_node->hdr,
1441
				dp->d_ops->node_hdr_size));
Linus Torvalds's avatar
Linus Torvalds committed
1442 1443 1444 1445

	/*
	 * Save the last hashval in the remaining block for upward propagation.
	 */
1446
	save_blk->hashval = be32_to_cpu(save_btree[save_hdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
}

/*========================================================================
 * Routines used for finding things in the Btree.
 *========================================================================*/

/*
 * Walk down the Btree looking for a particular filename, filling
 * in the state structure as we go.
 *
 * We will set the state structure to point to each of the elements
 * in each of the nodes where either the hashval is or should be.
 *
 * We support duplicate hashval's so for each entry in the current
 * node that could contain the desired hashval, descend.  This is a
 * pruned depth-first tree search.
 */
int							/* error */
1465 1466 1467
xfs_da3_node_lookup_int(
	struct xfs_da_state	*state,
	int			*result)
Linus Torvalds's avatar
Linus Torvalds committed
1468
{
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
	struct xfs_da_state_blk	*blk;
	struct xfs_da_blkinfo	*curr;
	struct xfs_da_intnode	*node;
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr nodehdr;
	struct xfs_da_args	*args;
	xfs_dablk_t		blkno;
	xfs_dahash_t		hashval;
	xfs_dahash_t		btreehashval;
	int			probe;
	int			span;
	int			max;
	int			error;
	int			retval;
1483
	unsigned int		expected_level = 0;
1484
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1485 1486 1487 1488 1489 1490 1491

	args = state->args;

	/*
	 * Descend thru the B-tree searching each level for the right
	 * node to use, until the right hashval is found.
	 */
1492
	blkno = args->geo->leafblk;
Linus Torvalds's avatar
Linus Torvalds committed
1493 1494 1495 1496 1497 1498 1499
	for (blk = &state->path.blk[0], state->path.active = 1;
			 state->path.active <= XFS_DA_NODE_MAXDEPTH;
			 blk++, state->path.active++) {
		/*
		 * Read the next node down in the tree.
		 */
		blk->blkno = blkno;
1500
		error = xfs_da3_node_read(args->trans, args->dp, blkno,
1501
					-1, &blk->bp, args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1502 1503 1504
		if (error) {
			blk->blkno = 0;
			state->path.active--;
Eric Sandeen's avatar
Eric Sandeen committed
1505
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
1506
		}
1507
		curr = blk->bp->b_addr;
1508
		blk->magic = be16_to_cpu(curr->magic);
1509

1510 1511 1512
		if (blk->magic == XFS_ATTR_LEAF_MAGIC ||
		    blk->magic == XFS_ATTR3_LEAF_MAGIC) {
			blk->magic = XFS_ATTR_LEAF_MAGIC;
1513 1514 1515 1516 1517 1518 1519
			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
			break;
		}

		if (blk->magic == XFS_DIR2_LEAFN_MAGIC ||
		    blk->magic == XFS_DIR3_LEAFN_MAGIC) {
			blk->magic = XFS_DIR2_LEAFN_MAGIC;
1520 1521
			blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
							      blk->bp, NULL);
1522 1523 1524 1525 1526
			break;
		}

		blk->magic = XFS_DA_NODE_MAGIC;

Linus Torvalds's avatar
Linus Torvalds committed
1527 1528 1529 1530

		/*
		 * Search an intermediate node for a match.
		 */
1531
		node = blk->bp->b_addr;
1532
		dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1533
		btree = dp->d_ops->node_tree_p(node);
Linus Torvalds's avatar
Linus Torvalds committed
1534

1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
		/* Tree taller than we can handle; bail out! */
		if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
			return -EFSCORRUPTED;

		/* Check the level from the root. */
		if (blkno == args->geo->leafblk)
			expected_level = nodehdr.level - 1;
		else if (expected_level != nodehdr.level)
			return -EFSCORRUPTED;
		else
			expected_level--;

1547 1548
		max = nodehdr.count;
		blk->hashval = be32_to_cpu(btree[max - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
1549

1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
		/*
		 * Binary search.  (note: small blocks will skip loop)
		 */
		probe = span = max / 2;
		hashval = args->hashval;
		while (span > 4) {
			span /= 2;
			btreehashval = be32_to_cpu(btree[probe].hashval);
			if (btreehashval < hashval)
				probe += span;
			else if (btreehashval > hashval)
				probe -= span;
			else
				break;
		}
		ASSERT((probe >= 0) && (probe < max));
		ASSERT((span <= 4) ||
			(be32_to_cpu(btree[probe].hashval) == hashval));
Linus Torvalds's avatar
Linus Torvalds committed
1568

1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
		/*
		 * Since we may have duplicate hashval's, find the first
		 * matching hashval in the node.
		 */
		while (probe > 0 &&
		       be32_to_cpu(btree[probe].hashval) >= hashval) {
			probe--;
		}
		while (probe < max &&
		       be32_to_cpu(btree[probe].hashval) < hashval) {
			probe++;
		}

		/*
		 * Pick the right block to descend on.
		 */
		if (probe == max) {
			blk->index = max - 1;
			blkno = be32_to_cpu(btree[max - 1].before);
		} else {
			blk->index = probe;
			blkno = be32_to_cpu(btree[probe].before);
Linus Torvalds's avatar
Linus Torvalds committed
1591
		}
1592 1593 1594 1595

		/* We can't point back to the root. */
		if (blkno == args->geo->leafblk)
			return -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
1596 1597
	}

1598 1599 1600
	if (expected_level != 0)
		return -EFSCORRUPTED;

Linus Torvalds's avatar
Linus Torvalds committed
1601 1602 1603 1604 1605 1606 1607
	/*
	 * A leaf block that ends in the hashval that we are interested in
	 * (final hashval == search hashval) means that the next block may
	 * contain more entries with the same hashval, shift upward to the
	 * next leaf and keep searching.
	 */
	for (;;) {
1608
		if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
1609 1610
			retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
							&blk->index, state);
1611
		} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
1612
			retval = xfs_attr3_leaf_lookup_int(blk->bp, args);
Linus Torvalds's avatar
Linus Torvalds committed
1613 1614
			blk->index = args->index;
			args->blkno = blk->blkno;
1615 1616
		} else {
			ASSERT(0);
1617
			return -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
1618
		}
1619
		if (((retval == -ENOENT) || (retval == -ENOATTR)) &&
Linus Torvalds's avatar
Linus Torvalds committed
1620
		    (blk->hashval == args->hashval)) {
1621
			error = xfs_da3_path_shift(state, &state->path, 1, 1,
Linus Torvalds's avatar
Linus Torvalds committed
1622 1623
							 &retval);
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1624
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
1625 1626
			if (retval == 0) {
				continue;
1627
			} else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
1628
				/* path_shift() gives ENOENT */
1629
				retval = -ENOATTR;
Linus Torvalds's avatar
Linus Torvalds committed
1630 1631 1632 1633 1634
			}
		}
		break;
	}
	*result = retval;
Eric Sandeen's avatar
Eric Sandeen committed
1635
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1636 1637 1638 1639 1640 1641
}

/*========================================================================
 * Utility routines.
 *========================================================================*/

1642 1643 1644 1645 1646
/*
 * Compare two intermediate nodes for "order".
 */
STATIC int
xfs_da3_node_order(
1647
	struct xfs_inode *dp,
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
	struct xfs_buf	*node1_bp,
	struct xfs_buf	*node2_bp)
{
	struct xfs_da_intnode	*node1;
	struct xfs_da_intnode	*node2;
	struct xfs_da_node_entry *btree1;
	struct xfs_da_node_entry *btree2;
	struct xfs_da3_icnode_hdr node1hdr;
	struct xfs_da3_icnode_hdr node2hdr;

	node1 = node1_bp->b_addr;
	node2 = node2_bp->b_addr;
1660 1661
	dp->d_ops->node_hdr_from_disk(&node1hdr, node1);
	dp->d_ops->node_hdr_from_disk(&node2hdr, node2);
1662 1663
	btree1 = dp->d_ops->node_tree_p(node1);
	btree2 = dp->d_ops->node_tree_p(node2);
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673

	if (node1hdr.count > 0 && node2hdr.count > 0 &&
	    ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) ||
	     (be32_to_cpu(btree2[node2hdr.count - 1].hashval) <
	      be32_to_cpu(btree1[node1hdr.count - 1].hashval)))) {
		return 1;
	}
	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
1674 1675 1676 1677
/*
 * Link a new block into a doubly linked list of blocks (of whatever type).
 */
int							/* error */
1678 1679 1680 1681
xfs_da3_blk_link(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*old_blk,
	struct xfs_da_state_blk	*new_blk)
Linus Torvalds's avatar
Linus Torvalds committed
1682
{
1683 1684 1685 1686 1687 1688 1689
	struct xfs_da_blkinfo	*old_info;
	struct xfs_da_blkinfo	*new_info;
	struct xfs_da_blkinfo	*tmp_info;
	struct xfs_da_args	*args;
	struct xfs_buf		*bp;
	int			before = 0;
	int			error;
1690
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1691 1692 1693 1694 1695 1696

	/*
	 * Set up environment.
	 */
	args = state->args;
	ASSERT(args != NULL);
1697 1698
	old_info = old_blk->bp->b_addr;
	new_info = new_blk->bp->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
1699
	ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||
1700
	       old_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
Linus Torvalds's avatar
Linus Torvalds committed
1701 1702 1703 1704 1705 1706 1707
	       old_blk->magic == XFS_ATTR_LEAF_MAGIC);

	switch (old_blk->magic) {
	case XFS_ATTR_LEAF_MAGIC:
		before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp);
		break;
	case XFS_DIR2_LEAFN_MAGIC:
1708
		before = xfs_dir2_leafn_order(dp, old_blk->bp, new_blk->bp);
Linus Torvalds's avatar
Linus Torvalds committed
1709 1710
		break;
	case XFS_DA_NODE_MAGIC:
1711
		before = xfs_da3_node_order(dp, old_blk->bp, new_blk->bp);
Linus Torvalds's avatar
Linus Torvalds committed
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
		break;
	}

	/*
	 * Link blocks in appropriate order.
	 */
	if (before) {
		/*
		 * Link new block in before existing block.
		 */
1722
		trace_xfs_da_link_before(args);
1723 1724 1725
		new_info->forw = cpu_to_be32(old_blk->blkno);
		new_info->back = old_info->back;
		if (old_info->back) {
1726
			error = xfs_da3_node_read(args->trans, dp,
1727
						be32_to_cpu(old_info->back),
1728
						-1, &bp, args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1729
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1730
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
1731
			ASSERT(bp != NULL);
1732
			tmp_info = bp->b_addr;
1733
			ASSERT(tmp_info->magic == old_info->magic);
1734 1735
			ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno);
			tmp_info->forw = cpu_to_be32(new_blk->blkno);
1736
			xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
Linus Torvalds's avatar
Linus Torvalds committed
1737
		}
1738
		old_info->back = cpu_to_be32(new_blk->blkno);
Linus Torvalds's avatar
Linus Torvalds committed
1739 1740 1741 1742
	} else {
		/*
		 * Link new block in after existing block.
		 */
1743
		trace_xfs_da_link_after(args);
1744 1745 1746
		new_info->forw = old_info->forw;
		new_info->back = cpu_to_be32(old_blk->blkno);
		if (old_info->forw) {
1747
			error = xfs_da3_node_read(args->trans, dp,
1748
						be32_to_cpu(old_info->forw),
1749
						-1, &bp, args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1750
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1751
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
1752
			ASSERT(bp != NULL);
1753
			tmp_info = bp->b_addr;
1754 1755 1756
			ASSERT(tmp_info->magic == old_info->magic);
			ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno);
			tmp_info->back = cpu_to_be32(new_blk->blkno);
1757
			xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
Linus Torvalds's avatar
Linus Torvalds committed
1758
		}
1759
		old_info->forw = cpu_to_be32(new_blk->blkno);
Linus Torvalds's avatar
Linus Torvalds committed
1760 1761
	}

1762 1763
	xfs_trans_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1);
	xfs_trans_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1);
Eric Sandeen's avatar
Eric Sandeen committed
1764
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1765 1766 1767 1768 1769
}

/*
 * Unlink a block from a doubly linked list of blocks.
 */
1770
STATIC int						/* error */
1771 1772 1773 1774
xfs_da3_blk_unlink(
	struct xfs_da_state	*state,
	struct xfs_da_state_blk	*drop_blk,
	struct xfs_da_state_blk	*save_blk)
Linus Torvalds's avatar
Linus Torvalds committed
1775
{
1776 1777 1778 1779 1780 1781
	struct xfs_da_blkinfo	*drop_info;
	struct xfs_da_blkinfo	*save_info;
	struct xfs_da_blkinfo	*tmp_info;
	struct xfs_da_args	*args;
	struct xfs_buf		*bp;
	int			error;
Linus Torvalds's avatar
Linus Torvalds committed
1782 1783 1784 1785 1786 1787

	/*
	 * Set up environment.
	 */
	args = state->args;
	ASSERT(args != NULL);
1788 1789
	save_info = save_blk->bp->b_addr;
	drop_info = drop_blk->bp->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
1790
	ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||
1791
	       save_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
Linus Torvalds's avatar
Linus Torvalds committed
1792 1793
	       save_blk->magic == XFS_ATTR_LEAF_MAGIC);
	ASSERT(save_blk->magic == drop_blk->magic);
1794 1795 1796 1797
	ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) ||
	       (be32_to_cpu(save_info->back) == drop_blk->blkno));
	ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) ||
	       (be32_to_cpu(drop_info->back) == save_blk->blkno));
Linus Torvalds's avatar
Linus Torvalds committed
1798 1799 1800 1801

	/*
	 * Unlink the leaf block from the doubly linked chain of leaves.
	 */
1802
	if (be32_to_cpu(save_info->back) == drop_blk->blkno) {
1803
		trace_xfs_da_unlink_back(args);
1804 1805
		save_info->back = drop_info->back;
		if (drop_info->back) {
1806
			error = xfs_da3_node_read(args->trans, args->dp,
1807
						be32_to_cpu(drop_info->back),
1808
						-1, &bp, args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1809
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1810
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
1811
			ASSERT(bp != NULL);
1812
			tmp_info = bp->b_addr;
1813 1814 1815
			ASSERT(tmp_info->magic == save_info->magic);
			ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno);
			tmp_info->forw = cpu_to_be32(save_blk->blkno);
1816
			xfs_trans_log_buf(args->trans, bp, 0,
Linus Torvalds's avatar
Linus Torvalds committed
1817 1818 1819
						    sizeof(*tmp_info) - 1);
		}
	} else {
1820
		trace_xfs_da_unlink_forward(args);
1821 1822
		save_info->forw = drop_info->forw;
		if (drop_info->forw) {
1823
			error = xfs_da3_node_read(args->trans, args->dp,
1824
						be32_to_cpu(drop_info->forw),
1825
						-1, &bp, args->whichfork);
Linus Torvalds's avatar
Linus Torvalds committed
1826
			if (error)
Eric Sandeen's avatar
Eric Sandeen committed
1827
				return error;
Linus Torvalds's avatar
Linus Torvalds committed
1828
			ASSERT(bp != NULL);
1829
			tmp_info = bp->b_addr;
1830 1831 1832
			ASSERT(tmp_info->magic == save_info->magic);
			ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno);
			tmp_info->back = cpu_to_be32(save_blk->blkno);
1833
			xfs_trans_log_buf(args->trans, bp, 0,
Linus Torvalds's avatar
Linus Torvalds committed
1834 1835 1836 1837
						    sizeof(*tmp_info) - 1);
		}
	}

1838
	xfs_trans_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1);
Eric Sandeen's avatar
Eric Sandeen committed
1839
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850
}

/*
 * Move a path "forward" or "!forward" one block at the current level.
 *
 * This routine will adjust a "path" to point to the next block
 * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the
 * Btree, including updating pointers to the intermediate nodes between
 * the new bottom and the root.
 */
int							/* error */
1851 1852 1853 1854 1855 1856
xfs_da3_path_shift(
	struct xfs_da_state	*state,
	struct xfs_da_state_path *path,
	int			forward,
	int			release,
	int			*result)
Linus Torvalds's avatar
Linus Torvalds committed
1857
{
1858 1859 1860 1861 1862 1863
	struct xfs_da_state_blk	*blk;
	struct xfs_da_blkinfo	*info;
	struct xfs_da_intnode	*node;
	struct xfs_da_args	*args;
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr nodehdr;
1864
	struct xfs_buf		*bp;
1865 1866 1867
	xfs_dablk_t		blkno = 0;
	int			level;
	int			error;
1868
	struct xfs_inode	*dp = state->args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
1869

1870 1871
	trace_xfs_da_path_shift(state->args);

Linus Torvalds's avatar
Linus Torvalds committed
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
	/*
	 * Roll up the Btree looking for the first block where our
	 * current index is not at the edge of the block.  Note that
	 * we skip the bottom layer because we want the sibling block.
	 */
	args = state->args;
	ASSERT(args != NULL);
	ASSERT(path != NULL);
	ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
	level = (path->active-1) - 1;	/* skip bottom layer in path */
	for (blk = &path->blk[level]; level >= 0; blk--, level--) {
1883
		node = blk->bp->b_addr;
1884
		dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1885
		btree = dp->d_ops->node_tree_p(node);
1886 1887

		if (forward && (blk->index < nodehdr.count - 1)) {
Linus Torvalds's avatar
Linus Torvalds committed
1888
			blk->index++;
1889
			blkno = be32_to_cpu(btree[blk->index].before);
Linus Torvalds's avatar
Linus Torvalds committed
1890 1891 1892
			break;
		} else if (!forward && (blk->index > 0)) {
			blk->index--;
1893
			blkno = be32_to_cpu(btree[blk->index].before);
Linus Torvalds's avatar
Linus Torvalds committed
1894 1895 1896 1897
			break;
		}
	}
	if (level < 0) {
1898
		*result = -ENOENT;	/* we're out of our tree */
1899
		ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
Eric Sandeen's avatar
Eric Sandeen committed
1900
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1901 1902 1903 1904 1905 1906 1907 1908
	}

	/*
	 * Roll down the edge of the subtree until we reach the
	 * same depth we were at originally.
	 */
	for (blk++, level++; level < path->active; blk++, level++) {
		/*
1909
		 * Read the next child block into a local buffer.
Linus Torvalds's avatar
Linus Torvalds committed
1910
		 */
1911 1912 1913 1914
		error = xfs_da3_node_read(args->trans, dp, blkno, -1, &bp,
					  args->whichfork);
		if (error)
			return error;
Linus Torvalds's avatar
Linus Torvalds committed
1915 1916

		/*
1917 1918 1919 1920
		 * Release the old block (if it's dirty, the trans doesn't
		 * actually let go) and swap the local buffer into the path
		 * structure. This ensures failure of the above read doesn't set
		 * a NULL buffer in an active slot in the path.
Linus Torvalds's avatar
Linus Torvalds committed
1921
		 */
1922 1923
		if (release)
			xfs_trans_brelse(args->trans, blk->bp);
Linus Torvalds's avatar
Linus Torvalds committed
1924
		blk->blkno = blkno;
1925 1926
		blk->bp = bp;

1927
		info = blk->bp->b_addr;
1928
		ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
1929
		       info->magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) ||
1930
		       info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
1931
		       info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) ||
1932 1933
		       info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) ||
		       info->magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC));
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943


		/*
		 * Note: we flatten the magic number to a single type so we
		 * don't have to compare against crc/non-crc types elsewhere.
		 */
		switch (be16_to_cpu(info->magic)) {
		case XFS_DA_NODE_MAGIC:
		case XFS_DA3_NODE_MAGIC:
			blk->magic = XFS_DA_NODE_MAGIC;
Linus Torvalds's avatar
Linus Torvalds committed
1944
			node = (xfs_da_intnode_t *)info;
1945
			dp->d_ops->node_hdr_from_disk(&nodehdr, node);
1946
			btree = dp->d_ops->node_tree_p(node);
1947
			blk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
1948 1949 1950
			if (forward)
				blk->index = 0;
			else
1951 1952 1953 1954
				blk->index = nodehdr.count - 1;
			blkno = be32_to_cpu(btree[blk->index].before);
			break;
		case XFS_ATTR_LEAF_MAGIC:
1955
		case XFS_ATTR3_LEAF_MAGIC:
1956
			blk->magic = XFS_ATTR_LEAF_MAGIC;
Linus Torvalds's avatar
Linus Torvalds committed
1957 1958
			ASSERT(level == path->active-1);
			blk->index = 0;
1959
			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
1960 1961 1962 1963 1964 1965
			break;
		case XFS_DIR2_LEAFN_MAGIC:
		case XFS_DIR3_LEAFN_MAGIC:
			blk->magic = XFS_DIR2_LEAFN_MAGIC;
			ASSERT(level == path->active-1);
			blk->index = 0;
1966 1967
			blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
							      blk->bp, NULL);
1968 1969 1970 1971
			break;
		default:
			ASSERT(0);
			break;
Linus Torvalds's avatar
Linus Torvalds committed
1972 1973 1974
		}
	}
	*result = 0;
1975
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
}


/*========================================================================
 * Utility routines.
 *========================================================================*/

/*
 * Implement a simple hash on a character string.
 * Rotate the hash value by 7 bits, then XOR each character in.
 * This is implemented with some source-level loop unrolling.
 */
xfs_dahash_t
1989
xfs_da_hashname(const uint8_t *name, int namelen)
Linus Torvalds's avatar
Linus Torvalds committed
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
{
	xfs_dahash_t hash;

	/*
	 * Do four characters at a time as long as we can.
	 */
	for (hash = 0; namelen >= 4; namelen -= 4, name += 4)
		hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
		       (name[3] << 0) ^ rol32(hash, 7 * 4);

	/*
	 * Now do the rest of the characters.
	 */
	switch (namelen) {
	case 3:
		return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
		       rol32(hash, 7 * 3);
	case 2:
		return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
	case 1:
		return (name[0] << 0) ^ rol32(hash, 7 * 1);
2011
	default: /* case 0: */
Linus Torvalds's avatar
Linus Torvalds committed
2012 2013 2014 2015
		return hash;
	}
}

2016 2017 2018
enum xfs_dacmp
xfs_da_compname(
	struct xfs_da_args *args,
2019 2020
	const unsigned char *name,
	int		len)
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
{
	return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
					XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
}

static xfs_dahash_t
xfs_default_hashname(
	struct xfs_name	*name)
{
	return xfs_da_hashname(name->name, name->len);
}

const struct xfs_nameops xfs_default_nameops = {
	.hashname	= xfs_default_hashname,
	.compname	= xfs_da_compname
};

Linus Torvalds's avatar
Linus Torvalds committed
2038
int
2039 2040 2041 2042
xfs_da_grow_inode_int(
	struct xfs_da_args	*args,
	xfs_fileoff_t		*bno,
	int			count)
Linus Torvalds's avatar
Linus Torvalds committed
2043
{
2044 2045 2046
	struct xfs_trans	*tp = args->trans;
	struct xfs_inode	*dp = args->dp;
	int			w = args->whichfork;
2047
	xfs_rfsblock_t		nblks = dp->i_d.di_nblocks;
2048 2049
	struct xfs_bmbt_irec	map, *mapp;
	int			nmap, error, got, i, mapi;
Linus Torvalds's avatar
Linus Torvalds committed
2050 2051 2052 2053

	/*
	 * Find a spot in the file space to put the new block.
	 */
2054 2055
	error = xfs_bmap_first_unused(tp, dp, count, bno, w);
	if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2056
		return error;
2057

Linus Torvalds's avatar
Linus Torvalds committed
2058 2059 2060 2061 2062
	/*
	 * Try mapping it in one filesystem block.
	 */
	nmap = 1;
	ASSERT(args->firstblock != NULL);
2063 2064
	error = xfs_bmapi_write(tp, dp, *bno, count,
			xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
2065
			args->firstblock, args->total, &map, &nmap);
2066
	if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2067
		return error;
2068

Linus Torvalds's avatar
Linus Torvalds committed
2069 2070 2071 2072
	ASSERT(nmap <= 1);
	if (nmap == 1) {
		mapp = &map;
		mapi = 1;
2073 2074 2075 2076 2077 2078 2079 2080
	} else if (nmap == 0 && count > 1) {
		xfs_fileoff_t		b;
		int			c;

		/*
		 * If we didn't get it and the block might work if fragmented,
		 * try without the CONTIG flag.  Loop until we get it all.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
2081
		mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP);
2082
		for (b = *bno, mapi = 0; b < *bno + count; ) {
Dave Chinner's avatar
Dave Chinner committed
2083
			nmap = min(XFS_BMAP_MAX_NMAP, count);
2084
			c = (int)(*bno + count - b);
2085 2086
			error = xfs_bmapi_write(tp, dp, b, c,
					xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA,
Linus Torvalds's avatar
Linus Torvalds committed
2087
					args->firstblock, args->total,
2088
					&mapp[mapi], &nmap);
2089 2090
			if (error)
				goto out_free_map;
Linus Torvalds's avatar
Linus Torvalds committed
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
			if (nmap < 1)
				break;
			mapi += nmap;
			b = mapp[mapi - 1].br_startoff +
			    mapp[mapi - 1].br_blockcount;
		}
	} else {
		mapi = 0;
		mapp = NULL;
	}
2101

Linus Torvalds's avatar
Linus Torvalds committed
2102 2103 2104 2105 2106
	/*
	 * Count the blocks we got, make sure it matches the total.
	 */
	for (i = 0, got = 0; i < mapi; i++)
		got += mapp[i].br_blockcount;
2107
	if (got != count || mapp[0].br_startoff != *bno ||
Linus Torvalds's avatar
Linus Torvalds committed
2108
	    mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
2109
	    *bno + count) {
2110
		error = -ENOSPC;
2111
		goto out_free_map;
Linus Torvalds's avatar
Linus Torvalds committed
2112
	}
2113

2114 2115
	/* account for newly allocated blocks in reserved blocks total */
	args->total -= dp->i_d.di_nblocks - nblks;
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134

out_free_map:
	if (mapp != &map)
		kmem_free(mapp);
	return error;
}

/*
 * Add a block to the btree ahead of the file.
 * Return the new block number to the caller.
 */
int
xfs_da_grow_inode(
	struct xfs_da_args	*args,
	xfs_dablk_t		*new_blkno)
{
	xfs_fileoff_t		bno;
	int			error;

2135 2136
	trace_xfs_da_grow_inode(args);

2137 2138
	bno = args->geo->leafblk;
	error = xfs_da_grow_inode_int(args, &bno, args->geo->fsbcount);
2139 2140 2141
	if (!error)
		*new_blkno = (xfs_dablk_t)bno;
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
}

/*
 * Ick.  We need to always be able to remove a btree block, even
 * if there's no space reservation because the filesystem is full.
 * This is called if xfs_bunmapi on a btree block fails due to ENOSPC.
 * It swaps the target block with the last block in the file.  The
 * last block in the file can always be removed since it can't cause
 * a bmap btree split to do that.
 */
STATIC int
2153 2154 2155 2156
xfs_da3_swap_lastblock(
	struct xfs_da_args	*args,
	xfs_dablk_t		*dead_blknop,
	struct xfs_buf		**dead_bufp)
Linus Torvalds's avatar
Linus Torvalds committed
2157
{
2158 2159 2160 2161 2162 2163 2164
	struct xfs_da_blkinfo	*dead_info;
	struct xfs_da_blkinfo	*sib_info;
	struct xfs_da_intnode	*par_node;
	struct xfs_da_intnode	*dead_node;
	struct xfs_dir2_leaf	*dead_leaf2;
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr par_hdr;
2165
	struct xfs_inode	*dp;
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182
	struct xfs_trans	*tp;
	struct xfs_mount	*mp;
	struct xfs_buf		*dead_buf;
	struct xfs_buf		*last_buf;
	struct xfs_buf		*sib_buf;
	struct xfs_buf		*par_buf;
	xfs_dahash_t		dead_hash;
	xfs_fileoff_t		lastoff;
	xfs_dablk_t		dead_blkno;
	xfs_dablk_t		last_blkno;
	xfs_dablk_t		sib_blkno;
	xfs_dablk_t		par_blkno;
	int			error;
	int			w;
	int			entno;
	int			level;
	int			dead_level;
Linus Torvalds's avatar
Linus Torvalds committed
2183

2184 2185
	trace_xfs_da_swap_lastblock(args);

Linus Torvalds's avatar
Linus Torvalds committed
2186 2187 2188
	dead_buf = *dead_bufp;
	dead_blkno = *dead_blknop;
	tp = args->trans;
2189
	dp = args->dp;
Linus Torvalds's avatar
Linus Torvalds committed
2190 2191
	w = args->whichfork;
	ASSERT(w == XFS_DATA_FORK);
2192
	mp = dp->i_mount;
2193
	lastoff = args->geo->freeblk;
2194
	error = xfs_bmap_last_before(tp, dp, &lastoff, w);
Linus Torvalds's avatar
Linus Torvalds committed
2195 2196 2197 2198 2199
	if (error)
		return error;
	if (unlikely(lastoff == 0)) {
		XFS_ERROR_REPORT("xfs_da_swap_lastblock(1)", XFS_ERRLEVEL_LOW,
				 mp);
2200
		return -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2201 2202 2203 2204
	}
	/*
	 * Read the last block in the btree space.
	 */
2205
	last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount;
2206
	error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w);
2207
	if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2208 2209 2210 2211
		return error;
	/*
	 * Copy the last block into the dead buffer and log it.
	 */
2212 2213
	memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize);
	xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1);
2214
	dead_info = dead_buf->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
2215 2216 2217
	/*
	 * Get values from the moved block.
	 */
2218 2219 2220 2221 2222
	if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
	    dead_info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
		struct xfs_dir3_icleaf_hdr leafhdr;
		struct xfs_dir2_leaf_entry *ents;

Linus Torvalds's avatar
Linus Torvalds committed
2223
		dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
2224
		dp->d_ops->leaf_hdr_from_disk(&leafhdr, dead_leaf2);
2225
		ents = dp->d_ops->leaf_ents_p(dead_leaf2);
Linus Torvalds's avatar
Linus Torvalds committed
2226
		dead_level = 0;
2227
		dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
2228
	} else {
2229 2230
		struct xfs_da3_icnode_hdr deadhdr;

Linus Torvalds's avatar
Linus Torvalds committed
2231
		dead_node = (xfs_da_intnode_t *)dead_info;
2232
		dp->d_ops->node_hdr_from_disk(&deadhdr, dead_node);
2233
		btree = dp->d_ops->node_tree_p(dead_node);
2234 2235
		dead_level = deadhdr.level;
		dead_hash = be32_to_cpu(btree[deadhdr.count - 1].hashval);
Linus Torvalds's avatar
Linus Torvalds committed
2236 2237 2238 2239 2240
	}
	sib_buf = par_buf = NULL;
	/*
	 * If the moved block has a left sibling, fix up the pointers.
	 */
2241
	if ((sib_blkno = be32_to_cpu(dead_info->back))) {
2242
		error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w);
2243
		if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2244
			goto done;
2245
		sib_info = sib_buf->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
2246
		if (unlikely(
2247 2248
		    be32_to_cpu(sib_info->forw) != last_blkno ||
		    sib_info->magic != dead_info->magic)) {
Linus Torvalds's avatar
Linus Torvalds committed
2249 2250
			XFS_ERROR_REPORT("xfs_da_swap_lastblock(2)",
					 XFS_ERRLEVEL_LOW, mp);
2251
			error = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2252 2253
			goto done;
		}
2254
		sib_info->forw = cpu_to_be32(dead_blkno);
2255
		xfs_trans_log_buf(tp, sib_buf,
Linus Torvalds's avatar
Linus Torvalds committed
2256 2257 2258 2259 2260 2261 2262
			XFS_DA_LOGRANGE(sib_info, &sib_info->forw,
					sizeof(sib_info->forw)));
		sib_buf = NULL;
	}
	/*
	 * If the moved block has a right sibling, fix up the pointers.
	 */
2263
	if ((sib_blkno = be32_to_cpu(dead_info->forw))) {
2264
		error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w);
2265
		if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2266
			goto done;
2267
		sib_info = sib_buf->b_addr;
Linus Torvalds's avatar
Linus Torvalds committed
2268
		if (unlikely(
2269 2270
		       be32_to_cpu(sib_info->back) != last_blkno ||
		       sib_info->magic != dead_info->magic)) {
Linus Torvalds's avatar
Linus Torvalds committed
2271 2272
			XFS_ERROR_REPORT("xfs_da_swap_lastblock(3)",
					 XFS_ERRLEVEL_LOW, mp);
2273
			error = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2274 2275
			goto done;
		}
2276
		sib_info->back = cpu_to_be32(dead_blkno);
2277
		xfs_trans_log_buf(tp, sib_buf,
Linus Torvalds's avatar
Linus Torvalds committed
2278 2279 2280 2281
			XFS_DA_LOGRANGE(sib_info, &sib_info->back,
					sizeof(sib_info->back)));
		sib_buf = NULL;
	}
2282
	par_blkno = args->geo->leafblk;
Linus Torvalds's avatar
Linus Torvalds committed
2283 2284 2285 2286 2287
	level = -1;
	/*
	 * Walk down the tree looking for the parent of the moved block.
	 */
	for (;;) {
2288
		error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w);
2289
		if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2290
			goto done;
2291
		par_node = par_buf->b_addr;
2292
		dp->d_ops->node_hdr_from_disk(&par_hdr, par_node);
2293
		if (level >= 0 && level != par_hdr.level + 1) {
Linus Torvalds's avatar
Linus Torvalds committed
2294 2295
			XFS_ERROR_REPORT("xfs_da_swap_lastblock(4)",
					 XFS_ERRLEVEL_LOW, mp);
2296
			error = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2297 2298
			goto done;
		}
2299
		level = par_hdr.level;
2300
		btree = dp->d_ops->node_tree_p(par_node);
Linus Torvalds's avatar
Linus Torvalds committed
2301
		for (entno = 0;
2302 2303
		     entno < par_hdr.count &&
		     be32_to_cpu(btree[entno].hashval) < dead_hash;
Linus Torvalds's avatar
Linus Torvalds committed
2304 2305
		     entno++)
			continue;
2306
		if (entno == par_hdr.count) {
Linus Torvalds's avatar
Linus Torvalds committed
2307 2308
			XFS_ERROR_REPORT("xfs_da_swap_lastblock(5)",
					 XFS_ERRLEVEL_LOW, mp);
2309
			error = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2310 2311
			goto done;
		}
2312
		par_blkno = be32_to_cpu(btree[entno].before);
Linus Torvalds's avatar
Linus Torvalds committed
2313 2314
		if (level == dead_level + 1)
			break;
2315
		xfs_trans_brelse(tp, par_buf);
Linus Torvalds's avatar
Linus Torvalds committed
2316 2317 2318 2319 2320 2321 2322 2323
		par_buf = NULL;
	}
	/*
	 * We're in the right parent block.
	 * Look for the right entry.
	 */
	for (;;) {
		for (;
2324 2325
		     entno < par_hdr.count &&
		     be32_to_cpu(btree[entno].before) != last_blkno;
Linus Torvalds's avatar
Linus Torvalds committed
2326 2327
		     entno++)
			continue;
2328
		if (entno < par_hdr.count)
Linus Torvalds's avatar
Linus Torvalds committed
2329
			break;
2330
		par_blkno = par_hdr.forw;
2331
		xfs_trans_brelse(tp, par_buf);
Linus Torvalds's avatar
Linus Torvalds committed
2332 2333 2334 2335
		par_buf = NULL;
		if (unlikely(par_blkno == 0)) {
			XFS_ERROR_REPORT("xfs_da_swap_lastblock(6)",
					 XFS_ERRLEVEL_LOW, mp);
2336
			error = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2337 2338
			goto done;
		}
2339
		error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w);
2340
		if (error)
Linus Torvalds's avatar
Linus Torvalds committed
2341
			goto done;
2342
		par_node = par_buf->b_addr;
2343
		dp->d_ops->node_hdr_from_disk(&par_hdr, par_node);
2344
		if (par_hdr.level != level) {
Linus Torvalds's avatar
Linus Torvalds committed
2345 2346
			XFS_ERROR_REPORT("xfs_da_swap_lastblock(7)",
					 XFS_ERRLEVEL_LOW, mp);
2347
			error = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
2348 2349
			goto done;
		}
2350
		btree = dp->d_ops->node_tree_p(par_node);
Linus Torvalds's avatar
Linus Torvalds committed
2351 2352 2353 2354 2355
		entno = 0;
	}
	/*
	 * Update the parent entry pointing to the moved block.
	 */
2356
	btree[entno].before = cpu_to_be32(dead_blkno);
2357
	xfs_trans_log_buf(tp, par_buf,
2358 2359
		XFS_DA_LOGRANGE(par_node, &btree[entno].before,
				sizeof(btree[entno].before)));
Linus Torvalds's avatar
Linus Torvalds committed
2360 2361 2362 2363 2364
	*dead_blknop = last_blkno;
	*dead_bufp = last_buf;
	return 0;
done:
	if (par_buf)
2365
		xfs_trans_brelse(tp, par_buf);
Linus Torvalds's avatar
Linus Torvalds committed
2366
	if (sib_buf)
2367 2368
		xfs_trans_brelse(tp, sib_buf);
	xfs_trans_brelse(tp, last_buf);
Linus Torvalds's avatar
Linus Torvalds committed
2369 2370 2371 2372 2373 2374 2375
	return error;
}

/*
 * Remove a btree block from a directory or attribute.
 */
int
2376
xfs_da_shrink_inode(
2377 2378 2379
	struct xfs_da_args	*args,
	xfs_dablk_t		dead_blkno,
	struct xfs_buf		*dead_buf)
Linus Torvalds's avatar
Linus Torvalds committed
2380
{
2381 2382 2383
	struct xfs_inode	*dp;
	int			done, error, w, count;
	struct xfs_trans	*tp;
Linus Torvalds's avatar
Linus Torvalds committed
2384

2385 2386
	trace_xfs_da_shrink_inode(args);

Linus Torvalds's avatar
Linus Torvalds committed
2387 2388 2389
	dp = args->dp;
	w = args->whichfork;
	tp = args->trans;
2390
	count = args->geo->fsbcount;
Linus Torvalds's avatar
Linus Torvalds committed
2391 2392 2393 2394 2395
	for (;;) {
		/*
		 * Remove extents.  If we get ENOSPC for a dir we have to move
		 * the last block to the place we want to kill.
		 */
2396
		error = xfs_bunmapi(tp, dp, dead_blkno, count,
2397
				    xfs_bmapi_aflag(w), 0, args->firstblock,
2398
				    args->trans->t_dfops, &done);
2399
		if (error == -ENOSPC) {
Linus Torvalds's avatar
Linus Torvalds committed
2400
			if (w != XFS_DATA_FORK)
2401
				break;
2402 2403 2404
			error = xfs_da3_swap_lastblock(args, &dead_blkno,
						      &dead_buf);
			if (error)
2405 2406
				break;
		} else {
Linus Torvalds's avatar
Linus Torvalds committed
2407 2408 2409
			break;
		}
	}
2410
	xfs_trans_binval(tp, dead_buf);
Linus Torvalds's avatar
Linus Torvalds committed
2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441
	return error;
}

/*
 * See if the mapping(s) for this btree block are valid, i.e.
 * don't contain holes, are logically contiguous, and cover the whole range.
 */
STATIC int
xfs_da_map_covers_blocks(
	int		nmap,
	xfs_bmbt_irec_t	*mapp,
	xfs_dablk_t	bno,
	int		count)
{
	int		i;
	xfs_fileoff_t	off;

	for (i = 0, off = bno; i < nmap; i++) {
		if (mapp[i].br_startblock == HOLESTARTBLOCK ||
		    mapp[i].br_startblock == DELAYSTARTBLOCK) {
			return 0;
		}
		if (off != mapp[i].br_startoff) {
			return 0;
		}
		off += mapp[i].br_blockcount;
	}
	return off == bno + count;
}

/*
2442 2443 2444 2445 2446 2447
 * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map.
 *
 * For the single map case, it is assumed that the caller has provided a pointer
 * to a valid xfs_buf_map.  For the multiple map case, this function will
 * allocate the xfs_buf_map to hold all the maps and replace the caller's single
 * map pointer with the allocated map.
Linus Torvalds's avatar
Linus Torvalds committed
2448
 */
2449 2450 2451 2452
static int
xfs_buf_map_from_irec(
	struct xfs_mount	*mp,
	struct xfs_buf_map	**mapp,
2453
	int			*nmaps,
2454
	struct xfs_bmbt_irec	*irecs,
2455
	int			nirecs)
Linus Torvalds's avatar
Linus Torvalds committed
2456
{
2457 2458 2459 2460 2461 2462 2463
	struct xfs_buf_map	*map;
	int			i;

	ASSERT(*nmaps == 1);
	ASSERT(nirecs >= 1);

	if (nirecs > 1) {
2464 2465
		map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map),
				  KM_SLEEP | KM_NOFS);
2466
		if (!map)
2467
			return -ENOMEM;
2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507
		*mapp = map;
	}

	*nmaps = nirecs;
	map = *mapp;
	for (i = 0; i < *nmaps; i++) {
		ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK &&
		       irecs[i].br_startblock != HOLESTARTBLOCK);
		map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock);
		map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount);
	}
	return 0;
}

/*
 * Map the block we are given ready for reading. There are three possible return
 * values:
 *	-1 - will be returned if we land in a hole and mappedbno == -2 so the
 *	     caller knows not to execute a subsequent read.
 *	 0 - if we mapped the block successfully
 *	>0 - positive error number if there was an error.
 */
static int
xfs_dabuf_map(
	struct xfs_inode	*dp,
	xfs_dablk_t		bno,
	xfs_daddr_t		mappedbno,
	int			whichfork,
	struct xfs_buf_map	**map,
	int			*nmaps)
{
	struct xfs_mount	*mp = dp->i_mount;
	int			nfsb;
	int			error = 0;
	struct xfs_bmbt_irec	irec;
	struct xfs_bmbt_irec	*irecs = &irec;
	int			nirecs;

	ASSERT(map && *map);
	ASSERT(*nmaps == 1);
Linus Torvalds's avatar
Linus Torvalds committed
2508

2509 2510 2511 2512
	if (whichfork == XFS_DATA_FORK)
		nfsb = mp->m_dir_geo->fsbcount;
	else
		nfsb = mp->m_attr_geo->fsbcount;
2513

Linus Torvalds's avatar
Linus Torvalds committed
2514 2515 2516 2517 2518 2519 2520 2521
	/*
	 * Caller doesn't have a mapping.  -2 means don't complain
	 * if we land in a hole.
	 */
	if (mappedbno == -1 || mappedbno == -2) {
		/*
		 * Optimize the one-block case.
		 */
2522
		if (nfsb != 1)
2523 2524
			irecs = kmem_zalloc(sizeof(irec) * nfsb,
					    KM_SLEEP | KM_NOFS);
2525

2526 2527 2528
		nirecs = nfsb;
		error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs,
				       &nirecs, xfs_bmapi_aflag(whichfork));
2529
		if (error)
2530
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
2531
	} else {
2532 2533 2534 2535 2536
		irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno);
		irecs->br_startoff = (xfs_fileoff_t)bno;
		irecs->br_blockcount = nfsb;
		irecs->br_state = 0;
		nirecs = 1;
Linus Torvalds's avatar
Linus Torvalds committed
2537
	}
2538 2539

	if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) {
2540 2541
		error = mappedbno == -2 ? -1 : -EFSCORRUPTED;
		if (unlikely(error == -EFSCORRUPTED)) {
Linus Torvalds's avatar
Linus Torvalds committed
2542
			if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
2543
				int i;
2544 2545
				xfs_alert(mp, "%s: bno %lld dir: inode %lld",
					__func__, (long long)bno,
Linus Torvalds's avatar
Linus Torvalds committed
2546
					(long long)dp->i_ino);
2547
				for (i = 0; i < *nmaps; i++) {
2548 2549
					xfs_alert(mp,
"[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d",
Linus Torvalds's avatar
Linus Torvalds committed
2550
						i,
2551 2552 2553 2554
						(long long)irecs[i].br_startoff,
						(long long)irecs[i].br_startblock,
						(long long)irecs[i].br_blockcount,
						irecs[i].br_state);
Linus Torvalds's avatar
Linus Torvalds committed
2555 2556 2557 2558 2559
				}
			}
			XFS_ERROR_REPORT("xfs_da_do_buf(1)",
					 XFS_ERRLEVEL_LOW, mp);
		}
2560
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
2561
	}
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
	error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs);
out:
	if (irecs != &irec)
		kmem_free(irecs);
	return error;
}

/*
 * Get a buffer for the dir/attr block.
 */
int
xfs_da_get_buf(
	struct xfs_trans	*trans,
	struct xfs_inode	*dp,
	xfs_dablk_t		bno,
	xfs_daddr_t		mappedbno,
2578
	struct xfs_buf		**bpp,
2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
	int			whichfork)
{
	struct xfs_buf		*bp;
	struct xfs_buf_map	map;
	struct xfs_buf_map	*mapp;
	int			nmap;
	int			error;

	*bpp = NULL;
	mapp = &map;
	nmap = 1;
2590
	error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
2591 2592 2593 2594
				&mapp, &nmap);
	if (error) {
		/* mapping a hole is not an error, but we don't continue */
		if (error == -1)
Linus Torvalds's avatar
Linus Torvalds committed
2595
			error = 0;
2596
		goto out_free;
Linus Torvalds's avatar
Linus Torvalds committed
2597
	}
2598 2599 2600

	bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp,
				    mapp, nmap, 0);
2601
	error = bp ? bp->b_error : -EIO;
2602
	if (error) {
2603 2604
		if (bp)
			xfs_trans_brelse(trans, bp);
2605 2606 2607
		goto out_free;
	}

2608
	*bpp = bp;
2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625

out_free:
	if (mapp != &map)
		kmem_free(mapp);

	return error;
}

/*
 * Get a buffer for the dir/attr block, fill in the contents.
 */
int
xfs_da_read_buf(
	struct xfs_trans	*trans,
	struct xfs_inode	*dp,
	xfs_dablk_t		bno,
	xfs_daddr_t		mappedbno,
2626
	struct xfs_buf		**bpp,
2627
	int			whichfork,
2628
	const struct xfs_buf_ops *ops)
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638
{
	struct xfs_buf		*bp;
	struct xfs_buf_map	map;
	struct xfs_buf_map	*mapp;
	int			nmap;
	int			error;

	*bpp = NULL;
	mapp = &map;
	nmap = 1;
2639
	error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
				&mapp, &nmap);
	if (error) {
		/* mapping a hole is not an error, but we don't continue */
		if (error == -1)
			error = 0;
		goto out_free;
	}

	error = xfs_trans_read_buf_map(dp->i_mount, trans,
					dp->i_mount->m_ddev_targp,
2650
					mapp, nmap, 0, &bp, ops);
2651 2652 2653 2654 2655
	if (error)
		goto out_free;

	if (whichfork == XFS_ATTR_FORK)
		xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
Linus Torvalds's avatar
Linus Torvalds committed
2656
	else
2657
		xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
2658
	*bpp = bp;
2659
out_free:
Linus Torvalds's avatar
Linus Torvalds committed
2660
	if (mapp != &map)
2661
		kmem_free(mapp);
Linus Torvalds's avatar
Linus Torvalds committed
2662

2663
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
2664 2665 2666 2667 2668
}

/*
 * Readahead the dir/attr block.
 */
2669
int
Linus Torvalds's avatar
Linus Torvalds committed
2670
xfs_da_reada_buf(
2671 2672
	struct xfs_inode	*dp,
	xfs_dablk_t		bno,
2673
	xfs_daddr_t		mappedbno,
2674
	int			whichfork,
2675
	const struct xfs_buf_ops *ops)
Linus Torvalds's avatar
Linus Torvalds committed
2676
{
2677 2678 2679 2680 2681 2682 2683
	struct xfs_buf_map	map;
	struct xfs_buf_map	*mapp;
	int			nmap;
	int			error;

	mapp = &map;
	nmap = 1;
2684
	error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
2685 2686 2687 2688 2689 2690 2691
				&mapp, &nmap);
	if (error) {
		/* mapping a hole is not an error, but we don't continue */
		if (error == -1)
			error = 0;
		goto out_free;
	}
Linus Torvalds's avatar
Linus Torvalds committed
2692

2693
	mappedbno = mapp[0].bm_bn;
2694
	xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, ops);
2695 2696 2697 2698 2699

out_free:
	if (mapp != &map)
		kmem_free(mapp);

2700
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
2701
}