blob: 1e48a0b62ba6682d4819475b87476b7863ff0af4 [file] [log] [blame]
Darrick J. Wong673930c2016-08-03 11:33:43 +10001/*
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 "xfs.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"
Darrick J. Wong0a1b0b32016-08-03 11:44:21 +100034#include "xfs_rmap_btree.h"
Darrick J. Wong673930c2016-08-03 11:33:43 +100035#include "xfs_trans_space.h"
36#include "xfs_trace.h"
37#include "xfs_error.h"
38#include "xfs_extent_busy.h"
39
Darrick J. Wong4b8ed672016-08-03 11:39:05 +100040/*
41 * Lookup the first record less than or equal to [bno, len, owner, offset]
42 * in the btree given by cur.
43 */
44int
45xfs_rmap_lookup_le(
46 struct xfs_btree_cur *cur,
47 xfs_agblock_t bno,
48 xfs_extlen_t len,
49 uint64_t owner,
50 uint64_t offset,
51 unsigned int flags,
52 int *stat)
53{
54 cur->bc_rec.r.rm_startblock = bno;
55 cur->bc_rec.r.rm_blockcount = len;
56 cur->bc_rec.r.rm_owner = owner;
57 cur->bc_rec.r.rm_offset = offset;
58 cur->bc_rec.r.rm_flags = flags;
59 return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
60}
61
62/*
63 * Lookup the record exactly matching [bno, len, owner, offset]
64 * in the btree given by cur.
65 */
66int
67xfs_rmap_lookup_eq(
68 struct xfs_btree_cur *cur,
69 xfs_agblock_t bno,
70 xfs_extlen_t len,
71 uint64_t owner,
72 uint64_t offset,
73 unsigned int flags,
74 int *stat)
75{
76 cur->bc_rec.r.rm_startblock = bno;
77 cur->bc_rec.r.rm_blockcount = len;
78 cur->bc_rec.r.rm_owner = owner;
79 cur->bc_rec.r.rm_offset = offset;
80 cur->bc_rec.r.rm_flags = flags;
81 return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
82}
83
84/*
85 * Update the record referred to by cur to the value given
86 * by [bno, len, owner, offset].
87 * This either works (return 0) or gets an EFSCORRUPTED error.
88 */
89STATIC int
90xfs_rmap_update(
91 struct xfs_btree_cur *cur,
92 struct xfs_rmap_irec *irec)
93{
94 union xfs_btree_rec rec;
95
96 rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
97 rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
98 rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
99 rec.rmap.rm_offset = cpu_to_be64(
100 xfs_rmap_irec_offset_pack(irec));
101 return xfs_btree_update(cur, &rec);
102}
103
104static int
105xfs_rmap_btrec_to_irec(
106 union xfs_btree_rec *rec,
107 struct xfs_rmap_irec *irec)
108{
109 irec->rm_flags = 0;
110 irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
111 irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
112 irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
113 return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
114 irec);
115}
116
117/*
118 * Get the data from the pointed-to record.
119 */
120int
121xfs_rmap_get_rec(
122 struct xfs_btree_cur *cur,
123 struct xfs_rmap_irec *irec,
124 int *stat)
125{
126 union xfs_btree_rec *rec;
127 int error;
128
129 error = xfs_btree_get_rec(cur, &rec, stat);
130 if (error || !*stat)
131 return error;
132
133 return xfs_rmap_btrec_to_irec(rec, irec);
134}
135
Darrick J. Wongf922cd92016-08-03 11:45:12 +1000136/*
137 * Find the extent in the rmap btree and remove it.
138 *
139 * The record we find should always be an exact match for the extent that we're
140 * looking for, since we insert them into the btree without modification.
141 *
142 * Special Case #1: when growing the filesystem, we "free" an extent when
143 * growing the last AG. This extent is new space and so it is not tracked as
144 * used space in the btree. The growfs code will pass in an owner of
145 * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
146 * extent. We verify that - the extent lookup result in a record that does not
147 * overlap.
148 *
149 * Special Case #2: EFIs do not record the owner of the extent, so when
150 * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
151 * btree to ignore the owner (i.e. wildcard match) so we don't trigger
152 * corruption checks during log recovery.
153 */
154STATIC int
155xfs_rmap_unmap(
156 struct xfs_btree_cur *cur,
157 xfs_agblock_t bno,
158 xfs_extlen_t len,
159 bool unwritten,
160 struct xfs_owner_info *oinfo)
161{
162 struct xfs_mount *mp = cur->bc_mp;
163 struct xfs_rmap_irec ltrec;
164 uint64_t ltoff;
165 int error = 0;
166 int i;
167 uint64_t owner;
168 uint64_t offset;
169 unsigned int flags;
170 bool ignore_off;
171
172 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
173 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
174 (flags & XFS_RMAP_BMBT_BLOCK);
175 if (unwritten)
176 flags |= XFS_RMAP_UNWRITTEN;
177 trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
178 unwritten, oinfo);
179
180 /*
181 * We should always have a left record because there's a static record
182 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
183 * will not ever be removed from the tree.
184 */
185 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i);
186 if (error)
187 goto out_error;
188 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
189
190 error = xfs_rmap_get_rec(cur, &ltrec, &i);
191 if (error)
192 goto out_error;
193 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
194 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
195 cur->bc_private.a.agno, ltrec.rm_startblock,
196 ltrec.rm_blockcount, ltrec.rm_owner,
197 ltrec.rm_offset, ltrec.rm_flags);
198 ltoff = ltrec.rm_offset;
199
200 /*
201 * For growfs, the incoming extent must be beyond the left record we
202 * just found as it is new space and won't be used by anyone. This is
203 * just a corruption check as we don't actually do anything with this
204 * extent. Note that we need to use >= instead of > because it might
205 * be the case that the "left" extent goes all the way to EOFS.
206 */
207 if (owner == XFS_RMAP_OWN_NULL) {
208 XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock +
209 ltrec.rm_blockcount, out_error);
210 goto out_done;
211 }
212
213 /* Make sure the unwritten flag matches. */
214 XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
215 (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
216
217 /* Make sure the extent we found covers the entire freeing range. */
218 XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
219 ltrec.rm_startblock + ltrec.rm_blockcount >=
220 bno + len, out_error);
221
222 /* Make sure the owner matches what we expect to find in the tree. */
223 XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner ||
224 XFS_RMAP_NON_INODE_OWNER(owner), out_error);
225
226 /* Check the offset, if necessary. */
227 if (!XFS_RMAP_NON_INODE_OWNER(owner)) {
228 if (flags & XFS_RMAP_BMBT_BLOCK) {
229 XFS_WANT_CORRUPTED_GOTO(mp,
230 ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK,
231 out_error);
232 } else {
233 XFS_WANT_CORRUPTED_GOTO(mp,
234 ltrec.rm_offset <= offset, out_error);
235 XFS_WANT_CORRUPTED_GOTO(mp,
236 ltoff + ltrec.rm_blockcount >= offset + len,
237 out_error);
238 }
239 }
240
241 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
242 /* exact match, simply remove the record from rmap tree */
243 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
244 ltrec.rm_startblock, ltrec.rm_blockcount,
245 ltrec.rm_owner, ltrec.rm_offset,
246 ltrec.rm_flags);
247 error = xfs_btree_delete(cur, &i);
248 if (error)
249 goto out_error;
250 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
251 } else if (ltrec.rm_startblock == bno) {
252 /*
253 * overlap left hand side of extent: move the start, trim the
254 * length and update the current record.
255 *
256 * ltbno ltlen
257 * Orig: |oooooooooooooooooooo|
258 * Freeing: |fffffffff|
259 * Result: |rrrrrrrrrr|
260 * bno len
261 */
262 ltrec.rm_startblock += len;
263 ltrec.rm_blockcount -= len;
264 if (!ignore_off)
265 ltrec.rm_offset += len;
266 error = xfs_rmap_update(cur, &ltrec);
267 if (error)
268 goto out_error;
269 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
270 /*
271 * overlap right hand side of extent: trim the length and update
272 * the current record.
273 *
274 * ltbno ltlen
275 * Orig: |oooooooooooooooooooo|
276 * Freeing: |fffffffff|
277 * Result: |rrrrrrrrrr|
278 * bno len
279 */
280 ltrec.rm_blockcount -= len;
281 error = xfs_rmap_update(cur, &ltrec);
282 if (error)
283 goto out_error;
284 } else {
285
286 /*
287 * overlap middle of extent: trim the length of the existing
288 * record to the length of the new left-extent size, increment
289 * the insertion position so we can insert a new record
290 * containing the remaining right-extent space.
291 *
292 * ltbno ltlen
293 * Orig: |oooooooooooooooooooo|
294 * Freeing: |fffffffff|
295 * Result: |rrrrr| |rrrr|
296 * bno len
297 */
298 xfs_extlen_t orig_len = ltrec.rm_blockcount;
299
300 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
301 error = xfs_rmap_update(cur, &ltrec);
302 if (error)
303 goto out_error;
304
305 error = xfs_btree_increment(cur, 0, &i);
306 if (error)
307 goto out_error;
308
309 cur->bc_rec.r.rm_startblock = bno + len;
310 cur->bc_rec.r.rm_blockcount = orig_len - len -
311 ltrec.rm_blockcount;
312 cur->bc_rec.r.rm_owner = ltrec.rm_owner;
313 if (ignore_off)
314 cur->bc_rec.r.rm_offset = 0;
315 else
316 cur->bc_rec.r.rm_offset = offset + len;
317 cur->bc_rec.r.rm_flags = flags;
318 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
319 cur->bc_rec.r.rm_startblock,
320 cur->bc_rec.r.rm_blockcount,
321 cur->bc_rec.r.rm_owner,
322 cur->bc_rec.r.rm_offset,
323 cur->bc_rec.r.rm_flags);
324 error = xfs_btree_insert(cur, &i);
325 if (error)
326 goto out_error;
327 }
328
329out_done:
330 trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
331 unwritten, oinfo);
332out_error:
333 if (error)
334 trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno,
335 error, _RET_IP_);
336 return error;
337}
338
339/*
340 * Remove a reference to an extent in the rmap btree.
341 */
Darrick J. Wong673930c2016-08-03 11:33:43 +1000342int
343xfs_rmap_free(
344 struct xfs_trans *tp,
345 struct xfs_buf *agbp,
346 xfs_agnumber_t agno,
347 xfs_agblock_t bno,
348 xfs_extlen_t len,
349 struct xfs_owner_info *oinfo)
350{
351 struct xfs_mount *mp = tp->t_mountp;
Darrick J. Wongf922cd92016-08-03 11:45:12 +1000352 struct xfs_btree_cur *cur;
353 int error;
Darrick J. Wong673930c2016-08-03 11:33:43 +1000354
355 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
356 return 0;
357
Darrick J. Wongf922cd92016-08-03 11:45:12 +1000358 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
359
360 error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
361 if (error)
Darrick J. Wong673930c2016-08-03 11:33:43 +1000362 goto out_error;
Darrick J. Wongf922cd92016-08-03 11:45:12 +1000363
364 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
Darrick J. Wong673930c2016-08-03 11:33:43 +1000365 return 0;
366
367out_error:
Darrick J. Wongf922cd92016-08-03 11:45:12 +1000368 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
Darrick J. Wong673930c2016-08-03 11:33:43 +1000369 return error;
370}
371
Darrick J. Wong0a1b0b32016-08-03 11:44:21 +1000372/*
373 * A mergeable rmap must have the same owner and the same values for
374 * the unwritten, attr_fork, and bmbt flags. The startblock and
375 * offset are checked separately.
376 */
377static bool
378xfs_rmap_is_mergeable(
379 struct xfs_rmap_irec *irec,
380 uint64_t owner,
381 unsigned int flags)
382{
383 if (irec->rm_owner == XFS_RMAP_OWN_NULL)
384 return false;
385 if (irec->rm_owner != owner)
386 return false;
387 if ((flags & XFS_RMAP_UNWRITTEN) ^
388 (irec->rm_flags & XFS_RMAP_UNWRITTEN))
389 return false;
390 if ((flags & XFS_RMAP_ATTR_FORK) ^
391 (irec->rm_flags & XFS_RMAP_ATTR_FORK))
392 return false;
393 if ((flags & XFS_RMAP_BMBT_BLOCK) ^
394 (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
395 return false;
396 return true;
397}
398
399/*
400 * When we allocate a new block, the first thing we do is add a reference to
401 * the extent in the rmap btree. This takes the form of a [agbno, length,
402 * owner, offset] record. Flags are encoded in the high bits of the offset
403 * field.
404 */
405STATIC int
406xfs_rmap_map(
407 struct xfs_btree_cur *cur,
408 xfs_agblock_t bno,
409 xfs_extlen_t len,
410 bool unwritten,
411 struct xfs_owner_info *oinfo)
412{
413 struct xfs_mount *mp = cur->bc_mp;
414 struct xfs_rmap_irec ltrec;
415 struct xfs_rmap_irec gtrec;
416 int have_gt;
417 int have_lt;
418 int error = 0;
419 int i;
420 uint64_t owner;
421 uint64_t offset;
422 unsigned int flags = 0;
423 bool ignore_off;
424
425 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
426 ASSERT(owner != 0);
427 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
428 (flags & XFS_RMAP_BMBT_BLOCK);
429 if (unwritten)
430 flags |= XFS_RMAP_UNWRITTEN;
431 trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
432 unwritten, oinfo);
433
434 /*
435 * For the initial lookup, look for an exact match or the left-adjacent
436 * record for our insertion point. This will also give us the record for
437 * start block contiguity tests.
438 */
439 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
440 &have_lt);
441 if (error)
442 goto out_error;
443 XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
444
445 error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
446 if (error)
447 goto out_error;
448 XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
449 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
450 cur->bc_private.a.agno, ltrec.rm_startblock,
451 ltrec.rm_blockcount, ltrec.rm_owner,
452 ltrec.rm_offset, ltrec.rm_flags);
453
454 if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
455 have_lt = 0;
456
457 XFS_WANT_CORRUPTED_GOTO(mp,
458 have_lt == 0 ||
459 ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error);
460
461 /*
462 * Increment the cursor to see if we have a right-adjacent record to our
463 * insertion point. This will give us the record for end block
464 * contiguity tests.
465 */
466 error = xfs_btree_increment(cur, 0, &have_gt);
467 if (error)
468 goto out_error;
469 if (have_gt) {
470 error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
471 if (error)
472 goto out_error;
473 XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
474 XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock,
475 out_error);
476 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
477 cur->bc_private.a.agno, gtrec.rm_startblock,
478 gtrec.rm_blockcount, gtrec.rm_owner,
479 gtrec.rm_offset, gtrec.rm_flags);
480 if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
481 have_gt = 0;
482 }
483
484 /*
485 * Note: cursor currently points one record to the right of ltrec, even
486 * if there is no record in the tree to the right.
487 */
488 if (have_lt &&
489 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
490 (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
491 /*
492 * left edge contiguous, merge into left record.
493 *
494 * ltbno ltlen
495 * orig: |ooooooooo|
496 * adding: |aaaaaaaaa|
497 * result: |rrrrrrrrrrrrrrrrrrr|
498 * bno len
499 */
500 ltrec.rm_blockcount += len;
501 if (have_gt &&
502 bno + len == gtrec.rm_startblock &&
503 (ignore_off || offset + len == gtrec.rm_offset) &&
504 (unsigned long)ltrec.rm_blockcount + len +
505 gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
506 /*
507 * right edge also contiguous, delete right record
508 * and merge into left record.
509 *
510 * ltbno ltlen gtbno gtlen
511 * orig: |ooooooooo| |ooooooooo|
512 * adding: |aaaaaaaaa|
513 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
514 */
515 ltrec.rm_blockcount += gtrec.rm_blockcount;
516 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
517 gtrec.rm_startblock,
518 gtrec.rm_blockcount,
519 gtrec.rm_owner,
520 gtrec.rm_offset,
521 gtrec.rm_flags);
522 error = xfs_btree_delete(cur, &i);
523 if (error)
524 goto out_error;
525 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
526 }
527
528 /* point the cursor back to the left record and update */
529 error = xfs_btree_decrement(cur, 0, &have_gt);
530 if (error)
531 goto out_error;
532 error = xfs_rmap_update(cur, &ltrec);
533 if (error)
534 goto out_error;
535 } else if (have_gt &&
536 bno + len == gtrec.rm_startblock &&
537 (ignore_off || offset + len == gtrec.rm_offset)) {
538 /*
539 * right edge contiguous, merge into right record.
540 *
541 * gtbno gtlen
542 * Orig: |ooooooooo|
543 * adding: |aaaaaaaaa|
544 * Result: |rrrrrrrrrrrrrrrrrrr|
545 * bno len
546 */
547 gtrec.rm_startblock = bno;
548 gtrec.rm_blockcount += len;
549 if (!ignore_off)
550 gtrec.rm_offset = offset;
551 error = xfs_rmap_update(cur, &gtrec);
552 if (error)
553 goto out_error;
554 } else {
555 /*
556 * no contiguous edge with identical owner, insert
557 * new record at current cursor position.
558 */
559 cur->bc_rec.r.rm_startblock = bno;
560 cur->bc_rec.r.rm_blockcount = len;
561 cur->bc_rec.r.rm_owner = owner;
562 cur->bc_rec.r.rm_offset = offset;
563 cur->bc_rec.r.rm_flags = flags;
564 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
565 owner, offset, flags);
566 error = xfs_btree_insert(cur, &i);
567 if (error)
568 goto out_error;
569 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
570 }
571
572 trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
573 unwritten, oinfo);
574out_error:
575 if (error)
576 trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno,
577 error, _RET_IP_);
578 return error;
579}
580
581/*
582 * Add a reference to an extent in the rmap btree.
583 */
Darrick J. Wong673930c2016-08-03 11:33:43 +1000584int
585xfs_rmap_alloc(
586 struct xfs_trans *tp,
587 struct xfs_buf *agbp,
588 xfs_agnumber_t agno,
589 xfs_agblock_t bno,
590 xfs_extlen_t len,
591 struct xfs_owner_info *oinfo)
592{
593 struct xfs_mount *mp = tp->t_mountp;
Darrick J. Wong0a1b0b32016-08-03 11:44:21 +1000594 struct xfs_btree_cur *cur;
595 int error;
Darrick J. Wong673930c2016-08-03 11:33:43 +1000596
597 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
598 return 0;
599
Darrick J. Wong0a1b0b32016-08-03 11:44:21 +1000600 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
601 error = xfs_rmap_map(cur, bno, len, false, oinfo);
602 if (error)
Darrick J. Wong673930c2016-08-03 11:33:43 +1000603 goto out_error;
Darrick J. Wong0a1b0b32016-08-03 11:44:21 +1000604
605 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
Darrick J. Wong673930c2016-08-03 11:33:43 +1000606 return 0;
607
608out_error:
Darrick J. Wong0a1b0b32016-08-03 11:44:21 +1000609 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
Darrick J. Wong673930c2016-08-03 11:33:43 +1000610 return error;
611}
Darrick J. Wongc5438382016-08-03 11:42:39 +1000612
613struct xfs_rmap_query_range_info {
614 xfs_rmap_query_range_fn fn;
615 void *priv;
616};
617
618/* Format btree record and pass to our callback. */
619STATIC int
620xfs_rmap_query_range_helper(
621 struct xfs_btree_cur *cur,
622 union xfs_btree_rec *rec,
623 void *priv)
624{
625 struct xfs_rmap_query_range_info *query = priv;
626 struct xfs_rmap_irec irec;
627 int error;
628
629 error = xfs_rmap_btrec_to_irec(rec, &irec);
630 if (error)
631 return error;
632 return query->fn(cur, &irec, query->priv);
633}
634
635/* Find all rmaps between two keys. */
636int
637xfs_rmap_query_range(
638 struct xfs_btree_cur *cur,
639 struct xfs_rmap_irec *low_rec,
640 struct xfs_rmap_irec *high_rec,
641 xfs_rmap_query_range_fn fn,
642 void *priv)
643{
644 union xfs_btree_irec low_brec;
645 union xfs_btree_irec high_brec;
646 struct xfs_rmap_query_range_info query;
647
648 low_brec.r = *low_rec;
649 high_brec.r = *high_rec;
650 query.priv = priv;
651 query.fn = fn;
652 return xfs_btree_query_range(cur, &low_brec, &high_brec,
653 xfs_rmap_query_range_helper, &query);
654}