]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.10.16/fuse-fix-fallocate-vs.-ftruncate-race.patch
Linux 4.14.95
[thirdparty/kernel/stable-queue.git] / releases / 3.10.16 / fuse-fix-fallocate-vs.-ftruncate-race.patch
CommitLineData
c430f7d2
GKH
1From 0ab08f576b9e6a6b689fc6b4e632079b978e619b Mon Sep 17 00:00:00 2001
2From: Maxim Patlasov <MPatlasov@parallels.com>
3Date: Fri, 13 Sep 2013 19:20:16 +0400
4Subject: fuse: fix fallocate vs. ftruncate race
5
6From: Maxim Patlasov <MPatlasov@parallels.com>
7
8commit 0ab08f576b9e6a6b689fc6b4e632079b978e619b upstream.
9
10A former patch introducing FUSE_I_SIZE_UNSTABLE flag provided detailed
11description of races between ftruncate and anyone who can extend i_size:
12
13> 1. As in the previous scenario fuse_dentry_revalidate() discovered that i_size
14> changed (due to our own fuse_do_setattr()) and is going to call
15> truncate_pagecache() for some 'new_size' it believes valid right now. But by
16> the time that particular truncate_pagecache() is called ...
17> 2. fuse_do_setattr() returns (either having called truncate_pagecache() or
18> not -- it doesn't matter).
19> 3. The file is extended either by write(2) or ftruncate(2) or fallocate(2).
20> 4. mmap-ed write makes a page in the extended region dirty.
21
22This patch adds necessary bits to fuse_file_fallocate() to protect from that
23race.
24
25Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
26Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
27Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
28
29---
30 fs/fuse/file.c | 7 +++++++
31 1 file changed, 7 insertions(+)
32
33--- a/fs/fuse/file.c
34+++ b/fs/fuse/file.c
35@@ -2468,6 +2468,7 @@ static long fuse_file_fallocate(struct f
36 {
37 struct fuse_file *ff = file->private_data;
38 struct inode *inode = file->f_inode;
39+ struct fuse_inode *fi = get_fuse_inode(inode);
40 struct fuse_conn *fc = ff->fc;
41 struct fuse_req *req;
42 struct fuse_fallocate_in inarg = {
43@@ -2496,6 +2497,9 @@ static long fuse_file_fallocate(struct f
44 }
45 }
46
47+ if (!(mode & FALLOC_FL_KEEP_SIZE))
48+ set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
49+
50 req = fuse_get_req_nopages(fc);
51 if (IS_ERR(req)) {
52 err = PTR_ERR(req);
53@@ -2528,6 +2532,9 @@ static long fuse_file_fallocate(struct f
54 fuse_invalidate_attr(inode);
55
56 out:
57+ if (!(mode & FALLOC_FL_KEEP_SIZE))
58+ clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
59+
60 if (lock_inode)
61 mutex_unlock(&inode->i_mutex);
62