diff options
Diffstat (limited to 'ext2fs/hyper.c')
-rw-r--r-- | ext2fs/hyper.c | 107 |
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"); |