[Devel] [PATCH RHEL8 COMMIT] fuse: Wait inflight requests only in case of close_wait
Konstantin Khorenko
khorenko at virtuozzo.com
Fri Apr 23 11:54:56 MSK 2021
The commit is pushed to "branch-rh8-4.18.0-240.1.1.vz8.5.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-240.1.1.vz8.5.19
------>
commit b76aad1dfda1beee8b415cc5c575c8259ad8c574
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date: Fri Apr 23 11:54:56 2021 +0300
fuse: Wait inflight requests only in case of close_wait
This idea came in process of porting below commits to rh7-3.10.0-1062.1.2.vz7.114:
ca507deff528 fuse: fix writeback/release race
9643b4a20fd6 fuse: fix erroneous unlock_page() in fuse_send_writepages()
-- fixup for previous commit (ca507deff528)
Both of them make close safe against pending writeback requests.
Before them __fuse_file_put() for final counter could occur after
file is closed, so BUG() used to fire.
Let's look at this from another side. The usage of writeback_cache
doesn't have to guarantee all pending requests are finished. It just
guarantees, write is cached and writeback is called, and this is
the way we have in ms. Waiting for all pending requests is needed
for vstorage only, but we never mount vstorage without close_wait
(see fuse_mount()). So, the case "!close_wait && writeback_cache"
is used by ordinary applications, which do not have any requirements
for close. Thus, we may restore ms behavior for this case and avoid
porting of these patches.
For branch-rh7-3.10.0-1062.1.2.vz7.114.x-ovz.
[Ildar Ismagilov: removed hack with insertion of dummy wpa, because the code
checking the fi->writepages for empty also removed from fuse_release()]
https://jira.sw.ru/browse/PSBM-98031
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
fs/fuse/file.c | 27 +++++----------------------
1 file changed, 5 insertions(+), 22 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 02f6a6eb2f29..441ca24fe356 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -437,9 +437,7 @@ static int fuse_release(struct inode *inode, struct file *file)
* it is safe, because we essentially wait only for writeback (and readahead)
* enqueued on this file and it is not going to get new one: it is closing.
*/
- if (!ff->fc->close_wait)
- wait_event(fi->page_waitq, RB_EMPTY_ROOT(&fi->writepages));
- else
+ if (ff->fc->close_wait)
wait_event(fi->page_waitq, refcount_read(&ff->count) == 1);
spin_lock(&fi->lock);
@@ -1886,7 +1884,7 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa)
for (i = 0; i < ap->num_pages; i++)
__free_page(ap->pages[i]);
- if (wpa->ia.ff && !fc->writeback_cache && !fc->close_wait)
+ if (wpa->ia.ff && !fc->close_wait)
fuse_file_put(wpa->ia.ff, false, false);
kfree(ap->pages);
@@ -1904,7 +1902,7 @@ static void fuse_writepage_finish(struct fuse_conn *fc,
if (!RB_EMPTY_NODE(&wpa->writepages_entry))
rb_erase(&wpa->writepages_entry, &fi->writepages);
- if (wpa->ia.ff && (fc->writeback_cache || fc->close_wait))
+ if (wpa->ia.ff && fc->close_wait)
__fuse_file_put(wpa->ia.ff);
for (i = 0; i < ap->num_pages; i++) {
dec_wb_stat(&bdi->wb, WB_WRITEBACK);
@@ -2026,24 +2024,11 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_args *args,
container_of(args, typeof(*wpa), ia.ap.args);
struct inode *inode = wpa->inode;
struct fuse_inode *fi = get_fuse_inode(inode);
- struct fuse_writepage_args dummy_wpa = {};
mapping_set_error(inode->i_mapping, error);
spin_lock(&fi->lock);
- if (wpa->next) {
- /*
- * The next wpa always intersect with current wap,
- * and to avoid BUG in the tree_insert() function we should first
- * remove the current wpa. And also we temprorary insert an dummy wpa
- * in order to the fi->writepages tree is not empty here
- * (this actual for fuse_release as example).
- */
- dummy_wpa.ia.write.in.offset = U64_MAX;
- dummy_wpa.ia.ap.num_pages = 1;
- tree_insert(&fi->writepages, &dummy_wpa);
- rb_erase(&wpa->writepages_entry, &fi->writepages);
- RB_CLEAR_NODE(&wpa->writepages_entry);
- }
+ rb_erase(&wpa->writepages_entry, &fi->writepages);
+ RB_CLEAR_NODE(&wpa->writepages_entry);
while (wpa->next) {
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_write_in *inarg = &wpa->ia.write.in;
@@ -2079,8 +2064,6 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_args *args,
*/
fuse_send_writepage(fc, next, inarg->offset + inarg->size);
}
- if (dummy_wpa.ia.ap.num_pages)
- rb_erase(&dummy_wpa.writepages_entry, &fi->writepages);
fi->writectr--;
fuse_writepage_finish(fc, wpa);
spin_unlock(&fi->lock);
More information about the Devel
mailing list