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