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