Support for larger disks.

- MFS, df(1), fsck(1), badblocks(8), de(1x) now compute the
  superblock's s_firstdatazone value if the on-disk value is zero
- mkfs(1) sets s_firstdatazone in the superblock to zero if the
  on-disk field is too small to store the actual value
- more agressive mkfs(1) inode number heuristic, copied from r5261
This commit is contained in:
David van Moolenbroek 2009-12-21 11:20:30 +00:00
parent 6aa43dc9e4
commit d5dee93bee
8 changed files with 97 additions and 46 deletions

View file

@ -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" );
}
}

View file

@ -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);

View file

@ -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 */

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 */