Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Jun 1997 15:09:17 +0200 (CEST)
From:      Dirk Keunecke <dk@panda.rhein-main.de>
To:        FreeBSD-gnats@FreeBSD.ORG, freebsd-bugs@FreeBSD.ORG
Subject:   Re: kern/3571: Mounted ext2 prevents umount of filesystems during reboot
Message-ID:  <199706081309.PAA00289@panda.rhein-main.de>
In-Reply-To: <199705100000.RAA06827@hub.freebsd.org>
References:  <199705092350.BAA01601@panda.rhein-main.de> <199705100000.RAA06827@hub.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

[The following is related to the problem report 'kern/3571']

Hello,

The 'ext2fs' stores group descriptors, inode and block bitmaps in buffers
which it "reserves" by not brelse'ing them after the data is read
in. The buffer is kept 'B_BUSY' until they are released at unmount
time (this is not 100% accurate, some buffers may be released at other
times). If one reboots the system, 'boot()' (in kern_shutdown.c')
syncs and then waits for these buffers to become unbusy. This will
never happen because they are brelse'ed in 'ext2_unmount()', which is
called by 'boot()' only if all buffers of all filesystems have been
successfully synced (as indicated by the non-busy state of all buffers).

The 'B_LOCKED' flag also seems to prevent an buffer from being reused,
but without keeping the buffer busy. I've made some minor changes to
'ext2' to use 'B_LOCKED' instead of 'B_BUSY' to reserve the buffers
for 'ext2'. It seems to solve 'kern/3571'.

If anybody cares enough, please review these changes. Comments, suggestions, 
corrections are welcome.

Disclaimer: I am no filesystem-, kernel- or whatever kind of a guru, just
someone who wants to learn something about the FreeBSD kernel. No warranty.


Regards,

Dirk


[The following patch was created against CURRENT as of May 30]

*** /sys/gnu/ext2fs/ext2_linux_balloc.c	Tue Apr  1 22:31:32 1997
--- ext2_linux_balloc.c	Sun Jun  1 16:44:13 1997
***************
*** 70,75 ****
--- 70,76 ----
  			    block_group, (unsigned long) gdp->bg_block_bitmap);
  	sb->s_block_bitmap_number[bitmap_nr] = block_group;
  	sb->s_block_bitmap[bitmap_nr] = bh;
+ 	LCK_BUF(bh)
  }
  
  /*
***************
*** 130,136 ****
  		if (sb->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
  			sb->s_loaded_block_bitmaps++;
  		else
! 			brelse (sb->s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
  		for (j = sb->s_loaded_block_bitmaps - 1; j > 0;  j--) {
  			sb->s_block_bitmap_number[j] =
  				sb->s_block_bitmap_number[j - 1];
--- 131,138 ----
  		if (sb->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
  			sb->s_loaded_block_bitmaps++;
  		else
! 			ULCK_BUF(sb->s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1])
! 
  		for (j = sb->s_loaded_block_bitmaps - 1; j > 0;  j--) {
  			sb->s_block_bitmap_number[j] =
  				sb->s_block_bitmap_number[j - 1];
*** /sys/gnu/ext2fs/ext2_linux_ialloc.c	Tue Apr  1 22:31:33 1997
--- ext2_linux_ialloc.c	Sun Jun  1 16:42:27 1997
***************
*** 121,126 ****
--- 121,127 ----
  			    block_group, (unsigned long) gdp->bg_inode_bitmap);
  	sb->s_inode_bitmap_number[bitmap_nr] = block_group;
  	sb->s_inode_bitmap[bitmap_nr] = bh;
+ 	LCK_BUF(bh)
  }
  
  /*
***************
*** 184,190 ****
  		if (sb->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
  			sb->s_loaded_inode_bitmaps++;
  		else
! 			brelse (sb->s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
  		for (j = sb->s_loaded_inode_bitmaps - 1; j > 0; j--) {
  			sb->s_inode_bitmap_number[j] =
  				sb->s_inode_bitmap_number[j - 1];
--- 185,191 ----
  		if (sb->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
  			sb->s_loaded_inode_bitmaps++;
  		else
! 			ULCK_BUF(sb->s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1])
  		for (j = sb->s_loaded_inode_bitmaps - 1; j > 0; j--) {
  			sb->s_inode_bitmap_number[j] =
  				sb->s_inode_bitmap_number[j - 1];
*** /sys/gnu/ext2fs/ext2_vfsops.c	Mon Mar 24 23:35:55 1997
--- ext2_vfsops.c	Sun Jun  1 17:28:38 1997
***************
*** 415,424 ****
  	    printf("EXT2-fs: unable to read group descriptors (%d)\n", error);
  	    return EIO;
  	}
      }
      if(!ext2_check_descriptors(fs)) {
  	    for (j = 0; j < db_count; j++)
! 		brelse(fs->s_group_desc[j]);
  	    bsd_free(fs->s_group_desc, M_UFSMNT);
  	    printf("EXT2-fs: (ext2_check_descriptors failure) "
  		   "unable to read group descriptors\n");
--- 415,426 ----
  	    printf("EXT2-fs: unable to read group descriptors (%d)\n", error);
  	    return EIO;
  	}
+ 	/* Set the B_LOCKED flag on the buffer, then brelse() it */
+ 	LCK_BUF(fs->s_group_desc[i])
      }
      if(!ext2_check_descriptors(fs)) {
  	    for (j = 0; j < db_count; j++)
! 		    ULCK_BUF(fs->s_group_desc[j])
  	    bsd_free(fs->s_group_desc, M_UFSMNT);
  	    printf("EXT2-fs: (ext2_check_descriptors failure) "
  		   "unable to read group descriptors\n");
***************
*** 694,709 ****
  		fs->s_es->s_state |= EXT2_VALID_FS;	/* was fs_clean = 1 */
  		ext2_sbupdate(ump, MNT_WAIT);
  	}
  	/* release buffers containing group descriptors */
  	for(i = 0; i < fs->s_db_per_group; i++) 
! 		brelse(fs->s_group_desc[i]);
  	/* release cached inode/block bitmaps */
          for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
                  if (fs->s_inode_bitmap[i])
!                         brelse (fs->s_inode_bitmap[i]);
          for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
                  if (fs->s_block_bitmap[i])
!                         brelse (fs->s_block_bitmap[i]);
  
  	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
  	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
--- 696,714 ----
  		fs->s_es->s_state |= EXT2_VALID_FS;	/* was fs_clean = 1 */
  		ext2_sbupdate(ump, MNT_WAIT);
  	}
+ 
  	/* release buffers containing group descriptors */
  	for(i = 0; i < fs->s_db_per_group; i++)
! 		ULCK_BUF(fs->s_group_desc[i])
! 
  	/* release cached inode/block bitmaps */
          for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
                  if (fs->s_inode_bitmap[i])
! 			ULCK_BUF(fs->s_inode_bitmap[i])
! 
          for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
                  if (fs->s_block_bitmap[i])
! 			ULCK_BUF(fs->s_block_bitmap[i])
  
  	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
  	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
***************
*** 1109,1128 ****
  	else
  		bawrite(bp);
  
! 	/* write group descriptors back on disk */
! 	for(i = 0; i < fs->s_db_per_group; i++) 
! 		/* Godmar thinks: we must avoid using any of the b*write
! 		 * functions here: we want to keep the buffer locked
! 		 * so we use my 'housemade' write routine:
  		 */
- 		error |= ll_w_block(fs->s_group_desc[i], waitfor == MNT_WAIT);
- 
-         for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
-                 if (fs->s_inode_bitmap[i])
-                         ll_w_block (fs->s_inode_bitmap[i], 1);
-         for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
-                 if (fs->s_block_bitmap[i])
-                         ll_w_block (fs->s_block_bitmap[i], 1);
  
  	return (error);
  }
--- 1115,1125 ----
  	else
  		bawrite(bp);
  
! 	/*
! 	 * The buffers for group descriptors, inode bitmaps and block bitmaps
! 	 * are not busy at this point and are (hopefully) written by the
! 	 * usual sync mechanism. No need to write them here
  	 */
  
  	return (error);
  }
*** /sys/gnu/ext2fs/fs.h	Mon Feb 10 04:19:21 1997
--- fs.h	Sun Jun  1 16:40:19 1997
***************
*** 155,157 ****
--- 155,177 ----
  #define  lock_super(devvp)   	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curproc)
  #define  unlock_super(devvp) 	VOP_UNLOCK(devvp, 0, curproc)
  
+ /*
+  * To lock a buffer, set the B_LOCKED flag and then brelse() it. To unlock,
+  * reset the B_LOCKED flag and brelse() the buffer back on the LRU list
+  */
+ #define LCK_BUF(bp) { \
+ 	int s; \
+ 	s = splbio(); \
+ 	(bp)->b_flags |= B_LOCKED; \
+ 	splx(s); \
+ 	brelse(bp); \
+ }
+ 
+ #define ULCK_BUF(bp) { \
+ 	int s; \
+ 	s = splbio(); \
+ 	(bp)->b_flags &= ~B_LOCKED; \
+ 	splx(s); \
+ 	bremfree(bp); \
+ 	brelse(bp); \
+ }









Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199706081309.PAA00289>