diff options
Diffstat (limited to 'fs/fuse/dev.c')
| -rw-r--r-- | fs/fuse/dev.c | 128 |
1 files changed, 96 insertions, 32 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index e83351aa5bad..e9bdec0b16d9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -34,34 +34,67 @@ static struct fuse_conn *fuse_get_conn(struct file *file) | |||
| 34 | return file->private_data; | 34 | return file->private_data; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | static void fuse_request_init(struct fuse_req *req) | 37 | static void fuse_request_init(struct fuse_req *req, struct page **pages, |
| 38 | struct fuse_page_desc *page_descs, | ||
| 39 | unsigned npages) | ||
| 38 | { | 40 | { |
| 39 | memset(req, 0, sizeof(*req)); | 41 | memset(req, 0, sizeof(*req)); |
| 42 | memset(pages, 0, sizeof(*pages) * npages); | ||
| 43 | memset(page_descs, 0, sizeof(*page_descs) * npages); | ||
| 40 | INIT_LIST_HEAD(&req->list); | 44 | INIT_LIST_HEAD(&req->list); |
| 41 | INIT_LIST_HEAD(&req->intr_entry); | 45 | INIT_LIST_HEAD(&req->intr_entry); |
| 42 | init_waitqueue_head(&req->waitq); | 46 | init_waitqueue_head(&req->waitq); |
| 43 | atomic_set(&req->count, 1); | 47 | atomic_set(&req->count, 1); |
| 48 | req->pages = pages; | ||
| 49 | req->page_descs = page_descs; | ||
| 50 | req->max_pages = npages; | ||
| 44 | } | 51 | } |
| 45 | 52 | ||
| 46 | struct fuse_req *fuse_request_alloc(void) | 53 | static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags) |
| 47 | { | 54 | { |
| 48 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL); | 55 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags); |
| 49 | if (req) | 56 | if (req) { |
| 50 | fuse_request_init(req); | 57 | struct page **pages; |
| 58 | struct fuse_page_desc *page_descs; | ||
| 59 | |||
| 60 | if (npages <= FUSE_REQ_INLINE_PAGES) { | ||
| 61 | pages = req->inline_pages; | ||
| 62 | page_descs = req->inline_page_descs; | ||
| 63 | } else { | ||
| 64 | pages = kmalloc(sizeof(struct page *) * npages, flags); | ||
| 65 | page_descs = kmalloc(sizeof(struct fuse_page_desc) * | ||
| 66 | npages, flags); | ||
| 67 | } | ||
| 68 | |||
| 69 | if (!pages || !page_descs) { | ||
| 70 | kfree(pages); | ||
| 71 | kfree(page_descs); | ||
| 72 | kmem_cache_free(fuse_req_cachep, req); | ||
| 73 | return NULL; | ||
| 74 | } | ||
| 75 | |||
| 76 | fuse_request_init(req, pages, page_descs, npages); | ||
| 77 | } | ||
| 51 | return req; | 78 | return req; |
| 52 | } | 79 | } |
| 80 | |||
| 81 | struct fuse_req *fuse_request_alloc(unsigned npages) | ||
| 82 | { | ||
| 83 | return __fuse_request_alloc(npages, GFP_KERNEL); | ||
| 84 | } | ||
| 53 | EXPORT_SYMBOL_GPL(fuse_request_alloc); | 85 | EXPORT_SYMBOL_GPL(fuse_request_alloc); |
| 54 | 86 | ||
| 55 | struct fuse_req *fuse_request_alloc_nofs(void) | 87 | struct fuse_req *fuse_request_alloc_nofs(unsigned npages) |
| 56 | { | 88 | { |
| 57 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_NOFS); | 89 | return __fuse_request_alloc(npages, GFP_NOFS); |
| 58 | if (req) | ||
| 59 | fuse_request_init(req); | ||
| 60 | return req; | ||
| 61 | } | 90 | } |
| 62 | 91 | ||
| 63 | void fuse_request_free(struct fuse_req *req) | 92 | void fuse_request_free(struct fuse_req *req) |
| 64 | { | 93 | { |
| 94 | if (req->pages != req->inline_pages) { | ||
| 95 | kfree(req->pages); | ||
| 96 | kfree(req->page_descs); | ||
| 97 | } | ||
| 65 | kmem_cache_free(fuse_req_cachep, req); | 98 | kmem_cache_free(fuse_req_cachep, req); |
| 66 | } | 99 | } |
| 67 | 100 | ||
| @@ -97,7 +130,7 @@ static void fuse_req_init_context(struct fuse_req *req) | |||
| 97 | req->in.h.pid = current->pid; | 130 | req->in.h.pid = current->pid; |
| 98 | } | 131 | } |
| 99 | 132 | ||
| 100 | struct fuse_req *fuse_get_req(struct fuse_conn *fc) | 133 | struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages) |
| 101 | { | 134 | { |
| 102 | struct fuse_req *req; | 135 | struct fuse_req *req; |
| 103 | sigset_t oldset; | 136 | sigset_t oldset; |
| @@ -116,7 +149,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) | |||
| 116 | if (!fc->connected) | 149 | if (!fc->connected) |
| 117 | goto out; | 150 | goto out; |
| 118 | 151 | ||
| 119 | req = fuse_request_alloc(); | 152 | req = fuse_request_alloc(npages); |
| 120 | err = -ENOMEM; | 153 | err = -ENOMEM; |
| 121 | if (!req) | 154 | if (!req) |
| 122 | goto out; | 155 | goto out; |
| @@ -165,7 +198,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) | |||
| 165 | struct fuse_file *ff = file->private_data; | 198 | struct fuse_file *ff = file->private_data; |
| 166 | 199 | ||
| 167 | spin_lock(&fc->lock); | 200 | spin_lock(&fc->lock); |
| 168 | fuse_request_init(req); | 201 | fuse_request_init(req, req->pages, req->page_descs, req->max_pages); |
| 169 | BUG_ON(ff->reserved_req); | 202 | BUG_ON(ff->reserved_req); |
| 170 | ff->reserved_req = req; | 203 | ff->reserved_req = req; |
| 171 | wake_up_all(&fc->reserved_req_waitq); | 204 | wake_up_all(&fc->reserved_req_waitq); |
| @@ -186,13 +219,14 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) | |||
| 186 | * filesystem should not have it's own file open. If deadlock is | 219 | * filesystem should not have it's own file open. If deadlock is |
| 187 | * intentional, it can still be broken by "aborting" the filesystem. | 220 | * intentional, it can still be broken by "aborting" the filesystem. |
| 188 | */ | 221 | */ |
| 189 | struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file) | 222 | struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, |
| 223 | struct file *file) | ||
| 190 | { | 224 | { |
| 191 | struct fuse_req *req; | 225 | struct fuse_req *req; |
| 192 | 226 | ||
| 193 | atomic_inc(&fc->num_waiting); | 227 | atomic_inc(&fc->num_waiting); |
| 194 | wait_event(fc->blocked_waitq, !fc->blocked); | 228 | wait_event(fc->blocked_waitq, !fc->blocked); |
| 195 | req = fuse_request_alloc(); | 229 | req = fuse_request_alloc(0); |
| 196 | if (!req) | 230 | if (!req) |
| 197 | req = get_reserved_req(fc, file); | 231 | req = get_reserved_req(fc, file); |
| 198 | 232 | ||
| @@ -406,9 +440,8 @@ __acquires(fc->lock) | |||
| 406 | } | 440 | } |
| 407 | } | 441 | } |
| 408 | 442 | ||
| 409 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | 443 | static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) |
| 410 | { | 444 | { |
| 411 | req->isreply = 1; | ||
| 412 | spin_lock(&fc->lock); | 445 | spin_lock(&fc->lock); |
| 413 | if (!fc->connected) | 446 | if (!fc->connected) |
| 414 | req->out.h.error = -ENOTCONN; | 447 | req->out.h.error = -ENOTCONN; |
| @@ -425,6 +458,12 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | |||
| 425 | } | 458 | } |
| 426 | spin_unlock(&fc->lock); | 459 | spin_unlock(&fc->lock); |
| 427 | } | 460 | } |
| 461 | |||
| 462 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | ||
| 463 | { | ||
| 464 | req->isreply = 1; | ||
| 465 | __fuse_request_send(fc, req); | ||
| 466 | } | ||
| 428 | EXPORT_SYMBOL_GPL(fuse_request_send); | 467 | EXPORT_SYMBOL_GPL(fuse_request_send); |
| 429 | 468 | ||
| 430 | static void fuse_request_send_nowait_locked(struct fuse_conn *fc, | 469 | static void fuse_request_send_nowait_locked(struct fuse_conn *fc, |
| @@ -491,6 +530,27 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, | |||
| 491 | fuse_request_send_nowait_locked(fc, req); | 530 | fuse_request_send_nowait_locked(fc, req); |
| 492 | } | 531 | } |
| 493 | 532 | ||
| 533 | void fuse_force_forget(struct file *file, u64 nodeid) | ||
| 534 | { | ||
| 535 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 536 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
| 537 | struct fuse_req *req; | ||
| 538 | struct fuse_forget_in inarg; | ||
| 539 | |||
| 540 | memset(&inarg, 0, sizeof(inarg)); | ||
| 541 | inarg.nlookup = 1; | ||
| 542 | req = fuse_get_req_nofail_nopages(fc, file); | ||
| 543 | req->in.h.opcode = FUSE_FORGET; | ||
| 544 | req->in.h.nodeid = nodeid; | ||
| 545 | req->in.numargs = 1; | ||
| 546 | req->in.args[0].size = sizeof(inarg); | ||
| 547 | req->in.args[0].value = &inarg; | ||
| 548 | req->isreply = 0; | ||
| 549 | __fuse_request_send(fc, req); | ||
| 550 | /* ignore errors */ | ||
| 551 | fuse_put_request(fc, req); | ||
| 552 | } | ||
| 553 | |||
| 494 | /* | 554 | /* |
| 495 | * Lock the request. Up to the next unlock_request() there mustn't be | 555 | * Lock the request. Up to the next unlock_request() there mustn't be |
| 496 | * anything that could cause a page-fault. If the request was already | 556 | * anything that could cause a page-fault. If the request was already |
| @@ -850,11 +910,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, | |||
| 850 | { | 910 | { |
| 851 | unsigned i; | 911 | unsigned i; |
| 852 | struct fuse_req *req = cs->req; | 912 | struct fuse_req *req = cs->req; |
| 853 | unsigned offset = req->page_offset; | ||
| 854 | unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset); | ||
| 855 | 913 | ||
