aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-01-17 01:14:42 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-17 02:15:31 -0500
commit64c6d8ed4c55f0a99b1b81558851da80c8d58244 (patch)
treeb8cfa96b8de4357e969e9492bfea65b22b0cca88 /fs/fuse
parent69a53bf267fa58b89aa659d121dfe38436562a30 (diff)
[PATCH] fuse: add asynchronous request support
Add possibility for requests to run asynchronously and call an 'end' callback when finished. With this, the special handling of the INIT and RELEASE requests can be cleaned up too. 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')
-rw-r--r--fs/fuse/dev.c42
-rw-r--r--fs/fuse/file.c10
-rw-r--r--fs/fuse/fuse_i.h5
3 files changed, 43 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 */
188static void request_end(struct fuse_conn *fc, struct fuse_req *req) 190static 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 */
868static void end_io_requests(struct fuse_conn *fc) 871static 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
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 52557664a89e..043d5b36846d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -113,6 +113,14 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
113 return err; 113 return err;
114} 114}
115 115
116/* Special case for failed iget in CREATE */
117static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
118{
119 u64 nodeid = req->in.h.nodeid;
120 fuse_reset_request(req);
121 fuse_send_forget(fc, req, nodeid, 1);
122}
123
116void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, 124void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
117 u64 nodeid, struct inode *inode, int flags, int isdir) 125 u64 nodeid, struct inode *inode, int flags, int isdir)
118{ 126{
@@ -128,6 +136,8 @@ void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
128 req->in.args[0].size = sizeof(struct fuse_release_in); 136 req->in.args[0].size = sizeof(struct fuse_release_in);
129 req->in.args[0].value = inarg; 137 req->in.args[0].value = inarg;
130 request_send_background(fc, req); 138 request_send_background(fc, req);
139 if (!inode)
140 req->end = fuse_release_end;
131 kfree(ff); 141 kfree(ff);
132} 142}
133 143
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e6381db41df9..145098056ca6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -120,6 +120,8 @@ enum fuse_req_state {
120 FUSE_REQ_FINISHED 120 FUSE_REQ_FINISHED
121}; 121};
122 122
123struct fuse_conn;
124
123/** 125/**
124 * A request to the client 126 * A request to the client
125 */ 127 */
@@ -186,6 +188,9 @@ struct fuse_req {
186 188
187 /** File used in the request (or NULL) */ 189 /** File used in the request (or NULL) */
188 struct file *file; 190 struct file *file;
191
192 /** Request completion callback */
193 void (*end)(struct fuse_conn *, struct fuse_req *);
189}; 194};
190 195
191/** 196/**