aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index e8f3170946f1..ca6fc0e96d7c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -26,7 +26,7 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file)
26 struct fuse_conn *fc; 26 struct fuse_conn *fc;
27 spin_lock(&fuse_lock); 27 spin_lock(&fuse_lock);
28 fc = file->private_data; 28 fc = file->private_data;
29 if (fc && !fc->sb) 29 if (fc && !fc->mounted)
30 fc = NULL; 30 fc = NULL;
31 spin_unlock(&fuse_lock); 31 spin_unlock(&fuse_lock);
32 return fc; 32 return fc;
@@ -148,6 +148,17 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
148 fuse_putback_request(fc, req); 148 fuse_putback_request(fc, req);
149} 149}
150 150
151void fuse_release_background(struct fuse_req *req)
152{
153 iput(req->inode);
154 iput(req->inode2);
155 if (req->file)
156 fput(req->file);
157 spin_lock(&fuse_lock);
158 list_del(&req->bg_entry);
159 spin_unlock(&fuse_lock);
160}
161
151/* 162/*
152 * This function is called when a request is finished. Either a reply 163 * This function is called when a request is finished. Either a reply
153 * has arrived or it was interrupted (and not yet sent) or some error 164 * has arrived or it was interrupted (and not yet sent) or some error
@@ -166,12 +177,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
166 putback = atomic_dec_and_test(&req->count); 177 putback = atomic_dec_and_test(&req->count);
167 spin_unlock(&fuse_lock); 178 spin_unlock(&fuse_lock);
168 if (req->background) { 179 if (req->background) {
169 if (req->inode) 180 down_read(&fc->sbput_sem);
170 iput(req->inode); 181 if (fc->mounted)
171 if (req->inode2) 182 fuse_release_background(req);
172 iput(req->inode2); 183 up_read(&fc->sbput_sem);
173 if (req->file)
174 fput(req->file);
175 } 184 }
176 wake_up(&req->waitq); 185 wake_up(&req->waitq);
177 if (req->in.h.opcode == FUSE_INIT) { 186 if (req->in.h.opcode == FUSE_INIT) {
@@ -191,11 +200,39 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
191 fuse_putback_request(fc, req); 200 fuse_putback_request(fc, req);
192} 201}
193 202
194static void background_request(struct fuse_req *req) 203/*
204 * Unfortunately request interruption not just solves the deadlock
205 * problem, it causes problems too. These stem from the fact, that an
206 * interrupted request is continued to be processed in userspace,
207 * while all the locks and object references (inode and file) held
208 * during the operation are released.
209 *
210 * To release the locks is exactly why there's a need to interrupt the
211 * request, so there's not a lot that can be done about this, except
212 * introduce additional locking in userspace.
213 *
214 * More important is to keep inode and file references until userspace
215 * has replied, otherwise FORGET and RELEASE could be sent while the
216 * inode/file is still used by the filesystem.
217 *
218 * For this reason the concept of "background" request is introduced.
219 * An interrupted request is backgrounded if it has been already sent
220 * to userspace. Backgrounding involves getting an extra reference to
221 * inode(s) or file used in the request, and adding the request to
222 * fc->background list. When a reply is received for a background
223 * request, the object references are released, and the request is
224 * removed from the list. If the filesystem is unmounted while there
225 * are still background requests, the list is walked and references
226 * are released as if a reply was received.
227 *
228 * There's one more use for a background request. The RELEASE message is
229 * always sent as background, since it doesn't return an error or
230 * data.
231 */
232static void background_request(struct fuse_conn *fc, struct fuse_req *req)
195{ 233{
196 /* Need to get hold of the inode(s) and/or file used in the
197 request, so FORGET and RELEASE are not sent too early */
198 req->background = 1; 234 req->background = 1;
235 list_add(&req->bg_entry, &fc->background);
199 if (req->inode) 236 if (req->inode)
200 req->inode = igrab(req->inode); 237 req->inode = igrab(req->inode);
201 if (req->inode2) 238 if (req->inode2)
@@ -215,7 +252,8 @@ static int request_wait_answer_nonint(struct fuse_req *req)
215} 252}
216 253
217/* Called with fuse_lock held. Releases, and then reacquires it. */ 254/* Called with fuse_lock held. Releases, and then reacquires it. */
218static void request_wait_answer(struct fuse_req *req, int interruptible) 255static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req,
256 int interruptible)
219{ 257{
220 int intr; 258 int intr;
221 259
@@ -255,7 +293,7 @@ static void request_wait_answer(struct fuse_req *req, int interruptible)
255 list_del(&req->list); 293 list_del(&req->list);
256 __fuse_put_request(req); 294 __fuse_put_request(req);
257 } else if (!req->finished && req->sent) 295 } else if (!req->finished && req->sent)
258 background_request(req); 296 background_request(fc, req);
259} 297}
260 298
261static unsigned len_args(unsigned numargs, struct fuse_arg *args) 299static unsigned len_args(unsigned numargs, struct fuse_arg *args)
@@ -297,7 +335,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
297{ 335{
298 req->isreply = 1; 336 req->isreply = 1;
299 spin_lock(&fuse_lock); 337 spin_lock(&fuse_lock);
300 if (!fc->file) 338 if (!fc->connected)
301 req->out.h.error = -ENOTCONN; 339 req->out.h.error = -ENOTCONN;
302 else if (fc->conn_error) 340 else if (fc->conn_error)
303 req->out.h.error = -ECONNREFUSED; 341 req->out.h.error = -ECONNREFUSED;
@@ -307,7 +345,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
307 after request_end() */ 345 after request_end() */
308 __fuse_get_request(req); 346 __fuse_get_request(req);
309 347
310 request_wait_answer(req, interruptible); 348 request_wait_answer(fc, req, interruptible);
311 } 349 }
312 spin_unlock(&fuse_lock); 350 spin_unlock(&fuse_lock);
313} 351}
@@ -330,7 +368,7 @@ void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req)
330static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) 368static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
331{ 369{
332 spin_lock(&fuse_lock); 370 spin_lock(&fuse_lock);
333 if (fc->file) { 371 if (fc->connected) {
334 queue_request(fc, req); 372 queue_request(fc, req);
335 spin_unlock(&fuse_lock); 373 spin_unlock(&fuse_lock);
336 } else { 374 } else {
@@ -348,7 +386,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
348void request_send_background(struct fuse_conn *fc, struct fuse_req *req) 386void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
349{ 387{
350 req->isreply = 1; 388 req->isreply = 1;
351 background_request(req); 389 spin_lock(&fuse_lock);
390 background_request(fc, req);
391 spin_unlock(&fuse_lock);
352 request_send_nowait(fc, req); 392 request_send_nowait(fc, req);
353} 393}
354 394
@@ -583,7 +623,7 @@ static void request_wait(struct fuse_conn *fc)
583 DECLARE_WAITQUEUE(wait, current); 623 DECLARE_WAITQUEUE(wait, current);
584 624
585 add_wait_queue_exclusive(&fc->waitq, &wait); 625 add_wait_queue_exclusive(&fc->waitq, &wait);
586 while (fc->sb && list_empty(&fc->pending)) { 626 while (fc->mounted && list_empty(&fc->pending)) {
587 set_current_state(TASK_INTERRUPTIBLE); 627 set_current_state(TASK_INTERRUPTIBLE);
588 if (signal_pending(current)) 628 if (signal_pending(current))
589 break; 629 break;
@@ -622,7 +662,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
622 goto err_unlock; 662 goto err_unlock;
623 request_wait(fc); 663 request_wait(fc);
624 err = -ENODEV; 664 err = -ENODEV;
625 if (!fc->sb) 665 if (!fc->mounted)
626 goto err_unlock; 666 goto err_unlock;
627 err = -ERESTARTSYS; 667 err = -ERESTARTSYS;
628 if (list_empty(&fc->pending)) 668 if (list_empty(&fc->pending))
@@ -839,7 +879,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
839 spin_lock(&fuse_lock); 879 spin_lock(&fuse_lock);
840 fc = file->private_data; 880 fc = file->private_data;
841 if (fc) { 881 if (fc) {
842 fc->file = NULL; 882 fc->connected = 0;
843 end_requests(fc, &fc->pending); 883 end_requests(fc, &fc->pending);
844 end_requests(fc, &fc->processing); 884 end_requests(fc, &fc->processing);
845 fuse_release_conn(fc); 885 fuse_release_conn(fc);