blob: 5baa22c07095727fb086c6beaa8e35a777448ffc [file] [log] [blame]
Dave Chinnerb16817b2018-05-13 23:10:08 -07001/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4 * Copyright (c) 2018 Red Hat, Inc.
5 * All rights reserved.
6 */
7
8#include "xfs.h"
9#include "xfs_fs.h"
10#include "xfs_shared.h"
11#include "xfs_format.h"
12#include "xfs_trans_resv.h"
13#include "xfs_sb.h"
14#include "xfs_mount.h"
15#include "xfs_btree.h"
16#include "xfs_alloc_btree.h"
17#include "xfs_rmap_btree.h"
18#include "xfs_alloc.h"
19#include "xfs_rmap.h"
20#include "xfs_ag.h"
21
22static struct xfs_buf *
23xfs_get_aghdr_buf(
24 struct xfs_mount *mp,
25 xfs_daddr_t blkno,
26 size_t numblks,
27 int flags,
28 const struct xfs_buf_ops *ops)
29{
30 struct xfs_buf *bp;
31
32 bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags);
33 if (!bp)
34 return NULL;
35
36 xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
37 bp->b_bn = blkno;
38 bp->b_maps[0].bm_bn = blkno;
39 bp->b_ops = ops;
40
41 return bp;
42}
43
44/*
45 * Generic btree root block init function
46 */
47static void
48xfs_btroot_init(
49 struct xfs_mount *mp,
50 struct xfs_buf *bp,
51 struct aghdr_init_data *id)
52{
53 xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno, 0);
54}
55
56/*
57 * Alloc btree root block init functions
58 */
59static void
60xfs_bnoroot_init(
61 struct xfs_mount *mp,
62 struct xfs_buf *bp,
63 struct aghdr_init_data *id)
64{
65 struct xfs_alloc_rec *arec;
66
67 xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno, 0);
68 arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
69 arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
70 arec->ar_blockcount = cpu_to_be32(id->agsize -
71 be32_to_cpu(arec->ar_startblock));
72}
73
74static void
75xfs_cntroot_init(
76 struct xfs_mount *mp,
77 struct xfs_buf *bp,
78 struct aghdr_init_data *id)
79{
80 struct xfs_alloc_rec *arec;
81
82 xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno, 0);
83 arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
84 arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
85 arec->ar_blockcount = cpu_to_be32(id->agsize -
86 be32_to_cpu(arec->ar_startblock));
87}
88
89/*
90 * Reverse map root block init
91 */
92static void
93xfs_rmaproot_init(
94 struct xfs_mount *mp,
95 struct xfs_buf *bp,
96 struct aghdr_init_data *id)
97{
98 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
99 struct xfs_rmap_rec *rrec;
100
101 xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno, 0);
102
103 /*
104 * mark the AG header regions as static metadata The BNO
105 * btree block is the first block after the headers, so
106 * it's location defines the size of region the static
107 * metadata consumes.
108 *
109 * Note: unlike mkfs, we never have to account for log
110 * space when growing the data regions
111 */
112 rrec = XFS_RMAP_REC_ADDR(block, 1);
113 rrec->rm_startblock = 0;
114 rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp));
115 rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS);
116 rrec->rm_offset = 0;
117
118 /* account freespace btree root blocks */
119 rrec = XFS_RMAP_REC_ADDR(block, 2);
120 rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp));
121 rrec->rm_blockcount = cpu_to_be32(2);
122 rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
123 rrec->rm_offset = 0;
124
125 /* account inode btree root blocks */
126 rrec = XFS_RMAP_REC_ADDR(block, 3);
127 rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp));
128 rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) -
129 XFS_IBT_BLOCK(mp));
130 rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT);
131 rrec->rm_offset = 0;
132
133 /* account for rmap btree root */
134 rrec = XFS_RMAP_REC_ADDR(block, 4);
135 rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp));
136 rrec->rm_blockcount = cpu_to_be32(1);
137 rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
138 rrec->rm_offset = 0;
139
140 /* account for refc btree root */
141 if (xfs_sb_version_hasreflink(&mp->m_sb)) {
142 rrec = XFS_RMAP_REC_ADDR(block, 5);
143 rrec->rm_startblock = cpu_to_be32(xfs_refc_block(mp));
144 rrec->rm_blockcount = cpu_to_be32(1);
145 rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC);
146 rrec->rm_offset = 0;
147 be16_add_cpu(&block->bb_numrecs, 1);
148 }
149}
150
151/*
152 * Initialise new secondary superblocks with the pre-grow geometry, but mark
153 * them as "in progress" so we know they haven't yet been activated. This will
154 * get cleared when the update with the new geometry information is done after
155 * changes to the primary are committed. This isn't strictly necessary, but we
156 * get it for free with the delayed buffer write lists and it means we can tell
157 * if a grow operation didn't complete properly after the fact.
158 */
159static void
160xfs_sbblock_init(
161 struct xfs_mount *mp,
162 struct xfs_buf *bp,
163 struct aghdr_init_data *id)
164{
165 struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp);
166
167 xfs_sb_to_disk(dsb, &mp->m_sb);
168 dsb->sb_inprogress = 1;
169}
170
171static void
172xfs_agfblock_init(
173 struct xfs_mount *mp,
174 struct xfs_buf *bp,
175 struct aghdr_init_data *id)
176{
177 struct xfs_agf *agf = XFS_BUF_TO_AGF(bp);
178 xfs_extlen_t tmpsize;
179
180 agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
181 agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
182 agf->agf_seqno = cpu_to_be32(id->agno);
183 agf->agf_length = cpu_to_be32(id->agsize);
184 agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp));
185 agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
186 agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
187 agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
188 if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
189 agf->agf_roots[XFS_BTNUM_RMAPi] =
190 cpu_to_be32(XFS_RMAP_BLOCK(mp));
191 agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1);
192 agf->agf_rmap_blocks = cpu_to_be32(1);
193 }
194
195 agf->agf_flfirst = cpu_to_be32(1);
196 agf->agf_fllast = 0;
197 agf->agf_flcount = 0;
198 tmpsize = id->agsize - mp->m_ag_prealloc_blocks;
199 agf->agf_freeblks = cpu_to_be32(tmpsize);
200 agf->agf_longest = cpu_to_be32(tmpsize);
201 if (xfs_sb_version_hascrc(&mp->m_sb))
202 uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
203 if (xfs_sb_version_hasreflink(&mp->m_sb)) {
204 agf->agf_refcount_root = cpu_to_be32(
205 xfs_refc_block(mp));
206 agf->agf_refcount_level = cpu_to_be32(1);
207 agf->agf_refcount_blocks = cpu_to_be32(1);
208 }
209}
210
211static void
212xfs_agflblock_init(
213 struct xfs_mount *mp,
214 struct xfs_buf *bp,
215 struct aghdr_init_data *id)
216{
217 struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp);
218 __be32 *agfl_bno;
219 int bucket;
220
221 if (xfs_sb_version_hascrc(&mp->m_sb)) {
222 agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
223 agfl->agfl_seqno = cpu_to_be32(id->agno);
224 uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
225 }
226
227 agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
228 for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++)
229 agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
230}
231
232static void
233xfs_agiblock_init(
234 struct xfs_mount *mp,
235 struct xfs_buf *bp,
236 struct aghdr_init_data *id)
237{
238 struct xfs_agi *agi = XFS_BUF_TO_AGI(bp);
239 int bucket;
240
241 agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
242 agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
243 agi->agi_seqno = cpu_to_be32(id->agno);
244 agi->agi_length = cpu_to_be32(id->agsize);
245 agi->agi_count = 0;
246 agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
247 agi->agi_level = cpu_to_be32(1);
248 agi->agi_freecount = 0;
249 agi->agi_newino = cpu_to_be32(NULLAGINO);
250 agi->agi_dirino = cpu_to_be32(NULLAGINO);
251 if (xfs_sb_version_hascrc(&mp->m_sb))
252 uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
253 if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
254 agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
255 agi->agi_free_level = cpu_to_be32(1);
256 }
257 for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
258 agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
259}
260
261typedef void (*aghdr_init_work_f)(struct xfs_mount *mp, struct xfs_buf *bp,
262 struct aghdr_init_data *id);
263static int
264xfs_ag_init_hdr(
265 struct xfs_mount *mp,
266 struct aghdr_init_data *id,
267 aghdr_init_work_f work,
268 const struct xfs_buf_ops *ops)
269
270{
271 struct xfs_buf *bp;
272
273 bp = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, 0, ops);
274 if (!bp)
275 return -ENOMEM;
276
277 (*work)(mp, bp, id);
278
279 xfs_buf_delwri_queue(bp, &id->buffer_list);
280 xfs_buf_relse(bp);
281 return 0;
282}
283
284struct xfs_aghdr_grow_data {
285 xfs_daddr_t daddr;
286 size_t numblks;
287 const struct xfs_buf_ops *ops;
288 aghdr_init_work_f work;
289 xfs_btnum_t type;
290 bool need_init;
291};
292
293/*
294 * Prepare new AG headers to be written to disk. We use uncached buffers here,
295 * as it is assumed these new AG headers are currently beyond the currently
296 * valid filesystem address space. Using cached buffers would trip over EOFS
297 * corruption detection alogrithms in the buffer cache lookup routines.
298 *
299 * This is a non-transactional function, but the prepared buffers are added to a
300 * delayed write buffer list supplied by the caller so they can submit them to
301 * disk and wait on them as required.
302 */
303int
304xfs_ag_init_headers(
305 struct xfs_mount *mp,
306 struct aghdr_init_data *id)
307
308{
309 struct xfs_aghdr_grow_data aghdr_data[] = {
310 { /* SB */
311 .daddr = XFS_AG_DADDR(mp, id->agno, XFS_SB_DADDR),
312 .numblks = XFS_FSS_TO_BB(mp, 1),
313 .ops = &xfs_sb_buf_ops,
314 .work = &xfs_sbblock_init,
315 .need_init = true
316 },
317 { /* AGF */
318 .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGF_DADDR(mp)),
319 .numblks = XFS_FSS_TO_BB(mp, 1),
320 .ops = &xfs_agf_buf_ops,
321 .work = &xfs_agfblock_init,
322 .need_init = true
323 },
324 { /* AGFL */
325 .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGFL_DADDR(mp)),
326 .numblks = XFS_FSS_TO_BB(mp, 1),
327 .ops = &xfs_agfl_buf_ops,
328 .work = &xfs_agflblock_init,
329 .need_init = true
330 },
331 { /* AGI */
332 .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGI_DADDR(mp)),
333 .numblks = XFS_FSS_TO_BB(mp, 1),
334 .ops = &xfs_agi_buf_ops,
335 .work = &xfs_agiblock_init,
336 .need_init = true
337 },
338 { /* BNO root block */
339 .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_BNO_BLOCK(mp)),
340 .numblks = BTOBB(mp->m_sb.sb_blocksize),
341 .ops = &xfs_allocbt_buf_ops,
342 .work = &xfs_bnoroot_init,
343 .need_init = true
344 },
345 { /* CNT root block */
346 .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_CNT_BLOCK(mp)),
347 .numblks = BTOBB(mp->m_sb.sb_blocksize),
348 .ops = &xfs_allocbt_buf_ops,
349 .work = &xfs_cntroot_init,
350 .need_init = true
351 },
352 { /* INO root block */
353 .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_IBT_BLOCK(mp)),
354 .numblks = BTOBB(mp->m_sb.sb_blocksize),
355 .ops = &xfs_inobt_buf_ops,
356 .work = &xfs_btroot_init,
357 .type = XFS_BTNUM_INO,
358 .need_init = true
359 },
360 { /* FINO root block */
361 .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_FIBT_BLOCK(mp)),
362 .numblks = BTOBB(mp->m_sb.sb_blocksize),
363 .ops = &xfs_inobt_buf_ops,
364 .work = &xfs_btroot_init,
365 .type = XFS_BTNUM_FINO,
366 .need_init = xfs_sb_version_hasfinobt(&mp->m_sb)
367 },
368 { /* RMAP root block */
369 .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_RMAP_BLOCK(mp)),
370 .numblks = BTOBB(mp->m_sb.sb_blocksize),
371 .ops = &xfs_rmapbt_buf_ops,
372 .work = &xfs_rmaproot_init,
373 .need_init = xfs_sb_version_hasrmapbt(&mp->m_sb)
374 },
375 { /* REFC root block */
376 .daddr = XFS_AGB_TO_DADDR(mp, id->agno, xfs_refc_block(mp)),
377 .numblks = BTOBB(mp->m_sb.sb_blocksize),
378 .ops = &xfs_refcountbt_buf_ops,
379 .work = &xfs_btroot_init,
380 .type = XFS_BTNUM_REFC,
381 .need_init = xfs_sb_version_hasreflink(&mp->m_sb)
382 },
383 { /* NULL terminating block */
384 .daddr = XFS_BUF_DADDR_NULL,
385 }
386 };
387 struct xfs_aghdr_grow_data *dp;
388 int error = 0;
389
390 /* Account for AG free space in new AG */
391 id->nfree += id->agsize - mp->m_ag_prealloc_blocks;
392 for (dp = &aghdr_data[0]; dp->daddr != XFS_BUF_DADDR_NULL; dp++) {
393 if (!dp->need_init)
394 continue;
395
396 id->daddr = dp->daddr;
397 id->numblks = dp->numblks;
398 id->type = dp->type;
399 error = xfs_ag_init_hdr(mp, id, dp->work, dp->ops);
400 if (error)
401 break;
402 }
403 return error;
404}