aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-06-25 08:48:50 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:19 -0400
commit51eb01e73599efb88c6c20b1c226d20309a75450 (patch)
treec37e7a61ce7c049a4615dfb2ee994866d3c85bd6 /fs/fuse/dev.c
parent3e8c54fad89144b8d63cc41619f363df1ec7cc42 (diff)
[PATCH] fuse: no backgrounding on interrupt
Don't put requests into the background when a fatal interrupt occurs while the request is in userspace. This removes a major wart from the implementation. Backgrounding of requests was introduced to allow breaking of deadlocks. However now the same can be achieved by aborting the filesystem through the 'abort' sysfs attribute. This is a change in the interface, but should not cause problems, since these kinds of deadlocks never happen during normal operation. 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.c157
1 files changed, 44 insertions, 113 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 104a62dadb94..fec4779e2b55 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -64,18 +64,6 @@ static void restore_sigs(sigset_t *oldset)
64 sigprocmask(SIG_SETMASK, oldset, NULL); 64 sigprocmask(SIG_SETMASK, oldset, NULL);
65} 65}
66 66
67/*
68 * Reset request, so that it can be reused
69 *
70 * The caller must be _very_ careful to make sure, that it is holding
71 * the only reference to req
72 */
73void fuse_reset_request(struct fuse_req *req)
74{
75 BUG_ON(atomic_read(&req->count) != 1);
76 fuse_request_init(req);
77}
78
79static void __fuse_get_request(struct fuse_req *req) 67static void __fuse_get_request(struct fuse_req *req)
80{ 68{
81 atomic_inc(&req->count); 69 atomic_inc(&req->count);
@@ -103,6 +91,10 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
103 if (intr) 91 if (intr)
104 goto out; 92 goto out;
105 93
94 err = -ENOTCONN;
95 if (!fc->connected)
96 goto out;
97
106 req = fuse_request_alloc(); 98 req = fuse_request_alloc();
107 err = -ENOMEM; 99 err = -ENOMEM;
108 if (!req) 100 if (!req)
@@ -129,113 +121,38 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
129} 121}
130 122
131/* 123/*
132 * Called with sbput_sem held for read (request_end) or write
133 * (fuse_put_super). By the time fuse_put_super() is finished, all
134 * inodes belonging to background requests must be released, so the
135 * iputs have to be done within the locked region.
136 */
137void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
138{
139 iput(req->inode);
140 iput(req->inode2);
141 spin_lock(&fc->lock);
142 list_del(&req->bg_entry);
143 if (fc->num_background == FUSE_MAX_BACKGROUND) {
144 fc->blocked = 0;
145 wake_up_all(&fc->blocked_waitq);
146 }
147 fc->num_background--;
148 spin_unlock(&fc->lock);
149}
150
151/*
152 * This function is called when a request is finished. Either a reply 124 * 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 125 * has arrived or it was interrupted (and not yet sent) or some error
154 * occurred during communication with userspace, or the device file 126 * occurred during communication with userspace, or the device file
155 * was closed. In case of a background request the reference to the 127 * was closed. The requester thread is woken up (if still waiting),
156 * stored objects are released. The requester thread is woken up (if 128 * the 'end' callback is called if given, else the reference to the
157 * still waiting), the 'end' callback is called if given, else the 129 * request is released
158 * reference to the request is released
159 *
160 * Releasing extra reference for foreground requests must be done
161 * within the same locked region as setting state to finished. This
162 * is because fuse_reset_request() may be called after request is
163 * finished and it must be the sole possessor. If request is
164 * interrupted and put in the background, it will return with an error
165 * and hence never be reset and reused.
166 * 130 *
167 * Called with fc->lock, unlocks it 131 * Called with fc->lock, unlocks it
168 */ 132 */
169static void request_end(struct fuse_conn *fc, struct fuse_req *req) 133static void request_end(struct fuse_conn *fc, struct fuse_req *req)
170{ 134{
135 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
136 req->end = NULL;
171 list_del(&req->list); 137 list_del(&req->list);
172 req->state = FUSE_REQ_FINISHED; 138 req->state = FUSE_REQ_FINISHED;
173 if (!req->background) { 139 if (req->background) {
174 spin_unlock(&fc->lock); 140 if (fc->num_background == FUSE_MAX_BACKGROUND) {
175 wake_up(&req->waitq); 141 fc->blocked = 0;
176 fuse_put_request(fc, req); 142 wake_up_all(&fc->blocked_waitq);
177 } else { 143 }
178 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; 144 fc->num_background--;
179 req->end = NULL;
180 spin_unlock(&fc->lock);
181 down_read(&fc->sbput_sem);
182 if (fc->mounted)
183 fuse_release_background(fc, req);
184 up_read(&fc->sbput_sem);
185
186 /* fput must go outside sbput_sem, otherwise it can deadlock */
187 if (req->file)
188 fput(req->file);
189
190 if (end)
191 end(fc, req);
192 else
193 fuse_put_request(fc, req);
194 } 145 }
195} 146 spin_unlock(&fc->lock);
196 147 dput(req->dentry);
197/* 148 mntput(req->vfsmount);
198 * Unfortunately request interruption not just solves the deadlock
199 * problem, it causes problems too. These stem from the fact, that an
200 * interrupted request is continued to be processed in userspace,
201 * while all the locks and object references (inode and file) held
202 * during the operation are released.
203 *
204 * To release the locks is exactly why there's a need to interrupt the
205 * request, so there's not a lot that can be done about this, except
206 * introduce additional locking in userspace.
207 *
208 * More important is to keep inode and file references until userspace
209 * has replied, otherwise FORGET and RELEASE could be sent while the
210 * inode/file is still used by the filesystem.
211 *
212 * For this reason the concept of "background" request is introduced.
213 * An interrupted request is backgrounded if it has been already sent
214 * to userspace. Backgrounding involves getting an extra reference to
215 * inode(s) or file used in the request, and adding the request to
216 * fc->background list. When a reply is received for a background
217 * request, the object references are released, and the request is
218 * removed from the list. If the filesystem is unmounted while there
219 * are still background requests, the list is walked and references
220 * are released as if a reply was received.
221 *
222 * There's one more use for a background request. The RELEASE message is
223 * always sent as background, since it doesn't return an error or
224 * data.
225 */
226static void background_request(struct fuse_conn *fc, struct fuse_req *req)
227{
228 req->background = 1;
229 list_add(&req->bg_entry, &fc->background);
230 fc->num_background++;
231 if (fc->num_background == FUSE_MAX_BACKGROUND)
232 fc->blocked = 1;
233 if (req->inode)
234 req->inode = igrab(req->inode);
235 if (req->inode2)
236 req->inode2 = igrab(req->inode2);
237 if (req->file) 149 if (req->file)
238 get_file(req->file); 150 fput(req->file);
151 wake_up(&req->waitq);
152 if (end)
153 end(fc, req);
154 else
155 fuse_put_request(fc, req);
239} 156}
240 157
241/* Called with fc->lock held. Releases, and then reacquires it. */ 158/* Called with fc->lock held. Releases, and then reacquires it. */
@@ -244,9 +161,14 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
244 sigset_t oldset; 161 sigset_t oldset;
245 162
246 spin_unlock(&fc->lock); 163 spin_unlock(&fc->lock);
247 block_sigs(&oldset); 164 if (req->force)
248 wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED); 165 wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
249 restore_sigs(&oldset); 166 else {
167 block_sigs(&oldset);
168 wait_event_interruptible(req->waitq,
169 req->state == FUSE_REQ_FINISHED);
170 restore_sigs(&oldset);
171 }
250 spin_lock(&fc->lock); 172 spin_lock(&fc->lock);
251 if (req->state == FUSE_REQ_FINISHED && !req->interrupted) 173 if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
252 return; 174 return;
@@ -268,8 +190,11 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
268 if (req->state == FUSE_REQ_PENDING) { 190 if (req->state == FUSE_REQ_PENDING) {
269 list_del(&req->list); 191 list_del(&req->list);
270 __fuse_put_request(req); 192 __fuse_put_request(req);
271 } else if (req->state == FUSE_REQ_SENT) 193 } else if (req->state == FUSE_REQ_SENT) {
272 background_request(fc, req); 194 spin_unlock(&fc->lock);
195 wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
196 spin_lock(&fc->lock);
197 }
273} 198}
274 199
275static unsigned len_args(unsigned numargs, struct fuse_arg *args) 200static unsigned len_args(unsigned numargs, struct fuse_arg *args)
@@ -327,8 +252,12 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
327static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) 252static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
328{ 253{
329 spin_lock(&fc->lock); 254 spin_lock(&fc->lock);
330 background_request(fc, req);
331 if (fc->connected) { 255 if (fc->connected) {
256 req->background = 1;
257 fc->num_background++;
258 if (fc->num_background == FUSE_MAX_BACKGROUND)
259 fc->blocked = 1;
260
332 queue_request(fc, req); 261 queue_request(fc, req);
333 spin_unlock(&fc->lock); 262 spin_unlock(&fc->lock);
334 } else { 263 } else {
@@ -883,10 +812,12 @@ void fuse_abort_conn(struct fuse_conn *fc)
883 spin_lock(&fc->lock); 812 spin_lock(&fc->lock);
884 if (fc->connected) { 813 if (fc->connected) {
885 fc->connected = 0; 814 fc->connected = 0;
815 fc->blocked = 0;
886 end_io_requests(fc); 816 end_io_requests(fc);
887 end_requests(fc, &fc->pending); 817 end_requests(fc, &fc->pending);
888 end_requests(fc, &fc->processing); 818 end_requests(fc, &fc->processing);
889 wake_up_all(&fc->waitq); 819 wake_up_all(&fc->waitq);
820 wake_up_all(&fc->blocked_waitq);
890 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 821 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
891 } 822 }
892 spin_unlock(&fc->lock); 823 spin_unlock(&fc->lock);