All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brian Foster <bfoster@redhat.com>
To: Maxim Patlasov <MPatlasov@parallels.com>
Cc: miklos@szeredi.hu, fuse-devel@lists.sourceforge.net,
	xemul@parallels.com, linux-kernel@vger.kernel.org,
	devel@openvz.org
Subject: Re: [PATCH 2/2] fuse: wait for writeback in fuse_file_fallocate() -v2
Date: Fri, 23 Aug 2013 09:02:56 -0400	[thread overview]
Message-ID: <52175D80.8060509@redhat.com> (raw)
In-Reply-To: <20130816112854.5630.1907.stgit@maximpc.sw.ru>

On 08/16/2013 07:30 AM, Maxim Patlasov wrote:
> The patch fixes a race between mmap-ed write and fallocate(PUNCH_HOLE):
> 
> 1) An user makes a page dirty via mmap-ed write.
> 2) The user performs fallocate(2) with mode == PUNCH_HOLE|KEEP_SIZE
>    and <offset, size> covering the page.
> 3) Before truncate_pagecache_range call from fuse_file_fallocate,
>    the page goes to write-back. The page is fully processed by fuse_writepage
>    (including end_page_writeback on the page), but fuse_flush_writepages did
>    nothing because fi->writectr < 0.
> 4) truncate_pagecache_range is called and fuse_file_fallocate is finishing
>    by calling fuse_release_nowrite. The latter triggers processing queued
>    write-back request which will write stale data to the hole soon.
> 
> Changed in v2 (thanks to Brian for suggestion):
>  - Do not truncate page cache until FUSE_FALLOCATE succeeded. Otherwise,
>    we can end up in returning -ENOTSUPP while user data is already punched
>    from page cache. Use filemap_write_and_wait_range() instead.
> 
> Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
> ---

Looks good to me, thanks Maxim.

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/fuse/file.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 48 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index d1715b3..e88ba8b 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -344,6 +344,31 @@ static bool fuse_page_is_writeback(struct inode *inode, pgoff_t index)
>  	return found;
>  }
>  
> +static bool fuse_range_is_writeback(struct inode *inode, pgoff_t idx_from,
> +				    pgoff_t idx_to)
> +{
> +	struct fuse_conn *fc = get_fuse_conn(inode);
> +	struct fuse_inode *fi = get_fuse_inode(inode);
> +	struct fuse_req *req;
> +	bool found = false;
> +
> +	spin_lock(&fc->lock);
> +	list_for_each_entry(req, &fi->writepages, writepages_entry) {
> +		pgoff_t curr_index;
> +
> +		BUG_ON(req->inode != inode);
> +		curr_index = req->misc.write.in.offset >> PAGE_CACHE_SHIFT;
> +		if (!(idx_from >= curr_index + req->num_pages ||
> +		      idx_to < curr_index)) {
> +			found = true;
> +			break;
> +		}
> +	}
> +	spin_unlock(&fc->lock);
> +
> +	return found;
> +}
> +
>  /*
>   * Wait for page writeback to be completed.
>   *
> @@ -358,6 +383,19 @@ static int fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index)
>  	return 0;
>  }
>  
> +static void fuse_wait_on_writeback(struct inode *inode, pgoff_t start,
> +				   size_t bytes)
> +{
> +	struct fuse_inode *fi = get_fuse_inode(inode);
> +	pgoff_t idx_from, idx_to;
> +
> +	idx_from = start >> PAGE_CACHE_SHIFT;
> +	idx_to = (start + bytes - 1) >> PAGE_CACHE_SHIFT;
> +
> +	wait_event(fi->page_waitq,
> +		   !fuse_range_is_writeback(inode, idx_from, idx_to));
> +}
> +
>  static int fuse_flush(struct file *file, fl_owner_t id)
>  {
>  	struct inode *inode = file_inode(file);
> @@ -2478,8 +2516,15 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
>  
>  	if (lock_inode) {
>  		mutex_lock(&inode->i_mutex);
> -		if (mode & FALLOC_FL_PUNCH_HOLE)
> -			fuse_set_nowrite(inode);
> +		if (mode & FALLOC_FL_PUNCH_HOLE) {
> +			loff_t endbyte = offset + length - 1;
> +			err = filemap_write_and_wait_range(inode->i_mapping,
> +							   offset, endbyte);
> +			if (err)
> +				goto out;
> +
> +			fuse_wait_on_writeback(inode, offset, length);
> +		}
>  	}
>  
>  	req = fuse_get_req_nopages(fc);
> @@ -2514,11 +2559,8 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
>  	fuse_invalidate_attr(inode);
>  
>  out:
> -	if (lock_inode) {
> -		if (mode & FALLOC_FL_PUNCH_HOLE)
> -			fuse_release_nowrite(inode);
> +	if (lock_inode)
>  		mutex_unlock(&inode->i_mutex);
> -	}
>  
>  	return err;
>  }
> 


  reply	other threads:[~2013-08-23 13:06 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-12 16:39 [PATCH 0/2] fuse: fix races related to fuse writeback Maxim Patlasov
2013-08-12 16:39 ` [PATCH 1/2] fuse: postpone end_page_writeback() in fuse_writepage_locked() Maxim Patlasov
2013-08-29 16:27   ` Miklos Szeredi
2013-08-12 16:39 ` [PATCH 2/2] fuse: wait for writeback in fuse_file_fallocate() Maxim Patlasov
2013-08-13 12:05   ` Brian Foster
2013-08-13 12:56     ` Maxim Patlasov
2013-08-13 13:23       ` Brian Foster
2013-08-13 13:45         ` Maxim Patlasov
2013-08-16 11:30   ` [PATCH 2/2] fuse: wait for writeback in fuse_file_fallocate() -v2 Maxim Patlasov
2013-08-23 13:02     ` Brian Foster [this message]
2013-08-29 15:41     ` Miklos Szeredi
2013-08-29 16:27       ` Maxim Patlasov
2013-08-29 16:37         ` Miklos Szeredi
2013-08-29 16:41           ` Miklos Szeredi
2013-08-30  9:13             ` Miklos Szeredi
2013-08-30 11:33               ` Maxim Patlasov
2013-09-11 10:12                 ` Miklos Szeredi
2013-09-11 12:21                   ` Maxim Patlasov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=52175D80.8060509@redhat.com \
    --to=bfoster@redhat.com \
    --cc=MPatlasov@parallels.com \
    --cc=devel@openvz.org \
    --cc=fuse-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=xemul@parallels.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.