diff options
Diffstat (limited to 'fs/fuse/dev.c')
| -rw-r--r-- | fs/fuse/dev.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ba1107977f2e..ed19a7d622fa 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -131,6 +131,13 @@ static void fuse_req_init_context(struct fuse_req *req) | |||
| 131 | req->in.h.pid = current->pid; | 131 | req->in.h.pid = current->pid; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | void fuse_set_initialized(struct fuse_conn *fc) | ||
| 135 | { | ||
| 136 | /* Make sure stores before this are seen on another CPU */ | ||
| 137 | smp_wmb(); | ||
| 138 | fc->initialized = 1; | ||
| 139 | } | ||
| 140 | |||
| 134 | static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) | 141 | static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) |
| 135 | { | 142 | { |
| 136 | return !fc->initialized || (for_background && fc->blocked); | 143 | return !fc->initialized || (for_background && fc->blocked); |
| @@ -155,6 +162,8 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, | |||
| 155 | if (intr) | 162 | if (intr) |
| 156 | goto out; | 163 | goto out; |
| 157 | } | 164 | } |
| 165 | /* Matches smp_wmb() in fuse_set_initialized() */ | ||
| 166 | smp_rmb(); | ||
| 158 | 167 | ||
| 159 | err = -ENOTCONN; | 168 | err = -ENOTCONN; |
| 160 | if (!fc->connected) | 169 | if (!fc->connected) |
| @@ -253,6 +262,8 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc, | |||
| 253 | 262 | ||
| 254 | atomic_inc(&fc->num_waiting); | 263 | atomic_inc(&fc->num_waiting); |
| 255 | wait_event(fc->blocked_waitq, fc->initialized); | 264 | wait_event(fc->blocked_waitq, fc->initialized); |
| 265 | /* Matches smp_wmb() in fuse_set_initialized() */ | ||
| 266 | smp_rmb(); | ||
| 256 | req = fuse_request_alloc(0); | 267 | req = fuse_request_alloc(0); |
| 257 | if (!req) | 268 | if (!req) |
| 258 | req = get_reserved_req(fc, file); | 269 | req = get_reserved_req(fc, file); |
| @@ -511,6 +522,39 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | |||
| 511 | } | 522 | } |
| 512 | EXPORT_SYMBOL_GPL(fuse_request_send); | 523 | EXPORT_SYMBOL_GPL(fuse_request_send); |
| 513 | 524 | ||
| 525 | static void fuse_adjust_compat(struct fuse_conn *fc, struct fuse_args *args) | ||
| 526 | { | ||
| 527 | if (fc->minor < 4 && args->in.h.opcode == FUSE_STATFS) | ||
| 528 | args->out.args[0].size = FUSE_COMPAT_STATFS_SIZE; | ||
| 529 | |||
| 530 | if (fc->minor < 9) { | ||
| 531 | switch (args->in.h.opcode) { | ||
| 532 | case FUSE_LOOKUP: | ||
| 533 | case FUSE_CREATE: | ||
| 534 | case FUSE_MKNOD: | ||
| 535 | case FUSE_MKDIR: | ||
| 536 | case FUSE_SYMLINK: | ||
| 537 | case FUSE_LINK: | ||
| 538 | args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; | ||
| 539 | break; | ||
| 540 | case FUSE_GETATTR: | ||
| 541 | case FUSE_SETATTR: | ||
| 542 | args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; | ||
| 543 | break; | ||
| 544 | } | ||
| 545 | } | ||
| 546 | if (fc->minor < 12) { | ||
| 547 | switch (args->in.h.opcode) { | ||
| 548 | case FUSE_CREATE: | ||
| 549 | args->in.args[0].size = sizeof(struct fuse_open_in); | ||
| 550 | break; | ||
| 551 | case FUSE_MKNOD: | ||
| 552 | args->in.args[0].size = FUSE_COMPAT_MKNOD_IN_SIZE; | ||
| 553 | break; | ||
| 554 | } | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 514 | ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) | 558 | ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) |
| 515 | { | 559 | { |
| 516 | struct fuse_req *req; | 560 | struct fuse_req *req; |
| @@ -520,6 +564,9 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) | |||
| 520 | if (IS_ERR(req)) | 564 | if (IS_ERR(req)) |
| 521 | return PTR_ERR(req); | 565 | return PTR_ERR(req); |
| 522 | 566 | ||
| 567 | /* Needs to be done after fuse_get_req() so that fc->minor is valid */ | ||
| 568 | fuse_adjust_compat(fc, args); | ||
| 569 | |||
| 523 | req->in.h.opcode = args->in.h.opcode; | 570 | req->in.h.opcode = args->in.h.opcode; |
| 524 | req->in.h.nodeid = args->in.h.nodeid; | 571 | req->in.h.nodeid = args->in.h.nodeid; |
| 525 | req->in.numargs = args->in.numargs; | 572 | req->in.numargs = args->in.numargs; |
| @@ -2127,7 +2174,7 @@ void fuse_abort_conn(struct fuse_conn *fc) | |||
| 2127 | if (fc->connected) { | 2174 | if (fc->connected) { |
| 2128 | fc->connected = 0; | 2175 | fc->connected = 0; |
| 2129 | fc->blocked = 0; | 2176 | fc->blocked = 0; |
| 2130 | fc->initialized = 1; | 2177 | fuse_set_initialized(fc); |
| 2131 | end_io_requests(fc); | 2178 | end_io_requests(fc); |
| 2132 | end_queued_requests(fc); | 2179 | end_queued_requests(fc); |
| 2133 | end_polls(fc); | 2180 | end_polls(fc); |
| @@ -2146,7 +2193,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) | |||
| 2146 | spin_lock(&fc->lock); | 2193 | spin_lock(&fc->lock); |
| 2147 | fc->connected = 0; | 2194 | fc->connected = 0; |
| 2148 | fc->blocked = 0; | 2195 | fc->blocked = 0; |
| 2149 | fc->initialized = 1; | 2196 | fuse_set_initialized(fc); |
| 2150 | end_queued_requests(fc); | 2197 | end_queued_requests(fc); |
| 2151 | end_polls(fc); | 2198 | end_polls(fc); |
| 2152 | wake_up_all(&fc->blocked_waitq); | 2199 | wake_up_all(&fc->blocked_waitq); |
