xfs_attr_remote.c 15.7 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
}

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

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

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

	while (len > 0) {
177 178
		struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;

179
		if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
D
Dave Chinner 已提交
180
			xfs_buf_ioerror(bp, -EFSCORRUPTED);
181
			xfs_verifier_error(bp);
D
Dave Chinner 已提交
182 183
			return;
		}
184

185 186 187 188 189 190 191 192
		/*
		 * Ensure we aren't writing bogus LSNs to disk. See
		 * xfs_attr3_rmt_hdr_set() for the explanation.
		 */
		if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
			xfs_buf_ioerror(bp, -EFSCORRUPTED);
			xfs_verifier_error(bp);
			return;
D
Dave Chinner 已提交
193
		}
194
		xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
D
Dave Chinner 已提交
195

196 197 198
		len -= blksize;
		ptr += blksize;
		bno += BTOBB(blksize);
199
	}
D
Dave Chinner 已提交
200
	ASSERT(len == 0);
201 202 203 204 205 206 207
}

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 已提交
208
STATIC int
209 210
xfs_attr3_rmt_hdr_set(
	struct xfs_mount	*mp,
D
Dave Chinner 已提交
211
	void			*ptr,
212 213 214
	xfs_ino_t		ino,
	uint32_t		offset,
	uint32_t		size,
D
Dave Chinner 已提交
215
	xfs_daddr_t		bno)
216
{
D
Dave Chinner 已提交
217
	struct xfs_attr3_rmt_hdr *rmt = ptr;
218 219 220 221 222 223 224

	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);
225
	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
226
	rmt->rm_owner = cpu_to_be64(ino);
D
Dave Chinner 已提交
227
	rmt->rm_blkno = cpu_to_be64(bno);
228

229 230 231 232 233 234 235 236 237 238 239 240
	/*
	 * Remote attribute blocks are written synchronously, so we don't
	 * have an LSN that we can stamp in them that makes any sense to log
	 * recovery. To ensure that log recovery handles overwrites of these
	 * blocks sanely (i.e. once they've been freed and reallocated as some
	 * other type of metadata) we need to ensure that the LSN has a value
	 * that tells log recovery to ignore the LSN and overwrite the buffer
	 * with whatever is in it's log. To do this, we use the magic
	 * NULLCOMMITLSN to indicate that the LSN is invalid.
	 */
	rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);

241 242 243 244
	return sizeof(struct xfs_attr3_rmt_hdr);
}

/*
D
Dave Chinner 已提交
245
 * Helper functions to copy attribute data in and out of the one disk extents
246
 */
D
Dave Chinner 已提交
247 248 249 250 251 252 253
STATIC int
xfs_attr_rmtval_copyout(
	struct xfs_mount *mp,
	struct xfs_buf	*bp,
	xfs_ino_t	ino,
	int		*offset,
	int		*valuelen,
254
	__uint8_t	**dst)
255
{
D
Dave Chinner 已提交
256 257 258
	char		*src = bp->b_addr;
	xfs_daddr_t	bno = bp->b_bn;
	int		len = BBTOB(bp->b_length);
259
	int		blksize = mp->m_attr_geo->blksize;
260

261
	ASSERT(len >= blksize);
262

D
Dave Chinner 已提交
263 264
	while (len > 0 && *valuelen > 0) {
		int hdr_size = 0;
265
		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
D
Dave Chinner 已提交
266

D
Dave Chinner 已提交
267
		byte_cnt = min(*valuelen, byte_cnt);
D
Dave Chinner 已提交
268 269

		if (xfs_sb_version_hascrc(&mp->m_sb)) {
270
			if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
D
Dave Chinner 已提交
271 272 273 274
						  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 已提交
275
				return -EFSCORRUPTED;
D
Dave Chinner 已提交
276 277 278 279 280 281 282
			}
			hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
		}

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

		/* roll buffer forwards */
283 284 285
		len -= blksize;
		src += blksize;
		bno += BTOBB(blksize);
D
Dave Chinner 已提交
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

		/* 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,
302
	__uint8_t	**src)
D
Dave Chinner 已提交
303 304 305 306
{
	char		*dst = bp->b_addr;
	xfs_daddr_t	bno = bp->b_bn;
	int		len = BBTOB(bp->b_length);
307
	int		blksize = mp->m_attr_geo->blksize;
D
Dave Chinner 已提交
308

309
	ASSERT(len >= blksize);
D
Dave Chinner 已提交
310 311 312

	while (len > 0 && *valuelen > 0) {
		int hdr_size;
313
		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
D
Dave Chinner 已提交
314 315 316 317 318 319 320 321 322 323 324

		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.
		 */
325
		if (byte_cnt + hdr_size < blksize) {
D
Dave Chinner 已提交
326
			ASSERT(*valuelen - byte_cnt == 0);
327
			ASSERT(len == blksize);
D
Dave Chinner 已提交
328
			memset(dst + hdr_size + byte_cnt, 0,
329
					blksize - hdr_size - byte_cnt);
D
Dave Chinner 已提交
330 331 332
		}

		/* roll buffer forwards */
333 334 335
		len -= blksize;
		dst += blksize;
		bno += BTOBB(blksize);
D
Dave Chinner 已提交
336 337 338 339 340 341

		/* roll attribute data forwards */
		*valuelen -= byte_cnt;
		*src += byte_cnt;
		*offset += byte_cnt;
	}
342 343
}

344 345 346 347 348
/*
 * Read the value associated with an attribute from the out-of-line buffer
 * that we stored it in.
 */
int
349 350
xfs_attr_rmtval_get(
	struct xfs_da_args	*args)
351
{
352 353 354 355
	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;
356
	__uint8_t		*dst = args->value;
357
	int			valuelen;
358 359
	int			nmap;
	int			error;
D
Dave Chinner 已提交
360
	int			blkcnt = args->rmtblkcnt;
361 362
	int			i;
	int			offset = 0;
363 364 365 366

	trace_xfs_attr_rmtval_get(args);

	ASSERT(!(args->flags & ATTR_KERNOVAL));
367
	ASSERT(args->rmtvaluelen == args->valuelen);
368

369
	valuelen = args->rmtvaluelen;
370 371 372
	while (valuelen > 0) {
		nmap = ATTR_RMTVALUE_MAPSIZE;
		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
373
				       blkcnt, map, &nmap,
374 375
				       XFS_BMAPI_ATTRFORK);
		if (error)
376
			return error;
377 378 379
		ASSERT(nmap >= 1);

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

383 384 385
			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
			       (map[i].br_startblock != HOLESTARTBLOCK));
			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
D
Dave Chinner 已提交
386
			dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
387
			error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
D
Dave Chinner 已提交
388
						   dblkno, dblkcnt, 0, &bp,
389
						   &xfs_attr3_rmt_buf_ops);
390
			if (error)
391 392
				return error;

D
Dave Chinner 已提交
393 394 395
			error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
							&offset, &valuelen,
							&dst);
396
			xfs_buf_relse(bp);
D
Dave Chinner 已提交
397 398
			if (error)
				return error;
399

D
Dave Chinner 已提交
400
			/* roll attribute extent map forwards */
401
			lblkno += map[i].br_blockcount;
D
Dave Chinner 已提交
402
			blkcnt -= map[i].br_blockcount;
403 404 405
		}
	}
	ASSERT(valuelen == 0);
406
	return 0;
407 408 409 410 411 412 413
}

/*
 * Write the value associated with an attribute into the out-of-line buffer
 * that we have defined for it.
 */
int
414 415
xfs_attr_rmtval_set(
	struct xfs_da_args	*args)
416
{
417 418 419 420 421
	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;
422
	__uint8_t		*src = args->value;
423 424 425 426 427
	int			blkcnt;
	int			valuelen;
	int			nmap;
	int			error;
	int			offset = 0;
428 429 430 431 432

	trace_xfs_attr_rmtval_set(args);

	/*
	 * Find a "hole" in the attribute address space large enough for
433 434
	 * 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 已提交
435
	 * conversion and have to take the header space into account.
436
	 */
437
	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
438 439
	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
						   XFS_ATTR_FORK);
440 441 442
	if (error)
		return error;

443 444 445 446 447 448 449
	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
	args->rmtblkcnt = blkcnt;

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

452 453
		/*
		 * Allocate a single extent, up to the size of the value.
454 455 456 457 458 459 460 461 462
		 *
		 * Note that we have to consider this a data allocation as we
		 * write the remote attribute without logging the contents.
		 * Hence we must ensure that we aren't using blocks that are on
		 * the busy list so that we don't overwrite blocks which have
		 * recently been freed but their transactions are not yet
		 * committed to disk. If we overwrite the contents of a busy
		 * extent and then crash then the block may not contain the
		 * correct metadata after log recovery occurs.
463 464 465 466
		 */
		xfs_bmap_init(args->flist, args->firstblock);
		nmap = 1;
		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
467 468
				  blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
				  args->total, &map, &nmap, args->flist);
469 470 471 472 473 474 475 476
		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 已提交
477
			return error;
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
		}

		/*
		 * 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 已提交
498
			return error;
499 500 501 502 503 504 505 506 507
	}

	/*
	 * 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;
508
	blkcnt = args->rmtblkcnt;
509
	valuelen = args->rmtvaluelen;
510
	while (valuelen > 0) {
D
Dave Chinner 已提交
511 512 513 514 515
		struct xfs_buf	*bp;
		xfs_daddr_t	dblkno;
		int		dblkcnt;

		ASSERT(blkcnt > 0);
516 517 518 519

		xfs_bmap_init(args->flist, args->firstblock);
		nmap = 1;
		error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
520
				       blkcnt, &map, &nmap,
521 522
				       XFS_BMAPI_ATTRFORK);
		if (error)
E
Eric Sandeen 已提交
523
			return error;
524 525 526 527 528
		ASSERT(nmap == 1);
		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
		       (map.br_startblock != HOLESTARTBLOCK));

		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
529
		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
530

531
		bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
532
		if (!bp)
D
Dave Chinner 已提交
533
			return -ENOMEM;
534
		bp->b_ops = &xfs_attr3_rmt_buf_ops;
535

D
Dave Chinner 已提交
536 537
		xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
				       &valuelen, &src);
538 539 540 541 542

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

544

D
Dave Chinner 已提交
545
		/* roll attribute extent map forwards */
546
		lblkno += map.br_blockcount;
547
		blkcnt -= map.br_blockcount;
548 549
	}
	ASSERT(valuelen == 0);
550
	return 0;
551 552 553 554 555 556 557
}

/*
 * Remove the value associated with an attribute by deleting the
 * out-of-line buffer that it is stored on.
 */
int
D
Dave Chinner 已提交
558 559
xfs_attr_rmtval_remove(
	struct xfs_da_args	*args)
560
{
D
Dave Chinner 已提交
561 562 563 564 565
	struct xfs_mount	*mp = args->dp->i_mount;
	xfs_dablk_t		lblkno;
	int			blkcnt;
	int			error;
	int			done;
566 567 568 569

	trace_xfs_attr_rmtval_remove(args);

	/*
570
	 * Roll through the "value", invalidating the attribute value's blocks.
571 572
	 */
	lblkno = args->rmtblkno;
D
Dave Chinner 已提交
573 574 575 576 577 578 579
	blkcnt = args->rmtblkcnt;
	while (blkcnt > 0) {
		struct xfs_bmbt_irec	map;
		struct xfs_buf		*bp;
		xfs_daddr_t		dblkno;
		int			dblkcnt;
		int			nmap;
580

581 582 583 584 585
		/*
		 * Try to remember where we decided to put the value.
		 */
		nmap = 1;
		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
586
				       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
587
		if (error)
E
Eric Sandeen 已提交
588
			return error;
589 590 591 592 593
		ASSERT(nmap == 1);
		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
		       (map.br_startblock != HOLESTARTBLOCK));

		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
594
		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
595 596 597 598

		/*
		 * If the "remote" value is in the cache, remove it.
		 */
599
		bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
600 601 602 603 604 605 606
		if (bp) {
			xfs_buf_stale(bp);
			xfs_buf_relse(bp);
			bp = NULL;
		}

		lblkno += map.br_blockcount;
607
		blkcnt -= map.br_blockcount;
608 609 610 611 612 613
	}

	/*
	 * Keep de-allocating extents until the remote-value region is gone.
	 */
	lblkno = args->rmtblkno;
D
Dave Chinner 已提交
614
	blkcnt = args->rmtblkcnt;
615 616
	done = 0;
	while (!done) {
D
Dave Chinner 已提交
617 618
		int committed;

619 620
		xfs_bmap_init(args->flist, args->firstblock);
		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
621 622
				    XFS_BMAPI_ATTRFORK, 1, args->firstblock,
				    args->flist, &done);
623 624 625 626 627 628 629 630
		if (!error) {
			error = xfs_bmap_finish(&args->trans, args->flist,
						&committed);
		}
		if (error) {
			ASSERT(committed);
			args->trans = NULL;
			xfs_bmap_cancel(args->flist);
631
			return error;
632 633 634 635 636 637 638 639 640 641 642 643 644 645
		}

		/*
		 * 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 已提交
646
			return error;
647
	}
E
Eric Sandeen 已提交
648
	return 0;
649
}