xref: /openbmc/linux/fs/xfs/libxfs/xfs_rmap.c (revision 75dc0345)
10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0
2673930c3SDarrick J. Wong /*
3673930c3SDarrick J. Wong  * Copyright (c) 2014 Red Hat, Inc.
4673930c3SDarrick J. Wong  * All Rights Reserved.
5673930c3SDarrick J. Wong  */
6673930c3SDarrick J. Wong #include "xfs.h"
7673930c3SDarrick J. Wong #include "xfs_fs.h"
8673930c3SDarrick J. Wong #include "xfs_shared.h"
9673930c3SDarrick J. Wong #include "xfs_format.h"
10673930c3SDarrick J. Wong #include "xfs_log_format.h"
11673930c3SDarrick J. Wong #include "xfs_trans_resv.h"
12673930c3SDarrick J. Wong #include "xfs_bit.h"
13673930c3SDarrick J. Wong #include "xfs_mount.h"
1445d06621SDave Chinner #include "xfs_sb.h"
15673930c3SDarrick J. Wong #include "xfs_defer.h"
16673930c3SDarrick J. Wong #include "xfs_btree.h"
17673930c3SDarrick J. Wong #include "xfs_trans.h"
18673930c3SDarrick J. Wong #include "xfs_alloc.h"
19673930c3SDarrick J. Wong #include "xfs_rmap.h"
200a1b0b38SDarrick J. Wong #include "xfs_rmap_btree.h"
21673930c3SDarrick J. Wong #include "xfs_trace.h"
22e9e899a2SDarrick J. Wong #include "xfs_errortag.h"
23673930c3SDarrick J. Wong #include "xfs_error.h"
249c194644SDarrick J. Wong #include "xfs_inode.h"
259bbafc71SDave Chinner #include "xfs_ag.h"
26673930c3SDarrick J. Wong 
27f3c799c2SDarrick J. Wong struct kmem_cache	*xfs_rmap_intent_cache;
28f3c799c2SDarrick J. Wong 
294b8ed677SDarrick J. Wong /*
304b8ed677SDarrick J. Wong  * Lookup the first record less than or equal to [bno, len, owner, offset]
314b8ed677SDarrick J. Wong  * in the btree given by cur.
324b8ed677SDarrick J. Wong  */
334b8ed677SDarrick J. Wong int
xfs_rmap_lookup_le(struct xfs_btree_cur * cur,xfs_agblock_t bno,uint64_t owner,uint64_t offset,unsigned int flags,struct xfs_rmap_irec * irec,int * stat)344b8ed677SDarrick J. Wong xfs_rmap_lookup_le(
354b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
364b8ed677SDarrick J. Wong 	xfs_agblock_t		bno,
374b8ed677SDarrick J. Wong 	uint64_t		owner,
384b8ed677SDarrick J. Wong 	uint64_t		offset,
394b8ed677SDarrick J. Wong 	unsigned int		flags,
405b7ca8b3SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
414b8ed677SDarrick J. Wong 	int			*stat)
424b8ed677SDarrick J. Wong {
435b7ca8b3SDarrick J. Wong 	int			get_stat = 0;
445b7ca8b3SDarrick J. Wong 	int			error;
455b7ca8b3SDarrick J. Wong 
464b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_startblock = bno;
475b7ca8b3SDarrick J. Wong 	cur->bc_rec.r.rm_blockcount = 0;
484b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_owner = owner;
494b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_offset = offset;
504b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_flags = flags;
515b7ca8b3SDarrick J. Wong 
525b7ca8b3SDarrick J. Wong 	error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
535b7ca8b3SDarrick J. Wong 	if (error || !(*stat) || !irec)
545b7ca8b3SDarrick J. Wong 		return error;
555b7ca8b3SDarrick J. Wong 
565b7ca8b3SDarrick J. Wong 	error = xfs_rmap_get_rec(cur, irec, &get_stat);
575b7ca8b3SDarrick J. Wong 	if (error)
585b7ca8b3SDarrick J. Wong 		return error;
595b7ca8b3SDarrick J. Wong 	if (!get_stat)
605b7ca8b3SDarrick J. Wong 		return -EFSCORRUPTED;
615b7ca8b3SDarrick J. Wong 
625b7ca8b3SDarrick J. Wong 	return 0;
634b8ed677SDarrick J. Wong }
644b8ed677SDarrick J. Wong 
654b8ed677SDarrick J. Wong /*
664b8ed677SDarrick J. Wong  * Lookup the record exactly matching [bno, len, owner, offset]
674b8ed677SDarrick J. Wong  * in the btree given by cur.
684b8ed677SDarrick J. Wong  */
694b8ed677SDarrick J. Wong int
xfs_rmap_lookup_eq(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,uint64_t owner,uint64_t offset,unsigned int flags,int * stat)704b8ed677SDarrick J. Wong xfs_rmap_lookup_eq(
714b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
724b8ed677SDarrick J. Wong 	xfs_agblock_t		bno,
734b8ed677SDarrick J. Wong 	xfs_extlen_t		len,
744b8ed677SDarrick J. Wong 	uint64_t		owner,
754b8ed677SDarrick J. Wong 	uint64_t		offset,
764b8ed677SDarrick J. Wong 	unsigned int		flags,
774b8ed677SDarrick J. Wong 	int			*stat)
784b8ed677SDarrick J. Wong {
794b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_startblock = bno;
804b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_blockcount = len;
814b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_owner = owner;
824b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_offset = offset;
834b8ed677SDarrick J. Wong 	cur->bc_rec.r.rm_flags = flags;
844b8ed677SDarrick J. Wong 	return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
854b8ed677SDarrick J. Wong }
864b8ed677SDarrick J. Wong 
874b8ed677SDarrick J. Wong /*
884b8ed677SDarrick J. Wong  * Update the record referred to by cur to the value given
894b8ed677SDarrick J. Wong  * by [bno, len, owner, offset].
904b8ed677SDarrick J. Wong  * This either works (return 0) or gets an EFSCORRUPTED error.
914b8ed677SDarrick J. Wong  */
924b8ed677SDarrick J. Wong STATIC int
xfs_rmap_update(struct xfs_btree_cur * cur,struct xfs_rmap_irec * irec)934b8ed677SDarrick J. Wong xfs_rmap_update(
944b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
954b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec)
964b8ed677SDarrick J. Wong {
974b8ed677SDarrick J. Wong 	union xfs_btree_rec	rec;
98abf09233SDarrick J. Wong 	int			error;
99abf09233SDarrick J. Wong 
10050f02fe3SDave Chinner 	trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
101abf09233SDarrick J. Wong 			irec->rm_startblock, irec->rm_blockcount,
102abf09233SDarrick J. Wong 			irec->rm_owner, irec->rm_offset, irec->rm_flags);
1034b8ed677SDarrick J. Wong 
1044b8ed677SDarrick J. Wong 	rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
1054b8ed677SDarrick J. Wong 	rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
1064b8ed677SDarrick J. Wong 	rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
1074b8ed677SDarrick J. Wong 	rec.rmap.rm_offset = cpu_to_be64(
1084b8ed677SDarrick J. Wong 			xfs_rmap_irec_offset_pack(irec));
109abf09233SDarrick J. Wong 	error = xfs_btree_update(cur, &rec);
110abf09233SDarrick J. Wong 	if (error)
111abf09233SDarrick J. Wong 		trace_xfs_rmap_update_error(cur->bc_mp,
11250f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
113abf09233SDarrick J. Wong 	return error;
114abf09233SDarrick J. Wong }
115abf09233SDarrick J. Wong 
116abf09233SDarrick J. Wong int
xfs_rmap_insert(struct xfs_btree_cur * rcur,xfs_agblock_t agbno,xfs_extlen_t len,uint64_t owner,uint64_t offset,unsigned int flags)117abf09233SDarrick J. Wong xfs_rmap_insert(
118abf09233SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
119abf09233SDarrick J. Wong 	xfs_agblock_t		agbno,
120abf09233SDarrick J. Wong 	xfs_extlen_t		len,
121abf09233SDarrick J. Wong 	uint64_t		owner,
122abf09233SDarrick J. Wong 	uint64_t		offset,
123abf09233SDarrick J. Wong 	unsigned int		flags)
124abf09233SDarrick J. Wong {
125abf09233SDarrick J. Wong 	int			i;
126abf09233SDarrick J. Wong 	int			error;
127abf09233SDarrick J. Wong 
12850f02fe3SDave Chinner 	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
129abf09233SDarrick J. Wong 			len, owner, offset, flags);
130abf09233SDarrick J. Wong 
131abf09233SDarrick J. Wong 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
132abf09233SDarrick J. Wong 	if (error)
133abf09233SDarrick J. Wong 		goto done;
134f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
135f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
136f9e03706SDarrick J. Wong 		goto done;
137f9e03706SDarrick J. Wong 	}
138abf09233SDarrick J. Wong 
139abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_startblock = agbno;
140abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_blockcount = len;
141abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_owner = owner;
142abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_offset = offset;
143abf09233SDarrick J. Wong 	rcur->bc_rec.r.rm_flags = flags;
144abf09233SDarrick J. Wong 	error = xfs_btree_insert(rcur, &i);
145abf09233SDarrick J. Wong 	if (error)
146abf09233SDarrick J. Wong 		goto done;
147f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
148f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
149f9e03706SDarrick J. Wong 		goto done;
150f9e03706SDarrick J. Wong 	}
151abf09233SDarrick J. Wong done:
152abf09233SDarrick J. Wong 	if (error)
153abf09233SDarrick J. Wong 		trace_xfs_rmap_insert_error(rcur->bc_mp,
15450f02fe3SDave Chinner 				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
155abf09233SDarrick J. Wong 	return error;
1564b8ed677SDarrick J. Wong }
1574b8ed677SDarrick J. Wong 
158ceeb9c83SDarrick J. Wong STATIC int
xfs_rmap_delete(struct xfs_btree_cur * rcur,xfs_agblock_t agbno,xfs_extlen_t len,uint64_t owner,uint64_t offset,unsigned int flags)159ceeb9c83SDarrick J. Wong xfs_rmap_delete(
160ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
161ceeb9c83SDarrick J. Wong 	xfs_agblock_t		agbno,
162ceeb9c83SDarrick J. Wong 	xfs_extlen_t		len,
163ceeb9c83SDarrick J. Wong 	uint64_t		owner,
164ceeb9c83SDarrick J. Wong 	uint64_t		offset,
165ceeb9c83SDarrick J. Wong 	unsigned int		flags)
166ceeb9c83SDarrick J. Wong {
167ceeb9c83SDarrick J. Wong 	int			i;
168ceeb9c83SDarrick J. Wong 	int			error;
169ceeb9c83SDarrick J. Wong 
17050f02fe3SDave Chinner 	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
171ceeb9c83SDarrick J. Wong 			len, owner, offset, flags);
172ceeb9c83SDarrick J. Wong 
173ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
174ceeb9c83SDarrick J. Wong 	if (error)
175ceeb9c83SDarrick J. Wong 		goto done;
176f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
177f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
178f9e03706SDarrick J. Wong 		goto done;
179f9e03706SDarrick J. Wong 	}
180ceeb9c83SDarrick J. Wong 
181ceeb9c83SDarrick J. Wong 	error = xfs_btree_delete(rcur, &i);
182ceeb9c83SDarrick J. Wong 	if (error)
183ceeb9c83SDarrick J. Wong 		goto done;
184f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
185f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
186f9e03706SDarrick J. Wong 		goto done;
187f9e03706SDarrick J. Wong 	}
188ceeb9c83SDarrick J. Wong done:
189ceeb9c83SDarrick J. Wong 	if (error)
190ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_delete_error(rcur->bc_mp,
19150f02fe3SDave Chinner 				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
192ceeb9c83SDarrick J. Wong 	return error;
193ceeb9c83SDarrick J. Wong }
194ceeb9c83SDarrick J. Wong 
19526788097SDarrick J. Wong /* Convert an internal btree record to an rmap record. */
19639ab26d5SDarrick J. Wong xfs_failaddr_t
xfs_rmap_btrec_to_irec(const union xfs_btree_rec * rec,struct xfs_rmap_irec * irec)1974b8ed677SDarrick J. Wong xfs_rmap_btrec_to_irec(
198159eb69dSDarrick J. Wong 	const union xfs_btree_rec	*rec,
1994b8ed677SDarrick J. Wong 	struct xfs_rmap_irec		*irec)
2004b8ed677SDarrick J. Wong {
2014b8ed677SDarrick J. Wong 	irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
2024b8ed677SDarrick J. Wong 	irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
2034b8ed677SDarrick J. Wong 	irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
2044b8ed677SDarrick J. Wong 	return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
2054b8ed677SDarrick J. Wong 			irec);
2064b8ed677SDarrick J. Wong }
2074b8ed677SDarrick J. Wong 
208c4e34172SDarrick J. Wong /* Simple checks for rmap records. */
209c4e34172SDarrick J. Wong xfs_failaddr_t
xfs_rmap_check_irec(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * irec)210c4e34172SDarrick J. Wong xfs_rmap_check_irec(
211c4e34172SDarrick J. Wong 	struct xfs_btree_cur		*cur,
212c4e34172SDarrick J. Wong 	const struct xfs_rmap_irec	*irec)
213c4e34172SDarrick J. Wong {
214c4e34172SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
2157d7d6d2fSDarrick J. Wong 	bool				is_inode;
2167d7d6d2fSDarrick J. Wong 	bool				is_unwritten;
2177d7d6d2fSDarrick J. Wong 	bool				is_bmbt;
2187d7d6d2fSDarrick J. Wong 	bool				is_attr;
219c4e34172SDarrick J. Wong 
220c4e34172SDarrick J. Wong 	if (irec->rm_blockcount == 0)
221c4e34172SDarrick J. Wong 		return __this_address;
222c4e34172SDarrick J. Wong 	if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
223c4e34172SDarrick J. Wong 		if (irec->rm_owner != XFS_RMAP_OWN_FS)
224c4e34172SDarrick J. Wong 			return __this_address;
225c4e34172SDarrick J. Wong 		if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
226c4e34172SDarrick J. Wong 			return __this_address;
227c4e34172SDarrick J. Wong 	} else {
228c4e34172SDarrick J. Wong 		/* check for valid extent range, including overflow */
229c4e34172SDarrick J. Wong 		if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
230c4e34172SDarrick J. Wong 						       irec->rm_blockcount))
231c4e34172SDarrick J. Wong 			return __this_address;
232c4e34172SDarrick J. Wong 	}
233c4e34172SDarrick J. Wong 
234c4e34172SDarrick J. Wong 	if (!(xfs_verify_ino(mp, irec->rm_owner) ||
235c4e34172SDarrick J. Wong 	      (irec->rm_owner <= XFS_RMAP_OWN_FS &&
236c4e34172SDarrick J. Wong 	       irec->rm_owner >= XFS_RMAP_OWN_MIN)))
237c4e34172SDarrick J. Wong 		return __this_address;
238c4e34172SDarrick J. Wong 
2397d7d6d2fSDarrick J. Wong 	/* Check flags. */
2407d7d6d2fSDarrick J. Wong 	is_inode = !XFS_RMAP_NON_INODE_OWNER(irec->rm_owner);
2417d7d6d2fSDarrick J. Wong 	is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK;
2427d7d6d2fSDarrick J. Wong 	is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK;
2437d7d6d2fSDarrick J. Wong 	is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN;
2447d7d6d2fSDarrick J. Wong 
2457d7d6d2fSDarrick J. Wong 	if (is_bmbt && irec->rm_offset != 0)
2467d7d6d2fSDarrick J. Wong 		return __this_address;
2477d7d6d2fSDarrick J. Wong 
2487d7d6d2fSDarrick J. Wong 	if (!is_inode && irec->rm_offset != 0)
2497d7d6d2fSDarrick J. Wong 		return __this_address;
2507d7d6d2fSDarrick J. Wong 
2517d7d6d2fSDarrick J. Wong 	if (is_unwritten && (is_bmbt || !is_inode || is_attr))
2527d7d6d2fSDarrick J. Wong 		return __this_address;
2537d7d6d2fSDarrick J. Wong 
2547d7d6d2fSDarrick J. Wong 	if (!is_inode && (is_bmbt || is_unwritten || is_attr))
2557d7d6d2fSDarrick J. Wong 		return __this_address;
2567d7d6d2fSDarrick J. Wong 
257e774b2eaSDarrick J. Wong 	/* Check for a valid fork offset, if applicable. */
258e774b2eaSDarrick J. Wong 	if (is_inode && !is_bmbt &&
259e774b2eaSDarrick J. Wong 	    !xfs_verify_fileext(mp, irec->rm_offset, irec->rm_blockcount))
260e774b2eaSDarrick J. Wong 		return __this_address;
261e774b2eaSDarrick J. Wong 
262c4e34172SDarrick J. Wong 	return NULL;
263c4e34172SDarrick J. Wong }
264c4e34172SDarrick J. Wong 
265ee12eaaaSDarrick J. Wong static inline int
xfs_rmap_complain_bad_rec(struct xfs_btree_cur * cur,xfs_failaddr_t fa,const struct xfs_rmap_irec * irec)266ee12eaaaSDarrick J. Wong xfs_rmap_complain_bad_rec(
267ee12eaaaSDarrick J. Wong 	struct xfs_btree_cur		*cur,
268ee12eaaaSDarrick J. Wong 	xfs_failaddr_t			fa,
269ee12eaaaSDarrick J. Wong 	const struct xfs_rmap_irec	*irec)
270ee12eaaaSDarrick J. Wong {
271ee12eaaaSDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
272ee12eaaaSDarrick J. Wong 
273ee12eaaaSDarrick J. Wong 	xfs_warn(mp,
274ee12eaaaSDarrick J. Wong 		"Reverse Mapping BTree record corruption in AG %d detected at %pS!",
275ee12eaaaSDarrick J. Wong 		cur->bc_ag.pag->pag_agno, fa);
276ee12eaaaSDarrick J. Wong 	xfs_warn(mp,
277ee12eaaaSDarrick J. Wong 		"Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
278ee12eaaaSDarrick J. Wong 		irec->rm_owner, irec->rm_flags, irec->rm_startblock,
279ee12eaaaSDarrick J. Wong 		irec->rm_blockcount);
280ee12eaaaSDarrick J. Wong 	return -EFSCORRUPTED;
281ee12eaaaSDarrick J. Wong }
282ee12eaaaSDarrick J. Wong 
2834b8ed677SDarrick J. Wong /*
2844b8ed677SDarrick J. Wong  * Get the data from the pointed-to record.
2854b8ed677SDarrick J. Wong  */
2864b8ed677SDarrick J. Wong int
xfs_rmap_get_rec(struct xfs_btree_cur * cur,struct xfs_rmap_irec * irec,int * stat)2874b8ed677SDarrick J. Wong xfs_rmap_get_rec(
2884b8ed677SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2894b8ed677SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
2904b8ed677SDarrick J. Wong 	int			*stat)
2914b8ed677SDarrick J. Wong {
2924b8ed677SDarrick J. Wong 	union xfs_btree_rec	*rec;
293c4e34172SDarrick J. Wong 	xfs_failaddr_t		fa;
2944b8ed677SDarrick J. Wong 	int			error;
2954b8ed677SDarrick J. Wong 
2964b8ed677SDarrick J. Wong 	error = xfs_btree_get_rec(cur, &rec, stat);
2974b8ed677SDarrick J. Wong 	if (error || !*stat)
2984b8ed677SDarrick J. Wong 		return error;
2994b8ed677SDarrick J. Wong 
300c4e34172SDarrick J. Wong 	fa = xfs_rmap_btrec_to_irec(rec, irec);
301c4e34172SDarrick J. Wong 	if (!fa)
302c4e34172SDarrick J. Wong 		fa = xfs_rmap_check_irec(cur, irec);
303c4e34172SDarrick J. Wong 	if (fa)
304ee12eaaaSDarrick J. Wong 		return xfs_rmap_complain_bad_rec(cur, fa, irec);
3059e6c08d4SDave Chinner 
3069e6c08d4SDave Chinner 	return 0;
3074b8ed677SDarrick J. Wong }
3084b8ed677SDarrick J. Wong 
309ceeb9c83SDarrick J. Wong struct xfs_find_left_neighbor_info {
310ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	high;
311ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec;
312ceeb9c83SDarrick J. Wong };
313ceeb9c83SDarrick J. Wong 
314ceeb9c83SDarrick J. Wong /* For each rmap given, figure out if it matches the key we want. */
315ceeb9c83SDarrick J. Wong STATIC int
xfs_rmap_find_left_neighbor_helper(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * rec,void * priv)316ceeb9c83SDarrick J. Wong xfs_rmap_find_left_neighbor_helper(
317ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
318159eb69dSDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
319ceeb9c83SDarrick J. Wong 	void				*priv)
320ceeb9c83SDarrick J. Wong {
321ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	*info = priv;
322ceeb9c83SDarrick J. Wong 
323ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
32450f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
325ceeb9c83SDarrick J. Wong 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
326ceeb9c83SDarrick J. Wong 			rec->rm_flags);
327ceeb9c83SDarrick J. Wong 
328ceeb9c83SDarrick J. Wong 	if (rec->rm_owner != info->high.rm_owner)
32939ee2239SDarrick J. Wong 		return 0;
330ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
331ceeb9c83SDarrick J. Wong 	    !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
332ceeb9c83SDarrick J. Wong 	    rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset)
33339ee2239SDarrick J. Wong 		return 0;
334ceeb9c83SDarrick J. Wong 
335ceeb9c83SDarrick J. Wong 	*info->irec = *rec;
336e7ee96dfSDarrick J. Wong 	return -ECANCELED;
337ceeb9c83SDarrick J. Wong }
338ceeb9c83SDarrick J. Wong 
339ceeb9c83SDarrick J. Wong /*
340ceeb9c83SDarrick J. Wong  * Find the record to the left of the given extent, being careful only to
341ceeb9c83SDarrick J. Wong  * return a match with the same owner and adjacent physical and logical
342ceeb9c83SDarrick J. Wong  * block ranges.
343ceeb9c83SDarrick J. Wong  */
3441edf8056SDarrick J. Wong STATIC int
xfs_rmap_find_left_neighbor(struct xfs_btree_cur * cur,xfs_agblock_t bno,uint64_t owner,uint64_t offset,unsigned int flags,struct xfs_rmap_irec * irec,int * stat)345ceeb9c83SDarrick J. Wong xfs_rmap_find_left_neighbor(
346ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
347ceeb9c83SDarrick J. Wong 	xfs_agblock_t		bno,
348ceeb9c83SDarrick J. Wong 	uint64_t		owner,
349ceeb9c83SDarrick J. Wong 	uint64_t		offset,
350ceeb9c83SDarrick J. Wong 	unsigned int		flags,
351ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
352ceeb9c83SDarrick J. Wong 	int			*stat)
353ceeb9c83SDarrick J. Wong {
354ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	info;
3551edf8056SDarrick J. Wong 	int			found = 0;
356ceeb9c83SDarrick J. Wong 	int			error;
357ceeb9c83SDarrick J. Wong 
358ceeb9c83SDarrick J. Wong 	*stat = 0;
359ceeb9c83SDarrick J. Wong 	if (bno == 0)
360ceeb9c83SDarrick J. Wong 		return 0;
361ceeb9c83SDarrick J. Wong 	info.high.rm_startblock = bno - 1;
362ceeb9c83SDarrick J. Wong 	info.high.rm_owner = owner;
363ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(owner) &&
364ceeb9c83SDarrick J. Wong 	    !(flags & XFS_RMAP_BMBT_BLOCK)) {
365ceeb9c83SDarrick J. Wong 		if (offset == 0)
366ceeb9c83SDarrick J. Wong 			return 0;
367ceeb9c83SDarrick J. Wong 		info.high.rm_offset = offset - 1;
368ceeb9c83SDarrick J. Wong 	} else
369ceeb9c83SDarrick J. Wong 		info.high.rm_offset = 0;
370ceeb9c83SDarrick J. Wong 	info.high.rm_flags = flags;
371ceeb9c83SDarrick J. Wong 	info.high.rm_blockcount = 0;
372ceeb9c83SDarrick J. Wong 	info.irec = irec;
373ceeb9c83SDarrick J. Wong 
374ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
37550f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
376ceeb9c83SDarrick J. Wong 
3771edf8056SDarrick J. Wong 	/*
3781edf8056SDarrick J. Wong 	 * Historically, we always used the range query to walk every reverse
3791edf8056SDarrick J. Wong 	 * mapping that could possibly overlap the key that the caller asked
3801edf8056SDarrick J. Wong 	 * for, and filter out the ones that don't.  That is very slow when
3811edf8056SDarrick J. Wong 	 * there are a lot of records.
3821edf8056SDarrick J. Wong 	 *
3831edf8056SDarrick J. Wong 	 * However, there are two scenarios where the classic btree search can
3841edf8056SDarrick J. Wong 	 * produce correct results -- if the index contains a record that is an
3851edf8056SDarrick J. Wong 	 * exact match for the lookup key; and if there are no other records
3861edf8056SDarrick J. Wong 	 * between the record we want and the key we supplied.
3871edf8056SDarrick J. Wong 	 *
3881edf8056SDarrick J. Wong 	 * As an optimization, try a non-overlapped lookup first.  This makes
3891edf8056SDarrick J. Wong 	 * extent conversion and remap operations run a bit faster if the
3901edf8056SDarrick J. Wong 	 * physical extents aren't being shared.  If we don't find what we
3911edf8056SDarrick J. Wong 	 * want, we fall back to the overlapped query.
3921edf8056SDarrick J. Wong 	 */
3931edf8056SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
3941edf8056SDarrick J. Wong 			&found);
3951edf8056SDarrick J. Wong 	if (error)
3961edf8056SDarrick J. Wong 		return error;
3971edf8056SDarrick J. Wong 	if (found)
3981edf8056SDarrick J. Wong 		error = xfs_rmap_find_left_neighbor_helper(cur, irec, &info);
3991edf8056SDarrick J. Wong 	if (!error)
400ceeb9c83SDarrick J. Wong 		error = xfs_rmap_query_range(cur, &info.high, &info.high,
401ceeb9c83SDarrick J. Wong 				xfs_rmap_find_left_neighbor_helper, &info);
4021edf8056SDarrick J. Wong 	if (error != -ECANCELED)
4031edf8056SDarrick J. Wong 		return error;
4041edf8056SDarrick J. Wong 
4051edf8056SDarrick J. Wong 	*stat = 1;
406ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
40750f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, irec->rm_startblock,
4081edf8056SDarrick J. Wong 			irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
4091edf8056SDarrick J. Wong 			irec->rm_flags);
4101edf8056SDarrick J. Wong 	return 0;
411ceeb9c83SDarrick J. Wong }
412ceeb9c83SDarrick J. Wong 
413ceeb9c83SDarrick J. Wong /* For each rmap given, figure out if it matches the key we want. */
414ceeb9c83SDarrick J. Wong STATIC int
xfs_rmap_lookup_le_range_helper(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * rec,void * priv)415ceeb9c83SDarrick J. Wong xfs_rmap_lookup_le_range_helper(
416ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
417159eb69dSDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
418ceeb9c83SDarrick J. Wong 	void				*priv)
419ceeb9c83SDarrick J. Wong {
420ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	*info = priv;
421ceeb9c83SDarrick J. Wong 
422ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
42350f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
424ceeb9c83SDarrick J. Wong 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
425ceeb9c83SDarrick J. Wong 			rec->rm_flags);
426ceeb9c83SDarrick J. Wong 
427ceeb9c83SDarrick J. Wong 	if (rec->rm_owner != info->high.rm_owner)
42839ee2239SDarrick J. Wong 		return 0;
429ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
430ceeb9c83SDarrick J. Wong 	    !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
431ceeb9c83SDarrick J. Wong 	    (rec->rm_offset > info->high.rm_offset ||
432ceeb9c83SDarrick J. Wong 	     rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset))
43339ee2239SDarrick J. Wong 		return 0;
434ceeb9c83SDarrick J. Wong 
435ceeb9c83SDarrick J. Wong 	*info->irec = *rec;
436e7ee96dfSDarrick J. Wong 	return -ECANCELED;
437ceeb9c83SDarrick J. Wong }
438ceeb9c83SDarrick J. Wong 
439ceeb9c83SDarrick J. Wong /*
440ceeb9c83SDarrick J. Wong  * Find the record to the left of the given extent, being careful only to
441ceeb9c83SDarrick J. Wong  * return a match with the same owner and overlapping physical and logical
442ceeb9c83SDarrick J. Wong  * block ranges.  This is the overlapping-interval version of
443ceeb9c83SDarrick J. Wong  * xfs_rmap_lookup_le.
444ceeb9c83SDarrick J. Wong  */
445ceeb9c83SDarrick J. Wong int
xfs_rmap_lookup_le_range(struct xfs_btree_cur * cur,xfs_agblock_t bno,uint64_t owner,uint64_t offset,unsigned int flags,struct xfs_rmap_irec * irec,int * stat)446ceeb9c83SDarrick J. Wong xfs_rmap_lookup_le_range(
447ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur	*cur,
448ceeb9c83SDarrick J. Wong 	xfs_agblock_t		bno,
449ceeb9c83SDarrick J. Wong 	uint64_t		owner,
450ceeb9c83SDarrick J. Wong 	uint64_t		offset,
451ceeb9c83SDarrick J. Wong 	unsigned int		flags,
452ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
453ceeb9c83SDarrick J. Wong 	int			*stat)
454ceeb9c83SDarrick J. Wong {
455ceeb9c83SDarrick J. Wong 	struct xfs_find_left_neighbor_info	info;
45675d893d1SDarrick J. Wong 	int			found = 0;
457ceeb9c83SDarrick J. Wong 	int			error;
458ceeb9c83SDarrick J. Wong 
459ceeb9c83SDarrick J. Wong 	info.high.rm_startblock = bno;
460ceeb9c83SDarrick J. Wong 	info.high.rm_owner = owner;
461ceeb9c83SDarrick J. Wong 	if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK))
462ceeb9c83SDarrick J. Wong 		info.high.rm_offset = offset;
463ceeb9c83SDarrick J. Wong 	else
464ceeb9c83SDarrick J. Wong 		info.high.rm_offset = 0;
465ceeb9c83SDarrick J. Wong 	info.high.rm_flags = flags;
466ceeb9c83SDarrick J. Wong 	info.high.rm_blockcount = 0;
467ceeb9c83SDarrick J. Wong 	*stat = 0;
468ceeb9c83SDarrick J. Wong 	info.irec = irec;
469ceeb9c83SDarrick J. Wong 
47075d893d1SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_ag.pag->pag_agno,
47175d893d1SDarrick J. Wong 			bno, 0, owner, offset, flags);
47275d893d1SDarrick J. Wong 
47375d893d1SDarrick J. Wong 	/*
47475d893d1SDarrick J. Wong 	 * Historically, we always used the range query to walk every reverse
47575d893d1SDarrick J. Wong 	 * mapping that could possibly overlap the key that the caller asked
47675d893d1SDarrick J. Wong 	 * for, and filter out the ones that don't.  That is very slow when
47775d893d1SDarrick J. Wong 	 * there are a lot of records.
47875d893d1SDarrick J. Wong 	 *
47975d893d1SDarrick J. Wong 	 * However, there are two scenarios where the classic btree search can
48075d893d1SDarrick J. Wong 	 * produce correct results -- if the index contains a record that is an
48175d893d1SDarrick J. Wong 	 * exact match for the lookup key; and if there are no other records
48275d893d1SDarrick J. Wong 	 * between the record we want and the key we supplied.
48375d893d1SDarrick J. Wong 	 *
48475d893d1SDarrick J. Wong 	 * As an optimization, try a non-overlapped lookup first.  This makes
48575d893d1SDarrick J. Wong 	 * scrub run much faster on most filesystems because bmbt records are
48675d893d1SDarrick J. Wong 	 * usually an exact match for rmap records.  If we don't find what we
48775d893d1SDarrick J. Wong 	 * want, we fall back to the overlapped query.
48875d893d1SDarrick J. Wong 	 */
48975d893d1SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
49075d893d1SDarrick J. Wong 			&found);
49175d893d1SDarrick J. Wong 	if (error)
49275d893d1SDarrick J. Wong 		return error;
49375d893d1SDarrick J. Wong 	if (found)
49475d893d1SDarrick J. Wong 		error = xfs_rmap_lookup_le_range_helper(cur, irec, &info);
49575d893d1SDarrick J. Wong 	if (!error)
496ceeb9c83SDarrick J. Wong 		error = xfs_rmap_query_range(cur, &info.high, &info.high,
497ceeb9c83SDarrick J. Wong 				xfs_rmap_lookup_le_range_helper, &info);
49875d893d1SDarrick J. Wong 	if (error != -ECANCELED)
49975d893d1SDarrick J. Wong 		return error;
50075d893d1SDarrick J. Wong 
50175d893d1SDarrick J. Wong 	*stat = 1;
502ceeb9c83SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
50350f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, irec->rm_startblock,
50475d893d1SDarrick J. Wong 			irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
50575d893d1SDarrick J. Wong 			irec->rm_flags);
50675d893d1SDarrick J. Wong 	return 0;
507ceeb9c83SDarrick J. Wong }
508ceeb9c83SDarrick J. Wong 
509f922cd90SDarrick J. Wong /*
51068c58e9bSDarrick J. Wong  * Perform all the relevant owner checks for a removal op.  If we're doing an
51168c58e9bSDarrick J. Wong  * unknown-owner removal then we have no owner information to check.
51268c58e9bSDarrick J. Wong  */
51368c58e9bSDarrick J. Wong static int
xfs_rmap_free_check_owner(struct xfs_mount * mp,uint64_t ltoff,struct xfs_rmap_irec * rec,xfs_filblks_t len,uint64_t owner,uint64_t offset,unsigned int flags)51468c58e9bSDarrick J. Wong xfs_rmap_free_check_owner(
51568c58e9bSDarrick J. Wong 	struct xfs_mount	*mp,
51668c58e9bSDarrick J. Wong 	uint64_t		ltoff,
51768c58e9bSDarrick J. Wong 	struct xfs_rmap_irec	*rec,
51868c58e9bSDarrick J. Wong 	xfs_filblks_t		len,
51968c58e9bSDarrick J. Wong 	uint64_t		owner,
52068c58e9bSDarrick J. Wong 	uint64_t		offset,
52168c58e9bSDarrick J. Wong 	unsigned int		flags)
52268c58e9bSDarrick J. Wong {
52368c58e9bSDarrick J. Wong 	int			error = 0;
52468c58e9bSDarrick J. Wong 
52568c58e9bSDarrick J. Wong 	if (owner == XFS_RMAP_OWN_UNKNOWN)
52668c58e9bSDarrick J. Wong 		return 0;
52768c58e9bSDarrick J. Wong 
52868c58e9bSDarrick J. Wong 	/* Make sure the unwritten flag matches. */
529f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
530f9e03706SDarrick J. Wong 			   (flags & XFS_RMAP_UNWRITTEN) !=
531f9e03706SDarrick J. Wong 			   (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
532f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
533f9e03706SDarrick J. Wong 		goto out;
534f9e03706SDarrick J. Wong 	}
53568c58e9bSDarrick J. Wong 
53668c58e9bSDarrick J. Wong 	/* Make sure the owner matches what we expect to find in the tree. */
537f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
538f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
539f9e03706SDarrick J. Wong 		goto out;
540f9e03706SDarrick J. Wong 	}
54168c58e9bSDarrick J. Wong 
54268c58e9bSDarrick J. Wong 	/* Check the offset, if necessary. */
54368c58e9bSDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(owner))
54468c58e9bSDarrick J. Wong 		goto out;
54568c58e9bSDarrick J. Wong 
54668c58e9bSDarrick J. Wong 	if (flags & XFS_RMAP_BMBT_BLOCK) {
547f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
548f9e03706SDarrick J. Wong 				   !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
549f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
550f9e03706SDarrick J. Wong 			goto out;
551f9e03706SDarrick J. Wong 		}
55268c58e9bSDarrick J. Wong 	} else {
553f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
554f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
555f9e03706SDarrick J. Wong 			goto out;
556f9e03706SDarrick J. Wong 		}
557f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
558f9e03706SDarrick J. Wong 				   offset + len > ltoff + rec->rm_blockcount)) {
559f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
560f9e03706SDarrick J. Wong 			goto out;
561f9e03706SDarrick J. Wong 		}
56268c58e9bSDarrick J. Wong 	}
56368c58e9bSDarrick J. Wong 
56468c58e9bSDarrick J. Wong out:
56568c58e9bSDarrick J. Wong 	return error;
56668c58e9bSDarrick J. Wong }
56768c58e9bSDarrick J. Wong 
56868c58e9bSDarrick J. Wong /*
569f922cd90SDarrick J. Wong  * Find the extent in the rmap btree and remove it.
570f922cd90SDarrick J. Wong  *
571f922cd90SDarrick J. Wong  * The record we find should always be an exact match for the extent that we're
572f922cd90SDarrick J. Wong  * looking for, since we insert them into the btree without modification.
573f922cd90SDarrick J. Wong  *
574f922cd90SDarrick J. Wong  * Special Case #1: when growing the filesystem, we "free" an extent when
575f922cd90SDarrick J. Wong  * growing the last AG. This extent is new space and so it is not tracked as
576f922cd90SDarrick J. Wong  * used space in the btree. The growfs code will pass in an owner of
577f922cd90SDarrick J. Wong  * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
578f922cd90SDarrick J. Wong  * extent. We verify that - the extent lookup result in a record that does not
579f922cd90SDarrick J. Wong  * overlap.
580f922cd90SDarrick J. Wong  *
581f922cd90SDarrick J. Wong  * Special Case #2: EFIs do not record the owner of the extent, so when
582f922cd90SDarrick J. Wong  * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
583f922cd90SDarrick J. Wong  * btree to ignore the owner (i.e. wildcard match) so we don't trigger
584f922cd90SDarrick J. Wong  * corruption checks during log recovery.
585f922cd90SDarrick J. Wong  */
586f922cd90SDarrick J. Wong STATIC int
xfs_rmap_unmap(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,bool unwritten,const struct xfs_owner_info * oinfo)587f922cd90SDarrick J. Wong xfs_rmap_unmap(
588f922cd90SDarrick J. Wong 	struct xfs_btree_cur		*cur,
589f922cd90SDarrick J. Wong 	xfs_agblock_t			bno,
590f922cd90SDarrick J. Wong 	xfs_extlen_t			len,
591f922cd90SDarrick J. Wong 	bool				unwritten,
59266e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
593f922cd90SDarrick J. Wong {
594f922cd90SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
595f922cd90SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
596f922cd90SDarrick J. Wong 	uint64_t			ltoff;
597f922cd90SDarrick J. Wong 	int				error = 0;
598f922cd90SDarrick J. Wong 	int				i;
599f922cd90SDarrick J. Wong 	uint64_t			owner;
600f922cd90SDarrick J. Wong 	uint64_t			offset;
601f922cd90SDarrick J. Wong 	unsigned int			flags;
602f922cd90SDarrick J. Wong 	bool				ignore_off;
603f922cd90SDarrick J. Wong 
604f922cd90SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
605f922cd90SDarrick J. Wong 	ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
606f922cd90SDarrick J. Wong 			(flags & XFS_RMAP_BMBT_BLOCK);
607f922cd90SDarrick J. Wong 	if (unwritten)
608f922cd90SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
60950f02fe3SDave Chinner 	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
610f922cd90SDarrick J. Wong 			unwritten, oinfo);
611f922cd90SDarrick J. Wong 
612f922cd90SDarrick J. Wong 	/*
613f922cd90SDarrick J. Wong 	 * We should always have a left record because there's a static record
614f922cd90SDarrick J. Wong 	 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
615f922cd90SDarrick J. Wong 	 * will not ever be removed from the tree.
616f922cd90SDarrick J. Wong 	 */
6175b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &ltrec, &i);
618f922cd90SDarrick J. Wong 	if (error)
619f922cd90SDarrick J. Wong 		goto out_error;
620f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
621f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
622f9e03706SDarrick J. Wong 		goto out_error;
623f9e03706SDarrick J. Wong 	}
624f922cd90SDarrick J. Wong 
625f922cd90SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
62650f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
627f922cd90SDarrick J. Wong 			ltrec.rm_blockcount, ltrec.rm_owner,
628f922cd90SDarrick J. Wong 			ltrec.rm_offset, ltrec.rm_flags);
629f922cd90SDarrick J. Wong 	ltoff = ltrec.rm_offset;
630f922cd90SDarrick J. Wong 
631f922cd90SDarrick J. Wong 	/*
632f922cd90SDarrick J. Wong 	 * For growfs, the incoming extent must be beyond the left record we
633f922cd90SDarrick J. Wong 	 * just found as it is new space and won't be used by anyone. This is
634f922cd90SDarrick J. Wong 	 * just a corruption check as we don't actually do anything with this
635f922cd90SDarrick J. Wong 	 * extent.  Note that we need to use >= instead of > because it might
636f922cd90SDarrick J. Wong 	 * be the case that the "left" extent goes all the way to EOFS.
637f922cd90SDarrick J. Wong 	 */
638f922cd90SDarrick J. Wong 	if (owner == XFS_RMAP_OWN_NULL) {
639f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
640f9e03706SDarrick J. Wong 				   bno <
641f9e03706SDarrick J. Wong 				   ltrec.rm_startblock + ltrec.rm_blockcount)) {
642f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
643f9e03706SDarrick J. Wong 			goto out_error;
644f9e03706SDarrick J. Wong 		}
645f922cd90SDarrick J. Wong 		goto out_done;
646f922cd90SDarrick J. Wong 	}
647f922cd90SDarrick J. Wong 
64833df3a9cSDarrick J. Wong 	/*
64933df3a9cSDarrick J. Wong 	 * If we're doing an unknown-owner removal for EFI recovery, we expect
65033df3a9cSDarrick J. Wong 	 * to find the full range in the rmapbt or nothing at all.  If we
65133df3a9cSDarrick J. Wong 	 * don't find any rmaps overlapping either end of the range, we're
65233df3a9cSDarrick J. Wong 	 * done.  Hopefully this means that the EFI creator already queued
65333df3a9cSDarrick J. Wong 	 * (and finished) a RUI to remove the rmap.
65433df3a9cSDarrick J. Wong 	 */
65533df3a9cSDarrick J. Wong 	if (owner == XFS_RMAP_OWN_UNKNOWN &&
65633df3a9cSDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount <= bno) {
65733df3a9cSDarrick J. Wong 		struct xfs_rmap_irec    rtrec;
65833df3a9cSDarrick J. Wong 
65933df3a9cSDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
66033df3a9cSDarrick J. Wong 		if (error)
66133df3a9cSDarrick J. Wong 			goto out_error;
66233df3a9cSDarrick J. Wong 		if (i == 0)
66333df3a9cSDarrick J. Wong 			goto out_done;
66433df3a9cSDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &rtrec, &i);
66533df3a9cSDarrick J. Wong 		if (error)
66633df3a9cSDarrick J. Wong 			goto out_error;
667f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
668f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
669f9e03706SDarrick J. Wong 			goto out_error;
670f9e03706SDarrick J. Wong 		}
67133df3a9cSDarrick J. Wong 		if (rtrec.rm_startblock >= bno + len)
67233df3a9cSDarrick J. Wong 			goto out_done;
67333df3a9cSDarrick J. Wong 	}
67433df3a9cSDarrick J. Wong 
675f922cd90SDarrick J. Wong 	/* Make sure the extent we found covers the entire freeing range. */
676f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
677f9e03706SDarrick J. Wong 			   ltrec.rm_startblock > bno ||
678f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount <
679f9e03706SDarrick J. Wong 			   bno + len)) {
680f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
681f9e03706SDarrick J. Wong 		goto out_error;
682f9e03706SDarrick J. Wong 	}
683f922cd90SDarrick J. Wong 
68468c58e9bSDarrick J. Wong 	/* Check owner information. */
685a1f69417SEric Sandeen 	error = xfs_rmap_free_check_owner(mp, ltoff, &ltrec, len, owner,
68668c58e9bSDarrick J. Wong 			offset, flags);
68768c58e9bSDarrick J. Wong 	if (error)
68868c58e9bSDarrick J. Wong 		goto out_error;
689f922cd90SDarrick J. Wong 
690f922cd90SDarrick J. Wong 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
691f922cd90SDarrick J. Wong 		/* exact match, simply remove the record from rmap tree */
69250f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
693f922cd90SDarrick J. Wong 				ltrec.rm_startblock, ltrec.rm_blockcount,
694f922cd90SDarrick J. Wong 				ltrec.rm_owner, ltrec.rm_offset,
695f922cd90SDarrick J. Wong 				ltrec.rm_flags);
696f922cd90SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
697f922cd90SDarrick J. Wong 		if (error)
698f922cd90SDarrick J. Wong 			goto out_error;
699f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
700f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
701f9e03706SDarrick J. Wong 			goto out_error;
702f9e03706SDarrick J. Wong 		}
703f922cd90SDarrick J. Wong 	} else if (ltrec.rm_startblock == bno) {
704f922cd90SDarrick J. Wong 		/*
705f922cd90SDarrick J. Wong 		 * overlap left hand side of extent: move the start, trim the
706f922cd90SDarrick J. Wong 		 * length and update the current record.
707f922cd90SDarrick J. Wong 		 *
708f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
709f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
710f922cd90SDarrick J. Wong 		 * Freeing: |fffffffff|
711f922cd90SDarrick J. Wong 		 * Result:            |rrrrrrrrrr|
712f922cd90SDarrick J. Wong 		 *         bno       len
713f922cd90SDarrick J. Wong 		 */
714f922cd90SDarrick J. Wong 		ltrec.rm_startblock += len;
715f922cd90SDarrick J. Wong 		ltrec.rm_blockcount -= len;
716f922cd90SDarrick J. Wong 		if (!ignore_off)
717f922cd90SDarrick J. Wong 			ltrec.rm_offset += len;
718f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
719f922cd90SDarrick J. Wong 		if (error)
720f922cd90SDarrick J. Wong 			goto out_error;
721f922cd90SDarrick J. Wong 	} else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
722f922cd90SDarrick J. Wong 		/*
723f922cd90SDarrick J. Wong 		 * overlap right hand side of extent: trim the length and update
724f922cd90SDarrick J. Wong 		 * the current record.
725f922cd90SDarrick J. Wong 		 *
726f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
727f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
728f922cd90SDarrick J. Wong 		 * Freeing:            |fffffffff|
729f922cd90SDarrick J. Wong 		 * Result:  |rrrrrrrrrr|
730f922cd90SDarrick J. Wong 		 *                    bno       len
731f922cd90SDarrick J. Wong 		 */
732f922cd90SDarrick J. Wong 		ltrec.rm_blockcount -= len;
733f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
734f922cd90SDarrick J. Wong 		if (error)
735f922cd90SDarrick J. Wong 			goto out_error;
736f922cd90SDarrick J. Wong 	} else {
737f922cd90SDarrick J. Wong 
738f922cd90SDarrick J. Wong 		/*
739f922cd90SDarrick J. Wong 		 * overlap middle of extent: trim the length of the existing
740f922cd90SDarrick J. Wong 		 * record to the length of the new left-extent size, increment
741f922cd90SDarrick J. Wong 		 * the insertion position so we can insert a new record
742f922cd90SDarrick J. Wong 		 * containing the remaining right-extent space.
743f922cd90SDarrick J. Wong 		 *
744f922cd90SDarrick J. Wong 		 *       ltbno                ltlen
745f922cd90SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
746f922cd90SDarrick J. Wong 		 * Freeing:       |fffffffff|
747f922cd90SDarrick J. Wong 		 * Result:  |rrrrr|         |rrrr|
748f922cd90SDarrick J. Wong 		 *               bno       len
749f922cd90SDarrick J. Wong 		 */
750f922cd90SDarrick J. Wong 		xfs_extlen_t	orig_len = ltrec.rm_blockcount;
751f922cd90SDarrick J. Wong 
752f922cd90SDarrick J. Wong 		ltrec.rm_blockcount = bno - ltrec.rm_startblock;
753f922cd90SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
754f922cd90SDarrick J. Wong 		if (error)
755f922cd90SDarrick J. Wong 			goto out_error;
756f922cd90SDarrick J. Wong 
757f922cd90SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
758f922cd90SDarrick J. Wong 		if (error)
759f922cd90SDarrick J. Wong 			goto out_error;
760f922cd90SDarrick J. Wong 
761f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_startblock = bno + len;
762f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_blockcount = orig_len - len -
763f922cd90SDarrick J. Wong 						     ltrec.rm_blockcount;
764f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_owner = ltrec.rm_owner;
765f922cd90SDarrick J. Wong 		if (ignore_off)
766f922cd90SDarrick J. Wong 			cur->bc_rec.r.rm_offset = 0;
767f922cd90SDarrick J. Wong 		else
768f922cd90SDarrick J. Wong 			cur->bc_rec.r.rm_offset = offset + len;
769f922cd90SDarrick J. Wong 		cur->bc_rec.r.rm_flags = flags;
77050f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
771f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_startblock,
772f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_blockcount,
773f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_owner,
774f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_offset,
775f922cd90SDarrick J. Wong 				cur->bc_rec.r.rm_flags);
776f922cd90SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
777f922cd90SDarrick J. Wong 		if (error)
778f922cd90SDarrick J. Wong 			goto out_error;
779f922cd90SDarrick J. Wong 	}
780f922cd90SDarrick J. Wong 
781f922cd90SDarrick J. Wong out_done:
78250f02fe3SDave Chinner 	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
783f922cd90SDarrick J. Wong 			unwritten, oinfo);
784f922cd90SDarrick J. Wong out_error:
785f922cd90SDarrick J. Wong 	if (error)
78650f02fe3SDave Chinner 		trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
787f922cd90SDarrick J. Wong 				error, _RET_IP_);
788f922cd90SDarrick J. Wong 	return error;
789f922cd90SDarrick J. Wong }
790f922cd90SDarrick J. Wong 
791f922cd90SDarrick J. Wong /*
792f922cd90SDarrick J. Wong  * Remove a reference to an extent in the rmap btree.
793f922cd90SDarrick J. Wong  */
794673930c3SDarrick J. Wong int
xfs_rmap_free(struct xfs_trans * tp,struct xfs_buf * agbp,struct xfs_perag * pag,xfs_agblock_t bno,xfs_extlen_t len,const struct xfs_owner_info * oinfo)795673930c3SDarrick J. Wong xfs_rmap_free(
796673930c3SDarrick J. Wong 	struct xfs_trans		*tp,
797673930c3SDarrick J. Wong 	struct xfs_buf			*agbp,
798fa9c3c19SDave Chinner 	struct xfs_perag		*pag,
799673930c3SDarrick J. Wong 	xfs_agblock_t			bno,
800673930c3SDarrick J. Wong 	xfs_extlen_t			len,
80166e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
802673930c3SDarrick J. Wong {
803673930c3SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
804f922cd90SDarrick J. Wong 	struct xfs_btree_cur		*cur;
805f922cd90SDarrick J. Wong 	int				error;
806673930c3SDarrick J. Wong 
80738c26bfdSDave Chinner 	if (!xfs_has_rmapbt(mp))
808673930c3SDarrick J. Wong 		return 0;
809673930c3SDarrick J. Wong 
810fa9c3c19SDave Chinner 	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
811f922cd90SDarrick J. Wong 
812f922cd90SDarrick J. Wong 	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
813f922cd90SDarrick J. Wong 
8140b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
815673930c3SDarrick J. Wong 	return error;
816673930c3SDarrick J. Wong }
817673930c3SDarrick J. Wong 
8180a1b0b38SDarrick J. Wong /*
8190a1b0b38SDarrick J. Wong  * A mergeable rmap must have the same owner and the same values for
8200a1b0b38SDarrick J. Wong  * the unwritten, attr_fork, and bmbt flags.  The startblock and
8210a1b0b38SDarrick J. Wong  * offset are checked separately.
8220a1b0b38SDarrick J. Wong  */
8230a1b0b38SDarrick J. Wong static bool
xfs_rmap_is_mergeable(struct xfs_rmap_irec * irec,uint64_t owner,unsigned int flags)8240a1b0b38SDarrick J. Wong xfs_rmap_is_mergeable(
8250a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec	*irec,
8260a1b0b38SDarrick J. Wong 	uint64_t		owner,
8270a1b0b38SDarrick J. Wong 	unsigned int		flags)
8280a1b0b38SDarrick J. Wong {
8290a1b0b38SDarrick J. Wong 	if (irec->rm_owner == XFS_RMAP_OWN_NULL)
8300a1b0b38SDarrick J. Wong 		return false;
8310a1b0b38SDarrick J. Wong 	if (irec->rm_owner != owner)
8320a1b0b38SDarrick J. Wong 		return false;
8330a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_UNWRITTEN) ^
8340a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_UNWRITTEN))
8350a1b0b38SDarrick J. Wong 		return false;
8360a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_ATTR_FORK) ^
8370a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_ATTR_FORK))
8380a1b0b38SDarrick J. Wong 		return false;
8390a1b0b38SDarrick J. Wong 	if ((flags & XFS_RMAP_BMBT_BLOCK) ^
8400a1b0b38SDarrick J. Wong 	    (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
8410a1b0b38SDarrick J. Wong 		return false;
8420a1b0b38SDarrick J. Wong 	return true;
8430a1b0b38SDarrick J. Wong }
8440a1b0b38SDarrick J. Wong 
8450a1b0b38SDarrick J. Wong /*
8460a1b0b38SDarrick J. Wong  * When we allocate a new block, the first thing we do is add a reference to
8470a1b0b38SDarrick J. Wong  * the extent in the rmap btree. This takes the form of a [agbno, length,
8480a1b0b38SDarrick J. Wong  * owner, offset] record.  Flags are encoded in the high bits of the offset
8490a1b0b38SDarrick J. Wong  * field.
8500a1b0b38SDarrick J. Wong  */
8510a1b0b38SDarrick J. Wong STATIC int
xfs_rmap_map(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,bool unwritten,const struct xfs_owner_info * oinfo)8520a1b0b38SDarrick J. Wong xfs_rmap_map(
8530a1b0b38SDarrick J. Wong 	struct xfs_btree_cur		*cur,
8540a1b0b38SDarrick J. Wong 	xfs_agblock_t			bno,
8550a1b0b38SDarrick J. Wong 	xfs_extlen_t			len,
8560a1b0b38SDarrick J. Wong 	bool				unwritten,
85766e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
8580a1b0b38SDarrick J. Wong {
8590a1b0b38SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
8600a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
8610a1b0b38SDarrick J. Wong 	struct xfs_rmap_irec		gtrec;
8620a1b0b38SDarrick J. Wong 	int				have_gt;
8630a1b0b38SDarrick J. Wong 	int				have_lt;
8640a1b0b38SDarrick J. Wong 	int				error = 0;
8650a1b0b38SDarrick J. Wong 	int				i;
8660a1b0b38SDarrick J. Wong 	uint64_t			owner;
8670a1b0b38SDarrick J. Wong 	uint64_t			offset;
8680a1b0b38SDarrick J. Wong 	unsigned int			flags = 0;
8690a1b0b38SDarrick J. Wong 	bool				ignore_off;
8700a1b0b38SDarrick J. Wong 
8710a1b0b38SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
8720a1b0b38SDarrick J. Wong 	ASSERT(owner != 0);
8730a1b0b38SDarrick J. Wong 	ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
8740a1b0b38SDarrick J. Wong 			(flags & XFS_RMAP_BMBT_BLOCK);
8750a1b0b38SDarrick J. Wong 	if (unwritten)
8760a1b0b38SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
87750f02fe3SDave Chinner 	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
8780a1b0b38SDarrick J. Wong 			unwritten, oinfo);
87933df3a9cSDarrick J. Wong 	ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
8800a1b0b38SDarrick J. Wong 
8810a1b0b38SDarrick J. Wong 	/*
8820a1b0b38SDarrick J. Wong 	 * For the initial lookup, look for an exact match or the left-adjacent
8830a1b0b38SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
8840a1b0b38SDarrick J. Wong 	 * start block contiguity tests.
8850a1b0b38SDarrick J. Wong 	 */
8865b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &ltrec,
8870a1b0b38SDarrick J. Wong 			&have_lt);
8880a1b0b38SDarrick J. Wong 	if (error)
8890a1b0b38SDarrick J. Wong 		goto out_error;
890fa248de9SDarrick J. Wong 	if (have_lt) {
8910a1b0b38SDarrick J. Wong 		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
89250f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
8930a1b0b38SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
8940a1b0b38SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
8950a1b0b38SDarrick J. Wong 
8960a1b0b38SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
8970a1b0b38SDarrick J. Wong 			have_lt = 0;
898fa248de9SDarrick J. Wong 	}
8990a1b0b38SDarrick J. Wong 
900f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
901f9e03706SDarrick J. Wong 			   have_lt != 0 &&
902f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
903f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
904f9e03706SDarrick J. Wong 		goto out_error;
905f9e03706SDarrick J. Wong 	}
9060a1b0b38SDarrick J. Wong 
9070a1b0b38SDarrick J. Wong 	/*
9080a1b0b38SDarrick J. Wong 	 * Increment the cursor to see if we have a right-adjacent record to our
9090a1b0b38SDarrick J. Wong 	 * insertion point. This will give us the record for end block
9100a1b0b38SDarrick J. Wong 	 * contiguity tests.
9110a1b0b38SDarrick J. Wong 	 */
9120a1b0b38SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &have_gt);
9130a1b0b38SDarrick J. Wong 	if (error)
9140a1b0b38SDarrick J. Wong 		goto out_error;
9150a1b0b38SDarrick J. Wong 	if (have_gt) {
9160a1b0b38SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
9170a1b0b38SDarrick J. Wong 		if (error)
9180a1b0b38SDarrick J. Wong 			goto out_error;
919f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
920f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
921f9e03706SDarrick J. Wong 			goto out_error;
922f9e03706SDarrick J. Wong 		}
923f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
924f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
925f9e03706SDarrick J. Wong 			goto out_error;
926f9e03706SDarrick J. Wong 		}
9270a1b0b38SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
92850f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
9290a1b0b38SDarrick J. Wong 			gtrec.rm_blockcount, gtrec.rm_owner,
9300a1b0b38SDarrick J. Wong 			gtrec.rm_offset, gtrec.rm_flags);
9310a1b0b38SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
9320a1b0b38SDarrick J. Wong 			have_gt = 0;
9330a1b0b38SDarrick J. Wong 	}
9340a1b0b38SDarrick J. Wong 
9350a1b0b38SDarrick J. Wong 	/*
9360a1b0b38SDarrick J. Wong 	 * Note: cursor currently points one record to the right of ltrec, even
9370a1b0b38SDarrick J. Wong 	 * if there is no record in the tree to the right.
9380a1b0b38SDarrick J. Wong 	 */
9390a1b0b38SDarrick J. Wong 	if (have_lt &&
9400a1b0b38SDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
9410a1b0b38SDarrick J. Wong 	    (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
9420a1b0b38SDarrick J. Wong 		/*
9430a1b0b38SDarrick J. Wong 		 * left edge contiguous, merge into left record.
9440a1b0b38SDarrick J. Wong 		 *
9450a1b0b38SDarrick J. Wong 		 *       ltbno     ltlen
9460a1b0b38SDarrick J. Wong 		 * orig:   |ooooooooo|
9470a1b0b38SDarrick J. Wong 		 * adding:           |aaaaaaaaa|
9480a1b0b38SDarrick J. Wong 		 * result: |rrrrrrrrrrrrrrrrrrr|
9490a1b0b38SDarrick J. Wong 		 *                  bno       len
9500a1b0b38SDarrick J. Wong 		 */
9510a1b0b38SDarrick J. Wong 		ltrec.rm_blockcount += len;
9520a1b0b38SDarrick J. Wong 		if (have_gt &&
9530a1b0b38SDarrick J. Wong 		    bno + len == gtrec.rm_startblock &&
9540a1b0b38SDarrick J. Wong 		    (ignore_off || offset + len == gtrec.rm_offset) &&
9550a1b0b38SDarrick J. Wong 		    (unsigned long)ltrec.rm_blockcount + len +
9560a1b0b38SDarrick J. Wong 				gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
9570a1b0b38SDarrick J. Wong 			/*
9580a1b0b38SDarrick J. Wong 			 * right edge also contiguous, delete right record
9590a1b0b38SDarrick J. Wong 			 * and merge into left record.
9600a1b0b38SDarrick J. Wong 			 *
9610a1b0b38SDarrick J. Wong 			 *       ltbno     ltlen    gtbno     gtlen
9620a1b0b38SDarrick J. Wong 			 * orig:   |ooooooooo|         |ooooooooo|
9630a1b0b38SDarrick J. Wong 			 * adding:           |aaaaaaaaa|
9640a1b0b38SDarrick J. Wong 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
9650a1b0b38SDarrick J. Wong 			 */
9660a1b0b38SDarrick J. Wong 			ltrec.rm_blockcount += gtrec.rm_blockcount;
96750f02fe3SDave Chinner 			trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
9680a1b0b38SDarrick J. Wong 					gtrec.rm_startblock,
9690a1b0b38SDarrick J. Wong 					gtrec.rm_blockcount,
9700a1b0b38SDarrick J. Wong 					gtrec.rm_owner,
9710a1b0b38SDarrick J. Wong 					gtrec.rm_offset,
9720a1b0b38SDarrick J. Wong 					gtrec.rm_flags);
9730a1b0b38SDarrick J. Wong 			error = xfs_btree_delete(cur, &i);
9740a1b0b38SDarrick J. Wong 			if (error)
9750a1b0b38SDarrick J. Wong 				goto out_error;
976f9e03706SDarrick J. Wong 			if (XFS_IS_CORRUPT(mp, i != 1)) {
977f9e03706SDarrick J. Wong 				error = -EFSCORRUPTED;
978f9e03706SDarrick J. Wong 				goto out_error;
979f9e03706SDarrick J. Wong 			}
9800a1b0b38SDarrick J. Wong 		}
9810a1b0b38SDarrick J. Wong 
9820a1b0b38SDarrick J. Wong 		/* point the cursor back to the left record and update */
9830a1b0b38SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &have_gt);
9840a1b0b38SDarrick J. Wong 		if (error)
9850a1b0b38SDarrick J. Wong 			goto out_error;
9860a1b0b38SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
9870a1b0b38SDarrick J. Wong 		if (error)
9880a1b0b38SDarrick J. Wong 			goto out_error;
9890a1b0b38SDarrick J. Wong 	} else if (have_gt &&
9900a1b0b38SDarrick J. Wong 		   bno + len == gtrec.rm_startblock &&
9910a1b0b38SDarrick J. Wong 		   (ignore_off || offset + len == gtrec.rm_offset)) {
9920a1b0b38SDarrick J. Wong 		/*
9930a1b0b38SDarrick J. Wong 		 * right edge contiguous, merge into right record.
9940a1b0b38SDarrick J. Wong 		 *
9950a1b0b38SDarrick J. Wong 		 *                 gtbno     gtlen
9960a1b0b38SDarrick J. Wong 		 * Orig:             |ooooooooo|
9970a1b0b38SDarrick J. Wong 		 * adding: |aaaaaaaaa|
9980a1b0b38SDarrick J. Wong 		 * Result: |rrrrrrrrrrrrrrrrrrr|
9990a1b0b38SDarrick J. Wong 		 *        bno       len
10000a1b0b38SDarrick J. Wong 		 */
10010a1b0b38SDarrick J. Wong 		gtrec.rm_startblock = bno;
10020a1b0b38SDarrick J. Wong 		gtrec.rm_blockcount += len;
10030a1b0b38SDarrick J. Wong 		if (!ignore_off)
10040a1b0b38SDarrick J. Wong 			gtrec.rm_offset = offset;
10050a1b0b38SDarrick J. Wong 		error = xfs_rmap_update(cur, &gtrec);
10060a1b0b38SDarrick J. Wong 		if (error)
10070a1b0b38SDarrick J. Wong 			goto out_error;
10080a1b0b38SDarrick J. Wong 	} else {
10090a1b0b38SDarrick J. Wong 		/*
10100a1b0b38SDarrick J. Wong 		 * no contiguous edge with identical owner, insert
10110a1b0b38SDarrick J. Wong 		 * new record at current cursor position.
10120a1b0b38SDarrick J. Wong 		 */
10130a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_startblock = bno;
10140a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_blockcount = len;
10150a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_owner = owner;
10160a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_offset = offset;
10170a1b0b38SDarrick J. Wong 		cur->bc_rec.r.rm_flags = flags;
101850f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
10190a1b0b38SDarrick J. Wong 			owner, offset, flags);
10200a1b0b38SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
10210a1b0b38SDarrick J. Wong 		if (error)
10220a1b0b38SDarrick J. Wong 			goto out_error;
1023f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1024f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1025f9e03706SDarrick J. Wong 			goto out_error;
1026f9e03706SDarrick J. Wong 		}
10270a1b0b38SDarrick J. Wong 	}
10280a1b0b38SDarrick J. Wong 
102950f02fe3SDave Chinner 	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
10300a1b0b38SDarrick J. Wong 			unwritten, oinfo);
10310a1b0b38SDarrick J. Wong out_error:
10320a1b0b38SDarrick J. Wong 	if (error)
103350f02fe3SDave Chinner 		trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
10340a1b0b38SDarrick J. Wong 				error, _RET_IP_);
10350a1b0b38SDarrick J. Wong 	return error;
10360a1b0b38SDarrick J. Wong }
10370a1b0b38SDarrick J. Wong 
10380a1b0b38SDarrick J. Wong /*
10390a1b0b38SDarrick J. Wong  * Add a reference to an extent in the rmap btree.
10400a1b0b38SDarrick J. Wong  */
1041673930c3SDarrick J. Wong int
xfs_rmap_alloc(struct xfs_trans * tp,struct xfs_buf * agbp,struct xfs_perag * pag,xfs_agblock_t bno,xfs_extlen_t len,const struct xfs_owner_info * oinfo)1042673930c3SDarrick J. Wong xfs_rmap_alloc(
1043673930c3SDarrick J. Wong 	struct xfs_trans		*tp,
1044673930c3SDarrick J. Wong 	struct xfs_buf			*agbp,
1045fa9c3c19SDave Chinner 	struct xfs_perag		*pag,
1046673930c3SDarrick J. Wong 	xfs_agblock_t			bno,
1047673930c3SDarrick J. Wong 	xfs_extlen_t			len,
104866e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
1049673930c3SDarrick J. Wong {
1050673930c3SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
10510a1b0b38SDarrick J. Wong 	struct xfs_btree_cur		*cur;
10520a1b0b38SDarrick J. Wong 	int				error;
1053673930c3SDarrick J. Wong 
105438c26bfdSDave Chinner 	if (!xfs_has_rmapbt(mp))
1055673930c3SDarrick J. Wong 		return 0;
1056673930c3SDarrick J. Wong 
1057fa9c3c19SDave Chinner 	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
10580a1b0b38SDarrick J. Wong 	error = xfs_rmap_map(cur, bno, len, false, oinfo);
10590a1b0b38SDarrick J. Wong 
10600b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(cur, error);
1061673930c3SDarrick J. Wong 	return error;
1062673930c3SDarrick J. Wong }
1063c543838aSDarrick J. Wong 
1064fb7d9267SDarrick J. Wong #define RMAP_LEFT_CONTIG	(1 << 0)
1065fb7d9267SDarrick J. Wong #define RMAP_RIGHT_CONTIG	(1 << 1)
1066fb7d9267SDarrick J. Wong #define RMAP_LEFT_FILLING	(1 << 2)
1067fb7d9267SDarrick J. Wong #define RMAP_RIGHT_FILLING	(1 << 3)
1068fb7d9267SDarrick J. Wong #define RMAP_LEFT_VALID		(1 << 6)
1069fb7d9267SDarrick J. Wong #define RMAP_RIGHT_VALID	(1 << 7)
1070fb7d9267SDarrick J. Wong 
1071fb7d9267SDarrick J. Wong #define LEFT		r[0]
1072fb7d9267SDarrick J. Wong #define RIGHT		r[1]
1073fb7d9267SDarrick J. Wong #define PREV		r[2]
1074fb7d9267SDarrick J. Wong #define NEW		r[3]
1075fb7d9267SDarrick J. Wong 
1076fb7d9267SDarrick J. Wong /*
1077fb7d9267SDarrick J. Wong  * Convert an unwritten extent to a real extent or vice versa.
1078fb7d9267SDarrick J. Wong  * Does not handle overlapping extents.
1079fb7d9267SDarrick J. Wong  */
1080fb7d9267SDarrick J. Wong STATIC int
xfs_rmap_convert(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,bool unwritten,const struct xfs_owner_info * oinfo)1081fb7d9267SDarrick J. Wong xfs_rmap_convert(
1082fb7d9267SDarrick J. Wong 	struct xfs_btree_cur		*cur,
1083fb7d9267SDarrick J. Wong 	xfs_agblock_t			bno,
1084fb7d9267SDarrick J. Wong 	xfs_extlen_t			len,
1085fb7d9267SDarrick J. Wong 	bool				unwritten,
108666e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
1087fb7d9267SDarrick J. Wong {
1088fb7d9267SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
1089fb7d9267SDarrick J. Wong 	struct xfs_rmap_irec		r[4];	/* neighbor extent entries */
109066e3237eSDarrick J. Wong 						/* left is 0, right is 1, */
109166e3237eSDarrick J. Wong 						/* prev is 2, new is 3 */
1092fb7d9267SDarrick J. Wong 	uint64_t		owner;
1093fb7d9267SDarrick J. Wong 	uint64_t		offset;
1094fb7d9267SDarrick J. Wong 	uint64_t		new_endoff;
1095fb7d9267SDarrick J. Wong 	unsigned int		oldext;
1096fb7d9267SDarrick J. Wong 	unsigned int		newext;
1097fb7d9267SDarrick J. Wong 	unsigned int		flags = 0;
1098fb7d9267SDarrick J. Wong 	int			i;
1099fb7d9267SDarrick J. Wong 	int			state = 0;
1100fb7d9267SDarrick J. Wong 	int			error;
1101fb7d9267SDarrick J. Wong 
1102fb7d9267SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1103fb7d9267SDarrick J. Wong 	ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1104fb7d9267SDarrick J. Wong 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1105fb7d9267SDarrick J. Wong 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1106fb7d9267SDarrick J. Wong 	new_endoff = offset + len;
110750f02fe3SDave Chinner 	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1108fb7d9267SDarrick J. Wong 			unwritten, oinfo);
1109fb7d9267SDarrick J. Wong 
1110fb7d9267SDarrick J. Wong 	/*
1111fb7d9267SDarrick J. Wong 	 * For the initial lookup, look for an exact match or the left-adjacent
1112fb7d9267SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
1113fb7d9267SDarrick J. Wong 	 * start block contiguity tests.
1114fb7d9267SDarrick J. Wong 	 */
11155b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, &PREV, &i);
1116fb7d9267SDarrick J. Wong 	if (error)
1117fb7d9267SDarrick J. Wong 		goto done;
1118f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1119f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1120f9e03706SDarrick J. Wong 		goto done;
1121f9e03706SDarrick J. Wong 	}
1122fb7d9267SDarrick J. Wong 
1123fb7d9267SDarrick J. Wong 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
112450f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
1125fb7d9267SDarrick J. Wong 			PREV.rm_blockcount, PREV.rm_owner,
1126fb7d9267SDarrick J. Wong 			PREV.rm_offset, PREV.rm_flags);
1127fb7d9267SDarrick J. Wong 
1128fb7d9267SDarrick J. Wong 	ASSERT(PREV.rm_offset <= offset);
1129fb7d9267SDarrick J. Wong 	ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1130fb7d9267SDarrick J. Wong 	ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1131fb7d9267SDarrick J. Wong 	newext = ~oldext & XFS_RMAP_UNWRITTEN;
1132fb7d9267SDarrick J. Wong 
1133fb7d9267SDarrick J. Wong 	/*
1134fb7d9267SDarrick J. Wong 	 * Set flags determining what part of the previous oldext allocation
1135fb7d9267SDarrick J. Wong 	 * extent is being replaced by a newext allocation.
1136fb7d9267SDarrick J. Wong 	 */
1137fb7d9267SDarrick J. Wong 	if (PREV.rm_offset == offset)
1138fb7d9267SDarrick J. Wong 		state |= RMAP_LEFT_FILLING;
1139fb7d9267SDarrick J. Wong 	if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1140fb7d9267SDarrick J. Wong 		state |= RMAP_RIGHT_FILLING;
1141fb7d9267SDarrick J. Wong 
1142fb7d9267SDarrick J. Wong 	/*
1143fb7d9267SDarrick J. Wong 	 * Decrement the cursor to see if we have a left-adjacent record to our
1144fb7d9267SDarrick J. Wong 	 * insertion point. This will give us the record for end block
1145fb7d9267SDarrick J. Wong 	 * contiguity tests.
1146fb7d9267SDarrick J. Wong 	 */
1147fb7d9267SDarrick J. Wong 	error = xfs_btree_decrement(cur, 0, &i);
1148fb7d9267SDarrick J. Wong 	if (error)
1149fb7d9267SDarrick J. Wong 		goto done;
1150fb7d9267SDarrick J. Wong 	if (i) {
1151fb7d9267SDarrick J. Wong 		state |= RMAP_LEFT_VALID;
1152fb7d9267SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &LEFT, &i);
1153fb7d9267SDarrick J. Wong 		if (error)
1154fb7d9267SDarrick J. Wong 			goto done;
1155f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1156f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1157f9e03706SDarrick J. Wong 			goto done;
1158f9e03706SDarrick J. Wong 		}
1159f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
1160f9e03706SDarrick J. Wong 				   LEFT.rm_startblock + LEFT.rm_blockcount >
1161f9e03706SDarrick J. Wong 				   bno)) {
1162f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1163f9e03706SDarrick J. Wong 			goto done;
1164f9e03706SDarrick J. Wong 		}
1165fb7d9267SDarrick J. Wong 		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
116650f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
1167fb7d9267SDarrick J. Wong 				LEFT.rm_blockcount, LEFT.rm_owner,
1168fb7d9267SDarrick J. Wong 				LEFT.rm_offset, LEFT.rm_flags);
1169fb7d9267SDarrick J. Wong 		if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
1170fb7d9267SDarrick J. Wong 		    LEFT.rm_offset + LEFT.rm_blockcount == offset &&
1171fb7d9267SDarrick J. Wong 		    xfs_rmap_is_mergeable(&LEFT, owner, newext))
1172fb7d9267SDarrick J. Wong 			state |= RMAP_LEFT_CONTIG;
1173fb7d9267SDarrick J. Wong 	}
1174fb7d9267SDarrick J. Wong 
1175fb7d9267SDarrick J. Wong 	/*
1176fb7d9267SDarrick J. Wong 	 * Increment the cursor to see if we have a right-adjacent record to our
1177fb7d9267SDarrick J. Wong 	 * insertion point. This will give us the record for end block
1178fb7d9267SDarrick J. Wong 	 * contiguity tests.
1179fb7d9267SDarrick J. Wong 	 */
1180fb7d9267SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &i);
1181fb7d9267SDarrick J. Wong 	if (error)
1182fb7d9267SDarrick J. Wong 		goto done;
1183f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1184f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1185f9e03706SDarrick J. Wong 		goto done;
1186f9e03706SDarrick J. Wong 	}
1187fb7d9267SDarrick J. Wong 	error = xfs_btree_increment(cur, 0, &i);
1188fb7d9267SDarrick J. Wong 	if (error)
1189fb7d9267SDarrick J. Wong 		goto done;
1190fb7d9267SDarrick J. Wong 	if (i) {
1191fb7d9267SDarrick J. Wong 		state |= RMAP_RIGHT_VALID;
1192fb7d9267SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1193fb7d9267SDarrick J. Wong 		if (error)
1194fb7d9267SDarrick J. Wong 			goto done;
1195f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1196f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1197f9e03706SDarrick J. Wong 			goto done;
1198f9e03706SDarrick J. Wong 		}
1199f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1200f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1201f9e03706SDarrick J. Wong 			goto done;
1202f9e03706SDarrick J. Wong 		}
1203fb7d9267SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
120450f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
1205fb7d9267SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
1206fb7d9267SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
1207fb7d9267SDarrick J. Wong 		if (bno + len == RIGHT.rm_startblock &&
1208fb7d9267SDarrick J. Wong 		    offset + len == RIGHT.rm_offset &&
1209fb7d9267SDarrick J. Wong 		    xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1210fb7d9267SDarrick J. Wong 			state |= RMAP_RIGHT_CONTIG;
1211fb7d9267SDarrick J. Wong 	}
1212fb7d9267SDarrick J. Wong 
1213fb7d9267SDarrick J. Wong 	/* check that left + prev + right is not too long */
1214fb7d9267SDarrick J. Wong 	if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1215fb7d9267SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1216fb7d9267SDarrick J. Wong 	    (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1217fb7d9267SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1218fb7d9267SDarrick J. Wong 	    (unsigned long)LEFT.rm_blockcount + len +
1219fb7d9267SDarrick J. Wong 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1220fb7d9267SDarrick J. Wong 		state &= ~RMAP_RIGHT_CONTIG;
1221fb7d9267SDarrick J. Wong 
122250f02fe3SDave Chinner 	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
1223fb7d9267SDarrick J. Wong 			_RET_IP_);
1224fb7d9267SDarrick J. Wong 
1225fb7d9267SDarrick J. Wong 	/* reset the cursor back to PREV */
12265b7ca8b3SDarrick J. Wong 	error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, NULL, &i);
1227fb7d9267SDarrick J. Wong 	if (error)
1228fb7d9267SDarrick J. Wong 		goto done;
1229f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1230f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1231f9e03706SDarrick J. Wong 		goto done;
1232f9e03706SDarrick J. Wong 	}
1233fb7d9267SDarrick J. Wong 
1234fb7d9267SDarrick J. Wong 	/*
1235fb7d9267SDarrick J. Wong 	 * Switch out based on the FILLING and CONTIG state bits.
1236fb7d9267SDarrick J. Wong 	 */
1237fb7d9267SDarrick J. Wong 	switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1238fb7d9267SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1239fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1240fb7d9267SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1241fb7d9267SDarrick J. Wong 		/*
1242fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1243fb7d9267SDarrick J. Wong 		 * The left and right neighbors are both contiguous with new.
1244fb7d9267SDarrick J. Wong 		 */
1245fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1246fb7d9267SDarrick J. Wong 		if (error)
1247fb7d9267SDarrick J. Wong 			goto done;
1248f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1249f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1250f9e03706SDarrick J. Wong 			goto done;
1251f9e03706SDarrick J. Wong 		}
125250f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1253fb7d9267SDarrick J. Wong 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
1254fb7d9267SDarrick J. Wong 				RIGHT.rm_owner, RIGHT.rm_offset,
1255fb7d9267SDarrick J. Wong 				RIGHT.rm_flags);
1256fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1257fb7d9267SDarrick J. Wong 		if (error)
1258fb7d9267SDarrick J. Wong 			goto done;
1259f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1260f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1261f9e03706SDarrick J. Wong 			goto done;
1262f9e03706SDarrick J. Wong 		}
1263fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1264fb7d9267SDarrick J. Wong 		if (error)
1265fb7d9267SDarrick J. Wong 			goto done;
1266f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1267f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1268f9e03706SDarrick J. Wong 			goto done;
1269f9e03706SDarrick J. Wong 		}
127050f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1271fb7d9267SDarrick J. Wong 				PREV.rm_startblock, PREV.rm_blockcount,
1272fb7d9267SDarrick J. Wong 				PREV.rm_owner, PREV.rm_offset,
1273fb7d9267SDarrick J. Wong 				PREV.rm_flags);
1274fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1275fb7d9267SDarrick J. Wong 		if (error)
1276fb7d9267SDarrick J. Wong 			goto done;
1277f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1278f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1279f9e03706SDarrick J. Wong 			goto done;
1280f9e03706SDarrick J. Wong 		}
1281fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1282fb7d9267SDarrick J. Wong 		if (error)
1283fb7d9267SDarrick J. Wong 			goto done;
1284f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1285f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1286f9e03706SDarrick J. Wong 			goto done;
1287f9e03706SDarrick J. Wong 		}
1288fb7d9267SDarrick J. Wong 		NEW = LEFT;
1289fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1290fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1291fb7d9267SDarrick J. Wong 		if (error)
1292fb7d9267SDarrick J. Wong 			goto done;
1293fb7d9267SDarrick J. Wong 		break;
1294fb7d9267SDarrick J. Wong 
1295fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1296fb7d9267SDarrick J. Wong 		/*
1297fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1298fb7d9267SDarrick J. Wong 		 * The left neighbor is contiguous, the right is not.
1299fb7d9267SDarrick J. Wong 		 */
130050f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1301fb7d9267SDarrick J. Wong 				PREV.rm_startblock, PREV.rm_blockcount,
1302fb7d9267SDarrick J. Wong 				PREV.rm_owner, PREV.rm_offset,
1303fb7d9267SDarrick J. Wong 				PREV.rm_flags);
1304fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1305fb7d9267SDarrick J. Wong 		if (error)
1306fb7d9267SDarrick J. Wong 			goto done;
1307f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1308f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1309f9e03706SDarrick J. Wong 			goto done;
1310f9e03706SDarrick J. Wong 		}
1311fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1312fb7d9267SDarrick J. Wong 		if (error)
1313fb7d9267SDarrick J. Wong 			goto done;
1314f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1315f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1316f9e03706SDarrick J. Wong 			goto done;
1317f9e03706SDarrick J. Wong 		}
1318fb7d9267SDarrick J. Wong 		NEW = LEFT;
1319fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount;
1320fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1321fb7d9267SDarrick J. Wong 		if (error)
1322fb7d9267SDarrick J. Wong 			goto done;
1323fb7d9267SDarrick J. Wong 		break;
1324fb7d9267SDarrick J. Wong 
1325fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1326fb7d9267SDarrick J. Wong 		/*
1327fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1328fb7d9267SDarrick J. Wong 		 * The right neighbor is contiguous, the left is not.
1329fb7d9267SDarrick J. Wong 		 */
1330fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1331fb7d9267SDarrick J. Wong 		if (error)
1332fb7d9267SDarrick J. Wong 			goto done;
1333f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1334f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1335f9e03706SDarrick J. Wong 			goto done;
1336f9e03706SDarrick J. Wong 		}
133750f02fe3SDave Chinner 		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
1338fb7d9267SDarrick J. Wong 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
1339fb7d9267SDarrick J. Wong 				RIGHT.rm_owner, RIGHT.rm_offset,
1340fb7d9267SDarrick J. Wong 				RIGHT.rm_flags);
1341fb7d9267SDarrick J. Wong 		error = xfs_btree_delete(cur, &i);
1342fb7d9267SDarrick J. Wong 		if (error)
1343fb7d9267SDarrick J. Wong 			goto done;
1344f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1345f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1346f9e03706SDarrick J. Wong 			goto done;
1347f9e03706SDarrick J. Wong 		}
1348fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1349fb7d9267SDarrick J. Wong 		if (error)
1350fb7d9267SDarrick J. Wong 			goto done;
1351f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1352f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1353f9e03706SDarrick J. Wong 			goto done;
1354f9e03706SDarrick J. Wong 		}
1355fb7d9267SDarrick J. Wong 		NEW = PREV;
1356fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len + RIGHT.rm_blockcount;
1357fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1358fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1359fb7d9267SDarrick J. Wong 		if (error)
1360fb7d9267SDarrick J. Wong 			goto done;
1361fb7d9267SDarrick J. Wong 		break;
1362fb7d9267SDarrick J. Wong 
1363fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1364fb7d9267SDarrick J. Wong 		/*
1365fb7d9267SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
1366fb7d9267SDarrick J. Wong 		 * Neither the left nor right neighbors are contiguous with
1367fb7d9267SDarrick J. Wong 		 * the new one.
1368fb7d9267SDarrick J. Wong 		 */
1369fb7d9267SDarrick J. Wong 		NEW = PREV;
1370fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1371fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1372fb7d9267SDarrick J. Wong 		if (error)
1373fb7d9267SDarrick J. Wong 			goto done;
1374fb7d9267SDarrick J. Wong 		break;
1375fb7d9267SDarrick J. Wong 
1376fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1377fb7d9267SDarrick J. Wong 		/*
1378fb7d9267SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
1379fb7d9267SDarrick J. Wong 		 * The left neighbor is contiguous.
1380fb7d9267SDarrick J. Wong 		 */
1381fb7d9267SDarrick J. Wong 		NEW = PREV;
1382fb7d9267SDarrick J. Wong 		NEW.rm_offset += len;
1383fb7d9267SDarrick J. Wong 		NEW.rm_startblock += len;
1384fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1385fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1386fb7d9267SDarrick J. Wong 		if (error)
1387fb7d9267SDarrick J. Wong 			goto done;
1388fb7d9267SDarrick J. Wong 		error = xfs_btree_decrement(cur, 0, &i);
1389fb7d9267SDarrick J. Wong 		if (error)
1390fb7d9267SDarrick J. Wong 			goto done;
1391fb7d9267SDarrick J. Wong 		NEW = LEFT;
1392fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += len;
1393fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1394fb7d9267SDarrick J. Wong 		if (error)
1395fb7d9267SDarrick J. Wong 			goto done;
1396fb7d9267SDarrick J. Wong 		break;
1397fb7d9267SDarrick J. Wong 
1398fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING:
1399fb7d9267SDarrick J. Wong 		/*
1400fb7d9267SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
1401fb7d9267SDarrick J. Wong 		 * The left neighbor is not contiguous.
1402fb7d9267SDarrick J. Wong 		 */
1403fb7d9267SDarrick J. Wong 		NEW = PREV;
1404fb7d9267SDarrick J. Wong 		NEW.rm_startblock += len;
1405fb7d9267SDarrick J. Wong 		NEW.rm_offset += len;
1406fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1407fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1408fb7d9267SDarrick J. Wong 		if (error)
1409fb7d9267SDarrick J. Wong 			goto done;
1410fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1411fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1412fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1413fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len;
1414fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1415fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
141650f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
1417fb7d9267SDarrick J. Wong 				len, owner, offset, newext);
1418fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1419fb7d9267SDarrick J. Wong 		if (error)
1420fb7d9267SDarrick J. Wong 			goto done;
1421f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1422f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1423f9e03706SDarrick J. Wong 			goto done;
1424f9e03706SDarrick J. Wong 		}
1425fb7d9267SDarrick J. Wong 		break;
1426fb7d9267SDarrick J. Wong 
1427fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1428fb7d9267SDarrick J. Wong 		/*
1429fb7d9267SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
1430fb7d9267SDarrick J. Wong 		 * The right neighbor is contiguous with the new allocation.
1431fb7d9267SDarrick J. Wong 		 */
1432fb7d9267SDarrick J. Wong 		NEW = PREV;
1433fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1434fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1435fb7d9267SDarrick J. Wong 		if (error)
1436fb7d9267SDarrick J. Wong 			goto done;
1437fb7d9267SDarrick J. Wong 		error = xfs_btree_increment(cur, 0, &i);
1438fb7d9267SDarrick J. Wong 		if (error)
1439fb7d9267SDarrick J. Wong 			goto done;
1440fb7d9267SDarrick J. Wong 		NEW = RIGHT;
1441fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1442fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1443fb7d9267SDarrick J. Wong 		NEW.rm_blockcount += len;
1444fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1445fb7d9267SDarrick J. Wong 		if (error)
1446fb7d9267SDarrick J. Wong 			goto done;
1447fb7d9267SDarrick J. Wong 		break;
1448fb7d9267SDarrick J. Wong 
1449fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING:
1450fb7d9267SDarrick J. Wong 		/*
1451fb7d9267SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
1452fb7d9267SDarrick J. Wong 		 * The right neighbor is not contiguous.
1453fb7d9267SDarrick J. Wong 		 */
1454fb7d9267SDarrick J. Wong 		NEW = PREV;
1455fb7d9267SDarrick J. Wong 		NEW.rm_blockcount -= len;
1456fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1457fb7d9267SDarrick J. Wong 		if (error)
1458fb7d9267SDarrick J. Wong 			goto done;
1459fb7d9267SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1460fb7d9267SDarrick J. Wong 				oldext, &i);
1461fb7d9267SDarrick J. Wong 		if (error)
1462fb7d9267SDarrick J. Wong 			goto done;
1463f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 0)) {
1464f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1465f9e03706SDarrick J. Wong 			goto done;
1466f9e03706SDarrick J. Wong 		}
1467fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno;
1468fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1469fb7d9267SDarrick J. Wong 		NEW.rm_offset = offset;
1470fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = len;
1471fb7d9267SDarrick J. Wong 		NEW.rm_flags = newext;
1472fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
147350f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
1474fb7d9267SDarrick J. Wong 				len, owner, offset, newext);
1475fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1476fb7d9267SDarrick J. Wong 		if (error)
1477fb7d9267SDarrick J. Wong 			goto done;
1478f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1479f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1480f9e03706SDarrick J. Wong 			goto done;
1481f9e03706SDarrick J. Wong 		}
1482fb7d9267SDarrick J. Wong 		break;
1483fb7d9267SDarrick J. Wong 
1484fb7d9267SDarrick J. Wong 	case 0:
1485fb7d9267SDarrick J. Wong 		/*
1486fb7d9267SDarrick J. Wong 		 * Setting the middle part of a previous oldext extent to
1487fb7d9267SDarrick J. Wong 		 * newext.  Contiguity is impossible here.
1488fb7d9267SDarrick J. Wong 		 * One extent becomes three extents.
1489fb7d9267SDarrick J. Wong 		 */
1490fb7d9267SDarrick J. Wong 		/* new right extent - oldext */
1491fb7d9267SDarrick J. Wong 		NEW.rm_startblock = bno + len;
1492fb7d9267SDarrick J. Wong 		NEW.rm_owner = owner;
1493fb7d9267SDarrick J. Wong 		NEW.rm_offset = new_endoff;
1494fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1495fb7d9267SDarrick J. Wong 				new_endoff;
1496fb7d9267SDarrick J. Wong 		NEW.rm_flags = PREV.rm_flags;
1497fb7d9267SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
1498fb7d9267SDarrick J. Wong 		if (error)
1499fb7d9267SDarrick J. Wong 			goto done;
1500fb7d9267SDarrick J. Wong 		/* new left extent - oldext */
1501fb7d9267SDarrick J. Wong 		NEW = PREV;
1502fb7d9267SDarrick J. Wong 		NEW.rm_blockcount = offset - PREV.rm_offset;
1503fb7d9267SDarrick J. Wong 		cur->bc_rec.r = NEW;
150450f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
1505fb7d9267SDarrick J. Wong 				NEW.rm_startblock, NEW.rm_blockcount,
1506fb7d9267SDarrick J. Wong 				NEW.rm_owner, NEW.rm_offset,
1507fb7d9267SDarrick J. Wong 				NEW.rm_flags);
1508fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1509fb7d9267SDarrick J. Wong 		if (error)
1510fb7d9267SDarrick J. Wong 			goto done;
1511f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1512f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1513f9e03706SDarrick J. Wong 			goto done;
1514f9e03706SDarrick J. Wong 		}
1515fb7d9267SDarrick J. Wong 		/*
1516fb7d9267SDarrick J. Wong 		 * Reset the cursor to the position of the new extent
1517fb7d9267SDarrick J. Wong 		 * we are about to insert as we can't trust it after
1518fb7d9267SDarrick J. Wong 		 * the previous insert.
1519fb7d9267SDarrick J. Wong 		 */
1520fb7d9267SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1521fb7d9267SDarrick J. Wong 				oldext, &i);
1522fb7d9267SDarrick J. Wong 		if (error)
1523fb7d9267SDarrick J. Wong 			goto done;
1524f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 0)) {
1525f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1526f9e03706SDarrick J. Wong 			goto done;
1527f9e03706SDarrick J. Wong 		}
1528fb7d9267SDarrick J. Wong 		/* new middle extent - newext */
1529fb7d9267SDarrick J. Wong 		cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
1530fb7d9267SDarrick J. Wong 		cur->bc_rec.r.rm_flags |= newext;
153150f02fe3SDave Chinner 		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
1532fb7d9267SDarrick J. Wong 				owner, offset, newext);
1533fb7d9267SDarrick J. Wong 		error = xfs_btree_insert(cur, &i);
1534fb7d9267SDarrick J. Wong 		if (error)
1535fb7d9267SDarrick J. Wong 			goto done;
1536f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1537f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1538f9e03706SDarrick J. Wong 			goto done;
1539f9e03706SDarrick J. Wong 		}
1540fb7d9267SDarrick J. Wong 		break;
1541fb7d9267SDarrick J. Wong 
1542fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1543fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1544fb7d9267SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1545fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1546fb7d9267SDarrick J. Wong 	case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1547fb7d9267SDarrick J. Wong 	case RMAP_LEFT_CONTIG:
1548fb7d9267SDarrick J. Wong 	case RMAP_RIGHT_CONTIG:
1549fb7d9267SDarrick J. Wong 		/*
1550fb7d9267SDarrick J. Wong 		 * These cases are all impossible.
1551fb7d9267SDarrick J. Wong 		 */
1552fb7d9267SDarrick J. Wong 		ASSERT(0);
1553fb7d9267SDarrick J. Wong 	}
1554fb7d9267SDarrick J. Wong 
155550f02fe3SDave Chinner 	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
1556fb7d9267SDarrick J. Wong 			unwritten, oinfo);
1557fb7d9267SDarrick J. Wong done:
1558fb7d9267SDarrick J. Wong 	if (error)
1559fb7d9267SDarrick J. Wong 		trace_xfs_rmap_convert_error(cur->bc_mp,
156050f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
1561fb7d9267SDarrick J. Wong 	return error;
1562fb7d9267SDarrick J. Wong }
1563fb7d9267SDarrick J. Wong 
15643f165b33SDarrick J. Wong /*
15653f165b33SDarrick J. Wong  * Convert an unwritten extent to a real extent or vice versa.  If there is no
15663f165b33SDarrick J. Wong  * possibility of overlapping extents, delegate to the simpler convert
15673f165b33SDarrick J. Wong  * function.
15683f165b33SDarrick J. Wong  */
15693f165b33SDarrick J. Wong STATIC int
xfs_rmap_convert_shared(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,bool unwritten,const struct xfs_owner_info * oinfo)15703f165b33SDarrick J. Wong xfs_rmap_convert_shared(
15713f165b33SDarrick J. Wong 	struct xfs_btree_cur		*cur,
15723f165b33SDarrick J. Wong 	xfs_agblock_t			bno,
15733f165b33SDarrick J. Wong 	xfs_extlen_t			len,
15743f165b33SDarrick J. Wong 	bool				unwritten,
157566e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
15763f165b33SDarrick J. Wong {
15773f165b33SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
15783f165b33SDarrick J. Wong 	struct xfs_rmap_irec		r[4];	/* neighbor extent entries */
157966e3237eSDarrick J. Wong 						/* left is 0, right is 1, */
158066e3237eSDarrick J. Wong 						/* prev is 2, new is 3 */
15813f165b33SDarrick J. Wong 	uint64_t		owner;
15823f165b33SDarrick J. Wong 	uint64_t		offset;
15833f165b33SDarrick J. Wong 	uint64_t		new_endoff;
15843f165b33SDarrick J. Wong 	unsigned int		oldext;
15853f165b33SDarrick J. Wong 	unsigned int		newext;
15863f165b33SDarrick J. Wong 	unsigned int		flags = 0;
15873f165b33SDarrick J. Wong 	int			i;
15883f165b33SDarrick J. Wong 	int			state = 0;
15893f165b33SDarrick J. Wong 	int			error;
15903f165b33SDarrick J. Wong 
15913f165b33SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
15923f165b33SDarrick J. Wong 	ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
15933f165b33SDarrick J. Wong 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
15943f165b33SDarrick J. Wong 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
15953f165b33SDarrick J. Wong 	new_endoff = offset + len;
159650f02fe3SDave Chinner 	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
15973f165b33SDarrick J. Wong 			unwritten, oinfo);
15983f165b33SDarrick J. Wong 
15993f165b33SDarrick J. Wong 	/*
16003f165b33SDarrick J. Wong 	 * For the initial lookup, look for and exact match or the left-adjacent
16013f165b33SDarrick J. Wong 	 * record for our insertion point. This will also give us the record for
16023f165b33SDarrick J. Wong 	 * start block contiguity tests.
16033f165b33SDarrick J. Wong 	 */
1604ea843989SDarrick J. Wong 	error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, oldext,
16053f165b33SDarrick J. Wong 			&PREV, &i);
160652101dfeSDarrick J. Wong 	if (error)
160752101dfeSDarrick J. Wong 		goto done;
1608f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
1609f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
1610f9e03706SDarrick J. Wong 		goto done;
1611f9e03706SDarrick J. Wong 	}
16123f165b33SDarrick J. Wong 
16133f165b33SDarrick J. Wong 	ASSERT(PREV.rm_offset <= offset);
16143f165b33SDarrick J. Wong 	ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
16153f165b33SDarrick J. Wong 	ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
16163f165b33SDarrick J. Wong 	newext = ~oldext & XFS_RMAP_UNWRITTEN;
16173f165b33SDarrick J. Wong 
16183f165b33SDarrick J. Wong 	/*
16193f165b33SDarrick J. Wong 	 * Set flags determining what part of the previous oldext allocation
16203f165b33SDarrick J. Wong 	 * extent is being replaced by a newext allocation.
16213f165b33SDarrick J. Wong 	 */
16223f165b33SDarrick J. Wong 	if (PREV.rm_offset == offset)
16233f165b33SDarrick J. Wong 		state |= RMAP_LEFT_FILLING;
16243f165b33SDarrick J. Wong 	if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
16253f165b33SDarrick J. Wong 		state |= RMAP_RIGHT_FILLING;
16263f165b33SDarrick J. Wong 
16273f165b33SDarrick J. Wong 	/* Is there a left record that abuts our range? */
16283f165b33SDarrick J. Wong 	error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext,
16293f165b33SDarrick J. Wong 			&LEFT, &i);
16303f165b33SDarrick J. Wong 	if (error)
16313f165b33SDarrick J. Wong 		goto done;
16323f165b33SDarrick J. Wong 	if (i) {
16333f165b33SDarrick J. Wong 		state |= RMAP_LEFT_VALID;
1634f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp,
1635f9e03706SDarrick J. Wong 				   LEFT.rm_startblock + LEFT.rm_blockcount >
1636f9e03706SDarrick J. Wong 				   bno)) {
1637f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1638f9e03706SDarrick J. Wong 			goto done;
1639f9e03706SDarrick J. Wong 		}
16403f165b33SDarrick J. Wong 		if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
16413f165b33SDarrick J. Wong 			state |= RMAP_LEFT_CONTIG;
16423f165b33SDarrick J. Wong 	}
16433f165b33SDarrick J. Wong 
16443f165b33SDarrick J. Wong 	/* Is there a right record that abuts our range? */
16453f165b33SDarrick J. Wong 	error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
16463f165b33SDarrick J. Wong 			newext, &i);
16473f165b33SDarrick J. Wong 	if (error)
16483f165b33SDarrick J. Wong 		goto done;
16493f165b33SDarrick J. Wong 	if (i) {
16503f165b33SDarrick J. Wong 		state |= RMAP_RIGHT_VALID;
16513f165b33SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &RIGHT, &i);
16523f165b33SDarrick J. Wong 		if (error)
16533f165b33SDarrick J. Wong 			goto done;
1654f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1655f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1656f9e03706SDarrick J. Wong 			goto done;
1657f9e03706SDarrick J. Wong 		}
1658f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1659f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1660f9e03706SDarrick J. Wong 			goto done;
1661f9e03706SDarrick J. Wong 		}
16623f165b33SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
166350f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
16643f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
16653f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
16663f165b33SDarrick J. Wong 		if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
16673f165b33SDarrick J. Wong 			state |= RMAP_RIGHT_CONTIG;
16683f165b33SDarrick J. Wong 	}
16693f165b33SDarrick J. Wong 
16703f165b33SDarrick J. Wong 	/* check that left + prev + right is not too long */
16713f165b33SDarrick J. Wong 	if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16723f165b33SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
16733f165b33SDarrick J. Wong 	    (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16743f165b33SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
16753f165b33SDarrick J. Wong 	    (unsigned long)LEFT.rm_blockcount + len +
16763f165b33SDarrick J. Wong 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
16773f165b33SDarrick J. Wong 		state &= ~RMAP_RIGHT_CONTIG;
16783f165b33SDarrick J. Wong 
167950f02fe3SDave Chinner 	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
16803f165b33SDarrick J. Wong 			_RET_IP_);
16813f165b33SDarrick J. Wong 	/*
16823f165b33SDarrick J. Wong 	 * Switch out based on the FILLING and CONTIG state bits.
16833f165b33SDarrick J. Wong 	 */
16843f165b33SDarrick J. Wong 	switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16853f165b33SDarrick J. Wong 			 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
16863f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
16873f165b33SDarrick J. Wong 	     RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
16883f165b33SDarrick J. Wong 		/*
16893f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
16903f165b33SDarrick J. Wong 		 * The left and right neighbors are both contiguous with new.
16913f165b33SDarrick J. Wong 		 */
16923f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
16933f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
16943f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
16953f165b33SDarrick J. Wong 		if (error)
16963f165b33SDarrick J. Wong 			goto done;
16973f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, PREV.rm_startblock,
16983f165b33SDarrick J. Wong 				PREV.rm_blockcount, PREV.rm_owner,
16993f165b33SDarrick J. Wong 				PREV.rm_offset, PREV.rm_flags);
17003f165b33SDarrick J. Wong 		if (error)
17013f165b33SDarrick J. Wong 			goto done;
17023f165b33SDarrick J. Wong 		NEW = LEFT;
17033f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17043f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17053f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17063f165b33SDarrick J. Wong 		if (error)
17073f165b33SDarrick J. Wong 			goto done;
1708f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1709f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1710f9e03706SDarrick J. Wong 			goto done;
1711f9e03706SDarrick J. Wong 		}
17123f165b33SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
17133f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17143f165b33SDarrick J. Wong 		if (error)
17153f165b33SDarrick J. Wong 			goto done;
17163f165b33SDarrick J. Wong 		break;
17173f165b33SDarrick J. Wong 
17183f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
17193f165b33SDarrick J. Wong 		/*
17203f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
17213f165b33SDarrick J. Wong 		 * The left neighbor is contiguous, the right is not.
17223f165b33SDarrick J. Wong 		 */
17233f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, PREV.rm_startblock,
17243f165b33SDarrick J. Wong 				PREV.rm_blockcount, PREV.rm_owner,
17253f165b33SDarrick J. Wong 				PREV.rm_offset, PREV.rm_flags);
17263f165b33SDarrick J. Wong 		if (error)
17273f165b33SDarrick J. Wong 			goto done;
17283f165b33SDarrick J. Wong 		NEW = LEFT;
17293f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17303f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17313f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17323f165b33SDarrick J. Wong 		if (error)
17333f165b33SDarrick J. Wong 			goto done;
1734f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1735f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1736f9e03706SDarrick J. Wong 			goto done;
1737f9e03706SDarrick J. Wong 		}
17383f165b33SDarrick J. Wong 		NEW.rm_blockcount += PREV.rm_blockcount;
17393f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17403f165b33SDarrick J. Wong 		if (error)
17413f165b33SDarrick J. Wong 			goto done;
17423f165b33SDarrick J. Wong 		break;
17433f165b33SDarrick J. Wong 
17443f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
17453f165b33SDarrick J. Wong 		/*
17463f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
17473f165b33SDarrick J. Wong 		 * The right neighbor is contiguous, the left is not.
17483f165b33SDarrick J. Wong 		 */
17493f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
17503f165b33SDarrick J. Wong 				RIGHT.rm_blockcount, RIGHT.rm_owner,
17513f165b33SDarrick J. Wong 				RIGHT.rm_offset, RIGHT.rm_flags);
17523f165b33SDarrick J. Wong 		if (error)
17533f165b33SDarrick J. Wong 			goto done;
17543f165b33SDarrick J. Wong 		NEW = PREV;
17553f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17563f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17573f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17583f165b33SDarrick J. Wong 		if (error)
17593f165b33SDarrick J. Wong 			goto done;
1760f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1761f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1762f9e03706SDarrick J. Wong 			goto done;
1763f9e03706SDarrick J. Wong 		}
17643f165b33SDarrick J. Wong 		NEW.rm_blockcount += RIGHT.rm_blockcount;
17653f165b33SDarrick J. Wong 		NEW.rm_flags = RIGHT.rm_flags;
17663f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17673f165b33SDarrick J. Wong 		if (error)
17683f165b33SDarrick J. Wong 			goto done;
17693f165b33SDarrick J. Wong 		break;
17703f165b33SDarrick J. Wong 
17713f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
17723f165b33SDarrick J. Wong 		/*
17733f165b33SDarrick J. Wong 		 * Setting all of a previous oldext extent to newext.
17743f165b33SDarrick J. Wong 		 * Neither the left nor right neighbors are contiguous with
17753f165b33SDarrick J. Wong 		 * the new one.
17763f165b33SDarrick J. Wong 		 */
17773f165b33SDarrick J. Wong 		NEW = PREV;
17783f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
17793f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
17803f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
17813f165b33SDarrick J. Wong 		if (error)
17823f165b33SDarrick J. Wong 			goto done;
1783f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1784f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1785f9e03706SDarrick J. Wong 			goto done;
1786f9e03706SDarrick J. Wong 		}
17873f165b33SDarrick J. Wong 		NEW.rm_flags = newext;
17883f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
17893f165b33SDarrick J. Wong 		if (error)
17903f165b33SDarrick J. Wong 			goto done;
17913f165b33SDarrick J. Wong 		break;
17923f165b33SDarrick J. Wong 
17933f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
17943f165b33SDarrick J. Wong 		/*
17953f165b33SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
17963f165b33SDarrick J. Wong 		 * The left neighbor is contiguous.
17973f165b33SDarrick J. Wong 		 */
17983f165b33SDarrick J. Wong 		NEW = PREV;
17993f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
18003f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18013f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18023f165b33SDarrick J. Wong 		if (error)
18033f165b33SDarrick J. Wong 			goto done;
18043f165b33SDarrick J. Wong 		NEW.rm_offset += len;
18053f165b33SDarrick J. Wong 		NEW.rm_startblock += len;
18063f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
18073f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18083f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18093f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18103f165b33SDarrick J. Wong 		if (error)
18113f165b33SDarrick J. Wong 			goto done;
18123f165b33SDarrick J. Wong 		NEW = LEFT;
18133f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18143f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18153f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18163f165b33SDarrick J. Wong 		if (error)
18173f165b33SDarrick J. Wong 			goto done;
1818f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1819f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1820f9e03706SDarrick J. Wong 			goto done;
1821f9e03706SDarrick J. Wong 		}
18223f165b33SDarrick J. Wong 		NEW.rm_blockcount += len;
18233f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18243f165b33SDarrick J. Wong 		if (error)
18253f165b33SDarrick J. Wong 			goto done;
18263f165b33SDarrick J. Wong 		break;
18273f165b33SDarrick J. Wong 
18283f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING:
18293f165b33SDarrick J. Wong 		/*
18303f165b33SDarrick J. Wong 		 * Setting the first part of a previous oldext extent to newext.
18313f165b33SDarrick J. Wong 		 * The left neighbor is not contiguous.
18323f165b33SDarrick J. Wong 		 */
18333f165b33SDarrick J. Wong 		NEW = PREV;
18343f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
18353f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18363f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18373f165b33SDarrick J. Wong 		if (error)
18383f165b33SDarrick J. Wong 			goto done;
18393f165b33SDarrick J. Wong 		NEW.rm_offset += len;
18403f165b33SDarrick J. Wong 		NEW.rm_startblock += len;
18413f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
18423f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18433f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18443f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18453f165b33SDarrick J. Wong 		if (error)
18463f165b33SDarrick J. Wong 			goto done;
18473f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
18483f165b33SDarrick J. Wong 		if (error)
18493f165b33SDarrick J. Wong 			goto done;
18503f165b33SDarrick J. Wong 		break;
18513f165b33SDarrick J. Wong 
18523f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
18533f165b33SDarrick J. Wong 		/*
18543f165b33SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
18553f165b33SDarrick J. Wong 		 * The right neighbor is contiguous with the new allocation.
18563f165b33SDarrick J. Wong 		 */
18573f165b33SDarrick J. Wong 		NEW = PREV;
18583f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18593f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18603f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18613f165b33SDarrick J. Wong 		if (error)
18623f165b33SDarrick J. Wong 			goto done;
1863f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1864f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1865f9e03706SDarrick J. Wong 			goto done;
1866f9e03706SDarrick J. Wong 		}
18673f165b33SDarrick J. Wong 		NEW.rm_blockcount = offset - NEW.rm_offset;
18683f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
18693f165b33SDarrick J. Wong 		if (error)
18703f165b33SDarrick J. Wong 			goto done;
18713f165b33SDarrick J. Wong 		NEW = RIGHT;
18723f165b33SDarrick J. Wong 		error = xfs_rmap_delete(cur, NEW.rm_startblock,
18733f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18743f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18753f165b33SDarrick J. Wong 		if (error)
18763f165b33SDarrick J. Wong 			goto done;
18773f165b33SDarrick J. Wong 		NEW.rm_offset = offset;
18783f165b33SDarrick J. Wong 		NEW.rm_startblock = bno;
18793f165b33SDarrick J. Wong 		NEW.rm_blockcount += len;
18803f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
18813f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18823f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags);
18833f165b33SDarrick J. Wong 		if (error)
18843f165b33SDarrick J. Wong 			goto done;
18853f165b33SDarrick J. Wong 		break;
18863f165b33SDarrick J. Wong 
18873f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING:
18883f165b33SDarrick J. Wong 		/*
18893f165b33SDarrick J. Wong 		 * Setting the last part of a previous oldext extent to newext.
18903f165b33SDarrick J. Wong 		 * The right neighbor is not contiguous.
18913f165b33SDarrick J. Wong 		 */
18923f165b33SDarrick J. Wong 		NEW = PREV;
18933f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
18943f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
18953f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
18963f165b33SDarrick J. Wong 		if (error)
18973f165b33SDarrick J. Wong 			goto done;
1898f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1899f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1900f9e03706SDarrick J. Wong 			goto done;
1901f9e03706SDarrick J. Wong 		}
19023f165b33SDarrick J. Wong 		NEW.rm_blockcount -= len;
19033f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
19043f165b33SDarrick J. Wong 		if (error)
19053f165b33SDarrick J. Wong 			goto done;
19063f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
19073f165b33SDarrick J. Wong 		if (error)
19083f165b33SDarrick J. Wong 			goto done;
19093f165b33SDarrick J. Wong 		break;
19103f165b33SDarrick J. Wong 
19113f165b33SDarrick J. Wong 	case 0:
19123f165b33SDarrick J. Wong 		/*
19133f165b33SDarrick J. Wong 		 * Setting the middle part of a previous oldext extent to
19143f165b33SDarrick J. Wong 		 * newext.  Contiguity is impossible here.
19153f165b33SDarrick J. Wong 		 * One extent becomes three extents.
19163f165b33SDarrick J. Wong 		 */
19173f165b33SDarrick J. Wong 		/* new right extent - oldext */
19183f165b33SDarrick J. Wong 		NEW.rm_startblock = bno + len;
19193f165b33SDarrick J. Wong 		NEW.rm_owner = owner;
19203f165b33SDarrick J. Wong 		NEW.rm_offset = new_endoff;
19213f165b33SDarrick J. Wong 		NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
19223f165b33SDarrick J. Wong 				new_endoff;
19233f165b33SDarrick J. Wong 		NEW.rm_flags = PREV.rm_flags;
19243f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
19253f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
19263f165b33SDarrick J. Wong 				NEW.rm_flags);
19273f165b33SDarrick J. Wong 		if (error)
19283f165b33SDarrick J. Wong 			goto done;
19293f165b33SDarrick J. Wong 		/* new left extent - oldext */
19303f165b33SDarrick J. Wong 		NEW = PREV;
19313f165b33SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
19323f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner,
19333f165b33SDarrick J. Wong 				NEW.rm_offset, NEW.rm_flags, &i);
19343f165b33SDarrick J. Wong 		if (error)
19353f165b33SDarrick J. Wong 			goto done;
1936f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
1937f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
1938f9e03706SDarrick J. Wong 			goto done;
1939f9e03706SDarrick J. Wong 		}
19403f165b33SDarrick J. Wong 		NEW.rm_blockcount = offset - NEW.rm_offset;
19413f165b33SDarrick J. Wong 		error = xfs_rmap_update(cur, &NEW);
19423f165b33SDarrick J. Wong 		if (error)
19433f165b33SDarrick J. Wong 			goto done;
19443f165b33SDarrick J. Wong 		/* new middle extent - newext */
19453f165b33SDarrick J. Wong 		NEW.rm_startblock = bno;
19463f165b33SDarrick J. Wong 		NEW.rm_blockcount = len;
19473f165b33SDarrick J. Wong 		NEW.rm_owner = owner;
19483f165b33SDarrick J. Wong 		NEW.rm_offset = offset;
19493f165b33SDarrick J. Wong 		NEW.rm_flags = newext;
19503f165b33SDarrick J. Wong 		error = xfs_rmap_insert(cur, NEW.rm_startblock,
19513f165b33SDarrick J. Wong 				NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
19523f165b33SDarrick J. Wong 				NEW.rm_flags);
19533f165b33SDarrick J. Wong 		if (error)
19543f165b33SDarrick J. Wong 			goto done;
19553f165b33SDarrick J. Wong 		break;
19563f165b33SDarrick J. Wong 
19573f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
19583f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
19593f165b33SDarrick J. Wong 	case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
19603f165b33SDarrick J. Wong 	case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
19613f165b33SDarrick J. Wong 	case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
19623f165b33SDarrick J. Wong 	case RMAP_LEFT_CONTIG:
19633f165b33SDarrick J. Wong 	case RMAP_RIGHT_CONTIG:
19643f165b33SDarrick J. Wong 		/*
19653f165b33SDarrick J. Wong 		 * These cases are all impossible.
19663f165b33SDarrick J. Wong 		 */
19673f165b33SDarrick J. Wong 		ASSERT(0);
19683f165b33SDarrick J. Wong 	}
19693f165b33SDarrick J. Wong 
197050f02fe3SDave Chinner 	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
19713f165b33SDarrick J. Wong 			unwritten, oinfo);
19723f165b33SDarrick J. Wong done:
19733f165b33SDarrick J. Wong 	if (error)
19743f165b33SDarrick J. Wong 		trace_xfs_rmap_convert_error(cur->bc_mp,
197550f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
19763f165b33SDarrick J. Wong 	return error;
19773f165b33SDarrick J. Wong }
19783f165b33SDarrick J. Wong 
1979fb7d9267SDarrick J. Wong #undef	NEW
1980fb7d9267SDarrick J. Wong #undef	LEFT
1981fb7d9267SDarrick J. Wong #undef	RIGHT
1982fb7d9267SDarrick J. Wong #undef	PREV
1983fb7d9267SDarrick J. Wong 
1984ceeb9c83SDarrick J. Wong /*
1985ceeb9c83SDarrick J. Wong  * Find an extent in the rmap btree and unmap it.  For rmap extent types that
1986ceeb9c83SDarrick J. Wong  * can overlap (data fork rmaps on reflink filesystems) we must be careful
1987ceeb9c83SDarrick J. Wong  * that the prev/next records in the btree might belong to another owner.
1988ceeb9c83SDarrick J. Wong  * Therefore we must use delete+insert to alter any of the key fields.
1989ceeb9c83SDarrick J. Wong  *
1990ceeb9c83SDarrick J. Wong  * For every other situation there can only be one owner for a given extent,
1991ceeb9c83SDarrick J. Wong  * so we can call the regular _free function.
1992ceeb9c83SDarrick J. Wong  */
1993ceeb9c83SDarrick J. Wong STATIC int
xfs_rmap_unmap_shared(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,bool unwritten,const struct xfs_owner_info * oinfo)1994ceeb9c83SDarrick J. Wong xfs_rmap_unmap_shared(
1995ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
1996ceeb9c83SDarrick J. Wong 	xfs_agblock_t			bno,
1997ceeb9c83SDarrick J. Wong 	xfs_extlen_t			len,
1998ceeb9c83SDarrick J. Wong 	bool				unwritten,
199966e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
2000ceeb9c83SDarrick J. Wong {
2001ceeb9c83SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
2002ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
2003ceeb9c83SDarrick J. Wong 	uint64_t			ltoff;
2004ceeb9c83SDarrick J. Wong 	int				error = 0;
2005ceeb9c83SDarrick J. Wong 	int				i;
2006ceeb9c83SDarrick J. Wong 	uint64_t			owner;
2007ceeb9c83SDarrick J. Wong 	uint64_t			offset;
2008ceeb9c83SDarrick J. Wong 	unsigned int			flags;
2009ceeb9c83SDarrick J. Wong 
2010ceeb9c83SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2011ceeb9c83SDarrick J. Wong 	if (unwritten)
2012ceeb9c83SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
201350f02fe3SDave Chinner 	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
2014ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2015ceeb9c83SDarrick J. Wong 
2016ceeb9c83SDarrick J. Wong 	/*
2017ceeb9c83SDarrick J. Wong 	 * We should always have a left record because there's a static record
2018ceeb9c83SDarrick J. Wong 	 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
2019ceeb9c83SDarrick J. Wong 	 * will not ever be removed from the tree.
2020ceeb9c83SDarrick J. Wong 	 */
2021ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
2022ceeb9c83SDarrick J. Wong 			&ltrec, &i);
2023ceeb9c83SDarrick J. Wong 	if (error)
2024ceeb9c83SDarrick J. Wong 		goto out_error;
2025f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, i != 1)) {
2026f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2027f9e03706SDarrick J. Wong 		goto out_error;
2028f9e03706SDarrick J. Wong 	}
2029ceeb9c83SDarrick J. Wong 	ltoff = ltrec.rm_offset;
2030ceeb9c83SDarrick J. Wong 
2031ceeb9c83SDarrick J. Wong 	/* Make sure the extent we found covers the entire freeing range. */
2032f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
2033f9e03706SDarrick J. Wong 			   ltrec.rm_startblock > bno ||
2034f9e03706SDarrick J. Wong 			   ltrec.rm_startblock + ltrec.rm_blockcount <
2035f9e03706SDarrick J. Wong 			   bno + len)) {
2036f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2037f9e03706SDarrick J. Wong 		goto out_error;
2038f9e03706SDarrick J. Wong 	}
2039ceeb9c83SDarrick J. Wong 
2040ceeb9c83SDarrick J. Wong 	/* Make sure the owner matches what we expect to find in the tree. */
2041f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
2042f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2043f9e03706SDarrick J. Wong 		goto out_error;
2044f9e03706SDarrick J. Wong 	}
2045ceeb9c83SDarrick J. Wong 
2046ceeb9c83SDarrick J. Wong 	/* Make sure the unwritten flag matches. */
2047f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp,
2048f9e03706SDarrick J. Wong 			   (flags & XFS_RMAP_UNWRITTEN) !=
2049f9e03706SDarrick J. Wong 			   (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
2050f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2051f9e03706SDarrick J. Wong 		goto out_error;
2052f9e03706SDarrick J. Wong 	}
2053ceeb9c83SDarrick J. Wong 
2054ceeb9c83SDarrick J. Wong 	/* Check the offset. */
2055f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
2056f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2057f9e03706SDarrick J. Wong 		goto out_error;
2058f9e03706SDarrick J. Wong 	}
2059f9e03706SDarrick J. Wong 	if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
2060f9e03706SDarrick J. Wong 		error = -EFSCORRUPTED;
2061f9e03706SDarrick J. Wong 		goto out_error;
2062f9e03706SDarrick J. Wong 	}
2063ceeb9c83SDarrick J. Wong 
2064ceeb9c83SDarrick J. Wong 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
2065ceeb9c83SDarrick J. Wong 		/* Exact match, simply remove the record from rmap tree. */
2066ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2067ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2068ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2069ceeb9c83SDarrick J. Wong 		if (error)
2070ceeb9c83SDarrick J. Wong 			goto out_error;
2071ceeb9c83SDarrick J. Wong 	} else if (ltrec.rm_startblock == bno) {
2072ceeb9c83SDarrick J. Wong 		/*
2073ceeb9c83SDarrick J. Wong 		 * Overlap left hand side of extent: move the start, trim the
2074ceeb9c83SDarrick J. Wong 		 * length and update the current record.
2075ceeb9c83SDarrick J. Wong 		 *
2076ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2077ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2078ceeb9c83SDarrick J. Wong 		 * Freeing: |fffffffff|
2079ceeb9c83SDarrick J. Wong 		 * Result:            |rrrrrrrrrr|
2080ceeb9c83SDarrick J. Wong 		 *         bno       len
2081ceeb9c83SDarrick J. Wong 		 */
2082ceeb9c83SDarrick J. Wong 
2083ceeb9c83SDarrick J. Wong 		/* Delete prev rmap. */
2084ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2085ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2086ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2087ceeb9c83SDarrick J. Wong 		if (error)
2088ceeb9c83SDarrick J. Wong 			goto out_error;
2089ceeb9c83SDarrick J. Wong 
2090ceeb9c83SDarrick J. Wong 		/* Add an rmap at the new offset. */
2091ceeb9c83SDarrick J. Wong 		ltrec.rm_startblock += len;
2092ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount -= len;
2093ceeb9c83SDarrick J. Wong 		ltrec.rm_offset += len;
2094ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, ltrec.rm_startblock,
2095ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2096ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags);
2097ceeb9c83SDarrick J. Wong 		if (error)
2098ceeb9c83SDarrick J. Wong 			goto out_error;
2099ceeb9c83SDarrick J. Wong 	} else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
2100ceeb9c83SDarrick J. Wong 		/*
2101ceeb9c83SDarrick J. Wong 		 * Overlap right hand side of extent: trim the length and
2102ceeb9c83SDarrick J. Wong 		 * update the current record.
2103ceeb9c83SDarrick J. Wong 		 *
2104ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2105ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2106ceeb9c83SDarrick J. Wong 		 * Freeing:            |fffffffff|
2107ceeb9c83SDarrick J. Wong 		 * Result:  |rrrrrrrrrr|
2108ceeb9c83SDarrick J. Wong 		 *                    bno       len
2109ceeb9c83SDarrick J. Wong 		 */
2110ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2111ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2112ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2113ceeb9c83SDarrick J. Wong 		if (error)
2114ceeb9c83SDarrick J. Wong 			goto out_error;
2115f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2116f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2117f9e03706SDarrick J. Wong 			goto out_error;
2118f9e03706SDarrick J. Wong 		}
2119ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount -= len;
2120ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2121ceeb9c83SDarrick J. Wong 		if (error)
2122ceeb9c83SDarrick J. Wong 			goto out_error;
2123ceeb9c83SDarrick J. Wong 	} else {
2124ceeb9c83SDarrick J. Wong 		/*
2125ceeb9c83SDarrick J. Wong 		 * Overlap middle of extent: trim the length of the existing
2126ceeb9c83SDarrick J. Wong 		 * record to the length of the new left-extent size, increment
2127ceeb9c83SDarrick J. Wong 		 * the insertion position so we can insert a new record
2128ceeb9c83SDarrick J. Wong 		 * containing the remaining right-extent space.
2129ceeb9c83SDarrick J. Wong 		 *
2130ceeb9c83SDarrick J. Wong 		 *       ltbno                ltlen
2131ceeb9c83SDarrick J. Wong 		 * Orig:    |oooooooooooooooooooo|
2132ceeb9c83SDarrick J. Wong 		 * Freeing:       |fffffffff|
2133ceeb9c83SDarrick J. Wong 		 * Result:  |rrrrr|         |rrrr|
2134ceeb9c83SDarrick J. Wong 		 *               bno       len
2135ceeb9c83SDarrick J. Wong 		 */
2136ceeb9c83SDarrick J. Wong 		xfs_extlen_t	orig_len = ltrec.rm_blockcount;
2137ceeb9c83SDarrick J. Wong 
2138ceeb9c83SDarrick J. Wong 		/* Shrink the left side of the rmap */
2139ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2140ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2141ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2142ceeb9c83SDarrick J. Wong 		if (error)
2143ceeb9c83SDarrick J. Wong 			goto out_error;
2144f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2145f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2146f9e03706SDarrick J. Wong 			goto out_error;
2147f9e03706SDarrick J. Wong 		}
2148ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount = bno - ltrec.rm_startblock;
2149ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2150ceeb9c83SDarrick J. Wong 		if (error)
2151ceeb9c83SDarrick J. Wong 			goto out_error;
2152ceeb9c83SDarrick J. Wong 
2153ceeb9c83SDarrick J. Wong 		/* Add an rmap at the new offset */
2154ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno + len,
2155ceeb9c83SDarrick J. Wong 				orig_len - len - ltrec.rm_blockcount,
2156ceeb9c83SDarrick J. Wong 				ltrec.rm_owner, offset + len,
2157ceeb9c83SDarrick J. Wong 				ltrec.rm_flags);
2158ceeb9c83SDarrick J. Wong 		if (error)
2159ceeb9c83SDarrick J. Wong 			goto out_error;
2160ceeb9c83SDarrick J. Wong 	}
2161ceeb9c83SDarrick J. Wong 
216250f02fe3SDave Chinner 	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
2163ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2164ceeb9c83SDarrick J. Wong out_error:
2165ceeb9c83SDarrick J. Wong 	if (error)
2166ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_unmap_error(cur->bc_mp,
216750f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
2168ceeb9c83SDarrick J. Wong 	return error;
2169ceeb9c83SDarrick J. Wong }
2170ceeb9c83SDarrick J. Wong 
2171ceeb9c83SDarrick J. Wong /*
2172ceeb9c83SDarrick J. Wong  * Find an extent in the rmap btree and map it.  For rmap extent types that
2173ceeb9c83SDarrick J. Wong  * can overlap (data fork rmaps on reflink filesystems) we must be careful
2174ceeb9c83SDarrick J. Wong  * that the prev/next records in the btree might belong to another owner.
2175ceeb9c83SDarrick J. Wong  * Therefore we must use delete+insert to alter any of the key fields.
2176ceeb9c83SDarrick J. Wong  *
2177ceeb9c83SDarrick J. Wong  * For every other situation there can only be one owner for a given extent,
2178ceeb9c83SDarrick J. Wong  * so we can call the regular _alloc function.
2179ceeb9c83SDarrick J. Wong  */
2180ceeb9c83SDarrick J. Wong STATIC int
xfs_rmap_map_shared(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,bool unwritten,const struct xfs_owner_info * oinfo)2181ceeb9c83SDarrick J. Wong xfs_rmap_map_shared(
2182ceeb9c83SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2183ceeb9c83SDarrick J. Wong 	xfs_agblock_t			bno,
2184ceeb9c83SDarrick J. Wong 	xfs_extlen_t			len,
2185ceeb9c83SDarrick J. Wong 	bool				unwritten,
218666e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo)
2187ceeb9c83SDarrick J. Wong {
2188ceeb9c83SDarrick J. Wong 	struct xfs_mount		*mp = cur->bc_mp;
2189ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		ltrec;
2190ceeb9c83SDarrick J. Wong 	struct xfs_rmap_irec		gtrec;
2191ceeb9c83SDarrick J. Wong 	int				have_gt;
2192ceeb9c83SDarrick J. Wong 	int				have_lt;
2193ceeb9c83SDarrick J. Wong 	int				error = 0;
2194ceeb9c83SDarrick J. Wong 	int				i;
2195ceeb9c83SDarrick J. Wong 	uint64_t			owner;
2196ceeb9c83SDarrick J. Wong 	uint64_t			offset;
2197ceeb9c83SDarrick J. Wong 	unsigned int			flags = 0;
2198ceeb9c83SDarrick J. Wong 
2199ceeb9c83SDarrick J. Wong 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2200ceeb9c83SDarrick J. Wong 	if (unwritten)
2201ceeb9c83SDarrick J. Wong 		flags |= XFS_RMAP_UNWRITTEN;
220250f02fe3SDave Chinner 	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
2203ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2204ceeb9c83SDarrick J. Wong 
2205ceeb9c83SDarrick J. Wong 	/* Is there a left record that abuts our range? */
2206ceeb9c83SDarrick J. Wong 	error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
2207ceeb9c83SDarrick J. Wong 			&ltrec, &have_lt);
2208ceeb9c83SDarrick J. Wong 	if (error)
2209ceeb9c83SDarrick J. Wong 		goto out_error;
2210ceeb9c83SDarrick J. Wong 	if (have_lt &&
2211ceeb9c83SDarrick J. Wong 	    !xfs_rmap_is_mergeable(&ltrec, owner, flags))
2212ceeb9c83SDarrick J. Wong 		have_lt = 0;
2213ceeb9c83SDarrick J. Wong 
2214ceeb9c83SDarrick J. Wong 	/* Is there a right record that abuts our range? */
2215ceeb9c83SDarrick J. Wong 	error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
2216ceeb9c83SDarrick J. Wong 			flags, &have_gt);
2217ceeb9c83SDarrick J. Wong 	if (error)
2218ceeb9c83SDarrick J. Wong 		goto out_error;
2219ceeb9c83SDarrick J. Wong 	if (have_gt) {
2220ceeb9c83SDarrick J. Wong 		error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
2221ceeb9c83SDarrick J. Wong 		if (error)
2222ceeb9c83SDarrick J. Wong 			goto out_error;
2223f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
2224f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2225f9e03706SDarrick J. Wong 			goto out_error;
2226f9e03706SDarrick J. Wong 		}
2227ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
222850f02fe3SDave Chinner 			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
2229ceeb9c83SDarrick J. Wong 			gtrec.rm_blockcount, gtrec.rm_owner,
2230ceeb9c83SDarrick J. Wong 			gtrec.rm_offset, gtrec.rm_flags);
2231ceeb9c83SDarrick J. Wong 
2232ceeb9c83SDarrick J. Wong 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
2233ceeb9c83SDarrick J. Wong 			have_gt = 0;
2234ceeb9c83SDarrick J. Wong 	}
2235ceeb9c83SDarrick J. Wong 
2236ceeb9c83SDarrick J. Wong 	if (have_lt &&
2237ceeb9c83SDarrick J. Wong 	    ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
2238ceeb9c83SDarrick J. Wong 	    ltrec.rm_offset + ltrec.rm_blockcount == offset) {
2239ceeb9c83SDarrick J. Wong 		/*
2240ceeb9c83SDarrick J. Wong 		 * Left edge contiguous, merge into left record.
2241ceeb9c83SDarrick J. Wong 		 *
2242ceeb9c83SDarrick J. Wong 		 *       ltbno     ltlen
2243ceeb9c83SDarrick J. Wong 		 * orig:   |ooooooooo|
2244ceeb9c83SDarrick J. Wong 		 * adding:           |aaaaaaaaa|
2245ceeb9c83SDarrick J. Wong 		 * result: |rrrrrrrrrrrrrrrrrrr|
2246ceeb9c83SDarrick J. Wong 		 *                  bno       len
2247ceeb9c83SDarrick J. Wong 		 */
2248ceeb9c83SDarrick J. Wong 		ltrec.rm_blockcount += len;
2249ceeb9c83SDarrick J. Wong 		if (have_gt &&
2250ceeb9c83SDarrick J. Wong 		    bno + len == gtrec.rm_startblock &&
2251ceeb9c83SDarrick J. Wong 		    offset + len == gtrec.rm_offset) {
2252ceeb9c83SDarrick J. Wong 			/*
2253ceeb9c83SDarrick J. Wong 			 * Right edge also contiguous, delete right record
2254ceeb9c83SDarrick J. Wong 			 * and merge into left record.
2255ceeb9c83SDarrick J. Wong 			 *
2256ceeb9c83SDarrick J. Wong 			 *       ltbno     ltlen    gtbno     gtlen
2257ceeb9c83SDarrick J. Wong 			 * orig:   |ooooooooo|         |ooooooooo|
2258ceeb9c83SDarrick J. Wong 			 * adding:           |aaaaaaaaa|
2259ceeb9c83SDarrick J. Wong 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
2260ceeb9c83SDarrick J. Wong 			 */
2261ceeb9c83SDarrick J. Wong 			ltrec.rm_blockcount += gtrec.rm_blockcount;
2262ceeb9c83SDarrick J. Wong 			error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2263ceeb9c83SDarrick J. Wong 					gtrec.rm_blockcount, gtrec.rm_owner,
2264ceeb9c83SDarrick J. Wong 					gtrec.rm_offset, gtrec.rm_flags);
2265ceeb9c83SDarrick J. Wong 			if (error)
2266ceeb9c83SDarrick J. Wong 				goto out_error;
2267ceeb9c83SDarrick J. Wong 		}
2268ceeb9c83SDarrick J. Wong 
2269ceeb9c83SDarrick J. Wong 		/* Point the cursor back to the left record and update. */
2270ceeb9c83SDarrick J. Wong 		error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2271ceeb9c83SDarrick J. Wong 				ltrec.rm_blockcount, ltrec.rm_owner,
2272ceeb9c83SDarrick J. Wong 				ltrec.rm_offset, ltrec.rm_flags, &i);
2273ceeb9c83SDarrick J. Wong 		if (error)
2274ceeb9c83SDarrick J. Wong 			goto out_error;
2275f9e03706SDarrick J. Wong 		if (XFS_IS_CORRUPT(mp, i != 1)) {
2276f9e03706SDarrick J. Wong 			error = -EFSCORRUPTED;
2277f9e03706SDarrick J. Wong 			goto out_error;
2278f9e03706SDarrick J. Wong 		}
2279ceeb9c83SDarrick J. Wong 
2280ceeb9c83SDarrick J. Wong 		error = xfs_rmap_update(cur, &ltrec);
2281ceeb9c83SDarrick J. Wong 		if (error)
2282ceeb9c83SDarrick J. Wong 			goto out_error;
2283ceeb9c83SDarrick J. Wong 	} else if (have_gt &&
2284ceeb9c83SDarrick J. Wong 		   bno + len == gtrec.rm_startblock &&
2285ceeb9c83SDarrick J. Wong 		   offset + len == gtrec.rm_offset) {
2286ceeb9c83SDarrick J. Wong 		/*
2287ceeb9c83SDarrick J. Wong 		 * Right edge contiguous, merge into right record.
2288ceeb9c83SDarrick J. Wong 		 *
2289ceeb9c83SDarrick J. Wong 		 *                 gtbno     gtlen
2290ceeb9c83SDarrick J. Wong 		 * Orig:             |ooooooooo|
2291ceeb9c83SDarrick J. Wong 		 * adding: |aaaaaaaaa|
2292ceeb9c83SDarrick J. Wong 		 * Result: |rrrrrrrrrrrrrrrrrrr|
2293ceeb9c83SDarrick J. Wong 		 *        bno       len
2294ceeb9c83SDarrick J. Wong 		 */
2295ceeb9c83SDarrick J. Wong 		/* Delete the old record. */
2296ceeb9c83SDarrick J. Wong 		error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2297ceeb9c83SDarrick J. Wong 				gtrec.rm_blockcount, gtrec.rm_owner,
2298ceeb9c83SDarrick J. Wong 				gtrec.rm_offset, gtrec.rm_flags);
2299ceeb9c83SDarrick J. Wong 		if (error)
2300ceeb9c83SDarrick J. Wong 			goto out_error;
2301ceeb9c83SDarrick J. Wong 
2302ceeb9c83SDarrick J. Wong 		/* Move the start and re-add it. */
2303ceeb9c83SDarrick J. Wong 		gtrec.rm_startblock = bno;
2304ceeb9c83SDarrick J. Wong 		gtrec.rm_blockcount += len;
2305ceeb9c83SDarrick J. Wong 		gtrec.rm_offset = offset;
2306ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, gtrec.rm_startblock,
2307ceeb9c83SDarrick J. Wong 				gtrec.rm_blockcount, gtrec.rm_owner,
2308ceeb9c83SDarrick J. Wong 				gtrec.rm_offset, gtrec.rm_flags);
2309ceeb9c83SDarrick J. Wong 		if (error)
2310ceeb9c83SDarrick J. Wong 			goto out_error;
2311ceeb9c83SDarrick J. Wong 	} else {
2312ceeb9c83SDarrick J. Wong 		/*
2313ceeb9c83SDarrick J. Wong 		 * No contiguous edge with identical owner, insert
2314ceeb9c83SDarrick J. Wong 		 * new record at current cursor position.
2315ceeb9c83SDarrick J. Wong 		 */
2316ceeb9c83SDarrick J. Wong 		error = xfs_rmap_insert(cur, bno, len, owner, offset, flags);
2317ceeb9c83SDarrick J. Wong 		if (error)
2318ceeb9c83SDarrick J. Wong 			goto out_error;
2319ceeb9c83SDarrick J. Wong 	}
2320ceeb9c83SDarrick J. Wong 
232150f02fe3SDave Chinner 	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
2322ceeb9c83SDarrick J. Wong 			unwritten, oinfo);
2323ceeb9c83SDarrick J. Wong out_error:
2324ceeb9c83SDarrick J. Wong 	if (error)
2325ceeb9c83SDarrick J. Wong 		trace_xfs_rmap_map_error(cur->bc_mp,
232650f02fe3SDave Chinner 				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
2327ceeb9c83SDarrick J. Wong 	return error;
2328ceeb9c83SDarrick J. Wong }
2329ceeb9c83SDarrick J. Wong 
23304d4f86b4SDarrick J. Wong /* Insert a raw rmap into the rmapbt. */
23314d4f86b4SDarrick J. Wong int
xfs_rmap_map_raw(struct xfs_btree_cur * cur,struct xfs_rmap_irec * rmap)23324d4f86b4SDarrick J. Wong xfs_rmap_map_raw(
23334d4f86b4SDarrick J. Wong 	struct xfs_btree_cur	*cur,
23344d4f86b4SDarrick J. Wong 	struct xfs_rmap_irec	*rmap)
23354d4f86b4SDarrick J. Wong {
23364d4f86b4SDarrick J. Wong 	struct xfs_owner_info	oinfo;
23374d4f86b4SDarrick J. Wong 
23384d4f86b4SDarrick J. Wong 	oinfo.oi_owner = rmap->rm_owner;
23394d4f86b4SDarrick J. Wong 	oinfo.oi_offset = rmap->rm_offset;
23404d4f86b4SDarrick J. Wong 	oinfo.oi_flags = 0;
23414d4f86b4SDarrick J. Wong 	if (rmap->rm_flags & XFS_RMAP_ATTR_FORK)
23424d4f86b4SDarrick J. Wong 		oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
23434d4f86b4SDarrick J. Wong 	if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK)
23444d4f86b4SDarrick J. Wong 		oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
23454d4f86b4SDarrick J. Wong 
23464d4f86b4SDarrick J. Wong 	if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
23474d4f86b4SDarrick J. Wong 		return xfs_rmap_map(cur, rmap->rm_startblock,
23484d4f86b4SDarrick J. Wong 				rmap->rm_blockcount,
23494d4f86b4SDarrick J. Wong 				rmap->rm_flags & XFS_RMAP_UNWRITTEN,
23504d4f86b4SDarrick J. Wong 				&oinfo);
23514d4f86b4SDarrick J. Wong 
23524d4f86b4SDarrick J. Wong 	return xfs_rmap_map_shared(cur, rmap->rm_startblock,
23534d4f86b4SDarrick J. Wong 			rmap->rm_blockcount,
23544d4f86b4SDarrick J. Wong 			rmap->rm_flags & XFS_RMAP_UNWRITTEN,
23554d4f86b4SDarrick J. Wong 			&oinfo);
23564d4f86b4SDarrick J. Wong }
23574d4f86b4SDarrick J. Wong 
2358c543838aSDarrick J. Wong struct xfs_rmap_query_range_info {
2359c543838aSDarrick J. Wong 	xfs_rmap_query_range_fn	fn;
2360c543838aSDarrick J. Wong 	void				*priv;
2361c543838aSDarrick J. Wong };
2362c543838aSDarrick J. Wong 
2363c543838aSDarrick J. Wong /* Format btree record and pass to our callback. */
2364c543838aSDarrick J. Wong STATIC int
xfs_rmap_query_range_helper(struct xfs_btree_cur * cur,const union xfs_btree_rec * rec,void * priv)2365c543838aSDarrick J. Wong xfs_rmap_query_range_helper(
2366c543838aSDarrick J. Wong 	struct xfs_btree_cur		*cur,
2367159eb69dSDarrick J. Wong 	const union xfs_btree_rec	*rec,
2368c543838aSDarrick J. Wong 	void				*priv)
2369c543838aSDarrick J. Wong {
2370c543838aSDarrick J. Wong 	struct xfs_rmap_query_range_info	*query = priv;
2371c543838aSDarrick J. Wong 	struct xfs_rmap_irec			irec;
2372ee12eaaaSDarrick J. Wong 	xfs_failaddr_t				fa;
2373c543838aSDarrick J. Wong 
2374ee12eaaaSDarrick J. Wong 	fa = xfs_rmap_btrec_to_irec(rec, &irec);
2375ee12eaaaSDarrick J. Wong 	if (!fa)
2376ee12eaaaSDarrick J. Wong 		fa = xfs_rmap_check_irec(cur, &irec);
2377ee12eaaaSDarrick J. Wong 	if (fa)
2378ee12eaaaSDarrick J. Wong 		return xfs_rmap_complain_bad_rec(cur, fa, &irec);
237939ab26d5SDarrick J. Wong 
2380c543838aSDarrick J. Wong 	return query->fn(cur, &irec, query->priv);
2381c543838aSDarrick J. Wong }
2382c543838aSDarrick J. Wong 
2383c543838aSDarrick J. Wong /* Find all rmaps between two keys. */
2384c543838aSDarrick J. Wong int
xfs_rmap_query_range(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * low_rec,const struct xfs_rmap_irec * high_rec,xfs_rmap_query_range_fn fn,void * priv)2385c543838aSDarrick J. Wong xfs_rmap_query_range(
2386c543838aSDarrick J. Wong 	struct xfs_btree_cur			*cur,
238704dcb474SDarrick J. Wong 	const struct xfs_rmap_irec		*low_rec,
238804dcb474SDarrick J. Wong 	const struct xfs_rmap_irec		*high_rec,
2389c543838aSDarrick J. Wong 	xfs_rmap_query_range_fn			fn,
2390c543838aSDarrick J. Wong 	void					*priv)
2391c543838aSDarrick J. Wong {
2392*75dc0345SDarrick J. Wong 	union xfs_btree_irec			low_brec = { .r = *low_rec };
2393*75dc0345SDarrick J. Wong 	union xfs_btree_irec			high_brec = { .r = *high_rec };
2394*75dc0345SDarrick J. Wong 	struct xfs_rmap_query_range_info	query = { .priv = priv, .fn = fn };
2395c543838aSDarrick J. Wong 
2396c543838aSDarrick J. Wong 	return xfs_btree_query_range(cur, &low_brec, &high_brec,
2397c543838aSDarrick J. Wong 			xfs_rmap_query_range_helper, &query);
2398e9a2599aSDarrick J. Wong }
2399e9a2599aSDarrick J. Wong 
2400e9a2599aSDarrick J. Wong /* Find all rmaps. */
2401e9a2599aSDarrick J. Wong int
xfs_rmap_query_all(struct xfs_btree_cur * cur,xfs_rmap_query_range_fn fn,void * priv)2402e9a2599aSDarrick J. Wong xfs_rmap_query_all(
2403e9a2599aSDarrick J. Wong 	struct xfs_btree_cur			*cur,
2404e9a2599aSDarrick J. Wong 	xfs_rmap_query_range_fn			fn,
2405e9a2599aSDarrick J. Wong 	void					*priv)
2406e9a2599aSDarrick J. Wong {
2407e9a2599aSDarrick J. Wong 	struct xfs_rmap_query_range_info	query;
2408e9a2599aSDarrick J. Wong 
2409e9a2599aSDarrick J. Wong 	query.priv = priv;
2410e9a2599aSDarrick J. Wong 	query.fn = fn;
2411e9a2599aSDarrick J. Wong 	return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query);
2412c543838aSDarrick J. Wong }
24139c194644SDarrick J. Wong 
24149c194644SDarrick J. Wong /* Clean up after calling xfs_rmap_finish_one. */
24159c194644SDarrick J. Wong void
xfs_rmap_finish_one_cleanup(struct xfs_trans * tp,struct xfs_btree_cur * rcur,int error)24169c194644SDarrick J. Wong xfs_rmap_finish_one_cleanup(
24179c194644SDarrick J. Wong 	struct xfs_trans	*tp,
24189c194644SDarrick J. Wong 	struct xfs_btree_cur	*rcur,
24199c194644SDarrick J. Wong 	int			error)
24209c194644SDarrick J. Wong {
24219c194644SDarrick J. Wong 	struct xfs_buf		*agbp;
24229c194644SDarrick J. Wong 
24239c194644SDarrick J. Wong 	if (rcur == NULL)
24249c194644SDarrick J. Wong 		return;
2425576af732SDave Chinner 	agbp = rcur->bc_ag.agbp;
24260b04b6b8SDarrick J. Wong 	xfs_btree_del_cursor(rcur, error);
24279c194644SDarrick J. Wong 	if (error)
24289c194644SDarrick J. Wong 		xfs_trans_brelse(tp, agbp);
24299c194644SDarrick J. Wong }
24309c194644SDarrick J. Wong 
24319c194644SDarrick J. Wong /*
24329c194644SDarrick J. Wong  * Process one of the deferred rmap operations.  We pass back the
24339c194644SDarrick J. Wong  * btree cursor to maintain our lock on the rmapbt between calls.
24349c194644SDarrick J. Wong  * This saves time and eliminates a buffer deadlock between the
24359c194644SDarrick J. Wong  * superblock and the AGF because we'll always grab them in the same
24369c194644SDarrick J. Wong  * order.
24379c194644SDarrick J. Wong  */
24389c194644SDarrick J. Wong int
xfs_rmap_finish_one(struct xfs_trans * tp,struct xfs_rmap_intent * ri,struct xfs_btree_cur ** pcur)24399c194644SDarrick J. Wong xfs_rmap_finish_one(
24409c194644SDarrick J. Wong 	struct xfs_trans		*tp,
24411534328bSDarrick J. Wong 	struct xfs_rmap_intent		*ri,
24429c194644SDarrick J. Wong 	struct xfs_btree_cur		**pcur)
24439c194644SDarrick J. Wong {
24449c194644SDarrick J. Wong 	struct xfs_mount		*mp = tp->t_mountp;
24459c194644SDarrick J. Wong 	struct xfs_btree_cur		*rcur;
24469c194644SDarrick J. Wong 	struct xfs_buf			*agbp = NULL;
24479c194644SDarrick J. Wong 	int				error = 0;
24489c194644SDarrick J. Wong 	struct xfs_owner_info		oinfo;
24499c194644SDarrick J. Wong 	xfs_agblock_t			bno;
24509c194644SDarrick J. Wong 	bool				unwritten;
24519c194644SDarrick J. Wong 
24521534328bSDarrick J. Wong 	bno = XFS_FSB_TO_AGBNO(mp, ri->ri_bmap.br_startblock);
24539c194644SDarrick J. Wong 
2454c13418e8SDarrick J. Wong 	trace_xfs_rmap_deferred(mp, ri->ri_pag->pag_agno, ri->ri_type, bno,
24551534328bSDarrick J. Wong 			ri->ri_owner, ri->ri_whichfork,
24561534328bSDarrick J. Wong 			ri->ri_bmap.br_startoff, ri->ri_bmap.br_blockcount,
24571534328bSDarrick J. Wong 			ri->ri_bmap.br_state);
24589c194644SDarrick J. Wong 
2459c13418e8SDarrick J. Wong 	if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE))
2460c13418e8SDarrick J. Wong 		return -EIO;
24619c194644SDarrick J. Wong 
24629c194644SDarrick J. Wong 	/*
24639c194644SDarrick J. Wong 	 * If we haven't gotten a cursor or the cursor AG doesn't match
24649c194644SDarrick J. Wong 	 * the startblock, get one now.
24659c194644SDarrick J. Wong 	 */
24669c194644SDarrick J. Wong 	rcur = *pcur;
2467c13418e8SDarrick J. Wong 	if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
24689c194644SDarrick J. Wong 		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
24699c194644SDarrick J. Wong 		rcur = NULL;
24709c194644SDarrick J. Wong 		*pcur = NULL;
24719c194644SDarrick J. Wong 	}
24729c194644SDarrick J. Wong 	if (rcur == NULL) {
24739c194644SDarrick J. Wong 		/*
24749c194644SDarrick J. Wong 		 * Refresh the freelist before we start changing the
24759c194644SDarrick J. Wong 		 * rmapbt, because a shape change could cause us to
24769c194644SDarrick J. Wong 		 * allocate blocks.
24779c194644SDarrick J. Wong 		 */
2478c13418e8SDarrick J. Wong 		error = xfs_free_extent_fix_freelist(tp, ri->ri_pag, &agbp);
24799c194644SDarrick J. Wong 		if (error)
2480c13418e8SDarrick J. Wong 			return error;
2481c13418e8SDarrick J. Wong 		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
2482c13418e8SDarrick J. Wong 			return -EFSCORRUPTED;
24839c194644SDarrick J. Wong 
2484c13418e8SDarrick J. Wong 		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, ri->ri_pag);
24859c194644SDarrick J. Wong 	}
24869c194644SDarrick J. Wong 	*pcur = rcur;
24879c194644SDarrick J. Wong 
24881534328bSDarrick J. Wong 	xfs_rmap_ino_owner(&oinfo, ri->ri_owner, ri->ri_whichfork,
24891534328bSDarrick J. Wong 			ri->ri_bmap.br_startoff);
24901534328bSDarrick J. Wong 	unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
24911534328bSDarrick J. Wong 	bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, ri->ri_bmap.br_startblock);
24929c194644SDarrick J. Wong 
24931534328bSDarrick J. Wong 	switch (ri->ri_type) {
24949c194644SDarrick J. Wong 	case XFS_RMAP_ALLOC:
24959c194644SDarrick J. Wong 	case XFS_RMAP_MAP:
24961534328bSDarrick J. Wong 		error = xfs_rmap_map(rcur, bno, ri->ri_bmap.br_blockcount,
24971534328bSDarrick J. Wong 				unwritten, &oinfo);
24989c194644SDarrick J. Wong 		break;
2499ceeb9c83SDarrick J. Wong 	case XFS_RMAP_MAP_SHARED:
25001534328bSDarrick J. Wong 		error = xfs_rmap_map_shared(rcur, bno,
25011534328bSDarrick J. Wong 				ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2502ceeb9c83SDarrick J. Wong 		break;
25039c194644SDarrick J. Wong 	case XFS_RMAP_FREE:
25049c194644SDarrick J. Wong 	case XFS_RMAP_UNMAP:
25051534328bSDarrick J. Wong 		error = xfs_rmap_unmap(rcur, bno, ri->ri_bmap.br_blockcount,
25061534328bSDarrick J. Wong 				unwritten, &oinfo);
25079c194644SDarrick J. Wong 		break;
2508ceeb9c83SDarrick J. Wong 	case XFS_RMAP_UNMAP_SHARED:
25091534328bSDarrick J. Wong 		error = xfs_rmap_unmap_shared(rcur, bno,
25101534328bSDarrick J. Wong 				ri->ri_bmap.br_blockcount, unwritten, &oinfo);
2511ceeb9c83SDarrick J. Wong 		break;
25129c194644SDarrick J. Wong 	case XFS_RMAP_CONVERT:
25131534328bSDarrick J. Wong 		error = xfs_rmap_convert(rcur, bno, ri->ri_bmap.br_blockcount,
25141534328bSDarrick J. Wong 				!unwritten, &oinfo);
25159c194644SDarrick J. Wong 		break;
25163f165b33SDarrick J. Wong 	case XFS_RMAP_CONVERT_SHARED:
25171534328bSDarrick J. Wong 		error = xfs_rmap_convert_shared(rcur, bno,
25181534328bSDarrick J. Wong 				ri->ri_bmap.br_blockcount, !unwritten, &oinfo);
25193f165b33SDarrick J. Wong 		break;
25209c194644SDarrick J. Wong 	default:
25219c194644SDarrick J. Wong 		ASSERT(0);
25229c194644SDarrick J. Wong 		error = -EFSCORRUPTED;
25239c194644SDarrick J. Wong 	}
2524c13418e8SDarrick J. Wong 
25259c194644SDarrick J. Wong 	return error;
25269c194644SDarrick J. Wong }
25279c194644SDarrick J. Wong 
25289c194644SDarrick J. Wong /*
25299c194644SDarrick J. Wong  * Don't defer an rmap if we aren't an rmap filesystem.
25309c194644SDarrick J. Wong  */
25319c194644SDarrick J. Wong static bool
xfs_rmap_update_is_needed(struct xfs_mount * mp,int whichfork)25329c194644SDarrick J. Wong xfs_rmap_update_is_needed(
25333993baebSDarrick J. Wong 	struct xfs_mount	*mp,
25343993baebSDarrick J. Wong 	int			whichfork)
25359c194644SDarrick J. Wong {
253638c26bfdSDave Chinner 	return xfs_has_rmapbt(mp) && whichfork != XFS_COW_FORK;
25379c194644SDarrick J. Wong }
25389c194644SDarrick J. Wong 
25399c194644SDarrick J. Wong /*
25409c194644SDarrick J. Wong  * Record a rmap intent; the list is kept sorted first by AG and then by
25419c194644SDarrick J. Wong  * increasing age.
25429c194644SDarrick J. Wong  */
2543bc46ac64SDarrick J. Wong static void
__xfs_rmap_add(struct xfs_trans * tp,enum xfs_rmap_intent_type type,uint64_t owner,int whichfork,struct xfs_bmbt_irec * bmap)25449c194644SDarrick J. Wong __xfs_rmap_add(
25450f37d178SBrian Foster 	struct xfs_trans		*tp,
25469c194644SDarrick J. Wong 	enum xfs_rmap_intent_type	type,
2547c8ce540dSDarrick J. Wong 	uint64_t			owner,
25489c194644SDarrick J. Wong 	int				whichfork,
25499c194644SDarrick J. Wong 	struct xfs_bmbt_irec		*bmap)
25509c194644SDarrick J. Wong {
25519c194644SDarrick J. Wong 	struct xfs_rmap_intent		*ri;
25529c194644SDarrick J. Wong 
25530f37d178SBrian Foster 	trace_xfs_rmap_defer(tp->t_mountp,
25540f37d178SBrian Foster 			XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
25559c194644SDarrick J. Wong 			type,
25560f37d178SBrian Foster 			XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
25579c194644SDarrick J. Wong 			owner, whichfork,
25589c194644SDarrick J. Wong 			bmap->br_startoff,
25599c194644SDarrick J. Wong 			bmap->br_blockcount,
25609c194644SDarrick J. Wong 			bmap->br_state);
25619c194644SDarrick J. Wong 
2562f3c799c2SDarrick J. Wong 	ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
25639c194644SDarrick J. Wong 	INIT_LIST_HEAD(&ri->ri_list);
25649c194644SDarrick J. Wong 	ri->ri_type = type;
25659c194644SDarrick J. Wong 	ri->ri_owner = owner;
25669c194644SDarrick J. Wong 	ri->ri_whichfork = whichfork;
25679c194644SDarrick J. Wong 	ri->ri_bmap = *bmap;
25689c194644SDarrick J. Wong 
2569c13418e8SDarrick J. Wong 	xfs_rmap_update_get_group(tp->t_mountp, ri);
25700f37d178SBrian Foster 	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
25719c194644SDarrick J. Wong }
25729c194644SDarrick J. Wong 
25739c194644SDarrick J. Wong /* Map an extent into a file. */
2574bc46ac64SDarrick J. Wong void
xfs_rmap_map_extent(struct xfs_trans * tp,struct xfs_inode * ip,int whichfork,struct xfs_bmbt_irec * PREV)25759c194644SDarrick J. Wong xfs_rmap_map_extent(
25760f37d178SBrian Foster 	struct xfs_trans	*tp,
25779c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25789c194644SDarrick J. Wong 	int			whichfork,
25799c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25809c194644SDarrick J. Wong {
2581d7884e6eSDarrick J. Wong 	enum xfs_rmap_intent_type type = XFS_RMAP_MAP;
2582d7884e6eSDarrick J. Wong 
25830f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2584bc46ac64SDarrick J. Wong 		return;
25859c194644SDarrick J. Wong 
2586d7884e6eSDarrick J. Wong 	if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2587d7884e6eSDarrick J. Wong 		type = XFS_RMAP_MAP_SHARED;
2588d7884e6eSDarrick J. Wong 
2589d7884e6eSDarrick J. Wong 	__xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
25909c194644SDarrick J. Wong }
25919c194644SDarrick J. Wong 
25929c194644SDarrick J. Wong /* Unmap an extent out of a file. */
2593bc46ac64SDarrick J. Wong void
xfs_rmap_unmap_extent(struct xfs_trans * tp,struct xfs_inode * ip,int whichfork,struct xfs_bmbt_irec * PREV)25949c194644SDarrick J. Wong xfs_rmap_unmap_extent(
25950f37d178SBrian Foster 	struct xfs_trans	*tp,
25969c194644SDarrick J. Wong 	struct xfs_inode	*ip,
25979c194644SDarrick J. Wong 	int			whichfork,
25989c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
25999c194644SDarrick J. Wong {
2600d7884e6eSDarrick J. Wong 	enum xfs_rmap_intent_type type = XFS_RMAP_UNMAP;
2601d7884e6eSDarrick J. Wong 
26020f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
2603bc46ac64SDarrick J. Wong 		return;
26049c194644SDarrick J. Wong 
2605d7884e6eSDarrick J. Wong 	if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2606d7884e6eSDarrick J. Wong 		type = XFS_RMAP_UNMAP_SHARED;
2607d7884e6eSDarrick J. Wong 
2608d7884e6eSDarrick J. Wong 	__xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
26099c194644SDarrick J. Wong }
26109c194644SDarrick J. Wong 
26110f37d178SBrian Foster /*
26120f37d178SBrian Foster  * Convert a data fork extent from unwritten to real or vice versa.
26130f37d178SBrian Foster  *
26140f37d178SBrian Foster  * Note that tp can be NULL here as no transaction is used for COW fork
26150f37d178SBrian Foster  * unwritten conversion.
26160f37d178SBrian Foster  */
2617bc46ac64SDarrick J. Wong void
xfs_rmap_convert_extent(struct xfs_mount * mp,struct xfs_trans * tp,struct xfs_inode * ip,int whichfork,struct xfs_bmbt_irec * PREV)26189c194644SDarrick J. Wong xfs_rmap_convert_extent(
26199c194644SDarrick J. Wong 	struct xfs_mount	*mp,
26200f37d178SBrian Foster 	struct xfs_trans	*tp,
26219c194644SDarrick J. Wong 	struct xfs_inode	*ip,
26229c194644SDarrick J. Wong 	int			whichfork,
26239c194644SDarrick J. Wong 	struct xfs_bmbt_irec	*PREV)
26249c194644SDarrick J. Wong {
2625d7884e6eSDarrick J. Wong 	enum xfs_rmap_intent_type type = XFS_RMAP_CONVERT;
2626d7884e6eSDarrick J. Wong 
26273993baebSDarrick J. Wong 	if (!xfs_rmap_update_is_needed(mp, whichfork))
2628bc46ac64SDarrick J. Wong 		return;
26299c194644SDarrick J. Wong 
2630d7884e6eSDarrick J. Wong 	if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2631d7884e6eSDarrick J. Wong 		type = XFS_RMAP_CONVERT_SHARED;
2632d7884e6eSDarrick J. Wong 
2633d7884e6eSDarrick J. Wong 	__xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
26349c194644SDarrick J. Wong }
26359c194644SDarrick J. Wong 
26369c194644SDarrick J. Wong /* Schedule the creation of an rmap for non-file data. */
2637bc46ac64SDarrick J. Wong void
xfs_rmap_alloc_extent(struct xfs_trans * tp,xfs_agnumber_t agno,xfs_agblock_t bno,xfs_extlen_t len,uint64_t owner)26389c194644SDarrick J. Wong xfs_rmap_alloc_extent(
26390f37d178SBrian Foster 	struct xfs_trans	*tp,
26409c194644SDarrick J. Wong 	xfs_agnumber_t		agno,
26419c194644SDarrick J. Wong 	xfs_agblock_t		bno,
26429c194644SDarrick J. Wong 	xfs_extlen_t		len,
2643c8ce540dSDarrick J. Wong 	uint64_t		owner)
26449c194644SDarrick J. Wong {
26459c194644SDarrick J. Wong 	struct xfs_bmbt_irec	bmap;
26469c194644SDarrick J. Wong 
26470f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2648bc46ac64SDarrick J. Wong 		return;
26499c194644SDarrick J. Wong 
26500f37d178SBrian Foster 	bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
26519c194644SDarrick J. Wong 	bmap.br_blockcount = len;
26529c194644SDarrick J. Wong 	bmap.br_startoff = 0;
26539c194644SDarrick J. Wong 	bmap.br_state = XFS_EXT_NORM;
26549c194644SDarrick J. Wong 
2655bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
26569c194644SDarrick J. Wong }
26579c194644SDarrick J. Wong 
26589c194644SDarrick J. Wong /* Schedule the deletion of an rmap for non-file data. */
2659bc46ac64SDarrick J. Wong void
xfs_rmap_free_extent(struct xfs_trans * tp,xfs_agnumber_t agno,xfs_agblock_t bno,xfs_extlen_t len,uint64_t owner)26609c194644SDarrick J. Wong xfs_rmap_free_extent(
26610f37d178SBrian Foster 	struct xfs_trans	*tp,
26629c194644SDarrick J. Wong 	xfs_agnumber_t		agno,
26639c194644SDarrick J. Wong 	xfs_agblock_t		bno,
26649c194644SDarrick J. Wong 	xfs_extlen_t		len,
2665c8ce540dSDarrick J. Wong 	uint64_t		owner)
26669c194644SDarrick J. Wong {
26679c194644SDarrick J. Wong 	struct xfs_bmbt_irec	bmap;
26689c194644SDarrick J. Wong 
26690f37d178SBrian Foster 	if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
2670bc46ac64SDarrick J. Wong 		return;
26719c194644SDarrick J. Wong 
26720f37d178SBrian Foster 	bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
26739c194644SDarrick J. Wong 	bmap.br_blockcount = len;
26749c194644SDarrick J. Wong 	bmap.br_startoff = 0;
26759c194644SDarrick J. Wong 	bmap.br_state = XFS_EXT_NORM;
26769c194644SDarrick J. Wong 
2677bc46ac64SDarrick J. Wong 	__xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
26789c194644SDarrick J. Wong }
2679e89c0413SDarrick J. Wong 
2680e89c0413SDarrick J. Wong /* Compare rmap records.  Returns -1 if a < b, 1 if a > b, and 0 if equal. */
2681e89c0413SDarrick J. Wong int
xfs_rmap_compare(const struct xfs_rmap_irec * a,const struct xfs_rmap_irec * b)2682e89c0413SDarrick J. Wong xfs_rmap_compare(
2683e89c0413SDarrick J. Wong 	const struct xfs_rmap_irec	*a,
2684e89c0413SDarrick J. Wong 	const struct xfs_rmap_irec	*b)
2685e89c0413SDarrick J. Wong {
2686e89c0413SDarrick J. Wong 	__u64				oa;
2687e89c0413SDarrick J. Wong 	__u64				ob;
2688e89c0413SDarrick J. Wong 
2689e89c0413SDarrick J. Wong 	oa = xfs_rmap_irec_offset_pack(a);
2690e89c0413SDarrick J. Wong 	ob = xfs_rmap_irec_offset_pack(b);
2691e89c0413SDarrick J. Wong 
2692e89c0413SDarrick J. Wong 	if (a->rm_startblock < b->rm_startblock)
2693e89c0413SDarrick J. Wong 		return -1;
2694e89c0413SDarrick J. Wong 	else if (a->rm_startblock > b->rm_startblock)
2695e89c0413SDarrick J. Wong 		return 1;
2696e89c0413SDarrick J. Wong 	else if (a->rm_owner < b->rm_owner)
2697e89c0413SDarrick J. Wong 		return -1;
2698e89c0413SDarrick J. Wong 	else if (a->rm_owner > b->rm_owner)
2699e89c0413SDarrick J. Wong 		return 1;
2700e89c0413SDarrick J. Wong 	else if (oa < ob)
2701e89c0413SDarrick J. Wong 		return -1;
2702e89c0413SDarrick J. Wong 	else if (oa > ob)
2703e89c0413SDarrick J. Wong 		return 1;
2704e89c0413SDarrick J. Wong 	else
2705e89c0413SDarrick J. Wong 		return 0;
2706e89c0413SDarrick J. Wong }
2707ed7c52d4SDarrick J. Wong 
27086abc7aefSDarrick J. Wong /*
27096abc7aefSDarrick J. Wong  * Scan the physical storage part of the keyspace of the reverse mapping index
27106abc7aefSDarrick J. Wong  * and tell us if the area has no records, is fully mapped by records, or is
27116abc7aefSDarrick J. Wong  * partially filled.
27126abc7aefSDarrick J. Wong  */
2713ed7c52d4SDarrick J. Wong int
xfs_rmap_has_records(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,enum xbtree_recpacking * outcome)27146abc7aefSDarrick J. Wong xfs_rmap_has_records(
2715ed7c52d4SDarrick J. Wong 	struct xfs_btree_cur	*cur,
2716ed7c52d4SDarrick J. Wong 	xfs_agblock_t		bno,
2717ed7c52d4SDarrick J. Wong 	xfs_extlen_t		len,
27186abc7aefSDarrick J. Wong 	enum xbtree_recpacking	*outcome)
2719ed7c52d4SDarrick J. Wong {
27204a200a09SDarrick J. Wong 	union xfs_btree_key	mask = {
27214a200a09SDarrick J. Wong 		.rmap.rm_startblock = cpu_to_be32(-1U),
27224a200a09SDarrick J. Wong 	};
2723ed7c52d4SDarrick J. Wong 	union xfs_btree_irec	low;
2724ed7c52d4SDarrick J. Wong 	union xfs_btree_irec	high;
2725ed7c52d4SDarrick J. Wong 
2726ed7c52d4SDarrick J. Wong 	memset(&low, 0, sizeof(low));
2727ed7c52d4SDarrick J. Wong 	low.r.rm_startblock = bno;
2728ed7c52d4SDarrick J. Wong 	memset(&high, 0xFF, sizeof(high));
2729ed7c52d4SDarrick J. Wong 	high.r.rm_startblock = bno + len - 1;
2730ed7c52d4SDarrick J. Wong 
27314a200a09SDarrick J. Wong 	return xfs_btree_has_records(cur, &low, &high, &mask, outcome);
2732ed7c52d4SDarrick J. Wong }
2733ed7c52d4SDarrick J. Wong 
273469115f77SDarrick J. Wong struct xfs_rmap_ownercount {
273569115f77SDarrick J. Wong 	/* Owner that we're looking for. */
273669115f77SDarrick J. Wong 	struct xfs_rmap_irec	good;
273769115f77SDarrick J. Wong 
273869115f77SDarrick J. Wong 	/* rmap search keys */
273969115f77SDarrick J. Wong 	struct xfs_rmap_irec	low;
274069115f77SDarrick J. Wong 	struct xfs_rmap_irec	high;
274169115f77SDarrick J. Wong 
274269115f77SDarrick J. Wong 	struct xfs_rmap_matches	*results;
274369115f77SDarrick J. Wong 
274469115f77SDarrick J. Wong 	/* Stop early if we find a nonmatch? */
274569115f77SDarrick J. Wong 	bool			stop_on_nonmatch;
274669115f77SDarrick J. Wong };
274769115f77SDarrick J. Wong 
274869115f77SDarrick J. Wong /* Does this rmap represent space that can have multiple owners? */
274969115f77SDarrick J. Wong static inline bool
xfs_rmap_shareable(struct xfs_mount * mp,const struct xfs_rmap_irec * rmap)275069115f77SDarrick J. Wong xfs_rmap_shareable(
275169115f77SDarrick J. Wong 	struct xfs_mount		*mp,
275269115f77SDarrick J. Wong 	const struct xfs_rmap_irec	*rmap)
275369115f77SDarrick J. Wong {
275469115f77SDarrick J. Wong 	if (!xfs_has_reflink(mp))
275569115f77SDarrick J. Wong 		return false;
275669115f77SDarrick J. Wong 	if (XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
275769115f77SDarrick J. Wong 		return false;
275869115f77SDarrick J. Wong 	if (rmap->rm_flags & (XFS_RMAP_ATTR_FORK |
275969115f77SDarrick J. Wong 			      XFS_RMAP_BMBT_BLOCK))
276069115f77SDarrick J. Wong 		return false;
276169115f77SDarrick J. Wong 	return true;
276269115f77SDarrick J. Wong }
276369115f77SDarrick J. Wong 
276469115f77SDarrick J. Wong static inline void
xfs_rmap_ownercount_init(struct xfs_rmap_ownercount * roc,xfs_agblock_t bno,xfs_extlen_t len,const struct xfs_owner_info * oinfo,struct xfs_rmap_matches * results)276569115f77SDarrick J. Wong xfs_rmap_ownercount_init(
276669115f77SDarrick J. Wong 	struct xfs_rmap_ownercount	*roc,
2767ed7c52d4SDarrick J. Wong 	xfs_agblock_t			bno,
2768ed7c52d4SDarrick J. Wong 	xfs_extlen_t			len,
276966e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
277069115f77SDarrick J. Wong 	struct xfs_rmap_matches		*results)
2771ed7c52d4SDarrick J. Wong {
277269115f77SDarrick J. Wong 	memset(roc, 0, sizeof(*roc));
277369115f77SDarrick J. Wong 	roc->results = results;
2774ed7c52d4SDarrick J. Wong 
277569115f77SDarrick J. Wong 	roc->low.rm_startblock = bno;
277669115f77SDarrick J. Wong 	memset(&roc->high, 0xFF, sizeof(roc->high));
277769115f77SDarrick J. Wong 	roc->high.rm_startblock = bno + len - 1;
2778ed7c52d4SDarrick J. Wong 
277969115f77SDarrick J. Wong 	memset(results, 0, sizeof(*results));
278069115f77SDarrick J. Wong 	roc->good.rm_startblock = bno;
278169115f77SDarrick J. Wong 	roc->good.rm_blockcount = len;
278269115f77SDarrick J. Wong 	roc->good.rm_owner = oinfo->oi_owner;
278369115f77SDarrick J. Wong 	roc->good.rm_offset = oinfo->oi_offset;
278469115f77SDarrick J. Wong 	if (oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK)
278569115f77SDarrick J. Wong 		roc->good.rm_flags |= XFS_RMAP_ATTR_FORK;
278669115f77SDarrick J. Wong 	if (oinfo->oi_flags & XFS_OWNER_INFO_BMBT_BLOCK)
278769115f77SDarrick J. Wong 		roc->good.rm_flags |= XFS_RMAP_BMBT_BLOCK;
2788ed7c52d4SDarrick J. Wong }
2789ed7c52d4SDarrick J. Wong 
279069115f77SDarrick J. Wong /* Figure out if this is a match for the owner. */
27914d4f86b4SDarrick J. Wong STATIC int
xfs_rmap_count_owners_helper(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * rec,void * priv)279269115f77SDarrick J. Wong xfs_rmap_count_owners_helper(
27934d4f86b4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
2794159eb69dSDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
27954d4f86b4SDarrick J. Wong 	void				*priv)
27964d4f86b4SDarrick J. Wong {
279769115f77SDarrick J. Wong 	struct xfs_rmap_ownercount	*roc = priv;
279869115f77SDarrick J. Wong 	struct xfs_rmap_irec		check = *rec;
279969115f77SDarrick J. Wong 	unsigned int			keyflags;
280069115f77SDarrick J. Wong 	bool				filedata;
280169115f77SDarrick J. Wong 	int64_t				delta;
28024d4f86b4SDarrick J. Wong 
280369115f77SDarrick J. Wong 	filedata = !XFS_RMAP_NON_INODE_OWNER(check.rm_owner) &&
280469115f77SDarrick J. Wong 		   !(check.rm_flags & XFS_RMAP_BMBT_BLOCK);
280569115f77SDarrick J. Wong 
280669115f77SDarrick J. Wong 	/* Trim the part of check that comes before the comparison range. */
280769115f77SDarrick J. Wong 	delta = (int64_t)roc->good.rm_startblock - check.rm_startblock;
280869115f77SDarrick J. Wong 	if (delta > 0) {
280969115f77SDarrick J. Wong 		check.rm_startblock += delta;
281069115f77SDarrick J. Wong 		check.rm_blockcount -= delta;
281169115f77SDarrick J. Wong 		if (filedata)
281269115f77SDarrick J. Wong 			check.rm_offset += delta;
281369115f77SDarrick J. Wong 	}
281469115f77SDarrick J. Wong 
281569115f77SDarrick J. Wong 	/* Trim the part of check that comes after the comparison range. */
281669115f77SDarrick J. Wong 	delta = (check.rm_startblock + check.rm_blockcount) -
281769115f77SDarrick J. Wong 		(roc->good.rm_startblock + roc->good.rm_blockcount);
281869115f77SDarrick J. Wong 	if (delta > 0)
281969115f77SDarrick J. Wong 		check.rm_blockcount -= delta;
282069115f77SDarrick J. Wong 
282169115f77SDarrick J. Wong 	/* Don't care about unwritten status for establishing ownership. */
282269115f77SDarrick J. Wong 	keyflags = check.rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK);
282369115f77SDarrick J. Wong 
282469115f77SDarrick J. Wong 	if (check.rm_startblock	== roc->good.rm_startblock &&
282569115f77SDarrick J. Wong 	    check.rm_blockcount	== roc->good.rm_blockcount &&
282669115f77SDarrick J. Wong 	    check.rm_owner	== roc->good.rm_owner &&
282769115f77SDarrick J. Wong 	    check.rm_offset	== roc->good.rm_offset &&
282869115f77SDarrick J. Wong 	    keyflags		== roc->good.rm_flags) {
282969115f77SDarrick J. Wong 		roc->results->matches++;
283069115f77SDarrick J. Wong 	} else {
283169115f77SDarrick J. Wong 		roc->results->non_owner_matches++;
283269115f77SDarrick J. Wong 		if (xfs_rmap_shareable(cur->bc_mp, &roc->good) ^
283369115f77SDarrick J. Wong 		    xfs_rmap_shareable(cur->bc_mp, &check))
283469115f77SDarrick J. Wong 			roc->results->bad_non_owner_matches++;
283569115f77SDarrick J. Wong 	}
283669115f77SDarrick J. Wong 
283769115f77SDarrick J. Wong 	if (roc->results->non_owner_matches && roc->stop_on_nonmatch)
2838e7ee96dfSDarrick J. Wong 		return -ECANCELED;
283969115f77SDarrick J. Wong 
284069115f77SDarrick J. Wong 	return 0;
284169115f77SDarrick J. Wong }
284269115f77SDarrick J. Wong 
284369115f77SDarrick J. Wong /* Count the number of owners and non-owners of this range of blocks. */
284469115f77SDarrick J. Wong int
xfs_rmap_count_owners(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,const struct xfs_owner_info * oinfo,struct xfs_rmap_matches * results)284569115f77SDarrick J. Wong xfs_rmap_count_owners(
284669115f77SDarrick J. Wong 	struct xfs_btree_cur		*cur,
284769115f77SDarrick J. Wong 	xfs_agblock_t			bno,
284869115f77SDarrick J. Wong 	xfs_extlen_t			len,
284969115f77SDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
285069115f77SDarrick J. Wong 	struct xfs_rmap_matches		*results)
285169115f77SDarrick J. Wong {
285269115f77SDarrick J. Wong 	struct xfs_rmap_ownercount	roc;
285369115f77SDarrick J. Wong 	int				error;
285469115f77SDarrick J. Wong 
285569115f77SDarrick J. Wong 	xfs_rmap_ownercount_init(&roc, bno, len, oinfo, results);
285669115f77SDarrick J. Wong 	error = xfs_rmap_query_range(cur, &roc.low, &roc.high,
285769115f77SDarrick J. Wong 			xfs_rmap_count_owners_helper, &roc);
285869115f77SDarrick J. Wong 	if (error)
285969115f77SDarrick J. Wong 		return error;
286069115f77SDarrick J. Wong 
286169115f77SDarrick J. Wong 	/*
286269115f77SDarrick J. Wong 	 * There can't be any non-owner rmaps that conflict with the given
286369115f77SDarrick J. Wong 	 * owner if we didn't find any rmaps matching the owner.
286469115f77SDarrick J. Wong 	 */
286569115f77SDarrick J. Wong 	if (!results->matches)
286669115f77SDarrick J. Wong 		results->bad_non_owner_matches = 0;
286769115f77SDarrick J. Wong 
286869115f77SDarrick J. Wong 	return 0;
28694d4f86b4SDarrick J. Wong }
28704d4f86b4SDarrick J. Wong 
28714d4f86b4SDarrick J. Wong /*
28724d4f86b4SDarrick J. Wong  * Given an extent and some owner info, can we find records overlapping
28734d4f86b4SDarrick J. Wong  * the extent whose owner info does not match the given owner?
28744d4f86b4SDarrick J. Wong  */
28754d4f86b4SDarrick J. Wong int
xfs_rmap_has_other_keys(struct xfs_btree_cur * cur,xfs_agblock_t bno,xfs_extlen_t len,const struct xfs_owner_info * oinfo,bool * has_other)28764d4f86b4SDarrick J. Wong xfs_rmap_has_other_keys(
28774d4f86b4SDarrick J. Wong 	struct xfs_btree_cur		*cur,
28784d4f86b4SDarrick J. Wong 	xfs_agblock_t			bno,
28794d4f86b4SDarrick J. Wong 	xfs_extlen_t			len,
288066e3237eSDarrick J. Wong 	const struct xfs_owner_info	*oinfo,
288169115f77SDarrick J. Wong 	bool				*has_other)
28824d4f86b4SDarrick J. Wong {
288369115f77SDarrick J. Wong 	struct xfs_rmap_matches		res;
288469115f77SDarrick J. Wong 	struct xfs_rmap_ownercount	roc;
28854d4f86b4SDarrick J. Wong 	int				error;
28864d4f86b4SDarrick J. Wong 
288769115f77SDarrick J. Wong 	xfs_rmap_ownercount_init(&roc, bno, len, oinfo, &res);
288869115f77SDarrick J. Wong 	roc.stop_on_nonmatch = true;
28894d4f86b4SDarrick J. Wong 
289069115f77SDarrick J. Wong 	error = xfs_rmap_query_range(cur, &roc.low, &roc.high,
289169115f77SDarrick J. Wong 			xfs_rmap_count_owners_helper, &roc);
2892a71e4228SDarrick J. Wong 	if (error == -ECANCELED) {
289369115f77SDarrick J. Wong 		*has_other = true;
28947380e8feSDarrick J. Wong 		return 0;
28954d4f86b4SDarrick J. Wong 	}
289669115f77SDarrick J. Wong 	if (error)
2897a71e4228SDarrick J. Wong 		return error;
289869115f77SDarrick J. Wong 
289969115f77SDarrick J. Wong 	*has_other = false;
290069115f77SDarrick J. Wong 	return 0;
2901a71e4228SDarrick J. Wong }
2902a71e4228SDarrick J. Wong 
29037280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = {
29047280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_NULL,
29057280fedaSDarrick J. Wong };
29067280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER = {
29077280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_UNKNOWN,
29087280fedaSDarrick J. Wong };
29097280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_FS = {
29107280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_FS,
29117280fedaSDarrick J. Wong };
29127280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_LOG = {
29137280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_LOG,
29147280fedaSDarrick J. Wong };
29157280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_AG = {
29167280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_AG,
29177280fedaSDarrick J. Wong };
29187280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_INOBT = {
29197280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_INOBT,
29207280fedaSDarrick J. Wong };
29217280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_INODES = {
29227280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_INODES,
29237280fedaSDarrick J. Wong };
29247280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_REFC = {
29257280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_REFC,
29267280fedaSDarrick J. Wong };
29277280fedaSDarrick J. Wong const struct xfs_owner_info XFS_RMAP_OINFO_COW = {
29287280fedaSDarrick J. Wong 	.oi_owner = XFS_RMAP_OWN_COW,
29297280fedaSDarrick J. Wong };
2930f3c799c2SDarrick J. Wong 
2931f3c799c2SDarrick J. Wong int __init
xfs_rmap_intent_init_cache(void)2932f3c799c2SDarrick J. Wong xfs_rmap_intent_init_cache(void)
2933f3c799c2SDarrick J. Wong {
2934f3c799c2SDarrick J. Wong 	xfs_rmap_intent_cache = kmem_cache_create("xfs_rmap_intent",
2935f3c799c2SDarrick J. Wong 			sizeof(struct xfs_rmap_intent),
2936f3c799c2SDarrick J. Wong 			0, 0, NULL);
2937f3c799c2SDarrick J. Wong 
2938f3c799c2SDarrick J. Wong 	return xfs_rmap_intent_cache != NULL ? 0 : -ENOMEM;
2939f3c799c2SDarrick J. Wong }
2940f3c799c2SDarrick J. Wong 
2941f3c799c2SDarrick J. Wong void
xfs_rmap_intent_destroy_cache(void)2942f3c799c2SDarrick J. Wong xfs_rmap_intent_destroy_cache(void)
2943f3c799c2SDarrick J. Wong {
2944f3c799c2SDarrick J. Wong 	kmem_cache_destroy(xfs_rmap_intent_cache);
2945f3c799c2SDarrick J. Wong 	xfs_rmap_intent_cache = NULL;
2946f3c799c2SDarrick J. Wong }
2947