From dk@panda.rhein-main.de  Fri May  9 16:56:05 1997
Received: from odb.rhein-main.de (odb.rhein-main.de [195.37.8.4])
          by hub.freebsd.org (8.8.5/8.8.5) with SMTP id QAA06709
          for <FreeBSD-gnats-submit@freebsd.org>; Fri, 9 May 1997 16:56:02 -0700 (PDT)
Received: from panda.rhein-main.de by odb.rhein-main.de with esmtp
	(Smail3.2 #2) id m0wPzSl-0007V2C; Sat, 10 May 1997 01:52:35 +0200 (MET DST)
Received: (from dk@localhost) by panda.rhein-main.de (8.8.5/8.8.3) id BAA01601; Sat, 10 May 1997 01:50:05 +0200 (CEST)
Message-Id: <199705092350.BAA01601@panda.rhein-main.de>
Date: Sat, 10 May 1997 01:50:05 +0200 (CEST)
From: Dirk Keunecke <dk@panda.rhein-main.de>
Reply-To: dk@panda.rhein-main.de
To: FreeBSD-gnats-submit@freebsd.org
Subject: Mounted ext2 prevents umount of filesystems during reboot
X-Send-Pr-Version: 3.2

>Number:         3571
>Category:       kern
>Synopsis:       Mounted ext2 prevents umount of filesystems during reboot
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri May  9 17:00:01 PDT 1997
>Closed-Date:    Mon Jan 10 22:24:54 PST 2000
>Last-Modified:  Mon Jan 10 22:31:17 PST 2000
>Originator:     Dirk Keunecke
>Release:        FreeBSD 3.0-CURRENT i386
>Organization:
>Environment:

	FreeBSD 3.0-CURRENT as of May 2

>Description:

	If I reboot(8) with an ext2fs partition mounted ('ro' or 'rw')
	the 'sync' does not succeed. It syncs some buffers (from 'ffs' ?)
	but can't push out others (xx xx xx xx... giving up) and does not 
	unmount the filesystems. 

>How-To-Repeat:

	Reboot(8) with an 'ext2fs' partition mounted. Easy to reproduce
	for me.

>Fix:
	
	Don't reboot(8) with an 'ext2fs' partition mounted.

>Release-Note:
>Audit-Trail:

From: Dirk Keunecke <dk@panda.rhein-main.de>
To: FreeBSD-gnats@freebsd.org, freebsd-bugs@freebsd.org
Cc:  Subject: Re: kern/3571: Mounted ext2 prevents umount of filesystems during reboot
Date: Sun, 8 Jun 1997 15:09:17 +0200 (CEST)

 [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); \
 + }
 
 
 
 
 
 

From: Dirk Keunecke <dk@panda.rhein-main.de>
To: freebsd-gnats-submit@freebsd.org
Cc:  Subject: Re: kern/3571: Mounted ext2 prevents umount of filesystems during reboot
Date: Sat, 25 Apr 1998 19:15:46 +0200

 Can be closed. Fix seem to have made it into -current
State-Changed-From-To: open->closed 
State-Changed-By: steve 
State-Changed-When: Sat Apr 25 15:04:05 PDT 1998 
State-Changed-Why:  
Closed at originator's request. 
State-Changed-From-To: closed->suspended 
State-Changed-By: steve 
State-Changed-When: Sun Apr 26 20:30:24 PDT 1998 
State-Changed-Why:  
Bruce says this is still a problem in -stable.  Changed to 
feedback since this is a -current PR, but should be addressed 
in -stable as well. 
State-Changed-From-To: suspended->closed 
State-Changed-By: bde 
State-Changed-When: Mon Jan 10 22:24:54 PST 2000 
State-Changed-Why:  
Fixed in -stable when 3.0-current became stable. 
>Unformatted:
