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