1240afd8cSMark Johnston /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3240afd8cSMark Johnston *
4240afd8cSMark Johnston * Copyright (c) 2022 The FreeBSD Foundation
5240afd8cSMark Johnston *
6240afd8cSMark Johnston * This software was developed by Mark Johnston under sponsorship from
7240afd8cSMark Johnston * the FreeBSD Foundation.
8240afd8cSMark Johnston *
9240afd8cSMark Johnston * Redistribution and use in source and binary forms, with or without
10240afd8cSMark Johnston * modification, are permitted provided that the following conditions are
11240afd8cSMark Johnston * met:
12240afd8cSMark Johnston * 1. Redistributions of source code must retain the above copyright
13240afd8cSMark Johnston * notice, this list of conditions and the following disclaimer.
14240afd8cSMark Johnston * 2. Redistributions in binary form must reproduce the above copyright
15240afd8cSMark Johnston * notice, this list of conditions and the following disclaimer in
16240afd8cSMark Johnston * the documentation and/or other materials provided with the distribution.
17240afd8cSMark Johnston *
18240afd8cSMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19240afd8cSMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20240afd8cSMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21240afd8cSMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22240afd8cSMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23240afd8cSMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24240afd8cSMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25240afd8cSMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26240afd8cSMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27240afd8cSMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28240afd8cSMark Johnston * SUCH DAMAGE.
29240afd8cSMark Johnston */
30240afd8cSMark Johnston
31240afd8cSMark Johnston #include <assert.h>
32240afd8cSMark Johnston #include <fcntl.h>
33c6890399SJessica Clarke #include <stdlib.h>
34240afd8cSMark Johnston #include <string.h>
35240afd8cSMark Johnston #include <unistd.h>
36240afd8cSMark Johnston
37240afd8cSMark Johnston #include <util.h>
38240afd8cSMark Johnston
39240afd8cSMark Johnston #include "zfs.h"
40240afd8cSMark Johnston
4182ac811eSJohn Baldwin #pragma GCC diagnostic push
4282ac811eSJohn Baldwin #pragma GCC diagnostic ignored "-Wunused-function"
43240afd8cSMark Johnston #include "zfs/fletcher.c"
44240afd8cSMark Johnston #include "zfs/sha256.c"
4582ac811eSJohn Baldwin #pragma GCC diagnostic pop
46240afd8cSMark Johnston
47240afd8cSMark Johnston static void
blkptr_set(blkptr_t * bp,off_t off,off_t size,uint8_t dntype,uint8_t level,uint64_t fill,enum zio_checksum cksumt,zio_cksum_t * cksum)48240afd8cSMark Johnston blkptr_set(blkptr_t *bp, off_t off, off_t size, uint8_t dntype, uint8_t level,
49240afd8cSMark Johnston uint64_t fill, enum zio_checksum cksumt, zio_cksum_t *cksum)
50240afd8cSMark Johnston {
51240afd8cSMark Johnston dva_t *dva;
52240afd8cSMark Johnston
53240afd8cSMark Johnston assert(powerof2(size));
54240afd8cSMark Johnston
55240afd8cSMark Johnston BP_ZERO(bp);
56240afd8cSMark Johnston BP_SET_LSIZE(bp, size);
57240afd8cSMark Johnston BP_SET_PSIZE(bp, size);
58240afd8cSMark Johnston BP_SET_CHECKSUM(bp, cksumt);
59240afd8cSMark Johnston BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
60240afd8cSMark Johnston BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
61240afd8cSMark Johnston BP_SET_BIRTH(bp, TXG, TXG);
62240afd8cSMark Johnston BP_SET_LEVEL(bp, level);
63240afd8cSMark Johnston BP_SET_FILL(bp, fill);
64240afd8cSMark Johnston BP_SET_TYPE(bp, dntype);
65240afd8cSMark Johnston
66240afd8cSMark Johnston dva = BP_IDENTITY(bp);
67240afd8cSMark Johnston DVA_SET_VDEV(dva, 0);
68240afd8cSMark Johnston DVA_SET_OFFSET(dva, off);
69240afd8cSMark Johnston DVA_SET_ASIZE(dva, size);
70240afd8cSMark Johnston memcpy(&bp->blk_cksum, cksum, sizeof(*cksum));
71240afd8cSMark Johnston }
72240afd8cSMark Johnston
73240afd8cSMark Johnston /*
74240afd8cSMark Johnston * Write a block of data to the vdev. The offset is always relative to the end
75240afd8cSMark Johnston * of the second leading vdev label.
76240afd8cSMark Johnston *
77240afd8cSMark Johnston * Consumers should generally use the helpers below, which provide block
78240afd8cSMark Johnston * pointers and update dnode accounting, rather than calling this function
79240afd8cSMark Johnston * directly.
80240afd8cSMark Johnston */
81240afd8cSMark Johnston static void
vdev_pwrite(const zfs_opt_t * zfs,const void * buf,size_t len,off_t off)82240afd8cSMark Johnston vdev_pwrite(const zfs_opt_t *zfs, const void *buf, size_t len, off_t off)
83240afd8cSMark Johnston {
84240afd8cSMark Johnston ssize_t n;
85240afd8cSMark Johnston
86240afd8cSMark Johnston assert(off >= 0 && off < zfs->asize);
87240afd8cSMark Johnston assert(powerof2(len));
88240afd8cSMark Johnston assert((off_t)len > 0 && off + (off_t)len > off &&
89240afd8cSMark Johnston off + (off_t)len < zfs->asize);
90240afd8cSMark Johnston if (zfs->spacemap != NULL) {
91240afd8cSMark Johnston /*
92240afd8cSMark Johnston * Verify that the blocks being written were in fact allocated.
93240afd8cSMark Johnston *
94240afd8cSMark Johnston * The space map isn't available once the on-disk space map is
95240afd8cSMark Johnston * finalized, so this check doesn't quite catch everything.
96240afd8cSMark Johnston */
97240afd8cSMark Johnston assert(bit_ntest(zfs->spacemap, off >> zfs->ashift,
98240afd8cSMark Johnston (off + len - 1) >> zfs->ashift, 1));
99240afd8cSMark Johnston }
100240afd8cSMark Johnston
101240afd8cSMark Johnston off += VDEV_LABEL_START_SIZE;
102240afd8cSMark Johnston for (size_t sofar = 0; sofar < len; sofar += n) {
103240afd8cSMark Johnston n = pwrite(zfs->fd, (const char *)buf + sofar, len - sofar,
104240afd8cSMark Johnston off + sofar);
105240afd8cSMark Johnston if (n < 0)
106240afd8cSMark Johnston err(1, "pwrite");
107240afd8cSMark Johnston assert(n > 0);
108240afd8cSMark Johnston }
109240afd8cSMark Johnston }
110240afd8cSMark Johnston
111240afd8cSMark Johnston void
vdev_pwrite_data(zfs_opt_t * zfs,uint8_t datatype,uint8_t cksumtype,uint8_t level,uint64_t fill,const void * data,off_t sz,off_t loc,blkptr_t * bp)112240afd8cSMark Johnston vdev_pwrite_data(zfs_opt_t *zfs, uint8_t datatype, uint8_t cksumtype,
113240afd8cSMark Johnston uint8_t level, uint64_t fill, const void *data, off_t sz, off_t loc,
114240afd8cSMark Johnston blkptr_t *bp)
115240afd8cSMark Johnston {
116240afd8cSMark Johnston zio_cksum_t cksum;
117240afd8cSMark Johnston
118240afd8cSMark Johnston assert(cksumtype == ZIO_CHECKSUM_FLETCHER_4);
119240afd8cSMark Johnston
120240afd8cSMark Johnston fletcher_4_native(data, sz, NULL, &cksum);
121240afd8cSMark Johnston blkptr_set(bp, loc, sz, datatype, level, fill, cksumtype, &cksum);
122240afd8cSMark Johnston vdev_pwrite(zfs, data, sz, loc);
123240afd8cSMark Johnston }
124240afd8cSMark Johnston
125240afd8cSMark Johnston void
vdev_pwrite_dnode_indir(zfs_opt_t * zfs,dnode_phys_t * dnode,uint8_t level,uint64_t fill,const void * data,off_t sz,off_t loc,blkptr_t * bp)126240afd8cSMark Johnston vdev_pwrite_dnode_indir(zfs_opt_t *zfs, dnode_phys_t *dnode, uint8_t level,
127240afd8cSMark Johnston uint64_t fill, const void *data, off_t sz, off_t loc, blkptr_t *bp)
128240afd8cSMark Johnston {
129240afd8cSMark Johnston vdev_pwrite_data(zfs, dnode->dn_type, dnode->dn_checksum, level, fill,
130240afd8cSMark Johnston data, sz, loc, bp);
131240afd8cSMark Johnston
132240afd8cSMark Johnston assert((dnode->dn_flags & DNODE_FLAG_USED_BYTES) != 0);
133240afd8cSMark Johnston dnode->dn_used += sz;
134240afd8cSMark Johnston }
135240afd8cSMark Johnston
136240afd8cSMark Johnston void
vdev_pwrite_dnode_data(zfs_opt_t * zfs,dnode_phys_t * dnode,const void * data,off_t sz,off_t loc)137240afd8cSMark Johnston vdev_pwrite_dnode_data(zfs_opt_t *zfs, dnode_phys_t *dnode, const void *data,
138240afd8cSMark Johnston off_t sz, off_t loc)
139240afd8cSMark Johnston {
140240afd8cSMark Johnston vdev_pwrite_dnode_indir(zfs, dnode, 0, 1, data, sz, loc,
141240afd8cSMark Johnston &dnode->dn_blkptr[0]);
142240afd8cSMark Johnston }
143240afd8cSMark Johnston
144240afd8cSMark Johnston static void
vdev_label_set_checksum(void * buf,off_t off,off_t size)145240afd8cSMark Johnston vdev_label_set_checksum(void *buf, off_t off, off_t size)
146240afd8cSMark Johnston {
147240afd8cSMark Johnston zio_cksum_t cksum;
148240afd8cSMark Johnston zio_eck_t *eck;
149240afd8cSMark Johnston
150240afd8cSMark Johnston assert(size > 0 && (size_t)size >= sizeof(zio_eck_t));
151240afd8cSMark Johnston
152240afd8cSMark Johnston eck = (zio_eck_t *)((char *)buf + size) - 1;
153240afd8cSMark Johnston eck->zec_magic = ZEC_MAGIC;
154240afd8cSMark Johnston ZIO_SET_CHECKSUM(&eck->zec_cksum, off, 0, 0, 0);
155240afd8cSMark Johnston zio_checksum_SHA256(buf, size, NULL, &cksum);
156240afd8cSMark Johnston eck->zec_cksum = cksum;
157240afd8cSMark Johnston }
158240afd8cSMark Johnston
159240afd8cSMark Johnston /*
160240afd8cSMark Johnston * Set embedded checksums and write the label at the specified index.
161240afd8cSMark Johnston */
162240afd8cSMark Johnston void
vdev_label_write(zfs_opt_t * zfs,int ind,const vdev_label_t * labelp)163240afd8cSMark Johnston vdev_label_write(zfs_opt_t *zfs, int ind, const vdev_label_t *labelp)
164240afd8cSMark Johnston {
165240afd8cSMark Johnston vdev_label_t *label;
166240afd8cSMark Johnston ssize_t n;
167240afd8cSMark Johnston off_t blksz, loff;
168240afd8cSMark Johnston
169240afd8cSMark Johnston assert(ind >= 0 && ind < VDEV_LABELS);
170240afd8cSMark Johnston
171240afd8cSMark Johnston /*
172240afd8cSMark Johnston * Make a copy since we have to modify the label to set checksums.
173240afd8cSMark Johnston */
174240afd8cSMark Johnston label = ecalloc(1, sizeof(*label));
175240afd8cSMark Johnston memcpy(label, labelp, sizeof(*label));
176240afd8cSMark Johnston
177240afd8cSMark Johnston if (ind < 2)
178240afd8cSMark Johnston loff = ind * sizeof(*label);
179240afd8cSMark Johnston else
180240afd8cSMark Johnston loff = zfs->vdevsize - (VDEV_LABELS - ind) * sizeof(*label);
181240afd8cSMark Johnston
182240afd8cSMark Johnston /*
183240afd8cSMark Johnston * Set the verifier checksum for the boot block. We don't use it, but
184240afd8cSMark Johnston * the FreeBSD loader reads it and will complain if the checksum isn't
185240afd8cSMark Johnston * valid.
186240afd8cSMark Johnston */
187240afd8cSMark Johnston vdev_label_set_checksum(&label->vl_be,
188240afd8cSMark Johnston loff + __offsetof(vdev_label_t, vl_be), sizeof(label->vl_be));
189240afd8cSMark Johnston
190240afd8cSMark Johnston /*
191240afd8cSMark Johnston * Set the verifier checksum for the label.
192240afd8cSMark Johnston */
193240afd8cSMark Johnston vdev_label_set_checksum(&label->vl_vdev_phys,
194240afd8cSMark Johnston loff + __offsetof(vdev_label_t, vl_vdev_phys),
195240afd8cSMark Johnston sizeof(label->vl_vdev_phys));
196240afd8cSMark Johnston
197240afd8cSMark Johnston /*
198240afd8cSMark Johnston * Set the verifier checksum for the uberblocks. There is one uberblock
199240afd8cSMark Johnston * per sector; for example, with an ashift of 12 we end up with
200240afd8cSMark Johnston * 128KB/4KB=32 copies of the uberblock in the ring.
201240afd8cSMark Johnston */
202240afd8cSMark Johnston blksz = 1 << zfs->ashift;
203240afd8cSMark Johnston assert(sizeof(label->vl_uberblock) % blksz == 0);
204240afd8cSMark Johnston for (size_t roff = 0; roff < sizeof(label->vl_uberblock);
205240afd8cSMark Johnston roff += blksz) {
206240afd8cSMark Johnston vdev_label_set_checksum(&label->vl_uberblock[0] + roff,
207240afd8cSMark Johnston loff + __offsetof(vdev_label_t, vl_uberblock) + roff,
208240afd8cSMark Johnston blksz);
209240afd8cSMark Johnston }
210240afd8cSMark Johnston
211240afd8cSMark Johnston n = pwrite(zfs->fd, label, sizeof(*label), loff);
212240afd8cSMark Johnston if (n < 0)
213240afd8cSMark Johnston err(1, "writing vdev label");
214240afd8cSMark Johnston assert(n == sizeof(*label));
215240afd8cSMark Johnston
216240afd8cSMark Johnston free(label);
217240afd8cSMark Johnston }
218240afd8cSMark Johnston
219240afd8cSMark Johnston /*
220240afd8cSMark Johnston * Find a chunk of contiguous free space of length *lenp, according to the
221240afd8cSMark Johnston * following rules:
222240afd8cSMark Johnston * 1. If the length is less than or equal to 128KB, the returned run's length
223240afd8cSMark Johnston * will be the smallest power of 2 equal to or larger than the length.
224240afd8cSMark Johnston * 2. If the length is larger than 128KB, the returned run's length will be
225240afd8cSMark Johnston * the smallest multiple of 128KB that is larger than the length.
226240afd8cSMark Johnston * 3. The returned run's length will be size-aligned up to 128KB.
227240afd8cSMark Johnston *
228240afd8cSMark Johnston * XXX-MJ the third rule isn't actually required, so this can just be a dumb
229240afd8cSMark Johnston * bump allocator. Maybe there's some benefit to keeping large blocks aligned,
230240afd8cSMark Johnston * so let's keep it for now and hope we don't get too much fragmentation.
231240afd8cSMark Johnston * Alternately we could try to allocate all blocks of a certain size from the
232240afd8cSMark Johnston * same metaslab.
233240afd8cSMark Johnston */
234240afd8cSMark Johnston off_t
vdev_space_alloc(zfs_opt_t * zfs,off_t * lenp)235240afd8cSMark Johnston vdev_space_alloc(zfs_opt_t *zfs, off_t *lenp)
236240afd8cSMark Johnston {
237240afd8cSMark Johnston off_t len;
238240afd8cSMark Johnston int align, loc, minblksz, nbits;
239240afd8cSMark Johnston
240240afd8cSMark Johnston minblksz = 1 << zfs->ashift;
241240afd8cSMark Johnston len = roundup2(*lenp, minblksz);
242240afd8cSMark Johnston
243240afd8cSMark Johnston assert(len != 0);
244240afd8cSMark Johnston assert(len / minblksz <= INT_MAX);
245240afd8cSMark Johnston
246240afd8cSMark Johnston if (len < MAXBLOCKSIZE) {
247240afd8cSMark Johnston if ((len & (len - 1)) != 0)
248240afd8cSMark Johnston len = (off_t)1 << flsll(len);
249240afd8cSMark Johnston align = len / minblksz;
250240afd8cSMark Johnston } else {
251240afd8cSMark Johnston len = roundup2(len, MAXBLOCKSIZE);
252240afd8cSMark Johnston align = MAXBLOCKSIZE / minblksz;
253240afd8cSMark Johnston }
254240afd8cSMark Johnston
255240afd8cSMark Johnston for (loc = 0, nbits = len / minblksz;; loc = roundup2(loc, align)) {
256240afd8cSMark Johnston bit_ffc_area_at(zfs->spacemap, loc, zfs->spacemapbits, nbits,
257240afd8cSMark Johnston &loc);
258240afd8cSMark Johnston if (loc == -1) {
259240afd8cSMark Johnston errx(1, "failed to find %ju bytes of space",
260240afd8cSMark Johnston (uintmax_t)len);
261240afd8cSMark Johnston }
262240afd8cSMark Johnston if ((loc & (align - 1)) == 0)
263240afd8cSMark Johnston break;
264240afd8cSMark Johnston }
265240afd8cSMark Johnston assert(loc + nbits > loc);
266240afd8cSMark Johnston bit_nset(zfs->spacemap, loc, loc + nbits - 1);
267240afd8cSMark Johnston *lenp = len;
268240afd8cSMark Johnston
269240afd8cSMark Johnston return ((off_t)loc << zfs->ashift);
270240afd8cSMark Johnston }
271240afd8cSMark Johnston
272240afd8cSMark Johnston static void
vdev_spacemap_init(zfs_opt_t * zfs)273240afd8cSMark Johnston vdev_spacemap_init(zfs_opt_t *zfs)
274240afd8cSMark Johnston {
275240afd8cSMark Johnston uint64_t nbits;
276240afd8cSMark Johnston
277240afd8cSMark Johnston assert(powerof2(zfs->mssize));
278240afd8cSMark Johnston
279240afd8cSMark Johnston nbits = rounddown2(zfs->asize, zfs->mssize) >> zfs->ashift;
280240afd8cSMark Johnston if (nbits > INT_MAX) {
281240afd8cSMark Johnston /*
282240afd8cSMark Johnston * With the smallest block size of 512B, the limit on the image
283240afd8cSMark Johnston * size is 2TB. That should be enough for anyone.
284240afd8cSMark Johnston */
285240afd8cSMark Johnston errx(1, "image size is too large");
286240afd8cSMark Johnston }
287240afd8cSMark Johnston zfs->spacemapbits = (int)nbits;
288240afd8cSMark Johnston zfs->spacemap = bit_alloc(zfs->spacemapbits);
289240afd8cSMark Johnston if (zfs->spacemap == NULL)
290240afd8cSMark Johnston err(1, "bitstring allocation failed");
291240afd8cSMark Johnston }
292240afd8cSMark Johnston
293240afd8cSMark Johnston void
vdev_spacemap_write(zfs_opt_t * zfs)294240afd8cSMark Johnston vdev_spacemap_write(zfs_opt_t *zfs)
295240afd8cSMark Johnston {
296240afd8cSMark Johnston dnode_phys_t *objarr;
297240afd8cSMark Johnston bitstr_t *spacemap;
298240afd8cSMark Johnston uint64_t *objarrblk;
299240afd8cSMark Johnston off_t smblksz, objarrblksz, objarrloc;
300240afd8cSMark Johnston
301240afd8cSMark Johnston struct {
302240afd8cSMark Johnston dnode_phys_t *dnode;
303240afd8cSMark Johnston uint64_t dnid;
304240afd8cSMark Johnston off_t loc;
305240afd8cSMark Johnston } *sma;
306240afd8cSMark Johnston
307240afd8cSMark Johnston objarrblksz = sizeof(uint64_t) * zfs->mscount;
308240afd8cSMark Johnston assert(objarrblksz <= MAXBLOCKSIZE);
309240afd8cSMark Johnston objarrloc = objset_space_alloc(zfs, zfs->mos, &objarrblksz);
310240afd8cSMark Johnston objarrblk = ecalloc(1, objarrblksz);
311240afd8cSMark Johnston
312240afd8cSMark Johnston objarr = objset_dnode_lookup(zfs->mos, zfs->objarrid);
313240afd8cSMark Johnston objarr->dn_datablkszsec = objarrblksz >> MINBLOCKSHIFT;
314240afd8cSMark Johnston
315240afd8cSMark Johnston /*
316240afd8cSMark Johnston * Use the smallest block size for space maps. The space allocation
317240afd8cSMark Johnston * algorithm should aim to minimize the number of holes.
318240afd8cSMark Johnston */
319240afd8cSMark Johnston smblksz = 1 << zfs->ashift;
320240afd8cSMark Johnston
321240afd8cSMark Johnston /*
322240afd8cSMark Johnston * First allocate dnodes and space for all of our space maps. No more
323240afd8cSMark Johnston * space can be allocated from the vdev after this point.
324240afd8cSMark Johnston */
325240afd8cSMark Johnston sma = ecalloc(zfs->mscount, sizeof(*sma));
326240afd8cSMark Johnston for (uint64_t i = 0; i < zfs->mscount; i++) {
327240afd8cSMark Johnston sma[i].dnode = objset_dnode_bonus_alloc(zfs->mos,
328240afd8cSMark Johnston DMU_OT_SPACE_MAP, DMU_OT_SPACE_MAP_HEADER,
329240afd8cSMark Johnston sizeof(space_map_phys_t), &sma[i].dnid);
330240afd8cSMark Johnston sma[i].loc = objset_space_alloc(zfs, zfs->mos, &smblksz);
331240afd8cSMark Johnston }
332240afd8cSMark Johnston spacemap = zfs->spacemap;
333240afd8cSMark Johnston zfs->spacemap = NULL;
334240afd8cSMark Johnston
335240afd8cSMark Johnston /*
336240afd8cSMark Johnston * Now that the set of allocated space is finalized, populate each space
337240afd8cSMark Johnston * map and write it to the vdev.
338240afd8cSMark Johnston */
339240afd8cSMark Johnston for (uint64_t i = 0; i < zfs->mscount; i++) {
340240afd8cSMark Johnston space_map_phys_t *sm;
341240afd8cSMark Johnston uint64_t alloc, length, *smblk;
342240afd8cSMark Johnston int shift, startb, endb, srunb, erunb;
343240afd8cSMark Johnston
344240afd8cSMark Johnston /*
345240afd8cSMark Johnston * We only allocate a single block for this space map, but
346240afd8cSMark Johnston * OpenZFS assumes that a space map object with sufficient bonus
347240afd8cSMark Johnston * space supports histograms.
348240afd8cSMark Johnston */
349240afd8cSMark Johnston sma[i].dnode->dn_nblkptr = 3;
350240afd8cSMark Johnston sma[i].dnode->dn_datablkszsec = smblksz >> MINBLOCKSHIFT;
351240afd8cSMark Johnston
352240afd8cSMark Johnston smblk = ecalloc(1, smblksz);
353240afd8cSMark Johnston
354240afd8cSMark Johnston alloc = length = 0;
355240afd8cSMark Johnston shift = zfs->msshift - zfs->ashift;
356240afd8cSMark Johnston for (srunb = startb = i * (1 << shift),
357240afd8cSMark Johnston endb = (i + 1) * (1 << shift);
358240afd8cSMark Johnston srunb < endb; srunb = erunb) {
359240afd8cSMark Johnston uint64_t runlen, runoff;
360240afd8cSMark Johnston
361240afd8cSMark Johnston /* Find a run of allocated space. */
362240afd8cSMark Johnston bit_ffs_at(spacemap, srunb, zfs->spacemapbits, &srunb);
363240afd8cSMark Johnston if (srunb == -1 || srunb >= endb)
364240afd8cSMark Johnston break;
365240afd8cSMark Johnston
366240afd8cSMark Johnston bit_ffc_at(spacemap, srunb, zfs->spacemapbits, &erunb);
367240afd8cSMark Johnston if (erunb == -1 || erunb > endb)
368240afd8cSMark Johnston erunb = endb;
369240afd8cSMark Johnston
370240afd8cSMark Johnston /*
371240afd8cSMark Johnston * The space represented by [srunb, erunb) has been
372240afd8cSMark Johnston * allocated. Add a record to the space map to indicate
373240afd8cSMark Johnston * this. Run offsets are relative to the beginning of
374240afd8cSMark Johnston * the metaslab.
375240afd8cSMark Johnston */
376240afd8cSMark Johnston runlen = erunb - srunb;
377240afd8cSMark Johnston runoff = srunb - startb;
378240afd8cSMark Johnston
379240afd8cSMark Johnston assert(length * sizeof(uint64_t) < (uint64_t)smblksz);
380240afd8cSMark Johnston smblk[length] = SM_PREFIX_ENCODE(SM2_PREFIX) |
381240afd8cSMark Johnston SM2_RUN_ENCODE(runlen) | SM2_VDEV_ENCODE(0);
382240afd8cSMark Johnston smblk[length + 1] = SM2_TYPE_ENCODE(SM_ALLOC) |
383240afd8cSMark Johnston SM2_OFFSET_ENCODE(runoff);
384240afd8cSMark Johnston
385240afd8cSMark Johnston alloc += runlen << zfs->ashift;
386240afd8cSMark Johnston length += 2;
387240afd8cSMark Johnston }
388240afd8cSMark Johnston
389240afd8cSMark Johnston sm = DN_BONUS(sma[i].dnode);
390240afd8cSMark Johnston sm->smp_length = length * sizeof(uint64_t);
391240afd8cSMark Johnston sm->smp_alloc = alloc;
392240afd8cSMark Johnston
393240afd8cSMark Johnston vdev_pwrite_dnode_data(zfs, sma[i].dnode, smblk, smblksz,
394240afd8cSMark Johnston sma[i].loc);
395240afd8cSMark Johnston free(smblk);
396240afd8cSMark Johnston
397240afd8cSMark Johnston /* Record this space map in the space map object array. */
398240afd8cSMark Johnston objarrblk[i] = sma[i].dnid;
399240afd8cSMark Johnston }
400240afd8cSMark Johnston
401240afd8cSMark Johnston /*
402240afd8cSMark Johnston * All of the space maps are written, now write the object array.
403240afd8cSMark Johnston */
404240afd8cSMark Johnston vdev_pwrite_dnode_data(zfs, objarr, objarrblk, objarrblksz, objarrloc);
405240afd8cSMark Johnston free(objarrblk);
406240afd8cSMark Johnston
407240afd8cSMark Johnston assert(zfs->spacemap == NULL);
408240afd8cSMark Johnston free(spacemap);
409240afd8cSMark Johnston free(sma);
410240afd8cSMark Johnston }
411240afd8cSMark Johnston
412240afd8cSMark Johnston void
vdev_init(zfs_opt_t * zfs,const char * image)413240afd8cSMark Johnston vdev_init(zfs_opt_t *zfs, const char *image)
414240afd8cSMark Johnston {
415240afd8cSMark Johnston assert(zfs->ashift >= MINBLOCKSHIFT);
416240afd8cSMark Johnston
417240afd8cSMark Johnston zfs->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0644);
418240afd8cSMark Johnston if (zfs->fd == -1)
419240afd8cSMark Johnston err(1, "Can't open `%s' for writing", image);
420240afd8cSMark Johnston if (ftruncate(zfs->fd, zfs->vdevsize) != 0)
421240afd8cSMark Johnston err(1, "Failed to extend image file `%s'", image);
422240afd8cSMark Johnston
423240afd8cSMark Johnston vdev_spacemap_init(zfs);
424240afd8cSMark Johnston }
425240afd8cSMark Johnston
426240afd8cSMark Johnston void
vdev_fini(zfs_opt_t * zfs)427240afd8cSMark Johnston vdev_fini(zfs_opt_t *zfs)
428240afd8cSMark Johnston {
429240afd8cSMark Johnston assert(zfs->spacemap == NULL);
430240afd8cSMark Johnston
431240afd8cSMark Johnston if (zfs->fd != -1) {
432240afd8cSMark Johnston if (close(zfs->fd) != 0)
433240afd8cSMark Johnston err(1, "close");
434240afd8cSMark Johnston zfs->fd = -1;
435240afd8cSMark Johnston }
436240afd8cSMark Johnston }
437