Merge remote-tracking branches 'asoc/topic/rockchip', 'asoc/topic/rt5659', 'asoc...
[deliverable/linux.git] / fs / xfs / libxfs / xfs_rmap.c
CommitLineData
673930c3
DW
1/*
2 * Copyright (c) 2014 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "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"
0a1b0b38 34#include "xfs_rmap_btree.h"
673930c3
DW
35#include "xfs_trans_space.h"
36#include "xfs_trace.h"
37#include "xfs_error.h"
38#include "xfs_extent_busy.h"
9c194644
DW
39#include "xfs_bmap.h"
40#include "xfs_inode.h"
673930c3 41
4b8ed677
DW
42/*
43 * Lookup the first record less than or equal to [bno, len, owner, offset]
44 * in the btree given by cur.
45 */
46int
47xfs_rmap_lookup_le(
48 struct xfs_btree_cur *cur,
49 xfs_agblock_t bno,
50 xfs_extlen_t len,
51 uint64_t owner,
52 uint64_t offset,
53 unsigned int flags,
54 int *stat)
55{
56 cur->bc_rec.r.rm_startblock = bno;
57 cur->bc_rec.r.rm_blockcount = len;
58 cur->bc_rec.r.rm_owner = owner;
59 cur->bc_rec.r.rm_offset = offset;
60 cur->bc_rec.r.rm_flags = flags;
61 return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
62}
63
64/*
65 * Lookup the record exactly matching [bno, len, owner, offset]
66 * in the btree given by cur.
67 */
68int
69xfs_rmap_lookup_eq(
70 struct xfs_btree_cur *cur,
71 xfs_agblock_t bno,
72 xfs_extlen_t len,
73 uint64_t owner,
74 uint64_t offset,
75 unsigned int flags,
76 int *stat)
77{
78 cur->bc_rec.r.rm_startblock = bno;
79 cur->bc_rec.r.rm_blockcount = len;
80 cur->bc_rec.r.rm_owner = owner;
81 cur->bc_rec.r.rm_offset = offset;
82 cur->bc_rec.r.rm_flags = flags;
83 return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
84}
85
86/*
87 * Update the record referred to by cur to the value given
88 * by [bno, len, owner, offset].
89 * This either works (return 0) or gets an EFSCORRUPTED error.
90 */
91STATIC int
92xfs_rmap_update(
93 struct xfs_btree_cur *cur,
94 struct xfs_rmap_irec *irec)
95{
96 union xfs_btree_rec rec;
abf09233
DW
97 int error;
98
99 trace_xfs_rmap_update(cur->bc_mp, cur->bc_private.a.agno,
100 irec->rm_startblock, irec->rm_blockcount,
101 irec->rm_owner, irec->rm_offset, irec->rm_flags);
4b8ed677
DW
102
103 rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
104 rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
105 rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
106 rec.rmap.rm_offset = cpu_to_be64(
107 xfs_rmap_irec_offset_pack(irec));
abf09233
DW
108 error = xfs_btree_update(cur, &rec);
109 if (error)
110 trace_xfs_rmap_update_error(cur->bc_mp,
111 cur->bc_private.a.agno, error, _RET_IP_);
112 return error;
113}
114
115int
116xfs_rmap_insert(
117 struct xfs_btree_cur *rcur,
118 xfs_agblock_t agbno,
119 xfs_extlen_t len,
120 uint64_t owner,
121 uint64_t offset,
122 unsigned int flags)
123{
124 int i;
125 int error;
126
127 trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, agbno,
128 len, owner, offset, flags);
129
130 error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
131 if (error)
132 goto done;
133 XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 0, done);
134
135 rcur->bc_rec.r.rm_startblock = agbno;
136 rcur->bc_rec.r.rm_blockcount = len;
137 rcur->bc_rec.r.rm_owner = owner;
138 rcur->bc_rec.r.rm_offset = offset;
139 rcur->bc_rec.r.rm_flags = flags;
140 error = xfs_btree_insert(rcur, &i);
141 if (error)
142 goto done;
143 XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
144done:
145 if (error)
146 trace_xfs_rmap_insert_error(rcur->bc_mp,
147 rcur->bc_private.a.agno, error, _RET_IP_);
148 return error;
4b8ed677
DW
149}
150
151static int
152xfs_rmap_btrec_to_irec(
153 union xfs_btree_rec *rec,
154 struct xfs_rmap_irec *irec)
155{
156 irec->rm_flags = 0;
157 irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
158 irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
159 irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
160 return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
161 irec);
162}
163
164/*
165 * Get the data from the pointed-to record.
166 */
167int
168xfs_rmap_get_rec(
169 struct xfs_btree_cur *cur,
170 struct xfs_rmap_irec *irec,
171 int *stat)
172{
173 union xfs_btree_rec *rec;
174 int error;
175
176 error = xfs_btree_get_rec(cur, &rec, stat);
177 if (error || !*stat)
178 return error;
179
180 return xfs_rmap_btrec_to_irec(rec, irec);
181}
182
f922cd90
DW
183/*
184 * Find the extent in the rmap btree and remove it.
185 *
186 * The record we find should always be an exact match for the extent that we're
187 * looking for, since we insert them into the btree without modification.
188 *
189 * Special Case #1: when growing the filesystem, we "free" an extent when
190 * growing the last AG. This extent is new space and so it is not tracked as
191 * used space in the btree. The growfs code will pass in an owner of
192 * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
193 * extent. We verify that - the extent lookup result in a record that does not
194 * overlap.
195 *
196 * Special Case #2: EFIs do not record the owner of the extent, so when
197 * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
198 * btree to ignore the owner (i.e. wildcard match) so we don't trigger
199 * corruption checks during log recovery.
200 */
201STATIC int
202xfs_rmap_unmap(
203 struct xfs_btree_cur *cur,
204 xfs_agblock_t bno,
205 xfs_extlen_t len,
206 bool unwritten,
207 struct xfs_owner_info *oinfo)
208{
209 struct xfs_mount *mp = cur->bc_mp;
210 struct xfs_rmap_irec ltrec;
211 uint64_t ltoff;
212 int error = 0;
213 int i;
214 uint64_t owner;
215 uint64_t offset;
216 unsigned int flags;
217 bool ignore_off;
218
219 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
220 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
221 (flags & XFS_RMAP_BMBT_BLOCK);
222 if (unwritten)
223 flags |= XFS_RMAP_UNWRITTEN;
224 trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
225 unwritten, oinfo);
226
227 /*
228 * We should always have a left record because there's a static record
229 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
230 * will not ever be removed from the tree.
231 */
232 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i);
233 if (error)
234 goto out_error;
235 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
236
237 error = xfs_rmap_get_rec(cur, &ltrec, &i);
238 if (error)
239 goto out_error;
240 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
241 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
242 cur->bc_private.a.agno, ltrec.rm_startblock,
243 ltrec.rm_blockcount, ltrec.rm_owner,
244 ltrec.rm_offset, ltrec.rm_flags);
245 ltoff = ltrec.rm_offset;
246
247 /*
248 * For growfs, the incoming extent must be beyond the left record we
249 * just found as it is new space and won't be used by anyone. This is
250 * just a corruption check as we don't actually do anything with this
251 * extent. Note that we need to use >= instead of > because it might
252 * be the case that the "left" extent goes all the way to EOFS.
253 */
254 if (owner == XFS_RMAP_OWN_NULL) {
255 XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock +
256 ltrec.rm_blockcount, out_error);
257 goto out_done;
258 }
259
260 /* Make sure the unwritten flag matches. */
261 XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
262 (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
263
264 /* Make sure the extent we found covers the entire freeing range. */
265 XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
266 ltrec.rm_startblock + ltrec.rm_blockcount >=
267 bno + len, out_error);
268
269 /* Make sure the owner matches what we expect to find in the tree. */
270 XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner ||
271 XFS_RMAP_NON_INODE_OWNER(owner), out_error);
272
273 /* Check the offset, if necessary. */
274 if (!XFS_RMAP_NON_INODE_OWNER(owner)) {
275 if (flags & XFS_RMAP_BMBT_BLOCK) {
276 XFS_WANT_CORRUPTED_GOTO(mp,
277 ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK,
278 out_error);
279 } else {
280 XFS_WANT_CORRUPTED_GOTO(mp,
281 ltrec.rm_offset <= offset, out_error);
282 XFS_WANT_CORRUPTED_GOTO(mp,
283 ltoff + ltrec.rm_blockcount >= offset + len,
284 out_error);
285 }
286 }
287
288 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
289 /* exact match, simply remove the record from rmap tree */
290 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
291 ltrec.rm_startblock, ltrec.rm_blockcount,
292 ltrec.rm_owner, ltrec.rm_offset,
293 ltrec.rm_flags);
294 error = xfs_btree_delete(cur, &i);
295 if (error)
296 goto out_error;
297 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
298 } else if (ltrec.rm_startblock == bno) {
299 /*
300 * overlap left hand side of extent: move the start, trim the
301 * length and update the current record.
302 *
303 * ltbno ltlen
304 * Orig: |oooooooooooooooooooo|
305 * Freeing: |fffffffff|
306 * Result: |rrrrrrrrrr|
307 * bno len
308 */
309 ltrec.rm_startblock += len;
310 ltrec.rm_blockcount -= len;
311 if (!ignore_off)
312 ltrec.rm_offset += len;
313 error = xfs_rmap_update(cur, &ltrec);
314 if (error)
315 goto out_error;
316 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
317 /*
318 * overlap right hand side of extent: trim the length and update
319 * the current record.
320 *
321 * ltbno ltlen
322 * Orig: |oooooooooooooooooooo|
323 * Freeing: |fffffffff|
324 * Result: |rrrrrrrrrr|
325 * bno len
326 */
327 ltrec.rm_blockcount -= len;
328 error = xfs_rmap_update(cur, &ltrec);
329 if (error)
330 goto out_error;
331 } else {
332
333 /*
334 * overlap middle of extent: trim the length of the existing
335 * record to the length of the new left-extent size, increment
336 * the insertion position so we can insert a new record
337 * containing the remaining right-extent space.
338 *
339 * ltbno ltlen
340 * Orig: |oooooooooooooooooooo|
341 * Freeing: |fffffffff|
342 * Result: |rrrrr| |rrrr|
343 * bno len
344 */
345 xfs_extlen_t orig_len = ltrec.rm_blockcount;
346
347 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
348 error = xfs_rmap_update(cur, &ltrec);
349 if (error)
350 goto out_error;
351
352 error = xfs_btree_increment(cur, 0, &i);
353 if (error)
354 goto out_error;
355
356 cur->bc_rec.r.rm_startblock = bno + len;
357 cur->bc_rec.r.rm_blockcount = orig_len - len -
358 ltrec.rm_blockcount;
359 cur->bc_rec.r.rm_owner = ltrec.rm_owner;
360 if (ignore_off)
361 cur->bc_rec.r.rm_offset = 0;
362 else
363 cur->bc_rec.r.rm_offset = offset + len;
364 cur->bc_rec.r.rm_flags = flags;
365 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
366 cur->bc_rec.r.rm_startblock,
367 cur->bc_rec.r.rm_blockcount,
368 cur->bc_rec.r.rm_owner,
369 cur->bc_rec.r.rm_offset,
370 cur->bc_rec.r.rm_flags);
371 error = xfs_btree_insert(cur, &i);
372 if (error)
373 goto out_error;
374 }
375
376out_done:
377 trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
378 unwritten, oinfo);
379out_error:
380 if (error)
381 trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno,
382 error, _RET_IP_);
383 return error;
384}
385
386/*
387 * Remove a reference to an extent in the rmap btree.
388 */
673930c3
DW
389int
390xfs_rmap_free(
391 struct xfs_trans *tp,
392 struct xfs_buf *agbp,
393 xfs_agnumber_t agno,
394 xfs_agblock_t bno,
395 xfs_extlen_t len,
396 struct xfs_owner_info *oinfo)
397{
398 struct xfs_mount *mp = tp->t_mountp;
f922cd90
DW
399 struct xfs_btree_cur *cur;
400 int error;
673930c3
DW
401
402 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
403 return 0;
404
f922cd90
DW
405 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
406
407 error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
408 if (error)
673930c3 409 goto out_error;
f922cd90
DW
410
411 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
673930c3
DW
412 return 0;
413
414out_error:
f922cd90 415 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
673930c3
DW
416 return error;
417}
418
0a1b0b38
DW
419/*
420 * A mergeable rmap must have the same owner and the same values for
421 * the unwritten, attr_fork, and bmbt flags. The startblock and
422 * offset are checked separately.
423 */
424static bool
425xfs_rmap_is_mergeable(
426 struct xfs_rmap_irec *irec,
427 uint64_t owner,
428 unsigned int flags)
429{
430 if (irec->rm_owner == XFS_RMAP_OWN_NULL)
431 return false;
432 if (irec->rm_owner != owner)
433 return false;
434 if ((flags & XFS_RMAP_UNWRITTEN) ^
435 (irec->rm_flags & XFS_RMAP_UNWRITTEN))
436 return false;
437 if ((flags & XFS_RMAP_ATTR_FORK) ^
438 (irec->rm_flags & XFS_RMAP_ATTR_FORK))
439 return false;
440 if ((flags & XFS_RMAP_BMBT_BLOCK) ^
441 (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
442 return false;
443 return true;
444}
445
446/*
447 * When we allocate a new block, the first thing we do is add a reference to
448 * the extent in the rmap btree. This takes the form of a [agbno, length,
449 * owner, offset] record. Flags are encoded in the high bits of the offset
450 * field.
451 */
452STATIC int
453xfs_rmap_map(
454 struct xfs_btree_cur *cur,
455 xfs_agblock_t bno,
456 xfs_extlen_t len,
457 bool unwritten,
458 struct xfs_owner_info *oinfo)
459{
460 struct xfs_mount *mp = cur->bc_mp;
461 struct xfs_rmap_irec ltrec;
462 struct xfs_rmap_irec gtrec;
463 int have_gt;
464 int have_lt;
465 int error = 0;
466 int i;
467 uint64_t owner;
468 uint64_t offset;
469 unsigned int flags = 0;
470 bool ignore_off;
471
472 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
473 ASSERT(owner != 0);
474 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
475 (flags & XFS_RMAP_BMBT_BLOCK);
476 if (unwritten)
477 flags |= XFS_RMAP_UNWRITTEN;
478 trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
479 unwritten, oinfo);
480
481 /*
482 * For the initial lookup, look for an exact match or the left-adjacent
483 * record for our insertion point. This will also give us the record for
484 * start block contiguity tests.
485 */
486 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
487 &have_lt);
488 if (error)
489 goto out_error;
490 XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
491
492 error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
493 if (error)
494 goto out_error;
495 XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
496 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
497 cur->bc_private.a.agno, ltrec.rm_startblock,
498 ltrec.rm_blockcount, ltrec.rm_owner,
499 ltrec.rm_offset, ltrec.rm_flags);
500
501 if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
502 have_lt = 0;
503
504 XFS_WANT_CORRUPTED_GOTO(mp,
505 have_lt == 0 ||
506 ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error);
507
508 /*
509 * Increment the cursor to see if we have a right-adjacent record to our
510 * insertion point. This will give us the record for end block
511 * contiguity tests.
512 */
513 error = xfs_btree_increment(cur, 0, &have_gt);
514 if (error)
515 goto out_error;
516 if (have_gt) {
517 error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
518 if (error)
519 goto out_error;
520 XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
521 XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock,
522 out_error);
523 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
524 cur->bc_private.a.agno, gtrec.rm_startblock,
525 gtrec.rm_blockcount, gtrec.rm_owner,
526 gtrec.rm_offset, gtrec.rm_flags);
527 if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
528 have_gt = 0;
529 }
530
531 /*
532 * Note: cursor currently points one record to the right of ltrec, even
533 * if there is no record in the tree to the right.
534 */
535 if (have_lt &&
536 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
537 (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
538 /*
539 * left edge contiguous, merge into left record.
540 *
541 * ltbno ltlen
542 * orig: |ooooooooo|
543 * adding: |aaaaaaaaa|
544 * result: |rrrrrrrrrrrrrrrrrrr|
545 * bno len
546 */
547 ltrec.rm_blockcount += len;
548 if (have_gt &&
549 bno + len == gtrec.rm_startblock &&
550 (ignore_off || offset + len == gtrec.rm_offset) &&
551 (unsigned long)ltrec.rm_blockcount + len +
552 gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
553 /*
554 * right edge also contiguous, delete right record
555 * and merge into left record.
556 *
557 * ltbno ltlen gtbno gtlen
558 * orig: |ooooooooo| |ooooooooo|
559 * adding: |aaaaaaaaa|
560 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
561 */
562 ltrec.rm_blockcount += gtrec.rm_blockcount;
563 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
564 gtrec.rm_startblock,
565 gtrec.rm_blockcount,
566 gtrec.rm_owner,
567 gtrec.rm_offset,
568 gtrec.rm_flags);
569 error = xfs_btree_delete(cur, &i);
570 if (error)
571 goto out_error;
572 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
573 }
574
575 /* point the cursor back to the left record and update */
576 error = xfs_btree_decrement(cur, 0, &have_gt);
577 if (error)
578 goto out_error;
579 error = xfs_rmap_update(cur, &ltrec);
580 if (error)
581 goto out_error;
582 } else if (have_gt &&
583 bno + len == gtrec.rm_startblock &&
584 (ignore_off || offset + len == gtrec.rm_offset)) {
585 /*
586 * right edge contiguous, merge into right record.
587 *
588 * gtbno gtlen
589 * Orig: |ooooooooo|
590 * adding: |aaaaaaaaa|
591 * Result: |rrrrrrrrrrrrrrrrrrr|
592 * bno len
593 */
594 gtrec.rm_startblock = bno;
595 gtrec.rm_blockcount += len;
596 if (!ignore_off)
597 gtrec.rm_offset = offset;
598 error = xfs_rmap_update(cur, &gtrec);
599 if (error)
600 goto out_error;
601 } else {
602 /*
603 * no contiguous edge with identical owner, insert
604 * new record at current cursor position.
605 */
606 cur->bc_rec.r.rm_startblock = bno;
607 cur->bc_rec.r.rm_blockcount = len;
608 cur->bc_rec.r.rm_owner = owner;
609 cur->bc_rec.r.rm_offset = offset;
610 cur->bc_rec.r.rm_flags = flags;
611 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
612 owner, offset, flags);
613 error = xfs_btree_insert(cur, &i);
614 if (error)
615 goto out_error;
616 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
617 }
618
619 trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
620 unwritten, oinfo);
621out_error:
622 if (error)
623 trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno,
624 error, _RET_IP_);
625 return error;
626}
627
628/*
629 * Add a reference to an extent in the rmap btree.
630 */
673930c3
DW
631int
632xfs_rmap_alloc(
633 struct xfs_trans *tp,
634 struct xfs_buf *agbp,
635 xfs_agnumber_t agno,
636 xfs_agblock_t bno,
637 xfs_extlen_t len,
638 struct xfs_owner_info *oinfo)
639{
640 struct xfs_mount *mp = tp->t_mountp;
0a1b0b38
DW
641 struct xfs_btree_cur *cur;
642 int error;
673930c3
DW
643
644 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
645 return 0;
646
0a1b0b38
DW
647 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
648 error = xfs_rmap_map(cur, bno, len, false, oinfo);
649 if (error)
673930c3 650 goto out_error;
0a1b0b38
DW
651
652 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
673930c3
DW
653 return 0;
654
655out_error:
0a1b0b38 656 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
673930c3
DW
657 return error;
658}
c543838a 659
fb7d9267
DW
660#define RMAP_LEFT_CONTIG (1 << 0)
661#define RMAP_RIGHT_CONTIG (1 << 1)
662#define RMAP_LEFT_FILLING (1 << 2)
663#define RMAP_RIGHT_FILLING (1 << 3)
664#define RMAP_LEFT_VALID (1 << 6)
665#define RMAP_RIGHT_VALID (1 << 7)
666
667#define LEFT r[0]
668#define RIGHT r[1]
669#define PREV r[2]
670#define NEW r[3]
671
672/*
673 * Convert an unwritten extent to a real extent or vice versa.
674 * Does not handle overlapping extents.
675 */
676STATIC int
677xfs_rmap_convert(
678 struct xfs_btree_cur *cur,
679 xfs_agblock_t bno,
680 xfs_extlen_t len,
681 bool unwritten,
682 struct xfs_owner_info *oinfo)
683{
684 struct xfs_mount *mp = cur->bc_mp;
685 struct xfs_rmap_irec r[4]; /* neighbor extent entries */
686 /* left is 0, right is 1, prev is 2 */
687 /* new is 3 */
688 uint64_t owner;
689 uint64_t offset;
690 uint64_t new_endoff;
691 unsigned int oldext;
692 unsigned int newext;
693 unsigned int flags = 0;
694 int i;
695 int state = 0;
696 int error;
697
698 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
699 ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
700 (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
701 oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
702 new_endoff = offset + len;
703 trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len,
704 unwritten, oinfo);
705
706 /*
707 * For the initial lookup, look for an exact match or the left-adjacent
708 * record for our insertion point. This will also give us the record for
709 * start block contiguity tests.
710 */
711 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
712 if (error)
713 goto done;
714 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
715
716 error = xfs_rmap_get_rec(cur, &PREV, &i);
717 if (error)
718 goto done;
719 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
720 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
721 cur->bc_private.a.agno, PREV.rm_startblock,
722 PREV.rm_blockcount, PREV.rm_owner,
723 PREV.rm_offset, PREV.rm_flags);
724
725 ASSERT(PREV.rm_offset <= offset);
726 ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
727 ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
728 newext = ~oldext & XFS_RMAP_UNWRITTEN;
729
730 /*
731 * Set flags determining what part of the previous oldext allocation
732 * extent is being replaced by a newext allocation.
733 */
734 if (PREV.rm_offset == offset)
735 state |= RMAP_LEFT_FILLING;
736 if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
737 state |= RMAP_RIGHT_FILLING;
738
739 /*
740 * Decrement the cursor to see if we have a left-adjacent record to our
741 * insertion point. This will give us the record for end block
742 * contiguity tests.
743 */
744 error = xfs_btree_decrement(cur, 0, &i);
745 if (error)
746 goto done;
747 if (i) {
748 state |= RMAP_LEFT_VALID;
749 error = xfs_rmap_get_rec(cur, &LEFT, &i);
750 if (error)
751 goto done;
752 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
753 XFS_WANT_CORRUPTED_GOTO(mp,
754 LEFT.rm_startblock + LEFT.rm_blockcount <= bno,
755 done);
756 trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
757 cur->bc_private.a.agno, LEFT.rm_startblock,
758 LEFT.rm_blockcount, LEFT.rm_owner,
759 LEFT.rm_offset, LEFT.rm_flags);
760 if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
761 LEFT.rm_offset + LEFT.rm_blockcount == offset &&
762 xfs_rmap_is_mergeable(&LEFT, owner, newext))
763 state |= RMAP_LEFT_CONTIG;
764 }
765
766 /*
767 * Increment the cursor to see if we have a right-adjacent record to our
768 * insertion point. This will give us the record for end block
769 * contiguity tests.
770 */
771 error = xfs_btree_increment(cur, 0, &i);
772 if (error)
773 goto done;
774 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
775 error = xfs_btree_increment(cur, 0, &i);
776 if (error)
777 goto done;
778 if (i) {
779 state |= RMAP_RIGHT_VALID;
780 error = xfs_rmap_get_rec(cur, &RIGHT, &i);
781 if (error)
782 goto done;
783 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
784 XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock,
785 done);
786 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
787 cur->bc_private.a.agno, RIGHT.rm_startblock,
788 RIGHT.rm_blockcount, RIGHT.rm_owner,
789 RIGHT.rm_offset, RIGHT.rm_flags);
790 if (bno + len == RIGHT.rm_startblock &&
791 offset + len == RIGHT.rm_offset &&
792 xfs_rmap_is_mergeable(&RIGHT, owner, newext))
793 state |= RMAP_RIGHT_CONTIG;
794 }
795
796 /* check that left + prev + right is not too long */
797 if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
798 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
799 (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
800 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
801 (unsigned long)LEFT.rm_blockcount + len +
802 RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
803 state &= ~RMAP_RIGHT_CONTIG;
804
805 trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state,
806 _RET_IP_);
807
808 /* reset the cursor back to PREV */
809 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
810 if (error)
811 goto done;
812 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
813
814 /*
815 * Switch out based on the FILLING and CONTIG state bits.
816 */
817 switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
818 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
819 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
820 RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
821 /*
822 * Setting all of a previous oldext extent to newext.
823 * The left and right neighbors are both contiguous with new.
824 */
825 error = xfs_btree_increment(cur, 0, &i);
826 if (error)
827 goto done;
828 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
829 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
830 RIGHT.rm_startblock, RIGHT.rm_blockcount,
831 RIGHT.rm_owner, RIGHT.rm_offset,
832 RIGHT.rm_flags);
833 error = xfs_btree_delete(cur, &i);
834 if (error)
835 goto done;
836 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
837 error = xfs_btree_decrement(cur, 0, &i);
838 if (error)
839 goto done;
840 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
841 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
842 PREV.rm_startblock, PREV.rm_blockcount,
843 PREV.rm_owner, PREV.rm_offset,
844 PREV.rm_flags);
845 error = xfs_btree_delete(cur, &i);
846 if (error)
847 goto done;
848 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
849 error = xfs_btree_decrement(cur, 0, &i);
850 if (error)
851 goto done;
852 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
853 NEW = LEFT;
854 NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
855 error = xfs_rmap_update(cur, &NEW);
856 if (error)
857 goto done;
858 break;
859
860 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
861 /*
862 * Setting all of a previous oldext extent to newext.
863 * The left neighbor is contiguous, the right is not.
864 */
865 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
866 PREV.rm_startblock, PREV.rm_blockcount,
867 PREV.rm_owner, PREV.rm_offset,
868 PREV.rm_flags);
869 error = xfs_btree_delete(cur, &i);
870 if (error)
871 goto done;
872 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
873 error = xfs_btree_decrement(cur, 0, &i);
874 if (error)
875 goto done;
876 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
877 NEW = LEFT;
878 NEW.rm_blockcount += PREV.rm_blockcount;
879 error = xfs_rmap_update(cur, &NEW);
880 if (error)
881 goto done;
882 break;
883
884 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
885 /*
886 * Setting all of a previous oldext extent to newext.
887 * The right neighbor is contiguous, the left is not.
888 */
889 error = xfs_btree_increment(cur, 0, &i);
890 if (error)
891 goto done;
892 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
893 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
894 RIGHT.rm_startblock, RIGHT.rm_blockcount,
895 RIGHT.rm_owner, RIGHT.rm_offset,
896 RIGHT.rm_flags);
897 error = xfs_btree_delete(cur, &i);
898 if (error)
899 goto done;
900 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
901 error = xfs_btree_decrement(cur, 0, &i);
902 if (error)
903 goto done;
904 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
905 NEW = PREV;
906 NEW.rm_blockcount = len + RIGHT.rm_blockcount;
907 NEW.rm_flags = newext;
908 error = xfs_rmap_update(cur, &NEW);
909 if (error)
910 goto done;
911 break;
912
913 case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
914 /*
915 * Setting all of a previous oldext extent to newext.
916 * Neither the left nor right neighbors are contiguous with
917 * the new one.
918 */
919 NEW = PREV;
920 NEW.rm_flags = newext;
921 error = xfs_rmap_update(cur, &NEW);
922 if (error)
923 goto done;
924 break;
925
926 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
927 /*
928 * Setting the first part of a previous oldext extent to newext.
929 * The left neighbor is contiguous.
930 */
931 NEW = PREV;
932 NEW.rm_offset += len;
933 NEW.rm_startblock += len;
934 NEW.rm_blockcount -= len;
935 error = xfs_rmap_update(cur, &NEW);
936 if (error)
937 goto done;
938 error = xfs_btree_decrement(cur, 0, &i);
939 if (error)
940 goto done;
941 NEW = LEFT;
942 NEW.rm_blockcount += len;
943 error = xfs_rmap_update(cur, &NEW);
944 if (error)
945 goto done;
946 break;
947
948 case RMAP_LEFT_FILLING:
949 /*
950 * Setting the first part of a previous oldext extent to newext.
951 * The left neighbor is not contiguous.
952 */
953 NEW = PREV;
954 NEW.rm_startblock += len;
955 NEW.rm_offset += len;
956 NEW.rm_blockcount -= len;
957 error = xfs_rmap_update(cur, &NEW);
958 if (error)
959 goto done;
960 NEW.rm_startblock = bno;
961 NEW.rm_owner = owner;
962 NEW.rm_offset = offset;
963 NEW.rm_blockcount = len;
964 NEW.rm_flags = newext;
965 cur->bc_rec.r = NEW;
966 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
967 len, owner, offset, newext);
968 error = xfs_btree_insert(cur, &i);
969 if (error)
970 goto done;
971 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
972 break;
973
974 case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
975 /*
976 * Setting the last part of a previous oldext extent to newext.
977 * The right neighbor is contiguous with the new allocation.
978 */
979 NEW = PREV;
980 NEW.rm_blockcount -= len;
981 error = xfs_rmap_update(cur, &NEW);
982 if (error)
983 goto done;
984 error = xfs_btree_increment(cur, 0, &i);
985 if (error)
986 goto done;
987 NEW = RIGHT;
988 NEW.rm_offset = offset;
989 NEW.rm_startblock = bno;
990 NEW.rm_blockcount += len;
991 error = xfs_rmap_update(cur, &NEW);
992 if (error)
993 goto done;
994 break;
995
996 case RMAP_RIGHT_FILLING:
997 /*
998 * Setting the last part of a previous oldext extent to newext.
999 * The right neighbor is not contiguous.
1000 */
1001 NEW = PREV;
1002 NEW.rm_blockcount -= len;
1003 error = xfs_rmap_update(cur, &NEW);
1004 if (error)
1005 goto done;
1006 error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1007 oldext, &i);
1008 if (error)
1009 goto done;
1010 XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
1011 NEW.rm_startblock = bno;
1012 NEW.rm_owner = owner;
1013 NEW.rm_offset = offset;
1014 NEW.rm_blockcount = len;
1015 NEW.rm_flags = newext;
1016 cur->bc_rec.r = NEW;
1017 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
1018 len, owner, offset, newext);
1019 error = xfs_btree_insert(cur, &i);
1020 if (error)
1021 goto done;
1022 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1023 break;
1024
1025 case 0:
1026 /*
1027 * Setting the middle part of a previous oldext extent to
1028 * newext. Contiguity is impossible here.
1029 * One extent becomes three extents.
1030 */
1031 /* new right extent - oldext */
1032 NEW.rm_startblock = bno + len;
1033 NEW.rm_owner = owner;
1034 NEW.rm_offset = new_endoff;
1035 NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
1036 new_endoff;
1037 NEW.rm_flags = PREV.rm_flags;
1038 error = xfs_rmap_update(cur, &NEW);
1039 if (error)
1040 goto done;
1041 /* new left extent - oldext */
1042 NEW = PREV;
1043 NEW.rm_blockcount = offset - PREV.rm_offset;
1044 cur->bc_rec.r = NEW;
1045 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
1046 NEW.rm_startblock, NEW.rm_blockcount,
1047 NEW.rm_owner, NEW.rm_offset,
1048 NEW.rm_flags);
1049 error = xfs_btree_insert(cur, &i);
1050 if (error)
1051 goto done;
1052 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1053 /*
1054 * Reset the cursor to the position of the new extent
1055 * we are about to insert as we can't trust it after
1056 * the previous insert.
1057 */
1058 error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
1059 oldext, &i);
1060 if (error)
1061 goto done;
1062 XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
1063 /* new middle extent - newext */
1064 cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
1065 cur->bc_rec.r.rm_flags |= newext;
1066 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
1067 owner, offset, newext);
1068 error = xfs_btree_insert(cur, &i);
1069 if (error)
1070 goto done;
1071 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
1072 break;
1073
1074 case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1075 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1076 case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
1077 case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
1078 case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
1079 case RMAP_LEFT_CONTIG:
1080 case RMAP_RIGHT_CONTIG:
1081 /*
1082 * These cases are all impossible.
1083 */
1084 ASSERT(0);
1085 }
1086
1087 trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len,
1088 unwritten, oinfo);
1089done:
1090 if (error)
1091 trace_xfs_rmap_convert_error(cur->bc_mp,
1092 cur->bc_private.a.agno, error, _RET_IP_);
1093 return error;
1094}
1095
1096#undef NEW
1097#undef LEFT
1098#undef RIGHT
1099#undef PREV
1100
c543838a
DW
1101struct xfs_rmap_query_range_info {
1102 xfs_rmap_query_range_fn fn;
1103 void *priv;
1104};
1105
1106/* Format btree record and pass to our callback. */
1107STATIC int
1108xfs_rmap_query_range_helper(
1109 struct xfs_btree_cur *cur,
1110 union xfs_btree_rec *rec,
1111 void *priv)
1112{
1113 struct xfs_rmap_query_range_info *query = priv;
1114 struct xfs_rmap_irec irec;
1115 int error;
1116
1117 error = xfs_rmap_btrec_to_irec(rec, &irec);
1118 if (error)
1119 return error;
1120 return query->fn(cur, &irec, query->priv);
1121}
1122
1123/* Find all rmaps between two keys. */
1124int
1125xfs_rmap_query_range(
1126 struct xfs_btree_cur *cur,
1127 struct xfs_rmap_irec *low_rec,
1128 struct xfs_rmap_irec *high_rec,
1129 xfs_rmap_query_range_fn fn,
1130 void *priv)
1131{
1132 union xfs_btree_irec low_brec;
1133 union xfs_btree_irec high_brec;
1134 struct xfs_rmap_query_range_info query;
1135
1136 low_brec.r = *low_rec;
1137 high_brec.r = *high_rec;
1138 query.priv = priv;
1139 query.fn = fn;
1140 return xfs_btree_query_range(cur, &low_brec, &high_brec,
1141 xfs_rmap_query_range_helper, &query);
1142}
9c194644
DW
1143
1144/* Clean up after calling xfs_rmap_finish_one. */
1145void
1146xfs_rmap_finish_one_cleanup(
1147 struct xfs_trans *tp,
1148 struct xfs_btree_cur *rcur,
1149 int error)
1150{
1151 struct xfs_buf *agbp;
1152
1153 if (rcur == NULL)
1154 return;
1155 agbp = rcur->bc_private.a.agbp;
1156 xfs_btree_del_cursor(rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
1157 if (error)
1158 xfs_trans_brelse(tp, agbp);
1159}
1160
1161/*
1162 * Process one of the deferred rmap operations. We pass back the
1163 * btree cursor to maintain our lock on the rmapbt between calls.
1164 * This saves time and eliminates a buffer deadlock between the
1165 * superblock and the AGF because we'll always grab them in the same
1166 * order.
1167 */
1168int
1169xfs_rmap_finish_one(
1170 struct xfs_trans *tp,
1171 enum xfs_rmap_intent_type type,
1172 __uint64_t owner,
1173 int whichfork,
1174 xfs_fileoff_t startoff,
1175 xfs_fsblock_t startblock,
1176 xfs_filblks_t blockcount,
1177 xfs_exntst_t state,
1178 struct xfs_btree_cur **pcur)
1179{
1180 struct xfs_mount *mp = tp->t_mountp;
1181 struct xfs_btree_cur *rcur;
1182 struct xfs_buf *agbp = NULL;
1183 int error = 0;
1184 xfs_agnumber_t agno;
1185 struct xfs_owner_info oinfo;
1186 xfs_agblock_t bno;
1187 bool unwritten;
1188
1189 agno = XFS_FSB_TO_AGNO(mp, startblock);
1190 ASSERT(agno != NULLAGNUMBER);
1191 bno = XFS_FSB_TO_AGBNO(mp, startblock);
1192
1193 trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork,
1194 startoff, blockcount, state);
1195
1196 if (XFS_TEST_ERROR(false, mp,
1197 XFS_ERRTAG_RMAP_FINISH_ONE,
1198 XFS_RANDOM_RMAP_FINISH_ONE))
1199 return -EIO;
1200
1201 /*
1202 * If we haven't gotten a cursor or the cursor AG doesn't match
1203 * the startblock, get one now.
1204 */
1205 rcur = *pcur;
1206 if (rcur != NULL && rcur->bc_private.a.agno != agno) {
1207 xfs_rmap_finish_one_cleanup(tp, rcur, 0);
1208 rcur = NULL;
1209 *pcur = NULL;
1210 }
1211 if (rcur == NULL) {
1212 /*
1213 * Refresh the freelist before we start changing the
1214 * rmapbt, because a shape change could cause us to
1215 * allocate blocks.
1216 */
1217 error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
1218 if (error)
1219 return error;
1220 if (!agbp)
1221 return -EFSCORRUPTED;
1222
1223 rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
1224 if (!rcur) {
1225 error = -ENOMEM;
1226 goto out_cur;
1227 }
1228 }
1229 *pcur = rcur;
1230
1231 xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff);
1232 unwritten = state == XFS_EXT_UNWRITTEN;
1233 bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock);
1234
1235 switch (type) {
1236 case XFS_RMAP_ALLOC:
1237 case XFS_RMAP_MAP:
1238 error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo);
1239 break;
1240 case XFS_RMAP_FREE:
1241 case XFS_RMAP_UNMAP:
1242 error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten,
1243 &oinfo);
1244 break;
1245 case XFS_RMAP_CONVERT:
1246 error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten,
1247 &oinfo);
1248 break;
1249 default:
1250 ASSERT(0);
1251 error = -EFSCORRUPTED;
1252 }
1253 return error;
1254
1255out_cur:
1256 xfs_trans_brelse(tp, agbp);
1257
1258 return error;
1259}
1260
1261/*
1262 * Don't defer an rmap if we aren't an rmap filesystem.
1263 */
1264static bool
1265xfs_rmap_update_is_needed(
1266 struct xfs_mount *mp)
1267{
1268 return xfs_sb_version_hasrmapbt(&mp->m_sb);
1269}
1270
1271/*
1272 * Record a rmap intent; the list is kept sorted first by AG and then by
1273 * increasing age.
1274 */
1275static int
1276__xfs_rmap_add(
1277 struct xfs_mount *mp,
1278 struct xfs_defer_ops *dfops,
1279 enum xfs_rmap_intent_type type,
1280 __uint64_t owner,
1281 int whichfork,
1282 struct xfs_bmbt_irec *bmap)
1283{
1284 struct xfs_rmap_intent *ri;
1285
1286 trace_xfs_rmap_defer(mp, XFS_FSB_TO_AGNO(mp, bmap->br_startblock),
1287 type,
1288 XFS_FSB_TO_AGBNO(mp, bmap->br_startblock),
1289 owner, whichfork,
1290 bmap->br_startoff,
1291 bmap->br_blockcount,
1292 bmap->br_state);
1293
1294 ri = kmem_alloc(sizeof(struct xfs_rmap_intent), KM_SLEEP | KM_NOFS);
1295 INIT_LIST_HEAD(&ri->ri_list);
1296 ri->ri_type = type;
1297 ri->ri_owner = owner;
1298 ri->ri_whichfork = whichfork;
1299 ri->ri_bmap = *bmap;
1300
1301 xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
1302 return 0;
1303}
1304
1305/* Map an extent into a file. */
1306int
1307xfs_rmap_map_extent(
1308 struct xfs_mount *mp,
1309 struct xfs_defer_ops *dfops,
1310 struct xfs_inode *ip,
1311 int whichfork,
1312 struct xfs_bmbt_irec *PREV)
1313{
1314 if (!xfs_rmap_update_is_needed(mp))
1315 return 0;
1316
1317 return __xfs_rmap_add(mp, dfops, XFS_RMAP_MAP, ip->i_ino,
1318 whichfork, PREV);
1319}
1320
1321/* Unmap an extent out of a file. */
1322int
1323xfs_rmap_unmap_extent(
1324 struct xfs_mount *mp,
1325 struct xfs_defer_ops *dfops,
1326 struct xfs_inode *ip,
1327 int whichfork,
1328 struct xfs_bmbt_irec *PREV)
1329{
1330 if (!xfs_rmap_update_is_needed(mp))
1331 return 0;
1332
1333 return __xfs_rmap_add(mp, dfops, XFS_RMAP_UNMAP, ip->i_ino,
1334 whichfork, PREV);
1335}
1336
1337/* Convert a data fork extent from unwritten to real or vice versa. */
1338int
1339xfs_rmap_convert_extent(
1340 struct xfs_mount *mp,
1341 struct xfs_defer_ops *dfops,
1342 struct xfs_inode *ip,
1343 int whichfork,
1344 struct xfs_bmbt_irec *PREV)
1345{
1346 if (!xfs_rmap_update_is_needed(mp))
1347 return 0;
1348
1349 return __xfs_rmap_add(mp, dfops, XFS_RMAP_CONVERT, ip->i_ino,
1350 whichfork, PREV);
1351}
1352
1353/* Schedule the creation of an rmap for non-file data. */
1354int
1355xfs_rmap_alloc_extent(
1356 struct xfs_mount *mp,
1357 struct xfs_defer_ops *dfops,
1358 xfs_agnumber_t agno,
1359 xfs_agblock_t bno,
1360 xfs_extlen_t len,
1361 __uint64_t owner)
1362{
1363 struct xfs_bmbt_irec bmap;
1364
1365 if (!xfs_rmap_update_is_needed(mp))
1366 return 0;
1367
1368 bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno);
1369 bmap.br_blockcount = len;
1370 bmap.br_startoff = 0;
1371 bmap.br_state = XFS_EXT_NORM;
1372
1373 return __xfs_rmap_add(mp, dfops, XFS_RMAP_ALLOC, owner,
1374 XFS_DATA_FORK, &bmap);
1375}
1376
1377/* Schedule the deletion of an rmap for non-file data. */
1378int
1379xfs_rmap_free_extent(
1380 struct xfs_mount *mp,
1381 struct xfs_defer_ops *dfops,
1382 xfs_agnumber_t agno,
1383 xfs_agblock_t bno,
1384 xfs_extlen_t len,
1385 __uint64_t owner)
1386{
1387 struct xfs_bmbt_irec bmap;
1388
1389 if (!xfs_rmap_update_is_needed(mp))
1390 return 0;
1391
1392 bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno);
1393 bmap.br_blockcount = len;
1394 bmap.br_startoff = 0;
1395 bmap.br_state = XFS_EXT_NORM;
1396
1397 return __xfs_rmap_add(mp, dfops, XFS_RMAP_FREE, owner,
1398 XFS_DATA_FORK, &bmap);
1399}
This page took 0.120253 seconds and 5 git commands to generate.