aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-01-15 20:58:16 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-01-15 20:58:16 -0500
commitcb59670870d90ff8bc31f5f2efc407c6fe4938c0 (patch)
tree9b98fe97ca563de8b06f4c2200b4be7e449ff0e1 /fs
parent0b6212e0a426d75239757dc5d23e9814c2e4d1ad (diff)
parent9759bd51899458af4f4bcc11046f01285642ca10 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse fixes from Miklos Szeredi: "This fixes a regression in the latest fuse update plus a fix for a rather theoretical memory ordering issue" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: add memory barrier to INIT fuse: fix LOOKUP vs INIT compat handling
Diffstat (limited to 'fs')
-rw-r--r--fs/fuse/dev.c51
-rw-r--r--fs/fuse/dir.c31
-rw-r--r--fs/fuse/fuse_i.h2
-rw-r--r--fs/fuse/inode.c5
4 files changed, 60 insertions, 29 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
134void 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
134static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) 141static 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}
512EXPORT_SYMBOL_GPL(fuse_request_send); 523EXPORT_SYMBOL_GPL(fuse_request_send);
513 524
525static 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
514ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) 558ssize_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);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 252b8a5de8b5..08e7b1a9d5d0 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -156,10 +156,7 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
156 args->in.args[0].size = name->len + 1; 156 args->in.args[0].size = name->len + 1;
157 args->in.args[0].value = name->name; 157 args->in.args[0].value = name->name;
158 args->out.numargs = 1; 158 args->out.numargs = 1;
159 if (fc->minor < 9) 159 args->out.args[0].size = sizeof(struct fuse_entry_out);
160 args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
161 else
162 args->out.args[0].size = sizeof(struct fuse_entry_out);
163 args->out.args[0].value = outarg; 160 args->out.args[0].value = outarg;
164} 161}
165 162
@@ -422,16 +419,12 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
422 args.in.h.opcode = FUSE_CREATE; 419 args.in.h.opcode = FUSE_CREATE;
423 args.in.h.nodeid = get_node_id(dir); 420 args.in.h.nodeid = get_node_id(dir);
424 args.in.numargs = 2; 421 args.in.numargs = 2;
425 args.in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : 422 args.in.args[0].size = sizeof(inarg);
426 sizeof(inarg);
427 args.in.args[0].value = &inarg; 423 args.in.args[0].value = &inarg;
428 args.in.args[1].size = entry->d_name.len + 1; 424 args.in.args[1].size = entry->d_name.len + 1;
429 args.in.args[1].value = entry->d_name.name; 425 args.in.args[1].value = entry->d_name.name;
430 args.out.numargs = 2; 426 args.out.numargs = 2;
431 if (fc->minor < 9) 427 args.out.args[0].size = sizeof(outentry);
432 args.out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
433 else
434 args.out.args[0].size = sizeof(outentry);
435 args.out.args[0].value = &outentry; 428 args.out.args[0].value = &outentry;
436 args.out.args[1].size = sizeof(outopen); 429 args.out.args[1].size = sizeof(outopen);
437 args.out.args[1].value = &outopen; 430 args.out.args[1].value = &outopen;
@@ -539,10 +532,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
539 memset(&outarg, 0, sizeof(outarg)); 532 memset(&outarg, 0, sizeof(outarg));
540 args->in.h.nodeid = get_node_id(dir); 533 args->in.h.nodeid = get_node_id(dir);
541 args->out.numargs = 1; 534 args->out.numargs = 1;
542 if (fc->minor < 9) 535 args->out.args[0].size = sizeof(outarg);
543 args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
544 else
545 args->out.args[0].size = sizeof(outarg);
546 args->out.args[0].value = &outarg; 536 args->out.args[0].value = &outarg;
547 err = fuse_simple_request(fc, args); 537 err = fuse_simple_request(fc, args);
548 if (err) 538 if (err)
@@ -592,8 +582,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
592 inarg.umask = current_umask(); 582 inarg.umask = current_umask();
593 args.in.h.opcode = FUSE_MKNOD; 583 args.in.h.opcode = FUSE_MKNOD;
594 args.in.numargs = 2; 584 args.in.numargs = 2;
595 args.in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : 585 args.in.args[0].size = sizeof(inarg);
596 sizeof(inarg);
597 args.in.args[0].value = &inarg; 586 args.in.args[0].value = &inarg;
598 args.in.args[1].size = entry->d_name.len + 1; 587 args.in.args[1].size = entry->d_name.len + 1;
599 args.in.args[1].value = entry->d_name.name; 588 args.in.args[1].value = entry->d_name.name;
@@ -899,10 +888,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
899 args.in.args[0].size = sizeof(inarg); 888 args.in.args[0].size = sizeof(inarg);
900 args.in.args[0].value = &inarg; 889 args.in.args[0].value = &inarg;
901 args.out.numargs = 1; 890 args.out.numargs = 1;
902 if (fc->minor < 9) 891 args.out.args[0].size = sizeof(outarg);
903 args.out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
904 else
905 args.out.args[0].size = sizeof(outarg);
906 args.out.args[0].value = &outarg; 892 args.out.args[0].value = &outarg;
907 err = fuse_simple_request(fc, &args); 893 err = fuse_simple_request(fc, &args);
908 if (!err) { 894 if (!err) {
@@ -1574,10 +1560,7 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args,
1574 args->in.args[0].size = sizeof(*inarg_p); 1560 args->in.args[0].size = sizeof(*inarg_p);
1575 args->in.args[0].value = inarg_p; 1561 args->in.args[0].value = inarg_p;
1576 args->out.numargs = 1; 1562 args->out.numargs = 1;
1577 if (fc->minor < 9) 1563 args->out.args[0].size = sizeof(*outarg_p);
1578 args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
1579 else
1580 args->out.args[0].size = sizeof(*outarg_p);
1581 args->out.args[0].value = outarg_p; 1564 args->out.args[0].value = outarg_p;
1582} 1565}
1583 1566
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e0fc6725d1d0..1cdfb07c1376 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -906,4 +906,6 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
906int fuse_do_setattr(struct inode *inode, struct iattr *attr, 906int fuse_do_setattr(struct inode *inode, struct iattr *attr,
907 struct file *file); 907 struct file *file);
908 908
909void fuse_set_initialized(struct fuse_conn *fc);
910
909#endif /* _FS_FUSE_I_H */ 911#endif /* _FS_FUSE_I_H */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 6749109f255d..f38256e4476e 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -424,8 +424,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
424 args.in.h.opcode = FUSE_STATFS; 424 args.in.h.opcode = FUSE_STATFS;
425 args.in.h.nodeid = get_node_id(dentry->d_inode); 425 args.in.h.nodeid = get_node_id(dentry->d_inode);
426 args.out.numargs = 1; 426 args.out.numargs = 1;
427 args.out.args[0].size = 427 args.out.args[0].size = sizeof(outarg);
428 fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
429 args.out.args[0].value = &outarg; 428 args.out.args[0].value = &outarg;
430 err = fuse_simple_request(fc, &args); 429 err = fuse_simple_request(fc, &args);
431 if (!err) 430 if (!err)
@@ -898,7 +897,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
898 fc->max_write = max_t(unsigned, 4096, fc->max_write); 897 fc->max_write = max_t(unsigned, 4096, fc->max_write);
899 fc->conn_init = 1; 898 fc->conn_init = 1;
900 } 899 }
901 fc->initialized = 1; 900 fuse_set_initialized(fc);
902 wake_up_all(&fc->blocked_waitq); 901 wake_up_all(&fc->blocked_waitq);
903} 902}
904 903