Hello,

Sometimes ext2fs just hangs, and gdb-ing it shows a huge lot of threads
almost all blocked at hurd/ext2fs/getblk.c:236, i.e. on a dereference
of sblock (unfortunately I forgot to ask for a backtrace).  I was
wondering: what happens if because of memory pressure the superblock
gets swapped out by Mach?  Is ext2fs able to read it back?  It looks to
me like it may not be.  I don't know so much about paging, but a kind of
problematic path I can find is:

vm_fault() on sblock
  calls memory_object_data_request
    calls pager_read_page 
  calls memory_object_data_unlock 
    calls pager_unlock_page 
      calls ext2_getblk 
        reads sblock, faults
and thus restarts again in a new thread (fortunately in the debian
package there is a thread number threshold).

I'm currently trying the attached (ugly) patch on top of the >2GB patch,
and for now haven't encountered the problem any more.

Samuel
--- ext2fs/hyper.c      2008-03-01 22:55:01.000000000 +0000
+++ ext2fs/hyper.c      2008-03-01 23:05:40.000000000 +0000
@@ -55,17 +55,22 @@
 
 static int ext2fs_clean;       /* fs clean before we started writing? */
 
+struct ext2_super_block *__sblock = NULL;
 void
 get_hypermetadata (void)
 {
   error_t err;
   size_t read;
+  static struct ext2_super_block _sblock;
 
   assert (! sblock);
   err = store_read (store, SBLOCK_OFFS >> store->log2_block_size,
-                   SBLOCK_SIZE, (void **)&sblock, &read);
+                   SBLOCK_SIZE, (void **)&__sblock, &read);
   if (err || read != SBLOCK_SIZE)
     ext2_panic ("Cannot read hypermetadata");
+
+  sblock = &_sblock;
+  *sblock = *__sblock;
   
   if (sblock->s_magic != EXT2_SUPER_MAGIC
 #ifdef EXT2FS_PRE_02B_COMPAT
@@ -159,18 +164,18 @@
   if (zeroblock == 0)
     zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
 
-  munmap (sblock, SBLOCK_SIZE);
-  sblock = NULL;
+  munmap (__sblock, SBLOCK_SIZE);
+  __sblock = NULL;
 }
 
 void
 map_hypermetadata (void)
 {
-  sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
+  __sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
 
   /* 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);
+  group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (__sblock) + 
1);
 }
 
 error_t
@@ -193,8 +198,9 @@
  if (sblock_dirty)
    {
      sblock_dirty = 0;
-     disk_cache_block_ref_ptr (sblock);
-     record_global_poke (sblock);
+     *__sblock = *sblock;
+     disk_cache_block_ref_ptr (__sblock);
+     record_global_poke (__sblock);
    }
 
   sync_global (wait);

Reply via email to