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>
index | next in thread | previous in thread | raw e-mail
[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); \
+ }
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199706081309.PAA00289>
