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) > XFS_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
}

const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
204
	.name = "xfs_attr3_rmt",
205 206 207 208
	.verify_read = xfs_attr3_rmt_read_verify,
	.verify_write = xfs_attr3_rmt_write_verify,
};

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

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

230 231 232 233 234 235 236 237 238 239 240 241
	/*
	 * 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);

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

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

262
	ASSERT(len >= blksize);
263

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

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

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

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

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

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

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

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

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

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

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

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

	trace_xfs_attr_rmtval_get(args);

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

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

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

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

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

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

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

	trace_xfs_attr_rmtval_set(args);

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

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

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

453 454
		/*
		 * Allocate a single extent, up to the size of the value.
455 456 457 458 459 460 461 462 463
		 *
		 * 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.
464 465 466 467
		 */
		xfs_bmap_init(args->flist, args->firstblock);
		nmap = 1;
		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
468 469
				  blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
				  args->total, &map, &nmap, args->flist);
470 471 472 473 474 475 476 477
		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 已提交
478
			return error;
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
		}

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

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

		ASSERT(blkcnt > 0);
517 518 519 520

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

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

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

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

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

545

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

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

	trace_xfs_attr_rmtval_remove(args);

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

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

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

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

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

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

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

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