blob: 81d58b09af718eccb6851f7ec923af1756ca4d69 [file] [log] [blame]
Darrick J. Wong1946b912016-10-03 09:11:18 -07001/*
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 "xfs.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_error.h"
33#include "xfs_trace.h"
34#include "xfs_cksum.h"
35#include "xfs_trans.h"
36#include "xfs_bit.h"
Darrick J. Wongbdf28632016-10-03 09:11:19 -070037#include "xfs_rmap.h"
Darrick J. Wong1946b912016-10-03 09:11:18 -070038
39static struct xfs_btree_cur *
40xfs_refcountbt_dup_cursor(
41 struct xfs_btree_cur *cur)
42{
43 return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
44 cur->bc_private.a.agbp, cur->bc_private.a.agno,
45 cur->bc_private.a.dfops);
46}
47
Darrick J. Wongbdf28632016-10-03 09:11:19 -070048STATIC void
49xfs_refcountbt_set_root(
50 struct xfs_btree_cur *cur,
51 union xfs_btree_ptr *ptr,
52 int inc)
53{
54 struct xfs_buf *agbp = cur->bc_private.a.agbp;
55 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
56 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
57 struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno);
58
59 ASSERT(ptr->s != 0);
60
61 agf->agf_refcount_root = ptr->s;
62 be32_add_cpu(&agf->agf_refcount_level, inc);
63 pag->pagf_refcount_level += inc;
64 xfs_perag_put(pag);
65
66 xfs_alloc_log_agf(cur->bc_tp, agbp,
67 XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL);
68}
69
70STATIC int
71xfs_refcountbt_alloc_block(
72 struct xfs_btree_cur *cur,
73 union xfs_btree_ptr *start,
74 union xfs_btree_ptr *new,
75 int *stat)
76{
77 struct xfs_buf *agbp = cur->bc_private.a.agbp;
78 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
79 struct xfs_alloc_arg args; /* block allocation args */
80 int error; /* error return value */
81
82 memset(&args, 0, sizeof(args));
83 args.tp = cur->bc_tp;
84 args.mp = cur->bc_mp;
85 args.type = XFS_ALLOCTYPE_NEAR_BNO;
86 args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno,
87 xfs_refc_block(args.mp));
88 args.firstblock = args.fsbno;
89 xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_REFC);
90 args.minlen = args.maxlen = args.prod = 1;
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) {
98 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
99 *stat = 0;
100 return 0;
101 }
102 ASSERT(args.agno == cur->bc_private.a.agno);
103 ASSERT(args.len == 1);
104
105 new->s = cpu_to_be32(args.agbno);
106 be32_add_cpu(&agf->agf_refcount_blocks, 1);
107 xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
108
109 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
110 *stat = 1;
111 return 0;
112
113out_error:
114 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
115 return error;
116}
117
118STATIC int
119xfs_refcountbt_free_block(
120 struct xfs_btree_cur *cur,
121 struct xfs_buf *bp)
122{
123 struct xfs_mount *mp = cur->bc_mp;
124 struct xfs_buf *agbp = cur->bc_private.a.agbp;
125 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
126 xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
127 struct xfs_owner_info oinfo;
128
129 trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_private.a.agno,
130 XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
131 xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_REFC);
132 be32_add_cpu(&agf->agf_refcount_blocks, -1);
133 xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
134 xfs_bmap_add_free(mp, cur->bc_private.a.dfops, fsbno, 1,
135 &oinfo);
136
137 return 0;
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
199STATIC __int64_t
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
207 return (__int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock;
208}
209
210STATIC __int64_t
211xfs_refcountbt_diff_two_keys(
212 struct xfs_btree_cur *cur,
213 union xfs_btree_key *k1,
214 union xfs_btree_key *k2)
215{
216 return (__int64_t)be32_to_cpu(k1->refc.rc_startblock) -
217 be32_to_cpu(k2->refc.rc_startblock);
218}
219
Darrick J. Wong1946b912016-10-03 09:11:18 -0700220STATIC bool
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;
227 unsigned int level;
228
229 if (block->bb_magic != cpu_to_be32(XFS_REFC_CRC_MAGIC))
230 return false;
231
232 if (!xfs_sb_version_hasreflink(&mp->m_sb))
233 return false;
234 if (!xfs_btree_sblock_v5hdr_verify(bp))
235 return false;
236
237 level = be16_to_cpu(block->bb_level);
238 if (pag && pag->pagf_init) {
239 if (level >= pag->pagf_refcount_level)
240 return false;
241 } else if (level >= mp->m_refc_maxlevels)
242 return false;
243
244 return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]);
245}
246
247STATIC void
248xfs_refcountbt_read_verify(
249 struct xfs_buf *bp)
250{
251 if (!xfs_btree_sblock_verify_crc(bp))
252 xfs_buf_ioerror(bp, -EFSBADCRC);
253 else if (!xfs_refcountbt_verify(bp))
254 xfs_buf_ioerror(bp, -EFSCORRUPTED);
255
256 if (bp->b_error) {
257 trace_xfs_btree_corrupt(bp, _RET_IP_);
258 xfs_verifier_error(bp);
259 }
260}
261
262STATIC void
263xfs_refcountbt_write_verify(
264 struct xfs_buf *bp)
265{
266 if (!xfs_refcountbt_verify(bp)) {
267 trace_xfs_btree_corrupt(bp, _RET_IP_);
268 xfs_buf_ioerror(bp, -EFSCORRUPTED);
269 xfs_verifier_error(bp);
270 return;
271 }
272 xfs_btree_sblock_calc_crc(bp);
273
274}
275
276const struct xfs_buf_ops xfs_refcountbt_buf_ops = {
277 .name = "xfs_refcountbt",
278 .verify_read = xfs_refcountbt_read_verify,
279 .verify_write = xfs_refcountbt_write_verify,
280};
281
Darrick J. Wongbdf28632016-10-03 09:11:19 -0700282#if defined(DEBUG) || defined(XFS_WARN)
283STATIC int
284xfs_refcountbt_keys_inorder(
285 struct xfs_btree_cur *cur,
286 union xfs_btree_key *k1,
287 union xfs_btree_key *k2)
288{
289 return be32_to_cpu(k1->refc.rc_startblock) <
290 be32_to_cpu(k2->refc.rc_startblock);
291}
292
293STATIC int
294xfs_refcountbt_recs_inorder(
295 struct xfs_btree_cur *cur,
296 union xfs_btree_rec *r1,
297 union xfs_btree_rec *r2)
298{
299 return be32_to_cpu(r1->refc.rc_startblock) +
300 be32_to_cpu(r1->refc.rc_blockcount) <=
301 be32_to_cpu(r2->refc.rc_startblock);
302}
303#endif
304
Darrick J. Wong1946b912016-10-03 09:11:18 -0700305static const struct xfs_btree_ops xfs_refcountbt_ops = {
306 .rec_len = sizeof(struct xfs_refcount_rec),
307 .key_len = sizeof(struct xfs_refcount_key),
308
309 .dup_cursor = xfs_refcountbt_dup_cursor,
Darrick J. Wongbdf28632016-10-03 09:11:19 -0700310 .set_root = xfs_refcountbt_set_root,
311 .alloc_block = xfs_refcountbt_alloc_block,
312 .free_block = xfs_refcountbt_free_block,
313 .get_minrecs = xfs_refcountbt_get_minrecs,
314 .get_maxrecs = xfs_refcountbt_get_maxrecs,
315 .init_key_from_rec = xfs_refcountbt_init_key_from_rec,
316 .init_high_key_from_rec = xfs_refcountbt_init_high_key_from_rec,
317 .init_rec_from_cur = xfs_refcountbt_init_rec_from_cur,
318 .init_ptr_from_cur = xfs_refcountbt_init_ptr_from_cur,
319 .key_diff = xfs_refcountbt_key_diff,
Darrick J. Wong1946b912016-10-03 09:11:18 -0700320 .buf_ops = &xfs_refcountbt_buf_ops,
Darrick J. Wongbdf28632016-10-03 09:11:19 -0700321 .diff_two_keys = xfs_refcountbt_diff_two_keys,
322#if defined(DEBUG) || defined(XFS_WARN)
323 .keys_inorder = xfs_refcountbt_keys_inorder,
324 .recs_inorder = xfs_refcountbt_recs_inorder,
325#endif
Darrick J. Wong1946b912016-10-03 09:11:18 -0700326};
327
328/*
329 * Allocate a new refcount btree cursor.
330 */
331struct xfs_btree_cur *
332xfs_refcountbt_init_cursor(
333 struct xfs_mount *mp,
334 struct xfs_trans *tp,
335 struct xfs_buf *agbp,
336 xfs_agnumber_t agno,
337 struct xfs_defer_ops *dfops)
338{
339 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
340 struct xfs_btree_cur *cur;
341
342 ASSERT(agno != NULLAGNUMBER);
343 ASSERT(agno < mp->m_sb.sb_agcount);
344 cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS);
345
346 cur->bc_tp = tp;
347 cur->bc_mp = mp;
348 cur->bc_btnum = XFS_BTNUM_REFC;
349 cur->bc_blocklog = mp->m_sb.sb_blocklog;
350 cur->bc_ops = &xfs_refcountbt_ops;
351
352 cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
353
354 cur->bc_private.a.agbp = agbp;
355 cur->bc_private.a.agno = agno;
356 cur->bc_private.a.dfops = dfops;
357 cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
358
359 cur->bc_private.a.priv.refc.nr_ops = 0;
360 cur->bc_private.a.priv.refc.shape_changes = 0;
361
362 return cur;
363}
364
365/*
366 * Calculate the number of records in a refcount btree block.
367 */
368int
369xfs_refcountbt_maxrecs(
370 struct xfs_mount *mp,
371 int blocklen,
372 bool leaf)
373{
374 blocklen -= XFS_REFCOUNT_BLOCK_LEN;
375
376 if (leaf)
377 return blocklen / sizeof(struct xfs_refcount_rec);
378 return blocklen / (sizeof(struct xfs_refcount_key) +
379 sizeof(xfs_refcount_ptr_t));
380}
381
382/* Compute the maximum height of a refcount btree. */
383void
384xfs_refcountbt_compute_maxlevels(
385 struct xfs_mount *mp)
386{
387 mp->m_refc_maxlevels = xfs_btree_compute_maxlevels(mp,
388 mp->m_refc_mnr, mp->m_sb.sb_agblocks);
389}