From: Maxim Patlasov <mpatlasov@parallels.com>
To: miklos@szeredi.hu
Cc: dev@parallels.com, xemul@parallels.com,
fuse-devel@lists.sourceforge.net, bfoster@redhat.com,
linux-kernel@vger.kernel.org, devel@openvz.org,
anand.avati@gmail.com
Subject: [PATCH 3/5] fuse: wait for end of IO on release
Date: Thu, 20 Dec 2012 16:31:59 +0400 [thread overview]
Message-ID: <20121220123144.4101.84499.stgit@maximpc.sw.ru> (raw)
In-Reply-To: <20121220122702.4101.80042.stgit@maximpc.sw.ru>
There are two types of I/O activity that can be "in progress" at the time
of fuse_release() execution: asynchronous read-ahead and write-back. The
patch ensures that they are completed before fuse_release_common sends
FUSE_RELEASE to userspace.
So far as fuse_release() waits for end of async I/O, its callbacks
(fuse_readpages_end and fuse_writepage_finish) calling fuse_file_put cannot
be the last holders of fuse file anymore. To emphasize the fact, the patch
replaces fuse_file_put with __fuse_file_put there.
Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
---
fs/fuse/file.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 4f23134..aed9be2 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -137,6 +137,12 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
}
}
+static void __fuse_file_put(struct fuse_file *ff)
+{
+ if (atomic_dec_and_test(&ff->count))
+ BUG();
+}
+
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
bool isdir)
{
@@ -260,7 +266,12 @@ void fuse_release_common(struct file *file, int opcode)
* Make the release synchronous if this is a fuseblk mount,
* synchronous RELEASE is allowed (and desirable) in this case
* because the server can be trusted not to screw up.
+ *
+ * We might wait for them (asynchronous READ or WRITE requests), so:
*/
+ if (ff->fc->close_wait)
+ BUG_ON(atomic_read(&ff->count) != 1);
+
fuse_file_put(ff, ff->fc->destroy_req != NULL);
}
@@ -271,6 +282,31 @@ static int fuse_open(struct inode *inode, struct file *file)
static int fuse_release(struct inode *inode, struct file *file)
{
+ struct fuse_file *ff = file->private_data;
+
+ if (ff->fc->close_wait) {
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ /*
+ * Must remove file from write list. Otherwise it is possible
+ * this file will get more writeback from another files
+ * rerouted via write_files.
+ */
+ spin_lock(&ff->fc->lock);
+ list_del_init(&ff->write_entry);
+ spin_unlock(&ff->fc->lock);
+
+ wait_event(fi->page_waitq, atomic_read(&ff->count) == 1);
+
+ /*
+ * Wait for threads just released ff to leave their critical
+ * sections. Taking spinlock is the first thing
+ * fuse_release_common does, so that this is unnecessary, but
+ * it is still good to emphasize right here, that we need this.
+ */
+ spin_unlock_wait(&ff->fc->lock);
+ }
+
fuse_release_common(file, FUSE_RELEASE);
/* return value is ignored by VFS */
@@ -610,8 +646,17 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
unlock_page(page);
page_cache_release(page);
}
- if (req->ff)
- fuse_file_put(req->ff, false);
+ if (req->ff) {
+ if (fc->close_wait) {
+ struct fuse_inode *fi = get_fuse_inode(req->inode);
+
+ spin_lock(&fc->lock);
+ __fuse_file_put(req->ff);
+ wake_up(&fi->page_waitq);
+ spin_unlock(&fc->lock);
+ } else
+ fuse_file_put(req->ff, false);
+ }
}
struct fuse_fill_data {
@@ -637,6 +682,7 @@ static void fuse_send_readpages(struct fuse_fill_data *data)
if (fc->async_read) {
req->ff = fuse_file_get(ff);
req->end = fuse_readpages_end;
+ req->inode = data->inode;
fuse_request_send_background(fc, req);
} else {
fuse_request_send(fc, req);
@@ -1178,7 +1224,8 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req)
{
__free_page(req->pages[0]);
- fuse_file_put(req->ff, false);
+ if (!fc->close_wait)
+ fuse_file_put(req->ff, false);
}
static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
@@ -1191,6 +1238,8 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
dec_bdi_stat(bdi, BDI_WRITEBACK);
dec_zone_page_state(req->pages[0], NR_WRITEBACK_TEMP);
bdi_writeout_inc(bdi);
+ if (fc->close_wait)
+ __fuse_file_put(req->ff);
wake_up(&fi->page_waitq);
}
next prev parent reply other threads:[~2012-12-20 12:32 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-12-20 12:30 [PATCH 0/5] fuse: close file synchronously Maxim Patlasov
2012-12-20 12:31 ` [PATCH 1/5] fuse: add close_wait flag to fuse_conn Maxim Patlasov
2012-12-20 12:31 ` [PATCH 2/5] fuse: cosmetic rework of fuse_send_readpages Maxim Patlasov
2012-12-20 12:31 ` Maxim Patlasov [this message]
2013-01-02 20:35 ` [PATCH 3/5] fuse: wait for end of IO on release Brian Foster
2013-01-15 14:04 ` Maxim V. Patlasov
2013-01-15 15:02 ` [PATCH] fuse: wait for end of IO on release (v2) Maxim Patlasov
2012-12-20 12:32 ` [PATCH 4/5] fuse: enable close_wait feature Maxim Patlasov
2013-01-15 15:07 ` [PATCH] fuse: enable close_wait feature (v2) Maxim Patlasov
2012-12-20 12:32 ` [PATCH 5/5] fuse: fix synchronous case of fuse_file_put() Maxim Patlasov
2013-04-11 11:21 ` [fuse-devel] [PATCH 0/5] fuse: close file synchronously Maxim V. Patlasov
2013-04-15 15:08 ` Miklos Szeredi
2013-04-15 15:30 ` Miklos Szeredi
2013-04-15 18:17 ` Al Viro
2013-04-16 9:09 ` Miklos Szeredi
2013-04-17 20:53 ` Miklos Szeredi
2013-04-18 3:25 ` Maxim Patlasov
2013-04-16 18:13 ` Maxim Patlasov
-- strict thread matches above, loose matches on Subject: below --
2014-06-06 13:27 [PATCH 0/5] fuse: close file synchronously (v2) Maxim Patlasov
2014-06-06 13:29 ` [PATCH 3/5] fuse: wait for end of IO on release Maxim Patlasov
2014-09-25 12:05 [PATCH 0/5] fuse: handle release synchronously (v4) Maxim Patlasov
2014-09-25 12:06 ` [PATCH 3/5] fuse: wait for end of IO on release 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=20121220123144.4101.84499.stgit@maximpc.sw.ru \
--to=mpatlasov@parallels.com \
--cc=anand.avati@gmail.com \
--cc=bfoster@redhat.com \
--cc=dev@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.