aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-02-02 14:59:05 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2006-02-02 14:59:05 +0000
commitce28c7e8288b28bd380a75b6240e1fe65a7cc304 (patch)
tree6833313c86c9a1c28d7de60e5a56dd1344fa44f3 /kernel/dev.c
parent08dab162b8029e95079e7d78c93429961ae8398e (diff)
downloadlibfuse-ce28c7e8288b28bd380a75b6240e1fe65a7cc304.tar.gz
fix
Diffstat (limited to 'kernel/dev.c')
-rw-r--r--kernel/dev.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/kernel/dev.c b/kernel/dev.c
index 2fc773b..2a2453f 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -202,27 +202,39 @@ void fuse_release_background(struct fuse_req *req)
* stored objects are released. The requester thread is woken up (if
* still waiting), the 'end' callback is called if given, else the
* reference to the request is released
+ *
+ * Releasing extra reference for foreground requests must be done
+ * within the same locked region as setting state to finished. This
+ * is because fuse_reset_request() may be called after request is
+ * finished and it must be the sole possessor. If request is
+ * interrupted and put in the background, it will return with an error
+ * and hence never be reset and reused.
*
* Called with fuse_lock, unlocks it
*/
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
{
- void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
- req->end = NULL;
list_del(&req->list);
req->state = FUSE_REQ_FINISHED;
- spin_unlock(&fuse_lock);
- if (req->background) {
- down_read(&fc->sbput_sem);
- if (fc->mounted)
- fuse_release_background(req);
- up_read(&fc->sbput_sem);
+ if (req->isreply && !req->background) {
+ wake_up(&req->waitq);
+ __fuse_put_request(req);
+ spin_unlock(&fuse_lock);
+ } else {
+ void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+ req->end = NULL;
+ spin_unlock(&fuse_lock);
+ if (req->background) {
+ down_read(&fc->sbput_sem);
+ if (fc->mounted)
+ fuse_release_background(req);
+ up_read(&fc->sbput_sem);
+ }
+ if (end)
+ end(fc, req);
+ else
+ fuse_put_request(fc, req);
}
- wake_up(&req->waitq);
- if (end)
- end(fc, req);
- else
- fuse_put_request(fc, req);
}
/*
@@ -296,7 +308,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
if (req->state == FUSE_REQ_PENDING) {
list_del(&req->list);
__fuse_put_request(req);
- } else if (req->state == FUSE_REQ_SENT)
+ } else if (req->state != FUSE_REQ_FINISHED)
background_request(fc, req);
}