1 |
|
|
/* $OpenBSD: mkfs.c,v 1.13 2016/11/11 09:54:07 natano Exp $ */ |
2 |
|
|
/* $NetBSD: mkfs.c,v 1.34 2016/06/24 19:24:11 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 2002 Networks Associates Technology, Inc. |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This software was developed for the FreeBSD Project by Marshall |
9 |
|
|
* Kirk McKusick and Network Associates Laboratories, the Security |
10 |
|
|
* Research Division of Network Associates, Inc. under DARPA/SPAWAR |
11 |
|
|
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS |
12 |
|
|
* research program |
13 |
|
|
* |
14 |
|
|
* Copyright (c) 1980, 1989, 1993 |
15 |
|
|
* The Regents of the University of California. All rights reserved. |
16 |
|
|
* |
17 |
|
|
* Redistribution and use in source and binary forms, with or without |
18 |
|
|
* modification, are permitted provided that the following conditions |
19 |
|
|
* are met: |
20 |
|
|
* 1. Redistributions of source code must retain the above copyright |
21 |
|
|
* notice, this list of conditions and the following disclaimer. |
22 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
23 |
|
|
* notice, this list of conditions and the following disclaimer in the |
24 |
|
|
* documentation and/or other materials provided with the distribution. |
25 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
26 |
|
|
* may be used to endorse or promote products derived from this software |
27 |
|
|
* without specific prior written permission. |
28 |
|
|
* |
29 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
30 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
31 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
32 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
33 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
34 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
35 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
36 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
37 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
38 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
39 |
|
|
* SUCH DAMAGE. |
40 |
|
|
*/ |
41 |
|
|
|
42 |
|
|
#include <sys/param.h> |
43 |
|
|
#include <sys/time.h> |
44 |
|
|
#include <sys/resource.h> |
45 |
|
|
|
46 |
|
|
#include <stdio.h> |
47 |
|
|
#include <stdlib.h> |
48 |
|
|
#include <string.h> |
49 |
|
|
#include <unistd.h> |
50 |
|
|
#include <errno.h> |
51 |
|
|
#include <util.h> |
52 |
|
|
|
53 |
|
|
#include <ufs/ufs/dinode.h> |
54 |
|
|
#include <ufs/ffs/fs.h> |
55 |
|
|
|
56 |
|
|
#include "ffs/ufs_inode.h" |
57 |
|
|
#include "ffs/ffs_extern.h" |
58 |
|
|
|
59 |
|
|
#include "makefs.h" |
60 |
|
|
#include "ffs.h" |
61 |
|
|
#include "ffs/newfs_extern.h" |
62 |
|
|
|
63 |
|
|
static void initcg(int, time_t, const fsinfo_t *); |
64 |
|
|
static int ilog2(int); |
65 |
|
|
|
66 |
|
|
static int count_digits(int); |
67 |
|
|
|
68 |
|
|
/* |
69 |
|
|
* make file system for cylinder-group style file systems |
70 |
|
|
*/ |
71 |
|
|
#define UMASK 0755 |
72 |
|
|
#define POWEROF2(num) (((num) & ((num) - 1)) == 0) |
73 |
|
|
|
74 |
|
|
union { |
75 |
|
|
struct fs fs; |
76 |
|
|
char pad[SBLOCKSIZE]; |
77 |
|
|
} fsun; |
78 |
|
|
#define sblock fsun.fs |
79 |
|
|
struct csum *fscs; |
80 |
|
|
|
81 |
|
|
union { |
82 |
|
|
struct cg cg; |
83 |
|
|
char pad[FFS_MAXBSIZE]; |
84 |
|
|
} cgun; |
85 |
|
|
#define acg cgun.cg |
86 |
|
|
|
87 |
|
|
char *iobuf; |
88 |
|
|
int iobufsize; |
89 |
|
|
|
90 |
|
|
char writebuf[FFS_MAXBSIZE]; |
91 |
|
|
|
92 |
|
|
static int Oflag; /* format as an 4.3BSD file system */ |
93 |
|
|
static int64_t fssize; /* file system size */ |
94 |
|
|
static int sectorsize; /* bytes/sector */ |
95 |
|
|
static int fsize; /* fragment size */ |
96 |
|
|
static int bsize; /* block size */ |
97 |
|
|
static int maxbsize; /* maximum clustering */ |
98 |
|
|
static int maxblkspercg; |
99 |
|
|
static int minfree; /* free space threshold */ |
100 |
|
|
static int opt; /* optimization preference (space or time) */ |
101 |
|
|
static int density; /* number of bytes per inode */ |
102 |
|
|
static int maxcontig; /* max contiguous blocks to allocate */ |
103 |
|
|
static int maxbpg; /* maximum blocks per file in a cyl group */ |
104 |
|
|
static int bbsize; /* boot block size */ |
105 |
|
|
static int avgfilesize; /* expected average file size */ |
106 |
|
|
static int avgfpdir; /* expected number of files per directory */ |
107 |
|
|
|
108 |
|
|
struct fs * |
109 |
|
|
ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp) |
110 |
|
|
{ |
111 |
|
|
int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; |
112 |
|
|
int32_t cylno, i, csfrags; |
113 |
|
|
long long sizepb; |
114 |
|
|
void *space; |
115 |
|
|
int size; |
116 |
|
|
int nprintcols, printcolwidth; |
117 |
|
|
ffs_opt_t *ffs_opts = fsopts->fs_specific; |
118 |
|
|
|
119 |
|
|
Oflag = ffs_opts->version; |
120 |
|
|
fssize = fsopts->size / fsopts->sectorsize; |
121 |
|
|
sectorsize = fsopts->sectorsize; |
122 |
|
|
fsize = ffs_opts->fsize; |
123 |
|
|
bsize = ffs_opts->bsize; |
124 |
|
|
maxbsize = ffs_opts->maxbsize; |
125 |
|
|
maxblkspercg = ffs_opts->maxblkspercg; |
126 |
|
|
minfree = ffs_opts->minfree; |
127 |
|
|
opt = ffs_opts->optimization; |
128 |
|
|
density = ffs_opts->density; |
129 |
|
|
maxcontig = MAX(1, MIN(MAXBSIZE, FFS_MAXBSIZE) / bsize); |
130 |
|
|
maxbpg = ffs_opts->maxbpg; |
131 |
|
|
avgfilesize = ffs_opts->avgfilesize; |
132 |
|
|
avgfpdir = ffs_opts->avgfpdir; |
133 |
|
|
bbsize = BBSIZE; |
134 |
|
|
|
135 |
|
|
strlcpy((char *)sblock.fs_volname, ffs_opts->label, |
136 |
|
|
sizeof(sblock.fs_volname)); |
137 |
|
|
|
138 |
|
|
sblock.fs_inodefmt = FS_44INODEFMT; |
139 |
|
|
sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 : |
140 |
|
|
MAXSYMLINKLEN_UFS2); |
141 |
|
|
sblock.fs_ffs1_flags = FS_FLAGS_UPDATED; |
142 |
|
|
sblock.fs_flags = 0; |
143 |
|
|
|
144 |
|
|
/* |
145 |
|
|
* Validate the given file system size. |
146 |
|
|
* Verify that its last block can actually be accessed. |
147 |
|
|
* Convert to file system fragment sized units. |
148 |
|
|
*/ |
149 |
|
|
if (fssize <= 0) { |
150 |
|
|
printf("preposterous size %lld\n", (long long)fssize); |
151 |
|
|
exit(13); |
152 |
|
|
} |
153 |
|
|
ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts); |
154 |
|
|
|
155 |
|
|
/* |
156 |
|
|
* collect and verify the filesystem density info |
157 |
|
|
*/ |
158 |
|
|
sblock.fs_avgfilesize = avgfilesize; |
159 |
|
|
sblock.fs_avgfpdir = avgfpdir; |
160 |
|
|
if (sblock.fs_avgfilesize <= 0) |
161 |
|
|
printf("illegal expected average file size %d\n", |
162 |
|
|
sblock.fs_avgfilesize), exit(14); |
163 |
|
|
if (sblock.fs_avgfpdir <= 0) |
164 |
|
|
printf("illegal expected number of files per directory %d\n", |
165 |
|
|
sblock.fs_avgfpdir), exit(15); |
166 |
|
|
/* |
167 |
|
|
* collect and verify the block and fragment sizes |
168 |
|
|
*/ |
169 |
|
|
sblock.fs_bsize = bsize; |
170 |
|
|
sblock.fs_fsize = fsize; |
171 |
|
|
if (!POWEROF2(sblock.fs_bsize)) { |
172 |
|
|
printf("block size must be a power of 2, not %d\n", |
173 |
|
|
sblock.fs_bsize); |
174 |
|
|
exit(16); |
175 |
|
|
} |
176 |
|
|
if (!POWEROF2(sblock.fs_fsize)) { |
177 |
|
|
printf("fragment size must be a power of 2, not %d\n", |
178 |
|
|
sblock.fs_fsize); |
179 |
|
|
exit(17); |
180 |
|
|
} |
181 |
|
|
if (sblock.fs_fsize < sectorsize) { |
182 |
|
|
printf("fragment size %d is too small, minimum is %d\n", |
183 |
|
|
sblock.fs_fsize, sectorsize); |
184 |
|
|
exit(18); |
185 |
|
|
} |
186 |
|
|
if (sblock.fs_bsize < MINBSIZE) { |
187 |
|
|
printf("block size %d is too small, minimum is %d\n", |
188 |
|
|
sblock.fs_bsize, MINBSIZE); |
189 |
|
|
exit(19); |
190 |
|
|
} |
191 |
|
|
if (sblock.fs_bsize > FFS_MAXBSIZE) { |
192 |
|
|
printf("block size %d is too large, maximum is %d\n", |
193 |
|
|
sblock.fs_bsize, FFS_MAXBSIZE); |
194 |
|
|
exit(19); |
195 |
|
|
} |
196 |
|
|
if (sblock.fs_bsize < sblock.fs_fsize) { |
197 |
|
|
printf("block size (%d) cannot be smaller than fragment size (%d)\n", |
198 |
|
|
sblock.fs_bsize, sblock.fs_fsize); |
199 |
|
|
exit(20); |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
if (maxbsize < bsize || !POWEROF2(maxbsize)) { |
203 |
|
|
sblock.fs_maxbsize = sblock.fs_bsize; |
204 |
|
|
printf("Extent size set to %d\n", sblock.fs_maxbsize); |
205 |
|
|
} else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { |
206 |
|
|
sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; |
207 |
|
|
printf("Extent size reduced to %d\n", sblock.fs_maxbsize); |
208 |
|
|
} else { |
209 |
|
|
sblock.fs_maxbsize = maxbsize; |
210 |
|
|
} |
211 |
|
|
sblock.fs_maxcontig = maxcontig; |
212 |
|
|
if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { |
213 |
|
|
sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; |
214 |
|
|
printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); |
215 |
|
|
} |
216 |
|
|
|
217 |
|
|
if (sblock.fs_maxcontig > 1) |
218 |
|
|
sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); |
219 |
|
|
|
220 |
|
|
sblock.fs_bmask = ~(sblock.fs_bsize - 1); |
221 |
|
|
sblock.fs_fmask = ~(sblock.fs_fsize - 1); |
222 |
|
|
sblock.fs_qbmask = ~sblock.fs_bmask; |
223 |
|
|
sblock.fs_qfmask = ~sblock.fs_fmask; |
224 |
|
|
for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) |
225 |
|
|
sblock.fs_bshift++; |
226 |
|
|
for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) |
227 |
|
|
sblock.fs_fshift++; |
228 |
|
|
sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); |
229 |
|
|
for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) |
230 |
|
|
sblock.fs_fragshift++; |
231 |
|
|
if (sblock.fs_frag > MAXFRAG) { |
232 |
|
|
printf("fragment size %d is too small, " |
233 |
|
|
"minimum with block size %d is %d\n", |
234 |
|
|
sblock.fs_fsize, sblock.fs_bsize, |
235 |
|
|
sblock.fs_bsize / MAXFRAG); |
236 |
|
|
exit(21); |
237 |
|
|
} |
238 |
|
|
sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); |
239 |
|
|
sblock.fs_size = fssize = dbtofsb(&sblock, fssize); |
240 |
|
|
|
241 |
|
|
if (Oflag <= 1) { |
242 |
|
|
sblock.fs_magic = FS_UFS1_MAGIC; |
243 |
|
|
sblock.fs_sblockloc = SBLOCK_UFS1; |
244 |
|
|
sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t); |
245 |
|
|
sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); |
246 |
|
|
sblock.fs_maxsymlinklen = (NDADDR + NIADDR) * sizeof (int32_t); |
247 |
|
|
sblock.fs_inodefmt = FS_44INODEFMT; |
248 |
|
|
sblock.fs_cgoffset = 0; |
249 |
|
|
sblock.fs_cgmask = 0xffffffff; |
250 |
|
|
sblock.fs_ffs1_size = sblock.fs_size; |
251 |
|
|
sblock.fs_rotdelay = 0; |
252 |
|
|
sblock.fs_rps = 60; |
253 |
|
|
sblock.fs_nspf = sblock.fs_fsize / sectorsize; |
254 |
|
|
sblock.fs_cpg = 1; |
255 |
|
|
sblock.fs_interleave = 1; |
256 |
|
|
sblock.fs_trackskew = 0; |
257 |
|
|
sblock.fs_cpc = 0; |
258 |
|
|
sblock.fs_postblformat = 1; |
259 |
|
|
sblock.fs_nrpos = 1; |
260 |
|
|
} else { |
261 |
|
|
sblock.fs_magic = FS_UFS2_MAGIC; |
262 |
|
|
#if 0 /* XXX makefs is used for small filesystems. */ |
263 |
|
|
sblock.fs_sblockloc = SBLOCK_UFS2; |
264 |
|
|
#else |
265 |
|
|
sblock.fs_sblockloc = SBLOCK_UFS1; |
266 |
|
|
#endif |
267 |
|
|
sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t); |
268 |
|
|
sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); |
269 |
|
|
sblock.fs_maxsymlinklen = (NDADDR + NIADDR) * sizeof (int64_t); |
270 |
|
|
} |
271 |
|
|
|
272 |
|
|
sblock.fs_sblkno = |
273 |
|
|
roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), |
274 |
|
|
sblock.fs_frag); |
275 |
|
|
sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + |
276 |
|
|
roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag)); |
277 |
|
|
sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; |
278 |
|
|
sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; |
279 |
|
|
for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { |
280 |
|
|
sizepb *= NINDIR(&sblock); |
281 |
|
|
sblock.fs_maxfilesize += sizepb; |
282 |
|
|
} |
283 |
|
|
|
284 |
|
|
/* |
285 |
|
|
* Calculate the number of blocks to put into each cylinder group. |
286 |
|
|
* |
287 |
|
|
* This algorithm selects the number of blocks per cylinder |
288 |
|
|
* group. The first goal is to have at least enough data blocks |
289 |
|
|
* in each cylinder group to meet the density requirement. Once |
290 |
|
|
* this goal is achieved we try to expand to have at least |
291 |
|
|
* 1 cylinder group. Once this goal is achieved, we pack as |
292 |
|
|
* many blocks into each cylinder group map as will fit. |
293 |
|
|
* |
294 |
|
|
* We start by calculating the smallest number of blocks that we |
295 |
|
|
* can put into each cylinder group. If this is too big, we reduce |
296 |
|
|
* the density until it fits. |
297 |
|
|
*/ |
298 |
|
|
origdensity = density; |
299 |
|
|
for (;;) { |
300 |
|
|
fragsperinode = MAX(numfrags(&sblock, density), 1); |
301 |
|
|
minfpg = fragsperinode * INOPB(&sblock); |
302 |
|
|
if (minfpg > sblock.fs_size) |
303 |
|
|
minfpg = sblock.fs_size; |
304 |
|
|
sblock.fs_ipg = INOPB(&sblock); |
305 |
|
|
sblock.fs_fpg = roundup(sblock.fs_iblkno + |
306 |
|
|
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); |
307 |
|
|
if (sblock.fs_fpg < minfpg) |
308 |
|
|
sblock.fs_fpg = minfpg; |
309 |
|
|
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), |
310 |
|
|
INOPB(&sblock)); |
311 |
|
|
sblock.fs_fpg = roundup(sblock.fs_iblkno + |
312 |
|
|
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); |
313 |
|
|
if (sblock.fs_fpg < minfpg) |
314 |
|
|
sblock.fs_fpg = minfpg; |
315 |
|
|
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), |
316 |
|
|
INOPB(&sblock)); |
317 |
|
|
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) |
318 |
|
|
break; |
319 |
|
|
density -= sblock.fs_fsize; |
320 |
|
|
} |
321 |
|
|
if (density != origdensity) |
322 |
|
|
printf("density reduced from %d to %d\n", origdensity, density); |
323 |
|
|
|
324 |
|
|
if (maxblkspercg <= 0 || maxblkspercg >= fssize) |
325 |
|
|
maxblkspercg = fssize - 1; |
326 |
|
|
/* |
327 |
|
|
* Start packing more blocks into the cylinder group until |
328 |
|
|
* it cannot grow any larger, the number of cylinder groups |
329 |
|
|
* drops below 1, or we reach the size requested. |
330 |
|
|
*/ |
331 |
|
|
for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { |
332 |
|
|
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), |
333 |
|
|
INOPB(&sblock)); |
334 |
|
|
if (sblock.fs_size / sblock.fs_fpg < 1) |
335 |
|
|
break; |
336 |
|
|
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) |
337 |
|
|
continue; |
338 |
|
|
if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) |
339 |
|
|
break; |
340 |
|
|
sblock.fs_fpg -= sblock.fs_frag; |
341 |
|
|
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), |
342 |
|
|
INOPB(&sblock)); |
343 |
|
|
break; |
344 |
|
|
} |
345 |
|
|
/* |
346 |
|
|
* Check to be sure that the last cylinder group has enough blocks |
347 |
|
|
* to be viable. If it is too small, reduce the number of blocks |
348 |
|
|
* per cylinder group which will have the effect of moving more |
349 |
|
|
* blocks into the last cylinder group. |
350 |
|
|
*/ |
351 |
|
|
optimalfpg = sblock.fs_fpg; |
352 |
|
|
for (;;) { |
353 |
|
|
sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); |
354 |
|
|
lastminfpg = roundup(sblock.fs_iblkno + |
355 |
|
|
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); |
356 |
|
|
if (sblock.fs_size < lastminfpg) { |
357 |
|
|
printf("Filesystem size %lld < minimum size of %d\n", |
358 |
|
|
(long long)sblock.fs_size, lastminfpg); |
359 |
|
|
exit(28); |
360 |
|
|
} |
361 |
|
|
if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || |
362 |
|
|
sblock.fs_size % sblock.fs_fpg == 0) |
363 |
|
|
break; |
364 |
|
|
sblock.fs_fpg -= sblock.fs_frag; |
365 |
|
|
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), |
366 |
|
|
INOPB(&sblock)); |
367 |
|
|
} |
368 |
|
|
if (optimalfpg != sblock.fs_fpg) |
369 |
|
|
printf("Reduced frags per cylinder group from %d to %d %s\n", |
370 |
|
|
optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); |
371 |
|
|
sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); |
372 |
|
|
sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); |
373 |
|
|
if (Oflag <= 1) { |
374 |
|
|
sblock.fs_spc = sblock.fs_fpg * sblock.fs_nspf; |
375 |
|
|
sblock.fs_nsect = sblock.fs_spc; |
376 |
|
|
sblock.fs_npsect = sblock.fs_spc; |
377 |
|
|
sblock.fs_ncyl = sblock.fs_ncg; |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
/* |
381 |
|
|
* fill in remaining fields of the super block |
382 |
|
|
*/ |
383 |
|
|
sblock.fs_csaddr = cgdmin(&sblock, 0); |
384 |
|
|
sblock.fs_cssize = |
385 |
|
|
fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); |
386 |
|
|
|
387 |
|
|
/* |
388 |
|
|
* Setup memory for temporary in-core cylgroup summaries. |
389 |
|
|
* Cribbed from ffs_mountfs(). |
390 |
|
|
*/ |
391 |
|
|
size = sblock.fs_cssize; |
392 |
|
|
if (sblock.fs_contigsumsize > 0) |
393 |
|
|
size += sblock.fs_ncg * sizeof(int32_t); |
394 |
|
|
space = ecalloc(1, size); |
395 |
|
|
sblock.fs_csp = space; |
396 |
|
|
space = (char *)space + sblock.fs_cssize; |
397 |
|
|
if (sblock.fs_contigsumsize > 0) { |
398 |
|
|
int32_t *lp; |
399 |
|
|
|
400 |
|
|
sblock.fs_maxcluster = lp = space; |
401 |
|
|
for (i = 0; i < sblock.fs_ncg; i++) |
402 |
|
|
*lp++ = sblock.fs_contigsumsize; |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); |
406 |
|
|
if (sblock.fs_sbsize > SBLOCKSIZE) |
407 |
|
|
sblock.fs_sbsize = SBLOCKSIZE; |
408 |
|
|
sblock.fs_minfree = minfree; |
409 |
|
|
sblock.fs_maxcontig = maxcontig; |
410 |
|
|
sblock.fs_maxbpg = maxbpg; |
411 |
|
|
sblock.fs_optim = opt; |
412 |
|
|
sblock.fs_cgrotor = 0; |
413 |
|
|
sblock.fs_pendingblocks = 0; |
414 |
|
|
sblock.fs_pendinginodes = 0; |
415 |
|
|
sblock.fs_cstotal.cs_ndir = 0; |
416 |
|
|
sblock.fs_cstotal.cs_nbfree = 0; |
417 |
|
|
sblock.fs_cstotal.cs_nifree = 0; |
418 |
|
|
sblock.fs_cstotal.cs_nffree = 0; |
419 |
|
|
sblock.fs_fmod = 0; |
420 |
|
|
sblock.fs_ronly = 0; |
421 |
|
|
sblock.fs_state = 0; |
422 |
|
|
sblock.fs_clean = FS_ISCLEAN; |
423 |
|
|
sblock.fs_ronly = 0; |
424 |
|
|
sblock.fs_id[0] = tstamp; |
425 |
|
|
sblock.fs_id[1] = random(); |
426 |
|
|
sblock.fs_fsmnt[0] = '\0'; |
427 |
|
|
csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); |
428 |
|
|
sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - |
429 |
|
|
sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); |
430 |
|
|
sblock.fs_cstotal.cs_nbfree = |
431 |
|
|
fragstoblks(&sblock, sblock.fs_dsize) - |
432 |
|
|
howmany(csfrags, sblock.fs_frag); |
433 |
|
|
sblock.fs_cstotal.cs_nffree = |
434 |
|
|
fragnum(&sblock, sblock.fs_size) + |
435 |
|
|
(fragnum(&sblock, csfrags) > 0 ? |
436 |
|
|
sblock.fs_frag - fragnum(&sblock, csfrags) : 0); |
437 |
|
|
sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; |
438 |
|
|
sblock.fs_cstotal.cs_ndir = 0; |
439 |
|
|
sblock.fs_dsize -= csfrags; |
440 |
|
|
sblock.fs_time = tstamp; |
441 |
|
|
if (Oflag <= 1) { |
442 |
|
|
sblock.fs_ffs1_time = tstamp; |
443 |
|
|
sblock.fs_ffs1_dsize = sblock.fs_dsize; |
444 |
|
|
sblock.fs_ffs1_csaddr = sblock.fs_csaddr; |
445 |
|
|
sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; |
446 |
|
|
sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; |
447 |
|
|
sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; |
448 |
|
|
sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; |
449 |
|
|
} |
450 |
|
|
/* |
451 |
|
|
* Dump out summary information about file system. |
452 |
|
|
*/ |
453 |
|
|
#define B2MBFACTOR (1 / (1024.0 * 1024.0)) |
454 |
|
|
printf("%s: %.1fMB (%lld sectors) block size %d, " |
455 |
|
|
"fragment size %d\n", |
456 |
|
|
fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, |
457 |
|
|
(long long)fsbtodb(&sblock, sblock.fs_size), |
458 |
|
|
sblock.fs_bsize, sblock.fs_fsize); |
459 |
|
|
printf("\tusing %d cylinder groups of %.2fMB, %d blks, " |
460 |
|
|
"%d inodes.\n", |
461 |
|
|
sblock.fs_ncg, |
462 |
|
|
(float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, |
463 |
|
|
sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); |
464 |
|
|
#undef B2MBFACTOR |
465 |
|
|
/* |
466 |
|
|
* Now determine how wide each column will be, and calculate how |
467 |
|
|
* many columns will fit in a 76 char line. 76 is the width of the |
468 |
|
|
* subwindows in sysinst. |
469 |
|
|
*/ |
470 |
|
|
printcolwidth = count_digits( |
471 |
|
|
fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1))); |
472 |
|
|
nprintcols = 76 / (printcolwidth + 2); |
473 |
|
|
|
474 |
|
|
/* |
475 |
|
|
* allocate space for superblock, cylinder group map, and |
476 |
|
|
* two sets of inode blocks. |
477 |
|
|
*/ |
478 |
|
|
if (sblock.fs_bsize < SBLOCKSIZE) |
479 |
|
|
iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; |
480 |
|
|
else |
481 |
|
|
iobufsize = 4 * sblock.fs_bsize; |
482 |
|
|
iobuf = ecalloc(1, iobufsize); |
483 |
|
|
/* |
484 |
|
|
* Make a copy of the superblock into the buffer that we will be |
485 |
|
|
* writing out in each cylinder group. |
486 |
|
|
*/ |
487 |
|
|
memcpy(writebuf, &sblock, SBLOCKSIZE); |
488 |
|
|
memcpy(iobuf, writebuf, SBLOCKSIZE); |
489 |
|
|
|
490 |
|
|
printf("super-block backups (for fsck -b #) at:"); |
491 |
|
|
for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { |
492 |
|
|
initcg(cylno, tstamp, fsopts); |
493 |
|
|
if (cylno % nprintcols == 0) |
494 |
|
|
printf("\n"); |
495 |
|
|
printf(" %*lld,", printcolwidth, |
496 |
|
|
(long long)fsbtodb(&sblock, cgsblock(&sblock, cylno))); |
497 |
|
|
fflush(stdout); |
498 |
|
|
} |
499 |
|
|
printf("\n"); |
500 |
|
|
|
501 |
|
|
/* |
502 |
|
|
* Now construct the initial file system, |
503 |
|
|
* then write out the super-block. |
504 |
|
|
*/ |
505 |
|
|
sblock.fs_time = tstamp; |
506 |
|
|
if (Oflag <= 1) { |
507 |
|
|
sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; |
508 |
|
|
sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; |
509 |
|
|
sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; |
510 |
|
|
sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; |
511 |
|
|
} |
512 |
|
|
ffs_write_superblock(&sblock, fsopts); |
513 |
|
|
return (&sblock); |
514 |
|
|
} |
515 |
|
|
|
516 |
|
|
/* |
517 |
|
|
* Write out the superblock and its duplicates, |
518 |
|
|
* and the cylinder group summaries |
519 |
|
|
*/ |
520 |
|
|
void |
521 |
|
|
ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts) |
522 |
|
|
{ |
523 |
|
|
int cylno, size, blks, i; |
524 |
|
|
struct fs *fsdup; |
525 |
|
|
void *space; |
526 |
|
|
char *wrbuf; |
527 |
|
|
|
528 |
|
|
memcpy(writebuf, fs, SBLOCKSIZE); |
529 |
|
|
|
530 |
|
|
fsdup = (struct fs *)writebuf; |
531 |
|
|
fsdup->fs_csp = NULL; |
532 |
|
|
fsdup->fs_maxcluster = NULL; |
533 |
|
|
|
534 |
|
|
ffs_wtfs(fs->fs_sblockloc / sectorsize, SBLOCKSIZE, writebuf, fsopts); |
535 |
|
|
|
536 |
|
|
/* Write out the duplicate super blocks */ |
537 |
|
|
for (cylno = 0; cylno < fs->fs_ncg; cylno++) |
538 |
|
|
ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)), |
539 |
|
|
SBLOCKSIZE, writebuf, fsopts); |
540 |
|
|
|
541 |
|
|
/* Write out the cylinder group summaries */ |
542 |
|
|
size = fs->fs_cssize; |
543 |
|
|
blks = howmany(size, fs->fs_fsize); |
544 |
|
|
space = (void *)fs->fs_csp; |
545 |
|
|
wrbuf = emalloc(size); |
546 |
|
|
for (i = 0; i < blks; i+= fs->fs_frag) { |
547 |
|
|
size = fs->fs_bsize; |
548 |
|
|
if (i + fs->fs_frag > blks) |
549 |
|
|
size = (blks - i) * fs->fs_fsize; |
550 |
|
|
memcpy(wrbuf, space, (u_int)size); |
551 |
|
|
ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts); |
552 |
|
|
space = (char *)space + size; |
553 |
|
|
} |
554 |
|
|
free(wrbuf); |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
/* |
558 |
|
|
* Initialize a cylinder group. |
559 |
|
|
*/ |
560 |
|
|
static void |
561 |
|
|
initcg(int cylno, time_t utime, const fsinfo_t *fsopts) |
562 |
|
|
{ |
563 |
|
|
daddr_t cbase, dmax; |
564 |
|
|
int i, j, d, dlower, dupper, blkno; |
565 |
|
|
struct ufs1_dinode *dp1; |
566 |
|
|
struct ufs2_dinode *dp2; |
567 |
|
|
int start; |
568 |
|
|
|
569 |
|
|
/* |
570 |
|
|
* Determine block bounds for cylinder group. |
571 |
|
|
* Allow space for super block summary information in first |
572 |
|
|
* cylinder group. |
573 |
|
|
*/ |
574 |
|
|
cbase = cgbase(&sblock, cylno); |
575 |
|
|
dmax = cbase + sblock.fs_fpg; |
576 |
|
|
if (dmax > sblock.fs_size) |
577 |
|
|
dmax = sblock.fs_size; |
578 |
|
|
dlower = cgsblock(&sblock, cylno) - cbase; |
579 |
|
|
dupper = cgdmin(&sblock, cylno) - cbase; |
580 |
|
|
if (cylno == 0) |
581 |
|
|
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); |
582 |
|
|
memset(&acg, 0, sblock.fs_cgsize); |
583 |
|
|
acg.cg_ffs2_time = utime; |
584 |
|
|
acg.cg_magic = CG_MAGIC; |
585 |
|
|
acg.cg_cgx = cylno; |
586 |
|
|
acg.cg_ffs2_niblk = sblock.fs_ipg; |
587 |
|
|
acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? |
588 |
|
|
sblock.fs_ipg : 2 * INOPB(&sblock); |
589 |
|
|
acg.cg_ndblk = dmax - cbase; |
590 |
|
|
if (sblock.fs_contigsumsize > 0) |
591 |
|
|
acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift; |
592 |
|
|
start = sizeof(struct cg); |
593 |
|
|
if (Oflag == 2) { |
594 |
|
|
acg.cg_iusedoff = start; |
595 |
|
|
} else { |
596 |
|
|
if (cylno == sblock.fs_ncg - 1) |
597 |
|
|
acg.cg_ncyl = howmany(acg.cg_ndblk, |
598 |
|
|
sblock.fs_fpg / sblock.fs_cpg); |
599 |
|
|
else |
600 |
|
|
acg.cg_ncyl = sblock.fs_cpg; |
601 |
|
|
acg.cg_time = acg.cg_ffs2_time; |
602 |
|
|
acg.cg_ffs2_time = 0; |
603 |
|
|
acg.cg_niblk = acg.cg_ffs2_niblk; |
604 |
|
|
acg.cg_ffs2_niblk = 0; |
605 |
|
|
acg.cg_initediblk = 0; |
606 |
|
|
acg.cg_btotoff = start; |
607 |
|
|
acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(int32_t); |
608 |
|
|
acg.cg_iusedoff = acg.cg_boff + |
609 |
|
|
sblock.fs_cpg * sizeof(u_int16_t); |
610 |
|
|
} |
611 |
|
|
acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); |
612 |
|
|
if (sblock.fs_contigsumsize <= 0) { |
613 |
|
|
acg.cg_nextfreeoff = acg.cg_freeoff + |
614 |
|
|
howmany(sblock.fs_fpg, CHAR_BIT); |
615 |
|
|
} else { |
616 |
|
|
acg.cg_clustersumoff = acg.cg_freeoff + |
617 |
|
|
howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t); |
618 |
|
|
acg.cg_clustersumoff = |
619 |
|
|
roundup(acg.cg_clustersumoff, sizeof(int32_t)); |
620 |
|
|
acg.cg_clusteroff = acg.cg_clustersumoff + |
621 |
|
|
(sblock.fs_contigsumsize + 1) * sizeof(int32_t); |
622 |
|
|
acg.cg_nextfreeoff = acg.cg_clusteroff + |
623 |
|
|
howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); |
624 |
|
|
} |
625 |
|
|
if (acg.cg_nextfreeoff > sblock.fs_cgsize) { |
626 |
|
|
printf("Panic: cylinder group too big\n"); |
627 |
|
|
exit(37); |
628 |
|
|
} |
629 |
|
|
acg.cg_cs.cs_nifree += sblock.fs_ipg; |
630 |
|
|
if (cylno == 0) { |
631 |
|
|
size_t r; |
632 |
|
|
|
633 |
|
|
for (r = 0; r < ROOTINO; r++) { |
634 |
|
|
setbit(cg_inosused(&acg), r); |
635 |
|
|
acg.cg_cs.cs_nifree--; |
636 |
|
|
} |
637 |
|
|
} |
638 |
|
|
if (cylno > 0) { |
639 |
|
|
/* |
640 |
|
|
* In cylno 0, beginning space is reserved |
641 |
|
|
* for boot and super blocks. |
642 |
|
|
*/ |
643 |
|
|
for (d = 0, blkno = 0; d < dlower;) { |
644 |
|
|
ffs_setblock(&sblock, cg_blksfree(&acg), blkno); |
645 |
|
|
if (sblock.fs_contigsumsize > 0) |
646 |
|
|
setbit(cg_clustersfree(&acg), blkno); |
647 |
|
|
acg.cg_cs.cs_nbfree++; |
648 |
|
|
d += sblock.fs_frag; |
649 |
|
|
blkno++; |
650 |
|
|
} |
651 |
|
|
} |
652 |
|
|
if ((i = (dupper & (sblock.fs_frag - 1))) != 0) { |
653 |
|
|
acg.cg_frsum[sblock.fs_frag - i]++; |
654 |
|
|
for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { |
655 |
|
|
setbit(cg_blksfree(&acg), dupper); |
656 |
|
|
acg.cg_cs.cs_nffree++; |
657 |
|
|
} |
658 |
|
|
} |
659 |
|
|
for (d = dupper, blkno = dupper >> sblock.fs_fragshift; |
660 |
|
|
d + sblock.fs_frag <= acg.cg_ndblk; ) { |
661 |
|
|
ffs_setblock(&sblock, cg_blksfree(&acg), blkno); |
662 |
|
|
if (sblock.fs_contigsumsize > 0) |
663 |
|
|
setbit(cg_clustersfree(&acg), blkno); |
664 |
|
|
acg.cg_cs.cs_nbfree++; |
665 |
|
|
d += sblock.fs_frag; |
666 |
|
|
blkno++; |
667 |
|
|
} |
668 |
|
|
if (d < acg.cg_ndblk) { |
669 |
|
|
acg.cg_frsum[acg.cg_ndblk - d]++; |
670 |
|
|
for (; d < acg.cg_ndblk; d++) { |
671 |
|
|
setbit(cg_blksfree(&acg), d); |
672 |
|
|
acg.cg_cs.cs_nffree++; |
673 |
|
|
} |
674 |
|
|
} |
675 |
|
|
if (sblock.fs_contigsumsize > 0) { |
676 |
|
|
int32_t *sump = cg_clustersum(&acg); |
677 |
|
|
u_char *mapp = cg_clustersfree(&acg); |
678 |
|
|
int map = *mapp++; |
679 |
|
|
int bit = 1; |
680 |
|
|
int run = 0; |
681 |
|
|
|
682 |
|
|
for (i = 0; i < acg.cg_nclusterblks; i++) { |
683 |
|
|
if ((map & bit) != 0) { |
684 |
|
|
run++; |
685 |
|
|
} else if (run != 0) { |
686 |
|
|
if (run > sblock.fs_contigsumsize) |
687 |
|
|
run = sblock.fs_contigsumsize; |
688 |
|
|
sump[run]++; |
689 |
|
|
run = 0; |
690 |
|
|
} |
691 |
|
|
if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) { |
692 |
|
|
bit <<= 1; |
693 |
|
|
} else { |
694 |
|
|
map = *mapp++; |
695 |
|
|
bit = 1; |
696 |
|
|
} |
697 |
|
|
} |
698 |
|
|
if (run != 0) { |
699 |
|
|
if (run > sblock.fs_contigsumsize) |
700 |
|
|
run = sblock.fs_contigsumsize; |
701 |
|
|
sump[run]++; |
702 |
|
|
} |
703 |
|
|
} |
704 |
|
|
sblock.fs_cs(&sblock, cylno) = acg.cg_cs; |
705 |
|
|
/* |
706 |
|
|
* Write out the duplicate super block, the cylinder group map |
707 |
|
|
* and two blocks worth of inodes in a single write. |
708 |
|
|
*/ |
709 |
|
|
start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE; |
710 |
|
|
memcpy(&iobuf[start], &acg, sblock.fs_cgsize); |
711 |
|
|
start += sblock.fs_bsize; |
712 |
|
|
dp1 = (struct ufs1_dinode *)(&iobuf[start]); |
713 |
|
|
dp2 = (struct ufs2_dinode *)(&iobuf[start]); |
714 |
|
|
for (i = 0; i < acg.cg_initediblk; i++) { |
715 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) { |
716 |
|
|
/* No need to swap, it'll stay random */ |
717 |
|
|
dp1->di_gen = random(); |
718 |
|
|
dp1++; |
719 |
|
|
} else { |
720 |
|
|
dp2->di_gen = random(); |
721 |
|
|
dp2++; |
722 |
|
|
} |
723 |
|
|
} |
724 |
|
|
ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf, |
725 |
|
|
fsopts); |
726 |
|
|
/* |
727 |
|
|
* For the old file system, we have to initialize all the inodes. |
728 |
|
|
*/ |
729 |
|
|
if (Oflag <= 1) { |
730 |
|
|
for (i = 2 * sblock.fs_frag; |
731 |
|
|
i < sblock.fs_ipg / INOPF(&sblock); |
732 |
|
|
i += sblock.fs_frag) { |
733 |
|
|
dp1 = (struct ufs1_dinode *)(&iobuf[start]); |
734 |
|
|
for (j = 0; j < INOPB(&sblock); j++) { |
735 |
|
|
dp1->di_gen = random(); |
736 |
|
|
dp1++; |
737 |
|
|
} |
738 |
|
|
ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), |
739 |
|
|
sblock.fs_bsize, &iobuf[start], fsopts); |
740 |
|
|
} |
741 |
|
|
} |
742 |
|
|
} |
743 |
|
|
|
744 |
|
|
/* |
745 |
|
|
* read a block from the file system |
746 |
|
|
*/ |
747 |
|
|
void |
748 |
|
|
ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) |
749 |
|
|
{ |
750 |
|
|
int n; |
751 |
|
|
off_t offset; |
752 |
|
|
|
753 |
|
|
offset = bno * fsopts->sectorsize + fsopts->offset; |
754 |
|
|
if (lseek(fsopts->fd, offset, SEEK_SET) < 0) |
755 |
|
|
err(1, "%s: seek error for sector %lld", __func__, |
756 |
|
|
(long long)bno); |
757 |
|
|
n = read(fsopts->fd, bf, size); |
758 |
|
|
if (n == -1) { |
759 |
|
|
err(1, "%s: read error bno %lld size %d", __func__, |
760 |
|
|
(long long)bno, size); |
761 |
|
|
} |
762 |
|
|
else if (n != size) |
763 |
|
|
errx(1, "%s: short read error for sector %lld", __func__, |
764 |
|
|
(long long)bno); |
765 |
|
|
} |
766 |
|
|
|
767 |
|
|
/* |
768 |
|
|
* write a block to the file system |
769 |
|
|
*/ |
770 |
|
|
void |
771 |
|
|
ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) |
772 |
|
|
{ |
773 |
|
|
int n; |
774 |
|
|
off_t offset; |
775 |
|
|
|
776 |
|
|
offset = bno * fsopts->sectorsize + fsopts->offset; |
777 |
|
|
if (lseek(fsopts->fd, offset, SEEK_SET) == -1) |
778 |
|
|
err(1, "%s: seek error for sector %lld", __func__, |
779 |
|
|
(long long)bno); |
780 |
|
|
n = write(fsopts->fd, bf, size); |
781 |
|
|
if (n == -1) |
782 |
|
|
err(1, "%s: write error for sector %lld", __func__, |
783 |
|
|
(long long)bno); |
784 |
|
|
else if (n != size) |
785 |
|
|
errx(1, "%s: short write error for sector %lld", __func__, |
786 |
|
|
(long long)bno); |
787 |
|
|
} |
788 |
|
|
|
789 |
|
|
|
790 |
|
|
/* Determine how many digits are needed to print a given integer */ |
791 |
|
|
static int |
792 |
|
|
count_digits(int num) |
793 |
|
|
{ |
794 |
|
|
int ndig; |
795 |
|
|
|
796 |
|
|
for(ndig = 1; num > 9; num /=10, ndig++); |
797 |
|
|
|
798 |
|
|
return (ndig); |
799 |
|
|
} |
800 |
|
|
|
801 |
|
|
static int |
802 |
|
|
ilog2(int val) |
803 |
|
|
{ |
804 |
|
|
u_int n; |
805 |
|
|
|
806 |
|
|
for (n = 0; n < sizeof(n) * CHAR_BIT; n++) |
807 |
|
|
if (1 << n == val) |
808 |
|
|
return (n); |
809 |
|
|
errx(1, "%s: %d is not a power of 2", __func__, val); |
810 |
|
|
} |