aboutsummaryrefslogtreecommitdiff
path: root/ext2fs/hyper.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs/hyper.c')
-rw-r--r--ext2fs/hyper.c107
1 files changed, 64 insertions, 43 deletions
diff --git a/ext2fs/hyper.c b/ext2fs/hyper.c
index f46d0fcb..bee4175f 100644
--- a/ext2fs/hyper.c
+++ b/ext2fs/hyper.c
@@ -1,8 +1,7 @@
/* Fetching and storing the hypermetadata (superblock and bg summary info)
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1994,95,96,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,20 +20,20 @@
#include <string.h>
#include <stdio.h>
#include <error.h>
+#include <hurd/store.h>
#include "ext2fs.h"
-vm_address_t zeroblock = 0;
-char *modified_global_blocks = 0;
+vm_address_t zeroblock;
+char *modified_global_blocks;
static void
allocate_mod_map (void)
{
- static vm_size_t mod_map_size = 0;
+ static vm_size_t mod_map_size;
if (modified_global_blocks && mod_map_size)
/* Get rid of the old one. */
- vm_deallocate (mach_task_self (),
- (vm_address_t)modified_global_blocks, mod_map_size);
+ munmap (modified_global_blocks, mod_map_size);
if (!diskfs_readonly && block_size < vm_page_size)
/* If the block size is too small, we have to take extra care when
@@ -42,18 +41,18 @@ allocate_mod_map (void)
on any file pager blocks. In this case use a bitmap to record which
global blocks are actually modified so the pager can write only them. */
{
- error_t err;
/* One bit per filesystem block. */
mod_map_size = sblock->s_blocks_count >> 3;
- err =
- vm_allocate (mach_task_self (),
- (vm_address_t *)&modified_global_blocks, mod_map_size, 1);
- assert_perror (err);
+ modified_global_blocks = mmap (0, mod_map_size, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ assert (modified_global_blocks != (void *) -1);
}
else
modified_global_blocks = 0;
}
+unsigned int sblock_block = SBLOCK_BLOCK; /* in 1k blocks */
+
static int ext2fs_clean; /* fs clean before we started writing? */
void
@@ -63,10 +62,7 @@ get_hypermetadata (void)
if (err)
ext2_panic ("can't read superblock: %s", strerror (err));
- if (zeroblock)
- vm_deallocate (mach_task_self (), zeroblock, block_size);
-
- sblock = (struct ext2_super_block *)boffs_ptr (SBLOCK_OFFS);
+ sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
if (sblock->s_magic != EXT2_SUPER_MAGIC
#ifdef EXT2FS_PRE_02B_COMPAT
@@ -76,38 +72,39 @@ get_hypermetadata (void)
ext2_panic ("bad magic number %#x (should be %#x)",
sblock->s_magic, EXT2_SUPER_MAGIC);
- block_size = EXT2_MIN_BLOCK_SIZE << sblock->s_log_block_size;
-
- if (block_size > 8192)
- ext2_panic ("block size %ld is too big (max is 8192 bytes)", block_size);
+ log2_block_size = EXT2_MIN_BLOCK_LOG_SIZE + sblock->s_log_block_size;
+ block_size = 1 << log2_block_size;
- log2_block_size = ffs (block_size) - 1;
- if ((1 << log2_block_size) != block_size)
- ext2_panic ("block size %ld isn't a power of two!", block_size);
+ if (block_size > EXT2_MAX_BLOCK_SIZE)
+ ext2_panic ("block size %d is too big (max is %d bytes)",
+ block_size, EXT2_MAX_BLOCK_SIZE);
- log2_dev_blocks_per_fs_block
- = log2_block_size - diskfs_log2_device_block_size;
+ log2_dev_blocks_per_fs_block = log2_block_size - store->log2_block_size;
if (log2_dev_blocks_per_fs_block < 0)
- ext2_panic ("block size %ld isn't a power-of-two multiple of the device"
- " block size (%d)!",
- block_size, diskfs_device_block_size);
+ ext2_panic ("block size %d isn't a power-of-two multiple of the device"
+ " block size (%zd)!",
+ block_size, store->block_size);
log2_stat_blocks_per_fs_block = 0;
while ((512 << log2_stat_blocks_per_fs_block) < block_size)
log2_stat_blocks_per_fs_block++;
if ((512 << log2_stat_blocks_per_fs_block) != block_size)
- ext2_panic ("block size %ld isn't a power-of-two multiple of 512!",
+ ext2_panic ("block size %d isn't a power-of-two multiple of 512!",
block_size);
- if (diskfs_device_size
- < (sblock->s_blocks_count << log2_dev_blocks_per_fs_block))
- ext2_panic ("disk size (%ld blocks) too small "
- "(superblock says we need %ld)",
- diskfs_device_size,
- sblock->s_blocks_count << log2_dev_blocks_per_fs_block);
+ if ((store->size >> log2_block_size) < sblock->s_blocks_count)
+ ext2_panic ("disk size (%qd bytes) too small; superblock says we need %qd",
+ (long long int) store->size,
+ (long long int) sblock->s_blocks_count << log2_block_size);
+ if (log2_dev_blocks_per_fs_block != 0
+ && (store->size & ((1 << log2_dev_blocks_per_fs_block) - 1)) != 0)
+ ext2_warning ("%Ld (%zd byte) device blocks "
+ " unused after last filesystem (%d byte) block",
+ (store->size & ((1 << log2_dev_blocks_per_fs_block) - 1)),
+ store->block_size, block_size);
/* Set these handy variables. */
- inodes_per_block = block_size / sizeof (struct ext2_inode);
+ inodes_per_block = block_size / EXT2_INODE_SIZE (sblock);
frag_size = EXT2_MIN_FRAG_SIZE << sblock->s_log_frag_size;
if (frag_size)
@@ -115,6 +112,23 @@ get_hypermetadata (void)
else
ext2_panic ("frag size is zero!");
+ if (sblock->s_rev_level > EXT2_GOOD_OLD_REV)
+ {
+ if (sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP)
+ ext2_panic ("could not mount because of unsupported optional features"
+ " (0x%x)",
+ sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP);
+ if (sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)
+ {
+ ext2_warning ("mounted readonly because of"
+ " unsupported optional features (0x%x)",
+ sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP);
+ diskfs_readonly = 1;
+ }
+ if (sblock->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
+ ext2_panic ("inode size %d isn't supported", sblock->s_inode_size);
+ }
+
groups_count =
((sblock->s_blocks_count - sblock->s_first_data_block +
sblock->s_blocks_per_group - 1)
@@ -140,11 +154,16 @@ get_hypermetadata (void)
diskfs_end_catch_exception ();
+ /* Cache a convenient pointer to the block group descriptors for allocation.
+ These are stored in the filesystem blocks following the superblock. */
+ group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (sblock) + 1);
+
/* A handy source of page-aligned zeros. */
- vm_allocate (mach_task_self (), &zeroblock, block_size, 1);
+ if (zeroblock == 0)
+ zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
}
-void
+error_t
diskfs_set_hypermetadata (int wait, int clean)
{
if (clean && ext2fs_clean && !(sblock->s_state & EXT2_VALID_FS))
@@ -168,6 +187,9 @@ diskfs_set_hypermetadata (int wait, int clean)
}
sync_global (wait);
+
+ /* Should check writability here and return EROFS if necessary. XXX */
+ return 0;
}
void
@@ -175,10 +197,9 @@ diskfs_readonly_changed (int readonly)
{
allocate_mod_map ();
- vm_protect (mach_task_self (),
- (vm_address_t)disk_image,
- diskfs_device_size << diskfs_log2_device_block_size,
- 0, VM_PROT_READ | (readonly ? 0 : VM_PROT_WRITE));
+ (*(readonly ? store_set_flags : store_clear_flags)) (store, STORE_READONLY);
+
+ mprotect (disk_image, store->size, PROT_READ | (readonly ? 0 : PROT_WRITE));
if (!readonly && !(sblock->s_state & EXT2_VALID_FS))
ext2_warning ("UNCLEANED FILESYSTEM NOW WRITABLE");