File: | src/sbin/growfs/growfs.c |
Warning: | line 1369, column 8 Potential leak of memory pointed to by 'bp' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: growfs.c,v 1.55 2022/12/04 23:50:46 cheloha Exp $ */ | |||
2 | /* | |||
3 | * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz | |||
4 | * Copyright (c) 1980, 1989, 1993 The Regents of the University of California. | |||
5 | * All rights reserved. | |||
6 | * | |||
7 | * This code is derived from software contributed to Berkeley by | |||
8 | * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt. | |||
9 | * | |||
10 | * Redistribution and use in source and binary forms, with or without | |||
11 | * modification, are permitted provided that the following conditions | |||
12 | * are met: | |||
13 | * 1. Redistributions of source code must retain the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer. | |||
15 | * 2. Redistributions in binary form must reproduce the above copyright | |||
16 | * notice, this list of conditions and the following disclaimer in the | |||
17 | * documentation and/or other materials provided with the distribution. | |||
18 | * 3. All advertising materials mentioning features or use of this software | |||
19 | * must display the following acknowledgment: | |||
20 | * This product includes software developed by the University of | |||
21 | * California, Berkeley and its contributors, as well as Christoph | |||
22 | * Herrmann and Thomas-Henning von Kamptz. | |||
23 | * 4. Neither the name of the University nor the names of its contributors | |||
24 | * may be used to endorse or promote products derived from this software | |||
25 | * without specific prior written permission. | |||
26 | * | |||
27 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
37 | * SUCH DAMAGE. | |||
38 | * | |||
39 | * $TSHeader: src/sbin/growfs/growfs.c,v 1.5 2000/12/12 19:31:00 tomsoft Exp $ | |||
40 | * $FreeBSD: src/sbin/growfs/growfs.c,v 1.25 2006/07/17 20:48:36 stefanf Exp $ | |||
41 | * | |||
42 | */ | |||
43 | ||||
44 | #include <sys/param.h> /* DEV_BSIZE MAXBSIZE setbit isset isclr clrbit */ | |||
45 | #include <sys/types.h> | |||
46 | #include <sys/disklabel.h> | |||
47 | #include <sys/ioctl.h> | |||
48 | #include <sys/dkio.h> | |||
49 | #include <sys/stat.h> | |||
50 | ||||
51 | #include <stdio.h> | |||
52 | #include <paths.h> | |||
53 | #include <ctype.h> | |||
54 | #include <err.h> | |||
55 | #include <fcntl.h> | |||
56 | #include <limits.h> | |||
57 | #include <stdlib.h> | |||
58 | #include <stdint.h> | |||
59 | #include <string.h> | |||
60 | #include <time.h> | |||
61 | #include <unistd.h> | |||
62 | #include <util.h> | |||
63 | ||||
64 | #include <ufs/ufs/dinode.h> | |||
65 | #include <ufs/ffs/fs.h> | |||
66 | ||||
67 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) | |||
68 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) | |||
69 | ||||
70 | #define rounddown(x, y)(((x)/(y))*(y)) (((x)/(y))*(y)) | |||
71 | #define roundup(x, y)((((x)+((y)-1))/(y))*(y)) ((((x)+((y)-1))/(y))*(y)) | |||
72 | ||||
73 | static int quiet; /* quiet flag */ | |||
74 | ||||
75 | static union { | |||
76 | struct fs fs; | |||
77 | char pad[SBLOCKSIZE8192]; | |||
78 | } fsun1, fsun2; | |||
79 | #define sblockfsun1.fs fsun1.fs /* the new superblock */ | |||
80 | #define osblockfsun2.fs fsun2.fs /* the old superblock */ | |||
81 | ||||
82 | /* | |||
83 | * Possible superblock locations ordered from most to least likely. | |||
84 | */ | |||
85 | static int sblock_try[] = SBLOCKSEARCH{ 65536, 8192, 262144, -1 }; | |||
86 | static daddr_t sblockloc; | |||
87 | ||||
88 | static union { | |||
89 | struct cg cg; | |||
90 | char pad[MAXBSIZE(64 * 1024)]; | |||
91 | } cgun1, cgun2; | |||
92 | #define acgcgun1.cg cgun1.cg /* a cylinder cgroup (new) */ | |||
93 | #define aocgcgun2.cg cgun2.cg /* an old cylinder group */ | |||
94 | ||||
95 | static char ablk[MAXBSIZE(64 * 1024)]; /* a block */ | |||
96 | ||||
97 | static struct csum *fscs; /* cylinder summary */ | |||
98 | ||||
99 | union dinode { | |||
100 | struct ufs1_dinode dp1; | |||
101 | struct ufs2_dinode dp2; | |||
102 | }; | |||
103 | #define DIP(dp, field)((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(dp)->dp1.field : (dp)->dp2.field) \ | |||
104 | ((sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) ? \ | |||
105 | (uint32_t)(dp)->dp1.field : (dp)->dp2.field) | |||
106 | #define DIP_SET(dp, field, val)do { if (fsun1.fs.fs_magic == 0x011954) (dp)->dp1.field = ( val); else (dp)->dp2.field = (val); } while (0) do { \ | |||
107 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) \ | |||
108 | (dp)->dp1.field = (val); \ | |||
109 | else \ | |||
110 | (dp)->dp2.field = (val); \ | |||
111 | } while (0) | |||
112 | static daddr_t inoblk; /* inode block address */ | |||
113 | static char inobuf[MAXBSIZE(64 * 1024)]; /* inode block */ | |||
114 | ino_t maxino; /* last valid inode */ | |||
115 | ||||
116 | /* | |||
117 | * An array of elements of type struct gfs_bpp describes all blocks to | |||
118 | * be relocated in order to free the space needed for the cylinder group | |||
119 | * summary for all cylinder groups located in the first cylinder group. | |||
120 | */ | |||
121 | struct gfs_bpp { | |||
122 | daddr_t old; /* old block number */ | |||
123 | daddr_t new; /* new block number */ | |||
124 | #define GFS_FL_FIRST1 1 | |||
125 | #define GFS_FL_LAST2 2 | |||
126 | unsigned int flags; /* special handling required */ | |||
127 | int found; /* how many references were updated */ | |||
128 | }; | |||
129 | ||||
130 | static void growfs(int, int, unsigned int); | |||
131 | static void rdfs(daddr_t, size_t, void *, int); | |||
132 | static void wtfs(daddr_t, size_t, void *, int, unsigned int); | |||
133 | static daddr_t alloc(void); | |||
134 | static int charsperline(void); | |||
135 | static void usage(void); | |||
136 | static int isblock(struct fs *, unsigned char *, int); | |||
137 | static void clrblock(struct fs *, unsigned char *, int); | |||
138 | static void setblock(struct fs *, unsigned char *, int); | |||
139 | static void initcg(u_int, time_t, int, unsigned int); | |||
140 | static void updjcg(u_int, time_t, int, int, unsigned int); | |||
141 | static void updcsloc(time_t, int, int, unsigned int); | |||
142 | static struct disklabel *get_disklabel(int); | |||
143 | static void return_disklabel(int, struct disklabel *, unsigned int); | |||
144 | static union dinode *ginode(ino_t, int, int); | |||
145 | static void frag_adjust(daddr_t, int); | |||
146 | static int cond_bl_upd(daddr_t *, struct gfs_bpp *, int, int, | |||
147 | unsigned int); | |||
148 | static void updclst(int); | |||
149 | static void updrefs(int, ino_t, struct gfs_bpp *, int, int, unsigned int); | |||
150 | static void indirchk(daddr_t, daddr_t, daddr_t, daddr_t, | |||
151 | struct gfs_bpp *, int, int, unsigned int); | |||
152 | static void ffs1_sb_update(struct fs *, daddr_t); | |||
153 | ||||
154 | int colwidth; | |||
155 | ||||
156 | /* | |||
157 | * Here we actually start growing the filesystem. We basically read the | |||
158 | * cylinder summary from the first cylinder group as we want to update | |||
159 | * this on the fly during our various operations. First we handle the | |||
160 | * changes in the former last cylinder group. Afterwards we create all new | |||
161 | * cylinder groups. Now we handle the cylinder group containing the | |||
162 | * cylinder summary which might result in a relocation of the whole | |||
163 | * structure. In the end we write back the updated cylinder summary, the | |||
164 | * new superblock, and slightly patched versions of the super block | |||
165 | * copies. | |||
166 | */ | |||
167 | static void | |||
168 | growfs(int fsi, int fso, unsigned int Nflag) | |||
169 | { | |||
170 | int i, j; | |||
171 | u_int cg; | |||
172 | time_t utime; | |||
173 | char tmpbuf[100]; | |||
174 | ||||
175 | time(&utime); | |||
176 | ||||
177 | /* | |||
178 | * Get the cylinder summary into the memory. | |||
179 | */ | |||
180 | fscs = calloc(1, (size_t)sblockfsun1.fs.fs_cssize); | |||
181 | if (fscs == NULL((void *)0)) | |||
182 | errx(1, "calloc failed"); | |||
183 | for (i = 0; i < osblockfsun2.fs.fs_cssize; i += osblockfsun2.fs.fs_bsize) { | |||
184 | rdfs(fsbtodb(&osblock, osblock.fs_csaddr +((fsun2.fs.fs_csaddr + ((i) >> (&fsun2.fs)->fs_fshift )) << (&fsun2.fs)->fs_fsbtodb) | |||
185 | numfrags(&osblock, i))((fsun2.fs.fs_csaddr + ((i) >> (&fsun2.fs)->fs_fshift )) << (&fsun2.fs)->fs_fsbtodb), (size_t)MINIMUM(osblock.fs_cssize - i,(((fsun2.fs.fs_cssize - i) < (fsun2.fs.fs_bsize)) ? (fsun2 .fs.fs_cssize - i) : (fsun2.fs.fs_bsize)) | |||
186 | osblock.fs_bsize)(((fsun2.fs.fs_cssize - i) < (fsun2.fs.fs_bsize)) ? (fsun2 .fs.fs_cssize - i) : (fsun2.fs.fs_bsize)), (void *)(((char *)fscs)+i), fsi); | |||
187 | } | |||
188 | ||||
189 | /* | |||
190 | * Do all needed changes in the former last cylinder group. | |||
191 | */ | |||
192 | updjcg(osblockfsun2.fs.fs_ncg - 1, utime, fsi, fso, Nflag); | |||
193 | ||||
194 | /* | |||
195 | * Dump out summary information about filesystem. | |||
196 | */ | |||
197 | #define B2MBFACTOR (1 / (1024.0 * 1024.0)) | |||
198 | printf("growfs: %.1fMB (%jd sectors) block size %d, fragment size %d\n", | |||
199 | (float)sblockfsun1.fs.fs_size * sblockfsun1.fs.fs_fsize * B2MBFACTOR, | |||
200 | (intmax_t)fsbtodb(&sblock, sblock.fs_size)((fsun1.fs.fs_size) << (&fsun1.fs)->fs_fsbtodb), sblockfsun1.fs.fs_bsize, | |||
201 | sblockfsun1.fs.fs_fsize); | |||
202 | printf("\tusing %u cylinder groups of %.2fMB, %d blks, %u inodes.\n", | |||
203 | sblockfsun1.fs.fs_ncg, (float)sblockfsun1.fs.fs_fpg * sblockfsun1.fs.fs_fsize * B2MBFACTOR, | |||
204 | sblockfsun1.fs.fs_fpg / sblockfsun1.fs.fs_frag, sblockfsun1.fs.fs_ipg); | |||
205 | if (sblockfsun1.fs.fs_flags & FS_DOSOFTDEP0x02) | |||
206 | printf("\twith soft updates\n"); | |||
207 | #undef B2MBFACTOR | |||
208 | ||||
209 | /* | |||
210 | * Now build the cylinders group blocks and | |||
211 | * then print out indices of cylinder groups. | |||
212 | */ | |||
213 | if (!quiet) | |||
214 | printf("super-block backups (for fsck -b #) at:\n"); | |||
215 | i = 0; | |||
216 | ||||
217 | /* | |||
218 | * Iterate for only the new cylinder groups. | |||
219 | */ | |||
220 | for (cg = osblockfsun2.fs.fs_ncg; cg < sblockfsun1.fs.fs_ncg; cg++) { | |||
221 | initcg(cg, utime, fso, Nflag); | |||
222 | if (quiet) | |||
223 | continue; | |||
224 | j = snprintf(tmpbuf, sizeof(tmpbuf), " %lld%s", | |||
225 | fsbtodb(&sblock, cgsblock(&sblock, cg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1 .fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_sblkno)) << (&fsun1.fs )->fs_fsbtodb), | |||
226 | cg < (sblockfsun1.fs.fs_ncg - 1) ? "," : ""); | |||
227 | if (j >= sizeof(tmpbuf)) | |||
228 | j = sizeof(tmpbuf) - 1; | |||
229 | if (j < 0 || i + j >= colwidth) { | |||
230 | printf("\n"); | |||
231 | i = 0; | |||
232 | } | |||
233 | i += j; | |||
234 | printf("%s", tmpbuf); | |||
235 | fflush(stdout(&__sF[1])); | |||
236 | } | |||
237 | if (!quiet) | |||
238 | printf("\n"); | |||
239 | ||||
240 | /* | |||
241 | * Do all needed changes in the first cylinder group. | |||
242 | * allocate blocks in new location | |||
243 | */ | |||
244 | updcsloc(utime, fsi, fso, Nflag); | |||
245 | ||||
246 | /* | |||
247 | * Now write the cylinder summary back to disk. | |||
248 | */ | |||
249 | for (i = 0; i < sblockfsun1.fs.fs_cssize; i += sblockfsun1.fs.fs_bsize) { | |||
250 | wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i))((fsun1.fs.fs_csaddr + ((i) >> (&fsun1.fs)->fs_fshift )) << (&fsun1.fs)->fs_fsbtodb), | |||
251 | (size_t)MINIMUM(sblock.fs_cssize - i, sblock.fs_bsize)(((fsun1.fs.fs_cssize - i) < (fsun1.fs.fs_bsize)) ? (fsun1 .fs.fs_cssize - i) : (fsun1.fs.fs_bsize)), | |||
252 | (void *)(((char *)fscs) + i), fso, Nflag); | |||
253 | } | |||
254 | ||||
255 | /* | |||
256 | * Now write the new superblock back to disk. | |||
257 | */ | |||
258 | sblockfsun1.fs.fs_time = utime; | |||
259 | sblockfsun1.fs.fs_clean = 0; | |||
260 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) { | |||
261 | sblockfsun1.fs.fs_ffs1_time = (int32_t)sblockfsun1.fs.fs_time; | |||
262 | sblockfsun1.fs.fs_ffs1_size = (int32_t)sblockfsun1.fs.fs_size; | |||
263 | sblockfsun1.fs.fs_ffs1_dsize = (int32_t)sblockfsun1.fs.fs_dsize; | |||
264 | sblockfsun1.fs.fs_ffs1_csaddr = (int32_t)sblockfsun1.fs.fs_csaddr; | |||
265 | sblockfsun1.fs.fs_ffs1_cstotal.cs_ndir = | |||
266 | (int32_t)sblockfsun1.fs.fs_cstotal.cs_ndir; | |||
267 | sblockfsun1.fs.fs_ffs1_cstotal.cs_nbfree = | |||
268 | (int32_t)sblockfsun1.fs.fs_cstotal.cs_nbfree; | |||
269 | sblockfsun1.fs.fs_ffs1_cstotal.cs_nifree = | |||
270 | (int32_t)sblockfsun1.fs.fs_cstotal.cs_nifree; | |||
271 | sblockfsun1.fs.fs_ffs1_cstotal.cs_nffree = | |||
272 | (int32_t)sblockfsun1.fs.fs_cstotal.cs_nffree; | |||
273 | } | |||
274 | wtfs(sblockloc, (size_t)SBLOCKSIZE8192, (void *)&sblockfsun1.fs, fso, Nflag); | |||
275 | ||||
276 | /* | |||
277 | * Clean up the dynamic fields in our superblock copies. | |||
278 | */ | |||
279 | sblockfsun1.fs.fs_fmod = 0; | |||
280 | sblockfsun1.fs.fs_clean = 1; | |||
281 | sblockfsun1.fs.fs_ronly = 0; | |||
282 | sblockfsun1.fs.fs_cgrotor = 0; | |||
283 | sblockfsun1.fs.fs_state = 0; | |||
284 | memset(&sblockfsun1.fs.fs_fsmnt, 0, sizeof(sblockfsun1.fs.fs_fsmnt)); | |||
285 | sblockfsun1.fs.fs_flags &= FS_DOSOFTDEP0x02; | |||
286 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) | |||
287 | sblockfsun1.fs.fs_ffs1_flags &= FS_DOSOFTDEP0x02; | |||
288 | ||||
289 | /* | |||
290 | * XXX | |||
291 | * The following fields are currently distributed from the superblock | |||
292 | * to the copies: | |||
293 | * fs_minfree | |||
294 | * fs_rotdelay | |||
295 | * fs_maxcontig | |||
296 | * fs_maxbpg | |||
297 | * fs_minfree, | |||
298 | * fs_optim | |||
299 | * fs_flags regarding SOFTPDATES | |||
300 | * | |||
301 | * We probably should rather change the summary for the cylinder group | |||
302 | * statistics here to the value of what would be in there, if the file | |||
303 | * system were created initially with the new size. Therefore we still | |||
304 | * need to find an easy way of calculating that. | |||
305 | * Possibly we can try to read the first superblock copy and apply the | |||
306 | * "diffed" stats between the old and new superblock by still copying | |||
307 | * certain parameters onto that. | |||
308 | */ | |||
309 | ||||
310 | /* | |||
311 | * Write out the duplicate superblocks. | |||
312 | */ | |||
313 | for (cg = 0; cg < sblockfsun1.fs.fs_ncg; cg++) { | |||
314 | wtfs(fsbtodb(&sblock, cgsblock(&sblock, cg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1 .fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_sblkno)) << (&fsun1.fs )->fs_fsbtodb), | |||
315 | (size_t)SBLOCKSIZE8192, (void *)&sblockfsun1.fs, fso, Nflag); | |||
316 | } | |||
317 | } | |||
318 | ||||
319 | /* | |||
320 | * This creates a new cylinder group structure, for more details please see | |||
321 | * the source of newfs(8), as this function is taken over almost unchanged. | |||
322 | * As this is never called for the first cylinder group, the special | |||
323 | * provisions for that case are removed here. | |||
324 | */ | |||
325 | static void | |||
326 | initcg(u_int cg, time_t utime, int fso, unsigned int Nflag) | |||
327 | { | |||
328 | static char *iobuf; | |||
329 | daddr_t d, dlower, dupper, blkno, start; | |||
330 | daddr_t i, cbase, dmax; | |||
331 | struct ufs1_dinode *dp1; | |||
332 | struct ufs2_dinode *dp2; | |||
333 | struct csum *cs; | |||
334 | ino_t j; | |||
335 | size_t iobufsize; | |||
336 | ||||
337 | if (sblockfsun1.fs.fs_bsize < SBLOCKSIZE8192) | |||
338 | iobufsize = SBLOCKSIZE8192 + 3 * sblockfsun1.fs.fs_bsize; | |||
339 | else | |||
340 | iobufsize = 4 * sblockfsun1.fs.fs_bsize; | |||
341 | ||||
342 | if (iobuf == NULL((void *)0) && (iobuf = malloc(iobufsize)) == NULL((void *)0)) | |||
343 | errx(37, "panic: cannot allocate I/O buffer"); | |||
344 | bzero(iobuf, iobufsize); | |||
345 | ||||
346 | /* | |||
347 | * Determine block bounds for cylinder group. | |||
348 | * Allow space for super block summary information in first | |||
349 | * cylinder group. | |||
350 | */ | |||
351 | cbase = cgbase(&sblock, cg)((daddr_t)(&fsun1.fs)->fs_fpg * (cg)); | |||
352 | dmax = cbase + sblockfsun1.fs.fs_fpg; | |||
353 | if (dmax > sblockfsun1.fs.fs_size) | |||
354 | dmax = sblockfsun1.fs.fs_size; | |||
355 | dlower = cgsblock(&sblock, cg)((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1. fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_sblkno) - cbase; | |||
356 | dupper = cgdmin(&sblock, cg)((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1. fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_dblkno) - cbase; | |||
357 | if (cg == 0) /* XXX fscs may be relocated */ | |||
358 | dupper += howmany(sblock.fs_cssize, sblock.fs_fsize)(((fsun1.fs.fs_cssize) + ((fsun1.fs.fs_fsize) - 1)) / (fsun1. fs.fs_fsize)); | |||
359 | cs = &fscs[cg]; | |||
360 | memset(&acgcgun1.cg, 0, sblockfsun1.fs.fs_cgsize); | |||
361 | acgcgun1.cg.cg_ffs2_time = utime; | |||
362 | acgcgun1.cg.cg_magic = CG_MAGIC0x090255; | |||
363 | acgcgun1.cg.cg_cgx = cg; | |||
364 | acgcgun1.cg.cg_ffs2_niblk = sblockfsun1.fs.fs_ipg; | |||
365 | acgcgun1.cg.cg_initediblk = MINIMUM(sblock.fs_ipg, 2 * INOPB(&sblock))(((fsun1.fs.fs_ipg) < (2 * ((&fsun1.fs)->fs_inopb)) ) ? (fsun1.fs.fs_ipg) : (2 * ((&fsun1.fs)->fs_inopb))); | |||
366 | acgcgun1.cg.cg_ndblk = dmax - cbase; | |||
367 | if (sblockfsun1.fs.fs_contigsumsize > 0) | |||
368 | acgcgun1.cg.cg_nclusterblks = acgcgun1.cg.cg_ndblk / sblockfsun1.fs.fs_frag; | |||
369 | start = sizeof(struct cg); | |||
370 | if (sblockfsun1.fs.fs_magic == FS_UFS2_MAGIC0x19540119) { | |||
371 | acgcgun1.cg.cg_iusedoff = start; | |||
372 | } else { | |||
373 | if (cg == sblockfsun1.fs.fs_ncg - 1) | |||
374 | acgcgun1.cg.cg_ncyl = sblockfsun1.fs.fs_ncyl % sblockfsun1.fs.fs_cpg; | |||
375 | else | |||
376 | acgcgun1.cg.cg_ncyl = sblockfsun1.fs.fs_cpg; | |||
377 | acgcgun1.cg.cg_time = (int32_t)acgcgun1.cg.cg_ffs2_time; | |||
378 | acgcgun1.cg.cg_ffs2_time = 0; | |||
379 | acgcgun1.cg.cg_niblk = (int16_t)acgcgun1.cg.cg_ffs2_niblk; | |||
380 | acgcgun1.cg.cg_ffs2_niblk = 0; | |||
381 | acgcgun1.cg.cg_initediblk = 0; | |||
382 | acgcgun1.cg.cg_btotoff = start; | |||
383 | acgcgun1.cg.cg_boff = acgcgun1.cg.cg_btotoff + | |||
384 | sblockfsun1.fs.fs_cpg * sizeof(int32_t); | |||
385 | acgcgun1.cg.cg_iusedoff = acgcgun1.cg.cg_boff + | |||
386 | sblockfsun1.fs.fs_cpg * sizeof(u_int16_t); | |||
387 | } | |||
388 | acgcgun1.cg.cg_freeoff = acgcgun1.cg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT)(((fsun1.fs.fs_ipg) + ((8) - 1)) / (8)); | |||
389 | acgcgun1.cg.cg_nextfreeoff = acgcgun1.cg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT)(((fsun1.fs.fs_fpg) + ((8) - 1)) / (8)); | |||
390 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
391 | acgcgun1.cg.cg_clustersumoff = | |||
392 | roundup(acg.cg_nextfreeoff, sizeof(u_int32_t))((((cgun1.cg.cg_nextfreeoff)+((sizeof(u_int32_t))-1))/(sizeof (u_int32_t)))*(sizeof(u_int32_t))); | |||
393 | acgcgun1.cg.cg_clustersumoff -= sizeof(u_int32_t); | |||
394 | acgcgun1.cg.cg_clusteroff = acgcgun1.cg.cg_clustersumoff + | |||
395 | (sblockfsun1.fs.fs_contigsumsize + 1) * sizeof(u_int32_t); | |||
396 | acgcgun1.cg.cg_nextfreeoff = acgcgun1.cg.cg_clusteroff + | |||
397 | howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT)(((((fsun1.fs.fs_fpg) >> (&fsun1.fs)->fs_fragshift )) + ((8) - 1)) / (8)); | |||
398 | } | |||
399 | if (acgcgun1.cg.cg_nextfreeoff > sblockfsun1.fs.fs_cgsize) { | |||
400 | /* | |||
401 | * This should never happen as we would have had that panic | |||
402 | * already on filesystem creation | |||
403 | */ | |||
404 | errx(37, "panic: cylinder group too big"); | |||
405 | } | |||
406 | acgcgun1.cg.cg_cs.cs_nifree += sblockfsun1.fs.fs_ipg; | |||
407 | if (cg == 0) { | |||
408 | for (i = 0; i < ROOTINO((ufsino_t)2); i++) { | |||
409 | setbit(cg_inosused(&acg), i)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_iused) : ((u_int8_t *)((u_int8_t * )(&cgun1.cg) + (&cgun1.cg)->cg_iusedoff))))[(i)>> 3] |= 1<<((i)&(8 -1))); | |||
410 | acgcgun1.cg.cg_cs.cs_nifree--; | |||
411 | } | |||
412 | } | |||
413 | if (cg > 0) { | |||
414 | /* | |||
415 | * In cg 0, beginning space is reserved | |||
416 | * for boot and super blocks. | |||
417 | */ | |||
418 | for (d = 0; d < dlower; d += sblockfsun1.fs.fs_frag) { | |||
419 | blkno = d / sblockfsun1.fs.fs_frag; | |||
420 | setblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), blkno); | |||
421 | if (sblockfsun1.fs.fs_contigsumsize > 0) | |||
422 | setbit(cg_clustersfree(&acg), blkno)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[(blkno)>>3] |= 1<<((blkno)& (8 -1))); | |||
423 | acgcgun1.cg.cg_cs.cs_nbfree++; | |||
424 | } | |||
425 | sblockfsun1.fs.fs_dsize += dlower; | |||
426 | } | |||
427 | sblockfsun1.fs.fs_dsize += acgcgun1.cg.cg_ndblk - dupper; | |||
428 | if ((i = dupper % sblockfsun1.fs.fs_frag)) { | |||
429 | acgcgun1.cg.cg_frsum[sblockfsun1.fs.fs_frag - i]++; | |||
430 | for (d = dupper + sblockfsun1.fs.fs_frag - i; dupper < d; dupper++) { | |||
431 | setbit(cg_blksfree(&acg), dupper)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(dupper) >>3] |= 1<<((dupper)&(8 -1))); | |||
432 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
433 | } | |||
434 | } | |||
435 | for (d = dupper; d + sblockfsun1.fs.fs_frag <= acgcgun1.cg.cg_ndblk; | |||
436 | d += sblockfsun1.fs.fs_frag) { | |||
437 | blkno = d / sblockfsun1.fs.fs_frag; | |||
438 | setblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), blkno); | |||
439 | if (sblockfsun1.fs.fs_contigsumsize > 0) | |||
440 | setbit(cg_clustersfree(&acg), blkno)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[(blkno)>>3] |= 1<<((blkno)& (8 -1))); | |||
441 | acgcgun1.cg.cg_cs.cs_nbfree++; | |||
442 | } | |||
443 | if (d < acgcgun1.cg.cg_ndblk) { | |||
444 | acgcgun1.cg.cg_frsum[acgcgun1.cg.cg_ndblk - d]++; | |||
445 | for (; d < acgcgun1.cg.cg_ndblk; d++) { | |||
446 | setbit(cg_blksfree(&acg), d)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d)>> 3] |= 1<<((d)&(8 -1))); | |||
447 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
448 | } | |||
449 | } | |||
450 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
451 | int32_t *sump = cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff)); | |||
452 | u_char *mapp = cg_clustersfree(&acg)((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clusteroff)); | |||
453 | int map = *mapp++; | |||
454 | int bit = 1; | |||
455 | int run = 0; | |||
456 | ||||
457 | for (i = 0; i < acgcgun1.cg.cg_nclusterblks; i++) { | |||
458 | if ((map & bit) != 0) | |||
459 | run++; | |||
460 | else if (run != 0) { | |||
461 | if (run > sblockfsun1.fs.fs_contigsumsize) | |||
462 | run = sblockfsun1.fs.fs_contigsumsize; | |||
463 | sump[run]++; | |||
464 | run = 0; | |||
465 | } | |||
466 | if ((i & (CHAR_BIT8 - 1)) != CHAR_BIT8 - 1) | |||
467 | bit <<= 1; | |||
468 | else { | |||
469 | map = *mapp++; | |||
470 | bit = 1; | |||
471 | } | |||
472 | } | |||
473 | if (run != 0) { | |||
474 | if (run > sblockfsun1.fs.fs_contigsumsize) | |||
475 | run = sblockfsun1.fs.fs_contigsumsize; | |||
476 | sump[run]++; | |||
477 | } | |||
478 | } | |||
479 | sblockfsun1.fs.fs_cstotal.cs_ndir += acgcgun1.cg.cg_cs.cs_ndir; | |||
480 | sblockfsun1.fs.fs_cstotal.cs_nffree += acgcgun1.cg.cg_cs.cs_nffree; | |||
481 | sblockfsun1.fs.fs_cstotal.cs_nbfree += acgcgun1.cg.cg_cs.cs_nbfree; | |||
482 | sblockfsun1.fs.fs_cstotal.cs_nifree += acgcgun1.cg.cg_cs.cs_nifree; | |||
483 | *cs = acgcgun1.cg.cg_cs; | |||
484 | ||||
485 | /* | |||
486 | * Write out the duplicate superblock, the cylinder group map | |||
487 | * and two blocks worth of inodes in a single write. | |||
488 | */ | |||
489 | bcopy(&sblockfsun1.fs, iobuf, SBLOCKSIZE8192); | |||
490 | start = sblockfsun1.fs.fs_bsize > SBLOCKSIZE8192 ? sblockfsun1.fs.fs_bsize : SBLOCKSIZE8192; | |||
491 | bcopy(&acgcgun1.cg, &iobuf[start], sblockfsun1.fs.fs_cgsize); | |||
492 | start += sblockfsun1.fs.fs_bsize; | |||
493 | dp1 = (struct ufs1_dinode *)&iobuf[start]; | |||
494 | dp2 = (struct ufs2_dinode *)&iobuf[start]; | |||
495 | for (i = MINIMUM(sblock.fs_ipg, 2 * INOPB(&sblock))(((fsun1.fs.fs_ipg) < (2 * ((&fsun1.fs)->fs_inopb)) ) ? (fsun1.fs.fs_ipg) : (2 * ((&fsun1.fs)->fs_inopb))); i != 0; i--) { | |||
496 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) { | |||
497 | dp1->di_gen = arc4random(); | |||
498 | dp1++; | |||
499 | } else { | |||
500 | dp2->di_gen = arc4random(); | |||
501 | dp2++; | |||
502 | } | |||
503 | } | |||
504 | wtfs(fsbtodb(&sblock, cgsblock(&sblock, cg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1 .fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_sblkno)) << (&fsun1.fs )->fs_fsbtodb), iobufsize, | |||
505 | iobuf, fso, Nflag); | |||
506 | ||||
507 | /* Initialize inodes for FFS1. */ | |||
508 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) { | |||
509 | for (i = 2 * sblockfsun1.fs.fs_frag; i < sblockfsun1.fs.fs_ipg / INOPF(&sblock)((&fsun1.fs)->fs_inopb >> (&fsun1.fs)->fs_fragshift ); | |||
510 | i += sblockfsun1.fs.fs_frag) { | |||
511 | dp1 = (struct ufs1_dinode *)&iobuf[start]; | |||
512 | for (j = 0; j < INOPB(&sblock)((&fsun1.fs)->fs_inopb); j++) { | |||
513 | dp1->di_gen = arc4random(); | |||
514 | dp1++; | |||
515 | } | |||
516 | wtfs(fsbtodb(&sblock, cgimin(&sblock, cg) + i)((((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1 .fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_iblkno) + i) << (&fsun1 .fs)->fs_fsbtodb), | |||
517 | (size_t)sblockfsun1.fs.fs_bsize, &iobuf[start], fso, Nflag); | |||
518 | } | |||
519 | } | |||
520 | } | |||
521 | ||||
522 | /* | |||
523 | * Here we add or subtract (sign +1/-1) the available fragments in a given | |||
524 | * block to or from the fragment statistics. By subtracting before and adding | |||
525 | * after an operation on the free frag map we can easy update the fragment | |||
526 | * statistic, which seems to be otherwise a rather complex operation. | |||
527 | */ | |||
528 | static void | |||
529 | frag_adjust(daddr_t frag, int sign) | |||
530 | { | |||
531 | int fragsize; | |||
532 | int f; | |||
533 | ||||
534 | fragsize = 0; | |||
535 | /* | |||
536 | * Here frag only needs to point to any fragment in the block we want | |||
537 | * to examine. | |||
538 | */ | |||
539 | for (f = rounddown(frag, sblock.fs_frag)(((frag)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag)); | |||
540 | f < roundup(frag + 1, sblock.fs_frag)((((frag + 1)+((fsun1.fs.fs_frag)-1))/(fsun1.fs.fs_frag))*(fsun1 .fs.fs_frag)); | |||
541 | f++) { | |||
542 | /* | |||
543 | * Count contiguous free fragments. | |||
544 | */ | |||
545 | if (isset(cg_blksfree(&acg), f)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(f)>> 3] & (1<<((f)&(8 -1))))) { | |||
546 | fragsize++; | |||
547 | } else { | |||
548 | if (fragsize && fragsize < sblockfsun1.fs.fs_frag) { | |||
549 | /* | |||
550 | * We found something in between. | |||
551 | */ | |||
552 | acgcgun1.cg.cg_frsum[fragsize] += sign; | |||
553 | } | |||
554 | fragsize = 0; | |||
555 | } | |||
556 | } | |||
557 | if (fragsize && fragsize < sblockfsun1.fs.fs_frag) { | |||
558 | /* | |||
559 | * We found something. | |||
560 | */ | |||
561 | acgcgun1.cg.cg_frsum[fragsize] += sign; | |||
562 | } | |||
563 | } | |||
564 | ||||
565 | /* | |||
566 | * Here we conditionally update a pointer to a fragment. We check for all | |||
567 | * relocated blocks if any of its fragments is referenced by the current | |||
568 | * field, and update the pointer to the respective fragment in our new | |||
569 | * block. If we find a reference we write back the block immediately, | |||
570 | * as there is no easy way for our general block reading engine to figure | |||
571 | * out if a write back operation is needed. | |||
572 | */ | |||
573 | static int | |||
574 | cond_bl_upd(daddr_t *block, struct gfs_bpp *field, int fsi, int fso, | |||
575 | unsigned int Nflag) | |||
576 | { | |||
577 | struct gfs_bpp *f; | |||
578 | daddr_t src, dst; | |||
579 | int fragnum; | |||
580 | void *ibuf; | |||
581 | ||||
582 | for (f = field; f->old != 0; f++) { | |||
583 | src = *block; | |||
584 | if (fragstoblks(&sblock, src)((src) >> (&fsun1.fs)->fs_fragshift) != f->old) | |||
585 | continue; | |||
586 | /* | |||
587 | * The fragment is part of the block, so update. | |||
588 | */ | |||
589 | dst = blkstofrags(&sblock, f->new)((f->new) << (&fsun1.fs)->fs_fragshift); | |||
590 | fragnum = fragnum(&sblock, src)((src) & ((&fsun1.fs)->fs_frag - 1)); | |||
591 | *block = dst + fragnum; | |||
592 | f->found++; | |||
593 | ||||
594 | /* | |||
595 | * Copy the block back immediately. | |||
596 | * | |||
597 | * XXX If src is from an indirect block we have | |||
598 | * to implement copy on write here in case of | |||
599 | * active snapshots. | |||
600 | */ | |||
601 | ibuf = malloc(sblockfsun1.fs.fs_bsize); | |||
602 | if (!ibuf) | |||
603 | errx(1, "malloc failed"); | |||
604 | src -= fragnum; | |||
605 | rdfs(fsbtodb(&sblock, src)((src) << (&fsun1.fs)->fs_fsbtodb), (size_t)sblockfsun1.fs.fs_bsize, ibuf, fsi); | |||
606 | wtfs(dst, (size_t)sblockfsun1.fs.fs_bsize, ibuf, fso, Nflag); | |||
607 | free(ibuf); | |||
608 | /* | |||
609 | * The same block can't be found again in this loop. | |||
610 | */ | |||
611 | return (1); | |||
612 | } | |||
613 | ||||
614 | return (0); | |||
615 | } | |||
616 | ||||
617 | /* | |||
618 | * Here we do all needed work for the former last cylinder group. It has to be | |||
619 | * changed in any case, even if the filesystem ended exactly on the end of | |||
620 | * this group, as there is some slightly inconsistent handling of the number | |||
621 | * of cylinders in the cylinder group. We start again by reading the cylinder | |||
622 | * group from disk. If the last block was not fully available, we first handle | |||
623 | * the missing fragments, then we handle all new full blocks in that file | |||
624 | * system and finally we handle the new last fragmented block in the file | |||
625 | * system. We again have to handle the fragment statistics rotational layout | |||
626 | * tables and cluster summary during all those operations. | |||
627 | */ | |||
628 | static void | |||
629 | updjcg(u_int cg, time_t utime, int fsi, int fso, unsigned int Nflag) | |||
630 | { | |||
631 | daddr_t cbase, dmax, dupper; | |||
632 | struct csum *cs; | |||
633 | int i, k; | |||
634 | int j = 0; | |||
635 | ||||
636 | /* | |||
637 | * Read the former last (joining) cylinder group from disk, and make | |||
638 | * a copy. | |||
639 | */ | |||
640 | rdfs(fsbtodb(&osblock, cgtod(&osblock, cg))((((((daddr_t)(&fsun2.fs)->fs_fpg * (cg)) + (&fsun2 .fs)->fs_cgoffset * ((cg) & ~((&fsun2.fs)->fs_cgmask ))) + (&fsun2.fs)->fs_cblkno)) << (&fsun2.fs )->fs_fsbtodb), | |||
641 | (size_t)osblockfsun2.fs.fs_cgsize, (void *)&aocgcgun2.cg, fsi); | |||
642 | ||||
643 | memcpy(&cgun1, &cgun2, sizeof(cgun2)); | |||
644 | ||||
645 | /* | |||
646 | * If the cylinder group had already its new final size almost | |||
647 | * nothing is to be done ... except: | |||
648 | * For some reason the value of cg_ncyl in the last cylinder group has | |||
649 | * to be zero instead of fs_cpg. As this is now no longer the last | |||
650 | * cylinder group we have to change that value now to fs_cpg. | |||
651 | */ | |||
652 | if (cgbase(&osblock, cg+1)((daddr_t)(&fsun2.fs)->fs_fpg * (cg+1)) == osblockfsun2.fs.fs_size) { | |||
653 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) | |||
654 | acgcgun1.cg.cg_ncyl = sblockfsun1.fs.fs_cpg; | |||
655 | ||||
656 | wtfs(fsbtodb(&sblock, cgtod(&sblock, cg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1 .fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_cblkno)) << (&fsun1.fs )->fs_fsbtodb), | |||
657 | (size_t)sblockfsun1.fs.fs_cgsize, (void *)&acgcgun1.cg, fso, Nflag); | |||
658 | ||||
659 | return; | |||
660 | } | |||
661 | ||||
662 | /* | |||
663 | * Set up some variables needed later. | |||
664 | */ | |||
665 | cbase = cgbase(&sblock, cg)((daddr_t)(&fsun1.fs)->fs_fpg * (cg)); | |||
666 | dmax = cbase + sblockfsun1.fs.fs_fpg; | |||
667 | if (dmax > sblockfsun1.fs.fs_size) | |||
668 | dmax = sblockfsun1.fs.fs_size; | |||
669 | dupper = cgdmin(&sblock, cg)((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1. fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_dblkno) - cbase; | |||
670 | if (cg == 0) /* XXX fscs may be relocated */ | |||
671 | dupper += howmany(sblock.fs_cssize, sblock.fs_fsize)(((fsun1.fs.fs_cssize) + ((fsun1.fs.fs_fsize) - 1)) / (fsun1. fs.fs_fsize)); | |||
672 | ||||
673 | /* | |||
674 | * Set pointer to the cylinder summary for our cylinder group. | |||
675 | */ | |||
676 | cs = fscs + cg; | |||
677 | ||||
678 | /* | |||
679 | * Touch the cylinder group, update all fields in the cylinder group as | |||
680 | * needed, update the free space in the superblock. | |||
681 | */ | |||
682 | acgcgun1.cg.cg_time = utime; | |||
683 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) { | |||
684 | if (cg == sblockfsun1.fs.fs_ncg - 1) { | |||
685 | /* | |||
686 | * This is still the last cylinder group. | |||
687 | */ | |||
688 | acgcgun1.cg.cg_ncyl = sblockfsun1.fs.fs_ncyl % sblockfsun1.fs.fs_cpg; | |||
689 | } else { | |||
690 | acgcgun1.cg.cg_ncyl = sblockfsun1.fs.fs_cpg; | |||
691 | } | |||
692 | } | |||
693 | acgcgun1.cg.cg_ndblk = dmax - cbase; | |||
694 | sblockfsun1.fs.fs_dsize += acgcgun1.cg.cg_ndblk-aocgcgun2.cg.cg_ndblk; | |||
695 | if (sblockfsun1.fs.fs_contigsumsize > 0) | |||
696 | acgcgun1.cg.cg_nclusterblks = acgcgun1.cg.cg_ndblk / sblockfsun1.fs.fs_frag; | |||
697 | ||||
698 | /* | |||
699 | * Now we have to update the free fragment bitmap for our new free | |||
700 | * space. There again we have to handle the fragmentation and also | |||
701 | * the rotational layout tables and the cluster summary. This is | |||
702 | * also done per fragment for the first new block if the old file | |||
703 | * system end was not on a block boundary, per fragment for the new | |||
704 | * last block if the new filesystem end is not on a block boundary, | |||
705 | * and per block for all space in between. | |||
706 | * | |||
707 | * Handle the first new block here if it was partially available | |||
708 | * before. | |||
709 | */ | |||
710 | if (osblockfsun2.fs.fs_size % sblockfsun1.fs.fs_frag) { | |||
711 | if (roundup(osblock.fs_size, sblock.fs_frag)((((fsun2.fs.fs_size)+((fsun1.fs.fs_frag)-1))/(fsun1.fs.fs_frag ))*(fsun1.fs.fs_frag)) <= sblockfsun1.fs.fs_size) { | |||
712 | /* | |||
713 | * The new space is enough to fill at least this | |||
714 | * block | |||
715 | */ | |||
716 | j = 0; | |||
717 | for (i = roundup(osblock.fs_size-cbase, sblock.fs_frag)((((fsun2.fs.fs_size-cbase)+((fsun1.fs.fs_frag)-1))/(fsun1.fs .fs_frag))*(fsun1.fs.fs_frag)) - 1; | |||
718 | i >= osblockfsun2.fs.fs_size-cbase; i--) { | |||
719 | setbit(cg_blksfree(&acg), i)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(i)>> 3] |= 1<<((i)&(8 -1))); | |||
720 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
721 | j++; | |||
722 | } | |||
723 | ||||
724 | /* | |||
725 | * Check if the fragment just created could join an | |||
726 | * already existing fragment at the former end of the | |||
727 | * filesystem. | |||
728 | */ | |||
729 | if (isblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), | |||
730 | ((osblockfsun2.fs.fs_size - cgbase(&sblock, cg)((daddr_t)(&fsun1.fs)->fs_fpg * (cg)))/ | |||
731 | sblockfsun1.fs.fs_frag))) { | |||
732 | /* | |||
733 | * The block is now completely available. | |||
734 | */ | |||
735 | acgcgun1.cg.cg_frsum[osblockfsun2.fs.fs_size%sblockfsun1.fs.fs_frag]--; | |||
736 | acgcgun1.cg.cg_cs.cs_nbfree++; | |||
737 | acgcgun1.cg.cg_cs.cs_nffree-=sblockfsun1.fs.fs_frag; | |||
738 | k = rounddown(osblock.fs_size-cbase,(((fsun2.fs.fs_size-cbase)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag )) | |||
739 | sblock.fs_frag)(((fsun2.fs.fs_size-cbase)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag )); | |||
740 | updclst((osblockfsun2.fs.fs_size-cbase)/sblockfsun1.fs.fs_frag); | |||
741 | } else { | |||
742 | /* | |||
743 | * Lets rejoin a possible partially growed | |||
744 | * fragment. | |||
745 | */ | |||
746 | k = 0; | |||
747 | while (isset(cg_blksfree(&acg), i)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(i)>> 3] & (1<<((i)&(8 -1)))) && | |||
748 | (i >= rounddown(osblock.fs_size - cbase,(((fsun2.fs.fs_size - cbase)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag )) | |||
749 | sblock.fs_frag)(((fsun2.fs.fs_size - cbase)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag )))) { | |||
750 | i--; | |||
751 | k++; | |||
752 | } | |||
753 | if (k) | |||
754 | acgcgun1.cg.cg_frsum[k]--; | |||
755 | acgcgun1.cg.cg_frsum[k + j]++; | |||
756 | } | |||
757 | } else { | |||
758 | /* | |||
759 | * We only grow by some fragments within this last | |||
760 | * block. | |||
761 | */ | |||
762 | for (i = sblockfsun1.fs.fs_size-cbase-1; | |||
763 | i >= osblockfsun2.fs.fs_size-cbase; i--) { | |||
764 | setbit(cg_blksfree(&acg), i)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(i)>> 3] |= 1<<((i)&(8 -1))); | |||
765 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
766 | j++; | |||
767 | } | |||
768 | /* | |||
769 | * Lets rejoin a possible partially growed fragment. | |||
770 | */ | |||
771 | k = 0; | |||
772 | while (isset(cg_blksfree(&acg), i)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(i)>> 3] & (1<<((i)&(8 -1)))) && | |||
773 | (i >= rounddown(osblock.fs_size - cbase,(((fsun2.fs.fs_size - cbase)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag )) | |||
774 | sblock.fs_frag)(((fsun2.fs.fs_size - cbase)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag )))) { | |||
775 | i--; | |||
776 | k++; | |||
777 | } | |||
778 | if (k) | |||
779 | acgcgun1.cg.cg_frsum[k]--; | |||
780 | acgcgun1.cg.cg_frsum[k + j]++; | |||
781 | } | |||
782 | } | |||
783 | ||||
784 | /* | |||
785 | * Handle all new complete blocks here. | |||
786 | */ | |||
787 | for (i = roundup(osblock.fs_size - cbase, sblock.fs_frag)((((fsun2.fs.fs_size - cbase)+((fsun1.fs.fs_frag)-1))/(fsun1. fs.fs_frag))*(fsun1.fs.fs_frag)); | |||
788 | i + sblockfsun1.fs.fs_frag <= dmax-cbase; /* XXX <= or only < ? */ | |||
789 | i += sblockfsun1.fs.fs_frag) { | |||
790 | j = i / sblockfsun1.fs.fs_frag; | |||
791 | setblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), j); | |||
792 | updclst(j); | |||
793 | acgcgun1.cg.cg_cs.cs_nbfree++; | |||
794 | } | |||
795 | ||||
796 | /* | |||
797 | * Handle the last new block if there are stll some new fragments left. | |||
798 | * Here we don't have to bother about the cluster summary or the even | |||
799 | * the rotational layout table. | |||
800 | */ | |||
801 | if (i < (dmax - cbase)) { | |||
802 | acgcgun1.cg.cg_frsum[dmax - cbase - i]++; | |||
803 | for (; i < dmax - cbase; i++) { | |||
804 | setbit(cg_blksfree(&acg), i)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(i)>> 3] |= 1<<((i)&(8 -1))); | |||
805 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
806 | } | |||
807 | } | |||
808 | ||||
809 | sblockfsun1.fs.fs_cstotal.cs_nffree += | |||
810 | (acgcgun1.cg.cg_cs.cs_nffree - aocgcgun2.cg.cg_cs.cs_nffree); | |||
811 | sblockfsun1.fs.fs_cstotal.cs_nbfree += | |||
812 | (acgcgun1.cg.cg_cs.cs_nbfree - aocgcgun2.cg.cg_cs.cs_nbfree); | |||
813 | /* | |||
814 | * The following statistics are not changed here: | |||
815 | * sblock.fs_cstotal.cs_ndir | |||
816 | * sblock.fs_cstotal.cs_nifree | |||
817 | * As the statistics for this cylinder group are ready, copy it to | |||
818 | * the summary information array. | |||
819 | */ | |||
820 | *cs = acgcgun1.cg.cg_cs; | |||
821 | ||||
822 | /* | |||
823 | * Write the updated "joining" cylinder group back to disk. | |||
824 | */ | |||
825 | wtfs(fsbtodb(&sblock, cgtod(&sblock, cg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (cg)) + (&fsun1 .fs)->fs_cgoffset * ((cg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_cblkno)) << (&fsun1.fs )->fs_fsbtodb), (size_t)sblockfsun1.fs.fs_cgsize, | |||
826 | (void *)&acgcgun1.cg, fso, Nflag); | |||
827 | } | |||
828 | ||||
829 | /* | |||
830 | * Here we update the location of the cylinder summary. We have two possible | |||
831 | * ways of growing the cylinder summary. | |||
832 | * (1) We can try to grow the summary in the current location, and relocate | |||
833 | * possibly used blocks within the current cylinder group. | |||
834 | * (2) Alternatively we can relocate the whole cylinder summary to the first | |||
835 | * new completely empty cylinder group. Once the cylinder summary is no | |||
836 | * longer in the beginning of the first cylinder group you should never | |||
837 | * use a version of fsck which is not aware of the possibility to have | |||
838 | * this structure in a non standard place. | |||
839 | * Option (1) is considered to be less intrusive to the structure of the file- | |||
840 | * system. So we try to stick to that whenever possible. If there is not enough | |||
841 | * space in the cylinder group containing the cylinder summary we have to use | |||
842 | * method (2). In case of active snapshots in the filesystem we probably can | |||
843 | * completely avoid implementing copy on write if we stick to method (2) only. | |||
844 | */ | |||
845 | static void | |||
846 | updcsloc(time_t utime, int fsi, int fso, unsigned int Nflag) | |||
847 | { | |||
848 | struct csum *cs; | |||
849 | int ocscg, ncscg; | |||
850 | int blocks; | |||
851 | daddr_t cbase, dupper, odupper, d, f, g; | |||
852 | int ind; | |||
853 | u_int cg, inc; | |||
854 | struct gfs_bpp *bp; | |||
855 | int i, l; | |||
856 | int lcs = 0; | |||
857 | int block; | |||
858 | ||||
859 | if (howmany(sblock.fs_cssize, sblock.fs_fsize)(((fsun1.fs.fs_cssize) + ((fsun1.fs.fs_fsize) - 1)) / (fsun1. fs.fs_fsize)) == | |||
| ||||
860 | howmany(osblock.fs_cssize, osblock.fs_fsize)(((fsun2.fs.fs_cssize) + ((fsun2.fs.fs_fsize) - 1)) / (fsun2. fs.fs_fsize))) { | |||
861 | /* | |||
862 | * No new fragment needed. | |||
863 | */ | |||
864 | return; | |||
865 | } | |||
866 | ocscg = dtog(&osblock, osblock.fs_csaddr)((fsun2.fs.fs_csaddr) / (&fsun2.fs)->fs_fpg); | |||
867 | cs = fscs + ocscg; | |||
868 | blocks = 1+howmany(sblock.fs_cssize, sblock.fs_bsize)(((fsun1.fs.fs_cssize) + ((fsun1.fs.fs_bsize) - 1)) / (fsun1. fs.fs_bsize))- | |||
869 | howmany(osblock.fs_cssize, osblock.fs_bsize)(((fsun2.fs.fs_cssize) + ((fsun2.fs.fs_bsize) - 1)) / (fsun2. fs.fs_bsize)); | |||
870 | ||||
871 | /* | |||
872 | * Read original cylinder group from disk, and make a copy. | |||
873 | * XXX If Nflag is set in some very rare cases we now miss | |||
874 | * some changes done in updjcg by reading the unmodified | |||
875 | * block from disk. | |||
876 | */ | |||
877 | rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg))((((((daddr_t)(&fsun2.fs)->fs_fpg * (ocscg)) + (&fsun2 .fs)->fs_cgoffset * ((ocscg) & ~((&fsun2.fs)->fs_cgmask ))) + (&fsun2.fs)->fs_cblkno)) << (&fsun2.fs )->fs_fsbtodb), | |||
878 | (size_t)osblockfsun2.fs.fs_cgsize, (void *)&aocgcgun2.cg, fsi); | |||
879 | ||||
880 | memcpy(&cgun1, &cgun2, sizeof(cgun2)); | |||
881 | ||||
882 | /* | |||
883 | * Touch the cylinder group, set up local variables needed later | |||
884 | * and update the superblock. | |||
885 | */ | |||
886 | acgcgun1.cg.cg_time = utime; | |||
887 | ||||
888 | /* | |||
889 | * XXX In the case of having active snapshots we may need much more | |||
890 | * blocks for the copy on write. We need each block twice, and | |||
891 | * also up to 8*3 blocks for indirect blocks for all possible | |||
892 | * references. | |||
893 | */ | |||
894 | if (/*((int)sblock.fs_time & 0x3) > 0 || */ cs->cs_nbfree < blocks) { | |||
895 | /* | |||
896 | * There is not enough space in the old cylinder group to | |||
897 | * relocate all blocks as needed, so we relocate the whole | |||
898 | * cylinder group summary to a new group. We try to use the | |||
899 | * first complete new cylinder group just created. Within the | |||
900 | * cylinder group we align the area immediately after the | |||
901 | * cylinder group information location in order to be as | |||
902 | * close as possible to the original implementation of ffs. | |||
903 | * | |||
904 | * First we have to make sure we'll find enough space in the | |||
905 | * new cylinder group. If not, then we currently give up. | |||
906 | * We start with freeing everything which was used by the | |||
907 | * fragments of the old cylinder summary in the current group. | |||
908 | * Now we write back the group meta data, read in the needed | |||
909 | * meta data from the new cylinder group, and start allocating | |||
910 | * within that group. Here we can assume, the group to be | |||
911 | * completely empty. Which makes the handling of fragments and | |||
912 | * clusters a lot easier. | |||
913 | */ | |||
914 | if (sblockfsun1.fs.fs_ncg-osblockfsun2.fs.fs_ncg < 2) | |||
915 | errx(2, "panic: not enough space"); | |||
916 | ||||
917 | /* | |||
918 | * Point "d" to the first fragment not used by the cylinder | |||
919 | * summary. | |||
920 | */ | |||
921 | d = osblockfsun2.fs.fs_csaddr + (osblockfsun2.fs.fs_cssize / osblockfsun2.fs.fs_fsize); | |||
922 | ||||
923 | /* | |||
924 | * Set up last cluster size ("lcs") already here. Calculate | |||
925 | * the size for the trailing cluster just behind where "d" | |||
926 | * points to. | |||
927 | */ | |||
928 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
929 | for (block = howmany(d % sblock.fs_fpg, sblock.fs_frag)(((d % fsun1.fs.fs_fpg) + ((fsun1.fs.fs_frag) - 1)) / (fsun1. fs.fs_frag)), | |||
930 | lcs = 0; lcs < sblockfsun1.fs.fs_contigsumsize; | |||
931 | block++, lcs++) { | |||
932 | if (isclr(cg_clustersfree(&acg), block)(((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg )->cg_clusteroff)))[(block)>>3] & (1<<((block )&(8 -1)))) == 0)) | |||
933 | break; | |||
934 | } | |||
935 | } | |||
936 | ||||
937 | /* | |||
938 | * Point "d" to the last frag used by the cylinder summary. | |||
939 | */ | |||
940 | d--; | |||
941 | ||||
942 | if ((d + 1) % sblockfsun1.fs.fs_frag) { | |||
943 | /* | |||
944 | * The end of the cylinder summary is not a complete | |||
945 | * block. | |||
946 | */ | |||
947 | frag_adjust(d % sblockfsun1.fs.fs_fpg, -1); | |||
948 | for (; (d + 1) % sblockfsun1.fs.fs_frag; d--) { | |||
949 | setbit(cg_blksfree(&acg), d % sblock.fs_fpg)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d % fsun1 .fs.fs_fpg)>>3] |= 1<<((d % fsun1.fs.fs_fpg)& (8 -1))); | |||
950 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
951 | sblockfsun1.fs.fs_cstotal.cs_nffree++; | |||
952 | } | |||
953 | /* | |||
954 | * Point "d" to the last fragment of the last | |||
955 | * (incomplete) block of the cylinder summary. | |||
956 | */ | |||
957 | d++; | |||
958 | frag_adjust(d % sblockfsun1.fs.fs_fpg, 1); | |||
959 | ||||
960 | if (isblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), | |||
961 | (d % sblockfsun1.fs.fs_fpg) / sblockfsun1.fs.fs_frag)) { | |||
962 | acgcgun1.cg.cg_cs.cs_nffree -= sblockfsun1.fs.fs_frag; | |||
963 | acgcgun1.cg.cg_cs.cs_nbfree++; | |||
964 | sblockfsun1.fs.fs_cstotal.cs_nffree -= sblockfsun1.fs.fs_frag; | |||
965 | sblockfsun1.fs.fs_cstotal.cs_nbfree++; | |||
966 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
967 | setbit(cg_clustersfree(&acg),((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] |= 1<<(((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )&(8 -1))) | |||
968 | (d % sblock.fs_fpg) / sblock.fs_frag)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] |= 1<<(((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )&(8 -1))); | |||
969 | if (lcs < sblockfsun1.fs.fs_contigsumsize) { | |||
970 | if (lcs) { | |||
971 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff)) | |||
972 | [lcs]--; | |||
973 | } | |||
974 | lcs++; | |||
975 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]++; | |||
976 | } | |||
977 | } | |||
978 | } | |||
979 | /* | |||
980 | * Point "d" to the first fragment of the block before | |||
981 | * the last incomplete block. | |||
982 | */ | |||
983 | d--; | |||
984 | } | |||
985 | ||||
986 | for (d = rounddown(d, sblock.fs_frag)(((d)/(fsun1.fs.fs_frag))*(fsun1.fs.fs_frag)); d >= osblockfsun2.fs.fs_csaddr; | |||
987 | d -= sblockfsun1.fs.fs_frag) { | |||
988 | setblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), | |||
989 | (d % sblockfsun1.fs.fs_fpg) / sblockfsun1.fs.fs_frag); | |||
990 | acgcgun1.cg.cg_cs.cs_nbfree++; | |||
991 | sblockfsun1.fs.fs_cstotal.cs_nbfree++; | |||
992 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
993 | setbit(cg_clustersfree(&acg),((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] |= 1<<(((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )&(8 -1))) | |||
994 | (d % sblock.fs_fpg) / sblock.fs_frag)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] |= 1<<(((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )&(8 -1))); | |||
995 | /* | |||
996 | * The last cluster size is already set up. | |||
997 | */ | |||
998 | if (lcs < sblockfsun1.fs.fs_contigsumsize) { | |||
999 | if (lcs) { | |||
1000 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]--; | |||
1001 | } | |||
1002 | lcs++; | |||
1003 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]++; | |||
1004 | } | |||
1005 | } | |||
1006 | } | |||
1007 | *cs = acgcgun1.cg.cg_cs; | |||
1008 | ||||
1009 | /* | |||
1010 | * Now write the former cylinder group containing the cylinder | |||
1011 | * summary back to disk. | |||
1012 | */ | |||
1013 | wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (ocscg)) + (&fsun1 .fs)->fs_cgoffset * ((ocscg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_cblkno)) << (&fsun1.fs )->fs_fsbtodb), | |||
1014 | (size_t)sblockfsun1.fs.fs_cgsize, (void *)&acgcgun1.cg, fso, Nflag); | |||
1015 | ||||
1016 | /* | |||
1017 | * Find the beginning of the new cylinder group containing the | |||
1018 | * cylinder summary. | |||
1019 | */ | |||
1020 | sblockfsun1.fs.fs_csaddr = cgdmin(&sblock, osblock.fs_ncg)((((daddr_t)(&fsun1.fs)->fs_fpg * (fsun2.fs.fs_ncg)) + (&fsun1.fs)->fs_cgoffset * ((fsun2.fs.fs_ncg) & ~ ((&fsun1.fs)->fs_cgmask))) + (&fsun1.fs)->fs_dblkno ); | |||
1021 | ncscg = dtog(&sblock, sblock.fs_csaddr)((fsun1.fs.fs_csaddr) / (&fsun1.fs)->fs_fpg); | |||
1022 | cs = fscs + ncscg; | |||
1023 | ||||
1024 | ||||
1025 | /* | |||
1026 | * If Nflag is specified, we would now read random data instead | |||
1027 | * of an empty cg structure from disk. So we can't simulate that | |||
1028 | * part for now. | |||
1029 | */ | |||
1030 | if (Nflag) | |||
1031 | return; | |||
1032 | ||||
1033 | /* | |||
1034 | * Read the future cylinder group containing the cylinder | |||
1035 | * summary from disk, and make a copy. | |||
1036 | */ | |||
1037 | rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (ncscg)) + (&fsun1 .fs)->fs_cgoffset * ((ncscg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_cblkno)) << (&fsun1.fs )->fs_fsbtodb), | |||
1038 | (size_t)sblockfsun1.fs.fs_cgsize, &aocgcgun2.cg, fsi); | |||
1039 | ||||
1040 | memcpy(&cgun1, &cgun2, sizeof(cgun2)); | |||
1041 | ||||
1042 | /* | |||
1043 | * Allocate all complete blocks used by the new cylinder | |||
1044 | * summary. | |||
1045 | */ | |||
1046 | for (d = sblockfsun1.fs.fs_csaddr; d + sblockfsun1.fs.fs_frag <= | |||
1047 | sblockfsun1.fs.fs_csaddr + (sblockfsun1.fs.fs_cssize / sblockfsun1.fs.fs_fsize); | |||
1048 | d += sblockfsun1.fs.fs_frag) { | |||
1049 | clrblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), | |||
1050 | (d%sblockfsun1.fs.fs_fpg)/sblockfsun1.fs.fs_frag); | |||
1051 | acgcgun1.cg.cg_cs.cs_nbfree--; | |||
1052 | sblockfsun1.fs.fs_cstotal.cs_nbfree--; | |||
1053 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
1054 | clrbit(cg_clustersfree(&acg),((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] &= ~(1<<(((d % fsun1.fs.fs_fpg) / fsun1 .fs.fs_frag)&(8 -1)))) | |||
1055 | (d % sblock.fs_fpg) / sblock.fs_frag)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d % fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] &= ~(1<<(((d % fsun1.fs.fs_fpg) / fsun1 .fs.fs_frag)&(8 -1)))); | |||
1056 | } | |||
1057 | } | |||
1058 | ||||
1059 | /* | |||
1060 | * Allocate all fragments used by the cylinder summary in the | |||
1061 | * last block. | |||
1062 | */ | |||
1063 | if (d < sblockfsun1.fs.fs_csaddr + (sblockfsun1.fs.fs_cssize / sblockfsun1.fs.fs_fsize)) { | |||
1064 | for (; d - sblockfsun1.fs.fs_csaddr < | |||
1065 | sblockfsun1.fs.fs_cssize/sblockfsun1.fs.fs_fsize; | |||
1066 | d++) { | |||
1067 | clrbit(cg_blksfree(&acg), d%sblock.fs_fpg)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d%fsun1 .fs.fs_fpg)>>3] &= ~(1<<((d%fsun1.fs.fs_fpg)& (8 -1)))); | |||
1068 | acgcgun1.cg.cg_cs.cs_nffree--; | |||
1069 | sblockfsun1.fs.fs_cstotal.cs_nffree--; | |||
1070 | } | |||
1071 | acgcgun1.cg.cg_cs.cs_nbfree--; | |||
1072 | acgcgun1.cg.cg_cs.cs_nffree += sblockfsun1.fs.fs_frag; | |||
1073 | sblockfsun1.fs.fs_cstotal.cs_nbfree--; | |||
1074 | sblockfsun1.fs.fs_cstotal.cs_nffree += sblockfsun1.fs.fs_frag; | |||
1075 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
1076 | clrbit(cg_clustersfree(&acg),((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d%fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] &= ~(1<<(((d%fsun1.fs.fs_fpg) / fsun1.fs .fs_frag)&(8 -1)))) | |||
1077 | (d%sblock.fs_fpg) / sblock.fs_frag)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[((d%fsun1.fs.fs_fpg) / fsun1.fs.fs_frag )>>3] &= ~(1<<(((d%fsun1.fs.fs_fpg) / fsun1.fs .fs_frag)&(8 -1)))); | |||
1078 | } | |||
1079 | ||||
1080 | frag_adjust(d % sblockfsun1.fs.fs_fpg, 1); | |||
1081 | } | |||
1082 | /* | |||
1083 | * XXX Handle the cluster statistics here in the case this | |||
1084 | * cylinder group is now almost full, and the remaining | |||
1085 | * space is less then the maximum cluster size. This is | |||
1086 | * probably not needed, as you would hardly find a file | |||
1087 | * system which has only MAXCSBUFS+FS_MAXCONTIG of free | |||
1088 | * space right behind the cylinder group information in | |||
1089 | * any new cylinder group. | |||
1090 | */ | |||
1091 | ||||
1092 | /* | |||
1093 | * Update our statistics in the cylinder summary. | |||
1094 | */ | |||
1095 | *cs = acgcgun1.cg.cg_cs; | |||
1096 | ||||
1097 | /* | |||
1098 | * Write the new cylinder group containing the cylinder summary | |||
1099 | * back to disk. | |||
1100 | */ | |||
1101 | wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (ncscg)) + (&fsun1 .fs)->fs_cgoffset * ((ncscg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_cblkno)) << (&fsun1.fs )->fs_fsbtodb), | |||
1102 | (size_t)sblockfsun1.fs.fs_cgsize, (void *)&acgcgun1.cg, fso, Nflag); | |||
1103 | return; | |||
1104 | } | |||
1105 | /* | |||
1106 | * We have got enough of space in the current cylinder group, so we | |||
1107 | * can relocate just a few blocks, and let the summary information | |||
1108 | * grow in place where it is right now. | |||
1109 | */ | |||
1110 | cbase = cgbase(&osblock, ocscg)((daddr_t)(&fsun2.fs)->fs_fpg * (ocscg)); /* old and new are equal */ | |||
1111 | dupper = sblockfsun1.fs.fs_csaddr - cbase + | |||
1112 | howmany(sblock.fs_cssize, sblock.fs_fsize)(((fsun1.fs.fs_cssize) + ((fsun1.fs.fs_fsize) - 1)) / (fsun1. fs.fs_fsize)); | |||
1113 | odupper = osblockfsun2.fs.fs_csaddr - cbase + | |||
1114 | howmany(osblock.fs_cssize, osblock.fs_fsize)(((fsun2.fs.fs_cssize) + ((fsun2.fs.fs_fsize) - 1)) / (fsun2. fs.fs_fsize)); | |||
1115 | ||||
1116 | sblockfsun1.fs.fs_dsize -= dupper-odupper; | |||
1117 | ||||
1118 | /* | |||
1119 | * Allocate the space for the array of blocks to be relocated. | |||
1120 | */ | |||
1121 | bp = calloc(((dupper-odupper) / sblockfsun1.fs.fs_frag + 2), | |||
1122 | sizeof(struct gfs_bpp)); | |||
1123 | if (bp == NULL((void *)0)) | |||
1124 | errx(1, "calloc failed"); | |||
1125 | ||||
1126 | /* | |||
1127 | * Lock all new frags needed for the cylinder group summary. This is | |||
1128 | * done per fragment in the first and last block of the new required | |||
1129 | * area, and per block for all other blocks. | |||
1130 | * | |||
1131 | * Handle the first new block here (but only if some fragments where | |||
1132 | * already used for the cylinder summary). | |||
1133 | */ | |||
1134 | ind = 0; | |||
1135 | frag_adjust(odupper, -1); | |||
1136 | for (d = odupper; ((d < dupper) && (d % sblockfsun1.fs.fs_frag)); d++) { | |||
1137 | if (isclr(cg_blksfree(&acg), d)((((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d)>> 3] & (1<<((d)&(8 -1)))) == 0)) { | |||
1138 | if (!ind) { | |||
1139 | bp[ind].old = d / sblockfsun1.fs.fs_frag; | |||
1140 | bp[ind].flags|=GFS_FL_FIRST1; | |||
1141 | if (roundup(d, sblock.fs_frag)((((d)+((fsun1.fs.fs_frag)-1))/(fsun1.fs.fs_frag))*(fsun1.fs. fs_frag)) >= dupper) | |||
1142 | bp[ind].flags |= GFS_FL_LAST2; | |||
1143 | ind++; | |||
1144 | } | |||
1145 | } else { | |||
1146 | clrbit(cg_blksfree(&acg), d)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d)>> 3] &= ~(1<<((d)&(8 -1)))); | |||
1147 | acgcgun1.cg.cg_cs.cs_nffree--; | |||
1148 | sblockfsun1.fs.fs_cstotal.cs_nffree--; | |||
1149 | } | |||
1150 | /* | |||
1151 | * No cluster handling is needed here, as there was at least | |||
1152 | * one fragment in use by the cylinder summary in the old | |||
1153 | * filesystem. | |||
1154 | * No block - free counter handling here as this block was not | |||
1155 | * a free block. | |||
1156 | */ | |||
1157 | } | |||
1158 | frag_adjust(odupper, 1); | |||
1159 | ||||
1160 | /* | |||
1161 | * Handle all needed complete blocks here. | |||
1162 | */ | |||
1163 | for (; d + sblockfsun1.fs.fs_frag <= dupper; d += sblockfsun1.fs.fs_frag) { | |||
1164 | if (!isblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), d / sblockfsun1.fs.fs_frag)) { | |||
1165 | for (f = d; f < d + sblockfsun1.fs.fs_frag; f++) { | |||
1166 | if (isset(cg_blksfree(&aocg), f)(((((&cgun2.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun2.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun2.cg) + (&cgun2.cg)->cg_freeoff))))[(f)>> 3] & (1<<((f)&(8 -1))))) { | |||
1167 | acgcgun1.cg.cg_cs.cs_nffree--; | |||
1168 | sblockfsun1.fs.fs_cstotal.cs_nffree--; | |||
1169 | } | |||
1170 | } | |||
1171 | clrblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), d / sblockfsun1.fs.fs_frag); | |||
1172 | bp[ind].old = d / sblockfsun1.fs.fs_frag; | |||
1173 | ind++; | |||
1174 | } else { | |||
1175 | clrblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), d / sblockfsun1.fs.fs_frag); | |||
1176 | acgcgun1.cg.cg_cs.cs_nbfree--; | |||
1177 | sblockfsun1.fs.fs_cstotal.cs_nbfree--; | |||
1178 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
1179 | clrbit(cg_clustersfree(&acg), d / sblock.fs_frag)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[(d / fsun1.fs.fs_frag)>>3] &= ~(1<<((d / fsun1.fs.fs_frag)&(8 -1)))); | |||
1180 | for (lcs = 0, l = (d / sblockfsun1.fs.fs_frag) + 1; | |||
1181 | lcs < sblockfsun1.fs.fs_contigsumsize; | |||
1182 | l++, lcs++) { | |||
1183 | if (isclr(cg_clustersfree(&acg), l)(((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg )->cg_clusteroff)))[(l)>>3] & (1<<((l)& (8 -1)))) == 0)) | |||
1184 | break; | |||
1185 | } | |||
1186 | if (lcs < sblockfsun1.fs.fs_contigsumsize) { | |||
1187 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs + 1]--; | |||
1188 | if (lcs) | |||
1189 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]++; | |||
1190 | } | |||
1191 | } | |||
1192 | } | |||
1193 | /* | |||
1194 | * No fragment counter handling is needed here, as this finally | |||
1195 | * doesn't change after the relocation. | |||
1196 | */ | |||
1197 | } | |||
1198 | ||||
1199 | /* | |||
1200 | * Handle all fragments needed in the last new affected block. | |||
1201 | */ | |||
1202 | if (d
| |||
1203 | frag_adjust(dupper - 1, -1); | |||
1204 | ||||
1205 | if (isblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), d / sblockfsun1.fs.fs_frag)) { | |||
1206 | acgcgun1.cg.cg_cs.cs_nbfree--; | |||
1207 | sblockfsun1.fs.fs_cstotal.cs_nbfree--; | |||
1208 | acgcgun1.cg.cg_cs.cs_nffree+=sblockfsun1.fs.fs_frag; | |||
1209 | sblockfsun1.fs.fs_cstotal.cs_nffree+=sblockfsun1.fs.fs_frag; | |||
1210 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
1211 | clrbit(cg_clustersfree(&acg), d / sblock.fs_frag)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[(d / fsun1.fs.fs_frag)>>3] &= ~(1<<((d / fsun1.fs.fs_frag)&(8 -1)))); | |||
1212 | for (lcs = 0, l = (d / sblockfsun1.fs.fs_frag) + 1; | |||
1213 | lcs < sblockfsun1.fs.fs_contigsumsize; | |||
1214 | l++, lcs++) { | |||
1215 | if (isclr(cg_clustersfree(&acg), l)(((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg )->cg_clusteroff)))[(l)>>3] & (1<<((l)& (8 -1)))) == 0)) | |||
1216 | break; | |||
1217 | } | |||
1218 | if (lcs < sblockfsun1.fs.fs_contigsumsize) { | |||
1219 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs + 1]--; | |||
1220 | if (lcs) | |||
1221 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]++; | |||
1222 | } | |||
1223 | } | |||
1224 | } | |||
1225 | ||||
1226 | for (; d < dupper; d++) { | |||
1227 | if (isclr(cg_blksfree(&acg), d)((((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d)>> 3] & (1<<((d)&(8 -1)))) == 0)) { | |||
1228 | bp[ind].old = d / sblockfsun1.fs.fs_frag; | |||
1229 | bp[ind].flags |= GFS_FL_LAST2; | |||
1230 | } else { | |||
1231 | clrbit(cg_blksfree(&acg), d)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(d)>> 3] &= ~(1<<((d)&(8 -1)))); | |||
1232 | acgcgun1.cg.cg_cs.cs_nffree--; | |||
1233 | sblockfsun1.fs.fs_cstotal.cs_nffree--; | |||
1234 | } | |||
1235 | } | |||
1236 | if (bp[ind].flags & GFS_FL_LAST2) /* we have to advance here */ | |||
1237 | ind++; | |||
1238 | frag_adjust(dupper - 1, 1); | |||
1239 | } | |||
1240 | ||||
1241 | /* | |||
1242 | * If we found a block to relocate just do so. | |||
1243 | */ | |||
1244 | if (ind
| |||
1245 | for (i = 0; i < ind; i++) { | |||
1246 | if (!bp[i].old) { /* no more blocks listed */ | |||
1247 | /* | |||
1248 | * XXX A relative blocknumber should not be | |||
1249 | * zero, which is not explicitly | |||
1250 | * guaranteed by our code. | |||
1251 | */ | |||
1252 | break; | |||
1253 | } | |||
1254 | /* | |||
1255 | * Allocate a complete block in the same (current) | |||
1256 | * cylinder group. | |||
1257 | */ | |||
1258 | bp[i].new = alloc() / sblockfsun1.fs.fs_frag; | |||
1259 | ||||
1260 | /* | |||
1261 | * There is no frag_adjust() needed for the new block | |||
1262 | * as it will have no fragments yet :-). | |||
1263 | */ | |||
1264 | for (f = bp[i].old * sblockfsun1.fs.fs_frag, | |||
1265 | g = bp[i].new * sblockfsun1.fs.fs_frag; | |||
1266 | f < (bp[i].old + 1) * sblockfsun1.fs.fs_frag; | |||
1267 | f++, g++) { | |||
1268 | if (isset(cg_blksfree(&aocg), f)(((((&cgun2.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun2.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun2.cg) + (&cgun2.cg)->cg_freeoff))))[(f)>> 3] & (1<<((f)&(8 -1))))) { | |||
1269 | setbit(cg_blksfree(&acg), g)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(g)>> 3] |= 1<<((g)&(8 -1))); | |||
1270 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
1271 | sblockfsun1.fs.fs_cstotal.cs_nffree++; | |||
1272 | } | |||
1273 | } | |||
1274 | ||||
1275 | /* | |||
1276 | * Special handling is required if this was the first | |||
1277 | * block. We have to consider the fragments which were | |||
1278 | * used by the cylinder summary in the original block | |||
1279 | * which re to be free in the copy of our block. We | |||
1280 | * have to be careful if this first block happens to | |||
1281 | * be also the last block to be relocated. | |||
1282 | */ | |||
1283 | if (bp[i].flags & GFS_FL_FIRST1) { | |||
1284 | for (f = bp[i].old * sblockfsun1.fs.fs_frag, | |||
1285 | g = bp[i].new * sblockfsun1.fs.fs_frag; | |||
1286 | f < odupper; | |||
1287 | f++, g++) { | |||
1288 | setbit(cg_blksfree(&acg), g)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(g)>> 3] |= 1<<((g)&(8 -1))); | |||
1289 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
1290 | sblockfsun1.fs.fs_cstotal.cs_nffree++; | |||
1291 | } | |||
1292 | if (!(bp[i].flags & GFS_FL_LAST2)) | |||
1293 | frag_adjust(bp[i].new * sblockfsun1.fs.fs_frag, 1); | |||
1294 | } | |||
1295 | ||||
1296 | /* | |||
1297 | * Special handling is required if this is the last | |||
1298 | * block to be relocated. | |||
1299 | */ | |||
1300 | if (bp[i].flags & GFS_FL_LAST2) { | |||
1301 | frag_adjust(bp[i].new * sblockfsun1.fs.fs_frag, 1); | |||
1302 | frag_adjust(bp[i].old * sblockfsun1.fs.fs_frag, -1); | |||
1303 | for (f = dupper; | |||
1304 | f < roundup(dupper, sblock.fs_frag)((((dupper)+((fsun1.fs.fs_frag)-1))/(fsun1.fs.fs_frag))*(fsun1 .fs.fs_frag)); | |||
1305 | f++) { | |||
1306 | if (isclr(cg_blksfree(&acg), f)((((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(f)>> 3] & (1<<((f)&(8 -1)))) == 0)) { | |||
1307 | setbit(cg_blksfree(&acg), f)(((((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *) (&cgun1.cg) + (&cgun1.cg)->cg_freeoff))))[(f)>> 3] |= 1<<((f)&(8 -1))); | |||
1308 | acgcgun1.cg.cg_cs.cs_nffree++; | |||
1309 | sblockfsun1.fs.fs_cstotal.cs_nffree++; | |||
1310 | } | |||
1311 | } | |||
1312 | frag_adjust(bp[i].old * sblockfsun1.fs.fs_frag, 1); | |||
1313 | } | |||
1314 | ||||
1315 | /* | |||
1316 | * !!! Attach the cylindergroup offset here. | |||
1317 | */ | |||
1318 | bp[i].old += cbase / sblockfsun1.fs.fs_frag; | |||
1319 | bp[i].new += cbase / sblockfsun1.fs.fs_frag; | |||
1320 | ||||
1321 | /* | |||
1322 | * Copy the content of the block. | |||
1323 | */ | |||
1324 | /* | |||
1325 | * XXX Here we will have to implement a copy on write | |||
1326 | * in the case we have any active snapshots. | |||
1327 | */ | |||
1328 | rdfs(fsbtodb(&sblock, bp[i].old * sblock.fs_frag)((bp[i].old * fsun1.fs.fs_frag) << (&fsun1.fs)-> fs_fsbtodb), | |||
1329 | (size_t)sblockfsun1.fs.fs_bsize, (void *)&ablk, fsi); | |||
1330 | wtfs(fsbtodb(&sblock, bp[i].new * sblock.fs_frag)((bp[i].new * fsun1.fs.fs_frag) << (&fsun1.fs)-> fs_fsbtodb), | |||
1331 | (size_t)sblockfsun1.fs.fs_bsize, (void *)&ablk, fso, Nflag); | |||
1332 | } | |||
1333 | ||||
1334 | /* | |||
1335 | * Now we have to update all references to any fragment which | |||
1336 | * belongs to any block relocated. We iterate now over all | |||
1337 | * cylinder groups, within those over all non zero length | |||
1338 | * inodes. | |||
1339 | */ | |||
1340 | for (cg = 0; cg < osblockfsun2.fs.fs_ncg; cg++) { | |||
1341 | for (inc = osblockfsun2.fs.fs_ipg - 1; inc > 0; inc--) { | |||
1342 | updrefs(cg, (ino_t)inc, bp, fsi, fso, Nflag); | |||
1343 | } | |||
1344 | } | |||
1345 | ||||
1346 | /* | |||
1347 | * All inodes are checked, now make sure the number of | |||
1348 | * references found make sense. | |||
1349 | */ | |||
1350 | for (i = 0; i < ind; i++) { | |||
1351 | if (!bp[i].found || (bp[i].found > sblockfsun1.fs.fs_frag)) { | |||
1352 | warnx("error: %jd refs found for block %jd.", | |||
1353 | (intmax_t)bp[i].found, (intmax_t)bp[i].old); | |||
1354 | } | |||
1355 | ||||
1356 | } | |||
1357 | } | |||
1358 | /* | |||
1359 | * The following statistics are not changed here: | |||
1360 | * sblock.fs_cstotal.cs_ndir | |||
1361 | * sblock.fs_cstotal.cs_nifree | |||
1362 | * The following statistics were already updated on the fly: | |||
1363 | * sblock.fs_cstotal.cs_nffree | |||
1364 | * sblock.fs_cstotal.cs_nbfree | |||
1365 | * As the statistics for this cylinder group are ready, copy it to | |||
1366 | * the summary information array. | |||
1367 | */ | |||
1368 | ||||
1369 | *cs = acgcgun1.cg.cg_cs; | |||
| ||||
1370 | ||||
1371 | /* | |||
1372 | * Write summary cylinder group back to disk. | |||
1373 | */ | |||
1374 | wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg))((((((daddr_t)(&fsun1.fs)->fs_fpg * (ocscg)) + (&fsun1 .fs)->fs_cgoffset * ((ocscg) & ~((&fsun1.fs)->fs_cgmask ))) + (&fsun1.fs)->fs_cblkno)) << (&fsun1.fs )->fs_fsbtodb), (size_t)sblockfsun1.fs.fs_cgsize, | |||
1375 | (void *)&acgcgun1.cg, fso, Nflag); | |||
1376 | } | |||
1377 | ||||
1378 | /* | |||
1379 | * Here we read some block(s) from disk. | |||
1380 | */ | |||
1381 | static void | |||
1382 | rdfs(daddr_t bno, size_t size, void *bf, int fsi) | |||
1383 | { | |||
1384 | ssize_t n; | |||
1385 | ||||
1386 | if (bno < 0) { | |||
1387 | err(32, "rdfs: attempting to read negative block number"); | |||
1388 | } | |||
1389 | if (lseek(fsi, (off_t)bno * DEV_BSIZE(1 << 9), SEEK_SET0) == -1) { | |||
1390 | err(33, "rdfs: seek error: %jd", (intmax_t)bno); | |||
1391 | } | |||
1392 | n = read(fsi, bf, size); | |||
1393 | if (n != (ssize_t)size) { | |||
1394 | err(34, "rdfs: read error: %jd", (intmax_t)bno); | |||
1395 | } | |||
1396 | } | |||
1397 | ||||
1398 | /* | |||
1399 | * Here we write some block(s) to disk. | |||
1400 | */ | |||
1401 | static void | |||
1402 | wtfs(daddr_t bno, size_t size, void *bf, int fso, unsigned int Nflag) | |||
1403 | { | |||
1404 | ssize_t n; | |||
1405 | ||||
1406 | if (Nflag) | |||
1407 | return; | |||
1408 | ||||
1409 | if (lseek(fso, (off_t)bno * DEV_BSIZE(1 << 9), SEEK_SET0) == -1) | |||
1410 | err(35, "wtfs: seek error: %ld", (long)bno); | |||
1411 | n = write(fso, bf, size); | |||
1412 | if (n != (ssize_t)size) | |||
1413 | err(36, "wtfs: write error: %ld", (long)bno); | |||
1414 | } | |||
1415 | ||||
1416 | /* | |||
1417 | * Here we allocate a free block in the current cylinder group. It is assumed, | |||
1418 | * that acg contains the current cylinder group. As we may take a block from | |||
1419 | * somewhere in the filesystem we have to handle cluster summary here. | |||
1420 | */ | |||
1421 | static daddr_t | |||
1422 | alloc(void) | |||
1423 | { | |||
1424 | daddr_t d, blkno; | |||
1425 | int lcs1, lcs2; | |||
1426 | int l; | |||
1427 | int csmin, csmax; | |||
1428 | int dlower, dupper, dmax; | |||
1429 | ||||
1430 | if (acgcgun1.cg.cg_magic != CG_MAGIC0x090255) { | |||
1431 | warnx("acg: bad magic number"); | |||
1432 | return (0); | |||
1433 | } | |||
1434 | if (acgcgun1.cg.cg_cs.cs_nbfree == 0) { | |||
1435 | warnx("error: cylinder group ran out of space"); | |||
1436 | return (0); | |||
1437 | } | |||
1438 | /* | |||
1439 | * We start seeking for free blocks only from the space available after | |||
1440 | * the end of the new grown cylinder summary. Otherwise we allocate a | |||
1441 | * block here which we have to relocate a couple of seconds later again | |||
1442 | * again, and we are not prepared to to this anyway. | |||
1443 | */ | |||
1444 | blkno = -1; | |||
1445 | dlower = cgsblock(&sblock, acg.cg_cgx)((((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)) + (&fsun1.fs)->fs_cgoffset * ((cgun1.cg.cg_cgx) & ~ ((&fsun1.fs)->fs_cgmask))) + (&fsun1.fs)->fs_sblkno ) - cgbase(&sblock, acg.cg_cgx)((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)); | |||
1446 | dupper = cgdmin(&sblock, acg.cg_cgx)((((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)) + (&fsun1.fs)->fs_cgoffset * ((cgun1.cg.cg_cgx) & ~ ((&fsun1.fs)->fs_cgmask))) + (&fsun1.fs)->fs_dblkno ) - cgbase(&sblock, acg.cg_cgx)((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)); | |||
1447 | dmax = cgbase(&sblock, acg.cg_cgx)((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)) + sblockfsun1.fs.fs_fpg; | |||
1448 | if (dmax > sblockfsun1.fs.fs_size) { | |||
1449 | dmax = sblockfsun1.fs.fs_size; | |||
1450 | } | |||
1451 | dmax -= cgbase(&sblock, acg.cg_cgx)((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)); /* retransform into cg */ | |||
1452 | csmin=sblockfsun1.fs.fs_csaddr-cgbase(&sblock, acg.cg_cgx)((daddr_t)(&fsun1.fs)->fs_fpg * (cgun1.cg.cg_cgx)); | |||
1453 | csmax = csmin + howmany(sblock.fs_cssize, sblock.fs_fsize)(((fsun1.fs.fs_cssize) + ((fsun1.fs.fs_fsize) - 1)) / (fsun1. fs.fs_fsize)); | |||
1454 | ||||
1455 | for (d = 0; (d < dlower && blkno == -1); d += sblockfsun1.fs.fs_frag) { | |||
1456 | if (d >= csmin && d <= csmax) { | |||
1457 | continue; | |||
1458 | } | |||
1459 | if (isblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), fragstoblks(&sblock,((d) >> (&fsun1.fs)->fs_fragshift) | |||
1460 | d)((d) >> (&fsun1.fs)->fs_fragshift))) { | |||
1461 | blkno = fragstoblks(&sblock, d)((d) >> (&fsun1.fs)->fs_fragshift);/* Yeah found a block */ | |||
1462 | break; | |||
1463 | } | |||
1464 | } | |||
1465 | for (d = dupper; (d < dmax && blkno == -1); d += sblockfsun1.fs.fs_frag) { | |||
1466 | if (d >= csmin && d <= csmax) { | |||
1467 | continue; | |||
1468 | } | |||
1469 | if (isblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), fragstoblks(&sblock,((d) >> (&fsun1.fs)->fs_fragshift) | |||
1470 | d)((d) >> (&fsun1.fs)->fs_fragshift))) { | |||
1471 | blkno = fragstoblks(&sblock, d)((d) >> (&fsun1.fs)->fs_fragshift);/* Yeah found a block */ | |||
1472 | break; | |||
1473 | } | |||
1474 | } | |||
1475 | if (blkno == -1) { | |||
1476 | warnx("internal error: couldn't find promised block in cg"); | |||
1477 | return (0); | |||
1478 | } | |||
1479 | ||||
1480 | /* | |||
1481 | * This is needed if the block was found already in the first loop. | |||
1482 | */ | |||
1483 | d = blkstofrags(&sblock, blkno)((blkno) << (&fsun1.fs)->fs_fragshift); | |||
1484 | ||||
1485 | clrblock(&sblockfsun1.fs, cg_blksfree(&acg)(((&cgun1.cg)->cg_magic != 0x090255) ? (((struct ocg * )(&cgun1.cg))->cg_free) : ((u_int8_t *)((u_int8_t *)(& cgun1.cg) + (&cgun1.cg)->cg_freeoff))), blkno); | |||
1486 | if (sblockfsun1.fs.fs_contigsumsize > 0) { | |||
1487 | /* | |||
1488 | * Handle the cluster allocation bitmap. | |||
1489 | */ | |||
1490 | clrbit(cg_clustersfree(&acg), blkno)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[(blkno)>>3] &= ~(1<<((blkno )&(8 -1)))); | |||
1491 | /* | |||
1492 | * We possibly have split a cluster here, so we have to do | |||
1493 | * recalculate the sizes of the remaining cluster halves now, | |||
1494 | * and use them for updating the cluster summary information. | |||
1495 | * | |||
1496 | * Lets start with the blocks before our allocated block ... | |||
1497 | */ | |||
1498 | for (lcs1 = 0, l = blkno - 1; lcs1 < sblockfsun1.fs.fs_contigsumsize; | |||
1499 | l--, lcs1++) { | |||
1500 | if (isclr(cg_clustersfree(&acg), l)(((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg )->cg_clusteroff)))[(l)>>3] & (1<<((l)& (8 -1)))) == 0)) | |||
1501 | break; | |||
1502 | } | |||
1503 | /* | |||
1504 | * ... and continue with the blocks right after our allocated | |||
1505 | * block. | |||
1506 | */ | |||
1507 | for (lcs2 = 0, l = blkno + 1; lcs2 < sblockfsun1.fs.fs_contigsumsize; | |||
1508 | l++, lcs2++) { | |||
1509 | if (isclr(cg_clustersfree(&acg), l)(((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg )->cg_clusteroff)))[(l)>>3] & (1<<((l)& (8 -1)))) == 0)) | |||
1510 | break; | |||
1511 | } | |||
1512 | ||||
1513 | /* | |||
1514 | * Now update all counters. | |||
1515 | */ | |||
1516 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[MINIMUM(lcs1 + lcs2 + 1, sblock.fs_contigsumsize)(((lcs1 + lcs2 + 1) < (fsun1.fs.fs_contigsumsize)) ? (lcs1 + lcs2 + 1) : (fsun1.fs.fs_contigsumsize))]--; | |||
1517 | if (lcs1) | |||
1518 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs1]++; | |||
1519 | if (lcs2) | |||
1520 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs2]++; | |||
1521 | } | |||
1522 | /* | |||
1523 | * Update all statistics based on blocks. | |||
1524 | */ | |||
1525 | acgcgun1.cg.cg_cs.cs_nbfree--; | |||
1526 | sblockfsun1.fs.fs_cstotal.cs_nbfree--; | |||
1527 | ||||
1528 | return (d); | |||
1529 | } | |||
1530 | ||||
1531 | /* | |||
1532 | * Here we check if all frags of a block are free. For more details again | |||
1533 | * please see the source of newfs(8), as this function is taken over almost | |||
1534 | * unchanged. | |||
1535 | */ | |||
1536 | static int | |||
1537 | isblock(struct fs *fs, unsigned char *cp, int h) | |||
1538 | { | |||
1539 | unsigned char mask; | |||
1540 | ||||
1541 | switch (fs->fs_frag) { | |||
1542 | case 8: | |||
1543 | return (cp[h] == 0xff); | |||
1544 | case 4: | |||
1545 | mask = 0x0f << ((h & 0x1) << 2); | |||
1546 | return ((cp[h >> 1] & mask) == mask); | |||
1547 | case 2: | |||
1548 | mask = 0x03 << ((h & 0x3) << 1); | |||
1549 | return ((cp[h >> 2] & mask) == mask); | |||
1550 | case 1: | |||
1551 | mask = 0x01 << (h & 0x7); | |||
1552 | return ((cp[h >> 3] & mask) == mask); | |||
1553 | default: | |||
1554 | fprintf(stderr(&__sF[2]), "isblock bad fs_frag %d\n", fs->fs_frag); | |||
1555 | return (0); | |||
1556 | } | |||
1557 | } | |||
1558 | ||||
1559 | /* | |||
1560 | * Here we allocate a complete block in the block map. For more details again | |||
1561 | * please see the source of newfs(8), as this function is taken over almost | |||
1562 | * unchanged. | |||
1563 | */ | |||
1564 | static void | |||
1565 | clrblock(struct fs *fs, unsigned char *cp, int h) | |||
1566 | { | |||
1567 | switch ((fs)->fs_frag) { | |||
1568 | case 8: | |||
1569 | cp[h] = 0; | |||
1570 | break; | |||
1571 | case 4: | |||
1572 | cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); | |||
1573 | break; | |||
1574 | case 2: | |||
1575 | cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); | |||
1576 | break; | |||
1577 | case 1: | |||
1578 | cp[h >> 3] &= ~(0x01 << (h & 0x7)); | |||
1579 | break; | |||
1580 | default: | |||
1581 | warnx("clrblock bad fs_frag %d", fs->fs_frag); | |||
1582 | break; | |||
1583 | } | |||
1584 | } | |||
1585 | ||||
1586 | /* | |||
1587 | * Here we free a complete block in the free block map. For more details again | |||
1588 | * please see the source of newfs(8), as this function is taken over almost | |||
1589 | * unchanged. | |||
1590 | */ | |||
1591 | static void | |||
1592 | setblock(struct fs *fs, unsigned char *cp, int h) | |||
1593 | { | |||
1594 | switch (fs->fs_frag) { | |||
1595 | case 8: | |||
1596 | cp[h] = 0xff; | |||
1597 | break; | |||
1598 | case 4: | |||
1599 | cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); | |||
1600 | break; | |||
1601 | case 2: | |||
1602 | cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); | |||
1603 | break; | |||
1604 | case 1: | |||
1605 | cp[h >> 3] |= (0x01 << (h & 0x7)); | |||
1606 | break; | |||
1607 | default: | |||
1608 | warnx("setblock bad fs_frag %d", fs->fs_frag); | |||
1609 | break; | |||
1610 | } | |||
1611 | } | |||
1612 | ||||
1613 | /* | |||
1614 | * This function provides access to an individual inode. We find out in which | |||
1615 | * block the requested inode is located, read it from disk if needed, and | |||
1616 | * return the pointer into that block. We maintain a cache of one block to | |||
1617 | * not read the same block again and again if we iterate linearly over all | |||
1618 | * inodes. | |||
1619 | */ | |||
1620 | static union dinode * | |||
1621 | ginode(ino_t inumber, int fsi, int cg) | |||
1622 | { | |||
1623 | static ino_t startinum = 0; /* first inode in cached block */ | |||
1624 | ||||
1625 | /* | |||
1626 | * The inumber passed in is relative to the cg, so use it here to see | |||
1627 | * if the inode has been allocated yet. | |||
1628 | */ | |||
1629 | if (isclr(cg_inosused(&aocg), inumber)((((((&cgun2.cg)->cg_magic != 0x090255) ? (((struct ocg *)(&cgun2.cg))->cg_iused) : ((u_int8_t *)((u_int8_t * )(&cgun2.cg) + (&cgun2.cg)->cg_iusedoff))))[(inumber )>>3] & (1<<((inumber)&(8 -1)))) == 0)) { | |||
1630 | return NULL((void *)0); | |||
1631 | } | |||
1632 | /* | |||
1633 | * Now make the inumber relative to the entire inode space so it can | |||
1634 | * be sanity checked. | |||
1635 | */ | |||
1636 | inumber += (cg * sblockfsun1.fs.fs_ipg); | |||
1637 | if (inumber < ROOTINO((ufsino_t)2)) { | |||
1638 | return NULL((void *)0); | |||
1639 | } | |||
1640 | if (inumber > maxino) | |||
1641 | errx(8, "bad inode number %llu to ginode", | |||
1642 | (unsigned long long)inumber); | |||
1643 | if (startinum == 0 || | |||
1644 | inumber < startinum || inumber >= startinum + INOPB(&sblock)((&fsun1.fs)->fs_inopb)) { | |||
1645 | inoblk = fsbtodb(&sblock, ino_to_fsba(&sblock, inumber))((((daddr_t)(((((daddr_t)(&fsun1.fs)->fs_fpg * (((inumber ) / (&fsun1.fs)->fs_ipg))) + (&fsun1.fs)->fs_cgoffset * ((((inumber) / (&fsun1.fs)->fs_ipg)) & ~((& fsun1.fs)->fs_cgmask))) + (&fsun1.fs)->fs_iblkno) + ((((((inumber) % (&fsun1.fs)->fs_ipg) / ((&fsun1. fs)->fs_inopb))) << ((&fsun1.fs))->fs_fragshift ))))) << (&fsun1.fs)->fs_fsbtodb); | |||
1646 | rdfs(inoblk, (size_t)sblockfsun1.fs.fs_bsize, inobuf, fsi); | |||
1647 | startinum = (inumber / INOPB(&sblock)((&fsun1.fs)->fs_inopb)) * INOPB(&sblock)((&fsun1.fs)->fs_inopb); | |||
1648 | } | |||
1649 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) | |||
1650 | return (union dinode *)((uintptr_t)inobuf + | |||
1651 | (inumber % INOPB(&sblock)((&fsun1.fs)->fs_inopb)) * sizeof(struct ufs1_dinode)); | |||
1652 | return (union dinode *)((uintptr_t)inobuf + | |||
1653 | (inumber % INOPB(&sblock)((&fsun1.fs)->fs_inopb)) * sizeof(struct ufs2_dinode)); | |||
1654 | } | |||
1655 | ||||
1656 | /* | |||
1657 | * Figure out how many lines our current terminal has. For more details again | |||
1658 | * please see the source of newfs(8), as this function is taken over almost | |||
1659 | * unchanged. | |||
1660 | */ | |||
1661 | static int | |||
1662 | charsperline(void) | |||
1663 | { | |||
1664 | int columns; | |||
1665 | char *cp; | |||
1666 | struct winsize ws; | |||
1667 | ||||
1668 | columns = 0; | |||
1669 | if ((cp = getenv("COLUMNS")) != NULL((void *)0)) | |||
1670 | columns = strtonum(cp, 1, INT_MAX0x7fffffff, NULL((void *)0)); | |||
1671 | if (columns == 0 && ioctl(STDOUT_FILENO1, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff ) << 16) | ((('t')) << 8) | ((104))), &ws) == 0 && | |||
1672 | ws.ws_col > 0) | |||
1673 | columns = ws.ws_col; | |||
1674 | if (columns == 0) | |||
1675 | columns = 80; | |||
1676 | ||||
1677 | return columns; | |||
1678 | } | |||
1679 | ||||
1680 | /* | |||
1681 | * growfs(8) is a utility which allows to increase the size of an existing | |||
1682 | * ufs filesystem. Currently this can only be done on unmounted file system. | |||
1683 | * It recognizes some command line options to specify the new desired size, | |||
1684 | * and it does some basic checkings. The old filesystem size is determined | |||
1685 | * and after some more checks like we can really access the new last block | |||
1686 | * on the disk etc. we calculate the new parameters for the superblock. After | |||
1687 | * having done this we just call growfs() which will do the work. Before | |||
1688 | * we finish the only thing left is to update the disklabel. | |||
1689 | * We still have to provide support for snapshots. Therefore we first have to | |||
1690 | * understand what data structures are always replicated in the snapshot on | |||
1691 | * creation, for all other blocks we touch during our procedure, we have to | |||
1692 | * keep the old blocks unchanged somewhere available for the snapshots. If we | |||
1693 | * are lucky, then we only have to handle our blocks to be relocated in that | |||
1694 | * way. | |||
1695 | * Also we have to consider in what order we actually update the critical | |||
1696 | * data structures of the filesystem to make sure, that in case of a disaster | |||
1697 | * fsck(8) is still able to restore any lost data. | |||
1698 | * The foreseen last step then will be to provide for growing even mounted | |||
1699 | * file systems. There we have to extend the mount() system call to provide | |||
1700 | * userland access to the filesystem locking facility. | |||
1701 | */ | |||
1702 | int | |||
1703 | main(int argc, char **argv) | |||
1704 | { | |||
1705 | char *device, *lastsector; | |||
1706 | int ch; | |||
1707 | long long size = 0; | |||
1708 | unsigned int Nflag = 0; | |||
1709 | int ExpertFlag = 0; | |||
1710 | struct stat st; | |||
1711 | struct disklabel *lp; | |||
1712 | struct partition *pp; | |||
1713 | int i, fsi, fso; | |||
1714 | char reply[5]; | |||
1715 | const char *errstr; | |||
1716 | #ifdef FSMAXSNAP20 | |||
1717 | int j; | |||
1718 | #endif /* FSMAXSNAP */ | |||
1719 | ||||
1720 | while ((ch = getopt(argc, argv, "Nqs:vy")) != -1) { | |||
1721 | switch (ch) { | |||
1722 | case 'N': | |||
1723 | Nflag = 1; | |||
1724 | break; | |||
1725 | case 'q': | |||
1726 | quiet = 1; | |||
1727 | break; | |||
1728 | case 's': | |||
1729 | size = strtonum(optarg, 1, LLONG_MAX0x7fffffffffffffffLL, &errstr); | |||
1730 | if (errstr) | |||
1731 | usage(); | |||
1732 | break; | |||
1733 | case 'v': /* for compatibility to newfs */ | |||
1734 | break; | |||
1735 | case 'y': | |||
1736 | ExpertFlag = 1; | |||
1737 | break; | |||
1738 | default: | |||
1739 | usage(); | |||
1740 | } | |||
1741 | } | |||
1742 | argc -= optind; | |||
1743 | argv += optind; | |||
1744 | ||||
1745 | if (argc != 1) | |||
1746 | usage(); | |||
1747 | ||||
1748 | colwidth = charsperline(); | |||
1749 | ||||
1750 | /* | |||
1751 | * Rather than guessing, use opendev() to get the device | |||
1752 | * name, which we open for reading. | |||
1753 | */ | |||
1754 | if ((fsi = opendev(*argv, O_RDONLY0x0000, 0, &device)) == -1) | |||
1755 | err(1, "%s", *argv); | |||
1756 | ||||
1757 | /* | |||
1758 | * Try to access our devices for writing ... | |||
1759 | */ | |||
1760 | if (Nflag) { | |||
1761 | fso = -1; | |||
1762 | } else { | |||
1763 | fso = open(device, O_WRONLY0x0001); | |||
1764 | if (fso == -1) | |||
1765 | err(1, "%s", device); | |||
1766 | } | |||
1767 | ||||
1768 | /* | |||
1769 | * Now we have a file descriptor for our device, fstat() it to | |||
1770 | * figure out the partition number. | |||
1771 | */ | |||
1772 | if (fstat(fsi, &st) == -1) | |||
1773 | err(1, "%s: fstat()", device); | |||
1774 | ||||
1775 | /* | |||
1776 | * Try to read a label from the disk. Then get the partition from the | |||
1777 | * device minor number, using DISKPART(). Probably don't need to | |||
1778 | * check against getmaxpartitions(). | |||
1779 | */ | |||
1780 | lp = get_disklabel(fsi); | |||
1781 | if (DISKPART(st.st_rdev)(((unsigned)((st.st_rdev) & 0xff) | (((st.st_rdev) & 0xffff0000 ) >> 8)) % 16) < getmaxpartitions()) | |||
1782 | pp = &lp->d_partitions[DISKPART(st.st_rdev)(((unsigned)((st.st_rdev) & 0xff) | (((st.st_rdev) & 0xffff0000 ) >> 8)) % 16)]; | |||
1783 | else | |||
1784 | errx(1, "%s: invalid partition number %u", | |||
1785 | device, DISKPART(st.st_rdev)(((unsigned)((st.st_rdev) & 0xff) | (((st.st_rdev) & 0xffff0000 ) >> 8)) % 16)); | |||
1786 | ||||
1787 | if (pledge("stdio disklabel", NULL((void *)0)) == -1) | |||
1788 | err(1, "pledge"); | |||
1789 | ||||
1790 | /* | |||
1791 | * Check if that partition is suitable for growing a file system. | |||
1792 | */ | |||
1793 | if (DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) < 1) | |||
1794 | errx(1, "partition is unavailable"); | |||
1795 | if (pp->p_fstype != FS_BSDFFS7) | |||
1796 | errx(1, "can only grow ffs partitions"); | |||
1797 | ||||
1798 | /* | |||
1799 | * Read the current superblock, and take a backup. | |||
1800 | */ | |||
1801 | for (i = 0; sblock_try[i] != -1; i++) { | |||
1802 | sblockloc = sblock_try[i] / DEV_BSIZE(1 << 9); | |||
1803 | rdfs(sblockloc, (size_t)SBLOCKSIZE8192, (void *)&(osblockfsun2.fs), fsi); | |||
1804 | if ((osblockfsun2.fs.fs_magic == FS_UFS1_MAGIC0x011954 || | |||
1805 | (osblockfsun2.fs.fs_magic == FS_UFS2_MAGIC0x19540119 && | |||
1806 | osblockfsun2.fs.fs_sblockloc == sblock_try[i])) && | |||
1807 | osblockfsun2.fs.fs_bsize <= MAXBSIZE(64 * 1024) && | |||
1808 | osblockfsun2.fs.fs_bsize >= (int32_t) sizeof(struct fs)) | |||
1809 | break; | |||
1810 | } | |||
1811 | if (sblock_try[i] == -1) | |||
1812 | errx(1, "superblock not recognized"); | |||
1813 | if (osblockfsun2.fs.fs_clean == 0) | |||
1814 | errx(1, "filesystem not clean - run fsck"); | |||
1815 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954 && | |||
1816 | (sblockfsun1.fs.fs_ffs1_flags & FS_FLAGS_UPDATED0x80) == 0) | |||
1817 | ffs1_sb_update(&sblockfsun1.fs, sblock_try[i]); | |||
1818 | memcpy(&fsun1, &fsun2, sizeof(fsun2)); | |||
1819 | maxino = sblockfsun1.fs.fs_ncg * sblockfsun1.fs.fs_ipg; | |||
1820 | ||||
1821 | /* | |||
1822 | * Determine size to grow to. Default to the full size specified in | |||
1823 | * the disk label. | |||
1824 | */ | |||
1825 | sblockfsun1.fs.fs_size = dbtofsb(&osblock, DL_SECTOBLK(lp, DL_GETPSIZE(pp)))(((((((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size )) * ((lp)->d_secsize / (1 << 9)))) >> (&fsun2 .fs)->fs_fsbtodb); | |||
1826 | if (size != 0) { | |||
1827 | if (size > DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size)) { | |||
1828 | errx(1, "there is not enough space (%llu < %lld)", | |||
1829 | DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size), size); | |||
1830 | } | |||
1831 | sblockfsun1.fs.fs_size = dbtofsb(&osblock, DL_SECTOBLK(lp, size))((((size) * ((lp)->d_secsize / (1 << 9)))) >> ( &fsun2.fs)->fs_fsbtodb); | |||
1832 | } | |||
1833 | ||||
1834 | /* | |||
1835 | * Are we really growing ? | |||
1836 | */ | |||
1837 | if (osblockfsun2.fs.fs_size >= sblockfsun1.fs.fs_size) { | |||
1838 | errx(1, "we are not growing (%jd->%jd)", | |||
1839 | (intmax_t)osblockfsun2.fs.fs_size, (intmax_t)sblockfsun1.fs.fs_size); | |||
1840 | } | |||
1841 | ||||
1842 | ||||
1843 | #ifdef FSMAXSNAP20 | |||
1844 | /* | |||
1845 | * Check if we find an active snapshot. | |||
1846 | */ | |||
1847 | if (ExpertFlag == 0) { | |||
1848 | for (j = 0; j < FSMAXSNAP20; j++) { | |||
1849 | if (sblockfsun1.fs.fs_snapinum[j]) { | |||
1850 | errx(1, "active snapshot found in filesystem\n" | |||
1851 | " please remove all snapshots before " | |||
1852 | "using growfs"); | |||
1853 | } | |||
1854 | if (!sblockfsun1.fs.fs_snapinum[j]) /* list is dense */ | |||
1855 | break; | |||
1856 | } | |||
1857 | } | |||
1858 | #endif | |||
1859 | ||||
1860 | if (ExpertFlag == 0 && Nflag == 0) { | |||
1861 | printf("We strongly recommend you to make a backup " | |||
1862 | "before growing the Filesystem\n\n" | |||
1863 | " Did you backup your data (Yes/No) ? "); | |||
1864 | if (fgets(reply, (int)sizeof(reply), stdin(&__sF[0])) == NULL((void *)0) || | |||
1865 | strncasecmp(reply, "Yes", 3)) { | |||
1866 | printf("\n Nothing done \n"); | |||
1867 | exit (0); | |||
1868 | } | |||
1869 | } | |||
1870 | ||||
1871 | if (!quiet) | |||
1872 | printf("new filesystem size is: %jd frags\n", | |||
1873 | (intmax_t)sblockfsun1.fs.fs_size); | |||
1874 | ||||
1875 | /* | |||
1876 | * Try to access our new last sector in the filesystem. Even if we | |||
1877 | * later on realize we have to abort our operation, on that sector | |||
1878 | * there should be no data, so we can't destroy something yet. | |||
1879 | */ | |||
1880 | lastsector = calloc(1, lp->d_secsize); | |||
1881 | if (!lastsector) | |||
1882 | err(1, "No memory for last sector test write"); | |||
1883 | wtfs(DL_SECTOBLK(lp, DL_GETPSIZE(pp) - 1)(((((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size ) - 1) * ((lp)->d_secsize / (1 << 9))), lp->d_secsize, | |||
1884 | lastsector, fso, Nflag); | |||
1885 | free(lastsector); | |||
1886 | ||||
1887 | /* | |||
1888 | * Now calculate new superblock values and check for reasonable | |||
1889 | * bound for new filesystem size: | |||
1890 | * fs_size: is derived from label or user input | |||
1891 | * fs_dsize: should get updated in the routines creating or | |||
1892 | * updating the cylinder groups on the fly | |||
1893 | * fs_cstotal: should get updated in the routines creating or | |||
1894 | * updating the cylinder groups | |||
1895 | */ | |||
1896 | ||||
1897 | /* | |||
1898 | * Update the number of cylinders and cylinder groups in the file system. | |||
1899 | */ | |||
1900 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) { | |||
1901 | sblockfsun1.fs.fs_ncyl = sblockfsun1.fs.fs_size * NSPF(&sblock)((&fsun1.fs)->fs_nspf) / sblockfsun1.fs.fs_spc; | |||
1902 | if (sblockfsun1.fs.fs_size * NSPF(&sblock)((&fsun1.fs)->fs_nspf) > | |||
1903 | sblockfsun1.fs.fs_ncyl * sblockfsun1.fs.fs_spc) | |||
1904 | sblockfsun1.fs.fs_ncyl++; | |||
1905 | } | |||
1906 | sblockfsun1.fs.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg)(((fsun1.fs.fs_size) + ((fsun1.fs.fs_fpg) - 1)) / (fsun1.fs.fs_fpg )); | |||
1907 | if ((ino_t)sblockfsun1.fs.fs_ncg * sblockfsun1.fs.fs_ipg > UINT_MAX0xffffffffU) | |||
1908 | errx(1, "more than 2^32 inodes requested"); | |||
1909 | maxino = sblockfsun1.fs.fs_ncg * sblockfsun1.fs.fs_ipg; | |||
1910 | ||||
1911 | if (sblockfsun1.fs.fs_size % sblockfsun1.fs.fs_fpg != 0 && | |||
1912 | sblockfsun1.fs.fs_size % sblockfsun1.fs.fs_fpg < cgdmin(&sblock, sblock.fs_ncg)((((daddr_t)(&fsun1.fs)->fs_fpg * (fsun1.fs.fs_ncg)) + (&fsun1.fs)->fs_cgoffset * ((fsun1.fs.fs_ncg) & ~ ((&fsun1.fs)->fs_cgmask))) + (&fsun1.fs)->fs_dblkno )) { | |||
1913 | /* | |||
1914 | * The space in the new last cylinder group is too small, | |||
1915 | * so revert back. | |||
1916 | */ | |||
1917 | sblockfsun1.fs.fs_ncg--; | |||
1918 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) | |||
1919 | sblockfsun1.fs.fs_ncyl = sblockfsun1.fs.fs_ncg * sblockfsun1.fs.fs_cpg; | |||
1920 | if (!quiet) | |||
1921 | printf("Warning: %jd sector(s) cannot be allocated.\n", | |||
1922 | (intmax_t)fsbtodb(&sblock,((fsun1.fs.fs_size % fsun1.fs.fs_fpg) << (&fsun1.fs )->fs_fsbtodb) | |||
1923 | sblock.fs_size % sblock.fs_fpg)((fsun1.fs.fs_size % fsun1.fs.fs_fpg) << (&fsun1.fs )->fs_fsbtodb)); | |||
1924 | sblockfsun1.fs.fs_size = sblockfsun1.fs.fs_ncg * sblockfsun1.fs.fs_fpg; | |||
1925 | } | |||
1926 | ||||
1927 | /* | |||
1928 | * Update the space for the cylinder group summary information in the | |||
1929 | * respective cylinder group data area. | |||
1930 | */ | |||
1931 | sblockfsun1.fs.fs_cssize = | |||
1932 | fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum))(((fsun1.fs.fs_ncg * sizeof(struct csum)) + (&fsun1.fs)-> fs_qfmask) & (&fsun1.fs)->fs_fmask); | |||
1933 | ||||
1934 | if (osblockfsun2.fs.fs_size >= sblockfsun1.fs.fs_size) | |||
1935 | errx(1, "not enough new space"); | |||
1936 | ||||
1937 | /* | |||
1938 | * Ok, everything prepared, so now let's do the tricks. | |||
1939 | */ | |||
1940 | growfs(fsi, fso, Nflag); | |||
1941 | ||||
1942 | /* | |||
1943 | * Update the disk label. | |||
1944 | */ | |||
1945 | pp->p_fragblock = | |||
1946 | DISKLABELV1_FFS_FRAGBLOCK(sblock.fs_fsize, sblock.fs_frag)((fsun1.fs.fs_fsize) * (fsun1.fs.fs_frag) == 0 ? 0 : (((ffs(( fsun1.fs.fs_fsize) * (fsun1.fs.fs_frag)) - 13) << 3) | ( ffs(fsun1.fs.fs_frag)))); | |||
1947 | pp->p_cpg = sblockfsun1.fs.fs_fpg; | |||
1948 | ||||
1949 | return_disklabel(fso, lp, Nflag); | |||
1950 | ||||
1951 | close(fsi); | |||
1952 | if (fso > -1) | |||
1953 | close(fso); | |||
1954 | ||||
1955 | return 0; | |||
1956 | } | |||
1957 | ||||
1958 | /* | |||
1959 | * Write the updated disklabel back to disk. | |||
1960 | */ | |||
1961 | static void | |||
1962 | return_disklabel(int fd, struct disklabel *lp, unsigned int Nflag) | |||
1963 | { | |||
1964 | u_short sum; | |||
1965 | u_short *ptr; | |||
1966 | ||||
1967 | if (!lp) | |||
1968 | return; | |||
1969 | ||||
1970 | if (!Nflag) { | |||
1971 | lp->d_checksum = 0; | |||
1972 | sum = 0; | |||
1973 | ptr = (u_short *)lp; | |||
1974 | ||||
1975 | /* | |||
1976 | * recalculate checksum | |||
1977 | */ | |||
1978 | while (ptr < (u_short *)&lp->d_partitions[lp->d_npartitions]) | |||
1979 | sum ^= *ptr++; | |||
1980 | lp->d_checksum = sum; | |||
1981 | ||||
1982 | if (ioctl(fd, DIOCWDINFO((unsigned long)0x80000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((103))), (char *)lp) == -1) | |||
1983 | errx(1, "DIOCWDINFO failed"); | |||
1984 | } | |||
1985 | free(lp); | |||
1986 | ||||
1987 | return ; | |||
1988 | } | |||
1989 | ||||
1990 | /* | |||
1991 | * Read the disklabel from disk. | |||
1992 | */ | |||
1993 | static struct disklabel * | |||
1994 | get_disklabel(int fd) | |||
1995 | { | |||
1996 | static struct disklabel *lab; | |||
1997 | ||||
1998 | lab = malloc(sizeof(struct disklabel)); | |||
1999 | if (!lab) | |||
2000 | errx(1, "malloc failed"); | |||
2001 | if (ioctl(fd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (char *)lab) != 0) | |||
2002 | err(1, "DIOCGDINFO"); | |||
2003 | ||||
2004 | return (lab); | |||
2005 | } | |||
2006 | ||||
2007 | ||||
2008 | /* | |||
2009 | * Dump a line of usage. | |||
2010 | */ | |||
2011 | static void | |||
2012 | usage(void) | |||
2013 | { | |||
2014 | fprintf(stderr(&__sF[2]), "usage: growfs [-Nqy] [-s size] special\n"); | |||
2015 | exit(1); | |||
2016 | } | |||
2017 | ||||
2018 | /* | |||
2019 | * This updates most parameters and the bitmap related to cluster. We have to | |||
2020 | * assume that sblock, osblock, acg are set up. | |||
2021 | */ | |||
2022 | static void | |||
2023 | updclst(int block) | |||
2024 | { | |||
2025 | static int lcs = 0; | |||
2026 | ||||
2027 | if (sblockfsun1.fs.fs_contigsumsize < 1) /* no clustering */ | |||
2028 | return; | |||
2029 | ||||
2030 | /* | |||
2031 | * update cluster allocation map | |||
2032 | */ | |||
2033 | setbit(cg_clustersfree(&acg), block)((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg) ->cg_clusteroff)))[(block)>>3] |= 1<<((block)& (8 -1))); | |||
2034 | ||||
2035 | /* | |||
2036 | * update cluster summary table | |||
2037 | */ | |||
2038 | if (!lcs) { | |||
2039 | /* | |||
2040 | * calculate size for the trailing cluster | |||
2041 | */ | |||
2042 | for (block--; lcs < sblockfsun1.fs.fs_contigsumsize; block--, lcs++) { | |||
2043 | if (isclr(cg_clustersfree(&acg), block)(((((u_int8_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg )->cg_clusteroff)))[(block)>>3] & (1<<((block )&(8 -1)))) == 0)) | |||
2044 | break; | |||
2045 | } | |||
2046 | } | |||
2047 | if (lcs < sblockfsun1.fs.fs_contigsumsize) { | |||
2048 | if (lcs) | |||
2049 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]--; | |||
2050 | lcs++; | |||
2051 | cg_clustersum(&acg)((int32_t *)((u_int8_t *)(&cgun1.cg) + (&cgun1.cg)-> cg_clustersumoff))[lcs]++; | |||
2052 | } | |||
2053 | } | |||
2054 | ||||
2055 | /* | |||
2056 | * This updates all references to relocated blocks for the given inode. The | |||
2057 | * inode is given as number within the cylinder group, and the number of the | |||
2058 | * cylinder group. | |||
2059 | */ | |||
2060 | static void | |||
2061 | updrefs(int cg, ino_t in, struct gfs_bpp *bp, int fsi, int fso, unsigned int | |||
2062 | Nflag) | |||
2063 | { | |||
2064 | daddr_t len, lbn, numblks; | |||
2065 | daddr_t iptr, blksperindir; | |||
2066 | union dinode *ino; | |||
2067 | int i, mode, inodeupdated; | |||
2068 | ||||
2069 | ino = ginode(in, fsi, cg); | |||
2070 | if (ino == NULL((void *)0)) | |||
2071 | return; | |||
2072 | ||||
2073 | mode = DIP(ino, di_mode)((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(ino)->dp1.di_mode : (ino)->dp2.di_mode) & IFMT0170000; | |||
2074 | if (mode != IFDIR0040000 && mode != IFREG0100000 && mode != IFLNK0120000) | |||
2075 | return; /* only check DIR, FILE, LINK */ | |||
2076 | if (mode == IFLNK0120000 && | |||
2077 | DIP(ino, di_size)((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(ino)->dp1.di_size : (ino)->dp2.di_size) < (u_int64_t) sblockfsun1.fs.fs_maxsymlinklen) | |||
2078 | return; /* skip short symlinks */ | |||
2079 | numblks = howmany(DIP(ino, di_size), sblock.fs_bsize)(((((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(ino)->dp1 .di_size : (ino)->dp2.di_size)) + ((fsun1.fs.fs_bsize) - 1 )) / (fsun1.fs.fs_bsize)); | |||
2080 | if (numblks == 0) | |||
2081 | return; /* skip empty file */ | |||
2082 | if (DIP(ino, di_blocks)((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(ino)->dp1.di_blocks : (ino)->dp2.di_blocks) == 0) | |||
2083 | return; /* skip empty swiss cheesy file or old fastlink */ | |||
2084 | ||||
2085 | /* | |||
2086 | * Check all the blocks. | |||
2087 | */ | |||
2088 | inodeupdated = 0; | |||
2089 | len = numblks < NDADDR12 ? numblks : NDADDR12; | |||
2090 | for (i = 0; i < len; i++) { | |||
2091 | iptr = DIP(ino, di_db[i])((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(ino)->dp1.di_db [i] : (ino)->dp2.di_db[i]); | |||
2092 | if (iptr == 0) | |||
2093 | continue; | |||
2094 | if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { | |||
2095 | DIP_SET(ino, di_db[i], iptr)do { if (fsun1.fs.fs_magic == 0x011954) (ino)->dp1.di_db[i ] = (iptr); else (ino)->dp2.di_db[i] = (iptr); } while (0); | |||
2096 | inodeupdated++; | |||
2097 | } | |||
2098 | } | |||
2099 | ||||
2100 | blksperindir = 1; | |||
2101 | len = numblks - NDADDR12; | |||
2102 | lbn = NDADDR12; | |||
2103 | for (i = 0; len > 0 && i < NIADDR3; i++) { | |||
2104 | iptr = DIP(ino, di_ib[i])((fsun1.fs.fs_magic == 0x011954) ? (uint32_t)(ino)->dp1.di_ib [i] : (ino)->dp2.di_ib[i]); | |||
2105 | if (iptr == 0) | |||
2106 | continue; | |||
2107 | if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { | |||
2108 | DIP_SET(ino, di_ib[i], iptr)do { if (fsun1.fs.fs_magic == 0x011954) (ino)->dp1.di_ib[i ] = (iptr); else (ino)->dp2.di_ib[i] = (iptr); } while (0); | |||
2109 | inodeupdated++; | |||
2110 | } | |||
2111 | indirchk(blksperindir, lbn, iptr, numblks, bp, fsi, fso, Nflag); | |||
2112 | blksperindir *= NINDIR(&sblock)((&fsun1.fs)->fs_nindir); | |||
2113 | lbn += blksperindir; | |||
2114 | len -= blksperindir; | |||
2115 | } | |||
2116 | if (inodeupdated) | |||
2117 | wtfs(inoblk, sblockfsun1.fs.fs_bsize, inobuf, fso, Nflag); | |||
2118 | } | |||
2119 | ||||
2120 | /* | |||
2121 | * Recursively check all the indirect blocks. | |||
2122 | */ | |||
2123 | static void | |||
2124 | indirchk(daddr_t blksperindir, daddr_t lbn, daddr_t blkno, | |||
2125 | daddr_t lastlbn, struct gfs_bpp *bp, int fsi, int fso, unsigned int Nflag) | |||
2126 | { | |||
2127 | void *ibuf; | |||
2128 | int i, last; | |||
2129 | daddr_t iptr; | |||
2130 | ||||
2131 | /* read in the indirect block. */ | |||
2132 | ibuf = malloc(sblockfsun1.fs.fs_bsize); | |||
2133 | if (!ibuf) | |||
2134 | errx(1, "malloc failed"); | |||
2135 | rdfs(fsbtodb(&sblock, blkno)((blkno) << (&fsun1.fs)->fs_fsbtodb), (size_t)sblockfsun1.fs.fs_bsize, ibuf, fsi); | |||
2136 | last = howmany(lastlbn - lbn, blksperindir)(((lastlbn - lbn) + ((blksperindir) - 1)) / (blksperindir)) < NINDIR(&sblock)((&fsun1.fs)->fs_nindir) ? | |||
2137 | howmany(lastlbn - lbn, blksperindir)(((lastlbn - lbn) + ((blksperindir) - 1)) / (blksperindir)) : NINDIR(&sblock)((&fsun1.fs)->fs_nindir); | |||
2138 | for (i = 0; i < last; i++) { | |||
2139 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) | |||
2140 | iptr = ((int32_t *)ibuf)[i]; | |||
2141 | else | |||
2142 | iptr = ((daddr_t *)ibuf)[i]; | |||
2143 | if (iptr == 0) | |||
2144 | continue; | |||
2145 | if (cond_bl_upd(&iptr, bp, fsi, fso, Nflag)) { | |||
2146 | if (sblockfsun1.fs.fs_magic == FS_UFS1_MAGIC0x011954) | |||
2147 | ((int32_t *)ibuf)[i] = iptr; | |||
2148 | else | |||
2149 | ((daddr_t *)ibuf)[i] = iptr; | |||
2150 | } | |||
2151 | if (blksperindir == 1) | |||
2152 | continue; | |||
2153 | indirchk(blksperindir / NINDIR(&sblock)((&fsun1.fs)->fs_nindir), lbn + blksperindir * i, | |||
2154 | iptr, lastlbn, bp, fsi, fso, Nflag); | |||
2155 | } | |||
2156 | free(ibuf); | |||
2157 | } | |||
2158 | ||||
2159 | static void | |||
2160 | ffs1_sb_update(struct fs *fs, daddr_t sbloc) | |||
2161 | { | |||
2162 | fs->fs_flags = fs->fs_ffs1_flags; | |||
2163 | fs->fs_sblockloc = sbloc; | |||
2164 | fs->fs_maxbsize = fs->fs_bsize; | |||
2165 | fs->fs_time = fs->fs_ffs1_time; | |||
2166 | fs->fs_size = fs->fs_ffs1_size; | |||
2167 | fs->fs_dsize = fs->fs_ffs1_dsize; | |||
2168 | fs->fs_csaddr = fs->fs_ffs1_csaddr; | |||
2169 | fs->fs_cstotal.cs_ndir = fs->fs_ffs1_cstotal.cs_ndir; | |||
2170 | fs->fs_cstotal.cs_nbfree = fs->fs_ffs1_cstotal.cs_nbfree; | |||
2171 | fs->fs_cstotal.cs_nifree = fs->fs_ffs1_cstotal.cs_nifree; | |||
2172 | fs->fs_cstotal.cs_nffree = fs->fs_ffs1_cstotal.cs_nffree; | |||
2173 | fs->fs_ffs1_flags |= FS_FLAGS_UPDATED0x80; | |||
2174 | } |