xfs_attr.c 33.4 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
L
Linus Torvalds 已提交
4
 *
5 6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
L
Linus Torvalds 已提交
7 8
 * published by the Free Software Foundation.
 *
9 10 11 12
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
L
Linus Torvalds 已提交
13
 *
14 15 16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
L
Linus Torvalds 已提交
17 18
 */
#include "xfs.h"
19
#include "xfs_fs.h"
20
#include "xfs_shared.h"
21 22 23
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
24
#include "xfs_bit.h"
L
Linus Torvalds 已提交
25
#include "xfs_mount.h"
26
#include "xfs_defer.h"
27
#include "xfs_da_format.h"
28 29
#include "xfs_da_btree.h"
#include "xfs_attr_sf.h"
L
Linus Torvalds 已提交
30
#include "xfs_inode.h"
31
#include "xfs_alloc.h"
32
#include "xfs_trans.h"
33
#include "xfs_inode_item.h"
L
Linus Torvalds 已提交
34
#include "xfs_bmap.h"
D
Dave Chinner 已提交
35
#include "xfs_bmap_util.h"
36
#include "xfs_bmap_btree.h"
L
Linus Torvalds 已提交
37 38
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
39
#include "xfs_attr_remote.h"
L
Linus Torvalds 已提交
40 41 42
#include "xfs_error.h"
#include "xfs_quota.h"
#include "xfs_trans_space.h"
C
Christoph Hellwig 已提交
43
#include "xfs_trace.h"
L
Linus Torvalds 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

/*
 * 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.
 */
63
STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
L
Linus Torvalds 已提交
64 65 66 67 68 69
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.
 */
70
STATIC int xfs_attr_node_get(xfs_da_args_t *args);
L
Linus Torvalds 已提交
71 72 73 74 75 76
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);


77
STATIC int
78 79 80 81 82
xfs_attr_args_init(
	struct xfs_da_args	*args,
	struct xfs_inode	*dp,
	const unsigned char	*name,
	int			flags)
83
{
84 85

	if (!name)
D
Dave Chinner 已提交
86
		return -EINVAL;
87 88

	memset(args, 0, sizeof(*args));
89
	args->geo = dp->i_mount->m_attr_geo;
90 91 92 93 94 95
	args->whichfork = XFS_ATTR_FORK;
	args->dp = dp;
	args->flags = flags;
	args->name = name;
	args->namelen = strlen((const char *)name);
	if (args->namelen >= MAXNAMELEN)
D
Dave Chinner 已提交
96
		return -EFAULT;		/* match IRIX behaviour */
97

98
	args->hashval = xfs_da_hashname(args->name, args->namelen);
99 100
	return 0;
}
L
Linus Torvalds 已提交
101

102
int
103 104 105 106 107 108 109 110 111 112
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 已提交
113 114 115 116
/*========================================================================
 * Overall external interface routines.
 *========================================================================*/

117
/* Retrieve an extended attribute and its value.  Must have ilock. */
118 119 120 121 122
int
xfs_attr_get_ilocked(
	struct xfs_inode	*ip,
	struct xfs_da_args	*args)
{
123 124
	ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));

125 126 127 128 129 130 131 132 133 134 135
	if (!xfs_inode_hasattr(ip))
		return -ENOATTR;
	else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
		return xfs_attr_shortform_getvalue(args);
	else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
		return xfs_attr_leaf_get(args);
	else
		return xfs_attr_node_get(args);
}

/* Retrieve an extended attribute by name, and its value. */
136 137
int
xfs_attr_get(
138
	struct xfs_inode	*ip,
139
	const unsigned char	*name,
140
	unsigned char		*value,
141 142
	int			*valuelenp,
	int			flags)
L
Linus Torvalds 已提交
143
{
144 145 146 147
	struct xfs_da_args	args;
	uint			lock_mode;
	int			error;

148
	XFS_STATS_INC(ip->i_mount, xs_attr_get);
149 150

	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
D
Dave Chinner 已提交
151
		return -EIO;
L
Linus Torvalds 已提交
152

153
	error = xfs_attr_args_init(&args, ip, name, flags);
154 155 156
	if (error)
		return error;

L
Linus Torvalds 已提交
157 158
	args.value = value;
	args.valuelen = *valuelenp;
159 160
	/* Entirely possible to look up a name which doesn't exist */
	args.op_flags = XFS_DA_OP_OKNOENT;
L
Linus Torvalds 已提交
161

162
	lock_mode = xfs_ilock_attr_map_shared(ip);
163
	error = xfs_attr_get_ilocked(ip, &args);
164
	xfs_iunlock(ip, lock_mode);
L
Linus Torvalds 已提交
165 166

	*valuelenp = args.valuelen;
D
Dave Chinner 已提交
167
	return error == -EEXIST ? 0 : error;
L
Linus Torvalds 已提交
168 169
}

170 171 172
/*
 * Calculate how many blocks we need for the new attribute,
 */
173
STATIC int
174
xfs_attr_calc_size(
175
	struct xfs_da_args	*args,
176 177
	int			*local)
{
178
	struct xfs_mount	*mp = args->dp->i_mount;
179 180 181 182 183 184 185
	int			size;
	int			nblks;

	/*
	 * Determine space new attribute will use, and if it would be
	 * "local" or "remote" (note: local != inline).
	 */
186
	size = xfs_attr_leaf_newentsize(args, local);
187 188
	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
	if (*local) {
189
		if (size > (args->geo->blksize / 2)) {
190 191 192 193 194 195 196 197
			/* Double split possible */
			nblks *= 2;
		}
	} else {
		/*
		 * Out of line attribute, cannot double split, but
		 * make room for the attribute value itself.
		 */
198
		uint	dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
199 200 201 202 203 204 205
		nblks += dblocks;
		nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
	}

	return nblks;
}

206 207 208 209 210 211 212
int
xfs_attr_set(
	struct xfs_inode	*dp,
	const unsigned char	*name,
	unsigned char		*value,
	int			valuelen,
	int			flags)
L
Linus Torvalds 已提交
213
{
214
	struct xfs_mount	*mp = dp->i_mount;
215
	struct xfs_da_args	args;
216
	struct xfs_defer_ops	dfops;
217
	struct xfs_trans_res	tres;
218
	xfs_fsblock_t		firstblock;
219
	int			rsvd = (flags & ATTR_ROOT) != 0;
220
	int			error, err2, local;
221

222
	XFS_STATS_INC(mp, xs_attr_set);
223 224

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

227
	error = xfs_attr_args_init(&args, dp, name, flags);
228 229
	if (error)
		return error;
L
Linus Torvalds 已提交
230

231 232 233
	args.value = value;
	args.valuelen = valuelen;
	args.firstblock = &firstblock;
234
	args.dfops = &dfops;
235
	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
236
	args.total = xfs_attr_calc_size(&args, &local);
L
Linus Torvalds 已提交
237

C
Christoph Hellwig 已提交
238 239 240
	error = xfs_qm_dqattach(dp, 0);
	if (error)
		return error;
L
Linus Torvalds 已提交
241 242 243 244 245 246

	/*
	 * 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) {
247
		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
248
			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
249

250 251 252
		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
		if (error)
			return error;
L
Linus Torvalds 已提交
253 254
	}

255 256 257 258
	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
			 M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
L
Linus Torvalds 已提交
259 260 261 262 263

	/*
	 * Root fork attributes can use reserved data blocks for this
	 * operation if necessary
	 */
264 265 266
	error = xfs_trans_alloc(mp, &tres, args.total, 0,
			rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
	if (error)
267
		return error;
L
Linus Torvalds 已提交
268

269
	xfs_ilock(dp, XFS_ILOCK_EXCL);
C
Christoph Hellwig 已提交
270
	error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
271 272
				rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
				       XFS_QMOPT_RES_REGBLKS);
L
Linus Torvalds 已提交
273 274
	if (error) {
		xfs_iunlock(dp, XFS_ILOCK_EXCL);
275
		xfs_trans_cancel(args.trans);
276
		return error;
L
Linus Torvalds 已提交
277 278
	}

279
	xfs_trans_ijoin(args.trans, dp, 0);
L
Linus Torvalds 已提交
280 281

	/*
282
	 * If the attribute list is non-existent or a shortform list,
L
Linus Torvalds 已提交
283 284
	 * upgrade it to a single-leaf-block attribute list.
	 */
285 286 287
	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)) {
L
Linus Torvalds 已提交
288 289 290 291 292

		/*
		 * Build initial attribute list (if required).
		 */
		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
293
			xfs_attr_shortform_create(&args);
L
Linus Torvalds 已提交
294 295 296 297 298 299

		/*
		 * Try to add the attr to the attribute list in
		 * the inode.
		 */
		error = xfs_attr_shortform_addname(&args);
D
Dave Chinner 已提交
300
		if (error != -ENOSPC) {
L
Linus Torvalds 已提交
301 302 303 304 305 306 307 308 309 310 311
			/*
			 * Commit the shortform mods, and we're done.
			 * NOTE: this is also the error path (EEXIST, etc).
			 */
			ASSERT(args.trans != NULL);

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

			if (!error && (flags & ATTR_KERNOTIME) == 0) {
				xfs_trans_ichgtime(args.trans, dp,
							XFS_ICHGTIME_CHG);
			}
319
			err2 = xfs_trans_commit(args.trans);
L
Linus Torvalds 已提交
320 321
			xfs_iunlock(dp, XFS_ILOCK_EXCL);

322
			return error ? error : err2;
L
Linus Torvalds 已提交
323 324 325 326 327 328
		}

		/*
		 * It won't fit in the shortform, transform to a leaf block.
		 * GROT: another possible req'mt for a double-split btree op.
		 */
329
		xfs_defer_init(args.dfops, args.firstblock);
L
Linus Torvalds 已提交
330
		error = xfs_attr_shortform_to_leaf(&args);
331
		if (!error)
332
			error = xfs_defer_finish(&args.trans, args.dfops, dp);
L
Linus Torvalds 已提交
333 334
		if (error) {
			args.trans = NULL;
335
			xfs_defer_cancel(&dfops);
L
Linus Torvalds 已提交
336 337 338 339 340 341 342
			goto out;
		}

		/*
		 * Commit the leaf transformation.  We'll need another (linked)
		 * transaction to add the new attribute to the leaf.
		 */
343 344 345

		error = xfs_trans_roll(&args.trans, dp);
		if (error)
L
Linus Torvalds 已提交
346 347 348 349
			goto out;

	}

350
	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
L
Linus Torvalds 已提交
351
		error = xfs_attr_leaf_addname(&args);
352
	else
L
Linus Torvalds 已提交
353
		error = xfs_attr_node_addname(&args);
354
	if (error)
L
Linus Torvalds 已提交
355 356 357 358 359 360
		goto out;

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

364 365 366
	if ((flags & ATTR_KERNOTIME) == 0)
		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);

L
Linus Torvalds 已提交
367 368 369 370
	/*
	 * Commit the last in the sequence of transactions.
	 */
	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
371
	error = xfs_trans_commit(args.trans);
L
Linus Torvalds 已提交
372 373
	xfs_iunlock(dp, XFS_ILOCK_EXCL);

374
	return error;
L
Linus Torvalds 已提交
375 376

out:
377 378
	if (args.trans)
		xfs_trans_cancel(args.trans);
L
Linus Torvalds 已提交
379
	xfs_iunlock(dp, XFS_ILOCK_EXCL);
380
	return error;
L
Linus Torvalds 已提交
381 382
}

383 384 385 386 387
/*
 * Generic handler routine to remove a name from an attribute list.
 * Transitions attribute list from Btree to shortform as necessary.
 */
int
388 389 390 391
xfs_attr_remove(
	struct xfs_inode	*dp,
	const unsigned char	*name,
	int			flags)
L
Linus Torvalds 已提交
392
{
393 394
	struct xfs_mount	*mp = dp->i_mount;
	struct xfs_da_args	args;
395
	struct xfs_defer_ops	dfops;
396 397
	xfs_fsblock_t		firstblock;
	int			error;
L
Linus Torvalds 已提交
398

399
	XFS_STATS_INC(mp, xs_attr_remove);
L
Linus Torvalds 已提交
400

401
	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
D
Dave Chinner 已提交
402
		return -EIO;
403

404
	error = xfs_attr_args_init(&args, dp, name, flags);
405 406 407
	if (error)
		return error;

L
Linus Torvalds 已提交
408
	args.firstblock = &firstblock;
409
	args.dfops = &dfops;
L
Linus Torvalds 已提交
410

411 412 413 414 415 416 417
	/*
	 * 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.
	 */
	args.op_flags = XFS_DA_OP_OKNOENT;

C
Christoph Hellwig 已提交
418 419 420
	error = xfs_qm_dqattach(dp, 0);
	if (error)
		return error;
L
Linus Torvalds 已提交
421 422 423 424 425

	/*
	 * Root fork attributes can use reserved data blocks for this
	 * operation if necessary
	 */
426 427 428 429 430
	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
			XFS_ATTRRM_SPACE_RES(mp), 0,
			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
			&args.trans);
	if (error)
431
		return error;
L
Linus Torvalds 已提交
432 433 434 435 436 437

	xfs_ilock(dp, XFS_ILOCK_EXCL);
	/*
	 * No need to make quota reservations here. We expect to release some
	 * blocks not allocate in the common case.
	 */
438
	xfs_trans_ijoin(args.trans, dp, 0);
L
Linus Torvalds 已提交
439

440
	if (!xfs_inode_hasattr(dp)) {
D
Dave Chinner 已提交
441
		error = -ENOATTR;
442
	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
L
Linus Torvalds 已提交
443 444 445 446 447 448 449
		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);
	}
450 451

	if (error)
L
Linus Torvalds 已提交
452 453 454 455 456 457
		goto out;

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

461 462 463
	if ((flags & ATTR_KERNOTIME) == 0)
		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);

L
Linus Torvalds 已提交
464 465 466 467
	/*
	 * Commit the last in the sequence of transactions.
	 */
	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
468
	error = xfs_trans_commit(args.trans);
L
Linus Torvalds 已提交
469 470
	xfs_iunlock(dp, XFS_ILOCK_EXCL);

471
	return error;
L
Linus Torvalds 已提交
472 473

out:
474 475
	if (args.trans)
		xfs_trans_cancel(args.trans);
476 477
	xfs_iunlock(dp, XFS_ILOCK_EXCL);
	return error;
478 479
}

L
Linus Torvalds 已提交
480 481 482 483 484 485 486 487 488 489 490
/*========================================================================
 * 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)
{
491
	int newsize, forkoff, retval;
L
Linus Torvalds 已提交
492

493 494
	trace_xfs_attr_sf_addname(args);

L
Linus Torvalds 已提交
495
	retval = xfs_attr_shortform_lookup(args);
D
Dave Chinner 已提交
496
	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
E
Eric Sandeen 已提交
497
		return retval;
D
Dave Chinner 已提交
498
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
499
		if (args->flags & ATTR_CREATE)
E
Eric Sandeen 已提交
500
			return retval;
L
Linus Torvalds 已提交
501 502 503 504
		retval = xfs_attr_shortform_remove(args);
		ASSERT(retval == 0);
	}

505 506
	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
D
Dave Chinner 已提交
507
		return -ENOSPC;
508

L
Linus Torvalds 已提交
509 510
	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
511 512 513

	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
	if (!forkoff)
D
Dave Chinner 已提交
514
		return -ENOSPC;
515 516

	xfs_attr_shortform_add(args, forkoff);
E
Eric Sandeen 已提交
517
	return 0;
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525 526 527 528 529 530
}


/*========================================================================
 * 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 已提交
531
STATIC int
L
Linus Torvalds 已提交
532 533 534
xfs_attr_leaf_addname(xfs_da_args_t *args)
{
	xfs_inode_t *dp;
535
	struct xfs_buf *bp;
536
	int retval, error, forkoff;
L
Linus Torvalds 已提交
537

538 539
	trace_xfs_attr_leaf_addname(args);

L
Linus Torvalds 已提交
540 541 542 543 544
	/*
	 * Read the (only) block in the attribute list in.
	 */
	dp = args->dp;
	args->blkno = 0;
D
Dave Chinner 已提交
545
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
L
Linus Torvalds 已提交
546
	if (error)
547
		return error;
L
Linus Torvalds 已提交
548 549 550 551 552

	/*
	 * 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 已提交
553
	retval = xfs_attr3_leaf_lookup_int(bp, args);
D
Dave Chinner 已提交
554
	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
555
		xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
556
		return retval;
D
Dave Chinner 已提交
557
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
558
		if (args->flags & ATTR_CREATE) {	/* pure create op */
559
			xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
560
			return retval;
L
Linus Torvalds 已提交
561
		}
562 563 564

		trace_xfs_attr_leaf_replace(args);

565
		/* save the attribute state for later removal*/
566
		args->op_flags |= XFS_DA_OP_RENAME;	/* an atomic rename */
L
Linus Torvalds 已提交
567 568 569 570
		args->blkno2 = args->blkno;		/* set 2nd entry info*/
		args->index2 = args->index;
		args->rmtblkno2 = args->rmtblkno;
		args->rmtblkcnt2 = args->rmtblkcnt;
571 572 573 574 575 576 577 578 579 580
		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 已提交
581 582 583 584 585 586
	}

	/*
	 * Add the attribute to the leaf block, transitioning to a Btree
	 * if required.
	 */
D
Dave Chinner 已提交
587
	retval = xfs_attr3_leaf_add(bp, args);
D
Dave Chinner 已提交
588
	if (retval == -ENOSPC) {
L
Linus Torvalds 已提交
589 590 591 592 593
		/*
		 * Promote the attribute list to the Btree format, then
		 * Commit that transaction so that the node_addname() call
		 * can manage its own transactions.
		 */
594
		xfs_defer_init(args->dfops, args->firstblock);
D
Dave Chinner 已提交
595
		error = xfs_attr3_leaf_to_node(args);
596
		if (!error)
597
			error = xfs_defer_finish(&args->trans, args->dfops, dp);
L
Linus Torvalds 已提交
598 599
		if (error) {
			args->trans = NULL;
600
			xfs_defer_cancel(args->dfops);
E
Eric Sandeen 已提交
601
			return error;
L
Linus Torvalds 已提交
602 603 604 605 606 607
		}

		/*
		 * Commit the current trans (including the inode) and start
		 * a new one.
		 */
608 609
		error = xfs_trans_roll(&args->trans, dp);
		if (error)
E
Eric Sandeen 已提交
610
			return error;
L
Linus Torvalds 已提交
611 612 613 614 615

		/*
		 * Fob the whole rest of the problem off on the Btree code.
		 */
		error = xfs_attr_node_addname(args);
E
Eric Sandeen 已提交
616
		return error;
L
Linus Torvalds 已提交
617 618 619 620 621 622
	}

	/*
	 * Commit the transaction that added the attr name so that
	 * later routines can manage their own transactions.
	 */
623 624
	error = xfs_trans_roll(&args->trans, dp);
	if (error)
E
Eric Sandeen 已提交
625
		return error;
L
Linus Torvalds 已提交
626 627 628 629 630 631 632 633 634 635

	/*
	 * 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 已提交
636
			return error;
L
Linus Torvalds 已提交
637 638 639 640 641 642 643 644
	}

	/*
	 * 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.
	 */
645
	if (args->op_flags & XFS_DA_OP_RENAME) {
L
Linus Torvalds 已提交
646 647 648 649
		/*
		 * In a separate transaction, set the incomplete flag on the
		 * "old" attr and clear the incomplete flag on the "new" attr.
		 */
D
Dave Chinner 已提交
650
		error = xfs_attr3_leaf_flipflags(args);
L
Linus Torvalds 已提交
651
		if (error)
E
Eric Sandeen 已提交
652
			return error;
L
Linus Torvalds 已提交
653 654 655 656 657 658 659 660 661

		/*
		 * 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;
662
		args->rmtvaluelen = args->rmtvaluelen2;
L
Linus Torvalds 已提交
663 664 665
		if (args->rmtblkno) {
			error = xfs_attr_rmtval_remove(args);
			if (error)
E
Eric Sandeen 已提交
666
				return error;
L
Linus Torvalds 已提交
667 668 669 670 671 672
		}

		/*
		 * Read in the block containing the "old" attr, then
		 * remove the "old" attr from that block (neat, huh!)
		 */
D
Dave Chinner 已提交
673
		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
674
					   -1, &bp);
L
Linus Torvalds 已提交
675
		if (error)
676 677
			return error;

D
Dave Chinner 已提交
678
		xfs_attr3_leaf_remove(bp, args);
L
Linus Torvalds 已提交
679 680 681 682

		/*
		 * If the result is small enough, shrink it all into the inode.
		 */
683
		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
684
			xfs_defer_init(args->dfops, args->firstblock);
D
Dave Chinner 已提交
685
			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
L
Linus Torvalds 已提交
686
			/* bp is gone due to xfs_da_shrink_inode */
687
			if (!error)
688
				error = xfs_defer_finish(&args->trans,
689
							args->dfops, dp);
L
Linus Torvalds 已提交
690 691
			if (error) {
				args->trans = NULL;
692
				xfs_defer_cancel(args->dfops);
E
Eric Sandeen 已提交
693
				return error;
L
Linus Torvalds 已提交
694
			}
695
		}
L
Linus Torvalds 已提交
696 697 698 699

		/*
		 * Commit the remove and start the next trans in series.
		 */
700
		error = xfs_trans_roll(&args->trans, dp);
L
Linus Torvalds 已提交
701 702 703 704 705

	} else if (args->rmtblkno > 0) {
		/*
		 * Added a "remote" value, just clear the incomplete flag.
		 */
D
Dave Chinner 已提交
706
		error = xfs_attr3_leaf_clearflag(args);
L
Linus Torvalds 已提交
707
	}
D
Dave Chinner 已提交
708
	return error;
L
Linus Torvalds 已提交
709 710 711 712 713 714 715 716 717 718 719 720
}

/*
 * 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
xfs_attr_leaf_removename(xfs_da_args_t *args)
{
	xfs_inode_t *dp;
721
	struct xfs_buf *bp;
722
	int error, forkoff;
L
Linus Torvalds 已提交
723

724 725
	trace_xfs_attr_leaf_removename(args);

L
Linus Torvalds 已提交
726 727 728 729 730
	/*
	 * Remove the attribute.
	 */
	dp = args->dp;
	args->blkno = 0;
D
Dave Chinner 已提交
731
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
732 733
	if (error)
		return error;
L
Linus Torvalds 已提交
734

D
Dave Chinner 已提交
735
	error = xfs_attr3_leaf_lookup_int(bp, args);
D
Dave Chinner 已提交
736
	if (error == -ENOATTR) {
737
		xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
738
		return error;
L
Linus Torvalds 已提交
739 740
	}

D
Dave Chinner 已提交
741
	xfs_attr3_leaf_remove(bp, args);
L
Linus Torvalds 已提交
742 743 744 745

	/*
	 * If the result is small enough, shrink it all into the inode.
	 */
746
	if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
747
		xfs_defer_init(args->dfops, args->firstblock);
D
Dave Chinner 已提交
748
		error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
L
Linus Torvalds 已提交
749
		/* bp is gone due to xfs_da_shrink_inode */
750
		if (!error)
751
			error = xfs_defer_finish(&args->trans, args->dfops, dp);
L
Linus Torvalds 已提交
752 753
		if (error) {
			args->trans = NULL;
754
			xfs_defer_cancel(args->dfops);
D
Dave Chinner 已提交
755
			return error;
L
Linus Torvalds 已提交
756
		}
757
	}
D
Dave Chinner 已提交
758
	return 0;
L
Linus Torvalds 已提交
759 760 761 762 763 764 765 766
}

/*
 * 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).
 */
767
STATIC int
L
Linus Torvalds 已提交
768 769
xfs_attr_leaf_get(xfs_da_args_t *args)
{
770
	struct xfs_buf *bp;
L
Linus Torvalds 已提交
771 772
	int error;

773 774
	trace_xfs_attr_leaf_get(args);

L
Linus Torvalds 已提交
775
	args->blkno = 0;
D
Dave Chinner 已提交
776
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
L
Linus Torvalds 已提交
777
	if (error)
778
		return error;
L
Linus Torvalds 已提交
779

D
Dave Chinner 已提交
780
	error = xfs_attr3_leaf_lookup_int(bp, args);
D
Dave Chinner 已提交
781
	if (error != -EEXIST)  {
782
		xfs_trans_brelse(args->trans, bp);
D
Dave Chinner 已提交
783
		return error;
L
Linus Torvalds 已提交
784
	}
D
Dave Chinner 已提交
785
	error = xfs_attr3_leaf_getvalue(bp, args);
786
	xfs_trans_brelse(args->trans, bp);
L
Linus Torvalds 已提交
787 788 789
	if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
		error = xfs_attr_rmtval_get(args);
	}
D
Dave Chinner 已提交
790
	return error;
L
Linus Torvalds 已提交
791 792 793
}

/*========================================================================
794
 * External routines when attribute list size > geo->blksize
L
Linus Torvalds 已提交
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
 *========================================================================*/

/*
 * 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
xfs_attr_node_addname(xfs_da_args_t *args)
{
	xfs_da_state_t *state;
	xfs_da_state_blk_t *blk;
	xfs_inode_t *dp;
	xfs_mount_t *mp;
814
	int retval, error;
L
Linus Torvalds 已提交
815

816 817
	trace_xfs_attr_node_addname(args);

L
Linus Torvalds 已提交
818 819 820 821 822 823 824 825 826 827 828 829 830 831
	/*
	 * 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.
	 */
832
	error = xfs_da3_node_lookup_int(state, &retval);
L
Linus Torvalds 已提交
833 834 835 836
	if (error)
		goto out;
	blk = &state->path.blk[ state->path.active-1 ];
	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
D
Dave Chinner 已提交
837
	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
L
Linus Torvalds 已提交
838
		goto out;
D
Dave Chinner 已提交
839
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
840 841
		if (args->flags & ATTR_CREATE)
			goto out;
842 843 844

		trace_xfs_attr_node_replace(args);

845
		/* save the attribute state for later removal*/
846
		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
L
Linus Torvalds 已提交
847 848 849 850
		args->blkno2 = args->blkno;		/* set 2nd entry info*/
		args->index2 = args->index;
		args->rmtblkno2 = args->rmtblkno;
		args->rmtblkcnt2 = args->rmtblkcnt;
851 852 853 854 855 856 857
		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 已提交
858 859
		args->rmtblkno = 0;
		args->rmtblkcnt = 0;
860
		args->rmtvaluelen = 0;
L
Linus Torvalds 已提交
861 862
	}

D
Dave Chinner 已提交
863
	retval = xfs_attr3_leaf_add(blk->bp, state->args);
D
Dave Chinner 已提交
864
	if (retval == -ENOSPC) {
L
Linus Torvalds 已提交
865 866 867 868 869 870 871
		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);
872
			state = NULL;
873
			xfs_defer_init(args->dfops, args->firstblock);
D
Dave Chinner 已提交
874
			error = xfs_attr3_leaf_to_node(args);
875
			if (!error)
876
				error = xfs_defer_finish(&args->trans,
877
							args->dfops, dp);
L
Linus Torvalds 已提交
878 879
			if (error) {
				args->trans = NULL;
880
				xfs_defer_cancel(args->dfops);
L
Linus Torvalds 已提交
881 882 883 884 885 886 887
				goto out;
			}

			/*
			 * Commit the node conversion and start the next
			 * trans in the chain.
			 */
888 889
			error = xfs_trans_roll(&args->trans, dp);
			if (error)
L
Linus Torvalds 已提交
890 891 892 893 894 895 896 897 898 899 900
				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.
		 */
901
		xfs_defer_init(args->dfops, args->firstblock);
902
		error = xfs_da3_split(state);
903
		if (!error)
904
			error = xfs_defer_finish(&args->trans, args->dfops, dp);
L
Linus Torvalds 已提交
905 906
		if (error) {
			args->trans = NULL;
907
			xfs_defer_cancel(args->dfops);
L
Linus Torvalds 已提交
908 909 910 911 912 913
			goto out;
		}
	} else {
		/*
		 * Addition succeeded, update Btree hashvals.
		 */
914
		xfs_da3_fixhashpath(state, &state->path);
L
Linus Torvalds 已提交
915 916 917 918 919 920 921 922 923 924 925 926 927
	}

	/*
	 * 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.
	 */
928 929
	error = xfs_trans_roll(&args->trans, dp);
	if (error)
L
Linus Torvalds 已提交
930 931 932 933 934 935 936 937 938 939 940
		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 已提交
941
			return error;
L
Linus Torvalds 已提交
942 943 944 945 946 947 948 949
	}

	/*
	 * 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.
	 */
950
	if (args->op_flags & XFS_DA_OP_RENAME) {
L
Linus Torvalds 已提交
951 952 953 954
		/*
		 * In a separate transaction, set the incomplete flag on the
		 * "old" attr and clear the incomplete flag on the "new" attr.
		 */
D
Dave Chinner 已提交
955
		error = xfs_attr3_leaf_flipflags(args);
L
Linus Torvalds 已提交
956 957 958 959 960 961 962 963 964 965 966
		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;
967
		args->rmtvaluelen = args->rmtvaluelen2;
L
Linus Torvalds 已提交
968 969 970
		if (args->rmtblkno) {
			error = xfs_attr_rmtval_remove(args);
			if (error)
E
Eric Sandeen 已提交
971
				return error;
L
Linus Torvalds 已提交
972 973 974 975 976 977 978 979 980 981 982 983
		}

		/*
		 * 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.
		 */
		args->flags |= XFS_ATTR_INCOMPLETE;
		state = xfs_da_state_alloc();
		state->args = args;
		state->mp = mp;
		state->inleaf = 0;
984
		error = xfs_da3_node_lookup_int(state, &retval);
L
Linus Torvalds 已提交
985 986 987 988 989 990 991 992
		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 已提交
993
		error = xfs_attr3_leaf_remove(blk->bp, args);
994
		xfs_da3_fixhashpath(state, &state->path);
L
Linus Torvalds 已提交
995 996 997 998 999

		/*
		 * Check to see if the tree needs to be collapsed.
		 */
		if (retval && (state->path.active > 1)) {
1000
			xfs_defer_init(args->dfops, args->firstblock);
1001
			error = xfs_da3_join(state);
1002
			if (!error)
1003
				error = xfs_defer_finish(&args->trans,
1004
							args->dfops, dp);
L
Linus Torvalds 已提交
1005 1006
			if (error) {
				args->trans = NULL;
1007
				xfs_defer_cancel(args->dfops);
L
Linus Torvalds 已提交
1008 1009 1010 1011 1012 1013 1014
				goto out;
			}
		}

		/*
		 * Commit and start the next trans in the chain.
		 */
1015 1016
		error = xfs_trans_roll(&args->trans, dp);
		if (error)
L
Linus Torvalds 已提交
1017 1018 1019 1020 1021 1022
			goto out;

	} else if (args->rmtblkno > 0) {
		/*
		 * Added a "remote" value, just clear the incomplete flag.
		 */
D
Dave Chinner 已提交
1023
		error = xfs_attr3_leaf_clearflag(args);
L
Linus Torvalds 已提交
1024 1025 1026 1027 1028 1029 1030 1031 1032
		if (error)
			goto out;
	}
	retval = error = 0;

out:
	if (state)
		xfs_da_state_free(state);
	if (error)
E
Eric Sandeen 已提交
1033 1034
		return error;
	return retval;
L
Linus Torvalds 已提交
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
}

/*
 * 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
xfs_attr_node_removename(xfs_da_args_t *args)
{
	xfs_da_state_t *state;
	xfs_da_state_blk_t *blk;
	xfs_inode_t *dp;
1050
	struct xfs_buf *bp;
1051
	int retval, error, forkoff;
L
Linus Torvalds 已提交
1052

1053 1054
	trace_xfs_attr_node_removename(args);

L
Linus Torvalds 已提交
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
	/*
	 * 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.
	 */
1066
	error = xfs_da3_node_lookup_int(state, &retval);
D
Dave Chinner 已提交
1067
	if (error || (retval != -EEXIST)) {
L
Linus Torvalds 已提交
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
		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 已提交
1095
		error = xfs_attr3_leaf_setflag(args);
L
Linus Torvalds 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
		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 已提交
1116
	retval = xfs_attr3_leaf_remove(blk->bp, args);
1117
	xfs_da3_fixhashpath(state, &state->path);
L
Linus Torvalds 已提交
1118 1119 1120 1121 1122

	/*
	 * Check to see if the tree needs to be collapsed.
	 */
	if (retval && (state->path.active > 1)) {
1123
		xfs_defer_init(args->dfops, args->firstblock);
1124
		error = xfs_da3_join(state);
1125
		if (!error)
1126
			error = xfs_defer_finish(&args->trans, args->dfops, dp);
L
Linus Torvalds 已提交
1127 1128
		if (error) {
			args->trans = NULL;
1129
			xfs_defer_cancel(args->dfops);
L
Linus Torvalds 已提交
1130 1131 1132 1133 1134
			goto out;
		}
		/*
		 * Commit the Btree join operation and start a new trans.
		 */
1135 1136
		error = xfs_trans_roll(&args->trans, dp);
		if (error)
L
Linus Torvalds 已提交
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
			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;

D
Dave Chinner 已提交
1151
		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
L
Linus Torvalds 已提交
1152 1153 1154
		if (error)
			goto out;

1155
		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1156
			xfs_defer_init(args->dfops, args->firstblock);
D
Dave Chinner 已提交
1157
			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
L
Linus Torvalds 已提交
1158
			/* bp is gone due to xfs_da_shrink_inode */
1159
			if (!error)
1160
				error = xfs_defer_finish(&args->trans,
1161
							args->dfops, dp);
L
Linus Torvalds 已提交
1162 1163
			if (error) {
				args->trans = NULL;
1164
				xfs_defer_cancel(args->dfops);
L
Linus Torvalds 已提交
1165 1166 1167
				goto out;
			}
		} else
1168
			xfs_trans_brelse(args->trans, bp);
L
Linus Torvalds 已提交
1169 1170 1171 1172 1173
	}
	error = 0;

out:
	xfs_da_state_free(state);
E
Eric Sandeen 已提交
1174
	return error;
L
Linus Torvalds 已提交
1175 1176 1177 1178 1179 1180
}

/*
 * 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
1181
 * after some set of transaction commits have released these buffers.
L
Linus Torvalds 已提交
1182 1183 1184 1185 1186 1187 1188 1189
 */
STATIC int
xfs_attr_fillstate(xfs_da_state_t *state)
{
	xfs_da_state_path_t *path;
	xfs_da_state_blk_t *blk;
	int level;

1190 1191
	trace_xfs_attr_fillstate(state->args);

L
Linus Torvalds 已提交
1192 1193 1194 1195 1196 1197 1198 1199
	/*
	 * 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) {
1200
			blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
L
Linus Torvalds 已提交
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
			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) {
1215
			blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
L
Linus Torvalds 已提交
1216 1217 1218 1219 1220 1221
			blk->bp = NULL;
		} else {
			blk->disk_blkno = 0;
		}
	}

E
Eric Sandeen 已提交
1222
	return 0;
L
Linus Torvalds 已提交
1223 1224 1225 1226 1227
}

/*
 * Reattach the buffers to the state structure based on the disk block
 * numbers stored in the state structure.
1228
 * This is done after some set of transaction commits have released those
L
Linus Torvalds 已提交
1229 1230 1231 1232 1233 1234 1235 1236 1237
 * 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;

1238 1239
	trace_xfs_attr_refillstate(state->args);

L
Linus Torvalds 已提交
1240 1241 1242 1243 1244 1245 1246 1247
	/*
	 * 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) {
1248
			error = xfs_da3_node_read(state->args->trans,
L
Linus Torvalds 已提交
1249 1250
						state->args->dp,
						blk->blkno, blk->disk_blkno,
D
Dave Chinner 已提交
1251
						&blk->bp, XFS_ATTR_FORK);
L
Linus Torvalds 已提交
1252
			if (error)
E
Eric Sandeen 已提交
1253
				return error;
L
Linus Torvalds 已提交
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
		} 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) {
1267
			error = xfs_da3_node_read(state->args->trans,
L
Linus Torvalds 已提交
1268 1269
						state->args->dp,
						blk->blkno, blk->disk_blkno,
D
Dave Chinner 已提交
1270
						&blk->bp, XFS_ATTR_FORK);
L
Linus Torvalds 已提交
1271
			if (error)
E
Eric Sandeen 已提交
1272
				return error;
L
Linus Torvalds 已提交
1273 1274 1275 1276 1277
		} else {
			blk->bp = NULL;
		}
	}

E
Eric Sandeen 已提交
1278
	return 0;
L
Linus Torvalds 已提交
1279 1280 1281 1282 1283 1284 1285 1286 1287
}

/*
 * Look up a filename in a node attribute list.
 *
 * 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.
 */
1288
STATIC int
L
Linus Torvalds 已提交
1289 1290 1291 1292 1293 1294 1295
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;

1296 1297
	trace_xfs_attr_node_get(args);

L
Linus Torvalds 已提交
1298 1299 1300 1301 1302 1303 1304
	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.
	 */
1305
	error = xfs_da3_node_lookup_int(state, &retval);
L
Linus Torvalds 已提交
1306 1307
	if (error) {
		retval = error;
D
Dave Chinner 已提交
1308
	} else if (retval == -EEXIST) {
L
Linus Torvalds 已提交
1309 1310 1311 1312 1313 1314 1315
		blk = &state->path.blk[ state->path.active-1 ];
		ASSERT(blk->bp != NULL);
		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);

		/*
		 * Get the value, local or "remote"
		 */
D
Dave Chinner 已提交
1316
		retval = xfs_attr3_leaf_getvalue(blk->bp, args);
L
Linus Torvalds 已提交
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
		if (!retval && (args->rmtblkno > 0)
		    && !(args->flags & ATTR_KERNOVAL)) {
			retval = xfs_attr_rmtval_get(args);
		}
	}

	/*
	 * If not in a transaction, we have to release all the buffers.
	 */
	for (i = 0; i < state->path.active; i++) {
1327
		xfs_trans_brelse(args->trans, state->path.blk[i].bp);
L
Linus Torvalds 已提交
1328 1329 1330 1331
		state->path.blk[i].bp = NULL;
	}

	xfs_da_state_free(state);
E
Eric Sandeen 已提交
1332
	return retval;
L
Linus Torvalds 已提交
1333
}