aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dev.c40
-rw-r--r--fs/fuse/file.c9
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/inode.c14
4 files changed, 51 insertions, 15 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 4526da8907c6..f556a0d5c0d3 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -120,9 +120,9 @@ struct fuse_req *fuse_get_request(struct fuse_conn *fc)
120 return do_get_request(fc); 120 return do_get_request(fc);
121} 121}
122 122
123/* Must be called with fuse_lock held */
123static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req) 124static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
124{ 125{
125 spin_lock(&fuse_lock);
126 if (req->preallocated) { 126 if (req->preallocated) {
127 atomic_dec(&fc->num_waiting); 127 atomic_dec(&fc->num_waiting);
128 list_add(&req->list, &fc->unused_list); 128 list_add(&req->list, &fc->unused_list);
@@ -134,11 +134,19 @@ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
134 fc->outstanding_debt--; 134 fc->outstanding_debt--;
135 else 135 else
136 up(&fc->outstanding_sem); 136 up(&fc->outstanding_sem);
137 spin_unlock(&fuse_lock);
138} 137}
139 138
140void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) 139void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
141{ 140{
141 if (atomic_dec_and_test(&req->count)) {
142 spin_lock(&fuse_lock);
143 fuse_putback_request(fc, req);
144 spin_unlock(&fuse_lock);
145 }
146}
147
148static void fuse_put_request_locked(struct fuse_conn *fc, struct fuse_req *req)
149{
142 if (atomic_dec_and_test(&req->count)) 150 if (atomic_dec_and_test(&req->count))
143 fuse_putback_request(fc, req); 151 fuse_putback_request(fc, req);
144} 152}
@@ -163,26 +171,36 @@ void fuse_release_background(struct fuse_req *req)
163 * still waiting), the 'end' callback is called if given, else the 171 * still waiting), the 'end' callback is called if given, else the
164 * reference to the request is released 172 * reference to the request is released
165 * 173 *
174 * Releasing extra reference for foreground requests must be done
175 * within the same locked region as setting state to finished. This
176 * is because fuse_reset_request() may be called after request is
177 * finished and it must be the sole possessor. If request is
178 * interrupted and put in the background, it will return with an error
179 * and hence never be reset and reused.
180 *
166 * Called with fuse_lock, unlocks it 181 * Called with fuse_lock, unlocks it
167 */ 182 */
168static void request_end(struct fuse_conn *fc, struct fuse_req *req) 183static void request_end(struct fuse_conn *fc, struct fuse_req *req)
169{ 184{
170 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
171 req->end = NULL;
172 list_del(&req->list); 185 list_del(&req->list);
173 req->state = FUSE_REQ_FINISHED; 186 req->state = FUSE_REQ_FINISHED;
174 spin_unlock(&fuse_lock); 187 if (!req->background) {
175 if (req->background) { 188 wake_up(&req->waitq);
189 fuse_put_request_locked(fc, req);
190 spin_unlock(&fuse_lock);
191 } else {
192 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
193 req->end = NULL;
194 spin_unlock(&fuse_lock);
176 down_read(&fc->sbput_sem); 195 down_read(&fc->sbput_sem);
177 if (fc->mounted) 196 if (fc->mounted)
178 fuse_release_background(req); 197 fuse_release_background(req);
179 up_read(&fc->sbput_sem); 198 up_read(&fc->sbput_sem);
199 if (end)
200 end(fc, req);
201 else
202 fuse_put_request(fc, req);
180 } 203 }
181 wake_up(&req->waitq);
182 if (end)
183 end(fc, req);
184 else
185 fuse_put_request(fc, req);
186} 204}
187 205
188/* 206/*
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a7ef5e716f3c..296351615b00 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -335,9 +335,14 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
335 loff_t pos = page_offset(req->pages[0]); 335 loff_t pos = page_offset(req->pages[0]);
336 size_t count = req->num_pages << PAGE_CACHE_SHIFT; 336 size_t count = req->num_pages << PAGE_CACHE_SHIFT;
337 req->out.page_zeroing = 1; 337 req->out.page_zeroing = 1;
338 req->end = fuse_readpages_end;
339 fuse_read_fill(req, file, inode, pos, count, FUSE_READ); 338 fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
340 request_send_background(fc, req); 339 if (fc->async_read) {
340 req->end = fuse_readpages_end;
341 request_send_background(fc, req);
342 } else {
343 request_send(fc, req);
344 fuse_readpages_end(fc, req);
345 }
341} 346}
342 347
343struct fuse_readpages_data { 348struct fuse_readpages_data {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 46cf933aa3bf..4a83adfec968 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -272,6 +272,9 @@ struct fuse_conn {
272 reply, before any other request, and never cleared */ 272 reply, before any other request, and never cleared */
273 unsigned conn_error : 1; 273 unsigned conn_error : 1;
274 274
275 /** Do readpages asynchronously? Only set in INIT */
276 unsigned async_read : 1;
277
275 /* 278 /*
276 * The following bitfields are only for optimization purposes 279 * The following bitfields are only for optimization purposes
277 * and hence races in setting them will not cause malfunction 280 * and hence races in setting them will not cause malfunction
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index c755a0440a66..879e6fba9480 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -473,6 +473,16 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
473 if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) 473 if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
474 fc->conn_error = 1; 474 fc->conn_error = 1;
475 else { 475 else {
476 unsigned long ra_pages;
477
478 if (arg->minor >= 6) {
479 ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
480 if (arg->flags & FUSE_ASYNC_READ)
481 fc->async_read = 1;
482 } else
483 ra_pages = fc->max_read / PAGE_CACHE_SIZE;
484
485 fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
476 fc->minor = arg->minor; 486 fc->minor = arg->minor;
477 fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; 487 fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
478 } 488 }
@@ -496,6 +506,8 @@ static void fuse_send_init(struct fuse_conn *fc)
496 506
497 arg->major = FUSE_KERNEL_VERSION; 507 arg->major = FUSE_KERNEL_VERSION;
498 arg->minor = FUSE_KERNEL_MINOR_VERSION; 508 arg->minor = FUSE_KERNEL_MINOR_VERSION;
509 arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
510 arg->flags |= FUSE_ASYNC_READ;
499 req->in.h.opcode = FUSE_INIT; 511 req->in.h.opcode = FUSE_INIT;
500 req->in.numargs = 1; 512 req->in.numargs = 1;
501 req->in.args[0].size = sizeof(*arg); 513 req->in.args[0].size = sizeof(*arg);
@@ -552,8 +564,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
552 fc->user_id = d.user_id; 564 fc->user_id = d.user_id;
553 fc->group_id = d.group_id; 565 fc->group_id = d.group_id;
554 fc->max_read = d.max_read; 566 fc->max_read = d.max_read;
555 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
556 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
557 567
558 /* Used by get_root_inode() */ 568 /* Used by get_root_inode() */
559 sb->s_fs_info = fc; 569 sb->s_fs_info = fc;