]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_rmap.c
xfsprogs: Release v6.7.0
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_rmap.c
CommitLineData
37b3b4d6 1// SPDX-License-Identifier: GPL-2.0
631ac87a
DW
2/*
3 * Copyright (c) 2014 Red Hat, Inc.
4 * All Rights Reserved.
631ac87a
DW
5 */
6#include "libxfs_priv.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_bit.h"
631ac87a 13#include "xfs_mount.h"
7635c486 14#include "xfs_sb.h"
631ac87a 15#include "xfs_defer.h"
631ac87a
DW
16#include "xfs_btree.h"
17#include "xfs_trans.h"
18#include "xfs_alloc.h"
19#include "xfs_rmap.h"
631bda23 20#include "xfs_rmap_btree.h"
631ac87a 21#include "xfs_trace.h"
2cf10e4c 22#include "xfs_errortag.h"
d7f80320 23#include "xfs_inode.h"
f93d2173 24#include "xfs_ag.h"
631ac87a 25
1577541c
DW
26struct kmem_cache *xfs_rmap_intent_cache;
27
936ca687
DW
28/*
29 * Lookup the first record less than or equal to [bno, len, owner, offset]
30 * in the btree given by cur.
31 */
32int
33xfs_rmap_lookup_le(
34 struct xfs_btree_cur *cur,
35 xfs_agblock_t bno,
936ca687
DW
36 uint64_t owner,
37 uint64_t offset,
38 unsigned int flags,
4a195282 39 struct xfs_rmap_irec *irec,
936ca687
DW
40 int *stat)
41{
4a195282
DW
42 int get_stat = 0;
43 int error;
44
936ca687 45 cur->bc_rec.r.rm_startblock = bno;
4a195282 46 cur->bc_rec.r.rm_blockcount = 0;
936ca687
DW
47 cur->bc_rec.r.rm_owner = owner;
48 cur->bc_rec.r.rm_offset = offset;
49 cur->bc_rec.r.rm_flags = flags;
4a195282
DW
50
51 error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
52 if (error || !(*stat) || !irec)
53 return error;
54
55 error = xfs_rmap_get_rec(cur, irec, &get_stat);
56 if (error)
57 return error;
58 if (!get_stat)
59 return -EFSCORRUPTED;
60
61 return 0;
936ca687
DW
62}
63
64/*
65 * Lookup the record exactly matching [bno, len, owner, offset]
66 * in the btree given by cur.
67 */
68int
69xfs_rmap_lookup_eq(
70 struct xfs_btree_cur *cur,
71 xfs_agblock_t bno,
72 xfs_extlen_t len,
73 uint64_t owner,
74 uint64_t offset,
75 unsigned int flags,
76 int *stat)
77{
78 cur->bc_rec.r.rm_startblock = bno;
79 cur->bc_rec.r.rm_blockcount = len;
80 cur->bc_rec.r.rm_owner = owner;
81 cur->bc_rec.r.rm_offset = offset;
82 cur->bc_rec.r.rm_flags = flags;
83 return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
84}
85
86/*
87 * Update the record referred to by cur to the value given
88 * by [bno, len, owner, offset].
89 * This either works (return 0) or gets an EFSCORRUPTED error.
90 */
91STATIC int
92xfs_rmap_update(
93 struct xfs_btree_cur *cur,
94 struct xfs_rmap_irec *irec)
95{
96 union xfs_btree_rec rec;
b26675c4
DW
97 int error;
98
a0577dbb 99 trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
b26675c4
DW
100 irec->rm_startblock, irec->rm_blockcount,
101 irec->rm_owner, irec->rm_offset, irec->rm_flags);
936ca687
DW
102
103 rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
104 rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
105 rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
106 rec.rmap.rm_offset = cpu_to_be64(
107 xfs_rmap_irec_offset_pack(irec));
b26675c4
DW
108 error = xfs_btree_update(cur, &rec);
109 if (error)
110 trace_xfs_rmap_update_error(cur->bc_mp,
a0577dbb 111 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
b26675c4
DW
112 return error;
113}
114
115int
116xfs_rmap_insert(
117 struct xfs_btree_cur *rcur,
118 xfs_agblock_t agbno,
119 xfs_extlen_t len,
120 uint64_t owner,
121 uint64_t offset,
122 unsigned int flags)
123{
124 int i;
125 int error;
126
a0577dbb 127 trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
b26675c4
DW
128 len, owner, offset, flags);
129
130 error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
131 if (error)
132 goto done;
fbb4fa7f
DW
133 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 0)) {
134 error = -EFSCORRUPTED;
135 goto done;
136 }
b26675c4
DW
137
138 rcur->bc_rec.r.rm_startblock = agbno;
139 rcur->bc_rec.r.rm_blockcount = len;
140 rcur->bc_rec.r.rm_owner = owner;
141 rcur->bc_rec.r.rm_offset = offset;
142 rcur->bc_rec.r.rm_flags = flags;
143 error = xfs_btree_insert(rcur, &i);
144 if (error)
145 goto done;
fbb4fa7f
DW
146 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
147 error = -EFSCORRUPTED;
148 goto done;
149 }
b26675c4
DW
150done:
151 if (error)
152 trace_xfs_rmap_insert_error(rcur->bc_mp,
a0577dbb 153 rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
b26675c4 154 return error;
936ca687
DW
155}
156
6c6bdf6f
DW
157STATIC int
158xfs_rmap_delete(
159 struct xfs_btree_cur *rcur,
160 xfs_agblock_t agbno,
161 xfs_extlen_t len,
162 uint64_t owner,
163 uint64_t offset,
164 unsigned int flags)
165{
166 int i;
167 int error;
168
a0577dbb 169 trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
6c6bdf6f
DW
170 len, owner, offset, flags);
171
172 error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
173 if (error)
174 goto done;
fbb4fa7f
DW
175 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
176 error = -EFSCORRUPTED;
177 goto done;
178 }
6c6bdf6f
DW
179
180 error = xfs_btree_delete(rcur, &i);
181 if (error)
182 goto done;
fbb4fa7f
DW
183 if (XFS_IS_CORRUPT(rcur->bc_mp, i != 1)) {
184 error = -EFSCORRUPTED;
185 goto done;
186 }
6c6bdf6f
DW
187done:
188 if (error)
189 trace_xfs_rmap_delete_error(rcur->bc_mp,
a0577dbb 190 rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
6c6bdf6f
DW
191 return error;
192}
193
50bb67d6 194/* Convert an internal btree record to an rmap record. */
8d444a7a 195xfs_failaddr_t
936ca687 196xfs_rmap_btrec_to_irec(
e62318a3
DW
197 const union xfs_btree_rec *rec,
198 struct xfs_rmap_irec *irec)
936ca687 199{
936ca687
DW
200 irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
201 irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
202 irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
203 return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
204 irec);
205}
206
fd1d74cd
DW
207/* Simple checks for rmap records. */
208xfs_failaddr_t
209xfs_rmap_check_irec(
210 struct xfs_btree_cur *cur,
211 const struct xfs_rmap_irec *irec)
212{
213 struct xfs_mount *mp = cur->bc_mp;
7e7856ce
DW
214 bool is_inode;
215 bool is_unwritten;
216 bool is_bmbt;
217 bool is_attr;
fd1d74cd
DW
218
219 if (irec->rm_blockcount == 0)
220 return __this_address;
221 if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
222 if (irec->rm_owner != XFS_RMAP_OWN_FS)
223 return __this_address;
224 if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
225 return __this_address;
226 } else {
227 /* check for valid extent range, including overflow */
228 if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
229 irec->rm_blockcount))
230 return __this_address;
231 }
232
233 if (!(xfs_verify_ino(mp, irec->rm_owner) ||
234 (irec->rm_owner <= XFS_RMAP_OWN_FS &&
235 irec->rm_owner >= XFS_RMAP_OWN_MIN)))
236 return __this_address;
237
7e7856ce
DW
238 /* Check flags. */
239 is_inode = !XFS_RMAP_NON_INODE_OWNER(irec->rm_owner);
240 is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK;
241 is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK;
242 is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN;
243
244 if (is_bmbt && irec->rm_offset != 0)
245 return __this_address;
246
247 if (!is_inode && irec->rm_offset != 0)
248 return __this_address;
249
250 if (is_unwritten && (is_bmbt || !is_inode || is_attr))
251 return __this_address;
252
253 if (!is_inode && (is_bmbt || is_unwritten || is_attr))
254 return __this_address;
255
b3c8146e
DW
256 /* Check for a valid fork offset, if applicable. */
257 if (is_inode && !is_bmbt &&
258 !xfs_verify_fileext(mp, irec->rm_offset, irec->rm_blockcount))
259 return __this_address;
260
fd1d74cd
DW
261 return NULL;
262}
263
e70bf9ba
DW
264static inline int
265xfs_rmap_complain_bad_rec(
266 struct xfs_btree_cur *cur,
267 xfs_failaddr_t fa,
268 const struct xfs_rmap_irec *irec)
269{
270 struct xfs_mount *mp = cur->bc_mp;
271
272 xfs_warn(mp,
273 "Reverse Mapping BTree record corruption in AG %d detected at %pS!",
274 cur->bc_ag.pag->pag_agno, fa);
275 xfs_warn(mp,
276 "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
277 irec->rm_owner, irec->rm_flags, irec->rm_startblock,
278 irec->rm_blockcount);
279 return -EFSCORRUPTED;
280}
281
936ca687
DW
282/*
283 * Get the data from the pointed-to record.
284 */
285int
286xfs_rmap_get_rec(
287 struct xfs_btree_cur *cur,
288 struct xfs_rmap_irec *irec,
289 int *stat)
290{
291 union xfs_btree_rec *rec;
fd1d74cd 292 xfs_failaddr_t fa;
936ca687
DW
293 int error;
294
295 error = xfs_btree_get_rec(cur, &rec, stat);
296 if (error || !*stat)
297 return error;
298
fd1d74cd
DW
299 fa = xfs_rmap_btrec_to_irec(rec, irec);
300 if (!fa)
301 fa = xfs_rmap_check_irec(cur, irec);
302 if (fa)
e70bf9ba 303 return xfs_rmap_complain_bad_rec(cur, fa, irec);
ec291989
DC
304
305 return 0;
936ca687
DW
306}
307
6c6bdf6f
DW
308struct xfs_find_left_neighbor_info {
309 struct xfs_rmap_irec high;
310 struct xfs_rmap_irec *irec;
6c6bdf6f
DW
311};
312
313/* For each rmap given, figure out if it matches the key we want. */
314STATIC int
315xfs_rmap_find_left_neighbor_helper(
e62318a3
DW
316 struct xfs_btree_cur *cur,
317 const struct xfs_rmap_irec *rec,
318 void *priv)
6c6bdf6f
DW
319{
320 struct xfs_find_left_neighbor_info *info = priv;
321
322 trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
a0577dbb 323 cur->bc_ag.pag->pag_agno, rec->rm_startblock,
6c6bdf6f
DW
324 rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
325 rec->rm_flags);
326
327 if (rec->rm_owner != info->high.rm_owner)
7dd6dee1 328 return 0;
6c6bdf6f
DW
329 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
330 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
331 rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset)
7dd6dee1 332 return 0;
6c6bdf6f
DW
333
334 *info->irec = *rec;
a0f17dde 335 return -ECANCELED;
6c6bdf6f
DW
336}
337
338/*
339 * Find the record to the left of the given extent, being careful only to
340 * return a match with the same owner and adjacent physical and logical
341 * block ranges.
342 */
92798496 343STATIC int
6c6bdf6f
DW
344xfs_rmap_find_left_neighbor(
345 struct xfs_btree_cur *cur,
346 xfs_agblock_t bno,
347 uint64_t owner,
348 uint64_t offset,
349 unsigned int flags,
350 struct xfs_rmap_irec *irec,
351 int *stat)
352{
353 struct xfs_find_left_neighbor_info info;
92798496 354 int found = 0;
6c6bdf6f
DW
355 int error;
356
357 *stat = 0;
358 if (bno == 0)
359 return 0;
360 info.high.rm_startblock = bno - 1;
361 info.high.rm_owner = owner;
362 if (!XFS_RMAP_NON_INODE_OWNER(owner) &&
363 !(flags & XFS_RMAP_BMBT_BLOCK)) {
364 if (offset == 0)
365 return 0;
366 info.high.rm_offset = offset - 1;
367 } else
368 info.high.rm_offset = 0;
369 info.high.rm_flags = flags;
370 info.high.rm_blockcount = 0;
371 info.irec = irec;
6c6bdf6f
DW
372
373 trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
a0577dbb 374 cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
6c6bdf6f 375
92798496
DW
376 /*
377 * Historically, we always used the range query to walk every reverse
378 * mapping that could possibly overlap the key that the caller asked
379 * for, and filter out the ones that don't. That is very slow when
380 * there are a lot of records.
381 *
382 * However, there are two scenarios where the classic btree search can
383 * produce correct results -- if the index contains a record that is an
384 * exact match for the lookup key; and if there are no other records
385 * between the record we want and the key we supplied.
386 *
387 * As an optimization, try a non-overlapped lookup first. This makes
388 * extent conversion and remap operations run a bit faster if the
389 * physical extents aren't being shared. If we don't find what we
390 * want, we fall back to the overlapped query.
391 */
392 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
393 &found);
394 if (error)
395 return error;
396 if (found)
397 error = xfs_rmap_find_left_neighbor_helper(cur, irec, &info);
398 if (!error)
399 error = xfs_rmap_query_range(cur, &info.high, &info.high,
400 xfs_rmap_find_left_neighbor_helper, &info);
401 if (error != -ECANCELED)
402 return error;
403
404 *stat = 1;
405 trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
406 cur->bc_ag.pag->pag_agno, irec->rm_startblock,
407 irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
408 irec->rm_flags);
409 return 0;
6c6bdf6f
DW
410}
411
412/* For each rmap given, figure out if it matches the key we want. */
413STATIC int
414xfs_rmap_lookup_le_range_helper(
e62318a3
DW
415 struct xfs_btree_cur *cur,
416 const struct xfs_rmap_irec *rec,
417 void *priv)
6c6bdf6f
DW
418{
419 struct xfs_find_left_neighbor_info *info = priv;
420
421 trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
a0577dbb 422 cur->bc_ag.pag->pag_agno, rec->rm_startblock,
6c6bdf6f
DW
423 rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
424 rec->rm_flags);
425
426 if (rec->rm_owner != info->high.rm_owner)
7dd6dee1 427 return 0;
6c6bdf6f
DW
428 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
429 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
430 (rec->rm_offset > info->high.rm_offset ||
431 rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset))
7dd6dee1 432 return 0;
6c6bdf6f
DW
433
434 *info->irec = *rec;
a0f17dde 435 return -ECANCELED;
6c6bdf6f
DW
436}
437
438/*
439 * Find the record to the left of the given extent, being careful only to
440 * return a match with the same owner and overlapping physical and logical
441 * block ranges. This is the overlapping-interval version of
442 * xfs_rmap_lookup_le.
443 */
444int
445xfs_rmap_lookup_le_range(
446 struct xfs_btree_cur *cur,
447 xfs_agblock_t bno,
448 uint64_t owner,
449 uint64_t offset,
450 unsigned int flags,
451 struct xfs_rmap_irec *irec,
452 int *stat)
453{
454 struct xfs_find_left_neighbor_info info;
8b03b413 455 int found = 0;
6c6bdf6f
DW
456 int error;
457
458 info.high.rm_startblock = bno;
459 info.high.rm_owner = owner;
460 if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK))
461 info.high.rm_offset = offset;
462 else
463 info.high.rm_offset = 0;
464 info.high.rm_flags = flags;
465 info.high.rm_blockcount = 0;
466 *stat = 0;
467 info.irec = irec;
6c6bdf6f 468
8b03b413
DW
469 trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_ag.pag->pag_agno,
470 bno, 0, owner, offset, flags);
471
472 /*
473 * Historically, we always used the range query to walk every reverse
474 * mapping that could possibly overlap the key that the caller asked
475 * for, and filter out the ones that don't. That is very slow when
476 * there are a lot of records.
477 *
478 * However, there are two scenarios where the classic btree search can
479 * produce correct results -- if the index contains a record that is an
480 * exact match for the lookup key; and if there are no other records
481 * between the record we want and the key we supplied.
482 *
483 * As an optimization, try a non-overlapped lookup first. This makes
484 * scrub run much faster on most filesystems because bmbt records are
485 * usually an exact match for rmap records. If we don't find what we
486 * want, we fall back to the overlapped query.
487 */
488 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
489 &found);
490 if (error)
491 return error;
492 if (found)
493 error = xfs_rmap_lookup_le_range_helper(cur, irec, &info);
494 if (!error)
495 error = xfs_rmap_query_range(cur, &info.high, &info.high,
496 xfs_rmap_lookup_le_range_helper, &info);
497 if (error != -ECANCELED)
498 return error;
499
500 *stat = 1;
501 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
502 cur->bc_ag.pag->pag_agno, irec->rm_startblock,
503 irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
504 irec->rm_flags);
505 return 0;
6c6bdf6f
DW
506}
507
19f9a63a
DW
508/*
509 * Perform all the relevant owner checks for a removal op. If we're doing an
510 * unknown-owner removal then we have no owner information to check.
511 */
512static int
513xfs_rmap_free_check_owner(
514 struct xfs_mount *mp,
515 uint64_t ltoff,
516 struct xfs_rmap_irec *rec,
19f9a63a
DW
517 xfs_filblks_t len,
518 uint64_t owner,
519 uint64_t offset,
520 unsigned int flags)
521{
522 int error = 0;
523
524 if (owner == XFS_RMAP_OWN_UNKNOWN)
525 return 0;
526
527 /* Make sure the unwritten flag matches. */
fbb4fa7f
DW
528 if (XFS_IS_CORRUPT(mp,
529 (flags & XFS_RMAP_UNWRITTEN) !=
530 (rec->rm_flags & XFS_RMAP_UNWRITTEN))) {
531 error = -EFSCORRUPTED;
532 goto out;
533 }
19f9a63a
DW
534
535 /* Make sure the owner matches what we expect to find in the tree. */
fbb4fa7f
DW
536 if (XFS_IS_CORRUPT(mp, owner != rec->rm_owner)) {
537 error = -EFSCORRUPTED;
538 goto out;
539 }
19f9a63a
DW
540
541 /* Check the offset, if necessary. */
542 if (XFS_RMAP_NON_INODE_OWNER(owner))
543 goto out;
544
545 if (flags & XFS_RMAP_BMBT_BLOCK) {
fbb4fa7f
DW
546 if (XFS_IS_CORRUPT(mp,
547 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK))) {
548 error = -EFSCORRUPTED;
549 goto out;
550 }
19f9a63a 551 } else {
fbb4fa7f
DW
552 if (XFS_IS_CORRUPT(mp, rec->rm_offset > offset)) {
553 error = -EFSCORRUPTED;
554 goto out;
555 }
556 if (XFS_IS_CORRUPT(mp,
557 offset + len > ltoff + rec->rm_blockcount)) {
558 error = -EFSCORRUPTED;
559 goto out;
560 }
19f9a63a
DW
561 }
562
563out:
564 return error;
565}
566
ae81ebf2
DW
567/*
568 * Find the extent in the rmap btree and remove it.
569 *
570 * The record we find should always be an exact match for the extent that we're
571 * looking for, since we insert them into the btree without modification.
572 *
573 * Special Case #1: when growing the filesystem, we "free" an extent when
574 * growing the last AG. This extent is new space and so it is not tracked as
575 * used space in the btree. The growfs code will pass in an owner of
576 * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
577 * extent. We verify that - the extent lookup result in a record that does not
578 * overlap.
579 *
580 * Special Case #2: EFIs do not record the owner of the extent, so when
581 * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
582 * btree to ignore the owner (i.e. wildcard match) so we don't trigger
583 * corruption checks during log recovery.
584 */
585STATIC int
586xfs_rmap_unmap(
5837e73b
DW
587 struct xfs_btree_cur *cur,
588 xfs_agblock_t bno,
589 xfs_extlen_t len,
590 bool unwritten,
591 const struct xfs_owner_info *oinfo)
ae81ebf2 592{
5837e73b
DW
593 struct xfs_mount *mp = cur->bc_mp;
594 struct xfs_rmap_irec ltrec;
595 uint64_t ltoff;
596 int error = 0;
597 int i;
598 uint64_t owner;
599 uint64_t offset;
600 unsigned int flags;
601 bool ignore_off;
ae81ebf2
DW
602
603 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
604 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
605 (flags & XFS_RMAP_BMBT_BLOCK);
606 if (unwritten)
607 flags |= XFS_RMAP_UNWRITTEN;
a0577dbb 608 trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
ae81ebf2
DW
609 unwritten, oinfo);
610
611 /*
612 * We should always have a left record because there's a static record
613 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
614 * will not ever be removed from the tree.
615 */
4a195282 616 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &ltrec, &i);
ae81ebf2
DW
617 if (error)
618 goto out_error;
fbb4fa7f
DW
619 if (XFS_IS_CORRUPT(mp, i != 1)) {
620 error = -EFSCORRUPTED;
621 goto out_error;
622 }
ae81ebf2 623
ae81ebf2 624 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
a0577dbb 625 cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
ae81ebf2
DW
626 ltrec.rm_blockcount, ltrec.rm_owner,
627 ltrec.rm_offset, ltrec.rm_flags);
628 ltoff = ltrec.rm_offset;
629
630 /*
631 * For growfs, the incoming extent must be beyond the left record we
632 * just found as it is new space and won't be used by anyone. This is
633 * just a corruption check as we don't actually do anything with this
634 * extent. Note that we need to use >= instead of > because it might
635 * be the case that the "left" extent goes all the way to EOFS.
636 */
637 if (owner == XFS_RMAP_OWN_NULL) {
fbb4fa7f
DW
638 if (XFS_IS_CORRUPT(mp,
639 bno <
640 ltrec.rm_startblock + ltrec.rm_blockcount)) {
641 error = -EFSCORRUPTED;
642 goto out_error;
643 }
ae81ebf2
DW
644 goto out_done;
645 }
646
3ee858aa
DW
647 /*
648 * If we're doing an unknown-owner removal for EFI recovery, we expect
649 * to find the full range in the rmapbt or nothing at all. If we
650 * don't find any rmaps overlapping either end of the range, we're
651 * done. Hopefully this means that the EFI creator already queued
652 * (and finished) a RUI to remove the rmap.
653 */
654 if (owner == XFS_RMAP_OWN_UNKNOWN &&
655 ltrec.rm_startblock + ltrec.rm_blockcount <= bno) {
656 struct xfs_rmap_irec rtrec;
657
658 error = xfs_btree_increment(cur, 0, &i);
659 if (error)
660 goto out_error;
661 if (i == 0)
662 goto out_done;
663 error = xfs_rmap_get_rec(cur, &rtrec, &i);
664 if (error)
665 goto out_error;
fbb4fa7f
DW
666 if (XFS_IS_CORRUPT(mp, i != 1)) {
667 error = -EFSCORRUPTED;
668 goto out_error;
669 }
3ee858aa
DW
670 if (rtrec.rm_startblock >= bno + len)
671 goto out_done;
672 }
673
ae81ebf2 674 /* Make sure the extent we found covers the entire freeing range. */
fbb4fa7f
DW
675 if (XFS_IS_CORRUPT(mp,
676 ltrec.rm_startblock > bno ||
677 ltrec.rm_startblock + ltrec.rm_blockcount <
678 bno + len)) {
679 error = -EFSCORRUPTED;
680 goto out_error;
681 }
ae81ebf2 682
19f9a63a 683 /* Check owner information. */
1421de38 684 error = xfs_rmap_free_check_owner(mp, ltoff, &ltrec, len, owner,
19f9a63a
DW
685 offset, flags);
686 if (error)
687 goto out_error;
ae81ebf2
DW
688
689 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
690 /* exact match, simply remove the record from rmap tree */
a0577dbb 691 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
ae81ebf2
DW
692 ltrec.rm_startblock, ltrec.rm_blockcount,
693 ltrec.rm_owner, ltrec.rm_offset,
694 ltrec.rm_flags);
695 error = xfs_btree_delete(cur, &i);
696 if (error)
697 goto out_error;
fbb4fa7f
DW
698 if (XFS_IS_CORRUPT(mp, i != 1)) {
699 error = -EFSCORRUPTED;
700 goto out_error;
701 }
ae81ebf2
DW
702 } else if (ltrec.rm_startblock == bno) {
703 /*
704 * overlap left hand side of extent: move the start, trim the
705 * length and update the current record.
706 *
707 * ltbno ltlen
708 * Orig: |oooooooooooooooooooo|
709 * Freeing: |fffffffff|
710 * Result: |rrrrrrrrrr|
711 * bno len
712 */
713 ltrec.rm_startblock += len;
714 ltrec.rm_blockcount -= len;
715 if (!ignore_off)
716 ltrec.rm_offset += len;
717 error = xfs_rmap_update(cur, &ltrec);
718 if (error)
719 goto out_error;
720 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
721 /*
722 * overlap right hand side of extent: trim the length and update
723 * the current record.
724 *
725 * ltbno ltlen
726 * Orig: |oooooooooooooooooooo|
727 * Freeing: |fffffffff|
728 * Result: |rrrrrrrrrr|
729 * bno len
730 */
731 ltrec.rm_blockcount -= len;
732 error = xfs_rmap_update(cur, &ltrec);
733 if (error)
734 goto out_error;
735 } else {
736
737 /*
738 * overlap middle of extent: trim the length of the existing
739 * record to the length of the new left-extent size, increment
740 * the insertion position so we can insert a new record
741 * containing the remaining right-extent space.
742 *
743 * ltbno ltlen
744 * Orig: |oooooooooooooooooooo|
745 * Freeing: |fffffffff|
746 * Result: |rrrrr| |rrrr|
747 * bno len
748 */
749 xfs_extlen_t orig_len = ltrec.rm_blockcount;
750
751 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
752 error = xfs_rmap_update(cur, &ltrec);
753 if (error)
754 goto out_error;
755
756 error = xfs_btree_increment(cur, 0, &i);
757 if (error)
758 goto out_error;
759
760 cur->bc_rec.r.rm_startblock = bno + len;
761 cur->bc_rec.r.rm_blockcount = orig_len - len -
762 ltrec.rm_blockcount;
763 cur->bc_rec.r.rm_owner = ltrec.rm_owner;
764 if (ignore_off)
765 cur->bc_rec.r.rm_offset = 0;
766 else
767 cur->bc_rec.r.rm_offset = offset + len;
768 cur->bc_rec.r.rm_flags = flags;
a0577dbb 769 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
ae81ebf2
DW
770 cur->bc_rec.r.rm_startblock,
771 cur->bc_rec.r.rm_blockcount,
772 cur->bc_rec.r.rm_owner,
773 cur->bc_rec.r.rm_offset,
774 cur->bc_rec.r.rm_flags);
775 error = xfs_btree_insert(cur, &i);
776 if (error)
777 goto out_error;
778 }
779
780out_done:
a0577dbb 781 trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
ae81ebf2
DW
782 unwritten, oinfo);
783out_error:
784 if (error)
a0577dbb 785 trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
ae81ebf2
DW
786 error, _RET_IP_);
787 return error;
788}
789
790/*
791 * Remove a reference to an extent in the rmap btree.
792 */
631ac87a
DW
793int
794xfs_rmap_free(
5837e73b
DW
795 struct xfs_trans *tp,
796 struct xfs_buf *agbp,
195c248c 797 struct xfs_perag *pag,
5837e73b
DW
798 xfs_agblock_t bno,
799 xfs_extlen_t len,
800 const struct xfs_owner_info *oinfo)
631ac87a 801{
5837e73b
DW
802 struct xfs_mount *mp = tp->t_mountp;
803 struct xfs_btree_cur *cur;
804 int error;
631ac87a 805
b16a427a 806 if (!xfs_has_rmapbt(mp))
631ac87a
DW
807 return 0;
808
195c248c 809 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
ae81ebf2
DW
810
811 error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
ae81ebf2 812
660265b7 813 xfs_btree_del_cursor(cur, error);
631ac87a
DW
814 return error;
815}
816
631bda23
DW
817/*
818 * A mergeable rmap must have the same owner and the same values for
819 * the unwritten, attr_fork, and bmbt flags. The startblock and
820 * offset are checked separately.
821 */
822static bool
823xfs_rmap_is_mergeable(
824 struct xfs_rmap_irec *irec,
825 uint64_t owner,
826 unsigned int flags)
827{
828 if (irec->rm_owner == XFS_RMAP_OWN_NULL)
829 return false;
830 if (irec->rm_owner != owner)
831 return false;
832 if ((flags & XFS_RMAP_UNWRITTEN) ^
833 (irec->rm_flags & XFS_RMAP_UNWRITTEN))
834 return false;
835 if ((flags & XFS_RMAP_ATTR_FORK) ^
836 (irec->rm_flags & XFS_RMAP_ATTR_FORK))
837 return false;
838 if ((flags & XFS_RMAP_BMBT_BLOCK) ^
839 (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
840 return false;
841 return true;
842}
843
844/*
845 * When we allocate a new block, the first thing we do is add a reference to
846 * the extent in the rmap btree. This takes the form of a [agbno, length,
847 * owner, offset] record. Flags are encoded in the high bits of the offset
848 * field.
849 */
850STATIC int
851xfs_rmap_map(
5837e73b
DW
852 struct xfs_btree_cur *cur,
853 xfs_agblock_t bno,
854 xfs_extlen_t len,
855 bool unwritten,
856 const struct xfs_owner_info *oinfo)
631bda23 857{
5837e73b
DW
858 struct xfs_mount *mp = cur->bc_mp;
859 struct xfs_rmap_irec ltrec;
860 struct xfs_rmap_irec gtrec;
861 int have_gt;
862 int have_lt;
863 int error = 0;
864 int i;
865 uint64_t owner;
866 uint64_t offset;
867 unsigned int flags = 0;
868 bool ignore_off;
631bda23
DW
869
870 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
871 ASSERT(owner != 0);
872 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
873 (flags & XFS_RMAP_BMBT_BLOCK);
874 if (unwritten)
875 flags |= XFS_RMAP_UNWRITTEN;
a0577dbb 876 trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
631bda23 877 unwritten, oinfo);
3ee858aa 878 ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
631bda23
DW
879
880 /*
881 * For the initial lookup, look for an exact match or the left-adjacent
882 * record for our insertion point. This will also give us the record for
883 * start block contiguity tests.
884 */
4a195282 885 error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, &ltrec,
631bda23
DW
886 &have_lt);
887 if (error)
888 goto out_error;
a6ad7ea8 889 if (have_lt) {
a6ad7ea8 890 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
a0577dbb 891 cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
a6ad7ea8
DW
892 ltrec.rm_blockcount, ltrec.rm_owner,
893 ltrec.rm_offset, ltrec.rm_flags);
631bda23 894
a6ad7ea8
DW
895 if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
896 have_lt = 0;
897 }
631bda23 898
fbb4fa7f
DW
899 if (XFS_IS_CORRUPT(mp,
900 have_lt != 0 &&
901 ltrec.rm_startblock + ltrec.rm_blockcount > bno)) {
902 error = -EFSCORRUPTED;
903 goto out_error;
904 }
631bda23
DW
905
906 /*
907 * Increment the cursor to see if we have a right-adjacent record to our
908 * insertion point. This will give us the record for end block
909 * contiguity tests.
910 */
911 error = xfs_btree_increment(cur, 0, &have_gt);
912 if (error)
913 goto out_error;
914 if (have_gt) {
915 error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
916 if (error)
917 goto out_error;
fbb4fa7f
DW
918 if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
919 error = -EFSCORRUPTED;
920 goto out_error;
921 }
922 if (XFS_IS_CORRUPT(mp, bno + len > gtrec.rm_startblock)) {
923 error = -EFSCORRUPTED;
924 goto out_error;
925 }
631bda23 926 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
a0577dbb 927 cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
631bda23
DW
928 gtrec.rm_blockcount, gtrec.rm_owner,
929 gtrec.rm_offset, gtrec.rm_flags);
930 if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
931 have_gt = 0;
932 }
933
934 /*
935 * Note: cursor currently points one record to the right of ltrec, even
936 * if there is no record in the tree to the right.
937 */
938 if (have_lt &&
939 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
940 (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
941 /*
942 * left edge contiguous, merge into left record.
943 *
944 * ltbno ltlen
945 * orig: |ooooooooo|
946 * adding: |aaaaaaaaa|
947 * result: |rrrrrrrrrrrrrrrrrrr|
948 * bno len
949 */
950 ltrec.rm_blockcount += len;
951 if (have_gt &&
952 bno + len == gtrec.rm_startblock &&
953 (ignore_off || offset + len == gtrec.rm_offset) &&
954 (unsigned long)ltrec.rm_blockcount + len +
955 gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
956 /*
957 * right edge also contiguous, delete right record
958 * and merge into left record.
959 *
960 * ltbno ltlen gtbno gtlen
961 * orig: |ooooooooo| |ooooooooo|
962 * adding: |aaaaaaaaa|
963 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
964 */
965 ltrec.rm_blockcount += gtrec.rm_blockcount;
a0577dbb 966 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
631bda23
DW
967 gtrec.rm_startblock,
968 gtrec.rm_blockcount,
969 gtrec.rm_owner,
970 gtrec.rm_offset,
971 gtrec.rm_flags);
972 error = xfs_btree_delete(cur, &i);
973 if (error)
974 goto out_error;
fbb4fa7f
DW
975 if (XFS_IS_CORRUPT(mp, i != 1)) {
976 error = -EFSCORRUPTED;
977 goto out_error;
978 }
631bda23
DW
979 }
980
981 /* point the cursor back to the left record and update */
982 error = xfs_btree_decrement(cur, 0, &have_gt);
983 if (error)
984 goto out_error;
985 error = xfs_rmap_update(cur, &ltrec);
986 if (error)
987 goto out_error;
988 } else if (have_gt &&
989 bno + len == gtrec.rm_startblock &&
990 (ignore_off || offset + len == gtrec.rm_offset)) {
991 /*
992 * right edge contiguous, merge into right record.
993 *
994 * gtbno gtlen
995 * Orig: |ooooooooo|
996 * adding: |aaaaaaaaa|
997 * Result: |rrrrrrrrrrrrrrrrrrr|
998 * bno len
999 */
1000 gtrec.rm_startblock = bno;
1001 gtrec.rm_blockcount += len;
1002 if (!ignore_off)
1003 gtrec.rm_offset = offset;
1004 error = xfs_rmap_update(cur, &gtrec);
1005 if (error)
1006 goto out_error;
1007 } else {
1008 /*
1009 * no contiguous edge with identical owner, insert
1010 * new record at current cursor position.
1011 */
1012 cur->bc_rec.r.rm_startblock = bno;
1013 cur->bc_rec.r.rm_blockcount = len;
1014 cur->bc_rec.r.rm_owner = owner;
1015 cur->bc_rec.r.rm_offset = offset;
1016 cur->bc_rec.r.rm_flags = flags;
a0577dbb 1017 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
631bda23
DW
1018 owner, offset, flags);
1019 error = xfs_btree_insert(cur, &i);
1020 if (error)
1021 goto out_error;
fbb4fa7f
DW
1022 if (XFS_IS_CORRUPT(mp, i != 1)) {
1023 error = -EFSCORRUPTED;
1024 goto out_error;
1025 }
631bda23
DW
1026 }
1027
a0577dbb 1028 trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
631bda23
DW
1029 unwritten, oinfo);
1030out_error:
1031 if (error)
a0577dbb 1032 trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
631bda23
DW
1033 error, _RET_IP_);
1034 return error;
1035}
1036
1037/*
1038 * Add a reference to an extent in the rmap btree.
1039 */
631ac87a
DW
1040int
1041xfs_rmap_alloc(
5837e73b
DW
1042 struct xfs_trans *tp,
1043 struct xfs_buf *agbp,
195c248c 1044 struct xfs_perag *pag,
5837e73b
DW
1045 xfs_agblock_t bno,
1046 xfs_extlen_t len,
1047 const struct xfs_owner_info *oinfo)
631ac87a 1048{
5837e73b
DW
1049 struct xfs_mount *mp = tp->t_mountp;
1050 struct xfs_btree_cur *cur;
1051 int error;
631ac87a 1052
b16a427a 1053 if (!xfs_has_rmapbt(mp))
631ac87a
DW
1054 return 0;
1055
195c248c 1056 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
631bda23 1057 error = xfs_rmap_map(cur, bno, len, false, oinfo);
631bda23 1058
660265b7 1059 xfs_btree_del_cursor(cur, error);
631ac87a
DW
1060 return error;
1061}
890e1174 1062
7faf209c
DW
1063#define RMAP_LEFT_CONTIG (1 << 0)
1064#define RMAP_RIGHT_CONTIG (1 << 1)
1065#define RMAP_LEFT_FILLING (1 << 2)
1066#define RMAP_RIGHT_FILLING (1 << 3)
1067#define RMAP_LEFT_VALID (1 << 6)
1068#define RMAP_RIGHT_VALID (1 << 7)
1069
1070#define LEFT r[0]
1071#define RIGHT r[1]
1072#define PREV r[2]
1073#define NEW r[3]
1074
1075/*
1076 * Convert an unwritten extent to a real extent or vice versa.
1077 * Does not handle overlapping extents.
1078 */
1079STATIC int
1080xfs_rmap_convert(
5837e73b
DW
1081 struct xfs_btree_cur *cur,
1082 xfs_agblock_t bno,
1083 xfs_extlen_t len,
1084 bool unwritten,
1085 const struct xfs_owner_info *oinfo)
7faf209c 1086{
5837e73b
DW
1087 struct xfs_mount *mp = cur->bc_mp;
1088 struct xfs_rmap_irec r[4]; /* neighbor extent entries */
1089 /* left is 0, right is 1, */
1090 /* prev is 2, new is 3 */
7faf209c
DW
1091 uint64_t owner;
1092 uint64_t offset;
1093 uint64_t new_endoff;
1094 unsigned int oldext;
1095 unsigned int newext;
1096 unsigned int flags = 0;
1097 int i;
1098 int state = 0;
1099 int error;
1100
1101 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1102 ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1103 (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1104 oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1105 new_endoff = offset + len;
a0577dbb 1106 trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
7faf209c
DW
1107 unwritten, oinfo);
1108
1109 /*
1110 * For the initial lookup, look for an exact match or the left-adjacent
1111 * record for our insertion point. This will also give us the record for
1112 * start block contiguity tests.
1113 */
4a195282 1114 error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, &PREV, &i);
7faf209c
DW
1115 if (error)
1116 goto done;
fbb4fa7f
DW
1117 if (XFS_IS_CORRUPT(mp, i != 1)) {
1118 error = -EFSCORRUPTED;
1119 goto done;
1120 }
7faf209c 1121
7faf209c 1122 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
a0577dbb 1123 cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
7faf209c
DW
1124 PREV.rm_blockcount, PREV.rm_owner,
1125 PREV.rm_offset, PREV.rm_flags);
1126
1127 ASSERT(PREV.rm_offset <= offset);
1128 ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1129 ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1130 newext = ~oldext & XFS_RMAP_UNWRITTEN;
1131
1132 /*
1133 * Set flags determining what part of the previous oldext allocation
1134 * extent is being replaced by a newext allocation.
1135 */
1136 if (PREV.rm_offset == offset)
1137 state |= RMAP_LEFT_FILLING;
1138 if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1139 state |= RMAP_RIGHT_FILLING;
1140
1141 /*
1142 * Decrement the cursor to see if we have a left-adjacent record to our
1143 * insertion point. This will give us the record for end block
1144 * contiguity tests.
1145 */
1146 error = xfs_btree_decrement(cur, 0, &i);
1147 if (error)
1148 goto done;
1149 if (i) {
1150 state |= RMAP_LEFT_VALID;
1151 error = xfs_rmap_get_rec(cur, &LEFT, &i);
1152 if (error)
1153 goto done;
fbb4fa7f
DW
1154 if (XFS_IS_CORRUPT(mp, i != 1)) {
1155 error = -EFSCORRUPTED;
1156 goto done;
1157 }
1158 if (XFS_IS_CORRUPT(mp,
1159 LEFT.rm_startblock + LEFT.rm_blockcount >
1160 bno)) {
1161 error = -EFSCORRUPTED;
1162 goto done;
1163 }
7faf209c 1164 trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
a0577dbb 1165 cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
7faf209c
DW
1166 LEFT.rm_blockcount, LEFT.rm_owner,
1167 LEFT.rm_offset, LEFT.rm_flags);
1168 if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
1169 LEFT.rm_offset + LEFT.rm_blockcount == offset &&
1170 xfs_rmap_is_mergeable(&LEFT, owner, newext))
1171 state |= RMAP_LEFT_CONTIG;
1172 }
1173
1174 /*
1175 * Increment the cursor to see if we have a right-adjacent record to our
1176 * insertion point. This will give us the record for end block
1177 * contiguity tests.
1178 */
1179 error = xfs_btree_increment(cur, 0, &i);
1180 if (error)
1181 goto done;
fbb4fa7f
DW
1182 if (XFS_IS_CORRUPT(mp, i != 1)) {
1183 error = -EFSCORRUPTED;
1184 goto done;
1185 }
7faf209c
DW
1186 error = xfs_btree_increment(cur, 0, &i);
1187 if (error)
1188 goto done;
1189 if (i) {
1190 state |= RMAP_RIGHT_VALID;
1191 error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1192 if (error)
1193 goto done;
fbb4fa7f
DW
1194 if (XFS_IS_CORRUPT(mp, i != 1)) {
1195 error = -EFSCORRUPTED;
1196 goto done;
1197 }
1198 if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1199 error = -EFSCORRUPTED;
1200 goto done;
1201 }
7faf209c 1202 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
a0577dbb 1203 cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
7faf209c
DW
1204 RIGHT.rm_blockcount, RIGHT.rm_owner,
1205 RIGHT.rm_offset, RIGHT.rm_flags);
1206 if (bno + len == RIGHT.rm_startblock &&
1207 offset + len == RIGHT.rm_offset &&
1208 xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1209 state |= RMAP_RIGHT_CONTIG;
1210 }
1211
1212 /* check that left + prev + right is not too long */
1213 if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1214 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1215 (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1216 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1217 (unsigned long)LEFT.rm_blockcount + len +
1218 RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1219 state &= ~RMAP_RIGHT_CONTIG;
1220
a0577dbb 1221 trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
7faf209c
DW
1222 _RET_IP_);
1223
1224 /* reset the cursor back to PREV */
4a195282 1225 error = xfs_rmap_lookup_le(cur, bno, owner, offset, oldext, NULL, &i);
7faf209c
DW
1226 if (error)
1227 goto done;
fbb4fa7f
DW
1228 if (XFS_IS_CORRUPT(mp, i != 1)) {
1229 error = -EFSCORRUPTED;
1230 goto done;
1231 }
7faf209c
DW
1232
1233 /*
1234 * Switch out based on the FILLING and CONTIG state bits.
1235 */
1236 switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1237 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1238 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1239 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1240 /*
1241 * Setting all of a previous oldext extent to newext.
1242 * The left and right neighbors are both contiguous with new.
1243 */
1244 error = xfs_btree_increment(cur, 0, &i);
1245 if (error)
1246 goto done;
fbb4fa7f
DW
1247 if (XFS_IS_CORRUPT(mp, i != 1)) {
1248 error = -EFSCORRUPTED;
1249 goto done;
1250 }
a0577dbb 1251 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
7faf209c
DW
1252 RIGHT.rm_startblock, RIGHT.rm_blockcount,
1253 RIGHT.rm_owner, RIGHT.rm_offset,
1254 RIGHT.rm_flags);
1255 error = xfs_btree_delete(cur, &i);
1256 if (error)
1257 goto done;
fbb4fa7f
DW
1258 if (XFS_IS_CORRUPT(mp, i != 1)) {
1259 error = -EFSCORRUPTED;
1260 goto done;
1261 }
7faf209c
DW
1262 error = xfs_btree_decrement(cur, 0, &i);
1263 if (error)
1264 goto done;
fbb4fa7f
DW
1265 if (XFS_IS_CORRUPT(mp, i != 1)) {
1266 error = -EFSCORRUPTED;
1267 goto done;
1268 }
a0577dbb 1269 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
7faf209c
DW
1270 PREV.rm_startblock, PREV.rm_blockcount,
1271 PREV.rm_owner, PREV.rm_offset,
1272 PREV.rm_flags);
1273 error = xfs_btree_delete(cur, &i);
1274 if (error)
1275 goto done;
fbb4fa7f
DW
1276 if (XFS_IS_CORRUPT(mp, i != 1)) {
1277 error = -EFSCORRUPTED;
1278 goto done;
1279 }
7faf209c
DW
1280 error = xfs_btree_decrement(cur, 0, &i);
1281 if (error)
1282 goto done;
fbb4fa7f
DW
1283 if (XFS_IS_CORRUPT(mp, i != 1)) {
1284 error = -EFSCORRUPTED;
1285 goto done;
1286 }
7faf209c
DW
1287 NEW = LEFT;
1288 NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1289 error = xfs_rmap_update(cur, &NEW);
1290 if (error)
1291 goto done;
1292 break;
1293
1294 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1295 /*
1296 * Setting all of a previous oldext extent to newext.
1297 * The left neighbor is contiguous, the right is not.
1298 */
a0577dbb 1299 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
7faf209c
DW
1300 PREV.rm_startblock, PREV.rm_blockcount,
1301 PREV.rm_owner, PREV.rm_offset,
1302 PREV.rm_flags);
1303 error = xfs_btree_delete(cur, &i);
1304 if (error)
1305 goto done;
fbb4fa7f
DW
1306 if (XFS_IS_CORRUPT(mp, i != 1)) {
1307 error = -EFSCORRUPTED;
1308 goto done;
1309 }
7faf209c
DW
1310 error = xfs_btree_decrement(cur, 0, &i);
1311 if (error)
1312 goto done;
fbb4fa7f
DW
1313 if (XFS_IS_CORRUPT(mp, i != 1)) {
1314 error = -EFSCORRUPTED;
1315 goto done;
1316 }
7faf209c
DW
1317 NEW = LEFT;
1318 NEW.rm_blockcount += PREV.rm_blockcount;
1319 error = xfs_rmap_update(cur, &NEW);
1320 if (error)
1321 goto done;
1322 break;
1323
1324 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1325 /*
1326 * Setting all of a previous oldext extent to newext.
1327 * The right neighbor is contiguous, the left is not.
1328 */
1329 error = xfs_btree_increment(cur, 0, &i);
1330 if (error)
1331 goto done;
fbb4fa7f
DW
1332 if (XFS_IS_CORRUPT(mp, i != 1)) {
1333 error = -EFSCORRUPTED;
1334 goto done;
1335 }
a0577dbb 1336 trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
7faf209c
DW
1337 RIGHT.rm_startblock, RIGHT.rm_blockcount,
1338 RIGHT.rm_owner, RIGHT.rm_offset,
1339 RIGHT.rm_flags);
1340 error = xfs_btree_delete(cur, &i);
1341 if (error)
1342 goto done;
fbb4fa7f
DW
1343 if (XFS_IS_CORRUPT(mp, i != 1)) {
1344 error = -EFSCORRUPTED;
1345 goto done;
1346 }
7faf209c
DW
1347 error = xfs_btree_decrement(cur, 0, &i);
1348 if (error)
1349 goto done;
fbb4fa7f
DW
1350 if (XFS_IS_CORRUPT(mp, i != 1)) {
1351 error = -EFSCORRUPTED;
1352 goto done;
1353 }
7faf209c
DW
1354 NEW = PREV;
1355 NEW.rm_blockcount = len + RIGHT.rm_blockcount;
1356 NEW.rm_flags = newext;
1357 error = xfs_rmap_update(cur, &NEW);
1358 if (error)
1359 goto done;
1360 break;
1361
1362 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1363 /*
1364 * Setting all of a previous oldext extent to newext.
1365 * Neither the left nor right neighbors are contiguous with
1366 * the new one.
1367 */
1368 NEW = PREV;
1369 NEW.rm_flags = newext;
1370 error = xfs_rmap_update(cur, &NEW);
1371 if (error)
1372 goto done;
1373 break;
1374
1375 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1376 /*
1377 * Setting the first part of a previous oldext extent to newext.
1378 * The left neighbor is contiguous.
1379 */
1380 NEW = PREV;
1381 NEW.rm_offset += len;
1382 NEW.rm_startblock += len;
1383 NEW.rm_blockcount -= len;
1384 error = xfs_rmap_update(cur, &NEW);
1385 if (error)
1386 goto done;
1387 error = xfs_btree_decrement(cur, 0, &i);
1388 if (error)
1389 goto done;
1390 NEW = LEFT;
1391 NEW.rm_blockcount += len;
1392 error = xfs_rmap_update(cur, &NEW);
1393 if (error)
1394 goto done;
1395 break;
1396
1397 case RMAP_LEFT_FILLING:
1398 /*
1399 * Setting the first part of a previous oldext extent to newext.
1400 * The left neighbor is not contiguous.
1401 */
1402 NEW = PREV;
1403 NEW.rm_startblock += len;
1404 NEW.rm_offset += len;
1405 NEW.rm_blockcount -= len;
1406 error = xfs_rmap_update(cur, &NEW);
1407 if (error)
1408 goto done;
1409 NEW.rm_startblock = bno;
1410 NEW.rm_owner = owner;
1411 NEW.rm_offset = offset;
1412 NEW.rm_blockcount = len;
1413 NEW.rm_flags = newext;
1414 cur->bc_rec.r = NEW;
a0577dbb 1415 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
7faf209c
DW
1416 len, owner, offset, newext);
1417 error = xfs_btree_insert(cur, &i);
1418 if (error)
1419 goto done;
fbb4fa7f
DW
1420 if (XFS_IS_CORRUPT(mp, i != 1)) {
1421 error = -EFSCORRUPTED;
1422 goto done;
1423 }
7faf209c
DW
1424 break;
1425
1426 case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1427 /*
1428 * Setting the last part of a previous oldext extent to newext.
1429 * The right neighbor is contiguous with the new allocation.
1430 */
1431 NEW = PREV;
1432 NEW.rm_blockcount -= len;
1433 error = xfs_rmap_update(cur, &NEW);
1434 if (error)
1435 goto done;
1436 error = xfs_btree_increment(cur, 0, &i);
1437 if (error)
1438 goto done;
1439 NEW = RIGHT;
1440 NEW.rm_offset = offset;
1441 NEW.rm_startblock = bno;
1442 NEW.rm_blockcount += len;
1443 error = xfs_rmap_update(cur, &NEW);
1444 if (error)
1445 goto done;
1446 break;
1447
1448 case RMAP_RIGHT_FILLING:
1449 /*
1450 * Setting the last part of a previous oldext extent to newext.
1451 * The right neighbor is not contiguous.
1452 */
1453 NEW = PREV;
1454 NEW.rm_blockcount -= len;
1455 error = xfs_rmap_update(cur, &NEW);
1456 if (error)
1457 goto done;
1458 error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1459 oldext, &i);
1460 if (error)
1461 goto done;
fbb4fa7f
DW
1462 if (XFS_IS_CORRUPT(mp, i != 0)) {
1463 error = -EFSCORRUPTED;
1464 goto done;
1465 }
7faf209c
DW
1466 NEW.rm_startblock = bno;
1467 NEW.rm_owner = owner;
1468 NEW.rm_offset = offset;
1469 NEW.rm_blockcount = len;
1470 NEW.rm_flags = newext;
1471 cur->bc_rec.r = NEW;
a0577dbb 1472 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
7faf209c
DW
1473 len, owner, offset, newext);
1474 error = xfs_btree_insert(cur, &i);
1475 if (error)
1476 goto done;
fbb4fa7f
DW
1477 if (XFS_IS_CORRUPT(mp, i != 1)) {
1478 error = -EFSCORRUPTED;
1479 goto done;
1480 }
7faf209c
DW
1481 break;
1482
1483 case 0:
1484 /*
1485 * Setting the middle part of a previous oldext extent to
1486 * newext. Contiguity is impossible here.
1487 * One extent becomes three extents.
1488 */
1489 /* new right extent - oldext */
1490 NEW.rm_startblock = bno + len;
1491 NEW.rm_owner = owner;
1492 NEW.rm_offset = new_endoff;
1493 NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1494 new_endoff;
1495 NEW.rm_flags = PREV.rm_flags;
1496 error = xfs_rmap_update(cur, &NEW);
1497 if (error)
1498 goto done;
1499 /* new left extent - oldext */
1500 NEW = PREV;
1501 NEW.rm_blockcount = offset - PREV.rm_offset;
1502 cur->bc_rec.r = NEW;
a0577dbb 1503 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
7faf209c
DW
1504 NEW.rm_startblock, NEW.rm_blockcount,
1505 NEW.rm_owner, NEW.rm_offset,
1506 NEW.rm_flags);
1507 error = xfs_btree_insert(cur, &i);
1508 if (error)
1509 goto done;
fbb4fa7f
DW
1510 if (XFS_IS_CORRUPT(mp, i != 1)) {
1511 error = -EFSCORRUPTED;
1512 goto done;
1513 }
7faf209c
DW
1514 /*
1515 * Reset the cursor to the position of the new extent
1516 * we are about to insert as we can't trust it after
1517 * the previous insert.
1518 */
1519 error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1520 oldext, &i);
1521 if (error)
1522 goto done;
fbb4fa7f
DW
1523 if (XFS_IS_CORRUPT(mp, i != 0)) {
1524 error = -EFSCORRUPTED;
1525 goto done;
1526 }
7faf209c
DW
1527 /* new middle extent - newext */
1528 cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
1529 cur->bc_rec.r.rm_flags |= newext;
a0577dbb 1530 trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
7faf209c
DW
1531 owner, offset, newext);
1532 error = xfs_btree_insert(cur, &i);
1533 if (error)
1534 goto done;
fbb4fa7f
DW
1535 if (XFS_IS_CORRUPT(mp, i != 1)) {
1536 error = -EFSCORRUPTED;
1537 goto done;
1538 }
7faf209c
DW
1539 break;
1540
1541 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1542 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1543 case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1544 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1545 case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1546 case RMAP_LEFT_CONTIG:
1547 case RMAP_RIGHT_CONTIG:
1548 /*
1549 * These cases are all impossible.
1550 */
1551 ASSERT(0);
1552 }
1553
a0577dbb 1554 trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
7faf209c
DW
1555 unwritten, oinfo);
1556done:
1557 if (error)
1558 trace_xfs_rmap_convert_error(cur->bc_mp,
a0577dbb 1559 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
7faf209c
DW
1560 return error;
1561}
1562
9c7bc093
DW
1563/*
1564 * Convert an unwritten extent to a real extent or vice versa. If there is no
1565 * possibility of overlapping extents, delegate to the simpler convert
1566 * function.
1567 */
1568STATIC int
1569xfs_rmap_convert_shared(
5837e73b
DW
1570 struct xfs_btree_cur *cur,
1571 xfs_agblock_t bno,
1572 xfs_extlen_t len,
1573 bool unwritten,
1574 const struct xfs_owner_info *oinfo)
9c7bc093 1575{
5837e73b
DW
1576 struct xfs_mount *mp = cur->bc_mp;
1577 struct xfs_rmap_irec r[4]; /* neighbor extent entries */
1578 /* left is 0, right is 1, */
1579 /* prev is 2, new is 3 */
9c7bc093
DW
1580 uint64_t owner;
1581 uint64_t offset;
1582 uint64_t new_endoff;
1583 unsigned int oldext;
1584 unsigned int newext;
1585 unsigned int flags = 0;
1586 int i;
1587 int state = 0;
1588 int error;
1589
1590 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1591 ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
1592 (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
1593 oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
1594 new_endoff = offset + len;
a0577dbb 1595 trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
9c7bc093
DW
1596 unwritten, oinfo);
1597
1598 /*
1599 * For the initial lookup, look for and exact match or the left-adjacent
1600 * record for our insertion point. This will also give us the record for
1601 * start block contiguity tests.
1602 */
4d1b7499 1603 error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, oldext,
9c7bc093 1604 &PREV, &i);
cfa7d896
DW
1605 if (error)
1606 goto done;
fbb4fa7f
DW
1607 if (XFS_IS_CORRUPT(mp, i != 1)) {
1608 error = -EFSCORRUPTED;
1609 goto done;
1610 }
9c7bc093
DW
1611
1612 ASSERT(PREV.rm_offset <= offset);
1613 ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
1614 ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
1615 newext = ~oldext & XFS_RMAP_UNWRITTEN;
1616
1617 /*
1618 * Set flags determining what part of the previous oldext allocation
1619 * extent is being replaced by a newext allocation.
1620 */
1621 if (PREV.rm_offset == offset)
1622 state |= RMAP_LEFT_FILLING;
1623 if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
1624 state |= RMAP_RIGHT_FILLING;
1625
1626 /* Is there a left record that abuts our range? */
1627 error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext,
1628 &LEFT, &i);
1629 if (error)
1630 goto done;
1631 if (i) {
1632 state |= RMAP_LEFT_VALID;
fbb4fa7f
DW
1633 if (XFS_IS_CORRUPT(mp,
1634 LEFT.rm_startblock + LEFT.rm_blockcount >
1635 bno)) {
1636 error = -EFSCORRUPTED;
1637 goto done;
1638 }
9c7bc093
DW
1639 if (xfs_rmap_is_mergeable(&LEFT, owner, newext))
1640 state |= RMAP_LEFT_CONTIG;
1641 }
1642
1643 /* Is there a right record that abuts our range? */
1644 error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
1645 newext, &i);
1646 if (error)
1647 goto done;
1648 if (i) {
1649 state |= RMAP_RIGHT_VALID;
1650 error = xfs_rmap_get_rec(cur, &RIGHT, &i);
1651 if (error)
1652 goto done;
fbb4fa7f
DW
1653 if (XFS_IS_CORRUPT(mp, i != 1)) {
1654 error = -EFSCORRUPTED;
1655 goto done;
1656 }
1657 if (XFS_IS_CORRUPT(mp, bno + len > RIGHT.rm_startblock)) {
1658 error = -EFSCORRUPTED;
1659 goto done;
1660 }
9c7bc093 1661 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
a0577dbb 1662 cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
9c7bc093
DW
1663 RIGHT.rm_blockcount, RIGHT.rm_owner,
1664 RIGHT.rm_offset, RIGHT.rm_flags);
1665 if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
1666 state |= RMAP_RIGHT_CONTIG;
1667 }
1668
1669 /* check that left + prev + right is not too long */
1670 if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1671 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
1672 (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1673 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
1674 (unsigned long)LEFT.rm_blockcount + len +
1675 RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
1676 state &= ~RMAP_RIGHT_CONTIG;
1677
a0577dbb 1678 trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
9c7bc093
DW
1679 _RET_IP_);
1680 /*
1681 * Switch out based on the FILLING and CONTIG state bits.
1682 */
1683 switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1684 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
1685 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
1686 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1687 /*
1688 * Setting all of a previous oldext extent to newext.
1689 * The left and right neighbors are both contiguous with new.
1690 */
1691 error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
1692 RIGHT.rm_blockcount, RIGHT.rm_owner,
1693 RIGHT.rm_offset, RIGHT.rm_flags);
1694 if (error)
1695 goto done;
1696 error = xfs_rmap_delete(cur, PREV.rm_startblock,
1697 PREV.rm_blockcount, PREV.rm_owner,
1698 PREV.rm_offset, PREV.rm_flags);
1699 if (error)
1700 goto done;
1701 NEW = LEFT;
1702 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1703 NEW.rm_blockcount, NEW.rm_owner,
1704 NEW.rm_offset, NEW.rm_flags, &i);
1705 if (error)
1706 goto done;
fbb4fa7f
DW
1707 if (XFS_IS_CORRUPT(mp, i != 1)) {
1708 error = -EFSCORRUPTED;
1709 goto done;
1710 }
9c7bc093
DW
1711 NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
1712 error = xfs_rmap_update(cur, &NEW);
1713 if (error)
1714 goto done;
1715 break;
1716
1717 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1718 /*
1719 * Setting all of a previous oldext extent to newext.
1720 * The left neighbor is contiguous, the right is not.
1721 */
1722 error = xfs_rmap_delete(cur, PREV.rm_startblock,
1723 PREV.rm_blockcount, PREV.rm_owner,
1724 PREV.rm_offset, PREV.rm_flags);
1725 if (error)
1726 goto done;
1727 NEW = LEFT;
1728 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1729 NEW.rm_blockcount, NEW.rm_owner,
1730 NEW.rm_offset, NEW.rm_flags, &i);
1731 if (error)
1732 goto done;
fbb4fa7f
DW
1733 if (XFS_IS_CORRUPT(mp, i != 1)) {
1734 error = -EFSCORRUPTED;
1735 goto done;
1736 }
9c7bc093
DW
1737 NEW.rm_blockcount += PREV.rm_blockcount;
1738 error = xfs_rmap_update(cur, &NEW);
1739 if (error)
1740 goto done;
1741 break;
1742
1743 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1744 /*
1745 * Setting all of a previous oldext extent to newext.
1746 * The right neighbor is contiguous, the left is not.
1747 */
1748 error = xfs_rmap_delete(cur, RIGHT.rm_startblock,
1749 RIGHT.rm_blockcount, RIGHT.rm_owner,
1750 RIGHT.rm_offset, RIGHT.rm_flags);
1751 if (error)
1752 goto done;
1753 NEW = PREV;
1754 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1755 NEW.rm_blockcount, NEW.rm_owner,
1756 NEW.rm_offset, NEW.rm_flags, &i);
1757 if (error)
1758 goto done;
fbb4fa7f
DW
1759 if (XFS_IS_CORRUPT(mp, i != 1)) {
1760 error = -EFSCORRUPTED;
1761 goto done;
1762 }
9c7bc093
DW
1763 NEW.rm_blockcount += RIGHT.rm_blockcount;
1764 NEW.rm_flags = RIGHT.rm_flags;
1765 error = xfs_rmap_update(cur, &NEW);
1766 if (error)
1767 goto done;
1768 break;
1769
1770 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
1771 /*
1772 * Setting all of a previous oldext extent to newext.
1773 * Neither the left nor right neighbors are contiguous with
1774 * the new one.
1775 */
1776 NEW = PREV;
1777 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1778 NEW.rm_blockcount, NEW.rm_owner,
1779 NEW.rm_offset, NEW.rm_flags, &i);
1780 if (error)
1781 goto done;
fbb4fa7f
DW
1782 if (XFS_IS_CORRUPT(mp, i != 1)) {
1783 error = -EFSCORRUPTED;
1784 goto done;
1785 }
9c7bc093
DW
1786 NEW.rm_flags = newext;
1787 error = xfs_rmap_update(cur, &NEW);
1788 if (error)
1789 goto done;
1790 break;
1791
1792 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
1793 /*
1794 * Setting the first part of a previous oldext extent to newext.
1795 * The left neighbor is contiguous.
1796 */
1797 NEW = PREV;
1798 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1799 NEW.rm_blockcount, NEW.rm_owner,
1800 NEW.rm_offset, NEW.rm_flags);
1801 if (error)
1802 goto done;
1803 NEW.rm_offset += len;
1804 NEW.rm_startblock += len;
1805 NEW.rm_blockcount -= len;
1806 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1807 NEW.rm_blockcount, NEW.rm_owner,
1808 NEW.rm_offset, NEW.rm_flags);
1809 if (error)
1810 goto done;
1811 NEW = LEFT;
1812 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1813 NEW.rm_blockcount, NEW.rm_owner,
1814 NEW.rm_offset, NEW.rm_flags, &i);
1815 if (error)
1816 goto done;
fbb4fa7f
DW
1817 if (XFS_IS_CORRUPT(mp, i != 1)) {
1818 error = -EFSCORRUPTED;
1819 goto done;
1820 }
9c7bc093
DW
1821 NEW.rm_blockcount += len;
1822 error = xfs_rmap_update(cur, &NEW);
1823 if (error)
1824 goto done;
1825 break;
1826
1827 case RMAP_LEFT_FILLING:
1828 /*
1829 * Setting the first part of a previous oldext extent to newext.
1830 * The left neighbor is not contiguous.
1831 */
1832 NEW = PREV;
1833 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1834 NEW.rm_blockcount, NEW.rm_owner,
1835 NEW.rm_offset, NEW.rm_flags);
1836 if (error)
1837 goto done;
1838 NEW.rm_offset += len;
1839 NEW.rm_startblock += len;
1840 NEW.rm_blockcount -= len;
1841 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1842 NEW.rm_blockcount, NEW.rm_owner,
1843 NEW.rm_offset, NEW.rm_flags);
1844 if (error)
1845 goto done;
1846 error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
1847 if (error)
1848 goto done;
1849 break;
1850
1851 case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
1852 /*
1853 * Setting the last part of a previous oldext extent to newext.
1854 * The right neighbor is contiguous with the new allocation.
1855 */
1856 NEW = PREV;
1857 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1858 NEW.rm_blockcount, NEW.rm_owner,
1859 NEW.rm_offset, NEW.rm_flags, &i);
1860 if (error)
1861 goto done;
fbb4fa7f
DW
1862 if (XFS_IS_CORRUPT(mp, i != 1)) {
1863 error = -EFSCORRUPTED;
1864 goto done;
1865 }
9c7bc093
DW
1866 NEW.rm_blockcount = offset - NEW.rm_offset;
1867 error = xfs_rmap_update(cur, &NEW);
1868 if (error)
1869 goto done;
1870 NEW = RIGHT;
1871 error = xfs_rmap_delete(cur, NEW.rm_startblock,
1872 NEW.rm_blockcount, NEW.rm_owner,
1873 NEW.rm_offset, NEW.rm_flags);
1874 if (error)
1875 goto done;
1876 NEW.rm_offset = offset;
1877 NEW.rm_startblock = bno;
1878 NEW.rm_blockcount += len;
1879 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1880 NEW.rm_blockcount, NEW.rm_owner,
1881 NEW.rm_offset, NEW.rm_flags);
1882 if (error)
1883 goto done;
1884 break;
1885
1886 case RMAP_RIGHT_FILLING:
1887 /*
1888 * Setting the last part of a previous oldext extent to newext.
1889 * The right neighbor is not contiguous.
1890 */
1891 NEW = PREV;
1892 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1893 NEW.rm_blockcount, NEW.rm_owner,
1894 NEW.rm_offset, NEW.rm_flags, &i);
1895 if (error)
1896 goto done;
fbb4fa7f
DW
1897 if (XFS_IS_CORRUPT(mp, i != 1)) {
1898 error = -EFSCORRUPTED;
1899 goto done;
1900 }
9c7bc093
DW
1901 NEW.rm_blockcount -= len;
1902 error = xfs_rmap_update(cur, &NEW);
1903 if (error)
1904 goto done;
1905 error = xfs_rmap_insert(cur, bno, len, owner, offset, newext);
1906 if (error)
1907 goto done;
1908 break;
1909
1910 case 0:
1911 /*
1912 * Setting the middle part of a previous oldext extent to
1913 * newext. Contiguity is impossible here.
1914 * One extent becomes three extents.
1915 */
1916 /* new right extent - oldext */
1917 NEW.rm_startblock = bno + len;
1918 NEW.rm_owner = owner;
1919 NEW.rm_offset = new_endoff;
1920 NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1921 new_endoff;
1922 NEW.rm_flags = PREV.rm_flags;
1923 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1924 NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
1925 NEW.rm_flags);
1926 if (error)
1927 goto done;
1928 /* new left extent - oldext */
1929 NEW = PREV;
1930 error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock,
1931 NEW.rm_blockcount, NEW.rm_owner,
1932 NEW.rm_offset, NEW.rm_flags, &i);
1933 if (error)
1934 goto done;
fbb4fa7f
DW
1935 if (XFS_IS_CORRUPT(mp, i != 1)) {
1936 error = -EFSCORRUPTED;
1937 goto done;
1938 }
9c7bc093
DW
1939 NEW.rm_blockcount = offset - NEW.rm_offset;
1940 error = xfs_rmap_update(cur, &NEW);
1941 if (error)
1942 goto done;
1943 /* new middle extent - newext */
1944 NEW.rm_startblock = bno;
1945 NEW.rm_blockcount = len;
1946 NEW.rm_owner = owner;
1947 NEW.rm_offset = offset;
1948 NEW.rm_flags = newext;
1949 error = xfs_rmap_insert(cur, NEW.rm_startblock,
1950 NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset,
1951 NEW.rm_flags);
1952 if (error)
1953 goto done;
1954 break;
1955
1956 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1957 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1958 case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1959 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1960 case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1961 case RMAP_LEFT_CONTIG:
1962 case RMAP_RIGHT_CONTIG:
1963 /*
1964 * These cases are all impossible.
1965 */
1966 ASSERT(0);
1967 }
1968
a0577dbb 1969 trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
9c7bc093
DW
1970 unwritten, oinfo);
1971done:
1972 if (error)
1973 trace_xfs_rmap_convert_error(cur->bc_mp,
a0577dbb 1974 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
9c7bc093
DW
1975 return error;
1976}
1977
7faf209c
DW
1978#undef NEW
1979#undef LEFT
1980#undef RIGHT
1981#undef PREV
1982
6c6bdf6f
DW
1983/*
1984 * Find an extent in the rmap btree and unmap it. For rmap extent types that
1985 * can overlap (data fork rmaps on reflink filesystems) we must be careful
1986 * that the prev/next records in the btree might belong to another owner.
1987 * Therefore we must use delete+insert to alter any of the key fields.
1988 *
1989 * For every other situation there can only be one owner for a given extent,
1990 * so we can call the regular _free function.
1991 */
1992STATIC int
1993xfs_rmap_unmap_shared(
5837e73b
DW
1994 struct xfs_btree_cur *cur,
1995 xfs_agblock_t bno,
1996 xfs_extlen_t len,
1997 bool unwritten,
1998 const struct xfs_owner_info *oinfo)
6c6bdf6f 1999{
5837e73b
DW
2000 struct xfs_mount *mp = cur->bc_mp;
2001 struct xfs_rmap_irec ltrec;
2002 uint64_t ltoff;
2003 int error = 0;
2004 int i;
2005 uint64_t owner;
2006 uint64_t offset;
2007 unsigned int flags;
6c6bdf6f
DW
2008
2009 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2010 if (unwritten)
2011 flags |= XFS_RMAP_UNWRITTEN;
a0577dbb 2012 trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
6c6bdf6f
DW
2013 unwritten, oinfo);
2014
2015 /*
2016 * We should always have a left record because there's a static record
2017 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
2018 * will not ever be removed from the tree.
2019 */
2020 error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
2021 &ltrec, &i);
2022 if (error)
2023 goto out_error;
fbb4fa7f
DW
2024 if (XFS_IS_CORRUPT(mp, i != 1)) {
2025 error = -EFSCORRUPTED;
2026 goto out_error;
2027 }
6c6bdf6f
DW
2028 ltoff = ltrec.rm_offset;
2029
2030 /* Make sure the extent we found covers the entire freeing range. */
fbb4fa7f
DW
2031 if (XFS_IS_CORRUPT(mp,
2032 ltrec.rm_startblock > bno ||
2033 ltrec.rm_startblock + ltrec.rm_blockcount <
2034 bno + len)) {
2035 error = -EFSCORRUPTED;
2036 goto out_error;
2037 }
6c6bdf6f
DW
2038
2039 /* Make sure the owner matches what we expect to find in the tree. */
fbb4fa7f
DW
2040 if (XFS_IS_CORRUPT(mp, owner != ltrec.rm_owner)) {
2041 error = -EFSCORRUPTED;
2042 goto out_error;
2043 }
6c6bdf6f
DW
2044
2045 /* Make sure the unwritten flag matches. */
fbb4fa7f
DW
2046 if (XFS_IS_CORRUPT(mp,
2047 (flags & XFS_RMAP_UNWRITTEN) !=
2048 (ltrec.rm_flags & XFS_RMAP_UNWRITTEN))) {
2049 error = -EFSCORRUPTED;
2050 goto out_error;
2051 }
6c6bdf6f
DW
2052
2053 /* Check the offset. */
fbb4fa7f
DW
2054 if (XFS_IS_CORRUPT(mp, ltrec.rm_offset > offset)) {
2055 error = -EFSCORRUPTED;
2056 goto out_error;
2057 }
2058 if (XFS_IS_CORRUPT(mp, offset > ltoff + ltrec.rm_blockcount)) {
2059 error = -EFSCORRUPTED;
2060 goto out_error;
2061 }
6c6bdf6f
DW
2062
2063 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
2064 /* Exact match, simply remove the record from rmap tree. */
2065 error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2066 ltrec.rm_blockcount, ltrec.rm_owner,
2067 ltrec.rm_offset, ltrec.rm_flags);
2068 if (error)
2069 goto out_error;
2070 } else if (ltrec.rm_startblock == bno) {
2071 /*
2072 * Overlap left hand side of extent: move the start, trim the
2073 * length and update the current record.
2074 *
2075 * ltbno ltlen
2076 * Orig: |oooooooooooooooooooo|
2077 * Freeing: |fffffffff|
2078 * Result: |rrrrrrrrrr|
2079 * bno len
2080 */
2081
2082 /* Delete prev rmap. */
2083 error = xfs_rmap_delete(cur, ltrec.rm_startblock,
2084 ltrec.rm_blockcount, ltrec.rm_owner,
2085 ltrec.rm_offset, ltrec.rm_flags);
2086 if (error)
2087 goto out_error;
2088
2089 /* Add an rmap at the new offset. */
2090 ltrec.rm_startblock += len;
2091 ltrec.rm_blockcount -= len;
2092 ltrec.rm_offset += len;
2093 error = xfs_rmap_insert(cur, ltrec.rm_startblock,
2094 ltrec.rm_blockcount, ltrec.rm_owner,
2095 ltrec.rm_offset, ltrec.rm_flags);
2096 if (error)
2097 goto out_error;
2098 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
2099 /*
2100 * Overlap right hand side of extent: trim the length and
2101 * update the current record.
2102 *
2103 * ltbno ltlen
2104 * Orig: |oooooooooooooooooooo|
2105 * Freeing: |fffffffff|
2106 * Result: |rrrrrrrrrr|
2107 * bno len
2108 */
2109 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2110 ltrec.rm_blockcount, ltrec.rm_owner,
2111 ltrec.rm_offset, ltrec.rm_flags, &i);
2112 if (error)
2113 goto out_error;
fbb4fa7f
DW
2114 if (XFS_IS_CORRUPT(mp, i != 1)) {
2115 error = -EFSCORRUPTED;
2116 goto out_error;
2117 }
6c6bdf6f
DW
2118 ltrec.rm_blockcount -= len;
2119 error = xfs_rmap_update(cur, &ltrec);
2120 if (error)
2121 goto out_error;
2122 } else {
2123 /*
2124 * Overlap middle of extent: trim the length of the existing
2125 * record to the length of the new left-extent size, increment
2126 * the insertion position so we can insert a new record
2127 * containing the remaining right-extent space.
2128 *
2129 * ltbno ltlen
2130 * Orig: |oooooooooooooooooooo|
2131 * Freeing: |fffffffff|
2132 * Result: |rrrrr| |rrrr|
2133 * bno len
2134 */
2135 xfs_extlen_t orig_len = ltrec.rm_blockcount;
2136
2137 /* Shrink the left side of the rmap */
2138 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2139 ltrec.rm_blockcount, ltrec.rm_owner,
2140 ltrec.rm_offset, ltrec.rm_flags, &i);
2141 if (error)
2142 goto out_error;
fbb4fa7f
DW
2143 if (XFS_IS_CORRUPT(mp, i != 1)) {
2144 error = -EFSCORRUPTED;
2145 goto out_error;
2146 }
6c6bdf6f
DW
2147 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
2148 error = xfs_rmap_update(cur, &ltrec);
2149 if (error)
2150 goto out_error;
2151
2152 /* Add an rmap at the new offset */
2153 error = xfs_rmap_insert(cur, bno + len,
2154 orig_len - len - ltrec.rm_blockcount,
2155 ltrec.rm_owner, offset + len,
2156 ltrec.rm_flags);
2157 if (error)
2158 goto out_error;
2159 }
2160
a0577dbb 2161 trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
6c6bdf6f
DW
2162 unwritten, oinfo);
2163out_error:
2164 if (error)
2165 trace_xfs_rmap_unmap_error(cur->bc_mp,
a0577dbb 2166 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
6c6bdf6f
DW
2167 return error;
2168}
2169
2170/*
2171 * Find an extent in the rmap btree and map it. For rmap extent types that
2172 * can overlap (data fork rmaps on reflink filesystems) we must be careful
2173 * that the prev/next records in the btree might belong to another owner.
2174 * Therefore we must use delete+insert to alter any of the key fields.
2175 *
2176 * For every other situation there can only be one owner for a given extent,
2177 * so we can call the regular _alloc function.
2178 */
2179STATIC int
2180xfs_rmap_map_shared(
5837e73b
DW
2181 struct xfs_btree_cur *cur,
2182 xfs_agblock_t bno,
2183 xfs_extlen_t len,
2184 bool unwritten,
2185 const struct xfs_owner_info *oinfo)
6c6bdf6f 2186{
5837e73b
DW
2187 struct xfs_mount *mp = cur->bc_mp;
2188 struct xfs_rmap_irec ltrec;
2189 struct xfs_rmap_irec gtrec;
2190 int have_gt;
2191 int have_lt;
2192 int error = 0;
2193 int i;
2194 uint64_t owner;
2195 uint64_t offset;
2196 unsigned int flags = 0;
6c6bdf6f
DW
2197
2198 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
2199 if (unwritten)
2200 flags |= XFS_RMAP_UNWRITTEN;
a0577dbb 2201 trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
6c6bdf6f
DW
2202 unwritten, oinfo);
2203
2204 /* Is there a left record that abuts our range? */
2205 error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
2206 &ltrec, &have_lt);
2207 if (error)
2208 goto out_error;
2209 if (have_lt &&
2210 !xfs_rmap_is_mergeable(&ltrec, owner, flags))
2211 have_lt = 0;
2212
2213 /* Is there a right record that abuts our range? */
2214 error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
2215 flags, &have_gt);
2216 if (error)
2217 goto out_error;
2218 if (have_gt) {
2219 error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
2220 if (error)
2221 goto out_error;
fbb4fa7f
DW
2222 if (XFS_IS_CORRUPT(mp, have_gt != 1)) {
2223 error = -EFSCORRUPTED;
2224 goto out_error;
2225 }
6c6bdf6f 2226 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
a0577dbb 2227 cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
6c6bdf6f
DW
2228 gtrec.rm_blockcount, gtrec.rm_owner,
2229 gtrec.rm_offset, gtrec.rm_flags);
2230
2231 if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
2232 have_gt = 0;
2233 }
2234
2235 if (have_lt &&
2236 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
2237 ltrec.rm_offset + ltrec.rm_blockcount == offset) {
2238 /*
2239 * Left edge contiguous, merge into left record.
2240 *
2241 * ltbno ltlen
2242 * orig: |ooooooooo|
2243 * adding: |aaaaaaaaa|
2244 * result: |rrrrrrrrrrrrrrrrrrr|
2245 * bno len
2246 */
2247 ltrec.rm_blockcount += len;
2248 if (have_gt &&
2249 bno + len == gtrec.rm_startblock &&
2250 offset + len == gtrec.rm_offset) {
2251 /*
2252 * Right edge also contiguous, delete right record
2253 * and merge into left record.
2254 *
2255 * ltbno ltlen gtbno gtlen
2256 * orig: |ooooooooo| |ooooooooo|
2257 * adding: |aaaaaaaaa|
2258 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
2259 */
2260 ltrec.rm_blockcount += gtrec.rm_blockcount;
2261 error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2262 gtrec.rm_blockcount, gtrec.rm_owner,
2263 gtrec.rm_offset, gtrec.rm_flags);
2264 if (error)
2265 goto out_error;
2266 }
2267
2268 /* Point the cursor back to the left record and update. */
2269 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
2270 ltrec.rm_blockcount, ltrec.rm_owner,
2271 ltrec.rm_offset, ltrec.rm_flags, &i);
2272 if (error)
2273 goto out_error;
fbb4fa7f
DW
2274 if (XFS_IS_CORRUPT(mp, i != 1)) {
2275 error = -EFSCORRUPTED;
2276 goto out_error;
2277 }
6c6bdf6f
DW
2278
2279 error = xfs_rmap_update(cur, &ltrec);
2280 if (error)
2281 goto out_error;
2282 } else if (have_gt &&
2283 bno + len == gtrec.rm_startblock &&
2284 offset + len == gtrec.rm_offset) {
2285 /*
2286 * Right edge contiguous, merge into right record.
2287 *
2288 * gtbno gtlen
2289 * Orig: |ooooooooo|
2290 * adding: |aaaaaaaaa|
2291 * Result: |rrrrrrrrrrrrrrrrrrr|
2292 * bno len
2293 */
2294 /* Delete the old record. */
2295 error = xfs_rmap_delete(cur, gtrec.rm_startblock,
2296 gtrec.rm_blockcount, gtrec.rm_owner,
2297 gtrec.rm_offset, gtrec.rm_flags);
2298 if (error)
2299 goto out_error;
2300
2301 /* Move the start and re-add it. */
2302 gtrec.rm_startblock = bno;
2303 gtrec.rm_blockcount += len;
2304 gtrec.rm_offset = offset;
2305 error = xfs_rmap_insert(cur, gtrec.rm_startblock,
2306 gtrec.rm_blockcount, gtrec.rm_owner,
2307 gtrec.rm_offset, gtrec.rm_flags);
2308 if (error)
2309 goto out_error;
2310 } else {
2311 /*
2312 * No contiguous edge with identical owner, insert
2313 * new record at current cursor position.
2314 */
2315 error = xfs_rmap_insert(cur, bno, len, owner, offset, flags);
2316 if (error)
2317 goto out_error;
2318 }
2319
a0577dbb 2320 trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
6c6bdf6f
DW
2321 unwritten, oinfo);
2322out_error:
2323 if (error)
2324 trace_xfs_rmap_map_error(cur->bc_mp,
a0577dbb 2325 cur->bc_ag.pag->pag_agno, error, _RET_IP_);
6c6bdf6f
DW
2326 return error;
2327}
2328
d264e392
DW
2329/* Insert a raw rmap into the rmapbt. */
2330int
2331xfs_rmap_map_raw(
2332 struct xfs_btree_cur *cur,
2333 struct xfs_rmap_irec *rmap)
2334{
2335 struct xfs_owner_info oinfo;
2336
2337 oinfo.oi_owner = rmap->rm_owner;
2338 oinfo.oi_offset = rmap->rm_offset;
2339 oinfo.oi_flags = 0;
2340 if (rmap->rm_flags & XFS_RMAP_ATTR_FORK)
2341 oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
2342 if (rmap->rm_flags & XFS_RMAP_BMBT_BLOCK)
2343 oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
2344
2345 if (rmap->rm_flags || XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
2346 return xfs_rmap_map(cur, rmap->rm_startblock,
2347 rmap->rm_blockcount,
2348 rmap->rm_flags & XFS_RMAP_UNWRITTEN,
2349 &oinfo);
2350
2351 return xfs_rmap_map_shared(cur, rmap->rm_startblock,
2352 rmap->rm_blockcount,
2353 rmap->rm_flags & XFS_RMAP_UNWRITTEN,
2354 &oinfo);
2355}
2356
890e1174
DW
2357struct xfs_rmap_query_range_info {
2358 xfs_rmap_query_range_fn fn;
2359 void *priv;
2360};
2361
2362/* Format btree record and pass to our callback. */
2363STATIC int
2364xfs_rmap_query_range_helper(
e62318a3
DW
2365 struct xfs_btree_cur *cur,
2366 const union xfs_btree_rec *rec,
2367 void *priv)
890e1174
DW
2368{
2369 struct xfs_rmap_query_range_info *query = priv;
2370 struct xfs_rmap_irec irec;
e70bf9ba 2371 xfs_failaddr_t fa;
890e1174 2372
e70bf9ba
DW
2373 fa = xfs_rmap_btrec_to_irec(rec, &irec);
2374 if (!fa)
2375 fa = xfs_rmap_check_irec(cur, &irec);
2376 if (fa)
2377 return xfs_rmap_complain_bad_rec(cur, fa, &irec);
8d444a7a 2378
890e1174
DW
2379 return query->fn(cur, &irec, query->priv);
2380}
2381
2382/* Find all rmaps between two keys. */
2383int
2384xfs_rmap_query_range(
7e05e856 2385 struct xfs_btree_cur *cur,
d34c6373
DW
2386 const struct xfs_rmap_irec *low_rec,
2387 const struct xfs_rmap_irec *high_rec,
7e05e856
DW
2388 xfs_rmap_query_range_fn fn,
2389 void *priv)
890e1174 2390{
05dcea07
DW
2391 union xfs_btree_irec low_brec = { .r = *low_rec };
2392 union xfs_btree_irec high_brec = { .r = *high_rec };
2393 struct xfs_rmap_query_range_info query = { .priv = priv, .fn = fn };
890e1174 2394
890e1174
DW
2395 return xfs_btree_query_range(cur, &low_brec, &high_brec,
2396 xfs_rmap_query_range_helper, &query);
2397}
d7f80320 2398
7e05e856
DW
2399/* Find all rmaps. */
2400int
2401xfs_rmap_query_all(
2402 struct xfs_btree_cur *cur,
2403 xfs_rmap_query_range_fn fn,
2404 void *priv)
2405{
2406 struct xfs_rmap_query_range_info query;
2407
2408 query.priv = priv;
2409 query.fn = fn;
2410 return xfs_btree_query_all(cur, xfs_rmap_query_range_helper, &query);
2411}
2412
d7f80320
DW
2413/* Clean up after calling xfs_rmap_finish_one. */
2414void
2415xfs_rmap_finish_one_cleanup(
2416 struct xfs_trans *tp,
2417 struct xfs_btree_cur *rcur,
2418 int error)
2419{
2420 struct xfs_buf *agbp;
2421
2422 if (rcur == NULL)
2423 return;
aa6fa37f 2424 agbp = rcur->bc_ag.agbp;
660265b7 2425 xfs_btree_del_cursor(rcur, error);
d7f80320
DW
2426 if (error)
2427 xfs_trans_brelse(tp, agbp);
2428}
2429
2430/*
2431 * Process one of the deferred rmap operations. We pass back the
2432 * btree cursor to maintain our lock on the rmapbt between calls.
2433 * This saves time and eliminates a buffer deadlock between the
2434 * superblock and the AGF because we'll always grab them in the same
2435 * order.
2436 */
2437int
2438xfs_rmap_finish_one(
2439 struct xfs_trans *tp,
74492d88 2440 struct xfs_rmap_intent *ri,
d7f80320
DW
2441 struct xfs_btree_cur **pcur)
2442{
2443 struct xfs_mount *mp = tp->t_mountp;
2444 struct xfs_btree_cur *rcur;
2445 struct xfs_buf *agbp = NULL;
2446 int error = 0;
d7f80320
DW
2447 struct xfs_owner_info oinfo;
2448 xfs_agblock_t bno;
2449 bool unwritten;
2450
74492d88 2451 bno = XFS_FSB_TO_AGBNO(mp, ri->ri_bmap.br_startblock);
d7f80320 2452
818f0c29 2453 trace_xfs_rmap_deferred(mp, ri->ri_pag->pag_agno, ri->ri_type, bno,
74492d88
DW
2454 ri->ri_owner, ri->ri_whichfork,
2455 ri->ri_bmap.br_startoff, ri->ri_bmap.br_blockcount,
2456 ri->ri_bmap.br_state);
d7f80320 2457
818f0c29
DW
2458 if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE))
2459 return -EIO;
d7f80320
DW
2460
2461 /*
2462 * If we haven't gotten a cursor or the cursor AG doesn't match
2463 * the startblock, get one now.
2464 */
2465 rcur = *pcur;
818f0c29 2466 if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) {
d7f80320
DW
2467 xfs_rmap_finish_one_cleanup(tp, rcur, 0);
2468 rcur = NULL;
2469 *pcur = NULL;
2470 }
2471 if (rcur == NULL) {
2472 /*
2473 * Refresh the freelist before we start changing the
2474 * rmapbt, because a shape change could cause us to
2475 * allocate blocks.
2476 */
818f0c29 2477 error = xfs_free_extent_fix_freelist(tp, ri->ri_pag, &agbp);
d7f80320 2478 if (error)
818f0c29
DW
2479 return error;
2480 if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
2481 return -EFSCORRUPTED;
d7f80320 2482
818f0c29 2483 rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, ri->ri_pag);
d7f80320
DW
2484 }
2485 *pcur = rcur;
2486
74492d88
DW
2487 xfs_rmap_ino_owner(&oinfo, ri->ri_owner, ri->ri_whichfork,
2488 ri->ri_bmap.br_startoff);
2489 unwritten = ri->ri_bmap.br_state == XFS_EXT_UNWRITTEN;
2490 bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, ri->ri_bmap.br_startblock);
d7f80320 2491
74492d88 2492 switch (ri->ri_type) {
d7f80320
DW
2493 case XFS_RMAP_ALLOC:
2494 case XFS_RMAP_MAP:
74492d88
DW
2495 error = xfs_rmap_map(rcur, bno, ri->ri_bmap.br_blockcount,
2496 unwritten, &oinfo);
d7f80320 2497 break;
6c6bdf6f 2498 case XFS_RMAP_MAP_SHARED:
74492d88
DW
2499 error = xfs_rmap_map_shared(rcur, bno,
2500 ri->ri_bmap.br_blockcount, unwritten, &oinfo);
6c6bdf6f 2501 break;
d7f80320
DW
2502 case XFS_RMAP_FREE:
2503 case XFS_RMAP_UNMAP:
74492d88
DW
2504 error = xfs_rmap_unmap(rcur, bno, ri->ri_bmap.br_blockcount,
2505 unwritten, &oinfo);
d7f80320 2506 break;
6c6bdf6f 2507 case XFS_RMAP_UNMAP_SHARED:
74492d88
DW
2508 error = xfs_rmap_unmap_shared(rcur, bno,
2509 ri->ri_bmap.br_blockcount, unwritten, &oinfo);
6c6bdf6f 2510 break;
d7f80320 2511 case XFS_RMAP_CONVERT:
74492d88
DW
2512 error = xfs_rmap_convert(rcur, bno, ri->ri_bmap.br_blockcount,
2513 !unwritten, &oinfo);
d7f80320 2514 break;
9c7bc093 2515 case XFS_RMAP_CONVERT_SHARED:
74492d88
DW
2516 error = xfs_rmap_convert_shared(rcur, bno,
2517 ri->ri_bmap.br_blockcount, !unwritten, &oinfo);
9c7bc093 2518 break;
d7f80320
DW
2519 default:
2520 ASSERT(0);
2521 error = -EFSCORRUPTED;
2522 }
818f0c29 2523
d7f80320 2524 return error;
d7f80320
DW
2525}
2526
2527/*
2528 * Don't defer an rmap if we aren't an rmap filesystem.
2529 */
2530static bool
2531xfs_rmap_update_is_needed(
cb8a004a
DW
2532 struct xfs_mount *mp,
2533 int whichfork)
d7f80320 2534{
b16a427a 2535 return xfs_has_rmapbt(mp) && whichfork != XFS_COW_FORK;
d7f80320
DW
2536}
2537
2538/*
2539 * Record a rmap intent; the list is kept sorted first by AG and then by
2540 * increasing age.
2541 */
46d29bb9 2542static void
d7f80320 2543__xfs_rmap_add(
21375e5d 2544 struct xfs_trans *tp,
d7f80320 2545 enum xfs_rmap_intent_type type,
4a492e72 2546 uint64_t owner,
d7f80320
DW
2547 int whichfork,
2548 struct xfs_bmbt_irec *bmap)
2549{
21375e5d 2550 struct xfs_rmap_intent *ri;
d7f80320 2551
21375e5d
BF
2552 trace_xfs_rmap_defer(tp->t_mountp,
2553 XFS_FSB_TO_AGNO(tp->t_mountp, bmap->br_startblock),
d7f80320 2554 type,
21375e5d 2555 XFS_FSB_TO_AGBNO(tp->t_mountp, bmap->br_startblock),
d7f80320
DW
2556 owner, whichfork,
2557 bmap->br_startoff,
2558 bmap->br_blockcount,
2559 bmap->br_state);
2560
1577541c 2561 ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
d7f80320
DW
2562 INIT_LIST_HEAD(&ri->ri_list);
2563 ri->ri_type = type;
2564 ri->ri_owner = owner;
2565 ri->ri_whichfork = whichfork;
2566 ri->ri_bmap = *bmap;
2567
818f0c29 2568 xfs_rmap_update_get_group(tp->t_mountp, ri);
21375e5d 2569 xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
d7f80320
DW
2570}
2571
2572/* Map an extent into a file. */
46d29bb9 2573void
d7f80320 2574xfs_rmap_map_extent(
21375e5d 2575 struct xfs_trans *tp,
d7f80320
DW
2576 struct xfs_inode *ip,
2577 int whichfork,
2578 struct xfs_bmbt_irec *PREV)
2579{
171bead5
DW
2580 enum xfs_rmap_intent_type type = XFS_RMAP_MAP;
2581
21375e5d 2582 if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
46d29bb9 2583 return;
d7f80320 2584
171bead5
DW
2585 if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2586 type = XFS_RMAP_MAP_SHARED;
2587
2588 __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
d7f80320
DW
2589}
2590
2591/* Unmap an extent out of a file. */
46d29bb9 2592void
d7f80320 2593xfs_rmap_unmap_extent(
21375e5d 2594 struct xfs_trans *tp,
d7f80320
DW
2595 struct xfs_inode *ip,
2596 int whichfork,
2597 struct xfs_bmbt_irec *PREV)
2598{
171bead5
DW
2599 enum xfs_rmap_intent_type type = XFS_RMAP_UNMAP;
2600
21375e5d 2601 if (!xfs_rmap_update_is_needed(tp->t_mountp, whichfork))
46d29bb9 2602 return;
d7f80320 2603
171bead5
DW
2604 if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2605 type = XFS_RMAP_UNMAP_SHARED;
2606
2607 __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
d7f80320
DW
2608}
2609
21375e5d
BF
2610/*
2611 * Convert a data fork extent from unwritten to real or vice versa.
2612 *
2613 * Note that tp can be NULL here as no transaction is used for COW fork
2614 * unwritten conversion.
2615 */
46d29bb9 2616void
d7f80320
DW
2617xfs_rmap_convert_extent(
2618 struct xfs_mount *mp,
21375e5d 2619 struct xfs_trans *tp,
d7f80320
DW
2620 struct xfs_inode *ip,
2621 int whichfork,
2622 struct xfs_bmbt_irec *PREV)
2623{
171bead5
DW
2624 enum xfs_rmap_intent_type type = XFS_RMAP_CONVERT;
2625
cb8a004a 2626 if (!xfs_rmap_update_is_needed(mp, whichfork))
46d29bb9 2627 return;
d7f80320 2628
171bead5
DW
2629 if (whichfork != XFS_ATTR_FORK && xfs_is_reflink_inode(ip))
2630 type = XFS_RMAP_CONVERT_SHARED;
2631
2632 __xfs_rmap_add(tp, type, ip->i_ino, whichfork, PREV);
d7f80320
DW
2633}
2634
2635/* Schedule the creation of an rmap for non-file data. */
46d29bb9 2636void
d7f80320 2637xfs_rmap_alloc_extent(
21375e5d 2638 struct xfs_trans *tp,
d7f80320
DW
2639 xfs_agnumber_t agno,
2640 xfs_agblock_t bno,
2641 xfs_extlen_t len,
4a492e72 2642 uint64_t owner)
d7f80320
DW
2643{
2644 struct xfs_bmbt_irec bmap;
2645
21375e5d 2646 if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
46d29bb9 2647 return;
d7f80320 2648
21375e5d 2649 bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
d7f80320
DW
2650 bmap.br_blockcount = len;
2651 bmap.br_startoff = 0;
2652 bmap.br_state = XFS_EXT_NORM;
2653
46d29bb9 2654 __xfs_rmap_add(tp, XFS_RMAP_ALLOC, owner, XFS_DATA_FORK, &bmap);
d7f80320
DW
2655}
2656
2657/* Schedule the deletion of an rmap for non-file data. */
46d29bb9 2658void
d7f80320 2659xfs_rmap_free_extent(
21375e5d 2660 struct xfs_trans *tp,
d7f80320
DW
2661 xfs_agnumber_t agno,
2662 xfs_agblock_t bno,
2663 xfs_extlen_t len,
4a492e72 2664 uint64_t owner)
d7f80320
DW
2665{
2666 struct xfs_bmbt_irec bmap;
2667
21375e5d 2668 if (!xfs_rmap_update_is_needed(tp->t_mountp, XFS_DATA_FORK))
46d29bb9 2669 return;
d7f80320 2670
21375e5d 2671 bmap.br_startblock = XFS_AGB_TO_FSB(tp->t_mountp, agno, bno);
d7f80320
DW
2672 bmap.br_blockcount = len;
2673 bmap.br_startoff = 0;
2674 bmap.br_state = XFS_EXT_NORM;
2675
46d29bb9 2676 __xfs_rmap_add(tp, XFS_RMAP_FREE, owner, XFS_DATA_FORK, &bmap);
d7f80320 2677}
9282c506
DW
2678
2679/* Compare rmap records. Returns -1 if a < b, 1 if a > b, and 0 if equal. */
2680int
2681xfs_rmap_compare(
2682 const struct xfs_rmap_irec *a,
2683 const struct xfs_rmap_irec *b)
2684{
2685 __u64 oa;
2686 __u64 ob;
2687
2688 oa = xfs_rmap_irec_offset_pack(a);
2689 ob = xfs_rmap_irec_offset_pack(b);
2690
2691 if (a->rm_startblock < b->rm_startblock)
2692 return -1;
2693 else if (a->rm_startblock > b->rm_startblock)
2694 return 1;
2695 else if (a->rm_owner < b->rm_owner)
2696 return -1;
2697 else if (a->rm_owner > b->rm_owner)
2698 return 1;
2699 else if (oa < ob)
2700 return -1;
2701 else if (oa > ob)
2702 return 1;
2703 else
2704 return 0;
2705}
556c739d 2706
9ba4dc82
DW
2707/*
2708 * Scan the physical storage part of the keyspace of the reverse mapping index
2709 * and tell us if the area has no records, is fully mapped by records, or is
2710 * partially filled.
2711 */
556c739d 2712int
9ba4dc82 2713xfs_rmap_has_records(
556c739d
DW
2714 struct xfs_btree_cur *cur,
2715 xfs_agblock_t bno,
2716 xfs_extlen_t len,
9ba4dc82 2717 enum xbtree_recpacking *outcome)
556c739d 2718{
d99b8900
DW
2719 union xfs_btree_key mask = {
2720 .rmap.rm_startblock = cpu_to_be32(-1U),
2721 };
556c739d
DW
2722 union xfs_btree_irec low;
2723 union xfs_btree_irec high;
2724
2725 memset(&low, 0, sizeof(low));
2726 low.r.rm_startblock = bno;
2727 memset(&high, 0xFF, sizeof(high));
2728 high.r.rm_startblock = bno + len - 1;
2729
d99b8900 2730 return xfs_btree_has_records(cur, &low, &high, &mask, outcome);
556c739d
DW
2731}
2732
54644f25
DW
2733struct xfs_rmap_ownercount {
2734 /* Owner that we're looking for. */
2735 struct xfs_rmap_irec good;
2736
2737 /* rmap search keys */
2738 struct xfs_rmap_irec low;
2739 struct xfs_rmap_irec high;
2740
2741 struct xfs_rmap_matches *results;
2742
2743 /* Stop early if we find a nonmatch? */
2744 bool stop_on_nonmatch;
2745};
2746
2747/* Does this rmap represent space that can have multiple owners? */
2748static inline bool
2749xfs_rmap_shareable(
2750 struct xfs_mount *mp,
2751 const struct xfs_rmap_irec *rmap)
2752{
2753 if (!xfs_has_reflink(mp))
2754 return false;
2755 if (XFS_RMAP_NON_INODE_OWNER(rmap->rm_owner))
2756 return false;
2757 if (rmap->rm_flags & (XFS_RMAP_ATTR_FORK |
2758 XFS_RMAP_BMBT_BLOCK))
2759 return false;
2760 return true;
2761}
2762
2763static inline void
2764xfs_rmap_ownercount_init(
2765 struct xfs_rmap_ownercount *roc,
5837e73b
DW
2766 xfs_agblock_t bno,
2767 xfs_extlen_t len,
2768 const struct xfs_owner_info *oinfo,
54644f25 2769 struct xfs_rmap_matches *results)
556c739d 2770{
54644f25
DW
2771 memset(roc, 0, sizeof(*roc));
2772 roc->results = results;
2773
2774 roc->low.rm_startblock = bno;
2775 memset(&roc->high, 0xFF, sizeof(roc->high));
2776 roc->high.rm_startblock = bno + len - 1;
2777
2778 memset(results, 0, sizeof(*results));
2779 roc->good.rm_startblock = bno;
2780 roc->good.rm_blockcount = len;
2781 roc->good.rm_owner = oinfo->oi_owner;
2782 roc->good.rm_offset = oinfo->oi_offset;
2783 if (oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK)
2784 roc->good.rm_flags |= XFS_RMAP_ATTR_FORK;
2785 if (oinfo->oi_flags & XFS_OWNER_INFO_BMBT_BLOCK)
2786 roc->good.rm_flags |= XFS_RMAP_BMBT_BLOCK;
2787}
556c739d 2788
54644f25
DW
2789/* Figure out if this is a match for the owner. */
2790STATIC int
2791xfs_rmap_count_owners_helper(
2792 struct xfs_btree_cur *cur,
2793 const struct xfs_rmap_irec *rec,
2794 void *priv)
2795{
2796 struct xfs_rmap_ownercount *roc = priv;
2797 struct xfs_rmap_irec check = *rec;
2798 unsigned int keyflags;
2799 bool filedata;
2800 int64_t delta;
2801
2802 filedata = !XFS_RMAP_NON_INODE_OWNER(check.rm_owner) &&
2803 !(check.rm_flags & XFS_RMAP_BMBT_BLOCK);
2804
2805 /* Trim the part of check that comes before the comparison range. */
2806 delta = (int64_t)roc->good.rm_startblock - check.rm_startblock;
2807 if (delta > 0) {
2808 check.rm_startblock += delta;
2809 check.rm_blockcount -= delta;
2810 if (filedata)
2811 check.rm_offset += delta;
2812 }
556c739d 2813
54644f25
DW
2814 /* Trim the part of check that comes after the comparison range. */
2815 delta = (check.rm_startblock + check.rm_blockcount) -
2816 (roc->good.rm_startblock + roc->good.rm_blockcount);
2817 if (delta > 0)
2818 check.rm_blockcount -= delta;
2819
2820 /* Don't care about unwritten status for establishing ownership. */
2821 keyflags = check.rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK);
2822
2823 if (check.rm_startblock == roc->good.rm_startblock &&
2824 check.rm_blockcount == roc->good.rm_blockcount &&
2825 check.rm_owner == roc->good.rm_owner &&
2826 check.rm_offset == roc->good.rm_offset &&
2827 keyflags == roc->good.rm_flags) {
2828 roc->results->matches++;
2829 } else {
2830 roc->results->non_owner_matches++;
2831 if (xfs_rmap_shareable(cur->bc_mp, &roc->good) ^
2832 xfs_rmap_shareable(cur->bc_mp, &check))
2833 roc->results->bad_non_owner_matches++;
556c739d
DW
2834 }
2835
54644f25
DW
2836 if (roc->results->non_owner_matches && roc->stop_on_nonmatch)
2837 return -ECANCELED;
2838
556c739d
DW
2839 return 0;
2840}
d264e392 2841
54644f25
DW
2842/* Count the number of owners and non-owners of this range of blocks. */
2843int
2844xfs_rmap_count_owners(
d264e392 2845 struct xfs_btree_cur *cur,
54644f25
DW
2846 xfs_agblock_t bno,
2847 xfs_extlen_t len,
2848 const struct xfs_owner_info *oinfo,
2849 struct xfs_rmap_matches *results)
d264e392 2850{
54644f25
DW
2851 struct xfs_rmap_ownercount roc;
2852 int error;
d264e392 2853
54644f25
DW
2854 xfs_rmap_ownercount_init(&roc, bno, len, oinfo, results);
2855 error = xfs_rmap_query_range(cur, &roc.low, &roc.high,
2856 xfs_rmap_count_owners_helper, &roc);
2857 if (error)
2858 return error;
2859
2860 /*
2861 * There can't be any non-owner rmaps that conflict with the given
2862 * owner if we didn't find any rmaps matching the owner.
2863 */
2864 if (!results->matches)
2865 results->bad_non_owner_matches = 0;
2866
2867 return 0;
d264e392
DW
2868}
2869
2870/*
2871 * Given an extent and some owner info, can we find records overlapping
2872 * the extent whose owner info does not match the given owner?
2873 */
2874int
2875xfs_rmap_has_other_keys(
2876 struct xfs_btree_cur *cur,
2877 xfs_agblock_t bno,
2878 xfs_extlen_t len,
5837e73b 2879 const struct xfs_owner_info *oinfo,
54644f25 2880 bool *has_other)
d264e392 2881{
54644f25
DW
2882 struct xfs_rmap_matches res;
2883 struct xfs_rmap_ownercount roc;
d264e392
DW
2884 int error;
2885
54644f25
DW
2886 xfs_rmap_ownercount_init(&roc, bno, len, oinfo, &res);
2887 roc.stop_on_nonmatch = true;
d264e392 2888
54644f25
DW
2889 error = xfs_rmap_query_range(cur, &roc.low, &roc.high,
2890 xfs_rmap_count_owners_helper, &roc);
443d6241 2891 if (error == -ECANCELED) {
54644f25 2892 *has_other = true;
443d6241
DW
2893 return 0;
2894 }
54644f25
DW
2895 if (error)
2896 return error;
6c3013ad 2897
54644f25
DW
2898 *has_other = false;
2899 return 0;
d264e392 2900}
007347e3
DW
2901
2902const struct xfs_owner_info XFS_RMAP_OINFO_SKIP_UPDATE = {
2903 .oi_owner = XFS_RMAP_OWN_NULL,
2904};
2905const struct xfs_owner_info XFS_RMAP_OINFO_ANY_OWNER = {
2906 .oi_owner = XFS_RMAP_OWN_UNKNOWN,
2907};
2908const struct xfs_owner_info XFS_RMAP_OINFO_FS = {
2909 .oi_owner = XFS_RMAP_OWN_FS,
2910};
2911const struct xfs_owner_info XFS_RMAP_OINFO_LOG = {
2912 .oi_owner = XFS_RMAP_OWN_LOG,
2913};
2914const struct xfs_owner_info XFS_RMAP_OINFO_AG = {
2915 .oi_owner = XFS_RMAP_OWN_AG,
2916};
2917const struct xfs_owner_info XFS_RMAP_OINFO_INOBT = {
2918 .oi_owner = XFS_RMAP_OWN_INOBT,
2919};
2920const struct xfs_owner_info XFS_RMAP_OINFO_INODES = {
2921 .oi_owner = XFS_RMAP_OWN_INODES,
2922};
2923const struct xfs_owner_info XFS_RMAP_OINFO_REFC = {
2924 .oi_owner = XFS_RMAP_OWN_REFC,
2925};
2926const struct xfs_owner_info XFS_RMAP_OINFO_COW = {
2927 .oi_owner = XFS_RMAP_OWN_COW,
2928};
1577541c
DW
2929
2930int __init
2931xfs_rmap_intent_init_cache(void)
2932{
2933 xfs_rmap_intent_cache = kmem_cache_create("xfs_rmap_intent",
2934 sizeof(struct xfs_rmap_intent),
2935 0, 0, NULL);
2936
2937 return xfs_rmap_intent_cache != NULL ? 0 : -ENOMEM;
2938}
2939
2940void
2941xfs_rmap_intent_destroy_cache(void)
2942{
2943 kmem_cache_destroy(xfs_rmap_intent_cache);
2944 xfs_rmap_intent_cache = NULL;
2945}