From 5fd549b62eeb2d34acff683fceabcc532ea7eb4a Mon Sep 17 00:00:00 2001 From: John Dyson Date: Mon, 4 Aug 1997 05:10:31 +0000 Subject: [PATCH] Fix a problem with ext2fs so that filesystems mounted at reboot don't keep ahold of buffers, and therefore leave filesystems dirty. I haven't been able to test, but the code compiles. Those who run -current, please test and report back!!! (Sorry :-)). PR: kern/3571 Submitted by: Dirk Keunecke --- sys/gnu/ext2fs/ext2_linux_balloc.c | 4 +++- sys/gnu/ext2fs/ext2_linux_ialloc.c | 3 ++- sys/gnu/ext2fs/ext2_vfsops.c | 30 ++++++++++++--------------- sys/gnu/ext2fs/fs.h | 20 ++++++++++++++++++ sys/gnu/fs/ext2fs/ext2_linux_balloc.c | 4 +++- sys/gnu/fs/ext2fs/ext2_linux_ialloc.c | 3 ++- sys/gnu/fs/ext2fs/ext2_vfsops.c | 30 ++++++++++++--------------- sys/gnu/fs/ext2fs/fs.h | 20 ++++++++++++++++++ 8 files changed, 76 insertions(+), 38 deletions(-) diff --git a/sys/gnu/ext2fs/ext2_linux_balloc.c b/sys/gnu/ext2fs/ext2_linux_balloc.c index e0c955a150dc..aa1765028ccf 100644 --- a/sys/gnu/ext2fs/ext2_linux_balloc.c +++ b/sys/gnu/ext2fs/ext2_linux_balloc.c @@ -69,6 +69,7 @@ static void read_block_bitmap (struct mount * mp, 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) } /* @@ -129,7 +130,8 @@ static int load__block_bitmap (struct mount * mp, 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]); + 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]; diff --git a/sys/gnu/ext2fs/ext2_linux_ialloc.c b/sys/gnu/ext2fs/ext2_linux_ialloc.c index c93c20e6cd98..9f2a967f47c6 100644 --- a/sys/gnu/ext2fs/ext2_linux_ialloc.c +++ b/sys/gnu/ext2fs/ext2_linux_ialloc.c @@ -127,6 +127,7 @@ static void read_inode_bitmap (struct mount * mp, 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) } /* @@ -190,7 +191,7 @@ static int load_inode_bitmap (struct mount * mp, 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]); + 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]; diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c index b56ed976dbd9..253d0e54dde4 100644 --- a/sys/gnu/ext2fs/ext2_vfsops.c +++ b/sys/gnu/ext2fs/ext2_vfsops.c @@ -412,10 +412,12 @@ static int compute_sb_data(devvp, es, fs) 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++) - brelse(fs->s_group_desc[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"); @@ -691,16 +693,19 @@ ext2_unmount(mp, mntflags, p) 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]); + 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]) - brelse (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]) - brelse (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, @@ -1106,20 +1111,11 @@ printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no"); 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: + /* + * 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 */ - 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); } diff --git a/sys/gnu/ext2fs/fs.h b/sys/gnu/ext2fs/fs.h index 03f137c854c8..3cb4fc0095d1 100644 --- a/sys/gnu/ext2fs/fs.h +++ b/sys/gnu/ext2fs/fs.h @@ -155,3 +155,23 @@ extern u_char *fragtbl[]; #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); \ +} diff --git a/sys/gnu/fs/ext2fs/ext2_linux_balloc.c b/sys/gnu/fs/ext2fs/ext2_linux_balloc.c index e0c955a150dc..aa1765028ccf 100644 --- a/sys/gnu/fs/ext2fs/ext2_linux_balloc.c +++ b/sys/gnu/fs/ext2fs/ext2_linux_balloc.c @@ -69,6 +69,7 @@ static void read_block_bitmap (struct mount * mp, 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) } /* @@ -129,7 +130,8 @@ static int load__block_bitmap (struct mount * mp, 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]); + 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]; diff --git a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c index c93c20e6cd98..9f2a967f47c6 100644 --- a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c +++ b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c @@ -127,6 +127,7 @@ static void read_inode_bitmap (struct mount * mp, 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) } /* @@ -190,7 +191,7 @@ static int load_inode_bitmap (struct mount * mp, 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]); + 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]; diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c index b56ed976dbd9..253d0e54dde4 100644 --- a/sys/gnu/fs/ext2fs/ext2_vfsops.c +++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c @@ -412,10 +412,12 @@ static int compute_sb_data(devvp, es, fs) 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++) - brelse(fs->s_group_desc[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"); @@ -691,16 +693,19 @@ ext2_unmount(mp, mntflags, p) 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]); + 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]) - brelse (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]) - brelse (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, @@ -1106,20 +1111,11 @@ printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no"); 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: + /* + * 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 */ - 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); } diff --git a/sys/gnu/fs/ext2fs/fs.h b/sys/gnu/fs/ext2fs/fs.h index 03f137c854c8..3cb4fc0095d1 100644 --- a/sys/gnu/fs/ext2fs/fs.h +++ b/sys/gnu/fs/ext2fs/fs.h @@ -155,3 +155,23 @@ extern u_char *fragtbl[]; #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); \ +}