diff options
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ae813e609932..a5e516a40e7a 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -165,9 +165,13 @@ static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) | |||
165 | 165 | ||
166 | static void fuse_drop_waiting(struct fuse_conn *fc) | 166 | static void fuse_drop_waiting(struct fuse_conn *fc) |
167 | { | 167 | { |
168 | if (fc->connected) { | 168 | /* |
169 | atomic_dec(&fc->num_waiting); | 169 | * lockess check of fc->connected is okay, because atomic_dec_and_test() |
170 | } else if (atomic_dec_and_test(&fc->num_waiting)) { | 170 | * provides a memory barrier mached with the one in fuse_wait_aborted() |
171 | * to ensure no wake-up is missed. | ||
172 | */ | ||
173 | if (atomic_dec_and_test(&fc->num_waiting) && | ||
174 | !READ_ONCE(fc->connected)) { | ||
171 | /* wake up aborters */ | 175 | /* wake up aborters */ |
172 | wake_up_all(&fc->blocked_waitq); | 176 | wake_up_all(&fc->blocked_waitq); |
173 | } | 177 | } |
@@ -1768,8 +1772,10 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, | |||
1768 | req->in.args[1].size = total_len; | 1772 | req->in.args[1].size = total_len; |
1769 | 1773 | ||
1770 | err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique); | 1774 | err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique); |
1771 | if (err) | 1775 | if (err) { |
1772 | fuse_retrieve_end(fc, req); | 1776 | fuse_retrieve_end(fc, req); |
1777 | fuse_put_request(fc, req); | ||
1778 | } | ||
1773 | 1779 | ||
1774 | return err; | 1780 | return err; |
1775 | } | 1781 | } |
@@ -2219,6 +2225,8 @@ EXPORT_SYMBOL_GPL(fuse_abort_conn); | |||
2219 | 2225 | ||
2220 | void fuse_wait_aborted(struct fuse_conn *fc) | 2226 | void fuse_wait_aborted(struct fuse_conn *fc) |
2221 | { | 2227 | { |
2228 | /* matches implicit memory barrier in fuse_drop_waiting() */ | ||
2229 | smp_mb(); | ||
2222 | wait_event(fc->blocked_waitq, atomic_read(&fc->num_waiting) == 0); | 2230 | wait_event(fc->blocked_waitq, atomic_read(&fc->num_waiting) == 0); |
2223 | } | 2231 | } |
2224 | 2232 | ||