aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-03-15 19:52:42 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-03-15 19:52:42 +0000
commit53a0cadbe1f0a2bde37ca86e1185d286424181f0 (patch)
tree306d8ad4c9a20e971356afc3b3a76abc15263458
parentca274d1bbe798fbf3950c31e92c9f33d29cef48c (diff)
downloadbusybox-w32-53a0cadbe1f0a2bde37ca86e1185d286424181f0.tar.gz
busybox-w32-53a0cadbe1f0a2bde37ca86e1185d286424181f0.tar.bz2
busybox-w32-53a0cadbe1f0a2bde37ca86e1185d286424181f0.zip
mkfs_minix: stop using lots of bss/data.
data -3500 bytes, code -300 bytes keep_data_small: expand/fix git-svn-id: svn://busybox.net/trunk/busybox@18123 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--docs/keep_data_small.txt68
-rw-r--r--util-linux/mkfs_minix.c368
2 files changed, 242 insertions, 194 deletions
diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt
index ec13b4d3f..5137dffc6 100644
--- a/docs/keep_data_small.txt
+++ b/docs/keep_data_small.txt
@@ -1,4 +1,4 @@
1 Keeping data small 1 Keeping data small
2 2
3When many applets are compiled into busybox, all rw data and 3When many applets are compiled into busybox, all rw data and
4bss for each applet are concatenated. Including those from libc, 4bss for each applet are concatenated. Including those from libc,
@@ -10,6 +10,11 @@ On nommu it's probably bites the most, actually using real
10RAM for rwdata and bss. On i386, bss is lazily allocated 10RAM for rwdata and bss. On i386, bss is lazily allocated
11by COWed zero pages. Not sure about rwdata - also COW? 11by COWed zero pages. Not sure about rwdata - also COW?
12 12
13In order to keep bbox NOMMU and small-mem systems friendly
14we should avoid large global data in our applets, and should
15minimize usage of libc functions which implicitly use
16such structures in libc.
17
13Small experiment measures "parasitic" bbox memory consumption. 18Small experiment measures "parasitic" bbox memory consumption.
14Here we start 1000 "busybox sleep 10" in parallel. 19Here we start 1000 "busybox sleep 10" in parallel.
15bbox binary is practically allyesconfig static one, 20bbox binary is practically allyesconfig static one,
@@ -34,14 +39,10 @@ bash-3.2# nmeter '%t %c %b %m %p %[pn]'
3423:17:43 .......... 0 0 168M 0 147 3923:17:43 .......... 0 0 168M 0 147
35 40
36This requires 55M of memory. Thus 1 trivial busybox applet 41This requires 55M of memory. Thus 1 trivial busybox applet
37takes 55k of userspace memory (nmeter doesn't account for kernel-side 42takes 55k of memory.
38allocations). Definitely can be improved.
39 43
40Thus we should avoid large global data in our applets,
41and should minimize usage of libc functions which implicitly use
42such structures in libc.
43 44
44 Example 1 45 Example 1
45 46
46One example how to reduce global data usage is in 47One example how to reduce global data usage is in
47archival/libunarchive/decompress_unzip.c: 48archival/libunarchive/decompress_unzip.c:
@@ -57,12 +58,15 @@ archival/libunarchive/decompress_unzip.c:
57#define STATE_IN_BSS 0 58#define STATE_IN_BSS 0
58#define STATE_IN_MALLOC 1 59#define STATE_IN_MALLOC 1
59 60
61(see the rest of the file to get the idea)
62
60This example completely eliminates globals in that module. 63This example completely eliminates globals in that module.
61Required memory is allocated in inflate_gunzip() [its main module] 64Required memory is allocated in inflate_gunzip() [its main module]
62and then passed down to all subroutines which need to access 'globals' 65and then passed down to all subroutines which need to access 'globals'
63as a parameter. 66as a parameter.
64 67
65 Example 2 68
69 Example 2
66 70
67In case you don't want to pass this additional parameter everywhere, 71In case you don't want to pass this additional parameter everywhere,
68take a look at archival/gzip.c. Here all global data is replaced by 72take a look at archival/gzip.c. Here all global data is replaced by
@@ -70,7 +74,7 @@ single global pointer (ptr_to_globals) to allocated storage.
70 74
71In order to not duplicate ptr_to_globals in every applet, you can 75In order to not duplicate ptr_to_globals in every applet, you can
72reuse single common one. It is defined in libbb/messages.c 76reuse single common one. It is defined in libbb/messages.c
73as struct globals *ptr_to_globals, but the struct globals is 77as struct globals *const ptr_to_globals, but the struct globals is
74NOT defined in libbb.h. You first define your own struct: 78NOT defined in libbb.h. You first define your own struct:
75 79
76struct globals { int a; char buf[1000]; }; 80struct globals { int a; char buf[1000]; };
@@ -79,13 +83,45 @@ and then declare that ptr_to_globals is a pointer to it:
79 83
80#define G (*ptr_to_globals) 84#define G (*ptr_to_globals)
81 85
82Linker magic ensures that these two merge into single pointer object. 86ptr_to_globals is declared as constant pointer.
83Now initialize it in <applet>_main(): 87This helps gcc understand that it won't change, resulting in noticeably
88smaller code. In order to assign it, use PTR_TO_GLOBALS macro:
89
90 PTR_TO_GLOBALS = xzalloc(sizeof(G));
91
92Typically it is done in <applet>_main().
93
94Now you can reference "globals" by G.a, G.buf and so on, in any function.
95
96
97 bb_common_bufsiz1
98
99There is one big common buffer in bss - bb_common_bufsiz1. It is a much
100earlier mechanism to reduce bss usage. Each applet can use it for
101its needs. Library functions are prohibited from using it.
102
103'G.' trick can be done using bb_common_bufsiz1 instead of malloced buffer:
104
105#define G (*(struct globals*)&bb_common_bufsiz1)
106
107Be careful, though, and use it only if
108sizeof(struct globals) <= sizeof(bb_common_bufsiz1).
109
110
111 Drawbacks
112
113You have to initialize it by hand. xzalloc() can be helpful in clearing
114allocated storage to 0, but anything more must be done by hand.
115
116All global variables are prefixed by 'G.' now. If this makes code
117less readable, use #defines:
118
119#define dev_fd (G.dev_fd)
120#define sector (G.sector)
84 121
85 ptr_to_globals = xzalloc(sizeof(G));
86 122
87and you can reference "globals" by G.a, G.buf and so on, in any function. 123 Word of caution
88 124
89The drawback is that now you have to initialize it by hand. xzalloc() 125If applet doesn't use much of global data, converting it to using
90can be helpful in clearing allocated storage to 0, but anything more 126one of above methods is not worth resulting code obfuscation.
91must be done by hand. 127If you have less that ~300 bytes of global data - don't bother.
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c
index e9ac9350d..2ba9233df 100644
--- a/util-linux/mkfs_minix.c
+++ b/util-linux/mkfs_minix.c
@@ -85,42 +85,49 @@ enum {
85 TEST_BUFFER_BLOCKS = 16, 85 TEST_BUFFER_BLOCKS = 16,
86}; 86};
87 87
88#if ENABLE_FEATURE_MINIX2 88#if !ENABLE_FEATURE_MINIX2
89static int version2;
90#else
91enum { version2 = 0 }; 89enum { version2 = 0 };
92#endif 90#endif
93 91
94static char *device_name; 92struct globals {
95static int dev_fd = -1;
96static uint32_t total_blocks;
97static int badblocks;
98/* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
99static int namelen = 30;
100static int dirsize = 32;
101static int magic = MINIX1_SUPER_MAGIC2;
102 93
103static char root_block[BLOCK_SIZE]; 94 int dev_fd;
104static char super_block_buffer[BLOCK_SIZE];
105static char boot_block_buffer[512];
106static char *inode_buffer;
107 95
108static char *inode_map; 96#if ENABLE_FEATURE_MINIX2
109static char *zone_map; 97 int version2;
98#define version2 G.version2
99#endif
100 char *device_name;
101 uint32_t total_blocks;
102 int badblocks;
103 int namelen;
104 int dirsize;
105 int magic;
106 char *inode_buffer;
107 char *inode_map;
108 char *zone_map;
109 int used_good_blocks;
110 unsigned long req_nr_inodes;
111 unsigned currently_testing;
112
113
114 char root_block[BLOCK_SIZE];
115 char super_block_buffer[BLOCK_SIZE];
116 char boot_block_buffer[512];
117 unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
118};
110 119
111static int used_good_blocks; 120#define G (*ptr_to_globals)
112static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
113static unsigned long req_nr_inodes;
114 121
115static ATTRIBUTE_ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n) 122static ATTRIBUTE_ALWAYS_INLINE unsigned div_roundup(unsigned size, unsigned n)
116{ 123{
117 return (size + n-1) / n; 124 return (size + n-1) / n;
118} 125}
119 126
120#define INODE_BUF1 (((struct minix1_inode*)inode_buffer) - 1) 127#define INODE_BUF1 (((struct minix1_inode*)G.inode_buffer) - 1)
121#define INODE_BUF2 (((struct minix2_inode*)inode_buffer) - 1) 128#define INODE_BUF2 (((struct minix2_inode*)G.inode_buffer) - 1)
122 129
123#define SB (*(struct minix_super_block*)super_block_buffer) 130#define SB (*(struct minix_super_block*)G.super_block_buffer)
124 131
125#define SB_INODES (SB.s_ninodes) 132#define SB_INODES (SB.s_ninodes)
126#define SB_IMAPS (SB.s_imap_blocks) 133#define SB_IMAPS (SB.s_imap_blocks)
@@ -160,13 +167,13 @@ static void minix_clrbit(char *a, unsigned i)
160} 167}
161 168
162/* Note: do not assume 0/1, it is 0/nonzero */ 169/* Note: do not assume 0/1, it is 0/nonzero */
163#define zone_in_use(x) minix_bit(zone_map,(x)-SB_FIRSTZONE+1) 170#define zone_in_use(x) minix_bit(G.zone_map,(x)-SB_FIRSTZONE+1)
164/*#define inode_in_use(x) minix_bit(inode_map,(x))*/ 171/*#define inode_in_use(x) minix_bit(G.inode_map,(x))*/
165 172
166#define mark_inode(x) minix_setbit(inode_map,(x)) 173#define mark_inode(x) minix_setbit(G.inode_map,(x))
167#define unmark_inode(x) minix_clrbit(inode_map,(x)) 174#define unmark_inode(x) minix_clrbit(G.inode_map,(x))
168#define mark_zone(x) minix_setbit(zone_map,(x)-SB_FIRSTZONE+1) 175#define mark_zone(x) minix_setbit(G.zone_map,(x)-SB_FIRSTZONE+1)
169#define unmark_zone(x) minix_clrbit(zone_map,(x)-SB_FIRSTZONE+1) 176#define unmark_zone(x) minix_clrbit(G.zone_map,(x)-SB_FIRSTZONE+1)
170 177
171#ifndef BLKGETSIZE 178#ifndef BLKGETSIZE
172# define BLKGETSIZE _IO(0x12,96) /* return device size */ 179# define BLKGETSIZE _IO(0x12,96) /* return device size */
@@ -227,51 +234,51 @@ static void write_tables(void)
227 SB.s_state &= ~MINIX_ERROR_FS; 234 SB.s_state &= ~MINIX_ERROR_FS;
228 235
229 msg_eol = "seek to 0 failed"; 236 msg_eol = "seek to 0 failed";
230 xlseek(dev_fd, 0, SEEK_SET); 237 xlseek(G.dev_fd, 0, SEEK_SET);
231 238
232 msg_eol = "cannot clear boot sector"; 239 msg_eol = "cannot clear boot sector";
233 xwrite(dev_fd, boot_block_buffer, 512); 240 xwrite(G.dev_fd, G.boot_block_buffer, 512);
234 241
235 msg_eol = "seek to BLOCK_SIZE failed"; 242 msg_eol = "seek to BLOCK_SIZE failed";
236 xlseek(dev_fd, BLOCK_SIZE, SEEK_SET); 243 xlseek(G.dev_fd, BLOCK_SIZE, SEEK_SET);
237 244
238 msg_eol = "cannot write superblock"; 245 msg_eol = "cannot write superblock";
239 xwrite(dev_fd, super_block_buffer, BLOCK_SIZE); 246 xwrite(G.dev_fd, G.super_block_buffer, BLOCK_SIZE);
240 247
241 msg_eol = "cannot write inode map"; 248 msg_eol = "cannot write inode map";
242 xwrite(dev_fd, inode_map, SB_IMAPS * BLOCK_SIZE); 249 xwrite(G.dev_fd, G.inode_map, SB_IMAPS * BLOCK_SIZE);
243 250
244 msg_eol = "cannot write zone map"; 251 msg_eol = "cannot write zone map";
245 xwrite(dev_fd, zone_map, SB_ZMAPS * BLOCK_SIZE); 252 xwrite(G.dev_fd, G.zone_map, SB_ZMAPS * BLOCK_SIZE);
246 253
247 msg_eol = "cannot write inodes"; 254 msg_eol = "cannot write inodes";
248 xwrite(dev_fd, inode_buffer, INODE_BUFFER_SIZE); 255 xwrite(G.dev_fd, G.inode_buffer, INODE_BUFFER_SIZE);
249 256
250 msg_eol = "\n"; 257 msg_eol = "\n";
251} 258}
252 259
253static void write_block(int blk, char *buffer) 260static void write_block(int blk, char *buffer)
254{ 261{
255 xlseek(dev_fd, blk * BLOCK_SIZE, SEEK_SET); 262 xlseek(G.dev_fd, blk * BLOCK_SIZE, SEEK_SET);
256 xwrite(dev_fd, buffer, BLOCK_SIZE); 263 xwrite(G.dev_fd, buffer, BLOCK_SIZE);
257} 264}
258 265
259static int get_free_block(void) 266static int get_free_block(void)
260{ 267{
261 int blk; 268 int blk;
262 269
263 if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS) 270 if (G.used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
264 bb_error_msg_and_die("too many bad blocks"); 271 bb_error_msg_and_die("too many bad blocks");
265 if (used_good_blocks) 272 if (G.used_good_blocks)
266 blk = good_blocks_table[used_good_blocks - 1] + 1; 273 blk = G.good_blocks_table[G.used_good_blocks - 1] + 1;
267 else 274 else
268 blk = SB_FIRSTZONE; 275 blk = SB_FIRSTZONE;
269 while (blk < SB_ZONES && zone_in_use(blk)) 276 while (blk < SB_ZONES && zone_in_use(blk))
270 blk++; 277 blk++;
271 if (blk >= SB_ZONES) 278 if (blk >= SB_ZONES)
272 bb_error_msg_and_die("not enough good blocks"); 279 bb_error_msg_and_die("not enough good blocks");
273 good_blocks_table[used_good_blocks] = blk; 280 G.good_blocks_table[G.used_good_blocks] = blk;
274 used_good_blocks++; 281 G.used_good_blocks++;
275 return blk; 282 return blk;
276} 283}
277 284
@@ -279,8 +286,8 @@ static void mark_good_blocks(void)
279{ 286{
280 int blk; 287 int blk;
281 288
282 for (blk = 0; blk < used_good_blocks; blk++) 289 for (blk = 0; blk < G.used_good_blocks; blk++)
283 mark_zone(good_blocks_table[blk]); 290 mark_zone(G.good_blocks_table[blk]);
284} 291}
285 292
286static int next(int zone) 293static int next(int zone)
@@ -303,7 +310,7 @@ static void make_bad_inode(void)
303 310
304#define NEXT_BAD (zone = next(zone)) 311#define NEXT_BAD (zone = next(zone))
305 312
306 if (!badblocks) 313 if (!G.badblocks)
307 return; 314 return;
308 mark_inode(MINIX_BAD_INO); 315 mark_inode(MINIX_BAD_INO);
309 inode->i_nlinks = 1; 316 inode->i_nlinks = 1;
@@ -311,7 +318,7 @@ static void make_bad_inode(void)
311 /* it's harder to check for bugs then - diff isn't helpful :(... */ 318 /* it's harder to check for bugs then - diff isn't helpful :(... */
312 inode->i_time = CUR_TIME; 319 inode->i_time = CUR_TIME;
313 inode->i_mode = S_IFREG + 0000; 320 inode->i_mode = S_IFREG + 0000;
314 inode->i_size = badblocks * BLOCK_SIZE; 321 inode->i_size = G.badblocks * BLOCK_SIZE;
315 zone = next(0); 322 zone = next(0);
316 for (i = 0; i < 7; i++) { 323 for (i = 0; i < 7; i++) {
317 inode->i_zone[i] = zone; 324 inode->i_zone[i] = zone;
@@ -354,13 +361,13 @@ static void make_bad_inode2(void)
354 unsigned long ind_block[BLOCK_SIZE >> 2]; 361 unsigned long ind_block[BLOCK_SIZE >> 2];
355 unsigned long dind_block[BLOCK_SIZE >> 2]; 362 unsigned long dind_block[BLOCK_SIZE >> 2];
356 363
357 if (!badblocks) 364 if (!G.badblocks)
358 return; 365 return;
359 mark_inode(MINIX_BAD_INO); 366 mark_inode(MINIX_BAD_INO);
360 inode->i_nlinks = 1; 367 inode->i_nlinks = 1;
361 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME; 368 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
362 inode->i_mode = S_IFREG + 0000; 369 inode->i_mode = S_IFREG + 0000;
363 inode->i_size = badblocks * BLOCK_SIZE; 370 inode->i_size = G.badblocks * BLOCK_SIZE;
364 zone = next(0); 371 zone = next(0);
365 for (i = 0; i < 7; i++) { 372 for (i = 0; i < 7; i++) {
366 inode->i_zone[i] = zone; 373 inode->i_zone[i] = zone;
@@ -406,18 +413,18 @@ static void make_root_inode(void)
406 inode->i_zone[0] = get_free_block(); 413 inode->i_zone[0] = get_free_block();
407 inode->i_nlinks = 2; 414 inode->i_nlinks = 2;
408 inode->i_time = CUR_TIME; 415 inode->i_time = CUR_TIME;
409 if (badblocks) 416 if (G.badblocks)
410 inode->i_size = 3 * dirsize; 417 inode->i_size = 3 * G.dirsize;
411 else { 418 else {
412 root_block[2 * dirsize] = '\0'; 419 G.root_block[2 * G.dirsize] = '\0';
413 root_block[2 * dirsize + 1] = '\0'; 420 G.root_block[2 * G.dirsize + 1] = '\0';
414 inode->i_size = 2 * dirsize; 421 inode->i_size = 2 * G.dirsize;
415 } 422 }
416 inode->i_mode = S_IFDIR + 0755; 423 inode->i_mode = S_IFDIR + 0755;
417 inode->i_uid = GETUID; 424 inode->i_uid = GETUID;
418 if (inode->i_uid) 425 if (inode->i_uid)
419 inode->i_gid = GETGID; 426 inode->i_gid = GETGID;
420 write_block(inode->i_zone[0], root_block); 427 write_block(inode->i_zone[0], G.root_block);
421} 428}
422 429
423#if ENABLE_FEATURE_MINIX2 430#if ENABLE_FEATURE_MINIX2
@@ -429,94 +436,23 @@ static void make_root_inode2(void)
429 inode->i_zone[0] = get_free_block(); 436 inode->i_zone[0] = get_free_block();
430 inode->i_nlinks = 2; 437 inode->i_nlinks = 2;
431 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME; 438 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
432 if (badblocks) 439 if (G.badblocks)
433 inode->i_size = 3 * dirsize; 440 inode->i_size = 3 * G.dirsize;
434 else { 441 else {
435 root_block[2 * dirsize] = '\0'; 442 G.root_block[2 * G.dirsize] = '\0';
436 root_block[2 * dirsize + 1] = '\0'; 443 G.root_block[2 * G.dirsize + 1] = '\0';
437 inode->i_size = 2 * dirsize; 444 inode->i_size = 2 * G.dirsize;
438 } 445 }
439 inode->i_mode = S_IFDIR + 0755; 446 inode->i_mode = S_IFDIR + 0755;
440 inode->i_uid = GETUID; 447 inode->i_uid = GETUID;
441 if (inode->i_uid) 448 if (inode->i_uid)
442 inode->i_gid = GETGID; 449 inode->i_gid = GETGID;
443 write_block(inode->i_zone[0], root_block); 450 write_block(inode->i_zone[0], G.root_block);
444} 451}
445#else 452#else
446void make_root_inode2(void); 453void make_root_inode2(void);
447#endif 454#endif
448 455
449static void setup_tables(void)
450{
451 unsigned long inodes;
452 unsigned norm_firstzone;
453 unsigned sb_zmaps;
454 unsigned i;
455
456 memset(super_block_buffer, 0, BLOCK_SIZE);
457 memset(boot_block_buffer, 0, 512);
458 SB_MAGIC = magic;
459 SB_ZONE_SIZE = 0;
460 SB_MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
461 if (version2)
462 SB.s_zones = total_blocks;
463 else
464 SB.s_nzones = total_blocks;
465
466 /* some magic nrs: 1 inode / 3 blocks */
467 if (req_nr_inodes == 0)
468 inodes = total_blocks / 3;
469 else
470 inodes = req_nr_inodes;
471 /* Round up inode count to fill block size */
472 if (version2)
473 inodes = (inodes + MINIX2_INODES_PER_BLOCK - 1) &
474 ~(MINIX2_INODES_PER_BLOCK - 1);
475 else
476 inodes = (inodes + MINIX1_INODES_PER_BLOCK - 1) &
477 ~(MINIX1_INODES_PER_BLOCK - 1);
478 if (inodes > 65535)
479 inodes = 65535;
480 SB_INODES = inodes;
481 SB_IMAPS = div_roundup(SB_INODES + 1, BITS_PER_BLOCK);
482
483 /* Real bad hack but overwise mkfs.minix can be thrown
484 * in infinite loop...
485 * try:
486 * dd if=/dev/zero of=test.fs count=10 bs=1024
487 * mkfs.minix -i 200 test.fs
488 */
489 /* This code is not insane: NORM_FIRSTZONE is not a constant,
490 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
491 i = 999;
492 SB_ZMAPS = 0;
493 do {
494 norm_firstzone = NORM_FIRSTZONE;
495 sb_zmaps = div_roundup(total_blocks - norm_firstzone + 1, BITS_PER_BLOCK);
496 if (SB_ZMAPS == sb_zmaps) goto got_it;
497 SB_ZMAPS = sb_zmaps;
498 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
499 } while (--i);
500 bb_error_msg_and_die("incompatible size/inode count, try different -i N");
501 got_it:
502
503 SB_FIRSTZONE = norm_firstzone;
504 inode_map = xmalloc(SB_IMAPS * BLOCK_SIZE);
505 zone_map = xmalloc(SB_ZMAPS * BLOCK_SIZE);
506 memset(inode_map, 0xff, SB_IMAPS * BLOCK_SIZE);
507 memset(zone_map, 0xff, SB_ZMAPS * BLOCK_SIZE);
508 for (i = SB_FIRSTZONE; i < SB_ZONES; i++)
509 unmark_zone(i);
510 for (i = MINIX_ROOT_INO; i <= SB_INODES; i++)
511 unmark_inode(i);
512 inode_buffer = xzalloc(INODE_BUFFER_SIZE);
513 printf("%ld inodes\n", (long)SB_INODES);
514 printf("%ld blocks\n", (long)SB_ZONES);
515 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE, (long)norm_firstzone);
516 printf("Zonesize=%d\n", BLOCK_SIZE << SB_ZONE_SIZE);
517 printf("Maxsize=%ld\n", (long)SB_MAXSIZE);
518}
519
520/* 456/*
521 * Perform a test of a block; return the number of 457 * Perform a test of a block; return the number of
522 * blocks readable. 458 * blocks readable.
@@ -527,11 +463,11 @@ static size_t do_check(char *buffer, size_t try, unsigned current_block)
527 463
528 /* Seek to the correct loc. */ 464 /* Seek to the correct loc. */
529 msg_eol = "seek failed during testing of blocks"; 465 msg_eol = "seek failed during testing of blocks";
530 xlseek(dev_fd, current_block * BLOCK_SIZE, SEEK_SET); 466 xlseek(G.dev_fd, current_block * BLOCK_SIZE, SEEK_SET);
531 msg_eol = "\n"; 467 msg_eol = "\n";
532 468
533 /* Try the read */ 469 /* Try the read */
534 got = read(dev_fd, buffer, try * BLOCK_SIZE); 470 got = read(G.dev_fd, buffer, try * BLOCK_SIZE);
535 if (got < 0) 471 if (got < 0)
536 got = 0; 472 got = 0;
537 try = ((size_t)got) / BLOCK_SIZE; 473 try = ((size_t)got) / BLOCK_SIZE;
@@ -541,17 +477,15 @@ static size_t do_check(char *buffer, size_t try, unsigned current_block)
541 return try; 477 return try;
542} 478}
543 479
544static unsigned currently_testing;
545
546static void alarm_intr(int alnum) 480static void alarm_intr(int alnum)
547{ 481{
548 if (currently_testing >= SB_ZONES) 482 if (G.currently_testing >= SB_ZONES)
549 return; 483 return;
550 signal(SIGALRM, alarm_intr); 484 signal(SIGALRM, alarm_intr);
551 alarm(5); 485 alarm(5);
552 if (!currently_testing) 486 if (!G.currently_testing)
553 return; 487 return;
554 printf("%d ...", currently_testing); 488 printf("%d ...", G.currently_testing);
555 fflush(stdout); 489 fflush(stdout);
556} 490}
557 491
@@ -561,28 +495,29 @@ static void check_blocks(void)
561 /* buffer[] was the biggest static in entire bbox */ 495 /* buffer[] was the biggest static in entire bbox */
562 char *buffer = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS); 496 char *buffer = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS);
563 497
564 currently_testing = 0; 498 G.currently_testing = 0;
565 signal(SIGALRM, alarm_intr); 499 signal(SIGALRM, alarm_intr);
566 alarm(5); 500 alarm(5);
567 while (currently_testing < SB_ZONES) { 501 while (G.currently_testing < SB_ZONES) {
568 msg_eol = "seek failed in check_blocks"; 502 msg_eol = "seek failed in check_blocks";
569 xlseek(dev_fd, currently_testing * BLOCK_SIZE, SEEK_SET); 503 xlseek(G.dev_fd, G.currently_testing * BLOCK_SIZE, SEEK_SET);
570 msg_eol = "\n"; 504 msg_eol = "\n";
571 try = TEST_BUFFER_BLOCKS; 505 try = TEST_BUFFER_BLOCKS;
572 if (currently_testing + try > SB_ZONES) 506 if (G.currently_testing + try > SB_ZONES)
573 try = SB_ZONES - currently_testing; 507 try = SB_ZONES - G.currently_testing;
574 got = do_check(buffer, try, currently_testing); 508 got = do_check(buffer, try, G.currently_testing);
575 currently_testing += got; 509 G.currently_testing += got;
576 if (got == try) 510 if (got == try)
577 continue; 511 continue;
578 if (currently_testing < SB_FIRSTZONE) 512 if (G.currently_testing < SB_FIRSTZONE)
579 bb_error_msg_and_die("bad blocks before data-area: cannot make fs"); 513 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
580 mark_zone(currently_testing); 514 mark_zone(G.currently_testing);
581 badblocks++; 515 G.badblocks++;
582 currently_testing++; 516 G.currently_testing++;
583 } 517 }
518 alarm(0);
584 free(buffer); 519 free(buffer);
585 printf("%d bad block(s)\n", badblocks); 520 printf("%d bad block(s)\n", G.badblocks);
586} 521}
587 522
588static void get_list_blocks(char *filename) 523static void get_list_blocks(char *filename)
@@ -594,9 +529,80 @@ static void get_list_blocks(char *filename)
594 while (!feof(listfile)) { 529 while (!feof(listfile)) {
595 fscanf(listfile, "%ld\n", &blockno); 530 fscanf(listfile, "%ld\n", &blockno);
596 mark_zone(blockno); 531 mark_zone(blockno);
597 badblocks++; 532 G.badblocks++;
598 } 533 }
599 printf("%d bad block(s)\n", badblocks); 534 printf("%d bad block(s)\n", G.badblocks);
535}
536
537static void setup_tables(void)
538{
539 unsigned long inodes;
540 unsigned norm_firstzone;
541 unsigned sb_zmaps;
542 unsigned i;
543
544 /* memset(G.super_block_buffer, 0, BLOCK_SIZE); */
545 /* memset(G.boot_block_buffer, 0, 512); */
546 SB_MAGIC = G.magic;
547 SB_ZONE_SIZE = 0;
548 SB_MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
549 if (version2)
550 SB.s_zones = G.total_blocks;
551 else
552 SB.s_nzones = G.total_blocks;
553
554 /* some magic nrs: 1 inode / 3 blocks */
555 if (G.req_nr_inodes == 0)
556 inodes = G.total_blocks / 3;
557 else
558 inodes = G.req_nr_inodes;
559 /* Round up inode count to fill block size */
560 if (version2)
561 inodes = (inodes + MINIX2_INODES_PER_BLOCK - 1) &
562 ~(MINIX2_INODES_PER_BLOCK - 1);
563 else
564 inodes = (inodes + MINIX1_INODES_PER_BLOCK - 1) &
565 ~(MINIX1_INODES_PER_BLOCK - 1);
566 if (inodes > 65535)
567 inodes = 65535;
568 SB_INODES = inodes;
569 SB_IMAPS = div_roundup(SB_INODES + 1, BITS_PER_BLOCK);
570
571 /* Real bad hack but overwise mkfs.minix can be thrown
572 * in infinite loop...
573 * try:
574 * dd if=/dev/zero of=test.fs count=10 bs=1024
575 * mkfs.minix -i 200 test.fs
576 */
577 /* This code is not insane: NORM_FIRSTZONE is not a constant,
578 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
579 i = 999;
580 SB_ZMAPS = 0;
581 do {
582 norm_firstzone = NORM_FIRSTZONE;
583 sb_zmaps = div_roundup(G.total_blocks - norm_firstzone + 1, BITS_PER_BLOCK);
584 if (SB_ZMAPS == sb_zmaps) goto got_it;
585 SB_ZMAPS = sb_zmaps;
586 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
587 } while (--i);
588 bb_error_msg_and_die("incompatible size/inode count, try different -i N");
589 got_it:
590
591 SB_FIRSTZONE = norm_firstzone;
592 G.inode_map = xmalloc(SB_IMAPS * BLOCK_SIZE);
593 G.zone_map = xmalloc(SB_ZMAPS * BLOCK_SIZE);
594 memset(G.inode_map, 0xff, SB_IMAPS * BLOCK_SIZE);
595 memset(G.zone_map, 0xff, SB_ZMAPS * BLOCK_SIZE);
596 for (i = SB_FIRSTZONE; i < SB_ZONES; i++)
597 unmark_zone(i);
598 for (i = MINIX_ROOT_INO; i <= SB_INODES; i++)
599 unmark_inode(i);
600 G.inode_buffer = xzalloc(INODE_BUFFER_SIZE);
601 printf("%ld inodes\n", (long)SB_INODES);
602 printf("%ld blocks\n", (long)SB_ZONES);
603 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE, (long)norm_firstzone);
604 printf("Zonesize=%d\n", BLOCK_SIZE << SB_ZONE_SIZE);
605 printf("Maxsize=%ld\n", (long)SB_MAXSIZE);
600} 606}
601 607
602int mkfs_minix_main(int argc, char **argv); 608int mkfs_minix_main(int argc, char **argv);
@@ -609,6 +615,12 @@ int mkfs_minix_main(int argc, char **argv)
609 char *str_i, *str_n; 615 char *str_i, *str_n;
610 char *listfile = NULL; 616 char *listfile = NULL;
611 617
618 PTR_TO_GLOBALS = xzalloc(sizeof(G));
619/* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
620 G.namelen = 30;
621 G.dirsize = 32;
622 G.magic = MINIX1_SUPER_MAGIC2;
623
612 if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE) 624 if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE)
613 bb_error_msg_and_die("bad inode size"); 625 bb_error_msg_and_die("bad inode size");
614#if ENABLE_FEATURE_MINIX2 626#if ENABLE_FEATURE_MINIX2
@@ -619,14 +631,14 @@ int mkfs_minix_main(int argc, char **argv)
619 opt = getopt32(argc, argv, "ci:l:n:v", &str_i, &listfile, &str_n); 631 opt = getopt32(argc, argv, "ci:l:n:v", &str_i, &listfile, &str_n);
620 argv += optind; 632 argv += optind;
621 //if (opt & 1) -c 633 //if (opt & 1) -c
622 if (opt & 2) req_nr_inodes = xatoul(str_i); // -i 634 if (opt & 2) G.req_nr_inodes = xatoul(str_i); // -i
623 //if (opt & 4) -l 635 //if (opt & 4) -l
624 if (opt & 8) { // -n 636 if (opt & 8) { // -n
625 namelen = xatoi_u(str_n); 637 G.namelen = xatoi_u(str_n);
626 if (namelen == 14) magic = MINIX1_SUPER_MAGIC; 638 if (G.namelen == 14) G.magic = MINIX1_SUPER_MAGIC;
627 else if (namelen == 30) magic = MINIX1_SUPER_MAGIC2; 639 else if (G.namelen == 30) G.magic = MINIX1_SUPER_MAGIC2;
628 else bb_show_usage(); 640 else bb_show_usage();
629 dirsize = namelen + 2; 641 G.dirsize = G.namelen + 2;
630 } 642 }
631 if (opt & 0x10) { // -v 643 if (opt & 0x10) { // -v
632#if ENABLE_FEATURE_MINIX2 644#if ENABLE_FEATURE_MINIX2
@@ -636,34 +648,34 @@ int mkfs_minix_main(int argc, char **argv)
636#endif 648#endif
637 } 649 }
638 650
639 device_name = *argv++; 651 G.device_name = *argv++;
640 if (!device_name) 652 if (!G.device_name)
641 bb_show_usage(); 653 bb_show_usage();
642 if (*argv) 654 if (*argv)
643 total_blocks = xatou32(*argv); 655 G.total_blocks = xatou32(*argv);
644 else 656 else
645 total_blocks = get_size(device_name) / 1024; 657 G.total_blocks = get_size(G.device_name) / 1024;
646 658
647 if (total_blocks < 10) 659 if (G.total_blocks < 10)
648 bb_error_msg_and_die("must have at least 10 blocks"); 660 bb_error_msg_and_die("must have at least 10 blocks");
649 661
650 if (version2) { 662 if (version2) {
651 magic = MINIX2_SUPER_MAGIC2; 663 G.magic = MINIX2_SUPER_MAGIC2;
652 if (namelen == 14) 664 if (G.namelen == 14)
653 magic = MINIX2_SUPER_MAGIC; 665 G.magic = MINIX2_SUPER_MAGIC;
654 } else if (total_blocks > 65535) 666 } else if (G.total_blocks > 65535)
655 total_blocks = 65535; 667 G.total_blocks = 65535;
656 668
657 /* Check if it is mounted */ 669 /* Check if it is mounted */
658 mp = find_mount_point(device_name, NULL); 670 mp = find_mount_point(G.device_name, NULL);
659 if (mp && strcmp(device_name, mp->mnt_fsname) == 0) 671 if (mp && strcmp(G.device_name, mp->mnt_fsname) == 0)
660 bb_error_msg_and_die("%s is mounted on %s; " 672 bb_error_msg_and_die("%s is mounted on %s; "
661 "refusing to make a filesystem", 673 "refusing to make a filesystem",
662 device_name, mp->mnt_dir); 674 G.device_name, mp->mnt_dir);
663 675
664 dev_fd = xopen(device_name, O_RDWR); 676 G.dev_fd = xopen(G.device_name, O_RDWR);
665 if (fstat(dev_fd, &statbuf) < 0) 677 if (fstat(G.dev_fd, &statbuf) < 0)
666 bb_error_msg_and_die("cannot stat %s", device_name); 678 bb_error_msg_and_die("cannot stat %s", G.device_name);
667 if (!S_ISBLK(statbuf.st_mode)) 679 if (!S_ISBLK(statbuf.st_mode))
668 opt &= ~1; // clear -c (check) 680 opt &= ~1; // clear -c (check)
669 681
@@ -673,16 +685,16 @@ int mkfs_minix_main(int argc, char **argv)
673 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) 685 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
674 /* what is this? */ 686 /* what is this? */
675 bb_error_msg_and_die("will not try " 687 bb_error_msg_and_die("will not try "
676 "to make filesystem on '%s'", device_name); 688 "to make filesystem on '%s'", G.device_name);
677#endif 689#endif
678 690
679 tmp = root_block; 691 tmp = G.root_block;
680 *(short *) tmp = 1; 692 *(short *) tmp = 1;
681 strcpy(tmp + 2, "."); 693 strcpy(tmp + 2, ".");
682 tmp += dirsize; 694 tmp += G.dirsize;
683 *(short *) tmp = 1; 695 *(short *) tmp = 1;
684 strcpy(tmp + 2, ".."); 696 strcpy(tmp + 2, "..");
685 tmp += dirsize; 697 tmp += G.dirsize;
686 *(short *) tmp = 2; 698 *(short *) tmp = 2;
687 strcpy(tmp + 2, ".badblocks"); 699 strcpy(tmp + 2, ".badblocks");
688 700