diff options
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 60c222517ccd..99325547604f 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -172,6 +172,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
172 | fuse_putback_request() */ | 172 | fuse_putback_request() */ |
173 | for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) | 173 | for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) |
174 | up(&fc->outstanding_sem); | 174 | up(&fc->outstanding_sem); |
175 | |||
176 | fuse_put_request(fc, req); | ||
175 | } | 177 | } |
176 | 178 | ||
177 | /* | 179 | /* |
@@ -180,13 +182,15 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
180 | * occurred during communication with userspace, or the device file | 182 | * occurred during communication with userspace, or the device file |
181 | * was closed. In case of a background request the reference to the | 183 | * was closed. In case of a background request the reference to the |
182 | * stored objects are released. The requester thread is woken up (if | 184 | * stored objects are released. The requester thread is woken up (if |
183 | * still waiting), and finally the reference to the request is | 185 | * still waiting), the 'end' callback is called if given, else the |
184 | * released | 186 | * reference to the request is released |
185 | * | 187 | * |
186 | * Called with fuse_lock, unlocks it | 188 | * Called with fuse_lock, unlocks it |
187 | */ | 189 | */ |
188 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) | 190 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) |
189 | { | 191 | { |
192 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; | ||
193 | req->end = NULL; | ||
190 | list_del(&req->list); | 194 | list_del(&req->list); |
191 | req->state = FUSE_REQ_FINISHED; | 195 | req->state = FUSE_REQ_FINISHED; |
192 | spin_unlock(&fuse_lock); | 196 | spin_unlock(&fuse_lock); |
@@ -197,16 +201,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
197 | up_read(&fc->sbput_sem); | 201 | up_read(&fc->sbput_sem); |
198 | } | 202 | } |
199 | wake_up(&req->waitq); | 203 | wake_up(&req->waitq); |
200 | if (req->in.h.opcode == FUSE_INIT) | 204 | if (end) |
201 | process_init_reply(fc, req); | 205 | end(fc, req); |
202 | else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) { | 206 | else |
203 | /* Special case for failed iget in CREATE */ | 207 | fuse_put_request(fc, req); |
204 | u64 nodeid = req->in.h.nodeid; | ||
205 | fuse_reset_request(req); | ||
206 | fuse_send_forget(fc, req, nodeid, 1); | ||
207 | return; | ||
208 | } | ||
209 | fuse_put_request(fc, req); | ||
210 | } | 208 | } |
211 | 209 | ||
212 | /* | 210 | /* |
@@ -387,6 +385,7 @@ void fuse_send_init(struct fuse_conn *fc) | |||
387 | req->out.argvar = 1; | 385 | req->out.argvar = 1; |
388 | req->out.args[0].size = sizeof(struct fuse_init_out); | 386 | req->out.args[0].size = sizeof(struct fuse_init_out); |
389 | req->out.args[0].value = &req->misc.init_out; | 387 | req->out.args[0].value = &req->misc.init_out; |
388 | req->end = process_init_reply; | ||
390 | request_send_background(fc, req); | 389 | request_send_background(fc, req); |
391 | } | 390 | } |
392 | 391 | ||
@@ -864,17 +863,32 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head) | |||
864 | * The requests are set to interrupted and finished, and the request | 863 | * The requests are set to interrupted and finished, and the request |
865 | * waiter is woken up. This will make request_wait_answer() wait | 864 | * waiter is woken up. This will make request_wait_answer() wait |
866 | * until the request is unlocked and then return. | 865 | * until the request is unlocked and then return. |
866 | * | ||
867 | * If the request is asynchronous, then the end function needs to be | ||
868 | * called after waiting for the request to be unlocked (if it was | ||
869 | * locked). | ||
867 | */ | 870 | */ |
868 | static void end_io_requests(struct fuse_conn *fc) | 871 | static void end_io_requests(struct fuse_conn *fc) |
869 | { | 872 | { |
870 | while (!list_empty(&fc->io)) { | 873 | while (!list_empty(&fc->io)) { |
871 | struct fuse_req *req; | 874 | struct fuse_req *req = |
872 | req = list_entry(fc->io.next, struct fuse_req, list); | 875 | list_entry(fc->io.next, struct fuse_req, list); |
876 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; | ||
877 | |||
873 | req->interrupted = 1; | 878 | req->interrupted = 1; |
874 | req->out.h.error = -ECONNABORTED; | 879 | req->out.h.error = -ECONNABORTED; |
875 | req->state = FUSE_REQ_FINISHED; | 880 | req->state = FUSE_REQ_FINISHED; |
876 | list_del_init(&req->list); | 881 | list_del_init(&req->list); |
877 | wake_up(&req->waitq); | 882 | wake_up(&req->waitq); |
883 | if (end) { | ||
884 | req->end = NULL; | ||
885 | /* The end function will consume this reference */ | ||
886 | __fuse_get_request(req); | ||
887 | spin_unlock(&fuse_lock); | ||
888 | wait_event(req->waitq, !req->locked); | ||
889 | end(fc, req); | ||
890 | spin_lock(&fuse_lock); | ||
891 | } | ||
878 | } | 892 | } |
879 | } | 893 | } |
880 | 894 | ||