<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;
        mso-fareast-language:EN-US;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri",sans-serif;
        mso-fareast-language:EN-US;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style>
</head>
<body lang="EN-SG" link="#0563C1" vlink="#954F72" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">There are many places where it is critical to know if invalidate files<o:p></o:p></p>
<p class="MsoNormal">operation is in progress, otherwise deadlock would happen. Currently<o:p></o:p></p>
<p class="MsoNormal">this can be done by checking the FUSE_S_FAIL_IMMEDIATELY flag bit from<o:p></o:p></p>
<p class="MsoNormal">fuse_file state. However this is inconvenient in case where a fuse_file<o:p></o:p></p>
<p class="MsoNormal">is not directly available, for example in fuse_writepages(), where it<o:p></o:p></p>
<p class="MsoNormal">has to be done by indirectly checking the fuse_files in fi->rw_files via<o:p></o:p></p>
<p class="MsoNormal">piece of code like this:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> spin_lock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal"> if (!list_empty(&fi->rw_files)) {<o:p></o:p></p>
<p class="MsoNormal"> struct fuse_file *ff = list_entry(fi->rw_files.next,<o:p></o:p></p>
<p class="MsoNormal"> struct fuse_file, rw_entry);<o:p></o:p></p>
<p class="MsoNormal"> if (!test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state))<o:p></o:p></p>
<p class="MsoNormal"> blocked = true;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal"> spin_unlock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Apparently above piece of code is too heavy for just checking whether we<o:p></o:p></p>
<p class="MsoNormal">are in a particular state. However it can be easily solved by add a new<o:p></o:p></p>
<p class="MsoNormal">state flag bit to fuse inode state. With this newly added flag bit, we<o:p></o:p></p>
<p class="MsoNormal">can greatly simplify code in following scenario:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">1. Replace above mentioned code with following just a single line of code<o:p></o:p></p>
<p class="MsoNormal"> in places where only the 'inode' parameters is directly available.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> test_bit(FUSE_I_INVAL_FILES, &get_fuse_inode(inode)->state)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">2. We can make fuse_range_is_writeback() return false if invalidate files<o:p></o:p></p>
<p class="MsoNormal"> operation is in progress. This makes sense in that page cache will be<o:p></o:p></p>
<p class="MsoNormal"> invalidated and all pending page write will be discarded anyway once<o:p></o:p></p>
<p class="MsoNormal"> invalidate files operation starts. This is critical for avoidng deadlock<o:p></o:p></p>
<p class="MsoNormal"> in places where fuse_wait_on_page_writeback() is needed, and we don't<o:p></o:p></p>
<p class="MsoNormal"> have to use the variant fuse_wait_on_page_writeback_or_invalidate(),<o:p></o:p></p>
<p class="MsoNormal"> because fuse_wait_on_page_writeback() can now be woken up by<o:p></o:p></p>
<p class="MsoNormal"> fuse_notify_inval_files().<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> Another benefit is we can guarante fuse_launder_page() always returns<o:p></o:p></p>
<p class="MsoNormal"> success in case invalidate files is in progress.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">3. The fuse_dummy_writpage() case can be merged into fuse_writepages_fill()<o:p></o:p></p>
<p class="MsoNormal"> by simply adding the following check at the begining of fuse_writepages_fill()<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> if (!wpa && test_bit(FUSE_I_INVAL_FILES, &fi->state)) {<o:p></o:p></p>
<p class="MsoNormal"> unlock_page(page);<o:p></o:p></p>
<p class="MsoNormal"> return 0;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> This makes sure that fuse_writepages() returns immediately when it is called via<o:p></o:p></p>
<p class="MsoNormal"> fuse_notify_inval_files(), which is essentially what fuse_dummy_writpage() does.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> Additionaly,it also can make fuse_writepages() returns faster if it was initiated<o:p></o:p></p>
<p class="MsoNormal"> by others and still in the middle of write_cache_pages() when invalidate files<o:p></o:p></p>
<p class="MsoNormal"> operation started.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Signed-off-by: Liu Kui <Kui.Liu@acronis.com><o:p></o:p></p>
<p class="MsoNormal">---<o:p></o:p></p>
<p class="MsoNormal">fs/fuse/file.c | 111 ++++++++++++++++-------------------------------<o:p></o:p></p>
<p class="MsoNormal">fs/fuse/fuse_i.h | 12 +++++<o:p></o:p></p>
<p class="MsoNormal">fs/fuse/inode.c | 5 +++<o:p></o:p></p>
<p class="MsoNormal">3 files changed, 55 insertions(+), 73 deletions(-)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">diff --git a/fs/fuse/file.c b/fs/fuse/file.c<o:p></o:p></p>
<p class="MsoNormal">index 1cce68a2feb5..e666c660ef1c 100644<o:p></o:p></p>
<p class="MsoNormal">--- a/fs/fuse/file.c<o:p></o:p></p>
<p class="MsoNormal">+++ b/fs/fuse/file.c<o:p></o:p></p>
<p class="MsoNormal">@@ -586,6 +586,16 @@ static bool fuse_range_is_writeback(struct inode *inode, pgoff_t idx_from,<o:p></o:p></p>
<p class="MsoNormal"> found = fuse_find_writeback(fi, idx_from, idx_to);<o:p></o:p></p>
<p class="MsoNormal"> spin_unlock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">+ /*<o:p></o:p></p>
<p class="MsoNormal">+ * Return false if invalidate files is in progress, which makes<o:p></o:p></p>
<p class="MsoNormal">+ * sense in that page cache will be invalidated and all pending<o:p></o:p></p>
<p class="MsoNormal">+ * write requests will be discarded anyway.<o:p></o:p></p>
<p class="MsoNormal">+ *<o:p></o:p></p>
<p class="MsoNormal">+ * This can make fuse_wait_on_page_writeback() return when<o:p></o:p></p>
<p class="MsoNormal">+ * FUSE_NOTIFY_INVAL_FILES is in progress.<o:p></o:p></p>
<p class="MsoNormal">+ */<o:p></o:p></p>
<p class="MsoNormal">+ found = found && !test_bit(FUSE_I_INVAL_FILES, &fi->state);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> return found;<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">@@ -607,20 +617,6 @@ static void fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index)<o:p></o:p></p>
<p class="MsoNormal"> wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index));<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">-/*<o:p></o:p></p>
<p class="MsoNormal">- * Can be woken up by FUSE_NOTIFY_INVAL_FILES<o:p></o:p></p>
<p class="MsoNormal">- */<o:p></o:p></p>
<p class="MsoNormal">-static void fuse_wait_on_page_writeback_or_invalidate(struct inode *inode,<o:p></o:p></p>
<p class="MsoNormal">- struct file *file,<o:p></o:p></p>
<p class="MsoNormal">- pgoff_t index)<o:p></o:p></p>
<p class="MsoNormal">-{<o:p></o:p></p>
<p class="MsoNormal">- struct fuse_inode *fi = get_fuse_inode(inode);<o:p></o:p></p>
<p class="MsoNormal">- struct fuse_file *ff = file->private_data;<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal">- wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index) ||<o:p></o:p></p>
<p class="MsoNormal">- test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state));<o:p></o:p></p>
<p class="MsoNormal">-}<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal">/*<o:p></o:p></p>
<p class="MsoNormal"> * Wait for all pending writepages on the inode to finish.<o:p></o:p></p>
<p class="MsoNormal"> *<o:p></o:p></p>
<p class="MsoNormal">@@ -1079,10 +1075,11 @@ static int fuse_do_readpage(struct file *file, struct page *page,<o:p></o:p></p>
<p class="MsoNormal"> * Page writeback can extend beyond the lifetime of the<o:p></o:p></p>
<p class="MsoNormal"> * page-cache page, so make sure we read a properly synced<o:p></o:p></p>
<p class="MsoNormal"> * page.<o:p></o:p></p>
<p class="MsoNormal">- *<o:p></o:p></p>
<p class="MsoNormal">- * But we can't wait if FUSE_NOTIFY_INVAL_FILES is in progress.<o:p></o:p></p>
<p class="MsoNormal"> */<o:p></o:p></p>
<p class="MsoNormal">- fuse_wait_on_page_writeback_or_invalidate(inode, file, page->index);<o:p></o:p></p>
<p class="MsoNormal">+ fuse_wait_on_page_writeback(inode, page->index);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+ if (fuse_file_fail_immediately(file))<o:p></o:p></p>
<p class="MsoNormal">+ return -EIO;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> attr_ver = fuse_get_attr_version(fm->fc);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">@@ -1246,8 +1243,7 @@ static void fuse_readahead(struct readahead_control *rac)<o:p></o:p></p>
<p class="MsoNormal"> ap = &ia->ap;<o:p></o:p></p>
<p class="MsoNormal"> nr_pages = __readahead_batch(rac, ap->pages, nr_pages);<o:p></o:p></p>
<p class="MsoNormal"> for (i = 0; i < nr_pages; i++) {<o:p></o:p></p>
<p class="MsoNormal">- /* we can't wait if FUSE_NOTIFY_INVAL_FILES is in progress */<o:p></o:p></p>
<p class="MsoNormal">- fuse_wait_on_page_writeback_or_invalidate(inode, rac->file,<o:p></o:p></p>
<p class="MsoNormal">+ fuse_wait_on_page_writeback(inode,<o:p></o:p></p>
<p class="MsoNormal"> readahead_index(rac) + i);<o:p></o:p></p>
<p class="MsoNormal"> ap->descs[i].length = PAGE_SIZE;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal">@@ -2404,21 +2400,8 @@ static inline bool fuse_blocked_for_wb(struct inode *inode)<o:p></o:p></p>
<p class="MsoNormal">{<o:p></o:p></p>
<p class="MsoNormal"> struct fuse_conn *fc = get_fuse_conn(inode);<o:p></o:p></p>
<p class="MsoNormal"> struct fuse_inode *fi = get_fuse_inode(inode);<o:p></o:p></p>
<p class="MsoNormal">- bool blocked = false;<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal">- if (!fc->blocked)<o:p></o:p></p>
<p class="MsoNormal">- return false;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">- spin_lock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal">- if (!list_empty(&fi->rw_files)) {<o:p></o:p></p>
<p class="MsoNormal">- struct fuse_file *ff = list_entry(fi->rw_files.next,<o:p></o:p></p>
<p class="MsoNormal">- struct fuse_file, rw_entry);<o:p></o:p></p>
<p class="MsoNormal">- if (!test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state))<o:p></o:p></p>
<p class="MsoNormal">- blocked = true;<o:p></o:p></p>
<p class="MsoNormal">- }<o:p></o:p></p>
<p class="MsoNormal">- spin_unlock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal">- return blocked;<o:p></o:p></p>
<p class="MsoNormal">+ return fc->blocked && !test_bit(FUSE_I_INVAL_FILES, &fi->state);<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">void fuse_release_ff(struct inode *inode, struct fuse_file *ff);<o:p></o:p></p>
<p class="MsoNormal">@@ -2438,6 +2421,15 @@ static int fuse_writepages_fill(struct page *page,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> BUG_ON(wpa && !data->ff);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">+ /* More than optimization: writeback pages to /dev/null; fused would<o:p></o:p></p>
<p class="MsoNormal">+ * drop our FUSE_WRITE requests anyway, but it will be blocked while<o:p></o:p></p>
<p class="MsoNormal">+ * sending NOTIFY_INVAL_FILES until we return!<o:p></o:p></p>
<p class="MsoNormal">+ */<o:p></o:p></p>
<p class="MsoNormal">+ if (!wpa && test_bit(FUSE_I_INVAL_FILES, &fi->state)) {<o:p></o:p></p>
<p class="MsoNormal">+ unlock_page(page);<o:p></o:p></p>
<p class="MsoNormal">+ return 0;<o:p></o:p></p>
<p class="MsoNormal">+ }<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> if (wpa && fuse_writepage_need_send(fc, page, ap, data)) {<o:p></o:p></p>
<p class="MsoNormal"> fuse_writepages_send(data);<o:p></o:p></p>
<p class="MsoNormal"> fuse_release_ff(inode, data->ff);<o:p></o:p></p>
<p class="MsoNormal">@@ -2516,7 +2508,6 @@ static int fuse_writepages_fill(struct page *page,<o:p></o:p></p>
<p class="MsoNormal"> end_page_writeback(page);<o:p></o:p></p>
<p class="MsoNormal"> fuse_release_ff(inode, data->ff);<o:p></o:p></p>
<p class="MsoNormal"> data->ff = NULL;<o:p></o:p></p>
<p class="MsoNormal">- goto out_unlock;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal">out_unlock:<o:p></o:p></p>
<p class="MsoNormal"> unlock_page(page);<o:p></o:p></p>
<p class="MsoNormal">@@ -2527,14 +2518,6 @@ static int fuse_writepages_fill(struct page *page,<o:p></o:p></p>
<p class="MsoNormal"> return err;<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">-static int fuse_dummy_writepage(struct page *page,<o:p></o:p></p>
<p class="MsoNormal">- struct writeback_control *wbc,<o:p></o:p></p>
<p class="MsoNormal">- void *data)<o:p></o:p></p>
<p class="MsoNormal">-{<o:p></o:p></p>
<p class="MsoNormal">- unlock_page(page);<o:p></o:p></p>
<p class="MsoNormal">- return 0;<o:p></o:p></p>
<p class="MsoNormal">-}<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal">static int fuse_writepages(struct address_space *mapping,<o:p></o:p></p>
<p class="MsoNormal"> struct writeback_control *wbc)<o:p></o:p></p>
<p class="MsoNormal">{<o:p></o:p></p>
<p class="MsoNormal">@@ -2555,29 +2538,9 @@ static int fuse_writepages(struct address_space *mapping,<o:p></o:p></p>
<p class="MsoNormal"> if (wbc->sync_mode != WB_SYNC_NONE)<o:p></o:p></p>
<p class="MsoNormal"> wait_event(fc->blocked_waitq, !fuse_blocked_for_wb(inode));<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">- /* More than optimization: writeback pages to /dev/null; fused would<o:p></o:p></p>
<p class="MsoNormal">- * drop our FUSE_WRITE requests anyway, but it will be blocked while<o:p></o:p></p>
<p class="MsoNormal">- * sending NOTIFY_INVAL_FILES until we return!<o:p></o:p></p>
<p class="MsoNormal">- *<o:p></o:p></p>
<p class="MsoNormal">- * NB: We can't wait till fuse_send_writepages() because<o:p></o:p></p>
<p class="MsoNormal">- * fuse_writepages_fill() would possibly deadlock on<o:p></o:p></p>
<p class="MsoNormal">- * fuse_page_is_writeback().<o:p></o:p></p>
<p class="MsoNormal">- */<o:p></o:p></p>
<p class="MsoNormal">- data.ff = __fuse_write_file_get(fc, get_fuse_inode(inode));<o:p></o:p></p>
<p class="MsoNormal">- if (data.ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &data.ff->ff_state)) {<o:p></o:p></p>
<p class="MsoNormal">- err = write_cache_pages(mapping, wbc, fuse_dummy_writepage,<o:p></o:p></p>
<p class="MsoNormal">- mapping);<o:p></o:p></p>
<p class="MsoNormal">- fuse_release_ff(inode, data.ff);<o:p></o:p></p>
<p class="MsoNormal">- data.ff = NULL;<o:p></o:p></p>
<p class="MsoNormal">- goto out;<o:p></o:p></p>
<p class="MsoNormal">- }<o:p></o:p></p>
<p class="MsoNormal">- if (data.ff) {<o:p></o:p></p>
<p class="MsoNormal">- fuse_release_ff(inode, data.ff);<o:p></o:p></p>
<p class="MsoNormal">- data.ff = NULL;<o:p></o:p></p>
<p class="MsoNormal">- }<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal"> data.inode = inode;<o:p></o:p></p>
<p class="MsoNormal"> data.wpa = NULL;<o:p></o:p></p>
<p class="MsoNormal">+ data.ff = NULL;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> err = -ENOMEM;<o:p></o:p></p>
<p class="MsoNormal"> data.orig_pages = kcalloc(fc->max_pages,<o:p></o:p></p>
<p class="MsoNormal">@@ -2601,12 +2564,7 @@ static int fuse_writepages(struct address_space *mapping,<o:p></o:p></p>
<p class="MsoNormal"> return err;<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">-static inline bool fuse_file_fail_immediately(struct file *file)<o:p></o:p></p>
<p class="MsoNormal">-{<o:p></o:p></p>
<p class="MsoNormal">- struct fuse_file *ff = file->private_data;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">- return test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state);<o:p></o:p></p>
<p class="MsoNormal">-}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">/*<o:p></o:p></p>
<p class="MsoNormal"> * It's worthy to make sure that space is reserved on disk for the write,<o:p></o:p></p>
<p class="MsoNormal">@@ -2629,13 +2587,13 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping,<o:p></o:p></p>
<p class="MsoNormal"> if (!page)<o:p></o:p></p>
<p class="MsoNormal"> goto error;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">+ fuse_wait_on_page_writeback(mapping->host, page->index);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> if (fuse_file_fail_immediately(file)) {<o:p></o:p></p>
<p class="MsoNormal"> err = -EIO;<o:p></o:p></p>
<p class="MsoNormal"> goto cleanup;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">- fuse_wait_on_page_writeback(mapping->host, page->index);<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal"> if (PageUptodate(page) || len == PAGE_SIZE)<o:p></o:p></p>
<p class="MsoNormal"> goto success;<o:p></o:p></p>
<p class="MsoNormal"> /*<o:p></o:p></p>
<p class="MsoNormal">@@ -2701,6 +2659,11 @@ static int fuse_launder_page(struct page *page)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> /* Serialize with pending writeback for the same page */<o:p></o:p></p>
<p class="MsoNormal"> fuse_wait_on_page_writeback(inode, page->index);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+ /* Return success if FUSE_NOTIFY_INVAL_FILES is in progress */<o:p></o:p></p>
<p class="MsoNormal">+ if (test_bit(FUSE_I_INVAL_FILES, &get_fuse_inode(inode)->state))<o:p></o:p></p>
<p class="MsoNormal">+ return 0;<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> err = fuse_writepage_locked(page);<o:p></o:p></p>
<p class="MsoNormal"> if (!err)<o:p></o:p></p>
<p class="MsoNormal"> fuse_wait_on_page_writeback(inode, page->index);<o:p></o:p></p>
<p class="MsoNormal">@@ -2748,10 +2711,12 @@ static vm_fault_t fuse_page_mkwrite(struct vm_fault *vmf)<o:p></o:p></p>
<p class="MsoNormal"> return VM_FAULT_NOPAGE;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">- if (fuse_file_fail_immediately(vmf->vma->vm_file))<o:p></o:p></p>
<p class="MsoNormal">- return -EIO;<o:p></o:p></p>
<p class="MsoNormal">-<o:p></o:p></p>
<p class="MsoNormal"> fuse_wait_on_page_writeback(inode, page->index);<o:p></o:p></p>
<p class="MsoNormal">+ if (fuse_file_fail_immediately(vmf->vma->vm_file)) {<o:p></o:p></p>
<p class="MsoNormal">+ unlock_page(page);<o:p></o:p></p>
<p class="MsoNormal">+ return VM_FAULT_SIGSEGV;<o:p></o:p></p>
<p class="MsoNormal">+ }<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> return VM_FAULT_LOCKED;<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h<o:p></o:p></p>
<p class="MsoNormal">index aa74b63b2392..3221892765b5 100644<o:p></o:p></p>
<p class="MsoNormal">--- a/fs/fuse/fuse_i.h<o:p></o:p></p>
<p class="MsoNormal">+++ b/fs/fuse/fuse_i.h<o:p></o:p></p>
<p class="MsoNormal">@@ -198,6 +198,8 @@ enum {<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> /** kdirect open try has already made */<o:p></o:p></p>
<p class="MsoNormal"> FUSE_I_KIO_OPEN_TRY_MADE,<o:p></o:p></p>
<p class="MsoNormal">+ /** Operation invalidating files is in progress */<o:p></o:p></p>
<p class="MsoNormal">+ FUSE_I_INVAL_FILES,<o:p></o:p></p>
<p class="MsoNormal">};<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">struct fuse_conn;<o:p></o:p></p>
<p class="MsoNormal">@@ -1357,6 +1359,16 @@ static inline void fuse_dio_wait(struct fuse_inode *fi)<o:p></o:p></p>
<p class="MsoNormal"> fuse_write_dio_wait(fi);<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">+static inline bool __fuse_file_fail_immediately(struct fuse_file *ff)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+ return test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state);<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">+static inline bool fuse_file_fail_immediately(struct file *file)<o:p></o:p></p>
<p class="MsoNormal">+{<o:p></o:p></p>
<p class="MsoNormal">+ return __fuse_file_fail_immediately(file->private_data);<o:p></o:p></p>
<p class="MsoNormal">+}<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal">/**<o:p></o:p></p>
<p class="MsoNormal"> * Scan all fuse_mounts belonging to fc to find the first where<o:p></o:p></p>
<p class="MsoNormal"> * ilookup5() returns a result. Return that result and the<o:p></o:p></p>
<p class="MsoNormal">diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c<o:p></o:p></p>
<p class="MsoNormal">index 87a3834fcd32..125a0280e853 100644<o:p></o:p></p>
<p class="MsoNormal">--- a/fs/fuse/inode.c<o:p></o:p></p>
<p class="MsoNormal">+++ b/fs/fuse/inode.c<o:p></o:p></p>
<p class="MsoNormal">@@ -511,12 +511,16 @@ int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)<o:p></o:p></p>
<p class="MsoNormal"> return -ENOENT;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> fi = get_fuse_inode(inode);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> spin_lock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal"> list_for_each_entry(ff, &fi->rw_files, rw_entry) {<o:p></o:p></p>
<p class="MsoNormal"> set_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state);<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal"> spin_unlock(&fi->lock);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">+ /* Mark that invalidate files is in progress */<o:p></o:p></p>
<p class="MsoNormal">+ set_bit(FUSE_I_INVAL_FILES, &fi->state);<o:p></o:p></p>
<p class="MsoNormal">+<o:p></o:p></p>
<p class="MsoNormal"> /* let them see FUSE_S_FAIL_IMMEDIATELY */<o:p></o:p></p>
<p class="MsoNormal"> wake_up_all(&fc->blocked_waitq);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">@@ -552,6 +556,7 @@ int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)<o:p></o:p></p>
<p class="MsoNormal"> if (!err)<o:p></o:p></p>
<p class="MsoNormal"> fuse_invalidate_attr(inode);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">+ clear_bit(FUSE_I_INVAL_FILES, &fi->state);<o:p></o:p></p>
<p class="MsoNormal"> iput(inode);<o:p></o:p></p>
<p class="MsoNormal"> return err;<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal">--<o:p></o:p></p>
<p class="MsoNormal">2.27.0<o:p></o:p></p>
</div>
</body>
</html>