File Index
Files and directories
Sign in
FILE

xfs_attr_remote.c

File preview with syntax highlighting.

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