Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (C) 2021-2023 Oracle. All Rights Reserved.
4 : * Author: Darrick J. Wong <djwong@kernel.org>
5 : */
6 : #include "xfs.h"
7 : #include "xfs_fs.h"
8 : #include "xfs_shared.h"
9 : #include "xfs_format.h"
10 : #include "xfs_log_format.h"
11 : #include "xfs_trans_resv.h"
12 : #include "xfs_mount.h"
13 : #include "xfs_inode.h"
14 : #include "xfs_trans.h"
15 : #include "xfs_btree.h"
16 : #include "xfs_trace.h"
17 : #include "xfs_alloc.h"
18 : #include "xfs_bit.h"
19 : #include "xfs_fsrefs.h"
20 : #include "xfs_refcount.h"
21 : #include "xfs_refcount_btree.h"
22 : #include "xfs_alloc_btree.h"
23 : #include "xfs_rtalloc.h"
24 : #include "xfs_rtrefcount_btree.h"
25 : #include "xfs_ag.h"
26 : #include "xfs_rtbitmap.h"
27 : #include "xfs_rtgroup.h"
28 :
29 : /* getfsrefs query state */
30 : struct xfs_fsrefs_info {
31 : struct xfs_fsrefs_head *head;
32 : struct xfs_getfsrefs *fsrefs_recs; /* mapping records */
33 :
34 : struct xfs_btree_cur *refc_cur; /* refcount btree cursor */
35 : struct xfs_btree_cur *bno_cur; /* bnobt btree cursor */
36 :
37 : struct xfs_buf *agf_bp; /* AGF, for refcount queries */
38 : struct xfs_perag *pag; /* perag structure */
39 : struct xfs_rtgroup *rtg;
40 :
41 : xfs_daddr_t next_daddr; /* next daddr we expect */
42 : /* daddr of low fsmap key when we're using the rtbitmap */
43 : xfs_daddr_t low_daddr;
44 :
45 : /*
46 : * Low refcount key for the query. If low.rc_blockcount is nonzero,
47 : * this is the second (or later) call to retrieve the recordset in
48 : * pieces. xfs_getfsrefs_rec_before_start will compare all records
49 : * retrieved by the refcountbt query to filter out any records that
50 : * start before the last record.
51 : */
52 : struct xfs_refcount_irec low;
53 : struct xfs_refcount_irec high; /* high refcount key */
54 :
55 : u32 dev; /* device id */
56 : bool last; /* last extent? */
57 : };
58 :
59 : /* Associate a device with a getfsrefs handler. */
60 : struct xfs_fsrefs_dev {
61 : u32 dev;
62 : int (*fn)(struct xfs_trans *tp,
63 : const struct xfs_fsrefs *keys,
64 : struct xfs_fsrefs_info *info);
65 : };
66 :
67 : /* Convert an xfs_fsrefs to an fsrefs. */
68 : static void
69 : xfs_fsrefs_from_internal(
70 : struct xfs_getfsrefs *dest,
71 : struct xfs_fsrefs *src)
72 : {
73 2545 : dest->fcr_device = src->fcr_device;
74 2545 : dest->fcr_flags = src->fcr_flags;
75 2545 : dest->fcr_physical = BBTOB(src->fcr_physical);
76 2545 : dest->fcr_owners = src->fcr_owners;
77 2545 : dest->fcr_length = BBTOB(src->fcr_length);
78 2545 : dest->fcr_reserved[0] = 0;
79 2545 : dest->fcr_reserved[1] = 0;
80 2545 : dest->fcr_reserved[2] = 0;
81 2545 : dest->fcr_reserved[3] = 0;
82 : }
83 :
84 : /* Convert an fsrefs to an xfs_fsrefs. */
85 : void
86 3033 : xfs_fsrefs_to_internal(
87 : struct xfs_fsrefs *dest,
88 : struct xfs_getfsrefs *src)
89 : {
90 3033 : dest->fcr_device = src->fcr_device;
91 3033 : dest->fcr_flags = src->fcr_flags;
92 3033 : dest->fcr_physical = BTOBBT(src->fcr_physical);
93 3033 : dest->fcr_owners = src->fcr_owners;
94 3033 : dest->fcr_length = BTOBBT(src->fcr_length);
95 3033 : }
96 :
97 : /* Compare two getfsrefs device handlers. */
98 : static int
99 3033 : xfs_fsrefs_dev_compare(
100 : const void *p1,
101 : const void *p2)
102 : {
103 3033 : const struct xfs_fsrefs_dev *d1 = p1;
104 3033 : const struct xfs_fsrefs_dev *d2 = p2;
105 :
106 3033 : return d1->dev - d2->dev;
107 : }
108 :
109 : static inline bool
110 : xfs_fsrefs_rec_before_start(
111 : struct xfs_fsrefs_info *info,
112 : const struct xfs_refcount_irec *rec,
113 : xfs_daddr_t rec_daddr)
114 : {
115 4209 : if (info->low_daddr != -1ULL)
116 0 : return rec_daddr < info->low_daddr;
117 4209 : if (info->low.rc_blockcount)
118 2635 : return rec->rc_startblock < info->low.rc_startblock;
119 : return false;
120 : }
121 :
122 : /*
123 : * Format a refcount record for fsrefs, having translated rc_startblock into
124 : * the appropriate daddr units.
125 : */
126 : STATIC int
127 4209 : xfs_fsrefs_helper(
128 : struct xfs_trans *tp,
129 : struct xfs_fsrefs_info *info,
130 : const struct xfs_refcount_irec *rec,
131 : xfs_daddr_t rec_daddr,
132 : xfs_daddr_t len_daddr)
133 : {
134 4209 : struct xfs_fsrefs fcr;
135 4209 : struct xfs_getfsrefs *row;
136 4209 : struct xfs_mount *mp = tp->t_mountp;
137 :
138 4209 : if (fatal_signal_pending(current))
139 : return -EINTR;
140 :
141 4209 : if (len_daddr == 0)
142 4209 : len_daddr = XFS_FSB_TO_BB(mp, rec->rc_blockcount);
143 :
144 : /*
145 : * Filter out records that start before our startpoint, if the
146 : * caller requested that.
147 : */
148 6844 : if (xfs_fsrefs_rec_before_start(info, rec, rec_daddr))
149 : return 0;
150 :
151 : /* Are we just counting mappings? */
152 4209 : if (info->head->fch_count == 0) {
153 0 : if (info->head->fch_entries == UINT_MAX)
154 : return -ECANCELED;
155 :
156 0 : info->head->fch_entries++;
157 0 : return 0;
158 : }
159 :
160 : /* Fill out the extent we found */
161 4209 : if (info->head->fch_entries >= info->head->fch_count)
162 : return -ECANCELED;
163 :
164 2545 : if (info->pag)
165 2545 : trace_xfs_fsrefs_mapping(mp, info->dev, info->pag->pag_agno,
166 : rec);
167 0 : else if (info->rtg)
168 0 : trace_xfs_fsrefs_mapping(mp, info->dev, info->rtg->rtg_rgno,
169 : rec);
170 : else
171 0 : trace_xfs_fsrefs_mapping(mp, info->dev, NULLAGNUMBER, rec);
172 :
173 2545 : fcr.fcr_device = info->dev;
174 2545 : fcr.fcr_flags = 0;
175 2545 : fcr.fcr_physical = rec_daddr;
176 2545 : fcr.fcr_owners = rec->rc_refcount;
177 2545 : fcr.fcr_length = len_daddr;
178 :
179 2545 : trace_xfs_getfsrefs_mapping(mp, &fcr);
180 :
181 2545 : row = &info->fsrefs_recs[info->head->fch_entries++];
182 2545 : xfs_fsrefs_from_internal(row, &fcr);
183 2545 : return 0;
184 : }
185 :
186 : /* Synthesize fsrefs records from free space data. */
187 : STATIC int
188 5012 : xfs_fsrefs_ddev_bnobt_helper(
189 : struct xfs_btree_cur *cur,
190 : const struct xfs_alloc_rec_incore *rec,
191 : void *priv)
192 : {
193 5012 : struct xfs_refcount_irec irec;
194 5012 : struct xfs_mount *mp = cur->bc_mp;
195 5012 : struct xfs_fsrefs_info *info = priv;
196 5012 : xfs_agnumber_t next_agno;
197 5012 : xfs_agblock_t next_agbno;
198 5012 : xfs_daddr_t rec_daddr;
199 :
200 : /*
201 : * Figure out if there's a gap between the last fsrefs record we
202 : * emitted and this free extent. If there is, report the gap as a
203 : * refcount==1 record.
204 : */
205 5012 : next_agno = xfs_daddr_to_agno(mp, info->next_daddr);
206 5012 : next_agbno = xfs_daddr_to_agbno(mp, info->next_daddr);
207 :
208 5012 : ASSERT(next_agno >= cur->bc_ag.pag->pag_agno);
209 5012 : ASSERT(rec->ar_startblock >= next_agbno);
210 :
211 : /*
212 : * If we've already moved on to the next AG, we don't have any fsrefs
213 : * records to synthesize.
214 : */
215 5012 : if (next_agno > cur->bc_ag.pag->pag_agno)
216 : return 0;
217 :
218 4982 : info->next_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
219 : rec->ar_startblock + rec->ar_blockcount);
220 :
221 4982 : if (rec->ar_startblock == next_agbno)
222 : return 0;
223 :
224 : /* Emit a record for the in-use space */
225 4062 : irec.rc_startblock = next_agbno;
226 4062 : irec.rc_blockcount = rec->ar_startblock - next_agbno;
227 4062 : irec.rc_refcount = 1;
228 4062 : irec.rc_domain = XFS_REFC_DOMAIN_SHARED;
229 4062 : rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
230 : irec.rc_startblock);
231 :
232 4062 : return xfs_fsrefs_helper(cur->bc_tp, info, &irec, rec_daddr, 0);
233 : }
234 :
235 : /* Emit records to fill a gap in the refcount btree with singly-owned blocks. */
236 : STATIC int
237 1793 : xfs_fsrefs_ddev_fill_refcount_gap(
238 : struct xfs_trans *tp,
239 : struct xfs_fsrefs_info *info,
240 : xfs_agblock_t agbno)
241 : {
242 1793 : struct xfs_alloc_rec_incore low = {0};
243 1793 : struct xfs_alloc_rec_incore high = {0};
244 1793 : struct xfs_mount *mp = tp->t_mountp;
245 1793 : struct xfs_btree_cur *cur = info->bno_cur;
246 1793 : struct xfs_agf *agf;
247 1793 : int error;
248 :
249 1793 : ASSERT(xfs_daddr_to_agno(mp, info->next_daddr) ==
250 : cur->bc_ag.pag->pag_agno);
251 :
252 1793 : low.ar_startblock = xfs_daddr_to_agbno(mp, info->next_daddr);
253 1793 : if (low.ar_startblock >= agbno)
254 : return 0;
255 :
256 1742 : high.ar_startblock = agbno;
257 1742 : error = xfs_alloc_query_range(cur, &low, &high,
258 : xfs_fsrefs_ddev_bnobt_helper, info);
259 1742 : if (error)
260 : return error;
261 :
262 : /*
263 : * Synthesize records for single-owner extents between the last
264 : * fsrefcount record emitted and the end of the query range.
265 : */
266 170 : agf = cur->bc_ag.agbp->b_addr;
267 170 : low.ar_startblock = min_t(xfs_agblock_t, agbno,
268 : be32_to_cpu(agf->agf_length));
269 170 : if (xfs_daddr_to_agbno(mp, info->next_daddr) > low.ar_startblock)
270 : return 0;
271 :
272 170 : info->last = true;
273 170 : return xfs_fsrefs_ddev_bnobt_helper(cur, &low, info);
274 : }
275 :
276 : /* Transform a refcountbt irec into a fsrefs */
277 : STATIC int
278 758 : xfs_fsrefs_ddev_refcountbt_helper(
279 : struct xfs_btree_cur *cur,
280 : const struct xfs_refcount_irec *rec,
281 : void *priv)
282 : {
283 758 : struct xfs_mount *mp = cur->bc_mp;
284 758 : struct xfs_fsrefs_info *info = priv;
285 758 : xfs_daddr_t rec_daddr;
286 758 : int error;
287 :
288 : /*
289 : * Stop once we get to the CoW staging extents; they're all shoved to
290 : * the right side of the btree and were already covered by the bnobt
291 : * scan.
292 : */
293 758 : if (rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
294 : return -ECANCELED;
295 :
296 : /* Report on any gaps first */
297 758 : error = xfs_fsrefs_ddev_fill_refcount_gap(cur->bc_tp, info,
298 758 : rec->rc_startblock);
299 758 : if (error)
300 : return error;
301 :
302 147 : rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
303 : rec->rc_startblock);
304 147 : info->next_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
305 : rec->rc_startblock + rec->rc_blockcount);
306 :
307 147 : return xfs_fsrefs_helper(cur->bc_tp, info, rec, rec_daddr, 0);
308 : }
309 :
310 : /* Execute a getfsrefs query against the regular data device. */
311 : STATIC int
312 1011 : xfs_fsrefs_ddev(
313 : struct xfs_trans *tp,
314 : const struct xfs_fsrefs *keys,
315 : struct xfs_fsrefs_info *info)
316 : {
317 1011 : struct xfs_mount *mp = tp->t_mountp;
318 1011 : struct xfs_buf *agf_bp = NULL;
319 1011 : struct xfs_perag *pag = NULL;
320 1011 : xfs_fsblock_t start_fsb;
321 1011 : xfs_fsblock_t end_fsb;
322 1011 : xfs_agnumber_t start_ag;
323 1011 : xfs_agnumber_t end_ag;
324 1011 : xfs_agnumber_t agno;
325 1011 : uint64_t eofs;
326 1011 : int error = 0;
327 :
328 1011 : eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
329 1011 : if (keys[0].fcr_physical >= eofs)
330 : return 0;
331 1011 : start_fsb = XFS_DADDR_TO_FSB(mp, keys[0].fcr_physical);
332 1011 : end_fsb = XFS_DADDR_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
333 :
334 1011 : info->refc_cur = info->bno_cur = NULL;
335 :
336 : /*
337 : * Convert the fsrefs low/high keys to AG based keys. Initialize
338 : * low to the fsrefs low key and max out the high key to the end
339 : * of the AG.
340 : */
341 1011 : info->low.rc_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
342 1011 : info->low.rc_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fcr_length);
343 1011 : info->low.rc_refcount = 0;
344 1011 : info->low.rc_domain = XFS_REFC_DOMAIN_SHARED;
345 :
346 : /* Adjust the low key if we are continuing from where we left off. */
347 1011 : if (info->low.rc_blockcount > 0) {
348 1005 : info->low.rc_startblock += info->low.rc_blockcount;
349 :
350 1005 : start_fsb += info->low.rc_blockcount;
351 1005 : if (XFS_FSB_TO_DADDR(mp, start_fsb) >= eofs)
352 : return 0;
353 : }
354 :
355 1011 : info->high.rc_startblock = -1U;
356 1011 : info->high.rc_blockcount = 0;
357 1011 : info->high.rc_refcount = 0;
358 1011 : info->high.rc_domain = XFS_REFC_DOMAIN_SHARED;
359 :
360 1011 : start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
361 1011 : end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
362 :
363 : /* Query each AG */
364 1011 : agno = start_ag;
365 1041 : for_each_perag_range(mp, agno, end_ag, pag) {
366 : /*
367 : * Set the AG high key from the fsrefs high key if this
368 : * is the last AG that we're querying.
369 : */
370 1035 : info->pag = pag;
371 1035 : if (pag->pag_agno == end_ag)
372 254 : info->high.rc_startblock = XFS_FSB_TO_AGBNO(mp,
373 : end_fsb);
374 :
375 1035 : if (info->refc_cur) {
376 24 : xfs_btree_del_cursor(info->refc_cur, XFS_BTREE_NOERROR);
377 24 : info->refc_cur = NULL;
378 : }
379 1035 : if (info->bno_cur) {
380 24 : xfs_btree_del_cursor(info->bno_cur, XFS_BTREE_NOERROR);
381 24 : info->bno_cur = NULL;
382 : }
383 1035 : if (agf_bp) {
384 24 : xfs_trans_brelse(tp, agf_bp);
385 24 : agf_bp = NULL;
386 : }
387 :
388 1035 : error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
389 1035 : if (error)
390 : break;
391 :
392 1035 : trace_xfs_fsrefs_low_key(mp, info->dev, pag->pag_agno,
393 1035 : &info->low);
394 1035 : trace_xfs_fsrefs_high_key(mp, info->dev, pag->pag_agno,
395 1035 : &info->high);
396 :
397 1035 : info->bno_cur = xfs_allocbt_init_cursor(mp, tp, agf_bp, pag,
398 : XFS_BTNUM_BNO);
399 :
400 1035 : if (xfs_has_reflink(mp)) {
401 1035 : info->refc_cur = xfs_refcountbt_init_cursor(mp, tp,
402 : agf_bp, pag);
403 :
404 : /*
405 : * Fill the query with refcount records and synthesize
406 : * singly-owned block records from free space data.
407 : */
408 1035 : error = xfs_refcount_query_range(info->refc_cur,
409 : &info->low, &info->high,
410 : xfs_fsrefs_ddev_refcountbt_helper,
411 : info);
412 1035 : if (error && error != -ECANCELED)
413 : break;
414 : }
415 :
416 : /*
417 : * Synthesize refcount==1 records from the free space data
418 : * between the end of the last fsrefs record reported and the
419 : * end of the range. If we don't have refcount support, the
420 : * starting point will be the start of the query range.
421 : */
422 1035 : error = xfs_fsrefs_ddev_fill_refcount_gap(tp, info,
423 : info->high.rc_startblock);
424 1035 : if (error)
425 : break;
426 :
427 : /*
428 : * Set the AG low key to the start of the AG prior to
429 : * moving on to the next AG.
430 : */
431 30 : if (pag->pag_agno == start_ag)
432 36 : memset(&info->low, 0, sizeof(info->low));
433 :
434 30 : info->pag = NULL;
435 : }
436 :
437 1011 : if (info->refc_cur) {
438 1011 : xfs_btree_del_cursor(info->refc_cur, error);
439 1011 : info->refc_cur = NULL;
440 : }
441 1011 : if (info->bno_cur) {
442 1011 : xfs_btree_del_cursor(info->bno_cur, error);
443 1011 : info->bno_cur = NULL;
444 : }
445 1011 : if (agf_bp)
446 1011 : xfs_trans_brelse(tp, agf_bp);
447 1011 : if (info->pag) {
448 1005 : xfs_perag_rele(info->pag);
449 1005 : info->pag = NULL;
450 6 : } else if (pag) {
451 : /* loop termination case */
452 0 : xfs_perag_rele(pag);
453 : }
454 :
455 : return error;
456 : }
457 :
458 : /* Execute a getfsrefs query against the log device. */
459 : STATIC int
460 0 : xfs_fsrefs_logdev(
461 : struct xfs_trans *tp,
462 : const struct xfs_fsrefs *keys,
463 : struct xfs_fsrefs_info *info)
464 : {
465 0 : struct xfs_mount *mp = tp->t_mountp;
466 0 : struct xfs_refcount_irec refc;
467 0 : xfs_daddr_t rec_daddr, len_daddr;
468 0 : xfs_fsblock_t start_fsb, end_fsb;
469 0 : uint64_t eofs;
470 :
471 0 : eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
472 0 : if (keys[0].fcr_physical >= eofs)
473 : return 0;
474 0 : start_fsb = XFS_BB_TO_FSBT(mp,
475 : keys[0].fcr_physical + keys[0].fcr_length);
476 0 : end_fsb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
477 :
478 : /* Adjust the low key if we are continuing from where we left off. */
479 0 : if (keys[0].fcr_length > 0)
480 0 : info->low_daddr = XFS_FSB_TO_BB(mp, start_fsb);
481 :
482 0 : trace_xfs_fsrefs_low_key_linear(mp, info->dev, start_fsb);
483 0 : trace_xfs_fsrefs_high_key_linear(mp, info->dev, end_fsb);
484 :
485 0 : if (start_fsb > 0)
486 : return 0;
487 :
488 : /* Fabricate an refc entry for the external log device. */
489 0 : refc.rc_startblock = 0;
490 0 : refc.rc_blockcount = mp->m_sb.sb_logblocks;
491 0 : refc.rc_refcount = 1;
492 0 : refc.rc_domain = XFS_REFC_DOMAIN_SHARED;
493 :
494 0 : rec_daddr = XFS_FSB_TO_BB(mp, refc.rc_startblock);
495 0 : len_daddr = XFS_FSB_TO_BB(mp, refc.rc_blockcount);
496 0 : return xfs_fsrefs_helper(tp, info, &refc, rec_daddr, len_daddr);
497 : }
498 :
499 : #ifdef CONFIG_XFS_RT
500 : /* Synthesize fsrefs records from rtbitmap records. */
501 : STATIC int
502 0 : xfs_fsrefs_rtdev_bitmap_helper(
503 : struct xfs_mount *mp,
504 : struct xfs_trans *tp,
505 : const struct xfs_rtalloc_rec *rec,
506 : void *priv)
507 : {
508 0 : struct xfs_refcount_irec irec;
509 0 : struct xfs_fsrefs_info *info = priv;
510 0 : xfs_rtblock_t rt_startblock;
511 0 : xfs_rtblock_t rec_rtlen;
512 0 : xfs_rtblock_t next_rtbno;
513 0 : xfs_daddr_t rec_daddr, len_daddr;
514 :
515 : /*
516 : * Figure out if there's a gap between the last fsrefs record we
517 : * emitted and this free extent. If there is, report the gap as a
518 : * refcount==1 record.
519 : */
520 0 : next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
521 0 : rec_daddr = XFS_FSB_TO_BB(mp, next_rtbno);
522 0 : irec.rc_startblock = next_rtbno;
523 :
524 0 : rt_startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
525 0 : rec_rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
526 :
527 0 : ASSERT(rt_startblock >= next_rtbno);
528 :
529 0 : info->next_daddr = XFS_FSB_TO_BB(mp, rt_startblock + rec_rtlen);
530 :
531 0 : if (rt_startblock == next_rtbno)
532 : return 0;
533 :
534 : /* Emit a record for the in-use space */
535 0 : irec.rc_blockcount = rt_startblock - next_rtbno;
536 0 : len_daddr = XFS_FSB_TO_BB(mp, rt_startblock - next_rtbno);
537 :
538 0 : irec.rc_refcount = 1;
539 0 : irec.rc_domain = XFS_REFC_DOMAIN_SHARED;
540 :
541 0 : return xfs_fsrefs_helper(tp, info, &irec, rec_daddr, len_daddr);
542 : }
543 :
544 : /* Emit records to fill a gap in the refcount btree with singly-owned blocks. */
545 : STATIC int
546 0 : xfs_fsrefs_rtdev_fill_refcount_gap(
547 : struct xfs_trans *tp,
548 : struct xfs_fsrefs_info *info,
549 : xfs_rtblock_t start_rtb,
550 : xfs_rtblock_t end_rtb)
551 : {
552 0 : struct xfs_rtalloc_rec low = { 0 };
553 0 : struct xfs_rtalloc_rec high = { 0 };
554 0 : struct xfs_mount *mp = tp->t_mountp;
555 0 : xfs_daddr_t rec_daddr;
556 0 : xfs_extlen_t mod;
557 0 : int error;
558 :
559 : /*
560 : * Set up query parameters to return free extents covering the range we
561 : * want.
562 : */
563 0 : low.ar_startext = xfs_rtb_to_rtxt(mp, start_rtb);
564 0 : high.ar_startext = xfs_rtb_to_rtx(mp, end_rtb, &mod);
565 0 : if (mod)
566 0 : high.ar_startext++;
567 :
568 0 : error = xfs_rtalloc_query_range(mp, tp, &low, &high,
569 : xfs_fsrefs_rtdev_bitmap_helper, info);
570 0 : if (error)
571 : return error;
572 :
573 : /*
574 : * Synthesize records for single-owner extents between the last
575 : * fsrefcount record emitted and the end of the query range.
576 : */
577 0 : high.ar_startext = min(mp->m_sb.sb_rextents, high.ar_startext);
578 0 : rec_daddr = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, high.ar_startext));
579 0 : if (info->next_daddr > rec_daddr)
580 : return 0;
581 :
582 0 : info->last = true;
583 0 : return xfs_fsrefs_rtdev_bitmap_helper(mp, tp, &high, info);
584 : }
585 :
586 : /* Transform a absolute-startblock refcount (rtdev, logdev) into a fsrefs */
587 : STATIC int
588 0 : xfs_fsrefs_rtdev_refcountbt_helper(
589 : struct xfs_btree_cur *cur,
590 : const struct xfs_refcount_irec *rec,
591 : void *priv)
592 : {
593 0 : struct xfs_mount *mp = cur->bc_mp;
594 0 : struct xfs_fsrefs_info *info = priv;
595 0 : xfs_rtblock_t rec_rtbno, next_rtbno;
596 0 : int error;
597 :
598 : /*
599 : * Stop once we get to the CoW staging extents; they're all shoved to
600 : * the right side of the btree and were already covered by the rtbitmap
601 : * scan.
602 : */
603 0 : if (rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
604 : return -ECANCELED;
605 :
606 : /* Report on any gaps first */
607 0 : rec_rtbno = xfs_rgbno_to_rtb(mp, cur->bc_ino.rtg->rtg_rgno,
608 0 : rec->rc_startblock);
609 0 : next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
610 0 : error = xfs_fsrefs_rtdev_fill_refcount_gap(cur->bc_tp, info,
611 : next_rtbno, rec_rtbno);
612 0 : if (error)
613 : return error;
614 :
615 : /* Report this refcount extent. */
616 0 : info->next_daddr = XFS_FSB_TO_BB(mp, rec_rtbno + rec->rc_blockcount);
617 0 : return xfs_fsrefs_helper(cur->bc_tp, info, rec,
618 0 : XFS_FSB_TO_BB(mp, rec_rtbno), 0);
619 : }
620 :
621 : /* Execute a getfsrefs query against the realtime bitmap. */
622 : STATIC int
623 0 : xfs_fsrefs_rtdev_rtbitmap(
624 : struct xfs_trans *tp,
625 : const struct xfs_fsrefs *keys,
626 : struct xfs_fsrefs_info *info)
627 : {
628 0 : struct xfs_mount *mp = tp->t_mountp;
629 0 : xfs_rtblock_t start_rtb;
630 0 : xfs_rtblock_t end_rtb;
631 0 : uint64_t eofs;
632 0 : int error;
633 :
634 0 : eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
635 0 : if (keys[0].fcr_physical >= eofs)
636 : return 0;
637 0 : start_rtb = XFS_BB_TO_FSBT(mp,
638 : keys[0].fcr_physical + keys[0].fcr_length);
639 0 : end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
640 :
641 0 : info->refc_cur = NULL;
642 :
643 : /* Adjust the low key if we are continuing from where we left off. */
644 0 : if (keys[0].fcr_length > 0) {
645 0 : info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
646 0 : if (info->low_daddr >= eofs)
647 : return 0;
648 : }
649 :
650 0 : trace_xfs_fsrefs_low_key_linear(mp, info->dev, start_rtb);
651 0 : trace_xfs_fsrefs_high_key_linear(mp, info->dev, end_rtb);
652 :
653 : /* Synthesize refcount==1 records from the free space data. */
654 0 : xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
655 0 : error = xfs_fsrefs_rtdev_fill_refcount_gap(tp, info, start_rtb,
656 : end_rtb);
657 0 : xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
658 0 : return error;
659 : }
660 :
661 : #define XFS_RTGLOCK_FSREFS (XFS_RTGLOCK_BITMAP_SHARED | \
662 : XFS_RTGLOCK_REFCOUNT)
663 :
664 : /* Execute a getfsrefs query against the realtime device. */
665 : STATIC int
666 0 : xfs_fsrefs_rtdev(
667 : struct xfs_trans *tp,
668 : const struct xfs_fsrefs *keys,
669 : struct xfs_fsrefs_info *info)
670 : {
671 0 : struct xfs_mount *mp = tp->t_mountp;
672 0 : struct xfs_rtgroup *rtg;
673 0 : xfs_rtblock_t start_rtb;
674 0 : xfs_rtblock_t end_rtb;
675 0 : uint64_t eofs;
676 0 : xfs_rgnumber_t start_rg, end_rg;
677 0 : int error = 0;
678 :
679 0 : eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
680 0 : if (keys[0].fcr_physical >= eofs)
681 : return 0;
682 0 : start_rtb = XFS_BB_TO_FSBT(mp, keys[0].fcr_physical);
683 0 : end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
684 :
685 0 : info->refc_cur = NULL;
686 :
687 : /*
688 : * Convert the fsrefs low/high keys to rtgroup based keys. Initialize
689 : * low to the fsrefs low key and max out the high key to the end of the
690 : * rtgroup.
691 : */
692 0 : info->low.rc_startblock = xfs_rtb_to_rgbno(mp, start_rtb, &start_rg);
693 0 : info->low.rc_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fcr_length);
694 0 : info->low.rc_refcount = 0;
695 0 : info->low.rc_domain = XFS_REFC_DOMAIN_SHARED;
696 :
697 : /* Adjust the low key if we are continuing from where we left off. */
698 0 : if (info->low.rc_blockcount > 0) {
699 0 : info->low.rc_startblock += info->low.rc_blockcount;
700 :
701 0 : start_rtb += info->low.rc_blockcount;
702 0 : if (xfs_rtb_to_daddr(mp, start_rtb) >= eofs)
703 : return 0;
704 : }
705 :
706 0 : info->high.rc_startblock = -1U;
707 0 : info->high.rc_blockcount = 0;
708 0 : info->high.rc_refcount = 0;
709 0 : info->high.rc_domain = XFS_REFC_DOMAIN_SHARED;
710 :
711 0 : end_rg = xfs_rtb_to_rgno(mp, end_rtb);
712 :
713 0 : for_each_rtgroup_range(mp, start_rg, end_rg, rtg) {
714 : /*
715 : * Set the rtgroup high key from the fsrefs high key if this
716 : * is the last rtgroup that we're querying.
717 : */
718 0 : info->rtg = rtg;
719 0 : if (rtg->rtg_rgno == end_rg) {
720 0 : xfs_rgnumber_t junk;
721 :
722 0 : info->high.rc_startblock = xfs_rtb_to_rgbno(mp,
723 : end_rtb, &junk);
724 : }
725 :
726 0 : if (info->refc_cur) {
727 0 : xfs_rtgroup_unlock(info->refc_cur->bc_ino.rtg,
728 : XFS_RTGLOCK_FSREFS);
729 0 : xfs_btree_del_cursor(info->refc_cur, XFS_BTREE_NOERROR);
730 0 : info->refc_cur = NULL;
731 : }
732 :
733 0 : trace_xfs_fsrefs_low_key(mp, info->dev, rtg->rtg_rgno,
734 0 : &info->low);
735 0 : trace_xfs_fsrefs_high_key(mp, info->dev, rtg->rtg_rgno,
736 0 : &info->high);
737 :
738 0 : xfs_rtgroup_lock(NULL, rtg, XFS_RTGLOCK_FSREFS);
739 0 : info->refc_cur = xfs_rtrefcountbt_init_cursor(mp, tp, rtg,
740 : rtg->rtg_refcountip);
741 :
742 : /*
743 : * Fill the query with refcount records and synthesize
744 : * singly-owned block records from free space data.
745 : */
746 0 : error = xfs_refcount_query_range(info->refc_cur,
747 : &info->low, &info->high,
748 : xfs_fsrefs_rtdev_refcountbt_helper, info);
749 0 : if (error && error != -ECANCELED)
750 : break;
751 :
752 : /*
753 : * Set the rtgroup low key to the start of the rtgroup prior to
754 : * moving on to the next rtgroup.
755 : */
756 0 : if (rtg->rtg_rgno == start_rg)
757 0 : memset(&info->low, 0, sizeof(info->low));
758 :
759 : /*
760 : * If this is the last rtgroup, report any gap at the end of it
761 : * before we drop the reference to the perag when the loop
762 : * terminates.
763 : */
764 0 : if (rtg->rtg_rgno == end_rg) {
765 0 : xfs_rtblock_t next_rtbno;
766 :
767 0 : info->last = true;
768 0 : next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
769 0 : error = xfs_fsrefs_rtdev_fill_refcount_gap(tp, info,
770 : next_rtbno, end_rtb);
771 0 : if (error)
772 : break;
773 : }
774 0 : info->rtg = NULL;
775 : }
776 :
777 0 : if (info->refc_cur) {
778 0 : xfs_rtgroup_unlock(info->refc_cur->bc_ino.rtg,
779 : XFS_RTGLOCK_FSREFS);
780 0 : xfs_btree_del_cursor(info->refc_cur, error);
781 0 : info->refc_cur = NULL;
782 : }
783 0 : if (info->rtg) {
784 0 : xfs_rtgroup_rele(info->rtg);
785 0 : info->rtg = NULL;
786 0 : } else if (rtg) {
787 : /* loop termination case */
788 0 : xfs_rtgroup_rele(rtg);
789 : }
790 :
791 : return error;
792 : }
793 : #endif
794 :
795 : /* Do we recognize the device? */
796 : STATIC bool
797 2022 : xfs_fsrefs_is_valid_device(
798 : struct xfs_mount *mp,
799 : struct xfs_fsrefs *fcr)
800 : {
801 2022 : if (fcr->fcr_device == 0 || fcr->fcr_device == UINT_MAX ||
802 1005 : fcr->fcr_device == new_encode_dev(mp->m_ddev_targp->bt_dev))
803 : return true;
804 0 : if (mp->m_logdev_targp &&
805 0 : fcr->fcr_device == new_encode_dev(mp->m_logdev_targp->bt_dev))
806 : return true;
807 0 : if (mp->m_rtdev_targp &&
808 0 : fcr->fcr_device == new_encode_dev(mp->m_rtdev_targp->bt_dev))
809 0 : return true;
810 : return false;
811 : }
812 :
813 : /* Ensure that the low key is less than the high key. */
814 : STATIC bool
815 1011 : xfs_fsrefs_check_keys(
816 : struct xfs_fsrefs *low_key,
817 : struct xfs_fsrefs *high_key)
818 : {
819 1011 : if (low_key->fcr_device > high_key->fcr_device)
820 : return false;
821 1011 : if (low_key->fcr_device < high_key->fcr_device)
822 : return true;
823 :
824 0 : if (low_key->fcr_physical > high_key->fcr_physical)
825 : return false;
826 0 : if (low_key->fcr_physical < high_key->fcr_physical)
827 0 : return true;
828 :
829 : return false;
830 : }
831 :
832 : /*
833 : * There are only two devices if we didn't configure RT devices at build time.
834 : */
835 : #ifdef CONFIG_XFS_RT
836 : #define XFS_GETFSREFS_DEVS 3
837 : #else
838 : #define XFS_GETFSREFS_DEVS 2
839 : #endif /* CONFIG_XFS_RT */
840 :
841 : /*
842 : * Get filesystem's extent refcounts as described in head, and format for
843 : * output. Fills in the supplied records array until there are no more reverse
844 : * mappings to return or head.fch_entries == head.fch_count. In the second
845 : * case, this function returns -ECANCELED to indicate that more records would
846 : * have been returned.
847 : *
848 : * Key to Confusion
849 : * ----------------
850 : * There are multiple levels of keys and counters at work here:
851 : * xfs_fsrefs_head.fch_keys -- low and high fsrefs keys passed in;
852 : * these reflect fs-wide sector addrs.
853 : * dkeys -- fch_keys used to query each device;
854 : * these are fch_keys but w/ the low key
855 : * bumped up by fcr_length.
856 : * xfs_fsrefs_info.next_daddr-- next disk addr we expect to see; this
857 : * is how we detect gaps in the fsrefs
858 : * records and report them.
859 : * xfs_fsrefs_info.low/high -- per-AG low/high keys computed from
860 : * dkeys; used to query the metadata.
861 : */
862 : int
863 1011 : xfs_getfsrefs(
864 : struct xfs_mount *mp,
865 : struct xfs_fsrefs_head *head,
866 : struct xfs_getfsrefs *fsrefs_recs)
867 : {
868 1011 : struct xfs_trans *tp = NULL;
869 1011 : struct xfs_fsrefs dkeys[2]; /* per-dev keys */
870 1011 : struct xfs_fsrefs_dev handlers[XFS_GETFSREFS_DEVS];
871 1011 : struct xfs_fsrefs_info info = { NULL };
872 1011 : int i;
873 1011 : int error = 0;
874 :
875 1011 : if (head->fch_iflags & ~FCH_IF_VALID)
876 : return -EINVAL;
877 1011 : if (!xfs_fsrefs_is_valid_device(mp, &head->fch_keys[0]) ||
878 1011 : !xfs_fsrefs_is_valid_device(mp, &head->fch_keys[1]))
879 : return -EINVAL;
880 1011 : if (!xfs_fsrefs_check_keys(&head->fch_keys[0], &head->fch_keys[1]))
881 : return -EINVAL;
882 :
883 1011 : head->fch_entries = 0;
884 :
885 : /* Set up our device handlers. */
886 1011 : memset(handlers, 0, sizeof(handlers));
887 1011 : handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
888 1011 : handlers[0].fn = xfs_fsrefs_ddev;
889 1011 : if (mp->m_logdev_targp != mp->m_ddev_targp) {
890 0 : handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
891 0 : handlers[1].fn = xfs_fsrefs_logdev;
892 : }
893 : #ifdef CONFIG_XFS_RT
894 1011 : if (mp->m_rtdev_targp) {
895 0 : handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
896 0 : if (xfs_has_rtreflink(mp))
897 0 : handlers[2].fn = xfs_fsrefs_rtdev;
898 : else
899 0 : handlers[2].fn = xfs_fsrefs_rtdev_rtbitmap;
900 : }
901 : #endif /* CONFIG_XFS_RT */
902 :
903 1011 : xfs_sort(handlers, XFS_GETFSREFS_DEVS, sizeof(struct xfs_fsrefs_dev),
904 : xfs_fsrefs_dev_compare);
905 :
906 : /*
907 : * To continue where we left off, we allow userspace to use the last
908 : * mapping from a previous call as the low key of the next. This is
909 : * identified by a non-zero length in the low key. We have to increment
910 : * the low key in this scenario to ensure we don't return the same
911 : * mapping again, and instead return the very next mapping. Bump the
912 : * physical offset as there can be no other mapping for the same
913 : * physical block range.
914 : *
915 : * Each fsrefs backend is responsible for making this adjustment as
916 : * appropriate for the backend.
917 : */
918 1011 : dkeys[0] = head->fch_keys[0];
919 1011 : memset(&dkeys[1], 0xFF, sizeof(struct xfs_fsrefs));
920 :
921 1011 : info.next_daddr = head->fch_keys[0].fcr_physical +
922 1011 : head->fch_keys[0].fcr_length;
923 1011 : info.fsrefs_recs = fsrefs_recs;
924 1011 : info.head = head;
925 :
926 : /* For each device we support... */
927 3039 : for (i = 0; i < XFS_GETFSREFS_DEVS; i++) {
928 : /* Is this device within the range the user asked for? */
929 3033 : if (!handlers[i].fn)
930 2022 : continue;
931 1011 : if (head->fch_keys[0].fcr_device > handlers[i].dev)
932 0 : continue;
933 1011 : if (head->fch_keys[1].fcr_device < handlers[i].dev)
934 : break;
935 :
936 : /*
937 : * If this device number matches the high key, we have to pass
938 : * the high key to the handler to limit the query results. If
939 : * the device number exceeds the low key, zero out the low key
940 : * so that we get everything from the beginning.
941 : */
942 1011 : if (handlers[i].dev == head->fch_keys[1].fcr_device)
943 0 : dkeys[1] = head->fch_keys[1];
944 1011 : if (handlers[i].dev > head->fch_keys[0].fcr_device)
945 6 : memset(&dkeys[0], 0, sizeof(struct xfs_fsrefs));
946 :
947 : /*
948 : * Grab an empty transaction so that we can use its recursive
949 : * buffer locking abilities to detect cycles in the refcountbt
950 : * without deadlocking.
951 : */
952 1011 : error = xfs_trans_alloc_empty(mp, &tp);
953 1011 : if (error)
954 : break;
955 :
956 1011 : info.dev = handlers[i].dev;
957 1011 : info.last = false;
958 1011 : info.pag = NULL;
959 1011 : info.rtg = NULL;
960 1011 : info.low_daddr = -1ULL;
961 1011 : info.low.rc_blockcount = 0;
962 1011 : error = handlers[i].fn(tp, dkeys, &info);
963 1011 : if (error)
964 : break;
965 6 : xfs_trans_cancel(tp);
966 6 : tp = NULL;
967 6 : info.next_daddr = 0;
968 : }
969 :
970 1011 : if (tp)
971 1005 : xfs_trans_cancel(tp);
972 1011 : head->fch_oflags = FCH_OF_DEV_T;
973 1011 : return error;
974 : }
|