<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
&nbsp;Hello,&nbsp;</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
#1, yeah, it's intentional, both close_wait and fuse_link_rw_file() are our proprietary extention that are not applicable to other client.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
   the FIEMAP case is a different issue that's been fix in v3</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
#2 #3. again it's intentional.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
#4. there is no no_open case in vStorage,&nbsp; the no_open case in non-vStorage daemon is irrelevant here</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
#5. it's exactly what we want.&nbsp;</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
#6. Addressed in v3.&nbsp;</div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<hr style="display: inline-block; width: 98%;">
<div id="divRplyFwdMsg">
<div style="direction: ltr; font-family: Calibri, sans-serif; font-size: 11pt; color: rgb(0, 0, 0);">
<b>From:</b>&nbsp;Konstantin Khorenko &lt;khorenko@virtuozzo.com&gt;<br>
<b>Sent:</b>&nbsp;19 June 2026 04:11<br>
<b>To:</b>&nbsp;Kui Liu &lt;kui.liu@virtuozzo.com&gt;; devel@openvz.org &lt;devel@openvz.org&gt;<br>
<b>Cc:</b>&nbsp;Alexey Kuznetsov &lt;kuznet@virtuozzo.com&gt;; Andrey Zaitsev &lt;azaitsev@virtuozzo.com&gt;<br>
<b>Subject:</b>&nbsp;Re: [PATCH VZ10 v2] fs/fuse: order FUSE_OPEN reply against FUSE_NOTIFY_INVAL_FILES</div>
<div style="direction: ltr;">&nbsp;</div>
</div>
<div style="font-size: 11pt;">&nbsp; Concerns (in decreasing order of importance)<br>
<br>
&nbsp; 1. fuse_link_rw_file() is now under if (fc-&gt;close_wait) - possibly an unintended regression.<br>
&nbsp; Previously fuse_link_rw_file() was called unconditionally in fuse_finish_open(), and fi-&gt;rw_files was populated for all<br>
&nbsp; fuse mounts. Now both the linking and the wait are hidden under close_wait. But rw_files is read not only by invalidation:<br>
<br>
&nbsp; fs/fuse/file.c:3864&nbsp;&nbsp; (FIEMAP helper) - finds any ff for the inode among rw_files<br>
<br>
&nbsp; For a non-close_wait mount where only readers are open, this path will now get an empty list where before it would have<br>
&nbsp; found an ff. The &quot;Only apply to vStorage&quot; comment refers to the wait, but the braces captured the linking as well. Most<br>
&nbsp; likely fuse_link_rw_file(file) should stay unconditional, and only the new fuse_wait_on_inval_files() should be hidden<br>
&nbsp; under close_wait. Please confirm that capturing the linking is intentional.<br>
<br>
&nbsp; 2. Per-fuse_dev write_seq - the comparison is valid only if the OPEN reply and the INVAL_FILES notification go over the<br>
&nbsp; same fd.<br>
&nbsp; Each /dev/fuse clone (FUSE_DEV_IOC_CLONE) is a separate fuse_dev with its own counter starting at 0 (fuse_dev_alloc() now<br>
&nbsp; explicitly sets write_seq = 0). If a multithreaded daemon sends the OPEN reply on one device and the notification on<br>
&nbsp; another, then ff-&gt;open_seq and fi-&gt;inval_files_seq are taken from independent counters and are incomparable - the<br>
&nbsp; comparison result is random. This is the key correctness question: does the vStorage daemon guarantee that for a given<br>
&nbsp; inode both messages go over the same fud? If not - the mechanism is unsafe. This requirement should at least be pinned<br>
&nbsp; down with a comment in the code.<br>
<br>
&nbsp; 3. fud-&gt;write_seq++ is non-atomic.<br>
&nbsp; The increment is done without a lock. Parallel write()s to the same fd will race on the ++ (lost/duplicated seq). In<br>
&nbsp; practice there is usually one thread per clone device, so it is fine, but formally this is a data race on a shared field -<br>
&nbsp; it is worth at least noting the &quot;single writer per fud&quot; assumption in a comment, or using WRITE_ONCE.<br>
<br>
&nbsp; 4. The default open_seq = 0 is a latent fragility.<br>
&nbsp; fuse_file_alloc() zeroes ff via kzalloc, and open_seq stays 0 on paths where OPEN is not sent (fc-&gt;no_open). Then 0 &lt;<br>
&nbsp; inval_files_seq will falsely flag the open as stale forever after the first invalidation. For close_wait filesystems OPEN<br>
&nbsp; is always implemented, so it does not actually trigger, but the &quot;no_open + invalidate_files&quot; combination would be broken.<br>
&nbsp; One could explicitly initialize open_seq to some &quot;fresh&quot; value on the no-open path, or at least leave a comment.<br>
<br>
&nbsp; 5. The FAIL loop in fuse_invalidate_files() is seq-blind - a benign false positive.<br>
&nbsp; A valid new open (open_seq &gt; inval_files_seq) that managed to link into rw_files before the notification ran will be<br>
&nbsp; flagged FUSE_S_FAIL_IMMEDIATELY by the unconditional loop -&gt; an extra reopen on the client. Not a regression (the loop was<br>
&nbsp; unconditional in the old code too) and not data corruption, but the loop could be made seq-aware (if (ff-&gt;open_seq &lt;=<br>
&nbsp; fi-&gt;inval_files_seq)) so it does not hit valid races. Your call.<br>
<br>
&nbsp; 6. Style: uint64_t instead of the kernel u64 in the fuse_send_open() signature and in the struct fields. A minor thing,<br>
&nbsp; but u64 is more consistent.<br>
<br>
--<br>
Best regards,<br>
<br>
Konstantin Khorenko,<br>
Virtuozzo Linux Kernel Team<br>
<br>
On 6/16/26 18:51, Liu Kui wrote:<br>
&gt; The userspace daemon's send order of a FUSE_OPEN reply and a<br>
&gt; FUSE_NOTIFY_INVAL_FILES notification can be reversed by the time the<br>
&gt; kernel processes them. The kernel must distinguish the two cases:<br>
&gt;<br>
&gt;&nbsp;&nbsp; - reply sent before the notification: the open is stale and must<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; be flagged FUSE_S_FAIL_IMMEDIATELY;<br>
&gt;&nbsp;&nbsp; - reply sent after the notification: the open is valid but must<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; wait for fuse_inval_files_work() to complete before returning,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; or the caller hits IO errors on an inode still being invalidated.<br>
&gt;<br>
&gt; The FUSE_I_INVAL_FILES bit carries no ordering and cannot tell these<br>
&gt; apart. Add a per-fuse_dev write_seq bumped on every reply/notification<br>
&gt; write, saved to ff-&gt;open_seq on OPEN replies and fi-&gt;inval_files_seq<br>
&gt; on FUSE_NOTIFY_INVAL_FILES, and compared in fuse_link_rw_file() to<br>
&gt; flag stale opens. fuse_finish_open() then waits on FUSE_I_INVAL_FILES<br>
&gt; for the remaining case.<br>
&gt;<br>
&gt; <a href="https://virtuozzo.atlassian.net/browse/VSTOR-133093" id="OWAeea710d0-5401-711d-880e-fbf9e1282d63" class="OWAAutoLink" data-auth="NotApplicable">
https://virtuozzo.atlassian.net/browse/VSTOR-133093</a><br>
&gt; Signed-off-by: Liu Kui &lt;kui.liu@virtuozzo.com&gt;<br>
&gt; ---<br>
&gt; Changes in v2:<br>
&gt;&nbsp;&nbsp; - Rename write_counter / *_ts fields to write_seq / *_seq throughout<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; (write_counter -&gt; write_seq, reply_ts -&gt; reply_seq, open_ts -&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; open_seq, inval_file_ts -&gt; inval_files_seq). The values are a<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; logical sequence number, not a wall-clock timestamp; &quot;_seq&quot; is the<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; kernel-idiomatic name for a Lamport-style monotonic counter. Also<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; pluralise inval_file_ts -&gt; inval_files_seq to match the surrounding<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; inval_files_* family.<br>
&gt;&nbsp;&nbsp; - Propagate args.reply_seq into ff-&gt;open_seq from fuse_create_open()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; in dir.c (the create+open path missed it in v1).<br>
&gt;&nbsp;&nbsp; - Gate the new fuse_link_rw_file() / fuse_wait_on_inval_files() block<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; in fuse_finish_open() behind fc-&gt;close_wait so only vStorage runs<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; the new ordering work.<br>
&gt;&nbsp;&nbsp; - Also initialise fi-&gt;inval_files_seq in fuse_init_inode(), not only<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; in fuse_alloc_inode().<br>
&gt;&nbsp;&nbsp; - Update kernel-doc and inline comments to use &quot;sequence number&quot; /<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; write_seq wording instead of &quot;timestamp&quot; / &quot;write counter&quot;.<br>
&gt;<br>
&gt;&nbsp; fs/fuse/dev.c&nbsp;&nbsp;&nbsp; | 17 +++++++++----<br>
&gt;&nbsp; fs/fuse/dir.c&nbsp;&nbsp;&nbsp; |&nbsp; 1 +<br>
&gt;&nbsp; fs/fuse/file.c&nbsp;&nbsp; | 65 +++++++++++++++++++++++++++++++++++-------------<br>
&gt;&nbsp; fs/fuse/fuse_i.h | 14 ++++++++++-<br>
&gt;&nbsp; fs/fuse/inode.c&nbsp; | 26 ++++++++++++-------<br>
&gt;&nbsp; 5 files changed, 91 insertions(+), 32 deletions(-)<br>
&gt;<br>
&gt; diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c<br>
&gt; index 4fcfd644dcf6..3304082a635b 100644<br>
&gt; --- a/fs/fuse/dev.c<br>
&gt; +++ b/fs/fuse/dev.c<br>
&gt; @@ -2003,9 +2003,10 @@ static int fuse_notify_resend(struct fuse_conn *fc)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt; -static int fuse_notify_inval_files(struct fuse_conn *fc, unsigned int size,<br>
&gt; +static int fuse_notify_inval_files(struct fuse_dev *fud, unsigned int size,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_copy_state *cs)<br>
&gt;&nbsp; {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_conn *fc = fud-&gt;fc;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_notify_inval_files_out outarg;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int err = -EINVAL;<br>
&gt;&nbsp;<br>
&gt; @@ -2019,7 +2020,7 @@ static int fuse_notify_inval_files(struct fuse_conn *fc, unsigned int size,<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; down_read(&amp;fc-&gt;killsb);<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_invalidate_files(fc, outarg.ino);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_invalidate_files(fud, outarg.ino);<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up_read(&amp;fc-&gt;killsb);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return err;<br>
&gt; @@ -2029,9 +2030,11 @@ static int fuse_notify_inval_files(struct fuse_conn *fc, unsigned int size,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return err;<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt; -static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,<br>
&gt; +static int fuse_notify(struct fuse_dev *fud, enum fuse_notify_code code,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int size, struct fuse_copy_state *cs)<br>
&gt;&nbsp; {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_conn *fc = fud-&gt;fc;<br>
&gt; +<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Don't try to move pages (yet) */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cs-&gt;move_pages = 0;<br>
&gt;&nbsp;<br>
&gt; @@ -2062,7 +2065,7 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fuse_notify_resend(fc);<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case FUSE_NOTIFY_INVAL_FILES:<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fuse_notify_inval_files(fc, size, cs);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fuse_notify_inval_files(fud, size, cs);<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; default:<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_copy_finish(cs);<br>
&gt; @@ -2375,6 +2378,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_req *req;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_out_header oh;<br>
&gt;&nbsp;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /* Monotonic sequence number matching the daemon's reply/notification send order. */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; fud-&gt;write_seq++;<br>
&gt; +<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = -EINVAL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nbytes &lt; sizeof(struct fuse_out_header))<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto out;<br>
&gt; @@ -2392,7 +2398,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * and error contains notification code.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!oh.unique) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_notify(fud, oh.error, nbytes - sizeof(oh), cs);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto out;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;<br>
&gt; @@ -2462,6 +2468,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_del_init(&amp;req-&gt;list);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;fpq-&gt;lock);<br>
&gt;&nbsp;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; req-&gt;args-&gt;reply_seq = fud-&gt;write_seq;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_request_end(req);<br>
&gt;&nbsp; out:<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return err ? err : nbytes;<br>
&gt; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c<br>
&gt; index 6637914c8f28..45ee4f1e4b68 100644<br>
&gt; --- a/fs/fuse/dir.c<br>
&gt; +++ b/fs/fuse/dir.c<br>
&gt; @@ -693,6 +693,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ff-&gt;fh = outopenp-&gt;fh;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ff-&gt;nodeid = outentry.nodeid;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ff-&gt;open_flags = outopenp-&gt;open_flags;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; ff-&gt;open_seq = args.reply_seq;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inode = fuse_iget(dir-&gt;i_sb, outentry.nodeid, outentry.generation,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;outentry.attr, ATTR_TIMEOUT(&amp;outentry), 0);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!inode) {<br>
&gt; diff --git a/fs/fuse/file.c b/fs/fuse/file.c<br>
&gt; index edea59ee4839..504492845159 100644<br>
&gt; --- a/fs/fuse/file.c<br>
&gt; +++ b/fs/fuse/file.c<br>
&gt; @@ -45,10 +45,11 @@ static DECLARE_WORK(fuse_fput_work, fuse_fput_routine);<br>
&gt;&nbsp;<br>
&gt;&nbsp; static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int open_flags, int opcode,<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_open_out *outargp)<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_open_out *outargp, uint64_t *reply_seq)<br>
&gt;&nbsp; {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_open_in inarg;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FUSE_ARGS(args);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; int err;<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(&amp;inarg, 0, sizeof(inarg));<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inarg.flags = open_flags &amp; ~(O_CREAT | O_EXCL | O_NOCTTY);<br>
&gt; @@ -69,7 +70,14 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args.out_args[0].size = sizeof(*outargp);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args.out_args[0].value = outargp;<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; return fuse_simple_request(fm, &amp;args);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_simple_request(fm, &amp;args);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Propagate the dev write_seq so fuse_link_rw_file() can order<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * this open against any concurrent FUSE_NOTIFY_INVAL_FILES.<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; *reply_seq = args.reply_seq;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; return err;<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt;&nbsp; struct fuse_file *fuse_file_alloc(struct fuse_mount *fm, bool release)<br>
&gt; @@ -192,7 +200,7 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_open_out *outargp = &amp;ff-&gt;args-&gt;open_outarg;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int err;<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_send_open(fm, nodeid, open_flags, opcode, outargp);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_send_open(fm, nodeid, open_flags, opcode, outargp, &amp;ff-&gt;open_seq);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!err) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ff-&gt;fh = outargp-&gt;fh;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ff-&gt;open_flags = outargp-&gt;open_flags;<br>
&gt; @@ -245,6 +253,18 @@ static void fuse_link_write_file(struct file *file)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;fi-&gt;lock);<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt; +static int fuse_wait_on_inval_files(struct inode *inode)<br>
&gt; +{<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_inode *fi = get_fuse_inode(inode);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_conn *fc = get_fuse_mount(inode)-&gt;fc;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (likely(!test_bit(FUSE_I_INVAL_FILES, &amp;fi-&gt;state)))<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(fc, &quot;waiting for invalidate_files on [%llu] to complete&quot;, fi-&gt;nodeid);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; return wait_on_bit(&amp;fi-&gt;state, FUSE_I_INVAL_FILES, TASK_KILLABLE);<br>
&gt; +}<br>
&gt; +<br>
&gt;&nbsp; static void fuse_link_rw_file(struct file *file)<br>
&gt;&nbsp; {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct inode *inode = file_inode(file);<br>
&gt; @@ -252,14 +272,17 @@ static void fuse_link_rw_file(struct file *file)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_file *ff = file-&gt;private_data;<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;fi-&gt;lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; if (unlikely(test_bit(FUSE_I_INVAL_FILES, &amp;fi-&gt;state))) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ff-&gt;lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_bit(FUSE_S_FAIL_IMMEDIATELY, &amp;ff-&gt;ff_state);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ff-&gt;lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(ff-&gt;fm-&gt;fc, &quot;fuse_file[%llu] --&gt; invalidate_file on [%llu] pending&quot;, ff-&gt;fh, ff-&gt;nodeid);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (list_empty(&amp;ff-&gt;rw_entry))<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_add(&amp;ff-&gt;rw_entry, &amp;fi-&gt;rw_files);<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * If this open reply was received before the last<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * FUSE_NOTIFY_INVAL_FILES on this inode, the open is<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * stale, fail it immediately.<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (ff-&gt;open_seq &lt; fi-&gt;inval_files_seq)<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_bit(FUSE_S_FAIL_IMMEDIATELY, &amp;ff-&gt;ff_state);<br>
&gt; +<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;fi-&gt;lock);<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt; @@ -285,9 +308,20 @@ int fuse_finish_open(struct inode *inode, struct file *file)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((file-&gt;f_mode &amp; FMODE_WRITE) &amp;&amp; fc-&gt;writeback_cache)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_link_write_file(file);<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; fuse_link_rw_file(file);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /* Only apply to vStorage */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (fc-&gt;close_wait) {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_link_rw_file(file);<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Wait for fuse_inval_files_work() on this inode to complete<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * before returning, otherwise the caller can hit IO errors<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * on an inode still being invalidated.<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!test_bit(FUSE_S_FAIL_IMMEDIATELY, &amp;ff-&gt;ff_state))<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_wait_on_inval_files(inode);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; return err;<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt;&nbsp; static void fuse_truncate_update_attr(struct inode *inode, struct file *file)<br>
&gt; @@ -320,12 +354,9 @@ static int fuse_open(struct inode *inode, struct file *file)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((file-&gt;f_flags &amp; O_DIRECT) &amp;&amp; !fc-&gt;direct_enable)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EINVAL;<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; if (unlikely(test_bit(FUSE_I_INVAL_FILES, &amp;fi-&gt;state))) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(fc, &quot;waiting for invalidate_file on [%llu] to complete&quot;, fi-&gt;nodeid);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = wait_on_bit(&amp;fi-&gt;state, FUSE_I_INVAL_FILES, TASK_KILLABLE);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err)<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return err;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; err = fuse_wait_on_inval_files(inode);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (err)<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return err;<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = generic_file_open(inode, file);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err)<br>
&gt; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h<br>
&gt; index 966c8e6c2ab7..693ec756dcf3 100644<br>
&gt; --- a/fs/fuse/fuse_i.h<br>
&gt; +++ b/fs/fuse/fuse_i.h<br>
&gt; @@ -218,6 +218,9 @@ struct fuse_inode {<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Entry on fc-&gt;inval_files_list list */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head inval_files_entry;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /** fud-&gt;write_seq when the last FUSE_NOTIFY_INVAL_FILES notification was received */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; uint64_t inval_files_seq;<br>
&gt;&nbsp; };<br>
&gt;&nbsp;<br>
&gt;&nbsp; /** FUSE inode state bits */<br>
&gt; @@ -315,6 +318,9 @@ struct fuse_file {<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** List of requests that may be killed **/<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head revoke_list;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /** fud-&gt;write_seq when the FUSE_OPEN reply was received */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; uint64_t open_seq;<br>
&gt;&nbsp; };<br>
&gt;&nbsp;<br>
&gt;&nbsp; /** FUSE file states (ff_state) */<br>
&gt; @@ -379,6 +385,9 @@ struct fuse_args {<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Fuse file used in the request or NULL*/<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_file *ff;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /** fud-&gt;write_seq when the reply was received */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; uint64_t reply_seq;<br>
&gt;&nbsp; };<br>
&gt;&nbsp;<br>
&gt;&nbsp; struct fuse_args_pages {<br>
&gt; @@ -625,6 +634,9 @@ struct fuse_dev {<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** list entry on fc-&gt;devices */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head entry;<br>
&gt; +<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /** Monotonic sequence number, bumped on every reply/notification write */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; uint64_t write_seq;<br>
&gt;&nbsp; };<br>
&gt;&nbsp;<br>
&gt;&nbsp; enum fuse_dax_mode {<br>
&gt; @@ -1604,7 +1616,7 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,<br>
&gt;&nbsp;&nbsp; * File-system tells the kernel to invalidate all fuse-files (and cache)<br>
&gt;&nbsp;&nbsp; * for the given node id.<br>
&gt;&nbsp;&nbsp; */<br>
&gt; -int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid);<br>
&gt; +int fuse_invalidate_files(struct fuse_dev *fud, u64 nodeid);<br>
&gt;&nbsp;<br>
&gt;&nbsp; int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool isdir);<br>
&gt; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c<br>
&gt; index 1e0c86f4b37a..841dfaca96a7 100644<br>
&gt; --- a/fs/fuse/inode.c<br>
&gt; +++ b/fs/fuse/inode.c<br>
&gt; @@ -118,6 +118,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;submount_lookup = NULL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;i_size_unstable = 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;private = NULL;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;inval_files_seq = 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;fi-&gt;rw_files);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;fi-&gt;inval_files_entry);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_init(&amp;fi-&gt;mutex);<br>
&gt; @@ -424,6 +425,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_inode *fi = get_fuse_inode(inode);<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;num_openers = 0;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;inval_files_seq = 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inode-&gt;i_mode = attr-&gt;mode &amp; S_IFMT;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inode-&gt;i_size = attr-&gt;size;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inode_set_mtime(inode, attr-&gt;mtime, attr-&gt;mtimensec);<br>
&gt; @@ -623,7 +625,7 @@ static void fuse_inval_files_work(struct work_struct *w)<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi = list_first_entry(&amp;inval_files_list, struct fuse_inode, inval_files_entry);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_del(&amp;fi-&gt;inval_files_entry);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(fc, &quot;invalidate_file on [%llu] starts&quot;, fi-&gt;nodeid);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(fc, &quot;invalidate_files on [%llu] starts&quot;, fi-&gt;nodeid);<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;fi-&gt;lock);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_for_each_entry(ff, &amp;fi-&gt;rw_files, rw_entry)<br>
&gt; @@ -640,15 +642,16 @@ static void fuse_inval_files_work(struct work_struct *w)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wake_up_bit(&amp;fi-&gt;state, FUSE_I_INVAL_FILES);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;fi-&gt;lock);<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(fc, &quot;invalidate_file on [%llu] ends&quot;, fi-&gt;nodeid);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_ktrace(fc, &quot;invalidate_files on [%llu] ends&quot;, fi-&gt;nodeid);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iput(&amp;fi-&gt;inode);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_drop_waiting(fc);<br>
&gt;&nbsp; }<br>
&gt;&nbsp;<br>
&gt; -int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)<br>
&gt; +int fuse_invalidate_files(struct fuse_dev *fud, u64 nodeid)<br>
&gt;&nbsp; {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_conn *fc = fud-&gt;fc;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct inode *inode;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_inode *fi;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct fuse_file *ff;<br>
&gt; @@ -666,19 +669,23 @@ int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi = get_fuse_inode(inode);<br>
&gt;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; /* Mark that invalidate files is in progress */<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Save this notification's write_seq and fail every fuse_file<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * currently linked on the inode.<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;fi-&gt;lock);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;inval_files_seq = fud-&gt;write_seq;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; list_for_each_entry(ff, &amp;fi-&gt;rw_files, rw_entry) {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ff-&gt;lock);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_bit(FUSE_S_FAIL_IMMEDIATELY, &amp;ff-&gt;ff_state);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ff-&gt;lock);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (test_bit(FUSE_I_INVAL_FILES, &amp;fi-&gt;state)) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;fi-&gt;lock);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iput(inode);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_bit(FUSE_I_INVAL_FILES, &amp;fi-&gt;state);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; list_for_each_entry(ff, &amp;fi-&gt;rw_files, rw_entry) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ff-&gt;lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_bit(FUSE_S_FAIL_IMMEDIATELY, &amp;ff-&gt;ff_state);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ff-&gt;lock);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fi-&gt;i_size_unstable = 1;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;fi-&gt;lock);<br>
&gt;&nbsp;<br>
&gt; @@ -1921,6 +1928,7 @@ struct fuse_dev *fuse_dev_alloc(void)<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fud-&gt;pq.processing = pq;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fuse_pqueue_init(&amp;fud-&gt;pq);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; fud-&gt;write_seq = 0;<br>
&gt;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fud;<br>
&gt;&nbsp; }<br>
<br>
</div>
</body>
</html>