1 |
|
|
/* $OpenBSD: growfs.c,v 1.51 2016/05/28 20:40:23 tb 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)) |
68 |
|
|
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) |
69 |
|
|
|
70 |
|
|
#define rounddown(x, y) (((x)/(y))*(y)) |
71 |
|
|
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) |
72 |
|
|
|
73 |
|
|
static int quiet; /* quiet flag */ |
74 |
|
|
|
75 |
|
|
static union { |
76 |
|
|
struct fs fs; |
77 |
|
|
char pad[SBLOCKSIZE]; |
78 |
|
|
} fsun1, fsun2; |
79 |
|
|
#define sblock fsun1.fs /* the new superblock */ |
80 |
|
|
#define osblock fsun2.fs /* the old superblock */ |
81 |
|
|
|
82 |
|
|
/* |
83 |
|
|
* Possible superblock locations ordered from most to least likely. |
84 |
|
|
*/ |
85 |
|
|
static int sblock_try[] = SBLOCKSEARCH; |
86 |
|
|
static daddr_t sblockloc; |
87 |
|
|
|
88 |
|
|
static union { |
89 |
|
|
struct cg cg; |
90 |
|
|
char pad[MAXBSIZE]; |
91 |
|
|
} cgun1, cgun2; |
92 |
|
|
#define acg cgun1.cg /* a cylinder cgroup (new) */ |
93 |
|
|
#define aocg cgun2.cg /* an old cylinder group */ |
94 |
|
|
|
95 |
|
|
static char ablk[MAXBSIZE]; /* 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) \ |
104 |
|
|
((sblock.fs_magic == FS_UFS1_MAGIC) ? \ |
105 |
|
|
(uint32_t)(dp)->dp1.field : (dp)->dp2.field) |
106 |
|
|
#define DIP_SET(dp, field, val) do { \ |
107 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) \ |
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]; /* 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_FIRST 1 |
125 |
|
|
#define GFS_FL_LAST 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(int, time_t, int, unsigned int); |
140 |
|
|
static void updjcg(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; |
171 |
|
|
int cylno, j; |
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)sblock.fs_cssize); |
181 |
|
|
if (fscs == NULL) |
182 |
|
|
errx(1, "calloc failed"); |
183 |
|
|
for (i = 0; i < osblock.fs_cssize; i += osblock.fs_bsize) { |
184 |
|
|
rdfs(fsbtodb(&osblock, osblock.fs_csaddr + |
185 |
|
|
numfrags(&osblock, i)), (size_t)MINIMUM(osblock.fs_cssize - i, |
186 |
|
|
osblock.fs_bsize), (void *)(((char *)fscs)+i), fsi); |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
/* |
190 |
|
|
* Do all needed changes in the former last cylinder group. |
191 |
|
|
*/ |
192 |
|
|
updjcg(osblock.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)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, |
200 |
|
|
(intmax_t)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, |
201 |
|
|
sblock.fs_fsize); |
202 |
|
|
printf("\tusing %d cylinder groups of %.2fMB, %d blks, %d inodes.\n", |
203 |
|
|
sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, |
204 |
|
|
sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); |
205 |
|
|
if (sblock.fs_flags & FS_DOSOFTDEP) |
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 (cylno = osblock.fs_ncg; cylno < sblock.fs_ncg; cylno++) { |
221 |
|
|
initcg(cylno, utime, fso, Nflag); |
222 |
|
|
if (quiet) |
223 |
|
|
continue; |
224 |
|
|
j = snprintf(tmpbuf, sizeof(tmpbuf), " %lld%s", |
225 |
|
|
fsbtodb(&sblock, cgsblock(&sblock, cylno)), |
226 |
|
|
cylno < (sblock.fs_ncg - 1) ? "," : ""); |
227 |
|
|
if (j >= sizeof(tmpbuf)) |
228 |
|
|
j = sizeof(tmpbuf) - 1; |
229 |
|
|
if (j == -1 || i + j >= colwidth) { |
230 |
|
|
printf("\n"); |
231 |
|
|
i = 0; |
232 |
|
|
} |
233 |
|
|
i += j; |
234 |
|
|
printf("%s", tmpbuf); |
235 |
|
|
fflush(stdout); |
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 < sblock.fs_cssize; i += sblock.fs_bsize) { |
250 |
|
|
wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), |
251 |
|
|
(size_t)MINIMUM(sblock.fs_cssize - i, sblock.fs_bsize), |
252 |
|
|
(void *)(((char *)fscs) + i), fso, Nflag); |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
/* |
256 |
|
|
* Now write the new superblock back to disk. |
257 |
|
|
*/ |
258 |
|
|
sblock.fs_time = utime; |
259 |
|
|
sblock.fs_clean = 0; |
260 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) { |
261 |
|
|
sblock.fs_ffs1_time = (int32_t)sblock.fs_time; |
262 |
|
|
sblock.fs_ffs1_size = (int32_t)sblock.fs_size; |
263 |
|
|
sblock.fs_ffs1_dsize = (int32_t)sblock.fs_dsize; |
264 |
|
|
sblock.fs_ffs1_csaddr = (int32_t)sblock.fs_csaddr; |
265 |
|
|
sblock.fs_ffs1_cstotal.cs_ndir = |
266 |
|
|
(int32_t)sblock.fs_cstotal.cs_ndir; |
267 |
|
|
sblock.fs_ffs1_cstotal.cs_nbfree = |
268 |
|
|
(int32_t)sblock.fs_cstotal.cs_nbfree; |
269 |
|
|
sblock.fs_ffs1_cstotal.cs_nifree = |
270 |
|
|
(int32_t)sblock.fs_cstotal.cs_nifree; |
271 |
|
|
sblock.fs_ffs1_cstotal.cs_nffree = |
272 |
|
|
(int32_t)sblock.fs_cstotal.cs_nffree; |
273 |
|
|
} |
274 |
|
|
wtfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&sblock, fso, Nflag); |
275 |
|
|
|
276 |
|
|
/* |
277 |
|
|
* Clean up the dynamic fields in our superblock copies. |
278 |
|
|
*/ |
279 |
|
|
sblock.fs_fmod = 0; |
280 |
|
|
sblock.fs_clean = 1; |
281 |
|
|
sblock.fs_ronly = 0; |
282 |
|
|
sblock.fs_cgrotor = 0; |
283 |
|
|
sblock.fs_state = 0; |
284 |
|
|
memset(&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt)); |
285 |
|
|
sblock.fs_flags &= FS_DOSOFTDEP; |
286 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) |
287 |
|
|
sblock.fs_ffs1_flags &= FS_DOSOFTDEP; |
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 (cylno = 0; cylno < sblock.fs_ncg; cylno++) { |
314 |
|
|
wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), |
315 |
|
|
(size_t)SBLOCKSIZE, (void *)&sblock, 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(int cylno, 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 (sblock.fs_bsize < SBLOCKSIZE) |
338 |
|
|
iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; |
339 |
|
|
else |
340 |
|
|
iobufsize = 4 * sblock.fs_bsize; |
341 |
|
|
|
342 |
|
|
if (iobuf == NULL && (iobuf = malloc(iobufsize)) == NULL) |
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, cylno); |
352 |
|
|
dmax = cbase + sblock.fs_fpg; |
353 |
|
|
if (dmax > sblock.fs_size) |
354 |
|
|
dmax = sblock.fs_size; |
355 |
|
|
dlower = cgsblock(&sblock, cylno) - cbase; |
356 |
|
|
dupper = cgdmin(&sblock, cylno) - cbase; |
357 |
|
|
if (cylno == 0) /* XXX fscs may be relocated */ |
358 |
|
|
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); |
359 |
|
|
cs = &fscs[cylno]; |
360 |
|
|
memset(&acg, 0, sblock.fs_cgsize); |
361 |
|
|
acg.cg_ffs2_time = utime; |
362 |
|
|
acg.cg_magic = CG_MAGIC; |
363 |
|
|
acg.cg_cgx = cylno; |
364 |
|
|
acg.cg_ffs2_niblk = sblock.fs_ipg; |
365 |
|
|
acg.cg_initediblk = MINIMUM(sblock.fs_ipg, 2 * INOPB(&sblock)); |
366 |
|
|
acg.cg_ndblk = dmax - cbase; |
367 |
|
|
if (sblock.fs_contigsumsize > 0) |
368 |
|
|
acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; |
369 |
|
|
start = sizeof(struct cg); |
370 |
|
|
if (sblock.fs_magic == FS_UFS2_MAGIC) { |
371 |
|
|
acg.cg_iusedoff = start; |
372 |
|
|
} else { |
373 |
|
|
if (cylno == sblock.fs_ncg - 1) |
374 |
|
|
acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; |
375 |
|
|
else |
376 |
|
|
acg.cg_ncyl = sblock.fs_cpg; |
377 |
|
|
acg.cg_time = (int32_t)acg.cg_ffs2_time; |
378 |
|
|
acg.cg_ffs2_time = 0; |
379 |
|
|
acg.cg_niblk = (int16_t)acg.cg_ffs2_niblk; |
380 |
|
|
acg.cg_ffs2_niblk = 0; |
381 |
|
|
acg.cg_initediblk = 0; |
382 |
|
|
acg.cg_btotoff = start; |
383 |
|
|
acg.cg_boff = acg.cg_btotoff + |
384 |
|
|
sblock.fs_cpg * sizeof(int32_t); |
385 |
|
|
acg.cg_iusedoff = acg.cg_boff + |
386 |
|
|
sblock.fs_cpg * sizeof(u_int16_t); |
387 |
|
|
} |
388 |
|
|
acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); |
389 |
|
|
acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT); |
390 |
|
|
if (sblock.fs_contigsumsize > 0) { |
391 |
|
|
acg.cg_clustersumoff = |
392 |
|
|
roundup(acg.cg_nextfreeoff, sizeof(u_int32_t)); |
393 |
|
|
acg.cg_clustersumoff -= sizeof(u_int32_t); |
394 |
|
|
acg.cg_clusteroff = acg.cg_clustersumoff + |
395 |
|
|
(sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); |
396 |
|
|
acg.cg_nextfreeoff = acg.cg_clusteroff + |
397 |
|
|
howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); |
398 |
|
|
} |
399 |
|
|
if (acg.cg_nextfreeoff > sblock.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 |
|
|
acg.cg_cs.cs_nifree += sblock.fs_ipg; |
407 |
|
|
if (cylno == 0) { |
408 |
|
|
for (i = 0; i < ROOTINO; i++) { |
409 |
|
|
setbit(cg_inosused(&acg), i); |
410 |
|
|
acg.cg_cs.cs_nifree--; |
411 |
|
|
} |
412 |
|
|
} |
413 |
|
|
if (cylno > 0) { |
414 |
|
|
/* |
415 |
|
|
* In cylno 0, beginning space is reserved |
416 |
|
|
* for boot and super blocks. |
417 |
|
|
*/ |
418 |
|
|
for (d = 0; d < dlower; d += sblock.fs_frag) { |
419 |
|
|
blkno = d / sblock.fs_frag; |
420 |
|
|
setblock(&sblock, cg_blksfree(&acg), blkno); |
421 |
|
|
if (sblock.fs_contigsumsize > 0) |
422 |
|
|
setbit(cg_clustersfree(&acg), blkno); |
423 |
|
|
acg.cg_cs.cs_nbfree++; |
424 |
|
|
} |
425 |
|
|
sblock.fs_dsize += dlower; |
426 |
|
|
} |
427 |
|
|
sblock.fs_dsize += acg.cg_ndblk - dupper; |
428 |
|
|
if ((i = dupper % sblock.fs_frag)) { |
429 |
|
|
acg.cg_frsum[sblock.fs_frag - i]++; |
430 |
|
|
for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { |
431 |
|
|
setbit(cg_blksfree(&acg), dupper); |
432 |
|
|
acg.cg_cs.cs_nffree++; |
433 |
|
|
} |
434 |
|
|
} |
435 |
|
|
for (d = dupper; d + sblock.fs_frag <= acg.cg_ndblk; |
436 |
|
|
d += sblock.fs_frag) { |
437 |
|
|
blkno = d / sblock.fs_frag; |
438 |
|
|
setblock(&sblock, cg_blksfree(&acg), blkno); |
439 |
|
|
if (sblock.fs_contigsumsize > 0) |
440 |
|
|
setbit(cg_clustersfree(&acg), blkno); |
441 |
|
|
acg.cg_cs.cs_nbfree++; |
442 |
|
|
} |
443 |
|
|
if (d < acg.cg_ndblk) { |
444 |
|
|
acg.cg_frsum[acg.cg_ndblk - d]++; |
445 |
|
|
for (; d < acg.cg_ndblk; d++) { |
446 |
|
|
setbit(cg_blksfree(&acg), d); |
447 |
|
|
acg.cg_cs.cs_nffree++; |
448 |
|
|
} |
449 |
|
|
} |
450 |
|
|
if (sblock.fs_contigsumsize > 0) { |
451 |
|
|
int32_t *sump = cg_clustersum(&acg); |
452 |
|
|
u_char *mapp = cg_clustersfree(&acg); |
453 |
|
|
int map = *mapp++; |
454 |
|
|
int bit = 1; |
455 |
|
|
int run = 0; |
456 |
|
|
|
457 |
|
|
for (i = 0; i < acg.cg_nclusterblks; i++) { |
458 |
|
|
if ((map & bit) != 0) |
459 |
|
|
run++; |
460 |
|
|
else if (run != 0) { |
461 |
|
|
if (run > sblock.fs_contigsumsize) |
462 |
|
|
run = sblock.fs_contigsumsize; |
463 |
|
|
sump[run]++; |
464 |
|
|
run = 0; |
465 |
|
|
} |
466 |
|
|
if ((i & (CHAR_BIT - 1)) != CHAR_BIT - 1) |
467 |
|
|
bit <<= 1; |
468 |
|
|
else { |
469 |
|
|
map = *mapp++; |
470 |
|
|
bit = 1; |
471 |
|
|
} |
472 |
|
|
} |
473 |
|
|
if (run != 0) { |
474 |
|
|
if (run > sblock.fs_contigsumsize) |
475 |
|
|
run = sblock.fs_contigsumsize; |
476 |
|
|
sump[run]++; |
477 |
|
|
} |
478 |
|
|
} |
479 |
|
|
sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir; |
480 |
|
|
sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree; |
481 |
|
|
sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree; |
482 |
|
|
sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree; |
483 |
|
|
*cs = acg.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(&sblock, iobuf, SBLOCKSIZE); |
490 |
|
|
start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE; |
491 |
|
|
bcopy(&acg, &iobuf[start], sblock.fs_cgsize); |
492 |
|
|
start += sblock.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)); i != 0; i--) { |
496 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) { |
497 |
|
|
dp1->di_gen = arc4random(); |
498 |
|
|
dp1++; |
499 |
|
|
} else { |
500 |
|
|
dp2->di_gen = arc4random(); |
501 |
|
|
dp2++; |
502 |
|
|
} |
503 |
|
|
} |
504 |
|
|
wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, |
505 |
|
|
iobuf, fso, Nflag); |
506 |
|
|
|
507 |
|
|
/* Initialize inodes for FFS1. */ |
508 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) { |
509 |
|
|
for (i = 2 * sblock.fs_frag; i < sblock.fs_ipg / INOPF(&sblock); |
510 |
|
|
i += sblock.fs_frag) { |
511 |
|
|
dp1 = (struct ufs1_dinode *)&iobuf[start]; |
512 |
|
|
for (j = 0; j < INOPB(&sblock); j++) { |
513 |
|
|
dp1->di_gen = arc4random(); |
514 |
|
|
dp1++; |
515 |
|
|
} |
516 |
|
|
wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), |
517 |
|
|
(size_t)sblock.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); |
540 |
|
|
f < roundup(frag + 1, sblock.fs_frag); |
541 |
|
|
f++) { |
542 |
|
|
/* |
543 |
|
|
* Count contiguous free fragments. |
544 |
|
|
*/ |
545 |
|
|
if (isset(cg_blksfree(&acg), f)) { |
546 |
|
|
fragsize++; |
547 |
|
|
} else { |
548 |
|
|
if (fragsize && fragsize < sblock.fs_frag) { |
549 |
|
|
/* |
550 |
|
|
* We found something in between. |
551 |
|
|
*/ |
552 |
|
|
acg.cg_frsum[fragsize] += sign; |
553 |
|
|
} |
554 |
|
|
fragsize = 0; |
555 |
|
|
} |
556 |
|
|
} |
557 |
|
|
if (fragsize && fragsize < sblock.fs_frag) { |
558 |
|
|
/* |
559 |
|
|
* We found something. |
560 |
|
|
*/ |
561 |
|
|
acg.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) != f->old) |
585 |
|
|
continue; |
586 |
|
|
/* |
587 |
|
|
* The fragment is part of the block, so update. |
588 |
|
|
*/ |
589 |
|
|
dst = blkstofrags(&sblock, f->new); |
590 |
|
|
fragnum = fragnum(&sblock, src); |
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(sblock.fs_bsize); |
602 |
|
|
if (!ibuf) |
603 |
|
|
errx(1, "malloc failed"); |
604 |
|
|
src -= fragnum; |
605 |
|
|
rdfs(fsbtodb(&sblock, src), (size_t)sblock.fs_bsize, ibuf, fsi); |
606 |
|
|
wtfs(dst, (size_t)sblock.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(int cylno, 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, cylno)), |
641 |
|
|
(size_t)osblock.fs_cgsize, (void *)&aocg, 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, cylno+1) == osblock.fs_size) { |
653 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) |
654 |
|
|
acg.cg_ncyl = sblock.fs_cpg; |
655 |
|
|
|
656 |
|
|
wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), |
657 |
|
|
(size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); |
658 |
|
|
|
659 |
|
|
return; |
660 |
|
|
} |
661 |
|
|
|
662 |
|
|
/* |
663 |
|
|
* Set up some variables needed later. |
664 |
|
|
*/ |
665 |
|
|
cbase = cgbase(&sblock, cylno); |
666 |
|
|
dmax = cbase + sblock.fs_fpg; |
667 |
|
|
if (dmax > sblock.fs_size) |
668 |
|
|
dmax = sblock.fs_size; |
669 |
|
|
dupper = cgdmin(&sblock, cylno) - cbase; |
670 |
|
|
if (cylno == 0) /* XXX fscs may be relocated */ |
671 |
|
|
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); |
672 |
|
|
|
673 |
|
|
/* |
674 |
|
|
* Set pointer to the cylinder summary for our cylinder group. |
675 |
|
|
*/ |
676 |
|
|
cs = fscs + cylno; |
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 |
|
|
acg.cg_time = utime; |
683 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) { |
684 |
|
|
if (cylno == sblock.fs_ncg - 1) { |
685 |
|
|
/* |
686 |
|
|
* This is still the last cylinder group. |
687 |
|
|
*/ |
688 |
|
|
acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; |
689 |
|
|
} else { |
690 |
|
|
acg.cg_ncyl = sblock.fs_cpg; |
691 |
|
|
} |
692 |
|
|
} |
693 |
|
|
acg.cg_ndblk = dmax - cbase; |
694 |
|
|
sblock.fs_dsize += acg.cg_ndblk-aocg.cg_ndblk; |
695 |
|
|
if (sblock.fs_contigsumsize > 0) |
696 |
|
|
acg.cg_nclusterblks = acg.cg_ndblk / sblock.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 (osblock.fs_size % sblock.fs_frag) { |
711 |
|
|
if (roundup(osblock.fs_size, sblock.fs_frag) <= sblock.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) - 1; |
718 |
|
|
i >= osblock.fs_size-cbase; i--) { |
719 |
|
|
setbit(cg_blksfree(&acg), i); |
720 |
|
|
acg.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(&sblock, cg_blksfree(&acg), |
730 |
|
|
((osblock.fs_size - cgbase(&sblock, cylno))/ |
731 |
|
|
sblock.fs_frag))) { |
732 |
|
|
/* |
733 |
|
|
* The block is now completely available. |
734 |
|
|
*/ |
735 |
|
|
acg.cg_frsum[osblock.fs_size%sblock.fs_frag]--; |
736 |
|
|
acg.cg_cs.cs_nbfree++; |
737 |
|
|
acg.cg_cs.cs_nffree-=sblock.fs_frag; |
738 |
|
|
k = rounddown(osblock.fs_size-cbase, |
739 |
|
|
sblock.fs_frag); |
740 |
|
|
updclst((osblock.fs_size-cbase)/sblock.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) && |
748 |
|
|
(i >= rounddown(osblock.fs_size - cbase, |
749 |
|
|
sblock.fs_frag))) { |
750 |
|
|
i--; |
751 |
|
|
k++; |
752 |
|
|
} |
753 |
|
|
if (k) |
754 |
|
|
acg.cg_frsum[k]--; |
755 |
|
|
acg.cg_frsum[k + j]++; |
756 |
|
|
} |
757 |
|
|
} else { |
758 |
|
|
/* |
759 |
|
|
* We only grow by some fragments within this last |
760 |
|
|
* block. |
761 |
|
|
*/ |
762 |
|
|
for (i = sblock.fs_size-cbase-1; |
763 |
|
|
i >= osblock.fs_size-cbase; i--) { |
764 |
|
|
setbit(cg_blksfree(&acg), i); |
765 |
|
|
acg.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) && |
773 |
|
|
(i >= rounddown(osblock.fs_size - cbase, |
774 |
|
|
sblock.fs_frag))) { |
775 |
|
|
i--; |
776 |
|
|
k++; |
777 |
|
|
} |
778 |
|
|
if (k) |
779 |
|
|
acg.cg_frsum[k]--; |
780 |
|
|
acg.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); |
788 |
|
|
i + sblock.fs_frag <= dmax-cbase; /* XXX <= or only < ? */ |
789 |
|
|
i += sblock.fs_frag) { |
790 |
|
|
j = i / sblock.fs_frag; |
791 |
|
|
setblock(&sblock, cg_blksfree(&acg), j); |
792 |
|
|
updclst(j); |
793 |
|
|
acg.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 |
|
|
acg.cg_frsum[dmax - cbase - i]++; |
803 |
|
|
for (; i < dmax - cbase; i++) { |
804 |
|
|
setbit(cg_blksfree(&acg), i); |
805 |
|
|
acg.cg_cs.cs_nffree++; |
806 |
|
|
} |
807 |
|
|
} |
808 |
|
|
|
809 |
|
|
sblock.fs_cstotal.cs_nffree += |
810 |
|
|
(acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree); |
811 |
|
|
sblock.fs_cstotal.cs_nbfree += |
812 |
|
|
(acg.cg_cs.cs_nbfree - aocg.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 = acg.cg_cs; |
821 |
|
|
|
822 |
|
|
/* |
823 |
|
|
* Write the updated "joining" cylinder group back to disk. |
824 |
|
|
*/ |
825 |
|
|
wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), (size_t)sblock.fs_cgsize, |
826 |
|
|
(void *)&acg, 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 |
|
|
int cylno, 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) == |
860 |
|
|
howmany(osblock.fs_cssize, osblock.fs_fsize)) { |
861 |
|
|
/* |
862 |
|
|
* No new fragment needed. |
863 |
|
|
*/ |
864 |
|
|
return; |
865 |
|
|
} |
866 |
|
|
ocscg = dtog(&osblock, osblock.fs_csaddr); |
867 |
|
|
cs = fscs + ocscg; |
868 |
|
|
blocks = 1+howmany(sblock.fs_cssize, sblock.fs_bsize)- |
869 |
|
|
howmany(osblock.fs_cssize, osblock.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)), |
878 |
|
|
(size_t)osblock.fs_cgsize, (void *)&aocg, 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 |
|
|
acg.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 (sblock.fs_ncg-osblock.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 = osblock.fs_csaddr + (osblock.fs_cssize / osblock.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 (sblock.fs_contigsumsize > 0) { |
929 |
|
|
for (block = howmany(d % sblock.fs_fpg, sblock.fs_frag), |
930 |
|
|
lcs = 0; lcs < sblock.fs_contigsumsize; |
931 |
|
|
block++, lcs++) { |
932 |
|
|
if (isclr(cg_clustersfree(&acg), block)) |
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) % sblock.fs_frag) { |
943 |
|
|
/* |
944 |
|
|
* The end of the cylinder summary is not a complete |
945 |
|
|
* block. |
946 |
|
|
*/ |
947 |
|
|
frag_adjust(d % sblock.fs_fpg, -1); |
948 |
|
|
for (; (d + 1) % sblock.fs_frag; d--) { |
949 |
|
|
setbit(cg_blksfree(&acg), d % sblock.fs_fpg); |
950 |
|
|
acg.cg_cs.cs_nffree++; |
951 |
|
|
sblock.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 % sblock.fs_fpg, 1); |
959 |
|
|
|
960 |
|
|
if (isblock(&sblock, cg_blksfree(&acg), |
961 |
|
|
(d % sblock.fs_fpg) / sblock.fs_frag)) { |
962 |
|
|
acg.cg_cs.cs_nffree -= sblock.fs_frag; |
963 |
|
|
acg.cg_cs.cs_nbfree++; |
964 |
|
|
sblock.fs_cstotal.cs_nffree -= sblock.fs_frag; |
965 |
|
|
sblock.fs_cstotal.cs_nbfree++; |
966 |
|
|
if (sblock.fs_contigsumsize > 0) { |
967 |
|
|
setbit(cg_clustersfree(&acg), |
968 |
|
|
(d % sblock.fs_fpg) / sblock.fs_frag); |
969 |
|
|
if (lcs < sblock.fs_contigsumsize) { |
970 |
|
|
if (lcs) { |
971 |
|
|
cg_clustersum(&acg) |
972 |
|
|
[lcs]--; |
973 |
|
|
} |
974 |
|
|
lcs++; |
975 |
|
|
cg_clustersum(&acg)[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 >= osblock.fs_csaddr; |
987 |
|
|
d -= sblock.fs_frag) { |
988 |
|
|
setblock(&sblock, cg_blksfree(&acg), |
989 |
|
|
(d % sblock.fs_fpg) / sblock.fs_frag); |
990 |
|
|
acg.cg_cs.cs_nbfree++; |
991 |
|
|
sblock.fs_cstotal.cs_nbfree++; |
992 |
|
|
if (sblock.fs_contigsumsize > 0) { |
993 |
|
|
setbit(cg_clustersfree(&acg), |
994 |
|
|
(d % sblock.fs_fpg) / sblock.fs_frag); |
995 |
|
|
/* |
996 |
|
|
* The last cluster size is already set up. |
997 |
|
|
*/ |
998 |
|
|
if (lcs < sblock.fs_contigsumsize) { |
999 |
|
|
if (lcs) { |
1000 |
|
|
cg_clustersum(&acg)[lcs]--; |
1001 |
|
|
} |
1002 |
|
|
lcs++; |
1003 |
|
|
cg_clustersum(&acg)[lcs]++; |
1004 |
|
|
} |
1005 |
|
|
} |
1006 |
|
|
} |
1007 |
|
|
*cs = acg.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)), |
1014 |
|
|
(size_t)sblock.fs_cgsize, (void *)&acg, fso, Nflag); |
1015 |
|
|
|
1016 |
|
|
/* |
1017 |
|
|
* Find the beginning of the new cylinder group containing the |
1018 |
|
|
* cylinder summary. |
1019 |
|
|
*/ |
1020 |
|
|
sblock.fs_csaddr = cgdmin(&sblock, osblock.fs_ncg); |
1021 |
|
|
ncscg = dtog(&sblock, sblock.fs_csaddr); |
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)), |
1038 |
|
|
(size_t)sblock.fs_cgsize, &aocg, 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 = sblock.fs_csaddr; d + sblock.fs_frag <= |
1047 |
|
|
sblock.fs_csaddr + (sblock.fs_cssize / sblock.fs_fsize); |
1048 |
|
|
d += sblock.fs_frag) { |
1049 |
|
|
clrblock(&sblock, cg_blksfree(&acg), |
1050 |
|
|
(d%sblock.fs_fpg)/sblock.fs_frag); |
1051 |
|
|
acg.cg_cs.cs_nbfree--; |
1052 |
|
|
sblock.fs_cstotal.cs_nbfree--; |
1053 |
|
|
if (sblock.fs_contigsumsize > 0) { |
1054 |
|
|
clrbit(cg_clustersfree(&acg), |
1055 |
|
|
(d % sblock.fs_fpg) / sblock.fs_frag); |
1056 |
|
|
} |
1057 |
|
|
} |
1058 |
|
|
|
1059 |
|
|
/* |
1060 |
|
|
* Allocate all fragments used by the cylinder summary in the |
1061 |
|
|
* last block. |
1062 |
|
|
*/ |
1063 |
|
|
if (d < sblock.fs_csaddr + (sblock.fs_cssize / sblock.fs_fsize)) { |
1064 |
|
|
for (; d - sblock.fs_csaddr < |
1065 |
|
|
sblock.fs_cssize/sblock.fs_fsize; |
1066 |
|
|
d++) { |
1067 |
|
|
clrbit(cg_blksfree(&acg), d%sblock.fs_fpg); |
1068 |
|
|
acg.cg_cs.cs_nffree--; |
1069 |
|
|
sblock.fs_cstotal.cs_nffree--; |
1070 |
|
|
} |
1071 |
|
|
acg.cg_cs.cs_nbfree--; |
1072 |
|
|
acg.cg_cs.cs_nffree += sblock.fs_frag; |
1073 |
|
|
sblock.fs_cstotal.cs_nbfree--; |
1074 |
|
|
sblock.fs_cstotal.cs_nffree += sblock.fs_frag; |
1075 |
|
|
if (sblock.fs_contigsumsize > 0) { |
1076 |
|
|
clrbit(cg_clustersfree(&acg), |
1077 |
|
|
(d%sblock.fs_fpg) / sblock.fs_frag); |
1078 |
|
|
} |
1079 |
|
|
|
1080 |
|
|
frag_adjust(d % sblock.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 = acg.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)), |
1102 |
|
|
(size_t)sblock.fs_cgsize, (void *)&acg, 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); /* old and new are equal */ |
1111 |
|
|
dupper = sblock.fs_csaddr - cbase + |
1112 |
|
|
howmany(sblock.fs_cssize, sblock.fs_fsize); |
1113 |
|
|
odupper = osblock.fs_csaddr - cbase + |
1114 |
|
|
howmany(osblock.fs_cssize, osblock.fs_fsize); |
1115 |
|
|
|
1116 |
|
|
sblock.fs_dsize -= dupper-odupper; |
1117 |
|
|
|
1118 |
|
|
/* |
1119 |
|
|
* Allocate the space for the array of blocks to be relocated. |
1120 |
|
|
*/ |
1121 |
|
|
bp = calloc(((dupper-odupper) / sblock.fs_frag + 2), |
1122 |
|
|
sizeof(struct gfs_bpp)); |
1123 |
|
|
if (bp == NULL) |
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 % sblock.fs_frag)); d++) { |
1137 |
|
|
if (isclr(cg_blksfree(&acg), d)) { |
1138 |
|
|
if (!ind) { |
1139 |
|
|
bp[ind].old = d / sblock.fs_frag; |
1140 |
|
|
bp[ind].flags|=GFS_FL_FIRST; |
1141 |
|
|
if (roundup(d, sblock.fs_frag) >= dupper) |
1142 |
|
|
bp[ind].flags |= GFS_FL_LAST; |
1143 |
|
|
ind++; |
1144 |
|
|
} |
1145 |
|
|
} else { |
1146 |
|
|
clrbit(cg_blksfree(&acg), d); |
1147 |
|
|
acg.cg_cs.cs_nffree--; |
1148 |
|
|
sblock.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 + sblock.fs_frag <= dupper; d += sblock.fs_frag) { |
1164 |
|
|
if (!isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag)) { |
1165 |
|
|
for (f = d; f < d + sblock.fs_frag; f++) { |
1166 |
|
|
if (isset(cg_blksfree(&aocg), f)) { |
1167 |
|
|
acg.cg_cs.cs_nffree--; |
1168 |
|
|
sblock.fs_cstotal.cs_nffree--; |
1169 |
|
|
} |
1170 |
|
|
} |
1171 |
|
|
clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag); |
1172 |
|
|
bp[ind].old = d / sblock.fs_frag; |
1173 |
|
|
ind++; |
1174 |
|
|
} else { |
1175 |
|
|
clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag); |
1176 |
|
|
acg.cg_cs.cs_nbfree--; |
1177 |
|
|
sblock.fs_cstotal.cs_nbfree--; |
1178 |
|
|
if (sblock.fs_contigsumsize > 0) { |
1179 |
|
|
clrbit(cg_clustersfree(&acg), d / sblock.fs_frag); |
1180 |
|
|
for (lcs = 0, l = (d / sblock.fs_frag) + 1; |
1181 |
|
|
lcs < sblock.fs_contigsumsize; |
1182 |
|
|
l++, lcs++) { |
1183 |
|
|
if (isclr(cg_clustersfree(&acg), l)) |
1184 |
|
|
break; |
1185 |
|
|
} |
1186 |
|
|
if (lcs < sblock.fs_contigsumsize) { |
1187 |
|
|
cg_clustersum(&acg)[lcs + 1]--; |
1188 |
|
|
if (lcs) |
1189 |
|
|
cg_clustersum(&acg)[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 < dupper) { |
1203 |
|
|
frag_adjust(dupper - 1, -1); |
1204 |
|
|
|
1205 |
|
|
if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag)) { |
1206 |
|
|
acg.cg_cs.cs_nbfree--; |
1207 |
|
|
sblock.fs_cstotal.cs_nbfree--; |
1208 |
|
|
acg.cg_cs.cs_nffree+=sblock.fs_frag; |
1209 |
|
|
sblock.fs_cstotal.cs_nffree+=sblock.fs_frag; |
1210 |
|
|
if (sblock.fs_contigsumsize > 0) { |
1211 |
|
|
clrbit(cg_clustersfree(&acg), d / sblock.fs_frag); |
1212 |
|
|
for (lcs = 0, l = (d / sblock.fs_frag) + 1; |
1213 |
|
|
lcs < sblock.fs_contigsumsize; |
1214 |
|
|
l++, lcs++) { |
1215 |
|
|
if (isclr(cg_clustersfree(&acg), l)) |
1216 |
|
|
break; |
1217 |
|
|
} |
1218 |
|
|
if (lcs < sblock.fs_contigsumsize) { |
1219 |
|
|
cg_clustersum(&acg)[lcs + 1]--; |
1220 |
|
|
if (lcs) |
1221 |
|
|
cg_clustersum(&acg)[lcs]++; |
1222 |
|
|
} |
1223 |
|
|
} |
1224 |
|
|
} |
1225 |
|
|
|
1226 |
|
|
for (; d < dupper; d++) { |
1227 |
|
|
if (isclr(cg_blksfree(&acg), d)) { |
1228 |
|
|
bp[ind].old = d / sblock.fs_frag; |
1229 |
|
|
bp[ind].flags |= GFS_FL_LAST; |
1230 |
|
|
} else { |
1231 |
|
|
clrbit(cg_blksfree(&acg), d); |
1232 |
|
|
acg.cg_cs.cs_nffree--; |
1233 |
|
|
sblock.fs_cstotal.cs_nffree--; |
1234 |
|
|
} |
1235 |
|
|
} |
1236 |
|
|
if (bp[ind].flags & GFS_FL_LAST) /* 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() / sblock.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 * sblock.fs_frag, |
1265 |
|
|
g = bp[i].new * sblock.fs_frag; |
1266 |
|
|
f < (bp[i].old + 1) * sblock.fs_frag; |
1267 |
|
|
f++, g++) { |
1268 |
|
|
if (isset(cg_blksfree(&aocg), f)) { |
1269 |
|
|
setbit(cg_blksfree(&acg), g); |
1270 |
|
|
acg.cg_cs.cs_nffree++; |
1271 |
|
|
sblock.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_FIRST) { |
1284 |
|
|
for (f = bp[i].old * sblock.fs_frag, |
1285 |
|
|
g = bp[i].new * sblock.fs_frag; |
1286 |
|
|
f < odupper; |
1287 |
|
|
f++, g++) { |
1288 |
|
|
setbit(cg_blksfree(&acg), g); |
1289 |
|
|
acg.cg_cs.cs_nffree++; |
1290 |
|
|
sblock.fs_cstotal.cs_nffree++; |
1291 |
|
|
} |
1292 |
|
|
if (!(bp[i].flags & GFS_FL_LAST)) |
1293 |
|
|
frag_adjust(bp[i].new * sblock.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_LAST) { |
1301 |
|
|
frag_adjust(bp[i].new * sblock.fs_frag, 1); |
1302 |
|
|
frag_adjust(bp[i].old * sblock.fs_frag, -1); |
1303 |
|
|
for (f = dupper; |
1304 |
|
|
f < roundup(dupper, sblock.fs_frag); |
1305 |
|
|
f++) { |
1306 |
|
|
if (isclr(cg_blksfree(&acg), f)) { |
1307 |
|
|
setbit(cg_blksfree(&acg), f); |
1308 |
|
|
acg.cg_cs.cs_nffree++; |
1309 |
|
|
sblock.fs_cstotal.cs_nffree++; |
1310 |
|
|
} |
1311 |
|
|
} |
1312 |
|
|
frag_adjust(bp[i].old * sblock.fs_frag, 1); |
1313 |
|
|
} |
1314 |
|
|
|
1315 |
|
|
/* |
1316 |
|
|
* !!! Attach the cylindergroup offset here. |
1317 |
|
|
*/ |
1318 |
|
|
bp[i].old += cbase / sblock.fs_frag; |
1319 |
|
|
bp[i].new += cbase / sblock.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), |
1329 |
|
|
(size_t)sblock.fs_bsize, (void *)&ablk, fsi); |
1330 |
|
|
wtfs(fsbtodb(&sblock, bp[i].new * sblock.fs_frag), |
1331 |
|
|
(size_t)sblock.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 (cylno = 0; cylno < osblock.fs_ncg; cylno++) { |
1341 |
|
|
for (inc = osblock.fs_ipg - 1; inc > 0; inc--) { |
1342 |
|
|
updrefs(cylno, (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 > sblock.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 = acg.cg_cs; |
1370 |
|
|
|
1371 |
|
|
/* |
1372 |
|
|
* Write summary cylinder group back to disk. |
1373 |
|
|
*/ |
1374 |
|
|
wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), (size_t)sblock.fs_cgsize, |
1375 |
|
|
(void *)&acg, 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, SEEK_SET) < 0) { |
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, SEEK_SET) < 0) |
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 (acg.cg_magic != CG_MAGIC) { |
1431 |
|
|
warnx("acg: bad magic number"); |
1432 |
|
|
return (0); |
1433 |
|
|
} |
1434 |
|
|
if (acg.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) - cgbase(&sblock, acg.cg_cgx); |
1446 |
|
|
dupper = cgdmin(&sblock, acg.cg_cgx) - cgbase(&sblock, acg.cg_cgx); |
1447 |
|
|
dmax = cgbase(&sblock, acg.cg_cgx) + sblock.fs_fpg; |
1448 |
|
|
if (dmax > sblock.fs_size) { |
1449 |
|
|
dmax = sblock.fs_size; |
1450 |
|
|
} |
1451 |
|
|
dmax -= cgbase(&sblock, acg.cg_cgx); /* retransform into cg */ |
1452 |
|
|
csmin=sblock.fs_csaddr-cgbase(&sblock, acg.cg_cgx); |
1453 |
|
|
csmax = csmin + howmany(sblock.fs_cssize, sblock.fs_fsize); |
1454 |
|
|
|
1455 |
|
|
for (d = 0; (d < dlower && blkno == -1); d += sblock.fs_frag) { |
1456 |
|
|
if (d >= csmin && d <= csmax) { |
1457 |
|
|
continue; |
1458 |
|
|
} |
1459 |
|
|
if (isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, |
1460 |
|
|
d))) { |
1461 |
|
|
blkno = fragstoblks(&sblock, d);/* Yeah found a block */ |
1462 |
|
|
break; |
1463 |
|
|
} |
1464 |
|
|
} |
1465 |
|
|
for (d = dupper; (d < dmax && blkno == -1); d += sblock.fs_frag) { |
1466 |
|
|
if (d >= csmin && d <= csmax) { |
1467 |
|
|
continue; |
1468 |
|
|
} |
1469 |
|
|
if (isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock, |
1470 |
|
|
d))) { |
1471 |
|
|
blkno = fragstoblks(&sblock, d);/* 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); |
1484 |
|
|
|
1485 |
|
|
clrblock(&sblock, cg_blksfree(&acg), blkno); |
1486 |
|
|
if (sblock.fs_contigsumsize > 0) { |
1487 |
|
|
/* |
1488 |
|
|
* Handle the cluster allocation bitmap. |
1489 |
|
|
*/ |
1490 |
|
|
clrbit(cg_clustersfree(&acg), blkno); |
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 < sblock.fs_contigsumsize; |
1499 |
|
|
l--, lcs1++) { |
1500 |
|
|
if (isclr(cg_clustersfree(&acg), l)) |
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 < sblock.fs_contigsumsize; |
1508 |
|
|
l++, lcs2++) { |
1509 |
|
|
if (isclr(cg_clustersfree(&acg), l)) |
1510 |
|
|
break; |
1511 |
|
|
} |
1512 |
|
|
|
1513 |
|
|
/* |
1514 |
|
|
* Now update all counters. |
1515 |
|
|
*/ |
1516 |
|
|
cg_clustersum(&acg)[MINIMUM(lcs1 + lcs2 + 1, sblock.fs_contigsumsize)]--; |
1517 |
|
|
if (lcs1) |
1518 |
|
|
cg_clustersum(&acg)[lcs1]++; |
1519 |
|
|
if (lcs2) |
1520 |
|
|
cg_clustersum(&acg)[lcs2]++; |
1521 |
|
|
} |
1522 |
|
|
/* |
1523 |
|
|
* Update all statistics based on blocks. |
1524 |
|
|
*/ |
1525 |
|
|
acg.cg_cs.cs_nbfree--; |
1526 |
|
|
sblock.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, "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)) { |
1630 |
|
|
return NULL; |
1631 |
|
|
} |
1632 |
|
|
/* |
1633 |
|
|
* Now make the inumber relative to the entire inode space so it can |
1634 |
|
|
* be sanity checked. |
1635 |
|
|
*/ |
1636 |
|
|
inumber += (cg * sblock.fs_ipg); |
1637 |
|
|
if (inumber < ROOTINO) { |
1638 |
|
|
return NULL; |
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)) { |
1645 |
|
|
inoblk = fsbtodb(&sblock, ino_to_fsba(&sblock, inumber)); |
1646 |
|
|
rdfs(inoblk, (size_t)sblock.fs_bsize, inobuf, fsi); |
1647 |
|
|
startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); |
1648 |
|
|
} |
1649 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) |
1650 |
|
|
return (union dinode *)((uintptr_t)inobuf + |
1651 |
|
|
(inumber % INOPB(&sblock)) * sizeof(struct ufs1_dinode)); |
1652 |
|
|
return (union dinode *)((uintptr_t)inobuf + |
1653 |
|
|
(inumber % INOPB(&sblock)) * 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) |
1670 |
|
|
columns = strtonum(cp, 1, INT_MAX, NULL); |
1671 |
|
|
if (columns == 0 && ioctl(STDOUT_FILENO, TIOCGWINSZ, &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 FSMAXSNAP |
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_MAX, &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 |
|
|
case '?': |
1739 |
|
|
/* FALLTHROUGH */ |
1740 |
|
|
default: |
1741 |
|
|
usage(); |
1742 |
|
|
} |
1743 |
|
|
} |
1744 |
|
|
argc -= optind; |
1745 |
|
|
argv += optind; |
1746 |
|
|
|
1747 |
|
|
if (argc != 1) |
1748 |
|
|
usage(); |
1749 |
|
|
|
1750 |
|
|
colwidth = charsperline(); |
1751 |
|
|
|
1752 |
|
|
/* |
1753 |
|
|
* Rather than guessing, use opendev() to get the device |
1754 |
|
|
* name, which we open for reading. |
1755 |
|
|
*/ |
1756 |
|
|
if ((fsi = opendev(*argv, O_RDONLY, 0, &device)) < 0) |
1757 |
|
|
err(1, "%s", *argv); |
1758 |
|
|
|
1759 |
|
|
/* |
1760 |
|
|
* Try to access our devices for writing ... |
1761 |
|
|
*/ |
1762 |
|
|
if (Nflag) { |
1763 |
|
|
fso = -1; |
1764 |
|
|
} else { |
1765 |
|
|
fso = open(device, O_WRONLY); |
1766 |
|
|
if (fso < 0) |
1767 |
|
|
err(1, "%s", device); |
1768 |
|
|
} |
1769 |
|
|
|
1770 |
|
|
/* |
1771 |
|
|
* Now we have a file descriptor for our device, fstat() it to |
1772 |
|
|
* figure out the partition number. |
1773 |
|
|
*/ |
1774 |
|
|
if (fstat(fsi, &st) != 0) |
1775 |
|
|
err(1, "%s: fstat()", device); |
1776 |
|
|
|
1777 |
|
|
/* |
1778 |
|
|
* Try to read a label from the disk. Then get the partition from the |
1779 |
|
|
* device minor number, using DISKPART(). Probably don't need to |
1780 |
|
|
* check against getmaxpartitions(). |
1781 |
|
|
*/ |
1782 |
|
|
lp = get_disklabel(fsi); |
1783 |
|
|
if (DISKPART(st.st_rdev) < getmaxpartitions()) |
1784 |
|
|
pp = &lp->d_partitions[DISKPART(st.st_rdev)]; |
1785 |
|
|
else |
1786 |
|
|
errx(1, "%s: invalid partition number %u", |
1787 |
|
|
device, DISKPART(st.st_rdev)); |
1788 |
|
|
|
1789 |
|
|
if (pledge("stdio disklabel flock rpath cpath wpath", NULL) == -1) |
1790 |
|
|
err(1, "pledge"); |
1791 |
|
|
|
1792 |
|
|
/* |
1793 |
|
|
* Check if that partition is suitable for growing a file system. |
1794 |
|
|
*/ |
1795 |
|
|
if (DL_GETPSIZE(pp) < 1) |
1796 |
|
|
errx(1, "partition is unavailable"); |
1797 |
|
|
if (pp->p_fstype != FS_BSDFFS) |
1798 |
|
|
errx(1, "can only grow ffs partitions"); |
1799 |
|
|
|
1800 |
|
|
/* |
1801 |
|
|
* Read the current superblock, and take a backup. |
1802 |
|
|
*/ |
1803 |
|
|
for (i = 0; sblock_try[i] != -1; i++) { |
1804 |
|
|
sblockloc = sblock_try[i] / DEV_BSIZE; |
1805 |
|
|
rdfs(sblockloc, (size_t)SBLOCKSIZE, (void *)&(osblock), fsi); |
1806 |
|
|
if ((osblock.fs_magic == FS_UFS1_MAGIC || |
1807 |
|
|
(osblock.fs_magic == FS_UFS2_MAGIC && |
1808 |
|
|
osblock.fs_sblockloc == sblock_try[i])) && |
1809 |
|
|
osblock.fs_bsize <= MAXBSIZE && |
1810 |
|
|
osblock.fs_bsize >= (int32_t) sizeof(struct fs)) |
1811 |
|
|
break; |
1812 |
|
|
} |
1813 |
|
|
if (sblock_try[i] == -1) |
1814 |
|
|
errx(1, "superblock not recognized"); |
1815 |
|
|
if (osblock.fs_clean == 0) |
1816 |
|
|
errx(1, "filesystem not clean - run fsck"); |
1817 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC && |
1818 |
|
|
(sblock.fs_ffs1_flags & FS_FLAGS_UPDATED) == 0) |
1819 |
|
|
ffs1_sb_update(&sblock, sblock_try[i]); |
1820 |
|
|
memcpy(&fsun1, &fsun2, sizeof(fsun2)); |
1821 |
|
|
maxino = sblock.fs_ncg * sblock.fs_ipg; |
1822 |
|
|
|
1823 |
|
|
/* |
1824 |
|
|
* Determine size to grow to. Default to the full size specified in |
1825 |
|
|
* the disk label. |
1826 |
|
|
*/ |
1827 |
|
|
sblock.fs_size = dbtofsb(&osblock, DL_SECTOBLK(lp, DL_GETPSIZE(pp))); |
1828 |
|
|
if (size != 0) { |
1829 |
|
|
if (size > DL_GETPSIZE(pp)) { |
1830 |
|
|
errx(1, "there is not enough space (%llu < %lld)", |
1831 |
|
|
DL_GETPSIZE(pp), size); |
1832 |
|
|
} |
1833 |
|
|
sblock.fs_size = dbtofsb(&osblock, DL_SECTOBLK(lp, size)); |
1834 |
|
|
} |
1835 |
|
|
|
1836 |
|
|
/* |
1837 |
|
|
* Are we really growing ? |
1838 |
|
|
*/ |
1839 |
|
|
if (osblock.fs_size >= sblock.fs_size) { |
1840 |
|
|
errx(1, "we are not growing (%jd->%jd)", |
1841 |
|
|
(intmax_t)osblock.fs_size, (intmax_t)sblock.fs_size); |
1842 |
|
|
} |
1843 |
|
|
|
1844 |
|
|
|
1845 |
|
|
#ifdef FSMAXSNAP |
1846 |
|
|
/* |
1847 |
|
|
* Check if we find an active snapshot. |
1848 |
|
|
*/ |
1849 |
|
|
if (ExpertFlag == 0) { |
1850 |
|
|
for (j = 0; j < FSMAXSNAP; j++) { |
1851 |
|
|
if (sblock.fs_snapinum[j]) { |
1852 |
|
|
errx(1, "active snapshot found in filesystem\n" |
1853 |
|
|
" please remove all snapshots before " |
1854 |
|
|
"using growfs"); |
1855 |
|
|
} |
1856 |
|
|
if (!sblock.fs_snapinum[j]) /* list is dense */ |
1857 |
|
|
break; |
1858 |
|
|
} |
1859 |
|
|
} |
1860 |
|
|
#endif |
1861 |
|
|
|
1862 |
|
|
if (ExpertFlag == 0 && Nflag == 0) { |
1863 |
|
|
printf("We strongly recommend you to make a backup " |
1864 |
|
|
"before growing the Filesystem\n\n" |
1865 |
|
|
" Did you backup your data (Yes/No) ? "); |
1866 |
|
|
if (fgets(reply, (int)sizeof(reply), stdin) == NULL || |
1867 |
|
|
strncasecmp(reply, "Yes", 3)) { |
1868 |
|
|
printf("\n Nothing done \n"); |
1869 |
|
|
exit (0); |
1870 |
|
|
} |
1871 |
|
|
} |
1872 |
|
|
|
1873 |
|
|
if (!quiet) |
1874 |
|
|
printf("new filesystem size is: %jd frags\n", |
1875 |
|
|
(intmax_t)sblock.fs_size); |
1876 |
|
|
|
1877 |
|
|
/* |
1878 |
|
|
* Try to access our new last sector in the filesystem. Even if we |
1879 |
|
|
* later on realize we have to abort our operation, on that sector |
1880 |
|
|
* there should be no data, so we can't destroy something yet. |
1881 |
|
|
*/ |
1882 |
|
|
lastsector = calloc(1, lp->d_secsize); |
1883 |
|
|
if (!lastsector) |
1884 |
|
|
err(1, "No memory for last sector test write"); |
1885 |
|
|
wtfs(DL_SECTOBLK(lp, DL_GETPSIZE(pp) - 1), lp->d_secsize, |
1886 |
|
|
lastsector, fso, Nflag); |
1887 |
|
|
free(lastsector); |
1888 |
|
|
|
1889 |
|
|
/* |
1890 |
|
|
* Now calculate new superblock values and check for reasonable |
1891 |
|
|
* bound for new filesystem size: |
1892 |
|
|
* fs_size: is derived from label or user input |
1893 |
|
|
* fs_dsize: should get updated in the routines creating or |
1894 |
|
|
* updating the cylinder groups on the fly |
1895 |
|
|
* fs_cstotal: should get updated in the routines creating or |
1896 |
|
|
* updating the cylinder groups |
1897 |
|
|
*/ |
1898 |
|
|
|
1899 |
|
|
/* |
1900 |
|
|
* Update the number of cylinders and cylinder groups in the file system. |
1901 |
|
|
*/ |
1902 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) { |
1903 |
|
|
sblock.fs_ncyl = sblock.fs_size * NSPF(&sblock) / sblock.fs_spc; |
1904 |
|
|
if (sblock.fs_size * NSPF(&sblock) > |
1905 |
|
|
sblock.fs_ncyl * sblock.fs_spc) |
1906 |
|
|
sblock.fs_ncyl++; |
1907 |
|
|
} |
1908 |
|
|
sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); |
1909 |
|
|
maxino = sblock.fs_ncg * sblock.fs_ipg; |
1910 |
|
|
|
1911 |
|
|
if (sblock.fs_size % sblock.fs_fpg != 0 && |
1912 |
|
|
sblock.fs_size % sblock.fs_fpg < cgdmin(&sblock, sblock.fs_ncg)) { |
1913 |
|
|
/* |
1914 |
|
|
* The space in the new last cylinder group is too small, |
1915 |
|
|
* so revert back. |
1916 |
|
|
*/ |
1917 |
|
|
sblock.fs_ncg--; |
1918 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) |
1919 |
|
|
sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg; |
1920 |
|
|
if (!quiet) |
1921 |
|
|
printf("Warning: %jd sector(s) cannot be allocated.\n", |
1922 |
|
|
(intmax_t)fsbtodb(&sblock, |
1923 |
|
|
sblock.fs_size % sblock.fs_fpg)); |
1924 |
|
|
sblock.fs_size = sblock.fs_ncg * sblock.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 |
|
|
sblock.fs_cssize = |
1932 |
|
|
fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); |
1933 |
|
|
|
1934 |
|
|
if (osblock.fs_size >= sblock.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); |
1947 |
|
|
pp->p_cpg = sblock.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, (char *)lp) < 0) |
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, (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, "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 (sblock.fs_contigsumsize < 1) /* no clustering */ |
2028 |
|
|
return; |
2029 |
|
|
|
2030 |
|
|
/* |
2031 |
|
|
* update cluster allocation map |
2032 |
|
|
*/ |
2033 |
|
|
setbit(cg_clustersfree(&acg), block); |
2034 |
|
|
|
2035 |
|
|
/* |
2036 |
|
|
* update cluster summary table |
2037 |
|
|
*/ |
2038 |
|
|
if (!lcs) { |
2039 |
|
|
/* |
2040 |
|
|
* calculate size for the trailing cluster |
2041 |
|
|
*/ |
2042 |
|
|
for (block--; lcs < sblock.fs_contigsumsize; block--, lcs++) { |
2043 |
|
|
if (isclr(cg_clustersfree(&acg), block)) |
2044 |
|
|
break; |
2045 |
|
|
} |
2046 |
|
|
} |
2047 |
|
|
if (lcs < sblock.fs_contigsumsize) { |
2048 |
|
|
if (lcs) |
2049 |
|
|
cg_clustersum(&acg)[lcs]--; |
2050 |
|
|
lcs++; |
2051 |
|
|
cg_clustersum(&acg)[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) |
2071 |
|
|
return; |
2072 |
|
|
|
2073 |
|
|
mode = DIP(ino, di_mode) & IFMT; |
2074 |
|
|
if (mode != IFDIR && mode != IFREG && mode != IFLNK) |
2075 |
|
|
return; /* only check DIR, FILE, LINK */ |
2076 |
|
|
if (mode == IFLNK && |
2077 |
|
|
DIP(ino, di_size) < (u_int64_t) sblock.fs_maxsymlinklen) |
2078 |
|
|
return; /* skip short symlinks */ |
2079 |
|
|
numblks = howmany(DIP(ino, di_size), sblock.fs_bsize); |
2080 |
|
|
if (numblks == 0) |
2081 |
|
|
return; /* skip empty file */ |
2082 |
|
|
if (DIP(ino, 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 < NDADDR ? numblks : NDADDR; |
2090 |
|
|
for (i = 0; i < len; i++) { |
2091 |
|
|
iptr = DIP(ino, 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); |
2096 |
|
|
inodeupdated++; |
2097 |
|
|
} |
2098 |
|
|
} |
2099 |
|
|
|
2100 |
|
|
blksperindir = 1; |
2101 |
|
|
len = numblks - NDADDR; |
2102 |
|
|
lbn = NDADDR; |
2103 |
|
|
for (i = 0; len > 0 && i < NIADDR; i++) { |
2104 |
|
|
iptr = DIP(ino, 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); |
2109 |
|
|
inodeupdated++; |
2110 |
|
|
} |
2111 |
|
|
indirchk(blksperindir, lbn, iptr, numblks, bp, fsi, fso, Nflag); |
2112 |
|
|
blksperindir *= NINDIR(&sblock); |
2113 |
|
|
lbn += blksperindir; |
2114 |
|
|
len -= blksperindir; |
2115 |
|
|
} |
2116 |
|
|
if (inodeupdated) |
2117 |
|
|
wtfs(inoblk, sblock.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(sblock.fs_bsize); |
2133 |
|
|
if (!ibuf) |
2134 |
|
|
errx(1, "malloc failed"); |
2135 |
|
|
rdfs(fsbtodb(&sblock, blkno), (size_t)sblock.fs_bsize, ibuf, fsi); |
2136 |
|
|
last = howmany(lastlbn - lbn, blksperindir) < NINDIR(&sblock) ? |
2137 |
|
|
howmany(lastlbn - lbn, blksperindir) : NINDIR(&sblock); |
2138 |
|
|
for (i = 0; i < last; i++) { |
2139 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) |
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 (sblock.fs_magic == FS_UFS1_MAGIC) |
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), 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_UPDATED; |
2174 |
|
|
} |