diff -urN ref/fs/ext2/inode.c inode/fs/ext2/inode.c --- ref/fs/ext2/inode.c Fri Feb 11 00:05:36 2000 +++ inode/fs/ext2/inode.c Sun Feb 20 20:29:46 2000 @@ -35,7 +35,9 @@ */ void ext2_put_inode (struct inode * inode) { + lock_kernel(); ext2_discard_prealloc (inode); + unlock_kernel(); } /* @@ -43,6 +45,8 @@ */ void ext2_delete_inode (struct inode * inode) { + lock_kernel(); + if (is_bad_inode(inode) || inode->i_ino == EXT2_ACL_IDX_INO || inode->i_ino == EXT2_ACL_DATA_INO) @@ -54,6 +58,8 @@ if (inode->i_blocks) ext2_truncate (inode); ext2_free_inode (inode); + + unlock_kernel(); } #define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)])) @@ -893,7 +899,9 @@ void ext2_write_inode (struct inode * inode) { + lock_kernel(); ext2_update_inode (inode, 0); + unlock_kernel(); } int ext2_sync_inode (struct inode *inode) diff -urN ref/fs/inode.c inode/fs/inode.c --- ref/fs/inode.c Sun Feb 20 19:28:19 2000 +++ inode/fs/inode.c Sun Feb 20 21:31:15 2000 @@ -168,8 +168,10 @@ static inline void sync_one(struct inode *inode) { if (inode->i_state & I_LOCK) { + __iget(inode); spin_unlock(&inode_lock); __wait_on_inode(inode); + iput(inode); spin_lock(&inode_lock); } else { list_del(&inode->i_list); @@ -262,6 +264,8 @@ BUG(); if (!(inode->i_state & I_FREEING)) BUG(); + if (inode->i_state & I_CLEAR) + BUG(); wait_on_inode(inode); if (IS_QUOTAINIT(inode)) DQUOT_DROP(inode); @@ -271,7 +275,7 @@ bdput(inode->i_bdev); inode->i_bdev = NULL; } - inode->i_state = 0; + inode->i_state = I_CLEAR; } /* @@ -386,6 +390,8 @@ entry = entry->prev; inode = INODE(tmp); + if (inode->i_state & (I_FREEING|I_CLEAR)) + BUG(); if (!CAN_UNUSE(inode)) continue; if (inode->i_count) @@ -622,6 +628,11 @@ if (!(inode->i_state & I_FREEING)) __iget(inode); else + /* + * Handle the case where s_op->clear_inode is not been + * called yet, and somebody is calling igrab + * while the inode is getting freed. + */ inode = NULL; spin_unlock(&inode_lock); if (inode) @@ -688,32 +699,39 @@ list_del(&inode->i_list); INIT_LIST_HEAD(&inode->i_list); inode->i_state|=I_FREEING; + spin_unlock(&inode_lock); + + destroy = 1; if (op && op->delete_inode) { void (*delete)(struct inode *) = op->delete_inode; - spin_unlock(&inode_lock); if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); + /* s_op->delete_inode internally recalls clear_inode() */ delete(inode); - spin_lock(&inode_lock); - } - } - if (list_empty(&inode->i_hash)) { - list_del(&inode->i_list); - INIT_LIST_HEAD(&inode->i_list); - inode->i_state|=I_FREEING; - spin_unlock(&inode_lock); - clear_inode(inode); - destroy = 1; + } else + clear_inode(inode); + if (inode->i_state != I_CLEAR) + BUG(); + spin_lock(&inode_lock); - } - else - { - if (!(inode->i_state & I_DIRTY)) { + } else { + if (!list_empty(&inode->i_hash)) { + if (!(inode->i_state & I_DIRTY)) { + list_del(&inode->i_list); + list_add(&inode->i_list, + &inode_unused); + } + inodes_stat.nr_unused++; + } else { + /* magic nfs path */ list_del(&inode->i_list); - list_add(&inode->i_list, - &inode_unused); + INIT_LIST_HEAD(&inode->i_list); + inode->i_state|=I_FREEING; + spin_unlock(&inode_lock); + clear_inode(inode); + destroy = 1; + spin_lock(&inode_lock); } - inodes_stat.nr_unused++; } #ifdef INODE_PARANOIA if (inode->i_flock) diff -urN ref/fs/minix/inode.c inode/fs/minix/inode.c --- ref/fs/minix/inode.c Fri Feb 11 00:05:37 2000 +++ inode/fs/minix/inode.c Sun Feb 20 18:07:17 2000 @@ -35,9 +35,13 @@ static void minix_delete_inode(struct inode *inode) { + lock_kernel(); + inode->i_size = 0; minix_truncate(inode); minix_free_inode(inode); + + unlock_kernel(); } static void minix_commit_super(struct super_block * sb) @@ -1243,7 +1247,9 @@ { struct buffer_head *bh; + lock_kernel(); bh = minix_update_inode(inode); + unlock_kernel(); brelse(bh); } diff -urN ref/fs/nfs/inode.c inode/fs/nfs/inode.c --- ref/fs/nfs/inode.c Thu Feb 17 20:20:30 2000 +++ inode/fs/nfs/inode.c Sun Feb 20 19:34:14 2000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,7 @@ dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino); + lock_kernel(); if (S_ISDIR(inode->i_mode)) { nfs_free_dircache(inode); } else { @@ -129,6 +131,8 @@ if (failed) printk("NFS: inode %ld had %d failed requests\n", inode->i_ino, failed); + unlock_kernel(); + clear_inode(inode); } diff -urN ref/fs/proc/inode.c inode/fs/proc/inode.c --- ref/fs/proc/inode.c Wed Nov 24 18:22:06 1999 +++ inode/fs/proc/inode.c Sun Feb 20 21:28:55 2000 @@ -15,6 +15,7 @@ #include #define __NO_VERSION__ #include +#include #include #include @@ -34,6 +35,7 @@ void de_put(struct proc_dir_entry *de) { if (de) { + lock_kernel(); /* FIXME: count should be atomic_t */ if (!de->count) { printk("de_put: entry %s already free!\n", de->name); return; @@ -46,6 +48,7 @@ free_proc_entry(de); } } + unlock_kernel(); } } @@ -65,6 +68,8 @@ static void proc_delete_inode(struct inode *inode) { struct proc_dir_entry *de = inode->u.generic_ip; + + inode->i_state = I_CLEAR; if (PROC_INODE_PROPER(inode)) { proc_pid_delete_inode(inode); diff -urN ref/include/linux/fs.h inode/include/linux/fs.h --- ref/include/linux/fs.h Sun Feb 20 16:10:35 2000 +++ inode/include/linux/fs.h Sun Feb 20 20:29:17 2000 @@ -435,6 +435,7 @@ #define I_DIRTY 1 #define I_LOCK 2 #define I_FREEING 4 +#define I_CLEAR 8 extern void __mark_inode_dirty(struct inode *); static inline void mark_inode_dirty(struct inode *inode) @@ -676,6 +677,10 @@ int (*revalidate) (struct dentry *); }; +/* + * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called + * without the big kernel lock held in all filesystems. + */ struct super_operations { void (*read_inode) (struct inode *); void (*write_inode) (struct inode *);