NFS: Fix nfs_file_llseek()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 23 Sep 2008 21:28:35 +0000 (17:28 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 7 Oct 2008 00:08:26 +0000 (20:08 -0400)
After the BKL removal patches were applied to the rest of the NFS code, the
BKL protection in nfs_file_llseek() is no longer sufficient to ensure that
inode->i_size is read safely in generic_file_llseek_unlocked().

In order to fix the situation, we either have to replace the naked read of
inode->i_size in generic_file_llseek_unlocked() with i_size_read(), or the
whole thing needs to be executed under the inode->i_lock;
In order to avoid disrupting other filesystems, avoid touching
generic_file_llseek_unlocked() for now...

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/file.c

index 7846065..3ddb004 100644 (file)
@@ -188,13 +188,16 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
        /* origin == SEEK_END => we must revalidate the cached file length */
        if (origin == SEEK_END) {
                struct inode *inode = filp->f_mapping->host;
+
                int retval = nfs_revalidate_file_size(inode, filp);
                if (retval < 0)
                        return (loff_t)retval;
-       }
-       lock_kernel();  /* BKL needed? */
-       loff = generic_file_llseek_unlocked(filp, offset, origin);
-       unlock_kernel();
+
+               spin_lock(&inode->i_lock);
+               loff = generic_file_llseek_unlocked(filp, offset, origin);
+               spin_unlock(&inode->i_lock);
+       } else
+               loff = generic_file_llseek_unlocked(filp, offset, origin);
        return loff;
 }