]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_refcount_btree.c
xfs: xfs_rtbuf_get should check the bmapi_read results
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_refcount_btree.c
CommitLineData
d8079fe0
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_priv.h"
21#include "xfs_fs.h"
22#include "xfs_shared.h"
23#include "xfs_format.h"
24#include "xfs_log_format.h"
25#include "xfs_trans_resv.h"
26#include "xfs_sb.h"
27#include "xfs_mount.h"
28#include "xfs_btree.h"
29#include "xfs_bmap.h"
30#include "xfs_refcount_btree.h"
31#include "xfs_alloc.h"
32#include "xfs_trace.h"
33#include "xfs_cksum.h"
34#include "xfs_trans.h"
35#include "xfs_bit.h"
bc859611 36#include "xfs_rmap.h"
d8079fe0
DW
37
38static struct xfs_btree_cur *
39xfs_refcountbt_dup_cursor(
40 struct xfs_btree_cur *cur)
41{
42 return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
43 cur->bc_private.a.agbp, cur->bc_private.a.agno,
44 cur->bc_private.a.dfops);
45}
46
bc859611
DW
47STATIC void
48xfs_refcountbt_set_root(
49 struct xfs_btree_cur *cur,
50 union xfs_btree_ptr *ptr,
51 int inc)
52{
53 struct xfs_buf *agbp = cur->bc_private.a.agbp;
54 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
55 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
56 struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno);
57
58 ASSERT(ptr->s != 0);
59
60 agf->agf_refcount_root = ptr->s;
61 be32_add_cpu(&agf->agf_refcount_level, inc);
62 pag->pagf_refcount_level += inc;
63 xfs_perag_put(pag);
64
65 xfs_alloc_log_agf(cur->bc_tp, agbp,
66 XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL);
67}
68
69STATIC int
70xfs_refcountbt_alloc_block(
71 struct xfs_btree_cur *cur,
72 union xfs_btree_ptr *start,
73 union xfs_btree_ptr *new,
74 int *stat)
75{
76 struct xfs_buf *agbp = cur->bc_private.a.agbp;
77 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
78 struct xfs_alloc_arg args; /* block allocation args */
79 int error; /* error return value */
80
81 memset(&args, 0, sizeof(args));
82 args.tp = cur->bc_tp;
83 args.mp = cur->bc_mp;
84 args.type = XFS_ALLOCTYPE_NEAR_BNO;
85 args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno,
86 xfs_refc_block(args.mp));
87 args.firstblock = args.fsbno;
88 xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_REFC);
89 args.minlen = args.maxlen = args.prod = 1;
02cc8b2a 90 args.resv = XFS_AG_RESV_METADATA;
bc859611
DW
91
92 error = xfs_alloc_vextent(&args);
93 if (error)
94 goto out_error;
95 trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno,
96 args.agbno, 1);
97 if (args.fsbno == NULLFSBLOCK) {
bc859611
DW
98 *stat = 0;
99 return 0;
100 }
101 ASSERT(args.agno == cur->bc_private.a.agno);
102 ASSERT(args.len == 1);
103
104 new->s = cpu_to_be32(args.agbno);
105 be32_add_cpu(&agf->agf_refcount_blocks, 1);
106 xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
107
bc859611
DW
108 *stat = 1;
109 return 0;
110
111out_error:
bc859611
DW
112 return error;
113}
114
115STATIC int
116xfs_refcountbt_free_block(
117 struct xfs_btree_cur *cur,
118 struct xfs_buf *bp)
119{
120 struct xfs_mount *mp = cur->bc_mp;
121 struct xfs_buf *agbp = cur->bc_private.a.agbp;
122 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
123 xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
124 struct xfs_owner_info oinfo;
02cc8b2a 125 int error;
bc859611
DW
126
127 trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_private.a.agno,
128 XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
129 xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_REFC);
130 be32_add_cpu(&agf->agf_refcount_blocks, -1);
131 xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
02cc8b2a
DW
132 error = xfs_free_extent(cur->bc_tp, fsbno, 1, &oinfo,
133 XFS_AG_RESV_METADATA);
134 if (error)
135 return error;
bc859611 136
02cc8b2a 137 return error;
bc859611
DW
138}
139
140STATIC int
141xfs_refcountbt_get_minrecs(
142 struct xfs_btree_cur *cur,
143 int level)
144{
145 return cur->bc_mp->m_refc_mnr[level != 0];
146}
147
148STATIC int
149xfs_refcountbt_get_maxrecs(
150 struct xfs_btree_cur *cur,
151 int level)
152{
153 return cur->bc_mp->m_refc_mxr[level != 0];
154}
155
156STATIC void
157xfs_refcountbt_init_key_from_rec(
158 union xfs_btree_key *key,
159 union xfs_btree_rec *rec)
160{
161 key->refc.rc_startblock = rec->refc.rc_startblock;
162}
163
164STATIC void
165xfs_refcountbt_init_high_key_from_rec(
166 union xfs_btree_key *key,
167 union xfs_btree_rec *rec)
168{
169 __u32 x;
170
171 x = be32_to_cpu(rec->refc.rc_startblock);
172 x += be32_to_cpu(rec->refc.rc_blockcount) - 1;
173 key->refc.rc_startblock = cpu_to_be32(x);
174}
175
176STATIC void
177xfs_refcountbt_init_rec_from_cur(
178 struct xfs_btree_cur *cur,
179 union xfs_btree_rec *rec)
180{
181 rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock);
182 rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount);
183 rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount);
184}
185
186STATIC void
187xfs_refcountbt_init_ptr_from_cur(
188 struct xfs_btree_cur *cur,
189 union xfs_btree_ptr *ptr)
190{
191 struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
192
193 ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno));
194 ASSERT(agf->agf_refcount_root != 0);
195
196 ptr->s = agf->agf_refcount_root;
197}
198
4a492e72 199STATIC int64_t
bc859611
DW
200xfs_refcountbt_key_diff(
201 struct xfs_btree_cur *cur,
202 union xfs_btree_key *key)
203{
204 struct xfs_refcount_irec *rec = &cur->bc_rec.rc;
205 struct xfs_refcount_key *kp = &key->refc;
206
4a492e72 207 return (int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock;
bc859611
DW
208}
209
4a492e72 210STATIC int64_t
bc859611
DW
211xfs_refcountbt_diff_two_keys(
212 struct xfs_btree_cur *cur,
213 union xfs_btree_key *k1,
214 union xfs_btree_key *k2)
215{
4a492e72 216 return (int64_t)be32_to_cpu(k1->refc.rc_startblock) -
bc859611
DW
217 be32_to_cpu(k2->refc.rc_startblock);
218}
219
bc01119d 220STATIC xfs_failaddr_t
d8079fe0
DW
221xfs_refcountbt_verify(
222 struct xfs_buf *bp)
223{
224 struct xfs_mount *mp = bp->b_target->bt_mount;
225 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
226 struct xfs_perag *pag = bp->b_pag;
bc01119d 227 xfs_failaddr_t fa;
d8079fe0
DW
228 unsigned int level;
229
230 if (block->bb_magic != cpu_to_be32(XFS_REFC_CRC_MAGIC))
bc01119d 231 return __this_address;
d8079fe0
DW
232
233 if (!xfs_sb_version_hasreflink(&mp->m_sb))
bc01119d
DW
234 return __this_address;
235 fa = xfs_btree_sblock_v5hdr_verify(bp);
236 if (fa)
237 return fa;
d8079fe0
DW
238
239 level = be16_to_cpu(block->bb_level);
240 if (pag && pag->pagf_init) {
241 if (level >= pag->pagf_refcount_level)
bc01119d 242 return __this_address;
d8079fe0 243 } else if (level >= mp->m_refc_maxlevels)
bc01119d 244 return __this_address;
d8079fe0
DW
245
246 return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]);
247}
248
249STATIC void
250xfs_refcountbt_read_verify(
251 struct xfs_buf *bp)
252{
1e697959
DW
253 xfs_failaddr_t fa;
254
d8079fe0 255 if (!xfs_btree_sblock_verify_crc(bp))
1e697959
DW
256 xfs_verifier_error(bp, -EFSBADCRC, __this_address);
257 else {
258 fa = xfs_refcountbt_verify(bp);
259 if (fa)
260 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
261 }
d8079fe0 262
7e6c95f1 263 if (bp->b_error)
d8079fe0 264 trace_xfs_btree_corrupt(bp, _RET_IP_);
d8079fe0
DW
265}
266
267STATIC void
268xfs_refcountbt_write_verify(
269 struct xfs_buf *bp)
270{
1e697959
DW
271 xfs_failaddr_t fa;
272
273 fa = xfs_refcountbt_verify(bp);
274 if (fa) {
d8079fe0 275 trace_xfs_btree_corrupt(bp, _RET_IP_);
1e697959 276 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
d8079fe0
DW
277 return;
278 }
279 xfs_btree_sblock_calc_crc(bp);
280
281}
282
283const struct xfs_buf_ops xfs_refcountbt_buf_ops = {
284 .name = "xfs_refcountbt",
285 .verify_read = xfs_refcountbt_read_verify,
286 .verify_write = xfs_refcountbt_write_verify,
95d9582b 287 .verify_struct = xfs_refcountbt_verify,
d8079fe0
DW
288};
289
bc859611
DW
290STATIC int
291xfs_refcountbt_keys_inorder(
292 struct xfs_btree_cur *cur,
293 union xfs_btree_key *k1,
294 union xfs_btree_key *k2)
295{
296 return be32_to_cpu(k1->refc.rc_startblock) <
297 be32_to_cpu(k2->refc.rc_startblock);
298}
299
300STATIC int
301xfs_refcountbt_recs_inorder(
302 struct xfs_btree_cur *cur,
303 union xfs_btree_rec *r1,
304 union xfs_btree_rec *r2)
305{
306 return be32_to_cpu(r1->refc.rc_startblock) +
307 be32_to_cpu(r1->refc.rc_blockcount) <=
308 be32_to_cpu(r2->refc.rc_startblock);
309}
bc859611 310
d8079fe0
DW
311static const struct xfs_btree_ops xfs_refcountbt_ops = {
312 .rec_len = sizeof(struct xfs_refcount_rec),
313 .key_len = sizeof(struct xfs_refcount_key),
314
315 .dup_cursor = xfs_refcountbt_dup_cursor,
bc859611
DW
316 .set_root = xfs_refcountbt_set_root,
317 .alloc_block = xfs_refcountbt_alloc_block,
318 .free_block = xfs_refcountbt_free_block,
319 .get_minrecs = xfs_refcountbt_get_minrecs,
320 .get_maxrecs = xfs_refcountbt_get_maxrecs,
321 .init_key_from_rec = xfs_refcountbt_init_key_from_rec,
322 .init_high_key_from_rec = xfs_refcountbt_init_high_key_from_rec,
323 .init_rec_from_cur = xfs_refcountbt_init_rec_from_cur,
324 .init_ptr_from_cur = xfs_refcountbt_init_ptr_from_cur,
325 .key_diff = xfs_refcountbt_key_diff,
d8079fe0 326 .buf_ops = &xfs_refcountbt_buf_ops,
bc859611 327 .diff_two_keys = xfs_refcountbt_diff_two_keys,
bc859611
DW
328 .keys_inorder = xfs_refcountbt_keys_inorder,
329 .recs_inorder = xfs_refcountbt_recs_inorder,
d8079fe0
DW
330};
331
332/*
333 * Allocate a new refcount btree cursor.
334 */
335struct xfs_btree_cur *
336xfs_refcountbt_init_cursor(
337 struct xfs_mount *mp,
338 struct xfs_trans *tp,
339 struct xfs_buf *agbp,
340 xfs_agnumber_t agno,
341 struct xfs_defer_ops *dfops)
342{
343 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
344 struct xfs_btree_cur *cur;
345
346 ASSERT(agno != NULLAGNUMBER);
347 ASSERT(agno < mp->m_sb.sb_agcount);
348 cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS);
349
350 cur->bc_tp = tp;
351 cur->bc_mp = mp;
352 cur->bc_btnum = XFS_BTNUM_REFC;
353 cur->bc_blocklog = mp->m_sb.sb_blocklog;
354 cur->bc_ops = &xfs_refcountbt_ops;
5d8acc46 355 cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
d8079fe0
DW
356
357 cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
358
359 cur->bc_private.a.agbp = agbp;
360 cur->bc_private.a.agno = agno;
361 cur->bc_private.a.dfops = dfops;
362 cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
363
364 cur->bc_private.a.priv.refc.nr_ops = 0;
365 cur->bc_private.a.priv.refc.shape_changes = 0;
366
367 return cur;
368}
369
370/*
371 * Calculate the number of records in a refcount btree block.
372 */
373int
374xfs_refcountbt_maxrecs(
d8079fe0
DW
375 int blocklen,
376 bool leaf)
377{
378 blocklen -= XFS_REFCOUNT_BLOCK_LEN;
379
380 if (leaf)
381 return blocklen / sizeof(struct xfs_refcount_rec);
382 return blocklen / (sizeof(struct xfs_refcount_key) +
383 sizeof(xfs_refcount_ptr_t));
384}
385
386/* Compute the maximum height of a refcount btree. */
387void
388xfs_refcountbt_compute_maxlevels(
389 struct xfs_mount *mp)
390{
1421de38 391 mp->m_refc_maxlevels = xfs_btree_compute_maxlevels(
d8079fe0
DW
392 mp->m_refc_mnr, mp->m_sb.sb_agblocks);
393}
02cc8b2a
DW
394
395/* Calculate the refcount btree size for some records. */
396xfs_extlen_t
397xfs_refcountbt_calc_size(
398 struct xfs_mount *mp,
399 unsigned long long len)
400{
1421de38 401 return xfs_btree_calc_size(mp->m_refc_mnr, len);
02cc8b2a
DW
402}
403
404/*
405 * Calculate the maximum refcount btree size.
406 */
407xfs_extlen_t
408xfs_refcountbt_max_size(
f21c57ed
DW
409 struct xfs_mount *mp,
410 xfs_agblock_t agblocks)
02cc8b2a
DW
411{
412 /* Bail out if we're uninitialized, which can happen in mkfs. */
413 if (mp->m_refc_mxr[0] == 0)
414 return 0;
415
f21c57ed 416 return xfs_refcountbt_calc_size(mp, agblocks);
02cc8b2a
DW
417}
418
419/*
420 * Figure out how many blocks to reserve and how many are used by this btree.
421 */
422int
423xfs_refcountbt_calc_reserves(
424 struct xfs_mount *mp,
425 xfs_agnumber_t agno,
426 xfs_extlen_t *ask,
427 xfs_extlen_t *used)
428{
429 struct xfs_buf *agbp;
430 struct xfs_agf *agf;
f21c57ed 431 xfs_agblock_t agblocks;
02cc8b2a
DW
432 xfs_extlen_t tree_len;
433 int error;
434
435 if (!xfs_sb_version_hasreflink(&mp->m_sb))
436 return 0;
437
02cc8b2a
DW
438
439 error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
440 if (error)
441 return error;
442
443 agf = XFS_BUF_TO_AGF(agbp);
f21c57ed 444 agblocks = be32_to_cpu(agf->agf_length);
02cc8b2a
DW
445 tree_len = be32_to_cpu(agf->agf_refcount_blocks);
446 xfs_buf_relse(agbp);
447
f21c57ed 448 *ask += xfs_refcountbt_max_size(mp, agblocks);
02cc8b2a
DW
449 *used += tree_len;
450
451 return error;
452}