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/*
47 * Each contiguous block has a header, so it is not just a simple attribute
48 * length to FSB conversion.
49 */
50int
51xfs_attr3_rmt_blocks(
52	struct xfs_mount *mp,
53	int		attrlen)
54{
55	if (xfs_has_crc(mp)) {
56		int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
57		return (attrlen + buflen - 1) / buflen;
58	}
59	return XFS_B_TO_FSB(mp, attrlen);
60}
61
62/*
63 * Checking of the remote attribute header is split into two parts. The verifier
64 * does CRC, location and bounds checking, the unpacking function checks the
65 * attribute parameters and owner.
66 */
67static xfs_failaddr_t
68xfs_attr3_rmt_hdr_ok(
69	void			*ptr,
70	xfs_ino_t		ino,
71	uint32_t		offset,
72	uint32_t		size,
73	xfs_daddr_t		bno)
74{
75	struct xfs_attr3_rmt_hdr *rmt = ptr;
76
77	if (bno != be64_to_cpu(rmt->rm_blkno))
78		return __this_address;
79	if (offset != be32_to_cpu(rmt->rm_offset))
80		return __this_address;
81	if (size != be32_to_cpu(rmt->rm_bytes))
82		return __this_address;
83	if (ino != be64_to_cpu(rmt->rm_owner))
84		return __this_address;
85
86	/* ok */
87	return NULL;
88}
89
90static xfs_failaddr_t
91xfs_attr3_rmt_verify(
92	struct xfs_mount	*mp,
93	struct xfs_buf		*bp,
94	void			*ptr,
95	int			fsbsize,
96	xfs_daddr_t		bno)
97{
98	struct xfs_attr3_rmt_hdr *rmt = ptr;
99
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
117static int
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_has_crc(mp))
131		return 0;
132
133	ptr = bp->b_addr;
134	bno = xfs_buf_daddr(bp);
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
160static void
161xfs_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
172static xfs_failaddr_t
173xfs_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
183static void
184xfs_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_has_crc(mp))
196		return;
197
198	ptr = bp->b_addr;
199	bno = xfs_buf_daddr(bp);
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
231const 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
239STATIC int
240xfs_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_has_crc(mp))
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 */
278STATIC int
279xfs_attr_rmtval_copyout(
280	struct xfs_mount	*mp,
281	struct xfs_buf		*bp,
282	struct xfs_inode	*dp,
283	int			*offset,
284	int			*valuelen,
285	uint8_t			**dst)
286{
287	char			*src = bp->b_addr;
288	xfs_ino_t		ino = dp->i_ino;
289	xfs_daddr_t		bno = xfs_buf_daddr(bp);
290	int			len = BBTOB(bp->b_length);
291	int			blksize = mp->m_attr_geo->blksize;
292
293	ASSERT(len >= blksize);
294
295	while (len > 0 && *valuelen > 0) {
296		int hdr_size = 0;
297		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
298
299		byte_cnt = min(*valuelen, byte_cnt);
300
301		if (xfs_has_crc(mp)) {
302			if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
303						  byte_cnt, bno)) {
304				xfs_alert(mp,
305"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
306					bno, *offset, byte_cnt, ino);
307				xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
308				return -EFSCORRUPTED;
309			}
310			hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
311		}
312
313		memcpy(*dst, src + hdr_size, byte_cnt);
314
315		/* roll buffer forwards */
316		len -= blksize;
317		src += blksize;
318		bno += BTOBB(blksize);
319
320		/* roll attribute data forwards */
321		*valuelen -= byte_cnt;
322		*dst += byte_cnt;
323		*offset += byte_cnt;
324	}
325	return 0;
326}
327
328STATIC void
329xfs_attr_rmtval_copyin(
330	struct xfs_mount *mp,
331	struct xfs_buf	*bp,
332	xfs_ino_t	ino,
333	int		*offset,
334	int		*valuelen,
335	uint8_t		**src)
336{
337	char		*dst = bp->b_addr;
338	xfs_daddr_t	bno = xfs_buf_daddr(bp);
339	int		len = BBTOB(bp->b_length);
340	int		blksize = mp->m_attr_geo->blksize;
341
342	ASSERT(len >= blksize);
343
344	while (len > 0 && *valuelen > 0) {
345		int hdr_size;
346		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
347
348		byte_cnt = min(*valuelen, byte_cnt);
349		hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
350						 byte_cnt, bno);
351
352		memcpy(dst + hdr_size, *src, byte_cnt);
353
354		/*
355		 * If this is the last block, zero the remainder of it.
356		 * Check that we are actually the last block, too.
357		 */
358		if (byte_cnt + hdr_size < blksize) {
359			ASSERT(*valuelen - byte_cnt == 0);
360			ASSERT(len == blksize);
361			memset(dst + hdr_size + byte_cnt, 0,
362					blksize - hdr_size - byte_cnt);
363		}
364
365		/* roll buffer forwards */
366		len -= blksize;
367		dst += blksize;
368		bno += BTOBB(blksize);
369
370		/* roll attribute data forwards */
371		*valuelen -= byte_cnt;
372		*src += byte_cnt;
373		*offset += byte_cnt;
374	}
375}
376
377/*
378 * Read the value associated with an attribute from the out-of-line buffer
379 * that we stored it in.
380 *
381 * Returns 0 on successful retrieval, otherwise an error.
382 */
383int
384xfs_attr_rmtval_get(
385	struct xfs_da_args	*args)
386{
387	struct xfs_bmbt_irec	map[ATTR_RMTVALUE_MAPSIZE];
388	struct xfs_mount	*mp = args->dp->i_mount;
389	struct xfs_buf		*bp;
390	xfs_dablk_t		lblkno = args->rmtblkno;
391	uint8_t			*dst = args->value;
392	int			valuelen;
393	int			nmap;
394	int			error;
395	int			blkcnt = args->rmtblkcnt;
396	int			i;
397	int			offset = 0;
398
399	trace_xfs_attr_rmtval_get(args);
400
401	ASSERT(args->valuelen != 0);
402	ASSERT(args->rmtvaluelen == args->valuelen);
403
404	valuelen = args->rmtvaluelen;
405	while (valuelen > 0) {
406		nmap = ATTR_RMTVALUE_MAPSIZE;
407		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
408				       blkcnt, map, &nmap,
409				       XFS_BMAPI_ATTRFORK);
410		if (error)
411			return error;
412		ASSERT(nmap >= 1);
413
414		for (i = 0; (i < nmap) && (valuelen > 0); i++) {
415			xfs_daddr_t	dblkno;
416			int		dblkcnt;
417
418			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
419			       (map[i].br_startblock != HOLESTARTBLOCK));
420			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
421			dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
422			error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
423					0, &bp, &xfs_attr3_rmt_buf_ops);
424			if (xfs_metadata_is_sick(error))
425				xfs_dirattr_mark_sick(args->dp, XFS_ATTR_FORK);
426			if (error)
427				return error;
428
429			error = xfs_attr_rmtval_copyout(mp, bp, args->dp,
430							&offset, &valuelen,
431							&dst);
432			xfs_buf_relse(bp);
433			if (error)
434				return error;
435
436			/* roll attribute extent map forwards */
437			lblkno += map[i].br_blockcount;
438			blkcnt -= map[i].br_blockcount;
439		}
440	}
441	ASSERT(valuelen == 0);
442	return 0;
443}
444
445/*
446 * Find a "hole" in the attribute address space large enough for us to drop the
447 * new attributes value into
448 */
449int
450xfs_attr_rmt_find_hole(
451	struct xfs_da_args	*args)
452{
453	struct xfs_inode	*dp = args->dp;
454	struct xfs_mount	*mp = dp->i_mount;
455	int			error;
456	int			blkcnt;
457	xfs_fileoff_t		lfileoff = 0;
458
459	/*
460	 * Because CRC enable attributes have headers, we can't just do a
461	 * straight byte to FSB conversion and have to take the header space
462	 * into account.
463	 */
464	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
465	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
466						   XFS_ATTR_FORK);
467	if (error)
468		return error;
469
470	args->rmtblkno = (xfs_dablk_t)lfileoff;
471	args->rmtblkcnt = blkcnt;
472
473	return 0;
474}
475
476int
477xfs_attr_rmtval_set_value(
478	struct xfs_da_args	*args)
479{
480	struct xfs_inode	*dp = args->dp;
481	struct xfs_mount	*mp = dp->i_mount;
482	struct xfs_bmbt_irec	map;
483	xfs_dablk_t		lblkno;
484	uint8_t			*src = args->value;
485	int			blkcnt;
486	int			valuelen;
487	int			nmap;
488	int			error;
489	int			offset = 0;
490
491	/*
492	 * Roll through the "value", copying the attribute value to the
493	 * already-allocated blocks.  Blocks are written synchronously
494	 * so that we can know they are all on disk before we turn off
495	 * the INCOMPLETE flag.
496	 */
497	lblkno = args->rmtblkno;
498	blkcnt = args->rmtblkcnt;
499	valuelen = args->rmtvaluelen;
500	while (valuelen > 0) {
501		struct xfs_buf	*bp;
502		xfs_daddr_t	dblkno;
503		int		dblkcnt;
504
505		ASSERT(blkcnt > 0);
506
507		nmap = 1;
508		error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
509				       blkcnt, &map, &nmap,
510				       XFS_BMAPI_ATTRFORK);
511		if (error)
512			return error;
513		ASSERT(nmap == 1);
514		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
515		       (map.br_startblock != HOLESTARTBLOCK));
516
517		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
518		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
519
520		error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
521		if (error)
522			return error;
523		bp->b_ops = &xfs_attr3_rmt_buf_ops;
524
525		xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
526				       &valuelen, &src);
527
528		error = xfs_bwrite(bp);	/* GROT: NOTE: synchronous write */
529		xfs_buf_relse(bp);
530		if (error)
531			return error;
532
533
534		/* roll attribute extent map forwards */
535		lblkno += map.br_blockcount;
536		blkcnt -= map.br_blockcount;
537	}
538	ASSERT(valuelen == 0);
539	return 0;
540}
541
542/* Mark stale any incore buffers for the remote value. */
543int
544xfs_attr_rmtval_stale(
545	struct xfs_inode	*ip,
546	struct xfs_bmbt_irec	*map,
547	xfs_buf_flags_t		incore_flags)
548{
549	struct xfs_mount	*mp = ip->i_mount;
550	struct xfs_buf		*bp;
551	int			error;
552
553	xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
554
555	if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
556	    XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK)) {
557		xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
558		return -EFSCORRUPTED;
559	}
560
561	error = xfs_buf_incore(mp->m_ddev_targp,
562			XFS_FSB_TO_DADDR(mp, map->br_startblock),
563			XFS_FSB_TO_BB(mp, map->br_blockcount),
564			incore_flags, &bp);
565	if (error) {
566		if (error == -ENOENT)
567			return 0;
568		return error;
569	}
570
571	xfs_buf_stale(bp);
572	xfs_buf_relse(bp);
573	return 0;
574}
575
576/*
577 * Find a hole for the attr and store it in the delayed attr context.  This
578 * initializes the context to roll through allocating an attr extent for a
579 * delayed attr operation
580 */
581int
582xfs_attr_rmtval_find_space(
583	struct xfs_attr_intent		*attr)
584{
585	struct xfs_da_args		*args = attr->xattri_da_args;
586	struct xfs_bmbt_irec		*map = &attr->xattri_map;
587	int				error;
588
589	attr->xattri_lblkno = 0;
590	attr->xattri_blkcnt = 0;
591	args->rmtblkcnt = 0;
592	args->rmtblkno = 0;
593	memset(map, 0, sizeof(struct xfs_bmbt_irec));
594
595	error = xfs_attr_rmt_find_hole(args);
596	if (error)
597		return error;
598
599	attr->xattri_blkcnt = args->rmtblkcnt;
600	attr->xattri_lblkno = args->rmtblkno;
601
602	return 0;
603}
604
605/*
606 * Write one block of the value associated with an attribute into the
607 * out-of-line buffer that we have defined for it. This is similar to a subset
608 * of xfs_attr_rmtval_set, but records the current block to the delayed attr
609 * context, and leaves transaction handling to the caller.
610 */
611int
612xfs_attr_rmtval_set_blk(
613	struct xfs_attr_intent		*attr)
614{
615	struct xfs_da_args		*args = attr->xattri_da_args;
616	struct xfs_inode		*dp = args->dp;
617	struct xfs_bmbt_irec		*map = &attr->xattri_map;
618	int nmap;
619	int error;
620
621	nmap = 1;
622	error = xfs_bmapi_write(args->trans, dp,
623			(xfs_fileoff_t)attr->xattri_lblkno,
624			attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,
625			map, &nmap);
626	if (error)
627		return error;
628
629	ASSERT(nmap == 1);
630	ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
631	       (map->br_startblock != HOLESTARTBLOCK));
632
633	/* roll attribute extent map forwards */
634	attr->xattri_lblkno += map->br_blockcount;
635	attr->xattri_blkcnt -= map->br_blockcount;
636
637	return 0;
638}
639
640/*
641 * Remove the value associated with an attribute by deleting the
642 * out-of-line buffer that it is stored on.
643 */
644int
645xfs_attr_rmtval_invalidate(
646	struct xfs_da_args	*args)
647{
648	xfs_dablk_t		lblkno;
649	int			blkcnt;
650	int			error;
651
652	/*
653	 * Roll through the "value", invalidating the attribute value's blocks.
654	 */
655	lblkno = args->rmtblkno;
656	blkcnt = args->rmtblkcnt;
657	while (blkcnt > 0) {
658		struct xfs_bmbt_irec	map;
659		int			nmap;
660
661		/*
662		 * Try to remember where we decided to put the value.
663		 */
664		nmap = 1;
665		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
666				       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
667		if (error)
668			return error;
669		if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1)) {
670			xfs_bmap_mark_sick(args->dp, XFS_ATTR_FORK);
671			return -EFSCORRUPTED;
672		}
673		error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
674		if (error)
675			return error;
676
677		lblkno += map.br_blockcount;
678		blkcnt -= map.br_blockcount;
679	}
680	return 0;
681}
682
683/*
684 * Remove the value associated with an attribute by deleting the out-of-line
685 * buffer that it is stored on. Returns -EAGAIN for the caller to refresh the
686 * transaction and re-call the function.  Callers should keep calling this
687 * routine until it returns something other than -EAGAIN.
688 */
689int
690xfs_attr_rmtval_remove(
691	struct xfs_attr_intent		*attr)
692{
693	struct xfs_da_args		*args = attr->xattri_da_args;
694	int				error, done;
695
696	/*
697	 * Unmap value blocks for this attr.
698	 */
699	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
700			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
701	if (error)
702		return error;
703
704	/*
705	 * We don't need an explicit state here to pick up where we left off. We
706	 * can figure it out using the !done return code. The actual value of
707	 * attr->xattri_dela_state may be some value reminiscent of the calling
708	 * function, but it's value is irrelevant with in the context of this
709	 * function. Once we are done here, the next state is set as needed by
710	 * the parent
711	 */
712	if (!done) {
713		trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,
714						    args->dp);
715		return -EAGAIN;
716	}
717
718	args->rmtblkno = 0;
719	args->rmtblkcnt = 0;
720	return 0;
721}
722