18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc.
48c2ecf20Sopenharmony_ci * Copyright (c) 2013 Red Hat, Inc.
58c2ecf20Sopenharmony_ci * All Rights Reserved.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include "xfs.h"
88c2ecf20Sopenharmony_ci#include "xfs_fs.h"
98c2ecf20Sopenharmony_ci#include "xfs_shared.h"
108c2ecf20Sopenharmony_ci#include "xfs_format.h"
118c2ecf20Sopenharmony_ci#include "xfs_log_format.h"
128c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
138c2ecf20Sopenharmony_ci#include "xfs_bit.h"
148c2ecf20Sopenharmony_ci#include "xfs_mount.h"
158c2ecf20Sopenharmony_ci#include "xfs_defer.h"
168c2ecf20Sopenharmony_ci#include "xfs_da_format.h"
178c2ecf20Sopenharmony_ci#include "xfs_da_btree.h"
188c2ecf20Sopenharmony_ci#include "xfs_inode.h"
198c2ecf20Sopenharmony_ci#include "xfs_trans.h"
208c2ecf20Sopenharmony_ci#include "xfs_bmap.h"
218c2ecf20Sopenharmony_ci#include "xfs_attr.h"
228c2ecf20Sopenharmony_ci#include "xfs_attr_remote.h"
238c2ecf20Sopenharmony_ci#include "xfs_trace.h"
248c2ecf20Sopenharmony_ci#include "xfs_error.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/*
298c2ecf20Sopenharmony_ci * Remote Attribute Values
308c2ecf20Sopenharmony_ci * =======================
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * Remote extended attribute values are conceptually simple -- they're written
338c2ecf20Sopenharmony_ci * to data blocks mapped by an inode's attribute fork, and they have an upper
348c2ecf20Sopenharmony_ci * size limit of 64k.  Setting a value does not involve the XFS log.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * However, on a v5 filesystem, maximally sized remote attr values require one
378c2ecf20Sopenharmony_ci * block more than 64k worth of space to hold both the remote attribute value
388c2ecf20Sopenharmony_ci * header (64 bytes).  On a 4k block filesystem this results in a 68k buffer;
398c2ecf20Sopenharmony_ci * on a 64k block filesystem, this would be a 128k buffer.  Note that the log
408c2ecf20Sopenharmony_ci * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
418c2ecf20Sopenharmony_ci * Therefore, we /must/ ensure that remote attribute value buffers never touch
428c2ecf20Sopenharmony_ci * the logging system and therefore never have a log item.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * Each contiguous block has a header, so it is not just a simple attribute
478c2ecf20Sopenharmony_ci * length to FSB conversion.
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ciint
508c2ecf20Sopenharmony_cixfs_attr3_rmt_blocks(
518c2ecf20Sopenharmony_ci	struct xfs_mount *mp,
528c2ecf20Sopenharmony_ci	int		attrlen)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	if (xfs_sb_version_hascrc(&mp->m_sb)) {
558c2ecf20Sopenharmony_ci		int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
568c2ecf20Sopenharmony_ci		return (attrlen + buflen - 1) / buflen;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	return XFS_B_TO_FSB(mp, attrlen);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * Checking of the remote attribute header is split into two parts. The verifier
638c2ecf20Sopenharmony_ci * does CRC, location and bounds checking, the unpacking function checks the
648c2ecf20Sopenharmony_ci * attribute parameters and owner.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_cistatic xfs_failaddr_t
678c2ecf20Sopenharmony_cixfs_attr3_rmt_hdr_ok(
688c2ecf20Sopenharmony_ci	void			*ptr,
698c2ecf20Sopenharmony_ci	xfs_ino_t		ino,
708c2ecf20Sopenharmony_ci	uint32_t		offset,
718c2ecf20Sopenharmony_ci	uint32_t		size,
728c2ecf20Sopenharmony_ci	xfs_daddr_t		bno)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct xfs_attr3_rmt_hdr *rmt = ptr;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (bno != be64_to_cpu(rmt->rm_blkno))
778c2ecf20Sopenharmony_ci		return __this_address;
788c2ecf20Sopenharmony_ci	if (offset != be32_to_cpu(rmt->rm_offset))
798c2ecf20Sopenharmony_ci		return __this_address;
808c2ecf20Sopenharmony_ci	if (size != be32_to_cpu(rmt->rm_bytes))
818c2ecf20Sopenharmony_ci		return __this_address;
828c2ecf20Sopenharmony_ci	if (ino != be64_to_cpu(rmt->rm_owner))
838c2ecf20Sopenharmony_ci		return __this_address;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* ok */
868c2ecf20Sopenharmony_ci	return NULL;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic xfs_failaddr_t
908c2ecf20Sopenharmony_cixfs_attr3_rmt_verify(
918c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
928c2ecf20Sopenharmony_ci	struct xfs_buf		*bp,
938c2ecf20Sopenharmony_ci	void			*ptr,
948c2ecf20Sopenharmony_ci	int			fsbsize,
958c2ecf20Sopenharmony_ci	xfs_daddr_t		bno)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct xfs_attr3_rmt_hdr *rmt = ptr;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (!xfs_verify_magic(bp, rmt->rm_magic))
1008c2ecf20Sopenharmony_ci		return __this_address;
1018c2ecf20Sopenharmony_ci	if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
1028c2ecf20Sopenharmony_ci		return __this_address;
1038c2ecf20Sopenharmony_ci	if (be64_to_cpu(rmt->rm_blkno) != bno)
1048c2ecf20Sopenharmony_ci		return __this_address;
1058c2ecf20Sopenharmony_ci	if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
1068c2ecf20Sopenharmony_ci		return __this_address;
1078c2ecf20Sopenharmony_ci	if (be32_to_cpu(rmt->rm_offset) +
1088c2ecf20Sopenharmony_ci				be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
1098c2ecf20Sopenharmony_ci		return __this_address;
1108c2ecf20Sopenharmony_ci	if (rmt->rm_owner == 0)
1118c2ecf20Sopenharmony_ci		return __this_address;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return NULL;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int
1178c2ecf20Sopenharmony_ci__xfs_attr3_rmt_read_verify(
1188c2ecf20Sopenharmony_ci	struct xfs_buf	*bp,
1198c2ecf20Sopenharmony_ci	bool		check_crc,
1208c2ecf20Sopenharmony_ci	xfs_failaddr_t	*failaddr)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct xfs_mount *mp = bp->b_mount;
1238c2ecf20Sopenharmony_ci	char		*ptr;
1248c2ecf20Sopenharmony_ci	int		len;
1258c2ecf20Sopenharmony_ci	xfs_daddr_t	bno;
1268c2ecf20Sopenharmony_ci	int		blksize = mp->m_attr_geo->blksize;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* no verification of non-crc buffers */
1298c2ecf20Sopenharmony_ci	if (!xfs_sb_version_hascrc(&mp->m_sb))
1308c2ecf20Sopenharmony_ci		return 0;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ptr = bp->b_addr;
1338c2ecf20Sopenharmony_ci	bno = bp->b_bn;
1348c2ecf20Sopenharmony_ci	len = BBTOB(bp->b_length);
1358c2ecf20Sopenharmony_ci	ASSERT(len >= blksize);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	while (len > 0) {
1388c2ecf20Sopenharmony_ci		if (check_crc &&
1398c2ecf20Sopenharmony_ci		    !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
1408c2ecf20Sopenharmony_ci			*failaddr = __this_address;
1418c2ecf20Sopenharmony_ci			return -EFSBADCRC;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci		*failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
1448c2ecf20Sopenharmony_ci		if (*failaddr)
1458c2ecf20Sopenharmony_ci			return -EFSCORRUPTED;
1468c2ecf20Sopenharmony_ci		len -= blksize;
1478c2ecf20Sopenharmony_ci		ptr += blksize;
1488c2ecf20Sopenharmony_ci		bno += BTOBB(blksize);
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (len != 0) {
1528c2ecf20Sopenharmony_ci		*failaddr = __this_address;
1538c2ecf20Sopenharmony_ci		return -EFSCORRUPTED;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return 0;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void
1608c2ecf20Sopenharmony_cixfs_attr3_rmt_read_verify(
1618c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
1648c2ecf20Sopenharmony_ci	int		error;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
1678c2ecf20Sopenharmony_ci	if (error)
1688c2ecf20Sopenharmony_ci		xfs_verifier_error(bp, error, fa);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic xfs_failaddr_t
1728c2ecf20Sopenharmony_cixfs_attr3_rmt_verify_struct(
1738c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
1768c2ecf20Sopenharmony_ci	int		error;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
1798c2ecf20Sopenharmony_ci	return error ? fa : NULL;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void
1838c2ecf20Sopenharmony_cixfs_attr3_rmt_write_verify(
1848c2ecf20Sopenharmony_ci	struct xfs_buf	*bp)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct xfs_mount *mp = bp->b_mount;
1878c2ecf20Sopenharmony_ci	xfs_failaddr_t	fa;
1888c2ecf20Sopenharmony_ci	int		blksize = mp->m_attr_geo->blksize;
1898c2ecf20Sopenharmony_ci	char		*ptr;
1908c2ecf20Sopenharmony_ci	int		len;
1918c2ecf20Sopenharmony_ci	xfs_daddr_t	bno;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* no verification of non-crc buffers */
1948c2ecf20Sopenharmony_ci	if (!xfs_sb_version_hascrc(&mp->m_sb))
1958c2ecf20Sopenharmony_ci		return;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	ptr = bp->b_addr;
1988c2ecf20Sopenharmony_ci	bno = bp->b_bn;
1998c2ecf20Sopenharmony_ci	len = BBTOB(bp->b_length);
2008c2ecf20Sopenharmony_ci	ASSERT(len >= blksize);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	while (len > 0) {
2038c2ecf20Sopenharmony_ci		struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
2068c2ecf20Sopenharmony_ci		if (fa) {
2078c2ecf20Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, fa);
2088c2ecf20Sopenharmony_ci			return;
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		/*
2128c2ecf20Sopenharmony_ci		 * Ensure we aren't writing bogus LSNs to disk. See
2138c2ecf20Sopenharmony_ci		 * xfs_attr3_rmt_hdr_set() for the explanation.
2148c2ecf20Sopenharmony_ci		 */
2158c2ecf20Sopenharmony_ci		if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
2168c2ecf20Sopenharmony_ci			xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
2178c2ecf20Sopenharmony_ci			return;
2188c2ecf20Sopenharmony_ci		}
2198c2ecf20Sopenharmony_ci		xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		len -= blksize;
2228c2ecf20Sopenharmony_ci		ptr += blksize;
2238c2ecf20Sopenharmony_ci		bno += BTOBB(blksize);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (len != 0)
2278c2ecf20Sopenharmony_ci		xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
2318c2ecf20Sopenharmony_ci	.name = "xfs_attr3_rmt",
2328c2ecf20Sopenharmony_ci	.magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
2338c2ecf20Sopenharmony_ci	.verify_read = xfs_attr3_rmt_read_verify,
2348c2ecf20Sopenharmony_ci	.verify_write = xfs_attr3_rmt_write_verify,
2358c2ecf20Sopenharmony_ci	.verify_struct = xfs_attr3_rmt_verify_struct,
2368c2ecf20Sopenharmony_ci};
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ciSTATIC int
2398c2ecf20Sopenharmony_cixfs_attr3_rmt_hdr_set(
2408c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
2418c2ecf20Sopenharmony_ci	void			*ptr,
2428c2ecf20Sopenharmony_ci	xfs_ino_t		ino,
2438c2ecf20Sopenharmony_ci	uint32_t		offset,
2448c2ecf20Sopenharmony_ci	uint32_t		size,
2458c2ecf20Sopenharmony_ci	xfs_daddr_t		bno)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct xfs_attr3_rmt_hdr *rmt = ptr;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (!xfs_sb_version_hascrc(&mp->m_sb))
2508c2ecf20Sopenharmony_ci		return 0;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
2538c2ecf20Sopenharmony_ci	rmt->rm_offset = cpu_to_be32(offset);
2548c2ecf20Sopenharmony_ci	rmt->rm_bytes = cpu_to_be32(size);
2558c2ecf20Sopenharmony_ci	uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
2568c2ecf20Sopenharmony_ci	rmt->rm_owner = cpu_to_be64(ino);
2578c2ecf20Sopenharmony_ci	rmt->rm_blkno = cpu_to_be64(bno);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/*
2608c2ecf20Sopenharmony_ci	 * Remote attribute blocks are written synchronously, so we don't
2618c2ecf20Sopenharmony_ci	 * have an LSN that we can stamp in them that makes any sense to log
2628c2ecf20Sopenharmony_ci	 * recovery. To ensure that log recovery handles overwrites of these
2638c2ecf20Sopenharmony_ci	 * blocks sanely (i.e. once they've been freed and reallocated as some
2648c2ecf20Sopenharmony_ci	 * other type of metadata) we need to ensure that the LSN has a value
2658c2ecf20Sopenharmony_ci	 * that tells log recovery to ignore the LSN and overwrite the buffer
2668c2ecf20Sopenharmony_ci	 * with whatever is in it's log. To do this, we use the magic
2678c2ecf20Sopenharmony_ci	 * NULLCOMMITLSN to indicate that the LSN is invalid.
2688c2ecf20Sopenharmony_ci	 */
2698c2ecf20Sopenharmony_ci	rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return sizeof(struct xfs_attr3_rmt_hdr);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/*
2758c2ecf20Sopenharmony_ci * Helper functions to copy attribute data in and out of the one disk extents
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_ciSTATIC int
2788c2ecf20Sopenharmony_cixfs_attr_rmtval_copyout(
2798c2ecf20Sopenharmony_ci	struct xfs_mount *mp,
2808c2ecf20Sopenharmony_ci	struct xfs_buf	*bp,
2818c2ecf20Sopenharmony_ci	xfs_ino_t	ino,
2828c2ecf20Sopenharmony_ci	int		*offset,
2838c2ecf20Sopenharmony_ci	int		*valuelen,
2848c2ecf20Sopenharmony_ci	uint8_t		**dst)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	char		*src = bp->b_addr;
2878c2ecf20Sopenharmony_ci	xfs_daddr_t	bno = bp->b_bn;
2888c2ecf20Sopenharmony_ci	int		len = BBTOB(bp->b_length);
2898c2ecf20Sopenharmony_ci	int		blksize = mp->m_attr_geo->blksize;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	ASSERT(len >= blksize);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	while (len > 0 && *valuelen > 0) {
2948c2ecf20Sopenharmony_ci		int hdr_size = 0;
2958c2ecf20Sopenharmony_ci		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		byte_cnt = min(*valuelen, byte_cnt);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		if (xfs_sb_version_hascrc(&mp->m_sb)) {
3008c2ecf20Sopenharmony_ci			if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
3018c2ecf20Sopenharmony_ci						  byte_cnt, bno)) {
3028c2ecf20Sopenharmony_ci				xfs_alert(mp,
3038c2ecf20Sopenharmony_ci"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
3048c2ecf20Sopenharmony_ci					bno, *offset, byte_cnt, ino);
3058c2ecf20Sopenharmony_ci				return -EFSCORRUPTED;
3068c2ecf20Sopenharmony_ci			}
3078c2ecf20Sopenharmony_ci			hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
3088c2ecf20Sopenharmony_ci		}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		memcpy(*dst, src + hdr_size, byte_cnt);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		/* roll buffer forwards */
3138c2ecf20Sopenharmony_ci		len -= blksize;
3148c2ecf20Sopenharmony_ci		src += blksize;
3158c2ecf20Sopenharmony_ci		bno += BTOBB(blksize);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		/* roll attribute data forwards */
3188c2ecf20Sopenharmony_ci		*valuelen -= byte_cnt;
3198c2ecf20Sopenharmony_ci		*dst += byte_cnt;
3208c2ecf20Sopenharmony_ci		*offset += byte_cnt;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	return 0;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ciSTATIC void
3268c2ecf20Sopenharmony_cixfs_attr_rmtval_copyin(
3278c2ecf20Sopenharmony_ci	struct xfs_mount *mp,
3288c2ecf20Sopenharmony_ci	struct xfs_buf	*bp,
3298c2ecf20Sopenharmony_ci	xfs_ino_t	ino,
3308c2ecf20Sopenharmony_ci	int		*offset,
3318c2ecf20Sopenharmony_ci	int		*valuelen,
3328c2ecf20Sopenharmony_ci	uint8_t		**src)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	char		*dst = bp->b_addr;
3358c2ecf20Sopenharmony_ci	xfs_daddr_t	bno = bp->b_bn;
3368c2ecf20Sopenharmony_ci	int		len = BBTOB(bp->b_length);
3378c2ecf20Sopenharmony_ci	int		blksize = mp->m_attr_geo->blksize;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	ASSERT(len >= blksize);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	while (len > 0 && *valuelen > 0) {
3428c2ecf20Sopenharmony_ci		int hdr_size;
3438c2ecf20Sopenharmony_ci		int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		byte_cnt = min(*valuelen, byte_cnt);
3468c2ecf20Sopenharmony_ci		hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
3478c2ecf20Sopenharmony_ci						 byte_cnt, bno);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		memcpy(dst + hdr_size, *src, byte_cnt);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		/*
3528c2ecf20Sopenharmony_ci		 * If this is the last block, zero the remainder of it.
3538c2ecf20Sopenharmony_ci		 * Check that we are actually the last block, too.
3548c2ecf20Sopenharmony_ci		 */
3558c2ecf20Sopenharmony_ci		if (byte_cnt + hdr_size < blksize) {
3568c2ecf20Sopenharmony_ci			ASSERT(*valuelen - byte_cnt == 0);
3578c2ecf20Sopenharmony_ci			ASSERT(len == blksize);
3588c2ecf20Sopenharmony_ci			memset(dst + hdr_size + byte_cnt, 0,
3598c2ecf20Sopenharmony_ci					blksize - hdr_size - byte_cnt);
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		/* roll buffer forwards */
3638c2ecf20Sopenharmony_ci		len -= blksize;
3648c2ecf20Sopenharmony_ci		dst += blksize;
3658c2ecf20Sopenharmony_ci		bno += BTOBB(blksize);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		/* roll attribute data forwards */
3688c2ecf20Sopenharmony_ci		*valuelen -= byte_cnt;
3698c2ecf20Sopenharmony_ci		*src += byte_cnt;
3708c2ecf20Sopenharmony_ci		*offset += byte_cnt;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/*
3758c2ecf20Sopenharmony_ci * Read the value associated with an attribute from the out-of-line buffer
3768c2ecf20Sopenharmony_ci * that we stored it in.
3778c2ecf20Sopenharmony_ci *
3788c2ecf20Sopenharmony_ci * Returns 0 on successful retrieval, otherwise an error.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_ciint
3818c2ecf20Sopenharmony_cixfs_attr_rmtval_get(
3828c2ecf20Sopenharmony_ci	struct xfs_da_args	*args)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	map[ATTR_RMTVALUE_MAPSIZE];
3858c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = args->dp->i_mount;
3868c2ecf20Sopenharmony_ci	struct xfs_buf		*bp;
3878c2ecf20Sopenharmony_ci	xfs_dablk_t		lblkno = args->rmtblkno;
3888c2ecf20Sopenharmony_ci	uint8_t			*dst = args->value;
3898c2ecf20Sopenharmony_ci	int			valuelen;
3908c2ecf20Sopenharmony_ci	int			nmap;
3918c2ecf20Sopenharmony_ci	int			error;
3928c2ecf20Sopenharmony_ci	int			blkcnt = args->rmtblkcnt;
3938c2ecf20Sopenharmony_ci	int			i;
3948c2ecf20Sopenharmony_ci	int			offset = 0;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	trace_xfs_attr_rmtval_get(args);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	ASSERT(args->valuelen != 0);
3998c2ecf20Sopenharmony_ci	ASSERT(args->rmtvaluelen == args->valuelen);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	valuelen = args->rmtvaluelen;
4028c2ecf20Sopenharmony_ci	while (valuelen > 0) {
4038c2ecf20Sopenharmony_ci		nmap = ATTR_RMTVALUE_MAPSIZE;
4048c2ecf20Sopenharmony_ci		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
4058c2ecf20Sopenharmony_ci				       blkcnt, map, &nmap,
4068c2ecf20Sopenharmony_ci				       XFS_BMAPI_ATTRFORK);
4078c2ecf20Sopenharmony_ci		if (error)
4088c2ecf20Sopenharmony_ci			return error;
4098c2ecf20Sopenharmony_ci		ASSERT(nmap >= 1);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci		for (i = 0; (i < nmap) && (valuelen > 0); i++) {
4128c2ecf20Sopenharmony_ci			xfs_daddr_t	dblkno;
4138c2ecf20Sopenharmony_ci			int		dblkcnt;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci			ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
4168c2ecf20Sopenharmony_ci			       (map[i].br_startblock != HOLESTARTBLOCK));
4178c2ecf20Sopenharmony_ci			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
4188c2ecf20Sopenharmony_ci			dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
4198c2ecf20Sopenharmony_ci			error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
4208c2ecf20Sopenharmony_ci					0, &bp, &xfs_attr3_rmt_buf_ops);
4218c2ecf20Sopenharmony_ci			if (error)
4228c2ecf20Sopenharmony_ci				return error;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci			error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
4258c2ecf20Sopenharmony_ci							&offset, &valuelen,
4268c2ecf20Sopenharmony_ci							&dst);
4278c2ecf20Sopenharmony_ci			xfs_buf_relse(bp);
4288c2ecf20Sopenharmony_ci			if (error)
4298c2ecf20Sopenharmony_ci				return error;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci			/* roll attribute extent map forwards */
4328c2ecf20Sopenharmony_ci			lblkno += map[i].br_blockcount;
4338c2ecf20Sopenharmony_ci			blkcnt -= map[i].br_blockcount;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci	ASSERT(valuelen == 0);
4378c2ecf20Sopenharmony_ci	return 0;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/*
4418c2ecf20Sopenharmony_ci * Find a "hole" in the attribute address space large enough for us to drop the
4428c2ecf20Sopenharmony_ci * new attribute's value into
4438c2ecf20Sopenharmony_ci */
4448c2ecf20Sopenharmony_ciSTATIC int
4458c2ecf20Sopenharmony_cixfs_attr_rmt_find_hole(
4468c2ecf20Sopenharmony_ci	struct xfs_da_args	*args)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
4498c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
4508c2ecf20Sopenharmony_ci	int			error;
4518c2ecf20Sopenharmony_ci	int			blkcnt;
4528c2ecf20Sopenharmony_ci	xfs_fileoff_t		lfileoff = 0;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/*
4558c2ecf20Sopenharmony_ci	 * Because CRC enable attributes have headers, we can't just do a
4568c2ecf20Sopenharmony_ci	 * straight byte to FSB conversion and have to take the header space
4578c2ecf20Sopenharmony_ci	 * into account.
4588c2ecf20Sopenharmony_ci	 */
4598c2ecf20Sopenharmony_ci	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
4608c2ecf20Sopenharmony_ci	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
4618c2ecf20Sopenharmony_ci						   XFS_ATTR_FORK);
4628c2ecf20Sopenharmony_ci	if (error)
4638c2ecf20Sopenharmony_ci		return error;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	args->rmtblkno = (xfs_dablk_t)lfileoff;
4668c2ecf20Sopenharmony_ci	args->rmtblkcnt = blkcnt;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ciSTATIC int
4728c2ecf20Sopenharmony_cixfs_attr_rmtval_set_value(
4738c2ecf20Sopenharmony_ci	struct xfs_da_args	*args)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
4768c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = dp->i_mount;
4778c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	map;
4788c2ecf20Sopenharmony_ci	xfs_dablk_t		lblkno;
4798c2ecf20Sopenharmony_ci	uint8_t			*src = args->value;
4808c2ecf20Sopenharmony_ci	int			blkcnt;
4818c2ecf20Sopenharmony_ci	int			valuelen;
4828c2ecf20Sopenharmony_ci	int			nmap;
4838c2ecf20Sopenharmony_ci	int			error;
4848c2ecf20Sopenharmony_ci	int			offset = 0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/*
4878c2ecf20Sopenharmony_ci	 * Roll through the "value", copying the attribute value to the
4888c2ecf20Sopenharmony_ci	 * already-allocated blocks.  Blocks are written synchronously
4898c2ecf20Sopenharmony_ci	 * so that we can know they are all on disk before we turn off
4908c2ecf20Sopenharmony_ci	 * the INCOMPLETE flag.
4918c2ecf20Sopenharmony_ci	 */
4928c2ecf20Sopenharmony_ci	lblkno = args->rmtblkno;
4938c2ecf20Sopenharmony_ci	blkcnt = args->rmtblkcnt;
4948c2ecf20Sopenharmony_ci	valuelen = args->rmtvaluelen;
4958c2ecf20Sopenharmony_ci	while (valuelen > 0) {
4968c2ecf20Sopenharmony_ci		struct xfs_buf	*bp;
4978c2ecf20Sopenharmony_ci		xfs_daddr_t	dblkno;
4988c2ecf20Sopenharmony_ci		int		dblkcnt;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci		ASSERT(blkcnt > 0);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		nmap = 1;
5038c2ecf20Sopenharmony_ci		error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
5048c2ecf20Sopenharmony_ci				       blkcnt, &map, &nmap,
5058c2ecf20Sopenharmony_ci				       XFS_BMAPI_ATTRFORK);
5068c2ecf20Sopenharmony_ci		if (error)
5078c2ecf20Sopenharmony_ci			return error;
5088c2ecf20Sopenharmony_ci		ASSERT(nmap == 1);
5098c2ecf20Sopenharmony_ci		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
5108c2ecf20Sopenharmony_ci		       (map.br_startblock != HOLESTARTBLOCK));
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
5138c2ecf20Sopenharmony_ci		dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
5168c2ecf20Sopenharmony_ci		if (error)
5178c2ecf20Sopenharmony_ci			return error;
5188c2ecf20Sopenharmony_ci		bp->b_ops = &xfs_attr3_rmt_buf_ops;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
5218c2ecf20Sopenharmony_ci				       &valuelen, &src);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		error = xfs_bwrite(bp);	/* GROT: NOTE: synchronous write */
5248c2ecf20Sopenharmony_ci		xfs_buf_relse(bp);
5258c2ecf20Sopenharmony_ci		if (error)
5268c2ecf20Sopenharmony_ci			return error;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		/* roll attribute extent map forwards */
5308c2ecf20Sopenharmony_ci		lblkno += map.br_blockcount;
5318c2ecf20Sopenharmony_ci		blkcnt -= map.br_blockcount;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci	ASSERT(valuelen == 0);
5348c2ecf20Sopenharmony_ci	return 0;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci/* Mark stale any incore buffers for the remote value. */
5388c2ecf20Sopenharmony_ciint
5398c2ecf20Sopenharmony_cixfs_attr_rmtval_stale(
5408c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
5418c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	*map,
5428c2ecf20Sopenharmony_ci	xfs_buf_flags_t		incore_flags)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct xfs_mount	*mp = ip->i_mount;
5458c2ecf20Sopenharmony_ci	struct xfs_buf		*bp;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
5508c2ecf20Sopenharmony_ci	    XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
5518c2ecf20Sopenharmony_ci		return -EFSCORRUPTED;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	bp = xfs_buf_incore(mp->m_ddev_targp,
5548c2ecf20Sopenharmony_ci			XFS_FSB_TO_DADDR(mp, map->br_startblock),
5558c2ecf20Sopenharmony_ci			XFS_FSB_TO_BB(mp, map->br_blockcount), incore_flags);
5568c2ecf20Sopenharmony_ci	if (bp) {
5578c2ecf20Sopenharmony_ci		xfs_buf_stale(bp);
5588c2ecf20Sopenharmony_ci		xfs_buf_relse(bp);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return 0;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci/*
5658c2ecf20Sopenharmony_ci * Write the value associated with an attribute into the out-of-line buffer
5668c2ecf20Sopenharmony_ci * that we have defined for it.
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_ciint
5698c2ecf20Sopenharmony_cixfs_attr_rmtval_set(
5708c2ecf20Sopenharmony_ci	struct xfs_da_args	*args)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	struct xfs_inode	*dp = args->dp;
5738c2ecf20Sopenharmony_ci	struct xfs_bmbt_irec	map;
5748c2ecf20Sopenharmony_ci	xfs_dablk_t		lblkno;
5758c2ecf20Sopenharmony_ci	int			blkcnt;
5768c2ecf20Sopenharmony_ci	int			nmap;
5778c2ecf20Sopenharmony_ci	int			error;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	trace_xfs_attr_rmtval_set(args);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	error = xfs_attr_rmt_find_hole(args);
5828c2ecf20Sopenharmony_ci	if (error)
5838c2ecf20Sopenharmony_ci		return error;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	blkcnt = args->rmtblkcnt;
5868c2ecf20Sopenharmony_ci	lblkno = (xfs_dablk_t)args->rmtblkno;
5878c2ecf20Sopenharmony_ci	/*
5888c2ecf20Sopenharmony_ci	 * Roll through the "value", allocating blocks on disk as required.
5898c2ecf20Sopenharmony_ci	 */
5908c2ecf20Sopenharmony_ci	while (blkcnt > 0) {
5918c2ecf20Sopenharmony_ci		/*
5928c2ecf20Sopenharmony_ci		 * Allocate a single extent, up to the size of the value.
5938c2ecf20Sopenharmony_ci		 *
5948c2ecf20Sopenharmony_ci		 * Note that we have to consider this a data allocation as we
5958c2ecf20Sopenharmony_ci		 * write the remote attribute without logging the contents.
5968c2ecf20Sopenharmony_ci		 * Hence we must ensure that we aren't using blocks that are on
5978c2ecf20Sopenharmony_ci		 * the busy list so that we don't overwrite blocks which have
5988c2ecf20Sopenharmony_ci		 * recently been freed but their transactions are not yet
5998c2ecf20Sopenharmony_ci		 * committed to disk. If we overwrite the contents of a busy
6008c2ecf20Sopenharmony_ci		 * extent and then crash then the block may not contain the
6018c2ecf20Sopenharmony_ci		 * correct metadata after log recovery occurs.
6028c2ecf20Sopenharmony_ci		 */
6038c2ecf20Sopenharmony_ci		nmap = 1;
6048c2ecf20Sopenharmony_ci		error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
6058c2ecf20Sopenharmony_ci				  blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
6068c2ecf20Sopenharmony_ci				  &nmap);
6078c2ecf20Sopenharmony_ci		if (error)
6088c2ecf20Sopenharmony_ci			return error;
6098c2ecf20Sopenharmony_ci		error = xfs_defer_finish(&args->trans);
6108c2ecf20Sopenharmony_ci		if (error)
6118c2ecf20Sopenharmony_ci			return error;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci		ASSERT(nmap == 1);
6148c2ecf20Sopenharmony_ci		ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
6158c2ecf20Sopenharmony_ci		       (map.br_startblock != HOLESTARTBLOCK));
6168c2ecf20Sopenharmony_ci		lblkno += map.br_blockcount;
6178c2ecf20Sopenharmony_ci		blkcnt -= map.br_blockcount;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		/*
6208c2ecf20Sopenharmony_ci		 * Start the next trans in the chain.
6218c2ecf20Sopenharmony_ci		 */
6228c2ecf20Sopenharmony_ci		error = xfs_trans_roll_inode(&args->trans, dp);
6238c2ecf20Sopenharmony_ci		if (error)
6248c2ecf20Sopenharmony_ci			return error;
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	return xfs_attr_rmtval_set_value(args);
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci/*
6318c2ecf20Sopenharmony_ci * Remove the value associated with an attribute by deleting the
6328c2ecf20Sopenharmony_ci * out-of-line buffer that it is stored on.
6338c2ecf20Sopenharmony_ci */
6348c2ecf20Sopenharmony_ciint
6358c2ecf20Sopenharmony_cixfs_attr_rmtval_invalidate(
6368c2ecf20Sopenharmony_ci	struct xfs_da_args	*args)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	xfs_dablk_t		lblkno;
6398c2ecf20Sopenharmony_ci	int			blkcnt;
6408c2ecf20Sopenharmony_ci	int			error;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	/*
6438c2ecf20Sopenharmony_ci	 * Roll through the "value", invalidating the attribute value's blocks.
6448c2ecf20Sopenharmony_ci	 */
6458c2ecf20Sopenharmony_ci	lblkno = args->rmtblkno;
6468c2ecf20Sopenharmony_ci	blkcnt = args->rmtblkcnt;
6478c2ecf20Sopenharmony_ci	while (blkcnt > 0) {
6488c2ecf20Sopenharmony_ci		struct xfs_bmbt_irec	map;
6498c2ecf20Sopenharmony_ci		int			nmap;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		/*
6528c2ecf20Sopenharmony_ci		 * Try to remember where we decided to put the value.
6538c2ecf20Sopenharmony_ci		 */
6548c2ecf20Sopenharmony_ci		nmap = 1;
6558c2ecf20Sopenharmony_ci		error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
6568c2ecf20Sopenharmony_ci				       blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
6578c2ecf20Sopenharmony_ci		if (error)
6588c2ecf20Sopenharmony_ci			return error;
6598c2ecf20Sopenharmony_ci		if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
6608c2ecf20Sopenharmony_ci			return -EFSCORRUPTED;
6618c2ecf20Sopenharmony_ci		error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
6628c2ecf20Sopenharmony_ci		if (error)
6638c2ecf20Sopenharmony_ci			return error;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		lblkno += map.br_blockcount;
6668c2ecf20Sopenharmony_ci		blkcnt -= map.br_blockcount;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	return 0;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci/*
6728c2ecf20Sopenharmony_ci * Remove the value associated with an attribute by deleting the
6738c2ecf20Sopenharmony_ci * out-of-line buffer that it is stored on.
6748c2ecf20Sopenharmony_ci */
6758c2ecf20Sopenharmony_ciint
6768c2ecf20Sopenharmony_cixfs_attr_rmtval_remove(
6778c2ecf20Sopenharmony_ci	struct xfs_da_args      *args)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	int			error;
6808c2ecf20Sopenharmony_ci	int			retval;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	trace_xfs_attr_rmtval_remove(args);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/*
6858c2ecf20Sopenharmony_ci	 * Keep de-allocating extents until the remote-value region is gone.
6868c2ecf20Sopenharmony_ci	 */
6878c2ecf20Sopenharmony_ci	do {
6888c2ecf20Sopenharmony_ci		retval = __xfs_attr_rmtval_remove(args);
6898c2ecf20Sopenharmony_ci		if (retval && retval != -EAGAIN)
6908c2ecf20Sopenharmony_ci			return retval;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		/*
6938c2ecf20Sopenharmony_ci		 * Close out trans and start the next one in the chain.
6948c2ecf20Sopenharmony_ci		 */
6958c2ecf20Sopenharmony_ci		error = xfs_trans_roll_inode(&args->trans, args->dp);
6968c2ecf20Sopenharmony_ci		if (error)
6978c2ecf20Sopenharmony_ci			return error;
6988c2ecf20Sopenharmony_ci	} while (retval == -EAGAIN);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	return 0;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci/*
7048c2ecf20Sopenharmony_ci * Remove the value associated with an attribute by deleting the out-of-line
7058c2ecf20Sopenharmony_ci * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
7068c2ecf20Sopenharmony_ci * transaction and re-call the function
7078c2ecf20Sopenharmony_ci */
7088c2ecf20Sopenharmony_ciint
7098c2ecf20Sopenharmony_ci__xfs_attr_rmtval_remove(
7108c2ecf20Sopenharmony_ci	struct xfs_da_args	*args)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	int			error, done;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/*
7158c2ecf20Sopenharmony_ci	 * Unmap value blocks for this attr.
7168c2ecf20Sopenharmony_ci	 */
7178c2ecf20Sopenharmony_ci	error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
7188c2ecf20Sopenharmony_ci			    args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
7198c2ecf20Sopenharmony_ci	if (error)
7208c2ecf20Sopenharmony_ci		return error;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	error = xfs_defer_finish(&args->trans);
7238c2ecf20Sopenharmony_ci	if (error)
7248c2ecf20Sopenharmony_ci		return error;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (!done)
7278c2ecf20Sopenharmony_ci		return -EAGAIN;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	return error;
7308c2ecf20Sopenharmony_ci}
731