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