linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] fuse: invalidate inode pagecache when atomic_o_trunc flag is enabled
@ 2017-12-05 21:12 Chad Austin
  2018-02-08 14:17 ` Miklos Szeredi
  0 siblings, 1 reply; 3+ messages in thread
From: Chad Austin @ 2017-12-05 21:12 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-fsdevel, clm, chad, Chad Austin

When the atomic_o_trunc flag is set, fuse_do_setattr skips most of its
logic, including truncating the page cache.  Run the same invalidation
logic in fuse_finish_open when truncating.  This fixes a bug where
open(O_TRUNC) followed by a sequence of writes does not flush the page
cache, resulting in an mmap longer than the new file's length (from
another process) not properly zero-filling the last page.

Does fuse_finish_open() need additional locking?  I am not sure of the
locking requirements of truncate_pagecache or invalidate_inode_pages2.

The following C++ program reproduces the bug.  The FUSE daemon must
have enabled the ATOMIC_O_TRUNC flag
https://gist.github.com/chadaustin/8e4ba1e2cd2d023ff6f9eff921eb8bfc

Signed-off-by: Chad Austin <chadaustin@fb.com>
---
 fs/fuse/dir.c    |  7 ++-----
 fs/fuse/file.c   | 12 ++++++++++++
 fs/fuse/fuse_i.h |  2 ++
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 2496738..c387171 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1698,11 +1698,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
 	 * Only call invalidate_inode_pages2() after removing
 	 * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
 	 */
-	if ((is_truncate || !is_wb) &&
-	    S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
-		truncate_pagecache(inode, outarg.attr.size);
-		invalidate_inode_pages2(inode->i_mapping);
-	}
+	if ((is_truncate || !is_wb) && oldsize != outarg.attr.size)
+		fuse_truncate_inode_cache(inode, outarg.attr.size);
 
 	clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
 	return 0;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index cb7dff5..cb1968e 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -188,6 +188,10 @@ void fuse_finish_open(struct inode *inode, struct file *file)
 		i_size_write(inode, 0);
 		spin_unlock(&fc->lock);
 		fuse_invalidate_attr(inode);
+
+		if (!fc->writeback_cache)
+			fuse_truncate_inode_cache(inode, 0);
+
 		if (fc->writeback_cache)
 			file_update_time(file);
 	}
@@ -195,6 +199,14 @@ void fuse_finish_open(struct inode *inode, struct file *file)
 		fuse_link_write_file(file);
 }
 
+void fuse_truncate_inode_cache(struct inode *inode, loff_t newsize)
+{
+	if (S_ISREG(inode->i_mode)) {
+		truncate_pagecache(inode, newsize);
+		invalidate_inode_pages2(inode->i_mapping);
+	}
+}
+
 int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
 {
 	struct fuse_conn *fc = get_fuse_conn(inode);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d5773ca..47baea4 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -913,6 +913,8 @@ void fuse_release_nowrite(struct inode *inode);
 
 u64 fuse_get_attr_version(struct fuse_conn *fc);
 
+void fuse_truncate_inode_cache(struct inode *inode, loff_t newsize);
+
 /**
  * File-system tells the kernel to invalidate cache for the given node id.
  */
-- 
2.9.5

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] fuse: invalidate inode pagecache when atomic_o_trunc flag is enabled
  2017-12-05 21:12 [PATCH] fuse: invalidate inode pagecache when atomic_o_trunc flag is enabled Chad Austin
@ 2018-02-08 14:17 ` Miklos Szeredi
  2018-02-09 18:05   ` Chad Austin
  0 siblings, 1 reply; 3+ messages in thread
From: Miklos Szeredi @ 2018-02-08 14:17 UTC (permalink / raw)
  To: Chad Austin; +Cc: linux-fsdevel, Chris Mason, chad

[-- Attachment #1: Type: text/plain, Size: 1133 bytes --]

On Tue, Dec 5, 2017 at 10:12 PM, Chad Austin <chadaustin@fb.com> wrote:
> When the atomic_o_trunc flag is set, fuse_do_setattr skips most of its
> logic, including truncating the page cache.  Run the same invalidation
> logic in fuse_finish_open when truncating.  This fixes a bug where
> open(O_TRUNC) followed by a sequence of writes does not flush the page
> cache, resulting in an mmap longer than the new file's length (from
> another process) not properly zero-filling the last page.
>
> Does fuse_finish_open() need additional locking?  I am not sure of the
> locking requirements of truncate_pagecache or invalidate_inode_pages2.
>
> The following C++ program reproduces the bug.  The FUSE daemon must
> have enabled the ATOMIC_O_TRUNC flag
> https://gist.github.com/chadaustin/8e4ba1e2cd2d023ff6f9eff921eb8bfc

Thanks for the report and the patch.

Here's a simpler patch (we don't actually need the
invalidate_inode_pages2(), because all the pages have already been
truncated).

I tested it with your reproducer and it fixes the issue for me.

Unless you see a problem with it, I'll queue this up for 4.16.

Thanks,
Miklos

[-- Attachment #2: fuse-atomic_o_trunc-should-truncate-pagecache.patch --]
[-- Type: text/x-patch, Size: 447 bytes --]

---
 fs/fuse/dir.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1629,8 +1629,12 @@ int fuse_do_setattr(struct dentry *dentr
 		return err;
 
 	if (attr->ia_valid & ATTR_OPEN) {
-		if (fc->atomic_o_trunc)
+		if (fc->atomic_o_trunc) {
+			WARN_ON(!(attr->ia_valid & ATTR_SIZE));
+			WARN_ON(attr->ia_size != 0);
+			truncate_pagecache(inode, 0);
 			return 0;
+		}
 		file = NULL;
 	}
 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] fuse: invalidate inode pagecache when atomic_o_trunc flag is enabled
  2018-02-08 14:17 ` Miklos Szeredi
@ 2018-02-09 18:05   ` Chad Austin
  0 siblings, 0 replies; 3+ messages in thread
From: Chad Austin @ 2018-02-09 18:05 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Chad Austin, linux-fsdevel, Chris Mason, chad

On Thu, Feb 8, 2018 at 6:17 AM, Miklos Szeredi <miklos@szeredi.hu> wrote:
> Thanks for the report and the patch.
>
> Here's a simpler patch (we don't actually need the
> invalidate_inode_pages2(), because all the pages have already been
> truncated).
>
> I tested it with your reproducer and it fixes the issue for me.
>
> Unless you see a problem with it, I'll queue this up for 4.16.

Thanks!  I verified that your simpler patch also fixes our more
complex internal reproduction.  Looking forward to it landing!

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-02-09 18:05 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-05 21:12 [PATCH] fuse: invalidate inode pagecache when atomic_o_trunc flag is enabled Chad Austin
2018-02-08 14:17 ` Miklos Szeredi
2018-02-09 18:05   ` Chad Austin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).