xfs_attr.c 31.8 KB
Newer Older
D
Dave Chinner 已提交
1
// SPDX-License-Identifier: GPL-2.0
L
Linus Torvalds 已提交
2
/*
3 4
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
L
Linus Torvalds 已提交
5 6
 */
#include "xfs.h"
7
#include "xfs_fs.h"
8
#include "xfs_shared.h"
9 10 11
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
L
Linus Torvalds 已提交
12
#include "xfs_mount.h"
13
#include "xfs_defer.h"
14
#include "xfs_da_format.h"
15 16
#include "xfs_da_btree.h"
#include "xfs_attr_sf.h"
L
Linus Torvalds 已提交
17
#include "xfs_inode.h"
18
#include "xfs_trans.h"
L
Linus Torvalds 已提交
19
#include "xfs_bmap.h"
20
#include "xfs_bmap_btree.h"
L
Linus Torvalds 已提交
21 22
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
23
#include "xfs_attr_remote.h"
L
Linus Torvalds 已提交
24 25
#include "xfs_quota.h"
#include "xfs_trans_space.h"
C
Christoph Hellwig 已提交
26
#include "xfs_trace.h"
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

/*
 * xfs_attr.c
 *
 * Provide the external interfaces to manage attribute lists.
 */

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

/*
 * Internal routines when attribute list fits inside the inode.
 */
STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);

/*
 * Internal routines when attribute list is one block.
 */
46
STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
L
Linus Torvalds 已提交
47 48 49 50 51 52
STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);

/*
 * Internal routines when attribute list is more than one block.
 */
53
STATIC int xfs_attr_node_get(xfs_da_args_t *args);
L
Linus Torvalds 已提交
54 55 56 57 58
STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
STATIC int xfs_attr_refillstate(xfs_da_state_t *state);

59
int
60 61 62 63 64 65 66 67 68 69
xfs_inode_hasattr(
	struct xfs_inode	*ip)
{
	if (!XFS_IFORK_Q(ip) ||
	    (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
	     ip->i_d.di_anextents == 0))
		return 0;
	return 1;
}

L
Linus Torvalds 已提交
70 71 72 73
/*========================================================================
 * Overall external interface routines.
 *========================================================================*/

74 75 76 77
/*
 * Retrieve an extended attribute and its value.  Must have ilock.
 * Returns 0 on successful retrieval, otherwise an error.
 */
78 79 80 81
int
xfs_attr_get_ilocked(
	struct xfs_da_args	*args)
{
82
	ASSERT(xfs_isilocked(args->dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
83

84
	if (!xfs_inode_hasattr(args->dp))
85
		return -ENOATTR;
86 87

	if (args->dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
88
		return xfs_attr_shortform_getvalue(args);
89
	if (xfs_bmap_one_block(args->dp, XFS_ATTR_FORK))
90
		return xfs_attr_leaf_get(args);
91
	return xfs_attr_node_get(args);
92 93
}

94 95 96
/*
 * Retrieve an extended attribute by name, and its value if requested.
 *
C
Christoph Hellwig 已提交
97 98 99
 * If args->valuelen is zero, then the caller does not want the value, just an
 * indication whether the attribute exists and the size of the value if it
 * exists. The size is returned in args.valuelen.
100 101
 *
 * If the attribute is found, but exceeds the size limit set by the caller in
102 103
 * args->valuelen, return -ERANGE with the size of the attribute that was found
 * in args->valuelen.
104
 *
105
 * If ATTR_ALLOC is set in args->flags, allocate the buffer for the value after
106 107 108 109 110
 * existence of the attribute has been determined. On success, return that
 * buffer to the caller and leave them to free it. On failure, free any
 * allocated buffer and ensure the buffer pointer returned to the caller is
 * null.
 */
111 112
int
xfs_attr_get(
113
	struct xfs_da_args	*args)
L
Linus Torvalds 已提交
114
{
115 116 117
	uint			lock_mode;
	int			error;

C
Christoph Hellwig 已提交
118
	ASSERT((args->flags & ATTR_ALLOC) || !args->valuelen || args->value);
119

120
	XFS_STATS_INC(args->dp->i_mount, xs_attr_get);
121

122
	if (XFS_FORCED_SHUTDOWN(args->dp->i_mount))
D
Dave Chinner 已提交
123
		return -EIO;
L
Linus Torvalds 已提交
124

125 126 127
	args->geo = args->dp->i_mount->m_attr_geo;
	args->whichfork = XFS_ATTR_FORK;
	args->hashval = xfs_da_hashname(args->name, args->namelen);
128

129
	/* Entirely possible to look up a name which doesn't exist */
130 131 132
	args->op_flags = XFS_DA_OP_OKNOENT;
	if (args->flags & ATTR_ALLOC)
		args->op_flags |= XFS_DA_OP_ALLOCVAL;
L
Linus Torvalds 已提交
133

134
	lock_mode = xfs_ilock_attr_map_shared(args->dp);
135
	error = xfs_attr_get_ilocked(args);
136
	xfs_iunlock(args->dp, lock_mode);
137 138

	/* on error, we have to clean up allocated value buffers */
139 140 141
	if (error && (args->flags & ATTR_ALLOC)) {
		kmem_free(args->value);
		args->value = NULL;
142
	}
143
	return error;
L
Linus Torvalds 已提交
144 145
}

146 147 148
/*
 * Calculate how many blocks we need for the new attribute,
 */
149
STATIC int
150
xfs_attr_calc_size(
151
	struct xfs_da_args	*args,
152 153
	int			*local)
{
154
	struct xfs_mount	*mp = args->dp->i_mount;
155 156 157 158 159 160 161
	int			size;
	int			nblks;

	/*
	 * Determine space new attribute will use, and if it would be
	 * "local" or "remote" (note: local != inline).
	 */
162
	size = xfs_attr_leaf_newentsize(args, local);
163 164
	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
	if (*local) {
165
		if (size > (args->geo->blksize / 2)) {
166 167 168 169 170 171 172 173
			/* Double split possible */
			nblks *= 2;
		}
	} else {
		/*
		 * Out of line attribute, cannot double split, but
		 * make room for the attribute value itself.
		 */
174
		uint	dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
175 176 177 178 179 180 181
		nblks += dblocks;
		nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
	}

	return nblks;
}

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
STATIC int
xfs_attr_try_sf_addname(
	struct xfs_inode	*dp,
	struct xfs_da_args	*args)
{

	struct xfs_mount	*mp = dp->i_mount;
	int			error, error2;

	error = xfs_attr_shortform_addname(args);
	if (error == -ENOSPC)
		return error;

	/*
	 * Commit the shortform mods, and we're done.
	 * NOTE: this is also the error path (EEXIST, etc).
	 */
	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);

	if (mp->m_flags & XFS_MOUNT_WSYNC)
		xfs_trans_set_sync(args->trans);

	error2 = xfs_trans_commit(args->trans);
206
	args->trans = NULL;
207 208 209
	return error ? error : error2;
}

210 211 212 213 214
/*
 * Set the attribute specified in @args.
 */
int
xfs_attr_set_args(
215
	struct xfs_da_args	*args)
216 217
{
	struct xfs_inode	*dp = args->dp;
218
	struct xfs_buf          *leaf_bp = NULL;
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	int			error;

	/*
	 * If the attribute list is non-existent or a shortform list,
	 * upgrade it to a single-leaf-block attribute list.
	 */
	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
	     dp->i_d.di_anextents == 0)) {

		/*
		 * Build initial attribute list (if required).
		 */
		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
			xfs_attr_shortform_create(args);

		/*
		 * Try to add the attr to the attribute list in the inode.
		 */
		error = xfs_attr_try_sf_addname(dp, args);
		if (error != -ENOSPC)
			return error;

		/*
		 * It won't fit in the shortform, transform to a leaf block.
		 * GROT: another possible req'mt for a double-split btree op.
		 */
246
		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
247 248 249 250 251 252 253
		if (error)
			return error;

		/*
		 * Prevent the leaf buffer from being unlocked so that a
		 * concurrent AIL push cannot grab the half-baked leaf
		 * buffer and run into problems with the write verifier.
254 255
		 * Once we're done rolling the transaction we can release
		 * the hold and add the attr to the leaf.
256
		 */
257
		xfs_trans_bhold(args->trans, leaf_bp);
258
		error = xfs_defer_finish(&args->trans);
259 260 261
		xfs_trans_bhold_release(args->trans, leaf_bp);
		if (error) {
			xfs_trans_brelse(args->trans, leaf_bp);
262
			return error;
263
		}
264 265 266 267 268 269 270 271 272
	}

	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
		error = xfs_attr_leaf_addname(args);
	else
		error = xfs_attr_node_addname(args);
	return error;
}

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
/*
 * Remove the attribute specified in @args.
 */
int
xfs_attr_remove_args(
	struct xfs_da_args      *args)
{
	struct xfs_inode	*dp = args->dp;
	int			error;

	if (!xfs_inode_hasattr(dp)) {
		error = -ENOATTR;
	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
		error = xfs_attr_shortform_remove(args);
	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
		error = xfs_attr_leaf_removename(args);
	} else {
		error = xfs_attr_node_removename(args);
	}

	return error;
}

297
/*
298
 * Note: If args->value is NULL the attribute will be removed, just like the
299 300
 * Linux ->setattr API.
 */
301 302
int
xfs_attr_set(
303
	struct xfs_da_args	*args)
L
Linus Torvalds 已提交
304
{
305
	struct xfs_inode	*dp = args->dp;
306 307
	struct xfs_mount	*mp = dp->i_mount;
	struct xfs_trans_res	tres;
308
	int			rsvd = (args->flags & ATTR_ROOT) != 0;
309
	int			error, local;
310
	unsigned int		total;
311 312

	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
D
Dave Chinner 已提交
313
		return -EIO;
314

315 316 317 318
	error = xfs_qm_dqattach(dp);
	if (error)
		return error;

319 320 321
	args->geo = mp->m_attr_geo;
	args->whichfork = XFS_ATTR_FORK;
	args->hashval = xfs_da_hashname(args->name, args->namelen);
L
Linus Torvalds 已提交
322 323

	/*
324 325 326
	 * We have no control over the attribute names that userspace passes us
	 * to remove, so we have to allow the name lookup prior to attribute
	 * removal to fail as well.
L
Linus Torvalds 已提交
327
	 */
328
	args->op_flags = XFS_DA_OP_OKNOENT;
329

330
	if (args->value) {
331 332
		XFS_STATS_INC(mp, xs_attr_set);

333 334
		args->op_flags |= XFS_DA_OP_ADDNAME;
		args->total = xfs_attr_calc_size(args, &local);
335 336 337 338 339 340 341

		/*
		 * If the inode doesn't have an attribute fork, add one.
		 * (inode must not be locked when we call this routine)
		 */
		if (XFS_IFORK_Q(dp) == 0) {
			int sf_size = sizeof(struct xfs_attr_sf_hdr) +
342 343
				XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen,
						args->valuelen);
344 345 346 347 348 349 350

			error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
			if (error)
				return error;
		}

		tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
351 352
				 M_RES(mp)->tr_attrsetrt.tr_logres *
					args->total;
353 354
		tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
		tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
355
		total = args->total;
356 357
	} else {
		XFS_STATS_INC(mp, xs_attr_remove);
L
Linus Torvalds 已提交
358

359 360 361
		tres = M_RES(mp)->tr_attrrm;
		total = XFS_ATTRRM_SPACE_RES(mp);
	}
L
Linus Torvalds 已提交
362 363 364 365 366

	/*
	 * Root fork attributes can use reserved data blocks for this
	 * operation if necessary
	 */
367
	error = xfs_trans_alloc(mp, &tres, total, 0,
368
			rsvd ? XFS_TRANS_RESERVE : 0, &args->trans);
369
	if (error)
370
		return error;
L
Linus Torvalds 已提交
371

372
	xfs_ilock(dp, XFS_ILOCK_EXCL);
373 374
	xfs_trans_ijoin(args->trans, dp, 0);
	if (args->value) {
375 376 377 378
		unsigned int	quota_flags = XFS_QMOPT_RES_REGBLKS;

		if (rsvd)
			quota_flags |= XFS_QMOPT_FORCE_RES;
379 380
		error = xfs_trans_reserve_quota_nblks(args->trans, dp,
				args->total, 0, quota_flags);
381 382
		if (error)
			goto out_trans_cancel;
383
		error = xfs_attr_set_args(args);
384 385
		if (error)
			goto out_trans_cancel;
386
		/* shortform attribute has already been committed */
387
		if (!args->trans)
388 389
			goto out_unlock;
	} else {
390
		error = xfs_attr_remove_args(args);
391 392
		if (error)
			goto out_trans_cancel;
393
	}
L
Linus Torvalds 已提交
394 395 396 397 398

	/*
	 * If this is a synchronous mount, make sure that the
	 * transaction goes to disk before returning to the user.
	 */
399
	if (mp->m_flags & XFS_MOUNT_WSYNC)
400
		xfs_trans_set_sync(args->trans);
L
Linus Torvalds 已提交
401

402 403
	if ((args->flags & ATTR_KERNOTIME) == 0)
		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
404

L
Linus Torvalds 已提交
405 406 407
	/*
	 * Commit the last in the sequence of transactions.
	 */
408 409
	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
	error = xfs_trans_commit(args->trans);
410
out_unlock:
L
Linus Torvalds 已提交
411
	xfs_iunlock(dp, XFS_ILOCK_EXCL);
412
	return error;
L
Linus Torvalds 已提交
413

414
out_trans_cancel:
415 416
	if (args->trans)
		xfs_trans_cancel(args->trans);
417
	goto out_unlock;
L
Linus Torvalds 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430
}

/*========================================================================
 * External routines when attribute list is inside the inode
 *========================================================================*/

/*
 * Add a name to the shortform attribute list structure
 * This is the external routine.
 */
STATIC int
xfs_attr_shortform_addname(xfs_da_args_t *args)
{
431
	int newsize, forkoff, retval;
L
Linus Torvalds 已提交
432

433 434
	trace_xfs_attr_sf_addname(args);

L
Linus Torvalds 已提交
435
	retval = xfs_attr_shortform_lookup(args);
D
Dave Chinner 已提交
436
	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
E
Eric Sandeen 已提交
437
		return retval;
D
Dave Chinner 已提交
438
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
439
		if (args->flags & ATTR_CREATE)
E
Eric Sandeen 已提交
440
			return retval;
L
Linus Torvalds 已提交
441
		retval = xfs_attr_shortform_remove(args);
442 443 444 445 446 447 448 449
		if (retval)
			return retval;
		/*
		 * Since we have removed the old attr, clear ATTR_REPLACE so
		 * that the leaf format add routine won't trip over the attr
		 * not being around.
		 */
		args->flags &= ~ATTR_REPLACE;
L
Linus Torvalds 已提交
450 451
	}

452 453
	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
D
Dave Chinner 已提交
454
		return -ENOSPC;
455

L
Linus Torvalds 已提交
456 457
	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
458 459 460

	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
	if (!forkoff)
D
Dave Chinner 已提交
461
		return -ENOSPC;
462 463

	xfs_attr_shortform_add(args, forkoff);
E
Eric Sandeen 已提交
464
	return 0;
L
Linus Torvalds 已提交
465 466 467 468 469 470 471 472 473 474 475 476 477
}


/*========================================================================
 * External routines when attribute list is one block
 *========================================================================*/

/*
 * Add a name to the leaf attribute list structure
 *
 * This leaf block cannot have a "remote" value, we only call this routine
 * if bmap_one_block() says there is only one block (ie: no remote blks).
 */
D
David Chinner 已提交
478
STATIC int
479 480
xfs_attr_leaf_addname(
	struct xfs_da_args	*args)
L
Linus Torvalds 已提交
481
{
482 483 484
	struct xfs_inode	*dp;
	struct xfs_buf		*bp;
	int			retval, error, forkoff;
L
Linus Torvalds 已提交
485

486 487
	trace_xfs_attr_leaf_addname(args);

L
Linus Torvalds 已提交
488 489 490 491 492
	/*
	 * Read the (only) block in the attribute list in.
	 */
	dp = args->dp;
	args->blkno = 0;
493
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
L
Linus Torvalds 已提交
494
	if (error)
495
		return error;
L
Linus Torvalds 已提交
496 497 498 499 500

	/*
	 * Look up the given attribute in the leaf block.  Figure out if
	 * the given flags produce an error or call for an atomic rename.
	 */
D
Dave Chinner 已提交
501
	retval = xfs_attr3_leaf_lookup_int(bp, args);
D
Dave Chinner 已提交
502
	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
503
		xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
504
		return retval;
D
Dave Chinner 已提交
505
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
506
		if (args->flags & ATTR_CREATE) {	/* pure create op */
507
			xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
508
			return retval;
L
Linus Torvalds 已提交
509
		}
510 511 512

		trace_xfs_attr_leaf_replace(args);

513
		/* save the attribute state for later removal*/
514
		args->op_flags |= XFS_DA_OP_RENAME;	/* an atomic rename */
L
Linus Torvalds 已提交
515 516 517 518
		args->blkno2 = args->blkno;		/* set 2nd entry info*/
		args->index2 = args->index;
		args->rmtblkno2 = args->rmtblkno;
		args->rmtblkcnt2 = args->rmtblkcnt;
519 520 521 522 523 524 525 526 527 528
		args->rmtvaluelen2 = args->rmtvaluelen;

		/*
		 * clear the remote attr state now that it is saved so that the
		 * values reflect the state of the attribute we are about to
		 * add, not the attribute we just found and will remove later.
		 */
		args->rmtblkno = 0;
		args->rmtblkcnt = 0;
		args->rmtvaluelen = 0;
L
Linus Torvalds 已提交
529 530 531 532 533 534
	}

	/*
	 * Add the attribute to the leaf block, transitioning to a Btree
	 * if required.
	 */
D
Dave Chinner 已提交
535
	retval = xfs_attr3_leaf_add(bp, args);
D
Dave Chinner 已提交
536
	if (retval == -ENOSPC) {
L
Linus Torvalds 已提交
537 538 539 540 541
		/*
		 * Promote the attribute list to the Btree format, then
		 * Commit that transaction so that the node_addname() call
		 * can manage its own transactions.
		 */
D
Dave Chinner 已提交
542
		error = xfs_attr3_leaf_to_node(args);
543
		if (error)
544
			return error;
545
		error = xfs_defer_finish(&args->trans);
546
		if (error)
547
			return error;
L
Linus Torvalds 已提交
548 549 550 551 552

		/*
		 * Commit the current trans (including the inode) and start
		 * a new one.
		 */
C
Christoph Hellwig 已提交
553
		error = xfs_trans_roll_inode(&args->trans, dp);
554
		if (error)
E
Eric Sandeen 已提交
555
			return error;
L
Linus Torvalds 已提交
556 557 558 559 560

		/*
		 * Fob the whole rest of the problem off on the Btree code.
		 */
		error = xfs_attr_node_addname(args);
E
Eric Sandeen 已提交
561
		return error;
L
Linus Torvalds 已提交
562 563 564 565 566 567
	}

	/*
	 * Commit the transaction that added the attr name so that
	 * later routines can manage their own transactions.
	 */
C
Christoph Hellwig 已提交
568
	error = xfs_trans_roll_inode(&args->trans, dp);
569
	if (error)
E
Eric Sandeen 已提交
570
		return error;
L
Linus Torvalds 已提交
571 572 573 574 575 576 577 578 579 580

	/*
	 * If there was an out-of-line value, allocate the blocks we
	 * identified for its storage and copy the value.  This is done
	 * after we create the attribute so that we don't overflow the
	 * maximum size of a transaction and/or hit a deadlock.
	 */
	if (args->rmtblkno > 0) {
		error = xfs_attr_rmtval_set(args);
		if (error)
E
Eric Sandeen 已提交
581
			return error;
L
Linus Torvalds 已提交
582 583 584 585 586 587 588 589
	}

	/*
	 * If this is an atomic rename operation, we must "flip" the
	 * incomplete flags on the "new" and "old" attribute/value pairs
	 * so that one disappears and one appears atomically.  Then we
	 * must remove the "old" attribute/value pair.
	 */
590
	if (args->op_flags & XFS_DA_OP_RENAME) {
L
Linus Torvalds 已提交
591 592 593 594
		/*
		 * In a separate transaction, set the incomplete flag on the
		 * "old" attr and clear the incomplete flag on the "new" attr.
		 */
D
Dave Chinner 已提交
595
		error = xfs_attr3_leaf_flipflags(args);
L
Linus Torvalds 已提交
596
		if (error)
E
Eric Sandeen 已提交
597
			return error;
L
Linus Torvalds 已提交
598 599 600 601 602 603 604 605 606

		/*
		 * Dismantle the "old" attribute/value pair by removing
		 * a "remote" value (if it exists).
		 */
		args->index = args->index2;
		args->blkno = args->blkno2;
		args->rmtblkno = args->rmtblkno2;
		args->rmtblkcnt = args->rmtblkcnt2;
607
		args->rmtvaluelen = args->rmtvaluelen2;
L
Linus Torvalds 已提交
608 609 610
		if (args->rmtblkno) {
			error = xfs_attr_rmtval_remove(args);
			if (error)
E
Eric Sandeen 已提交
611
				return error;
L
Linus Torvalds 已提交
612 613 614 615 616 617
		}

		/*
		 * Read in the block containing the "old" attr, then
		 * remove the "old" attr from that block (neat, huh!)
		 */
D
Dave Chinner 已提交
618
		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
619
					   &bp);
L
Linus Torvalds 已提交
620
		if (error)
621 622
			return error;

D
Dave Chinner 已提交
623
		xfs_attr3_leaf_remove(bp, args);
L
Linus Torvalds 已提交
624 625 626 627

		/*
		 * If the result is small enough, shrink it all into the inode.
		 */
628
		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
D
Dave Chinner 已提交
629
			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
L
Linus Torvalds 已提交
630
			/* bp is gone due to xfs_da_shrink_inode */
631
			if (error)
632
				return error;
633
			error = xfs_defer_finish(&args->trans);
634
			if (error)
635
				return error;
636
		}
L
Linus Torvalds 已提交
637 638 639 640

		/*
		 * Commit the remove and start the next trans in series.
		 */
C
Christoph Hellwig 已提交
641
		error = xfs_trans_roll_inode(&args->trans, dp);
L
Linus Torvalds 已提交
642 643 644 645 646

	} else if (args->rmtblkno > 0) {
		/*
		 * Added a "remote" value, just clear the incomplete flag.
		 */
D
Dave Chinner 已提交
647
		error = xfs_attr3_leaf_clearflag(args);
L
Linus Torvalds 已提交
648
	}
D
Dave Chinner 已提交
649
	return error;
L
Linus Torvalds 已提交
650 651 652 653 654 655 656 657 658
}

/*
 * Remove a name from the leaf attribute list structure
 *
 * This leaf block cannot have a "remote" value, we only call this routine
 * if bmap_one_block() says there is only one block (ie: no remote blks).
 */
STATIC int
659 660
xfs_attr_leaf_removename(
	struct xfs_da_args	*args)
L
Linus Torvalds 已提交
661
{
662 663 664
	struct xfs_inode	*dp;
	struct xfs_buf		*bp;
	int			error, forkoff;
L
Linus Torvalds 已提交
665

666 667
	trace_xfs_attr_leaf_removename(args);

L
Linus Torvalds 已提交
668 669 670 671 672
	/*
	 * Remove the attribute.
	 */
	dp = args->dp;
	args->blkno = 0;
673
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
674 675
	if (error)
		return error;
L
Linus Torvalds 已提交
676

D
Dave Chinner 已提交
677
	error = xfs_attr3_leaf_lookup_int(bp, args);
D
Dave Chinner 已提交
678
	if (error == -ENOATTR) {
679
		xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
680
		return error;
L
Linus Torvalds 已提交
681 682
	}

D
Dave Chinner 已提交
683
	xfs_attr3_leaf_remove(bp, args);
L
Linus Torvalds 已提交
684 685 686 687

	/*
	 * If the result is small enough, shrink it all into the inode.
	 */
688
	if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
D
Dave Chinner 已提交
689
		error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
L
Linus Torvalds 已提交
690
		/* bp is gone due to xfs_da_shrink_inode */
691
		if (error)
692
			return error;
693
		error = xfs_defer_finish(&args->trans);
694
		if (error)
695
			return error;
696
	}
D
Dave Chinner 已提交
697
	return 0;
L
Linus Torvalds 已提交
698 699 700 701 702 703 704
}

/*
 * Look up a name in a leaf attribute list structure.
 *
 * This leaf block cannot have a "remote" value, we only call this routine
 * if bmap_one_block() says there is only one block (ie: no remote blks).
705 706
 *
 * Returns 0 on successful retrieval, otherwise an error.
L
Linus Torvalds 已提交
707
 */
708
STATIC int
L
Linus Torvalds 已提交
709 710
xfs_attr_leaf_get(xfs_da_args_t *args)
{
711
	struct xfs_buf *bp;
L
Linus Torvalds 已提交
712 713
	int error;

714 715
	trace_xfs_attr_leaf_get(args);

L
Linus Torvalds 已提交
716
	args->blkno = 0;
717
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
L
Linus Torvalds 已提交
718
	if (error)
719
		return error;
L
Linus Torvalds 已提交
720

D
Dave Chinner 已提交
721
	error = xfs_attr3_leaf_lookup_int(bp, args);
D
Dave Chinner 已提交
722
	if (error != -EEXIST)  {
723
		xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
724
		return error;
L
Linus Torvalds 已提交
725
	}
D
Dave Chinner 已提交
726
	error = xfs_attr3_leaf_getvalue(bp, args);
727
	xfs_trans_brelse(args->trans, bp);
728
	return error;
L
Linus Torvalds 已提交
729 730 731
}

/*========================================================================
732
 * External routines when attribute list size > geo->blksize
L
Linus Torvalds 已提交
733 734 735 736 737 738 739 740 741 742 743 744 745
 *========================================================================*/

/*
 * Add a name to a Btree-format attribute list.
 *
 * This will involve walking down the Btree, and may involve splitting
 * leaf nodes and even splitting intermediate nodes up to and including
 * the root node (a special case of an intermediate node).
 *
 * "Remote" attribute values confuse the issue and atomic rename operations
 * add a whole extra layer of confusion on top of that.
 */
STATIC int
746 747
xfs_attr_node_addname(
	struct xfs_da_args	*args)
L
Linus Torvalds 已提交
748
{
749 750 751 752 753
	struct xfs_da_state	*state;
	struct xfs_da_state_blk	*blk;
	struct xfs_inode	*dp;
	struct xfs_mount	*mp;
	int			retval, error;
L
Linus Torvalds 已提交
754

755 756
	trace_xfs_attr_node_addname(args);

L
Linus Torvalds 已提交
757 758 759 760 761 762 763 764 765 766 767 768 769 770
	/*
	 * Fill in bucket of arguments/results/context to carry around.
	 */
	dp = args->dp;
	mp = dp->i_mount;
restart:
	state = xfs_da_state_alloc();
	state->args = args;
	state->mp = mp;

	/*
	 * Search to see if name already exists, and get back a pointer
	 * to where it should go.
	 */
771
	error = xfs_da3_node_lookup_int(state, &retval);
L
Linus Torvalds 已提交
772 773 774 775
	if (error)
		goto out;
	blk = &state->path.blk[ state->path.active-1 ];
	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
D
Dave Chinner 已提交
776
	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
L
Linus Torvalds 已提交
777
		goto out;
D
Dave Chinner 已提交
778
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
779 780
		if (args->flags & ATTR_CREATE)
			goto out;
781 782 783

		trace_xfs_attr_node_replace(args);

784
		/* save the attribute state for later removal*/
785
		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
L
Linus Torvalds 已提交
786 787 788 789
		args->blkno2 = args->blkno;		/* set 2nd entry info*/
		args->index2 = args->index;
		args->rmtblkno2 = args->rmtblkno;
		args->rmtblkcnt2 = args->rmtblkcnt;
790 791 792 793 794 795 796
		args->rmtvaluelen2 = args->rmtvaluelen;

		/*
		 * clear the remote attr state now that it is saved so that the
		 * values reflect the state of the attribute we are about to
		 * add, not the attribute we just found and will remove later.
		 */
L
Linus Torvalds 已提交
797 798
		args->rmtblkno = 0;
		args->rmtblkcnt = 0;
799
		args->rmtvaluelen = 0;
L
Linus Torvalds 已提交
800 801
	}

D
Dave Chinner 已提交
802
	retval = xfs_attr3_leaf_add(blk->bp, state->args);
D
Dave Chinner 已提交
803
	if (retval == -ENOSPC) {
L
Linus Torvalds 已提交
804 805 806 807 808 809 810
		if (state->path.active == 1) {
			/*
			 * Its really a single leaf node, but it had
			 * out-of-line values so it looked like it *might*
			 * have been a b-tree.
			 */
			xfs_da_state_free(state);
811
			state = NULL;
D
Dave Chinner 已提交
812
			error = xfs_attr3_leaf_to_node(args);
813
			if (error)
814
				goto out;
815
			error = xfs_defer_finish(&args->trans);
816
			if (error)
817
				goto out;
L
Linus Torvalds 已提交
818 819 820 821 822

			/*
			 * Commit the node conversion and start the next
			 * trans in the chain.
			 */
C
Christoph Hellwig 已提交
823
			error = xfs_trans_roll_inode(&args->trans, dp);
824
			if (error)
L
Linus Torvalds 已提交
825 826 827 828 829 830 831 832 833 834 835
				goto out;

			goto restart;
		}

		/*
		 * Split as many Btree elements as required.
		 * This code tracks the new and old attr's location
		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
		 */
836
		error = xfs_da3_split(state);
837
		if (error)
838
			goto out;
839
		error = xfs_defer_finish(&args->trans);
840
		if (error)
841
			goto out;
L
Linus Torvalds 已提交
842 843 844 845
	} else {
		/*
		 * Addition succeeded, update Btree hashvals.
		 */
846
		xfs_da3_fixhashpath(state, &state->path);
L
Linus Torvalds 已提交
847 848 849 850 851 852 853 854 855 856 857 858 859
	}

	/*
	 * Kill the state structure, we're done with it and need to
	 * allow the buffers to come back later.
	 */
	xfs_da_state_free(state);
	state = NULL;

	/*
	 * Commit the leaf addition or btree split and start the next
	 * trans in the chain.
	 */
C
Christoph Hellwig 已提交
860
	error = xfs_trans_roll_inode(&args->trans, dp);
861
	if (error)
L
Linus Torvalds 已提交
862 863 864 865 866 867 868 869 870 871 872
		goto out;

	/*
	 * If there was an out-of-line value, allocate the blocks we
	 * identified for its storage and copy the value.  This is done
	 * after we create the attribute so that we don't overflow the
	 * maximum size of a transaction and/or hit a deadlock.
	 */
	if (args->rmtblkno > 0) {
		error = xfs_attr_rmtval_set(args);
		if (error)
E
Eric Sandeen 已提交
873
			return error;
L
Linus Torvalds 已提交
874 875 876 877 878 879 880 881
	}

	/*
	 * If this is an atomic rename operation, we must "flip" the
	 * incomplete flags on the "new" and "old" attribute/value pairs
	 * so that one disappears and one appears atomically.  Then we
	 * must remove the "old" attribute/value pair.
	 */
882
	if (args->op_flags & XFS_DA_OP_RENAME) {
L
Linus Torvalds 已提交
883 884 885 886
		/*
		 * In a separate transaction, set the incomplete flag on the
		 * "old" attr and clear the incomplete flag on the "new" attr.
		 */
D
Dave Chinner 已提交
887
		error = xfs_attr3_leaf_flipflags(args);
L
Linus Torvalds 已提交
888 889 890 891 892 893 894 895 896 897 898
		if (error)
			goto out;

		/*
		 * Dismantle the "old" attribute/value pair by removing
		 * a "remote" value (if it exists).
		 */
		args->index = args->index2;
		args->blkno = args->blkno2;
		args->rmtblkno = args->rmtblkno2;
		args->rmtblkcnt = args->rmtblkcnt2;
899
		args->rmtvaluelen = args->rmtvaluelen2;
L
Linus Torvalds 已提交
900 901 902
		if (args->rmtblkno) {
			error = xfs_attr_rmtval_remove(args);
			if (error)
E
Eric Sandeen 已提交
903
				return error;
L
Linus Torvalds 已提交
904 905 906 907 908 909 910
		}

		/*
		 * Re-find the "old" attribute entry after any split ops.
		 * The INCOMPLETE flag means that we will find the "old"
		 * attr, not the "new" one.
		 */
911
		args->op_flags |= XFS_DA_OP_INCOMPLETE;
L
Linus Torvalds 已提交
912 913 914 915
		state = xfs_da_state_alloc();
		state->args = args;
		state->mp = mp;
		state->inleaf = 0;
916
		error = xfs_da3_node_lookup_int(state, &retval);
L
Linus Torvalds 已提交
917 918 919 920 921 922 923 924
		if (error)
			goto out;

		/*
		 * Remove the name and update the hashvals in the tree.
		 */
		blk = &state->path.blk[ state->path.active-1 ];
		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
D
Dave Chinner 已提交
925
		error = xfs_attr3_leaf_remove(blk->bp, args);
926
		xfs_da3_fixhashpath(state, &state->path);
L
Linus Torvalds 已提交
927 928 929 930 931

		/*
		 * Check to see if the tree needs to be collapsed.
		 */
		if (retval && (state->path.active > 1)) {
932
			error = xfs_da3_join(state);
933
			if (error)
934
				goto out;
935
			error = xfs_defer_finish(&args->trans);
936
			if (error)
937
				goto out;
L
Linus Torvalds 已提交
938 939 940 941 942
		}

		/*
		 * Commit and start the next trans in the chain.
		 */
C
Christoph Hellwig 已提交
943
		error = xfs_trans_roll_inode(&args->trans, dp);
944
		if (error)
L
Linus Torvalds 已提交
945 946 947 948 949 950
			goto out;

	} else if (args->rmtblkno > 0) {
		/*
		 * Added a "remote" value, just clear the incomplete flag.
		 */
D
Dave Chinner 已提交
951
		error = xfs_attr3_leaf_clearflag(args);
L
Linus Torvalds 已提交
952 953 954 955 956 957 958 959 960
		if (error)
			goto out;
	}
	retval = error = 0;

out:
	if (state)
		xfs_da_state_free(state);
	if (error)
E
Eric Sandeen 已提交
961 962
		return error;
	return retval;
L
Linus Torvalds 已提交
963 964 965 966 967 968 969 970 971 972
}

/*
 * Remove a name from a B-tree attribute list.
 *
 * This will involve walking down the Btree, and may involve joining
 * leaf nodes and even joining intermediate nodes up to and including
 * the root node (a special case of an intermediate node).
 */
STATIC int
973 974
xfs_attr_node_removename(
	struct xfs_da_args	*args)
L
Linus Torvalds 已提交
975
{
976 977 978 979 980
	struct xfs_da_state	*state;
	struct xfs_da_state_blk	*blk;
	struct xfs_inode	*dp;
	struct xfs_buf		*bp;
	int			retval, error, forkoff;
L
Linus Torvalds 已提交
981

982 983
	trace_xfs_attr_node_removename(args);

L
Linus Torvalds 已提交
984 985 986 987 988 989 990 991 992 993 994
	/*
	 * Tie a string around our finger to remind us where we are.
	 */
	dp = args->dp;
	state = xfs_da_state_alloc();
	state->args = args;
	state->mp = dp->i_mount;

	/*
	 * Search to see if name exists, and get back a pointer to it.
	 */
995
	error = xfs_da3_node_lookup_int(state, &retval);
D
Dave Chinner 已提交
996
	if (error || (retval != -EEXIST)) {
L
Linus Torvalds 已提交
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
		if (error == 0)
			error = retval;
		goto out;
	}

	/*
	 * If there is an out-of-line value, de-allocate the blocks.
	 * This is done before we remove the attribute so that we don't
	 * overflow the maximum size of a transaction and/or hit a deadlock.
	 */
	blk = &state->path.blk[ state->path.active-1 ];
	ASSERT(blk->bp != NULL);
	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
	if (args->rmtblkno > 0) {
		/*
		 * Fill in disk block numbers in the state structure
		 * so that we can get the buffers back after we commit
		 * several transactions in the following calls.
		 */
		error = xfs_attr_fillstate(state);
		if (error)
			goto out;

		/*
		 * Mark the attribute as INCOMPLETE, then bunmapi() the
		 * remote value.
		 */
D
Dave Chinner 已提交
1024
		error = xfs_attr3_leaf_setflag(args);
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
		if (error)
			goto out;
		error = xfs_attr_rmtval_remove(args);
		if (error)
			goto out;

		/*
		 * Refill the state structure with buffers, the prior calls
		 * released our buffers.
		 */
		error = xfs_attr_refillstate(state);
		if (error)
			goto out;
	}

	/*
	 * Remove the name and update the hashvals in the tree.
	 */
	blk = &state->path.blk[ state->path.active-1 ];
	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
D
Dave Chinner 已提交
1045
	retval = xfs_attr3_leaf_remove(blk->bp, args);
1046
	xfs_da3_fixhashpath(state, &state->path);
L
Linus Torvalds 已提交
1047 1048 1049 1050 1051

	/*
	 * Check to see if the tree needs to be collapsed.
	 */
	if (retval && (state->path.active > 1)) {
1052
		error = xfs_da3_join(state);
1053
		if (error)
1054
			goto out;
1055
		error = xfs_defer_finish(&args->trans);
1056
		if (error)
1057
			goto out;
L
Linus Torvalds 已提交
1058 1059 1060
		/*
		 * Commit the Btree join operation and start a new trans.
		 */
C
Christoph Hellwig 已提交
1061
		error = xfs_trans_roll_inode(&args->trans, dp);
1062
		if (error)
L
Linus Torvalds 已提交
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
			goto out;
	}

	/*
	 * If the result is small enough, push it all into the inode.
	 */
	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
		/*
		 * Have to get rid of the copy of this dabuf in the state.
		 */
		ASSERT(state->path.active == 1);
		ASSERT(state->path.blk[0].bp);
		state->path.blk[0].bp = NULL;

1077
		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
L
Linus Torvalds 已提交
1078 1079 1080
		if (error)
			goto out;

1081
		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
D
Dave Chinner 已提交
1082
			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
L
Linus Torvalds 已提交
1083
			/* bp is gone due to xfs_da_shrink_inode */
1084
			if (error)
1085
				goto out;
1086
			error = xfs_defer_finish(&args->trans);
1087
			if (error)
1088
				goto out;
L
Linus Torvalds 已提交
1089
		} else
1090
			xfs_trans_brelse(args->trans, bp);
L
Linus Torvalds 已提交
1091 1092 1093 1094 1095
	}
	error = 0;

out:
	xfs_da_state_free(state);
E
Eric Sandeen 已提交
1096
	return error;
L
Linus Torvalds 已提交
1097 1098 1099 1100 1101 1102
}

/*
 * Fill in the disk block numbers in the state structure for the buffers
 * that are attached to the state structure.
 * This is done so that we can quickly reattach ourselves to those buffers
1103
 * after some set of transaction commits have released these buffers.
L
Linus Torvalds 已提交
1104 1105 1106 1107 1108 1109 1110 1111
 */
STATIC int
xfs_attr_fillstate(xfs_da_state_t *state)
{
	xfs_da_state_path_t *path;
	xfs_da_state_blk_t *blk;
	int level;

1112 1113
	trace_xfs_attr_fillstate(state->args);

L
Linus Torvalds 已提交
1114 1115 1116 1117 1118 1119 1120 1121
	/*
	 * Roll down the "path" in the state structure, storing the on-disk
	 * block number for those buffers in the "path".
	 */
	path = &state->path;
	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
		if (blk->bp) {
1122
			blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
L
Linus Torvalds 已提交
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
			blk->bp = NULL;
		} else {
			blk->disk_blkno = 0;
		}
	}

	/*
	 * Roll down the "altpath" in the state structure, storing the on-disk
	 * block number for those buffers in the "altpath".
	 */
	path = &state->altpath;
	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
		if (blk->bp) {
1137
			blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
L
Linus Torvalds 已提交
1138 1139 1140 1141 1142 1143
			blk->bp = NULL;
		} else {
			blk->disk_blkno = 0;
		}
	}

E
Eric Sandeen 已提交
1144
	return 0;
L
Linus Torvalds 已提交
1145 1146 1147 1148 1149
}

/*
 * Reattach the buffers to the state structure based on the disk block
 * numbers stored in the state structure.
1150
 * This is done after some set of transaction commits have released those
L
Linus Torvalds 已提交
1151 1152 1153 1154 1155 1156 1157 1158 1159
 * buffers from our grip.
 */
STATIC int
xfs_attr_refillstate(xfs_da_state_t *state)
{
	xfs_da_state_path_t *path;
	xfs_da_state_blk_t *blk;
	int level, error;

1160 1161
	trace_xfs_attr_refillstate(state->args);

L
Linus Torvalds 已提交
1162 1163 1164 1165 1166 1167 1168 1169
	/*
	 * Roll down the "path" in the state structure, storing the on-disk
	 * block number for those buffers in the "path".
	 */
	path = &state->path;
	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
		if (blk->disk_blkno) {
C
Christoph Hellwig 已提交
1170 1171 1172
			error = xfs_da3_node_read_mapped(state->args->trans,
					state->args->dp, blk->disk_blkno,
					&blk->bp, XFS_ATTR_FORK);
L
Linus Torvalds 已提交
1173
			if (error)
E
Eric Sandeen 已提交
1174
				return error;
L
Linus Torvalds 已提交
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
		} else {
			blk->bp = NULL;
		}
	}

	/*
	 * Roll down the "altpath" in the state structure, storing the on-disk
	 * block number for those buffers in the "altpath".
	 */
	path = &state->altpath;
	ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
	for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
		if (blk->disk_blkno) {
C
Christoph Hellwig 已提交
1188 1189 1190
			error = xfs_da3_node_read_mapped(state->args->trans,
					state->args->dp, blk->disk_blkno,
					&blk->bp, XFS_ATTR_FORK);
L
Linus Torvalds 已提交
1191
			if (error)
E
Eric Sandeen 已提交
1192
				return error;
L
Linus Torvalds 已提交
1193 1194 1195 1196 1197
		} else {
			blk->bp = NULL;
		}
	}

E
Eric Sandeen 已提交
1198
	return 0;
L
Linus Torvalds 已提交
1199 1200 1201
}

/*
1202
 * Retrieve the attribute data from a node attribute list.
L
Linus Torvalds 已提交
1203 1204 1205 1206
 *
 * This routine gets called for any attribute fork that has more than one
 * block, ie: both true Btree attr lists and for single-leaf-blocks with
 * "remote" values taking up more blocks.
1207 1208
 *
 * Returns 0 on successful retrieval, otherwise an error.
L
Linus Torvalds 已提交
1209
 */
1210
STATIC int
L
Linus Torvalds 已提交
1211 1212 1213 1214 1215 1216 1217
xfs_attr_node_get(xfs_da_args_t *args)
{
	xfs_da_state_t *state;
	xfs_da_state_blk_t *blk;
	int error, retval;
	int i;

1218 1219
	trace_xfs_attr_node_get(args);

L
Linus Torvalds 已提交
1220 1221 1222 1223 1224 1225 1226
	state = xfs_da_state_alloc();
	state->args = args;
	state->mp = args->dp->i_mount;

	/*
	 * Search to see if name exists, and get back a pointer to it.
	 */
1227
	error = xfs_da3_node_lookup_int(state, &retval);
L
Linus Torvalds 已提交
1228 1229
	if (error) {
		retval = error;
1230
		goto out_release;
L
Linus Torvalds 已提交
1231
	}
1232 1233 1234 1235 1236 1237 1238 1239
	if (retval != -EEXIST)
		goto out_release;

	/*
	 * Get the value, local or "remote"
	 */
	blk = &state->path.blk[state->path.active - 1];
	retval = xfs_attr3_leaf_getvalue(blk->bp, args);
L
Linus Torvalds 已提交
1240 1241 1242 1243

	/*
	 * If not in a transaction, we have to release all the buffers.
	 */
1244
out_release:
L
Linus Torvalds 已提交
1245
	for (i = 0; i < state->path.active; i++) {
1246
		xfs_trans_brelse(args->trans, state->path.blk[i].bp);
L
Linus Torvalds 已提交
1247 1248 1249 1250
		state->path.blk[i].bp = NULL;
	}

	xfs_da_state_free(state);
E
Eric Sandeen 已提交
1251
	return retval;
L
Linus Torvalds 已提交
1252
}
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269

/* Returns true if the attribute entry name is valid. */
bool
xfs_attr_namecheck(
	const void	*name,
	size_t		length)
{
	/*
	 * MAXNAMELEN includes the trailing null, but (name/length) leave it
	 * out, so use >= for the length check.
	 */
	if (length >= MAXNAMELEN)
		return false;

	/* There shouldn't be any nulls here */
	return !memchr(name, 0, length);
}