xref: /openbmc/linux/fs/xfs/libxfs/xfs_rmap.c (revision f9e03706)
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"
14673930c3SDarrick J. Wong #include "xfs_defer.h"
15673930c3SDarrick J. Wong #include "xfs_btree.h"
16673930c3SDarrick J. Wong #include "xfs_trans.h"
17673930c3SDarrick J. Wong #include "xfs_alloc.h"
18673930c3SDarrick J. Wong #include "xfs_rmap.h"
190a1b0b38SDarrick J. Wong #include "xfs_rmap_btree.h"
20673930c3SDarrick J. Wong #include "xfs_trace.h"
21e9e899a2SDarrick J. Wong #include "xfs_errortag.h"
22673930c3SDarrick J. Wong #include "xfs_error.h"
239c194644SDarrick J. Wong #include "xfs_inode.h"
24673930c3SDarrick J. Wong 
254b8ed677SDarrick J. Wong /*
264b8ed677SDarrick J. Wong  * Lookup the first record less than or equal to [bno, len, owner, offset]
274b8ed677SDarrick J. Wong  * in the btree given by cur.
284b8ed677SDarrick J. Wong  */
294b8ed677SDarrick J. Wong int
304b8ed677SDarrick J. Wong xfs_rmap_lookup_le(
314b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
324b8ed677SDarrick J. Wong 	xfs_agblock_t		bno,
334b8ed677SDarrick J. Wong 	xfs_extlen_t		len,
344b8ed677SDarrick J. Wong 	uint64_t		owner,
354b8ed677SDarrick J. Wong 	uint64_t		offset,
364b8ed677SDarrick J. Wong 	unsigned int		flags,
374b8ed677SDarrick J. Wong 	int			*stat)
384b8ed677SDarrick J. Wong {
394b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_startblock = bno;
404b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_blockcount = len;
414b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_owner = owner;
424b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_offset = offset;
434b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_flags = flags;
444b8ed677SDarrick J. Wong 	return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
454b8ed677SDarrick J. Wong }
464b8ed677SDarrick J. Wong 
474b8ed677SDarrick J. Wong /*
484b8ed677SDarrick J. Wong  * Lookup the record exactly matching [bno, len, owner, offset]
494b8ed677SDarrick J. Wong  * in the btree given by cur.
504b8ed677SDarrick J. Wong  */
514b8ed677SDarrick J. Wong int
524b8ed677SDarrick J. Wong xfs_rmap_lookup_eq(
534b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
544b8ed677SDarrick J. Wong 	xfs_agblock_t		bno,
554b8ed677SDarrick J. Wong 	xfs_extlen_t		len,
564b8ed677SDarrick J. Wong 	uint64_t		owner,
574b8ed677SDarrick J. Wong 	uint64_t		offset,
584b8ed677SDarrick J. Wong 	unsigned int		flags,
594b8ed677SDarrick J. Wong 	int			*stat)
604b8ed677SDarrick J. Wong {
614b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_startblock = bno;
624b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_blockcount = len;
634b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_owner = owner;
644b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_offset = offset;
654b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_flags = flags;
664b8ed677SDarrick J. Wong 	return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
674b8ed677SDarrick J. Wong }
684b8ed677SDarrick J. Wong 
694b8ed677SDarrick J. Wong /*
704b8ed677SDarrick J. Wong  * Update the record referred to by cur to the value given
714b8ed677SDarrick J. Wong  * by [bno, len, owner, offset].
724b8ed677SDarrick J. Wong  * This either works (return 0) or gets an EFSCORRUPTED error.
734b8ed677SDarrick J. Wong  */
744b8ed677SDarrick J. Wong STATIC int
754b8ed677SDarrick J. Wong xfs_rmap_update(
764b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
774b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec)
784b8ed677SDarrick J. Wong {
794b8ed677SDarrick J. Wong 	union xfs_btree_rec	rec;
80abf09233SDarrick J. Wong 	int			error;
81abf09233SDarrick J. Wong 
82abf09233SDarrick J. Wong 	trace_xfs_rmap_update(cur->bc_mp, cur->bc_private.a.agno,
83abf09233SDarrick J. Wong 			irec->rm_startblock, irec->rm_blockcount,
84abf09233SDarrick J. Wong 			irec->rm_owner, irec->rm_offset, irec->rm_flags);
854b8ed677SDarrick J. Wong 
864b8ed677SDarrick J. Wong 	rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
874b8ed677SDarrick J. Wong 	rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
884b8ed677SDarrick J. Wong 	rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
894b8ed677SDarrick J. Wong 	rec.rmap.rm_offset = cpu_to_be64(
904b8ed677SDarrick J. Wong 			xfs_rmap_irec_offset_pack(irec));
91abf09233SDarrick J. Wong 	error = xfs_btree_update(cur, &rec);
92abf09233SDarrick J. Wong 	if (error)
93abf09233SDarrick J. Wong 		trace_xfs_rmap_update_error(cur->bc_mp,
94abf09233SDarrick J. Wong 				cur->bc_private.a.agno, error, _RET_IP_);
95abf09233SDarrick J. Wong 	return error;
96abf09233SDarrick J. Wong }
97abf09233SDarrick J. Wong 
98abf09233SDarrick J. Wong int
99abf09233SDarrick J. Wong xfs_rmap_insert(
100abf09233SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
101abf09233SDarrick J. Wong 	xfs_agblock_t		agbno,
102abf09233SDarrick J. Wong 	xfs_extlen_t		len,
103abf09233SDarrick J. Wong 	uint64_t		owner,
104abf09233SDarrick J. Wong 	uint64_t		offset,
105abf09233SDarrick J. Wong 	unsigned int		flags)
106abf09233SDarrick J. Wong {
107abf09233SDarrick J. Wong 	int			i;
108abf09233SDarrick J. Wong 	int			error;
109abf09233SDarrick J. Wong 
110abf09233SDarrick J. Wong 	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, agbno,
111abf09233SDarrick J. Wong 			len, owner, offset, flags);
112abf09233SDarrick J. Wong 
113abf09233SDarrick J. Wong 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
114abf09233SDarrick J. Wong 	if (error)
115abf09233SDarrick J. Wong 		goto done;
116f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
117f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
118f9e03706SDarrick J. Wong 		goto done;
119f9e03706SDarrick J. Wong 	}
120abf09233SDarrick J. Wong 
121abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_startblock = agbno;
122abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_blockcount = len;
123abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_owner = owner;
124abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_offset = offset;
125abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_flags = flags;
126abf09233SDarrick J. Wong 	error = xfs_btree_insert(rcur, &i);
127abf09233SDarrick J. Wong 	if (error)
128abf09233SDarrick J. Wong 		goto done;
129f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
130f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
131f9e03706SDarrick J. Wong 		goto done;
132f9e03706SDarrick J. Wong 	}
133abf09233SDarrick J. Wong done:
134abf09233SDarrick J. Wong 	if (error)
135abf09233SDarrick J. Wong 		trace_xfs_rmap_insert_error(rcur->bc_mp,
136abf09233SDarrick J. Wong 				rcur->bc_private.a.agno, error, _RET_IP_);
137abf09233SDarrick J. Wong 	return error;
1384b8ed677SDarrick J. Wong }
1394b8ed677SDarrick J. Wong 
140ceeb9c83SDarrick J. Wong STATIC int
141ceeb9c83SDarrick J. Wong xfs_rmap_delete(
142ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
143ceeb9c83SDarrick J. Wong 	xfs_agblock_t		agbno,
144ceeb9c83SDarrick J. Wong 	xfs_extlen_t		len,
145ceeb9c83SDarrick J. Wong 	uint64_t		owner,
146ceeb9c83SDarrick J. Wong 	uint64_t		offset,
147ceeb9c83SDarrick J. Wong 	unsigned int		flags)
148ceeb9c83SDarrick J. Wong {
149ceeb9c83SDarrick J. Wong 	int			i;
150ceeb9c83SDarrick J. Wong 	int			error;
151ceeb9c83SDarrick J. Wong 
152ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_private.a.agno, agbno,
153ceeb9c83SDarrick J. Wong 			len, owner, offset, flags);
154ceeb9c83SDarrick J. Wong 
155ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
156ceeb9c83SDarrick J. Wong 	if (error)
157ceeb9c83SDarrick J. Wong 		goto done;
158f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
159f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
160f9e03706SDarrick J. Wong 		goto done;
161f9e03706SDarrick J. Wong 	}
162ceeb9c83SDarrick J. Wong 
163ceeb9c83SDarrick J. Wong 	error = xfs_btree_delete(rcur, &i);
164ceeb9c83SDarrick J. Wong 	if (error)
165ceeb9c83SDarrick J. Wong 		goto done;
166f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
167f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
168f9e03706SDarrick J. Wong 		goto done;
169f9e03706SDarrick J. Wong 	}
170ceeb9c83SDarrick J. Wong done:
171ceeb9c83SDarrick J. Wong 	if (error)
172ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_delete_error(rcur->bc_mp,
173ceeb9c83SDarrick J. Wong 				rcur->bc_private.a.agno, error, _RET_IP_);
174ceeb9c83SDarrick J. Wong 	return error;
175ceeb9c83SDarrick J. Wong }
176ceeb9c83SDarrick J. Wong 
17726788097SDarrick J. Wong /* Convert an internal btree record to an rmap record. */
17826788097SDarrick J. Wong int
1794b8ed677SDarrick J. Wong xfs_rmap_btrec_to_irec(
1804b8ed677SDarrick J. Wong 	union xfs_btree_rec	*rec,
1814b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec)
1824b8ed677SDarrick J. Wong {
1834b8ed677SDarrick J. Wong 	irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
1844b8ed677SDarrick J. Wong 	irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
1854b8ed677SDarrick J. Wong 	irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
1864b8ed677SDarrick J. Wong 	return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
1874b8ed677SDarrick J. Wong 			irec);
1884b8ed677SDarrick J. Wong }
1894b8ed677SDarrick J. Wong 
1904b8ed677SDarrick J. Wong /*
1914b8ed677SDarrick J. Wong  * Get the data from the pointed-to record.
1924b8ed677SDarrick J. Wong  */
1934b8ed677SDarrick J. Wong int
1944b8ed677SDarrick J. Wong xfs_rmap_get_rec(
1954b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
1964b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
1974b8ed677SDarrick J. Wong 	int			*stat)
1984b8ed677SDarrick J. Wong {
1999e6c08d4SDave Chinner 	struct xfs_mount	*mp = cur->bc_mp;
2009e6c08d4SDave Chinner 	xfs_agnumber_t		agno = cur->bc_private.a.agno;
2014b8ed677SDarrick J. Wong 	union xfs_btree_rec	*rec;
2024b8ed677SDarrick J. Wong 	int			error;
2034b8ed677SDarrick J. Wong 
2044b8ed677SDarrick J. Wong 	error = xfs_btree_get_rec(cur, &rec, stat);
2054b8ed677SDarrick J. Wong 	if (error || !*stat)
2064b8ed677SDarrick J. Wong 		return error;
2074b8ed677SDarrick J. Wong 
2089e6c08d4SDave Chinner 	if (xfs_rmap_btrec_to_irec(rec, irec))
2099e6c08d4SDave Chinner 		goto out_bad_rec;
2109e6c08d4SDave Chinner 
2119e6c08d4SDave Chinner 	if (irec->rm_blockcount == 0)
2129e6c08d4SDave Chinner 		goto out_bad_rec;
2139e6c08d4SDave Chinner 	if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
2149e6c08d4SDave Chinner 		if (irec->rm_owner != XFS_RMAP_OWN_FS)
2159e6c08d4SDave Chinner 			goto out_bad_rec;
2169e6c08d4SDave Chinner 		if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
2179e6c08d4SDave Chinner 			goto out_bad_rec;
2189e6c08d4SDave Chinner 	} else {
2199e6c08d4SDave Chinner 		/* check for valid extent range, including overflow */
2209e6c08d4SDave Chinner 		if (!xfs_verify_agbno(mp, agno, irec->rm_startblock))
2219e6c08d4SDave Chinner 			goto out_bad_rec;
2229e6c08d4SDave Chinner 		if (irec->rm_startblock >
2239e6c08d4SDave Chinner 				irec->rm_startblock + irec->rm_blockcount)
2249e6c08d4SDave Chinner 			goto out_bad_rec;
2259e6c08d4SDave Chinner 		if (!xfs_verify_agbno(mp, agno,
2269e6c08d4SDave Chinner 				irec->rm_startblock + irec->rm_blockcount - 1))
2279e6c08d4SDave Chinner 			goto out_bad_rec;
2289e6c08d4SDave Chinner 	}
2299e6c08d4SDave Chinner 
2309e6c08d4SDave Chinner 	if (!(xfs_verify_ino(mp, irec->rm_owner) ||
2319e6c08d4SDave Chinner 	      (irec->rm_owner <= XFS_RMAP_OWN_FS &&
2329e6c08d4SDave Chinner 	       irec->rm_owner >= XFS_RMAP_OWN_MIN)))
2339e6c08d4SDave Chinner 		goto out_bad_rec;
2349e6c08d4SDave Chinner 
2359e6c08d4SDave Chinner 	return 0;
2369e6c08d4SDave Chinner out_bad_rec:
2379e6c08d4SDave Chinner 	xfs_warn(mp,
2389e6c08d4SDave Chinner 		"Reverse Mapping BTree record corruption in AG %d detected!",
2399e6c08d4SDave Chinner 		agno);
2409e6c08d4SDave Chinner 	xfs_warn(mp,
2419e6c08d4SDave Chinner 		"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
2429e6c08d4SDave Chinner 		irec->rm_owner, irec->rm_flags, irec->rm_startblock,
2439e6c08d4SDave Chinner 		irec->rm_blockcount);
2449e6c08d4SDave Chinner 	return -EFSCORRUPTED;
2454b8ed677SDarrick J. Wong }
2464b8ed677SDarrick J. Wong 
247ceeb9c83SDarrick J. Wong struct xfs_find_left_neighbor_info {
248ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	high;
249ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec;
250ceeb9c83SDarrick J. Wong 	int			*stat;
251ceeb9c83SDarrick J. Wong };
252ceeb9c83SDarrick J. Wong 
253ceeb9c83SDarrick J. Wong /* For each rmap given, figure out if it matches the key we want. */
254ceeb9c83SDarrick J. Wong STATIC int
255ceeb9c83SDarrick J. Wong xfs_rmap_find_left_neighbor_helper(
256ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
257ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*rec,
258ceeb9c83SDarrick J. Wong 	void			*priv)
259ceeb9c83SDarrick J. Wong {
260ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	*info = priv;
261ceeb9c83SDarrick J. Wong 
262ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
263ceeb9c83SDarrick J. Wong 			cur->bc_private.a.agno, rec->rm_startblock,
264ceeb9c83SDarrick J. Wong 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
265ceeb9c83SDarrick J. Wong 			rec->rm_flags);
266ceeb9c83SDarrick J. Wong 
267ceeb9c83SDarrick J. Wong 	if (rec->rm_owner != info->high.rm_owner)
26839ee2239SDarrick J. Wong 		return 0;
269ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
270ceeb9c83SDarrick J. Wong 	    !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
271ceeb9c83SDarrick J. Wong 	    rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset)
27239ee2239SDarrick J. Wong 		return 0;
273ceeb9c83SDarrick J. Wong 
274ceeb9c83SDarrick J. Wong 	*info->irec = *rec;
275ceeb9c83SDarrick J. Wong 	*info->stat = 1;
276e7ee96dfSDarrick J. Wong 	return -ECANCELED;
277ceeb9c83SDarrick J. Wong }
278ceeb9c83SDarrick J. Wong 
279ceeb9c83SDarrick J. Wong /*
280ceeb9c83SDarrick J. Wong  * Find the record to the left of the given extent, being careful only to
281ceeb9c83SDarrick J. Wong  * return a match with the same owner and adjacent physical and logical
282ceeb9c83SDarrick J. Wong  * block ranges.
283ceeb9c83SDarrick J. Wong  */
284ceeb9c83SDarrick J. Wong int
285ceeb9c83SDarrick J. Wong xfs_rmap_find_left_neighbor(
286ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
287ceeb9c83SDarrick J. Wong 	xfs_agblock_t		bno,
288ceeb9c83SDarrick J. Wong 	uint64_t		owner,
289ceeb9c83SDarrick J. Wong 	uint64_t		offset,
290ceeb9c83SDarrick J. Wong 	unsigned int		flags,
291ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
292ceeb9c83SDarrick J. Wong 	int			*stat)
293ceeb9c83SDarrick J. Wong {
294ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	info;
295ceeb9c83SDarrick J. Wong 	int			error;
296ceeb9c83SDarrick J. Wong 
297ceeb9c83SDarrick J. Wong 	*stat = 0;
298ceeb9c83SDarrick J. Wong 	if (bno == 0)
299ceeb9c83SDarrick J. Wong 		return 0;
300ceeb9c83SDarrick J. Wong 	info.high.rm_startblock = bno - 1;
301ceeb9c83SDarrick J. Wong 	info.high.rm_owner = owner;
302ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(owner) &&
303ceeb9c83SDarrick J. Wong 	    !(flags & XFS_RMAP_BMBT_BLOCK)) {
304ceeb9c83SDarrick J. Wong 		if (offset == 0)
305ceeb9c83SDarrick J. Wong 			return 0;
306ceeb9c83SDarrick J. Wong 		info.high.rm_offset = offset - 1;
307ceeb9c83SDarrick J. Wong 	} else
308ceeb9c83SDarrick J. Wong 		info.high.rm_offset = 0;
309ceeb9c83SDarrick J. Wong 	info.high.rm_flags = flags;
310ceeb9c83SDarrick J. Wong 	info.high.rm_blockcount = 0;
311ceeb9c83SDarrick J. Wong 	info.irec = irec;
312ceeb9c83SDarrick J. Wong 	info.stat = stat;
313ceeb9c83SDarrick J. Wong 
314ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
315ceeb9c83SDarrick J. Wong 			cur->bc_private.a.agno, bno, 0, owner, offset, flags);
316ceeb9c83SDarrick J. Wong 
317ceeb9c83SDarrick J. Wong 	error = xfs_rmap_query_range(cur, &info.high, &info.high,
318ceeb9c83SDarrick J. Wong 			xfs_rmap_find_left_neighbor_helper, &info);
319e7ee96dfSDarrick J. Wong 	if (error == -ECANCELED)
320ceeb9c83SDarrick J. Wong 		error = 0;
321ceeb9c83SDarrick J. Wong 	if (*stat)
322ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
323ceeb9c83SDarrick J. Wong 				cur->bc_private.a.agno, irec->rm_startblock,
324ceeb9c83SDarrick J. Wong 				irec->rm_blockcount, irec->rm_owner,
325ceeb9c83SDarrick J. Wong 				irec->rm_offset, irec->rm_flags);
326ceeb9c83SDarrick J. Wong 	return error;
327ceeb9c83SDarrick J. Wong }
328ceeb9c83SDarrick J. Wong 
329ceeb9c83SDarrick J. Wong /* For each rmap given, figure out if it matches the key we want. */
330ceeb9c83SDarrick J. Wong STATIC int
331ceeb9c83SDarrick J. Wong xfs_rmap_lookup_le_range_helper(
332ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
333ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*rec,
334ceeb9c83SDarrick J. Wong 	void			*priv)
335ceeb9c83SDarrick J. Wong {
336ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	*info = priv;
337ceeb9c83SDarrick J. Wong 
338ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
339ceeb9c83SDarrick J. Wong 			cur->bc_private.a.agno, rec->rm_startblock,
340ceeb9c83SDarrick J. Wong 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
341ceeb9c83SDarrick J. Wong 			rec->rm_flags);
342ceeb9c83SDarrick J. Wong 
343ceeb9c83SDarrick J. Wong 	if (rec->rm_owner != info->high.rm_owner)
34439ee2239SDarrick J. Wong 		return 0;
345ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
346ceeb9c83SDarrick J. Wong 	    !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
347ceeb9c83SDarrick J. Wong 	    (rec->rm_offset > info->high.rm_offset ||
348ceeb9c83SDarrick J. Wong 	     rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset))
34939ee2239SDarrick J. Wong 		return 0;
350ceeb9c83SDarrick J. Wong 
351ceeb9c83SDarrick J. Wong 	*info->irec = *rec;
352ceeb9c83SDarrick J. Wong 	*info->stat = 1;
353e7ee96dfSDarrick J. Wong 	return -ECANCELED;
354ceeb9c83SDarrick J. Wong }
355ceeb9c83SDarrick J. Wong 
356ceeb9c83SDarrick J. Wong /*
357ceeb9c83SDarrick J. Wong  * Find the record to the left of the given extent, being careful only to
358ceeb9c83SDarrick J. Wong  * return a match with the same owner and overlapping physical and logical
359ceeb9c83SDarrick J. Wong  * block ranges.  This is the overlapping-interval version of
360ceeb9c83SDarrick J. Wong  * xfs_rmap_lookup_le.
361ceeb9c83SDarrick J. Wong  */
362ceeb9c83SDarrick J. Wong int
363ceeb9c83SDarrick J. Wong xfs_rmap_lookup_le_range(
364ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
365ceeb9c83SDarrick J. Wong 	xfs_agblock_t		bno,
366ceeb9c83SDarrick J. Wong 	uint64_t		owner,
367ceeb9c83SDarrick J. Wong 	uint64_t		offset,
368ceeb9c83SDarrick J. Wong 	unsigned int		flags,
369ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
370ceeb9c83SDarrick J. Wong 	int			*stat)
371ceeb9c83SDarrick J. Wong {
372ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	info;
373ceeb9c83SDarrick J. Wong 	int			error;
374ceeb9c83SDarrick J. Wong 
375ceeb9c83SDarrick J. Wong 	info.high.rm_startblock = bno;
376ceeb9c83SDarrick J. Wong 	info.high.rm_owner = owner;
377ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK))
378ceeb9c83SDarrick J. Wong 		info.high.rm_offset = offset;
379ceeb9c83SDarrick J. Wong 	else
380ceeb9c83SDarrick J. Wong 		info.high.rm_offset = 0;
381ceeb9c83SDarrick J. Wong 	info.high.rm_flags = flags;
382ceeb9c83SDarrick J. Wong 	info.high.rm_blockcount = 0;
383ceeb9c83SDarrick J. Wong 	*stat = 0;
384ceeb9c83SDarrick J. Wong 	info.irec = irec;
385ceeb9c83SDarrick J. Wong 	info.stat = stat;
386ceeb9c83SDarrick J. Wong 
387ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range(cur->bc_mp,
388ceeb9c83SDarrick J. Wong 			cur->bc_private.a.agno, bno, 0, owner, offset, flags);
389ceeb9c83SDarrick J. Wong 	error = xfs_rmap_query_range(cur, &info.high, &info.high,
390ceeb9c83SDarrick J. Wong 			xfs_rmap_lookup_le_range_helper, &info);
391e7ee96dfSDarrick J. Wong 	if (error == -ECANCELED)
392ceeb9c83SDarrick J. Wong 		error = 0;
393ceeb9c83SDarrick J. Wong 	if (*stat)
394ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
395ceeb9c83SDarrick J. Wong 				cur->bc_private.a.agno, irec->rm_startblock,
396ceeb9c83SDarrick J. Wong 				irec->rm_blockcount, irec->rm_owner,
397ceeb9c83SDarrick J. Wong 				irec->rm_offset, irec->rm_flags);
398ceeb9c83SDarrick J. Wong 	return error;
399ceeb9c83SDarrick J. Wong }
400ceeb9c83SDarrick J. Wong 
401f922cd90SDarrick J. Wong /*
40268c58e9bSDarrick J. Wong  * Perform all the relevant owner checks for a removal op.  If we're doing an
40368c58e9bSDarrick J. Wong  * unknown-owner removal then we have no owner information to check.
40468c58e9bSDarrick J. Wong  */
40568c58e9bSDarrick J. Wong static int
40668c58e9bSDarrick J. Wong xfs_rmap_free_check_owner(
40768c58e9bSDarrick J. Wong 	struct xfs_mount	*mp,
40868c58e9bSDarrick J. Wong 	uint64_t		ltoff,
40968c58e9bSDarrick J. Wong 	struct xfs_rmap_irec	*rec,
41068c58e9bSDarrick J. Wong 	xfs_filblks_t		len,
41168c58e9bSDarrick J. Wong 	uint64_t		owner,
41268c58e9bSDarrick J. Wong 	uint64_t		offset,
41368c58e9bSDarrick J. Wong 	unsigned int		flags)
41468c58e9bSDarrick J. Wong {
41568c58e9bSDarrick J. Wong 	int			error = 0;
41668c58e9bSDarrick J. Wong 
41768c58e9bSDarrick J. Wong 	if (owner == XFS_RMAP_OWN_UNKNOWN)
41868c58e9bSDarrick J. Wong 		return 0;
41968c58e9bSDarrick J. Wong 
42068c58e9bSDarrick J. Wong 	/* Make sure the unwritten flag matches. */
421f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
422f9e03706SDarrick J. Wong 			   (flags & XFS_RMAP_UNWRITTEN) !=
423f9e03706SDarrick J. Wong 			   (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
424f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
425f9e03706SDarrick J. Wong 		goto out;
426f9e03706SDarrick J. Wong 	}
42768c58e9bSDarrick J. Wong 
42868c58e9bSDarrick J. Wong 	/* Make sure the owner matches what we expect to find in the tree. */
429f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
430f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
431f9e03706SDarrick J. Wong 		goto out;
432f9e03706SDarrick J. Wong 	}
43368c58e9bSDarrick J. Wong 
43468c58e9bSDarrick J. Wong 	/* Check the offset, if necessary. */
43568c58e9bSDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(owner))
43668c58e9bSDarrick J. Wong 		goto out;
43768c58e9bSDarrick J. Wong 
43868c58e9bSDarrick J. Wong 	if (flags & XFS_RMAP_BMBT_BLOCK) {
439f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
440f9e03706SDarrick J. Wong 				   !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
441f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
442f9e03706SDarrick J. Wong 			goto out;
443f9e03706SDarrick J. Wong 		}
44468c58e9bSDarrick J. Wong 	} else {
445f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
446f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
447f9e03706SDarrick J. Wong 			goto out;
448f9e03706SDarrick J. Wong 		}
449f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
450f9e03706SDarrick J. Wong 				   offset + len > ltoff + rec->rm_blockcount)) {
451f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
452f9e03706SDarrick J. Wong 			goto out;
453f9e03706SDarrick J. Wong 		}
45468c58e9bSDarrick J. Wong 	}
45568c58e9bSDarrick J. Wong 
45668c58e9bSDarrick J. Wong out:
45768c58e9bSDarrick J. Wong 	return error;
45868c58e9bSDarrick J. Wong }
45968c58e9bSDarrick J. Wong 
46068c58e9bSDarrick J. Wong /*
461f922cd90SDarrick J. Wong  * Find the extent in the rmap btree and remove it.
462f922cd90SDarrick J. Wong  *
463f922cd90SDarrick J. Wong  * The record we find should always be an exact match for the extent that we're
464f922cd90SDarrick J. Wong  * looking for, since we insert them into the btree without modification.
465f922cd90SDarrick J. Wong  *
466f922cd90SDarrick J. Wong  * Special Case #1: when growing the filesystem, we "free" an extent when
467f922cd90SDarrick J. Wong  * growing the last AG. This extent is new space and so it is not tracked as
468f922cd90SDarrick J. Wong  * used space in the btree. The growfs code will pass in an owner of
469f922cd90SDarrick J. Wong  * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
470f922cd90SDarrick J. Wong  * extent. We verify that - the extent lookup result in a record that does not
471f922cd90SDarrick J. Wong  * overlap.
472f922cd90SDarrick J. Wong  *
473f922cd90SDarrick J. Wong  * Special Case #2: EFIs do not record the owner of the extent, so when
474f922cd90SDarrick J. Wong  * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
475f922cd90SDarrick J. Wong  * btree to ignore the owner (i.e. wildcard match) so we don't trigger
476f922cd90SDarrick J. Wong  * corruption checks during log recovery.
477f922cd90SDarrick J. Wong  */
478f922cd90SDarrick J. Wong STATIC int
479f922cd90SDarrick J. Wong xfs_rmap_unmap(
480f922cd90SDarrick J. Wong 	struct xfs_btree_cur		*cur,
481f922cd90SDarrick J. Wong 	xfs_agblock_t			bno,
482f922cd90SDarrick J. Wong 	xfs_extlen_t			len,
483f922cd90SDarrick J. Wong 	bool				unwritten,
48466e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
485f922cd90SDarrick J. Wong {
486f922cd90SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
487f922cd90SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
488f922cd90SDarrick J. Wong 	uint64_t			ltoff;
489f922cd90SDarrick J. Wong 	int				error = 0;
490f922cd90SDarrick J. Wong 	int				i;
491f922cd90SDarrick J. Wong 	uint64_t			owner;
492f922cd90SDarrick J. Wong 	uint64_t			offset;
493f922cd90SDarrick J. Wong 	unsigned int			flags;
494f922cd90SDarrick J. Wong 	bool				ignore_off;
495f922cd90SDarrick J. Wong 
496f922cd90SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
497f922cd90SDarrick J. Wong 	ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
498f922cd90SDarrick J. Wong 			(flags & XFS_RMAP_BMBT_BLOCK);
499f922cd90SDarrick J. Wong 	if (unwritten)
500f922cd90SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
501f922cd90SDarrick J. Wong 	trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
502f922cd90SDarrick J. Wong 			unwritten, oinfo);
503f922cd90SDarrick J. Wong 
504f922cd90SDarrick J. Wong 	/*
505f922cd90SDarrick J. Wong 	 * We should always have a left record because there's a static record
506f922cd90SDarrick J. Wong 	 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
507f922cd90SDarrick J. Wong 	 * will not ever be removed from the tree.
508f922cd90SDarrick J. Wong 	 */
509f922cd90SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i);
510f922cd90SDarrick J. Wong 	if (error)
511f922cd90SDarrick J. Wong 		goto out_error;
512f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
513f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
514f9e03706SDarrick J. Wong 		goto out_error;
515f9e03706SDarrick J. Wong 	}
516f922cd90SDarrick J. Wong 
517f922cd90SDarrick J. Wong 	error = xfs_rmap_get_rec(cur, &ltrec, &i);
518f922cd90SDarrick J. Wong 	if (error)
519f922cd90SDarrick J. Wong 		goto out_error;
520f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
521f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
522f9e03706SDarrick J. Wong 		goto out_error;
523f9e03706SDarrick J. Wong 	}
524f922cd90SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
525f922cd90SDarrick J. Wong 			cur->bc_private.a.agno, ltrec.rm_startblock,
526f922cd90SDarrick J. Wong 			ltrec.rm_blockcount, ltrec.rm_owner,
527f922cd90SDarrick J. Wong 			ltrec.rm_offset, ltrec.rm_flags);
528f922cd90SDarrick J. Wong 	ltoff = ltrec.rm_offset;
529f922cd90SDarrick J. Wong 
530f922cd90SDarrick J. Wong 	/*
531f922cd90SDarrick J. Wong 	 * For growfs, the incoming extent must be beyond the left record we
532f922cd90SDarrick J. Wong 	 * just found as it is new space and won't be used by anyone. This is
533f922cd90SDarrick J. Wong 	 * just a corruption check as we don't actually do anything with this
534f922cd90SDarrick J. Wong 	 * extent.  Note that we need to use >= instead of > because it might
535f922cd90SDarrick J. Wong 	 * be the case that the "left" extent goes all the way to EOFS.
536f922cd90SDarrick J. Wong 	 */
537f922cd90SDarrick J. Wong 	if (owner == XFS_RMAP_OWN_NULL) {
538f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
539f9e03706SDarrick J. Wong 				   bno <
540f9e03706SDarrick J. Wong 				   ltrec.rm_startblock + ltrec.rm_blockcount)) {
541f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
542f9e03706SDarrick J. Wong 			goto out_error;
543f9e03706SDarrick J. Wong 		}
544f922cd90SDarrick J. Wong 		goto out_done;
545f922cd90SDarrick J. Wong 	}
546f922cd90SDarrick J. Wong 
54733df3a9cSDarrick J. Wong 	/*
54833df3a9cSDarrick J. Wong 	 * If we're doing an unknown-owner removal for EFI recovery, we expect
54933df3a9cSDarrick J. Wong 	 * to find the full range in the rmapbt or nothing at all.  If we
55033df3a9cSDarrick J. Wong 	 * don't find any rmaps overlapping either end of the range, we're
55133df3a9cSDarrick J. Wong 	 * done.  Hopefully this means that the EFI creator already queued
55233df3a9cSDarrick J. Wong 	 * (and finished) a RUI to remove the rmap.
55333df3a9cSDarrick J. Wong 	 */
55433df3a9cSDarrick J. Wong 	if (owner == XFS_RMAP_OWN_UNKNOWN &&
55533df3a9cSDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount <= bno) {
55633df3a9cSDarrick J. Wong 		struct xfs_rmap_irec    rtrec;
55733df3a9cSDarrick J. Wong 
55833df3a9cSDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
55933df3a9cSDarrick J. Wong 		if (error)
56033df3a9cSDarrick J. Wong 			goto out_error;
56133df3a9cSDarrick J. Wong 		if (i == 0)
56233df3a9cSDarrick J. Wong 			goto out_done;
56333df3a9cSDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &rtrec, &i);
56433df3a9cSDarrick J. Wong 		if (error)
56533df3a9cSDarrick J. Wong 			goto out_error;
566f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
567f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
568f9e03706SDarrick J. Wong 			goto out_error;
569f9e03706SDarrick J. Wong 		}
57033df3a9cSDarrick J. Wong 		if (rtrec.rm_startblock >= bno + len)
57133df3a9cSDarrick J. Wong 			goto out_done;
57233df3a9cSDarrick J. Wong 	}
57333df3a9cSDarrick J. Wong 
574f922cd90SDarrick J. Wong 	/* Make sure the extent we found covers the entire freeing range. */
575f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
576f9e03706SDarrick J. Wong 			   ltrec.rm_startblock > bno ||
577f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount <
578f9e03706SDarrick J. Wong 			   bno + len)) {
579f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
580f9e03706SDarrick J. Wong 		goto out_error;
581f9e03706SDarrick J. Wong 	}
582f922cd90SDarrick J. Wong 
58368c58e9bSDarrick J. Wong 	/* Check owner information. */
584a1f69417SEric Sandeen 	error = xfs_rmap_free_check_owner(mp, ltoff, &ltrec, len, owner,
58568c58e9bSDarrick J. Wong 			offset, flags);
58668c58e9bSDarrick J. Wong 	if (error)
58768c58e9bSDarrick J. Wong 		goto out_error;
588f922cd90SDarrick J. Wong 
589f922cd90SDarrick J. Wong 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
590f922cd90SDarrick J. Wong 		/* exact match, simply remove the record from rmap tree */
591f922cd90SDarrick J. Wong 		trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
592f922cd90SDarrick J. Wong 				ltrec.rm_startblock, ltrec.rm_blockcount,
593f922cd90SDarrick J. Wong 				ltrec.rm_owner, ltrec.rm_offset,
594f922cd90SDarrick J. Wong 				ltrec.rm_flags);
595f922cd90SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
596f922cd90SDarrick J. Wong 		if (error)
597f922cd90SDarrick J. Wong 			goto out_error;
598f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
599f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
600f9e03706SDarrick J. Wong 			goto out_error;
601f9e03706SDarrick J. Wong 		}
602f922cd90SDarrick J. Wong 	} else if (ltrec.rm_startblock == bno) {
603f922cd90SDarrick J. Wong 		/*
604f922cd90SDarrick J. Wong 		 * overlap left hand side of extent: move the start, trim the
605f922cd90SDarrick J. Wong 		 * length and update the current record.
606f922cd90SDarrick J. Wong 		 *
607f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
608f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
609f922cd90SDarrick J. Wong 		 * Freeing: |fffffffff|
610f922cd90SDarrick J. Wong 		 * Result:            |rrrrrrrrrr|
611f922cd90SDarrick J. Wong 		 *         bno       len
612f922cd90SDarrick J. Wong 		 */
613f922cd90SDarrick J. Wong 		ltrec.rm_startblock += len;
614f922cd90SDarrick J. Wong 		ltrec.rm_blockcount -= len;
615f922cd90SDarrick J. Wong 		if (!ignore_off)
616f922cd90SDarrick J. Wong 			ltrec.rm_offset += len;
617f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
618f922cd90SDarrick J. Wong 		if (error)
619f922cd90SDarrick J. Wong 			goto out_error;
620f922cd90SDarrick J. Wong 	} else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
621f922cd90SDarrick J. Wong 		/*
622f922cd90SDarrick J. Wong 		 * overlap right hand side of extent: trim the length and update
623f922cd90SDarrick J. Wong 		 * the current record.
624f922cd90SDarrick J. Wong 		 *
625f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
626f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
627f922cd90SDarrick J. Wong 		 * Freeing:            |fffffffff|
628f922cd90SDarrick J. Wong 		 * Result:  |rrrrrrrrrr|
629f922cd90SDarrick J. Wong 		 *                    bno       len
630f922cd90SDarrick J. Wong 		 */
631f922cd90SDarrick J. Wong 		ltrec.rm_blockcount -= len;
632f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
633f922cd90SDarrick J. Wong 		if (error)
634f922cd90SDarrick J. Wong 			goto out_error;
635f922cd90SDarrick J. Wong 	} else {
636f922cd90SDarrick J. Wong 
637f922cd90SDarrick J. Wong 		/*
638f922cd90SDarrick J. Wong 		 * overlap middle of extent: trim the length of the existing
639f922cd90SDarrick J. Wong 		 * record to the length of the new left-extent size, increment
640f922cd90SDarrick J. Wong 		 * the insertion position so we can insert a new record
641f922cd90SDarrick J. Wong 		 * containing the remaining right-extent space.
642f922cd90SDarrick J. Wong 		 *
643f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
644f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
645f922cd90SDarrick J. Wong 		 * Freeing:       |fffffffff|
646f922cd90SDarrick J. Wong 		 * Result:  |rrrrr|         |rrrr|
647f922cd90SDarrick J. Wong 		 *               bno       len
648f922cd90SDarrick J. Wong 		 */
649f922cd90SDarrick J. Wong 		xfs_extlen_t	orig_len = ltrec.rm_blockcount;
650f922cd90SDarrick J. Wong 
651f922cd90SDarrick J. Wong 		ltrec.rm_blockcount = bno - ltrec.rm_startblock;
652f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
653f922cd90SDarrick J. Wong 		if (error)
654f922cd90SDarrick J. Wong 			goto out_error;
655f922cd90SDarrick J. Wong 
656f922cd90SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
657f922cd90SDarrick J. Wong 		if (error)
658f922cd90SDarrick J. Wong 			goto out_error;
659f922cd90SDarrick J. Wong 
660f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_startblock = bno + len;
661f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_blockcount = orig_len - len -
662f922cd90SDarrick J. Wong 						     ltrec.rm_blockcount;
663f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_owner = ltrec.rm_owner;
664f922cd90SDarrick J. Wong 		if (ignore_off)
665f922cd90SDarrick J. Wong 			cur->bc_rec.r.rm_offset = 0;
666f922cd90SDarrick J. Wong 		else
667f922cd90SDarrick J. Wong 			cur->bc_rec.r.rm_offset = offset + len;
668f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_flags = flags;
669f922cd90SDarrick J. Wong 		trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
670f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_startblock,
671f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_blockcount,
672f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_owner,
673f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_offset,
674f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_flags);
675f922cd90SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
676f922cd90SDarrick J. Wong 		if (error)
677f922cd90SDarrick J. Wong 			goto out_error;
678f922cd90SDarrick J. Wong 	}
679f922cd90SDarrick J. Wong 
680f922cd90SDarrick J. Wong out_done:
681f922cd90SDarrick J. Wong 	trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
682f922cd90SDarrick J. Wong 			unwritten, oinfo);
683f922cd90SDarrick J. Wong out_error:
684f922cd90SDarrick J. Wong 	if (error)
685f922cd90SDarrick J. Wong 		trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno,
686f922cd90SDarrick J. Wong 				error, _RET_IP_);
687f922cd90SDarrick J. Wong 	return error;
688f922cd90SDarrick J. Wong }
689f922cd90SDarrick J. Wong 
690f922cd90SDarrick J. Wong /*
691f922cd90SDarrick J. Wong  * Remove a reference to an extent in the rmap btree.
692f922cd90SDarrick J. Wong  */
693673930c3SDarrick J. Wong int
694673930c3SDarrick J. Wong xfs_rmap_free(
695673930c3SDarrick J. Wong 	struct xfs_trans		*tp,
696673930c3SDarrick J. Wong 	struct xfs_buf			*agbp,
697673930c3SDarrick J. Wong 	xfs_agnumber_t			agno,
698673930c3SDarrick J. Wong 	xfs_agblock_t			bno,
699673930c3SDarrick J. Wong 	xfs_extlen_t			len,
70066e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
701673930c3SDarrick J. Wong {
702673930c3SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
703f922cd90SDarrick J. Wong 	struct xfs_btree_cur		*cur;
704f922cd90SDarrick J. Wong 	int				error;
705673930c3SDarrick J. Wong 
706673930c3SDarrick J. Wong 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
707673930c3SDarrick J. Wong 		return 0;
708673930c3SDarrick J. Wong 
709f922cd90SDarrick J. Wong 	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
710f922cd90SDarrick J. Wong 
711f922cd90SDarrick J. Wong 	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
712f922cd90SDarrick J. Wong 
7130b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
714673930c3SDarrick J. Wong 	return error;
715673930c3SDarrick J. Wong }
716673930c3SDarrick J. Wong 
7170a1b0b38SDarrick J. Wong /*
7180a1b0b38SDarrick J. Wong  * A mergeable rmap must have the same owner and the same values for
7190a1b0b38SDarrick J. Wong  * the unwritten, attr_fork, and bmbt flags.  The startblock and
7200a1b0b38SDarrick J. Wong  * offset are checked separately.
7210a1b0b38SDarrick J. Wong  */
7220a1b0b38SDarrick J. Wong static bool
7230a1b0b38SDarrick J. Wong xfs_rmap_is_mergeable(
7240a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
7250a1b0b38SDarrick J. Wong 	uint64_t		owner,
7260a1b0b38SDarrick J. Wong 	unsigned int		flags)
7270a1b0b38SDarrick J. Wong {
7280a1b0b38SDarrick J. Wong 	if (irec->rm_owner == XFS_RMAP_OWN_NULL)
7290a1b0b38SDarrick J. Wong 		return false;
7300a1b0b38SDarrick J. Wong 	if (irec->rm_owner != owner)
7310a1b0b38SDarrick J. Wong 		return false;
7320a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_UNWRITTEN) ^
7330a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_UNWRITTEN))
7340a1b0b38SDarrick J. Wong 		return false;
7350a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_ATTR_FORK) ^
7360a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_ATTR_FORK))
7370a1b0b38SDarrick J. Wong 		return false;
7380a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_BMBT_BLOCK) ^
7390a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
7400a1b0b38SDarrick J. Wong 		return false;
7410a1b0b38SDarrick J. Wong 	return true;
7420a1b0b38SDarrick J. Wong }
7430a1b0b38SDarrick J. Wong 
7440a1b0b38SDarrick J. Wong /*
7450a1b0b38SDarrick J. Wong  * When we allocate a new block, the first thing we do is add a reference to
7460a1b0b38SDarrick J. Wong  * the extent in the rmap btree. This takes the form of a [agbno, length,
7470a1b0b38SDarrick J. Wong  * owner, offset] record.  Flags are encoded in the high bits of the offset
7480a1b0b38SDarrick J. Wong  * field.
7490a1b0b38SDarrick J. Wong  */
7500a1b0b38SDarrick J. Wong STATIC int
7510a1b0b38SDarrick J. Wong xfs_rmap_map(
7520a1b0b38SDarrick J. Wong 	struct xfs_btree_cur		*cur,
7530a1b0b38SDarrick J. Wong 	xfs_agblock_t			bno,
7540a1b0b38SDarrick J. Wong 	xfs_extlen_t			len,
7550a1b0b38SDarrick J. Wong 	bool				unwritten,
75666e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
7570a1b0b38SDarrick J. Wong {
7580a1b0b38SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
7590a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
7600a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec		gtrec;
7610a1b0b38SDarrick J. Wong 	int				have_gt;
7620a1b0b38SDarrick J. Wong 	int				have_lt;
7630a1b0b38SDarrick J. Wong 	int				error = 0;
7640a1b0b38SDarrick J. Wong 	int				i;
7650a1b0b38SDarrick J. Wong 	uint64_t			owner;
7660a1b0b38SDarrick J. Wong 	uint64_t			offset;
7670a1b0b38SDarrick J. Wong 	unsigned int			flags = 0;
7680a1b0b38SDarrick J. Wong 	bool				ignore_off;
7690a1b0b38SDarrick J. Wong 
7700a1b0b38SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
7710a1b0b38SDarrick J. Wong 	ASSERT(owner != 0);
7720a1b0b38SDarrick J. Wong 	ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
7730a1b0b38SDarrick J. Wong 			(flags & XFS_RMAP_BMBT_BLOCK);
7740a1b0b38SDarrick J. Wong 	if (unwritten)
7750a1b0b38SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
7760a1b0b38SDarrick J. Wong 	trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
7770a1b0b38SDarrick J. Wong 			unwritten, oinfo);
77833df3a9cSDarrick J. Wong 	ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
7790a1b0b38SDarrick J. Wong 
7800a1b0b38SDarrick J. Wong 	/*
7810a1b0b38SDarrick J. Wong 	 * For the initial lookup, look for an exact match or the left-adjacent
7820a1b0b38SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
7830a1b0b38SDarrick J. Wong 	 * start block contiguity tests.
7840a1b0b38SDarrick J. Wong 	 */
7850a1b0b38SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
7860a1b0b38SDarrick J. Wong 			&have_lt);
7870a1b0b38SDarrick J. Wong 	if (error)
7880a1b0b38SDarrick J. Wong 		goto out_error;
789fa248de9SDarrick J. Wong 	if (have_lt) {
7900a1b0b38SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
7910a1b0b38SDarrick J. Wong 		if (error)
7920a1b0b38SDarrick J. Wong 			goto out_error;
793f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_lt != 1)) {
794f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
795f9e03706SDarrick J. Wong 			goto out_error;
796f9e03706SDarrick J. Wong 		}
7970a1b0b38SDarrick J. Wong 		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
7980a1b0b38SDarrick J. Wong 				cur->bc_private.a.agno, ltrec.rm_startblock,
7990a1b0b38SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
8000a1b0b38SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
8010a1b0b38SDarrick J. Wong 
8020a1b0b38SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
8030a1b0b38SDarrick J. Wong 			have_lt = 0;
804fa248de9SDarrick J. Wong 	}
8050a1b0b38SDarrick J. Wong 
806f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
807f9e03706SDarrick J. Wong 			   have_lt != 0 &&
808f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
809f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
810f9e03706SDarrick J. Wong 		goto out_error;
811f9e03706SDarrick J. Wong 	}
8120a1b0b38SDarrick J. Wong 
8130a1b0b38SDarrick J. Wong 	/*
8140a1b0b38SDarrick J. Wong 	 * Increment the cursor to see if we have a right-adjacent record to our
8150a1b0b38SDarrick J. Wong 	 * insertion point. This will give us the record for end block
8160a1b0b38SDarrick J. Wong 	 * contiguity tests.
8170a1b0b38SDarrick J. Wong 	 */
8180a1b0b38SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &have_gt);
8190a1b0b38SDarrick J. Wong 	if (error)
8200a1b0b38SDarrick J. Wong 		goto out_error;
8210a1b0b38SDarrick J. Wong 	if (have_gt) {
8220a1b0b38SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
8230a1b0b38SDarrick J. Wong 		if (error)
8240a1b0b38SDarrick J. Wong 			goto out_error;
825f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
826f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
827f9e03706SDarrick J. Wong 			goto out_error;
828f9e03706SDarrick J. Wong 		}
829f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
830f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
831f9e03706SDarrick J. Wong 			goto out_error;
832f9e03706SDarrick J. Wong 		}
8330a1b0b38SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
8340a1b0b38SDarrick J. Wong 			cur->bc_private.a.agno, gtrec.rm_startblock,
8350a1b0b38SDarrick J. Wong 			gtrec.rm_blockcount, gtrec.rm_owner,
8360a1b0b38SDarrick J. Wong 			gtrec.rm_offset, gtrec.rm_flags);
8370a1b0b38SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
8380a1b0b38SDarrick J. Wong 			have_gt = 0;
8390a1b0b38SDarrick J. Wong 	}
8400a1b0b38SDarrick J. Wong 
8410a1b0b38SDarrick J. Wong 	/*
8420a1b0b38SDarrick J. Wong 	 * Note: cursor currently points one record to the right of ltrec, even
8430a1b0b38SDarrick J. Wong 	 * if there is no record in the tree to the right.
8440a1b0b38SDarrick J. Wong 	 */
8450a1b0b38SDarrick J. Wong 	if (have_lt &&
8460a1b0b38SDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
8470a1b0b38SDarrick J. Wong 	    (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
8480a1b0b38SDarrick J. Wong 		/*
8490a1b0b38SDarrick J. Wong 		 * left edge contiguous, merge into left record.
8500a1b0b38SDarrick J. Wong 		 *
8510a1b0b38SDarrick J. Wong 		 *       ltbno     ltlen
8520a1b0b38SDarrick J. Wong 		 * orig:   |ooooooooo|
8530a1b0b38SDarrick J. Wong 		 * adding:           |aaaaaaaaa|
8540a1b0b38SDarrick J. Wong 		 * result: |rrrrrrrrrrrrrrrrrrr|
8550a1b0b38SDarrick J. Wong 		 *                  bno       len
8560a1b0b38SDarrick J. Wong 		 */
8570a1b0b38SDarrick J. Wong 		ltrec.rm_blockcount += len;
8580a1b0b38SDarrick J. Wong 		if (have_gt &&
8590a1b0b38SDarrick J. Wong 		    bno + len == gtrec.rm_startblock &&
8600a1b0b38SDarrick J. Wong 		    (ignore_off || offset + len == gtrec.rm_offset) &&
8610a1b0b38SDarrick J. Wong 		    (unsigned long)ltrec.rm_blockcount + len +
8620a1b0b38SDarrick J. Wong 				gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
8630a1b0b38SDarrick J. Wong 			/*
8640a1b0b38SDarrick J. Wong 			 * right edge also contiguous, delete right record
8650a1b0b38SDarrick J. Wong 			 * and merge into left record.
8660a1b0b38SDarrick J. Wong 			 *
8670a1b0b38SDarrick J. Wong 			 *       ltbno     ltlen    gtbno     gtlen
8680a1b0b38SDarrick J. Wong 			 * orig:   |ooooooooo|         |ooooooooo|
8690a1b0b38SDarrick J. Wong 			 * adding:           |aaaaaaaaa|
8700a1b0b38SDarrick J. Wong 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
8710a1b0b38SDarrick J. Wong 			 */
8720a1b0b38SDarrick J. Wong 			ltrec.rm_blockcount += gtrec.rm_blockcount;
8730a1b0b38SDarrick J. Wong 			trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
8740a1b0b38SDarrick J. Wong 					gtrec.rm_startblock,
8750a1b0b38SDarrick J. Wong 					gtrec.rm_blockcount,
8760a1b0b38SDarrick J. Wong 					gtrec.rm_owner,
8770a1b0b38SDarrick J. Wong 					gtrec.rm_offset,
8780a1b0b38SDarrick J. Wong 					gtrec.rm_flags);
8790a1b0b38SDarrick J. Wong 			error = xfs_btree_delete(cur, &i);
8800a1b0b38SDarrick J. Wong 			if (error)
8810a1b0b38SDarrick J. Wong 				goto out_error;
882f9e03706SDarrick J. Wong 			if (XFS_IS_CORRUPT(mp, i != 1)) {
883f9e03706SDarrick J. Wong 				error = -EFSCORRUPTED;
884f9e03706SDarrick J. Wong 				goto out_error;
885f9e03706SDarrick J. Wong 			}
8860a1b0b38SDarrick J. Wong 		}
8870a1b0b38SDarrick J. Wong 
8880a1b0b38SDarrick J. Wong 		/* point the cursor back to the left record and update */
8890a1b0b38SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &have_gt);
8900a1b0b38SDarrick J. Wong 		if (error)
8910a1b0b38SDarrick J. Wong 			goto out_error;
8920a1b0b38SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
8930a1b0b38SDarrick J. Wong 		if (error)
8940a1b0b38SDarrick J. Wong 			goto out_error;
8950a1b0b38SDarrick J. Wong 	} else if (have_gt &&
8960a1b0b38SDarrick J. Wong 		   bno + len == gtrec.rm_startblock &&
8970a1b0b38SDarrick J. Wong 		   (ignore_off || offset + len == gtrec.rm_offset)) {
8980a1b0b38SDarrick J. Wong 		/*
8990a1b0b38SDarrick J. Wong 		 * right edge contiguous, merge into right record.
9000a1b0b38SDarrick J. Wong 		 *
9010a1b0b38SDarrick J. Wong 		 *                 gtbno     gtlen
9020a1b0b38SDarrick J. Wong 		 * Orig:             |ooooooooo|
9030a1b0b38SDarrick J. Wong 		 * adding: |aaaaaaaaa|
9040a1b0b38SDarrick J. Wong 		 * Result: |rrrrrrrrrrrrrrrrrrr|
9050a1b0b38SDarrick J. Wong 		 *        bno       len
9060a1b0b38SDarrick J. Wong 		 */
9070a1b0b38SDarrick J. Wong 		gtrec.rm_startblock = bno;
9080a1b0b38SDarrick J. Wong 		gtrec.rm_blockcount += len;
9090a1b0b38SDarrick J. Wong 		if (!ignore_off)
9100a1b0b38SDarrick J. Wong 			gtrec.rm_offset = offset;
9110a1b0b38SDarrick J. Wong 		error = xfs_rmap_update(cur, &gtrec);
9120a1b0b38SDarrick J. Wong 		if (error)
9130a1b0b38SDarrick J. Wong 			goto out_error;
9140a1b0b38SDarrick J. Wong 	} else {
9150a1b0b38SDarrick J. Wong 		/*
9160a1b0b38SDarrick J. Wong 		 * no contiguous edge with identical owner, insert
9170a1b0b38SDarrick J. Wong 		 * new record at current cursor position.
9180a1b0b38SDarrick J. Wong 		 */
9190a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_startblock = bno;
9200a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_blockcount = len;
9210a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_owner = owner;
9220a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_offset = offset;
9230a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_flags = flags;
9240a1b0b38SDarrick J. Wong 		trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
9250a1b0b38SDarrick J. Wong 			owner, offset, flags);
9260a1b0b38SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
9270a1b0b38SDarrick J. Wong 		if (error)
9280a1b0b38SDarrick J. Wong 			goto out_error;
929f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
930f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
931f9e03706SDarrick J. Wong 			goto out_error;
932f9e03706SDarrick J. Wong 		}
9330a1b0b38SDarrick J. Wong 	}
9340a1b0b38SDarrick J. Wong 
9350a1b0b38SDarrick J. Wong 	trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
9360a1b0b38SDarrick J. Wong 			unwritten, oinfo);
9370a1b0b38SDarrick J. Wong out_error:
9380a1b0b38SDarrick J. Wong 	if (error)
9390a1b0b38SDarrick J. Wong 		trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno,
9400a1b0b38SDarrick J. Wong 				error, _RET_IP_);
9410a1b0b38SDarrick J. Wong 	return error;
9420a1b0b38SDarrick J. Wong }
9430a1b0b38SDarrick J. Wong 
9440a1b0b38SDarrick J. Wong /*
9450a1b0b38SDarrick J. Wong  * Add a reference to an extent in the rmap btree.
9460a1b0b38SDarrick J. Wong  */
947673930c3SDarrick J. Wong int
948673930c3SDarrick J. Wong xfs_rmap_alloc(
949673930c3SDarrick J. Wong 	struct xfs_trans		*tp,
950673930c3SDarrick J. Wong 	struct xfs_buf			*agbp,
951673930c3SDarrick J. Wong 	xfs_agnumber_t			agno,
952673930c3SDarrick J. Wong 	xfs_agblock_t			bno,
953673930c3SDarrick J. Wong 	xfs_extlen_t			len,
95466e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
955673930c3SDarrick J. Wong {
956673930c3SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
9570a1b0b38SDarrick J. Wong 	struct xfs_btree_cur		*cur;
9580a1b0b38SDarrick J. Wong 	int				error;
959673930c3SDarrick J. Wong 
960673930c3SDarrick J. Wong 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
961673930c3SDarrick J. Wong 		return 0;
962673930c3SDarrick J. Wong 
9630a1b0b38SDarrick J. Wong 	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
9640a1b0b38SDarrick J. Wong 	error = xfs_rmap_map(cur, bno, len, false, oinfo);
9650a1b0b38SDarrick J. Wong 
9660b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
967673930c3SDarrick J. Wong 	return error;
968673930c3SDarrick J. Wong }
969c543838aSDarrick J. Wong 
970fb7d9267SDarrick J. Wong #define RMAP_LEFT_CONTIG	(1 << 0)
971fb7d9267SDarrick J. Wong #define RMAP_RIGHT_CONTIG	(1 << 1)
972fb7d9267SDarrick J. Wong #define RMAP_LEFT_FILLING	(1 << 2)
973fb7d9267SDarrick J. Wong #define RMAP_RIGHT_FILLING	(1 << 3)
974fb7d9267SDarrick J. Wong #define RMAP_LEFT_VALID		(1 << 6)
975fb7d9267SDarrick J. Wong #define RMAP_RIGHT_VALID	(1 << 7)
976fb7d9267SDarrick J. Wong 
977fb7d9267SDarrick J. Wong #define LEFT		r[0]
978fb7d9267SDarrick J. Wong #define RIGHT		r[1]
979fb7d9267SDarrick J. Wong #define PREV		r[2]
980fb7d9267SDarrick J. Wong #define NEW		r[3]
981fb7d9267SDarrick J. Wong 
982fb7d9267SDarrick J. Wong /*
983fb7d9267SDarrick J. Wong  * Convert an unwritten extent to a real extent or vice versa.
984fb7d9267SDarrick J. Wong  * Does not handle overlapping extents.
985fb7d9267SDarrick J. Wong  */
986fb7d9267SDarrick J. Wong STATIC int
987fb7d9267SDarrick J. Wong xfs_rmap_convert(
988fb7d9267SDarrick J. Wong 	struct xfs_btree_cur		*cur,
989fb7d9267SDarrick J. Wong 	xfs_agblock_t			bno,
990fb7d9267SDarrick J. Wong 	xfs_extlen_t			len,
991fb7d9267SDarrick J. Wong 	bool				unwritten,
99266e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
993fb7d9267SDarrick J. Wong {
994fb7d9267SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
995fb7d9267SDarrick J. Wong 	struct xfs_rmap_irec		r[4];	/* neighbor extent entries */
99666e3237eSDarrick J. Wong 						/* left is 0, right is 1, */
99766e3237eSDarrick J. Wong 						/* prev is 2, new is 3 */
998fb7d9267SDarrick J. Wong 	uint64_t		owner;
999fb7d9267SDarrick J. Wong 	uint64_t		offset;
1000fb7d9267SDarrick J. Wong 	uint64_t		new_endoff;
1001fb7d9267SDarrick J. Wong 	unsigned int		oldext;
1002fb7d9267SDarrick J. Wong 	unsigned int		newext;
1003fb7d9267SDarrick J. Wong 	unsigned int		flags = 0;
1004fb7d9267SDarrick J. Wong 	int			i;
1005fb7d9267SDarrick J. Wong 	int			state = 0;
1006fb7d9267SDarrick J. Wong 	int			error;
1007fb7d9267SDarrick J. Wong 
1008fb7d9267SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1009fb7d9267SDarrick J. Wong 	ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1010fb7d9267SDarrick J. Wong 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1011fb7d9267SDarrick J. Wong 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1012fb7d9267SDarrick J. Wong 	new_endoff = offset + len;
1013fb7d9267SDarrick J. Wong 	trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len,
1014fb7d9267SDarrick J. Wong 			unwritten, oinfo);
1015fb7d9267SDarrick J. Wong 
1016fb7d9267SDarrick J. Wong 	/*
1017fb7d9267SDarrick J. Wong 	 * For the initial lookup, look for an exact match or the left-adjacent
1018fb7d9267SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
1019fb7d9267SDarrick J. Wong 	 * start block contiguity tests.
1020fb7d9267SDarrick J. Wong 	 */
1021fb7d9267SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
1022fb7d9267SDarrick J. Wong 	if (error)
1023fb7d9267SDarrick J. Wong 		goto done;
1024f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1025f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1026f9e03706SDarrick J. Wong 		goto done;
1027f9e03706SDarrick J. Wong 	}
1028fb7d9267SDarrick J. Wong 
1029fb7d9267SDarrick J. Wong 	error = xfs_rmap_get_rec(cur, &PREV, &i);
1030fb7d9267SDarrick J. Wong 	if (error)
1031fb7d9267SDarrick J. Wong 		goto done;
1032f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1033f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1034f9e03706SDarrick J. Wong 		goto done;
1035f9e03706SDarrick J. Wong 	}
1036fb7d9267SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
1037fb7d9267SDarrick J. Wong 			cur->bc_private.a.agno, PREV.rm_startblock,
1038fb7d9267SDarrick J. Wong 			PREV.rm_blockcount, PREV.rm_owner,
1039fb7d9267SDarrick J. Wong 			PREV.rm_offset, PREV.rm_flags);
1040fb7d9267SDarrick J. Wong 
1041fb7d9267SDarrick J. Wong 	ASSERT(PREV.rm_offset <= offset);
1042fb7d9267SDarrick J. Wong 	ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1043fb7d9267SDarrick J. Wong 	ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1044fb7d9267SDarrick J. Wong 	newext = ~oldext & XFS_RMAP_UNWRITTEN;
1045fb7d9267SDarrick J. Wong 
1046fb7d9267SDarrick J. Wong 	/*
1047fb7d9267SDarrick J. Wong 	 * Set flags determining what part of the previous oldext allocation
1048fb7d9267SDarrick J. Wong 	 * extent is being replaced by a newext allocation.
1049fb7d9267SDarrick J. Wong 	 */
1050fb7d9267SDarrick J. Wong 	if (PREV.rm_offset == offset)
1051fb7d9267SDarrick J. Wong 		state |= RMAP_LEFT_FILLING;
1052fb7d9267SDarrick J. Wong 	if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1053fb7d9267SDarrick J. Wong 		state |= RMAP_RIGHT_FILLING;
1054fb7d9267SDarrick J. Wong 
1055fb7d9267SDarrick J. Wong 	/*
1056fb7d9267SDarrick J. Wong 	 * Decrement the cursor to see if we have a left-adjacent record to our
1057fb7d9267SDarrick J. Wong 	 * insertion point. This will give us the record for end block
1058fb7d9267SDarrick J. Wong 	 * contiguity tests.
1059fb7d9267SDarrick J. Wong 	 */
1060fb7d9267SDarrick J. Wong 	error = xfs_btree_decrement(cur, 0, &i);
1061fb7d9267SDarrick J. Wong 	if (error)
1062fb7d9267SDarrick J. Wong 		goto done;
1063fb7d9267SDarrick J. Wong 	if (i) {
1064fb7d9267SDarrick J. Wong 		state |= RMAP_LEFT_VALID;
1065fb7d9267SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &LEFT, &i);
1066fb7d9267SDarrick J. Wong 		if (error)
1067fb7d9267SDarrick J. Wong 			goto done;
1068f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1069f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1070f9e03706SDarrick J. Wong 			goto done;
1071f9e03706SDarrick J. Wong 		}
1072f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
1073f9e03706SDarrick J. Wong 				   LEFT.rm_startblock + LEFT.rm_blockcount >
1074f9e03706SDarrick J. Wong 				   bno)) {
1075f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1076f9e03706SDarrick J. Wong 			goto done;
1077f9e03706SDarrick J. Wong 		}
1078fb7d9267SDarrick J. Wong 		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
1079fb7d9267SDarrick J. Wong 				cur->bc_private.a.agno, LEFT.rm_startblock,
1080fb7d9267SDarrick J. Wong 				LEFT.rm_blockcount, LEFT.rm_owner,
1081fb7d9267SDarrick J. Wong 				LEFT.rm_offset, LEFT.rm_flags);
1082fb7d9267SDarrick J. Wong 		if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
1083fb7d9267SDarrick J. Wong 		    LEFT.rm_offset + LEFT.rm_blockcount == offset &&
1084fb7d9267SDarrick J. Wong 		    xfs_rmap_is_mergeable(&LEFT, owner, newext))
1085fb7d9267SDarrick J. Wong 			state |= RMAP_LEFT_CONTIG;
1086fb7d9267SDarrick J. Wong 	}
1087fb7d9267SDarrick J. Wong 
1088fb7d9267SDarrick J. Wong 	/*
1089fb7d9267SDarrick J. Wong 	 * Increment the cursor to see if we have a right-adjacent record to our
1090fb7d9267SDarrick J. Wong 	 * insertion point. This will give us the record for end block
1091fb7d9267SDarrick J. Wong 	 * contiguity tests.
1092fb7d9267SDarrick J. Wong 	 */
1093fb7d9267SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &i);
1094fb7d9267SDarrick J. Wong 	if (error)
1095fb7d9267SDarrick J. Wong 		goto done;
1096f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1097f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1098f9e03706SDarrick J. Wong 		goto done;
1099f9e03706SDarrick J. Wong 	}
1100fb7d9267SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &i);
1101fb7d9267SDarrick J. Wong 	if (error)
1102fb7d9267SDarrick J. Wong 		goto done;
1103fb7d9267SDarrick J. Wong 	if (i) {
1104fb7d9267SDarrick J. Wong 		state |= RMAP_RIGHT_VALID;
1105fb7d9267SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1106fb7d9267SDarrick J. Wong 		if (error)
1107fb7d9267SDarrick J. Wong 			goto done;
1108f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1109f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1110f9e03706SDarrick J. Wong 			goto done;
1111f9e03706SDarrick J. Wong 		}
1112f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1113f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1114f9e03706SDarrick J. Wong 			goto done;
1115f9e03706SDarrick J. Wong 		}
1116fb7d9267SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
1117fb7d9267SDarrick J. Wong 				cur->bc_private.a.agno, RIGHT.rm_startblock,
1118fb7d9267SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
1119fb7d9267SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
1120fb7d9267SDarrick J. Wong 		if (bno + len == RIGHT.rm_startblock &&
1121fb7d9267SDarrick J. Wong 		    offset + len == RIGHT.rm_offset &&
1122fb7d9267SDarrick J. Wong 		    xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1123fb7d9267SDarrick J. Wong 			state |= RMAP_RIGHT_CONTIG;
1124fb7d9267SDarrick J. Wong 	}
1125fb7d9267SDarrick J. Wong 
1126fb7d9267SDarrick J. Wong 	/* check that left + prev + right is not too long */
1127fb7d9267SDarrick J. Wong 	if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1128fb7d9267SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1129fb7d9267SDarrick J. Wong 	    (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1130fb7d9267SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1131fb7d9267SDarrick J. Wong 	    (unsigned long)LEFT.rm_blockcount + len +
1132fb7d9267SDarrick J. Wong 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1133fb7d9267SDarrick J. Wong 		state &= ~RMAP_RIGHT_CONTIG;
1134fb7d9267SDarrick J. Wong 
1135fb7d9267SDarrick J. Wong 	trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state,
1136fb7d9267SDarrick J. Wong 			_RET_IP_);
1137fb7d9267SDarrick J. Wong 
1138fb7d9267SDarrick J. Wong 	/* reset the cursor back to PREV */
1139fb7d9267SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
1140fb7d9267SDarrick J. Wong 	if (error)
1141fb7d9267SDarrick J. Wong 		goto done;
1142f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1143f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1144f9e03706SDarrick J. Wong 		goto done;
1145f9e03706SDarrick J. Wong 	}
1146fb7d9267SDarrick J. Wong 
1147fb7d9267SDarrick J. Wong 	/*
1148fb7d9267SDarrick J. Wong 	 * Switch out based on the FILLING and CONTIG state bits.
1149fb7d9267SDarrick J. Wong 	 */
1150fb7d9267SDarrick J. Wong 	switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1151fb7d9267SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1152fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1153fb7d9267SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1154fb7d9267SDarrick J. Wong 		/*
1155fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1156fb7d9267SDarrick J. Wong 		 * The left and right neighbors are both contiguous with new.
1157fb7d9267SDarrick J. Wong 		 */
1158fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1159fb7d9267SDarrick J. Wong 		if (error)
1160fb7d9267SDarrick J. Wong 			goto done;
1161f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1162f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1163f9e03706SDarrick J. Wong 			goto done;
1164f9e03706SDarrick J. Wong 		}
1165fb7d9267SDarrick J. Wong 		trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
1166fb7d9267SDarrick J. Wong 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
1167fb7d9267SDarrick J. Wong 				RIGHT.rm_owner, RIGHT.rm_offset,
1168fb7d9267SDarrick J. Wong 				RIGHT.rm_flags);
1169fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1170fb7d9267SDarrick J. Wong 		if (error)
1171fb7d9267SDarrick J. Wong 			goto done;
1172f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1173f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1174f9e03706SDarrick J. Wong 			goto done;
1175f9e03706SDarrick J. Wong 		}
1176fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1177fb7d9267SDarrick J. Wong 		if (error)
1178fb7d9267SDarrick J. Wong 			goto done;
1179f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1180f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1181f9e03706SDarrick J. Wong 			goto done;
1182f9e03706SDarrick J. Wong 		}
1183fb7d9267SDarrick J. Wong 		trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
1184fb7d9267SDarrick J. Wong 				PREV.rm_startblock, PREV.rm_blockcount,
1185fb7d9267SDarrick J. Wong 				PREV.rm_owner, PREV.rm_offset,
1186fb7d9267SDarrick J. Wong 				PREV.rm_flags);
1187fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1188fb7d9267SDarrick J. Wong 		if (error)
1189fb7d9267SDarrick J. Wong 			goto done;
1190f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1191f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1192f9e03706SDarrick J. Wong 			goto done;
1193f9e03706SDarrick J. Wong 		}
1194fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1195fb7d9267SDarrick J. Wong 		if (error)
1196fb7d9267SDarrick J. Wong 			goto done;
1197f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1198f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1199f9e03706SDarrick J. Wong 			goto done;
1200f9e03706SDarrick J. Wong 		}
1201fb7d9267SDarrick J. Wong 		NEW = LEFT;
1202fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1203fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1204fb7d9267SDarrick J. Wong 		if (error)
1205fb7d9267SDarrick J. Wong 			goto done;
1206fb7d9267SDarrick J. Wong 		break;
1207fb7d9267SDarrick J. Wong 
1208fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1209fb7d9267SDarrick J. Wong 		/*
1210fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1211fb7d9267SDarrick J. Wong 		 * The left neighbor is contiguous, the right is not.
1212fb7d9267SDarrick J. Wong 		 */
1213fb7d9267SDarrick J. Wong 		trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
1214fb7d9267SDarrick J. Wong 				PREV.rm_startblock, PREV.rm_blockcount,
1215fb7d9267SDarrick J. Wong 				PREV.rm_owner, PREV.rm_offset,
1216fb7d9267SDarrick J. Wong 				PREV.rm_flags);
1217fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1218fb7d9267SDarrick J. Wong 		if (error)
1219fb7d9267SDarrick J. Wong 			goto done;
1220f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1221f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1222f9e03706SDarrick J. Wong 			goto done;
1223f9e03706SDarrick J. Wong 		}
1224fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1225fb7d9267SDarrick J. Wong 		if (error)
1226fb7d9267SDarrick J. Wong 			goto done;
1227f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1228f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1229f9e03706SDarrick J. Wong 			goto done;
1230f9e03706SDarrick J. Wong 		}
1231fb7d9267SDarrick J. Wong 		NEW = LEFT;
1232fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount;
1233fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1234fb7d9267SDarrick J. Wong 		if (error)
1235fb7d9267SDarrick J. Wong 			goto done;
1236fb7d9267SDarrick J. Wong 		break;
1237fb7d9267SDarrick J. Wong 
1238fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1239fb7d9267SDarrick J. Wong 		/*
1240fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1241fb7d9267SDarrick J. Wong 		 * The right neighbor is contiguous, the left is not.
1242fb7d9267SDarrick J. Wong 		 */
1243fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1244fb7d9267SDarrick J. Wong 		if (error)
1245fb7d9267SDarrick J. Wong 			goto done;
1246f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1247f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1248f9e03706SDarrick J. Wong 			goto done;
1249f9e03706SDarrick J. Wong 		}
1250fb7d9267SDarrick J. Wong 		trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
1251fb7d9267SDarrick J. Wong 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
1252fb7d9267SDarrick J. Wong 				RIGHT.rm_owner, RIGHT.rm_offset,
1253fb7d9267SDarrick J. Wong 				RIGHT.rm_flags);
1254fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1255fb7d9267SDarrick J. Wong 		if (error)
1256fb7d9267SDarrick J. Wong 			goto done;
1257f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1258f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1259f9e03706SDarrick J. Wong 			goto done;
1260f9e03706SDarrick J. Wong 		}
1261fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1262fb7d9267SDarrick J. Wong 		if (error)
1263fb7d9267SDarrick J. Wong 			goto done;
1264f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1265f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1266f9e03706SDarrick J. Wong 			goto done;
1267f9e03706SDarrick J. Wong 		}
1268fb7d9267SDarrick J. Wong 		NEW = PREV;
1269fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len + RIGHT.rm_blockcount;
1270fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
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:
1277fb7d9267SDarrick J. Wong 		/*
1278fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1279fb7d9267SDarrick J. Wong 		 * Neither the left nor right neighbors are contiguous with
1280fb7d9267SDarrick J. Wong 		 * the new one.
1281fb7d9267SDarrick J. Wong 		 */
1282fb7d9267SDarrick J. Wong 		NEW = PREV;
1283fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1284fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1285fb7d9267SDarrick J. Wong 		if (error)
1286fb7d9267SDarrick J. Wong 			goto done;
1287fb7d9267SDarrick J. Wong 		break;
1288fb7d9267SDarrick J. Wong 
1289fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1290fb7d9267SDarrick J. Wong 		/*
1291fb7d9267SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
1292fb7d9267SDarrick J. Wong 		 * The left neighbor is contiguous.
1293fb7d9267SDarrick J. Wong 		 */
1294fb7d9267SDarrick J. Wong 		NEW = PREV;
1295fb7d9267SDarrick J. Wong 		NEW.rm_offset += len;
1296fb7d9267SDarrick J. Wong 		NEW.rm_startblock += len;
1297fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1298fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1299fb7d9267SDarrick J. Wong 		if (error)
1300fb7d9267SDarrick J. Wong 			goto done;
1301fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1302fb7d9267SDarrick J. Wong 		if (error)
1303fb7d9267SDarrick J. Wong 			goto done;
1304fb7d9267SDarrick J. Wong 		NEW = LEFT;
1305fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += len;
1306fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1307fb7d9267SDarrick J. Wong 		if (error)
1308fb7d9267SDarrick J. Wong 			goto done;
1309fb7d9267SDarrick J. Wong 		break;
1310fb7d9267SDarrick J. Wong 
1311fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING:
1312fb7d9267SDarrick J. Wong 		/*
1313fb7d9267SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
1314fb7d9267SDarrick J. Wong 		 * The left neighbor is not contiguous.
1315fb7d9267SDarrick J. Wong 		 */
1316fb7d9267SDarrick J. Wong 		NEW = PREV;
1317fb7d9267SDarrick J. Wong 		NEW.rm_startblock += len;
1318fb7d9267SDarrick J. Wong 		NEW.rm_offset += len;
1319fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1320fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1321fb7d9267SDarrick J. Wong 		if (error)
1322fb7d9267SDarrick J. Wong 			goto done;
1323fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1324fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1325fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1326fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len;
1327fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1328fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
1329fb7d9267SDarrick J. Wong 		trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
1330fb7d9267SDarrick J. Wong 				len, owner, offset, newext);
1331fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1332fb7d9267SDarrick J. Wong 		if (error)
1333fb7d9267SDarrick J. Wong 			goto done;
1334f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1335f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1336f9e03706SDarrick J. Wong 			goto done;
1337f9e03706SDarrick J. Wong 		}
1338fb7d9267SDarrick J. Wong 		break;
1339fb7d9267SDarrick J. Wong 
1340fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1341fb7d9267SDarrick J. Wong 		/*
1342fb7d9267SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
1343fb7d9267SDarrick J. Wong 		 * The right neighbor is contiguous with the new allocation.
1344fb7d9267SDarrick J. Wong 		 */
1345fb7d9267SDarrick J. Wong 		NEW = PREV;
1346fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1347fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1348fb7d9267SDarrick J. Wong 		if (error)
1349fb7d9267SDarrick J. Wong 			goto done;
1350fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1351fb7d9267SDarrick J. Wong 		if (error)
1352fb7d9267SDarrick J. Wong 			goto done;
1353fb7d9267SDarrick J. Wong 		NEW = RIGHT;
1354fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1355fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1356fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += len;
1357fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1358fb7d9267SDarrick J. Wong 		if (error)
1359fb7d9267SDarrick J. Wong 			goto done;
1360fb7d9267SDarrick J. Wong 		break;
1361fb7d9267SDarrick J. Wong 
1362fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING:
1363fb7d9267SDarrick J. Wong 		/*
1364fb7d9267SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
1365fb7d9267SDarrick J. Wong 		 * The right neighbor is not contiguous.
1366fb7d9267SDarrick J. Wong 		 */
1367fb7d9267SDarrick J. Wong 		NEW = PREV;
1368fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1369fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1370fb7d9267SDarrick J. Wong 		if (error)
1371fb7d9267SDarrick J. Wong 			goto done;
1372fb7d9267SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1373fb7d9267SDarrick J. Wong 				oldext, &i);
1374fb7d9267SDarrick J. Wong 		if (error)
1375fb7d9267SDarrick J. Wong 			goto done;
1376f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 0)) {
1377f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1378f9e03706SDarrick J. Wong 			goto done;
1379f9e03706SDarrick J. Wong 		}
1380fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1381fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1382fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1383fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len;
1384fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1385fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
1386fb7d9267SDarrick J. Wong 		trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
1387fb7d9267SDarrick J. Wong 				len, owner, offset, newext);
1388fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1389fb7d9267SDarrick J. Wong 		if (error)
1390fb7d9267SDarrick J. Wong 			goto done;
1391f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1392f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1393f9e03706SDarrick J. Wong 			goto done;
1394f9e03706SDarrick J. Wong 		}
1395fb7d9267SDarrick J. Wong 		break;
1396fb7d9267SDarrick J. Wong 
1397fb7d9267SDarrick J. Wong 	case 0:
1398fb7d9267SDarrick J. Wong 		/*
1399fb7d9267SDarrick J. Wong 		 * Setting the middle part of a previous oldext extent to
1400fb7d9267SDarrick J. Wong 		 * newext.  Contiguity is impossible here.
1401fb7d9267SDarrick J. Wong 		 * One extent becomes three extents.
1402fb7d9267SDarrick J. Wong 		 */
1403fb7d9267SDarrick J. Wong 		/* new right extent - oldext */
1404fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno + len;
1405fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1406fb7d9267SDarrick J. Wong 		NEW.rm_offset = new_endoff;
1407fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1408fb7d9267SDarrick J. Wong 				new_endoff;
1409fb7d9267SDarrick J. Wong 		NEW.rm_flags = PREV.rm_flags;
1410fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1411fb7d9267SDarrick J. Wong 		if (error)
1412fb7d9267SDarrick J. Wong 			goto done;
1413fb7d9267SDarrick J. Wong 		/* new left extent - oldext */
1414fb7d9267SDarrick J. Wong 		NEW = PREV;
1415fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = offset - PREV.rm_offset;
1416fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
1417fb7d9267SDarrick J. Wong 		trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
1418fb7d9267SDarrick J. Wong 				NEW.rm_startblock, NEW.rm_blockcount,
1419fb7d9267SDarrick J. Wong 				NEW.rm_owner, NEW.rm_offset,
1420fb7d9267SDarrick J. Wong 				NEW.rm_flags);
1421fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1422fb7d9267SDarrick J. Wong 		if (error)
1423fb7d9267SDarrick J. Wong 			goto done;
1424f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1425f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1426f9e03706SDarrick J. Wong 			goto done;
1427f9e03706SDarrick J. Wong 		}
1428fb7d9267SDarrick J. Wong 		/*
1429fb7d9267SDarrick J. Wong 		 * Reset the cursor to the position of the new extent
1430fb7d9267SDarrick J. Wong 		 * we are about to insert as we can't trust it after
1431fb7d9267SDarrick J. Wong 		 * the previous insert.
1432fb7d9267SDarrick J. Wong 		 */
1433fb7d9267SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1434fb7d9267SDarrick J. Wong 				oldext, &i);
1435fb7d9267SDarrick J. Wong 		if (error)
1436fb7d9267SDarrick J. Wong 			goto done;
1437f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 0)) {
1438f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1439f9e03706SDarrick J. Wong 			goto done;
1440f9e03706SDarrick J. Wong 		}
1441fb7d9267SDarrick J. Wong 		/* new middle extent - newext */
1442fb7d9267SDarrick J. Wong 		cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
1443fb7d9267SDarrick J. Wong 		cur->bc_rec.r.rm_flags |= newext;
1444fb7d9267SDarrick J. Wong 		trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
1445fb7d9267SDarrick J. Wong 				owner, offset, newext);
1446fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1447fb7d9267SDarrick J. Wong 		if (error)
1448fb7d9267SDarrick J. Wong 			goto done;
1449f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1450f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1451f9e03706SDarrick J. Wong 			goto done;
1452f9e03706SDarrick J. Wong 		}
1453fb7d9267SDarrick J. Wong 		break;
1454fb7d9267SDarrick J. Wong 
1455fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1456fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1457fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1458fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1459fb7d9267SDarrick J. Wong 	case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1460fb7d9267SDarrick J. Wong 	case RMAP_LEFT_CONTIG:
1461fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_CONTIG:
1462fb7d9267SDarrick J. Wong 		/*
1463fb7d9267SDarrick J. Wong 		 * These cases are all impossible.
1464fb7d9267SDarrick J. Wong 		 */
1465fb7d9267SDarrick J. Wong 		ASSERT(0);
1466fb7d9267SDarrick J. Wong 	}
1467fb7d9267SDarrick J. Wong 
1468fb7d9267SDarrick J. Wong 	trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len,
1469fb7d9267SDarrick J. Wong 			unwritten, oinfo);
1470fb7d9267SDarrick J. Wong done:
1471fb7d9267SDarrick J. Wong 	if (error)
1472fb7d9267SDarrick J. Wong 		trace_xfs_rmap_convert_error(cur->bc_mp,
1473fb7d9267SDarrick J. Wong 				cur->bc_private.a.agno, error, _RET_IP_);
1474fb7d9267SDarrick J. Wong 	return error;
1475fb7d9267SDarrick J. Wong }
1476fb7d9267SDarrick J. Wong 
14773f165b33SDarrick J. Wong /*
14783f165b33SDarrick J. Wong  * Convert an unwritten extent to a real extent or vice versa.  If there is no
14793f165b33SDarrick J. Wong  * possibility of overlapping extents, delegate to the simpler convert
14803f165b33SDarrick J. Wong  * function.
14813f165b33SDarrick J. Wong  */
14823f165b33SDarrick J. Wong STATIC int
14833f165b33SDarrick J. Wong xfs_rmap_convert_shared(
14843f165b33SDarrick J. Wong 	struct xfs_btree_cur		*cur,
14853f165b33SDarrick J. Wong 	xfs_agblock_t			bno,
14863f165b33SDarrick J. Wong 	xfs_extlen_t			len,
14873f165b33SDarrick J. Wong 	bool				unwritten,
148866e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
14893f165b33SDarrick J. Wong {
14903f165b33SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
14913f165b33SDarrick J. Wong 	struct xfs_rmap_irec		r[4];	/* neighbor extent entries */
149266e3237eSDarrick J. Wong 						/* left is 0, right is 1, */
149366e3237eSDarrick J. Wong 						/* prev is 2, new is 3 */
14943f165b33SDarrick J. Wong 	uint64_t		owner;
14953f165b33SDarrick J. Wong 	uint64_t		offset;
14963f165b33SDarrick J. Wong 	uint64_t		new_endoff;
14973f165b33SDarrick J. Wong 	unsigned int		oldext;
14983f165b33SDarrick J. Wong 	unsigned int		newext;
14993f165b33SDarrick J. Wong 	unsigned int		flags = 0;
15003f165b33SDarrick J. Wong 	int			i;
15013f165b33SDarrick J. Wong 	int			state = 0;
15023f165b33SDarrick J. Wong 	int			error;
15033f165b33SDarrick J. Wong 
15043f165b33SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
15053f165b33SDarrick J. Wong 	ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
15063f165b33SDarrick J. Wong 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
15073f165b33SDarrick J. Wong 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
15083f165b33SDarrick J. Wong 	new_endoff = offset + len;
15093f165b33SDarrick J. Wong 	trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len,
15103f165b33SDarrick J. Wong 			unwritten, oinfo);
15113f165b33SDarrick J. Wong 
15123f165b33SDarrick J. Wong 	/*
15133f165b33SDarrick J. Wong 	 * For the initial lookup, look for and exact match or the left-adjacent
15143f165b33SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
15153f165b33SDarrick J. Wong 	 * start block contiguity tests.
15163f165b33SDarrick J. Wong 	 */
15173f165b33SDarrick J. Wong 	error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
15183f165b33SDarrick J. Wong 			&PREV, &i);
151952101dfeSDarrick J. Wong 	if (error)
152052101dfeSDarrick J. Wong 		goto done;
1521f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1522f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1523f9e03706SDarrick J. Wong 		goto done;
1524f9e03706SDarrick J. Wong 	}
15253f165b33SDarrick J. Wong 
15263f165b33SDarrick J. Wong 	ASSERT(PREV.rm_offset <= offset);
15273f165b33SDarrick J. Wong 	ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
15283f165b33SDarrick J. Wong 	ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
15293f165b33SDarrick J. Wong 	newext = ~oldext & XFS_RMAP_UNWRITTEN;
15303f165b33SDarrick J. Wong 
15313f165b33SDarrick J. Wong 	/*
15323f165b33SDarrick J. Wong 	 * Set flags determining what part of the previous oldext allocation
15333f165b33SDarrick J. Wong 	 * extent is being replaced by a newext allocation.
15343f165b33SDarrick J. Wong 	 */
15353f165b33SDarrick J. Wong 	if (PREV.rm_offset == offset)
15363f165b33SDarrick J. Wong 		state |= RMAP_LEFT_FILLING;
15373f165b33SDarrick J. Wong 	if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
15383f165b33SDarrick J. Wong 		state |= RMAP_RIGHT_FILLING;
15393f165b33SDarrick J. Wong 
15403f165b33SDarrick J. Wong 	/* Is there a left record that abuts our range? */
15413f165b33SDarrick J. Wong 	error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext,
15423f165b33SDarrick J. Wong 			&LEFT, &i);
15433f165b33SDarrick J. Wong 	if (error)
15443f165b33SDarrick J. Wong 		goto done;
15453f165b33SDarrick J. Wong 	if (i) {
15463f165b33SDarrick J. Wong 		state |= RMAP_LEFT_VALID;
1547f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
1548f9e03706SDarrick J. Wong 				   LEFT.rm_startblock + LEFT.rm_blockcount >
1549f9e03706SDarrick J. Wong 				   bno)) {
1550f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1551f9e03706SDarrick J. Wong 			goto done;
1552f9e03706SDarrick J. Wong 		}
15533f165b33SDarrick J. Wong 		if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
15543f165b33SDarrick J. Wong 			state |= RMAP_LEFT_CONTIG;
15553f165b33SDarrick J. Wong 	}
15563f165b33SDarrick J. Wong 
15573f165b33SDarrick J. Wong 	/* Is there a right record that abuts our range? */
15583f165b33SDarrick J. Wong 	error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
15593f165b33SDarrick J. Wong 			newext, &i);
15603f165b33SDarrick J. Wong 	if (error)
15613f165b33SDarrick J. Wong 		goto done;
15623f165b33SDarrick J. Wong 	if (i) {
15633f165b33SDarrick J. Wong 		state |= RMAP_RIGHT_VALID;
15643f165b33SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &RIGHT, &i);
15653f165b33SDarrick J. Wong 		if (error)
15663f165b33SDarrick J. Wong 			goto done;
1567f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1568f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1569f9e03706SDarrick J. Wong 			goto done;
1570f9e03706SDarrick J. Wong 		}
1571f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1572f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1573f9e03706SDarrick J. Wong 			goto done;
1574f9e03706SDarrick J. Wong 		}
15753f165b33SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
15763f165b33SDarrick J. Wong 				cur->bc_private.a.agno, RIGHT.rm_startblock,
15773f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
15783f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
15793f165b33SDarrick J. Wong 		if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
15803f165b33SDarrick J. Wong 			state |= RMAP_RIGHT_CONTIG;
15813f165b33SDarrick J. Wong 	}
15823f165b33SDarrick J. Wong 
15833f165b33SDarrick J. Wong 	/* check that left + prev + right is not too long */
15843f165b33SDarrick J. Wong 	if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
15853f165b33SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
15863f165b33SDarrick J. Wong 	    (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
15873f165b33SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
15883f165b33SDarrick J. Wong 	    (unsigned long)LEFT.rm_blockcount + len +
15893f165b33SDarrick J. Wong 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
15903f165b33SDarrick J. Wong 		state &= ~RMAP_RIGHT_CONTIG;
15913f165b33SDarrick J. Wong 
15923f165b33SDarrick J. Wong 	trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state,
15933f165b33SDarrick J. Wong 			_RET_IP_);
15943f165b33SDarrick J. Wong 	/*
15953f165b33SDarrick J. Wong 	 * Switch out based on the FILLING and CONTIG state bits.
15963f165b33SDarrick J. Wong 	 */
15973f165b33SDarrick J. Wong 	switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
15983f165b33SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
15993f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16003f165b33SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
16013f165b33SDarrick J. Wong 		/*
16023f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16033f165b33SDarrick J. Wong 		 * The left and right neighbors are both contiguous with new.
16043f165b33SDarrick J. Wong 		 */
16053f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
16063f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
16073f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
16083f165b33SDarrick J. Wong 		if (error)
16093f165b33SDarrick J. Wong 			goto done;
16103f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, PREV.rm_startblock,
16113f165b33SDarrick J. Wong 				PREV.rm_blockcount, PREV.rm_owner,
16123f165b33SDarrick J. Wong 				PREV.rm_offset, PREV.rm_flags);
16133f165b33SDarrick J. Wong 		if (error)
16143f165b33SDarrick J. Wong 			goto done;
16153f165b33SDarrick J. Wong 		NEW = LEFT;
16163f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
16173f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
16183f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
16193f165b33SDarrick J. Wong 		if (error)
16203f165b33SDarrick J. Wong 			goto done;
1621f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1622f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1623f9e03706SDarrick J. Wong 			goto done;
1624f9e03706SDarrick J. Wong 		}
16253f165b33SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
16263f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
16273f165b33SDarrick J. Wong 		if (error)
16283f165b33SDarrick J. Wong 			goto done;
16293f165b33SDarrick J. Wong 		break;
16303f165b33SDarrick J. Wong 
16313f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
16323f165b33SDarrick J. Wong 		/*
16333f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16343f165b33SDarrick J. Wong 		 * The left neighbor is contiguous, the right is not.
16353f165b33SDarrick J. Wong 		 */
16363f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, PREV.rm_startblock,
16373f165b33SDarrick J. Wong 				PREV.rm_blockcount, PREV.rm_owner,
16383f165b33SDarrick J. Wong 				PREV.rm_offset, PREV.rm_flags);
16393f165b33SDarrick J. Wong 		if (error)
16403f165b33SDarrick J. Wong 			goto done;
16413f165b33SDarrick J. Wong 		NEW = LEFT;
16423f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
16433f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
16443f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
16453f165b33SDarrick J. Wong 		if (error)
16463f165b33SDarrick J. Wong 			goto done;
1647f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1648f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1649f9e03706SDarrick J. Wong 			goto done;
1650f9e03706SDarrick J. Wong 		}
16513f165b33SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount;
16523f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
16533f165b33SDarrick J. Wong 		if (error)
16543f165b33SDarrick J. Wong 			goto done;
16553f165b33SDarrick J. Wong 		break;
16563f165b33SDarrick J. Wong 
16573f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
16583f165b33SDarrick J. Wong 		/*
16593f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16603f165b33SDarrick J. Wong 		 * The right neighbor is contiguous, the left is not.
16613f165b33SDarrick J. Wong 		 */
16623f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
16633f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
16643f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
16653f165b33SDarrick J. Wong 		if (error)
16663f165b33SDarrick J. Wong 			goto done;
16673f165b33SDarrick J. Wong 		NEW = PREV;
16683f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
16693f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
16703f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
16713f165b33SDarrick J. Wong 		if (error)
16723f165b33SDarrick J. Wong 			goto done;
1673f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1674f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1675f9e03706SDarrick J. Wong 			goto done;
1676f9e03706SDarrick J. Wong 		}
16773f165b33SDarrick J. Wong 		NEW.rm_blockcount += RIGHT.rm_blockcount;
16783f165b33SDarrick J. Wong 		NEW.rm_flags = RIGHT.rm_flags;
16793f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
16803f165b33SDarrick J. Wong 		if (error)
16813f165b33SDarrick J. Wong 			goto done;
16823f165b33SDarrick J. Wong 		break;
16833f165b33SDarrick J. Wong 
16843f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
16853f165b33SDarrick J. Wong 		/*
16863f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16873f165b33SDarrick J. Wong 		 * Neither the left nor right neighbors are contiguous with
16883f165b33SDarrick J. Wong 		 * the new one.
16893f165b33SDarrick J. Wong 		 */
16903f165b33SDarrick J. Wong 		NEW = PREV;
16913f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
16923f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
16933f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
16943f165b33SDarrick J. Wong 		if (error)
16953f165b33SDarrick J. Wong 			goto done;
1696f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1697f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1698f9e03706SDarrick J. Wong 			goto done;
1699f9e03706SDarrick J. Wong 		}
17003f165b33SDarrick J. Wong 		NEW.rm_flags = newext;
17013f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17023f165b33SDarrick J. Wong 		if (error)
17033f165b33SDarrick J. Wong 			goto done;
17043f165b33SDarrick J. Wong 		break;
17053f165b33SDarrick J. Wong 
17063f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
17073f165b33SDarrick J. Wong 		/*
17083f165b33SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
17093f165b33SDarrick J. Wong 		 * The left neighbor is contiguous.
17103f165b33SDarrick J. Wong 		 */
17113f165b33SDarrick J. Wong 		NEW = PREV;
17123f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
17133f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17143f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17153f165b33SDarrick J. Wong 		if (error)
17163f165b33SDarrick J. Wong 			goto done;
17173f165b33SDarrick J. Wong 		NEW.rm_offset += len;
17183f165b33SDarrick J. Wong 		NEW.rm_startblock += len;
17193f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
17203f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
17213f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17223f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17233f165b33SDarrick J. Wong 		if (error)
17243f165b33SDarrick J. Wong 			goto done;
17253f165b33SDarrick J. Wong 		NEW = LEFT;
17263f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17273f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17283f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17293f165b33SDarrick J. Wong 		if (error)
17303f165b33SDarrick J. Wong 			goto done;
1731f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1732f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1733f9e03706SDarrick J. Wong 			goto done;
1734f9e03706SDarrick J. Wong 		}
17353f165b33SDarrick J. Wong 		NEW.rm_blockcount += len;
17363f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17373f165b33SDarrick J. Wong 		if (error)
17383f165b33SDarrick J. Wong 			goto done;
17393f165b33SDarrick J. Wong 		break;
17403f165b33SDarrick J. Wong 
17413f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING:
17423f165b33SDarrick J. Wong 		/*
17433f165b33SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
17443f165b33SDarrick J. Wong 		 * The left neighbor is not contiguous.
17453f165b33SDarrick J. Wong 		 */
17463f165b33SDarrick J. Wong 		NEW = PREV;
17473f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
17483f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17493f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17503f165b33SDarrick J. Wong 		if (error)
17513f165b33SDarrick J. Wong 			goto done;
17523f165b33SDarrick J. Wong 		NEW.rm_offset += len;
17533f165b33SDarrick J. Wong 		NEW.rm_startblock += len;
17543f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
17553f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
17563f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17573f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
17583f165b33SDarrick J. Wong 		if (error)
17593f165b33SDarrick J. Wong 			goto done;
17603f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
17613f165b33SDarrick J. Wong 		if (error)
17623f165b33SDarrick J. Wong 			goto done;
17633f165b33SDarrick J. Wong 		break;
17643f165b33SDarrick J. Wong 
17653f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
17663f165b33SDarrick J. Wong 		/*
17673f165b33SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
17683f165b33SDarrick J. Wong 		 * The right neighbor is contiguous with the new allocation.
17693f165b33SDarrick J. Wong 		 */
17703f165b33SDarrick J. Wong 		NEW = PREV;
17713f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17723f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17733f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17743f165b33SDarrick J. Wong 		if (error)
17753f165b33SDarrick J. Wong 			goto done;
1776f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1777f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1778f9e03706SDarrick J. Wong 			goto done;
1779f9e03706SDarrick J. Wong 		}
17803f165b33SDarrick J. Wong 		NEW.rm_blockcount = offset - NEW.rm_offset;
17813f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17823f165b33SDarrick J. Wong 		if (error)
17833f165b33SDarrick J. Wong 			goto done;
17843f165b33SDarrick J. Wong 		NEW = RIGHT;
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 = offset;
17913f165b33SDarrick J. Wong 		NEW.rm_startblock = bno;
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 		break;
17993f165b33SDarrick J. Wong 
18003f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING:
18013f165b33SDarrick J. Wong 		/*
18023f165b33SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
18033f165b33SDarrick J. Wong 		 * The right neighbor is not contiguous.
18043f165b33SDarrick J. Wong 		 */
18053f165b33SDarrick J. Wong 		NEW = PREV;
18063f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18073f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18083f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18093f165b33SDarrick J. Wong 		if (error)
18103f165b33SDarrick J. Wong 			goto done;
1811f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1812f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1813f9e03706SDarrick J. Wong 			goto done;
1814f9e03706SDarrick J. Wong 		}
18153f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
18163f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18173f165b33SDarrick J. Wong 		if (error)
18183f165b33SDarrick J. Wong 			goto done;
18193f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
18203f165b33SDarrick J. Wong 		if (error)
18213f165b33SDarrick J. Wong 			goto done;
18223f165b33SDarrick J. Wong 		break;
18233f165b33SDarrick J. Wong 
18243f165b33SDarrick J. Wong 	case 0:
18253f165b33SDarrick J. Wong 		/*
18263f165b33SDarrick J. Wong 		 * Setting the middle part of a previous oldext extent to
18273f165b33SDarrick J. Wong 		 * newext.  Contiguity is impossible here.
18283f165b33SDarrick J. Wong 		 * One extent becomes three extents.
18293f165b33SDarrick J. Wong 		 */
18303f165b33SDarrick J. Wong 		/* new right extent - oldext */
18313f165b33SDarrick J. Wong 		NEW.rm_startblock = bno + len;
18323f165b33SDarrick J. Wong 		NEW.rm_owner = owner;
18333f165b33SDarrick J. Wong 		NEW.rm_offset = new_endoff;
18343f165b33SDarrick J. Wong 		NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
18353f165b33SDarrick J. Wong 				new_endoff;
18363f165b33SDarrick J. Wong 		NEW.rm_flags = PREV.rm_flags;
18373f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18383f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
18393f165b33SDarrick J. Wong 				NEW.rm_flags);
18403f165b33SDarrick J. Wong 		if (error)
18413f165b33SDarrick J. Wong 			goto done;
18423f165b33SDarrick J. Wong 		/* new left extent - oldext */
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 = offset - NEW.rm_offset;
18543f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18553f165b33SDarrick J. Wong 		if (error)
18563f165b33SDarrick J. Wong 			goto done;
18573f165b33SDarrick J. Wong 		/* new middle extent - newext */
18583f165b33SDarrick J. Wong 		NEW.rm_startblock = bno;
18593f165b33SDarrick J. Wong 		NEW.rm_blockcount = len;
18603f165b33SDarrick J. Wong 		NEW.rm_owner = owner;
18613f165b33SDarrick J. Wong 		NEW.rm_offset = offset;
18623f165b33SDarrick J. Wong 		NEW.rm_flags = newext;
18633f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18643f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
18653f165b33SDarrick J. Wong 				NEW.rm_flags);
18663f165b33SDarrick J. Wong 		if (error)
18673f165b33SDarrick J. Wong 			goto done;
18683f165b33SDarrick J. Wong 		break;
18693f165b33SDarrick J. Wong 
18703f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
18713f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
18723f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
18733f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
18743f165b33SDarrick J. Wong 	case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
18753f165b33SDarrick J. Wong 	case RMAP_LEFT_CONTIG:
18763f165b33SDarrick J. Wong 	case RMAP_RIGHT_CONTIG:
18773f165b33SDarrick J. Wong 		/*
18783f165b33SDarrick J. Wong 		 * These cases are all impossible.
18793f165b33SDarrick J. Wong 		 */
18803f165b33SDarrick J. Wong 		ASSERT(0);
18813f165b33SDarrick J. Wong 	}
18823f165b33SDarrick J. Wong 
18833f165b33SDarrick J. Wong 	trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len,
18843f165b33SDarrick J. Wong 			unwritten, oinfo);
18853f165b33SDarrick J. Wong done:
18863f165b33SDarrick J. Wong 	if (error)
18873f165b33SDarrick J. Wong 		trace_xfs_rmap_convert_error(cur->bc_mp,
18883f165b33SDarrick J. Wong 				cur->bc_private.a.agno, error, _RET_IP_);
18893f165b33SDarrick J. Wong 	return error;
18903f165b33SDarrick J. Wong }
18913f165b33SDarrick J. Wong 
1892fb7d9267SDarrick J. Wong #undef	NEW
1893fb7d9267SDarrick J. Wong #undef	LEFT
1894fb7d9267SDarrick J. Wong #undef	RIGHT
1895fb7d9267SDarrick J. Wong #undef	PREV
1896fb7d9267SDarrick J. Wong 
1897ceeb9c83SDarrick J. Wong /*
1898ceeb9c83SDarrick J. Wong  * Find an extent in the rmap btree and unmap it.  For rmap extent types that
1899ceeb9c83SDarrick J. Wong  * can overlap (data fork rmaps on reflink filesystems) we must be careful
1900ceeb9c83SDarrick J. Wong  * that the prev/next records in the btree might belong to another owner.
1901ceeb9c83SDarrick J. Wong  * Therefore we must use delete+insert to alter any of the key fields.
1902ceeb9c83SDarrick J. Wong  *
1903ceeb9c83SDarrick J. Wong  * For every other situation there can only be one owner for a given extent,
1904ceeb9c83SDarrick J. Wong  * so we can call the regular _free function.
1905ceeb9c83SDarrick J. Wong  */
1906ceeb9c83SDarrick J. Wong STATIC int
1907ceeb9c83SDarrick J. Wong xfs_rmap_unmap_shared(
1908ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
1909ceeb9c83SDarrick J. Wong 	xfs_agblock_t			bno,
1910ceeb9c83SDarrick J. Wong 	xfs_extlen_t			len,
1911ceeb9c83SDarrick J. Wong 	bool				unwritten,
191266e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
1913ceeb9c83SDarrick J. Wong {
1914ceeb9c83SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
1915ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
1916ceeb9c83SDarrick J. Wong 	uint64_t			ltoff;
1917ceeb9c83SDarrick J. Wong 	int				error = 0;
1918ceeb9c83SDarrick J. Wong 	int				i;
1919ceeb9c83SDarrick J. Wong 	uint64_t			owner;
1920ceeb9c83SDarrick J. Wong 	uint64_t			offset;
1921ceeb9c83SDarrick J. Wong 	unsigned int			flags;
1922ceeb9c83SDarrick J. Wong 
1923ceeb9c83SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1924ceeb9c83SDarrick J. Wong 	if (unwritten)
1925ceeb9c83SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
1926ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
1927ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
1928ceeb9c83SDarrick J. Wong 
1929ceeb9c83SDarrick J. Wong 	/*
1930ceeb9c83SDarrick J. Wong 	 * We should always have a left record because there's a static record
1931ceeb9c83SDarrick J. Wong 	 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
1932ceeb9c83SDarrick J. Wong 	 * will not ever be removed from the tree.
1933ceeb9c83SDarrick J. Wong 	 */
1934ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
1935ceeb9c83SDarrick J. Wong 			&ltrec, &i);
1936ceeb9c83SDarrick J. Wong 	if (error)
1937ceeb9c83SDarrick J. Wong 		goto out_error;
1938f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1939f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1940f9e03706SDarrick J. Wong 		goto out_error;
1941f9e03706SDarrick J. Wong 	}
1942ceeb9c83SDarrick J. Wong 	ltoff = ltrec.rm_offset;
1943ceeb9c83SDarrick J. Wong 
1944ceeb9c83SDarrick J. Wong 	/* Make sure the extent we found covers the entire freeing range. */
1945f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
1946f9e03706SDarrick J. Wong 			   ltrec.rm_startblock > bno ||
1947f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount <
1948f9e03706SDarrick J. Wong 			   bno + len)) {
1949f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1950f9e03706SDarrick J. Wong 		goto out_error;
1951f9e03706SDarrick J. Wong 	}
1952ceeb9c83SDarrick J. Wong 
1953ceeb9c83SDarrick J. Wong 	/* Make sure the owner matches what we expect to find in the tree. */
1954f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
1955f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1956f9e03706SDarrick J. Wong 		goto out_error;
1957f9e03706SDarrick J. Wong 	}
1958ceeb9c83SDarrick J. Wong 
1959ceeb9c83SDarrick J. Wong 	/* Make sure the unwritten flag matches. */
1960f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
1961f9e03706SDarrick J. Wong 			   (flags & XFS_RMAP_UNWRITTEN) !=
1962f9e03706SDarrick J. Wong 			   (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
1963f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1964f9e03706SDarrick J. Wong 		goto out_error;
1965f9e03706SDarrick J. Wong 	}
1966ceeb9c83SDarrick J. Wong 
1967ceeb9c83SDarrick J. Wong 	/* Check the offset. */
1968f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
1969f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1970f9e03706SDarrick J. Wong 		goto out_error;
1971f9e03706SDarrick J. Wong 	}
1972f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
1973f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1974f9e03706SDarrick J. Wong 		goto out_error;
1975f9e03706SDarrick J. Wong 	}
1976ceeb9c83SDarrick J. Wong 
1977ceeb9c83SDarrick J. Wong 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
1978ceeb9c83SDarrick J. Wong 		/* Exact match, simply remove the record from rmap tree. */
1979ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, ltrec.rm_startblock,
1980ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
1981ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
1982ceeb9c83SDarrick J. Wong 		if (error)
1983ceeb9c83SDarrick J. Wong 			goto out_error;
1984ceeb9c83SDarrick J. Wong 	} else if (ltrec.rm_startblock == bno) {
1985ceeb9c83SDarrick J. Wong 		/*
1986ceeb9c83SDarrick J. Wong 		 * Overlap left hand side of extent: move the start, trim the
1987ceeb9c83SDarrick J. Wong 		 * length and update the current record.
1988ceeb9c83SDarrick J. Wong 		 *
1989ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
1990ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
1991ceeb9c83SDarrick J. Wong 		 * Freeing: |fffffffff|
1992ceeb9c83SDarrick J. Wong 		 * Result:            |rrrrrrrrrr|
1993ceeb9c83SDarrick J. Wong 		 *         bno       len
1994ceeb9c83SDarrick J. Wong 		 */
1995ceeb9c83SDarrick J. Wong 
1996ceeb9c83SDarrick J. Wong 		/* Delete prev rmap. */
1997ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, ltrec.rm_startblock,
1998ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
1999ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2000ceeb9c83SDarrick J. Wong 		if (error)
2001ceeb9c83SDarrick J. Wong 			goto out_error;
2002ceeb9c83SDarrick J. Wong 
2003ceeb9c83SDarrick J. Wong 		/* Add an rmap at the new offset. */
2004ceeb9c83SDarrick J. Wong 		ltrec.rm_startblock += len;
2005ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount -= len;
2006ceeb9c83SDarrick J. Wong 		ltrec.rm_offset += len;
2007ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, ltrec.rm_startblock,
2008ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2009ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2010ceeb9c83SDarrick J. Wong 		if (error)
2011ceeb9c83SDarrick J. Wong 			goto out_error;
2012ceeb9c83SDarrick J. Wong 	} else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
2013ceeb9c83SDarrick J. Wong 		/*
2014ceeb9c83SDarrick J. Wong 		 * Overlap right hand side of extent: trim the length and
2015ceeb9c83SDarrick J. Wong 		 * update the current record.
2016ceeb9c83SDarrick J. Wong 		 *
2017ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2018ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2019ceeb9c83SDarrick J. Wong 		 * Freeing:            |fffffffff|
2020ceeb9c83SDarrick J. Wong 		 * Result:  |rrrrrrrrrr|
2021ceeb9c83SDarrick J. Wong 		 *                    bno       len
2022ceeb9c83SDarrick J. Wong 		 */
2023ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2024ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2025ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2026ceeb9c83SDarrick J. Wong 		if (error)
2027ceeb9c83SDarrick J. Wong 			goto out_error;
2028f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2029f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2030f9e03706SDarrick J. Wong 			goto out_error;
2031f9e03706SDarrick J. Wong 		}
2032ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount -= len;
2033ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2034ceeb9c83SDarrick J. Wong 		if (error)
2035ceeb9c83SDarrick J. Wong 			goto out_error;
2036ceeb9c83SDarrick J. Wong 	} else {
2037ceeb9c83SDarrick J. Wong 		/*
2038ceeb9c83SDarrick J. Wong 		 * Overlap middle of extent: trim the length of the existing
2039ceeb9c83SDarrick J. Wong 		 * record to the length of the new left-extent size, increment
2040ceeb9c83SDarrick J. Wong 		 * the insertion position so we can insert a new record
2041ceeb9c83SDarrick J. Wong 		 * containing the remaining right-extent space.
2042ceeb9c83SDarrick J. Wong 		 *
2043ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2044ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2045ceeb9c83SDarrick J. Wong 		 * Freeing:       |fffffffff|
2046ceeb9c83SDarrick J. Wong 		 * Result:  |rrrrr|         |rrrr|
2047ceeb9c83SDarrick J. Wong 		 *               bno       len
2048ceeb9c83SDarrick J. Wong 		 */
2049ceeb9c83SDarrick J. Wong 		xfs_extlen_t	orig_len = ltrec.rm_blockcount;
2050ceeb9c83SDarrick J. Wong 
2051ceeb9c83SDarrick J. Wong 		/* Shrink the left side of the rmap */
2052ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2053ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2054ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2055ceeb9c83SDarrick J. Wong 		if (error)
2056ceeb9c83SDarrick J. Wong 			goto out_error;
2057f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2058f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2059f9e03706SDarrick J. Wong 			goto out_error;
2060f9e03706SDarrick J. Wong 		}
2061ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount = bno - ltrec.rm_startblock;
2062ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2063ceeb9c83SDarrick J. Wong 		if (error)
2064ceeb9c83SDarrick J. Wong 			goto out_error;
2065ceeb9c83SDarrick J. Wong 
2066ceeb9c83SDarrick J. Wong 		/* Add an rmap at the new offset */
2067ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno + len,
2068ceeb9c83SDarrick J. Wong 				orig_len - len - ltrec.rm_blockcount,
2069ceeb9c83SDarrick J. Wong 				ltrec.rm_owner, offset + len,
2070ceeb9c83SDarrick J. Wong 				ltrec.rm_flags);
2071ceeb9c83SDarrick J. Wong 		if (error)
2072ceeb9c83SDarrick J. Wong 			goto out_error;
2073ceeb9c83SDarrick J. Wong 	}
2074ceeb9c83SDarrick J. Wong 
2075ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
2076ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2077ceeb9c83SDarrick J. Wong out_error:
2078ceeb9c83SDarrick J. Wong 	if (error)
2079ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_unmap_error(cur->bc_mp,
2080ceeb9c83SDarrick J. Wong 				cur->bc_private.a.agno, error, _RET_IP_);
2081ceeb9c83SDarrick J. Wong 	return error;
2082ceeb9c83SDarrick J. Wong }
2083ceeb9c83SDarrick J. Wong 
2084ceeb9c83SDarrick J. Wong /*
2085ceeb9c83SDarrick J. Wong  * Find an extent in the rmap btree and map it.  For rmap extent types that
2086ceeb9c83SDarrick J. Wong  * can overlap (data fork rmaps on reflink filesystems) we must be careful
2087ceeb9c83SDarrick J. Wong  * that the prev/next records in the btree might belong to another owner.
2088ceeb9c83SDarrick J. Wong  * Therefore we must use delete+insert to alter any of the key fields.
2089ceeb9c83SDarrick J. Wong  *
2090ceeb9c83SDarrick J. Wong  * For every other situation there can only be one owner for a given extent,
2091ceeb9c83SDarrick J. Wong  * so we can call the regular _alloc function.
2092ceeb9c83SDarrick J. Wong  */
2093ceeb9c83SDarrick J. Wong STATIC int
2094ceeb9c83SDarrick J. Wong xfs_rmap_map_shared(
2095ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2096ceeb9c83SDarrick J. Wong 	xfs_agblock_t			bno,
2097ceeb9c83SDarrick J. Wong 	xfs_extlen_t			len,
2098ceeb9c83SDarrick J. Wong 	bool				unwritten,
209966e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
2100ceeb9c83SDarrick J. Wong {
2101ceeb9c83SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
2102ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
2103ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		gtrec;
2104ceeb9c83SDarrick J. Wong 	int				have_gt;
2105ceeb9c83SDarrick J. Wong 	int				have_lt;
2106ceeb9c83SDarrick J. Wong 	int				error = 0;
2107ceeb9c83SDarrick J. Wong 	int				i;
2108ceeb9c83SDarrick J. Wong 	uint64_t			owner;
2109ceeb9c83SDarrick J. Wong 	uint64_t			offset;
2110ceeb9c83SDarrick J. Wong 	unsigned int			flags = 0;
2111ceeb9c83SDarrick J. Wong 
2112ceeb9c83SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2113ceeb9c83SDarrick J. Wong 	if (unwritten)
2114ceeb9c83SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
2115ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
2116ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2117ceeb9c83SDarrick J. Wong 
2118ceeb9c83SDarrick J. Wong 	/* Is there a left record that abuts our range? */
2119ceeb9c83SDarrick J. Wong 	error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
2120ceeb9c83SDarrick J. Wong 			&ltrec, &have_lt);
2121ceeb9c83SDarrick J. Wong 	if (error)
2122ceeb9c83SDarrick J. Wong 		goto out_error;
2123ceeb9c83SDarrick J. Wong 	if (have_lt &&
2124ceeb9c83SDarrick J. Wong 	    !xfs_rmap_is_mergeable(&ltrec, owner, flags))
2125ceeb9c83SDarrick J. Wong 		have_lt = 0;
2126ceeb9c83SDarrick J. Wong 
2127ceeb9c83SDarrick J. Wong 	/* Is there a right record that abuts our range? */
2128ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
2129ceeb9c83SDarrick J. Wong 			flags, &have_gt);
2130ceeb9c83SDarrick J. Wong 	if (error)
2131ceeb9c83SDarrick J. Wong 		goto out_error;
2132ceeb9c83SDarrick J. Wong 	if (have_gt) {
2133ceeb9c83SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
2134ceeb9c83SDarrick J. Wong 		if (error)
2135ceeb9c83SDarrick J. Wong 			goto out_error;
2136f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
2137f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2138f9e03706SDarrick J. Wong 			goto out_error;
2139f9e03706SDarrick J. Wong 		}
2140ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
2141ceeb9c83SDarrick J. Wong 			cur->bc_private.a.agno, gtrec.rm_startblock,
2142ceeb9c83SDarrick J. Wong 			gtrec.rm_blockcount, gtrec.rm_owner,
2143ceeb9c83SDarrick J. Wong 			gtrec.rm_offset, gtrec.rm_flags);
2144ceeb9c83SDarrick J. Wong 
2145ceeb9c83SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
2146ceeb9c83SDarrick J. Wong 			have_gt = 0;
2147ceeb9c83SDarrick J. Wong 	}
2148ceeb9c83SDarrick J. Wong 
2149ceeb9c83SDarrick J. Wong 	if (have_lt &&
2150ceeb9c83SDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
2151ceeb9c83SDarrick J. Wong 	    ltrec.rm_offset + ltrec.rm_blockcount == offset) {
2152ceeb9c83SDarrick J. Wong 		/*
2153ceeb9c83SDarrick J. Wong 		 * Left edge contiguous, merge into left record.
2154ceeb9c83SDarrick J. Wong 		 *
2155ceeb9c83SDarrick J. Wong 		 *       ltbno     ltlen
2156ceeb9c83SDarrick J. Wong 		 * orig:   |ooooooooo|
2157ceeb9c83SDarrick J. Wong 		 * adding:           |aaaaaaaaa|
2158ceeb9c83SDarrick J. Wong 		 * result: |rrrrrrrrrrrrrrrrrrr|
2159ceeb9c83SDarrick J. Wong 		 *                  bno       len
2160ceeb9c83SDarrick J. Wong 		 */
2161ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount += len;
2162ceeb9c83SDarrick J. Wong 		if (have_gt &&
2163ceeb9c83SDarrick J. Wong 		    bno + len == gtrec.rm_startblock &&
2164ceeb9c83SDarrick J. Wong 		    offset + len == gtrec.rm_offset) {
2165ceeb9c83SDarrick J. Wong 			/*
2166ceeb9c83SDarrick J. Wong 			 * Right edge also contiguous, delete right record
2167ceeb9c83SDarrick J. Wong 			 * and merge into left record.
2168ceeb9c83SDarrick J. Wong 			 *
2169ceeb9c83SDarrick J. Wong 			 *       ltbno     ltlen    gtbno     gtlen
2170ceeb9c83SDarrick J. Wong 			 * orig:   |ooooooooo|         |ooooooooo|
2171ceeb9c83SDarrick J. Wong 			 * adding:           |aaaaaaaaa|
2172ceeb9c83SDarrick J. Wong 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
2173ceeb9c83SDarrick J. Wong 			 */
2174ceeb9c83SDarrick J. Wong 			ltrec.rm_blockcount += gtrec.rm_blockcount;
2175ceeb9c83SDarrick J. Wong 			error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2176ceeb9c83SDarrick J. Wong 					gtrec.rm_blockcount, gtrec.rm_owner,
2177ceeb9c83SDarrick J. Wong 					gtrec.rm_offset, gtrec.rm_flags);
2178ceeb9c83SDarrick J. Wong 			if (error)
2179ceeb9c83SDarrick J. Wong 				goto out_error;
2180ceeb9c83SDarrick J. Wong 		}
2181ceeb9c83SDarrick J. Wong 
2182ceeb9c83SDarrick J. Wong 		/* Point the cursor back to the left record and update. */
2183ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2184ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2185ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2186ceeb9c83SDarrick J. Wong 		if (error)
2187ceeb9c83SDarrick J. Wong 			goto out_error;
2188f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2189f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2190f9e03706SDarrick J. Wong 			goto out_error;
2191f9e03706SDarrick J. Wong 		}
2192ceeb9c83SDarrick J. Wong 
2193ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2194ceeb9c83SDarrick J. Wong 		if (error)
2195ceeb9c83SDarrick J. Wong 			goto out_error;
2196ceeb9c83SDarrick J. Wong 	} else if (have_gt &&
2197ceeb9c83SDarrick J. Wong 		   bno + len == gtrec.rm_startblock &&
2198ceeb9c83SDarrick J. Wong 		   offset + len == gtrec.rm_offset) {
2199ceeb9c83SDarrick J. Wong 		/*
2200ceeb9c83SDarrick J. Wong 		 * Right edge contiguous, merge into right record.
2201ceeb9c83SDarrick J. Wong 		 *
2202ceeb9c83SDarrick J. Wong 		 *                 gtbno     gtlen
2203ceeb9c83SDarrick J. Wong 		 * Orig:             |ooooooooo|
2204ceeb9c83SDarrick J. Wong 		 * adding: |aaaaaaaaa|
2205ceeb9c83SDarrick J. Wong 		 * Result: |rrrrrrrrrrrrrrrrrrr|
2206ceeb9c83SDarrick J. Wong 		 *        bno       len
2207ceeb9c83SDarrick J. Wong 		 */
2208ceeb9c83SDarrick J. Wong 		/* Delete the old record. */
2209ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2210ceeb9c83SDarrick J. Wong 				gtrec.rm_blockcount, gtrec.rm_owner,
2211ceeb9c83SDarrick J. Wong 				gtrec.rm_offset, gtrec.rm_flags);
2212ceeb9c83SDarrick J. Wong 		if (error)
2213ceeb9c83SDarrick J. Wong 			goto out_error;
2214ceeb9c83SDarrick J. Wong 
2215ceeb9c83SDarrick J. Wong 		/* Move the start and re-add it. */
2216ceeb9c83SDarrick J. Wong 		gtrec.rm_startblock = bno;
2217ceeb9c83SDarrick J. Wong 		gtrec.rm_blockcount += len;
2218ceeb9c83SDarrick J. Wong 		gtrec.rm_offset = offset;
2219ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, gtrec.rm_startblock,
2220ceeb9c83SDarrick J. Wong 				gtrec.rm_blockcount, gtrec.rm_owner,
2221ceeb9c83SDarrick J. Wong 				gtrec.rm_offset, gtrec.rm_flags);
2222ceeb9c83SDarrick J. Wong 		if (error)
2223ceeb9c83SDarrick J. Wong 			goto out_error;
2224ceeb9c83SDarrick J. Wong 	} else {
2225ceeb9c83SDarrick J. Wong 		/*
2226ceeb9c83SDarrick J. Wong 		 * No contiguous edge with identical owner, insert
2227ceeb9c83SDarrick J. Wong 		 * new record at current cursor position.
2228ceeb9c83SDarrick J. Wong 		 */
2229ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, flags);
2230ceeb9c83SDarrick J. Wong 		if (error)
2231ceeb9c83SDarrick J. Wong 			goto out_error;
2232ceeb9c83SDarrick J. Wong 	}
2233ceeb9c83SDarrick J. Wong 
2234ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
2235ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2236ceeb9c83SDarrick J. Wong out_error:
2237ceeb9c83SDarrick J. Wong 	if (error)
2238ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_map_error(cur->bc_mp,
2239ceeb9c83SDarrick J. Wong 				cur->bc_private.a.agno, error, _RET_IP_);
2240ceeb9c83SDarrick J. Wong 	return error;
2241ceeb9c83SDarrick J. Wong }
2242ceeb9c83SDarrick J. Wong 
22434d4f86b4SDarrick J. Wong /* Insert a raw rmap into the rmapbt. */
22444d4f86b4SDarrick J. Wong int
22454d4f86b4SDarrick J. Wong xfs_rmap_map_raw(
22464d4f86b4SDarrick J. Wong 	struct xfs_btree_cur	*cur,
22474d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec	*rmap)
22484d4f86b4SDarrick J. Wong {
22494d4f86b4SDarrick J. Wong 	struct xfs_owner_info	oinfo;
22504d4f86b4SDarrick J. Wong 
22514d4f86b4SDarrick J. Wong 	oinfo.oi_owner = rmap->rm_owner;
22524d4f86b4SDarrick J. Wong 	oinfo.oi_offset = rmap->rm_offset;
22534d4f86b4SDarrick J. Wong 	oinfo.oi_flags = 0;
22544d4f86b4SDarrick J. Wong 	if (rmap->rm_flags & XFS_RMAP_ATTR_FORK)
22554d4f86b4SDarrick J. Wong 		oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
22564d4f86b4SDarrick J. Wong 	if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK)
22574d4f86b4SDarrick J. Wong 		oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
22584d4f86b4SDarrick J. Wong 
22594d4f86b4SDarrick J. Wong 	if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
22604d4f86b4SDarrick J. Wong 		return xfs_rmap_map(cur, rmap->rm_startblock,
22614d4f86b4SDarrick J. Wong 				rmap->rm_blockcount,
22624d4f86b4SDarrick J. Wong 				rmap->rm_flags & XFS_RMAP_UNWRITTEN,
22634d4f86b4SDarrick J. Wong 				&oinfo);
22644d4f86b4SDarrick J. Wong 
22654d4f86b4SDarrick J. Wong 	return xfs_rmap_map_shared(cur, rmap->rm_startblock,
22664d4f86b4SDarrick J. Wong 			rmap->rm_blockcount,
22674d4f86b4SDarrick J. Wong 			rmap->rm_flags & XFS_RMAP_UNWRITTEN,
22684d4f86b4SDarrick J. Wong 			&oinfo);
22694d4f86b4SDarrick J. Wong }
22704d4f86b4SDarrick J. Wong 
2271c543838aSDarrick J. Wong struct xfs_rmap_query_range_info {
2272c543838aSDarrick J. Wong 	xfs_rmap_query_range_fn	fn;
2273c543838aSDarrick J. Wong 	void				*priv;
2274c543838aSDarrick J. Wong };
2275c543838aSDarrick J. Wong 
2276c543838aSDarrick J. Wong /* Format btree record and pass to our callback. */
2277c543838aSDarrick J. Wong STATIC int
2278c543838aSDarrick J. Wong xfs_rmap_query_range_helper(
2279c543838aSDarrick J. Wong 	struct xfs_btree_cur	*cur,
2280c543838aSDarrick J. Wong 	union xfs_btree_rec	*rec,
2281c543838aSDarrick J. Wong 	void			*priv)
2282c543838aSDarrick J. Wong {
2283c543838aSDarrick J. Wong 	struct xfs_rmap_query_range_info	*query = priv;
2284c543838aSDarrick J. Wong 	struct xfs_rmap_irec			irec;
2285c543838aSDarrick J. Wong 	int					error;
2286c543838aSDarrick J. Wong 
2287c543838aSDarrick J. Wong 	error = xfs_rmap_btrec_to_irec(rec, &irec);
2288c543838aSDarrick J. Wong 	if (error)
2289c543838aSDarrick J. Wong 		return error;
2290c543838aSDarrick J. Wong 	return query->fn(cur, &irec, query->priv);
2291c543838aSDarrick J. Wong }
2292c543838aSDarrick J. Wong 
2293c543838aSDarrick J. Wong /* Find all rmaps between two keys. */
2294c543838aSDarrick J. Wong int
2295c543838aSDarrick J. Wong xfs_rmap_query_range(
2296c543838aSDarrick J. Wong 	struct xfs_btree_cur			*cur,
2297c543838aSDarrick J. Wong 	struct xfs_rmap_irec			*low_rec,
2298c543838aSDarrick J. Wong 	struct xfs_rmap_irec			*high_rec,
2299c543838aSDarrick J. Wong 	xfs_rmap_query_range_fn			fn,
2300c543838aSDarrick J. Wong 	void					*priv)
2301c543838aSDarrick J. Wong {
2302c543838aSDarrick J. Wong 	union xfs_btree_irec			low_brec;
2303c543838aSDarrick J. Wong 	union xfs_btree_irec			high_brec;
2304c543838aSDarrick J. Wong 	struct xfs_rmap_query_range_info	query;
2305c543838aSDarrick J. Wong 
2306c543838aSDarrick J. Wong 	low_brec.r = *low_rec;
2307c543838aSDarrick J. Wong 	high_brec.r = *high_rec;
2308c543838aSDarrick J. Wong 	query.priv = priv;
2309c543838aSDarrick J. Wong 	query.fn = fn;
2310c543838aSDarrick J. Wong 	return xfs_btree_query_range(cur, &low_brec, &high_brec,
2311c543838aSDarrick J. Wong 			xfs_rmap_query_range_helper, &query);
2312e9a2599aSDarrick J. Wong }
2313e9a2599aSDarrick J. Wong 
2314e9a2599aSDarrick J. Wong /* Find all rmaps. */
2315e9a2599aSDarrick J. Wong int
2316e9a2599aSDarrick J. Wong xfs_rmap_query_all(
2317e9a2599aSDarrick J. Wong 	struct xfs_btree_cur			*cur,
2318e9a2599aSDarrick J. Wong 	xfs_rmap_query_range_fn			fn,
2319e9a2599aSDarrick J. Wong 	void					*priv)
2320e9a2599aSDarrick J. Wong {
2321e9a2599aSDarrick J. Wong 	struct xfs_rmap_query_range_info	query;
2322e9a2599aSDarrick J. Wong 
2323e9a2599aSDarrick J. Wong 	query.priv = priv;
2324e9a2599aSDarrick J. Wong 	query.fn = fn;
2325e9a2599aSDarrick J. Wong 	return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query);
2326c543838aSDarrick J. Wong }
23279c194644SDarrick J. Wong 
23289c194644SDarrick J. Wong /* Clean up after calling xfs_rmap_finish_one. */
23299c194644SDarrick J. Wong void
23309c194644SDarrick J. Wong xfs_rmap_finish_one_cleanup(
23319c194644SDarrick J. Wong 	struct xfs_trans	*tp,
23329c194644SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
23339c194644SDarrick J. Wong 	int			error)
23349c194644SDarrick J. Wong {
23359c194644SDarrick J. Wong 	struct xfs_buf		*agbp;
23369c194644SDarrick J. Wong 
23379c194644SDarrick J. Wong 	if (rcur == NULL)
23389c194644SDarrick J. Wong 		return;
23399c194644SDarrick J. Wong 	agbp = rcur->bc_private.a.agbp;
23400b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(rcur, error);
23419c194644SDarrick J. Wong 	if (error)
23429c194644SDarrick J. Wong 		xfs_trans_brelse(tp, agbp);
23439c194644SDarrick J. Wong }
23449c194644SDarrick J. Wong 
23459c194644SDarrick J. Wong /*
23469c194644SDarrick J. Wong  * Process one of the deferred rmap operations.  We pass back the
23479c194644SDarrick J. Wong  * btree cursor to maintain our lock on the rmapbt between calls.
23489c194644SDarrick J. Wong  * This saves time and eliminates a buffer deadlock between the
23499c194644SDarrick J. Wong  * superblock and the AGF because we'll always grab them in the same
23509c194644SDarrick J. Wong  * order.
23519c194644SDarrick J. Wong  */
23529c194644SDarrick J. Wong int
23539c194644SDarrick J. Wong xfs_rmap_finish_one(
23549c194644SDarrick J. Wong 	struct xfs_trans		*tp,
23559c194644SDarrick J. Wong 	enum xfs_rmap_intent_type	type,
2356c8ce540dSDarrick J. Wong 	uint64_t			owner,
23579c194644SDarrick J. Wong 	int				whichfork,
23589c194644SDarrick J. Wong 	xfs_fileoff_t			startoff,
23599c194644SDarrick J. Wong 	xfs_fsblock_t			startblock,
23609c194644SDarrick J. Wong 	xfs_filblks_t			blockcount,
23619c194644SDarrick J. Wong 	xfs_exntst_t			state,
23629c194644SDarrick J. Wong 	struct xfs_btree_cur		**pcur)
23639c194644SDarrick J. Wong {
23649c194644SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
23659c194644SDarrick J. Wong 	struct xfs_btree_cur		*rcur;
23669c194644SDarrick J. Wong 	struct xfs_buf			*agbp = NULL;
23679c194644SDarrick J. Wong 	int				error = 0;
23689c194644SDarrick J. Wong 	xfs_agnumber_t			agno;
23699c194644SDarrick J. Wong 	struct xfs_owner_info		oinfo;
23709c194644SDarrick J. Wong 	xfs_agblock_t			bno;
23719c194644SDarrick J. Wong 	bool				unwritten;
23729c194644SDarrick J. Wong 
23739c194644SDarrick J. Wong 	agno = XFS_FSB_TO_AGNO(mp, startblock);
23749c194644SDarrick J. Wong 	ASSERT(agno != NULLAGNUMBER);
23759c194644SDarrick J. Wong 	bno = XFS_FSB_TO_AGBNO(mp, startblock);
23769c194644SDarrick J. Wong 
23779c194644SDarrick J. Wong 	trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork,
23789c194644SDarrick J. Wong 			startoff, blockcount, state);
23799c194644SDarrick J. Wong 
23809c194644SDarrick J. Wong 	if (XFS_TEST_ERROR(false, mp,
23819e24cfd0SDarrick J. Wong 			XFS_ERRTAG_RMAP_FINISH_ONE))
23829c194644SDarrick J. Wong 		return -EIO;
23839c194644SDarrick J. Wong 
23849c194644SDarrick J. Wong 	/*
23859c194644SDarrick J. Wong 	 * If we haven't gotten a cursor or the cursor AG doesn't match
23869c194644SDarrick J. Wong 	 * the startblock, get one now.
23879c194644SDarrick J. Wong 	 */
23889c194644SDarrick J. Wong 	rcur = *pcur;
23899c194644SDarrick J. Wong 	if (rcur != NULL && rcur->bc_private.a.agno != agno) {
23909c194644SDarrick J. Wong 		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
23919c194644SDarrick J. Wong 		rcur = NULL;
23929c194644SDarrick J. Wong 		*pcur = NULL;
23939c194644SDarrick J. Wong 	}
23949c194644SDarrick J. Wong 	if (rcur == NULL) {
23959c194644SDarrick J. Wong 		/*
23969c194644SDarrick J. Wong 		 * Refresh the freelist before we start changing the
23979c194644SDarrick J. Wong 		 * rmapbt, because a shape change could cause us to
23989c194644SDarrick J. Wong 		 * allocate blocks.
23999c194644SDarrick J. Wong 		 */
24009c194644SDarrick J. Wong 		error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
24019c194644SDarrick J. Wong 		if (error)
24029c194644SDarrick J. Wong 			return error;
24039c194644SDarrick J. Wong 		if (!agbp)
24049c194644SDarrick J. Wong 			return -EFSCORRUPTED;
24059c194644SDarrick J. Wong 
24069c194644SDarrick J. Wong 		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
24079c194644SDarrick J. Wong 		if (!rcur) {
24089c194644SDarrick J. Wong 			error = -ENOMEM;
24099c194644SDarrick J. Wong 			goto out_cur;
24109c194644SDarrick J. Wong 		}
24119c194644SDarrick J. Wong 	}
24129c194644SDarrick J. Wong 	*pcur = rcur;
24139c194644SDarrick J. Wong 
24149c194644SDarrick J. Wong 	xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff);
24159c194644SDarrick J. Wong 	unwritten = state == XFS_EXT_UNWRITTEN;
24169c194644SDarrick J. Wong 	bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock);
24179c194644SDarrick J. Wong 
24189c194644SDarrick J. Wong 	switch (type) {
24199c194644SDarrick J. Wong 	case XFS_RMAP_ALLOC:
24209c194644SDarrick J. Wong 	case XFS_RMAP_MAP:
24219c194644SDarrick J. Wong 		error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo);
24229c194644SDarrick J. Wong 		break;
2423ceeb9c83SDarrick J. Wong 	case XFS_RMAP_MAP_SHARED:
2424ceeb9c83SDarrick J. Wong 		error = xfs_rmap_map_shared(rcur, bno, blockcount, unwritten,
2425ceeb9c83SDarrick J. Wong 				&oinfo);
2426ceeb9c83SDarrick J. Wong 		break;
24279c194644SDarrick J. Wong 	case XFS_RMAP_FREE:
24289c194644SDarrick J. Wong 	case XFS_RMAP_UNMAP:
24299c194644SDarrick J. Wong 		error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten,
24309c194644SDarrick J. Wong 				&oinfo);
24319c194644SDarrick J. Wong 		break;
2432ceeb9c83SDarrick J. Wong 	case XFS_RMAP_UNMAP_SHARED:
2433ceeb9c83SDarrick J. Wong 		error = xfs_rmap_unmap_shared(rcur, bno, blockcount, unwritten,
2434ceeb9c83SDarrick J. Wong 				&oinfo);
2435ceeb9c83SDarrick J. Wong 		break;
24369c194644SDarrick J. Wong 	case XFS_RMAP_CONVERT:
24379c194644SDarrick J. Wong 		error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten,
24389c194644SDarrick J. Wong 				&oinfo);
24399c194644SDarrick J. Wong 		break;
24403f165b33SDarrick J. Wong 	case XFS_RMAP_CONVERT_SHARED:
24413f165b33SDarrick J. Wong 		error = xfs_rmap_convert_shared(rcur, bno, blockcount,
24423f165b33SDarrick J. Wong 				!unwritten, &oinfo);
24433f165b33SDarrick J. Wong 		break;
24449c194644SDarrick J. Wong 	default:
24459c194644SDarrick J. Wong 		ASSERT(0);
24469c194644SDarrick J. Wong 		error = -EFSCORRUPTED;
24479c194644SDarrick J. Wong 	}
24489c194644SDarrick J. Wong 	return error;
24499c194644SDarrick J. Wong 
24509c194644SDarrick J. Wong out_cur:
24519c194644SDarrick J. Wong 	xfs_trans_brelse(tp, agbp);
24529c194644SDarrick J. Wong 
24539c194644SDarrick J. Wong 	return error;
24549c194644SDarrick J. Wong }
24559c194644SDarrick J. Wong 
24569c194644SDarrick J. Wong /*
24579c194644SDarrick J. Wong  * Don't defer an rmap if we aren't an rmap filesystem.
24589c194644SDarrick J. Wong  */
24599c194644SDarrick J. Wong static bool
24609c194644SDarrick J. Wong xfs_rmap_update_is_needed(
24613993baebSDarrick J. Wong 	struct xfs_mount	*mp,
24623993baebSDarrick J. Wong 	int			whichfork)
24639c194644SDarrick J. Wong {
24643993baebSDarrick J. Wong 	return xfs_sb_version_hasrmapbt(&mp->m_sb) && whichfork != XFS_COW_FORK;
24659c194644SDarrick J. Wong }
24669c194644SDarrick J. Wong 
24679c194644SDarrick J. Wong /*
24689c194644SDarrick J. Wong  * Record a rmap intent; the list is kept sorted first by AG and then by
24699c194644SDarrick J. Wong  * increasing age.
24709c194644SDarrick J. Wong  */
2471bc46ac64SDarrick J. Wong static void
24729c194644SDarrick J. Wong __xfs_rmap_add(
24730f37d178SBrian Foster 	struct xfs_trans		*tp,
24749c194644SDarrick J. Wong 	enum xfs_rmap_intent_type	type,
2475c8ce540dSDarrick J. Wong 	uint64_t			owner,
24769c194644SDarrick J. Wong 	int				whichfork,
24779c194644SDarrick J. Wong 	struct xfs_bmbt_irec		*bmap)
24789c194644SDarrick J. Wong {
24799c194644SDarrick J. Wong 	struct xfs_rmap_intent		*ri;
24809c194644SDarrick J. Wong 
24810f37d178SBrian Foster 	trace_xfs_rmap_defer(tp->t_mountp,
24820f37d178SBrian Foster 			XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
24839c194644SDarrick J. Wong 			type,
24840f37d178SBrian Foster 			XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
24859c194644SDarrick J. Wong 			owner, whichfork,
24869c194644SDarrick J. Wong 			bmap->br_startoff,
24879c194644SDarrick J. Wong 			bmap->br_blockcount,
24889c194644SDarrick J. Wong 			bmap->br_state);
24899c194644SDarrick J. Wong 
2490707e0ddaSTetsuo Handa 	ri = kmem_alloc(sizeof(struct xfs_rmap_intent), KM_NOFS);
24919c194644SDarrick J. Wong 	INIT_LIST_HEAD(&ri->ri_list);
24929c194644SDarrick J. Wong 	ri->ri_type = type;
24939c194644SDarrick J. Wong 	ri->ri_owner = owner;
24949c194644SDarrick J. Wong 	ri->ri_whichfork = whichfork;
24959c194644SDarrick J. Wong 	ri->ri_bmap = *bmap;
24969c194644SDarrick J. Wong 
24970f37d178SBrian Foster 	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
24989c194644SDarrick J. Wong }
24999c194644SDarrick J. Wong 
25009c194644SDarrick J. Wong /* Map an extent into a file. */
2501bc46ac64SDarrick J. Wong void
25029c194644SDarrick J. Wong xfs_rmap_map_extent(
25030f37d178SBrian Foster 	struct xfs_trans	*tp,
25049c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25059c194644SDarrick J. Wong 	int			whichfork,
25069c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25079c194644SDarrick J. Wong {
25080f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2509bc46ac64SDarrick J. Wong 		return;
25109c194644SDarrick J. Wong 
2511bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, xfs_is_reflink_inode(ip) ?
2512ceeb9c83SDarrick J. Wong 			XFS_RMAP_MAP_SHARED : XFS_RMAP_MAP, ip->i_ino,
25139c194644SDarrick J. Wong 			whichfork, PREV);
25149c194644SDarrick J. Wong }
25159c194644SDarrick J. Wong 
25169c194644SDarrick J. Wong /* Unmap an extent out of a file. */
2517bc46ac64SDarrick J. Wong void
25189c194644SDarrick J. Wong xfs_rmap_unmap_extent(
25190f37d178SBrian Foster 	struct xfs_trans	*tp,
25209c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25219c194644SDarrick J. Wong 	int			whichfork,
25229c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25239c194644SDarrick J. Wong {
25240f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2525bc46ac64SDarrick J. Wong 		return;
25269c194644SDarrick J. Wong 
2527bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, xfs_is_reflink_inode(ip) ?
2528ceeb9c83SDarrick J. Wong 			XFS_RMAP_UNMAP_SHARED : XFS_RMAP_UNMAP, ip->i_ino,
25299c194644SDarrick J. Wong 			whichfork, PREV);
25309c194644SDarrick J. Wong }
25319c194644SDarrick J. Wong 
25320f37d178SBrian Foster /*
25330f37d178SBrian Foster  * Convert a data fork extent from unwritten to real or vice versa.
25340f37d178SBrian Foster  *
25350f37d178SBrian Foster  * Note that tp can be NULL here as no transaction is used for COW fork
25360f37d178SBrian Foster  * unwritten conversion.
25370f37d178SBrian Foster  */
2538bc46ac64SDarrick J. Wong void
25399c194644SDarrick J. Wong xfs_rmap_convert_extent(
25409c194644SDarrick J. Wong 	struct xfs_mount	*mp,
25410f37d178SBrian Foster 	struct xfs_trans	*tp,
25429c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25439c194644SDarrick J. Wong 	int			whichfork,
25449c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25459c194644SDarrick J. Wong {
25463993baebSDarrick J. Wong 	if (!xfs_rmap_update_is_needed(mp, whichfork))
2547bc46ac64SDarrick J. Wong 		return;
25489c194644SDarrick J. Wong 
2549bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, xfs_is_reflink_inode(ip) ?
25503f165b33SDarrick J. Wong 			XFS_RMAP_CONVERT_SHARED : XFS_RMAP_CONVERT, ip->i_ino,
25519c194644SDarrick J. Wong 			whichfork, PREV);
25529c194644SDarrick J. Wong }
25539c194644SDarrick J. Wong 
25549c194644SDarrick J. Wong /* Schedule the creation of an rmap for non-file data. */
2555bc46ac64SDarrick J. Wong void
25569c194644SDarrick J. Wong xfs_rmap_alloc_extent(
25570f37d178SBrian Foster 	struct xfs_trans	*tp,
25589c194644SDarrick J. Wong 	xfs_agnumber_t		agno,
25599c194644SDarrick J. Wong 	xfs_agblock_t		bno,
25609c194644SDarrick J. Wong 	xfs_extlen_t		len,
2561c8ce540dSDarrick J. Wong 	uint64_t		owner)
25629c194644SDarrick J. Wong {
25639c194644SDarrick J. Wong 	struct xfs_bmbt_irec	bmap;
25649c194644SDarrick J. Wong 
25650f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2566bc46ac64SDarrick J. Wong 		return;
25679c194644SDarrick J. Wong 
25680f37d178SBrian Foster 	bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
25699c194644SDarrick J. Wong 	bmap.br_blockcount = len;
25709c194644SDarrick J. Wong 	bmap.br_startoff = 0;
25719c194644SDarrick J. Wong 	bmap.br_state = XFS_EXT_NORM;
25729c194644SDarrick J. Wong 
2573bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
25749c194644SDarrick J. Wong }
25759c194644SDarrick J. Wong 
25769c194644SDarrick J. Wong /* Schedule the deletion of an rmap for non-file data. */
2577bc46ac64SDarrick J. Wong void
25789c194644SDarrick J. Wong xfs_rmap_free_extent(
25790f37d178SBrian Foster 	struct xfs_trans	*tp,
25809c194644SDarrick J. Wong 	xfs_agnumber_t		agno,
25819c194644SDarrick J. Wong 	xfs_agblock_t		bno,
25829c194644SDarrick J. Wong 	xfs_extlen_t		len,
2583c8ce540dSDarrick J. Wong 	uint64_t		owner)
25849c194644SDarrick J. Wong {
25859c194644SDarrick J. Wong 	struct xfs_bmbt_irec	bmap;
25869c194644SDarrick J. Wong 
25870f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2588bc46ac64SDarrick J. Wong 		return;
25899c194644SDarrick J. Wong 
25900f37d178SBrian Foster 	bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
25919c194644SDarrick J. Wong 	bmap.br_blockcount = len;
25929c194644SDarrick J. Wong 	bmap.br_startoff = 0;
25939c194644SDarrick J. Wong 	bmap.br_state = XFS_EXT_NORM;
25949c194644SDarrick J. Wong 
2595bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
25969c194644SDarrick J. Wong }
2597e89c0413SDarrick J. Wong 
2598e89c0413SDarrick J. Wong /* Compare rmap records.  Returns -1 if a < b, 1 if a > b, and 0 if equal. */
2599e89c0413SDarrick J. Wong int
2600e89c0413SDarrick J. Wong xfs_rmap_compare(
2601e89c0413SDarrick J. Wong 	const struct xfs_rmap_irec	*a,
2602e89c0413SDarrick J. Wong 	const struct xfs_rmap_irec	*b)
2603e89c0413SDarrick J. Wong {
2604e89c0413SDarrick J. Wong 	__u64				oa;
2605e89c0413SDarrick J. Wong 	__u64				ob;
2606e89c0413SDarrick J. Wong 
2607e89c0413SDarrick J. Wong 	oa = xfs_rmap_irec_offset_pack(a);
2608e89c0413SDarrick J. Wong 	ob = xfs_rmap_irec_offset_pack(b);
2609e89c0413SDarrick J. Wong 
2610e89c0413SDarrick J. Wong 	if (a->rm_startblock < b->rm_startblock)
2611e89c0413SDarrick J. Wong 		return -1;
2612e89c0413SDarrick J. Wong 	else if (a->rm_startblock > b->rm_startblock)
2613e89c0413SDarrick J. Wong 		return 1;
2614e89c0413SDarrick J. Wong 	else if (a->rm_owner < b->rm_owner)
2615e89c0413SDarrick J. Wong 		return -1;
2616e89c0413SDarrick J. Wong 	else if (a->rm_owner > b->rm_owner)
2617e89c0413SDarrick J. Wong 		return 1;
2618e89c0413SDarrick J. Wong 	else if (oa < ob)
2619e89c0413SDarrick J. Wong 		return -1;
2620e89c0413SDarrick J. Wong 	else if (oa > ob)
2621e89c0413SDarrick J. Wong 		return 1;
2622e89c0413SDarrick J. Wong 	else
2623e89c0413SDarrick J. Wong 		return 0;
2624e89c0413SDarrick J. Wong }
2625ed7c52d4SDarrick J. Wong 
2626ed7c52d4SDarrick J. Wong /* Is there a record covering a given extent? */
2627ed7c52d4SDarrick J. Wong int
2628ed7c52d4SDarrick J. Wong xfs_rmap_has_record(
2629ed7c52d4SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2630ed7c52d4SDarrick J. Wong 	xfs_agblock_t		bno,
2631ed7c52d4SDarrick J. Wong 	xfs_extlen_t		len,
2632ed7c52d4SDarrick J. Wong 	bool			*exists)
2633ed7c52d4SDarrick J. Wong {
2634ed7c52d4SDarrick J. Wong 	union xfs_btree_irec	low;
2635ed7c52d4SDarrick J. Wong 	union xfs_btree_irec	high;
2636ed7c52d4SDarrick J. Wong 
2637ed7c52d4SDarrick J. Wong 	memset(&low, 0, sizeof(low));
2638ed7c52d4SDarrick J. Wong 	low.r.rm_startblock = bno;
2639ed7c52d4SDarrick J. Wong 	memset(&high, 0xFF, sizeof(high));
2640ed7c52d4SDarrick J. Wong 	high.r.rm_startblock = bno + len - 1;
2641ed7c52d4SDarrick J. Wong 
2642ed7c52d4SDarrick J. Wong 	return xfs_btree_has_record(cur, &low, &high, exists);
2643ed7c52d4SDarrick J. Wong }
2644ed7c52d4SDarrick J. Wong 
2645ed7c52d4SDarrick J. Wong /*
2646ed7c52d4SDarrick J. Wong  * Is there a record for this owner completely covering a given physical
2647ed7c52d4SDarrick J. Wong  * extent?  If so, *has_rmap will be set to true.  If there is no record
2648ed7c52d4SDarrick J. Wong  * or the record only covers part of the range, we set *has_rmap to false.
2649ed7c52d4SDarrick J. Wong  * This function doesn't perform range lookups or offset checks, so it is
2650ed7c52d4SDarrick J. Wong  * not suitable for checking data fork blocks.
2651ed7c52d4SDarrick J. Wong  */
2652ed7c52d4SDarrick J. Wong int
2653ed7c52d4SDarrick J. Wong xfs_rmap_record_exists(
2654ed7c52d4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2655ed7c52d4SDarrick J. Wong 	xfs_agblock_t			bno,
2656ed7c52d4SDarrick J. Wong 	xfs_extlen_t			len,
265766e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
2658ed7c52d4SDarrick J. Wong 	bool				*has_rmap)
2659ed7c52d4SDarrick J. Wong {
2660ed7c52d4SDarrick J. Wong 	uint64_t			owner;
2661ed7c52d4SDarrick J. Wong 	uint64_t			offset;
2662ed7c52d4SDarrick J. Wong 	unsigned int			flags;
2663ed7c52d4SDarrick J. Wong 	int				has_record;
2664ed7c52d4SDarrick J. Wong 	struct xfs_rmap_irec		irec;
2665ed7c52d4SDarrick J. Wong 	int				error;
2666ed7c52d4SDarrick J. Wong 
2667ed7c52d4SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2668ed7c52d4SDarrick J. Wong 	ASSERT(XFS_RMAP_NON_INODE_OWNER(owner) ||
2669ed7c52d4SDarrick J. Wong 	       (flags & XFS_RMAP_BMBT_BLOCK));
2670ed7c52d4SDarrick J. Wong 
2671ed7c52d4SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
2672ed7c52d4SDarrick J. Wong 			&has_record);
2673ed7c52d4SDarrick J. Wong 	if (error)
2674ed7c52d4SDarrick J. Wong 		return error;
2675ed7c52d4SDarrick J. Wong 	if (!has_record) {
2676ed7c52d4SDarrick J. Wong 		*has_rmap = false;
2677ed7c52d4SDarrick J. Wong 		return 0;
2678ed7c52d4SDarrick J. Wong 	}
2679ed7c52d4SDarrick J. Wong 
2680ed7c52d4SDarrick J. Wong 	error = xfs_rmap_get_rec(cur, &irec, &has_record);
2681ed7c52d4SDarrick J. Wong 	if (error)
2682ed7c52d4SDarrick J. Wong 		return error;
2683ed7c52d4SDarrick J. Wong 	if (!has_record) {
2684ed7c52d4SDarrick J. Wong 		*has_rmap = false;
2685ed7c52d4SDarrick J. Wong 		return 0;
2686ed7c52d4SDarrick J. Wong 	}
2687ed7c52d4SDarrick J. Wong 
2688ed7c52d4SDarrick J. Wong 	*has_rmap = (irec.rm_owner == owner && irec.rm_startblock <= bno &&
2689ed7c52d4SDarrick J. Wong 		     irec.rm_startblock + irec.rm_blockcount >= bno + len);
2690ed7c52d4SDarrick J. Wong 	return 0;
2691ed7c52d4SDarrick J. Wong }
26924d4f86b4SDarrick J. Wong 
26934d4f86b4SDarrick J. Wong struct xfs_rmap_key_state {
26944d4f86b4SDarrick J. Wong 	uint64_t			owner;
26954d4f86b4SDarrick J. Wong 	uint64_t			offset;
26964d4f86b4SDarrick J. Wong 	unsigned int			flags;
26974d4f86b4SDarrick J. Wong 	bool				has_rmap;
26984d4f86b4SDarrick J. Wong };
26994d4f86b4SDarrick J. Wong 
27004d4f86b4SDarrick J. Wong /* For each rmap given, figure out if it doesn't match the key we want. */
27014d4f86b4SDarrick J. Wong STATIC int
27024d4f86b4SDarrick J. Wong xfs_rmap_has_other_keys_helper(
27034d4f86b4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
27044d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec		*rec,
27054d4f86b4SDarrick J. Wong 	void				*priv)
27064d4f86b4SDarrick J. Wong {
27074d4f86b4SDarrick J. Wong 	struct xfs_rmap_key_state	*rks = priv;
27084d4f86b4SDarrick J. Wong 
27094d4f86b4SDarrick J. Wong 	if (rks->owner == rec->rm_owner && rks->offset == rec->rm_offset &&
27104d4f86b4SDarrick J. Wong 	    ((rks->flags & rec->rm_flags) & XFS_RMAP_KEY_FLAGS) == rks->flags)
27114d4f86b4SDarrick J. Wong 		return 0;
27124d4f86b4SDarrick J. Wong 	rks->has_rmap = true;
2713e7ee96dfSDarrick J. Wong 	return -ECANCELED;
27144d4f86b4SDarrick J. Wong }
27154d4f86b4SDarrick J. Wong 
27164d4f86b4SDarrick J. Wong /*
27174d4f86b4SDarrick J. Wong  * Given an extent and some owner info, can we find records overlapping
27184d4f86b4SDarrick J. Wong  * the extent whose owner info does not match the given owner?
27194d4f86b4SDarrick J. Wong  */
27204d4f86b4SDarrick J. Wong int
27214d4f86b4SDarrick J. Wong xfs_rmap_has_other_keys(
27224d4f86b4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
27234d4f86b4SDarrick J. Wong 	xfs_agblock_t			bno,
27244d4f86b4SDarrick J. Wong 	xfs_extlen_t			len,
272566e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
27264d4f86b4SDarrick J. Wong 	bool				*has_rmap)
27274d4f86b4SDarrick J. Wong {
27284d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec		low = {0};
27294d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec		high;
27304d4f86b4SDarrick J. Wong 	struct xfs_rmap_key_state	rks;
27314d4f86b4SDarrick J. Wong 	int				error;
27324d4f86b4SDarrick J. Wong 
27334d4f86b4SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &rks.owner, &rks.offset, &rks.flags);
27344d4f86b4SDarrick J. Wong 	rks.has_rmap = false;
27354d4f86b4SDarrick J. Wong 
27364d4f86b4SDarrick J. Wong 	low.rm_startblock = bno;
27374d4f86b4SDarrick J. Wong 	memset(&high, 0xFF, sizeof(high));
27384d4f86b4SDarrick J. Wong 	high.rm_startblock = bno + len - 1;
27394d4f86b4SDarrick J. Wong 
27404d4f86b4SDarrick J. Wong 	error = xfs_rmap_query_range(cur, &low, &high,
27414d4f86b4SDarrick J. Wong 			xfs_rmap_has_other_keys_helper, &rks);
27427380e8feSDarrick J. Wong 	if (error < 0)
27434d4f86b4SDarrick J. Wong 		return error;
27447380e8feSDarrick J. Wong 
27457380e8feSDarrick J. Wong 	*has_rmap = rks.has_rmap;
27467380e8feSDarrick J. Wong 	return 0;
27474d4f86b4SDarrick J. Wong }
27487280fedaSDarrick J. Wong 
27497280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = {
27507280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_NULL,
27517280fedaSDarrick J. Wong };
27527280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER = {
27537280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_UNKNOWN,
27547280fedaSDarrick J. Wong };
27557280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_FS = {
27567280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_FS,
27577280fedaSDarrick J. Wong };
27587280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_LOG = {
27597280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_LOG,
27607280fedaSDarrick J. Wong };
27617280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_AG = {
27627280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_AG,
27637280fedaSDarrick J. Wong };
27647280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_INOBT = {
27657280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_INOBT,
27667280fedaSDarrick J. Wong };
27677280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_INODES = {
27687280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_INODES,
27697280fedaSDarrick J. Wong };
27707280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_REFC = {
27717280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_REFC,
27727280fedaSDarrick J. Wong };
27737280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_COW = {
27747280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_COW,
27757280fedaSDarrick J. Wong };
2776