xref: /openbmc/linux/fs/xfs/libxfs/xfs_rmap.c (revision 39ab26d5)
10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0
2673930c3SDarrick J. Wong /*
3673930c3SDarrick J. Wong  * Copyright (c) 2014 Red Hat, Inc.
4673930c3SDarrick J. Wong  * All Rights Reserved.
5673930c3SDarrick J. Wong  */
6673930c3SDarrick J. Wong #include "xfs.h"
7673930c3SDarrick J. Wong #include "xfs_fs.h"
8673930c3SDarrick J. Wong #include "xfs_shared.h"
9673930c3SDarrick J. Wong #include "xfs_format.h"
10673930c3SDarrick J. Wong #include "xfs_log_format.h"
11673930c3SDarrick J. Wong #include "xfs_trans_resv.h"
12673930c3SDarrick J. Wong #include "xfs_bit.h"
13673930c3SDarrick J. Wong #include "xfs_mount.h"
1445d06621SDave Chinner #include "xfs_sb.h"
15673930c3SDarrick J. Wong #include "xfs_defer.h"
16673930c3SDarrick J. Wong #include "xfs_btree.h"
17673930c3SDarrick J. Wong #include "xfs_trans.h"
18673930c3SDarrick J. Wong #include "xfs_alloc.h"
19673930c3SDarrick J. Wong #include "xfs_rmap.h"
200a1b0b38SDarrick J. Wong #include "xfs_rmap_btree.h"
21673930c3SDarrick J. Wong #include "xfs_trace.h"
22e9e899a2SDarrick J. Wong #include "xfs_errortag.h"
23673930c3SDarrick J. Wong #include "xfs_error.h"
249c194644SDarrick J. Wong #include "xfs_inode.h"
259bbafc71SDave Chinner #include "xfs_ag.h"
26673930c3SDarrick J. Wong 
27f3c799c2SDarrick J. Wong struct kmem_cache	*xfs_rmap_intent_cache;
28f3c799c2SDarrick J. Wong 
294b8ed677SDarrick J. Wong /*
304b8ed677SDarrick J. Wong  * Lookup the first record less than or equal to [bno, len, owner, offset]
314b8ed677SDarrick J. Wong  * in the btree given by cur.
324b8ed677SDarrick J. Wong  */
334b8ed677SDarrick J. Wong int
344b8ed677SDarrick J. Wong xfs_rmap_lookup_le(
354b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
364b8ed677SDarrick J. Wong 	xfs_agblock_t		bno,
374b8ed677SDarrick J. Wong 	uint64_t		owner,
384b8ed677SDarrick J. Wong 	uint64_t		offset,
394b8ed677SDarrick J. Wong 	unsigned int		flags,
405b7ca8b3SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
414b8ed677SDarrick J. Wong 	int			*stat)
424b8ed677SDarrick J. Wong {
435b7ca8b3SDarrick J. Wong 	int			get_stat = 0;
445b7ca8b3SDarrick J. Wong 	int			error;
455b7ca8b3SDarrick J. Wong 
464b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_startblock = bno;
475b7ca8b3SDarrick J. Wong 	cur->bc_rec.r.rm_blockcount = 0;
484b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_owner = owner;
494b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_offset = offset;
504b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_flags = flags;
515b7ca8b3SDarrick J. Wong 
525b7ca8b3SDarrick J. Wong 	error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
535b7ca8b3SDarrick J. Wong 	if (error || !(*stat) || !irec)
545b7ca8b3SDarrick J. Wong 		return error;
555b7ca8b3SDarrick J. Wong 
565b7ca8b3SDarrick J. Wong 	error = xfs_rmap_get_rec(cur, irec, &get_stat);
575b7ca8b3SDarrick J. Wong 	if (error)
585b7ca8b3SDarrick J. Wong 		return error;
595b7ca8b3SDarrick J. Wong 	if (!get_stat)
605b7ca8b3SDarrick J. Wong 		return -EFSCORRUPTED;
615b7ca8b3SDarrick J. Wong 
625b7ca8b3SDarrick J. Wong 	return 0;
634b8ed677SDarrick J. Wong }
644b8ed677SDarrick J. Wong 
654b8ed677SDarrick J. Wong /*
664b8ed677SDarrick J. Wong  * Lookup the record exactly matching [bno, len, owner, offset]
674b8ed677SDarrick J. Wong  * in the btree given by cur.
684b8ed677SDarrick J. Wong  */
694b8ed677SDarrick J. Wong int
704b8ed677SDarrick J. Wong xfs_rmap_lookup_eq(
714b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
724b8ed677SDarrick J. Wong 	xfs_agblock_t		bno,
734b8ed677SDarrick J. Wong 	xfs_extlen_t		len,
744b8ed677SDarrick J. Wong 	uint64_t		owner,
754b8ed677SDarrick J. Wong 	uint64_t		offset,
764b8ed677SDarrick J. Wong 	unsigned int		flags,
774b8ed677SDarrick J. Wong 	int			*stat)
784b8ed677SDarrick J. Wong {
794b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_startblock = bno;
804b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_blockcount = len;
814b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_owner = owner;
824b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_offset = offset;
834b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_flags = flags;
844b8ed677SDarrick J. Wong 	return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
854b8ed677SDarrick J. Wong }
864b8ed677SDarrick J. Wong 
874b8ed677SDarrick J. Wong /*
884b8ed677SDarrick J. Wong  * Update the record referred to by cur to the value given
894b8ed677SDarrick J. Wong  * by [bno, len, owner, offset].
904b8ed677SDarrick J. Wong  * This either works (return 0) or gets an EFSCORRUPTED error.
914b8ed677SDarrick J. Wong  */
924b8ed677SDarrick J. Wong STATIC int
934b8ed677SDarrick J. Wong xfs_rmap_update(
944b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
954b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec)
964b8ed677SDarrick J. Wong {
974b8ed677SDarrick J. Wong 	union xfs_btree_rec	rec;
98abf09233SDarrick J. Wong 	int			error;
99abf09233SDarrick J. Wong 
10050f02fe3SDave Chinner 	trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
101abf09233SDarrick J. Wong 			irec->rm_startblock, irec->rm_blockcount,
102abf09233SDarrick J. Wong 			irec->rm_owner, irec->rm_offset, irec->rm_flags);
1034b8ed677SDarrick J. Wong 
1044b8ed677SDarrick J. Wong 	rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
1054b8ed677SDarrick J. Wong 	rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
1064b8ed677SDarrick J. Wong 	rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
1074b8ed677SDarrick J. Wong 	rec.rmap.rm_offset = cpu_to_be64(
1084b8ed677SDarrick J. Wong 			xfs_rmap_irec_offset_pack(irec));
109abf09233SDarrick J. Wong 	error = xfs_btree_update(cur, &rec);
110abf09233SDarrick J. Wong 	if (error)
111abf09233SDarrick J. Wong 		trace_xfs_rmap_update_error(cur->bc_mp,
11250f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
113abf09233SDarrick J. Wong 	return error;
114abf09233SDarrick J. Wong }
115abf09233SDarrick J. Wong 
116abf09233SDarrick J. Wong int
117abf09233SDarrick J. Wong xfs_rmap_insert(
118abf09233SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
119abf09233SDarrick J. Wong 	xfs_agblock_t		agbno,
120abf09233SDarrick J. Wong 	xfs_extlen_t		len,
121abf09233SDarrick J. Wong 	uint64_t		owner,
122abf09233SDarrick J. Wong 	uint64_t		offset,
123abf09233SDarrick J. Wong 	unsigned int		flags)
124abf09233SDarrick J. Wong {
125abf09233SDarrick J. Wong 	int			i;
126abf09233SDarrick J. Wong 	int			error;
127abf09233SDarrick J. Wong 
12850f02fe3SDave Chinner 	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
129abf09233SDarrick J. Wong 			len, owner, offset, flags);
130abf09233SDarrick J. Wong 
131abf09233SDarrick J. Wong 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
132abf09233SDarrick J. Wong 	if (error)
133abf09233SDarrick J. Wong 		goto done;
134f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
135f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
136f9e03706SDarrick J. Wong 		goto done;
137f9e03706SDarrick J. Wong 	}
138abf09233SDarrick J. Wong 
139abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_startblock = agbno;
140abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_blockcount = len;
141abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_owner = owner;
142abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_offset = offset;
143abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_flags = flags;
144abf09233SDarrick J. Wong 	error = xfs_btree_insert(rcur, &i);
145abf09233SDarrick J. Wong 	if (error)
146abf09233SDarrick J. Wong 		goto done;
147f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
148f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
149f9e03706SDarrick J. Wong 		goto done;
150f9e03706SDarrick J. Wong 	}
151abf09233SDarrick J. Wong done:
152abf09233SDarrick J. Wong 	if (error)
153abf09233SDarrick J. Wong 		trace_xfs_rmap_insert_error(rcur->bc_mp,
15450f02fe3SDave Chinner 				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
155abf09233SDarrick J. Wong 	return error;
1564b8ed677SDarrick J. Wong }
1574b8ed677SDarrick J. Wong 
158ceeb9c83SDarrick J. Wong STATIC int
159ceeb9c83SDarrick J. Wong xfs_rmap_delete(
160ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
161ceeb9c83SDarrick J. Wong 	xfs_agblock_t		agbno,
162ceeb9c83SDarrick J. Wong 	xfs_extlen_t		len,
163ceeb9c83SDarrick J. Wong 	uint64_t		owner,
164ceeb9c83SDarrick J. Wong 	uint64_t		offset,
165ceeb9c83SDarrick J. Wong 	unsigned int		flags)
166ceeb9c83SDarrick J. Wong {
167ceeb9c83SDarrick J. Wong 	int			i;
168ceeb9c83SDarrick J. Wong 	int			error;
169ceeb9c83SDarrick J. Wong 
17050f02fe3SDave Chinner 	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
171ceeb9c83SDarrick J. Wong 			len, owner, offset, flags);
172ceeb9c83SDarrick J. Wong 
173ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
174ceeb9c83SDarrick J. Wong 	if (error)
175ceeb9c83SDarrick J. Wong 		goto done;
176f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
177f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
178f9e03706SDarrick J. Wong 		goto done;
179f9e03706SDarrick J. Wong 	}
180ceeb9c83SDarrick J. Wong 
181ceeb9c83SDarrick J. Wong 	error = xfs_btree_delete(rcur, &i);
182ceeb9c83SDarrick J. Wong 	if (error)
183ceeb9c83SDarrick J. Wong 		goto done;
184f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
185f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
186f9e03706SDarrick J. Wong 		goto done;
187f9e03706SDarrick J. Wong 	}
188ceeb9c83SDarrick J. Wong done:
189ceeb9c83SDarrick J. Wong 	if (error)
190ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_delete_error(rcur->bc_mp,
19150f02fe3SDave Chinner 				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
192ceeb9c83SDarrick J. Wong 	return error;
193ceeb9c83SDarrick J. Wong }
194ceeb9c83SDarrick J. Wong 
19526788097SDarrick J. Wong /* Convert an internal btree record to an rmap record. */
196*39ab26d5SDarrick J. Wong xfs_failaddr_t
1974b8ed677SDarrick J. Wong xfs_rmap_btrec_to_irec(
198159eb69dSDarrick J. Wong 	const union xfs_btree_rec	*rec,
1994b8ed677SDarrick J. Wong 	struct xfs_rmap_irec		*irec)
2004b8ed677SDarrick J. Wong {
2014b8ed677SDarrick J. Wong 	irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
2024b8ed677SDarrick J. Wong 	irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
2034b8ed677SDarrick J. Wong 	irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
2044b8ed677SDarrick J. Wong 	return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
2054b8ed677SDarrick J. Wong 			irec);
2064b8ed677SDarrick J. Wong }
2074b8ed677SDarrick J. Wong 
2084b8ed677SDarrick J. Wong /*
2094b8ed677SDarrick J. Wong  * Get the data from the pointed-to record.
2104b8ed677SDarrick J. Wong  */
2114b8ed677SDarrick J. Wong int
2124b8ed677SDarrick J. Wong xfs_rmap_get_rec(
2134b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2144b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
2154b8ed677SDarrick J. Wong 	int			*stat)
2164b8ed677SDarrick J. Wong {
2179e6c08d4SDave Chinner 	struct xfs_mount	*mp = cur->bc_mp;
2180800169eSDave Chinner 	struct xfs_perag	*pag = cur->bc_ag.pag;
2194b8ed677SDarrick J. Wong 	union xfs_btree_rec	*rec;
2204b8ed677SDarrick J. Wong 	int			error;
2214b8ed677SDarrick J. Wong 
2224b8ed677SDarrick J. Wong 	error = xfs_btree_get_rec(cur, &rec, stat);
2234b8ed677SDarrick J. Wong 	if (error || !*stat)
2244b8ed677SDarrick J. Wong 		return error;
2254b8ed677SDarrick J. Wong 
2269e6c08d4SDave Chinner 	if (xfs_rmap_btrec_to_irec(rec, irec))
2279e6c08d4SDave Chinner 		goto out_bad_rec;
2289e6c08d4SDave Chinner 
2299e6c08d4SDave Chinner 	if (irec->rm_blockcount == 0)
2309e6c08d4SDave Chinner 		goto out_bad_rec;
2319e6c08d4SDave Chinner 	if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
2329e6c08d4SDave Chinner 		if (irec->rm_owner != XFS_RMAP_OWN_FS)
2339e6c08d4SDave Chinner 			goto out_bad_rec;
2349e6c08d4SDave Chinner 		if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
2359e6c08d4SDave Chinner 			goto out_bad_rec;
2369e6c08d4SDave Chinner 	} else {
2379e6c08d4SDave Chinner 		/* check for valid extent range, including overflow */
238b65e08f8SDarrick J. Wong 		if (!xfs_verify_agbext(pag, irec->rm_startblock,
239b65e08f8SDarrick J. Wong 					    irec->rm_blockcount))
2409e6c08d4SDave Chinner 			goto out_bad_rec;
2419e6c08d4SDave Chinner 	}
2429e6c08d4SDave Chinner 
2439e6c08d4SDave Chinner 	if (!(xfs_verify_ino(mp, irec->rm_owner) ||
2449e6c08d4SDave Chinner 	      (irec->rm_owner <= XFS_RMAP_OWN_FS &&
2459e6c08d4SDave Chinner 	       irec->rm_owner >= XFS_RMAP_OWN_MIN)))
2469e6c08d4SDave Chinner 		goto out_bad_rec;
2479e6c08d4SDave Chinner 
2489e6c08d4SDave Chinner 	return 0;
2499e6c08d4SDave Chinner out_bad_rec:
2509e6c08d4SDave Chinner 	xfs_warn(mp,
2519e6c08d4SDave Chinner 		"Reverse Mapping BTree record corruption in AG %d detected!",
2520800169eSDave Chinner 		pag->pag_agno);
2539e6c08d4SDave Chinner 	xfs_warn(mp,
2549e6c08d4SDave Chinner 		"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
2559e6c08d4SDave Chinner 		irec->rm_owner, irec->rm_flags, irec->rm_startblock,
2569e6c08d4SDave Chinner 		irec->rm_blockcount);
2579e6c08d4SDave Chinner 	return -EFSCORRUPTED;
2584b8ed677SDarrick J. Wong }
2594b8ed677SDarrick J. Wong 
260ceeb9c83SDarrick J. Wong struct xfs_find_left_neighbor_info {
261ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	high;
262ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec;
263ceeb9c83SDarrick J. Wong };
264ceeb9c83SDarrick J. Wong 
265ceeb9c83SDarrick J. Wong /* For each rmap given, figure out if it matches the key we want. */
266ceeb9c83SDarrick J. Wong STATIC int
267ceeb9c83SDarrick J. Wong xfs_rmap_find_left_neighbor_helper(
268ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
269159eb69dSDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
270ceeb9c83SDarrick J. Wong 	void				*priv)
271ceeb9c83SDarrick J. Wong {
272ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	*info = priv;
273ceeb9c83SDarrick J. Wong 
274ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
27550f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
276ceeb9c83SDarrick J. Wong 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
277ceeb9c83SDarrick J. Wong 			rec->rm_flags);
278ceeb9c83SDarrick J. Wong 
279ceeb9c83SDarrick J. Wong 	if (rec->rm_owner != info->high.rm_owner)
28039ee2239SDarrick J. Wong 		return 0;
281ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
282ceeb9c83SDarrick J. Wong 	    !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
283ceeb9c83SDarrick J. Wong 	    rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset)
28439ee2239SDarrick J. Wong 		return 0;
285ceeb9c83SDarrick J. Wong 
286ceeb9c83SDarrick J. Wong 	*info->irec = *rec;
287e7ee96dfSDarrick J. Wong 	return -ECANCELED;
288ceeb9c83SDarrick J. Wong }
289ceeb9c83SDarrick J. Wong 
290ceeb9c83SDarrick J. Wong /*
291ceeb9c83SDarrick J. Wong  * Find the record to the left of the given extent, being careful only to
292ceeb9c83SDarrick J. Wong  * return a match with the same owner and adjacent physical and logical
293ceeb9c83SDarrick J. Wong  * block ranges.
294ceeb9c83SDarrick J. Wong  */
2951edf8056SDarrick J. Wong STATIC int
296ceeb9c83SDarrick J. Wong xfs_rmap_find_left_neighbor(
297ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
298ceeb9c83SDarrick J. Wong 	xfs_agblock_t		bno,
299ceeb9c83SDarrick J. Wong 	uint64_t		owner,
300ceeb9c83SDarrick J. Wong 	uint64_t		offset,
301ceeb9c83SDarrick J. Wong 	unsigned int		flags,
302ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
303ceeb9c83SDarrick J. Wong 	int			*stat)
304ceeb9c83SDarrick J. Wong {
305ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	info;
3061edf8056SDarrick J. Wong 	int			found = 0;
307ceeb9c83SDarrick J. Wong 	int			error;
308ceeb9c83SDarrick J. Wong 
309ceeb9c83SDarrick J. Wong 	*stat = 0;
310ceeb9c83SDarrick J. Wong 	if (bno == 0)
311ceeb9c83SDarrick J. Wong 		return 0;
312ceeb9c83SDarrick J. Wong 	info.high.rm_startblock = bno - 1;
313ceeb9c83SDarrick J. Wong 	info.high.rm_owner = owner;
314ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(owner) &&
315ceeb9c83SDarrick J. Wong 	    !(flags & XFS_RMAP_BMBT_BLOCK)) {
316ceeb9c83SDarrick J. Wong 		if (offset == 0)
317ceeb9c83SDarrick J. Wong 			return 0;
318ceeb9c83SDarrick J. Wong 		info.high.rm_offset = offset - 1;
319ceeb9c83SDarrick J. Wong 	} else
320ceeb9c83SDarrick J. Wong 		info.high.rm_offset = 0;
321ceeb9c83SDarrick J. Wong 	info.high.rm_flags = flags;
322ceeb9c83SDarrick J. Wong 	info.high.rm_blockcount = 0;
323ceeb9c83SDarrick J. Wong 	info.irec = irec;
324ceeb9c83SDarrick J. Wong 
325ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
32650f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
327ceeb9c83SDarrick J. Wong 
3281edf8056SDarrick J. Wong 	/*
3291edf8056SDarrick J. Wong 	 * Historically, we always used the range query to walk every reverse
3301edf8056SDarrick J. Wong 	 * mapping that could possibly overlap the key that the caller asked
3311edf8056SDarrick J. Wong 	 * for, and filter out the ones that don't.  That is very slow when
3321edf8056SDarrick J. Wong 	 * there are a lot of records.
3331edf8056SDarrick J. Wong 	 *
3341edf8056SDarrick J. Wong 	 * However, there are two scenarios where the classic btree search can
3351edf8056SDarrick J. Wong 	 * produce correct results -- if the index contains a record that is an
3361edf8056SDarrick J. Wong 	 * exact match for the lookup key; and if there are no other records
3371edf8056SDarrick J. Wong 	 * between the record we want and the key we supplied.
3381edf8056SDarrick J. Wong 	 *
3391edf8056SDarrick J. Wong 	 * As an optimization, try a non-overlapped lookup first.  This makes
3401edf8056SDarrick J. Wong 	 * extent conversion and remap operations run a bit faster if the
3411edf8056SDarrick J. Wong 	 * physical extents aren't being shared.  If we don't find what we
3421edf8056SDarrick J. Wong 	 * want, we fall back to the overlapped query.
3431edf8056SDarrick J. Wong 	 */
3441edf8056SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
3451edf8056SDarrick J. Wong 			&found);
3461edf8056SDarrick J. Wong 	if (error)
3471edf8056SDarrick J. Wong 		return error;
3481edf8056SDarrick J. Wong 	if (found)
3491edf8056SDarrick J. Wong 		error = xfs_rmap_find_left_neighbor_helper(cur, irec, &info);
3501edf8056SDarrick J. Wong 	if (!error)
351ceeb9c83SDarrick J. Wong 		error = xfs_rmap_query_range(cur, &info.high, &info.high,
352ceeb9c83SDarrick J. Wong 				xfs_rmap_find_left_neighbor_helper, &info);
3531edf8056SDarrick J. Wong 	if (error != -ECANCELED)
3541edf8056SDarrick J. Wong 		return error;
3551edf8056SDarrick J. Wong 
3561edf8056SDarrick J. Wong 	*stat = 1;
357ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
35850f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, irec->rm_startblock,
3591edf8056SDarrick J. Wong 			irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
3601edf8056SDarrick J. Wong 			irec->rm_flags);
3611edf8056SDarrick J. Wong 	return 0;
362ceeb9c83SDarrick J. Wong }
363ceeb9c83SDarrick J. Wong 
364ceeb9c83SDarrick J. Wong /* For each rmap given, figure out if it matches the key we want. */
365ceeb9c83SDarrick J. Wong STATIC int
366ceeb9c83SDarrick J. Wong xfs_rmap_lookup_le_range_helper(
367ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
368159eb69dSDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
369ceeb9c83SDarrick J. Wong 	void				*priv)
370ceeb9c83SDarrick J. Wong {
371ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	*info = priv;
372ceeb9c83SDarrick J. Wong 
373ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
37450f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
375ceeb9c83SDarrick J. Wong 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
376ceeb9c83SDarrick J. Wong 			rec->rm_flags);
377ceeb9c83SDarrick J. Wong 
378ceeb9c83SDarrick J. Wong 	if (rec->rm_owner != info->high.rm_owner)
37939ee2239SDarrick J. Wong 		return 0;
380ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
381ceeb9c83SDarrick J. Wong 	    !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
382ceeb9c83SDarrick J. Wong 	    (rec->rm_offset > info->high.rm_offset ||
383ceeb9c83SDarrick J. Wong 	     rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset))
38439ee2239SDarrick J. Wong 		return 0;
385ceeb9c83SDarrick J. Wong 
386ceeb9c83SDarrick J. Wong 	*info->irec = *rec;
387e7ee96dfSDarrick J. Wong 	return -ECANCELED;
388ceeb9c83SDarrick J. Wong }
389ceeb9c83SDarrick J. Wong 
390ceeb9c83SDarrick J. Wong /*
391ceeb9c83SDarrick J. Wong  * Find the record to the left of the given extent, being careful only to
392ceeb9c83SDarrick J. Wong  * return a match with the same owner and overlapping physical and logical
393ceeb9c83SDarrick J. Wong  * block ranges.  This is the overlapping-interval version of
394ceeb9c83SDarrick J. Wong  * xfs_rmap_lookup_le.
395ceeb9c83SDarrick J. Wong  */
396ceeb9c83SDarrick J. Wong int
397ceeb9c83SDarrick J. Wong xfs_rmap_lookup_le_range(
398ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
399ceeb9c83SDarrick J. Wong 	xfs_agblock_t		bno,
400ceeb9c83SDarrick J. Wong 	uint64_t		owner,
401ceeb9c83SDarrick J. Wong 	uint64_t		offset,
402ceeb9c83SDarrick J. Wong 	unsigned int		flags,
403ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
404ceeb9c83SDarrick J. Wong 	int			*stat)
405ceeb9c83SDarrick J. Wong {
406ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	info;
40775d893d1SDarrick J. Wong 	int			found = 0;
408ceeb9c83SDarrick J. Wong 	int			error;
409ceeb9c83SDarrick J. Wong 
410ceeb9c83SDarrick J. Wong 	info.high.rm_startblock = bno;
411ceeb9c83SDarrick J. Wong 	info.high.rm_owner = owner;
412ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK))
413ceeb9c83SDarrick J. Wong 		info.high.rm_offset = offset;
414ceeb9c83SDarrick J. Wong 	else
415ceeb9c83SDarrick J. Wong 		info.high.rm_offset = 0;
416ceeb9c83SDarrick J. Wong 	info.high.rm_flags = flags;
417ceeb9c83SDarrick J. Wong 	info.high.rm_blockcount = 0;
418ceeb9c83SDarrick J. Wong 	*stat = 0;
419ceeb9c83SDarrick J. Wong 	info.irec = irec;
420ceeb9c83SDarrick J. Wong 
42175d893d1SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_ag.pag->pag_agno,
42275d893d1SDarrick J. Wong 			bno, 0, owner, offset, flags);
42375d893d1SDarrick J. Wong 
42475d893d1SDarrick J. Wong 	/*
42575d893d1SDarrick J. Wong 	 * Historically, we always used the range query to walk every reverse
42675d893d1SDarrick J. Wong 	 * mapping that could possibly overlap the key that the caller asked
42775d893d1SDarrick J. Wong 	 * for, and filter out the ones that don't.  That is very slow when
42875d893d1SDarrick J. Wong 	 * there are a lot of records.
42975d893d1SDarrick J. Wong 	 *
43075d893d1SDarrick J. Wong 	 * However, there are two scenarios where the classic btree search can
43175d893d1SDarrick J. Wong 	 * produce correct results -- if the index contains a record that is an
43275d893d1SDarrick J. Wong 	 * exact match for the lookup key; and if there are no other records
43375d893d1SDarrick J. Wong 	 * between the record we want and the key we supplied.
43475d893d1SDarrick J. Wong 	 *
43575d893d1SDarrick J. Wong 	 * As an optimization, try a non-overlapped lookup first.  This makes
43675d893d1SDarrick J. Wong 	 * scrub run much faster on most filesystems because bmbt records are
43775d893d1SDarrick J. Wong 	 * usually an exact match for rmap records.  If we don't find what we
43875d893d1SDarrick J. Wong 	 * want, we fall back to the overlapped query.
43975d893d1SDarrick J. Wong 	 */
44075d893d1SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
44175d893d1SDarrick J. Wong 			&found);
44275d893d1SDarrick J. Wong 	if (error)
44375d893d1SDarrick J. Wong 		return error;
44475d893d1SDarrick J. Wong 	if (found)
44575d893d1SDarrick J. Wong 		error = xfs_rmap_lookup_le_range_helper(cur, irec, &info);
44675d893d1SDarrick J. Wong 	if (!error)
447ceeb9c83SDarrick J. Wong 		error = xfs_rmap_query_range(cur, &info.high, &info.high,
448ceeb9c83SDarrick J. Wong 				xfs_rmap_lookup_le_range_helper, &info);
44975d893d1SDarrick J. Wong 	if (error != -ECANCELED)
45075d893d1SDarrick J. Wong 		return error;
45175d893d1SDarrick J. Wong 
45275d893d1SDarrick J. Wong 	*stat = 1;
453ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
45450f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, irec->rm_startblock,
45575d893d1SDarrick J. Wong 			irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
45675d893d1SDarrick J. Wong 			irec->rm_flags);
45775d893d1SDarrick J. Wong 	return 0;
458ceeb9c83SDarrick J. Wong }
459ceeb9c83SDarrick J. Wong 
460f922cd90SDarrick J. Wong /*
46168c58e9bSDarrick J. Wong  * Perform all the relevant owner checks for a removal op.  If we're doing an
46268c58e9bSDarrick J. Wong  * unknown-owner removal then we have no owner information to check.
46368c58e9bSDarrick J. Wong  */
46468c58e9bSDarrick J. Wong static int
46568c58e9bSDarrick J. Wong xfs_rmap_free_check_owner(
46668c58e9bSDarrick J. Wong 	struct xfs_mount	*mp,
46768c58e9bSDarrick J. Wong 	uint64_t		ltoff,
46868c58e9bSDarrick J. Wong 	struct xfs_rmap_irec	*rec,
46968c58e9bSDarrick J. Wong 	xfs_filblks_t		len,
47068c58e9bSDarrick J. Wong 	uint64_t		owner,
47168c58e9bSDarrick J. Wong 	uint64_t		offset,
47268c58e9bSDarrick J. Wong 	unsigned int		flags)
47368c58e9bSDarrick J. Wong {
47468c58e9bSDarrick J. Wong 	int			error = 0;
47568c58e9bSDarrick J. Wong 
47668c58e9bSDarrick J. Wong 	if (owner == XFS_RMAP_OWN_UNKNOWN)
47768c58e9bSDarrick J. Wong 		return 0;
47868c58e9bSDarrick J. Wong 
47968c58e9bSDarrick J. Wong 	/* Make sure the unwritten flag matches. */
480f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
481f9e03706SDarrick J. Wong 			   (flags & XFS_RMAP_UNWRITTEN) !=
482f9e03706SDarrick J. Wong 			   (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
483f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
484f9e03706SDarrick J. Wong 		goto out;
485f9e03706SDarrick J. Wong 	}
48668c58e9bSDarrick J. Wong 
48768c58e9bSDarrick J. Wong 	/* Make sure the owner matches what we expect to find in the tree. */
488f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
489f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
490f9e03706SDarrick J. Wong 		goto out;
491f9e03706SDarrick J. Wong 	}
49268c58e9bSDarrick J. Wong 
49368c58e9bSDarrick J. Wong 	/* Check the offset, if necessary. */
49468c58e9bSDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(owner))
49568c58e9bSDarrick J. Wong 		goto out;
49668c58e9bSDarrick J. Wong 
49768c58e9bSDarrick J. Wong 	if (flags & XFS_RMAP_BMBT_BLOCK) {
498f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
499f9e03706SDarrick J. Wong 				   !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
500f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
501f9e03706SDarrick J. Wong 			goto out;
502f9e03706SDarrick J. Wong 		}
50368c58e9bSDarrick J. Wong 	} else {
504f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
505f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
506f9e03706SDarrick J. Wong 			goto out;
507f9e03706SDarrick J. Wong 		}
508f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
509f9e03706SDarrick J. Wong 				   offset + len > ltoff + rec->rm_blockcount)) {
510f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
511f9e03706SDarrick J. Wong 			goto out;
512f9e03706SDarrick J. Wong 		}
51368c58e9bSDarrick J. Wong 	}
51468c58e9bSDarrick J. Wong 
51568c58e9bSDarrick J. Wong out:
51668c58e9bSDarrick J. Wong 	return error;
51768c58e9bSDarrick J. Wong }
51868c58e9bSDarrick J. Wong 
51968c58e9bSDarrick J. Wong /*
520f922cd90SDarrick J. Wong  * Find the extent in the rmap btree and remove it.
521f922cd90SDarrick J. Wong  *
522f922cd90SDarrick J. Wong  * The record we find should always be an exact match for the extent that we're
523f922cd90SDarrick J. Wong  * looking for, since we insert them into the btree without modification.
524f922cd90SDarrick J. Wong  *
525f922cd90SDarrick J. Wong  * Special Case #1: when growing the filesystem, we "free" an extent when
526f922cd90SDarrick J. Wong  * growing the last AG. This extent is new space and so it is not tracked as
527f922cd90SDarrick J. Wong  * used space in the btree. The growfs code will pass in an owner of
528f922cd90SDarrick J. Wong  * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
529f922cd90SDarrick J. Wong  * extent. We verify that - the extent lookup result in a record that does not
530f922cd90SDarrick J. Wong  * overlap.
531f922cd90SDarrick J. Wong  *
532f922cd90SDarrick J. Wong  * Special Case #2: EFIs do not record the owner of the extent, so when
533f922cd90SDarrick J. Wong  * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
534f922cd90SDarrick J. Wong  * btree to ignore the owner (i.e. wildcard match) so we don't trigger
535f922cd90SDarrick J. Wong  * corruption checks during log recovery.
536f922cd90SDarrick J. Wong  */
537f922cd90SDarrick J. Wong STATIC int
538f922cd90SDarrick J. Wong xfs_rmap_unmap(
539f922cd90SDarrick J. Wong 	struct xfs_btree_cur		*cur,
540f922cd90SDarrick J. Wong 	xfs_agblock_t			bno,
541f922cd90SDarrick J. Wong 	xfs_extlen_t			len,
542f922cd90SDarrick J. Wong 	bool				unwritten,
54366e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
544f922cd90SDarrick J. Wong {
545f922cd90SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
546f922cd90SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
547f922cd90SDarrick J. Wong 	uint64_t			ltoff;
548f922cd90SDarrick J. Wong 	int				error = 0;
549f922cd90SDarrick J. Wong 	int				i;
550f922cd90SDarrick J. Wong 	uint64_t			owner;
551f922cd90SDarrick J. Wong 	uint64_t			offset;
552f922cd90SDarrick J. Wong 	unsigned int			flags;
553f922cd90SDarrick J. Wong 	bool				ignore_off;
554f922cd90SDarrick J. Wong 
555f922cd90SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
556f922cd90SDarrick J. Wong 	ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
557f922cd90SDarrick J. Wong 			(flags & XFS_RMAP_BMBT_BLOCK);
558f922cd90SDarrick J. Wong 	if (unwritten)
559f922cd90SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
56050f02fe3SDave Chinner 	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
561f922cd90SDarrick J. Wong 			unwritten, oinfo);
562f922cd90SDarrick J. Wong 
563f922cd90SDarrick J. Wong 	/*
564f922cd90SDarrick J. Wong 	 * We should always have a left record because there's a static record
565f922cd90SDarrick J. Wong 	 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
566f922cd90SDarrick J. Wong 	 * will not ever be removed from the tree.
567f922cd90SDarrick J. Wong 	 */
5685b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &ltrec, &i);
569f922cd90SDarrick J. Wong 	if (error)
570f922cd90SDarrick J. Wong 		goto out_error;
571f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
572f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
573f9e03706SDarrick J. Wong 		goto out_error;
574f9e03706SDarrick J. Wong 	}
575f922cd90SDarrick J. Wong 
576f922cd90SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
57750f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
578f922cd90SDarrick J. Wong 			ltrec.rm_blockcount, ltrec.rm_owner,
579f922cd90SDarrick J. Wong 			ltrec.rm_offset, ltrec.rm_flags);
580f922cd90SDarrick J. Wong 	ltoff = ltrec.rm_offset;
581f922cd90SDarrick J. Wong 
582f922cd90SDarrick J. Wong 	/*
583f922cd90SDarrick J. Wong 	 * For growfs, the incoming extent must be beyond the left record we
584f922cd90SDarrick J. Wong 	 * just found as it is new space and won't be used by anyone. This is
585f922cd90SDarrick J. Wong 	 * just a corruption check as we don't actually do anything with this
586f922cd90SDarrick J. Wong 	 * extent.  Note that we need to use >= instead of > because it might
587f922cd90SDarrick J. Wong 	 * be the case that the "left" extent goes all the way to EOFS.
588f922cd90SDarrick J. Wong 	 */
589f922cd90SDarrick J. Wong 	if (owner == XFS_RMAP_OWN_NULL) {
590f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
591f9e03706SDarrick J. Wong 				   bno <
592f9e03706SDarrick J. Wong 				   ltrec.rm_startblock + ltrec.rm_blockcount)) {
593f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
594f9e03706SDarrick J. Wong 			goto out_error;
595f9e03706SDarrick J. Wong 		}
596f922cd90SDarrick J. Wong 		goto out_done;
597f922cd90SDarrick J. Wong 	}
598f922cd90SDarrick J. Wong 
59933df3a9cSDarrick J. Wong 	/*
60033df3a9cSDarrick J. Wong 	 * If we're doing an unknown-owner removal for EFI recovery, we expect
60133df3a9cSDarrick J. Wong 	 * to find the full range in the rmapbt or nothing at all.  If we
60233df3a9cSDarrick J. Wong 	 * don't find any rmaps overlapping either end of the range, we're
60333df3a9cSDarrick J. Wong 	 * done.  Hopefully this means that the EFI creator already queued
60433df3a9cSDarrick J. Wong 	 * (and finished) a RUI to remove the rmap.
60533df3a9cSDarrick J. Wong 	 */
60633df3a9cSDarrick J. Wong 	if (owner == XFS_RMAP_OWN_UNKNOWN &&
60733df3a9cSDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount <= bno) {
60833df3a9cSDarrick J. Wong 		struct xfs_rmap_irec    rtrec;
60933df3a9cSDarrick J. Wong 
61033df3a9cSDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
61133df3a9cSDarrick J. Wong 		if (error)
61233df3a9cSDarrick J. Wong 			goto out_error;
61333df3a9cSDarrick J. Wong 		if (i == 0)
61433df3a9cSDarrick J. Wong 			goto out_done;
61533df3a9cSDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &rtrec, &i);
61633df3a9cSDarrick J. Wong 		if (error)
61733df3a9cSDarrick J. Wong 			goto out_error;
618f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
619f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
620f9e03706SDarrick J. Wong 			goto out_error;
621f9e03706SDarrick J. Wong 		}
62233df3a9cSDarrick J. Wong 		if (rtrec.rm_startblock >= bno + len)
62333df3a9cSDarrick J. Wong 			goto out_done;
62433df3a9cSDarrick J. Wong 	}
62533df3a9cSDarrick J. Wong 
626f922cd90SDarrick J. Wong 	/* Make sure the extent we found covers the entire freeing range. */
627f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
628f9e03706SDarrick J. Wong 			   ltrec.rm_startblock > bno ||
629f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount <
630f9e03706SDarrick J. Wong 			   bno + len)) {
631f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
632f9e03706SDarrick J. Wong 		goto out_error;
633f9e03706SDarrick J. Wong 	}
634f922cd90SDarrick J. Wong 
63568c58e9bSDarrick J. Wong 	/* Check owner information. */
636a1f69417SEric Sandeen 	error = xfs_rmap_free_check_owner(mp, ltoff, &ltrec, len, owner,
63768c58e9bSDarrick J. Wong 			offset, flags);
63868c58e9bSDarrick J. Wong 	if (error)
63968c58e9bSDarrick J. Wong 		goto out_error;
640f922cd90SDarrick J. Wong 
641f922cd90SDarrick J. Wong 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
642f922cd90SDarrick J. Wong 		/* exact match, simply remove the record from rmap tree */
64350f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
644f922cd90SDarrick J. Wong 				ltrec.rm_startblock, ltrec.rm_blockcount,
645f922cd90SDarrick J. Wong 				ltrec.rm_owner, ltrec.rm_offset,
646f922cd90SDarrick J. Wong 				ltrec.rm_flags);
647f922cd90SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
648f922cd90SDarrick J. Wong 		if (error)
649f922cd90SDarrick J. Wong 			goto out_error;
650f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
651f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
652f9e03706SDarrick J. Wong 			goto out_error;
653f9e03706SDarrick J. Wong 		}
654f922cd90SDarrick J. Wong 	} else if (ltrec.rm_startblock == bno) {
655f922cd90SDarrick J. Wong 		/*
656f922cd90SDarrick J. Wong 		 * overlap left hand side of extent: move the start, trim the
657f922cd90SDarrick J. Wong 		 * length and update the current record.
658f922cd90SDarrick J. Wong 		 *
659f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
660f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
661f922cd90SDarrick J. Wong 		 * Freeing: |fffffffff|
662f922cd90SDarrick J. Wong 		 * Result:            |rrrrrrrrrr|
663f922cd90SDarrick J. Wong 		 *         bno       len
664f922cd90SDarrick J. Wong 		 */
665f922cd90SDarrick J. Wong 		ltrec.rm_startblock += len;
666f922cd90SDarrick J. Wong 		ltrec.rm_blockcount -= len;
667f922cd90SDarrick J. Wong 		if (!ignore_off)
668f922cd90SDarrick J. Wong 			ltrec.rm_offset += len;
669f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
670f922cd90SDarrick J. Wong 		if (error)
671f922cd90SDarrick J. Wong 			goto out_error;
672f922cd90SDarrick J. Wong 	} else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
673f922cd90SDarrick J. Wong 		/*
674f922cd90SDarrick J. Wong 		 * overlap right hand side of extent: trim the length and update
675f922cd90SDarrick J. Wong 		 * the current record.
676f922cd90SDarrick J. Wong 		 *
677f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
678f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
679f922cd90SDarrick J. Wong 		 * Freeing:            |fffffffff|
680f922cd90SDarrick J. Wong 		 * Result:  |rrrrrrrrrr|
681f922cd90SDarrick J. Wong 		 *                    bno       len
682f922cd90SDarrick J. Wong 		 */
683f922cd90SDarrick J. Wong 		ltrec.rm_blockcount -= len;
684f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
685f922cd90SDarrick J. Wong 		if (error)
686f922cd90SDarrick J. Wong 			goto out_error;
687f922cd90SDarrick J. Wong 	} else {
688f922cd90SDarrick J. Wong 
689f922cd90SDarrick J. Wong 		/*
690f922cd90SDarrick J. Wong 		 * overlap middle of extent: trim the length of the existing
691f922cd90SDarrick J. Wong 		 * record to the length of the new left-extent size, increment
692f922cd90SDarrick J. Wong 		 * the insertion position so we can insert a new record
693f922cd90SDarrick J. Wong 		 * containing the remaining right-extent space.
694f922cd90SDarrick J. Wong 		 *
695f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
696f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
697f922cd90SDarrick J. Wong 		 * Freeing:       |fffffffff|
698f922cd90SDarrick J. Wong 		 * Result:  |rrrrr|         |rrrr|
699f922cd90SDarrick J. Wong 		 *               bno       len
700f922cd90SDarrick J. Wong 		 */
701f922cd90SDarrick J. Wong 		xfs_extlen_t	orig_len = ltrec.rm_blockcount;
702f922cd90SDarrick J. Wong 
703f922cd90SDarrick J. Wong 		ltrec.rm_blockcount = bno - ltrec.rm_startblock;
704f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
705f922cd90SDarrick J. Wong 		if (error)
706f922cd90SDarrick J. Wong 			goto out_error;
707f922cd90SDarrick J. Wong 
708f922cd90SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
709f922cd90SDarrick J. Wong 		if (error)
710f922cd90SDarrick J. Wong 			goto out_error;
711f922cd90SDarrick J. Wong 
712f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_startblock = bno + len;
713f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_blockcount = orig_len - len -
714f922cd90SDarrick J. Wong 						     ltrec.rm_blockcount;
715f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_owner = ltrec.rm_owner;
716f922cd90SDarrick J. Wong 		if (ignore_off)
717f922cd90SDarrick J. Wong 			cur->bc_rec.r.rm_offset = 0;
718f922cd90SDarrick J. Wong 		else
719f922cd90SDarrick J. Wong 			cur->bc_rec.r.rm_offset = offset + len;
720f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_flags = flags;
72150f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
722f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_startblock,
723f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_blockcount,
724f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_owner,
725f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_offset,
726f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_flags);
727f922cd90SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
728f922cd90SDarrick J. Wong 		if (error)
729f922cd90SDarrick J. Wong 			goto out_error;
730f922cd90SDarrick J. Wong 	}
731f922cd90SDarrick J. Wong 
732f922cd90SDarrick J. Wong out_done:
73350f02fe3SDave Chinner 	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
734f922cd90SDarrick J. Wong 			unwritten, oinfo);
735f922cd90SDarrick J. Wong out_error:
736f922cd90SDarrick J. Wong 	if (error)
73750f02fe3SDave Chinner 		trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
738f922cd90SDarrick J. Wong 				error, _RET_IP_);
739f922cd90SDarrick J. Wong 	return error;
740f922cd90SDarrick J. Wong }
741f922cd90SDarrick J. Wong 
742f922cd90SDarrick J. Wong /*
743f922cd90SDarrick J. Wong  * Remove a reference to an extent in the rmap btree.
744f922cd90SDarrick J. Wong  */
745673930c3SDarrick J. Wong int
746673930c3SDarrick J. Wong xfs_rmap_free(
747673930c3SDarrick J. Wong 	struct xfs_trans		*tp,
748673930c3SDarrick J. Wong 	struct xfs_buf			*agbp,
749fa9c3c19SDave Chinner 	struct xfs_perag		*pag,
750673930c3SDarrick J. Wong 	xfs_agblock_t			bno,
751673930c3SDarrick J. Wong 	xfs_extlen_t			len,
75266e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
753673930c3SDarrick J. Wong {
754673930c3SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
755f922cd90SDarrick J. Wong 	struct xfs_btree_cur		*cur;
756f922cd90SDarrick J. Wong 	int				error;
757673930c3SDarrick J. Wong 
75838c26bfdSDave Chinner 	if (!xfs_has_rmapbt(mp))
759673930c3SDarrick J. Wong 		return 0;
760673930c3SDarrick J. Wong 
761fa9c3c19SDave Chinner 	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
762f922cd90SDarrick J. Wong 
763f922cd90SDarrick J. Wong 	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
764f922cd90SDarrick J. Wong 
7650b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
766673930c3SDarrick J. Wong 	return error;
767673930c3SDarrick J. Wong }
768673930c3SDarrick J. Wong 
7690a1b0b38SDarrick J. Wong /*
7700a1b0b38SDarrick J. Wong  * A mergeable rmap must have the same owner and the same values for
7710a1b0b38SDarrick J. Wong  * the unwritten, attr_fork, and bmbt flags.  The startblock and
7720a1b0b38SDarrick J. Wong  * offset are checked separately.
7730a1b0b38SDarrick J. Wong  */
7740a1b0b38SDarrick J. Wong static bool
7750a1b0b38SDarrick J. Wong xfs_rmap_is_mergeable(
7760a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
7770a1b0b38SDarrick J. Wong 	uint64_t		owner,
7780a1b0b38SDarrick J. Wong 	unsigned int		flags)
7790a1b0b38SDarrick J. Wong {
7800a1b0b38SDarrick J. Wong 	if (irec->rm_owner == XFS_RMAP_OWN_NULL)
7810a1b0b38SDarrick J. Wong 		return false;
7820a1b0b38SDarrick J. Wong 	if (irec->rm_owner != owner)
7830a1b0b38SDarrick J. Wong 		return false;
7840a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_UNWRITTEN) ^
7850a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_UNWRITTEN))
7860a1b0b38SDarrick J. Wong 		return false;
7870a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_ATTR_FORK) ^
7880a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_ATTR_FORK))
7890a1b0b38SDarrick J. Wong 		return false;
7900a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_BMBT_BLOCK) ^
7910a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
7920a1b0b38SDarrick J. Wong 		return false;
7930a1b0b38SDarrick J. Wong 	return true;
7940a1b0b38SDarrick J. Wong }
7950a1b0b38SDarrick J. Wong 
7960a1b0b38SDarrick J. Wong /*
7970a1b0b38SDarrick J. Wong  * When we allocate a new block, the first thing we do is add a reference to
7980a1b0b38SDarrick J. Wong  * the extent in the rmap btree. This takes the form of a [agbno, length,
7990a1b0b38SDarrick J. Wong  * owner, offset] record.  Flags are encoded in the high bits of the offset
8000a1b0b38SDarrick J. Wong  * field.
8010a1b0b38SDarrick J. Wong  */
8020a1b0b38SDarrick J. Wong STATIC int
8030a1b0b38SDarrick J. Wong xfs_rmap_map(
8040a1b0b38SDarrick J. Wong 	struct xfs_btree_cur		*cur,
8050a1b0b38SDarrick J. Wong 	xfs_agblock_t			bno,
8060a1b0b38SDarrick J. Wong 	xfs_extlen_t			len,
8070a1b0b38SDarrick J. Wong 	bool				unwritten,
80866e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
8090a1b0b38SDarrick J. Wong {
8100a1b0b38SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
8110a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
8120a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec		gtrec;
8130a1b0b38SDarrick J. Wong 	int				have_gt;
8140a1b0b38SDarrick J. Wong 	int				have_lt;
8150a1b0b38SDarrick J. Wong 	int				error = 0;
8160a1b0b38SDarrick J. Wong 	int				i;
8170a1b0b38SDarrick J. Wong 	uint64_t			owner;
8180a1b0b38SDarrick J. Wong 	uint64_t			offset;
8190a1b0b38SDarrick J. Wong 	unsigned int			flags = 0;
8200a1b0b38SDarrick J. Wong 	bool				ignore_off;
8210a1b0b38SDarrick J. Wong 
8220a1b0b38SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
8230a1b0b38SDarrick J. Wong 	ASSERT(owner != 0);
8240a1b0b38SDarrick J. Wong 	ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
8250a1b0b38SDarrick J. Wong 			(flags & XFS_RMAP_BMBT_BLOCK);
8260a1b0b38SDarrick J. Wong 	if (unwritten)
8270a1b0b38SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
82850f02fe3SDave Chinner 	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
8290a1b0b38SDarrick J. Wong 			unwritten, oinfo);
83033df3a9cSDarrick J. Wong 	ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
8310a1b0b38SDarrick J. Wong 
8320a1b0b38SDarrick J. Wong 	/*
8330a1b0b38SDarrick J. Wong 	 * For the initial lookup, look for an exact match or the left-adjacent
8340a1b0b38SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
8350a1b0b38SDarrick J. Wong 	 * start block contiguity tests.
8360a1b0b38SDarrick J. Wong 	 */
8375b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &ltrec,
8380a1b0b38SDarrick J. Wong 			&have_lt);
8390a1b0b38SDarrick J. Wong 	if (error)
8400a1b0b38SDarrick J. Wong 		goto out_error;
841fa248de9SDarrick J. Wong 	if (have_lt) {
8420a1b0b38SDarrick J. Wong 		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
84350f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
8440a1b0b38SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
8450a1b0b38SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
8460a1b0b38SDarrick J. Wong 
8470a1b0b38SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
8480a1b0b38SDarrick J. Wong 			have_lt = 0;
849fa248de9SDarrick J. Wong 	}
8500a1b0b38SDarrick J. Wong 
851f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
852f9e03706SDarrick J. Wong 			   have_lt != 0 &&
853f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
854f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
855f9e03706SDarrick J. Wong 		goto out_error;
856f9e03706SDarrick J. Wong 	}
8570a1b0b38SDarrick J. Wong 
8580a1b0b38SDarrick J. Wong 	/*
8590a1b0b38SDarrick J. Wong 	 * Increment the cursor to see if we have a right-adjacent record to our
8600a1b0b38SDarrick J. Wong 	 * insertion point. This will give us the record for end block
8610a1b0b38SDarrick J. Wong 	 * contiguity tests.
8620a1b0b38SDarrick J. Wong 	 */
8630a1b0b38SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &have_gt);
8640a1b0b38SDarrick J. Wong 	if (error)
8650a1b0b38SDarrick J. Wong 		goto out_error;
8660a1b0b38SDarrick J. Wong 	if (have_gt) {
8670a1b0b38SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
8680a1b0b38SDarrick J. Wong 		if (error)
8690a1b0b38SDarrick J. Wong 			goto out_error;
870f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
871f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
872f9e03706SDarrick J. Wong 			goto out_error;
873f9e03706SDarrick J. Wong 		}
874f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
875f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
876f9e03706SDarrick J. Wong 			goto out_error;
877f9e03706SDarrick J. Wong 		}
8780a1b0b38SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
87950f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
8800a1b0b38SDarrick J. Wong 			gtrec.rm_blockcount, gtrec.rm_owner,
8810a1b0b38SDarrick J. Wong 			gtrec.rm_offset, gtrec.rm_flags);
8820a1b0b38SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
8830a1b0b38SDarrick J. Wong 			have_gt = 0;
8840a1b0b38SDarrick J. Wong 	}
8850a1b0b38SDarrick J. Wong 
8860a1b0b38SDarrick J. Wong 	/*
8870a1b0b38SDarrick J. Wong 	 * Note: cursor currently points one record to the right of ltrec, even
8880a1b0b38SDarrick J. Wong 	 * if there is no record in the tree to the right.
8890a1b0b38SDarrick J. Wong 	 */
8900a1b0b38SDarrick J. Wong 	if (have_lt &&
8910a1b0b38SDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
8920a1b0b38SDarrick J. Wong 	    (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
8930a1b0b38SDarrick J. Wong 		/*
8940a1b0b38SDarrick J. Wong 		 * left edge contiguous, merge into left record.
8950a1b0b38SDarrick J. Wong 		 *
8960a1b0b38SDarrick J. Wong 		 *       ltbno     ltlen
8970a1b0b38SDarrick J. Wong 		 * orig:   |ooooooooo|
8980a1b0b38SDarrick J. Wong 		 * adding:           |aaaaaaaaa|
8990a1b0b38SDarrick J. Wong 		 * result: |rrrrrrrrrrrrrrrrrrr|
9000a1b0b38SDarrick J. Wong 		 *                  bno       len
9010a1b0b38SDarrick J. Wong 		 */
9020a1b0b38SDarrick J. Wong 		ltrec.rm_blockcount += len;
9030a1b0b38SDarrick J. Wong 		if (have_gt &&
9040a1b0b38SDarrick J. Wong 		    bno + len == gtrec.rm_startblock &&
9050a1b0b38SDarrick J. Wong 		    (ignore_off || offset + len == gtrec.rm_offset) &&
9060a1b0b38SDarrick J. Wong 		    (unsigned long)ltrec.rm_blockcount + len +
9070a1b0b38SDarrick J. Wong 				gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
9080a1b0b38SDarrick J. Wong 			/*
9090a1b0b38SDarrick J. Wong 			 * right edge also contiguous, delete right record
9100a1b0b38SDarrick J. Wong 			 * and merge into left record.
9110a1b0b38SDarrick J. Wong 			 *
9120a1b0b38SDarrick J. Wong 			 *       ltbno     ltlen    gtbno     gtlen
9130a1b0b38SDarrick J. Wong 			 * orig:   |ooooooooo|         |ooooooooo|
9140a1b0b38SDarrick J. Wong 			 * adding:           |aaaaaaaaa|
9150a1b0b38SDarrick J. Wong 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
9160a1b0b38SDarrick J. Wong 			 */
9170a1b0b38SDarrick J. Wong 			ltrec.rm_blockcount += gtrec.rm_blockcount;
91850f02fe3SDave Chinner 			trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
9190a1b0b38SDarrick J. Wong 					gtrec.rm_startblock,
9200a1b0b38SDarrick J. Wong 					gtrec.rm_blockcount,
9210a1b0b38SDarrick J. Wong 					gtrec.rm_owner,
9220a1b0b38SDarrick J. Wong 					gtrec.rm_offset,
9230a1b0b38SDarrick J. Wong 					gtrec.rm_flags);
9240a1b0b38SDarrick J. Wong 			error = xfs_btree_delete(cur, &i);
9250a1b0b38SDarrick J. Wong 			if (error)
9260a1b0b38SDarrick J. Wong 				goto out_error;
927f9e03706SDarrick J. Wong 			if (XFS_IS_CORRUPT(mp, i != 1)) {
928f9e03706SDarrick J. Wong 				error = -EFSCORRUPTED;
929f9e03706SDarrick J. Wong 				goto out_error;
930f9e03706SDarrick J. Wong 			}
9310a1b0b38SDarrick J. Wong 		}
9320a1b0b38SDarrick J. Wong 
9330a1b0b38SDarrick J. Wong 		/* point the cursor back to the left record and update */
9340a1b0b38SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &have_gt);
9350a1b0b38SDarrick J. Wong 		if (error)
9360a1b0b38SDarrick J. Wong 			goto out_error;
9370a1b0b38SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
9380a1b0b38SDarrick J. Wong 		if (error)
9390a1b0b38SDarrick J. Wong 			goto out_error;
9400a1b0b38SDarrick J. Wong 	} else if (have_gt &&
9410a1b0b38SDarrick J. Wong 		   bno + len == gtrec.rm_startblock &&
9420a1b0b38SDarrick J. Wong 		   (ignore_off || offset + len == gtrec.rm_offset)) {
9430a1b0b38SDarrick J. Wong 		/*
9440a1b0b38SDarrick J. Wong 		 * right edge contiguous, merge into right record.
9450a1b0b38SDarrick J. Wong 		 *
9460a1b0b38SDarrick J. Wong 		 *                 gtbno     gtlen
9470a1b0b38SDarrick J. Wong 		 * Orig:             |ooooooooo|
9480a1b0b38SDarrick J. Wong 		 * adding: |aaaaaaaaa|
9490a1b0b38SDarrick J. Wong 		 * Result: |rrrrrrrrrrrrrrrrrrr|
9500a1b0b38SDarrick J. Wong 		 *        bno       len
9510a1b0b38SDarrick J. Wong 		 */
9520a1b0b38SDarrick J. Wong 		gtrec.rm_startblock = bno;
9530a1b0b38SDarrick J. Wong 		gtrec.rm_blockcount += len;
9540a1b0b38SDarrick J. Wong 		if (!ignore_off)
9550a1b0b38SDarrick J. Wong 			gtrec.rm_offset = offset;
9560a1b0b38SDarrick J. Wong 		error = xfs_rmap_update(cur, &gtrec);
9570a1b0b38SDarrick J. Wong 		if (error)
9580a1b0b38SDarrick J. Wong 			goto out_error;
9590a1b0b38SDarrick J. Wong 	} else {
9600a1b0b38SDarrick J. Wong 		/*
9610a1b0b38SDarrick J. Wong 		 * no contiguous edge with identical owner, insert
9620a1b0b38SDarrick J. Wong 		 * new record at current cursor position.
9630a1b0b38SDarrick J. Wong 		 */
9640a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_startblock = bno;
9650a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_blockcount = len;
9660a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_owner = owner;
9670a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_offset = offset;
9680a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_flags = flags;
96950f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
9700a1b0b38SDarrick J. Wong 			owner, offset, flags);
9710a1b0b38SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
9720a1b0b38SDarrick J. Wong 		if (error)
9730a1b0b38SDarrick J. Wong 			goto out_error;
974f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
975f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
976f9e03706SDarrick J. Wong 			goto out_error;
977f9e03706SDarrick J. Wong 		}
9780a1b0b38SDarrick J. Wong 	}
9790a1b0b38SDarrick J. Wong 
98050f02fe3SDave Chinner 	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
9810a1b0b38SDarrick J. Wong 			unwritten, oinfo);
9820a1b0b38SDarrick J. Wong out_error:
9830a1b0b38SDarrick J. Wong 	if (error)
98450f02fe3SDave Chinner 		trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
9850a1b0b38SDarrick J. Wong 				error, _RET_IP_);
9860a1b0b38SDarrick J. Wong 	return error;
9870a1b0b38SDarrick J. Wong }
9880a1b0b38SDarrick J. Wong 
9890a1b0b38SDarrick J. Wong /*
9900a1b0b38SDarrick J. Wong  * Add a reference to an extent in the rmap btree.
9910a1b0b38SDarrick J. Wong  */
992673930c3SDarrick J. Wong int
993673930c3SDarrick J. Wong xfs_rmap_alloc(
994673930c3SDarrick J. Wong 	struct xfs_trans		*tp,
995673930c3SDarrick J. Wong 	struct xfs_buf			*agbp,
996fa9c3c19SDave Chinner 	struct xfs_perag		*pag,
997673930c3SDarrick J. Wong 	xfs_agblock_t			bno,
998673930c3SDarrick J. Wong 	xfs_extlen_t			len,
99966e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
1000673930c3SDarrick J. Wong {
1001673930c3SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
10020a1b0b38SDarrick J. Wong 	struct xfs_btree_cur		*cur;
10030a1b0b38SDarrick J. Wong 	int				error;
1004673930c3SDarrick J. Wong 
100538c26bfdSDave Chinner 	if (!xfs_has_rmapbt(mp))
1006673930c3SDarrick J. Wong 		return 0;
1007673930c3SDarrick J. Wong 
1008fa9c3c19SDave Chinner 	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
10090a1b0b38SDarrick J. Wong 	error = xfs_rmap_map(cur, bno, len, false, oinfo);
10100a1b0b38SDarrick J. Wong 
10110b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
1012673930c3SDarrick J. Wong 	return error;
1013673930c3SDarrick J. Wong }
1014c543838aSDarrick J. Wong 
1015fb7d9267SDarrick J. Wong #define RMAP_LEFT_CONTIG	(1 << 0)
1016fb7d9267SDarrick J. Wong #define RMAP_RIGHT_CONTIG	(1 << 1)
1017fb7d9267SDarrick J. Wong #define RMAP_LEFT_FILLING	(1 << 2)
1018fb7d9267SDarrick J. Wong #define RMAP_RIGHT_FILLING	(1 << 3)
1019fb7d9267SDarrick J. Wong #define RMAP_LEFT_VALID		(1 << 6)
1020fb7d9267SDarrick J. Wong #define RMAP_RIGHT_VALID	(1 << 7)
1021fb7d9267SDarrick J. Wong 
1022fb7d9267SDarrick J. Wong #define LEFT		r[0]
1023fb7d9267SDarrick J. Wong #define RIGHT		r[1]
1024fb7d9267SDarrick J. Wong #define PREV		r[2]
1025fb7d9267SDarrick J. Wong #define NEW		r[3]
1026fb7d9267SDarrick J. Wong 
1027fb7d9267SDarrick J. Wong /*
1028fb7d9267SDarrick J. Wong  * Convert an unwritten extent to a real extent or vice versa.
1029fb7d9267SDarrick J. Wong  * Does not handle overlapping extents.
1030fb7d9267SDarrick J. Wong  */
1031fb7d9267SDarrick J. Wong STATIC int
1032fb7d9267SDarrick J. Wong xfs_rmap_convert(
1033fb7d9267SDarrick J. Wong 	struct xfs_btree_cur		*cur,
1034fb7d9267SDarrick J. Wong 	xfs_agblock_t			bno,
1035fb7d9267SDarrick J. Wong 	xfs_extlen_t			len,
1036fb7d9267SDarrick J. Wong 	bool				unwritten,
103766e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
1038fb7d9267SDarrick J. Wong {
1039fb7d9267SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
1040fb7d9267SDarrick J. Wong 	struct xfs_rmap_irec		r[4];	/* neighbor extent entries */
104166e3237eSDarrick J. Wong 						/* left is 0, right is 1, */
104266e3237eSDarrick J. Wong 						/* prev is 2, new is 3 */
1043fb7d9267SDarrick J. Wong 	uint64_t		owner;
1044fb7d9267SDarrick J. Wong 	uint64_t		offset;
1045fb7d9267SDarrick J. Wong 	uint64_t		new_endoff;
1046fb7d9267SDarrick J. Wong 	unsigned int		oldext;
1047fb7d9267SDarrick J. Wong 	unsigned int		newext;
1048fb7d9267SDarrick J. Wong 	unsigned int		flags = 0;
1049fb7d9267SDarrick J. Wong 	int			i;
1050fb7d9267SDarrick J. Wong 	int			state = 0;
1051fb7d9267SDarrick J. Wong 	int			error;
1052fb7d9267SDarrick J. Wong 
1053fb7d9267SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1054fb7d9267SDarrick J. Wong 	ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1055fb7d9267SDarrick J. Wong 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1056fb7d9267SDarrick J. Wong 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1057fb7d9267SDarrick J. Wong 	new_endoff = offset + len;
105850f02fe3SDave Chinner 	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1059fb7d9267SDarrick J. Wong 			unwritten, oinfo);
1060fb7d9267SDarrick J. Wong 
1061fb7d9267SDarrick J. Wong 	/*
1062fb7d9267SDarrick J. Wong 	 * For the initial lookup, look for an exact match or the left-adjacent
1063fb7d9267SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
1064fb7d9267SDarrick J. Wong 	 * start block contiguity tests.
1065fb7d9267SDarrick J. Wong 	 */
10665b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, &PREV, &i);
1067fb7d9267SDarrick J. Wong 	if (error)
1068fb7d9267SDarrick J. Wong 		goto done;
1069f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1070f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1071f9e03706SDarrick J. Wong 		goto done;
1072f9e03706SDarrick J. Wong 	}
1073fb7d9267SDarrick J. Wong 
1074fb7d9267SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
107550f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
1076fb7d9267SDarrick J. Wong 			PREV.rm_blockcount, PREV.rm_owner,
1077fb7d9267SDarrick J. Wong 			PREV.rm_offset, PREV.rm_flags);
1078fb7d9267SDarrick J. Wong 
1079fb7d9267SDarrick J. Wong 	ASSERT(PREV.rm_offset <= offset);
1080fb7d9267SDarrick J. Wong 	ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1081fb7d9267SDarrick J. Wong 	ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1082fb7d9267SDarrick J. Wong 	newext = ~oldext & XFS_RMAP_UNWRITTEN;
1083fb7d9267SDarrick J. Wong 
1084fb7d9267SDarrick J. Wong 	/*
1085fb7d9267SDarrick J. Wong 	 * Set flags determining what part of the previous oldext allocation
1086fb7d9267SDarrick J. Wong 	 * extent is being replaced by a newext allocation.
1087fb7d9267SDarrick J. Wong 	 */
1088fb7d9267SDarrick J. Wong 	if (PREV.rm_offset == offset)
1089fb7d9267SDarrick J. Wong 		state |= RMAP_LEFT_FILLING;
1090fb7d9267SDarrick J. Wong 	if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1091fb7d9267SDarrick J. Wong 		state |= RMAP_RIGHT_FILLING;
1092fb7d9267SDarrick J. Wong 
1093fb7d9267SDarrick J. Wong 	/*
1094fb7d9267SDarrick J. Wong 	 * Decrement the cursor to see if we have a left-adjacent record to our
1095fb7d9267SDarrick J. Wong 	 * insertion point. This will give us the record for end block
1096fb7d9267SDarrick J. Wong 	 * contiguity tests.
1097fb7d9267SDarrick J. Wong 	 */
1098fb7d9267SDarrick J. Wong 	error = xfs_btree_decrement(cur, 0, &i);
1099fb7d9267SDarrick J. Wong 	if (error)
1100fb7d9267SDarrick J. Wong 		goto done;
1101fb7d9267SDarrick J. Wong 	if (i) {
1102fb7d9267SDarrick J. Wong 		state |= RMAP_LEFT_VALID;
1103fb7d9267SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &LEFT, &i);
1104fb7d9267SDarrick J. Wong 		if (error)
1105fb7d9267SDarrick J. Wong 			goto done;
1106f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1107f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1108f9e03706SDarrick J. Wong 			goto done;
1109f9e03706SDarrick J. Wong 		}
1110f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
1111f9e03706SDarrick J. Wong 				   LEFT.rm_startblock + LEFT.rm_blockcount >
1112f9e03706SDarrick J. Wong 				   bno)) {
1113f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1114f9e03706SDarrick J. Wong 			goto done;
1115f9e03706SDarrick J. Wong 		}
1116fb7d9267SDarrick J. Wong 		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
111750f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
1118fb7d9267SDarrick J. Wong 				LEFT.rm_blockcount, LEFT.rm_owner,
1119fb7d9267SDarrick J. Wong 				LEFT.rm_offset, LEFT.rm_flags);
1120fb7d9267SDarrick J. Wong 		if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
1121fb7d9267SDarrick J. Wong 		    LEFT.rm_offset + LEFT.rm_blockcount == offset &&
1122fb7d9267SDarrick J. Wong 		    xfs_rmap_is_mergeable(&LEFT, owner, newext))
1123fb7d9267SDarrick J. Wong 			state |= RMAP_LEFT_CONTIG;
1124fb7d9267SDarrick J. Wong 	}
1125fb7d9267SDarrick J. Wong 
1126fb7d9267SDarrick J. Wong 	/*
1127fb7d9267SDarrick J. Wong 	 * Increment the cursor to see if we have a right-adjacent record to our
1128fb7d9267SDarrick J. Wong 	 * insertion point. This will give us the record for end block
1129fb7d9267SDarrick J. Wong 	 * contiguity tests.
1130fb7d9267SDarrick J. Wong 	 */
1131fb7d9267SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &i);
1132fb7d9267SDarrick J. Wong 	if (error)
1133fb7d9267SDarrick J. Wong 		goto done;
1134f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1135f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1136f9e03706SDarrick J. Wong 		goto done;
1137f9e03706SDarrick J. Wong 	}
1138fb7d9267SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &i);
1139fb7d9267SDarrick J. Wong 	if (error)
1140fb7d9267SDarrick J. Wong 		goto done;
1141fb7d9267SDarrick J. Wong 	if (i) {
1142fb7d9267SDarrick J. Wong 		state |= RMAP_RIGHT_VALID;
1143fb7d9267SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1144fb7d9267SDarrick J. Wong 		if (error)
1145fb7d9267SDarrick J. Wong 			goto done;
1146f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1147f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1148f9e03706SDarrick J. Wong 			goto done;
1149f9e03706SDarrick J. Wong 		}
1150f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1151f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1152f9e03706SDarrick J. Wong 			goto done;
1153f9e03706SDarrick J. Wong 		}
1154fb7d9267SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
115550f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
1156fb7d9267SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
1157fb7d9267SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
1158fb7d9267SDarrick J. Wong 		if (bno + len == RIGHT.rm_startblock &&
1159fb7d9267SDarrick J. Wong 		    offset + len == RIGHT.rm_offset &&
1160fb7d9267SDarrick J. Wong 		    xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1161fb7d9267SDarrick J. Wong 			state |= RMAP_RIGHT_CONTIG;
1162fb7d9267SDarrick J. Wong 	}
1163fb7d9267SDarrick J. Wong 
1164fb7d9267SDarrick J. Wong 	/* check that left + prev + right is not too long */
1165fb7d9267SDarrick J. Wong 	if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1166fb7d9267SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1167fb7d9267SDarrick J. Wong 	    (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1168fb7d9267SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1169fb7d9267SDarrick J. Wong 	    (unsigned long)LEFT.rm_blockcount + len +
1170fb7d9267SDarrick J. Wong 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1171fb7d9267SDarrick J. Wong 		state &= ~RMAP_RIGHT_CONTIG;
1172fb7d9267SDarrick J. Wong 
117350f02fe3SDave Chinner 	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
1174fb7d9267SDarrick J. Wong 			_RET_IP_);
1175fb7d9267SDarrick J. Wong 
1176fb7d9267SDarrick J. Wong 	/* reset the cursor back to PREV */
11775b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, NULL, &i);
1178fb7d9267SDarrick J. Wong 	if (error)
1179fb7d9267SDarrick J. Wong 		goto done;
1180f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1181f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1182f9e03706SDarrick J. Wong 		goto done;
1183f9e03706SDarrick J. Wong 	}
1184fb7d9267SDarrick J. Wong 
1185fb7d9267SDarrick J. Wong 	/*
1186fb7d9267SDarrick J. Wong 	 * Switch out based on the FILLING and CONTIG state bits.
1187fb7d9267SDarrick J. Wong 	 */
1188fb7d9267SDarrick J. Wong 	switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1189fb7d9267SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1190fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1191fb7d9267SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1192fb7d9267SDarrick J. Wong 		/*
1193fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1194fb7d9267SDarrick J. Wong 		 * The left and right neighbors are both contiguous with new.
1195fb7d9267SDarrick J. Wong 		 */
1196fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1197fb7d9267SDarrick J. Wong 		if (error)
1198fb7d9267SDarrick J. Wong 			goto done;
1199f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1200f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1201f9e03706SDarrick J. Wong 			goto done;
1202f9e03706SDarrick J. Wong 		}
120350f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1204fb7d9267SDarrick J. Wong 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
1205fb7d9267SDarrick J. Wong 				RIGHT.rm_owner, RIGHT.rm_offset,
1206fb7d9267SDarrick J. Wong 				RIGHT.rm_flags);
1207fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1208fb7d9267SDarrick J. Wong 		if (error)
1209fb7d9267SDarrick J. Wong 			goto done;
1210f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1211f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1212f9e03706SDarrick J. Wong 			goto done;
1213f9e03706SDarrick J. Wong 		}
1214fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1215fb7d9267SDarrick J. Wong 		if (error)
1216fb7d9267SDarrick J. Wong 			goto done;
1217f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1218f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1219f9e03706SDarrick J. Wong 			goto done;
1220f9e03706SDarrick J. Wong 		}
122150f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1222fb7d9267SDarrick J. Wong 				PREV.rm_startblock, PREV.rm_blockcount,
1223fb7d9267SDarrick J. Wong 				PREV.rm_owner, PREV.rm_offset,
1224fb7d9267SDarrick J. Wong 				PREV.rm_flags);
1225fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1226fb7d9267SDarrick J. Wong 		if (error)
1227fb7d9267SDarrick J. Wong 			goto done;
1228f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1229f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1230f9e03706SDarrick J. Wong 			goto done;
1231f9e03706SDarrick J. Wong 		}
1232fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1233fb7d9267SDarrick J. Wong 		if (error)
1234fb7d9267SDarrick J. Wong 			goto done;
1235f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1236f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1237f9e03706SDarrick J. Wong 			goto done;
1238f9e03706SDarrick J. Wong 		}
1239fb7d9267SDarrick J. Wong 		NEW = LEFT;
1240fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1241fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1242fb7d9267SDarrick J. Wong 		if (error)
1243fb7d9267SDarrick J. Wong 			goto done;
1244fb7d9267SDarrick J. Wong 		break;
1245fb7d9267SDarrick J. Wong 
1246fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1247fb7d9267SDarrick J. Wong 		/*
1248fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1249fb7d9267SDarrick J. Wong 		 * The left neighbor is contiguous, the right is not.
1250fb7d9267SDarrick J. Wong 		 */
125150f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1252fb7d9267SDarrick J. Wong 				PREV.rm_startblock, PREV.rm_blockcount,
1253fb7d9267SDarrick J. Wong 				PREV.rm_owner, PREV.rm_offset,
1254fb7d9267SDarrick J. Wong 				PREV.rm_flags);
1255fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1256fb7d9267SDarrick J. Wong 		if (error)
1257fb7d9267SDarrick J. Wong 			goto done;
1258f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1259f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1260f9e03706SDarrick J. Wong 			goto done;
1261f9e03706SDarrick J. Wong 		}
1262fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1263fb7d9267SDarrick J. Wong 		if (error)
1264fb7d9267SDarrick J. Wong 			goto done;
1265f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1266f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1267f9e03706SDarrick J. Wong 			goto done;
1268f9e03706SDarrick J. Wong 		}
1269fb7d9267SDarrick J. Wong 		NEW = LEFT;
1270fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount;
1271fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1272fb7d9267SDarrick J. Wong 		if (error)
1273fb7d9267SDarrick J. Wong 			goto done;
1274fb7d9267SDarrick J. Wong 		break;
1275fb7d9267SDarrick J. Wong 
1276fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1277fb7d9267SDarrick J. Wong 		/*
1278fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1279fb7d9267SDarrick J. Wong 		 * The right neighbor is contiguous, the left is not.
1280fb7d9267SDarrick J. Wong 		 */
1281fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1282fb7d9267SDarrick J. Wong 		if (error)
1283fb7d9267SDarrick J. Wong 			goto done;
1284f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1285f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1286f9e03706SDarrick J. Wong 			goto done;
1287f9e03706SDarrick J. Wong 		}
128850f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1289fb7d9267SDarrick J. Wong 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
1290fb7d9267SDarrick J. Wong 				RIGHT.rm_owner, RIGHT.rm_offset,
1291fb7d9267SDarrick J. Wong 				RIGHT.rm_flags);
1292fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1293fb7d9267SDarrick J. Wong 		if (error)
1294fb7d9267SDarrick J. Wong 			goto done;
1295f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1296f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1297f9e03706SDarrick J. Wong 			goto done;
1298f9e03706SDarrick J. Wong 		}
1299fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1300fb7d9267SDarrick J. Wong 		if (error)
1301fb7d9267SDarrick J. Wong 			goto done;
1302f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1303f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1304f9e03706SDarrick J. Wong 			goto done;
1305f9e03706SDarrick J. Wong 		}
1306fb7d9267SDarrick J. Wong 		NEW = PREV;
1307fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len + RIGHT.rm_blockcount;
1308fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1309fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1310fb7d9267SDarrick J. Wong 		if (error)
1311fb7d9267SDarrick J. Wong 			goto done;
1312fb7d9267SDarrick J. Wong 		break;
1313fb7d9267SDarrick J. Wong 
1314fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1315fb7d9267SDarrick J. Wong 		/*
1316fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1317fb7d9267SDarrick J. Wong 		 * Neither the left nor right neighbors are contiguous with
1318fb7d9267SDarrick J. Wong 		 * the new one.
1319fb7d9267SDarrick J. Wong 		 */
1320fb7d9267SDarrick J. Wong 		NEW = PREV;
1321fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1322fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1323fb7d9267SDarrick J. Wong 		if (error)
1324fb7d9267SDarrick J. Wong 			goto done;
1325fb7d9267SDarrick J. Wong 		break;
1326fb7d9267SDarrick J. Wong 
1327fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1328fb7d9267SDarrick J. Wong 		/*
1329fb7d9267SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
1330fb7d9267SDarrick J. Wong 		 * The left neighbor is contiguous.
1331fb7d9267SDarrick J. Wong 		 */
1332fb7d9267SDarrick J. Wong 		NEW = PREV;
1333fb7d9267SDarrick J. Wong 		NEW.rm_offset += len;
1334fb7d9267SDarrick J. Wong 		NEW.rm_startblock += len;
1335fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1336fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1337fb7d9267SDarrick J. Wong 		if (error)
1338fb7d9267SDarrick J. Wong 			goto done;
1339fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1340fb7d9267SDarrick J. Wong 		if (error)
1341fb7d9267SDarrick J. Wong 			goto done;
1342fb7d9267SDarrick J. Wong 		NEW = LEFT;
1343fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += len;
1344fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1345fb7d9267SDarrick J. Wong 		if (error)
1346fb7d9267SDarrick J. Wong 			goto done;
1347fb7d9267SDarrick J. Wong 		break;
1348fb7d9267SDarrick J. Wong 
1349fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING:
1350fb7d9267SDarrick J. Wong 		/*
1351fb7d9267SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
1352fb7d9267SDarrick J. Wong 		 * The left neighbor is not contiguous.
1353fb7d9267SDarrick J. Wong 		 */
1354fb7d9267SDarrick J. Wong 		NEW = PREV;
1355fb7d9267SDarrick J. Wong 		NEW.rm_startblock += len;
1356fb7d9267SDarrick J. Wong 		NEW.rm_offset += len;
1357fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1358fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1359fb7d9267SDarrick J. Wong 		if (error)
1360fb7d9267SDarrick J. Wong 			goto done;
1361fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1362fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1363fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1364fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len;
1365fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1366fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
136750f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
1368fb7d9267SDarrick J. Wong 				len, owner, offset, newext);
1369fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1370fb7d9267SDarrick J. Wong 		if (error)
1371fb7d9267SDarrick J. Wong 			goto done;
1372f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1373f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1374f9e03706SDarrick J. Wong 			goto done;
1375f9e03706SDarrick J. Wong 		}
1376fb7d9267SDarrick J. Wong 		break;
1377fb7d9267SDarrick J. Wong 
1378fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1379fb7d9267SDarrick J. Wong 		/*
1380fb7d9267SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
1381fb7d9267SDarrick J. Wong 		 * The right neighbor is contiguous with the new allocation.
1382fb7d9267SDarrick J. Wong 		 */
1383fb7d9267SDarrick J. Wong 		NEW = PREV;
1384fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1385fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1386fb7d9267SDarrick J. Wong 		if (error)
1387fb7d9267SDarrick J. Wong 			goto done;
1388fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1389fb7d9267SDarrick J. Wong 		if (error)
1390fb7d9267SDarrick J. Wong 			goto done;
1391fb7d9267SDarrick J. Wong 		NEW = RIGHT;
1392fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1393fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1394fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += len;
1395fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1396fb7d9267SDarrick J. Wong 		if (error)
1397fb7d9267SDarrick J. Wong 			goto done;
1398fb7d9267SDarrick J. Wong 		break;
1399fb7d9267SDarrick J. Wong 
1400fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING:
1401fb7d9267SDarrick J. Wong 		/*
1402fb7d9267SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
1403fb7d9267SDarrick J. Wong 		 * The right neighbor is not contiguous.
1404fb7d9267SDarrick J. Wong 		 */
1405fb7d9267SDarrick J. Wong 		NEW = PREV;
1406fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1407fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1408fb7d9267SDarrick J. Wong 		if (error)
1409fb7d9267SDarrick J. Wong 			goto done;
1410fb7d9267SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1411fb7d9267SDarrick J. Wong 				oldext, &i);
1412fb7d9267SDarrick J. Wong 		if (error)
1413fb7d9267SDarrick J. Wong 			goto done;
1414f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 0)) {
1415f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1416f9e03706SDarrick J. Wong 			goto done;
1417f9e03706SDarrick J. Wong 		}
1418fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1419fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1420fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1421fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len;
1422fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1423fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
142450f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
1425fb7d9267SDarrick J. Wong 				len, owner, offset, newext);
1426fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1427fb7d9267SDarrick J. Wong 		if (error)
1428fb7d9267SDarrick J. Wong 			goto done;
1429f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1430f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1431f9e03706SDarrick J. Wong 			goto done;
1432f9e03706SDarrick J. Wong 		}
1433fb7d9267SDarrick J. Wong 		break;
1434fb7d9267SDarrick J. Wong 
1435fb7d9267SDarrick J. Wong 	case 0:
1436fb7d9267SDarrick J. Wong 		/*
1437fb7d9267SDarrick J. Wong 		 * Setting the middle part of a previous oldext extent to
1438fb7d9267SDarrick J. Wong 		 * newext.  Contiguity is impossible here.
1439fb7d9267SDarrick J. Wong 		 * One extent becomes three extents.
1440fb7d9267SDarrick J. Wong 		 */
1441fb7d9267SDarrick J. Wong 		/* new right extent - oldext */
1442fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno + len;
1443fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1444fb7d9267SDarrick J. Wong 		NEW.rm_offset = new_endoff;
1445fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1446fb7d9267SDarrick J. Wong 				new_endoff;
1447fb7d9267SDarrick J. Wong 		NEW.rm_flags = PREV.rm_flags;
1448fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1449fb7d9267SDarrick J. Wong 		if (error)
1450fb7d9267SDarrick J. Wong 			goto done;
1451fb7d9267SDarrick J. Wong 		/* new left extent - oldext */
1452fb7d9267SDarrick J. Wong 		NEW = PREV;
1453fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = offset - PREV.rm_offset;
1454fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
145550f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
1456fb7d9267SDarrick J. Wong 				NEW.rm_startblock, NEW.rm_blockcount,
1457fb7d9267SDarrick J. Wong 				NEW.rm_owner, NEW.rm_offset,
1458fb7d9267SDarrick J. Wong 				NEW.rm_flags);
1459fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1460fb7d9267SDarrick J. Wong 		if (error)
1461fb7d9267SDarrick J. Wong 			goto done;
1462f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1463f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1464f9e03706SDarrick J. Wong 			goto done;
1465f9e03706SDarrick J. Wong 		}
1466fb7d9267SDarrick J. Wong 		/*
1467fb7d9267SDarrick J. Wong 		 * Reset the cursor to the position of the new extent
1468fb7d9267SDarrick J. Wong 		 * we are about to insert as we can't trust it after
1469fb7d9267SDarrick J. Wong 		 * the previous insert.
1470fb7d9267SDarrick J. Wong 		 */
1471fb7d9267SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1472fb7d9267SDarrick J. Wong 				oldext, &i);
1473fb7d9267SDarrick J. Wong 		if (error)
1474fb7d9267SDarrick J. Wong 			goto done;
1475f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 0)) {
1476f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1477f9e03706SDarrick J. Wong 			goto done;
1478f9e03706SDarrick J. Wong 		}
1479fb7d9267SDarrick J. Wong 		/* new middle extent - newext */
1480fb7d9267SDarrick J. Wong 		cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
1481fb7d9267SDarrick J. Wong 		cur->bc_rec.r.rm_flags |= newext;
148250f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1483fb7d9267SDarrick J. Wong 				owner, offset, newext);
1484fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1485fb7d9267SDarrick J. Wong 		if (error)
1486fb7d9267SDarrick J. Wong 			goto done;
1487f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1488f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1489f9e03706SDarrick J. Wong 			goto done;
1490f9e03706SDarrick J. Wong 		}
1491fb7d9267SDarrick J. Wong 		break;
1492fb7d9267SDarrick J. Wong 
1493fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1494fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1495fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1496fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1497fb7d9267SDarrick J. Wong 	case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1498fb7d9267SDarrick J. Wong 	case RMAP_LEFT_CONTIG:
1499fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_CONTIG:
1500fb7d9267SDarrick J. Wong 		/*
1501fb7d9267SDarrick J. Wong 		 * These cases are all impossible.
1502fb7d9267SDarrick J. Wong 		 */
1503fb7d9267SDarrick J. Wong 		ASSERT(0);
1504fb7d9267SDarrick J. Wong 	}
1505fb7d9267SDarrick J. Wong 
150650f02fe3SDave Chinner 	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
1507fb7d9267SDarrick J. Wong 			unwritten, oinfo);
1508fb7d9267SDarrick J. Wong done:
1509fb7d9267SDarrick J. Wong 	if (error)
1510fb7d9267SDarrick J. Wong 		trace_xfs_rmap_convert_error(cur->bc_mp,
151150f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
1512fb7d9267SDarrick J. Wong 	return error;
1513fb7d9267SDarrick J. Wong }
1514fb7d9267SDarrick J. Wong 
15153f165b33SDarrick J. Wong /*
15163f165b33SDarrick J. Wong  * Convert an unwritten extent to a real extent or vice versa.  If there is no
15173f165b33SDarrick J. Wong  * possibility of overlapping extents, delegate to the simpler convert
15183f165b33SDarrick J. Wong  * function.
15193f165b33SDarrick J. Wong  */
15203f165b33SDarrick J. Wong STATIC int
15213f165b33SDarrick J. Wong xfs_rmap_convert_shared(
15223f165b33SDarrick J. Wong 	struct xfs_btree_cur		*cur,
15233f165b33SDarrick J. Wong 	xfs_agblock_t			bno,
15243f165b33SDarrick J. Wong 	xfs_extlen_t			len,
15253f165b33SDarrick J. Wong 	bool				unwritten,
152666e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
15273f165b33SDarrick J. Wong {
15283f165b33SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
15293f165b33SDarrick J. Wong 	struct xfs_rmap_irec		r[4];	/* neighbor extent entries */
153066e3237eSDarrick J. Wong 						/* left is 0, right is 1, */
153166e3237eSDarrick J. Wong 						/* prev is 2, new is 3 */
15323f165b33SDarrick J. Wong 	uint64_t		owner;
15333f165b33SDarrick J. Wong 	uint64_t		offset;
15343f165b33SDarrick J. Wong 	uint64_t		new_endoff;
15353f165b33SDarrick J. Wong 	unsigned int		oldext;
15363f165b33SDarrick J. Wong 	unsigned int		newext;
15373f165b33SDarrick J. Wong 	unsigned int		flags = 0;
15383f165b33SDarrick J. Wong 	int			i;
15393f165b33SDarrick J. Wong 	int			state = 0;
15403f165b33SDarrick J. Wong 	int			error;
15413f165b33SDarrick J. Wong 
15423f165b33SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
15433f165b33SDarrick J. Wong 	ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
15443f165b33SDarrick J. Wong 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
15453f165b33SDarrick J. Wong 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
15463f165b33SDarrick J. Wong 	new_endoff = offset + len;
154750f02fe3SDave Chinner 	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
15483f165b33SDarrick J. Wong 			unwritten, oinfo);
15493f165b33SDarrick J. Wong 
15503f165b33SDarrick J. Wong 	/*
15513f165b33SDarrick J. Wong 	 * For the initial lookup, look for and exact match or the left-adjacent
15523f165b33SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
15533f165b33SDarrick J. Wong 	 * start block contiguity tests.
15543f165b33SDarrick J. Wong 	 */
1555ea843989SDarrick J. Wong 	error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, oldext,
15563f165b33SDarrick J. Wong 			&PREV, &i);
155752101dfeSDarrick J. Wong 	if (error)
155852101dfeSDarrick J. Wong 		goto done;
1559f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1560f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1561f9e03706SDarrick J. Wong 		goto done;
1562f9e03706SDarrick J. Wong 	}
15633f165b33SDarrick J. Wong 
15643f165b33SDarrick J. Wong 	ASSERT(PREV.rm_offset <= offset);
15653f165b33SDarrick J. Wong 	ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
15663f165b33SDarrick J. Wong 	ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
15673f165b33SDarrick J. Wong 	newext = ~oldext & XFS_RMAP_UNWRITTEN;
15683f165b33SDarrick J. Wong 
15693f165b33SDarrick J. Wong 	/*
15703f165b33SDarrick J. Wong 	 * Set flags determining what part of the previous oldext allocation
15713f165b33SDarrick J. Wong 	 * extent is being replaced by a newext allocation.
15723f165b33SDarrick J. Wong 	 */
15733f165b33SDarrick J. Wong 	if (PREV.rm_offset == offset)
15743f165b33SDarrick J. Wong 		state |= RMAP_LEFT_FILLING;
15753f165b33SDarrick J. Wong 	if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
15763f165b33SDarrick J. Wong 		state |= RMAP_RIGHT_FILLING;
15773f165b33SDarrick J. Wong 
15783f165b33SDarrick J. Wong 	/* Is there a left record that abuts our range? */
15793f165b33SDarrick J. Wong 	error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext,
15803f165b33SDarrick J. Wong 			&LEFT, &i);
15813f165b33SDarrick J. Wong 	if (error)
15823f165b33SDarrick J. Wong 		goto done;
15833f165b33SDarrick J. Wong 	if (i) {
15843f165b33SDarrick J. Wong 		state |= RMAP_LEFT_VALID;
1585f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
1586f9e03706SDarrick J. Wong 				   LEFT.rm_startblock + LEFT.rm_blockcount >
1587f9e03706SDarrick J. Wong 				   bno)) {
1588f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1589f9e03706SDarrick J. Wong 			goto done;
1590f9e03706SDarrick J. Wong 		}
15913f165b33SDarrick J. Wong 		if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
15923f165b33SDarrick J. Wong 			state |= RMAP_LEFT_CONTIG;
15933f165b33SDarrick J. Wong 	}
15943f165b33SDarrick J. Wong 
15953f165b33SDarrick J. Wong 	/* Is there a right record that abuts our range? */
15963f165b33SDarrick J. Wong 	error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
15973f165b33SDarrick J. Wong 			newext, &i);
15983f165b33SDarrick J. Wong 	if (error)
15993f165b33SDarrick J. Wong 		goto done;
16003f165b33SDarrick J. Wong 	if (i) {
16013f165b33SDarrick J. Wong 		state |= RMAP_RIGHT_VALID;
16023f165b33SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &RIGHT, &i);
16033f165b33SDarrick J. Wong 		if (error)
16043f165b33SDarrick J. Wong 			goto done;
1605f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1606f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1607f9e03706SDarrick J. Wong 			goto done;
1608f9e03706SDarrick J. Wong 		}
1609f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1610f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1611f9e03706SDarrick J. Wong 			goto done;
1612f9e03706SDarrick J. Wong 		}
16133f165b33SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
161450f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
16153f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
16163f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
16173f165b33SDarrick J. Wong 		if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
16183f165b33SDarrick J. Wong 			state |= RMAP_RIGHT_CONTIG;
16193f165b33SDarrick J. Wong 	}
16203f165b33SDarrick J. Wong 
16213f165b33SDarrick J. Wong 	/* check that left + prev + right is not too long */
16223f165b33SDarrick J. Wong 	if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16233f165b33SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
16243f165b33SDarrick J. Wong 	    (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16253f165b33SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
16263f165b33SDarrick J. Wong 	    (unsigned long)LEFT.rm_blockcount + len +
16273f165b33SDarrick J. Wong 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
16283f165b33SDarrick J. Wong 		state &= ~RMAP_RIGHT_CONTIG;
16293f165b33SDarrick J. Wong 
163050f02fe3SDave Chinner 	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
16313f165b33SDarrick J. Wong 			_RET_IP_);
16323f165b33SDarrick J. Wong 	/*
16333f165b33SDarrick J. Wong 	 * Switch out based on the FILLING and CONTIG state bits.
16343f165b33SDarrick J. Wong 	 */
16353f165b33SDarrick J. Wong 	switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16363f165b33SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
16373f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16383f165b33SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
16393f165b33SDarrick J. Wong 		/*
16403f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16413f165b33SDarrick J. Wong 		 * The left and right neighbors are both contiguous with new.
16423f165b33SDarrick J. Wong 		 */
16433f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
16443f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
16453f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
16463f165b33SDarrick J. Wong 		if (error)
16473f165b33SDarrick J. Wong 			goto done;
16483f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, PREV.rm_startblock,
16493f165b33SDarrick J. Wong 				PREV.rm_blockcount, PREV.rm_owner,
16503f165b33SDarrick J. Wong 				PREV.rm_offset, PREV.rm_flags);
16513f165b33SDarrick J. Wong 		if (error)
16523f165b33SDarrick J. Wong 			goto done;
16533f165b33SDarrick J. Wong 		NEW = LEFT;
16543f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
16553f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
16563f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
16573f165b33SDarrick J. Wong 		if (error)
16583f165b33SDarrick J. Wong 			goto done;
1659f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1660f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1661f9e03706SDarrick J. Wong 			goto done;
1662f9e03706SDarrick J. Wong 		}
16633f165b33SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
16643f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
16653f165b33SDarrick J. Wong 		if (error)
16663f165b33SDarrick J. Wong 			goto done;
16673f165b33SDarrick J. Wong 		break;
16683f165b33SDarrick J. Wong 
16693f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
16703f165b33SDarrick J. Wong 		/*
16713f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16723f165b33SDarrick J. Wong 		 * The left neighbor is contiguous, the right is not.
16733f165b33SDarrick J. Wong 		 */
16743f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, PREV.rm_startblock,
16753f165b33SDarrick J. Wong 				PREV.rm_blockcount, PREV.rm_owner,
16763f165b33SDarrick J. Wong 				PREV.rm_offset, PREV.rm_flags);
16773f165b33SDarrick J. Wong 		if (error)
16783f165b33SDarrick J. Wong 			goto done;
16793f165b33SDarrick J. Wong 		NEW = LEFT;
16803f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
16813f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
16823f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
16833f165b33SDarrick J. Wong 		if (error)
16843f165b33SDarrick J. Wong 			goto done;
1685f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1686f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1687f9e03706SDarrick J. Wong 			goto done;
1688f9e03706SDarrick J. Wong 		}
16893f165b33SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount;
16903f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
16913f165b33SDarrick J. Wong 		if (error)
16923f165b33SDarrick J. Wong 			goto done;
16933f165b33SDarrick J. Wong 		break;
16943f165b33SDarrick J. Wong 
16953f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
16963f165b33SDarrick J. Wong 		/*
16973f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16983f165b33SDarrick J. Wong 		 * The right neighbor is contiguous, the left is not.
16993f165b33SDarrick J. Wong 		 */
17003f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
17013f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
17023f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
17033f165b33SDarrick J. Wong 		if (error)
17043f165b33SDarrick J. Wong 			goto done;
17053f165b33SDarrick J. Wong 		NEW = PREV;
17063f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17073f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17083f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17093f165b33SDarrick J. Wong 		if (error)
17103f165b33SDarrick J. Wong 			goto done;
1711f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1712f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1713f9e03706SDarrick J. Wong 			goto done;
1714f9e03706SDarrick J. Wong 		}
17153f165b33SDarrick J. Wong 		NEW.rm_blockcount += RIGHT.rm_blockcount;
17163f165b33SDarrick J. Wong 		NEW.rm_flags = RIGHT.rm_flags;
17173f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17183f165b33SDarrick J. Wong 		if (error)
17193f165b33SDarrick J. Wong 			goto done;
17203f165b33SDarrick J. Wong 		break;
17213f165b33SDarrick J. Wong 
17223f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
17233f165b33SDarrick J. Wong 		/*
17243f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
17253f165b33SDarrick J. Wong 		 * Neither the left nor right neighbors are contiguous with
17263f165b33SDarrick J. Wong 		 * the new one.
17273f165b33SDarrick J. Wong 		 */
17283f165b33SDarrick J. Wong 		NEW = PREV;
17293f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17303f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17313f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17323f165b33SDarrick J. Wong 		if (error)
17333f165b33SDarrick J. Wong 			goto done;
1734f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1735f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1736f9e03706SDarrick J. Wong 			goto done;
1737f9e03706SDarrick J. Wong 		}
17383f165b33SDarrick J. Wong 		NEW.rm_flags = newext;
17393f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17403f165b33SDarrick J. Wong 		if (error)
17413f165b33SDarrick J. Wong 			goto done;
17423f165b33SDarrick J. Wong 		break;
17433f165b33SDarrick J. Wong 
17443f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
17453f165b33SDarrick J. Wong 		/*
17463f165b33SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
17473f165b33SDarrick J. Wong 		 * The left neighbor is contiguous.
17483f165b33SDarrick J. Wong 		 */
17493f165b33SDarrick J. Wong 		NEW = PREV;
17503f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
17513f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17523f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17533f165b33SDarrick J. Wong 		if (error)
17543f165b33SDarrick J. Wong 			goto done;
17553f165b33SDarrick J. Wong 		NEW.rm_offset += len;
17563f165b33SDarrick J. Wong 		NEW.rm_startblock += len;
17573f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
17583f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
17593f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17603f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17613f165b33SDarrick J. Wong 		if (error)
17623f165b33SDarrick J. Wong 			goto done;
17633f165b33SDarrick J. Wong 		NEW = LEFT;
17643f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17653f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17663f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17673f165b33SDarrick J. Wong 		if (error)
17683f165b33SDarrick J. Wong 			goto done;
1769f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1770f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1771f9e03706SDarrick J. Wong 			goto done;
1772f9e03706SDarrick J. Wong 		}
17733f165b33SDarrick J. Wong 		NEW.rm_blockcount += len;
17743f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17753f165b33SDarrick J. Wong 		if (error)
17763f165b33SDarrick J. Wong 			goto done;
17773f165b33SDarrick J. Wong 		break;
17783f165b33SDarrick J. Wong 
17793f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING:
17803f165b33SDarrick J. Wong 		/*
17813f165b33SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
17823f165b33SDarrick J. Wong 		 * The left neighbor is not contiguous.
17833f165b33SDarrick J. Wong 		 */
17843f165b33SDarrick J. Wong 		NEW = PREV;
17853f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
17863f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17873f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17883f165b33SDarrick J. Wong 		if (error)
17893f165b33SDarrick J. Wong 			goto done;
17903f165b33SDarrick J. Wong 		NEW.rm_offset += len;
17913f165b33SDarrick J. Wong 		NEW.rm_startblock += len;
17923f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
17933f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
17943f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17953f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17963f165b33SDarrick J. Wong 		if (error)
17973f165b33SDarrick J. Wong 			goto done;
17983f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
17993f165b33SDarrick J. Wong 		if (error)
18003f165b33SDarrick J. Wong 			goto done;
18013f165b33SDarrick J. Wong 		break;
18023f165b33SDarrick J. Wong 
18033f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
18043f165b33SDarrick J. Wong 		/*
18053f165b33SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
18063f165b33SDarrick J. Wong 		 * The right neighbor is contiguous with the new allocation.
18073f165b33SDarrick J. Wong 		 */
18083f165b33SDarrick J. Wong 		NEW = PREV;
18093f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18103f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18113f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18123f165b33SDarrick J. Wong 		if (error)
18133f165b33SDarrick J. Wong 			goto done;
1814f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1815f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1816f9e03706SDarrick J. Wong 			goto done;
1817f9e03706SDarrick J. Wong 		}
18183f165b33SDarrick J. Wong 		NEW.rm_blockcount = offset - NEW.rm_offset;
18193f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18203f165b33SDarrick J. Wong 		if (error)
18213f165b33SDarrick J. Wong 			goto done;
18223f165b33SDarrick J. Wong 		NEW = RIGHT;
18233f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
18243f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18253f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18263f165b33SDarrick J. Wong 		if (error)
18273f165b33SDarrick J. Wong 			goto done;
18283f165b33SDarrick J. Wong 		NEW.rm_offset = offset;
18293f165b33SDarrick J. Wong 		NEW.rm_startblock = bno;
18303f165b33SDarrick J. Wong 		NEW.rm_blockcount += len;
18313f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18323f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18333f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18343f165b33SDarrick J. Wong 		if (error)
18353f165b33SDarrick J. Wong 			goto done;
18363f165b33SDarrick J. Wong 		break;
18373f165b33SDarrick J. Wong 
18383f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING:
18393f165b33SDarrick J. Wong 		/*
18403f165b33SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
18413f165b33SDarrick J. Wong 		 * The right neighbor is not contiguous.
18423f165b33SDarrick J. Wong 		 */
18433f165b33SDarrick J. Wong 		NEW = PREV;
18443f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18453f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18463f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18473f165b33SDarrick J. Wong 		if (error)
18483f165b33SDarrick J. Wong 			goto done;
1849f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1850f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1851f9e03706SDarrick J. Wong 			goto done;
1852f9e03706SDarrick J. Wong 		}
18533f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
18543f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18553f165b33SDarrick J. Wong 		if (error)
18563f165b33SDarrick J. Wong 			goto done;
18573f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
18583f165b33SDarrick J. Wong 		if (error)
18593f165b33SDarrick J. Wong 			goto done;
18603f165b33SDarrick J. Wong 		break;
18613f165b33SDarrick J. Wong 
18623f165b33SDarrick J. Wong 	case 0:
18633f165b33SDarrick J. Wong 		/*
18643f165b33SDarrick J. Wong 		 * Setting the middle part of a previous oldext extent to
18653f165b33SDarrick J. Wong 		 * newext.  Contiguity is impossible here.
18663f165b33SDarrick J. Wong 		 * One extent becomes three extents.
18673f165b33SDarrick J. Wong 		 */
18683f165b33SDarrick J. Wong 		/* new right extent - oldext */
18693f165b33SDarrick J. Wong 		NEW.rm_startblock = bno + len;
18703f165b33SDarrick J. Wong 		NEW.rm_owner = owner;
18713f165b33SDarrick J. Wong 		NEW.rm_offset = new_endoff;
18723f165b33SDarrick J. Wong 		NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
18733f165b33SDarrick J. Wong 				new_endoff;
18743f165b33SDarrick J. Wong 		NEW.rm_flags = PREV.rm_flags;
18753f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18763f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
18773f165b33SDarrick J. Wong 				NEW.rm_flags);
18783f165b33SDarrick J. Wong 		if (error)
18793f165b33SDarrick J. Wong 			goto done;
18803f165b33SDarrick J. Wong 		/* new left extent - oldext */
18813f165b33SDarrick J. Wong 		NEW = PREV;
18823f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18833f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18843f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18853f165b33SDarrick J. Wong 		if (error)
18863f165b33SDarrick J. Wong 			goto done;
1887f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1888f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1889f9e03706SDarrick J. Wong 			goto done;
1890f9e03706SDarrick J. Wong 		}
18913f165b33SDarrick J. Wong 		NEW.rm_blockcount = offset - NEW.rm_offset;
18923f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18933f165b33SDarrick J. Wong 		if (error)
18943f165b33SDarrick J. Wong 			goto done;
18953f165b33SDarrick J. Wong 		/* new middle extent - newext */
18963f165b33SDarrick J. Wong 		NEW.rm_startblock = bno;
18973f165b33SDarrick J. Wong 		NEW.rm_blockcount = len;
18983f165b33SDarrick J. Wong 		NEW.rm_owner = owner;
18993f165b33SDarrick J. Wong 		NEW.rm_offset = offset;
19003f165b33SDarrick J. Wong 		NEW.rm_flags = newext;
19013f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
19023f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
19033f165b33SDarrick J. Wong 				NEW.rm_flags);
19043f165b33SDarrick J. Wong 		if (error)
19053f165b33SDarrick J. Wong 			goto done;
19063f165b33SDarrick J. Wong 		break;
19073f165b33SDarrick J. Wong 
19083f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
19093f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
19103f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
19113f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
19123f165b33SDarrick J. Wong 	case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
19133f165b33SDarrick J. Wong 	case RMAP_LEFT_CONTIG:
19143f165b33SDarrick J. Wong 	case RMAP_RIGHT_CONTIG:
19153f165b33SDarrick J. Wong 		/*
19163f165b33SDarrick J. Wong 		 * These cases are all impossible.
19173f165b33SDarrick J. Wong 		 */
19183f165b33SDarrick J. Wong 		ASSERT(0);
19193f165b33SDarrick J. Wong 	}
19203f165b33SDarrick J. Wong 
192150f02fe3SDave Chinner 	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
19223f165b33SDarrick J. Wong 			unwritten, oinfo);
19233f165b33SDarrick J. Wong done:
19243f165b33SDarrick J. Wong 	if (error)
19253f165b33SDarrick J. Wong 		trace_xfs_rmap_convert_error(cur->bc_mp,
192650f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
19273f165b33SDarrick J. Wong 	return error;
19283f165b33SDarrick J. Wong }
19293f165b33SDarrick J. Wong 
1930fb7d9267SDarrick J. Wong #undef	NEW
1931fb7d9267SDarrick J. Wong #undef	LEFT
1932fb7d9267SDarrick J. Wong #undef	RIGHT
1933fb7d9267SDarrick J. Wong #undef	PREV
1934fb7d9267SDarrick J. Wong 
1935ceeb9c83SDarrick J. Wong /*
1936ceeb9c83SDarrick J. Wong  * Find an extent in the rmap btree and unmap it.  For rmap extent types that
1937ceeb9c83SDarrick J. Wong  * can overlap (data fork rmaps on reflink filesystems) we must be careful
1938ceeb9c83SDarrick J. Wong  * that the prev/next records in the btree might belong to another owner.
1939ceeb9c83SDarrick J. Wong  * Therefore we must use delete+insert to alter any of the key fields.
1940ceeb9c83SDarrick J. Wong  *
1941ceeb9c83SDarrick J. Wong  * For every other situation there can only be one owner for a given extent,
1942ceeb9c83SDarrick J. Wong  * so we can call the regular _free function.
1943ceeb9c83SDarrick J. Wong  */
1944ceeb9c83SDarrick J. Wong STATIC int
1945ceeb9c83SDarrick J. Wong xfs_rmap_unmap_shared(
1946ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
1947ceeb9c83SDarrick J. Wong 	xfs_agblock_t			bno,
1948ceeb9c83SDarrick J. Wong 	xfs_extlen_t			len,
1949ceeb9c83SDarrick J. Wong 	bool				unwritten,
195066e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
1951ceeb9c83SDarrick J. Wong {
1952ceeb9c83SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
1953ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
1954ceeb9c83SDarrick J. Wong 	uint64_t			ltoff;
1955ceeb9c83SDarrick J. Wong 	int				error = 0;
1956ceeb9c83SDarrick J. Wong 	int				i;
1957ceeb9c83SDarrick J. Wong 	uint64_t			owner;
1958ceeb9c83SDarrick J. Wong 	uint64_t			offset;
1959ceeb9c83SDarrick J. Wong 	unsigned int			flags;
1960ceeb9c83SDarrick J. Wong 
1961ceeb9c83SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1962ceeb9c83SDarrick J. Wong 	if (unwritten)
1963ceeb9c83SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
196450f02fe3SDave Chinner 	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
1965ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
1966ceeb9c83SDarrick J. Wong 
1967ceeb9c83SDarrick J. Wong 	/*
1968ceeb9c83SDarrick J. Wong 	 * We should always have a left record because there's a static record
1969ceeb9c83SDarrick J. Wong 	 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
1970ceeb9c83SDarrick J. Wong 	 * will not ever be removed from the tree.
1971ceeb9c83SDarrick J. Wong 	 */
1972ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
1973ceeb9c83SDarrick J. Wong 			&ltrec, &i);
1974ceeb9c83SDarrick J. Wong 	if (error)
1975ceeb9c83SDarrick J. Wong 		goto out_error;
1976f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1977f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1978f9e03706SDarrick J. Wong 		goto out_error;
1979f9e03706SDarrick J. Wong 	}
1980ceeb9c83SDarrick J. Wong 	ltoff = ltrec.rm_offset;
1981ceeb9c83SDarrick J. Wong 
1982ceeb9c83SDarrick J. Wong 	/* Make sure the extent we found covers the entire freeing range. */
1983f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
1984f9e03706SDarrick J. Wong 			   ltrec.rm_startblock > bno ||
1985f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount <
1986f9e03706SDarrick J. Wong 			   bno + len)) {
1987f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1988f9e03706SDarrick J. Wong 		goto out_error;
1989f9e03706SDarrick J. Wong 	}
1990ceeb9c83SDarrick J. Wong 
1991ceeb9c83SDarrick J. Wong 	/* Make sure the owner matches what we expect to find in the tree. */
1992f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
1993f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1994f9e03706SDarrick J. Wong 		goto out_error;
1995f9e03706SDarrick J. Wong 	}
1996ceeb9c83SDarrick J. Wong 
1997ceeb9c83SDarrick J. Wong 	/* Make sure the unwritten flag matches. */
1998f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
1999f9e03706SDarrick J. Wong 			   (flags & XFS_RMAP_UNWRITTEN) !=
2000f9e03706SDarrick J. Wong 			   (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
2001f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2002f9e03706SDarrick J. Wong 		goto out_error;
2003f9e03706SDarrick J. Wong 	}
2004ceeb9c83SDarrick J. Wong 
2005ceeb9c83SDarrick J. Wong 	/* Check the offset. */
2006f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
2007f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2008f9e03706SDarrick J. Wong 		goto out_error;
2009f9e03706SDarrick J. Wong 	}
2010f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
2011f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2012f9e03706SDarrick J. Wong 		goto out_error;
2013f9e03706SDarrick J. Wong 	}
2014ceeb9c83SDarrick J. Wong 
2015ceeb9c83SDarrick J. Wong 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
2016ceeb9c83SDarrick J. Wong 		/* Exact match, simply remove the record from rmap tree. */
2017ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2018ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2019ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2020ceeb9c83SDarrick J. Wong 		if (error)
2021ceeb9c83SDarrick J. Wong 			goto out_error;
2022ceeb9c83SDarrick J. Wong 	} else if (ltrec.rm_startblock == bno) {
2023ceeb9c83SDarrick J. Wong 		/*
2024ceeb9c83SDarrick J. Wong 		 * Overlap left hand side of extent: move the start, trim the
2025ceeb9c83SDarrick J. Wong 		 * length and update the current record.
2026ceeb9c83SDarrick J. Wong 		 *
2027ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2028ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2029ceeb9c83SDarrick J. Wong 		 * Freeing: |fffffffff|
2030ceeb9c83SDarrick J. Wong 		 * Result:            |rrrrrrrrrr|
2031ceeb9c83SDarrick J. Wong 		 *         bno       len
2032ceeb9c83SDarrick J. Wong 		 */
2033ceeb9c83SDarrick J. Wong 
2034ceeb9c83SDarrick J. Wong 		/* Delete prev rmap. */
2035ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2036ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2037ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2038ceeb9c83SDarrick J. Wong 		if (error)
2039ceeb9c83SDarrick J. Wong 			goto out_error;
2040ceeb9c83SDarrick J. Wong 
2041ceeb9c83SDarrick J. Wong 		/* Add an rmap at the new offset. */
2042ceeb9c83SDarrick J. Wong 		ltrec.rm_startblock += len;
2043ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount -= len;
2044ceeb9c83SDarrick J. Wong 		ltrec.rm_offset += len;
2045ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, ltrec.rm_startblock,
2046ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2047ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2048ceeb9c83SDarrick J. Wong 		if (error)
2049ceeb9c83SDarrick J. Wong 			goto out_error;
2050ceeb9c83SDarrick J. Wong 	} else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
2051ceeb9c83SDarrick J. Wong 		/*
2052ceeb9c83SDarrick J. Wong 		 * Overlap right hand side of extent: trim the length and
2053ceeb9c83SDarrick J. Wong 		 * update the current record.
2054ceeb9c83SDarrick J. Wong 		 *
2055ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2056ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2057ceeb9c83SDarrick J. Wong 		 * Freeing:            |fffffffff|
2058ceeb9c83SDarrick J. Wong 		 * Result:  |rrrrrrrrrr|
2059ceeb9c83SDarrick J. Wong 		 *                    bno       len
2060ceeb9c83SDarrick J. Wong 		 */
2061ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2062ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2063ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2064ceeb9c83SDarrick J. Wong 		if (error)
2065ceeb9c83SDarrick J. Wong 			goto out_error;
2066f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2067f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2068f9e03706SDarrick J. Wong 			goto out_error;
2069f9e03706SDarrick J. Wong 		}
2070ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount -= len;
2071ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2072ceeb9c83SDarrick J. Wong 		if (error)
2073ceeb9c83SDarrick J. Wong 			goto out_error;
2074ceeb9c83SDarrick J. Wong 	} else {
2075ceeb9c83SDarrick J. Wong 		/*
2076ceeb9c83SDarrick J. Wong 		 * Overlap middle of extent: trim the length of the existing
2077ceeb9c83SDarrick J. Wong 		 * record to the length of the new left-extent size, increment
2078ceeb9c83SDarrick J. Wong 		 * the insertion position so we can insert a new record
2079ceeb9c83SDarrick J. Wong 		 * containing the remaining right-extent space.
2080ceeb9c83SDarrick J. Wong 		 *
2081ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2082ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2083ceeb9c83SDarrick J. Wong 		 * Freeing:       |fffffffff|
2084ceeb9c83SDarrick J. Wong 		 * Result:  |rrrrr|         |rrrr|
2085ceeb9c83SDarrick J. Wong 		 *               bno       len
2086ceeb9c83SDarrick J. Wong 		 */
2087ceeb9c83SDarrick J. Wong 		xfs_extlen_t	orig_len = ltrec.rm_blockcount;
2088ceeb9c83SDarrick J. Wong 
2089ceeb9c83SDarrick J. Wong 		/* Shrink the left side of the rmap */
2090ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2091ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2092ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2093ceeb9c83SDarrick J. Wong 		if (error)
2094ceeb9c83SDarrick J. Wong 			goto out_error;
2095f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2096f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2097f9e03706SDarrick J. Wong 			goto out_error;
2098f9e03706SDarrick J. Wong 		}
2099ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount = bno - ltrec.rm_startblock;
2100ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2101ceeb9c83SDarrick J. Wong 		if (error)
2102ceeb9c83SDarrick J. Wong 			goto out_error;
2103ceeb9c83SDarrick J. Wong 
2104ceeb9c83SDarrick J. Wong 		/* Add an rmap at the new offset */
2105ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno + len,
2106ceeb9c83SDarrick J. Wong 				orig_len - len - ltrec.rm_blockcount,
2107ceeb9c83SDarrick J. Wong 				ltrec.rm_owner, offset + len,
2108ceeb9c83SDarrick J. Wong 				ltrec.rm_flags);
2109ceeb9c83SDarrick J. Wong 		if (error)
2110ceeb9c83SDarrick J. Wong 			goto out_error;
2111ceeb9c83SDarrick J. Wong 	}
2112ceeb9c83SDarrick J. Wong 
211350f02fe3SDave Chinner 	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
2114ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2115ceeb9c83SDarrick J. Wong out_error:
2116ceeb9c83SDarrick J. Wong 	if (error)
2117ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_unmap_error(cur->bc_mp,
211850f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
2119ceeb9c83SDarrick J. Wong 	return error;
2120ceeb9c83SDarrick J. Wong }
2121ceeb9c83SDarrick J. Wong 
2122ceeb9c83SDarrick J. Wong /*
2123ceeb9c83SDarrick J. Wong  * Find an extent in the rmap btree and map it.  For rmap extent types that
2124ceeb9c83SDarrick J. Wong  * can overlap (data fork rmaps on reflink filesystems) we must be careful
2125ceeb9c83SDarrick J. Wong  * that the prev/next records in the btree might belong to another owner.
2126ceeb9c83SDarrick J. Wong  * Therefore we must use delete+insert to alter any of the key fields.
2127ceeb9c83SDarrick J. Wong  *
2128ceeb9c83SDarrick J. Wong  * For every other situation there can only be one owner for a given extent,
2129ceeb9c83SDarrick J. Wong  * so we can call the regular _alloc function.
2130ceeb9c83SDarrick J. Wong  */
2131ceeb9c83SDarrick J. Wong STATIC int
2132ceeb9c83SDarrick J. Wong xfs_rmap_map_shared(
2133ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2134ceeb9c83SDarrick J. Wong 	xfs_agblock_t			bno,
2135ceeb9c83SDarrick J. Wong 	xfs_extlen_t			len,
2136ceeb9c83SDarrick J. Wong 	bool				unwritten,
213766e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
2138ceeb9c83SDarrick J. Wong {
2139ceeb9c83SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
2140ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
2141ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		gtrec;
2142ceeb9c83SDarrick J. Wong 	int				have_gt;
2143ceeb9c83SDarrick J. Wong 	int				have_lt;
2144ceeb9c83SDarrick J. Wong 	int				error = 0;
2145ceeb9c83SDarrick J. Wong 	int				i;
2146ceeb9c83SDarrick J. Wong 	uint64_t			owner;
2147ceeb9c83SDarrick J. Wong 	uint64_t			offset;
2148ceeb9c83SDarrick J. Wong 	unsigned int			flags = 0;
2149ceeb9c83SDarrick J. Wong 
2150ceeb9c83SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2151ceeb9c83SDarrick J. Wong 	if (unwritten)
2152ceeb9c83SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
215350f02fe3SDave Chinner 	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
2154ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2155ceeb9c83SDarrick J. Wong 
2156ceeb9c83SDarrick J. Wong 	/* Is there a left record that abuts our range? */
2157ceeb9c83SDarrick J. Wong 	error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
2158ceeb9c83SDarrick J. Wong 			&ltrec, &have_lt);
2159ceeb9c83SDarrick J. Wong 	if (error)
2160ceeb9c83SDarrick J. Wong 		goto out_error;
2161ceeb9c83SDarrick J. Wong 	if (have_lt &&
2162ceeb9c83SDarrick J. Wong 	    !xfs_rmap_is_mergeable(&ltrec, owner, flags))
2163ceeb9c83SDarrick J. Wong 		have_lt = 0;
2164ceeb9c83SDarrick J. Wong 
2165ceeb9c83SDarrick J. Wong 	/* Is there a right record that abuts our range? */
2166ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
2167ceeb9c83SDarrick J. Wong 			flags, &have_gt);
2168ceeb9c83SDarrick J. Wong 	if (error)
2169ceeb9c83SDarrick J. Wong 		goto out_error;
2170ceeb9c83SDarrick J. Wong 	if (have_gt) {
2171ceeb9c83SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
2172ceeb9c83SDarrick J. Wong 		if (error)
2173ceeb9c83SDarrick J. Wong 			goto out_error;
2174f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
2175f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2176f9e03706SDarrick J. Wong 			goto out_error;
2177f9e03706SDarrick J. Wong 		}
2178ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
217950f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
2180ceeb9c83SDarrick J. Wong 			gtrec.rm_blockcount, gtrec.rm_owner,
2181ceeb9c83SDarrick J. Wong 			gtrec.rm_offset, gtrec.rm_flags);
2182ceeb9c83SDarrick J. Wong 
2183ceeb9c83SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
2184ceeb9c83SDarrick J. Wong 			have_gt = 0;
2185ceeb9c83SDarrick J. Wong 	}
2186ceeb9c83SDarrick J. Wong 
2187ceeb9c83SDarrick J. Wong 	if (have_lt &&
2188ceeb9c83SDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
2189ceeb9c83SDarrick J. Wong 	    ltrec.rm_offset + ltrec.rm_blockcount == offset) {
2190ceeb9c83SDarrick J. Wong 		/*
2191ceeb9c83SDarrick J. Wong 		 * Left edge contiguous, merge into left record.
2192ceeb9c83SDarrick J. Wong 		 *
2193ceeb9c83SDarrick J. Wong 		 *       ltbno     ltlen
2194ceeb9c83SDarrick J. Wong 		 * orig:   |ooooooooo|
2195ceeb9c83SDarrick J. Wong 		 * adding:           |aaaaaaaaa|
2196ceeb9c83SDarrick J. Wong 		 * result: |rrrrrrrrrrrrrrrrrrr|
2197ceeb9c83SDarrick J. Wong 		 *                  bno       len
2198ceeb9c83SDarrick J. Wong 		 */
2199ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount += len;
2200ceeb9c83SDarrick J. Wong 		if (have_gt &&
2201ceeb9c83SDarrick J. Wong 		    bno + len == gtrec.rm_startblock &&
2202ceeb9c83SDarrick J. Wong 		    offset + len == gtrec.rm_offset) {
2203ceeb9c83SDarrick J. Wong 			/*
2204ceeb9c83SDarrick J. Wong 			 * Right edge also contiguous, delete right record
2205ceeb9c83SDarrick J. Wong 			 * and merge into left record.
2206ceeb9c83SDarrick J. Wong 			 *
2207ceeb9c83SDarrick J. Wong 			 *       ltbno     ltlen    gtbno     gtlen
2208ceeb9c83SDarrick J. Wong 			 * orig:   |ooooooooo|         |ooooooooo|
2209ceeb9c83SDarrick J. Wong 			 * adding:           |aaaaaaaaa|
2210ceeb9c83SDarrick J. Wong 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
2211ceeb9c83SDarrick J. Wong 			 */
2212ceeb9c83SDarrick J. Wong 			ltrec.rm_blockcount += gtrec.rm_blockcount;
2213ceeb9c83SDarrick J. Wong 			error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2214ceeb9c83SDarrick J. Wong 					gtrec.rm_blockcount, gtrec.rm_owner,
2215ceeb9c83SDarrick J. Wong 					gtrec.rm_offset, gtrec.rm_flags);
2216ceeb9c83SDarrick J. Wong 			if (error)
2217ceeb9c83SDarrick J. Wong 				goto out_error;
2218ceeb9c83SDarrick J. Wong 		}
2219ceeb9c83SDarrick J. Wong 
2220ceeb9c83SDarrick J. Wong 		/* Point the cursor back to the left record and update. */
2221ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2222ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2223ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2224ceeb9c83SDarrick J. Wong 		if (error)
2225ceeb9c83SDarrick J. Wong 			goto out_error;
2226f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2227f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2228f9e03706SDarrick J. Wong 			goto out_error;
2229f9e03706SDarrick J. Wong 		}
2230ceeb9c83SDarrick J. Wong 
2231ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2232ceeb9c83SDarrick J. Wong 		if (error)
2233ceeb9c83SDarrick J. Wong 			goto out_error;
2234ceeb9c83SDarrick J. Wong 	} else if (have_gt &&
2235ceeb9c83SDarrick J. Wong 		   bno + len == gtrec.rm_startblock &&
2236ceeb9c83SDarrick J. Wong 		   offset + len == gtrec.rm_offset) {
2237ceeb9c83SDarrick J. Wong 		/*
2238ceeb9c83SDarrick J. Wong 		 * Right edge contiguous, merge into right record.
2239ceeb9c83SDarrick J. Wong 		 *
2240ceeb9c83SDarrick J. Wong 		 *                 gtbno     gtlen
2241ceeb9c83SDarrick J. Wong 		 * Orig:             |ooooooooo|
2242ceeb9c83SDarrick J. Wong 		 * adding: |aaaaaaaaa|
2243ceeb9c83SDarrick J. Wong 		 * Result: |rrrrrrrrrrrrrrrrrrr|
2244ceeb9c83SDarrick J. Wong 		 *        bno       len
2245ceeb9c83SDarrick J. Wong 		 */
2246ceeb9c83SDarrick J. Wong 		/* Delete the old record. */
2247ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2248ceeb9c83SDarrick J. Wong 				gtrec.rm_blockcount, gtrec.rm_owner,
2249ceeb9c83SDarrick J. Wong 				gtrec.rm_offset, gtrec.rm_flags);
2250ceeb9c83SDarrick J. Wong 		if (error)
2251ceeb9c83SDarrick J. Wong 			goto out_error;
2252ceeb9c83SDarrick J. Wong 
2253ceeb9c83SDarrick J. Wong 		/* Move the start and re-add it. */
2254ceeb9c83SDarrick J. Wong 		gtrec.rm_startblock = bno;
2255ceeb9c83SDarrick J. Wong 		gtrec.rm_blockcount += len;
2256ceeb9c83SDarrick J. Wong 		gtrec.rm_offset = offset;
2257ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, gtrec.rm_startblock,
2258ceeb9c83SDarrick J. Wong 				gtrec.rm_blockcount, gtrec.rm_owner,
2259ceeb9c83SDarrick J. Wong 				gtrec.rm_offset, gtrec.rm_flags);
2260ceeb9c83SDarrick J. Wong 		if (error)
2261ceeb9c83SDarrick J. Wong 			goto out_error;
2262ceeb9c83SDarrick J. Wong 	} else {
2263ceeb9c83SDarrick J. Wong 		/*
2264ceeb9c83SDarrick J. Wong 		 * No contiguous edge with identical owner, insert
2265ceeb9c83SDarrick J. Wong 		 * new record at current cursor position.
2266ceeb9c83SDarrick J. Wong 		 */
2267ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, flags);
2268ceeb9c83SDarrick J. Wong 		if (error)
2269ceeb9c83SDarrick J. Wong 			goto out_error;
2270ceeb9c83SDarrick J. Wong 	}
2271ceeb9c83SDarrick J. Wong 
227250f02fe3SDave Chinner 	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
2273ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2274ceeb9c83SDarrick J. Wong out_error:
2275ceeb9c83SDarrick J. Wong 	if (error)
2276ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_map_error(cur->bc_mp,
227750f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
2278ceeb9c83SDarrick J. Wong 	return error;
2279ceeb9c83SDarrick J. Wong }
2280ceeb9c83SDarrick J. Wong 
22814d4f86b4SDarrick J. Wong /* Insert a raw rmap into the rmapbt. */
22824d4f86b4SDarrick J. Wong int
22834d4f86b4SDarrick J. Wong xfs_rmap_map_raw(
22844d4f86b4SDarrick J. Wong 	struct xfs_btree_cur	*cur,
22854d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec	*rmap)
22864d4f86b4SDarrick J. Wong {
22874d4f86b4SDarrick J. Wong 	struct xfs_owner_info	oinfo;
22884d4f86b4SDarrick J. Wong 
22894d4f86b4SDarrick J. Wong 	oinfo.oi_owner = rmap->rm_owner;
22904d4f86b4SDarrick J. Wong 	oinfo.oi_offset = rmap->rm_offset;
22914d4f86b4SDarrick J. Wong 	oinfo.oi_flags = 0;
22924d4f86b4SDarrick J. Wong 	if (rmap->rm_flags & XFS_RMAP_ATTR_FORK)
22934d4f86b4SDarrick J. Wong 		oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
22944d4f86b4SDarrick J. Wong 	if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK)
22954d4f86b4SDarrick J. Wong 		oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
22964d4f86b4SDarrick J. Wong 
22974d4f86b4SDarrick J. Wong 	if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
22984d4f86b4SDarrick J. Wong 		return xfs_rmap_map(cur, rmap->rm_startblock,
22994d4f86b4SDarrick J. Wong 				rmap->rm_blockcount,
23004d4f86b4SDarrick J. Wong 				rmap->rm_flags & XFS_RMAP_UNWRITTEN,
23014d4f86b4SDarrick J. Wong 				&oinfo);
23024d4f86b4SDarrick J. Wong 
23034d4f86b4SDarrick J. Wong 	return xfs_rmap_map_shared(cur, rmap->rm_startblock,
23044d4f86b4SDarrick J. Wong 			rmap->rm_blockcount,
23054d4f86b4SDarrick J. Wong 			rmap->rm_flags & XFS_RMAP_UNWRITTEN,
23064d4f86b4SDarrick J. Wong 			&oinfo);
23074d4f86b4SDarrick J. Wong }
23084d4f86b4SDarrick J. Wong 
2309c543838aSDarrick J. Wong struct xfs_rmap_query_range_info {
2310c543838aSDarrick J. Wong 	xfs_rmap_query_range_fn	fn;
2311c543838aSDarrick J. Wong 	void				*priv;
2312c543838aSDarrick J. Wong };
2313c543838aSDarrick J. Wong 
2314c543838aSDarrick J. Wong /* Format btree record and pass to our callback. */
2315c543838aSDarrick J. Wong STATIC int
2316c543838aSDarrick J. Wong xfs_rmap_query_range_helper(
2317c543838aSDarrick J. Wong 	struct xfs_btree_cur		*cur,
2318159eb69dSDarrick J. Wong 	const union xfs_btree_rec	*rec,
2319c543838aSDarrick J. Wong 	void				*priv)
2320c543838aSDarrick J. Wong {
2321c543838aSDarrick J. Wong 	struct xfs_rmap_query_range_info	*query = priv;
2322c543838aSDarrick J. Wong 	struct xfs_rmap_irec			irec;
2323c543838aSDarrick J. Wong 
2324*39ab26d5SDarrick J. Wong 	if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL)
2325*39ab26d5SDarrick J. Wong 		return -EFSCORRUPTED;
2326*39ab26d5SDarrick J. Wong 
2327c543838aSDarrick J. Wong 	return query->fn(cur, &irec, query->priv);
2328c543838aSDarrick J. Wong }
2329c543838aSDarrick J. Wong 
2330c543838aSDarrick J. Wong /* Find all rmaps between two keys. */
2331c543838aSDarrick J. Wong int
2332c543838aSDarrick J. Wong xfs_rmap_query_range(
2333c543838aSDarrick J. Wong 	struct xfs_btree_cur			*cur,
233404dcb474SDarrick J. Wong 	const struct xfs_rmap_irec		*low_rec,
233504dcb474SDarrick J. Wong 	const struct xfs_rmap_irec		*high_rec,
2336c543838aSDarrick J. Wong 	xfs_rmap_query_range_fn			fn,
2337c543838aSDarrick J. Wong 	void					*priv)
2338c543838aSDarrick J. Wong {
2339c543838aSDarrick J. Wong 	union xfs_btree_irec			low_brec;
2340c543838aSDarrick J. Wong 	union xfs_btree_irec			high_brec;
2341c543838aSDarrick J. Wong 	struct xfs_rmap_query_range_info	query;
2342c543838aSDarrick J. Wong 
2343c543838aSDarrick J. Wong 	low_brec.r = *low_rec;
2344c543838aSDarrick J. Wong 	high_brec.r = *high_rec;
2345c543838aSDarrick J. Wong 	query.priv = priv;
2346c543838aSDarrick J. Wong 	query.fn = fn;
2347c543838aSDarrick J. Wong 	return xfs_btree_query_range(cur, &low_brec, &high_brec,
2348c543838aSDarrick J. Wong 			xfs_rmap_query_range_helper, &query);
2349e9a2599aSDarrick J. Wong }
2350e9a2599aSDarrick J. Wong 
2351e9a2599aSDarrick J. Wong /* Find all rmaps. */
2352e9a2599aSDarrick J. Wong int
2353e9a2599aSDarrick J. Wong xfs_rmap_query_all(
2354e9a2599aSDarrick J. Wong 	struct xfs_btree_cur			*cur,
2355e9a2599aSDarrick J. Wong 	xfs_rmap_query_range_fn			fn,
2356e9a2599aSDarrick J. Wong 	void					*priv)
2357e9a2599aSDarrick J. Wong {
2358e9a2599aSDarrick J. Wong 	struct xfs_rmap_query_range_info	query;
2359e9a2599aSDarrick J. Wong 
2360e9a2599aSDarrick J. Wong 	query.priv = priv;
2361e9a2599aSDarrick J. Wong 	query.fn = fn;
2362e9a2599aSDarrick J. Wong 	return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query);
2363c543838aSDarrick J. Wong }
23649c194644SDarrick J. Wong 
23659c194644SDarrick J. Wong /* Clean up after calling xfs_rmap_finish_one. */
23669c194644SDarrick J. Wong void
23679c194644SDarrick J. Wong xfs_rmap_finish_one_cleanup(
23689c194644SDarrick J. Wong 	struct xfs_trans	*tp,
23699c194644SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
23709c194644SDarrick J. Wong 	int			error)
23719c194644SDarrick J. Wong {
23729c194644SDarrick J. Wong 	struct xfs_buf		*agbp;
23739c194644SDarrick J. Wong 
23749c194644SDarrick J. Wong 	if (rcur == NULL)
23759c194644SDarrick J. Wong 		return;
2376576af732SDave Chinner 	agbp = rcur->bc_ag.agbp;
23770b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(rcur, error);
23789c194644SDarrick J. Wong 	if (error)
23799c194644SDarrick J. Wong 		xfs_trans_brelse(tp, agbp);
23809c194644SDarrick J. Wong }
23819c194644SDarrick J. Wong 
23829c194644SDarrick J. Wong /*
23839c194644SDarrick J. Wong  * Process one of the deferred rmap operations.  We pass back the
23849c194644SDarrick J. Wong  * btree cursor to maintain our lock on the rmapbt between calls.
23859c194644SDarrick J. Wong  * This saves time and eliminates a buffer deadlock between the
23869c194644SDarrick J. Wong  * superblock and the AGF because we'll always grab them in the same
23879c194644SDarrick J. Wong  * order.
23889c194644SDarrick J. Wong  */
23899c194644SDarrick J. Wong int
23909c194644SDarrick J. Wong xfs_rmap_finish_one(
23919c194644SDarrick J. Wong 	struct xfs_trans		*tp,
23921534328bSDarrick J. Wong 	struct xfs_rmap_intent		*ri,
23939c194644SDarrick J. Wong 	struct xfs_btree_cur		**pcur)
23949c194644SDarrick J. Wong {
23959c194644SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
23969c194644SDarrick J. Wong 	struct xfs_btree_cur		*rcur;
23979c194644SDarrick J. Wong 	struct xfs_buf			*agbp = NULL;
23989c194644SDarrick J. Wong 	int				error = 0;
23999c194644SDarrick J. Wong 	struct xfs_owner_info		oinfo;
24009c194644SDarrick J. Wong 	xfs_agblock_t			bno;
24019c194644SDarrick J. Wong 	bool				unwritten;
24029c194644SDarrick J. Wong 
24031534328bSDarrick J. Wong 	bno = XFS_FSB_TO_AGBNO(mp, ri->ri_bmap.br_startblock);
24049c194644SDarrick J. Wong 
2405c13418e8SDarrick J. Wong 	trace_xfs_rmap_deferred(mp, ri->ri_pag->pag_agno, ri->ri_type, bno,
24061534328bSDarrick J. Wong 			ri->ri_owner, ri->ri_whichfork,
24071534328bSDarrick J. Wong 			ri->ri_bmap.br_startoff, ri->ri_bmap.br_blockcount,
24081534328bSDarrick J. Wong 			ri->ri_bmap.br_state);
24099c194644SDarrick J. Wong 
2410c13418e8SDarrick J. Wong 	if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE))
2411c13418e8SDarrick J. Wong 		return -EIO;
24129c194644SDarrick J. Wong 
24139c194644SDarrick J. Wong 	/*
24149c194644SDarrick J. Wong 	 * If we haven't gotten a cursor or the cursor AG doesn't match
24159c194644SDarrick J. Wong 	 * the startblock, get one now.
24169c194644SDarrick J. Wong 	 */
24179c194644SDarrick J. Wong 	rcur = *pcur;
2418c13418e8SDarrick J. Wong 	if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
24199c194644SDarrick J. Wong 		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
24209c194644SDarrick J. Wong 		rcur = NULL;
24219c194644SDarrick J. Wong 		*pcur = NULL;
24229c194644SDarrick J. Wong 	}
24239c194644SDarrick J. Wong 	if (rcur == NULL) {
24249c194644SDarrick J. Wong 		/*
24259c194644SDarrick J. Wong 		 * Refresh the freelist before we start changing the
24269c194644SDarrick J. Wong 		 * rmapbt, because a shape change could cause us to
24279c194644SDarrick J. Wong 		 * allocate blocks.
24289c194644SDarrick J. Wong 		 */
2429c13418e8SDarrick J. Wong 		error = xfs_free_extent_fix_freelist(tp, ri->ri_pag, &agbp);
24309c194644SDarrick J. Wong 		if (error)
2431c13418e8SDarrick J. Wong 			return error;
2432c13418e8SDarrick J. Wong 		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
2433c13418e8SDarrick J. Wong 			return -EFSCORRUPTED;
24349c194644SDarrick J. Wong 
2435c13418e8SDarrick J. Wong 		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, ri->ri_pag);
24369c194644SDarrick J. Wong 	}
24379c194644SDarrick J. Wong 	*pcur = rcur;
24389c194644SDarrick J. Wong 
24391534328bSDarrick J. Wong 	xfs_rmap_ino_owner(&oinfo, ri->ri_owner, ri->ri_whichfork,
24401534328bSDarrick J. Wong 			ri->ri_bmap.br_startoff);
24411534328bSDarrick J. Wong 	unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
24421534328bSDarrick J. Wong 	bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, ri->ri_bmap.br_startblock);
24439c194644SDarrick J. Wong 
24441534328bSDarrick J. Wong 	switch (ri->ri_type) {
24459c194644SDarrick J. Wong 	case XFS_RMAP_ALLOC:
24469c194644SDarrick J. Wong 	case XFS_RMAP_MAP:
24471534328bSDarrick J. Wong 		error = xfs_rmap_map(rcur, bno, ri->ri_bmap.br_blockcount,
24481534328bSDarrick J. Wong 				unwritten, &oinfo);
24499c194644SDarrick J. Wong 		break;
2450ceeb9c83SDarrick J. Wong 	case XFS_RMAP_MAP_SHARED:
24511534328bSDarrick J. Wong 		error = xfs_rmap_map_shared(rcur, bno,
24521534328bSDarrick J. Wong 				ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2453ceeb9c83SDarrick J. Wong 		break;
24549c194644SDarrick J. Wong 	case XFS_RMAP_FREE:
24559c194644SDarrick J. Wong 	case XFS_RMAP_UNMAP:
24561534328bSDarrick J. Wong 		error = xfs_rmap_unmap(rcur, bno, ri->ri_bmap.br_blockcount,
24571534328bSDarrick J. Wong 				unwritten, &oinfo);
24589c194644SDarrick J. Wong 		break;
2459ceeb9c83SDarrick J. Wong 	case XFS_RMAP_UNMAP_SHARED:
24601534328bSDarrick J. Wong 		error = xfs_rmap_unmap_shared(rcur, bno,
24611534328bSDarrick J. Wong 				ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2462ceeb9c83SDarrick J. Wong 		break;
24639c194644SDarrick J. Wong 	case XFS_RMAP_CONVERT:
24641534328bSDarrick J. Wong 		error = xfs_rmap_convert(rcur, bno, ri->ri_bmap.br_blockcount,
24651534328bSDarrick J. Wong 				!unwritten, &oinfo);
24669c194644SDarrick J. Wong 		break;
24673f165b33SDarrick J. Wong 	case XFS_RMAP_CONVERT_SHARED:
24681534328bSDarrick J. Wong 		error = xfs_rmap_convert_shared(rcur, bno,
24691534328bSDarrick J. Wong 				ri->ri_bmap.br_blockcount, !unwritten, &oinfo);
24703f165b33SDarrick J. Wong 		break;
24719c194644SDarrick J. Wong 	default:
24729c194644SDarrick J. Wong 		ASSERT(0);
24739c194644SDarrick J. Wong 		error = -EFSCORRUPTED;
24749c194644SDarrick J. Wong 	}
2475c13418e8SDarrick J. Wong 
24769c194644SDarrick J. Wong 	return error;
24779c194644SDarrick J. Wong }
24789c194644SDarrick J. Wong 
24799c194644SDarrick J. Wong /*
24809c194644SDarrick J. Wong  * Don't defer an rmap if we aren't an rmap filesystem.
24819c194644SDarrick J. Wong  */
24829c194644SDarrick J. Wong static bool
24839c194644SDarrick J. Wong xfs_rmap_update_is_needed(
24843993baebSDarrick J. Wong 	struct xfs_mount	*mp,
24853993baebSDarrick J. Wong 	int			whichfork)
24869c194644SDarrick J. Wong {
248738c26bfdSDave Chinner 	return xfs_has_rmapbt(mp) && whichfork != XFS_COW_FORK;
24889c194644SDarrick J. Wong }
24899c194644SDarrick J. Wong 
24909c194644SDarrick J. Wong /*
24919c194644SDarrick J. Wong  * Record a rmap intent; the list is kept sorted first by AG and then by
24929c194644SDarrick J. Wong  * increasing age.
24939c194644SDarrick J. Wong  */
2494bc46ac64SDarrick J. Wong static void
24959c194644SDarrick J. Wong __xfs_rmap_add(
24960f37d178SBrian Foster 	struct xfs_trans		*tp,
24979c194644SDarrick J. Wong 	enum xfs_rmap_intent_type	type,
2498c8ce540dSDarrick J. Wong 	uint64_t			owner,
24999c194644SDarrick J. Wong 	int				whichfork,
25009c194644SDarrick J. Wong 	struct xfs_bmbt_irec		*bmap)
25019c194644SDarrick J. Wong {
25029c194644SDarrick J. Wong 	struct xfs_rmap_intent		*ri;
25039c194644SDarrick J. Wong 
25040f37d178SBrian Foster 	trace_xfs_rmap_defer(tp->t_mountp,
25050f37d178SBrian Foster 			XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
25069c194644SDarrick J. Wong 			type,
25070f37d178SBrian Foster 			XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
25089c194644SDarrick J. Wong 			owner, whichfork,
25099c194644SDarrick J. Wong 			bmap->br_startoff,
25109c194644SDarrick J. Wong 			bmap->br_blockcount,
25119c194644SDarrick J. Wong 			bmap->br_state);
25129c194644SDarrick J. Wong 
2513f3c799c2SDarrick J. Wong 	ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
25149c194644SDarrick J. Wong 	INIT_LIST_HEAD(&ri->ri_list);
25159c194644SDarrick J. Wong 	ri->ri_type = type;
25169c194644SDarrick J. Wong 	ri->ri_owner = owner;
25179c194644SDarrick J. Wong 	ri->ri_whichfork = whichfork;
25189c194644SDarrick J. Wong 	ri->ri_bmap = *bmap;
25199c194644SDarrick J. Wong 
2520c13418e8SDarrick J. Wong 	xfs_rmap_update_get_group(tp->t_mountp, ri);
25210f37d178SBrian Foster 	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
25229c194644SDarrick J. Wong }
25239c194644SDarrick J. Wong 
25249c194644SDarrick J. Wong /* Map an extent into a file. */
2525bc46ac64SDarrick J. Wong void
25269c194644SDarrick J. Wong xfs_rmap_map_extent(
25270f37d178SBrian Foster 	struct xfs_trans	*tp,
25289c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25299c194644SDarrick J. Wong 	int			whichfork,
25309c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25319c194644SDarrick J. Wong {
2532d7884e6eSDarrick J. Wong 	enum xfs_rmap_intent_type type = XFS_RMAP_MAP;
2533d7884e6eSDarrick J. Wong 
25340f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2535bc46ac64SDarrick J. Wong 		return;
25369c194644SDarrick J. Wong 
2537d7884e6eSDarrick J. Wong 	if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2538d7884e6eSDarrick J. Wong 		type = XFS_RMAP_MAP_SHARED;
2539d7884e6eSDarrick J. Wong 
2540d7884e6eSDarrick J. Wong 	__xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
25419c194644SDarrick J. Wong }
25429c194644SDarrick J. Wong 
25439c194644SDarrick J. Wong /* Unmap an extent out of a file. */
2544bc46ac64SDarrick J. Wong void
25459c194644SDarrick J. Wong xfs_rmap_unmap_extent(
25460f37d178SBrian Foster 	struct xfs_trans	*tp,
25479c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25489c194644SDarrick J. Wong 	int			whichfork,
25499c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25509c194644SDarrick J. Wong {
2551d7884e6eSDarrick J. Wong 	enum xfs_rmap_intent_type type = XFS_RMAP_UNMAP;
2552d7884e6eSDarrick J. Wong 
25530f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2554bc46ac64SDarrick J. Wong 		return;
25559c194644SDarrick J. Wong 
2556d7884e6eSDarrick J. Wong 	if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2557d7884e6eSDarrick J. Wong 		type = XFS_RMAP_UNMAP_SHARED;
2558d7884e6eSDarrick J. Wong 
2559d7884e6eSDarrick J. Wong 	__xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
25609c194644SDarrick J. Wong }
25619c194644SDarrick J. Wong 
25620f37d178SBrian Foster /*
25630f37d178SBrian Foster  * Convert a data fork extent from unwritten to real or vice versa.
25640f37d178SBrian Foster  *
25650f37d178SBrian Foster  * Note that tp can be NULL here as no transaction is used for COW fork
25660f37d178SBrian Foster  * unwritten conversion.
25670f37d178SBrian Foster  */
2568bc46ac64SDarrick J. Wong void
25699c194644SDarrick J. Wong xfs_rmap_convert_extent(
25709c194644SDarrick J. Wong 	struct xfs_mount	*mp,
25710f37d178SBrian Foster 	struct xfs_trans	*tp,
25729c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25739c194644SDarrick J. Wong 	int			whichfork,
25749c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25759c194644SDarrick J. Wong {
2576d7884e6eSDarrick J. Wong 	enum xfs_rmap_intent_type type = XFS_RMAP_CONVERT;
2577d7884e6eSDarrick J. Wong 
25783993baebSDarrick J. Wong 	if (!xfs_rmap_update_is_needed(mp, whichfork))
2579bc46ac64SDarrick J. Wong 		return;
25809c194644SDarrick J. Wong 
2581d7884e6eSDarrick J. Wong 	if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2582d7884e6eSDarrick J. Wong 		type = XFS_RMAP_CONVERT_SHARED;
2583d7884e6eSDarrick J. Wong 
2584d7884e6eSDarrick J. Wong 	__xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
25859c194644SDarrick J. Wong }
25869c194644SDarrick J. Wong 
25879c194644SDarrick J. Wong /* Schedule the creation of an rmap for non-file data. */
2588bc46ac64SDarrick J. Wong void
25899c194644SDarrick J. Wong xfs_rmap_alloc_extent(
25900f37d178SBrian Foster 	struct xfs_trans	*tp,
25919c194644SDarrick J. Wong 	xfs_agnumber_t		agno,
25929c194644SDarrick J. Wong 	xfs_agblock_t		bno,
25939c194644SDarrick J. Wong 	xfs_extlen_t		len,
2594c8ce540dSDarrick J. Wong 	uint64_t		owner)
25959c194644SDarrick J. Wong {
25969c194644SDarrick J. Wong 	struct xfs_bmbt_irec	bmap;
25979c194644SDarrick J. Wong 
25980f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2599bc46ac64SDarrick J. Wong 		return;
26009c194644SDarrick J. Wong 
26010f37d178SBrian Foster 	bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
26029c194644SDarrick J. Wong 	bmap.br_blockcount = len;
26039c194644SDarrick J. Wong 	bmap.br_startoff = 0;
26049c194644SDarrick J. Wong 	bmap.br_state = XFS_EXT_NORM;
26059c194644SDarrick J. Wong 
2606bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
26079c194644SDarrick J. Wong }
26089c194644SDarrick J. Wong 
26099c194644SDarrick J. Wong /* Schedule the deletion of an rmap for non-file data. */
2610bc46ac64SDarrick J. Wong void
26119c194644SDarrick J. Wong xfs_rmap_free_extent(
26120f37d178SBrian Foster 	struct xfs_trans	*tp,
26139c194644SDarrick J. Wong 	xfs_agnumber_t		agno,
26149c194644SDarrick J. Wong 	xfs_agblock_t		bno,
26159c194644SDarrick J. Wong 	xfs_extlen_t		len,
2616c8ce540dSDarrick J. Wong 	uint64_t		owner)
26179c194644SDarrick J. Wong {
26189c194644SDarrick J. Wong 	struct xfs_bmbt_irec	bmap;
26199c194644SDarrick J. Wong 
26200f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2621bc46ac64SDarrick J. Wong 		return;
26229c194644SDarrick J. Wong 
26230f37d178SBrian Foster 	bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
26249c194644SDarrick J. Wong 	bmap.br_blockcount = len;
26259c194644SDarrick J. Wong 	bmap.br_startoff = 0;
26269c194644SDarrick J. Wong 	bmap.br_state = XFS_EXT_NORM;
26279c194644SDarrick J. Wong 
2628bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
26299c194644SDarrick J. Wong }
2630e89c0413SDarrick J. Wong 
2631e89c0413SDarrick J. Wong /* Compare rmap records.  Returns -1 if a < b, 1 if a > b, and 0 if equal. */
2632e89c0413SDarrick J. Wong int
2633e89c0413SDarrick J. Wong xfs_rmap_compare(
2634e89c0413SDarrick J. Wong 	const struct xfs_rmap_irec	*a,
2635e89c0413SDarrick J. Wong 	const struct xfs_rmap_irec	*b)
2636e89c0413SDarrick J. Wong {
2637e89c0413SDarrick J. Wong 	__u64				oa;
2638e89c0413SDarrick J. Wong 	__u64				ob;
2639e89c0413SDarrick J. Wong 
2640e89c0413SDarrick J. Wong 	oa = xfs_rmap_irec_offset_pack(a);
2641e89c0413SDarrick J. Wong 	ob = xfs_rmap_irec_offset_pack(b);
2642e89c0413SDarrick J. Wong 
2643e89c0413SDarrick J. Wong 	if (a->rm_startblock < b->rm_startblock)
2644e89c0413SDarrick J. Wong 		return -1;
2645e89c0413SDarrick J. Wong 	else if (a->rm_startblock > b->rm_startblock)
2646e89c0413SDarrick J. Wong 		return 1;
2647e89c0413SDarrick J. Wong 	else if (a->rm_owner < b->rm_owner)
2648e89c0413SDarrick J. Wong 		return -1;
2649e89c0413SDarrick J. Wong 	else if (a->rm_owner > b->rm_owner)
2650e89c0413SDarrick J. Wong 		return 1;
2651e89c0413SDarrick J. Wong 	else if (oa < ob)
2652e89c0413SDarrick J. Wong 		return -1;
2653e89c0413SDarrick J. Wong 	else if (oa > ob)
2654e89c0413SDarrick J. Wong 		return 1;
2655e89c0413SDarrick J. Wong 	else
2656e89c0413SDarrick J. Wong 		return 0;
2657e89c0413SDarrick J. Wong }
2658ed7c52d4SDarrick J. Wong 
2659ed7c52d4SDarrick J. Wong /* Is there a record covering a given extent? */
2660ed7c52d4SDarrick J. Wong int
2661ed7c52d4SDarrick J. Wong xfs_rmap_has_record(
2662ed7c52d4SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2663ed7c52d4SDarrick J. Wong 	xfs_agblock_t		bno,
2664ed7c52d4SDarrick J. Wong 	xfs_extlen_t		len,
2665ed7c52d4SDarrick J. Wong 	bool			*exists)
2666ed7c52d4SDarrick J. Wong {
2667ed7c52d4SDarrick J. Wong 	union xfs_btree_irec	low;
2668ed7c52d4SDarrick J. Wong 	union xfs_btree_irec	high;
2669ed7c52d4SDarrick J. Wong 
2670ed7c52d4SDarrick J. Wong 	memset(&low, 0, sizeof(low));
2671ed7c52d4SDarrick J. Wong 	low.r.rm_startblock = bno;
2672ed7c52d4SDarrick J. Wong 	memset(&high, 0xFF, sizeof(high));
2673ed7c52d4SDarrick J. Wong 	high.r.rm_startblock = bno + len - 1;
2674ed7c52d4SDarrick J. Wong 
2675ed7c52d4SDarrick J. Wong 	return xfs_btree_has_record(cur, &low, &high, exists);
2676ed7c52d4SDarrick J. Wong }
2677ed7c52d4SDarrick J. Wong 
2678ed7c52d4SDarrick J. Wong /*
2679ed7c52d4SDarrick J. Wong  * Is there a record for this owner completely covering a given physical
2680ed7c52d4SDarrick J. Wong  * extent?  If so, *has_rmap will be set to true.  If there is no record
2681ed7c52d4SDarrick J. Wong  * or the record only covers part of the range, we set *has_rmap to false.
2682ed7c52d4SDarrick J. Wong  * This function doesn't perform range lookups or offset checks, so it is
2683ed7c52d4SDarrick J. Wong  * not suitable for checking data fork blocks.
2684ed7c52d4SDarrick J. Wong  */
2685ed7c52d4SDarrick J. Wong int
2686ed7c52d4SDarrick J. Wong xfs_rmap_record_exists(
2687ed7c52d4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2688ed7c52d4SDarrick J. Wong 	xfs_agblock_t			bno,
2689ed7c52d4SDarrick J. Wong 	xfs_extlen_t			len,
269066e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
2691ed7c52d4SDarrick J. Wong 	bool				*has_rmap)
2692ed7c52d4SDarrick J. Wong {
2693ed7c52d4SDarrick J. Wong 	uint64_t			owner;
2694ed7c52d4SDarrick J. Wong 	uint64_t			offset;
2695ed7c52d4SDarrick J. Wong 	unsigned int			flags;
2696ed7c52d4SDarrick J. Wong 	int				has_record;
2697ed7c52d4SDarrick J. Wong 	struct xfs_rmap_irec		irec;
2698ed7c52d4SDarrick J. Wong 	int				error;
2699ed7c52d4SDarrick J. Wong 
2700ed7c52d4SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2701ed7c52d4SDarrick J. Wong 	ASSERT(XFS_RMAP_NON_INODE_OWNER(owner) ||
2702ed7c52d4SDarrick J. Wong 	       (flags & XFS_RMAP_BMBT_BLOCK));
2703ed7c52d4SDarrick J. Wong 
27045b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &irec,
2705ed7c52d4SDarrick J. Wong 			&has_record);
2706ed7c52d4SDarrick J. Wong 	if (error)
2707ed7c52d4SDarrick J. Wong 		return error;
2708ed7c52d4SDarrick J. Wong 	if (!has_record) {
2709ed7c52d4SDarrick J. Wong 		*has_rmap = false;
2710ed7c52d4SDarrick J. Wong 		return 0;
2711ed7c52d4SDarrick J. Wong 	}
2712ed7c52d4SDarrick J. Wong 
2713ed7c52d4SDarrick J. Wong 	*has_rmap = (irec.rm_owner == owner && irec.rm_startblock <= bno &&
2714ed7c52d4SDarrick J. Wong 		     irec.rm_startblock + irec.rm_blockcount >= bno + len);
2715ed7c52d4SDarrick J. Wong 	return 0;
2716ed7c52d4SDarrick J. Wong }
27174d4f86b4SDarrick J. Wong 
27184d4f86b4SDarrick J. Wong struct xfs_rmap_key_state {
27194d4f86b4SDarrick J. Wong 	uint64_t			owner;
27204d4f86b4SDarrick J. Wong 	uint64_t			offset;
27214d4f86b4SDarrick J. Wong 	unsigned int			flags;
27224d4f86b4SDarrick J. Wong };
27234d4f86b4SDarrick J. Wong 
27244d4f86b4SDarrick J. Wong /* For each rmap given, figure out if it doesn't match the key we want. */
27254d4f86b4SDarrick J. Wong STATIC int
27264d4f86b4SDarrick J. Wong xfs_rmap_has_other_keys_helper(
27274d4f86b4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2728159eb69dSDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
27294d4f86b4SDarrick J. Wong 	void				*priv)
27304d4f86b4SDarrick J. Wong {
27314d4f86b4SDarrick J. Wong 	struct xfs_rmap_key_state	*rks = priv;
27324d4f86b4SDarrick J. Wong 
27334d4f86b4SDarrick J. Wong 	if (rks->owner == rec->rm_owner && rks->offset == rec->rm_offset &&
27344d4f86b4SDarrick J. Wong 	    ((rks->flags & rec->rm_flags) & XFS_RMAP_KEY_FLAGS) == rks->flags)
27354d4f86b4SDarrick J. Wong 		return 0;
2736e7ee96dfSDarrick J. Wong 	return -ECANCELED;
27374d4f86b4SDarrick J. Wong }
27384d4f86b4SDarrick J. Wong 
27394d4f86b4SDarrick J. Wong /*
27404d4f86b4SDarrick J. Wong  * Given an extent and some owner info, can we find records overlapping
27414d4f86b4SDarrick J. Wong  * the extent whose owner info does not match the given owner?
27424d4f86b4SDarrick J. Wong  */
27434d4f86b4SDarrick J. Wong int
27444d4f86b4SDarrick J. Wong xfs_rmap_has_other_keys(
27454d4f86b4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
27464d4f86b4SDarrick J. Wong 	xfs_agblock_t			bno,
27474d4f86b4SDarrick J. Wong 	xfs_extlen_t			len,
274866e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
27494d4f86b4SDarrick J. Wong 	bool				*has_rmap)
27504d4f86b4SDarrick J. Wong {
27514d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec		low = {0};
27524d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec		high;
27534d4f86b4SDarrick J. Wong 	struct xfs_rmap_key_state	rks;
27544d4f86b4SDarrick J. Wong 	int				error;
27554d4f86b4SDarrick J. Wong 
27564d4f86b4SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &rks.owner, &rks.offset, &rks.flags);
2757a71e4228SDarrick J. Wong 	*has_rmap = false;
27584d4f86b4SDarrick J. Wong 
27594d4f86b4SDarrick J. Wong 	low.rm_startblock = bno;
27604d4f86b4SDarrick J. Wong 	memset(&high, 0xFF, sizeof(high));
27614d4f86b4SDarrick J. Wong 	high.rm_startblock = bno + len - 1;
27624d4f86b4SDarrick J. Wong 
27634d4f86b4SDarrick J. Wong 	error = xfs_rmap_query_range(cur, &low, &high,
27644d4f86b4SDarrick J. Wong 			xfs_rmap_has_other_keys_helper, &rks);
2765a71e4228SDarrick J. Wong 	if (error == -ECANCELED) {
2766a71e4228SDarrick J. Wong 		*has_rmap = true;
27677380e8feSDarrick J. Wong 		return 0;
27684d4f86b4SDarrick J. Wong 	}
27697280fedaSDarrick J. Wong 
2770a71e4228SDarrick J. Wong 	return error;
2771a71e4228SDarrick J. Wong }
2772a71e4228SDarrick J. Wong 
27737280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = {
27747280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_NULL,
27757280fedaSDarrick J. Wong };
27767280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER = {
27777280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_UNKNOWN,
27787280fedaSDarrick J. Wong };
27797280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_FS = {
27807280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_FS,
27817280fedaSDarrick J. Wong };
27827280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_LOG = {
27837280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_LOG,
27847280fedaSDarrick J. Wong };
27857280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_AG = {
27867280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_AG,
27877280fedaSDarrick J. Wong };
27887280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_INOBT = {
27897280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_INOBT,
27907280fedaSDarrick J. Wong };
27917280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_INODES = {
27927280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_INODES,
27937280fedaSDarrick J. Wong };
27947280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_REFC = {
27957280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_REFC,
27967280fedaSDarrick J. Wong };
27977280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_COW = {
27987280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_COW,
27997280fedaSDarrick J. Wong };
2800f3c799c2SDarrick J. Wong 
2801f3c799c2SDarrick J. Wong int __init
2802f3c799c2SDarrick J. Wong xfs_rmap_intent_init_cache(void)
2803f3c799c2SDarrick J. Wong {
2804f3c799c2SDarrick J. Wong 	xfs_rmap_intent_cache = kmem_cache_create("xfs_rmap_intent",
2805f3c799c2SDarrick J. Wong 			sizeof(struct xfs_rmap_intent),
2806f3c799c2SDarrick J. Wong 			0, 0, NULL);
2807f3c799c2SDarrick J. Wong 
2808f3c799c2SDarrick J. Wong 	return xfs_rmap_intent_cache != NULL ? 0 : -ENOMEM;
2809f3c799c2SDarrick J. Wong }
2810f3c799c2SDarrick J. Wong 
2811f3c799c2SDarrick J. Wong void
2812f3c799c2SDarrick J. Wong xfs_rmap_intent_destroy_cache(void)
2813f3c799c2SDarrick J. Wong {
2814f3c799c2SDarrick J. Wong 	kmem_cache_destroy(xfs_rmap_intent_cache);
2815f3c799c2SDarrick J. Wong 	xfs_rmap_intent_cache = NULL;
2816f3c799c2SDarrick J. Wong }
2817