• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4  * Copyright (c) 2013 Red Hat, Inc.
5  * All Rights Reserved.
6  */
7 #include "xfs.h"
8 #include "xfs_fs.h"
9 #include "xfs_shared.h"
10 #include "xfs_format.h"
11 #include "xfs_log_format.h"
12 #include "xfs_trans_resv.h"
13 #include "xfs_bit.h"
14 #include "xfs_mount.h"
15 #include "xfs_defer.h"
16 #include "xfs_da_format.h"
17 #include "xfs_da_btree.h"
18 #include "xfs_inode.h"
19 #include "xfs_trans.h"
20 #include "xfs_bmap.h"
21 #include "xfs_attr.h"
22 #include "xfs_trace.h"
23 #include "xfs_error.h"
24 
25 #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
26 
27 /*
28  * Remote Attribute Values
29  * =======================
30  *
31  * Remote extended attribute values are conceptually simple -- they're written
32  * to data blocks mapped by an inode's attribute fork, and they have an upper
33  * size limit of 64k.  Setting a value does not involve the XFS log.
34  *
35  * However, on a v5 filesystem, maximally sized remote attr values require one
36  * block more than 64k worth of space to hold both the remote attribute value
37  * header (64 bytes).  On a 4k block filesystem this results in a 68k buffer;
38  * on a 64k block filesystem, this would be a 128k buffer.  Note that the log
39  * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
40  * Therefore, we /must/ ensure that remote attribute value buffers never touch
41  * the logging system and therefore never have a log item.
42  */
43 
44 /*
45  * Each contiguous block has a header, so it is not just a simple attribute
46  * length to FSB conversion.
47  */
48 int
xfs_attr3_rmt_blocks(struct xfs_mount * mp,int attrlen)49 xfs_attr3_rmt_blocks(
50 	struct xfs_mount *mp,
51 	int		attrlen)
52 {
53 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
54 		int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
55 		return (attrlen + buflen - 1) / buflen;
56 	}
57 	return XFS_B_TO_FSB(mp, attrlen);
58 }
59 
60 /*
61  * Checking of the remote attribute header is split into two parts. The verifier
62  * does CRC, location and bounds checking, the unpacking function checks the
63  * attribute parameters and owner.
64  */
65 static xfs_failaddr_t
xfs_attr3_rmt_hdr_ok(void * ptr,xfs_ino_t ino,uint32_t offset,uint32_t size,xfs_daddr_t bno)66 xfs_attr3_rmt_hdr_ok(
67 	void			*ptr,
68 	xfs_ino_t		ino,
69 	uint32_t		offset,
70 	uint32_t		size,
71 	xfs_daddr_t		bno)
72 {
73 	struct xfs_attr3_rmt_hdr *rmt = ptr;
74 
75 	if (bno != be64_to_cpu(rmt->rm_blkno))
76 		return __this_address;
77 	if (offset != be32_to_cpu(rmt->rm_offset))
78 		return __this_address;
79 	if (size != be32_to_cpu(rmt->rm_bytes))
80 		return __this_address;
81 	if (ino != be64_to_cpu(rmt->rm_owner))
82 		return __this_address;
83 
84 	/* ok */
85 	return NULL;
86 }
87 
88 static xfs_failaddr_t
xfs_attr3_rmt_verify(struct xfs_mount * mp,struct xfs_buf * bp,void * ptr,int fsbsize,xfs_daddr_t bno)89 xfs_attr3_rmt_verify(
90 	struct xfs_mount	*mp,
91 	struct xfs_buf		*bp,
92 	void			*ptr,
93 	int			fsbsize,
94 	xfs_daddr_t		bno)
95 {
96 	struct xfs_attr3_rmt_hdr *rmt = ptr;
97 
98 	if (!xfs_sb_version_hascrc(&mp->m_sb))
99 		return __this_address;
100 	if (!xfs_verify_magic(bp, rmt->rm_magic))
101 		return __this_address;
102 	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
103 		return __this_address;
104 	if (be64_to_cpu(rmt->rm_blkno) != bno)
105 		return __this_address;
106 	if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
107 		return __this_address;
108 	if (be32_to_cpu(rmt->rm_offset) +
109 				be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
110 		return __this_address;
111 	if (rmt->rm_owner == 0)
112 		return __this_address;
113 
114 	return NULL;
115 }
116 
117 static int
__xfs_attr3_rmt_read_verify(struct xfs_buf * bp,bool check_crc,xfs_failaddr_t * failaddr)118 __xfs_attr3_rmt_read_verify(
119 	struct xfs_buf	*bp,
120 	bool		check_crc,
121 	xfs_failaddr_t	*failaddr)
122 {
123 	struct xfs_mount *mp = bp->b_mount;
124 	char		*ptr;
125 	int		len;
126 	xfs_daddr_t	bno;
127 	int		blksize = mp->m_attr_geo->blksize;
128 
129 	/* no verification of non-crc buffers */
130 	if (!xfs_sb_version_hascrc(&mp->m_sb))
131 		return 0;
132 
133 	ptr = bp->b_addr;
134 	bno = bp->b_bn;
135 	len = BBTOB(bp->b_length);
136 	ASSERT(len >= blksize);
137 
138 	while (len > 0) {
139 		if (check_crc &&
140 		    !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
141 			*failaddr = __this_address;
142 			return -EFSBADCRC;
143 		}
144 		*failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
145 		if (*failaddr)
146 			return -EFSCORRUPTED;
147 		len -= blksize;
148 		ptr += blksize;
149 		bno += BTOBB(blksize);
150 	}
151 
152 	if (len != 0) {
153 		*failaddr = __this_address;
154 		return -EFSCORRUPTED;
155 	}
156 
157 	return 0;
158 }
159 
160 static void
xfs_attr3_rmt_read_verify(struct xfs_buf * bp)161 xfs_attr3_rmt_read_verify(
162 	struct xfs_buf	*bp)
163 {
164 	xfs_failaddr_t	fa;
165 	int		error;
166 
167 	error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
168 	if (error)
169 		xfs_verifier_error(bp, error, fa);
170 }
171 
172 static xfs_failaddr_t
xfs_attr3_rmt_verify_struct(struct xfs_buf * bp)173 xfs_attr3_rmt_verify_struct(
174 	struct xfs_buf	*bp)
175 {
176 	xfs_failaddr_t	fa;
177 	int		error;
178 
179 	error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
180 	return error ? fa : NULL;
181 }
182 
183 static void
xfs_attr3_rmt_write_verify(struct xfs_buf * bp)184 xfs_attr3_rmt_write_verify(
185 	struct xfs_buf	*bp)
186 {
187 	struct xfs_mount *mp = bp->b_mount;
188 	xfs_failaddr_t	fa;
189 	int		blksize = mp->m_attr_geo->blksize;
190 	char		*ptr;
191 	int		len;
192 	xfs_daddr_t	bno;
193 
194 	/* no verification of non-crc buffers */
195 	if (!xfs_sb_version_hascrc(&mp->m_sb))
196 		return;
197 
198 	ptr = bp->b_addr;
199 	bno = bp->b_bn;
200 	len = BBTOB(bp->b_length);
201 	ASSERT(len >= blksize);
202 
203 	while (len > 0) {
204 		struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
205 
206 		fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
207 		if (fa) {
208 			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
209 			return;
210 		}
211 
212 		/*
213 		 * Ensure we aren't writing bogus LSNs to disk. See
214 		 * xfs_attr3_rmt_hdr_set() for the explanation.
215 		 */
216 		if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
217 			xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
218 			return;
219 		}
220 		xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
221 
222 		len -= blksize;
223 		ptr += blksize;
224 		bno += BTOBB(blksize);
225 	}
226 
227 	if (len != 0)
228 		xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
229 }
230 
231 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
232 	.name = "xfs_attr3_rmt",
233 	.magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
234 	.verify_read = xfs_attr3_rmt_read_verify,
235 	.verify_write = xfs_attr3_rmt_write_verify,
236 	.verify_struct = xfs_attr3_rmt_verify_struct,
237 };
238 
239 STATIC int
xfs_attr3_rmt_hdr_set(struct xfs_mount * mp,void * ptr,xfs_ino_t ino,uint32_t offset,uint32_t size,xfs_daddr_t bno)240 xfs_attr3_rmt_hdr_set(
241 	struct xfs_mount	*mp,
242 	void			*ptr,
243 	xfs_ino_t		ino,
244 	uint32_t		offset,
245 	uint32_t		size,
246 	xfs_daddr_t		bno)
247 {
248 	struct xfs_attr3_rmt_hdr *rmt = ptr;
249 
250 	if (!xfs_sb_version_hascrc(&mp->m_sb))
251 		return 0;
252 
253 	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
254 	rmt->rm_offset = cpu_to_be32(offset);
255 	rmt->rm_bytes = cpu_to_be32(size);
256 	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
257 	rmt->rm_owner = cpu_to_be64(ino);
258 	rmt->rm_blkno = cpu_to_be64(bno);
259 
260 	/*
261 	 * Remote attribute blocks are written synchronously, so we don't
262 	 * have an LSN that we can stamp in them that makes any sense to log
263 	 * recovery. To ensure that log recovery handles overwrites of these
264 	 * blocks sanely (i.e. once they've been freed and reallocated as some
265 	 * other type of metadata) we need to ensure that the LSN has a value
266 	 * that tells log recovery to ignore the LSN and overwrite the buffer
267 	 * with whatever is in it's log. To do this, we use the magic
268 	 * NULLCOMMITLSN to indicate that the LSN is invalid.
269 	 */
270 	rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
271 
272 	return sizeof(struct xfs_attr3_rmt_hdr);
273 }
274 
275 /*
276  * Helper functions to copy attribute data in and out of the one disk extents
277  */
278 STATIC int
xfs_attr_rmtval_copyout(struct xfs_mount * mp,struct xfs_buf * bp,xfs_ino_t ino,int * offset,int * valuelen,uint8_t ** dst)279 xfs_attr_rmtval_copyout(
280 	struct xfs_mount *mp,
281 	struct xfs_buf	*bp,
282 	xfs_ino_t	ino,
283 	int		*offset,
284 	int		*valuelen,
285 	uint8_t		**dst)
286 {
287 	char		*src = bp->b_addr;
288 	xfs_daddr_t	bno = bp->b_bn;
289 	int		len = BBTOB(bp->b_length);
290 	int		blksize = mp->m_attr_geo->blksize;
291 
292 	ASSERT(len >= blksize);
293 
294 	while (len > 0 && *valuelen > 0) {
295 		int hdr_size = 0;
296 		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
297 
298 		byte_cnt = min(*valuelen, byte_cnt);
299 
300 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
301 			if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
302 						  byte_cnt, bno)) {
303 				xfs_alert(mp,
304 "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
305 					bno, *offset, byte_cnt, ino);
306 				return -EFSCORRUPTED;
307 			}
308 			hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
309 		}
310 
311 		memcpy(*dst, src + hdr_size, byte_cnt);
312 
313 		/* roll buffer forwards */
314 		len -= blksize;
315 		src += blksize;
316 		bno += BTOBB(blksize);
317 
318 		/* roll attribute data forwards */
319 		*valuelen -= byte_cnt;
320 		*dst += byte_cnt;
321 		*offset += byte_cnt;
322 	}
323 	return 0;
324 }
325 
326 STATIC void
xfs_attr_rmtval_copyin(struct xfs_mount * mp,struct xfs_buf * bp,xfs_ino_t ino,int * offset,int * valuelen,uint8_t ** src)327 xfs_attr_rmtval_copyin(
328 	struct xfs_mount *mp,
329 	struct xfs_buf	*bp,
330 	xfs_ino_t	ino,
331 	int		*offset,
332 	int		*valuelen,
333 	uint8_t		**src)
334 {
335 	char		*dst = bp->b_addr;
336 	xfs_daddr_t	bno = bp->b_bn;
337 	int		len = BBTOB(bp->b_length);
338 	int		blksize = mp->m_attr_geo->blksize;
339 
340 	ASSERT(len >= blksize);
341 
342 	while (len > 0 && *valuelen > 0) {
343 		int hdr_size;
344 		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
345 
346 		byte_cnt = min(*valuelen, byte_cnt);
347 		hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
348 						 byte_cnt, bno);
349 
350 		memcpy(dst + hdr_size, *src, byte_cnt);
351 
352 		/*
353 		 * If this is the last block, zero the remainder of it.
354 		 * Check that we are actually the last block, too.
355 		 */
356 		if (byte_cnt + hdr_size < blksize) {
357 			ASSERT(*valuelen - byte_cnt == 0);
358 			ASSERT(len == blksize);
359 			memset(dst + hdr_size + byte_cnt, 0,
360 					blksize - hdr_size - byte_cnt);
361 		}
362 
363 		/* roll buffer forwards */
364 		len -= blksize;
365 		dst += blksize;
366 		bno += BTOBB(blksize);
367 
368 		/* roll attribute data forwards */
369 		*valuelen -= byte_cnt;
370 		*src += byte_cnt;
371 		*offset += byte_cnt;
372 	}
373 }
374 
375 /*
376  * Read the value associated with an attribute from the out-of-line buffer
377  * that we stored it in.
378  *
379  * Returns 0 on successful retrieval, otherwise an error.
380  */
381 int
xfs_attr_rmtval_get(struct xfs_da_args * args)382 xfs_attr_rmtval_get(
383 	struct xfs_da_args	*args)
384 {
385 	struct xfs_bmbt_irec	map[ATTR_RMTVALUE_MAPSIZE];
386 	struct xfs_mount	*mp = args->dp->i_mount;
387 	struct xfs_buf		*bp;
388 	xfs_dablk_t		lblkno = args->rmtblkno;
389 	uint8_t			*dst = args->value;
390 	int			valuelen;
391 	int			nmap;
392 	int			error;
393 	int			blkcnt = args->rmtblkcnt;
394 	int			i;
395 	int			offset = 0;
396 
397 	trace_xfs_attr_rmtval_get(args);
398 
399 	ASSERT(!(args->flags & ATTR_KERNOVAL));
400 	ASSERT(args->rmtvaluelen == args->valuelen);
401 
402 	valuelen = args->rmtvaluelen;
403 	while (valuelen > 0) {
404 		nmap = ATTR_RMTVALUE_MAPSIZE;
405 		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
406 				       blkcnt, map, &nmap,
407 				       XFS_BMAPI_ATTRFORK);
408 		if (error)
409 			return error;
410 		ASSERT(nmap >= 1);
411 
412 		for (i = 0; (i < nmap) && (valuelen > 0); i++) {
413 			xfs_daddr_t	dblkno;
414 			int		dblkcnt;
415 
416 			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
417 			       (map[i].br_startblock != HOLESTARTBLOCK));
418 			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
419 			dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
420 			bp = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, 0,
421 					&xfs_attr3_rmt_buf_ops);
422 			if (!bp)
423 				return -ENOMEM;
424 			error = bp->b_error;
425 			if (error) {
426 				xfs_buf_ioerror_alert(bp, __func__);
427 				xfs_buf_relse(bp);
428 
429 				/* bad CRC means corrupted metadata */
430 				if (error == -EFSBADCRC)
431 					error = -EFSCORRUPTED;
432 				return error;
433 			}
434 
435 			error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
436 							&offset, &valuelen,
437 							&dst);
438 			xfs_buf_relse(bp);
439 			if (error)
440 				return error;
441 
442 			/* roll attribute extent map forwards */
443 			lblkno += map[i].br_blockcount;
444 			blkcnt -= map[i].br_blockcount;
445 		}
446 	}
447 	ASSERT(valuelen == 0);
448 	return 0;
449 }
450 
451 /*
452  * Write the value associated with an attribute into the out-of-line buffer
453  * that we have defined for it.
454  */
455 int
xfs_attr_rmtval_set(struct xfs_da_args * args)456 xfs_attr_rmtval_set(
457 	struct xfs_da_args	*args)
458 {
459 	struct xfs_inode	*dp = args->dp;
460 	struct xfs_mount	*mp = dp->i_mount;
461 	struct xfs_bmbt_irec	map;
462 	xfs_dablk_t		lblkno;
463 	xfs_fileoff_t		lfileoff = 0;
464 	uint8_t			*src = args->value;
465 	int			blkcnt;
466 	int			valuelen;
467 	int			nmap;
468 	int			error;
469 	int			offset = 0;
470 
471 	trace_xfs_attr_rmtval_set(args);
472 
473 	/*
474 	 * Find a "hole" in the attribute address space large enough for
475 	 * us to drop the new attribute's value into. Because CRC enable
476 	 * attributes have headers, we can't just do a straight byte to FSB
477 	 * conversion and have to take the header space into account.
478 	 */
479 	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
480 	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
481 						   XFS_ATTR_FORK);
482 	if (error)
483 		return error;
484 
485 	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
486 	args->rmtblkcnt = blkcnt;
487 
488 	/*
489 	 * Roll through the "value", allocating blocks on disk as required.
490 	 */
491 	while (blkcnt > 0) {
492 		/*
493 		 * Allocate a single extent, up to the size of the value.
494 		 *
495 		 * Note that we have to consider this a data allocation as we
496 		 * write the remote attribute without logging the contents.
497 		 * Hence we must ensure that we aren't using blocks that are on
498 		 * the busy list so that we don't overwrite blocks which have
499 		 * recently been freed but their transactions are not yet
500 		 * committed to disk. If we overwrite the contents of a busy
501 		 * extent and then crash then the block may not contain the
502 		 * correct metadata after log recovery occurs.
503 		 */
504 		nmap = 1;
505 		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
506 				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
507 				  &nmap);
508 		if (error)
509 			return error;
510 		error = xfs_defer_finish(&args->trans);
511 		if (error)
512 			return error;
513 
514 		ASSERT(nmap == 1);
515 		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
516 		       (map.br_startblock != HOLESTARTBLOCK));
517 		lblkno += map.br_blockcount;
518 		blkcnt -= map.br_blockcount;
519 
520 		/*
521 		 * Start the next trans in the chain.
522 		 */
523 		error = xfs_trans_roll_inode(&args->trans, dp);
524 		if (error)
525 			return error;
526 	}
527 
528 	/*
529 	 * Roll through the "value", copying the attribute value to the
530 	 * already-allocated blocks.  Blocks are written synchronously
531 	 * so that we can know they are all on disk before we turn off
532 	 * the INCOMPLETE flag.
533 	 */
534 	lblkno = args->rmtblkno;
535 	blkcnt = args->rmtblkcnt;
536 	valuelen = args->rmtvaluelen;
537 	while (valuelen > 0) {
538 		struct xfs_buf	*bp;
539 		xfs_daddr_t	dblkno;
540 		int		dblkcnt;
541 
542 		ASSERT(blkcnt > 0);
543 
544 		nmap = 1;
545 		error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
546 				       blkcnt, &map, &nmap,
547 				       XFS_BMAPI_ATTRFORK);
548 		if (error)
549 			return error;
550 		ASSERT(nmap == 1);
551 		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
552 		       (map.br_startblock != HOLESTARTBLOCK));
553 
554 		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
555 		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
556 
557 		bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt);
558 		if (!bp)
559 			return -ENOMEM;
560 		bp->b_ops = &xfs_attr3_rmt_buf_ops;
561 
562 		xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
563 				       &valuelen, &src);
564 
565 		error = xfs_bwrite(bp);	/* GROT: NOTE: synchronous write */
566 		xfs_buf_relse(bp);
567 		if (error)
568 			return error;
569 
570 
571 		/* roll attribute extent map forwards */
572 		lblkno += map.br_blockcount;
573 		blkcnt -= map.br_blockcount;
574 	}
575 	ASSERT(valuelen == 0);
576 	return 0;
577 }
578 
579 /* Mark stale any incore buffers for the remote value. */
580 int
xfs_attr_rmtval_stale(struct xfs_inode * ip,struct xfs_bmbt_irec * map,xfs_buf_flags_t incore_flags)581 xfs_attr_rmtval_stale(
582 	struct xfs_inode	*ip,
583 	struct xfs_bmbt_irec	*map,
584 	xfs_buf_flags_t		incore_flags)
585 {
586 	struct xfs_mount	*mp = ip->i_mount;
587 	struct xfs_buf		*bp;
588 
589 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
590 
591 	ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
592 	       (map->br_startblock != HOLESTARTBLOCK));
593 
594 	bp = xfs_buf_incore(mp->m_ddev_targp,
595 			XFS_FSB_TO_DADDR(mp, map->br_startblock),
596 			XFS_FSB_TO_BB(mp, map->br_blockcount), incore_flags);
597 	if (bp) {
598 		xfs_buf_stale(bp);
599 		xfs_buf_relse(bp);
600 	}
601 
602 	return 0;
603 }
604 
605 /*
606  * Remove the value associated with an attribute by deleting the
607  * out-of-line buffer that it is stored on.
608  */
609 int
xfs_attr_rmtval_remove(struct xfs_da_args * args)610 xfs_attr_rmtval_remove(
611 	struct xfs_da_args	*args)
612 {
613 	xfs_dablk_t		lblkno;
614 	int			blkcnt;
615 	int			error;
616 	int			done;
617 
618 	trace_xfs_attr_rmtval_remove(args);
619 
620 	/*
621 	 * Roll through the "value", invalidating the attribute value's blocks.
622 	 */
623 	lblkno = args->rmtblkno;
624 	blkcnt = args->rmtblkcnt;
625 	while (blkcnt > 0) {
626 		struct xfs_bmbt_irec	map;
627 		int			nmap;
628 
629 		/*
630 		 * Try to remember where we decided to put the value.
631 		 */
632 		nmap = 1;
633 		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
634 				       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
635 		if (error)
636 			return error;
637 		ASSERT(nmap == 1);
638 		error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
639 		if (error)
640 			return error;
641 
642 		lblkno += map.br_blockcount;
643 		blkcnt -= map.br_blockcount;
644 	}
645 
646 	/*
647 	 * Keep de-allocating extents until the remote-value region is gone.
648 	 */
649 	lblkno = args->rmtblkno;
650 	blkcnt = args->rmtblkcnt;
651 	done = 0;
652 	while (!done) {
653 		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
654 				    XFS_BMAPI_ATTRFORK, 1, &done);
655 		if (error)
656 			return error;
657 		error = xfs_defer_finish(&args->trans);
658 		if (error)
659 			return error;
660 
661 		/*
662 		 * Close out trans and start the next one in the chain.
663 		 */
664 		error = xfs_trans_roll_inode(&args->trans, args->dp);
665 		if (error)
666 			return error;
667 	}
668 	return 0;
669 }
670