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