diff options
| -rw-r--r-- | fs/fuse/cuse.c | 10 | ||||
| -rw-r--r-- | fs/fuse/dev.c | 128 | ||||
| -rw-r--r-- | fs/fuse/dir.c | 259 | ||||
| -rw-r--r-- | fs/fuse/file.c | 238 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 74 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 16 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 | ||||
| -rw-r--r-- | include/uapi/linux/fuse.h | 60 | ||||
| -rw-r--r-- | mm/filemap.c | 2 |
9 files changed, 609 insertions, 180 deletions
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index e397b675b029..6f96a8def147 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c | |||
| @@ -91,19 +91,22 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count, | |||
| 91 | loff_t *ppos) | 91 | loff_t *ppos) |
| 92 | { | 92 | { |
| 93 | loff_t pos = 0; | 93 | loff_t pos = 0; |
| 94 | struct iovec iov = { .iov_base = buf, .iov_len = count }; | ||
| 94 | 95 | ||
| 95 | return fuse_direct_io(file, buf, count, &pos, 0); | 96 | return fuse_direct_io(file, &iov, 1, count, &pos, 0); |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | static ssize_t cuse_write(struct file *file, const char __user *buf, | 99 | static ssize_t cuse_write(struct file *file, const char __user *buf, |
| 99 | size_t count, loff_t *ppos) | 100 | size_t count, loff_t *ppos) |
| 100 | { | 101 | { |
| 101 | loff_t pos = 0; | 102 | loff_t pos = 0; |
| 103 | struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; | ||
| 104 | |||
| 102 | /* | 105 | /* |
| 103 | * No locking or generic_write_checks(), the server is | 106 | * No locking or generic_write_checks(), the server is |
| 104 | * responsible for locking and sanity checks. | 107 | * responsible for locking and sanity checks. |
| 105 | */ | 108 | */ |
| 106 | return fuse_direct_io(file, buf, count, &pos, 1); | 109 | return fuse_direct_io(file, &iov, 1, count, &pos, 1); |
| 107 | } | 110 | } |
| 108 | 111 | ||
| 109 | static int cuse_open(struct inode *inode, struct file *file) | 112 | static int cuse_open(struct inode *inode, struct file *file) |
| @@ -419,7 +422,7 @@ static int cuse_send_init(struct cuse_conn *cc) | |||
| 419 | 422 | ||
| 420 | BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE); | 423 | BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE); |
| 421 | 424 | ||
| 422 | req = fuse_get_req(fc); | 425 | req = fuse_get_req(fc, 1); |
| 423 | if (IS_ERR(req)) { | 426 | if (IS_ERR(req)) { |
| 424 | rc = PTR_ERR(req); | 427 | rc = PTR_ERR(req); |
| 425 | goto err; | 428 | goto err; |
| @@ -449,6 +452,7 @@ static int cuse_send_init(struct cuse_conn *cc) | |||
| 449 | req->out.argvar = 1; | 452 | req->out.argvar = 1; |
| 450 | req->out.argpages = 1; | 453 | req->out.argpages = 1; |
| 451 | req->pages[0] = page; | 454 | req->pages[0] = page; |
| 455 | req->page_descs[0].length = req->out.args[1].size; | ||
| 452 | req->num_pages = 1; | 456 | req->num_pages = 1; |
| 453 | req->end = cuse_process_init_reply; | 457 | req->end = cuse_process_init_reply; |
| 454 | fuse_request_send_background(fc, req); | 458 | fuse_request_send_background(fc, req); |
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 | |||
