aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 4526da8907c6..0c9a2ee54c91 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -66,6 +66,12 @@ static void restore_sigs(sigset_t *oldset)
66 sigprocmask(SIG_SETMASK, oldset, NULL); 66 sigprocmask(SIG_SETMASK, oldset, NULL);
67} 67}
68 68
69/*
70 * Reset request, so that it can be reused
71 *
72 * The caller must be _very_ careful to make sure, that it is holding
73 * the only reference to req
74 */
69void fuse_reset_request(struct fuse_req *req) 75void fuse_reset_request(struct fuse_req *req)
70{ 76{
71 int preallocated = req->preallocated; 77 int preallocated = req->preallocated;
@@ -120,9 +126,9 @@ struct fuse_req *fuse_get_request(struct fuse_conn *fc)
120 return do_get_request(fc); 126 return do_get_request(fc);
121} 127}
122 128
129/* Must be called with fuse_lock held */
123static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req) 130static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
124{ 131{
125 spin_lock(&fuse_lock);
126 if (req->preallocated) { 132 if (req->preallocated) {
127 atomic_dec(&fc->num_waiting); 133 atomic_dec(&fc->num_waiting);
128 list_add(&req->list, &fc->unused_list); 134 list_add(&req->list, &fc->unused_list);
@@ -134,11 +140,19 @@ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
134 fc->outstanding_debt--; 140 fc->outstanding_debt--;
135 else 141 else
136 up(&fc->outstanding_sem); 142 up(&fc->outstanding_sem);
137 spin_unlock(&fuse_lock);
138} 143}
139 144
140void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) 145void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
141{ 146{
147 if (atomic_dec_and_test(&req->count)) {
148 spin_lock(&fuse_lock);
149 fuse_putback_request(fc, req);
150 spin_unlock(&fuse_lock);
151 }
152}
153
154static void fuse_put_request_locked(struct fuse_conn *fc, struct fuse_req *req)
155{
142 if (atomic_dec_and_test(&req->count)) 156 if (atomic_dec_and_test(&req->count))
143 fuse_putback_request(fc, req); 157 fuse_putback_request(fc, req);
144} 158}
@@ -163,26 +177,36 @@ void fuse_release_background(struct fuse_req *req)
163 * still waiting), the 'end' callback is called if given, else the 177 * still waiting), the 'end' callback is called if given, else the
164 * reference to the request is released 178 * reference to the request is released
165 * 179 *
180 * Releasing extra reference for foreground requests must be done
181 * within the same locked region as setting state to finished. This
182 * is because fuse_reset_request() may be called after request is
183 * finished and it must be the sole possessor. If request is
184 * interrupted and put in the background, it will return with an error
185 * and hence never be reset and reused.
186 *
166 * Called with fuse_lock, unlocks it 187 * Called with fuse_lock, unlocks it
167 */ 188 */
168static void request_end(struct fuse_conn *fc, struct fuse_req *req) 189static void request_end(struct fuse_conn *fc, struct fuse_req *req)
169{ 190{
170 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
171 req->end = NULL;
172 list_del(&req->list); 191 list_del(&req->list);
173 req->state = FUSE_REQ_FINISHED; 192 req->state = FUSE_REQ_FINISHED;
174 spin_unlock(&fuse_lock); 193 if (!req->background) {
175 if (req->background) { 194 wake_up(&req->waitq);
195 fuse_put_request_locked(fc, req);
196 spin_unlock(&fuse_lock);
197 } else {
198 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
199 req->end = NULL;
200 spin_unlock(&fuse_lock);
176 down_read(&fc->sbput_sem); 201 down_read(&fc->sbput_sem);
177 if (fc->mounted) 202 if (fc->mounted)
178 fuse_release_background(req); 203 fuse_release_background(req);
179 up_read(&fc->sbput_sem); 204 up_read(&fc->sbput_sem);
205 if (end)
206 end(fc, req);
207 else
208 fuse_put_request(fc, req);
180 } 209 }
181 wake_up(&req->waitq);
182 if (end)
183 end(fc, req);
184 else
185 fuse_put_request(fc, req);
186} 210}
187 211
188/* 212/*