diff --git a/commands/de/de_diskio.c b/commands/de/de_diskio.c index e14383bd9..2151c359f 100644 --- a/commands/de/de_diskio.c +++ b/commands/de/de_diskio.c @@ -188,13 +188,14 @@ void Read_Super_Block( s ) s->inode_blocks = (s->inodes + inodes_per_block - 1) / inodes_per_block; s->first_data = 2 + s->inode_maps + s->zone_maps + s->inode_blocks; - if ( s->first_data != super->s_firstdatazone ) + if ( super->s_firstdatazone_old != 0 && + s->first_data != super->s_firstdatazone_old ) { - if ( s->first_data > super->s_firstdatazone ) + if ( s->first_data > super->s_firstdatazone_old ) Error( "Corrupted first data zone offset or inode count in super block" ); else Warning( "First data zone in super block suspiciously high" ); - s->first_data = super->s_firstdatazone; + s->first_data = super->s_firstdatazone_old; } s->inodes_in_map = s->inodes + 1; @@ -209,7 +210,7 @@ void Read_Super_Block( s ) if ( super->s_log_zone_size != 0 ) Error( "Can not handle multiple blocks per zone" ); - } +} diff --git a/commands/simple/badblocks.c b/commands/simple/badblocks.c index 5acbdbc27..cfa1c23c0 100644 --- a/commands/simple/badblocks.c +++ b/commands/simple/badblocks.c @@ -170,7 +170,7 @@ int rw_mode; i_num = stat_ptr->st_ino; - blk = (block_t) (2 + sp->s_imap_blocks + sp->s_zmap_blocks); + blk = (block_t) (START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks); blk += (block_t) ((i_num - 1) / inodes_per_block); blk *= (block_t) (BLOCK_SIZE);/* this block */ @@ -334,6 +334,14 @@ char *argv[]; inode_size = V2_INODE_SIZE; } + /* If the s_firstdatazone_old field is zero, we have to compute the value. */ + if (sp->s_firstdatazone_old == 0) + sp->s_firstdatazone = + START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks + + (sp->s_ninodes + inodes_per_block - 1) / inodes_per_block; + else + sp->s_firstdatazone = sp->s_firstdatazone_old; + get_inode(&stat_buf); for (finished = 0; !finished;) { @@ -481,7 +489,7 @@ block_t num; offset = z_num - (blk << BIT_MAP_SHIFT); /* offset */ words = z_num / INT_BITS; /* which word */ - blk_offset = (block_t) (2 + sp->s_imap_blocks); /* zone map */ + blk_offset = (block_t) (START_BLOCK + sp->s_imap_blocks); /* zone map */ blk_offset *= (block_t) BLOCK_SIZE; /* of course in block */ blk_offset += (block_t) (words * SIZE_OF_INT); /* offset */ @@ -520,7 +528,7 @@ zone_t num; offset = z_num - (blk << BIT_MAP_SHIFT); /* offset in block */ words = z_num / INT_BITS; /* which word */ - blk_offset = (long) (2 + sp->s_imap_blocks); + blk_offset = (long) (START_BLOCK + sp->s_imap_blocks); blk_offset *= (long) BLOCK_SIZE; blk_offset += (long) (words * SIZE_OF_INT); diff --git a/commands/simple/df.c b/commands/simple/df.c index 5379e94e1..823127960 100644 --- a/commands/simple/df.c +++ b/commands/simple/df.c @@ -271,7 +271,7 @@ int df(const struct mtab *mt) { int fd; bit_t i_count, z_count; - block_t totblocks, busyblocks; + block_t totblocks, busyblocks, offset; int n, block_size; struct v12_super_block super, *sp; @@ -300,7 +300,7 @@ int df(const struct mtab *mt) } if(sp->s_magic != SUPER_V3) block_size = _STATIC_BLOCK_SIZE; - else block_size = super.s_block_size; + else block_size = sp->s_block_size; if(block_size < _MIN_BLOCK_SIZE) { fprintf(stderr, "df: %s: funny block size (%d)\n", @@ -309,7 +309,24 @@ int df(const struct mtab *mt) return(1); } - if (sp->s_magic == SUPER_V1) sp->s_zones= sp->s_nzones; + if (sp->s_magic == SUPER_V1) { + sp->s_zones = sp->s_nzones; + sp->s_inodes_per_block = V1_INODES_PER_BLOCK; + } else { + sp->s_inodes_per_block = V2_INODES_PER_BLOCK(block_size); + } + + /* If the s_firstdatazone_old field is zero, we have to compute the value. */ + if (sp->s_firstdatazone_old == 0) { + offset = START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks; + offset += (sp->s_ninodes + sp->s_inodes_per_block - 1) / + sp->s_inodes_per_block; + + sp->s_firstdatazone = (offset + (1 << sp->s_log_zone_size) - 1) >> + sp->s_log_zone_size; + } else { + sp->s_firstdatazone = sp->s_firstdatazone_old; + } lseek(fd, (off_t) block_size * 2L, SEEK_SET); /* skip rest of super block */ diff --git a/commands/simple/fsck.c b/commands/simple/fsck.c index 7e63abf04..371c012af 100644 --- a/commands/simple/fsck.c +++ b/commands/simple/fsck.c @@ -528,8 +528,8 @@ void lsuper() if (input(buf, 80)) sb.s_imap_blocks = atol(buf); printf("zmap_blocks = %u", sb.s_zmap_blocks); if (input(buf, 80)) sb.s_zmap_blocks = atol(buf); - printf("firstdatazone = %u", sb.s_firstdatazone); - if (input(buf, 80)) sb.s_firstdatazone = atol(buf); + printf("firstdatazone = %u", sb.s_firstdatazone_old); + if (input(buf, 80)) sb.s_firstdatazone_old = atol(buf); printf("log_zone_size = %u", sb.s_log_zone_size); if (input(buf, 80)) sb.s_log_zone_size = atol(buf); printf("maxsize = %ld", sb.s_max_size); @@ -569,12 +569,12 @@ void getsuper() if (sb.s_zones <= 0) fatal("no zones"); if (sb.s_imap_blocks <= 0) fatal("no imap"); if (sb.s_zmap_blocks <= 0) fatal("no zmap"); - if (sb.s_firstdatazone <= 4) fatal("first data zone too small"); + if (sb.s_firstdatazone != 0 && sb.s_firstdatazone <= 4) + fatal("first data zone too small"); if (sb.s_log_zone_size < 0) fatal("zone size < block size"); if (sb.s_max_size <= 0) { - printf("max file size %ld ", sb.s_max_size); + printf("warning: invalid max file size %ld\n", sb.s_max_size); sb.s_max_size = LONG_MAX; - printf("set to %ld\n", sb.s_max_size); } } @@ -602,17 +602,22 @@ void chksuper() pr("warning: expected %d zmap_block%s", n, "", "s"); printf(" instead of %d\n", sb.s_zmap_blocks); } - if (sb.s_firstdatazone >= sb.s_zones) - fatal("first data zone too large"); if (sb.s_log_zone_size >= 8 * sizeof(block_nr)) fatal("log_zone_size too large"); if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n", sb.s_log_zone_size); - n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size; - if (sb.s_firstdatazone < n) fatal("first data zone too small"); - if (sb.s_firstdatazone != n) { - printf("warning: expected first data zone to be %d ", n); - printf("instead of %u\n", sb.s_firstdatazone); + sb.s_firstdatazone = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size; + if (sb.s_firstdatazone_old != 0) { + if (sb.s_firstdatazone_old >= sb.s_zones) + fatal("first data zone too large"); + if (sb.s_firstdatazone_old < sb.s_firstdatazone) + fatal("first data zone too small"); + if (sb.s_firstdatazone_old != sb.s_firstdatazone) { + printf("warning: expected first data zone to be %u ", + sb.s_firstdatazone); + printf("instead of %u\n", sb.s_firstdatazone_old); + sb.s_firstdatazone = sb.s_firstdatazone_old; + } } maxsize = MAX_FILE_POS; if (((maxsize - 1) >> sb.s_log_zone_size) / block_size >= MAX_ZONES) @@ -627,12 +632,12 @@ void chksuper() int inoblock(int inn) { - return div64u(mul64u(inn - 1, INODE_SIZE), block_size) + BLK_ILIST; + return div64u(mul64u(inn - 1, INODE_SIZE), block_size) + BLK_ILIST; } int inooff(int inn) { - return rem64u(mul64u(inn - 1, INODE_SIZE), block_size); + return rem64u(mul64u(inn - 1, INODE_SIZE), block_size); } /* Make a listing of the inodes given by `clist'. If `repair' is set, ask diff --git a/commands/simple/mkfs.c b/commands/simple/mkfs.c index 236293af8..dcac038a6 100644 --- a/commands/simple/mkfs.c +++ b/commands/simple/mkfs.c @@ -270,12 +270,9 @@ char *argv[]; if (blocks == 0) pexit("Can't open prototype file"); } if (i == 0) { - i = blocks / 2; - if (blocks >= 20000) i = blocks / 3; - if (blocks >= 40000) i = blocks / 4; - if (blocks >= 60000) i = blocks / 5; - if (blocks >= 80000) i = blocks / 6; - if (blocks >= 100000) i = blocks / 7; + u32_t kb = div64u(mul64u(blocks, block_size), 1024); + i = kb / 2; + if (kb >= 100000) i = kb / 4; /* round up to fill inode block */ i += inodes_per_block - 1; @@ -462,15 +459,21 @@ ino_t inodes; fprintf(stderr, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS); exit(1); } - inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2; + inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks; inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block; initblks = inode_offset + inodeblks; - sup->s_firstdatazone = nb = (initblks + (1 << zone_shift) - 1) >> zone_shift; + sup->s_firstdatazone_old = nb = + (initblks + (1 << zone_shift) - 1) >> zone_shift; if(nb >= zones) pexit("bit maps too large"); - if(nb != sup->s_firstdatazone) { - fprintf(stderr, "mkfs: too much bitmap and inode data.\n" BIGGERBLOCKS); - exit(1); + if(nb != sup->s_firstdatazone_old) { + /* The field is too small to store the value. Fortunately, the value + * can be computed from other fields. We set the on-disk field to zero + * to indicate that it must not be used. Eventually, we can always set + * the on-disk field to zero, and stop using it. + */ + sup->s_firstdatazone_old = 0; } + sup->s_firstdatazone = nb; zoff = sup->s_firstdatazone - 1; sup->s_log_zone_size = zone_shift; if (fs_version == 1) { @@ -508,7 +511,7 @@ ino_t inodes; } /* Clear maps and inodes. */ - for (i = 2; i < initblks; i++) put_block((block_t) i, zero); + for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero); next_zone = sup->s_firstdatazone; next_inode = 1; diff --git a/servers/mfs/inode.c b/servers/mfs/inode.c index 4f044dcd2..214d8b057 100644 --- a/servers/mfs/inode.c +++ b/servers/mfs/inode.c @@ -385,7 +385,7 @@ int rw_flag; /* READING or WRITING */ /* Get the block where the inode resides. */ sp = get_super(rip->i_dev); /* get pointer to super block */ rip->i_sp = sp; /* inode must contain super block pointer */ - offset = sp->s_imap_blocks + sp->s_zmap_blocks + 2; + offset = START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks; b = (block_t) (rip->i_num - 1)/sp->s_inodes_per_block + offset; bp = get_block(rip->i_dev, b, NORMAL); dip = bp->b_v1_ino + (rip->i_num - 1) % V1_INODES_PER_BLOCK; diff --git a/servers/mfs/super.c b/servers/mfs/super.c index 45090a250..52ea86a96 100644 --- a/servers/mfs/super.c +++ b/servers/mfs/super.c @@ -183,6 +183,7 @@ register struct super_block *sp; /* pointer to a superblock */ int magic; int version, native, r; static char *sbbuf; + block_t offset; STATICINIT(sbbuf, _MIN_BLOCK_SIZE); @@ -215,14 +216,14 @@ register struct super_block *sp; /* pointer to a superblock */ /* If the super block has the wrong byte order, swap the fields; the magic * number doesn't need conversion. */ - sp->s_ninodes = conv4(native, sp->s_ninodes); - sp->s_nzones = conv2(native, (int) sp->s_nzones); - sp->s_imap_blocks = conv2(native, (int) sp->s_imap_blocks); - sp->s_zmap_blocks = conv2(native, (int) sp->s_zmap_blocks); - sp->s_firstdatazone = conv2(native, (int) sp->s_firstdatazone); - sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size); - sp->s_max_size = conv4(native, sp->s_max_size); - sp->s_zones = conv4(native, sp->s_zones); + sp->s_ninodes = conv4(native, sp->s_ninodes); + sp->s_nzones = conv2(native, (int) sp->s_nzones); + sp->s_imap_blocks = conv2(native, (int) sp->s_imap_blocks); + sp->s_zmap_blocks = conv2(native, (int) sp->s_zmap_blocks); + sp->s_firstdatazone_old = conv2(native, (int) sp->s_firstdatazone_old); + sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size); + sp->s_max_size = conv4(native, sp->s_max_size); + sp->s_zones = conv4(native, sp->s_zones); /* In V1, the device size was kept in a short, s_nzones, which limited * devices to 32K zones. For V2, it was decided to keep the size as a @@ -252,6 +253,21 @@ register struct super_block *sp; /* pointer to a superblock */ sp->s_nindirs = V2_INDIRECTS(sp->s_block_size); } + /* For even larger disks, a similar problem occurs with s_firstdatazone. + * If the on-disk field contains zero, we assume that the value was too + * large to fit, and compute it on the fly. + */ + if (sp->s_firstdatazone_old == 0) { + offset = START_BLOCK + sp->s_imap_blocks + sp->s_zmap_blocks; + offset += (sp->s_ninodes + sp->s_inodes_per_block - 1) / + sp->s_inodes_per_block; + + sp->s_firstdatazone = (offset + (1 << sp->s_log_zone_size) - 1) >> + sp->s_log_zone_size; + } else { + sp->s_firstdatazone = sp->s_firstdatazone_old; + } + if (sp->s_block_size < _MIN_BLOCK_SIZE) return(EINVAL); diff --git a/servers/mfs/super.h b/servers/mfs/super.h index 42bea7cb8..4336bfd90 100644 --- a/servers/mfs/super.h +++ b/servers/mfs/super.h @@ -23,7 +23,7 @@ EXTERN struct super_block { zone1_t s_nzones; /* total device size, including bit maps etc */ short s_imap_blocks; /* # of blocks used by inode bit map */ short s_zmap_blocks; /* # of blocks used by zone bit map */ - zone1_t s_firstdatazone; /* number of first data zone */ + zone1_t s_firstdatazone_old; /* number of first data zone (small) */ short s_log_zone_size; /* log2 of blocks/zone */ short s_pad; /* try to avoid compiler-dependent padding */ off_t s_max_size; /* maximum file size on this device */ @@ -45,6 +45,7 @@ EXTERN struct super_block { /*struct inode *s_isup;*/ /* inode for root dir of mounted file sys */ /*struct inode *s_imount;*/ /* inode mounted on */ unsigned s_inodes_per_block; /* precalculated from magic number */ + zone_t s_firstdatazone; /* number of first data zone (big) */ dev_t s_dev; /* whose super block is this? */ int s_rd_only; /* set to 1 iff file sys mounted read only */ int s_native; /* set to 1 iff not byte swapped file system */