cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xfs_attr_remote.c (17289B)


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