]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/rmap.c
misc: fix Coverity errors
[thirdparty/xfsprogs-dev.git] / repair / rmap.c
CommitLineData
9e0f480e
DW
1/*
2 * Copyright (C) 2016 Oracle. All Rights Reserved.
3 *
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20#include <libxfs.h>
21#include "btree.h"
22#include "err_protos.h"
23#include "libxlog.h"
24#include "incore.h"
25#include "globals.h"
26#include "dinode.h"
27#include "slab.h"
28#include "rmap.h"
29
30#undef RMAP_DEBUG
31
32#ifdef RMAP_DEBUG
33# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
34#else
35# define dbg_printf(f, a...)
36#endif
37
38/* per-AG rmap object anchor */
39struct xfs_ag_rmap {
40 struct xfs_slab *ar_rmaps; /* rmap observations, p4 */
1102c155 41 struct xfs_slab *ar_raw_rmaps; /* unmerged rmaps */
62cf990a
DW
42 int ar_flcount; /* agfl entries from leftover */
43 /* agbt allocations */
b7f12e53 44 struct xfs_rmap_irec ar_last_rmap; /* last rmap seen */
9e0f480e
DW
45};
46
47static struct xfs_ag_rmap *ag_rmaps;
11b9e510 48static bool rmapbt_suspect;
9e0f480e
DW
49
50/*
51 * Compare rmap observations for array sorting.
52 */
53static int
54rmap_compare(
55 const void *a,
56 const void *b)
57{
58 const struct xfs_rmap_irec *pa;
59 const struct xfs_rmap_irec *pb;
60 __u64 oa;
61 __u64 ob;
62
63 pa = a; pb = b;
64 oa = xfs_rmap_irec_offset_pack(pa);
65 ob = xfs_rmap_irec_offset_pack(pb);
66
67 if (pa->rm_startblock < pb->rm_startblock)
68 return -1;
69 else if (pa->rm_startblock > pb->rm_startblock)
70 return 1;
71 else if (pa->rm_owner < pb->rm_owner)
72 return -1;
73 else if (pa->rm_owner > pb->rm_owner)
74 return 1;
75 else if (oa < ob)
76 return -1;
77 else if (oa > ob)
78 return 1;
79 else
80 return 0;
81}
82
83/*
84 * Returns true if we must reconstruct either the reference count or reverse
85 * mapping trees.
86 */
87bool
88needs_rmap_work(
89 struct xfs_mount *mp)
90{
91 return xfs_sb_version_hasrmapbt(&mp->m_sb);
92}
93
94/*
95 * Initialize per-AG reverse map data.
96 */
97void
98init_rmaps(
99 struct xfs_mount *mp)
100{
101 xfs_agnumber_t i;
102 int error;
103
104 if (!needs_rmap_work(mp))
105 return;
106
107 ag_rmaps = calloc(mp->m_sb.sb_agcount, sizeof(struct xfs_ag_rmap));
108 if (!ag_rmaps)
109 do_error(_("couldn't allocate per-AG reverse map roots\n"));
110
111 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
112 error = init_slab(&ag_rmaps[i].ar_rmaps,
113 sizeof(struct xfs_rmap_irec));
114 if (error)
115 do_error(
116_("Insufficient memory while allocating reverse mapping slabs."));
1102c155
DW
117 error = init_slab(&ag_rmaps[i].ar_raw_rmaps,
118 sizeof(struct xfs_rmap_irec));
119 if (error)
120 do_error(
121_("Insufficient memory while allocating raw metadata reverse mapping slabs."));
b7f12e53 122 ag_rmaps[i].ar_last_rmap.rm_owner = XFS_RMAP_OWN_UNKNOWN;
9e0f480e
DW
123 }
124}
125
126/*
127 * Free the per-AG reverse-mapping data.
128 */
129void
130free_rmaps(
131 struct xfs_mount *mp)
132{
133 xfs_agnumber_t i;
134
135 if (!needs_rmap_work(mp))
136 return;
137
1102c155 138 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
9e0f480e 139 free_slab(&ag_rmaps[i].ar_rmaps);
1102c155
DW
140 free_slab(&ag_rmaps[i].ar_raw_rmaps);
141 }
9e0f480e
DW
142 free(ag_rmaps);
143 ag_rmaps = NULL;
144}
145
1102c155
DW
146/*
147 * Decide if two reverse-mapping records can be merged.
148 */
149bool
150mergeable_rmaps(
151 struct xfs_rmap_irec *r1,
152 struct xfs_rmap_irec *r2)
153{
154 if (r1->rm_owner != r2->rm_owner)
155 return false;
156 if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock)
157 return false;
158 if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount >
159 XFS_RMAP_LEN_MAX)
160 return false;
161 if (XFS_RMAP_NON_INODE_OWNER(r2->rm_owner))
162 return true;
163 /* must be an inode owner below here */
164 if (r1->rm_flags != r2->rm_flags)
165 return false;
166 if (r1->rm_flags & XFS_RMAP_BMBT_BLOCK)
167 return true;
168 return r1->rm_offset + r1->rm_blockcount == r2->rm_offset;
169}
170
9e0f480e
DW
171/*
172 * Add an observation about a block mapping in an inode's data or attribute
173 * fork for later btree reconstruction.
174 */
175int
176add_rmap(
177 struct xfs_mount *mp,
178 xfs_ino_t ino,
179 int whichfork,
180 struct xfs_bmbt_irec *irec)
181{
9e0f480e
DW
182 struct xfs_rmap_irec rmap;
183 xfs_agnumber_t agno;
184 xfs_agblock_t agbno;
b7f12e53
DW
185 struct xfs_rmap_irec *last_rmap;
186 int error = 0;
9e0f480e
DW
187
188 if (!needs_rmap_work(mp))
189 return 0;
190
191 agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
192 agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
193 ASSERT(agno != NULLAGNUMBER);
194 ASSERT(agno < mp->m_sb.sb_agcount);
195 ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
196 ASSERT(ino != NULLFSINO);
197 ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
198
9e0f480e
DW
199 rmap.rm_owner = ino;
200 rmap.rm_offset = irec->br_startoff;
201 rmap.rm_flags = 0;
202 if (whichfork == XFS_ATTR_FORK)
203 rmap.rm_flags |= XFS_RMAP_ATTR_FORK;
204 rmap.rm_startblock = agbno;
205 rmap.rm_blockcount = irec->br_blockcount;
206 if (irec->br_state == XFS_EXT_UNWRITTEN)
207 rmap.rm_flags |= XFS_RMAP_UNWRITTEN;
b7f12e53
DW
208 last_rmap = &ag_rmaps[agno].ar_last_rmap;
209 if (last_rmap->rm_owner == XFS_RMAP_OWN_UNKNOWN)
210 *last_rmap = rmap;
211 else if (mergeable_rmaps(last_rmap, &rmap))
212 last_rmap->rm_blockcount += rmap.rm_blockcount;
213 else {
214 error = slab_add(ag_rmaps[agno].ar_rmaps, last_rmap);
215 if (error)
216 return error;
217 *last_rmap = rmap;
218 }
219
220 return error;
221}
222
223/* Finish collecting inode data/attr fork rmaps. */
224int
225finish_collecting_fork_rmaps(
226 struct xfs_mount *mp,
227 xfs_agnumber_t agno)
228{
229 if (!needs_rmap_work(mp) ||
230 ag_rmaps[agno].ar_last_rmap.rm_owner == XFS_RMAP_OWN_UNKNOWN)
231 return 0;
232 return slab_add(ag_rmaps[agno].ar_rmaps, &ag_rmaps[agno].ar_last_rmap);
9e0f480e
DW
233}
234
1102c155
DW
235/* add a raw rmap; these will be merged later */
236static int
237__add_raw_rmap(
238 struct xfs_mount *mp,
239 xfs_agnumber_t agno,
240 xfs_agblock_t agbno,
241 xfs_extlen_t len,
242 uint64_t owner,
243 bool is_attr,
244 bool is_bmbt)
245{
246 struct xfs_rmap_irec rmap;
247
248 ASSERT(len != 0);
249 rmap.rm_owner = owner;
250 rmap.rm_offset = 0;
251 rmap.rm_flags = 0;
252 if (is_attr)
253 rmap.rm_flags |= XFS_RMAP_ATTR_FORK;
254 if (is_bmbt)
255 rmap.rm_flags |= XFS_RMAP_BMBT_BLOCK;
256 rmap.rm_startblock = agbno;
257 rmap.rm_blockcount = len;
258 return slab_add(ag_rmaps[agno].ar_raw_rmaps, &rmap);
259}
260
00efc33a
DW
261/*
262 * Add a reverse mapping for an inode fork's block mapping btree block.
263 */
264int
265add_bmbt_rmap(
266 struct xfs_mount *mp,
267 xfs_ino_t ino,
268 int whichfork,
269 xfs_fsblock_t fsbno)
270{
271 xfs_agnumber_t agno;
272 xfs_agblock_t agbno;
273
274 if (!needs_rmap_work(mp))
275 return 0;
276
277 agno = XFS_FSB_TO_AGNO(mp, fsbno);
278 agbno = XFS_FSB_TO_AGBNO(mp, fsbno);
279 ASSERT(agno != NULLAGNUMBER);
280 ASSERT(agno < mp->m_sb.sb_agcount);
281 ASSERT(agbno + 1 <= mp->m_sb.sb_agblocks);
282
283 return __add_raw_rmap(mp, agno, agbno, 1, ino,
284 whichfork == XFS_ATTR_FORK, true);
285}
286
1102c155
DW
287/*
288 * Add a reverse mapping for a per-AG fixed metadata extent.
289 */
290int
291add_ag_rmap(
292 struct xfs_mount *mp,
293 xfs_agnumber_t agno,
294 xfs_agblock_t agbno,
295 xfs_extlen_t len,
296 uint64_t owner)
297{
298 if (!needs_rmap_work(mp))
299 return 0;
300
301 ASSERT(agno != NULLAGNUMBER);
302 ASSERT(agno < mp->m_sb.sb_agcount);
303 ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
304
305 return __add_raw_rmap(mp, agno, agbno, len, owner, false, false);
306}
307
308/*
309 * Merge adjacent raw rmaps and add them to the main rmap list.
310 */
311int
312fold_raw_rmaps(
313 struct xfs_mount *mp,
314 xfs_agnumber_t agno)
315{
316 struct xfs_slab_cursor *cur = NULL;
317 struct xfs_rmap_irec *prev, *rec;
318 size_t old_sz;
138ce9ff 319 int error = 0;
1102c155
DW
320
321 old_sz = slab_count(ag_rmaps[agno].ar_rmaps);
322 if (slab_count(ag_rmaps[agno].ar_raw_rmaps) == 0)
323 goto no_raw;
324 qsort_slab(ag_rmaps[agno].ar_raw_rmaps, rmap_compare);
325 error = init_slab_cursor(ag_rmaps[agno].ar_raw_rmaps, rmap_compare,
326 &cur);
327 if (error)
328 goto err;
329
330 prev = pop_slab_cursor(cur);
331 rec = pop_slab_cursor(cur);
138ce9ff 332 while (prev && rec) {
1102c155
DW
333 if (mergeable_rmaps(prev, rec)) {
334 prev->rm_blockcount += rec->rm_blockcount;
335 rec = pop_slab_cursor(cur);
336 continue;
337 }
338 error = slab_add(ag_rmaps[agno].ar_rmaps, prev);
339 if (error)
340 goto err;
341 prev = rec;
342 rec = pop_slab_cursor(cur);
343 }
344 if (prev) {
345 error = slab_add(ag_rmaps[agno].ar_rmaps, prev);
346 if (error)
347 goto err;
348 }
349 free_slab(&ag_rmaps[agno].ar_raw_rmaps);
350 error = init_slab(&ag_rmaps[agno].ar_raw_rmaps,
351 sizeof(struct xfs_rmap_irec));
352 if (error)
353 do_error(
354_("Insufficient memory while allocating raw metadata reverse mapping slabs."));
355no_raw:
356 if (old_sz)
357 qsort_slab(ag_rmaps[agno].ar_rmaps, rmap_compare);
358err:
359 free_slab_cursor(&cur);
360 return error;
361}
362
713b6817
DW
363static int
364find_first_zero_bit(
365 __uint64_t mask)
366{
367 int n;
368 int b = 0;
369
370 for (n = 0; n < sizeof(mask) * NBBY && (mask & 1); n++, mask >>= 1)
371 b++;
372
373 return b;
374}
375
376static int
377popcnt(
378 __uint64_t mask)
379{
380 int n;
381 int b = 0;
382
383 if (mask == 0)
384 return 0;
385
386 for (n = 0; n < sizeof(mask) * NBBY; n++, mask >>= 1)
387 if (mask & 1)
388 b++;
389
390 return b;
391}
392
393/*
394 * Add an allocation group's fixed metadata to the rmap list. This includes
395 * sb/agi/agf/agfl headers, inode chunks, and the log.
396 */
397int
398add_fixed_ag_rmap_data(
399 struct xfs_mount *mp,
400 xfs_agnumber_t agno)
401{
402 xfs_fsblock_t fsbno;
403 xfs_agblock_t agbno;
404 ino_tree_node_t *ino_rec;
405 xfs_agino_t agino;
406 int error;
407 int startidx;
408 int nr;
409
410 if (!needs_rmap_work(mp))
411 return 0;
412
413 /* sb/agi/agf/agfl headers */
414 error = add_ag_rmap(mp, agno, 0, XFS_BNO_BLOCK(mp),
415 XFS_RMAP_OWN_FS);
416 if (error)
417 goto out;
418
419 /* inodes */
420 ino_rec = findfirst_inode_rec(agno);
421 for (; ino_rec != NULL; ino_rec = next_ino_rec(ino_rec)) {
422 if (xfs_sb_version_hassparseinodes(&mp->m_sb)) {
423 startidx = find_first_zero_bit(ino_rec->ir_sparse);
424 nr = XFS_INODES_PER_CHUNK - popcnt(ino_rec->ir_sparse);
425 } else {
426 startidx = 0;
427 nr = XFS_INODES_PER_CHUNK;
428 }
429 nr /= mp->m_sb.sb_inopblock;
430 if (nr == 0)
431 nr = 1;
432 agino = ino_rec->ino_startnum + startidx;
433 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
434 if (XFS_AGINO_TO_OFFSET(mp, agino) == 0) {
435 error = add_ag_rmap(mp, agno, agbno, nr,
436 XFS_RMAP_OWN_INODES);
437 if (error)
438 goto out;
439 }
440 }
441
442 /* log */
443 fsbno = mp->m_sb.sb_logstart;
444 if (fsbno && XFS_FSB_TO_AGNO(mp, fsbno) == agno) {
445 agbno = XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart);
446 error = add_ag_rmap(mp, agno, agbno, mp->m_sb.sb_logblocks,
447 XFS_RMAP_OWN_LOG);
448 if (error)
449 goto out;
450 }
451out:
452 return error;
453}
454
62cf990a
DW
455/*
456 * Copy the per-AG btree reverse-mapping data into the rmapbt.
457 *
458 * At rmapbt reconstruction time, the rmapbt will be populated _only_ with
459 * rmaps for file extents, inode chunks, AG headers, and bmbt blocks. While
460 * building the AG btrees we can record all the blocks allocated for each
461 * btree, but we cannot resolve the conflict between the fact that one has to
462 * finish allocating the space for the rmapbt before building the bnobt and the
463 * fact that allocating blocks for the bnobt requires adding rmapbt entries.
464 * Therefore we record in-core the rmaps for each btree and here use the
465 * libxfs rmap functions to finish building the rmap btree.
466 *
467 * During AGF/AGFL reconstruction in phase 5, rmaps for the AG btrees are
468 * recorded in memory. The rmapbt has not been set up yet, so we need to be
469 * able to "expand" the AGFL without updating the rmapbt. After we've written
470 * out the new AGF header the new rmapbt is available, so this function reads
471 * each AGFL to generate rmap entries. These entries are merged with the AG
472 * btree rmap entries, and then we use libxfs' rmap functions to add them to
473 * the rmapbt, after which it is fully regenerated.
474 */
475int
476store_ag_btree_rmap_data(
477 struct xfs_mount *mp,
478 xfs_agnumber_t agno)
479{
480 struct xfs_slab_cursor *rm_cur;
481 struct xfs_rmap_irec *rm_rec = NULL;
482 struct xfs_buf *agbp = NULL;
483 struct xfs_buf *agflbp = NULL;
484 struct xfs_trans *tp;
485 struct xfs_trans_res tres = {0};
486 __be32 *agfl_bno, *b;
487 int error = 0;
488 struct xfs_owner_info oinfo;
489
490 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
491 return 0;
492
493 /* Release the ar_rmaps; they were put into the rmapbt during p5. */
494 free_slab(&ag_rmaps[agno].ar_rmaps);
495 error = init_slab(&ag_rmaps[agno].ar_rmaps,
496 sizeof(struct xfs_rmap_irec));
497 if (error)
498 goto err;
499
500 /* Add the AGFL blocks to the rmap list */
501 error = libxfs_trans_read_buf(
502 mp, NULL, mp->m_ddev_targp,
503 XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
504 XFS_FSS_TO_BB(mp, 1), 0, &agflbp, &xfs_agfl_buf_ops);
505 if (error)
506 goto err;
507
508 agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
509 agfl_bno += ag_rmaps[agno].ar_flcount;
510 b = agfl_bno;
511 while (*b != NULLAGBLOCK && b - agfl_bno <= XFS_AGFL_SIZE(mp)) {
512 error = add_ag_rmap(mp, agno, be32_to_cpu(*b), 1,
513 XFS_RMAP_OWN_AG);
514 if (error)
515 goto err;
516 b++;
517 }
518 libxfs_putbuf(agflbp);
519 agflbp = NULL;
520
521 /* Merge all the raw rmaps into the main list */
522 error = fold_raw_rmaps(mp, agno);
523 if (error)
524 goto err;
525
526 /* Create cursors to refcount structures */
527 error = init_slab_cursor(ag_rmaps[agno].ar_rmaps, rmap_compare,
528 &rm_cur);
529 if (error)
530 goto err;
531
532 /* Insert rmaps into the btree one at a time */
533 rm_rec = pop_slab_cursor(rm_cur);
534 while (rm_rec) {
535 error = -libxfs_trans_alloc(mp, &tres, 16, 0, 0, &tp);
536 if (error)
537 goto err_slab;
538
539 error = libxfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
540 if (error)
541 goto err_trans;
542
543 ASSERT(XFS_RMAP_NON_INODE_OWNER(rm_rec->rm_owner));
544 libxfs_rmap_ag_owner(&oinfo, rm_rec->rm_owner);
545 error = libxfs_rmap_alloc(tp, agbp, agno, rm_rec->rm_startblock,
546 rm_rec->rm_blockcount, &oinfo);
547 if (error)
548 goto err_trans;
549
550 error = -libxfs_trans_commit(tp);
551 if (error)
552 goto err_slab;
553
554 fix_freelist(mp, agno, false);
555
556 rm_rec = pop_slab_cursor(rm_cur);
557 }
558
559 free_slab_cursor(&rm_cur);
560 return 0;
561
562err_trans:
563 libxfs_trans_cancel(tp);
564err_slab:
565 free_slab_cursor(&rm_cur);
566err:
567 if (agflbp)
568 libxfs_putbuf(agflbp);
569 printf("FAIL err %d\n", error);
570 return error;
571}
572
9e0f480e
DW
573#ifdef RMAP_DEBUG
574static void
575dump_rmap(
576 const char *msg,
577 xfs_agnumber_t agno,
578 struct xfs_rmap_irec *rmap)
579{
580 printf("%s: %p agno=%u pblk=%llu own=%lld lblk=%llu len=%u flags=0x%x\n",
581 msg, rmap,
582 (unsigned int)agno,
583 (unsigned long long)rmap->rm_startblock,
584 (unsigned long long)rmap->rm_owner,
585 (unsigned long long)rmap->rm_offset,
586 (unsigned int)rmap->rm_blockcount,
587 (unsigned int)rmap->rm_flags);
588}
589#else
590# define dump_rmap(m, a, r)
591#endif
11b9e510
DW
592
593/*
594 * Return the number of rmap objects for an AG.
595 */
596size_t
597rmap_record_count(
598 struct xfs_mount *mp,
599 xfs_agnumber_t agno)
600{
601 return slab_count(ag_rmaps[agno].ar_rmaps);
602}
603
604/*
605 * Return a slab cursor that will return rmap objects in order.
606 */
607int
608init_rmap_cursor(
609 xfs_agnumber_t agno,
610 struct xfs_slab_cursor **cur)
611{
612 return init_slab_cursor(ag_rmaps[agno].ar_rmaps, rmap_compare, cur);
613}
614
615/*
616 * Disable the refcount btree check.
617 */
618void
619rmap_avoid_check(void)
620{
621 rmapbt_suspect = true;
622}
623
624/* Look for an rmap in the rmapbt that matches a given rmap. */
625static int
626lookup_rmap(
627 struct xfs_btree_cur *bt_cur,
628 struct xfs_rmap_irec *rm_rec,
629 struct xfs_rmap_irec *tmp,
630 int *have)
631{
632 int error;
633
634 /* Use the regular btree retrieval routine. */
635 error = -libxfs_rmap_lookup_le(bt_cur, rm_rec->rm_startblock,
636 rm_rec->rm_blockcount,
637 rm_rec->rm_owner, rm_rec->rm_offset,
638 rm_rec->rm_flags, have);
639 if (error)
640 return error;
641 if (*have == 0)
642 return error;
643 return -libxfs_rmap_get_rec(bt_cur, tmp, have);
644}
645
646/* Does the btree rmap cover the observed rmap? */
647#define NEXTP(x) ((x)->rm_startblock + (x)->rm_blockcount)
648#define NEXTL(x) ((x)->rm_offset + (x)->rm_blockcount)
649static bool
650is_good_rmap(
651 struct xfs_rmap_irec *observed,
652 struct xfs_rmap_irec *btree)
653{
654 /* Can't have mismatches in the flags or the owner. */
655 if (btree->rm_flags != observed->rm_flags ||
656 btree->rm_owner != observed->rm_owner)
657 return false;
658
659 /*
660 * Btree record can't physically start after the observed
661 * record, nor can it end before the observed record.
662 */
663 if (btree->rm_startblock > observed->rm_startblock ||
664 NEXTP(btree) < NEXTP(observed))
665 return false;
666
667 /* If this is metadata or bmbt, we're done. */
668 if (XFS_RMAP_NON_INODE_OWNER(observed->rm_owner) ||
669 (observed->rm_flags & XFS_RMAP_BMBT_BLOCK))
670 return true;
671 /*
672 * Btree record can't logically start after the observed
673 * record, nor can it end before the observed record.
674 */
675 if (btree->rm_offset > observed->rm_offset ||
676 NEXTL(btree) < NEXTL(observed))
677 return false;
678
679 return true;
680}
681#undef NEXTP
682#undef NEXTL
683
684/*
685 * Compare the observed reverse mappings against what's in the ag btree.
686 */
687int
688check_rmaps(
689 struct xfs_mount *mp,
690 xfs_agnumber_t agno)
691{
692 struct xfs_slab_cursor *rm_cur;
693 struct xfs_btree_cur *bt_cur = NULL;
694 int error;
695 int have;
696 struct xfs_buf *agbp = NULL;
697 struct xfs_rmap_irec *rm_rec;
698 struct xfs_rmap_irec tmp;
699 struct xfs_perag *pag; /* per allocation group data */
700
701 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
702 return 0;
703 if (rmapbt_suspect) {
704 if (no_modify && agno == 0)
705 do_warn(_("would rebuild corrupt rmap btrees.\n"));
706 return 0;
707 }
708
709 /* Create cursors to refcount structures */
710 error = init_rmap_cursor(agno, &rm_cur);
711 if (error)
712 return error;
713
714 error = -libxfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
715 if (error)
716 goto err;
717
718 /* Leave the per-ag data "uninitialized" since we rewrite it later */
719 pag = xfs_perag_get(mp, agno);
720 pag->pagf_init = 0;
721 xfs_perag_put(pag);
722
723 bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, agno);
724 if (!bt_cur) {
725 error = -ENOMEM;
726 goto err;
727 }
728
729 rm_rec = pop_slab_cursor(rm_cur);
730 while (rm_rec) {
731 error = lookup_rmap(bt_cur, rm_rec, &tmp, &have);
732 if (error)
733 goto err;
734 if (!have) {
735 do_warn(
736_("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \
737%s%soff %"PRIu64"\n"),
738 agno, rm_rec->rm_startblock,
739 (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN) ?
740 _("unwritten ") : "",
741 rm_rec->rm_blockcount,
742 rm_rec->rm_owner,
743 (rm_rec->rm_flags & XFS_RMAP_ATTR_FORK) ?
744 _("attr ") : "",
745 (rm_rec->rm_flags & XFS_RMAP_BMBT_BLOCK) ?
746 _("bmbt ") : "",
747 rm_rec->rm_offset);
748 goto next_loop;
749 }
750
751 /* Compare each refcount observation against the btree's */
752 if (!is_good_rmap(rm_rec, &tmp)) {
753 do_warn(
754_("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \
755%"PRIu64"; should be (%u/%u) %slen %u owner %"PRId64" %s%soff %"PRIu64"\n"),
756 agno, tmp.rm_startblock,
757 (tmp.rm_flags & XFS_RMAP_UNWRITTEN) ?
758 _("unwritten ") : "",
759 tmp.rm_blockcount,
760 tmp.rm_owner,
761 (tmp.rm_flags & XFS_RMAP_ATTR_FORK) ?
762 _("attr ") : "",
763 (tmp.rm_flags & XFS_RMAP_BMBT_BLOCK) ?
764 _("bmbt ") : "",
765 tmp.rm_offset,
766 agno, rm_rec->rm_startblock,
767 (rm_rec->rm_flags & XFS_RMAP_UNWRITTEN) ?
768 _("unwritten ") : "",
769 rm_rec->rm_blockcount,
770 rm_rec->rm_owner,
771 (rm_rec->rm_flags & XFS_RMAP_ATTR_FORK) ?
772 _("attr ") : "",
773 (rm_rec->rm_flags & XFS_RMAP_BMBT_BLOCK) ?
774 _("bmbt ") : "",
775 rm_rec->rm_offset);
776 goto next_loop;
777 }
778next_loop:
779 rm_rec = pop_slab_cursor(rm_cur);
780 }
781
782err:
783 if (bt_cur)
784 libxfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
785 if (agbp)
786 libxfs_putbuf(agbp);
787 free_slab_cursor(&rm_cur);
788 return 0;
789}
790
791/*
792 * Compare the key fields of two rmap records -- positive if key1 > key2,
793 * negative if key1 < key2, and zero if equal.
794 */
795__int64_t
796rmap_diffkeys(
797 struct xfs_rmap_irec *kp1,
798 struct xfs_rmap_irec *kp2)
799{
800 __u64 oa;
801 __u64 ob;
802 __int64_t d;
803 struct xfs_rmap_irec tmp;
804
805 tmp = *kp1;
806 tmp.rm_flags &= ~XFS_RMAP_REC_FLAGS;
807 oa = xfs_rmap_irec_offset_pack(&tmp);
808 tmp = *kp2;
809 tmp.rm_flags &= ~XFS_RMAP_REC_FLAGS;
810 ob = xfs_rmap_irec_offset_pack(&tmp);
811
812 d = (__int64_t)kp1->rm_startblock - kp2->rm_startblock;
813 if (d)
814 return d;
815
816 if (kp1->rm_owner > kp2->rm_owner)
817 return 1;
818 else if (kp2->rm_owner > kp1->rm_owner)
819 return -1;
820
821 if (oa > ob)
822 return 1;
823 else if (ob > oa)
824 return -1;
825 return 0;
826}
827
828/* Compute the high key of an rmap record. */
829void
830rmap_high_key_from_rec(
831 struct xfs_rmap_irec *rec,
832 struct xfs_rmap_irec *key)
833{
834 int adj;
835
836 adj = rec->rm_blockcount - 1;
837
838 key->rm_startblock = rec->rm_startblock + adj;
839 key->rm_owner = rec->rm_owner;
840 key->rm_offset = rec->rm_offset;
841 key->rm_flags = rec->rm_flags & XFS_RMAP_KEY_FLAGS;
842 if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) ||
843 (rec->rm_flags & XFS_RMAP_BMBT_BLOCK))
844 return;
845 key->rm_offset += adj;
846}
62cf990a
DW
847
848/*
849 * Regenerate the AGFL so that we don't run out of it while rebuilding the
850 * rmap btree. If skip_rmapbt is true, don't update the rmapbt (most probably
851 * because we're updating the rmapbt).
852 */
853void
854fix_freelist(
855 struct xfs_mount *mp,
856 xfs_agnumber_t agno,
857 bool skip_rmapbt)
858{
859 xfs_alloc_arg_t args;
860 xfs_trans_t *tp;
861 struct xfs_trans_res tres = {0};
862 int flags;
863 int error;
864
865 memset(&args, 0, sizeof(args));
866 args.mp = mp;
867 args.agno = agno;
868 args.alignment = 1;
869 args.pag = xfs_perag_get(mp, agno);
870 error = -libxfs_trans_alloc(mp, &tres,
871 libxfs_alloc_min_freelist(mp, args.pag), 0, 0, &tp);
872 if (error)
873 do_error(_("failed to fix AGFL on AG %d, error %d\n"),
874 agno, error);
875 args.tp = tp;
876
877 /*
878 * Prior to rmapbt, all we had to do to fix the freelist is "expand"
879 * the fresh AGFL header from empty to full. That hasn't changed. For
880 * rmapbt, however, things change a bit.
881 *
882 * When we're stuffing the rmapbt with the AG btree rmaps the tree can
883 * expand, so we need to keep the AGFL well-stocked for the expansion.
884 * However, this expansion can cause the bnobt/cntbt to shrink, which
885 * can make the AGFL eligible for shrinking. Shrinking involves
886 * freeing rmapbt entries, but since we haven't finished loading the
887 * rmapbt with the btree rmaps it's possible for the remove operation
888 * to fail. The AGFL block is large enough at this point to absorb any
889 * blocks freed from the bnobt/cntbt, so we can disable shrinking.
890 *
891 * During the initial AGFL regeneration during AGF generation in phase5
892 * we must also disable rmapbt modifications because the AGF that
893 * libxfs reads does not yet point to the new rmapbt. These initial
894 * AGFL entries are added just prior to adding the AG btree block rmaps
895 * to the rmapbt. It's ok to pass NOSHRINK here too, since the AGFL is
896 * empty and cannot shrink.
897 */
898 flags = XFS_ALLOC_FLAG_NOSHRINK;
899 if (skip_rmapbt)
900 flags |= XFS_ALLOC_FLAG_NORMAP;
901 error = libxfs_alloc_fix_freelist(&args, flags);
902 xfs_perag_put(args.pag);
903 if (error) {
904 do_error(_("failed to fix AGFL on AG %d, error %d\n"),
905 agno, error);
906 }
907 libxfs_trans_commit(tp);
908}
909
910/*
911 * Remember how many AGFL entries came from excess AG btree allocations and
912 * therefore already have rmap entries.
913 */
914void
915rmap_store_agflcount(
916 struct xfs_mount *mp,
917 xfs_agnumber_t agno,
918 int count)
919{
920 if (!needs_rmap_work(mp))
921 return;
922
923 ag_rmaps[agno].ar_flcount = count;
924}