| @@ -1,2200 +1,2188 @@ | | | @@ -1,2200 +1,2188 @@ |
1 | /* $NetBSD: resize_ffs.c,v 1.31 2011/08/15 02:22:46 dholland Exp $ */ | | 1 | /* $NetBSD: resize_ffs.c,v 1.32 2011/08/27 16:34:57 christos 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: |
15 | * | | 15 | * |
16 | * Resize a file system. Is capable of both growing and shrinking. | | 16 | * Resize a file system. Is capable of both growing and shrinking. |
17 | * | | 17 | * |
18 | * Usage: resize_ffs [-s newsize] [-y] file_system | | 18 | * Usage: resize_ffs [-s newsize] [-y] file_system |
19 | * | | 19 | * |
20 | * Example: resize_ffs -s 29574 /dev/rsd1e | | 20 | * Example: resize_ffs -s 29574 /dev/rsd1e |
21 | * | | 21 | * |
22 | * newsize is in DEV_BSIZE units (ie, disk sectors, usually 512 bytes | | 22 | * newsize is in DEV_BSIZE units (ie, disk sectors, usually 512 bytes |
23 | * each). | | 23 | * each). |
24 | * | | 24 | * |
25 | * Note: this currently requires gcc to build, since it is written | | 25 | * Note: this currently requires gcc to build, since it is written |
26 | * depending on gcc-specific features, notably nested function | | 26 | * depending on gcc-specific features, notably nested function |
27 | * definitions (which in at least a few cases depend on the lexical | | 27 | * definitions (which in at least a few cases depend on the lexical |
28 | * scoping gcc provides, so they can't be trivially moved outside). | | 28 | * scoping gcc provides, so they can't be trivially moved outside). |
29 | * | | 29 | * |
30 | * Many thanks go to John Kohl <jtk@NetBSD.org> for finding bugs: the | | 30 | * Many thanks go to John Kohl <jtk@NetBSD.org> for finding bugs: the |
31 | * one responsible for the "realloccgblk: can't find blk in cyl" | | 31 | * one responsible for the "realloccgblk: can't find blk in cyl" |
32 | * problem and a more minor one which left fs_dsize wrong when | | 32 | * problem and a more minor one which left fs_dsize wrong when |
33 | * shrinking. (These actually indicate bugs in fsck too - it should | | 33 | * shrinking. (These actually indicate bugs in fsck too - it should |
34 | * have caught and fixed them.) | | 34 | * have caught and fixed them.) |
35 | * | | 35 | * |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #include <sys/cdefs.h> | | 38 | #include <sys/cdefs.h> |
39 | __RCSID("$NetBSD: resize_ffs.c,v 1.31 2011/08/15 02:22:46 dholland Exp $"); | | 39 | __RCSID("$NetBSD: resize_ffs.c,v 1.32 2011/08/27 16:34:57 christos Exp $"); |
40 | | | 40 | |
41 | #include <sys/disk.h> | | 41 | #include <sys/disk.h> |
42 | #include <sys/disklabel.h> | | 42 | #include <sys/disklabel.h> |
43 | #include <sys/dkio.h> | | 43 | #include <sys/dkio.h> |
44 | #include <sys/ioctl.h> | | 44 | #include <sys/ioctl.h> |
45 | #include <sys/stat.h> | | 45 | #include <sys/stat.h> |
46 | #include <sys/mman.h> | | 46 | #include <sys/mman.h> |
47 | #include <sys/param.h> /* MAXFRAG */ | | 47 | #include <sys/param.h> /* MAXFRAG */ |
48 | #include <ufs/ffs/fs.h> | | 48 | #include <ufs/ffs/fs.h> |
49 | #include <ufs/ffs/ffs_extern.h> | | 49 | #include <ufs/ffs/ffs_extern.h> |
50 | #include <ufs/ufs/dir.h> | | 50 | #include <ufs/ufs/dir.h> |
51 | #include <ufs/ufs/dinode.h> | | 51 | #include <ufs/ufs/dinode.h> |
52 | #include <ufs/ufs/ufs_bswap.h> /* ufs_rw32 */ | | 52 | #include <ufs/ufs/ufs_bswap.h> /* ufs_rw32 */ |
53 | | | 53 | |
54 | #include <err.h> | | 54 | #include <err.h> |
55 | #include <errno.h> | | 55 | #include <errno.h> |
56 | #include <fcntl.h> | | 56 | #include <fcntl.h> |
57 | #include <stdio.h> | | 57 | #include <stdio.h> |
58 | #include <stdlib.h> | | 58 | #include <stdlib.h> |
59 | #include <strings.h> | | 59 | #include <strings.h> |
60 | #include <unistd.h> | | 60 | #include <unistd.h> |
61 | | | 61 | |
62 | /* new size of file system, in sectors */ | | 62 | /* new size of file system, in sectors */ |
63 | static int64_t newsize; | | 63 | static int64_t newsize; |
64 | | | 64 | |
65 | /* fd open onto disk device or file */ | | 65 | /* fd open onto disk device or file */ |
66 | static int fd; | | 66 | static int fd; |
67 | | | 67 | |
68 | /* must we break up big I/O operations - see checksmallio() */ | | 68 | /* must we break up big I/O operations - see checksmallio() */ |
69 | static int smallio; | | 69 | static int smallio; |
70 | | | 70 | |
71 | /* size of a cg, in bytes, rounded up to a frag boundary */ | | 71 | /* size of a cg, in bytes, rounded up to a frag boundary */ |
72 | static int cgblksz; | | 72 | static int cgblksz; |
73 | | | 73 | |
74 | /* possible superblock localtions */ | | 74 | /* possible superblock localtions */ |
75 | static int search[] = SBLOCKSEARCH; | | 75 | static int search[] = SBLOCKSEARCH; |
76 | /* location of the superblock */ | | 76 | /* location of the superblock */ |
77 | static off_t where; | | 77 | static off_t where; |
78 | | | 78 | |
79 | /* Superblocks. */ | | 79 | /* Superblocks. */ |
80 | static struct fs *oldsb; /* before we started */ | | 80 | static struct fs *oldsb; /* before we started */ |
81 | static struct fs *newsb; /* copy to work with */ | | 81 | static struct fs *newsb; /* copy to work with */ |
82 | /* Buffer to hold the above. Make sure it's aligned correctly. */ | | 82 | /* Buffer to hold the above. Make sure it's aligned correctly. */ |
83 | static char sbbuf[2 * SBLOCKSIZE] | | 83 | static char sbbuf[2 * SBLOCKSIZE] |
84 | __attribute__((__aligned__(__alignof__(struct fs)))); | | 84 | __attribute__((__aligned__(__alignof__(struct fs)))); |
85 | | | 85 | |
86 | union dinode { | | 86 | union dinode { |
87 | struct ufs1_dinode dp1; | | 87 | struct ufs1_dinode dp1; |
88 | struct ufs2_dinode dp2; | | 88 | struct ufs2_dinode dp2; |
89 | }; | | 89 | }; |
90 | #define DIP(dp, field) \ | | 90 | #define DIP(dp, field) \ |
91 | ((is_ufs2) ? \ | | 91 | ((is_ufs2) ? \ |
92 | (dp)->dp2.field : (dp)->dp1.field) | | 92 | (dp)->dp2.field : (dp)->dp1.field) |
93 | | | 93 | |
94 | #define DIP_ASSIGN(dp, field, value) \ | | 94 | #define DIP_ASSIGN(dp, field, value) \ |
95 | do { \ | | 95 | do { \ |
96 | if (is_ufs2) \ | | 96 | if (is_ufs2) \ |
97 | (dp)->dp2.field = (value); \ | | 97 | (dp)->dp2.field = (value); \ |
98 | else \ | | 98 | else \ |
99 | (dp)->dp1.field = (value); \ | | 99 | (dp)->dp1.field = (value); \ |
100 | } while (0) | | 100 | } while (0) |
101 | | | 101 | |
102 | /* a cg's worth of brand new squeaky-clean inodes */ | | 102 | /* a cg's worth of brand new squeaky-clean inodes */ |
103 | static struct ufs1_dinode *zinodes; | | 103 | static struct ufs1_dinode *zinodes; |
104 | | | 104 | |
105 | /* pointers to the in-core cgs, read off disk and possibly modified */ | | 105 | /* pointers to the in-core cgs, read off disk and possibly modified */ |
106 | static struct cg **cgs; | | 106 | static struct cg **cgs; |
107 | | | 107 | |
108 | /* pointer to csum array - the stuff pointed to on-disk by fs_csaddr */ | | 108 | /* pointer to csum array - the stuff pointed to on-disk by fs_csaddr */ |
109 | static struct csum *csums; | | 109 | static struct csum *csums; |
110 | | | 110 | |
111 | /* per-cg flags, indexed by cg number */ | | 111 | /* per-cg flags, indexed by cg number */ |
112 | static unsigned char *cgflags; | | 112 | static unsigned char *cgflags; |
113 | #define CGF_DIRTY 0x01 /* needs to be written to disk */ | | 113 | #define CGF_DIRTY 0x01 /* needs to be written to disk */ |
114 | #define CGF_BLKMAPS 0x02 /* block bitmaps need rebuilding */ | | 114 | #define CGF_BLKMAPS 0x02 /* block bitmaps need rebuilding */ |
115 | #define CGF_INOMAPS 0x04 /* inode bitmaps need rebuilding */ | | 115 | #define CGF_INOMAPS 0x04 /* inode bitmaps need rebuilding */ |
116 | | | 116 | |
117 | /* when shrinking, these two arrays record how we want blocks to move. */ | | 117 | /* when shrinking, these two arrays record how we want blocks to move. */ |
118 | /* if blkmove[i] is j, the frag that started out as frag #i should end */ | | 118 | /* if blkmove[i] is j, the frag that started out as frag #i should end */ |
119 | /* up as frag #j. inomove[i]=j means, similarly, that the inode that */ | | 119 | /* up as frag #j. inomove[i]=j means, similarly, that the inode that */ |
120 | /* started out as inode i should end up as inode j. */ | | 120 | /* started out as inode i should end up as inode j. */ |
121 | static unsigned int *blkmove; | | 121 | static unsigned int *blkmove; |
122 | static unsigned int *inomove; | | 122 | static unsigned int *inomove; |
123 | | | 123 | |
124 | /* in-core copies of all inodes in the fs, indexed by inumber */ | | 124 | /* in-core copies of all inodes in the fs, indexed by inumber */ |
125 | union dinode *inodes; | | 125 | union dinode *inodes; |
126 | | | 126 | |
127 | void *ibuf; /* ptr to fs block-sized buffer for reading/writing inodes */ | | 127 | void *ibuf; /* ptr to fs block-sized buffer for reading/writing inodes */ |
128 | | | 128 | |
129 | /* byteswapped inodes */ | | 129 | /* byteswapped inodes */ |
130 | union dinode *sinodes; | | 130 | union dinode *sinodes; |
131 | | | 131 | |
132 | /* per-inode flags, indexed by inumber */ | | 132 | /* per-inode flags, indexed by inumber */ |
133 | static unsigned char *iflags; | | 133 | static unsigned char *iflags; |
134 | #define IF_DIRTY 0x01 /* needs to be written to disk */ | | 134 | #define IF_DIRTY 0x01 /* needs to be written to disk */ |
135 | #define IF_BDIRTY 0x02 /* like DIRTY, but is set on first inode in a | | 135 | #define IF_BDIRTY 0x02 /* like DIRTY, but is set on first inode in a |
136 | * block of inodes, and applies to the whole | | 136 | * block of inodes, and applies to the whole |
137 | * block. */ | | 137 | * block. */ |
138 | | | 138 | |
139 | /* resize_ffs works directly on dinodes, adapt blksize() */ | | 139 | /* resize_ffs works directly on dinodes, adapt blksize() */ |
140 | #define dblksize(fs, dip, lbn, filesize) \ | | 140 | #define dblksize(fs, dip, lbn, filesize) \ |
141 | (((lbn) >= NDADDR || (filesize) >= lblktosize(fs, (lbn) + 1)) \ | | 141 | (((lbn) >= NDADDR || (filesize) >= lblktosize(fs, (lbn) + 1)) \ |
142 | ? (fs)->fs_bsize \ | | 142 | ? (fs)->fs_bsize \ |
143 | : (fragroundup(fs, blkoff(fs, (filesize))))) | | 143 | : (fragroundup(fs, blkoff(fs, (filesize))))) |
144 | | | 144 | |
145 | | | 145 | |
146 | /* | | 146 | /* |
147 | * Number of disk sectors per block/fragment | | 147 | * Number of disk sectors per block/fragment |
148 | */ | | 148 | */ |
149 | #define NSPB(fs) (fsbtodb((fs),1) << (fs)->fs_fragshift) | | 149 | #define NSPB(fs) (fsbtodb((fs),1) << (fs)->fs_fragshift) |
150 | #define NSPF(fs) (fsbtodb((fs),1)) | | 150 | #define NSPF(fs) (fsbtodb((fs),1)) |
151 | | | 151 | |
152 | /* global flags */ | | 152 | /* global flags */ |
153 | int is_ufs2 = 0; | | 153 | int is_ufs2 = 0; |
154 | int needswap = 0; | | 154 | int needswap = 0; |
155 | | | 155 | |
156 | static void usage(void) __dead; | | 156 | static void usage(void) __dead; |
157 | | | 157 | |
158 | /* | | 158 | /* |
159 | * See if we need to break up large I/O operations. This should never | | 159 | * See if we need to break up large I/O operations. This should never |
160 | * be needed, but under at least one <version,platform> combination, | | 160 | * be needed, but under at least one <version,platform> combination, |
161 | * large enough disk transfers to the raw device hang. So if we're | | 161 | * large enough disk transfers to the raw device hang. So if we're |
162 | * talking to a character special device, play it safe; in this case, | | 162 | * talking to a character special device, play it safe; in this case, |
163 | * readat() and writeat() break everything up into pieces no larger | | 163 | * readat() and writeat() break everything up into pieces no larger |
164 | * than 8K, doing multiple syscalls for larger operations. | | 164 | * than 8K, doing multiple syscalls for larger operations. |
165 | */ | | 165 | */ |
166 | static void | | 166 | static void |
167 | checksmallio(void) | | 167 | checksmallio(void) |
168 | { | | 168 | { |
169 | struct stat stb; | | 169 | struct stat stb; |
170 | | | 170 | |
171 | fstat(fd, &stb); | | 171 | fstat(fd, &stb); |
172 | smallio = ((stb.st_mode & S_IFMT) == S_IFCHR); | | 172 | smallio = ((stb.st_mode & S_IFMT) == S_IFCHR); |
173 | } | | 173 | } |
174 | | | 174 | |
175 | static int | | 175 | static int |
176 | isplainfile(void) | | 176 | isplainfile(void) |
177 | { | | 177 | { |
178 | struct stat stb; | | 178 | struct stat stb; |
179 | | | 179 | |
180 | fstat(fd, &stb); | | 180 | fstat(fd, &stb); |
181 | return S_ISREG(stb.st_mode); | | 181 | return S_ISREG(stb.st_mode); |
182 | } | | 182 | } |
183 | /* | | 183 | /* |
184 | * Read size bytes starting at blkno into buf. blkno is in DEV_BSIZE | | 184 | * Read size bytes starting at blkno into buf. blkno is in DEV_BSIZE |
185 | * units, ie, after fsbtodb(); size is in bytes. | | 185 | * units, ie, after fsbtodb(); size is in bytes. |
186 | */ | | 186 | */ |
187 | static void | | 187 | static void |
188 | readat(off_t blkno, void *buf, int size) | | 188 | readat(off_t blkno, void *buf, int size) |
189 | { | | 189 | { |
190 | /* Seek to the correct place. */ | | 190 | /* Seek to the correct place. */ |
191 | if (lseek(fd, blkno * DEV_BSIZE, L_SET) < 0) | | 191 | if (lseek(fd, blkno * DEV_BSIZE, L_SET) < 0) |
192 | err(EXIT_FAILURE, "lseek failed"); | | 192 | err(EXIT_FAILURE, "lseek failed"); |
193 | | | 193 | |
194 | /* See if we have to break up the transfer... */ | | 194 | /* See if we have to break up the transfer... */ |
195 | if (smallio) { | | 195 | if (smallio) { |
196 | char *bp; /* pointer into buf */ | | 196 | char *bp; /* pointer into buf */ |
197 | int left; /* bytes left to go */ | | 197 | int left; /* bytes left to go */ |
198 | int n; /* number to do this time around */ | | 198 | int n; /* number to do this time around */ |
199 | int rv; /* syscall return value */ | | 199 | int rv; /* syscall return value */ |
200 | bp = buf; | | 200 | bp = buf; |
201 | left = size; | | 201 | left = size; |
202 | while (left > 0) { | | 202 | while (left > 0) { |
203 | n = (left > 8192) ? 8192 : left; | | 203 | n = (left > 8192) ? 8192 : left; |
204 | rv = read(fd, bp, n); | | 204 | rv = read(fd, bp, n); |
205 | if (rv < 0) | | 205 | if (rv < 0) |
206 | err(EXIT_FAILURE, "read failed"); | | 206 | err(EXIT_FAILURE, "read failed"); |
207 | if (rv != n) | | 207 | if (rv != n) |
208 | errx(EXIT_FAILURE, | | 208 | errx(EXIT_FAILURE, |
209 | "read: wanted %d, got %d", n, rv); | | 209 | "read: wanted %d, got %d", n, rv); |
210 | bp += n; | | 210 | bp += n; |
211 | left -= n; | | 211 | left -= n; |
212 | } | | 212 | } |
213 | } else { | | 213 | } else { |
214 | int rv; | | 214 | int rv; |
215 | rv = read(fd, buf, size); | | 215 | rv = read(fd, buf, size); |
216 | if (rv < 0) | | 216 | if (rv < 0) |
217 | err(EXIT_FAILURE, "read failed"); | | 217 | err(EXIT_FAILURE, "read failed"); |
218 | if (rv != size) | | 218 | if (rv != size) |
219 | errx(EXIT_FAILURE, "read: wanted %d, got %d", | | 219 | errx(EXIT_FAILURE, "read: wanted %d, got %d", |
220 | size, rv); | | 220 | size, rv); |
221 | } | | 221 | } |
222 | } | | 222 | } |
223 | /* | | 223 | /* |
224 | * Write size bytes from buf starting at blkno. blkno is in DEV_BSIZE | | 224 | * Write size bytes from buf starting at blkno. blkno is in DEV_BSIZE |
225 | * units, ie, after fsbtodb(); size is in bytes. | | 225 | * units, ie, after fsbtodb(); size is in bytes. |
226 | */ | | 226 | */ |
227 | static void | | 227 | static void |
228 | writeat(off_t blkno, const void *buf, int size) | | 228 | writeat(off_t blkno, const void *buf, int size) |
229 | { | | 229 | { |
230 | /* Seek to the correct place. */ | | 230 | /* Seek to the correct place. */ |
231 | if (lseek(fd, blkno * DEV_BSIZE, L_SET) < 0) | | 231 | if (lseek(fd, blkno * DEV_BSIZE, L_SET) < 0) |
232 | err(EXIT_FAILURE, "lseek failed"); | | 232 | err(EXIT_FAILURE, "lseek failed"); |
233 | /* See if we have to break up the transfer... */ | | 233 | /* See if we have to break up the transfer... */ |
234 | if (smallio) { | | 234 | if (smallio) { |
235 | const char *bp; /* pointer into buf */ | | 235 | const char *bp; /* pointer into buf */ |
236 | int left; /* bytes left to go */ | | 236 | int left; /* bytes left to go */ |
237 | int n; /* number to do this time around */ | | 237 | int n; /* number to do this time around */ |
238 | int rv; /* syscall return value */ | | 238 | int rv; /* syscall return value */ |
239 | bp = buf; | | 239 | bp = buf; |
240 | left = size; | | 240 | left = size; |
241 | while (left > 0) { | | 241 | while (left > 0) { |
242 | n = (left > 8192) ? 8192 : left; | | 242 | n = (left > 8192) ? 8192 : left; |
243 | rv = write(fd, bp, n); | | 243 | rv = write(fd, bp, n); |
244 | if (rv < 0) | | 244 | if (rv < 0) |
245 | err(EXIT_FAILURE, "write failed"); | | 245 | err(EXIT_FAILURE, "write failed"); |
246 | if (rv != n) | | 246 | if (rv != n) |
247 | errx(EXIT_FAILURE, | | 247 | errx(EXIT_FAILURE, |
248 | "write: wanted %d, got %d", n, rv); | | 248 | "write: wanted %d, got %d", n, rv); |
249 | bp += n; | | 249 | bp += n; |
250 | left -= n; | | 250 | left -= n; |
251 | } | | 251 | } |
252 | } else { | | 252 | } else { |
253 | int rv; | | 253 | int rv; |
254 | rv = write(fd, buf, size); | | 254 | rv = write(fd, buf, size); |
255 | if (rv < 0) | | 255 | if (rv < 0) |
256 | err(EXIT_FAILURE, "write failed"); | | 256 | err(EXIT_FAILURE, "write failed"); |
257 | if (rv != size) | | 257 | if (rv != size) |
258 | errx(EXIT_FAILURE, | | 258 | errx(EXIT_FAILURE, |
259 | "write: wanted %d, got %d", size, rv); | | 259 | "write: wanted %d, got %d", size, rv); |
260 | } | | 260 | } |
261 | } | | 261 | } |
262 | /* | | 262 | /* |
263 | * Never-fail versions of malloc() and realloc(), and an allocation | | 263 | * Never-fail versions of malloc() and realloc(), and an allocation |
264 | * routine (which also never fails) for allocating memory that will | | 264 | * routine (which also never fails) for allocating memory that will |
265 | * never be freed until exit. | | 265 | * never be freed until exit. |
266 | */ | | 266 | */ |
267 | | | 267 | |
268 | /* | | 268 | /* |
269 | * Never-fail malloc. | | 269 | * Never-fail malloc. |
270 | */ | | 270 | */ |
271 | static void * | | 271 | static void * |
272 | nfmalloc(size_t nb, const char *tag) | | 272 | nfmalloc(size_t nb, const char *tag) |
273 | { | | 273 | { |
274 | void *rv; | | 274 | void *rv; |
275 | | | 275 | |
276 | rv = malloc(nb); | | 276 | rv = malloc(nb); |
277 | if (rv) | | 277 | if (rv) |
278 | return (rv); | | 278 | return (rv); |
279 | err(EXIT_FAILURE, "Can't allocate %lu bytes for %s", | | 279 | err(EXIT_FAILURE, "Can't allocate %lu bytes for %s", |
280 | (unsigned long int) nb, tag); | | 280 | (unsigned long int) nb, tag); |
281 | } | | 281 | } |
282 | /* | | 282 | /* |
283 | * Never-fail realloc. | | 283 | * Never-fail realloc. |
284 | */ | | 284 | */ |
285 | static void * | | 285 | static void * |
286 | nfrealloc(void *blk, size_t nb, const char *tag) | | 286 | nfrealloc(void *blk, size_t nb, const char *tag) |
287 | { | | 287 | { |
288 | void *rv; | | 288 | void *rv; |
289 | | | 289 | |
290 | rv = realloc(blk, nb); | | 290 | rv = realloc(blk, nb); |
291 | if (rv) | | 291 | if (rv) |
292 | return (rv); | | 292 | return (rv); |
293 | err(EXIT_FAILURE, "Can't re-allocate %lu bytes for %s", | | 293 | err(EXIT_FAILURE, "Can't re-allocate %lu bytes for %s", |
294 | (unsigned long int) nb, tag); | | 294 | (unsigned long int) nb, tag); |
295 | } | | 295 | } |
296 | /* | | 296 | /* |
297 | * Allocate memory that will never be freed or reallocated. Arguably | | 297 | * Allocate memory that will never be freed or reallocated. Arguably |
298 | * this routine should handle small allocations by chopping up pages, | | 298 | * this routine should handle small allocations by chopping up pages, |
299 | * but that's not worth the bother; it's not called more than a | | 299 | * but that's not worth the bother; it's not called more than a |
300 | * handful of times per run, and if the allocations are that small the | | 300 | * handful of times per run, and if the allocations are that small the |
301 | * waste in giving each one its own page is ignorable. | | 301 | * waste in giving each one its own page is ignorable. |
302 | */ | | 302 | */ |
303 | static void * | | 303 | static void * |
304 | alloconce(size_t nb, const char *tag) | | 304 | alloconce(size_t nb, const char *tag) |
305 | { | | 305 | { |
306 | void *rv; | | 306 | void *rv; |
307 | | | 307 | |
308 | rv = mmap(0, nb, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | | 308 | rv = mmap(0, nb, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
309 | if (rv != MAP_FAILED) | | 309 | if (rv != MAP_FAILED) |
310 | return (rv); | | 310 | return (rv); |
311 | err(EXIT_FAILURE, "Can't map %lu bytes for %s", | | 311 | err(EXIT_FAILURE, "Can't map %lu bytes for %s", |
312 | (unsigned long int) nb, tag); | | 312 | (unsigned long int) nb, tag); |
313 | } | | 313 | } |
314 | /* | | 314 | /* |
315 | * Load the cgs and csums off disk. Also allocates the space to load | | 315 | * Load the cgs and csums off disk. Also allocates the space to load |
316 | * them into and initializes the per-cg flags. | | 316 | * them into and initializes the per-cg flags. |
317 | */ | | 317 | */ |
318 | static void | | 318 | static void |
319 | loadcgs(void) | | 319 | loadcgs(void) |
320 | { | | 320 | { |
321 | int cg; | | 321 | int cg; |
322 | char *cgp; | | 322 | char *cgp; |
323 | | | 323 | |
324 | cgblksz = roundup(oldsb->fs_cgsize, oldsb->fs_fsize); | | 324 | cgblksz = roundup(oldsb->fs_cgsize, oldsb->fs_fsize); |
325 | cgs = nfmalloc(oldsb->fs_ncg * sizeof(struct cg *), "cg pointers"); | | 325 | cgs = nfmalloc(oldsb->fs_ncg * sizeof(*cgs), "cg pointers"); |
326 | cgp = alloconce(oldsb->fs_ncg * cgblksz, "cgs"); | | 326 | cgp = alloconce(oldsb->fs_ncg * cgblksz, "cgs"); |
327 | cgflags = nfmalloc(oldsb->fs_ncg, "cg flags"); | | 327 | cgflags = nfmalloc(oldsb->fs_ncg, "cg flags"); |
328 | csums = nfmalloc(oldsb->fs_cssize, "cg summary"); | | 328 | csums = nfmalloc(oldsb->fs_cssize, "cg summary"); |
329 | for (cg = 0; cg < oldsb->fs_ncg; cg++) { | | 329 | for (cg = 0; cg < oldsb->fs_ncg; cg++) { |
330 | cgs[cg] = (struct cg *) cgp; | | 330 | cgs[cg] = (struct cg *) cgp; |
331 | readat(fsbtodb(oldsb, cgtod(oldsb, cg)), cgp, cgblksz); | | 331 | readat(fsbtodb(oldsb, cgtod(oldsb, cg)), cgp, cgblksz); |
332 | if (needswap) | | 332 | if (needswap) |
333 | ffs_cg_swap(cgs[cg],cgs[cg],oldsb); | | 333 | ffs_cg_swap(cgs[cg],cgs[cg],oldsb); |
334 | cgflags[cg] = 0; | | 334 | cgflags[cg] = 0; |
335 | cgp += cgblksz; | | 335 | cgp += cgblksz; |
336 | } | | 336 | } |
337 | readat(fsbtodb(oldsb, oldsb->fs_csaddr), csums, oldsb->fs_cssize); | | 337 | readat(fsbtodb(oldsb, oldsb->fs_csaddr), csums, oldsb->fs_cssize); |
338 | if (needswap) | | 338 | if (needswap) |
339 | ffs_csum_swap(csums,csums,oldsb->fs_cssize); | | 339 | ffs_csum_swap(csums,csums,oldsb->fs_cssize); |
340 | } | | 340 | } |
341 | /* | | 341 | /* |
342 | * Set n bits, starting with bit #base, in the bitmap pointed to by | | 342 | * Set n bits, starting with bit #base, in the bitmap pointed to by |
343 | * bitvec (which is assumed to be large enough to include bits base | | 343 | * bitvec (which is assumed to be large enough to include bits base |
344 | * through base+n-1). | | 344 | * through base+n-1). |
345 | */ | | 345 | */ |
346 | static void | | 346 | static void |
347 | set_bits(unsigned char *bitvec, unsigned int base, unsigned int n) | | 347 | set_bits(unsigned char *bitvec, unsigned int base, unsigned int n) |
348 | { | | 348 | { |
349 | if (n < 1) | | 349 | if (n < 1) |
350 | return; /* nothing to do */ | | 350 | return; /* nothing to do */ |
351 | if (base & 7) { /* partial byte at beginning */ | | 351 | if (base & 7) { /* partial byte at beginning */ |
352 | if (n <= 8 - (base & 7)) { /* entirely within one byte */ | | 352 | if (n <= 8 - (base & 7)) { /* entirely within one byte */ |
353 | bitvec[base >> 3] |= (~((~0U) << n)) << (base & 7); | | 353 | bitvec[base >> 3] |= (~((~0U) << n)) << (base & 7); |
354 | return; | | 354 | return; |
355 | } | | 355 | } |
356 | bitvec[base >> 3] |= (~0U) << (base & 7); | | 356 | bitvec[base >> 3] |= (~0U) << (base & 7); |
357 | n -= 8 - (base & 7); | | 357 | n -= 8 - (base & 7); |
358 | base = (base & ~7) + 8; | | 358 | base = (base & ~7) + 8; |
359 | } | | 359 | } |
360 | if (n >= 8) { /* do full bytes */ | | 360 | if (n >= 8) { /* do full bytes */ |
361 | memset(bitvec + (base >> 3), 0xff, n >> 3); | | 361 | memset(bitvec + (base >> 3), 0xff, n >> 3); |
362 | base += n & ~7; | | 362 | base += n & ~7; |
363 | n &= 7; | | 363 | n &= 7; |
364 | } | | 364 | } |
365 | if (n) { /* partial byte at end */ | | 365 | if (n) { /* partial byte at end */ |
366 | bitvec[base >> 3] |= ~((~0U) << n); | | 366 | bitvec[base >> 3] |= ~((~0U) << n); |
367 | } | | 367 | } |
368 | } | | 368 | } |
369 | /* | | 369 | /* |
370 | * Clear n bits, starting with bit #base, in the bitmap pointed to by | | 370 | * Clear n bits, starting with bit #base, in the bitmap pointed to by |
371 | * bitvec (which is assumed to be large enough to include bits base | | 371 | * bitvec (which is assumed to be large enough to include bits base |
372 | * through base+n-1). Code parallels set_bits(). | | 372 | * through base+n-1). Code parallels set_bits(). |
373 | */ | | 373 | */ |
374 | static void | | 374 | static void |
375 | clr_bits(unsigned char *bitvec, int base, int n) | | 375 | clr_bits(unsigned char *bitvec, int base, int n) |
376 | { | | 376 | { |
377 | if (n < 1) | | 377 | if (n < 1) |
378 | return; | | 378 | return; |
379 | if (base & 7) { | | 379 | if (base & 7) { |
380 | if (n <= 8 - (base & 7)) { | | 380 | if (n <= 8 - (base & 7)) { |
381 | bitvec[base >> 3] &= ~((~((~0U) << n)) << (base & 7)); | | 381 | bitvec[base >> 3] &= ~((~((~0U) << n)) << (base & 7)); |
382 | return; | | 382 | return; |
383 | } | | 383 | } |
384 | bitvec[base >> 3] &= ~((~0U) << (base & 7)); | | 384 | bitvec[base >> 3] &= ~((~0U) << (base & 7)); |
385 | n -= 8 - (base & 7); | | 385 | n -= 8 - (base & 7); |
386 | base = (base & ~7) + 8; | | 386 | base = (base & ~7) + 8; |
387 | } | | 387 | } |
388 | if (n >= 8) { | | 388 | if (n >= 8) { |
389 | memset(bitvec + (base >> 3), 0, n >> 3); | | 389 | memset(bitvec + (base >> 3), 0, n >> 3); |
390 | base += n & ~7; | | 390 | base += n & ~7; |
391 | n &= 7; | | 391 | n &= 7; |
392 | } | | 392 | } |
393 | if (n) { | | 393 | if (n) { |
394 | bitvec[base >> 3] &= (~0U) << n; | | 394 | bitvec[base >> 3] &= (~0U) << n; |
395 | } | | 395 | } |
396 | } | | 396 | } |
397 | /* | | 397 | /* |
398 | * Test whether bit #bit is set in the bitmap pointed to by bitvec. | | 398 | * Test whether bit #bit is set in the bitmap pointed to by bitvec. |
399 | */ | | 399 | */ |
400 | static int | | 400 | static int |
401 | bit_is_set(unsigned char *bitvec, int bit) | | 401 | bit_is_set(unsigned char *bitvec, int bit) |
402 | { | | 402 | { |
403 | return (bitvec[bit >> 3] & (1 << (bit & 7))); | | 403 | return (bitvec[bit >> 3] & (1 << (bit & 7))); |
404 | } | | 404 | } |
405 | /* | | 405 | /* |
406 | * Test whether bit #bit is clear in the bitmap pointed to by bitvec. | | 406 | * Test whether bit #bit is clear in the bitmap pointed to by bitvec. |
407 | */ | | 407 | */ |
408 | static int | | 408 | static int |
409 | bit_is_clr(unsigned char *bitvec, int bit) | | 409 | bit_is_clr(unsigned char *bitvec, int bit) |
410 | { | | 410 | { |
411 | return (!bit_is_set(bitvec, bit)); | | 411 | return (!bit_is_set(bitvec, bit)); |
412 | } | | 412 | } |
413 | /* | | 413 | /* |
414 | * Test whether a whole block of bits is set in a bitmap. This is | | 414 | * Test whether a whole block of bits is set in a bitmap. This is |
415 | * designed for testing (aligned) disk blocks in a bit-per-frag | | 415 | * designed for testing (aligned) disk blocks in a bit-per-frag |
416 | * bitmap; it has assumptions wired into it based on that, essentially | | 416 | * bitmap; it has assumptions wired into it based on that, essentially |
417 | * that the entire block fits into a single byte. This returns true | | 417 | * that the entire block fits into a single byte. This returns true |
418 | * iff _all_ the bits are set; it is not just the complement of | | 418 | * iff _all_ the bits are set; it is not just the complement of |
419 | * blk_is_clr on the same arguments (unless blkfrags==1). | | 419 | * blk_is_clr on the same arguments (unless blkfrags==1). |
420 | */ | | 420 | */ |
421 | static int | | 421 | static int |
422 | blk_is_set(unsigned char *bitvec, int blkbase, int blkfrags) | | 422 | blk_is_set(unsigned char *bitvec, int blkbase, int blkfrags) |
423 | { | | 423 | { |
424 | unsigned int mask; | | 424 | unsigned int mask; |
425 | | | 425 | |
426 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); | | 426 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); |
427 | return ((bitvec[blkbase >> 3] & mask) == mask); | | 427 | return ((bitvec[blkbase >> 3] & mask) == mask); |
428 | } | | 428 | } |
429 | /* | | 429 | /* |
430 | * Test whether a whole block of bits is clear in a bitmap. See | | 430 | * Test whether a whole block of bits is clear in a bitmap. See |
431 | * blk_is_set (above) for assumptions. This returns true iff _all_ | | 431 | * blk_is_set (above) for assumptions. This returns true iff _all_ |
432 | * the bits are clear; it is not just the complement of blk_is_set on | | 432 | * the bits are clear; it is not just the complement of blk_is_set on |
433 | * the same arguments (unless blkfrags==1). | | 433 | * the same arguments (unless blkfrags==1). |
434 | */ | | 434 | */ |
435 | static int | | 435 | static int |
436 | blk_is_clr(unsigned char *bitvec, int blkbase, int blkfrags) | | 436 | blk_is_clr(unsigned char *bitvec, int blkbase, int blkfrags) |
437 | { | | 437 | { |
438 | unsigned int mask; | | 438 | unsigned int mask; |
439 | | | 439 | |
440 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); | | 440 | mask = (~((~0U) << blkfrags)) << (blkbase & 7); |
441 | return ((bitvec[blkbase >> 3] & mask) == 0); | | 441 | return ((bitvec[blkbase >> 3] & mask) == 0); |
442 | } | | 442 | } |
443 | /* | | 443 | /* |
444 | * Initialize a new cg. Called when growing. Assumes memory has been | | 444 | * Initialize a new cg. Called when growing. Assumes memory has been |
445 | * allocated but not otherwise set up. This code sets the fields of | | 445 | * allocated but not otherwise set up. This code sets the fields of |
446 | * the cg, initializes the bitmaps (and cluster summaries, if | | 446 | * the cg, initializes the bitmaps (and cluster summaries, if |
447 | * applicable), updates both per-cylinder summary info and the global | | 447 | * applicable), updates both per-cylinder summary info and the global |
448 | * summary info in newsb; it also writes out new inodes for the cg. | | 448 | * summary info in newsb; it also writes out new inodes for the cg. |
449 | * | | 449 | * |
450 | * This code knows it can never be called for cg 0, which makes it a | | 450 | * This code knows it can never be called for cg 0, which makes it a |
451 | * bit simpler than it would otherwise be. | | 451 | * bit simpler than it would otherwise be. |
452 | */ | | 452 | */ |
453 | static void | | 453 | static void |
454 | initcg(int cgn) | | 454 | initcg(int cgn) |
455 | { | | 455 | { |
456 | struct cg *cg; /* The in-core cg, of course */ | | 456 | struct cg *cg; /* The in-core cg, of course */ |
457 | int base; /* Disk address of cg base */ | | 457 | int base; /* Disk address of cg base */ |
458 | int dlow; /* Size of pre-cg data area */ | | 458 | int dlow; /* Size of pre-cg data area */ |
459 | int dhigh; /* Offset of post-inode data area, from base */ | | 459 | int dhigh; /* Offset of post-inode data area, from base */ |
460 | int dmax; /* Offset of end of post-inode data area */ | | 460 | int dmax; /* Offset of end of post-inode data area */ |
461 | int i; /* Generic loop index */ | | 461 | int i; /* Generic loop index */ |
462 | int n; /* Generic count */ | | 462 | int n; /* Generic count */ |
463 | int start; /* start of cg maps */ | | 463 | int start; /* start of cg maps */ |
464 | | | 464 | |
465 | cg = cgs[cgn]; | | 465 | cg = cgs[cgn]; |
466 | /* Place the data areas */ | | 466 | /* Place the data areas */ |
467 | base = cgbase(newsb, cgn); | | 467 | base = cgbase(newsb, cgn); |
468 | dlow = cgsblock(newsb, cgn) - base; | | 468 | dlow = cgsblock(newsb, cgn) - base; |
469 | dhigh = cgdmin(newsb, cgn) - base; | | 469 | dhigh = cgdmin(newsb, cgn) - base; |
470 | dmax = newsb->fs_size - base; | | 470 | dmax = newsb->fs_size - base; |
471 | if (dmax > newsb->fs_fpg) | | 471 | if (dmax > newsb->fs_fpg) |
472 | dmax = newsb->fs_fpg; | | 472 | dmax = newsb->fs_fpg; |
473 | start = &cg->cg_space[0] - (unsigned char *) cg; | | 473 | start = &cg->cg_space[0] - (unsigned char *) cg; |
474 | /* | | 474 | /* |
475 | * Clear out the cg - assumes all-0-bytes is the correct way | | 475 | * Clear out the cg - assumes all-0-bytes is the correct way |
476 | * to initialize fields we don't otherwise touch, which is | | 476 | * to initialize fields we don't otherwise touch, which is |
477 | * perhaps not the right thing to do, but it's what fsck and | | 477 | * perhaps not the right thing to do, but it's what fsck and |
478 | * mkfs do. | | 478 | * mkfs do. |
479 | */ | | 479 | */ |
480 | memset(cg, 0, newsb->fs_cgsize); | | 480 | memset(cg, 0, newsb->fs_cgsize); |
481 | if (newsb->fs_old_flags & FS_FLAGS_UPDATED) | | 481 | if (newsb->fs_old_flags & FS_FLAGS_UPDATED) |
482 | cg->cg_time = newsb->fs_time; | | 482 | cg->cg_time = newsb->fs_time; |
483 | cg->cg_magic = CG_MAGIC; | | 483 | cg->cg_magic = CG_MAGIC; |
484 | cg->cg_cgx = cgn; | | 484 | cg->cg_cgx = cgn; |
485 | cg->cg_niblk = newsb->fs_ipg; | | 485 | cg->cg_niblk = newsb->fs_ipg; |
486 | cg->cg_ndblk = dmax; | | 486 | cg->cg_ndblk = dmax; |
487 | | | 487 | |
488 | if (is_ufs2) { | | 488 | if (is_ufs2) { |
489 | cg->cg_time = newsb->fs_time; | | 489 | cg->cg_time = newsb->fs_time; |
490 | cg->cg_initediblk = newsb->fs_ipg < 2 * INOPB(newsb) ? | | 490 | cg->cg_initediblk = newsb->fs_ipg < 2 * INOPB(newsb) ? |
491 | newsb->fs_ipg : 2 * INOPB(newsb); | | 491 | newsb->fs_ipg : 2 * INOPB(newsb); |
492 | cg->cg_iusedoff = start; | | 492 | cg->cg_iusedoff = start; |
493 | } else { | | 493 | } else { |
494 | cg->cg_old_time = newsb->fs_time; | | 494 | cg->cg_old_time = newsb->fs_time; |
495 | cg->cg_old_niblk = cg->cg_niblk; | | 495 | cg->cg_old_niblk = cg->cg_niblk; |
496 | cg->cg_niblk = 0; | | 496 | cg->cg_niblk = 0; |
497 | cg->cg_initediblk = 0; | | 497 | cg->cg_initediblk = 0; |
498 | | | 498 | |
499 | | | 499 | |
500 | cg->cg_old_ncyl = newsb->fs_old_cpg; | | 500 | cg->cg_old_ncyl = newsb->fs_old_cpg; |
501 | /* Update the cg_old_ncyl value for the last cylinder. */ | | 501 | /* Update the cg_old_ncyl value for the last cylinder. */ |
502 | if (cgn == newsb->fs_ncg - 1) { | | 502 | if (cgn == newsb->fs_ncg - 1) { |
503 | if ((newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) | | 503 | if ((newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) |
504 | cg->cg_old_ncyl = newsb->fs_old_ncyl % | | 504 | cg->cg_old_ncyl = newsb->fs_old_ncyl % |
505 | newsb->fs_old_cpg; | | 505 | newsb->fs_old_cpg; |
506 | } | | 506 | } |
507 | | | 507 | |
508 | /* Set up the bitmap pointers. We have to be careful | | 508 | /* Set up the bitmap pointers. We have to be careful |
509 | * to lay out the cg _exactly_ the way mkfs and fsck | | 509 | * to lay out the cg _exactly_ the way mkfs and fsck |
510 | * do it, since fsck compares the _entire_ cg against | | 510 | * do it, since fsck compares the _entire_ cg against |
511 | * a recomputed cg, and whines if there is any | | 511 | * a recomputed cg, and whines if there is any |
512 | * mismatch, including the bitmap offsets. */ | | 512 | * mismatch, including the bitmap offsets. */ |
513 | /* XXX update this comment when fsck is fixed */ | | 513 | /* XXX update this comment when fsck is fixed */ |
514 | cg->cg_old_btotoff = start; | | 514 | cg->cg_old_btotoff = start; |
515 | cg->cg_old_boff = cg->cg_old_btotoff | | 515 | cg->cg_old_boff = cg->cg_old_btotoff |
516 | + (newsb->fs_old_cpg * sizeof(int32_t)); | | 516 | + (newsb->fs_old_cpg * sizeof(int32_t)); |
517 | cg->cg_iusedoff = cg->cg_old_boff + | | 517 | cg->cg_iusedoff = cg->cg_old_boff + |
518 | (newsb->fs_old_cpg * newsb->fs_old_nrpos * sizeof(int16_t)); | | 518 | (newsb->fs_old_cpg * newsb->fs_old_nrpos * sizeof(int16_t)); |
519 | } | | 519 | } |
520 | cg->cg_freeoff = cg->cg_iusedoff + howmany(newsb->fs_ipg, NBBY); | | 520 | cg->cg_freeoff = cg->cg_iusedoff + howmany(newsb->fs_ipg, NBBY); |
521 | if (newsb->fs_contigsumsize > 0) { | | 521 | if (newsb->fs_contigsumsize > 0) { |
522 | cg->cg_nclusterblks = cg->cg_ndblk / newsb->fs_frag; | | 522 | cg->cg_nclusterblks = cg->cg_ndblk / newsb->fs_frag; |
523 | cg->cg_clustersumoff = cg->cg_freeoff + | | 523 | cg->cg_clustersumoff = cg->cg_freeoff + |
524 | howmany(newsb->fs_fpg, NBBY) - sizeof(int32_t); | | 524 | howmany(newsb->fs_fpg, NBBY) - sizeof(int32_t); |
525 | cg->cg_clustersumoff = | | 525 | cg->cg_clustersumoff = |
526 | roundup(cg->cg_clustersumoff, sizeof(int32_t)); | | 526 | roundup(cg->cg_clustersumoff, sizeof(int32_t)); |
527 | cg->cg_clusteroff = cg->cg_clustersumoff + | | 527 | cg->cg_clusteroff = cg->cg_clustersumoff + |
528 | ((newsb->fs_contigsumsize + 1) * sizeof(int32_t)); | | 528 | ((newsb->fs_contigsumsize + 1) * sizeof(int32_t)); |
529 | cg->cg_nextfreeoff = cg->cg_clusteroff + | | 529 | cg->cg_nextfreeoff = cg->cg_clusteroff + |
530 | howmany(fragstoblks(newsb,newsb->fs_fpg), NBBY); | | 530 | howmany(fragstoblks(newsb,newsb->fs_fpg), NBBY); |
531 | n = dlow / newsb->fs_frag; | | 531 | n = dlow / newsb->fs_frag; |
532 | if (n > 0) { | | 532 | if (n > 0) { |
533 | set_bits(cg_clustersfree(cg, 0), 0, n); | | 533 | set_bits(cg_clustersfree(cg, 0), 0, n); |
534 | cg_clustersum(cg, 0)[(n > newsb->fs_contigsumsize) ? | | 534 | cg_clustersum(cg, 0)[(n > newsb->fs_contigsumsize) ? |
535 | newsb->fs_contigsumsize : n]++; | | 535 | newsb->fs_contigsumsize : n]++; |
536 | } | | 536 | } |
537 | } else { | | 537 | } else { |
538 | cg->cg_nextfreeoff = cg->cg_freeoff + | | 538 | cg->cg_nextfreeoff = cg->cg_freeoff + |
539 | howmany(newsb->fs_fpg, NBBY); | | 539 | howmany(newsb->fs_fpg, NBBY); |
540 | } | | 540 | } |
541 | /* Mark the data areas as free; everything else is marked busy by the | | 541 | /* Mark the data areas as free; everything else is marked busy by the |
542 | * memset() up at the top. */ | | 542 | * memset() up at the top. */ |
543 | set_bits(cg_blksfree(cg, 0), 0, dlow); | | 543 | set_bits(cg_blksfree(cg, 0), 0, dlow); |
544 | set_bits(cg_blksfree(cg, 0), dhigh, dmax - dhigh); | | 544 | set_bits(cg_blksfree(cg, 0), dhigh, dmax - dhigh); |
545 | /* Initialize summary info */ | | 545 | /* Initialize summary info */ |
546 | cg->cg_cs.cs_ndir = 0; | | 546 | cg->cg_cs.cs_ndir = 0; |
547 | cg->cg_cs.cs_nifree = newsb->fs_ipg; | | 547 | cg->cg_cs.cs_nifree = newsb->fs_ipg; |
548 | cg->cg_cs.cs_nbfree = dlow / newsb->fs_frag; | | 548 | cg->cg_cs.cs_nbfree = dlow / newsb->fs_frag; |
549 | cg->cg_cs.cs_nffree = 0; | | 549 | cg->cg_cs.cs_nffree = 0; |
550 | | | 550 | |
551 | /* This is the simplest way of doing this; we perhaps could | | 551 | /* This is the simplest way of doing this; we perhaps could |
552 | * compute the correct cg_blktot()[] and cg_blks()[] values | | 552 | * compute the correct cg_blktot()[] and cg_blks()[] values |
553 | * other ways, but it would be complicated and hardly seems | | 553 | * other ways, but it would be complicated and hardly seems |
554 | * worth the effort. (The reason there isn't | | 554 | * worth the effort. (The reason there isn't |
555 | * frag-at-beginning and frag-at-end code here, like the code | | 555 | * frag-at-beginning and frag-at-end code here, like the code |
556 | * below for the post-inode data area, is that the pre-sb data | | 556 | * below for the post-inode data area, is that the pre-sb data |
557 | * area always starts at 0, and thus is block-aligned, and | | 557 | * area always starts at 0, and thus is block-aligned, and |
558 | * always ends at the sb, which is block-aligned.) */ | | 558 | * always ends at the sb, which is block-aligned.) */ |
559 | if ((newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) | | 559 | if ((newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) |
560 | for (i = 0; i < dlow; i += newsb->fs_frag) { | | 560 | for (i = 0; i < dlow; i += newsb->fs_frag) { |
561 | old_cg_blktot(cg, 0)[old_cbtocylno(newsb, i)]++; | | 561 | old_cg_blktot(cg, 0)[old_cbtocylno(newsb, i)]++; |
562 | old_cg_blks(newsb, cg, | | 562 | old_cg_blks(newsb, cg, |
563 | old_cbtocylno(newsb, i), | | 563 | old_cbtocylno(newsb, i), |
564 | 0)[old_cbtorpos(newsb, i)]++; | | 564 | 0)[old_cbtorpos(newsb, i)]++; |
565 | } | | 565 | } |
566 | | | 566 | |
567 | /* Deal with a partial block at the beginning of the post-inode area. | | 567 | /* Deal with a partial block at the beginning of the post-inode area. |
568 | * I'm not convinced this can happen - I think the inodes are always | | 568 | * I'm not convinced this can happen - I think the inodes are always |
569 | * block-aligned and always an integral number of blocks - but it's | | 569 | * block-aligned and always an integral number of blocks - but it's |
570 | * cheap to do the right thing just in case. */ | | 570 | * cheap to do the right thing just in case. */ |
571 | if (dhigh % newsb->fs_frag) { | | 571 | if (dhigh % newsb->fs_frag) { |
572 | n = newsb->fs_frag - (dhigh % newsb->fs_frag); | | 572 | n = newsb->fs_frag - (dhigh % newsb->fs_frag); |
573 | cg->cg_frsum[n]++; | | 573 | cg->cg_frsum[n]++; |
574 | cg->cg_cs.cs_nffree += n; | | 574 | cg->cg_cs.cs_nffree += n; |
575 | dhigh += n; | | 575 | dhigh += n; |
576 | } | | 576 | } |
577 | n = (dmax - dhigh) / newsb->fs_frag; | | 577 | n = (dmax - dhigh) / newsb->fs_frag; |
578 | /* We have n full-size blocks in the post-inode data area. */ | | 578 | /* We have n full-size blocks in the post-inode data area. */ |
579 | if (n > 0) { | | 579 | if (n > 0) { |
580 | cg->cg_cs.cs_nbfree += n; | | 580 | cg->cg_cs.cs_nbfree += n; |
581 | if (newsb->fs_contigsumsize > 0) { | | 581 | if (newsb->fs_contigsumsize > 0) { |
582 | i = dhigh / newsb->fs_frag; | | 582 | i = dhigh / newsb->fs_frag; |
583 | set_bits(cg_clustersfree(cg, 0), i, n); | | 583 | set_bits(cg_clustersfree(cg, 0), i, n); |
584 | cg_clustersum(cg, 0)[(n > newsb->fs_contigsumsize) ? | | 584 | cg_clustersum(cg, 0)[(n > newsb->fs_contigsumsize) ? |
585 | newsb->fs_contigsumsize : n]++; | | 585 | newsb->fs_contigsumsize : n]++; |
586 | } | | 586 | } |
587 | if (is_ufs2 == 0) | | 587 | if (is_ufs2 == 0) |
588 | for (i = n; i > 0; i--) { | | 588 | for (i = n; i > 0; i--) { |
589 | old_cg_blktot(cg, 0)[old_cbtocylno(newsb, | | 589 | old_cg_blktot(cg, 0)[old_cbtocylno(newsb, |
590 | dhigh)]++; | | 590 | dhigh)]++; |
591 | old_cg_blks(newsb, cg, | | 591 | old_cg_blks(newsb, cg, |
592 | old_cbtocylno(newsb, dhigh), | | 592 | old_cbtocylno(newsb, dhigh), |
593 | 0)[old_cbtorpos(newsb, | | 593 | 0)[old_cbtorpos(newsb, |
594 | dhigh)]++; | | 594 | dhigh)]++; |
595 | dhigh += newsb->fs_frag; | | 595 | dhigh += newsb->fs_frag; |
596 | } | | 596 | } |
597 | } | | 597 | } |
598 | if (is_ufs2 == 0) { | | 598 | if (is_ufs2 == 0) { |
599 | /* Deal with any leftover frag at the end of the cg. */ | | 599 | /* Deal with any leftover frag at the end of the cg. */ |
600 | i = dmax - dhigh; | | 600 | i = dmax - dhigh; |
601 | if (i) { | | 601 | if (i) { |
602 | cg->cg_frsum[i]++; | | 602 | cg->cg_frsum[i]++; |
603 | cg->cg_cs.cs_nffree += i; | | 603 | cg->cg_cs.cs_nffree += i; |
604 | } | | 604 | } |
605 | } | | 605 | } |
606 | /* Update the csum info. */ | | 606 | /* Update the csum info. */ |
607 | csums[cgn] = cg->cg_cs; | | 607 | csums[cgn] = cg->cg_cs; |
608 | newsb->fs_cstotal.cs_nffree += cg->cg_cs.cs_nffree; | | 608 | newsb->fs_cstotal.cs_nffree += cg->cg_cs.cs_nffree; |
609 | newsb->fs_cstotal.cs_nbfree += cg->cg_cs.cs_nbfree; | | 609 | newsb->fs_cstotal.cs_nbfree += cg->cg_cs.cs_nbfree; |
610 | newsb->fs_cstotal.cs_nifree += cg->cg_cs.cs_nifree; | | 610 | newsb->fs_cstotal.cs_nifree += cg->cg_cs.cs_nifree; |
611 | if (is_ufs2 == 0) | | 611 | if (is_ufs2 == 0) |
612 | /* Write out the cleared inodes. */ | | 612 | /* Write out the cleared inodes. */ |
613 | writeat(fsbtodb(newsb, cgimin(newsb, cgn)), zinodes, | | 613 | writeat(fsbtodb(newsb, cgimin(newsb, cgn)), zinodes, |
614 | newsb->fs_ipg * sizeof(struct ufs1_dinode)); | | 614 | newsb->fs_ipg * sizeof(*zinodes)); |
615 | /* Dirty the cg. */ | | 615 | /* Dirty the cg. */ |
616 | cgflags[cgn] |= CGF_DIRTY; | | 616 | cgflags[cgn] |= CGF_DIRTY; |
617 | } | | 617 | } |
618 | /* | | 618 | /* |
619 | * Find free space, at least nfrags consecutive frags of it. Pays no | | 619 | * Find free space, at least nfrags consecutive frags of it. Pays no |
620 | * attention to block boundaries, but refuses to straddle cg | | 620 | * attention to block boundaries, but refuses to straddle cg |
621 | * boundaries, even if the disk blocks involved are in fact | | 621 | * boundaries, even if the disk blocks involved are in fact |
622 | * consecutive. Return value is the frag number of the first frag of | | 622 | * consecutive. Return value is the frag number of the first frag of |
623 | * the block, or -1 if no space was found. Uses newsb for sb values, | | 623 | * the block, or -1 if no space was found. Uses newsb for sb values, |
624 | * and assumes the cgs[] structures correctly describe the area to be | | 624 | * and assumes the cgs[] structures correctly describe the area to be |
625 | * searched. | | 625 | * searched. |
626 | * | | 626 | * |
627 | * XXX is there a bug lurking in the ignoring of block boundaries by | | 627 | * XXX is there a bug lurking in the ignoring of block boundaries by |
628 | * the routine used by fragmove() in evict_data()? Can an end-of-file | | 628 | * the routine used by fragmove() in evict_data()? Can an end-of-file |
629 | * frag legally straddle a block boundary? If not, this should be | | 629 | * frag legally straddle a block boundary? If not, this should be |
630 | * cloned and fixed to stop at block boundaries for that use. The | | 630 | * cloned and fixed to stop at block boundaries for that use. The |
631 | * current one may still be needed for csum info motion, in case that | | 631 | * current one may still be needed for csum info motion, in case that |
632 | * takes up more than a whole block (is the csum info allowed to begin | | 632 | * takes up more than a whole block (is the csum info allowed to begin |
633 | * partway through a block and continue into the following block?). | | 633 | * partway through a block and continue into the following block?). |
634 | * | | 634 | * |
635 | * If we wrap off the end of the file system back to the beginning, we | | 635 | * If we wrap off the end of the file system back to the beginning, we |
636 | * can end up searching the end of the file system twice. I ignore | | 636 | * can end up searching the end of the file system twice. I ignore |
637 | * this inefficiency, since if that happens we're going to croak with | | 637 | * this inefficiency, since if that happens we're going to croak with |
638 | * a no-space error anyway, so it happens at most once. | | 638 | * a no-space error anyway, so it happens at most once. |
639 | */ | | 639 | */ |
640 | static int | | 640 | static int |
641 | find_freespace(unsigned int nfrags) | | 641 | find_freespace(unsigned int nfrags) |
642 | { | | 642 | { |
643 | static int hand = 0; /* hand rotates through all frags in the fs */ | | 643 | static int hand = 0; /* hand rotates through all frags in the fs */ |
644 | int cgsize; /* size of the cg hand currently points into */ | | 644 | int cgsize; /* size of the cg hand currently points into */ |
645 | int cgn; /* number of cg hand currently points into */ | | 645 | int cgn; /* number of cg hand currently points into */ |
646 | int fwc; /* frag-within-cg number of frag hand points | | 646 | int fwc; /* frag-within-cg number of frag hand points |
647 | * to */ | | 647 | * to */ |
648 | unsigned int run; /* length of run of free frags seen so far */ | | 648 | unsigned int run; /* length of run of free frags seen so far */ |
649 | int secondpass; /* have we wrapped from end of fs to | | 649 | int secondpass; /* have we wrapped from end of fs to |
650 | * beginning? */ | | 650 | * beginning? */ |
651 | unsigned char *bits; /* cg_blksfree()[] for cg hand points into */ | | 651 | unsigned char *bits; /* cg_blksfree()[] for cg hand points into */ |
652 | | | 652 | |
653 | cgn = dtog(newsb, hand); | | 653 | cgn = dtog(newsb, hand); |
654 | fwc = dtogd(newsb, hand); | | 654 | fwc = dtogd(newsb, hand); |
655 | secondpass = (hand == 0); | | 655 | secondpass = (hand == 0); |
656 | run = 0; | | 656 | run = 0; |
657 | bits = cg_blksfree(cgs[cgn], 0); | | 657 | bits = cg_blksfree(cgs[cgn], 0); |
658 | cgsize = cgs[cgn]->cg_ndblk; | | 658 | cgsize = cgs[cgn]->cg_ndblk; |
659 | while (1) { | | 659 | while (1) { |
660 | if (bit_is_set(bits, fwc)) { | | 660 | if (bit_is_set(bits, fwc)) { |
661 | run++; | | 661 | run++; |
662 | if (run >= nfrags) | | 662 | if (run >= nfrags) |
663 | return (hand + 1 - run); | | 663 | return (hand + 1 - run); |
664 | } else { | | 664 | } else { |
665 | run = 0; | | 665 | run = 0; |
666 | } | | 666 | } |
667 | hand++; | | 667 | hand++; |
668 | fwc++; | | 668 | fwc++; |
669 | if (fwc >= cgsize) { | | 669 | if (fwc >= cgsize) { |
670 | fwc = 0; | | 670 | fwc = 0; |
671 | cgn++; | | 671 | cgn++; |
672 | if (cgn >= newsb->fs_ncg) { | | 672 | if (cgn >= newsb->fs_ncg) { |
673 | hand = 0; | | 673 | hand = 0; |
674 | if (secondpass) | | 674 | if (secondpass) |
675 | return (-1); | | 675 | return (-1); |
676 | secondpass = 1; | | 676 | secondpass = 1; |
677 | cgn = 0; | | 677 | cgn = 0; |
678 | } | | 678 | } |
679 | bits = cg_blksfree(cgs[cgn], 0); | | 679 | bits = cg_blksfree(cgs[cgn], 0); |
680 | cgsize = cgs[cgn]->cg_ndblk; | | 680 | cgsize = cgs[cgn]->cg_ndblk; |
681 | run = 0; | | 681 | run = 0; |
682 | } | | 682 | } |
683 | } | | 683 | } |
684 | } | | 684 | } |
685 | /* | | 685 | /* |
686 | * Find a free block of disk space. Finds an entire block of frags, | | 686 | * Find a free block of disk space. Finds an entire block of frags, |
687 | * all of which are free. Return value is the frag number of the | | 687 | * all of which are free. Return value is the frag number of the |
688 | * first frag of the block, or -1 if no space was found. Uses newsb | | 688 | * first frag of the block, or -1 if no space was found. Uses newsb |
689 | * for sb values, and assumes the cgs[] structures correctly describe | | 689 | * for sb values, and assumes the cgs[] structures correctly describe |
690 | * the area to be searched. | | 690 | * the area to be searched. |
691 | * | | 691 | * |
692 | * See find_freespace(), above, for remarks about hand wrapping around. | | 692 | * See find_freespace(), above, for remarks about hand wrapping around. |
693 | */ | | 693 | */ |
694 | static int | | 694 | static int |
695 | find_freeblock(void) | | 695 | find_freeblock(void) |
696 | { | | 696 | { |
697 | static int hand = 0; /* hand rotates through all frags in fs */ | | 697 | static int hand = 0; /* hand rotates through all frags in fs */ |
698 | int cgn; /* cg number of cg hand points into */ | | 698 | int cgn; /* cg number of cg hand points into */ |
699 | int fwc; /* frag-within-cg number of frag hand points | | 699 | int fwc; /* frag-within-cg number of frag hand points |
700 | * to */ | | 700 | * to */ |
701 | int cgsize; /* size of cg hand points into */ | | 701 | int cgsize; /* size of cg hand points into */ |
702 | int secondpass; /* have we wrapped from end to beginning? */ | | 702 | int secondpass; /* have we wrapped from end to beginning? */ |
703 | unsigned char *bits; /* cg_blksfree()[] for cg hand points into */ | | 703 | unsigned char *bits; /* cg_blksfree()[] for cg hand points into */ |
704 | | | 704 | |
705 | cgn = dtog(newsb, hand); | | 705 | cgn = dtog(newsb, hand); |
706 | fwc = dtogd(newsb, hand); | | 706 | fwc = dtogd(newsb, hand); |
707 | secondpass = (hand == 0); | | 707 | secondpass = (hand == 0); |
708 | bits = cg_blksfree(cgs[cgn], 0); | | 708 | bits = cg_blksfree(cgs[cgn], 0); |
709 | cgsize = blknum(newsb, cgs[cgn]->cg_ndblk); | | 709 | cgsize = blknum(newsb, cgs[cgn]->cg_ndblk); |
710 | while (1) { | | 710 | while (1) { |
711 | if (blk_is_set(bits, fwc, newsb->fs_frag)) | | 711 | if (blk_is_set(bits, fwc, newsb->fs_frag)) |
712 | return (hand); | | 712 | return (hand); |
713 | fwc += newsb->fs_frag; | | 713 | fwc += newsb->fs_frag; |
714 | hand += newsb->fs_frag; | | 714 | hand += newsb->fs_frag; |
715 | if (fwc >= cgsize) { | | 715 | if (fwc >= cgsize) { |
716 | fwc = 0; | | 716 | fwc = 0; |
717 | cgn++; | | 717 | cgn++; |
718 | if (cgn >= newsb->fs_ncg) { | | 718 | if (cgn >= newsb->fs_ncg) { |
719 | hand = 0; | | 719 | hand = 0; |
720 | if (secondpass) | | 720 | if (secondpass) |
721 | return (-1); | | 721 | return (-1); |
722 | secondpass = 1; | | 722 | secondpass = 1; |
723 | cgn = 0; | | 723 | cgn = 0; |
724 | } | | 724 | } |
725 | bits = cg_blksfree(cgs[cgn], 0); | | 725 | bits = cg_blksfree(cgs[cgn], 0); |
726 | cgsize = blknum(newsb, cgs[cgn]->cg_ndblk); | | 726 | cgsize = blknum(newsb, cgs[cgn]->cg_ndblk); |
727 | } | | 727 | } |
728 | } | | 728 | } |
729 | } | | 729 | } |
730 | /* | | 730 | /* |
731 | * Find a free inode, returning its inumber or -1 if none was found. | | 731 | * Find a free inode, returning its inumber or -1 if none was found. |
732 | * Uses newsb for sb values, and assumes the cgs[] structures | | 732 | * Uses newsb for sb values, and assumes the cgs[] structures |
733 | * correctly describe the area to be searched. | | 733 | * correctly describe the area to be searched. |
734 | * | | 734 | * |
735 | * See find_freespace(), above, for remarks about hand wrapping around. | | 735 | * See find_freespace(), above, for remarks about hand wrapping around. |
736 | */ | | 736 | */ |
737 | static int | | 737 | static int |
738 | find_freeinode(void) | | 738 | find_freeinode(void) |
739 | { | | 739 | { |
740 | static int hand = 0; /* hand rotates through all inodes in fs */ | | 740 | static int hand = 0; /* hand rotates through all inodes in fs */ |
741 | int cgn; /* cg number of cg hand points into */ | | 741 | int cgn; /* cg number of cg hand points into */ |
742 | int iwc; /* inode-within-cg number of inode hand points | | 742 | int iwc; /* inode-within-cg number of inode hand points |
743 | * to */ | | 743 | * to */ |
744 | int secondpass; /* have we wrapped from end to beginning? */ | | 744 | int secondpass; /* have we wrapped from end to beginning? */ |
745 | unsigned char *bits; /* cg_inosused()[] for cg hand points into */ | | 745 | unsigned char *bits; /* cg_inosused()[] for cg hand points into */ |
746 | | | 746 | |
747 | cgn = hand / newsb->fs_ipg; | | 747 | cgn = hand / newsb->fs_ipg; |
748 | iwc = hand % newsb->fs_ipg; | | 748 | iwc = hand % newsb->fs_ipg; |
749 | secondpass = (hand == 0); | | 749 | secondpass = (hand == 0); |
750 | bits = cg_inosused(cgs[cgn], 0); | | 750 | bits = cg_inosused(cgs[cgn], 0); |
751 | while (1) { | | 751 | while (1) { |
752 | if (bit_is_clr(bits, iwc)) | | 752 | if (bit_is_clr(bits, iwc)) |
753 | return (hand); | | 753 | return (hand); |
754 | hand++; | | 754 | hand++; |
755 | iwc++; | | 755 | iwc++; |
756 | if (iwc >= newsb->fs_ipg) { | | 756 | if (iwc >= newsb->fs_ipg) { |
757 | iwc = 0; | | 757 | iwc = 0; |
758 | cgn++; | | 758 | cgn++; |
759 | if (cgn >= newsb->fs_ncg) { | | 759 | if (cgn >= newsb->fs_ncg) { |
760 | hand = 0; | | 760 | hand = 0; |
761 | if (secondpass) | | 761 | if (secondpass) |
762 | return (-1); | | 762 | return (-1); |
763 | secondpass = 1; | | 763 | secondpass = 1; |
764 | cgn = 0; | | 764 | cgn = 0; |
765 | } | | 765 | } |
766 | bits = cg_inosused(cgs[cgn], 0); | | 766 | bits = cg_inosused(cgs[cgn], 0); |
767 | } | | 767 | } |
768 | } | | 768 | } |
769 | } | | 769 | } |
770 | /* | | 770 | /* |
771 | * Mark a frag as free. Sets the frag's bit in the cg_blksfree bitmap | | 771 | * Mark a frag as free. Sets the frag's bit in the cg_blksfree bitmap |
772 | * for the appropriate cg, and marks the cg as dirty. | | 772 | * for the appropriate cg, and marks the cg as dirty. |
773 | */ | | 773 | */ |
774 | static void | | 774 | static void |
775 | free_frag(int fno) | | 775 | free_frag(int fno) |
776 | { | | 776 | { |
777 | int cgn; | | 777 | int cgn; |
778 | | | 778 | |
779 | cgn = dtog(newsb, fno); | | 779 | cgn = dtog(newsb, fno); |
780 | set_bits(cg_blksfree(cgs[cgn], 0), dtogd(newsb, fno), 1); | | 780 | set_bits(cg_blksfree(cgs[cgn], 0), dtogd(newsb, fno), 1); |
781 | cgflags[cgn] |= CGF_DIRTY | CGF_BLKMAPS; | | 781 | cgflags[cgn] |= CGF_DIRTY | CGF_BLKMAPS; |
782 | } | | 782 | } |
783 | /* | | 783 | /* |
784 | * Allocate a frag. Clears the frag's bit in the cg_blksfree bitmap | | 784 | * Allocate a frag. Clears the frag's bit in the cg_blksfree bitmap |
785 | * for the appropriate cg, and marks the cg as dirty. | | 785 | * for the appropriate cg, and marks the cg as dirty. |
786 | */ | | 786 | */ |
787 | static void | | 787 | static void |
788 | alloc_frag(int fno) | | 788 | alloc_frag(int fno) |
789 | { | | 789 | { |
790 | int cgn; | | 790 | int cgn; |
791 | | | 791 | |
792 | cgn = dtog(newsb, fno); | | 792 | cgn = dtog(newsb, fno); |
793 | clr_bits(cg_blksfree(cgs[cgn], 0), dtogd(newsb, fno), 1); | | 793 | clr_bits(cg_blksfree(cgs[cgn], 0), dtogd(newsb, fno), 1); |
794 | cgflags[cgn] |= CGF_DIRTY | CGF_BLKMAPS; | | 794 | cgflags[cgn] |= CGF_DIRTY | CGF_BLKMAPS; |
795 | } | | 795 | } |
796 | /* | | 796 | /* |
797 | * Fix up the csum array. If shrinking, this involves freeing zero or | | 797 | * Fix up the csum array. If shrinking, this involves freeing zero or |
798 | * more frags; if growing, it involves allocating them, or if the | | 798 | * more frags; if growing, it involves allocating them, or if the |
799 | * frags being grown into aren't free, finding space elsewhere for the | | 799 | * frags being grown into aren't free, finding space elsewhere for the |
800 | * csum info. (If the number of occupied frags doesn't change, | | 800 | * csum info. (If the number of occupied frags doesn't change, |
801 | * nothing happens here.) | | 801 | * nothing happens here.) |
802 | */ | | 802 | */ |
803 | static void | | 803 | static void |
804 | csum_fixup(void) | | 804 | csum_fixup(void) |
805 | { | | 805 | { |
806 | int nold; /* # frags in old csum info */ | | 806 | int nold; /* # frags in old csum info */ |
807 | int ntot; /* # frags in new csum info */ | | 807 | int ntot; /* # frags in new csum info */ |
808 | int nnew; /* ntot-nold */ | | 808 | int nnew; /* ntot-nold */ |
809 | int newloc; /* new location for csum info, if necessary */ | | 809 | int newloc; /* new location for csum info, if necessary */ |
810 | int i; /* generic loop index */ | | 810 | int i; /* generic loop index */ |
811 | int j; /* generic loop index */ | | 811 | int j; /* generic loop index */ |
812 | int f; /* "from" frag number, if moving */ | | 812 | int f; /* "from" frag number, if moving */ |
813 | int t; /* "to" frag number, if moving */ | | 813 | int t; /* "to" frag number, if moving */ |
814 | int cgn; /* cg number, used when shrinking */ | | 814 | int cgn; /* cg number, used when shrinking */ |
815 | | | 815 | |
816 | ntot = howmany(newsb->fs_cssize, newsb->fs_fsize); | | 816 | ntot = howmany(newsb->fs_cssize, newsb->fs_fsize); |
817 | nold = howmany(oldsb->fs_cssize, newsb->fs_fsize); | | 817 | nold = howmany(oldsb->fs_cssize, newsb->fs_fsize); |
818 | nnew = ntot - nold; | | 818 | nnew = ntot - nold; |
819 | /* First, if there's no change in frag counts, it's easy. */ | | 819 | /* First, if there's no change in frag counts, it's easy. */ |
820 | if (nnew == 0) | | 820 | if (nnew == 0) |
821 | return; | | 821 | return; |
822 | /* Next, if we're shrinking, it's almost as easy. Just free up any | | 822 | /* Next, if we're shrinking, it's almost as easy. Just free up any |
823 | * frags in the old area we no longer need. */ | | 823 | * frags in the old area we no longer need. */ |
824 | if (nnew < 0) { | | 824 | if (nnew < 0) { |
825 | for ((i = newsb->fs_csaddr + ntot - 1), (j = nnew); | | 825 | for ((i = newsb->fs_csaddr + ntot - 1), (j = nnew); |
826 | j < 0; | | 826 | j < 0; |
827 | i--, j++) { | | 827 | i--, j++) { |
828 | free_frag(i); | | 828 | free_frag(i); |
829 | } | | 829 | } |
830 | return; | | 830 | return; |
831 | } | | 831 | } |
832 | /* We must be growing. Check to see that the new csum area fits | | 832 | /* We must be growing. Check to see that the new csum area fits |
833 | * within the file system. I think this can never happen, since for | | 833 | * within the file system. I think this can never happen, since for |
834 | * the csum area to grow, we must be adding at least one cg, so the | | 834 | * the csum area to grow, we must be adding at least one cg, so the |
835 | * old csum area can't be this close to the end of the new file system. | | 835 | * old csum area can't be this close to the end of the new file system. |
836 | * But it's a cheap check. */ | | 836 | * But it's a cheap check. */ |
837 | /* XXX what if csum info is at end of cg and grows into next cg, what | | 837 | /* XXX what if csum info is at end of cg and grows into next cg, what |
838 | * if it spills over onto the next cg's backup superblock? Can this | | 838 | * if it spills over onto the next cg's backup superblock? Can this |
839 | * happen? */ | | 839 | * happen? */ |
840 | if (newsb->fs_csaddr + ntot <= newsb->fs_size) { | | 840 | if (newsb->fs_csaddr + ntot <= newsb->fs_size) { |
841 | /* Okay, it fits - now, see if the space we want is free. */ | | 841 | /* Okay, it fits - now, see if the space we want is free. */ |
842 | for ((i = newsb->fs_csaddr + nold), (j = nnew); | | 842 | for ((i = newsb->fs_csaddr + nold), (j = nnew); |
843 | j > 0; | | 843 | j > 0; |
844 | i++, j--) { | | 844 | i++, j--) { |
845 | cgn = dtog(newsb, i); | | 845 | cgn = dtog(newsb, i); |
846 | if (bit_is_clr(cg_blksfree(cgs[cgn], 0), | | 846 | if (bit_is_clr(cg_blksfree(cgs[cgn], 0), |
847 | dtogd(newsb, i))) | | 847 | dtogd(newsb, i))) |
848 | break; | | 848 | break; |
849 | } | | 849 | } |
850 | if (j <= 0) { | | 850 | if (j <= 0) { |
851 | /* Win win - all the frags we want are free. Allocate | | 851 | /* Win win - all the frags we want are free. Allocate |
852 | * 'em and we're all done. */ | | 852 | * 'em and we're all done. */ |
853 | for ((i = newsb->fs_csaddr + ntot - nnew), | | 853 | for ((i = newsb->fs_csaddr + ntot - nnew), |
854 | (j = nnew); j > 0; i++, j--) { | | 854 | (j = nnew); j > 0; i++, j--) { |
855 | alloc_frag(i); | | 855 | alloc_frag(i); |
856 | } | | 856 | } |
857 | return; | | 857 | return; |
858 | } | | 858 | } |
859 | } | | 859 | } |
860 | /* We have to move the csum info, sigh. Look for new space, free old | | 860 | /* We have to move the csum info, sigh. Look for new space, free old |
861 | * space, and allocate new. Update fs_csaddr. We don't copy anything | | 861 | * space, and allocate new. Update fs_csaddr. We don't copy anything |
862 | * on disk at this point; the csum info will be written to the | | 862 | * on disk at this point; the csum info will be written to the |
863 | * then-current fs_csaddr as part of the final flush. */ | | 863 | * then-current fs_csaddr as part of the final flush. */ |
864 | newloc = find_freespace(ntot); | | 864 | newloc = find_freespace(ntot); |
865 | if (newloc < 0) { | | 865 | if (newloc < 0) |
866 | printf("Sorry, no space available for new csums\n"); | | 866 | errx(EXIT_FAILURE, "Sorry, no space available for new csums"); |
867 | exit(EXIT_FAILURE); | | | |
868 | } | | | |
869 | for (i = 0, f = newsb->fs_csaddr, t = newloc; i < ntot; i++, f++, t++) { | | 867 | for (i = 0, f = newsb->fs_csaddr, t = newloc; i < ntot; i++, f++, t++) { |
870 | if (i < nold) { | | 868 | if (i < nold) { |
871 | free_frag(f); | | 869 | free_frag(f); |
872 | } | | 870 | } |
873 | alloc_frag(t); | | 871 | alloc_frag(t); |
874 | } | | 872 | } |
875 | newsb->fs_csaddr = newloc; | | 873 | newsb->fs_csaddr = newloc; |
876 | } | | 874 | } |
877 | /* | | 875 | /* |
878 | * Recompute newsb->fs_dsize. Just scans all cgs, adding the number of | | 876 | * Recompute newsb->fs_dsize. Just scans all cgs, adding the number of |
879 | * data blocks in that cg to the total. | | 877 | * data blocks in that cg to the total. |
880 | */ | | 878 | */ |
881 | static void | | 879 | static void |
882 | recompute_fs_dsize(void) | | 880 | recompute_fs_dsize(void) |
883 | { | | 881 | { |
884 | int i; | | 882 | int i; |
885 | | | 883 | |
886 | newsb->fs_dsize = 0; | | 884 | newsb->fs_dsize = 0; |
887 | for (i = 0; i < newsb->fs_ncg; i++) { | | 885 | for (i = 0; i < newsb->fs_ncg; i++) { |
888 | int dlow; /* size of before-sb data area */ | | 886 | int dlow; /* size of before-sb data area */ |
889 | int dhigh; /* offset of post-inode data area */ | | 887 | int dhigh; /* offset of post-inode data area */ |
890 | int dmax; /* total size of cg */ | | 888 | int dmax; /* total size of cg */ |
891 | int base; /* base of cg, since cgsblock() etc add it in */ | | 889 | int base; /* base of cg, since cgsblock() etc add it in */ |
892 | base = cgbase(newsb, i); | | 890 | base = cgbase(newsb, i); |
893 | dlow = cgsblock(newsb, i) - base; | | 891 | dlow = cgsblock(newsb, i) - base; |
894 | dhigh = cgdmin(newsb, i) - base; | | 892 | dhigh = cgdmin(newsb, i) - base; |
895 | dmax = newsb->fs_size - base; | | 893 | dmax = newsb->fs_size - base; |
896 | if (dmax > newsb->fs_fpg) | | 894 | if (dmax > newsb->fs_fpg) |
897 | dmax = newsb->fs_fpg; | | 895 | dmax = newsb->fs_fpg; |
898 | newsb->fs_dsize += dlow + dmax - dhigh; | | 896 | newsb->fs_dsize += dlow + dmax - dhigh; |
899 | } | | 897 | } |
900 | /* Space in cg 0 before cgsblock is boot area, not free space! */ | | 898 | /* Space in cg 0 before cgsblock is boot area, not free space! */ |
901 | newsb->fs_dsize -= cgsblock(newsb, 0) - cgbase(newsb, 0); | | 899 | newsb->fs_dsize -= cgsblock(newsb, 0) - cgbase(newsb, 0); |
902 | /* And of course the csum info takes up space. */ | | 900 | /* And of course the csum info takes up space. */ |
903 | newsb->fs_dsize -= howmany(newsb->fs_cssize, newsb->fs_fsize); | | 901 | newsb->fs_dsize -= howmany(newsb->fs_cssize, newsb->fs_fsize); |
904 | } | | 902 | } |
905 | /* | | 903 | /* |
906 | * Return the current time. We call this and assign, rather than | | 904 | * Return the current time. We call this and assign, rather than |
907 | * calling time() directly, as insulation against OSes where fs_time | | 905 | * calling time() directly, as insulation against OSes where fs_time |
908 | * is not a time_t. | | 906 | * is not a time_t. |
909 | */ | | 907 | */ |
910 | static time_t | | 908 | static time_t |
911 | timestamp(void) | | 909 | timestamp(void) |
912 | { | | 910 | { |
913 | time_t t; | | 911 | time_t t; |
914 | | | 912 | |
915 | time(&t); | | 913 | time(&t); |
916 | return (t); | | 914 | return (t); |
917 | } | | 915 | } |
918 | /* | | 916 | /* |
919 | * Grow the file system. | | 917 | * Grow the file system. |
920 | */ | | 918 | */ |
921 | static void | | 919 | static void |
922 | grow(void) | | 920 | grow(void) |
923 | { | | 921 | { |
924 | int i; | | 922 | int i; |
925 | | | 923 | |
926 | /* Update the timestamp. */ | | 924 | /* Update the timestamp. */ |
927 | newsb->fs_time = timestamp(); | | 925 | newsb->fs_time = timestamp(); |
928 | /* Allocate and clear the new-inode area, in case we add any cgs. */ | | 926 | /* Allocate and clear the new-inode area, in case we add any cgs. */ |
929 | zinodes = alloconce(newsb->fs_ipg * sizeof(struct ufs1_dinode), | | 927 | zinodes = alloconce(newsb->fs_ipg * sizeof(*zinodes), "zeroed inodes"); |
930 | "zeroed inodes"); | | 928 | memset(zinodes, 0, newsb->fs_ipg * sizeof(*zinodes)); |
931 | memset(zinodes, 0, newsb->fs_ipg * sizeof(struct ufs1_dinode)); | | | |
932 | /* Update the size. */ | | 929 | /* Update the size. */ |
933 | newsb->fs_size = dbtofsb(newsb, newsize); | | 930 | newsb->fs_size = dbtofsb(newsb, newsize); |
934 | /* Did we actually not grow? (This can happen if newsize is less than | | 931 | /* Did we actually not grow? (This can happen if newsize is less than |
935 | * a frag larger than the old size - unlikely, but no excuse to | | 932 | * a frag larger than the old size - unlikely, but no excuse to |
936 | * misbehave if it happens.) */ | | 933 | * misbehave if it happens.) */ |
937 | if (newsb->fs_size == oldsb->fs_size) { | | 934 | if (newsb->fs_size == oldsb->fs_size) { |
938 | printf("New fs size %"PRIu64" = odl fs size %"PRIu64 | | 935 | printf("New fs size %"PRIu64" = old fs size %"PRIu64 |
939 | ", not growing.\n", newsb->fs_size, oldsb->fs_size); | | 936 | ", not growing.\n", newsb->fs_size, oldsb->fs_size); |
940 | return; | | 937 | return; |
941 | } | | 938 | } |
942 | /* Check that the new last sector (frag, actually) is writable. Since | | 939 | /* Check that the new last sector (frag, actually) is writable. Since |
943 | * it's at least one frag larger than it used to be, we know we aren't | | 940 | * it's at least one frag larger than it used to be, we know we aren't |
944 | * overwriting anything important by this. (The choice of sbbuf as | | 941 | * overwriting anything important by this. (The choice of sbbuf as |
945 | * what to write is irrelevant; it's just something handy that's known | | 942 | * what to write is irrelevant; it's just something handy that's known |
946 | * to be at least one frag in size.) */ | | 943 | * to be at least one frag in size.) */ |
947 | writeat(fsbtodb(newsb,newsb->fs_size - 1), &sbbuf, newsb->fs_fsize); | | 944 | writeat(fsbtodb(newsb,newsb->fs_size - 1), &sbbuf, newsb->fs_fsize); |
948 | if (is_ufs2) | | 945 | if (is_ufs2) |
949 | newsb->fs_ncg = howmany(newsb->fs_size, newsb->fs_fpg); | | 946 | newsb->fs_ncg = howmany(newsb->fs_size, newsb->fs_fpg); |
950 | else { | | 947 | else { |
951 | /* Update fs_old_ncyl and fs_ncg. */ | | 948 | /* Update fs_old_ncyl and fs_ncg. */ |
952 | newsb->fs_old_ncyl = howmany(newsb->fs_size * NSPF(newsb), | | 949 | newsb->fs_old_ncyl = howmany(newsb->fs_size * NSPF(newsb), |
953 | newsb->fs_old_spc); | | 950 | newsb->fs_old_spc); |
954 | newsb->fs_ncg = howmany(newsb->fs_old_ncyl, newsb->fs_old_cpg); | | 951 | newsb->fs_ncg = howmany(newsb->fs_old_ncyl, newsb->fs_old_cpg); |
955 | } | | 952 | } |
956 | | | 953 | |
957 | /* Does the last cg end before the end of its inode area? There is no | | 954 | /* Does the last cg end before the end of its inode area? There is no |
958 | * reason why this couldn't be handled, but it would complicate a lot | | 955 | * reason why this couldn't be handled, but it would complicate a lot |
959 | * of code (in all file system code - fsck, kernel, etc) because of the | | 956 | * of code (in all file system code - fsck, kernel, etc) because of the |
960 | * potential partial inode area, and the gain in space would be | | 957 | * potential partial inode area, and the gain in space would be |
961 | * minimal, at most the pre-sb data area. */ | | 958 | * minimal, at most the pre-sb data area. */ |
962 | if (cgdmin(newsb, newsb->fs_ncg - 1) > newsb->fs_size) { | | 959 | if (cgdmin(newsb, newsb->fs_ncg - 1) > newsb->fs_size) { |
963 | newsb->fs_ncg--; | | 960 | newsb->fs_ncg--; |
964 | newsb->fs_old_ncyl = newsb->fs_ncg * newsb->fs_old_cpg; | | 961 | newsb->fs_old_ncyl = newsb->fs_ncg * newsb->fs_old_cpg; |
965 | newsb->fs_size = (newsb->fs_old_ncyl * newsb->fs_old_spc) | | 962 | newsb->fs_size = (newsb->fs_old_ncyl * newsb->fs_old_spc) |
966 | / NSPF(newsb); | | 963 | / NSPF(newsb); |
967 | printf("Warning: last cylinder group is too small;\n"); | | 964 | printf("Warning: last cylinder group is too small;\n"); |
968 | printf(" dropping it. New size = %lu.\n", | | 965 | printf(" dropping it. New size = %lu.\n", |
969 | (unsigned long int) fsbtodb(newsb, newsb->fs_size)); | | 966 | (unsigned long int) fsbtodb(newsb, newsb->fs_size)); |
970 | } | | 967 | } |
971 | /* Find out how big the csum area is, and realloc csums if bigger. */ | | 968 | /* Find out how big the csum area is, and realloc csums if bigger. */ |
972 | newsb->fs_cssize = fragroundup(newsb, | | 969 | newsb->fs_cssize = fragroundup(newsb, |
973 | newsb->fs_ncg * sizeof(struct csum)); | | 970 | newsb->fs_ncg * sizeof(struct csum)); |
974 | if (newsb->fs_cssize > oldsb->fs_cssize) | | 971 | if (newsb->fs_cssize > oldsb->fs_cssize) |
975 | csums = nfrealloc(csums, newsb->fs_cssize, "new cg summary"); | | 972 | csums = nfrealloc(csums, newsb->fs_cssize, "new cg summary"); |
976 | /* If we're adding any cgs, realloc structures and set up the new | | 973 | /* If we're adding any cgs, realloc structures and set up the new |
977 | cgs. */ | | 974 | cgs. */ |
978 | if (newsb->fs_ncg > oldsb->fs_ncg) { | | 975 | if (newsb->fs_ncg > oldsb->fs_ncg) { |
979 | char *cgp; | | 976 | char *cgp; |
980 | cgs = nfrealloc(cgs, newsb->fs_ncg * sizeof(struct cg *), | | 977 | cgs = nfrealloc(cgs, newsb->fs_ncg * sizeof(*cgs), |
981 | "cg pointers"); | | 978 | "cg pointers"); |
982 | cgflags = nfrealloc(cgflags, newsb->fs_ncg, "cg flags"); | | 979 | cgflags = nfrealloc(cgflags, newsb->fs_ncg, "cg flags"); |
983 | memset(cgflags + oldsb->fs_ncg, 0, | | 980 | memset(cgflags + oldsb->fs_ncg, 0, |
984 | newsb->fs_ncg - oldsb->fs_ncg); | | 981 | newsb->fs_ncg - oldsb->fs_ncg); |
985 | cgp = alloconce((newsb->fs_ncg - oldsb->fs_ncg) * cgblksz, | | 982 | cgp = alloconce((newsb->fs_ncg - oldsb->fs_ncg) * cgblksz, |
986 | "cgs"); | | 983 | "cgs"); |
987 | for (i = oldsb->fs_ncg; i < newsb->fs_ncg; i++) { | | 984 | for (i = oldsb->fs_ncg; i < newsb->fs_ncg; i++) { |
988 | cgs[i] = (struct cg *) cgp; | | 985 | cgs[i] = (struct cg *) cgp; |
989 | initcg(i); | | 986 | initcg(i); |
990 | cgp += cgblksz; | | 987 | cgp += cgblksz; |
991 | } | | 988 | } |
992 | cgs[oldsb->fs_ncg - 1]->cg_old_ncyl = oldsb->fs_old_cpg; | | 989 | cgs[oldsb->fs_ncg - 1]->cg_old_ncyl = oldsb->fs_old_cpg; |
993 | cgflags[oldsb->fs_ncg - 1] |= CGF_DIRTY; | | 990 | cgflags[oldsb->fs_ncg - 1] |= CGF_DIRTY; |
994 | } | | 991 | } |
995 | /* If the old fs ended partway through a cg, we have to update the old | | 992 | /* If the old fs ended partway through a cg, we have to update the old |
996 | * last cg (though possibly not to a full cg!). */ | | 993 | * last cg (though possibly not to a full cg!). */ |
997 | if (oldsb->fs_size % oldsb->fs_fpg) { | | 994 | if (oldsb->fs_size % oldsb->fs_fpg) { |
998 | struct cg *cg; | | 995 | struct cg *cg; |
999 | int newcgsize; | | 996 | int newcgsize; |
1000 | int prevcgtop; | | 997 | int prevcgtop; |
1001 | int oldcgsize; | | 998 | int oldcgsize; |
1002 | cg = cgs[oldsb->fs_ncg - 1]; | | 999 | cg = cgs[oldsb->fs_ncg - 1]; |
1003 | cgflags[oldsb->fs_ncg - 1] |= CGF_DIRTY | CGF_BLKMAPS; | | 1000 | cgflags[oldsb->fs_ncg - 1] |= CGF_DIRTY | CGF_BLKMAPS; |
1004 | prevcgtop = oldsb->fs_fpg * (oldsb->fs_ncg - 1); | | 1001 | prevcgtop = oldsb->fs_fpg * (oldsb->fs_ncg - 1); |
1005 | newcgsize = newsb->fs_size - prevcgtop; | | 1002 | newcgsize = newsb->fs_size - prevcgtop; |
1006 | if (newcgsize > newsb->fs_fpg) | | 1003 | if (newcgsize > newsb->fs_fpg) |
1007 | newcgsize = newsb->fs_fpg; | | 1004 | newcgsize = newsb->fs_fpg; |
1008 | oldcgsize = oldsb->fs_size % oldsb->fs_fpg; | | 1005 | oldcgsize = oldsb->fs_size % oldsb->fs_fpg; |
1009 | set_bits(cg_blksfree(cg, 0), oldcgsize, newcgsize - oldcgsize); | | 1006 | set_bits(cg_blksfree(cg, 0), oldcgsize, newcgsize - oldcgsize); |
1010 | cg->cg_old_ncyl = oldsb->fs_old_cpg; | | 1007 | cg->cg_old_ncyl = oldsb->fs_old_cpg; |
1011 | cg->cg_ndblk = newcgsize; | | 1008 | cg->cg_ndblk = newcgsize; |
1012 | } | | 1009 | } |
1013 | /* Fix up the csum info, if necessary. */ | | 1010 | /* Fix up the csum info, if necessary. */ |
1014 | csum_fixup(); | | 1011 | csum_fixup(); |
1015 | /* Make fs_dsize match the new reality. */ | | 1012 | /* Make fs_dsize match the new reality. */ |
1016 | recompute_fs_dsize(); | | 1013 | recompute_fs_dsize(); |
1017 | } | | 1014 | } |
1018 | /* | | 1015 | /* |
1019 | * Call (*fn)() for each inode, passing the inode and its inumber. The | | 1016 | * Call (*fn)() for each inode, passing the inode and its inumber. The |
1020 | * number of cylinder groups is pased in, so this can be used to map | | 1017 | * number of cylinder groups is pased in, so this can be used to map |
1021 | * over either the old or the new file system's set of inodes. | | 1018 | * over either the old or the new file system's set of inodes. |
1022 | */ | | 1019 | */ |
1023 | static void | | 1020 | static void |
1024 | map_inodes(void (*fn) (union dinode * di, unsigned int, void *arg), | | 1021 | map_inodes(void (*fn) (union dinode * di, unsigned int, void *arg), |
1025 | int ncg, void *cbarg) { | | 1022 | int ncg, void *cbarg) { |
1026 | int i; | | 1023 | int i; |
1027 | int ni; | | 1024 | int ni; |
1028 | | | 1025 | |
1029 | ni = oldsb->fs_ipg * ncg; | | 1026 | ni = oldsb->fs_ipg * ncg; |
1030 | for (i = 0; i < ni; i++) | | 1027 | for (i = 0; i < ni; i++) |
1031 | (*fn) (inodes + i, i, cbarg); | | 1028 | (*fn) (inodes + i, i, cbarg); |
1032 | } | | 1029 | } |
1033 | /* Values for the third argument to the map function for | | 1030 | /* Values for the third argument to the map function for |
1034 | * map_inode_data_blocks. MDB_DATA indicates the block is contains | | 1031 | * map_inode_data_blocks. MDB_DATA indicates the block is contains |
1035 | * file data; MDB_INDIR_PRE and MDB_INDIR_POST indicate that it's an | | 1032 | * file data; MDB_INDIR_PRE and MDB_INDIR_POST indicate that it's an |
1036 | * indirect block. The MDB_INDIR_PRE call is made before the indirect | | 1033 | * indirect block. The MDB_INDIR_PRE call is made before the indirect |
1037 | * block pointers are followed and the pointed-to blocks scanned, | | 1034 | * block pointers are followed and the pointed-to blocks scanned, |
1038 | * MDB_INDIR_POST after. | | 1035 | * MDB_INDIR_POST after. |
1039 | */ | | 1036 | */ |
1040 | #define MDB_DATA 1 | | 1037 | #define MDB_DATA 1 |
1041 | #define MDB_INDIR_PRE 2 | | 1038 | #define MDB_INDIR_PRE 2 |
1042 | #define MDB_INDIR_POST 3 | | 1039 | #define MDB_INDIR_POST 3 |
1043 | | | 1040 | |
1044 | typedef void (*mark_callback_t) (off_t blocknum, unsigned int nfrags, | | 1041 | typedef void (*mark_callback_t) (off_t blocknum, unsigned int nfrags, |
1045 | unsigned int blksize, int opcode); | | 1042 | unsigned int blksize, int opcode); |
1046 | | | 1043 | |
1047 | /* Helper function - handles a data block. Calls the callback | | 1044 | /* Helper function - handles a data block. Calls the callback |
1048 | * function and returns number of bytes occupied in file (actually, | | 1045 | * function and returns number of bytes occupied in file (actually, |
1049 | * rounded up to a frag boundary). The name is historical. */ | | 1046 | * rounded up to a frag boundary). The name is historical. */ |
1050 | static int | | 1047 | static int |
1051 | markblk(mark_callback_t fn, union dinode * di, off_t bn, off_t o) | | 1048 | markblk(mark_callback_t fn, union dinode * di, off_t bn, off_t o) |
1052 | { | | 1049 | { |
1053 | int sz; | | 1050 | int sz; |
1054 | int nb; | | 1051 | int nb; |
1055 | off_t filesize; | | 1052 | off_t filesize; |
1056 | | | 1053 | |
1057 | filesize = DIP(di,di_size); | | 1054 | filesize = DIP(di,di_size); |
1058 | if (o >= filesize) | | 1055 | if (o >= filesize) |
1059 | return (0); | | 1056 | return (0); |
1060 | sz = dblksize(newsb, di, lblkno(newsb, o), filesize); | | 1057 | sz = dblksize(newsb, di, lblkno(newsb, o), filesize); |
1061 | nb = (sz > filesize - o) ? filesize - o : sz; | | 1058 | nb = (sz > filesize - o) ? filesize - o : sz; |
1062 | if (bn) | | 1059 | if (bn) |
1063 | (*fn) (bn, numfrags(newsb, sz), nb, MDB_DATA); | | 1060 | (*fn) (bn, numfrags(newsb, sz), nb, MDB_DATA); |
1064 | return (sz); | | 1061 | return (sz); |
1065 | } | | 1062 | } |
1066 | /* Helper function - handles an indirect block. Makes the | | 1063 | /* Helper function - handles an indirect block. Makes the |
1067 | * MDB_INDIR_PRE callback for the indirect block, loops over the | | 1064 | * MDB_INDIR_PRE callback for the indirect block, loops over the |
1068 | * pointers and recurses, and makes the MDB_INDIR_POST callback. | | 1065 | * pointers and recurses, and makes the MDB_INDIR_POST callback. |
1069 | * Returns the number of bytes occupied in file, as does markblk(). | | 1066 | * Returns the number of bytes occupied in file, as does markblk(). |
1070 | * For the sake of update_for_data_move(), we read the indirect block | | 1067 | * For the sake of update_for_data_move(), we read the indirect block |
1071 | * _after_ making the _PRE callback. The name is historical. */ | | 1068 | * _after_ making the _PRE callback. The name is historical. */ |
1072 | static int | | 1069 | static int |
1073 | markiblk(mark_callback_t fn, union dinode * di, off_t bn, off_t o, int lev) | | 1070 | markiblk(mark_callback_t fn, union dinode * di, off_t bn, off_t o, int lev) |
1074 | { | | 1071 | { |
1075 | int i; | | 1072 | int i; |
1076 | int j; | | 1073 | int j; |
1077 | unsigned k; | | 1074 | unsigned k; |
1078 | int tot; | | 1075 | int tot; |
1079 | static int32_t indirblk1[howmany(MAXBSIZE, sizeof(int32_t))]; | | 1076 | static int32_t indirblk1[howmany(MAXBSIZE, sizeof(int32_t))]; |
1080 | static int32_t indirblk2[howmany(MAXBSIZE, sizeof(int32_t))]; | | 1077 | static int32_t indirblk2[howmany(MAXBSIZE, sizeof(int32_t))]; |
1081 | static int32_t indirblk3[howmany(MAXBSIZE, sizeof(int32_t))]; | | 1078 | static int32_t indirblk3[howmany(MAXBSIZE, sizeof(int32_t))]; |
1082 | static int32_t *indirblks[3] = { | | 1079 | static int32_t *indirblks[3] = { |
1083 | &indirblk1[0], &indirblk2[0], &indirblk3[0] | | 1080 | &indirblk1[0], &indirblk2[0], &indirblk3[0] |
1084 | }; | | 1081 | }; |
1085 | | | 1082 | |
1086 | if (lev < 0) | | 1083 | if (lev < 0) |
1087 | return (markblk(fn, di, bn, o)); | | 1084 | return (markblk(fn, di, bn, o)); |
1088 | if (bn == 0) { | | 1085 | if (bn == 0) { |
1089 | for (i = newsb->fs_bsize; | | 1086 | for (i = newsb->fs_bsize; |
1090 | lev >= 0; | | 1087 | lev >= 0; |
1091 | i *= NINDIR(newsb), lev--); | | 1088 | i *= NINDIR(newsb), lev--); |
1092 | return (i); | | 1089 | return (i); |
1093 | } | | 1090 | } |
1094 | (*fn) (bn, newsb->fs_frag, newsb->fs_bsize, MDB_INDIR_PRE); | | 1091 | (*fn) (bn, newsb->fs_frag, newsb->fs_bsize, MDB_INDIR_PRE); |
1095 | readat(fsbtodb(newsb, bn), indirblks[lev], newsb->fs_bsize); | | 1092 | readat(fsbtodb(newsb, bn), indirblks[lev], newsb->fs_bsize); |
1096 | if (needswap) | | 1093 | if (needswap) |
1097 | for (k = 0; k < howmany(MAXBSIZE, sizeof(int32_t)); k++) | | 1094 | for (k = 0; k < howmany(MAXBSIZE, sizeof(int32_t)); k++) |
1098 | indirblks[lev][k] = bswap32(indirblks[lev][k]); | | 1095 | indirblks[lev][k] = bswap32(indirblks[lev][k]); |
1099 | tot = 0; | | 1096 | tot = 0; |
1100 | for (i = 0; i < NINDIR(newsb); i++) { | | 1097 | for (i = 0; i < NINDIR(newsb); i++) { |
1101 | j = markiblk(fn, di, indirblks[lev][i], o, lev - 1); | | 1098 | j = markiblk(fn, di, indirblks[lev][i], o, lev - 1); |
1102 | if (j == 0) | | 1099 | if (j == 0) |
1103 | break; | | 1100 | break; |
1104 | o += j; | | 1101 | o += j; |
1105 | tot += j; | | 1102 | tot += j; |
1106 | } | | 1103 | } |
1107 | (*fn) (bn, newsb->fs_frag, newsb->fs_bsize, MDB_INDIR_POST); | | 1104 | (*fn) (bn, newsb->fs_frag, newsb->fs_bsize, MDB_INDIR_POST); |
1108 | return (tot); | | 1105 | return (tot); |
1109 | } | | 1106 | } |
1110 | | | 1107 | |
1111 | | | 1108 | |
1112 | /* | | 1109 | /* |
1113 | * Call (*fn)() for each data block for an inode. This routine assumes | | 1110 | * Call (*fn)() for each data block for an inode. This routine assumes |
1114 | * the inode is known to be of a type that has data blocks (file, | | 1111 | * the inode is known to be of a type that has data blocks (file, |
1115 | * directory, or non-fast symlink). The called function is: | | 1112 | * directory, or non-fast symlink). The called function is: |
1116 | * | | 1113 | * |
1117 | * (*fn)(unsigned int blkno, unsigned int nf, unsigned int nb, int op) | | 1114 | * (*fn)(unsigned int blkno, unsigned int nf, unsigned int nb, int op) |
1118 | * | | 1115 | * |
1119 | * where blkno is the frag number, nf is the number of frags starting | | 1116 | * where blkno is the frag number, nf is the number of frags starting |
1120 | * at blkno (always <= fs_frag), nb is the number of bytes that belong | | 1117 | * at blkno (always <= fs_frag), nb is the number of bytes that belong |
1121 | * to the file (usually nf*fs_frag, often less for the last block/frag | | 1118 | * to the file (usually nf*fs_frag, often less for the last block/frag |
1122 | * of a file). | | 1119 | * of a file). |
1123 | */ | | 1120 | */ |
1124 | static void | | 1121 | static void |
1125 | map_inode_data_blocks(union dinode * di, mark_callback_t fn) | | 1122 | map_inode_data_blocks(union dinode * di, mark_callback_t fn) |
1126 | { | | 1123 | { |
1127 | off_t o; /* offset within inode */ | | 1124 | off_t o; /* offset within inode */ |
1128 | int inc; /* increment for o - maybe should be off_t? */ | | 1125 | int inc; /* increment for o - maybe should be off_t? */ |
1129 | int b; /* index within di_db[] and di_ib[] arrays */ | | 1126 | int b; /* index within di_db[] and di_ib[] arrays */ |
1130 | | | 1127 | |
1131 | /* Scan the direct blocks... */ | | 1128 | /* Scan the direct blocks... */ |
1132 | o = 0; | | 1129 | o = 0; |
1133 | for (b = 0; b < NDADDR; b++) { | | 1130 | for (b = 0; b < NDADDR; b++) { |
1134 | inc = markblk(fn, di, DIP(di,di_db[b]), o); | | 1131 | inc = markblk(fn, di, DIP(di,di_db[b]), o); |
1135 | if (inc == 0) | | 1132 | if (inc == 0) |
1136 | break; | | 1133 | break; |
1137 | o += inc; | | 1134 | o += inc; |
1138 | } | | 1135 | } |
1139 | /* ...and the indirect blocks. */ | | 1136 | /* ...and the indirect blocks. */ |
1140 | if (inc) { | | 1137 | if (inc) { |
1141 | for (b = 0; b < NIADDR; b++) { | | 1138 | for (b = 0; b < NIADDR; b++) { |
1142 | inc = markiblk(fn, di, DIP(di,di_ib[b]), o, b); | | 1139 | inc = markiblk(fn, di, DIP(di,di_ib[b]), o, b); |
1143 | if (inc == 0) | | 1140 | if (inc == 0) |
1144 | return; | | 1141 | return; |
1145 | o += inc; | | 1142 | o += inc; |
1146 | } | | 1143 | } |
1147 | } | | 1144 | } |
1148 | } | | 1145 | } |
1149 | | | 1146 | |
1150 | static void | | 1147 | static void |
1151 | dblk_callback(union dinode * di, unsigned int inum, void *arg) | | 1148 | dblk_callback(union dinode * di, unsigned int inum, void *arg) |
1152 | { | | 1149 | { |
1153 | mark_callback_t fn; | | 1150 | mark_callback_t fn; |
1154 | off_t filesize; | | 1151 | off_t filesize; |
1155 | | | 1152 | |
1156 | filesize = DIP(di,di_size); | | 1153 | filesize = DIP(di,di_size); |
1157 | fn = (mark_callback_t) arg; | | 1154 | fn = (mark_callback_t) arg; |
1158 | switch (DIP(di,di_mode) & IFMT) { | | 1155 | switch (DIP(di,di_mode) & IFMT) { |
1159 | case IFLNK: | | 1156 | case IFLNK: |
1160 | if (filesize <= newsb->fs_maxsymlinklen) { | | 1157 | if (filesize <= newsb->fs_maxsymlinklen) { |
1161 | break; | | 1158 | break; |
1162 | } | | 1159 | } |
1163 | /* FALLTHROUGH */ | | 1160 | /* FALLTHROUGH */ |
1164 | case IFDIR: | | 1161 | case IFDIR: |
1165 | case IFREG: | | 1162 | case IFREG: |
1166 | map_inode_data_blocks(di, fn); | | 1163 | map_inode_data_blocks(di, fn); |
1167 | break; | | 1164 | break; |
1168 | } | | 1165 | } |
1169 | } | | 1166 | } |
1170 | /* | | 1167 | /* |
1171 | * Make a callback call, a la map_inode_data_blocks, for all data | | 1168 | * Make a callback call, a la map_inode_data_blocks, for all data |
1172 | * blocks in the entire fs. This is used only once, in | | 1169 | * blocks in the entire fs. This is used only once, in |
1173 | * update_for_data_move, but it's out at top level because the complex | | 1170 | * update_for_data_move, but it's out at top level because the complex |
1174 | * downward-funarg nesting that would otherwise result seems to give | | 1171 | * downward-funarg nesting that would otherwise result seems to give |
1175 | * gcc gastric distress. | | 1172 | * gcc gastric distress. |
1176 | */ | | 1173 | */ |
1177 | static void | | 1174 | static void |
1178 | map_data_blocks(mark_callback_t fn, int ncg) | | 1175 | map_data_blocks(mark_callback_t fn, int ncg) |
1179 | { | | 1176 | { |
1180 | map_inodes(&dblk_callback, ncg, (void *) fn); | | 1177 | map_inodes(&dblk_callback, ncg, (void *) fn); |
1181 | } | | 1178 | } |
1182 | /* | | 1179 | /* |
1183 | * Initialize the blkmove array. | | 1180 | * Initialize the blkmove array. |
1184 | */ | | 1181 | */ |
1185 | static void | | 1182 | static void |
1186 | blkmove_init(void) | | 1183 | blkmove_init(void) |
1187 | { | | 1184 | { |
1188 | int i; | | 1185 | int i; |
1189 | | | 1186 | |
1190 | blkmove = alloconce(oldsb->fs_size * sizeof(*blkmove), "blkmove"); | | 1187 | blkmove = alloconce(oldsb->fs_size * sizeof(*blkmove), "blkmove"); |
1191 | for (i = 0; i < oldsb->fs_size; i++) | | 1188 | for (i = 0; i < oldsb->fs_size; i++) |
1192 | blkmove[i] = i; | | 1189 | blkmove[i] = i; |
1193 | } | | 1190 | } |
1194 | /* | | 1191 | /* |
1195 | * Load the inodes off disk. Allocates the structures and initializes | | 1192 | * Load the inodes off disk. Allocates the structures and initializes |
1196 | * them - the inodes from disk, the flags to zero. | | 1193 | * them - the inodes from disk, the flags to zero. |
1197 | */ | | 1194 | */ |
1198 | static void | | 1195 | static void |
1199 | loadinodes(void) | | 1196 | loadinodes(void) |
1200 | { | | 1197 | { |
1201 | int imax, ino, i, j; | | 1198 | int imax, ino, i, j; |
1202 | struct ufs1_dinode *dp1 = NULL; | | 1199 | struct ufs1_dinode *dp1 = NULL; |
1203 | struct ufs2_dinode *dp2 = NULL; | | 1200 | struct ufs2_dinode *dp2 = NULL; |
1204 | | | 1201 | |
1205 | /* read inodes one fs block at a time and copy them */ | | 1202 | /* read inodes one fs block at a time and copy them */ |
1206 | | | 1203 | |
1207 | inodes = alloconce(oldsb->fs_ncg * oldsb->fs_ipg * | | 1204 | inodes = alloconce(oldsb->fs_ncg * oldsb->fs_ipg * |
1208 | sizeof(union dinode), "inodes"); | | 1205 | sizeof(union dinode), "inodes"); |
1209 | iflags = alloconce(oldsb->fs_ncg * oldsb->fs_ipg, "inode flags"); | | 1206 | iflags = alloconce(oldsb->fs_ncg * oldsb->fs_ipg, "inode flags"); |
1210 | memset(iflags, 0, oldsb->fs_ncg * oldsb->fs_ipg); | | 1207 | memset(iflags, 0, oldsb->fs_ncg * oldsb->fs_ipg); |
1211 | | | 1208 | |
1212 | ibuf = nfmalloc(oldsb->fs_bsize,"inode block buf"); | | 1209 | ibuf = nfmalloc(oldsb->fs_bsize,"inode block buf"); |
1213 | if (is_ufs2) | | 1210 | if (is_ufs2) |
1214 | dp2 = (struct ufs2_dinode *)ibuf; | | 1211 | dp2 = (struct ufs2_dinode *)ibuf; |
1215 | else | | 1212 | else |
1216 | dp1 = (struct ufs1_dinode *)ibuf; | | 1213 | dp1 = (struct ufs1_dinode *)ibuf; |
1217 | | | 1214 | |
1218 | for (ino = 0,imax = oldsb->fs_ipg * oldsb->fs_ncg; ino < imax; ) { | | 1215 | for (ino = 0,imax = oldsb->fs_ipg * oldsb->fs_ncg; ino < imax; ) { |
1219 | readat(fsbtodb(oldsb, ino_to_fsba(oldsb, ino)), ibuf, | | 1216 | readat(fsbtodb(oldsb, ino_to_fsba(oldsb, ino)), ibuf, |
1220 | oldsb->fs_bsize); | | 1217 | oldsb->fs_bsize); |
1221 | | | 1218 | |
1222 | for (i = 0; i < oldsb->fs_inopb; i++) { | | 1219 | for (i = 0; i < oldsb->fs_inopb; i++) { |
1223 | if (is_ufs2) { | | 1220 | if (is_ufs2) { |
1224 | if (needswap) { | | 1221 | if (needswap) { |
1225 | ffs_dinode2_swap(&(dp2[i]), &(dp2[i])); | | 1222 | ffs_dinode2_swap(&(dp2[i]), &(dp2[i])); |
1226 | for (j = 0; j < NDADDR + NIADDR; j++) | | 1223 | for (j = 0; j < NDADDR + NIADDR; j++) |
1227 | dp2[i].di_db[j] = | | 1224 | dp2[i].di_db[j] = |
1228 | bswap32(dp2[i].di_db[j]); | | 1225 | bswap32(dp2[i].di_db[j]); |
1229 | } | | 1226 | } |
1230 | memcpy(&inodes[ino].dp2, &dp2[i], | | 1227 | memcpy(&inodes[ino].dp2, &dp2[i], |
1231 | sizeof(struct ufs2_dinode)); | | 1228 | sizeof(inodes[ino].dp2)); |
1232 | } else { | | 1229 | } else { |
1233 | if (needswap) { | | 1230 | if (needswap) { |
1234 | ffs_dinode1_swap(&(dp1[i]), &(dp1[i])); | | 1231 | ffs_dinode1_swap(&(dp1[i]), &(dp1[i])); |
1235 | for (j = 0; j < NDADDR + NIADDR; j++) | | 1232 | for (j = 0; j < NDADDR + NIADDR; j++) |
1236 | dp1[i].di_db[j] = | | 1233 | dp1[i].di_db[j] = |
1237 | bswap32(dp1[i].di_db[j]); | | 1234 | bswap32(dp1[i].di_db[j]); |
1238 | } | | 1235 | } |
1239 | memcpy(&inodes[ino].dp1, &dp1[i], | | 1236 | memcpy(&inodes[ino].dp1, &dp1[i], |
1240 | sizeof(struct ufs1_dinode)); | | 1237 | sizeof(inodes[ino].dp1)); |
1241 | } | | 1238 | } |
1242 | if (++ino > imax) | | 1239 | if (++ino > imax) |
1243 | errx(EXIT_FAILURE, | | 1240 | errx(EXIT_FAILURE, |
1244 | "Exceeded number of inodes"); | | 1241 | "Exceeded number of inodes"); |
1245 | } | | 1242 | } |
1246 | | | 1243 | |
1247 | } | | 1244 | } |
1248 | } | | 1245 | } |
1249 | /* | | 1246 | /* |
1250 | * Report a file-system-too-full problem. | | 1247 | * Report a file-system-too-full problem. |
1251 | */ | | 1248 | */ |
1252 | static void | | 1249 | __dead static void |
1253 | toofull(void) | | 1250 | toofull(void) |
1254 | { | | 1251 | { |
1255 | printf("Sorry, would run out of data blocks\n"); | | 1252 | errx(EXIT_FAILURE, "Sorry, would run out of data blocks"); |
1256 | exit(EXIT_FAILURE); | | | |
1257 | } | | 1253 | } |
1258 | /* | | 1254 | /* |
1259 | * Record a desire to move "n" frags from "from" to "to". | | 1255 | * Record a desire to move "n" frags from "from" to "to". |
1260 | */ | | 1256 | */ |
1261 | static void | | 1257 | static void |
1262 | mark_move(unsigned int from, unsigned int to, unsigned int n) | | 1258 | mark_move(unsigned int from, unsigned int to, unsigned int n) |
1263 | { | | 1259 | { |
1264 | for (; n > 0; n--) | | 1260 | for (; n > 0; n--) |
1265 | blkmove[from++] = to++; | | 1261 | blkmove[from++] = to++; |
1266 | } | | 1262 | } |
1267 | /* Helper function - evict n frags, starting with start (cg-relative). | | 1263 | /* Helper function - evict n frags, starting with start (cg-relative). |
1268 | * The free bitmap is scanned, unallocated frags are ignored, and | | 1264 | * The free bitmap is scanned, unallocated frags are ignored, and |
1269 | * each block of consecutive allocated frags is moved as a unit. | | 1265 | * each block of consecutive allocated frags is moved as a unit. |
1270 | */ | | 1266 | */ |
1271 | static void | | 1267 | static void |
1272 | fragmove(struct cg * cg, int base, unsigned int start, unsigned int n) | | 1268 | fragmove(struct cg * cg, int base, unsigned int start, unsigned int n) |
1273 | { | | 1269 | { |
1274 | unsigned int i; | | 1270 | unsigned int i; |
1275 | int run; | | 1271 | int run; |
1276 | | | 1272 | |
1277 | run = 0; | | 1273 | run = 0; |
1278 | for (i = 0; i <= n; i++) { | | 1274 | for (i = 0; i <= n; i++) { |
1279 | if ((i < n) && bit_is_clr(cg_blksfree(cg, 0), start + i)) { | | 1275 | if ((i < n) && bit_is_clr(cg_blksfree(cg, 0), start + i)) { |
1280 | run++; | | 1276 | run++; |
1281 | } else { | | 1277 | } else { |
1282 | if (run > 0) { | | 1278 | if (run > 0) { |
1283 | int off; | | 1279 | int off; |
1284 | off = find_freespace(run); | | 1280 | off = find_freespace(run); |
1285 | if (off < 0) | | 1281 | if (off < 0) |
1286 | toofull(); | | 1282 | toofull(); |
1287 | mark_move(base + start + i - run, off, run); | | 1283 | mark_move(base + start + i - run, off, run); |
1288 | set_bits(cg_blksfree(cg, 0), start + i - run, | | 1284 | set_bits(cg_blksfree(cg, 0), start + i - run, |
1289 | run); | | 1285 | run); |
1290 | clr_bits(cg_blksfree(cgs[dtog(oldsb, off)], 0), | | 1286 | clr_bits(cg_blksfree(cgs[dtog(oldsb, off)], 0), |
1291 | dtogd(oldsb, off), run); | | 1287 | dtogd(oldsb, off), run); |
1292 | } | | 1288 | } |
1293 | run = 0; | | 1289 | run = 0; |
1294 | } | | 1290 | } |
1295 | } | | 1291 | } |
1296 | } | | 1292 | } |
1297 | /* | | 1293 | /* |
1298 | * Evict all data blocks from the given cg, starting at minfrag (based | | 1294 | * Evict all data blocks from the given cg, starting at minfrag (based |
1299 | * at the beginning of the cg), for length nfrag. The eviction is | | 1295 | * at the beginning of the cg), for length nfrag. The eviction is |
1300 | * assumed to be entirely data-area; this should not be called with a | | 1296 | * assumed to be entirely data-area; this should not be called with a |
1301 | * range overlapping the metadata structures in the cg. It also | | 1297 | * range overlapping the metadata structures in the cg. It also |
1302 | * assumes minfrag points into the given cg; it will misbehave if this | | 1298 | * assumes minfrag points into the given cg; it will misbehave if this |
1303 | * is not true. | | 1299 | * is not true. |
1304 | * | | 1300 | * |
1305 | * See the comment header on find_freespace() for one possible bug | | 1301 | * See the comment header on find_freespace() for one possible bug |
1306 | * lurking here. | | 1302 | * lurking here. |
1307 | */ | | 1303 | */ |
1308 | static void | | 1304 | static void |
1309 | evict_data(struct cg * cg, unsigned int minfrag, int nfrag) | | 1305 | evict_data(struct cg * cg, unsigned int minfrag, int nfrag) |
1310 | { | | 1306 | { |
1311 | int base; /* base of cg (in frags from beginning of fs) */ | | 1307 | int base; /* base of cg (in frags from beginning of fs) */ |
1312 | | | 1308 | |
1313 | base = cgbase(oldsb, cg->cg_cgx); | | 1309 | base = cgbase(oldsb, cg->cg_cgx); |
1314 | /* Does the boundary fall in the middle of a block? To avoid | | 1310 | /* Does the boundary fall in the middle of a block? To avoid |
1315 | * breaking between frags allocated as consecutive, we always | | 1311 | * breaking between frags allocated as consecutive, we always |
1316 | * evict the whole block in this case, though one could argue | | 1312 | * evict the whole block in this case, though one could argue |
1317 | * we should check to see if the frag before or after the | | 1313 | * we should check to see if the frag before or after the |
1318 | * break is unallocated. */ | | 1314 | * break is unallocated. */ |
1319 | if (minfrag % oldsb->fs_frag) { | | 1315 | if (minfrag % oldsb->fs_frag) { |
1320 | int n; | | 1316 | int n; |
1321 | n = minfrag % oldsb->fs_frag; | | 1317 | n = minfrag % oldsb->fs_frag; |
1322 | minfrag -= n; | | 1318 | minfrag -= n; |
1323 | nfrag += n; | | 1319 | nfrag += n; |
1324 | } | | 1320 | } |
1325 | /* Do whole blocks. If a block is wholly free, skip it; if | | 1321 | /* Do whole blocks. If a block is wholly free, skip it; if |
1326 | * wholly allocated, move it in toto. If neither, call | | 1322 | * wholly allocated, move it in toto. If neither, call |
1327 | * fragmove() to move the frags to new locations. */ | | 1323 | * fragmove() to move the frags to new locations. */ |
1328 | while (nfrag >= oldsb->fs_frag) { | | 1324 | while (nfrag >= oldsb->fs_frag) { |
1329 | if (!blk_is_set(cg_blksfree(cg, 0), minfrag, oldsb->fs_frag)) { | | 1325 | if (!blk_is_set(cg_blksfree(cg, 0), minfrag, oldsb->fs_frag)) { |
1330 | if (blk_is_clr(cg_blksfree(cg, 0), minfrag, | | 1326 | if (blk_is_clr(cg_blksfree(cg, 0), minfrag, |
1331 | oldsb->fs_frag)) { | | 1327 | oldsb->fs_frag)) { |
1332 | int off; | | 1328 | int off; |
1333 | off = find_freeblock(); | | 1329 | off = find_freeblock(); |
1334 | if (off < 0) | | 1330 | if (off < 0) |
1335 | toofull(); | | 1331 | toofull(); |
1336 | mark_move(base + minfrag, off, oldsb->fs_frag); | | 1332 | mark_move(base + minfrag, off, oldsb->fs_frag); |
1337 | set_bits(cg_blksfree(cg, 0), minfrag, | | 1333 | set_bits(cg_blksfree(cg, 0), minfrag, |
1338 | oldsb->fs_frag); | | 1334 | oldsb->fs_frag); |
1339 | clr_bits(cg_blksfree(cgs[dtog(oldsb, off)], 0), | | 1335 | clr_bits(cg_blksfree(cgs[dtog(oldsb, off)], 0), |
1340 | dtogd(oldsb, off), oldsb->fs_frag); | | 1336 | dtogd(oldsb, off), oldsb->fs_frag); |
1341 | } else { | | 1337 | } else { |
1342 | fragmove(cg, base, minfrag, oldsb->fs_frag); | | 1338 | fragmove(cg, base, minfrag, oldsb->fs_frag); |
1343 | } | | 1339 | } |
1344 | } | | 1340 | } |
1345 | minfrag += oldsb->fs_frag; | | 1341 | minfrag += oldsb->fs_frag; |
1346 | nfrag -= oldsb->fs_frag; | | 1342 | nfrag -= oldsb->fs_frag; |
1347 | } | | 1343 | } |
1348 | /* Clean up any sub-block amount left over. */ | | 1344 | /* Clean up any sub-block amount left over. */ |
1349 | if (nfrag) { | | 1345 | if (nfrag) { |
1350 | fragmove(cg, base, minfrag, nfrag); | | 1346 | fragmove(cg, base, minfrag, nfrag); |
1351 | } | | 1347 | } |
1352 | } | | 1348 | } |
1353 | /* | | 1349 | /* |
1354 | * Move all data blocks according to blkmove. We have to be careful, | | 1350 | * Move all data blocks according to blkmove. We have to be careful, |
1355 | * because we may be updating indirect blocks that will themselves be | | 1351 | * because we may be updating indirect blocks that will themselves be |
1356 | * getting moved, or inode int32_t arrays that point to indirect | | 1352 | * getting moved, or inode int32_t arrays that point to indirect |
1357 | * blocks that will be moved. We call this before | | 1353 | * blocks that will be moved. We call this before |
1358 | * update_for_data_move, and update_for_data_move does inodes first, | | 1354 | * update_for_data_move, and update_for_data_move does inodes first, |
1359 | * then indirect blocks in preorder, so as to make sure that the | | 1355 | * then indirect blocks in preorder, so as to make sure that the |
1360 | * file system is self-consistent at all points, for better crash | | 1356 | * file system is self-consistent at all points, for better crash |
1361 | * tolerance. (We can get away with this only because all the writes | | 1357 | * tolerance. (We can get away with this only because all the writes |
1362 | * done by perform_data_move() are writing into space that's not used | | 1358 | * done by perform_data_move() are writing into space that's not used |
1363 | * by the old file system.) If we crash, some things may point to the | | 1359 | * by the old file system.) If we crash, some things may point to the |
1364 | * old data and some to the new, but both copies are the same. The | | 1360 | * old data and some to the new, but both copies are the same. The |
1365 | * only wrong things should be csum info and free bitmaps, which fsck | | 1361 | * only wrong things should be csum info and free bitmaps, which fsck |
1366 | * is entirely capable of cleaning up. | | 1362 | * is entirely capable of cleaning up. |
1367 | * | | 1363 | * |
1368 | * Since blkmove_init() initializes all blocks to move to their current | | 1364 | * Since blkmove_init() initializes all blocks to move to their current |
1369 | * locations, we can have two blocks marked as wanting to move to the | | 1365 | * locations, we can have two blocks marked as wanting to move to the |
1370 | * same location, but only two and only when one of them is the one | | 1366 | * same location, but only two and only when one of them is the one |
1371 | * that was already there. So if blkmove[i]==i, we ignore that entry | | 1367 | * that was already there. So if blkmove[i]==i, we ignore that entry |
1372 | * entirely - for unallocated blocks, we don't want it (and may be | | 1368 | * entirely - for unallocated blocks, we don't want it (and may be |
1373 | * putting something else there), and for allocated blocks, we don't | | 1369 | * putting something else there), and for allocated blocks, we don't |
1374 | * want to copy it anywhere. | | 1370 | * want to copy it anywhere. |
1375 | */ | | 1371 | */ |
1376 | static void | | 1372 | static void |
1377 | perform_data_move(void) | | 1373 | perform_data_move(void) |
1378 | { | | 1374 | { |
1379 | int i; | | 1375 | int i; |
1380 | int run; | | 1376 | int run; |
1381 | int maxrun; | | 1377 | int maxrun; |
1382 | char buf[65536]; | | 1378 | char buf[65536]; |
1383 | | | 1379 | |
1384 | maxrun = sizeof(buf) / newsb->fs_fsize; | | 1380 | maxrun = sizeof(buf) / newsb->fs_fsize; |
1385 | run = 0; | | 1381 | run = 0; |
1386 | for (i = 0; i < oldsb->fs_size; i++) { | | 1382 | for (i = 0; i < oldsb->fs_size; i++) { |
1387 | if ((blkmove[i] == (unsigned)i /*XXX cast*/) || | | 1383 | if ((blkmove[i] == (unsigned)i /*XXX cast*/) || |
1388 | (run >= maxrun) || | | 1384 | (run >= maxrun) || |
1389 | ((run > 0) && | | 1385 | ((run > 0) && |
1390 | (blkmove[i] != blkmove[i - 1] + 1))) { | | 1386 | (blkmove[i] != blkmove[i - 1] + 1))) { |
1391 | if (run > 0) { | | 1387 | if (run > 0) { |
1392 | readat(fsbtodb(oldsb, i - run), &buf[0], | | 1388 | readat(fsbtodb(oldsb, i - run), &buf[0], |
1393 | run << oldsb->fs_fshift); | | 1389 | run << oldsb->fs_fshift); |
1394 | writeat(fsbtodb(oldsb, blkmove[i - run]), | | 1390 | writeat(fsbtodb(oldsb, blkmove[i - run]), |
1395 | &buf[0], run << oldsb->fs_fshift); | | 1391 | &buf[0], run << oldsb->fs_fshift); |
1396 | } | | 1392 | } |
1397 | run = 0; | | 1393 | run = 0; |
1398 | } | | 1394 | } |
1399 | if (blkmove[i] != (unsigned)i /*XXX cast*/) | | 1395 | if (blkmove[i] != (unsigned)i /*XXX cast*/) |
1400 | run++; | | 1396 | run++; |
1401 | } | | 1397 | } |
1402 | if (run > 0) { | | 1398 | if (run > 0) { |
1403 | readat(fsbtodb(oldsb, i - run), &buf[0], | | 1399 | readat(fsbtodb(oldsb, i - run), &buf[0], |
1404 | run << oldsb->fs_fshift); | | 1400 | run << oldsb->fs_fshift); |
1405 | writeat(fsbtodb(oldsb, blkmove[i - run]), &buf[0], | | 1401 | writeat(fsbtodb(oldsb, blkmove[i - run]), &buf[0], |
1406 | run << oldsb->fs_fshift); | | 1402 | run << oldsb->fs_fshift); |
1407 | } | | 1403 | } |
1408 | } | | 1404 | } |
1409 | /* | | 1405 | /* |
1410 | * This modifies an array of int32_t, according to blkmove. This is | | 1406 | * This modifies an array of int32_t, according to blkmove. This is |
1411 | * used to update inode block arrays and indirect blocks to point to | | 1407 | * used to update inode block arrays and indirect blocks to point to |
1412 | * the new locations of data blocks. | | 1408 | * the new locations of data blocks. |
1413 | * | | 1409 | * |
1414 | * Return value is the number of int32_ts that needed updating; in | | 1410 | * Return value is the number of int32_ts that needed updating; in |
1415 | * particular, the return value is zero iff nothing was modified. | | 1411 | * particular, the return value is zero iff nothing was modified. |
1416 | */ | | 1412 | */ |
1417 | static int | | 1413 | static int |
1418 | movemap_blocks(int32_t * vec, int n) | | 1414 | movemap_blocks(int32_t * vec, int n) |
1419 | { | | 1415 | { |
1420 | int rv; | | 1416 | int rv; |
1421 | | | 1417 | |
1422 | rv = 0; | | 1418 | rv = 0; |
1423 | for (; n > 0; n--, vec++) { | | 1419 | for (; n > 0; n--, vec++) { |
1424 | if (blkmove[*vec] != (unsigned)*vec /*XXX cast*/) { | | 1420 | if (blkmove[*vec] != (unsigned)*vec /*XXX cast*/) { |
1425 | *vec = blkmove[*vec]; | | 1421 | *vec = blkmove[*vec]; |
1426 | rv++; | | 1422 | rv++; |
1427 | } | | 1423 | } |
1428 | } | | 1424 | } |
1429 | return (rv); | | 1425 | return (rv); |
1430 | } | | 1426 | } |
1431 | static void | | 1427 | static void |
1432 | moveblocks_callback(union dinode * di, unsigned int inum, void *arg) | | 1428 | moveblocks_callback(union dinode * di, unsigned int inum, void *arg) |
1433 | { | | 1429 | { |
1434 | int32_t *dblkptr, *iblkptr; | | 1430 | int32_t *dblkptr, *iblkptr; |
1435 | | | 1431 | |
1436 | switch (DIP(di,di_mode) & IFMT) { | | 1432 | switch (DIP(di,di_mode) & IFMT) { |
1437 | case IFLNK: | | 1433 | case IFLNK: |
1438 | if ((off_t)DIP(di,di_size) <= oldsb->fs_maxsymlinklen) { | | 1434 | if ((off_t)DIP(di,di_size) <= oldsb->fs_maxsymlinklen) { |
1439 | break; | | 1435 | break; |
1440 | } | | 1436 | } |
1441 | /* FALLTHROUGH */ | | 1437 | /* FALLTHROUGH */ |
1442 | case IFDIR: | | 1438 | case IFDIR: |
1443 | case IFREG: | | 1439 | case IFREG: |
1444 | if (is_ufs2) { | | 1440 | if (is_ufs2) { |
1445 | /* XXX these are not int32_t and this is WRONG! */ | | 1441 | /* XXX these are not int32_t and this is WRONG! */ |
1446 | dblkptr = (void *) &(di->dp2.di_db[0]); | | 1442 | dblkptr = (void *) &(di->dp2.di_db[0]); |
1447 | iblkptr = (void *) &(di->dp2.di_ib[0]); | | 1443 | iblkptr = (void *) &(di->dp2.di_ib[0]); |
1448 | } else { | | 1444 | } else { |
1449 | dblkptr = &(di->dp1.di_db[0]); | | 1445 | dblkptr = &(di->dp1.di_db[0]); |
1450 | iblkptr = &(di->dp1.di_ib[0]); | | 1446 | iblkptr = &(di->dp1.di_ib[0]); |
1451 | } | | 1447 | } |
1452 | /* | | 1448 | /* |
1453 | * Don't || these two calls; we need their | | 1449 | * Don't || these two calls; we need their |
1454 | * side-effects. | | 1450 | * side-effects. |
1455 | */ | | 1451 | */ |
1456 | if (movemap_blocks(dblkptr, NDADDR)) { | | 1452 | if (movemap_blocks(dblkptr, NDADDR)) { |
1457 | iflags[inum] |= IF_DIRTY; | | 1453 | iflags[inum] |= IF_DIRTY; |
1458 | } | | 1454 | } |
1459 | if (movemap_blocks(iblkptr, NIADDR)) { | | 1455 | if (movemap_blocks(iblkptr, NIADDR)) { |
1460 | iflags[inum] |= IF_DIRTY; | | 1456 | iflags[inum] |= IF_DIRTY; |
1461 | } | | 1457 | } |
1462 | break; | | 1458 | break; |
1463 | } | | 1459 | } |
1464 | } | | 1460 | } |
1465 | | | 1461 | |
1466 | static void | | 1462 | static void |
1467 | moveindir_callback(off_t off, unsigned int nfrag, unsigned int nbytes, | | 1463 | moveindir_callback(off_t off, unsigned int nfrag, unsigned int nbytes, |
1468 | int kind) | | 1464 | int kind) |
1469 | { | | 1465 | { |
1470 | unsigned int i; | | 1466 | unsigned int i; |
1471 | | | 1467 | |
1472 | if (kind == MDB_INDIR_PRE) { | | 1468 | if (kind == MDB_INDIR_PRE) { |
1473 | int32_t blk[howmany(MAXBSIZE, sizeof(int32_t))]; | | 1469 | int32_t blk[howmany(MAXBSIZE, sizeof(int32_t))]; |
1474 | readat(fsbtodb(oldsb, off), &blk[0], oldsb->fs_bsize); | | 1470 | readat(fsbtodb(oldsb, off), &blk[0], oldsb->fs_bsize); |
1475 | if (needswap) | | 1471 | if (needswap) |
1476 | for (i = 0; i < howmany(MAXBSIZE, sizeof(int32_t)); i++) | | 1472 | for (i = 0; i < howmany(MAXBSIZE, sizeof(int32_t)); i++) |
1477 | blk[i] = bswap32(blk[i]); | | 1473 | blk[i] = bswap32(blk[i]); |
1478 | if (movemap_blocks(&blk[0], NINDIR(oldsb))) { | | 1474 | if (movemap_blocks(&blk[0], NINDIR(oldsb))) { |
1479 | if (needswap) | | 1475 | if (needswap) |
1480 | for (i = 0; i < howmany(MAXBSIZE, | | 1476 | for (i = 0; i < howmany(MAXBSIZE, |
1481 | sizeof(int32_t)); i++) | | 1477 | sizeof(int32_t)); i++) |
1482 | blk[i] = bswap32(blk[i]); | | 1478 | blk[i] = bswap32(blk[i]); |
1483 | writeat(fsbtodb(oldsb, off), &blk[0], oldsb->fs_bsize); | | 1479 | writeat(fsbtodb(oldsb, off), &blk[0], oldsb->fs_bsize); |
1484 | } | | 1480 | } |
1485 | } | | 1481 | } |
1486 | } | | 1482 | } |
1487 | /* | | 1483 | /* |
1488 | * Update all inode data arrays and indirect blocks to point to the new | | 1484 | * Update all inode data arrays and indirect blocks to point to the new |
1489 | * locations of data blocks. See the comment header on | | 1485 | * locations of data blocks. See the comment header on |
1490 | * perform_data_move for some ordering considerations. | | 1486 | * perform_data_move for some ordering considerations. |
1491 | */ | | 1487 | */ |
1492 | static void | | 1488 | static void |
1493 | update_for_data_move(void) | | 1489 | update_for_data_move(void) |
1494 | { | | 1490 | { |
1495 | map_inodes(&moveblocks_callback, oldsb->fs_ncg, NULL); | | 1491 | map_inodes(&moveblocks_callback, oldsb->fs_ncg, NULL); |
1496 | map_data_blocks(&moveindir_callback, oldsb->fs_ncg); | | 1492 | map_data_blocks(&moveindir_callback, oldsb->fs_ncg); |
1497 | } | | 1493 | } |
1498 | /* | | 1494 | /* |
1499 | * Initialize the inomove array. | | 1495 | * Initialize the inomove array. |
1500 | */ | | 1496 | */ |
1501 | static void | | 1497 | static void |
1502 | inomove_init(void) | | 1498 | inomove_init(void) |
1503 | { | | 1499 | { |
1504 | int i; | | 1500 | int i; |
1505 | | | 1501 | |
1506 | inomove = alloconce(oldsb->fs_ipg * oldsb->fs_ncg * sizeof(*inomove), | | 1502 | inomove = alloconce(oldsb->fs_ipg * oldsb->fs_ncg * sizeof(*inomove), |
1507 | "inomove"); | | 1503 | "inomove"); |
1508 | for (i = (oldsb->fs_ipg * oldsb->fs_ncg) - 1; i >= 0; i--) | | 1504 | for (i = (oldsb->fs_ipg * oldsb->fs_ncg) - 1; i >= 0; i--) |
1509 | inomove[i] = i; | | 1505 | inomove[i] = i; |
1510 | } | | 1506 | } |
1511 | /* | | 1507 | /* |
1512 | * Flush all dirtied inodes to disk. Scans the inode flags array; for | | 1508 | * Flush all dirtied inodes to disk. Scans the inode flags array; for |
1513 | * each dirty inode, it sets the BDIRTY bit on the first inode in the | | 1509 | * each dirty inode, it sets the BDIRTY bit on the first inode in the |
1514 | * block containing the dirty inode. Then it scans by blocks, and for | | 1510 | * block containing the dirty inode. Then it scans by blocks, and for |
1515 | * each marked block, writes it. | | 1511 | * each marked block, writes it. |
1516 | */ | | 1512 | */ |
1517 | static void | | 1513 | static void |
1518 | flush_inodes(void) | | 1514 | flush_inodes(void) |
1519 | { | | 1515 | { |
1520 | int i, j, k, na, ni, m; | | 1516 | int i, j, k, na, ni, m; |
1521 | struct ufs1_dinode *dp1 = NULL; | | 1517 | struct ufs1_dinode *dp1 = NULL; |
1522 | struct ufs2_dinode *dp2 = NULL; | | 1518 | struct ufs2_dinode *dp2 = NULL; |
1523 | | | 1519 | |
1524 | na = NDADDR + NIADDR; | | 1520 | na = NDADDR + NIADDR; |
1525 | ni = newsb->fs_ipg * newsb->fs_ncg; | | 1521 | ni = newsb->fs_ipg * newsb->fs_ncg; |
1526 | m = INOPB(newsb) - 1; | | 1522 | m = INOPB(newsb) - 1; |
1527 | for (i = 0; i < ni; i++) { | | 1523 | for (i = 0; i < ni; i++) { |
1528 | if (iflags[i] & IF_DIRTY) { | | 1524 | if (iflags[i] & IF_DIRTY) { |
1529 | iflags[i & ~m] |= IF_BDIRTY; | | 1525 | iflags[i & ~m] |= IF_BDIRTY; |
1530 | } | | 1526 | } |
1531 | } | | 1527 | } |
1532 | m++; | | 1528 | m++; |
1533 | | | 1529 | |
1534 | if (is_ufs2) | | 1530 | if (is_ufs2) |
1535 | dp2 = (struct ufs2_dinode *)ibuf; | | 1531 | dp2 = (struct ufs2_dinode *)ibuf; |
1536 | else | | 1532 | else |
1537 | dp1 = (struct ufs1_dinode *)ibuf; | | 1533 | dp1 = (struct ufs1_dinode *)ibuf; |
1538 | | | 1534 | |
1539 | for (i = 0; i < ni; i += m) { | | 1535 | for (i = 0; i < ni; i += m) { |
1540 | if (iflags[i] & IF_BDIRTY) { | | 1536 | if (iflags[i] & IF_BDIRTY) { |
1541 | if (is_ufs2) | | 1537 | if (is_ufs2) |
1542 | for (j = 0; j < m; j++) { | | 1538 | for (j = 0; j < m; j++) { |
1543 | dp2[j] = inodes[i + j].dp2; | | 1539 | dp2[j] = inodes[i + j].dp2; |
1544 | if (needswap) { | | 1540 | if (needswap) { |
1545 | for (k = 0; k < na; k++) | | 1541 | for (k = 0; k < na; k++) |
1546 | dp2[j].di_db[k]= | | 1542 | dp2[j].di_db[k]= |
1547 | bswap32(dp2[j].di_db[k]); | | 1543 | bswap32(dp2[j].di_db[k]); |
1548 | ffs_dinode2_swap(&dp2[j], | | 1544 | ffs_dinode2_swap(&dp2[j], |
1549 | &dp2[j]); | | 1545 | &dp2[j]); |
1550 | } | | 1546 | } |
1551 | } | | 1547 | } |
1552 | else | | 1548 | else |
1553 | for (j = 0; j < m; j++) { | | 1549 | for (j = 0; j < m; j++) { |
1554 | dp1[j] = inodes[i + j].dp1; | | 1550 | dp1[j] = inodes[i + j].dp1; |
1555 | if (needswap) { | | 1551 | if (needswap) { |
1556 | for (k = 0; k < na; k++) | | 1552 | for (k = 0; k < na; k++) |
1557 | dp1[j].di_db[k]= | | 1553 | dp1[j].di_db[k]= |
1558 | bswap32(dp1[j].di_db[k]); | | 1554 | bswap32(dp1[j].di_db[k]); |
1559 | ffs_dinode1_swap(&dp1[j], | | 1555 | ffs_dinode1_swap(&dp1[j], |
1560 | &dp1[j]); | | 1556 | &dp1[j]); |
1561 | } | | 1557 | } |
1562 | } | | 1558 | } |
1563 | | | 1559 | |
1564 | writeat(fsbtodb(newsb, ino_to_fsba(newsb, i)), | | 1560 | writeat(fsbtodb(newsb, ino_to_fsba(newsb, i)), |
1565 | ibuf, newsb->fs_bsize); | | 1561 | ibuf, newsb->fs_bsize); |
1566 | } | | 1562 | } |
1567 | } | | 1563 | } |
1568 | } | | 1564 | } |
1569 | /* | | 1565 | /* |
1570 | * Evict all inodes from the specified cg. shrink() already checked | | 1566 | * Evict all inodes from the specified cg. shrink() already checked |
1571 | * that there were enough free inodes, so the no-free-inodes check is | | 1567 | * that there were enough free inodes, so the no-free-inodes check is |
1572 | * a can't-happen. If it does trip, the file system should be in good | | 1568 | * a can't-happen. If it does trip, the file system should be in good |
1573 | * enough shape for fsck to fix; see the comment on perform_data_move | | 1569 | * enough shape for fsck to fix; see the comment on perform_data_move |
1574 | * for the considerations in question. | | 1570 | * for the considerations in question. |
1575 | */ | | 1571 | */ |
1576 | static void | | 1572 | static void |
1577 | evict_inodes(struct cg * cg) | | 1573 | evict_inodes(struct cg * cg) |
1578 | { | | 1574 | { |
1579 | int inum; | | 1575 | int inum; |
1580 | int i; | | 1576 | int i; |
1581 | int fi; | | 1577 | int fi; |
1582 | | | 1578 | |
1583 | inum = newsb->fs_ipg * cg->cg_cgx; | | 1579 | inum = newsb->fs_ipg * cg->cg_cgx; |
1584 | for (i = 0; i < newsb->fs_ipg; i++, inum++) { | | 1580 | for (i = 0; i < newsb->fs_ipg; i++, inum++) { |
1585 | if (DIP(inodes + inum,di_mode) != 0) { | | 1581 | if (DIP(inodes + inum,di_mode) != 0) { |
1586 | fi = find_freeinode(); | | 1582 | fi = find_freeinode(); |
1587 | if (fi < 0) { | | 1583 | if (fi < 0) |
1588 | printf("Sorry, inodes evaporated - " | | 1584 | errx(EXIT_FAILURE, "Sorry, inodes evaporated - " |
1589 | "file system probably needs fsck\n"); | | 1585 | "file system probably needs fsck"); |
1590 | exit(EXIT_FAILURE); | | | |
1591 | } | | | |
1592 | inomove[inum] = fi; | | 1586 | inomove[inum] = fi; |
1593 | clr_bits(cg_inosused(cg, 0), i, 1); | | 1587 | clr_bits(cg_inosused(cg, 0), i, 1); |
1594 | set_bits(cg_inosused(cgs[ino_to_cg(newsb, fi)], 0), | | 1588 | set_bits(cg_inosused(cgs[ino_to_cg(newsb, fi)], 0), |
1595 | fi % newsb->fs_ipg, 1); | | 1589 | fi % newsb->fs_ipg, 1); |
1596 | } | | 1590 | } |
1597 | } | | 1591 | } |
1598 | } | | 1592 | } |
1599 | /* | | 1593 | /* |
1600 | * Move inodes from old locations to new. Does not actually write | | 1594 | * Move inodes from old locations to new. Does not actually write |
1601 | * anything to disk; just copies in-core and sets dirty bits. | | 1595 | * anything to disk; just copies in-core and sets dirty bits. |
1602 | * | | 1596 | * |
1603 | * We have to be careful here for reasons similar to those mentioned in | | 1597 | * We have to be careful here for reasons similar to those mentioned in |
1604 | * the comment header on perform_data_move, above: for the sake of | | 1598 | * the comment header on perform_data_move, above: for the sake of |
1605 | * crash tolerance, we want to make sure everything is present at both | | 1599 | * crash tolerance, we want to make sure everything is present at both |
1606 | * old and new locations before we update pointers. So we call this | | 1600 | * old and new locations before we update pointers. So we call this |
1607 | * first, then flush_inodes() to get them out on disk, then update | | 1601 | * first, then flush_inodes() to get them out on disk, then update |
1608 | * directories to match. | | 1602 | * directories to match. |
1609 | */ | | 1603 | */ |
1610 | static void | | 1604 | static void |
1611 | perform_inode_move(void) | | 1605 | perform_inode_move(void) |
1612 | { | | 1606 | { |
1613 | unsigned int i; | | 1607 | unsigned int i; |
1614 | unsigned int ni; | | 1608 | unsigned int ni; |
1615 | | | 1609 | |
1616 | ni = oldsb->fs_ipg * oldsb->fs_ncg; | | 1610 | ni = oldsb->fs_ipg * oldsb->fs_ncg; |
1617 | for (i = 0; i < ni; i++) { | | 1611 | for (i = 0; i < ni; i++) { |
1618 | if (inomove[i] != i) { | | 1612 | if (inomove[i] != i) { |
1619 | inodes[inomove[i]] = inodes[i]; | | 1613 | inodes[inomove[i]] = inodes[i]; |
1620 | iflags[inomove[i]] = iflags[i] | IF_DIRTY; | | 1614 | iflags[inomove[i]] = iflags[i] | IF_DIRTY; |
1621 | } | | 1615 | } |
1622 | } | | 1616 | } |
1623 | } | | 1617 | } |
1624 | /* | | 1618 | /* |
1625 | * Update the directory contained in the nb bytes at buf, to point to | | 1619 | * Update the directory contained in the nb bytes at buf, to point to |
1626 | * inodes' new locations. | | 1620 | * inodes' new locations. |
1627 | */ | | 1621 | */ |
1628 | static int | | 1622 | static int |
1629 | update_dirents(char *buf, int nb) | | 1623 | update_dirents(char *buf, int nb) |
1630 | { | | 1624 | { |
1631 | int rv; | | 1625 | int rv; |
1632 | #define d ((struct direct *)buf) | | 1626 | #define d ((struct direct *)buf) |
1633 | #define s32(x) (needswap?bswap32((x)):(x)) | | 1627 | #define s32(x) (needswap?bswap32((x)):(x)) |
1634 | #define s16(x) (needswap?bswap16((x)):(x)) | | 1628 | #define s16(x) (needswap?bswap16((x)):(x)) |
1635 | | | 1629 | |
1636 | rv = 0; | | 1630 | rv = 0; |
1637 | while (nb > 0) { | | 1631 | while (nb > 0) { |
1638 | if (inomove[s32(d->d_ino)] != s32(d->d_ino)) { | | 1632 | if (inomove[s32(d->d_ino)] != s32(d->d_ino)) { |
1639 | rv++; | | 1633 | rv++; |
1640 | d->d_ino = s32(inomove[s32(d->d_ino)]); | | 1634 | d->d_ino = s32(inomove[s32(d->d_ino)]); |
1641 | } | | 1635 | } |
1642 | nb -= s16(d->d_reclen); | | 1636 | nb -= s16(d->d_reclen); |
1643 | buf += s16(d->d_reclen); | | 1637 | buf += s16(d->d_reclen); |
1644 | } | | 1638 | } |
1645 | return (rv); | | 1639 | return (rv); |
1646 | #undef d | | 1640 | #undef d |
1647 | #undef s32 | | 1641 | #undef s32 |
1648 | #undef s16 | | 1642 | #undef s16 |
1649 | } | | 1643 | } |
1650 | /* | | 1644 | /* |
1651 | * Callback function for map_inode_data_blocks, for updating a | | 1645 | * Callback function for map_inode_data_blocks, for updating a |
1652 | * directory to point to new inode locations. | | 1646 | * directory to point to new inode locations. |
1653 | */ | | 1647 | */ |
1654 | static void | | 1648 | static void |
1655 | update_dir_data(off_t bn, unsigned int size, unsigned int nb, int kind) | | 1649 | update_dir_data(off_t bn, unsigned int size, unsigned int nb, int kind) |
1656 | { | | 1650 | { |
1657 | if (kind == MDB_DATA) { | | 1651 | if (kind == MDB_DATA) { |
1658 | union { | | 1652 | union { |
1659 | struct direct d; | | 1653 | struct direct d; |
1660 | char ch[MAXBSIZE]; | | 1654 | char ch[MAXBSIZE]; |
1661 | } buf; | | 1655 | } buf; |
1662 | readat(fsbtodb(oldsb, bn), &buf, size << oldsb->fs_fshift); | | 1656 | readat(fsbtodb(oldsb, bn), &buf, size << oldsb->fs_fshift); |
1663 | if (update_dirents((char *) &buf, nb)) { | | 1657 | if (update_dirents((char *) &buf, nb)) { |
1664 | writeat(fsbtodb(oldsb, bn), &buf, | | 1658 | writeat(fsbtodb(oldsb, bn), &buf, |
1665 | size << oldsb->fs_fshift); | | 1659 | size << oldsb->fs_fshift); |
1666 | } | | 1660 | } |
1667 | } | | 1661 | } |
1668 | } | | 1662 | } |
1669 | static void | | 1663 | static void |
1670 | dirmove_callback(union dinode * di, unsigned int inum, void *arg) | | 1664 | dirmove_callback(union dinode * di, unsigned int inum, void *arg) |
1671 | { | | 1665 | { |
1672 | switch (DIP(di,di_mode) & IFMT) { | | 1666 | switch (DIP(di,di_mode) & IFMT) { |
1673 | case IFDIR: | | 1667 | case IFDIR: |
1674 | map_inode_data_blocks(di, &update_dir_data); | | 1668 | map_inode_data_blocks(di, &update_dir_data); |
1675 | break; | | 1669 | break; |
1676 | } | | 1670 | } |
1677 | } | | 1671 | } |
1678 | /* | | 1672 | /* |
1679 | * Update directory entries to point to new inode locations. | | 1673 | * Update directory entries to point to new inode locations. |
1680 | */ | | 1674 | */ |
1681 | static void | | 1675 | static void |
1682 | update_for_inode_move(void) | | 1676 | update_for_inode_move(void) |
1683 | { | | 1677 | { |
1684 | map_inodes(&dirmove_callback, newsb->fs_ncg, NULL); | | 1678 | map_inodes(&dirmove_callback, newsb->fs_ncg, NULL); |
1685 | } | | 1679 | } |
1686 | /* | | 1680 | /* |
1687 | * Shrink the file system. | | 1681 | * Shrink the file system. |
1688 | */ | | 1682 | */ |
1689 | static void | | 1683 | static void |
1690 | shrink(void) | | 1684 | shrink(void) |
1691 | { | | 1685 | { |
1692 | int i; | | 1686 | int i; |
1693 | | | 1687 | |
1694 | /* Load the inodes off disk - we'll need 'em. */ | | 1688 | /* Load the inodes off disk - we'll need 'em. */ |
1695 | loadinodes(); | | 1689 | loadinodes(); |
1696 | /* Update the timestamp. */ | | 1690 | /* Update the timestamp. */ |
1697 | newsb->fs_time = timestamp(); | | 1691 | newsb->fs_time = timestamp(); |
1698 | /* Update the size figures. */ | | 1692 | /* Update the size figures. */ |
1699 | newsb->fs_size = dbtofsb(newsb, newsize); | | 1693 | newsb->fs_size = dbtofsb(newsb, newsize); |
1700 | if (is_ufs2) | | 1694 | if (is_ufs2) |
1701 | newsb->fs_ncg = howmany(newsb->fs_size, newsb->fs_fpg); | | 1695 | newsb->fs_ncg = howmany(newsb->fs_size, newsb->fs_fpg); |
1702 | else { | | 1696 | else { |
1703 | newsb->fs_old_ncyl = howmany(newsb->fs_size * NSPF(newsb), | | 1697 | newsb->fs_old_ncyl = howmany(newsb->fs_size * NSPF(newsb), |
1704 | newsb->fs_old_spc); | | 1698 | newsb->fs_old_spc); |
1705 | newsb->fs_ncg = howmany(newsb->fs_old_ncyl, newsb->fs_old_cpg); | | 1699 | newsb->fs_ncg = howmany(newsb->fs_old_ncyl, newsb->fs_old_cpg); |
1706 | } | | 1700 | } |
1707 | /* Does the (new) last cg end before the end of its inode area? See | | 1701 | /* Does the (new) last cg end before the end of its inode area? See |
1708 | * the similar code in grow() for more on this. */ | | 1702 | * the similar code in grow() for more on this. */ |
1709 | if (cgdmin(newsb, newsb->fs_ncg - 1) > newsb->fs_size) { | | 1703 | if (cgdmin(newsb, newsb->fs_ncg - 1) > newsb->fs_size) { |
1710 | newsb->fs_ncg--; | | 1704 | newsb->fs_ncg--; |
1711 | if (is_ufs2 == 0) { | | 1705 | if (is_ufs2 == 0) { |
1712 | newsb->fs_old_ncyl = newsb->fs_ncg * newsb->fs_old_cpg; | | 1706 | newsb->fs_old_ncyl = newsb->fs_ncg * newsb->fs_old_cpg; |
1713 | newsb->fs_size = (newsb->fs_old_ncyl * | | 1707 | newsb->fs_size = (newsb->fs_old_ncyl * |
1714 | newsb->fs_old_spc) / NSPF(newsb); | | 1708 | newsb->fs_old_spc) / NSPF(newsb); |
1715 | } else | | 1709 | } else |
1716 | newsb->fs_size = newsb->fs_ncg * newsb->fs_fpg; | | 1710 | newsb->fs_size = newsb->fs_ncg * newsb->fs_fpg; |
1717 | | | 1711 | |
1718 | printf("Warning: last cylinder group is too small;\n"); | | 1712 | printf("Warning: last cylinder group is too small;\n"); |
1719 | printf(" dropping it. New size = %lu.\n", | | 1713 | printf(" dropping it. New size = %lu.\n", |
1720 | (unsigned long int) fsbtodb(newsb, newsb->fs_size)); | | 1714 | (unsigned long int) fsbtodb(newsb, newsb->fs_size)); |
1721 | } | | 1715 | } |
1722 | /* Let's make sure we're not being shrunk into oblivion. */ | | 1716 | /* Let's make sure we're not being shrunk into oblivion. */ |
1723 | if (newsb->fs_ncg < 1) { | | 1717 | if (newsb->fs_ncg < 1) |
1724 | printf("Size too small - file system would " | | 1718 | errx(EXIT_FAILURE, "Size too small - file system would " |
1725 | "have no cylinders\n"); | | 1719 | "have no cylinders"); |
1726 | exit(EXIT_FAILURE); | | | |
1727 | } | | | |
1728 | /* Initialize for block motion. */ | | 1720 | /* Initialize for block motion. */ |
1729 | blkmove_init(); | | 1721 | blkmove_init(); |
1730 | /* Update csum size, then fix up for the new size */ | | 1722 | /* Update csum size, then fix up for the new size */ |
1731 | newsb->fs_cssize = fragroundup(newsb, | | 1723 | newsb->fs_cssize = fragroundup(newsb, |
1732 | newsb->fs_ncg * sizeof(struct csum)); | | 1724 | newsb->fs_ncg * sizeof(struct csum)); |
1733 | csum_fixup(); | | 1725 | csum_fixup(); |
1734 | /* Evict data from any cgs being wholly eliminated */ | | 1726 | /* Evict data from any cgs being wholly eliminated */ |
1735 | for (i = newsb->fs_ncg; i < oldsb->fs_ncg; i++) { | | 1727 | for (i = newsb->fs_ncg; i < oldsb->fs_ncg; i++) { |
1736 | int base; | | 1728 | int base; |
1737 | int dlow; | | 1729 | int dlow; |
1738 | int dhigh; | | 1730 | int dhigh; |
1739 | int dmax; | | 1731 | int dmax; |
1740 | base = cgbase(oldsb, i); | | 1732 | base = cgbase(oldsb, i); |
1741 | dlow = cgsblock(oldsb, i) - base; | | 1733 | dlow = cgsblock(oldsb, i) - base; |
1742 | dhigh = cgdmin(oldsb, i) - base; | | 1734 | dhigh = cgdmin(oldsb, i) - base; |
1743 | dmax = oldsb->fs_size - base; | | 1735 | dmax = oldsb->fs_size - base; |
1744 | if (dmax > cgs[i]->cg_ndblk) | | 1736 | if (dmax > cgs[i]->cg_ndblk) |
1745 | dmax = cgs[i]->cg_ndblk; | | 1737 | dmax = cgs[i]->cg_ndblk; |
1746 | evict_data(cgs[i], 0, dlow); | | 1738 | evict_data(cgs[i], 0, dlow); |
1747 | evict_data(cgs[i], dhigh, dmax - dhigh); | | 1739 | evict_data(cgs[i], dhigh, dmax - dhigh); |
1748 | newsb->fs_cstotal.cs_ndir -= cgs[i]->cg_cs.cs_ndir; | | 1740 | newsb->fs_cstotal.cs_ndir -= cgs[i]->cg_cs.cs_ndir; |
1749 | newsb->fs_cstotal.cs_nifree -= cgs[i]->cg_cs.cs_nifree; | | 1741 | newsb->fs_cstotal.cs_nifree -= cgs[i]->cg_cs.cs_nifree; |
1750 | newsb->fs_cstotal.cs_nffree -= cgs[i]->cg_cs.cs_nffree; | | 1742 | newsb->fs_cstotal.cs_nffree -= cgs[i]->cg_cs.cs_nffree; |
1751 | newsb->fs_cstotal.cs_nbfree -= cgs[i]->cg_cs.cs_nbfree; | | 1743 | newsb->fs_cstotal.cs_nbfree -= cgs[i]->cg_cs.cs_nbfree; |
1752 | } | | 1744 | } |
1753 | /* Update the new last cg. */ | | 1745 | /* Update the new last cg. */ |
1754 | cgs[newsb->fs_ncg - 1]->cg_ndblk = newsb->fs_size - | | 1746 | cgs[newsb->fs_ncg - 1]->cg_ndblk = newsb->fs_size - |
1755 | ((newsb->fs_ncg - 1) * newsb->fs_fpg); | | 1747 | ((newsb->fs_ncg - 1) * newsb->fs_fpg); |
1756 | /* Is the new last cg partial? If so, evict any data from the part | | 1748 | /* Is the new last cg partial? If so, evict any data from the part |
1757 | * being shrunken away. */ | | 1749 | * being shrunken away. */ |
1758 | if (newsb->fs_size % newsb->fs_fpg) { | | 1750 | if (newsb->fs_size % newsb->fs_fpg) { |
1759 | struct cg *cg; | | 1751 | struct cg *cg; |
1760 | int oldcgsize; | | 1752 | int oldcgsize; |
1761 | int newcgsize; | | 1753 | int newcgsize; |
1762 | cg = cgs[newsb->fs_ncg - 1]; | | 1754 | cg = cgs[newsb->fs_ncg - 1]; |
1763 | newcgsize = newsb->fs_size % newsb->fs_fpg; | | 1755 | newcgsize = newsb->fs_size % newsb->fs_fpg; |
1764 | oldcgsize = oldsb->fs_size - ((newsb->fs_ncg - 1) & | | 1756 | oldcgsize = oldsb->fs_size - ((newsb->fs_ncg - 1) & |
1765 | oldsb->fs_fpg); | | 1757 | oldsb->fs_fpg); |
1766 | if (oldcgsize > oldsb->fs_fpg) | | 1758 | if (oldcgsize > oldsb->fs_fpg) |
1767 | oldcgsize = oldsb->fs_fpg; | | 1759 | oldcgsize = oldsb->fs_fpg; |
1768 | evict_data(cg, newcgsize, oldcgsize - newcgsize); | | 1760 | evict_data(cg, newcgsize, oldcgsize - newcgsize); |
1769 | clr_bits(cg_blksfree(cg, 0), newcgsize, oldcgsize - newcgsize); | | 1761 | clr_bits(cg_blksfree(cg, 0), newcgsize, oldcgsize - newcgsize); |
1770 | } | | 1762 | } |
1771 | /* Find out whether we would run out of inodes. (Note we | | 1763 | /* Find out whether we would run out of inodes. (Note we |
1772 | * haven't actually done anything to the file system yet; all | | 1764 | * haven't actually done anything to the file system yet; all |
1773 | * those evict_data calls just update blkmove.) */ | | 1765 | * those evict_data calls just update blkmove.) */ |
1774 | { | | 1766 | { |
1775 | int slop; | | 1767 | int slop; |
1776 | slop = 0; | | 1768 | slop = 0; |
1777 | for (i = 0; i < newsb->fs_ncg; i++) | | 1769 | for (i = 0; i < newsb->fs_ncg; i++) |
1778 | slop += cgs[i]->cg_cs.cs_nifree; | | 1770 | slop += cgs[i]->cg_cs.cs_nifree; |
1779 | for (; i < oldsb->fs_ncg; i++) | | 1771 | for (; i < oldsb->fs_ncg; i++) |
1780 | slop -= oldsb->fs_ipg - cgs[i]->cg_cs.cs_nifree; | | 1772 | slop -= oldsb->fs_ipg - cgs[i]->cg_cs.cs_nifree; |
1781 | if (slop < 0) { | | 1773 | if (slop < 0) |
1782 | printf("Sorry, would run out of inodes\n"); | | 1774 | errx(EXIT_FAILURE, "Sorry, would run out of inodes"); |
1783 | exit(EXIT_FAILURE); | | | |
1784 | } | | | |
1785 | } | | 1775 | } |
1786 | /* Copy data, then update pointers to data. See the comment | | 1776 | /* Copy data, then update pointers to data. See the comment |
1787 | * header on perform_data_move for ordering considerations. */ | | 1777 | * header on perform_data_move for ordering considerations. */ |
1788 | perform_data_move(); | | 1778 | perform_data_move(); |
1789 | update_for_data_move(); | | 1779 | update_for_data_move(); |
1790 | /* Now do inodes. Initialize, evict, move, update - see the | | 1780 | /* Now do inodes. Initialize, evict, move, update - see the |
1791 | * comment header on perform_inode_move. */ | | 1781 | * comment header on perform_inode_move. */ |
1792 | inomove_init(); | | 1782 | inomove_init(); |
1793 | for (i = newsb->fs_ncg; i < oldsb->fs_ncg; i++) | | 1783 | for (i = newsb->fs_ncg; i < oldsb->fs_ncg; i++) |
1794 | evict_inodes(cgs[i]); | | 1784 | evict_inodes(cgs[i]); |
1795 | perform_inode_move(); | | 1785 | perform_inode_move(); |
1796 | flush_inodes(); | | 1786 | flush_inodes(); |
1797 | update_for_inode_move(); | | 1787 | update_for_inode_move(); |
1798 | /* Recompute all the bitmaps; most of them probably need it anyway, | | 1788 | /* Recompute all the bitmaps; most of them probably need it anyway, |
1799 | * the rest are just paranoia and not wanting to have to bother | | 1789 | * the rest are just paranoia and not wanting to have to bother |
1800 | * keeping track of exactly which ones require it. */ | | 1790 | * keeping track of exactly which ones require it. */ |
1801 | for (i = 0; i < newsb->fs_ncg; i++) | | 1791 | for (i = 0; i < newsb->fs_ncg; i++) |
1802 | cgflags[i] |= CGF_DIRTY | CGF_BLKMAPS | CGF_INOMAPS; | | 1792 | cgflags[i] |= CGF_DIRTY | CGF_BLKMAPS | CGF_INOMAPS; |
1803 | /* Update the cg_old_ncyl value for the last cylinder. */ | | 1793 | /* Update the cg_old_ncyl value for the last cylinder. */ |
1804 | if ((newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) | | 1794 | if ((newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) |
1805 | cgs[newsb->fs_ncg - 1]->cg_old_ncyl = | | 1795 | cgs[newsb->fs_ncg - 1]->cg_old_ncyl = |
1806 | newsb->fs_old_ncyl % newsb->fs_old_cpg; | | 1796 | newsb->fs_old_ncyl % newsb->fs_old_cpg; |
1807 | /* Make fs_dsize match the new reality. */ | | 1797 | /* Make fs_dsize match the new reality. */ |
1808 | recompute_fs_dsize(); | | 1798 | recompute_fs_dsize(); |
1809 | } | | 1799 | } |
1810 | /* | | 1800 | /* |
1811 | * Recompute the block totals, block cluster summaries, and rotational | | 1801 | * Recompute the block totals, block cluster summaries, and rotational |
1812 | * position summaries, for a given cg (specified by number), based on | | 1802 | * position summaries, for a given cg (specified by number), based on |
1813 | * its free-frag bitmap (cg_blksfree()[]). | | 1803 | * its free-frag bitmap (cg_blksfree()[]). |
1814 | */ | | 1804 | */ |
1815 | static void | | 1805 | static void |
1816 | rescan_blkmaps(int cgn) | | 1806 | rescan_blkmaps(int cgn) |
1817 | { | | 1807 | { |
1818 | struct cg *cg; | | 1808 | struct cg *cg; |
1819 | int f; | | 1809 | int f; |
1820 | int b; | | 1810 | int b; |
1821 | int blkfree; | | 1811 | int blkfree; |
1822 | int blkrun; | | 1812 | int blkrun; |
1823 | int fragrun; | | 1813 | int fragrun; |
1824 | int fwb; | | 1814 | int fwb; |
1825 | | | 1815 | |
1826 | cg = cgs[cgn]; | | 1816 | cg = cgs[cgn]; |
1827 | /* Subtract off the current totals from the sb's summary info */ | | 1817 | /* Subtract off the current totals from the sb's summary info */ |
1828 | newsb->fs_cstotal.cs_nffree -= cg->cg_cs.cs_nffree; | | 1818 | newsb->fs_cstotal.cs_nffree -= cg->cg_cs.cs_nffree; |
1829 | newsb->fs_cstotal.cs_nbfree -= cg->cg_cs.cs_nbfree; | | 1819 | newsb->fs_cstotal.cs_nbfree -= cg->cg_cs.cs_nbfree; |
1830 | /* Clear counters and bitmaps. */ | | 1820 | /* Clear counters and bitmaps. */ |
1831 | cg->cg_cs.cs_nffree = 0; | | 1821 | cg->cg_cs.cs_nffree = 0; |
1832 | cg->cg_cs.cs_nbfree = 0; | | 1822 | cg->cg_cs.cs_nbfree = 0; |
1833 | memset(&cg->cg_frsum[0], 0, MAXFRAG * sizeof(cg->cg_frsum[0])); | | 1823 | memset(&cg->cg_frsum[0], 0, MAXFRAG * sizeof(cg->cg_frsum[0])); |
1834 | memset(&old_cg_blktot(cg, 0)[0], 0, | | 1824 | memset(&old_cg_blktot(cg, 0)[0], 0, |
1835 | newsb->fs_old_cpg * sizeof(old_cg_blktot(cg, 0)[0])); | | 1825 | newsb->fs_old_cpg * sizeof(old_cg_blktot(cg, 0)[0])); |
1836 | memset(&old_cg_blks(newsb, cg, 0, 0)[0], 0, | | 1826 | memset(&old_cg_blks(newsb, cg, 0, 0)[0], 0, |
1837 | newsb->fs_old_cpg * newsb->fs_old_nrpos * | | 1827 | newsb->fs_old_cpg * newsb->fs_old_nrpos * |
1838 | sizeof(old_cg_blks(newsb, cg, 0, 0)[0])); | | 1828 | sizeof(old_cg_blks(newsb, cg, 0, 0)[0])); |
1839 | if (newsb->fs_contigsumsize > 0) { | | 1829 | if (newsb->fs_contigsumsize > 0) { |
1840 | cg->cg_nclusterblks = cg->cg_ndblk / newsb->fs_frag; | | 1830 | cg->cg_nclusterblks = cg->cg_ndblk / newsb->fs_frag; |
1841 | memset(&cg_clustersum(cg, 0)[1], 0, | | 1831 | memset(&cg_clustersum(cg, 0)[1], 0, |
1842 | newsb->fs_contigsumsize * | | 1832 | newsb->fs_contigsumsize * |
1843 | sizeof(cg_clustersum(cg, 0)[1])); | | 1833 | sizeof(cg_clustersum(cg, 0)[1])); |
1844 | if (is_ufs2) | | 1834 | if (is_ufs2) |
1845 | memset(&cg_clustersfree(cg, 0)[0], 0, | | 1835 | memset(&cg_clustersfree(cg, 0)[0], 0, |
1846 | howmany(newsb->fs_fpg / NSPB(newsb), NBBY)); | | 1836 | howmany(newsb->fs_fpg / NSPB(newsb), NBBY)); |
1847 | else | | 1837 | else |
1848 | memset(&cg_clustersfree(cg, 0)[0], 0, | | 1838 | memset(&cg_clustersfree(cg, 0)[0], 0, |
1849 | howmany((newsb->fs_old_cpg * newsb->fs_old_spc) / | | 1839 | howmany((newsb->fs_old_cpg * newsb->fs_old_spc) / |
1850 | NSPB(newsb), NBBY)); | | 1840 | NSPB(newsb), NBBY)); |
1851 | } | | 1841 | } |
1852 | /* Scan the free-frag bitmap. Runs of free frags are kept | | 1842 | /* Scan the free-frag bitmap. Runs of free frags are kept |
1853 | * track of with fragrun, and recorded into cg_frsum[] and | | 1843 | * track of with fragrun, and recorded into cg_frsum[] and |
1854 | * cg_cs.cs_nffree; on each block boundary, entire free blocks | | 1844 | * cg_cs.cs_nffree; on each block boundary, entire free blocks |
1855 | * are recorded as well. */ | | 1845 | * are recorded as well. */ |
1856 | blkfree = 1; | | 1846 | blkfree = 1; |
1857 | blkrun = 0; | | 1847 | blkrun = 0; |
1858 | fragrun = 0; | | 1848 | fragrun = 0; |
1859 | f = 0; | | 1849 | f = 0; |
1860 | b = 0; | | 1850 | b = 0; |
1861 | fwb = 0; | | 1851 | fwb = 0; |
1862 | while (f < cg->cg_ndblk) { | | 1852 | while (f < cg->cg_ndblk) { |
1863 | if (bit_is_set(cg_blksfree(cg, 0), f)) { | | 1853 | if (bit_is_set(cg_blksfree(cg, 0), f)) { |
1864 | fragrun++; | | 1854 | fragrun++; |
1865 | } else { | | 1855 | } else { |
1866 | blkfree = 0; | | 1856 | blkfree = 0; |
1867 | if (fragrun > 0) { | | 1857 | if (fragrun > 0) { |
1868 | cg->cg_frsum[fragrun]++; | | 1858 | cg->cg_frsum[fragrun]++; |
1869 | cg->cg_cs.cs_nffree += fragrun; | | 1859 | cg->cg_cs.cs_nffree += fragrun; |
1870 | } | | 1860 | } |
1871 | fragrun = 0; | | 1861 | fragrun = 0; |
1872 | } | | 1862 | } |
1873 | f++; | | 1863 | f++; |
1874 | fwb++; | | 1864 | fwb++; |
1875 | if (fwb >= newsb->fs_frag) { | | 1865 | if (fwb >= newsb->fs_frag) { |
1876 | if (blkfree) { | | 1866 | if (blkfree) { |
1877 | cg->cg_cs.cs_nbfree++; | | 1867 | cg->cg_cs.cs_nbfree++; |
1878 | if (newsb->fs_contigsumsize > 0) | | 1868 | if (newsb->fs_contigsumsize > 0) |
1879 | set_bits(cg_clustersfree(cg, 0), b, 1); | | 1869 | set_bits(cg_clustersfree(cg, 0), b, 1); |
1880 | if (is_ufs2 == 0) { | | 1870 | if (is_ufs2 == 0) { |
1881 | old_cg_blktot(cg, 0)[ | | 1871 | old_cg_blktot(cg, 0)[ |
1882 | old_cbtocylno(newsb, | | 1872 | old_cbtocylno(newsb, |
1883 | f - newsb->fs_frag)]++; | | 1873 | f - newsb->fs_frag)]++; |
1884 | old_cg_blks(newsb, cg, | | 1874 | old_cg_blks(newsb, cg, |
1885 | old_cbtocylno(newsb, | | 1875 | old_cbtocylno(newsb, |
1886 | f - newsb->fs_frag), | | 1876 | f - newsb->fs_frag), |
1887 | 0)[old_cbtorpos(newsb, | | 1877 | 0)[old_cbtorpos(newsb, |
1888 | f - newsb->fs_frag)]++; | | 1878 | f - newsb->fs_frag)]++; |
1889 | } | | 1879 | } |
1890 | blkrun++; | | 1880 | blkrun++; |
1891 | } else { | | 1881 | } else { |
1892 | if (fragrun > 0) { | | 1882 | if (fragrun > 0) { |
1893 | cg->cg_frsum[fragrun]++; | | 1883 | cg->cg_frsum[fragrun]++; |
1894 | cg->cg_cs.cs_nffree += fragrun; | | 1884 | cg->cg_cs.cs_nffree += fragrun; |
1895 | } | | 1885 | } |
1896 | if (newsb->fs_contigsumsize > 0) { | | 1886 | if (newsb->fs_contigsumsize > 0) { |
1897 | if (blkrun > 0) { | | 1887 | if (blkrun > 0) { |
1898 | cg_clustersum(cg, 0)[(blkrun | | 1888 | cg_clustersum(cg, 0)[(blkrun |
1899 | > newsb->fs_contigsumsize) | | 1889 | > newsb->fs_contigsumsize) |
1900 | ? newsb->fs_contigsumsize | | 1890 | ? newsb->fs_contigsumsize |
1901 | : blkrun]++; | | 1891 | : blkrun]++; |
1902 | } | | 1892 | } |
1903 | } | | 1893 | } |
1904 | blkrun = 0; | | 1894 | blkrun = 0; |
1905 | } | | 1895 | } |
1906 | fwb = 0; | | 1896 | fwb = 0; |
1907 | b++; | | 1897 | b++; |
1908 | blkfree = 1; | | 1898 | blkfree = 1; |
1909 | fragrun = 0; | | 1899 | fragrun = 0; |
1910 | } | | 1900 | } |
1911 | } | | 1901 | } |
1912 | if (fragrun > 0) { | | 1902 | if (fragrun > 0) { |
1913 | cg->cg_frsum[fragrun]++; | | 1903 | cg->cg_frsum[fragrun]++; |
1914 | cg->cg_cs.cs_nffree += fragrun; | | 1904 | cg->cg_cs.cs_nffree += fragrun; |
1915 | } | | 1905 | } |
1916 | if ((blkrun > 0) && (newsb->fs_contigsumsize > 0)) { | | 1906 | if ((blkrun > 0) && (newsb->fs_contigsumsize > 0)) { |
1917 | cg_clustersum(cg, 0)[(blkrun > newsb->fs_contigsumsize) ? | | 1907 | cg_clustersum(cg, 0)[(blkrun > newsb->fs_contigsumsize) ? |
1918 | newsb->fs_contigsumsize : blkrun]++; | | 1908 | newsb->fs_contigsumsize : blkrun]++; |
1919 | } | | 1909 | } |
1920 | /* | | 1910 | /* |
1921 | * Put the updated summary info back into csums, and add it | | 1911 | * Put the updated summary info back into csums, and add it |
1922 | * back into the sb's summary info. Then mark the cg dirty. | | 1912 | * back into the sb's summary info. Then mark the cg dirty. |
1923 | */ | | 1913 | */ |
1924 | csums[cgn] = cg->cg_cs; | | 1914 | csums[cgn] = cg->cg_cs; |
1925 | newsb->fs_cstotal.cs_nffree += cg->cg_cs.cs_nffree; | | 1915 | newsb->fs_cstotal.cs_nffree += cg->cg_cs.cs_nffree; |
1926 | newsb->fs_cstotal.cs_nbfree += cg->cg_cs.cs_nbfree; | | 1916 | newsb->fs_cstotal.cs_nbfree += cg->cg_cs.cs_nbfree; |
1927 | cgflags[cgn] |= CGF_DIRTY; | | 1917 | cgflags[cgn] |= CGF_DIRTY; |
1928 | } | | 1918 | } |
1929 | /* | | 1919 | /* |
1930 | * Recompute the cg_inosused()[] bitmap, and the cs_nifree and cs_ndir | | 1920 | * Recompute the cg_inosused()[] bitmap, and the cs_nifree and cs_ndir |
1931 | * values, for a cg, based on the in-core inodes for that cg. | | 1921 | * values, for a cg, based on the in-core inodes for that cg. |
1932 | */ | | 1922 | */ |
1933 | static void | | 1923 | static void |
1934 | rescan_inomaps(int cgn) | | 1924 | rescan_inomaps(int cgn) |
1935 | { | | 1925 | { |
1936 | struct cg *cg; | | 1926 | struct cg *cg; |
1937 | int inum; | | 1927 | int inum; |
1938 | int iwc; | | 1928 | int iwc; |
1939 | | | 1929 | |
1940 | cg = cgs[cgn]; | | 1930 | cg = cgs[cgn]; |
1941 | newsb->fs_cstotal.cs_ndir -= cg->cg_cs.cs_ndir; | | 1931 | newsb->fs_cstotal.cs_ndir -= cg->cg_cs.cs_ndir; |
1942 | newsb->fs_cstotal.cs_nifree -= cg->cg_cs.cs_nifree; | | 1932 | newsb->fs_cstotal.cs_nifree -= cg->cg_cs.cs_nifree; |
1943 | cg->cg_cs.cs_ndir = 0; | | 1933 | cg->cg_cs.cs_ndir = 0; |
1944 | cg->cg_cs.cs_nifree = 0; | | 1934 | cg->cg_cs.cs_nifree = 0; |
1945 | memset(&cg_inosused(cg, 0)[0], 0, howmany(newsb->fs_ipg, NBBY)); | | 1935 | memset(&cg_inosused(cg, 0)[0], 0, howmany(newsb->fs_ipg, NBBY)); |
1946 | inum = cgn * newsb->fs_ipg; | | 1936 | inum = cgn * newsb->fs_ipg; |
1947 | if (cgn == 0) { | | 1937 | if (cgn == 0) { |
1948 | set_bits(cg_inosused(cg, 0), 0, 2); | | 1938 | set_bits(cg_inosused(cg, 0), 0, 2); |
1949 | iwc = 2; | | 1939 | iwc = 2; |
1950 | inum += 2; | | 1940 | inum += 2; |
1951 | } else { | | 1941 | } else { |
1952 | iwc = 0; | | 1942 | iwc = 0; |
1953 | } | | 1943 | } |
1954 | for (; iwc < newsb->fs_ipg; iwc++, inum++) { | | 1944 | for (; iwc < newsb->fs_ipg; iwc++, inum++) { |
1955 | switch (DIP(inodes + inum, di_mode) & IFMT) { | | 1945 | switch (DIP(inodes + inum, di_mode) & IFMT) { |
1956 | case 0: | | 1946 | case 0: |
1957 | cg->cg_cs.cs_nifree++; | | 1947 | cg->cg_cs.cs_nifree++; |
1958 | break; | | 1948 | break; |
1959 | case IFDIR: | | 1949 | case IFDIR: |
1960 | cg->cg_cs.cs_ndir++; | | 1950 | cg->cg_cs.cs_ndir++; |
1961 | /* FALLTHROUGH */ | | 1951 | /* FALLTHROUGH */ |
1962 | default: | | 1952 | default: |
1963 | set_bits(cg_inosused(cg, 0), iwc, 1); | | 1953 | set_bits(cg_inosused(cg, 0), iwc, 1); |
1964 | break; | | 1954 | break; |
1965 | } | | 1955 | } |
1966 | } | | 1956 | } |
1967 | csums[cgn] = cg->cg_cs; | | 1957 | csums[cgn] = cg->cg_cs; |
1968 | newsb->fs_cstotal.cs_ndir += cg->cg_cs.cs_ndir; | | 1958 | newsb->fs_cstotal.cs_ndir += cg->cg_cs.cs_ndir; |
1969 | newsb->fs_cstotal.cs_nifree += cg->cg_cs.cs_nifree; | | 1959 | newsb->fs_cstotal.cs_nifree += cg->cg_cs.cs_nifree; |
1970 | cgflags[cgn] |= CGF_DIRTY; | | 1960 | cgflags[cgn] |= CGF_DIRTY; |
1971 | } | | 1961 | } |
1972 | /* | | 1962 | /* |
1973 | * Flush cgs to disk, recomputing anything they're marked as needing. | | 1963 | * Flush cgs to disk, recomputing anything they're marked as needing. |
1974 | */ | | 1964 | */ |
1975 | static void | | 1965 | static void |
1976 | flush_cgs(void) | | 1966 | flush_cgs(void) |
1977 | { | | 1967 | { |
1978 | int i; | | 1968 | int i; |
1979 | | | 1969 | |
1980 | for (i = 0; i < newsb->fs_ncg; i++) { | | 1970 | for (i = 0; i < newsb->fs_ncg; i++) { |
1981 | if (cgflags[i] & CGF_BLKMAPS) { | | 1971 | if (cgflags[i] & CGF_BLKMAPS) { |
1982 | rescan_blkmaps(i); | | 1972 | rescan_blkmaps(i); |
1983 | } | | 1973 | } |
1984 | if (cgflags[i] & CGF_INOMAPS) { | | 1974 | if (cgflags[i] & CGF_INOMAPS) { |
1985 | rescan_inomaps(i); | | 1975 | rescan_inomaps(i); |
1986 | } | | 1976 | } |
1987 | if (cgflags[i] & CGF_DIRTY) { | | 1977 | if (cgflags[i] & CGF_DIRTY) { |
1988 | cgs[i]->cg_rotor = 0; | | 1978 | cgs[i]->cg_rotor = 0; |
1989 | cgs[i]->cg_frotor = 0; | | 1979 | cgs[i]->cg_frotor = 0; |
1990 | cgs[i]->cg_irotor = 0; | | 1980 | cgs[i]->cg_irotor = 0; |
1991 | if (needswap) | | 1981 | if (needswap) |
1992 | ffs_cg_swap(cgs[i],cgs[i],newsb); | | 1982 | ffs_cg_swap(cgs[i],cgs[i],newsb); |
1993 | writeat(fsbtodb(newsb, cgtod(newsb, i)), cgs[i], | | 1983 | writeat(fsbtodb(newsb, cgtod(newsb, i)), cgs[i], |
1994 | cgblksz); | | 1984 | cgblksz); |
1995 | } | | 1985 | } |
1996 | } | | 1986 | } |
1997 | if (needswap) | | 1987 | if (needswap) |
1998 | ffs_csum_swap(csums,csums,newsb->fs_cssize); | | 1988 | ffs_csum_swap(csums,csums,newsb->fs_cssize); |
1999 | writeat(fsbtodb(newsb, newsb->fs_csaddr), csums, newsb->fs_cssize); | | 1989 | writeat(fsbtodb(newsb, newsb->fs_csaddr), csums, newsb->fs_cssize); |
2000 | } | | 1990 | } |
2001 | /* | | 1991 | /* |
2002 | * Write the superblock, both to the main superblock and to each cg's | | 1992 | * Write the superblock, both to the main superblock and to each cg's |
2003 | * alternative superblock. | | 1993 | * alternative superblock. |
2004 | */ | | 1994 | */ |
2005 | static void | | 1995 | static void |
2006 | write_sbs(void) | | 1996 | write_sbs(void) |
2007 | { | | 1997 | { |
2008 | int i; | | 1998 | int i; |
2009 | | | 1999 | |
2010 | if (newsb->fs_magic == FS_UFS1_MAGIC && | | 2000 | if (newsb->fs_magic == FS_UFS1_MAGIC && |
2011 | (newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) { | | 2001 | (newsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) { |
2012 | newsb->fs_old_time = newsb->fs_time; | | 2002 | newsb->fs_old_time = newsb->fs_time; |
2013 | newsb->fs_old_size = newsb->fs_size; | | 2003 | newsb->fs_old_size = newsb->fs_size; |
2014 | /* we don't update fs_csaddr */ | | 2004 | /* we don't update fs_csaddr */ |
2015 | newsb->fs_old_dsize = newsb->fs_dsize; | | 2005 | newsb->fs_old_dsize = newsb->fs_dsize; |
2016 | newsb->fs_old_cstotal.cs_ndir = newsb->fs_cstotal.cs_ndir; | | 2006 | newsb->fs_old_cstotal.cs_ndir = newsb->fs_cstotal.cs_ndir; |
2017 | newsb->fs_old_cstotal.cs_nbfree = newsb->fs_cstotal.cs_nbfree; | | 2007 | newsb->fs_old_cstotal.cs_nbfree = newsb->fs_cstotal.cs_nbfree; |
2018 | newsb->fs_old_cstotal.cs_nifree = newsb->fs_cstotal.cs_nifree; | | 2008 | newsb->fs_old_cstotal.cs_nifree = newsb->fs_cstotal.cs_nifree; |
2019 | newsb->fs_old_cstotal.cs_nffree = newsb->fs_cstotal.cs_nffree; | | 2009 | newsb->fs_old_cstotal.cs_nffree = newsb->fs_cstotal.cs_nffree; |
2020 | /* fill fs_old_postbl_start with 256 bytes of 0xff? */ | | 2010 | /* fill fs_old_postbl_start with 256 bytes of 0xff? */ |
2021 | } | | 2011 | } |
2022 | /* copy newsb back to oldsb, so we can use it for offsets if | | 2012 | /* copy newsb back to oldsb, so we can use it for offsets if |
2023 | newsb has been swapped for writing to disk */ | | 2013 | newsb has been swapped for writing to disk */ |
2024 | memcpy(oldsb, newsb, SBLOCKSIZE); | | 2014 | memcpy(oldsb, newsb, SBLOCKSIZE); |
2025 | if (needswap) | | 2015 | if (needswap) |
2026 | ffs_sb_swap(newsb,newsb); | | 2016 | ffs_sb_swap(newsb,newsb); |
2027 | writeat(where / DEV_BSIZE, newsb, SBLOCKSIZE); | | 2017 | writeat(where / DEV_BSIZE, newsb, SBLOCKSIZE); |
2028 | for (i = 0; i < oldsb->fs_ncg; i++) { | | 2018 | for (i = 0; i < oldsb->fs_ncg; i++) { |
2029 | writeat(fsbtodb(oldsb, cgsblock(oldsb, i)), newsb, SBLOCKSIZE); | | 2019 | writeat(fsbtodb(oldsb, cgsblock(oldsb, i)), newsb, SBLOCKSIZE); |
2030 | } | | 2020 | } |
2031 | } | | 2021 | } |
2032 | | | 2022 | |
2033 | static off_t | | 2023 | static off_t |
2034 | get_dev_size(char *dev_name) | | 2024 | get_dev_size(char *dev_name) |
2035 | { | | 2025 | { |
2036 | struct dkwedge_info dkw; | | 2026 | struct dkwedge_info dkw; |
2037 | struct partition *pp; | | 2027 | struct partition *pp; |
2038 | struct disklabel lp; | | 2028 | struct disklabel lp; |
2039 | size_t ptn; | | 2029 | size_t ptn; |
2040 | | | 2030 | |
2041 | /* Get info about partition/wedge */ | | 2031 | /* Get info about partition/wedge */ |
2042 | if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) { | | 2032 | if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) { |
2043 | if (ioctl(fd, DIOCGDINFO, &lp) == -1) | | 2033 | if (ioctl(fd, DIOCGDINFO, &lp) == -1) |
2044 | return 0; | | 2034 | return 0; |
2045 | | | 2035 | |
2046 | ptn = strchr(dev_name, '\0')[-1] - 'a'; | | 2036 | ptn = strchr(dev_name, '\0')[-1] - 'a'; |
2047 | if (ptn >= lp.d_npartitions) | | 2037 | if (ptn >= lp.d_npartitions) |
2048 | return 0; | | 2038 | return 0; |
2049 | | | 2039 | |
2050 | pp = &lp.d_partitions[ptn]; | | 2040 | pp = &lp.d_partitions[ptn]; |
2051 | return pp->p_size; | | 2041 | return pp->p_size; |
2052 | } | | 2042 | } |
2053 | | | 2043 | |
2054 | return dkw.dkw_size; | | 2044 | return dkw.dkw_size; |
2055 | } | | 2045 | } |
2056 | | | 2046 | |
2057 | /* | | 2047 | /* |
2058 | * main(). | | 2048 | * main(). |
2059 | */ | | 2049 | */ |
2060 | int | | 2050 | int |
2061 | main(int argc, char **argv) | | 2051 | main(int argc, char **argv) |
2062 | { | | 2052 | { |
2063 | int ch; | | 2053 | int ch; |
2064 | int ExpertFlag; | | 2054 | int ExpertFlag; |
2065 | int SFlag; | | 2055 | int SFlag; |
2066 | size_t i; | | 2056 | size_t i; |
2067 | | | 2057 | |
2068 | char *special; | | 2058 | char *special; |
2069 | char reply[5]; | | 2059 | char reply[5]; |
2070 | | | 2060 | |
2071 | newsize = 0; | | 2061 | newsize = 0; |
2072 | ExpertFlag = 0; | | 2062 | ExpertFlag = 0; |
2073 | SFlag = 0; | | 2063 | SFlag = 0; |
2074 | | | 2064 | |
2075 | while ((ch = getopt(argc, argv, "s:y")) != -1) { | | 2065 | while ((ch = getopt(argc, argv, "s:y")) != -1) { |
2076 | switch (ch) { | | 2066 | switch (ch) { |
2077 | case 's': | | 2067 | case 's': |
2078 | SFlag = 1; | | 2068 | SFlag = 1; |
2079 | newsize = strtoll(optarg, NULL, 10); | | 2069 | newsize = strtoll(optarg, NULL, 10); |
2080 | if(newsize < 1) { | | 2070 | if(newsize < 1) { |
2081 | usage(); | | 2071 | usage(); |
2082 | } | | 2072 | } |
2083 | break; | | 2073 | break; |
2084 | case 'y': | | 2074 | case 'y': |
2085 | ExpertFlag = 1; | | 2075 | ExpertFlag = 1; |
2086 | break; | | 2076 | break; |
2087 | case '?': | | 2077 | case '?': |
2088 | /* FALLTHROUGH */ | | 2078 | /* FALLTHROUGH */ |
2089 | default: | | 2079 | default: |
2090 | usage(); | | 2080 | usage(); |
2091 | } | | 2081 | } |
2092 | } | | 2082 | } |
2093 | argc -= optind; | | 2083 | argc -= optind; |
2094 | argv += optind; | | 2084 | argv += optind; |
2095 | | | 2085 | |
2096 | if (argc != 1) { | | 2086 | if (argc != 1) { |
2097 | usage(); | | 2087 | usage(); |
2098 | } | | 2088 | } |
2099 | | | 2089 | |
2100 | special = *argv; | | 2090 | special = *argv; |
2101 | | | 2091 | |
2102 | if (ExpertFlag == 0) { | | 2092 | if (ExpertFlag == 0) { |
2103 | printf("It's required to manually run fsck on file system " | | 2093 | printf("It's required to manually run fsck on file system " |
2104 | "before you can resize it\n\n" | | 2094 | "before you can resize it\n\n" |
2105 | " Did you run fsck on your disk (Yes/No) ? "); | | 2095 | " Did you run fsck on your disk (Yes/No) ? "); |
2106 | fgets(reply, (int)sizeof(reply), stdin); | | 2096 | fgets(reply, (int)sizeof(reply), stdin); |
2107 | if (strcasecmp(reply, "Yes\n")) { | | 2097 | if (strcasecmp(reply, "Yes\n")) { |
2108 | printf("\n Nothing done \n"); | | 2098 | printf("\n Nothing done \n"); |
2109 | exit(EXIT_SUCCESS); | | 2099 | exit(EXIT_SUCCESS); |
2110 | } | | 2100 | } |
2111 | } | | 2101 | } |
2112 | | | 2102 | |
2113 | fd = open(special, O_RDWR, 0); | | 2103 | fd = open(special, O_RDWR, 0); |
2114 | if (fd < 0) | | 2104 | if (fd < 0) |
2115 | err(EXIT_FAILURE, "Can't open `%s'", special); | | 2105 | err(EXIT_FAILURE, "Can't open `%s'", special); |
2116 | checksmallio(); | | 2106 | checksmallio(); |
2117 | | | 2107 | |
2118 | if (SFlag == 0) { | | 2108 | if (SFlag == 0) { |
2119 | newsize = get_dev_size(special); | | 2109 | newsize = get_dev_size(special); |
2120 | if (newsize == 0) | | 2110 | if (newsize == 0) |
2121 | err(EXIT_FAILURE, | | 2111 | err(EXIT_FAILURE, |
2122 | "Can't resize file system, newsize not known."); | | 2112 | "Can't resize file system, newsize not known."); |
2123 | } | | 2113 | } |
2124 | | | 2114 | |
2125 | oldsb = (struct fs *) & sbbuf; | | 2115 | oldsb = (struct fs *) & sbbuf; |
2126 | newsb = (struct fs *) (SBLOCKSIZE + (char *) &sbbuf); | | 2116 | newsb = (struct fs *) (SBLOCKSIZE + (char *) &sbbuf); |
2127 | for (where = search[i = 0]; search[i] != -1; where = search[++i]) { | | 2117 | for (where = search[i = 0]; search[i] != -1; where = search[++i]) { |
2128 | readat(where / DEV_BSIZE, oldsb, SBLOCKSIZE); | | 2118 | readat(where / DEV_BSIZE, oldsb, SBLOCKSIZE); |
2129 | switch (oldsb->fs_magic) { | | 2119 | switch (oldsb->fs_magic) { |
2130 | case FS_UFS2_MAGIC: | | 2120 | case FS_UFS2_MAGIC: |
2131 | is_ufs2 = 1; | | 2121 | is_ufs2 = 1; |
2132 | /* FALLTHROUGH */ | | 2122 | /* FALLTHROUGH */ |
2133 | case FS_UFS1_MAGIC: | | 2123 | case FS_UFS1_MAGIC: |
2134 | needswap = 0; | | 2124 | needswap = 0; |
2135 | break; | | 2125 | break; |
2136 | case FS_UFS2_MAGIC_SWAPPED: | | 2126 | case FS_UFS2_MAGIC_SWAPPED: |
2137 | is_ufs2 = 1; | | 2127 | is_ufs2 = 1; |
2138 | /* FALLTHROUGH */ | | 2128 | /* FALLTHROUGH */ |
2139 | case FS_UFS1_MAGIC_SWAPPED: | | 2129 | case FS_UFS1_MAGIC_SWAPPED: |
2140 | needswap = 1; | | 2130 | needswap = 1; |
2141 | break; | | 2131 | break; |
2142 | default: | | 2132 | default: |
2143 | continue; | | 2133 | continue; |
2144 | } | | 2134 | } |
2145 | if (!is_ufs2 && where == SBLOCK_UFS2) | | 2135 | if (!is_ufs2 && where == SBLOCK_UFS2) |
2146 | continue; | | 2136 | continue; |
2147 | break; | | 2137 | break; |
2148 | } | | 2138 | } |
2149 | if (where == (off_t)-1) | | 2139 | if (where == (off_t)-1) |
2150 | errx(EXIT_FAILURE, "Bad magic number"); | | 2140 | errx(EXIT_FAILURE, "Bad magic number"); |
2151 | if (needswap) | | 2141 | if (needswap) |
2152 | ffs_sb_swap(oldsb,oldsb); | | 2142 | ffs_sb_swap(oldsb,oldsb); |
2153 | if (oldsb->fs_magic == FS_UFS1_MAGIC && | | 2143 | if (oldsb->fs_magic == FS_UFS1_MAGIC && |
2154 | (oldsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) { | | 2144 | (oldsb->fs_old_flags & FS_FLAGS_UPDATED) == 0) { |
2155 | oldsb->fs_csaddr = oldsb->fs_old_csaddr; | | 2145 | oldsb->fs_csaddr = oldsb->fs_old_csaddr; |
2156 | oldsb->fs_size = oldsb->fs_old_size; | | 2146 | oldsb->fs_size = oldsb->fs_old_size; |
2157 | oldsb->fs_dsize = oldsb->fs_old_dsize; | | 2147 | oldsb->fs_dsize = oldsb->fs_old_dsize; |
2158 | oldsb->fs_cstotal.cs_ndir = oldsb->fs_old_cstotal.cs_ndir; | | 2148 | oldsb->fs_cstotal.cs_ndir = oldsb->fs_old_cstotal.cs_ndir; |
2159 | oldsb->fs_cstotal.cs_nbfree = oldsb->fs_old_cstotal.cs_nbfree; | | 2149 | oldsb->fs_cstotal.cs_nbfree = oldsb->fs_old_cstotal.cs_nbfree; |
2160 | oldsb->fs_cstotal.cs_nifree = oldsb->fs_old_cstotal.cs_nifree; | | 2150 | oldsb->fs_cstotal.cs_nifree = oldsb->fs_old_cstotal.cs_nifree; |
2161 | oldsb->fs_cstotal.cs_nffree = oldsb->fs_old_cstotal.cs_nffree; | | 2151 | oldsb->fs_cstotal.cs_nffree = oldsb->fs_old_cstotal.cs_nffree; |
2162 | /* any others? */ | | 2152 | /* any others? */ |
2163 | printf("Resizing with ffsv1 superblock\n"); | | 2153 | printf("Resizing with ffsv1 superblock\n"); |
2164 | } | | 2154 | } |
2165 | | | 2155 | |
2166 | oldsb->fs_qbmask = ~(int64_t) oldsb->fs_bmask; | | 2156 | oldsb->fs_qbmask = ~(int64_t) oldsb->fs_bmask; |
2167 | oldsb->fs_qfmask = ~(int64_t) oldsb->fs_fmask; | | 2157 | oldsb->fs_qfmask = ~(int64_t) oldsb->fs_fmask; |
2168 | if (oldsb->fs_ipg % INOPB(oldsb)) { | | 2158 | if (oldsb->fs_ipg % INOPB(oldsb)) |
2169 | (void)fprintf(stderr, "ipg[%d] %% INOPB[%d] != 0\n", | | 2159 | errx(EXIT_FAILURE, "ipg[%d] %% INOPB[%d] != 0", |
2170 | (int) oldsb->fs_ipg, (int) INOPB(oldsb)); | | 2160 | (int) oldsb->fs_ipg, (int) INOPB(oldsb)); |
2171 | exit(EXIT_FAILURE); | | | |
2172 | } | | | |
2173 | /* The superblock is bigger than struct fs (there are trailing | | 2161 | /* The superblock is bigger than struct fs (there are trailing |
2174 | * tables, of non-fixed size); make sure we copy the whole | | 2162 | * tables, of non-fixed size); make sure we copy the whole |
2175 | * thing. SBLOCKSIZE may be an over-estimate, but we do this | | 2163 | * thing. SBLOCKSIZE may be an over-estimate, but we do this |
2176 | * just once, so being generous is cheap. */ | | 2164 | * just once, so being generous is cheap. */ |
2177 | memcpy(newsb, oldsb, SBLOCKSIZE); | | 2165 | memcpy(newsb, oldsb, SBLOCKSIZE); |
2178 | loadcgs(); | | 2166 | loadcgs(); |
2179 | if (newsize > fsbtodb(oldsb, oldsb->fs_size)) { | | 2167 | if (newsize > fsbtodb(oldsb, oldsb->fs_size)) { |
2180 | grow(); | | 2168 | grow(); |
2181 | } else if (newsize < fsbtodb(oldsb, oldsb->fs_size)) { | | 2169 | } else if (newsize < fsbtodb(oldsb, oldsb->fs_size)) { |
2182 | if (is_ufs2) | | 2170 | if (is_ufs2) |
2183 | errx(EXIT_FAILURE,"shrinking not supported for ufs2"); | | 2171 | errx(EXIT_FAILURE,"shrinking not supported for ufs2"); |
2184 | shrink(); | | 2172 | shrink(); |
2185 | } | | 2173 | } |
2186 | flush_cgs(); | | 2174 | flush_cgs(); |
2187 | write_sbs(); | | 2175 | write_sbs(); |
2188 | if (isplainfile()) | | 2176 | if (isplainfile()) |
2189 | ftruncate(fd,newsize * DEV_BSIZE); | | 2177 | ftruncate(fd,newsize * DEV_BSIZE); |
2190 | return 0; | | 2178 | return 0; |
2191 | } | | 2179 | } |
2192 | | | 2180 | |
2193 | static void | | 2181 | static void |
2194 | usage(void) | | 2182 | usage(void) |
2195 | { | | 2183 | { |
2196 | | | 2184 | |
2197 | (void)fprintf(stderr, "usage: %s [-y] [-s size] special\n", | | 2185 | (void)fprintf(stderr, "usage: %s [-y] [-s size] special\n", |
2198 | getprogname()); | | 2186 | getprogname()); |
2199 | exit(EXIT_FAILURE); | | 2187 | exit(EXIT_FAILURE); |
2200 | } | | 2188 | } |