Pavel writes:
> [I'd really like to get patch it; killing user's data without good
> reason seems evil to me, and this did quite a lot of damage to my
> $HOME.]
> 
>                                                               Pavel
> PS: Only filesystem at use at time of problem was ext2, and it was
> ext2 iinode that got killed.

However, since make_bad_inode() only changes the file methods and not
the superblock, any of the put_inode(), delete_inode(), or write_inode()
methods can still be called.  While the write_inode() call is safe to
block in the VFS, I don't think it is safe to block *_put_inode() and
*_delete_inode() in the VFS because the filesystem may have allocated
memory or other things that need to be undone even for bad inodes.

The following patch fixes the VFS write_inode() (per Pavel's patch),
and ext2_put_inode(), bfs_delete_inode(), and udf_put_inode() to not
do anything with bad inodes.  I have bailed (with a FIXME) on
hpfs_delete_inode() and smb_delete_inode(), because I don't know what
(if anything) needs to be done to correctly clean up a bad inode.

I will post a patch separately which handles a couple of cases where
*_delete_inode() does not call clear_inode() in all cases.

Cheers, Andreas
=======================================================================
diff -ru linux-2.4.4p1.orig/fs/inode.c linux/fs/inode.c
--- linux-2.4.4p1.orig/fs/inode.c       Tue Apr 10 16:44:49 2001
+++ linux/fs/inode.c    Fri Apr 27 13:05:04 2001
@@ -179,6 +181,12 @@
 
 static inline void write_inode(struct inode *inode, int sync)
 {
+       if (is_bad_inode(inode)) {
+               printk(KERN_CRIT "Cowardly refusing to write bad inode %s:%d\n",+      
+                kdevname(inode->i_dev), inode->i_ino);
+               return;
+       }
+
        if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
                inode->i_sb->s_op->write_inode(inode, sync);
 }
diff -ru linux-2.4.4p1.orig/fs/ext2/inode.c linux/fs/ext2/inode.c
--- linux-2.4.4p1.orig/fs/ext2/inode.c  Tue Apr 10 16:44:49 2001
+++ linux/fs/ext2/inode.c       Fri Apr 27 13:51:15 2001
@@ -36,6 +36,9 @@
  */
 void ext2_put_inode (struct inode * inode)
 {
+       if (is_bad_inode(inode))
+               return;
+
        ext2_discard_prealloc (inode);
 }
 
diff -ru linux-2.4.4p1.orig/fs/bfs/inode.c linux/fs/bfs/inode.c
--- linux-2.4.4p1.orig/fs/bfs/inode.c   Tue Apr 10 16:44:49 2001
+++ linux/fs/bfs/inode.c        Fri Apr 27 15:45:31 2001
@@ -142,7 +142,8 @@
 
        dprintf("ino=%08lx\n", inode->i_ino);
 
-       if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > inode->i_sb->su_lasti) {
+       if (is_bad_inode(inode) || inode->i_ino < BFS_ROOT_INO ||
+           inode->i_ino > inode->i_sb->su_lasti) {
                printf("invalid ino=%08lx\n", inode->i_ino);
                return;
        }
diff -ru linux-2.4.4p1.orig/fs/udf/inode.c linux/fs/udf/inode.c
--- linux-2.4.4p1.orig/fs/udf/inode.c   Tue Apr 10 16:41:51 2001
+++ linux/fs/udf/inode.c        Fri Apr 27 14:03:49 2001
@@ -74,7 +74,7 @@
  */
 void udf_put_inode(struct inode * inode)
 {
-       if (!(inode->i_sb->s_flags & MS_RDONLY))
+       if (!(inode->i_sb->s_flags & MS_RDONLY) && !is_bad_inode(inode))
        {
                lock_kernel();
                udf_discard_prealloc(inode);
diff -ru linux-2.4.4p1.orig/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- linux-2.4.4p1.orig/fs/hpfs/inode.c  Tue Apr 10 16:41:50 2001
+++ linux/fs/hpfs/inode.c       Fri Apr 27 13:57:12 2001
@@ -316,6 +304,7 @@
 
 void hpfs_delete_inode(struct inode *inode)
 {
+       /* FIXME: handle is_bad_inode??? */
        lock_kernel();
        hpfs_remove_fnode(inode->i_sb, inode->i_ino);
        unlock_kernel();
diff -ru linux-2.4.4p1.orig/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- linux-2.4.4p1.orig/fs/smbfs/inode.c Tue Apr 10 16:44:54 2001
+++ linux/fs/smbfs/inode.c      Fri Apr 27 14:01:33 2001
@@ -254,6 +254,7 @@
 smb_delete_inode(struct inode *ino)
 {
        DEBUG1("ino=%ld\n", ino->i_ino);
+       /* FIXME: handle is_bad_inode() case??? */
        lock_kernel();
        if (smb_close(ino))
                PARANOIA("could not close inode %ld\n", ino->i_ino);
-- 
Andreas Dilger                               TurboLabs filesystem development
http://sourceforge.net/projects/ext2resize/
http://www-mddsp.enel.ucalgary.ca/People/adilger/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to