diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-01-17 01:14:26 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-17 02:15:29 -0500 |
commit | f43b155a5a8a95b06bc0b4474fbb7311c7e9709a (patch) | |
tree | 482a03476b71498939adb9aa7ec1a4c072902927 /fs/fuse/dev.c | |
parent | 222f1d69183f10d70a37de5785698fe0aa363c12 (diff) |
[PATCH] fuse: fix request_end()
This function used the request object after decrementing its reference count
and releasing the lock. This could in theory lead to all sorts of problems.
Fix and simplify at the same time.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 18 |
1 files changed, 7 insertions, 11 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 9af88953db69..de402e4d8bce 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -171,19 +171,17 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
171 | /* | 171 | /* |
172 | * This function is called when a request is finished. Either a reply | 172 | * This function is called when a request is finished. Either a reply |
173 | * has arrived or it was interrupted (and not yet sent) or some error | 173 | * has arrived or it was interrupted (and not yet sent) or some error |
174 | * occurred during communication with userspace, or the device file was | 174 | * occurred during communication with userspace, or the device file |
175 | * closed. It decreases the reference count for the request. In case | 175 | * was closed. In case of a background request the reference to the |
176 | * of a background request the reference to the stored objects are | 176 | * stored objects are released. The requester thread is woken up (if |
177 | * released. The requester thread is woken up (if still waiting), and | 177 | * still waiting), and finally the reference to the request is |
178 | * finally the request is either freed or put on the unused_list | 178 | * released |
179 | * | 179 | * |
180 | * Called with fuse_lock, unlocks it | 180 | * Called with fuse_lock, unlocks it |
181 | */ | 181 | */ |
182 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) | 182 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) |
183 | { | 183 | { |
184 | int putback; | ||
185 | req->finished = 1; | 184 | req->finished = 1; |
186 | putback = atomic_dec_and_test(&req->count); | ||
187 | spin_unlock(&fuse_lock); | 185 | spin_unlock(&fuse_lock); |
188 | if (req->background) { | 186 | if (req->background) { |
189 | down_read(&fc->sbput_sem); | 187 | down_read(&fc->sbput_sem); |
@@ -197,13 +195,11 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
197 | else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) { | 195 | else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) { |
198 | /* Special case for failed iget in CREATE */ | 196 | /* Special case for failed iget in CREATE */ |
199 | u64 nodeid = req->in.h.nodeid; | 197 | u64 nodeid = req->in.h.nodeid; |
200 | __fuse_get_request(req); | ||
201 | fuse_reset_request(req); | 198 | fuse_reset_request(req); |
202 | fuse_send_forget(fc, req, nodeid, 1); | 199 | fuse_send_forget(fc, req, nodeid, 1); |
203 | putback = 0; | 200 | return; |
204 | } | 201 | } |
205 | if (putback) | 202 | fuse_put_request(fc, req); |
206 | fuse_putback_request(fc, req); | ||
207 | } | 203 | } |
208 | 204 | ||
209 | /* | 205 | /* |