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 36143 : dest->fcr_device = src->fcr_device;
74 36143 : dest->fcr_flags = src->fcr_flags;
75 36143 : dest->fcr_physical = BBTOB(src->fcr_physical);
76 36143 : dest->fcr_owners = src->fcr_owners;
77 36143 : dest->fcr_length = BBTOB(src->fcr_length);
78 36143 : dest->fcr_reserved[0] = 0;
79 36143 : dest->fcr_reserved[1] = 0;
80 36143 : dest->fcr_reserved[2] = 0;
81 36143 : dest->fcr_reserved[3] = 0;
82 : }
83 :
84 : /* Convert an fsrefs to an xfs_fsrefs. */
85 : void
86 24837 : xfs_fsrefs_to_internal(
87 : struct xfs_fsrefs *dest,
88 : struct xfs_getfsrefs *src)
89 : {
90 24837 : dest->fcr_device = src->fcr_device;
91 24837 : dest->fcr_flags = src->fcr_flags;
92 24837 : dest->fcr_physical = BTOBBT(src->fcr_physical);
93 24837 : dest->fcr_owners = src->fcr_owners;
94 24837 : dest->fcr_length = BTOBBT(src->fcr_length);
95 24837 : }
96 :
97 : /* Compare two getfsrefs device handlers. */
98 : static int
99 24837 : xfs_fsrefs_dev_compare(
100 : const void *p1,
101 : const void *p2)
102 : {
103 24837 : const struct xfs_fsrefs_dev *d1 = p1;
104 24837 : const struct xfs_fsrefs_dev *d2 = p2;
105 :
106 24837 : 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 51130 : if (info->low_daddr != -1ULL)
116 4045 : return rec_daddr < info->low_daddr;
117 47085 : if (info->low.rc_blockcount)
118 22669 : 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 51130 : 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 51130 : struct xfs_fsrefs fcr;
135 51130 : struct xfs_getfsrefs *row;
136 51130 : struct xfs_mount *mp = tp->t_mountp;
137 :
138 51130 : if (fatal_signal_pending(current))
139 : return -EINTR;
140 :
141 51130 : if (len_daddr == 0)
142 38090 : 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 77844 : if (xfs_fsrefs_rec_before_start(info, rec, rec_daddr))
149 : return 0;
150 :
151 : /* Are we just counting mappings? */
152 51130 : 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 51130 : if (info->head->fch_entries >= info->head->fch_count)
162 : return -ECANCELED;
163 :
164 36143 : if (info->pag)
165 23888 : trace_xfs_fsrefs_mapping(mp, info->dev, info->pag->pag_agno,
166 : rec);
167 12255 : else if (info->rtg)
168 6152 : trace_xfs_fsrefs_mapping(mp, info->dev, info->rtg->rtg_rgno,
169 : rec);
170 : else
171 6103 : trace_xfs_fsrefs_mapping(mp, info->dev, NULLAGNUMBER, rec);
172 :
173 36143 : fcr.fcr_device = info->dev;
174 36143 : fcr.fcr_flags = 0;
175 36143 : fcr.fcr_physical = rec_daddr;
176 36143 : fcr.fcr_owners = rec->rc_refcount;
177 36143 : fcr.fcr_length = len_daddr;
178 :
179 36143 : trace_xfs_getfsrefs_mapping(mp, &fcr);
180 :
181 36143 : row = &info->fsrefs_recs[info->head->fch_entries++];
182 36143 : xfs_fsrefs_from_internal(row, &fcr);
183 36143 : return 0;
184 : }
185 :
186 : /* Synthesize fsrefs records from free space data. */
187 : STATIC int
188 42643 : xfs_fsrefs_ddev_bnobt_helper(
189 : struct xfs_btree_cur *cur,
190 : const struct xfs_alloc_rec_incore *rec,
191 : void *priv)
192 : {
193 42643 : struct xfs_refcount_irec irec;
194 42643 : struct xfs_mount *mp = cur->bc_mp;
195 42643 : struct xfs_fsrefs_info *info = priv;
196 42643 : xfs_agnumber_t next_agno;
197 42643 : xfs_agblock_t next_agbno;
198 42643 : 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 42643 : next_agno = xfs_daddr_to_agno(mp, info->next_daddr);
206 42643 : next_agbno = xfs_daddr_to_agbno(mp, info->next_daddr);
207 :
208 42643 : ASSERT(next_agno >= cur->bc_ag.pag->pag_agno);
209 42643 : 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 42643 : if (next_agno > cur->bc_ag.pag->pag_agno)
216 : return 0;
217 :
218 42424 : info->next_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
219 : rec->ar_startblock + rec->ar_blockcount);
220 :
221 42424 : if (rec->ar_startblock == next_agbno)
222 : return 0;
223 :
224 : /* Emit a record for the in-use space */
225 35528 : irec.rc_startblock = next_agbno;
226 35528 : irec.rc_blockcount = rec->ar_startblock - next_agbno;
227 35528 : irec.rc_refcount = 1;
228 35528 : irec.rc_domain = XFS_REFC_DOMAIN_SHARED;
229 35528 : rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
230 : irec.rc_startblock);
231 :
232 35528 : 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 14797 : xfs_fsrefs_ddev_fill_refcount_gap(
238 : struct xfs_trans *tp,
239 : struct xfs_fsrefs_info *info,
240 : xfs_agblock_t agbno)
241 : {
242 14797 : struct xfs_alloc_rec_incore low = {0};
243 14797 : struct xfs_alloc_rec_incore high = {0};
244 14797 : struct xfs_mount *mp = tp->t_mountp;
245 14797 : struct xfs_btree_cur *cur = info->bno_cur;
246 14797 : struct xfs_agf *agf;
247 14797 : int error;
248 :
249 14797 : ASSERT(xfs_daddr_to_agno(mp, info->next_daddr) ==
250 : cur->bc_ag.pag->pag_agno);
251 :
252 14797 : low.ar_startblock = xfs_daddr_to_agbno(mp, info->next_daddr);
253 14797 : if (low.ar_startblock >= agbno)
254 : return 0;
255 :
256 13891 : high.ar_startblock = agbno;
257 13891 : error = xfs_alloc_query_range(cur, &low, &high,
258 : xfs_fsrefs_ddev_bnobt_helper, info);
259 13891 : 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 1395 : agf = cur->bc_ag.agbp->b_addr;
267 1395 : low.ar_startblock = min_t(xfs_agblock_t, agbno,
268 : be32_to_cpu(agf->agf_length));
269 1395 : if (xfs_daddr_to_agbno(mp, info->next_daddr) > low.ar_startblock)
270 : return 0;
271 :
272 1395 : info->last = true;
273 1395 : return xfs_fsrefs_ddev_bnobt_helper(cur, &low, info);
274 : }
275 :
276 : /* Transform a refcountbt irec into a fsrefs */
277 : STATIC int
278 7086 : xfs_fsrefs_ddev_refcountbt_helper(
279 : struct xfs_btree_cur *cur,
280 : const struct xfs_refcount_irec *rec,
281 : void *priv)
282 : {
283 7086 : struct xfs_mount *mp = cur->bc_mp;
284 7086 : struct xfs_fsrefs_info *info = priv;
285 7086 : xfs_daddr_t rec_daddr;
286 7086 : 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 7086 : if (rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
294 : return -ECANCELED;
295 :
296 : /* Report on any gaps first */
297 7086 : error = xfs_fsrefs_ddev_fill_refcount_gap(cur->bc_tp, info,
298 7086 : rec->rc_startblock);
299 7086 : if (error)
300 : return error;
301 :
302 1756 : rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
303 : rec->rc_startblock);
304 1756 : info->next_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
305 : rec->rc_startblock + rec->rc_blockcount);
306 :
307 1756 : 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 7531 : xfs_fsrefs_ddev(
313 : struct xfs_trans *tp,
314 : const struct xfs_fsrefs *keys,
315 : struct xfs_fsrefs_info *info)
316 : {
317 7531 : struct xfs_mount *mp = tp->t_mountp;
318 7531 : struct xfs_buf *agf_bp = NULL;
319 7531 : struct xfs_perag *pag = NULL;
320 7531 : xfs_fsblock_t start_fsb;
321 7531 : xfs_fsblock_t end_fsb;
322 7531 : xfs_agnumber_t start_ag;
323 7531 : xfs_agnumber_t end_ag;
324 7531 : xfs_agnumber_t agno;
325 7531 : uint64_t eofs;
326 7531 : int error = 0;
327 :
328 7531 : eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
329 7531 : if (keys[0].fcr_physical >= eofs)
330 : return 0;
331 7531 : start_fsb = XFS_DADDR_TO_FSB(mp, keys[0].fcr_physical);
332 7531 : end_fsb = XFS_DADDR_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
333 :
334 7531 : 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 7531 : info->low.rc_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
342 7531 : info->low.rc_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fcr_length);
343 7531 : info->low.rc_refcount = 0;
344 7531 : info->low.rc_domain = XFS_REFC_DOMAIN_SHARED;
345 :
346 : /* Adjust the low key if we are continuing from where we left off. */
347 7531 : if (info->low.rc_blockcount > 0) {
348 7498 : info->low.rc_startblock += info->low.rc_blockcount;
349 :
350 7498 : start_fsb += info->low.rc_blockcount;
351 7498 : if (XFS_FSB_TO_DADDR(mp, start_fsb) >= eofs)
352 : return 0;
353 : }
354 :
355 7531 : info->high.rc_startblock = -1U;
356 7531 : info->high.rc_blockcount = 0;
357 7531 : info->high.rc_refcount = 0;
358 7531 : info->high.rc_domain = XFS_REFC_DOMAIN_SHARED;
359 :
360 7531 : start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
361 7531 : end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
362 :
363 : /* Query each AG */
364 7531 : agno = start_ag;
365 7750 : 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 7711 : info->pag = pag;
371 7711 : if (pag->pag_agno == end_ag)
372 1625 : info->high.rc_startblock = XFS_FSB_TO_AGBNO(mp,
373 : end_fsb);
374 :
375 7711 : if (info->refc_cur) {
376 168 : xfs_btree_del_cursor(info->refc_cur, XFS_BTREE_NOERROR);
377 168 : info->refc_cur = NULL;
378 : }
379 7711 : if (info->bno_cur) {
380 180 : xfs_btree_del_cursor(info->bno_cur, XFS_BTREE_NOERROR);
381 180 : info->bno_cur = NULL;
382 : }
383 7711 : if (agf_bp) {
384 180 : xfs_trans_brelse(tp, agf_bp);
385 180 : agf_bp = NULL;
386 : }
387 :
388 7711 : error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
389 7711 : if (error)
390 : break;
391 :
392 7711 : trace_xfs_fsrefs_low_key(mp, info->dev, pag->pag_agno,
393 7711 : &info->low);
394 7711 : trace_xfs_fsrefs_high_key(mp, info->dev, pag->pag_agno,
395 7711 : &info->high);
396 :
397 7711 : info->bno_cur = xfs_allocbt_init_cursor(mp, tp, agf_bp, pag,
398 : XFS_BTNUM_BNO);
399 :
400 7711 : if (xfs_has_reflink(mp)) {
401 7678 : 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 7678 : error = xfs_refcount_query_range(info->refc_cur,
409 : &info->low, &info->high,
410 : xfs_fsrefs_ddev_refcountbt_helper,
411 : info);
412 7678 : 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 7711 : error = xfs_fsrefs_ddev_fill_refcount_gap(tp, info,
423 : info->high.rc_startblock);
424 7711 : 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 219 : if (pag->pag_agno == start_ag)
432 252 : memset(&info->low, 0, sizeof(info->low));
433 :
434 219 : info->pag = NULL;
435 : }
436 :
437 7531 : if (info->refc_cur) {
438 7510 : xfs_btree_del_cursor(info->refc_cur, error);
439 7510 : info->refc_cur = NULL;
440 : }
441 7531 : if (info->bno_cur) {
442 7531 : xfs_btree_del_cursor(info->bno_cur, error);
443 7531 : info->bno_cur = NULL;
444 : }
445 7531 : if (agf_bp)
446 7531 : xfs_trans_brelse(tp, agf_bp);
447 7531 : if (info->pag) {
448 7492 : xfs_perag_rele(info->pag);
449 7492 : info->pag = NULL;
450 39 : } 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 24 : xfs_fsrefs_logdev(
461 : struct xfs_trans *tp,
462 : const struct xfs_fsrefs *keys,
463 : struct xfs_fsrefs_info *info)
464 : {
465 24 : struct xfs_mount *mp = tp->t_mountp;
466 24 : struct xfs_refcount_irec refc;
467 24 : xfs_daddr_t rec_daddr, len_daddr;
468 24 : xfs_fsblock_t start_fsb, end_fsb;
469 24 : uint64_t eofs;
470 :
471 24 : eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
472 24 : if (keys[0].fcr_physical >= eofs)
473 : return 0;
474 24 : start_fsb = XFS_BB_TO_FSBT(mp,
475 : keys[0].fcr_physical + keys[0].fcr_length);
476 24 : 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 24 : if (keys[0].fcr_length > 0)
480 4 : info->low_daddr = XFS_FSB_TO_BB(mp, start_fsb);
481 :
482 24 : trace_xfs_fsrefs_low_key_linear(mp, info->dev, start_fsb);
483 24 : trace_xfs_fsrefs_high_key_linear(mp, info->dev, end_fsb);
484 :
485 24 : if (start_fsb > 0)
486 : return 0;
487 :
488 : /* Fabricate an refc entry for the external log device. */
489 20 : refc.rc_startblock = 0;
490 20 : refc.rc_blockcount = mp->m_sb.sb_logblocks;
491 20 : refc.rc_refcount = 1;
492 20 : refc.rc_domain = XFS_REFC_DOMAIN_SHARED;
493 :
494 20 : rec_daddr = XFS_FSB_TO_BB(mp, refc.rc_startblock);
495 20 : len_daddr = XFS_FSB_TO_BB(mp, refc.rc_blockcount);
496 20 : 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 13736 : 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 13736 : struct xfs_refcount_irec irec;
509 13736 : struct xfs_fsrefs_info *info = priv;
510 13736 : xfs_rtblock_t rt_startblock;
511 13736 : xfs_rtblock_t rec_rtlen;
512 13736 : xfs_rtblock_t next_rtbno;
513 13736 : 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 13736 : next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
521 13736 : rec_daddr = XFS_FSB_TO_BB(mp, next_rtbno);
522 13736 : irec.rc_startblock = next_rtbno;
523 :
524 13736 : rt_startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
525 13736 : rec_rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
526 :
527 13736 : ASSERT(rt_startblock >= next_rtbno);
528 :
529 13736 : info->next_daddr = XFS_FSB_TO_BB(mp, rt_startblock + rec_rtlen);
530 :
531 13736 : if (rt_startblock == next_rtbno)
532 : return 0;
533 :
534 : /* Emit a record for the in-use space */
535 13020 : irec.rc_blockcount = rt_startblock - next_rtbno;
536 13020 : len_daddr = XFS_FSB_TO_BB(mp, rt_startblock - next_rtbno);
537 :
538 13020 : irec.rc_refcount = 1;
539 13020 : irec.rc_domain = XFS_REFC_DOMAIN_SHARED;
540 :
541 13020 : 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 2141 : 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 2141 : struct xfs_rtalloc_rec low = { 0 };
553 2141 : struct xfs_rtalloc_rec high = { 0 };
554 2141 : struct xfs_mount *mp = tp->t_mountp;
555 2141 : xfs_daddr_t rec_daddr;
556 2141 : xfs_extlen_t mod;
557 2141 : int error;
558 :
559 : /*
560 : * Set up query parameters to return free extents covering the range we
561 : * want.
562 : */
563 2141 : low.ar_startext = xfs_rtb_to_rtxt(mp, start_rtb);
564 2141 : high.ar_startext = xfs_rtb_to_rtx(mp, end_rtb, &mod);
565 2141 : if (mod)
566 0 : high.ar_startext++;
567 :
568 2141 : error = xfs_rtalloc_query_range(mp, tp, &low, &high,
569 : xfs_fsrefs_rtdev_bitmap_helper, info);
570 2141 : 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 1033 : high.ar_startext = min(mp->m_sb.sb_rextents, high.ar_startext);
578 1033 : rec_daddr = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, high.ar_startext));
579 1033 : if (info->next_daddr > rec_daddr)
580 : return 0;
581 :
582 1033 : info->last = true;
583 1033 : 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 1377 : xfs_fsrefs_rtdev_refcountbt_helper(
589 : struct xfs_btree_cur *cur,
590 : const struct xfs_refcount_irec *rec,
591 : void *priv)
592 : {
593 1377 : struct xfs_mount *mp = cur->bc_mp;
594 1377 : struct xfs_fsrefs_info *info = priv;
595 1377 : xfs_rtblock_t rec_rtbno, next_rtbno;
596 1377 : 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 1377 : if (rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
604 : return -ECANCELED;
605 :
606 : /* Report on any gaps first */
607 1377 : rec_rtbno = xfs_rgbno_to_rtb(mp, cur->bc_ino.rtg->rtg_rgno,
608 1377 : rec->rc_startblock);
609 1377 : next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
610 1377 : error = xfs_fsrefs_rtdev_fill_refcount_gap(cur->bc_tp, info,
611 : next_rtbno, rec_rtbno);
612 1377 : if (error)
613 : return error;
614 :
615 : /* Report this refcount extent. */
616 806 : info->next_daddr = XFS_FSB_TO_BB(mp, rec_rtbno + rec->rc_blockcount);
617 1612 : return xfs_fsrefs_helper(cur->bc_tp, info, rec,
618 806 : XFS_FSB_TO_BB(mp, rec_rtbno), 0);
619 : }
620 :
621 : /* Execute a getfsrefs query against the realtime bitmap. */
622 : STATIC int
623 11 : xfs_fsrefs_rtdev_rtbitmap(
624 : struct xfs_trans *tp,
625 : const struct xfs_fsrefs *keys,
626 : struct xfs_fsrefs_info *info)
627 : {
628 11 : struct xfs_mount *mp = tp->t_mountp;
629 11 : xfs_rtblock_t start_rtb;
630 11 : xfs_rtblock_t end_rtb;
631 11 : uint64_t eofs;
632 11 : int error;
633 :
634 11 : eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
635 11 : if (keys[0].fcr_physical >= eofs)
636 : return 0;
637 11 : start_rtb = XFS_BB_TO_FSBT(mp,
638 : keys[0].fcr_physical + keys[0].fcr_length);
639 11 : end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
640 :
641 11 : info->refc_cur = NULL;
642 :
643 : /* Adjust the low key if we are continuing from where we left off. */
644 11 : if (keys[0].fcr_length > 0) {
645 7 : info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
646 7 : if (info->low_daddr >= eofs)
647 : return 0;
648 : }
649 :
650 11 : trace_xfs_fsrefs_low_key_linear(mp, info->dev, start_rtb);
651 11 : trace_xfs_fsrefs_high_key_linear(mp, info->dev, end_rtb);
652 :
653 : /* Synthesize refcount==1 records from the free space data. */
654 11 : xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
655 11 : error = xfs_fsrefs_rtdev_fill_refcount_gap(tp, info, start_rtb,
656 : end_rtb);
657 11 : xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
658 11 : 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 753 : xfs_fsrefs_rtdev(
667 : struct xfs_trans *tp,
668 : const struct xfs_fsrefs *keys,
669 : struct xfs_fsrefs_info *info)
670 : {
671 753 : struct xfs_mount *mp = tp->t_mountp;
672 753 : struct xfs_rtgroup *rtg;
673 753 : xfs_rtblock_t start_rtb;
674 753 : xfs_rtblock_t end_rtb;
675 753 : uint64_t eofs;
676 753 : xfs_rgnumber_t start_rg, end_rg;
677 753 : int error = 0;
678 :
679 753 : eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
680 753 : if (keys[0].fcr_physical >= eofs)
681 : return 0;
682 753 : start_rtb = XFS_BB_TO_FSBT(mp, keys[0].fcr_physical);
683 753 : end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
684 :
685 753 : 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 753 : info->low.rc_startblock = xfs_rtb_to_rgbno(mp, start_rtb, &start_rg);
693 753 : info->low.rc_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fcr_length);
694 753 : info->low.rc_refcount = 0;
695 753 : info->low.rc_domain = XFS_REFC_DOMAIN_SHARED;
696 :
697 : /* Adjust the low key if we are continuing from where we left off. */
698 753 : if (info->low.rc_blockcount > 0) {
699 737 : info->low.rc_startblock += info->low.rc_blockcount;
700 :
701 737 : start_rtb += info->low.rc_blockcount;
702 737 : if (xfs_rtb_to_daddr(mp, start_rtb) >= eofs)
703 : return 0;
704 : }
705 :
706 753 : info->high.rc_startblock = -1U;
707 753 : info->high.rc_blockcount = 0;
708 753 : info->high.rc_refcount = 0;
709 753 : info->high.rc_domain = XFS_REFC_DOMAIN_SHARED;
710 :
711 753 : end_rg = xfs_rtb_to_rgno(mp, end_rtb);
712 :
713 1520 : 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 1508 : info->rtg = rtg;
719 1508 : if (rtg->rtg_rgno == end_rg) {
720 753 : xfs_rgnumber_t junk;
721 :
722 753 : info->high.rc_startblock = xfs_rtb_to_rgbno(mp,
723 : end_rtb, &junk);
724 : }
725 :
726 1508 : if (info->refc_cur) {
727 755 : xfs_rtgroup_unlock(info->refc_cur->bc_ino.rtg,
728 : XFS_RTGLOCK_FSREFS);
729 755 : xfs_btree_del_cursor(info->refc_cur, XFS_BTREE_NOERROR);
730 755 : info->refc_cur = NULL;
731 : }
732 :
733 1508 : trace_xfs_fsrefs_low_key(mp, info->dev, rtg->rtg_rgno,
734 1508 : &info->low);
735 1508 : trace_xfs_fsrefs_high_key(mp, info->dev, rtg->rtg_rgno,
736 1508 : &info->high);
737 :
738 1508 : xfs_rtgroup_lock(NULL, rtg, XFS_RTGLOCK_FSREFS);
739 1508 : 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 1508 : error = xfs_refcount_query_range(info->refc_cur,
747 : &info->low, &info->high,
748 : xfs_fsrefs_rtdev_refcountbt_helper, info);
749 1508 : 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 1508 : if (rtg->rtg_rgno == start_rg)
757 3016 : 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 1508 : if (rtg->rtg_rgno == end_rg) {
765 753 : xfs_rtblock_t next_rtbno;
766 :
767 753 : info->last = true;
768 753 : next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
769 753 : error = xfs_fsrefs_rtdev_fill_refcount_gap(tp, info,
770 : next_rtbno, end_rtb);
771 753 : if (error)
772 : break;
773 : }
774 767 : info->rtg = NULL;
775 : }
776 :
777 753 : if (info->refc_cur) {
778 753 : xfs_rtgroup_unlock(info->refc_cur->bc_ino.rtg,
779 : XFS_RTGLOCK_FSREFS);
780 753 : xfs_btree_del_cursor(info->refc_cur, error);
781 753 : info->refc_cur = NULL;
782 : }
783 753 : if (info->rtg) {
784 741 : xfs_rtgroup_rele(info->rtg);
785 741 : info->rtg = NULL;
786 12 : } 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 16558 : xfs_fsrefs_is_valid_device(
798 : struct xfs_mount *mp,
799 : struct xfs_fsrefs *fcr)
800 : {
801 16558 : if (fcr->fcr_device == 0 || fcr->fcr_device == UINT_MAX ||
802 8246 : fcr->fcr_device == new_encode_dev(mp->m_ddev_targp->bt_dev))
803 : return true;
804 748 : if (mp->m_logdev_targp &&
805 748 : fcr->fcr_device == new_encode_dev(mp->m_logdev_targp->bt_dev))
806 : return true;
807 744 : if (mp->m_rtdev_targp &&
808 744 : fcr->fcr_device == new_encode_dev(mp->m_rtdev_targp->bt_dev))
809 744 : return true;
810 : return false;
811 : }
812 :
813 : /* Ensure that the low key is less than the high key. */
814 : STATIC bool
815 8279 : xfs_fsrefs_check_keys(
816 : struct xfs_fsrefs *low_key,
817 : struct xfs_fsrefs *high_key)
818 : {
819 8279 : if (low_key->fcr_device > high_key->fcr_device)
820 : return false;
821 8279 : 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 8279 : xfs_getfsrefs(
864 : struct xfs_mount *mp,
865 : struct xfs_fsrefs_head *head,
866 : struct xfs_getfsrefs *fsrefs_recs)
867 : {
868 8279 : struct xfs_trans *tp = NULL;
869 8279 : struct xfs_fsrefs dkeys[2]; /* per-dev keys */
870 8279 : struct xfs_fsrefs_dev handlers[XFS_GETFSREFS_DEVS];
871 8279 : struct xfs_fsrefs_info info = { NULL };
872 8279 : int i;
873 8279 : int error = 0;
874 :
875 8279 : if (head->fch_iflags & ~FCH_IF_VALID)
876 : return -EINVAL;
877 8279 : if (!xfs_fsrefs_is_valid_device(mp, &head->fch_keys[0]) ||
878 8279 : !xfs_fsrefs_is_valid_device(mp, &head->fch_keys[1]))
879 : return -EINVAL;
880 8279 : if (!xfs_fsrefs_check_keys(&head->fch_keys[0], &head->fch_keys[1]))
881 : return -EINVAL;
882 :
883 8279 : head->fch_entries = 0;
884 :
885 : /* Set up our device handlers. */
886 8279 : memset(handlers, 0, sizeof(handlers));
887 8279 : handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
888 8279 : handlers[0].fn = xfs_fsrefs_ddev;
889 8279 : if (mp->m_logdev_targp != mp->m_ddev_targp) {
890 1931 : handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
891 1931 : handlers[1].fn = xfs_fsrefs_logdev;
892 : }
893 : #ifdef CONFIG_XFS_RT
894 8279 : if (mp->m_rtdev_targp) {
895 823 : handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
896 823 : if (xfs_has_rtreflink(mp))
897 795 : handlers[2].fn = xfs_fsrefs_rtdev;
898 : else
899 28 : handlers[2].fn = xfs_fsrefs_rtdev_rtbitmap;
900 : }
901 : #endif /* CONFIG_XFS_RT */
902 :
903 8279 : 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 8279 : dkeys[0] = head->fch_keys[0];
919 8279 : memset(&dkeys[1], 0xFF, sizeof(struct xfs_fsrefs));
920 :
921 8279 : info.next_daddr = head->fch_keys[0].fcr_physical +
922 8279 : head->fch_keys[0].fcr_length;
923 8279 : info.fsrefs_recs = fsrefs_recs;
924 8279 : info.head = head;
925 :
926 : /* For each device we support... */
927 23641 : for (i = 0; i < XFS_GETFSREFS_DEVS; i++) {
928 : /* Is this device within the range the user asked for? */
929 23608 : if (!handlers[i].fn)
930 13804 : continue;
931 9804 : if (head->fch_keys[0].fcr_device > handlers[i].dev)
932 1485 : continue;
933 8319 : 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 8319 : if (handlers[i].dev == head->fch_keys[1].fcr_device)
943 0 : dkeys[1] = head->fch_keys[1];
944 8319 : if (handlers[i].dev > head->fch_keys[0].fcr_device)
945 73 : 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 8319 : error = xfs_trans_alloc_empty(mp, &tp);
953 8319 : if (error)
954 : break;
955 :
956 8319 : info.dev = handlers[i].dev;
957 8319 : info.last = false;
958 8319 : info.pag = NULL;
959 8319 : info.rtg = NULL;
960 8319 : info.low_daddr = -1ULL;
961 8319 : info.low.rc_blockcount = 0;
962 8319 : error = handlers[i].fn(tp, dkeys, &info);
963 8319 : if (error)
964 : break;
965 73 : xfs_trans_cancel(tp);
966 73 : tp = NULL;
967 73 : info.next_daddr = 0;
968 : }
969 :
970 8279 : if (tp)
971 8246 : xfs_trans_cancel(tp);
972 8279 : head->fch_oflags = FCH_OF_DEV_T;
973 8279 : return error;
974 : }
|