[PATCH] fuse: fix hang on SMP

Fuse didn't always call i_size_write() with i_mutex held which caused rare
hangs on SMP/32bit.  This bug has been present since fuse-2.2, well before
being merged into mainline.

The simplest solution is to protect i_size_write() with the per-connection
spinlock.  Using i_mutex for this purpose would require some restructuring of
the code and I'm not even sure it's always safe to acquire i_mutex in all
places i_size needs to be set.

Since most of vmtruncate is already duplicated for other reasons, duplicate
the remaining part as well, making all i_size_write() calls internal to fuse.

Using i_size_write() was unnecessary in fuse_init_inode(), since this function
is only called on a newly created locked inode.

Reported by a few people over the years, but special thanks to Dana Henriksen
who was persistent enough in helping me debug it.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
このコミットが含まれているのは:
Miklos Szeredi
2006-10-17 00:10:06 -07:00
committed by Linus Torvalds
コミット 9ffbb91623
3個のファイルの変更34行の追加13行の削除

ファイルの表示

@@ -481,8 +481,10 @@ static int fuse_commit_write(struct file *file, struct page *page,
err = -EIO;
if (!err) {
pos += count;
if (pos > i_size_read(inode))
spin_lock(&fc->lock);
if (pos > inode->i_size)
i_size_write(inode, pos);
spin_unlock(&fc->lock);
if (offset == 0 && to == PAGE_CACHE_SIZE) {
clear_page_dirty(page);
@@ -586,8 +588,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
}
fuse_put_request(fc, req);
if (res > 0) {
if (write && pos > i_size_read(inode))
i_size_write(inode, pos);
if (write) {
spin_lock(&fc->lock);
if (pos > inode->i_size)
i_size_write(inode, pos);
spin_unlock(&fc->lock);
}
*ppos = pos;
}
fuse_invalidate_attr(inode);