xfs_attr_remote.c 14.6 KB
Newer Older
1 2
/*
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3
 * Copyright (c) 2013 Red Hat, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * 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.
 *
 * 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
 */
#include "xfs.h"
#include "xfs_fs.h"
21
#include "xfs_shared.h"
22
#include "xfs_format.h"
23 24
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
25 26
#include "xfs_bit.h"
#include "xfs_mount.h"
27
#include "xfs_da_format.h"
28 29 30
#include "xfs_da_btree.h"
#include "xfs_inode.h"
#include "xfs_alloc.h"
31
#include "xfs_trans.h"
32 33
#include "xfs_inode_item.h"
#include "xfs_bmap.h"
D
Dave Chinner 已提交
34
#include "xfs_bmap_util.h"
35 36 37 38 39
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
#include "xfs_attr_remote.h"
#include "xfs_trans_space.h"
#include "xfs_trace.h"
40 41
#include "xfs_cksum.h"
#include "xfs_buf_item.h"
42
#include "xfs_error.h"
43 44 45

#define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */

46 47 48 49
/*
 * Each contiguous block has a header, so it is not just a simple attribute
 * length to FSB conversion.
 */
D
Dave Chinner 已提交
50
int
51 52 53 54
xfs_attr3_rmt_blocks(
	struct xfs_mount *mp,
	int		attrlen)
{
55 56 57 58 59
	if (xfs_sb_version_hascrc(&mp->m_sb)) {
		int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
		return (attrlen + buflen - 1) / buflen;
	}
	return XFS_B_TO_FSB(mp, attrlen);
60 61
}

D
Dave Chinner 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
/*
 * Checking of the remote attribute header is split into two parts. The verifier
 * does CRC, location and bounds checking, the unpacking function checks the
 * attribute parameters and owner.
 */
static bool
xfs_attr3_rmt_hdr_ok(
	void			*ptr,
	xfs_ino_t		ino,
	uint32_t		offset,
	uint32_t		size,
	xfs_daddr_t		bno)
{
	struct xfs_attr3_rmt_hdr *rmt = ptr;

	if (bno != be64_to_cpu(rmt->rm_blkno))
		return false;
	if (offset != be32_to_cpu(rmt->rm_offset))
		return false;
	if (size != be32_to_cpu(rmt->rm_bytes))
		return false;
	if (ino != be64_to_cpu(rmt->rm_owner))
		return false;

	/* ok */
	return true;
}

90 91
static bool
xfs_attr3_rmt_verify(
D
Dave Chinner 已提交
92 93 94 95
	struct xfs_mount	*mp,
	void			*ptr,
	int			fsbsize,
	xfs_daddr_t		bno)
96
{
D
Dave Chinner 已提交
97
	struct xfs_attr3_rmt_hdr *rmt = ptr;
98 99 100 101 102

	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return false;
	if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
		return false;
103
	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
104
		return false;
D
Dave Chinner 已提交
105 106 107
	if (be64_to_cpu(rmt->rm_blkno) != bno)
		return false;
	if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
108 109
		return false;
	if (be32_to_cpu(rmt->rm_offset) +
110
				be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX)
111 112 113 114 115 116 117 118 119 120 121 122
		return false;
	if (rmt->rm_owner == 0)
		return false;

	return true;
}

static void
xfs_attr3_rmt_read_verify(
	struct xfs_buf	*bp)
{
	struct xfs_mount *mp = bp->b_target->bt_mount;
D
Dave Chinner 已提交
123 124 125
	char		*ptr;
	int		len;
	xfs_daddr_t	bno;
126
	int		blksize = mp->m_attr_geo->blksize;
127 128 129 130 131

	/* no verification of non-crc buffers */
	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return;

D
Dave Chinner 已提交
132 133 134
	ptr = bp->b_addr;
	bno = bp->b_bn;
	len = BBTOB(bp->b_length);
135
	ASSERT(len >= blksize);
D
Dave Chinner 已提交
136 137

	while (len > 0) {
138
		if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
D
Dave Chinner 已提交
139
			xfs_buf_ioerror(bp, -EFSBADCRC);
D
Dave Chinner 已提交
140 141
			break;
		}
142
		if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
D
Dave Chinner 已提交
143
			xfs_buf_ioerror(bp, -EFSCORRUPTED);
D
Dave Chinner 已提交
144 145
			break;
		}
146 147 148
		len -= blksize;
		ptr += blksize;
		bno += BTOBB(blksize);
D
Dave Chinner 已提交
149 150
	}

151 152 153
	if (bp->b_error)
		xfs_verifier_error(bp);
	else
D
Dave Chinner 已提交
154
		ASSERT(len == 0);
155 156 157 158 159 160 161 162
}

static void
xfs_attr3_rmt_write_verify(
	struct xfs_buf	*bp)
{
	struct xfs_mount *mp = bp->b_target->bt_mount;
	struct xfs_buf_log_item	*bip = bp->b_fspriv;
D
Dave Chinner 已提交
163 164 165
	char		*ptr;
	int		len;
	xfs_daddr_t	bno;
166
	int		blksize = mp->m_attr_geo->blksize;
167 168 169 170 171

	/* no verification of non-crc buffers */
	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return;

D
Dave Chinner 已提交
172 173 174
	ptr = bp->b_addr;
	bno = bp->b_bn;
	len = BBTOB(bp->b_length);
175
	ASSERT(len >= blksize);
D
Dave Chinner 已提交
176 177

	while (len > 0) {
178
		if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
D
Dave Chinner 已提交
179
			xfs_buf_ioerror(bp, -EFSCORRUPTED);
180
			xfs_verifier_error(bp);
D
Dave Chinner 已提交
181 182 183 184
			return;
		}
		if (bip) {
			struct xfs_attr3_rmt_hdr *rmt;
185

D
Dave Chinner 已提交
186 187 188
			rmt = (struct xfs_attr3_rmt_hdr *)ptr;
			rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
		}
189
		xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
D
Dave Chinner 已提交
190

191 192 193
		len -= blksize;
		ptr += blksize;
		bno += BTOBB(blksize);
194
	}
D
Dave Chinner 已提交
195
	ASSERT(len == 0);
196 197 198 199 200 201 202
}

const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
	.verify_read = xfs_attr3_rmt_read_verify,
	.verify_write = xfs_attr3_rmt_write_verify,
};

D
Dave Chinner 已提交
203
STATIC int
204 205
xfs_attr3_rmt_hdr_set(
	struct xfs_mount	*mp,
D
Dave Chinner 已提交
206
	void			*ptr,
207 208 209
	xfs_ino_t		ino,
	uint32_t		offset,
	uint32_t		size,
D
Dave Chinner 已提交
210
	xfs_daddr_t		bno)
211
{
D
Dave Chinner 已提交
212
	struct xfs_attr3_rmt_hdr *rmt = ptr;
213 214 215 216 217 218 219

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

	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
	rmt->rm_offset = cpu_to_be32(offset);
	rmt->rm_bytes = cpu_to_be32(size);
220
	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
221
	rmt->rm_owner = cpu_to_be64(ino);
D
Dave Chinner 已提交
222
	rmt->rm_blkno = cpu_to_be64(bno);
223 224 225 226 227

	return sizeof(struct xfs_attr3_rmt_hdr);
}

/*
D
Dave Chinner 已提交
228
 * Helper functions to copy attribute data in and out of the one disk extents
229
 */
D
Dave Chinner 已提交
230 231 232 233 234 235 236
STATIC int
xfs_attr_rmtval_copyout(
	struct xfs_mount *mp,
	struct xfs_buf	*bp,
	xfs_ino_t	ino,
	int		*offset,
	int		*valuelen,
237
	__uint8_t	**dst)
238
{
D
Dave Chinner 已提交
239 240 241
	char		*src = bp->b_addr;
	xfs_daddr_t	bno = bp->b_bn;
	int		len = BBTOB(bp->b_length);
242
	int		blksize = mp->m_attr_geo->blksize;
243

244
	ASSERT(len >= blksize);
245

D
Dave Chinner 已提交
246 247
	while (len > 0 && *valuelen > 0) {
		int hdr_size = 0;
248
		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
D
Dave Chinner 已提交
249

D
Dave Chinner 已提交
250
		byte_cnt = min(*valuelen, byte_cnt);
D
Dave Chinner 已提交
251 252

		if (xfs_sb_version_hascrc(&mp->m_sb)) {
253
			if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
D
Dave Chinner 已提交
254 255 256 257
						  byte_cnt, bno)) {
				xfs_alert(mp,
"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
					bno, *offset, byte_cnt, ino);
D
Dave Chinner 已提交
258
				return -EFSCORRUPTED;
D
Dave Chinner 已提交
259 260 261 262 263 264 265
			}
			hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
		}

		memcpy(*dst, src + hdr_size, byte_cnt);

		/* roll buffer forwards */
266 267 268
		len -= blksize;
		src += blksize;
		bno += BTOBB(blksize);
D
Dave Chinner 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

		/* roll attribute data forwards */
		*valuelen -= byte_cnt;
		*dst += byte_cnt;
		*offset += byte_cnt;
	}
	return 0;
}

STATIC void
xfs_attr_rmtval_copyin(
	struct xfs_mount *mp,
	struct xfs_buf	*bp,
	xfs_ino_t	ino,
	int		*offset,
	int		*valuelen,
285
	__uint8_t	**src)
D
Dave Chinner 已提交
286 287 288 289
{
	char		*dst = bp->b_addr;
	xfs_daddr_t	bno = bp->b_bn;
	int		len = BBTOB(bp->b_length);
290
	int		blksize = mp->m_attr_geo->blksize;
D
Dave Chinner 已提交
291

292
	ASSERT(len >= blksize);
D
Dave Chinner 已提交
293 294 295

	while (len > 0 && *valuelen > 0) {
		int hdr_size;
296
		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
D
Dave Chinner 已提交
297 298 299 300 301 302 303 304 305 306 307

		byte_cnt = min(*valuelen, byte_cnt);
		hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
						 byte_cnt, bno);

		memcpy(dst + hdr_size, *src, byte_cnt);

		/*
		 * If this is the last block, zero the remainder of it.
		 * Check that we are actually the last block, too.
		 */
308
		if (byte_cnt + hdr_size < blksize) {
D
Dave Chinner 已提交
309
			ASSERT(*valuelen - byte_cnt == 0);
310
			ASSERT(len == blksize);
D
Dave Chinner 已提交
311
			memset(dst + hdr_size + byte_cnt, 0,
312
					blksize - hdr_size - byte_cnt);
D
Dave Chinner 已提交
313 314 315
		}

		/* roll buffer forwards */
316 317 318
		len -= blksize;
		dst += blksize;
		bno += BTOBB(blksize);
D
Dave Chinner 已提交
319 320 321 322 323 324

		/* roll attribute data forwards */
		*valuelen -= byte_cnt;
		*src += byte_cnt;
		*offset += byte_cnt;
	}
325 326
}

327 328 329 330 331
/*
 * Read the value associated with an attribute from the out-of-line buffer
 * that we stored it in.
 */
int
332 333
xfs_attr_rmtval_get(
	struct xfs_da_args	*args)
334
{
335 336 337 338
	struct xfs_bmbt_irec	map[ATTR_RMTVALUE_MAPSIZE];
	struct xfs_mount	*mp = args->dp->i_mount;
	struct xfs_buf		*bp;
	xfs_dablk_t		lblkno = args->rmtblkno;
339
	__uint8_t		*dst = args->value;
340
	int			valuelen;
341 342
	int			nmap;
	int			error;
D
Dave Chinner 已提交
343
	int			blkcnt = args->rmtblkcnt;
344 345
	int			i;
	int			offset = 0;
346 347 348 349

	trace_xfs_attr_rmtval_get(args);

	ASSERT(!(args->flags & ATTR_KERNOVAL));
350
	ASSERT(args->rmtvaluelen == args->valuelen);
351

352
	valuelen = args->rmtvaluelen;
353 354 355
	while (valuelen > 0) {
		nmap = ATTR_RMTVALUE_MAPSIZE;
		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
356
				       blkcnt, map, &nmap,
357 358
				       XFS_BMAPI_ATTRFORK);
		if (error)
359
			return error;
360 361 362
		ASSERT(nmap >= 1);

		for (i = 0; (i < nmap) && (valuelen > 0); i++) {
D
Dave Chinner 已提交
363 364
			xfs_daddr_t	dblkno;
			int		dblkcnt;
365

366 367 368
			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
			       (map[i].br_startblock != HOLESTARTBLOCK));
			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
D
Dave Chinner 已提交
369
			dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
370
			error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
D
Dave Chinner 已提交
371
						   dblkno, dblkcnt, 0, &bp,
372
						   &xfs_attr3_rmt_buf_ops);
373
			if (error)
374 375
				return error;

D
Dave Chinner 已提交
376 377 378
			error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
							&offset, &valuelen,
							&dst);
379
			xfs_buf_relse(bp);
D
Dave Chinner 已提交
380 381
			if (error)
				return error;
382

D
Dave Chinner 已提交
383
			/* roll attribute extent map forwards */
384
			lblkno += map[i].br_blockcount;
D
Dave Chinner 已提交
385
			blkcnt -= map[i].br_blockcount;
386 387 388
		}
	}
	ASSERT(valuelen == 0);
389
	return 0;
390 391 392 393 394 395 396
}

/*
 * Write the value associated with an attribute into the out-of-line buffer
 * that we have defined for it.
 */
int
397 398
xfs_attr_rmtval_set(
	struct xfs_da_args	*args)
399
{
400 401 402 403 404
	struct xfs_inode	*dp = args->dp;
	struct xfs_mount	*mp = dp->i_mount;
	struct xfs_bmbt_irec	map;
	xfs_dablk_t		lblkno;
	xfs_fileoff_t		lfileoff = 0;
405
	__uint8_t		*src = args->value;
406 407 408 409 410
	int			blkcnt;
	int			valuelen;
	int			nmap;
	int			error;
	int			offset = 0;
411 412 413 414 415

	trace_xfs_attr_rmtval_set(args);

	/*
	 * Find a "hole" in the attribute address space large enough for
416 417
	 * us to drop the new attribute's value into. Because CRC enable
	 * attributes have headers, we can't just do a straight byte to FSB
D
Dave Chinner 已提交
418
	 * conversion and have to take the header space into account.
419
	 */
420
	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
421 422
	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
						   XFS_ATTR_FORK);
423 424 425
	if (error)
		return error;

426 427 428 429 430 431 432
	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
	args->rmtblkcnt = blkcnt;

	/*
	 * Roll through the "value", allocating blocks on disk as required.
	 */
	while (blkcnt > 0) {
433 434
		int	committed;

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
		/*
		 * Allocate a single extent, up to the size of the value.
		 */
		xfs_bmap_init(args->flist, args->firstblock);
		nmap = 1;
		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
				  blkcnt,
				  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
				  args->firstblock, args->total, &map, &nmap,
				  args->flist);
		if (!error) {
			error = xfs_bmap_finish(&args->trans, args->flist,
						&committed);
		}
		if (error) {
			ASSERT(committed);
			args->trans = NULL;
			xfs_bmap_cancel(args->flist);
E
Eric Sandeen 已提交
453
			return error;
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
		}

		/*
		 * bmap_finish() may have committed the last trans and started
		 * a new one.  We need the inode to be in all transactions.
		 */
		if (committed)
			xfs_trans_ijoin(args->trans, dp, 0);

		ASSERT(nmap == 1);
		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
		       (map.br_startblock != HOLESTARTBLOCK));
		lblkno += map.br_blockcount;
		blkcnt -= map.br_blockcount;

		/*
		 * Start the next trans in the chain.
		 */
		error = xfs_trans_roll(&args->trans, dp);
		if (error)
E
Eric Sandeen 已提交
474
			return error;
475 476 477 478 479 480 481 482 483
	}

	/*
	 * Roll through the "value", copying the attribute value to the
	 * already-allocated blocks.  Blocks are written synchronously
	 * so that we can know they are all on disk before we turn off
	 * the INCOMPLETE flag.
	 */
	lblkno = args->rmtblkno;
484
	blkcnt = args->rmtblkcnt;
485
	valuelen = args->rmtvaluelen;
486
	while (valuelen > 0) {
D
Dave Chinner 已提交
487 488 489 490 491
		struct xfs_buf	*bp;
		xfs_daddr_t	dblkno;
		int		dblkcnt;

		ASSERT(blkcnt > 0);
492 493 494 495

		xfs_bmap_init(args->flist, args->firstblock);
		nmap = 1;
		error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
496
				       blkcnt, &map, &nmap,
497 498
				       XFS_BMAPI_ATTRFORK);
		if (error)
E
Eric Sandeen 已提交
499
			return error;
500 501 502 503 504
		ASSERT(nmap == 1);
		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
		       (map.br_startblock != HOLESTARTBLOCK));

		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
505
		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
506

507
		bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
508
		if (!bp)
D
Dave Chinner 已提交
509
			return -ENOMEM;
510
		bp->b_ops = &xfs_attr3_rmt_buf_ops;
511

D
Dave Chinner 已提交
512 513
		xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
				       &valuelen, &src);
514 515 516 517 518

		error = xfs_bwrite(bp);	/* GROT: NOTE: synchronous write */
		xfs_buf_relse(bp);
		if (error)
			return error;
519

520

D
Dave Chinner 已提交
521
		/* roll attribute extent map forwards */
522
		lblkno += map.br_blockcount;
523
		blkcnt -= map.br_blockcount;
524 525
	}
	ASSERT(valuelen == 0);
526
	return 0;
527 528 529 530 531 532 533
}

/*
 * Remove the value associated with an attribute by deleting the
 * out-of-line buffer that it is stored on.
 */
int
D
Dave Chinner 已提交
534 535
xfs_attr_rmtval_remove(
	struct xfs_da_args	*args)
536
{
D
Dave Chinner 已提交
537 538 539 540 541
	struct xfs_mount	*mp = args->dp->i_mount;
	xfs_dablk_t		lblkno;
	int			blkcnt;
	int			error;
	int			done;
542 543 544 545

	trace_xfs_attr_rmtval_remove(args);

	/*
546
	 * Roll through the "value", invalidating the attribute value's blocks.
547 548
	 */
	lblkno = args->rmtblkno;
D
Dave Chinner 已提交
549 550 551 552 553 554 555
	blkcnt = args->rmtblkcnt;
	while (blkcnt > 0) {
		struct xfs_bmbt_irec	map;
		struct xfs_buf		*bp;
		xfs_daddr_t		dblkno;
		int			dblkcnt;
		int			nmap;
556

557 558 559 560 561
		/*
		 * Try to remember where we decided to put the value.
		 */
		nmap = 1;
		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
562
				       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
563
		if (error)
E
Eric Sandeen 已提交
564
			return error;
565 566 567 568 569
		ASSERT(nmap == 1);
		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
		       (map.br_startblock != HOLESTARTBLOCK));

		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
570
		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
571 572 573 574

		/*
		 * If the "remote" value is in the cache, remove it.
		 */
575
		bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
576 577 578 579 580 581 582
		if (bp) {
			xfs_buf_stale(bp);
			xfs_buf_relse(bp);
			bp = NULL;
		}

		lblkno += map.br_blockcount;
583
		blkcnt -= map.br_blockcount;
584 585 586 587 588 589
	}

	/*
	 * Keep de-allocating extents until the remote-value region is gone.
	 */
	lblkno = args->rmtblkno;
D
Dave Chinner 已提交
590
	blkcnt = args->rmtblkcnt;
591 592
	done = 0;
	while (!done) {
D
Dave Chinner 已提交
593 594
		int committed;

595 596 597 598 599 600 601 602 603 604 605 606 607
		xfs_bmap_init(args->flist, args->firstblock);
		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
				    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
				    1, args->firstblock, args->flist,
				    &done);
		if (!error) {
			error = xfs_bmap_finish(&args->trans, args->flist,
						&committed);
		}
		if (error) {
			ASSERT(committed);
			args->trans = NULL;
			xfs_bmap_cancel(args->flist);
608
			return error;
609 610 611 612 613 614 615 616 617 618 619 620 621 622
		}

		/*
		 * bmap_finish() may have committed the last trans and started
		 * a new one.  We need the inode to be in all transactions.
		 */
		if (committed)
			xfs_trans_ijoin(args->trans, args->dp, 0);

		/*
		 * Close out trans and start the next one in the chain.
		 */
		error = xfs_trans_roll(&args->trans, args->dp);
		if (error)
E
Eric Sandeen 已提交
623
			return error;
624
	}
E
Eric Sandeen 已提交
625
	return 0;
626
}