| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: resize_ffs.c,v 1.12 2007/12/15 19:44:47 perry Exp $ */ | | 1 | /* $NetBSD: resize_ffs.c,v 1.13 2010/10/30 21:16:07 haad Exp $ */ |
2 | /* From sources sent on February 17, 2003 */ | | 2 | /* From sources sent on February 17, 2003 */ |
3 | /*- | | 3 | /*- |
4 | * As its sole author, I explicitly place this code in the public | | 4 | * As its sole author, I explicitly place this code in the public |
5 | * domain. Anyone may use it for any purpose (though I would | | 5 | * domain. Anyone may use it for any purpose (though I would |
6 | * appreciate credit where it is due). | | 6 | * appreciate credit where it is due). |
7 | * | | 7 | * |
8 | * der Mouse | | 8 | * der Mouse |
9 | * | | 9 | * |
10 | * mouse@rodents.montreal.qc.ca | | 10 | * mouse@rodents.montreal.qc.ca |
11 | * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B | | 11 | * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B |
12 | */ | | 12 | */ |
13 | /* | | 13 | /* |
14 | * resize_ffs: | | 14 | * resize_ffs: |
| @@ -38,49 +38,40 @@ | | | @@ -38,49 +38,40 @@ |
38 | * shrinking. (These actually indicate bugs in fsck too - it should | | 38 | * shrinking. (These actually indicate bugs in fsck too - it should |
39 | * have caught and fixed them.) | | 39 | * have caught and fixed them.) |
40 | * | | 40 | * |
41 | */ | | 41 | */ |
42 | | | 42 | |
43 | #include <sys/cdefs.h> | | 43 | #include <sys/cdefs.h> |
44 | #include <stdio.h> | | 44 | #include <stdio.h> |
45 | #include <errno.h> | | 45 | #include <errno.h> |
46 | #include <fcntl.h> | | 46 | #include <fcntl.h> |
47 | #include <stdlib.h> | | 47 | #include <stdlib.h> |
48 | #include <unistd.h> | | 48 | #include <unistd.h> |
49 | #include <strings.h> | | 49 | #include <strings.h> |
50 | #include <err.h> | | 50 | #include <err.h> |
| | | 51 | #include <sys/disk.h> |
| | | 52 | #include <sys/disklabel.h> |
| | | 53 | #include <sys/dkio.h> |
| | | 54 | #include <sys/ioctl.h> |
51 | #include <sys/stat.h> | | 55 | #include <sys/stat.h> |
52 | #include <sys/mman.h> | | 56 | #include <sys/mman.h> |
53 | #include <sys/param.h> /* MAXFRAG */ | | 57 | #include <sys/param.h> /* MAXFRAG */ |
54 | #include <ufs/ffs/fs.h> | | 58 | #include <ufs/ffs/fs.h> |
55 | #include <ufs/ufs/dir.h> | | 59 | #include <ufs/ufs/dir.h> |
56 | #include <ufs/ufs/dinode.h> | | 60 | #include <ufs/ufs/dinode.h> |
57 | #include <ufs/ufs/ufs_bswap.h> /* ufs_rw32 */ | | 61 | #include <ufs/ufs/ufs_bswap.h> /* ufs_rw32 */ |
58 | | | 62 | |
59 | /* Suppress warnings about unused arguments */ | | | |
60 | #if defined(__GNUC__) && \ | | | |
61 | ( (__GNUC__ > 2) || \ | | | |
62 | ( (__GNUC__ == 2) && \ | | | |
63 | defined(__GNUC_MINOR__) && \ | | | |
64 | (__GNUC_MINOR__ >= 7) ) ) | | | |
65 | #define UNUSED_ARG(x) x __unused | | | |
66 | #define INLINE inline | | | |
67 | #else | | | |
68 | #define UNUSED_ARG(x) x | | | |
69 | #define INLINE /**/ | | | |
70 | #endif | | | |
71 | | | | |
72 | /* new size of filesystem, in sectors */ | | 63 | /* new size of filesystem, in sectors */ |
73 | static int newsize; | | 64 | static uint32_t newsize; |
74 | | | 65 | |
75 | /* fd open onto disk device */ | | 66 | /* fd open onto disk device */ |
76 | static int fd; | | 67 | static int fd; |
77 | | | 68 | |
78 | /* must we break up big I/O operations - see checksmallio() */ | | 69 | /* must we break up big I/O operations - see checksmallio() */ |
79 | static int smallio; | | 70 | static int smallio; |
80 | | | 71 | |
81 | /* size of a cg, in bytes, rounded up to a frag boundary */ | | 72 | /* size of a cg, in bytes, rounded up to a frag boundary */ |
82 | static int cgblksz; | | 73 | static int cgblksz; |
83 | | | 74 | |
84 | /* possible superblock localtions */ | | 75 | /* possible superblock localtions */ |
85 | static int search[] = SBLOCKSEARCH; | | 76 | static int search[] = SBLOCKSEARCH; |
86 | /* location of the superblock */ | | 77 | /* location of the superblock */ |
| @@ -146,26 +137,28 @@ static unsigned char *iflags; | | | @@ -146,26 +137,28 @@ static unsigned char *iflags; |
146 | #define dblksize(fs, dip, lbn) \ | | 137 | #define dblksize(fs, dip, lbn) \ |
147 | (((lbn) >= NDADDR || (dip)->di_size >= lblktosize(fs, (lbn) + 1)) \ | | 138 | (((lbn) >= NDADDR || (dip)->di_size >= lblktosize(fs, (lbn) + 1)) \ |
148 | ? (fs)->fs_bsize \ | | 139 | ? (fs)->fs_bsize \ |
149 | : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) | | 140 | : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) |
150 | | | 141 | |
151 | | | 142 | |
152 | /* | | 143 | /* |
153 | * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte | | 144 | * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte |
154 | * sector size. | | 145 | * sector size. |
155 | */ | | 146 | */ |
156 | #define NSPB(fs) ((fs)->fs_old_nspf << (fs)->fs_fragshift) | | 147 | #define NSPB(fs) ((fs)->fs_old_nspf << (fs)->fs_fragshift) |
157 | #define NSPF(fs) ((fs)->fs_old_nspf) | | 148 | #define NSPF(fs) ((fs)->fs_old_nspf) |
158 | | | 149 | |
| | | 150 | static void usage(void) __dead; |
| | | 151 | |
159 | /* | | 152 | /* |
160 | * See if we need to break up large I/O operations. This should never | | 153 | * See if we need to break up large I/O operations. This should never |
161 | * be needed, but under at least one <version,platform> combination, | | 154 | * be needed, but under at least one <version,platform> combination, |
162 | * large enough disk transfers to the raw device hang. So if we're | | 155 | * large enough disk transfers to the raw device hang. So if we're |
163 | * talking to a character special device, play it safe; in this case, | | 156 | * talking to a character special device, play it safe; in this case, |
164 | * readat() and writeat() break everything up into pieces no larger | | 157 | * readat() and writeat() break everything up into pieces no larger |
165 | * than 8K, doing multiple syscalls for larger operations. | | 158 | * than 8K, doing multiple syscalls for larger operations. |
166 | */ | | 159 | */ |
167 | static void | | 160 | static void |
168 | checksmallio(void) | | 161 | checksmallio(void) |
169 | { | | 162 | { |
170 | struct stat stb; | | 163 | struct stat stb; |
171 | | | 164 | |
| @@ -185,128 +178,128 @@ readat(off_t blkno, void *buf, int size) | | | @@ -185,128 +178,128 @@ readat(off_t blkno, void *buf, int size) |
185 | | | 178 | |
186 | /* See if we have to break up the transfer... */ | | 179 | /* See if we have to break up the transfer... */ |
187 | if (smallio) { | | 180 | if (smallio) { |
188 | char *bp; /* pointer into buf */ | | 181 | char *bp; /* pointer into buf */ |
189 | int left; /* bytes left to go */ | | 182 | int left; /* bytes left to go */ |
190 | int n; /* number to do this time around */ | | 183 | int n; /* number to do this time around */ |
191 | int rv; /* syscall return value */ | | 184 | int rv; /* syscall return value */ |
192 | bp = buf; | | 185 | bp = buf; |
193 | left = size; | | 186 | left = size; |
194 | while (left > 0) { | | 187 | while (left > 0) { |
195 | n = (left > 8192) ? 8192 : left; | | 188 | n = (left > 8192) ? 8192 : left; |
196 | rv = read(fd, bp, n); | | 189 | rv = read(fd, bp, n); |
197 | if (rv < 0) | | 190 | if (rv < 0) |
198 | err(1, "read failed"); | | 191 | err(EXIT_FAILURE, "read failed"); |
199 | if (rv != n) | | 192 | if (rv != n) |
200 | errx(1, "read: wanted %d, got %d", n, rv); | | 193 | errx(1, "read: wanted %d, got %d", n, rv); |
201 | bp += n; | | 194 | bp += n; |
202 | left -= n; | | 195 | left -= n; |
203 | } | | 196 | } |
204 | } else { | | 197 | } else { |
205 | int rv; | | 198 | int rv; |
206 | rv = read(fd, buf, size); | | 199 | rv = read(fd, buf, size); |
207 | if (rv < 0) | | 200 | if (rv < 0) |
208 | err(1, "read failed"); | | 201 | err(EXIT_FAILURE, "read failed"); |
209 | if (rv != size) | | 202 | if (rv != size) |
210 | errx(1, "read: wanted %d, got %d", size, rv); | | 203 | errx(1, "read: wanted %d, got %d", size, rv); |
211 | } | | 204 | } |
212 | } | | 205 | } |
213 | /* | | 206 | /* |
214 | * Write size bytes from buf starting at blkno. blkno is in DEV_BSIZE | | 207 | * Write size bytes from buf starting at blkno. blkno is in DEV_BSIZE |
215 | * units, ie, after fsbtodb(); size is in bytes. | | 208 | * units, ie, after fsbtodb(); size is in bytes. |
216 | */ | | 209 | */ |
217 | static void | | 210 | static void |
218 | writeat(off_t blkno, const void *buf, int size) | | 211 | writeat(off_t blkno, const void *buf, int size) |
219 | { | | 212 | { |
220 | /* Seek to the correct place. */ | | 213 | /* Seek to the correct place. */ |
221 | if (lseek(fd, blkno * DEV_BSIZE, L_SET) < 0) | | 214 | if (lseek(fd, blkno * DEV_BSIZE, L_SET) < 0) |
222 | err(1, "lseek failed"); | | 215 | err(EXIT_FAILURE, "lseek failed"); |
223 | /* See if we have to break up the transfer... */ | | 216 | /* See if we have to break up the transfer... */ |
224 | if (smallio) { | | 217 | if (smallio) { |
225 | const char *bp; /* pointer into buf */ | | 218 | const char *bp; /* pointer into buf */ |
226 | int left; /* bytes left to go */ | | 219 | int left; /* bytes left to go */ |
227 | int n; /* number to do this time around */ | | 220 | int n; /* number to do this time around */ |
228 | int rv; /* syscall return value */ | | 221 | int rv; /* syscall return value */ |
229 | bp = buf; | | 222 | bp = buf; |
230 | left = size; | | 223 | left = size; |
231 | while (left > 0) { | | 224 | while (left > 0) { |
232 | n = (left > 8192) ? 8192 : left; | | 225 | n = (left > 8192) ? 8192 : left; |
233 | rv = write(fd, bp, n); | | 226 | rv = write(fd, bp, n); |
234 | if (rv < 0) | | 227 | if (rv < 0) |
235 | err(1, "write failed"); | | 228 | err(EXIT_FAILURE, "write failed"); |
236 | if (rv != n) | | 229 | if (rv != n) |
237 | errx(1, "write: wanted %d, got %d", n, rv); | | 230 | errx(1, "write: wanted %d, got %d", n, rv); |
238 | bp += n; | | 231 | bp += n; |
239 | left -= n; | | 232 | left -= n; |
240 | } | | 233 | } |
241 | } else { | | 234 | } else { |
242 | int rv; | | 235 | int rv; |
243 | rv = write(fd, buf, size); | | 236 | rv = write(fd, buf, size); |
244 | if (rv < 0) | | 237 | if (rv < 0) |
245 | err(1, "write failed"); | | 238 | err(EXIT_FAILURE, "write failed"); |
246 | if (rv != size) | | 239 | if (rv != size) |
247 | errx(1, "write: wanted %d, got %d", size, rv); | | 240 | errx(1, "write: wanted %d, got %d", size, rv); |
248 | } | | 241 | } |
249 | } | | 242 | } |
250 | /* | | 243 | /* |
251 | * Never-fail versions of malloc() and realloc(), and an allocation | | 244 | * Never-fail versions of malloc() and realloc(), and an allocation |
252 | * routine (which also never fails) for allocating memory that will | | 245 | * routine (which also never fails) for allocating memory that will |
253 | * never be freed until exit. | | 246 | * never be freed until exit. |
254 | */ | | 247 | */ |
255 | | | 248 | |
256 | /* | | 249 | /* |
257 | * Never-fail malloc. | | 250 | * Never-fail malloc. |
258 | */ | | 251 | */ |
259 | static void * | | 252 | static void * |
260 | nfmalloc(size_t nb, const char *tag) | | 253 | nfmalloc(size_t nb, const char *tag) |
261 | { | | 254 | { |
262 | void *rv; | | 255 | void *rv; |
263 | | | 256 | |
264 | rv = malloc(nb); | | 257 | rv = malloc(nb); |
265 | if (rv) | | 258 | if (rv) |
266 | return (rv); | | 259 | return (rv); |
267 | err(1, "Can't allocate %lu bytes for %s", | | 260 | err(EXIT_FAILURE, "Can't allocate %lu bytes for %s", |
268 | (unsigned long int) nb, tag); | | 261 | (unsigned long int) nb, tag); |
269 | } | | 262 | } |
270 | /* | | 263 | /* |
271 | * Never-fail realloc. | | 264 | * Never-fail realloc. |
272 | */ | | 265 | */ |
273 | static void * | | 266 | static void * |
274 | nfrealloc(void *blk, size_t nb, const char *tag) | | 267 | nfrealloc(void *blk, size_t nb, const char *tag) |
275 | { | | 268 | { |
276 | void *rv; | | 269 | void *rv; |
277 | | | 270 | |
278 | rv = realloc(blk, nb); | | 271 | rv = realloc(blk, nb); |
279 | if (rv) | | 272 | if (rv) |
280 | return (rv); | | 273 | return (rv); |
281 | err(1, "Can't re-allocate %lu bytes for %s", | | 274 | err(EXIT_FAILURE, "Can't re-allocate %lu bytes for %s", |
282 | (unsigned long int) nb, tag); | | 275 | (unsigned long int) nb, tag); |
283 | } | | 276 | } |
284 | /* | | 277 | /* |
285 | * Allocate memory that will never be freed or reallocated. Arguably | | 278 | * Allocate memory that will never be freed or reallocated. Arguably |
286 | * this routine should handle small allocations by chopping up pages, | | 279 | * this routine should handle small allocations by chopping up pages, |
287 | * but that's not worth the bother; it's not called more than a | | 280 | * but that's not worth the bother; it's not called more than a |
288 | * handful of times per run, and if the allocations are that small the | | 281 | * handful of times per run, and if the allocations are that small the |
289 | * waste in giving each one its own page is ignorable. | | 282 | * waste in giving each one its own page is ignorable. |
290 | */ | | 283 | */ |
291 | static void * | | 284 | static void * |
292 | alloconce(size_t nb, const char *tag) | | 285 | alloconce(size_t nb, const char *tag) |
293 | { | | 286 | { |
294 | void *rv; | | 287 | void *rv; |
295 | | | 288 | |
296 | rv = mmap(0, nb, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | | 289 | rv = mmap(0, nb, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
297 | if (rv != MAP_FAILED) | | 290 | if (rv != MAP_FAILED) |
298 | return (rv); | | 291 | return (rv); |
299 | err(1, "Can't map %lu bytes for %s", | | 292 | err(EXIT_FAILURE, "Can't map %lu bytes for %s", |
300 | (unsigned long int) nb, tag); | | 293 | (unsigned long int) nb, tag); |
301 | } | | 294 | } |
302 | /* | | 295 | /* |
303 | * Load the cgs and csums off disk. Also allocates the space to load | | 296 | * Load the cgs and csums off disk. Also allocates the space to load |
304 | * them into and initializes the per-cg flags. | | 297 | * them into and initializes the per-cg flags. |
305 | */ | | 298 | */ |
306 | static void | | 299 | static void |
307 | loadcgs(void) | | 300 | loadcgs(void) |
308 | { | | 301 | { |
309 | int cg; | | 302 | int cg; |
310 | char *cgp; | | 303 | char *cgp; |
311 | | | 304 | |
312 | cgblksz = roundup(oldsb->fs_cgsize, oldsb->fs_fsize); | | 305 | cgblksz = roundup(oldsb->fs_cgsize, oldsb->fs_fsize); |
| @@ -371,62 +364,62 @@ clr_bits(unsigned char *bitvec, int base | | | @@ -371,62 +364,62 @@ clr_bits(unsigned char *bitvec, int base |
371 | } | | 364 | } |
372 | if (n >= 8) { | | 365 | if (n >= 8) { |
373 | bzero(bitvec + (base >> 3), n >> 3); | | 366 | bzero(bitvec + (base >> 3), n >> 3); |
374 | base += n & ~7; | | 367 | base += n & ~7; |
375 | n &= 7; | | 368 | n &= 7; |
376 | } | | 369 | } |
377 | if (n) { | | 370 | if (n) { |
378 | bitvec[base >> 3] &= (~0U) << n; | | 371 | bitvec[base >> 3] &= (~0U) << n; |
379 | } | | 372 | } |
380 | } | | 373 | } |
381 | /* | | 374 | /* |
382 | * Test whether bit #bit is set in the bitmap pointed to by bitvec. | | 375 | * Test whether bit #bit is set in the bitmap pointed to by bitvec. |
383 | */ | | 376 | */ |
384 | INLINE static int | | 377 | static int |
385 | bit_is_set(unsigned char *bitvec, int bit) | | 378 | bit_is_set(unsigned char *bitvec, int bit) |
386 | { | | 379 | { |
387 | return (bitvec[bit >> 3] & (1 << (bit & 7))); | | 380 | return (bitvec[bit >> 3] & (1 << (bit & 7))); |
388 | } | | 381 | } |
389 | /* | | 382 | /* |
390 | * Test whether bit #bit is clear in the bitmap pointed to by bitvec. | | 383 | * Test whether bit #bit is clear in the bitmap pointed to by bitvec. |
391 | */ | | 384 | */ |
392 | INLINE static int | | 385 | static int |
393 | bit_is_clr(unsigned char *bitvec, int bit) | | 386 | bit_is_clr(unsigned char *bitvec, int bit) |
394 | { | | 387 | { |
395 | return (!bit_is_set(bitvec, bit)); | | 388 | return (!bit_is_set(bitvec, bit)); |
396 | } | | 389 | } |
397 | /* | | 390 | /* |
398 | * Test whether a whole block of bits is set in a bitmap. This is | | 391 | * Test whether a whole block of bits is set in a bitmap. This is |
399 | * designed for testing (aligned) disk blocks in a bit-per-frag | | 392 | * designed for testing (aligned) disk blocks in a bit-per-frag |
400 | * bitmap; it has assumptions wired into it based on that, essentially | | 393 | * bitmap; it has assumptions wired into it based on that, essentially |
401 | * that the entire block fits into a single byte. This returns true | | 394 | * that the entire block fits into a single byte. This returns true |
402 | * iff _all_ the bits are set; it is not just the complement of | | 395 | * iff _all_ the bits are set; it is not just the complement of |
403 | * blk_is_clr on the same arguments (unless blkfrags==1). | | 396 | * blk_is_clr on the same arguments (unless blkfrags==1). |
404 | */ | | 397 | */ |
405 | INLINE static int | | 398 | static int |
406 | blk_is_set(unsigned char *bitvec, int blkbase, int blkfrags) | | 399 | blk_is_set(unsigned char *bitvec, int blkbase, int blkfrags) |
407 | { | | 400 | { |
408 | unsigned int mask; | | 401 | unsigned int mask; |
409 | | | 402 | |
410 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); | | 403 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); |
411 | return ((bitvec[blkbase >> 3] & mask) == mask); | | 404 | return ((bitvec[blkbase >> 3] & mask) == mask); |
412 | } | | 405 | } |
413 | /* | | 406 | /* |
414 | * Test whether a whole block of bits is clear in a bitmap. See | | 407 | * Test whether a whole block of bits is clear in a bitmap. See |
415 | * blk_is_set (above) for assumptions. This returns true iff _all_ | | 408 | * blk_is_set (above) for assumptions. This returns true iff _all_ |
416 | * the bits are clear; it is not just the complement of blk_is_set on | | 409 | * the bits are clear; it is not just the complement of blk_is_set on |
417 | * the same arguments (unless blkfrags==1). | | 410 | * the same arguments (unless blkfrags==1). |
418 | */ | | 411 | */ |
419 | INLINE static int | | 412 | static int |
420 | blk_is_clr(unsigned char *bitvec, int blkbase, int blkfrags) | | 413 | blk_is_clr(unsigned char *bitvec, int blkbase, int blkfrags) |
421 | { | | 414 | { |
422 | unsigned int mask; | | 415 | unsigned int mask; |
423 | | | 416 | |
424 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); | | 417 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); |
425 | return ((bitvec[blkbase >> 3] & mask) == 0); | | 418 | return ((bitvec[blkbase >> 3] & mask) == 0); |
426 | } | | 419 | } |
427 | /* | | 420 | /* |
428 | * Initialize a new cg. Called when growing. Assumes memory has been | | 421 | * Initialize a new cg. Called when growing. Assumes memory has been |
429 | * allocated but not otherwise set up. This code sets the fields of | | 422 | * allocated but not otherwise set up. This code sets the fields of |
430 | * the cg, initializes the bitmaps (and cluster summaries, if | | 423 | * the cg, initializes the bitmaps (and cluster summaries, if |
431 | * applicable), updates both per-cylinder summary info and the global | | 424 | * applicable), updates both per-cylinder summary info and the global |
432 | * summary info in newsb; it also writes out new inodes for the cg. | | 425 | * summary info in newsb; it also writes out new inodes for the cg. |
| @@ -880,28 +873,30 @@ grow(void) | | | @@ -880,28 +873,30 @@ grow(void) |
880 | int i; | | 873 | int i; |
881 | | | 874 | |
882 | /* Update the timestamp. */ | | 875 | /* Update the timestamp. */ |
883 | newsb->fs_time = timestamp(); | | 876 | newsb->fs_time = timestamp(); |
884 | /* Allocate and clear the new-inode area, in case we add any cgs. */ | | 877 | /* Allocate and clear the new-inode area, in case we add any cgs. */ |
885 | zinodes = alloconce(newsb->fs_ipg * sizeof(struct ufs1_dinode), | | 878 | zinodes = alloconce(newsb->fs_ipg * sizeof(struct ufs1_dinode), |
886 | "zeroed inodes"); | | 879 | "zeroed inodes"); |
887 | bzero(zinodes, newsb->fs_ipg * sizeof(struct ufs1_dinode)); | | 880 | bzero(zinodes, newsb->fs_ipg * sizeof(struct ufs1_dinode)); |
888 | /* Update the size. */ | | 881 | /* Update the size. */ |
889 | newsb->fs_size = dbtofsb(newsb, newsize); | | 882 | newsb->fs_size = dbtofsb(newsb, newsize); |
890 | /* Did we actually not grow? (This can happen if newsize is less than | | 883 | /* Did we actually not grow? (This can happen if newsize is less than |
891 | * a frag larger than the old size - unlikely, but no excuse to | | 884 | * a frag larger than the old size - unlikely, but no excuse to |
892 | * misbehave if it happens.) */ | | 885 | * misbehave if it happens.) */ |
893 | if (newsb->fs_size == oldsb->fs_size) | | 886 | if (newsb->fs_size == oldsb->fs_size) { |
| | | 887 | printf("New fs size %"PRIu64" = odl fs size %"PRIu64", not growing.\n", newsb->fs_size, oldsb->fs_size); |
894 | return; | | 888 | return; |
| | | 889 | } |
895 | /* Check that the new last sector (frag, actually) is writable. Since | | 890 | /* Check that the new last sector (frag, actually) is writable. Since |
896 | * it's at least one frag larger than it used to be, we know we aren't | | 891 | * it's at least one frag larger than it used to be, we know we aren't |
897 | * overwriting anything important by this. (The choice of sbbuf as | | 892 | * overwriting anything important by this. (The choice of sbbuf as |
898 | * what to write is irrelevant; it's just something handy that's known | | 893 | * what to write is irrelevant; it's just something handy that's known |
899 | * to be at least one frag in size.) */ | | 894 | * to be at least one frag in size.) */ |
900 | writeat(newsb->fs_size - 1, &sbbuf, newsb->fs_fsize); | | 895 | writeat(newsb->fs_size - 1, &sbbuf, newsb->fs_fsize); |
901 | /* Update fs_old_ncyl and fs_ncg. */ | | 896 | /* Update fs_old_ncyl and fs_ncg. */ |
902 | newsb->fs_old_ncyl = (newsb->fs_size * NSPF(newsb)) / newsb->fs_old_spc; | | 897 | newsb->fs_old_ncyl = (newsb->fs_size * NSPF(newsb)) / newsb->fs_old_spc; |
903 | newsb->fs_ncg = howmany(newsb->fs_old_ncyl, newsb->fs_old_cpg); | | 898 | newsb->fs_ncg = howmany(newsb->fs_old_ncyl, newsb->fs_old_cpg); |
904 | /* Does the last cg end before the end of its inode area? There is no | | 899 | /* Does the last cg end before the end of its inode area? There is no |
905 | * reason why this couldn't be handled, but it would complicate a lot | | 900 | * reason why this couldn't be handled, but it would complicate a lot |
906 | * of code (in all filesystem code - fsck, kernel, etc) because of the | | 901 | * of code (in all filesystem code - fsck, kernel, etc) because of the |
907 | * potential partial inode area, and the gain in space would be | | 902 | * potential partial inode area, and the gain in space would be |
| @@ -955,27 +950,27 @@ grow(void) | | | @@ -955,27 +950,27 @@ grow(void) |
955 | cg->cg_ndblk = newcgsize; | | 950 | cg->cg_ndblk = newcgsize; |
956 | } | | 951 | } |
957 | /* Fix up the csum info, if necessary. */ | | 952 | /* Fix up the csum info, if necessary. */ |
958 | csum_fixup(); | | 953 | csum_fixup(); |
959 | /* Make fs_dsize match the new reality. */ | | 954 | /* Make fs_dsize match the new reality. */ |
960 | recompute_fs_dsize(); | | 955 | recompute_fs_dsize(); |
961 | } | | 956 | } |
962 | /* | | 957 | /* |
963 | * Call (*fn)() for each inode, passing the inode and its inumber. The | | 958 | * Call (*fn)() for each inode, passing the inode and its inumber. The |
964 | * number of cylinder groups is pased in, so this can be used to map | | 959 | * number of cylinder groups is pased in, so this can be used to map |
965 | * over either the old or the new filesystem's set of inodes. | | 960 | * over either the old or the new filesystem's set of inodes. |
966 | */ | | 961 | */ |
967 | static void | | 962 | static void |
968 | map_inodes(void (*fn) (struct ufs1_dinode * di, unsigned int, void *arg), int ncg, void *cbarg) { | | 963 | map_inodes(void (*fn) (struct ufs1_dinode * di, unsigned int, void *arg), int ncg, void *cbarg) { |
969 | int i; | | 964 | int i; |
970 | int ni; | | 965 | int ni; |
971 | | | 966 | |
972 | ni = oldsb->fs_ipg * ncg; | | 967 | ni = oldsb->fs_ipg * ncg; |
973 | for (i = 0; i < ni; i++) | | 968 | for (i = 0; i < ni; i++) |
974 | (*fn) (inodes + i, i, cbarg); | | 969 | (*fn) (inodes + i, i, cbarg); |
975 | } | | 970 | } |
976 | /* Values for the third argument to the map function for | | 971 | /* Values for the third argument to the map function for |
977 | * map_inode_data_blocks. MDB_DATA indicates the block is contains | | 972 | * map_inode_data_blocks. MDB_DATA indicates the block is contains |
978 | * file data; MDB_INDIR_PRE and MDB_INDIR_POST indicate that it's an | | 973 | * file data; MDB_INDIR_PRE and MDB_INDIR_POST indicate that it's an |
979 | * indirect block. The MDB_INDIR_PRE call is made before the indirect | | 974 | * indirect block. The MDB_INDIR_PRE call is made before the indirect |
980 | * block pointers are followed and the pointed-to blocks scanned, | | 975 | * block pointers are followed and the pointed-to blocks scanned, |
981 | * MDB_INDIR_POST after. | | 976 | * MDB_INDIR_POST after. |
| @@ -1811,66 +1806,148 @@ flush_cgs(void) | | | @@ -1811,66 +1806,148 @@ flush_cgs(void) |
1811 | * Write the superblock, both to the main superblock and to each cg's | | 1806 | * Write the superblock, both to the main superblock and to each cg's |
1812 | * alternative superblock. | | 1807 | * alternative superblock. |
1813 | */ | | 1808 | */ |
1814 | static void | | 1809 | static void |
1815 | write_sbs(void) | | 1810 | write_sbs(void) |
1816 | { | | 1811 | { |
1817 | int i; | | 1812 | int i; |
1818 | | | 1813 | |
1819 | writeat(where / DEV_BSIZE, newsb, SBLOCKSIZE); | | 1814 | writeat(where / DEV_BSIZE, newsb, SBLOCKSIZE); |
1820 | for (i = 0; i < newsb->fs_ncg; i++) { | | 1815 | for (i = 0; i < newsb->fs_ncg; i++) { |
1821 | writeat(fsbtodb(newsb, cgsblock(newsb, i)), newsb, SBLOCKSIZE); | | 1816 | writeat(fsbtodb(newsb, cgsblock(newsb, i)), newsb, SBLOCKSIZE); |
1822 | } | | 1817 | } |
1823 | } | | 1818 | } |
| | | 1819 | |
| | | 1820 | static uint32_t |
| | | 1821 | get_dev_size(char *dev_name) |
| | | 1822 | { |
| | | 1823 | struct dkwedge_info dkw; |
| | | 1824 | struct partition *pp; |
| | | 1825 | struct disklabel lp; |
| | | 1826 | size_t ptn; |
| | | 1827 | |
| | | 1828 | /* Get info about partition/wedge */ |
| | | 1829 | if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) { |
| | | 1830 | if (ioctl(fd, DIOCGDINFO, &lp) == -1) |
| | | 1831 | return 0; |
| | | 1832 | |
| | | 1833 | ptn = strchr(dev_name, '\0')[-1] - 'a'; |
| | | 1834 | if (ptn >= lp.d_npartitions) |
| | | 1835 | return 0; |
| | | 1836 | |
| | | 1837 | pp = &lp.d_partitions[ptn]; |
| | | 1838 | return pp->p_size; |
| | | 1839 | } |
| | | 1840 | |
| | | 1841 | return dkw.dkw_size; |
| | | 1842 | } |
| | | 1843 | |
1824 | /* | | 1844 | /* |
1825 | * main(). | | 1845 | * main(). |
1826 | */ | | 1846 | */ |
1827 | int main(int, char **); | | | |
1828 | int | | 1847 | int |
1829 | main(int ac, char **av) | | 1848 | main(int argc, char **argv) |
1830 | { | | 1849 | { |
| | | 1850 | int ch; |
| | | 1851 | int ExpertFlag; |
| | | 1852 | int SFlag; |
1831 | size_t i; | | 1853 | size_t i; |
1832 | if (ac != 3) { | | 1854 | |
1833 | fprintf(stderr, "usage: %s filesystem new-size\n", | | 1855 | char *device; |
1834 | getprogname()); | | 1856 | char reply[5]; |
1835 | exit(1); | | 1857 | |
| | | 1858 | newsize = 0; |
| | | 1859 | ExpertFlag = 0; |
| | | 1860 | SFlag = 0; |
| | | 1861 | |
| | | 1862 | while ((ch = getopt(argc, argv, "s:y")) != -1) { |
| | | 1863 | switch (ch) { |
| | | 1864 | case 's': |
| | | 1865 | SFlag = 1; |
| | | 1866 | newsize = (size_t)strtoul(optarg, NULL, 10); |
| | | 1867 | if(newsize < 1) { |
| | | 1868 | usage(); |
| | | 1869 | } |
| | | 1870 | break; |
| | | 1871 | case 'y': |
| | | 1872 | ExpertFlag = 1; |
| | | 1873 | break; |
| | | 1874 | case '?': |
| | | 1875 | /* FALLTHROUGH */ |
| | | 1876 | default: |
| | | 1877 | usage(); |
| | | 1878 | } |
| | | 1879 | } |
| | | 1880 | argc -= optind; |
| | | 1881 | argv += optind; |
| | | 1882 | |
| | | 1883 | if (argc != 1) { |
| | | 1884 | usage(); |
| | | 1885 | } |
| | | 1886 | |
| | | 1887 | device = *argv; |
| | | 1888 | |
| | | 1889 | if (ExpertFlag == 0) { |
| | | 1890 | printf("It's required to manually run fsck on filesystem device " |
| | | 1891 | "before you can resize it\n\n" |
| | | 1892 | " Did you run fsck on your disk (Yes/No) ? "); |
| | | 1893 | fgets(reply, (int)sizeof(reply), stdin); |
| | | 1894 | if (strcasecmp(reply, "Yes\n")) { |
| | | 1895 | printf("\n Nothing done \n"); |
| | | 1896 | exit(EXIT_SUCCESS); |
| | | 1897 | } |
1836 | } | | 1898 | } |
1837 | fd = open(av[1], O_RDWR, 0); | | 1899 | |
| | | 1900 | fd = open(device, O_RDWR, 0); |
1838 | if (fd < 0) | | 1901 | if (fd < 0) |
1839 | err(1, "Cannot open `%s'", av[1]); | | 1902 | err(EXIT_FAILURE, "Cannot open `%s'", device); |
1840 | checksmallio(); | | 1903 | checksmallio(); |
1841 | newsize = atoi(av[2]); | | 1904 | |
| | | 1905 | if (SFlag == 0) { |
| | | 1906 | newsize = get_dev_size(device); |
| | | 1907 | if (newsize == 0) |
| | | 1908 | err(EXIT_FAILURE, "Cannot resize filesystem, newsize not known."); |
| | | 1909 | } |
| | | 1910 | |
1842 | oldsb = (struct fs *) & sbbuf; | | 1911 | oldsb = (struct fs *) & sbbuf; |
1843 | newsb = (struct fs *) (SBLOCKSIZE + (char *) &sbbuf); | | 1912 | newsb = (struct fs *) (SBLOCKSIZE + (char *) &sbbuf); |
1844 | for (where = search[i = 0]; search[i] != -1; where = search[++i]) { | | 1913 | for (where = search[i = 0]; search[i] != -1; where = search[++i]) { |
1845 | readat(where / DEV_BSIZE, oldsb, SBLOCKSIZE); | | 1914 | readat(where / DEV_BSIZE, oldsb, SBLOCKSIZE); |
1846 | if (oldsb->fs_magic == FS_UFS1_MAGIC) | | 1915 | if (oldsb->fs_magic == FS_UFS1_MAGIC) |
1847 | break; | | 1916 | break; |
1848 | if (where == SBLOCK_UFS2) | | 1917 | if (where == SBLOCK_UFS2) |
1849 | continue; | | 1918 | continue; |
1850 | if (oldsb->fs_old_flags & FS_FLAGS_UPDATED) | | 1919 | if (oldsb->fs_old_flags & FS_FLAGS_UPDATED) |
1851 | err(1, "Cannot resize ffsv2 format suberblock!"); | | 1920 | err(EXIT_FAILURE, "Cannot resize ffsv2 format suberblock!"); |
1852 | } | | 1921 | } |
1853 | if (where == (off_t)-1) | | 1922 | if (where == (off_t)-1) |
1854 | errx(1, "Bad magic number"); | | 1923 | errx(EXIT_FAILURE, "Bad magic number"); |
1855 | oldsb->fs_qbmask = ~(int64_t) oldsb->fs_bmask; | | 1924 | oldsb->fs_qbmask = ~(int64_t) oldsb->fs_bmask; |
1856 | oldsb->fs_qfmask = ~(int64_t) oldsb->fs_fmask; | | 1925 | oldsb->fs_qfmask = ~(int64_t) oldsb->fs_fmask; |
1857 | if (oldsb->fs_ipg % INOPB(oldsb)) { | | 1926 | if (oldsb->fs_ipg % INOPB(oldsb)) { |
1858 | printf("ipg[%d] %% INOPB[%d] != 0\n", (int) oldsb->fs_ipg, | | 1927 | (void)fprintf(stderr, "ipg[%d] %% INOPB[%d] != 0\n", (int) oldsb->fs_ipg, |
1859 | (int) INOPB(oldsb)); | | 1928 | (int) INOPB(oldsb)); |
1860 | exit(1); | | 1929 | exit(EXIT_FAILURE); |
1861 | } | | 1930 | } |
1862 | /* The superblock is bigger than struct fs (there are trailing tables, | | 1931 | /* The superblock is bigger than struct fs (there are trailing tables, |
1863 | * of non-fixed size); make sure we copy the whole thing. SBLOCKSIZE may | | 1932 | * of non-fixed size); make sure we copy the whole thing. SBLOCKSIZE may |
1864 | * be an over-estimate, but we do this just once, so being generous is | | 1933 | * be an over-estimate, but we do this just once, so being generous is |
1865 | * cheap. */ | | 1934 | * cheap. */ |
1866 | bcopy(oldsb, newsb, SBLOCKSIZE); | | 1935 | bcopy(oldsb, newsb, SBLOCKSIZE); |
1867 | loadcgs(); | | 1936 | loadcgs(); |
1868 | if (newsize > fsbtodb(oldsb, oldsb->fs_size)) { | | 1937 | if (newsize > fsbtodb(oldsb, oldsb->fs_size)) { |
1869 | grow(); | | 1938 | grow(); |
1870 | } else if (newsize < fsbtodb(oldsb, oldsb->fs_size)) { | | 1939 | } else if (newsize < fsbtodb(oldsb, oldsb->fs_size)) { |
1871 | shrink(); | | 1940 | shrink(); |
1872 | } | | 1941 | } |
1873 | flush_cgs(); | | 1942 | flush_cgs(); |
1874 | write_sbs(); | | 1943 | write_sbs(); |
1875 | exit(0); | | 1944 | return 0; |
| | | 1945 | } |
| | | 1946 | |
| | | 1947 | static void |
| | | 1948 | usage(void) |
| | | 1949 | { |
| | | 1950 | |
| | | 1951 | (void)fprintf(stderr, "usage: %s [-y] [-s size] device\n", getprogname()); |
| | | 1952 | exit(EXIT_FAILURE); |
1876 | } | | 1953 | } |