diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-22 13:42:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-22 13:42:43 -0400 |
commit | f741a79e982cf56d7584435bad663553ffe6715f (patch) | |
tree | 491f0a8a05d9add4c0338ee8af4a18f3508503cd /fs/fuse | |
parent | 73d5a8675f32b8e22e11773b314324316f920192 (diff) | |
parent | e7c0a167860620bd2938366896964f729ddaeaaa (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: make fuse_dentry_revalidate() RCU aware
fuse: make fuse_permission() RCU aware
fuse: wakeup pollers on connection release/abort
fuse: reduce size of struct fuse_request
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/cuse.c | 12 | ||||
-rw-r--r-- | fs/fuse/dev.c | 17 | ||||
-rw-r--r-- | fs/fuse/dir.c | 38 | ||||
-rw-r--r-- | fs/fuse/file.c | 2 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 1 |
5 files changed, 54 insertions, 16 deletions
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 7c39b885f969..b6cca47f7b07 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c | |||
@@ -305,7 +305,7 @@ static void cuse_gendev_release(struct device *dev) | |||
305 | static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | 305 | static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req) |
306 | { | 306 | { |
307 | struct cuse_conn *cc = fc_to_cc(fc); | 307 | struct cuse_conn *cc = fc_to_cc(fc); |
308 | struct cuse_init_out *arg = &req->misc.cuse_init_out; | 308 | struct cuse_init_out *arg = req->out.args[0].value; |
309 | struct page *page = req->pages[0]; | 309 | struct page *page = req->pages[0]; |
310 | struct cuse_devinfo devinfo = { }; | 310 | struct cuse_devinfo devinfo = { }; |
311 | struct device *dev; | 311 | struct device *dev; |
@@ -384,6 +384,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
384 | dev_set_uevent_suppress(dev, 0); | 384 | dev_set_uevent_suppress(dev, 0); |
385 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 385 | kobject_uevent(&dev->kobj, KOBJ_ADD); |
386 | out: | 386 | out: |
387 | kfree(arg); | ||
387 | __free_page(page); | 388 | __free_page(page); |
388 | return; | 389 | return; |
389 | 390 | ||
@@ -405,6 +406,7 @@ static int cuse_send_init(struct cuse_conn *cc) | |||
405 | struct page *page; | 406 | struct page *page; |
406 | struct fuse_conn *fc = &cc->fc; | 407 | struct fuse_conn *fc = &cc->fc; |
407 | struct cuse_init_in *arg; | 408 | struct cuse_init_in *arg; |
409 | void *outarg; | ||
408 | 410 | ||
409 | BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE); | 411 | BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE); |
410 | 412 | ||
@@ -419,6 +421,10 @@ static int cuse_send_init(struct cuse_conn *cc) | |||
419 | if (!page) | 421 | if (!page) |
420 | goto err_put_req; | 422 | goto err_put_req; |
421 | 423 | ||
424 | outarg = kzalloc(sizeof(struct cuse_init_out), GFP_KERNEL); | ||
425 | if (!outarg) | ||
426 | goto err_free_page; | ||
427 | |||
422 | arg = &req->misc.cuse_init_in; | 428 | arg = &req->misc.cuse_init_in; |
423 | arg->major = FUSE_KERNEL_VERSION; | 429 | arg->major = FUSE_KERNEL_VERSION; |
424 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 430 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
@@ -429,7 +435,7 @@ static int cuse_send_init(struct cuse_conn *cc) | |||
429 | req->in.args[0].value = arg; | 435 | req->in.args[0].value = arg; |
430 | req->out.numargs = 2; | 436 | req->out.numargs = 2; |
431 | req->out.args[0].size = sizeof(struct cuse_init_out); | 437 | req->out.args[0].size = sizeof(struct cuse_init_out); |
432 | req->out.args[0].value = &req->misc.cuse_init_out; | 438 | req->out.args[0].value = outarg; |
433 | req->out.args[1].size = CUSE_INIT_INFO_MAX; | 439 | req->out.args[1].size = CUSE_INIT_INFO_MAX; |
434 | req->out.argvar = 1; | 440 | req->out.argvar = 1; |
435 | req->out.argpages = 1; | 441 | req->out.argpages = 1; |
@@ -440,6 +446,8 @@ static int cuse_send_init(struct cuse_conn *cc) | |||
440 | 446 | ||
441 | return 0; | 447 | return 0; |
442 | 448 | ||
449 | err_free_page: | ||
450 | __free_page(page); | ||
443 | err_put_req: | 451 | err_put_req: |
444 | fuse_put_request(fc, req); | 452 | fuse_put_request(fc, req); |
445 | err: | 453 | err: |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index cf8d28d1fbad..213d3cf4f5e9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -1910,6 +1910,21 @@ __acquires(fc->lock) | |||
1910 | kfree(dequeue_forget(fc, 1, NULL)); | 1910 | kfree(dequeue_forget(fc, 1, NULL)); |
1911 | } | 1911 | } |
1912 | 1912 | ||
1913 | static void end_polls(struct fuse_conn *fc) | ||
1914 | { | ||
1915 | struct rb_node *p; | ||
1916 | |||
1917 | p = rb_first(&fc->polled_files); | ||
1918 | |||
1919 | while (p) { | ||
1920 | struct fuse_file *ff; | ||
1921 | ff = rb_entry(p, struct fuse_file, polled_node); | ||
1922 | wake_up_interruptible_all(&ff->poll_wait); | ||
1923 | |||
1924 | p = rb_next(p); | ||
1925 | } | ||
1926 | } | ||
1927 | |||
1913 | /* | 1928 | /* |
1914 | * Abort all requests. | 1929 | * Abort all requests. |
1915 | * | 1930 | * |
@@ -1937,6 +1952,7 @@ void fuse_abort_conn(struct fuse_conn *fc) | |||
1937 | fc->blocked = 0; | 1952 | fc->blocked = 0; |
1938 | end_io_requests(fc); | 1953 | end_io_requests(fc); |
1939 | end_queued_requests(fc); | 1954 | end_queued_requests(fc); |
1955 | end_polls(fc); | ||
1940 | wake_up_all(&fc->waitq); | 1956 | wake_up_all(&fc->waitq); |
1941 | wake_up_all(&fc->blocked_waitq); | 1957 | wake_up_all(&fc->blocked_waitq); |
1942 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 1958 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
@@ -1953,6 +1969,7 @@ int fuse_dev_release(struct inode *inode, struct file *file) | |||
1953 | fc->connected = 0; | 1969 | fc->connected = 0; |
1954 | fc->blocked = 0; | 1970 | fc->blocked = 0; |
1955 | end_queued_requests(fc); | 1971 | end_queued_requests(fc); |
1972 | end_polls(fc); | ||
1956 | wake_up_all(&fc->blocked_waitq); | 1973 | wake_up_all(&fc->blocked_waitq); |
1957 | spin_unlock(&fc->lock); | 1974 | spin_unlock(&fc->lock); |
1958 | fuse_conn_put(fc); | 1975 | fuse_conn_put(fc); |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8bd0ef9286c3..c6ba49bd95b3 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -158,10 +158,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
158 | { | 158 | { |
159 | struct inode *inode; | 159 | struct inode *inode; |
160 | 160 | ||
161 | if (nd && nd->flags & LOOKUP_RCU) | 161 | inode = ACCESS_ONCE(entry->d_inode); |
162 | return -ECHILD; | ||
163 | |||
164 | inode = entry->d_inode; | ||
165 | if (inode && is_bad_inode(inode)) | 162 | if (inode && is_bad_inode(inode)) |
166 | return 0; | 163 | return 0; |
167 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { | 164 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { |
@@ -177,6 +174,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
177 | if (!inode) | 174 | if (!inode) |
178 | return 0; | 175 | return 0; |
179 | 176 | ||
177 | if (nd->flags & LOOKUP_RCU) | ||
178 | return -ECHILD; | ||
179 | |||
180 | fc = get_fuse_conn(inode); | 180 | fc = get_fuse_conn(inode); |
181 | req = fuse_get_req(fc); | 181 | req = fuse_get_req(fc); |
182 | if (IS_ERR(req)) | 182 | if (IS_ERR(req)) |
@@ -970,6 +970,14 @@ static int fuse_access(struct inode *inode, int mask) | |||
970 | return err; | 970 | return err; |
971 | } | 971 | } |
972 | 972 | ||
973 | static int fuse_perm_getattr(struct inode *inode, int flags) | ||
974 | { | ||
975 | if (flags & IPERM_FLAG_RCU) | ||
976 | return -ECHILD; | ||
977 | |||
978 | return fuse_do_getattr(inode, NULL, NULL); | ||
979 | } | ||
980 | |||
973 | /* | 981 | /* |
974 | * Check permission. The two basic access models of FUSE are: | 982 | * Check permission. The two basic access models of FUSE are: |
975 | * | 983 | * |
@@ -989,9 +997,6 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags) | |||
989 | bool refreshed = false; | 997 | bool refreshed = false; |
990 | int err = 0; | 998 | int err = 0; |
991 | 999 | ||
992 | if (flags & IPERM_FLAG_RCU) | ||
993 | return -ECHILD; | ||
994 | |||
995 | if (!fuse_allow_task(fc, current)) | 1000 | if (!fuse_allow_task(fc, current)) |
996 | return -EACCES; | 1001 | return -EACCES; |
997 | 1002 | ||
@@ -1000,9 +1005,15 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags) | |||
1000 | */ | 1005 | */ |
1001 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || | 1006 | if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) || |
1002 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { | 1007 | ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { |
1003 | err = fuse_update_attributes(inode, NULL, NULL, &refreshed); | 1008 | struct fuse_inode *fi = get_fuse_inode(inode); |
1004 | if (err) | 1009 | |
1005 | return err; | 1010 | if (fi->i_time < get_jiffies_64()) { |
1011 | refreshed = true; | ||
1012 | |||
1013 | err = fuse_perm_getattr(inode, flags); | ||
1014 | if (err) | ||
1015 | return err; | ||
1016 | } | ||
1006 | } | 1017 | } |
1007 | 1018 | ||
1008 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { | 1019 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { |
@@ -1012,7 +1023,7 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags) | |||
1012 | attributes. This is also needed, because the root | 1023 | attributes. This is also needed, because the root |
1013 | node will at first have no permissions */ | 1024 | node will at first have no permissions */ |
1014 | if (err == -EACCES && !refreshed) { | 1025 | if (err == -EACCES && !refreshed) { |
1015 | err = fuse_do_getattr(inode, NULL, NULL); | 1026 | err = fuse_perm_getattr(inode, flags); |
1016 | if (!err) | 1027 | if (!err) |
1017 | err = generic_permission(inode, mask, | 1028 | err = generic_permission(inode, mask, |
1018 | flags, NULL); | 1029 | flags, NULL); |
@@ -1023,13 +1034,16 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags) | |||
1023 | noticed immediately, only after the attribute | 1034 | noticed immediately, only after the attribute |
1024 | timeout has expired */ | 1035 | timeout has expired */ |
1025 | } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { | 1036 | } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { |
1037 | if (flags & IPERM_FLAG_RCU) | ||
1038 | return -ECHILD; | ||
1039 | |||
1026 | err = fuse_access(inode, mask); | 1040 | err = fuse_access(inode, mask); |
1027 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { | 1041 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { |
1028 | if (!(inode->i_mode & S_IXUGO)) { | 1042 | if (!(inode->i_mode & S_IXUGO)) { |
1029 | if (refreshed) | 1043 | if (refreshed) |
1030 | return -EACCES; | 1044 | return -EACCES; |
1031 | 1045 | ||
1032 | err = fuse_do_getattr(inode, NULL, NULL); | 1046 | err = fuse_perm_getattr(inode, flags); |
1033 | if (!err && !(inode->i_mode & S_IXUGO)) | 1047 | if (!err && !(inode->i_mode & S_IXUGO)) |
1034 | return -EACCES; | 1048 | return -EACCES; |
1035 | } | 1049 | } |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 9e0832dbb1e3..6ea00734984e 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -222,7 +222,7 @@ static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode) | |||
222 | rb_erase(&ff->polled_node, &fc->polled_files); | 222 | rb_erase(&ff->polled_node, &fc->polled_files); |
223 | spin_unlock(&fc->lock); | 223 | spin_unlock(&fc->lock); |
224 | 224 | ||
225 | wake_up_interruptible_sync(&ff->poll_wait); | 225 | wake_up_interruptible_all(&ff->poll_wait); |
226 | 226 | ||
227 | inarg->fh = ff->fh; | 227 | inarg->fh = ff->fh; |
228 | inarg->flags = flags; | 228 | inarg->flags = flags; |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d4286947bc2c..b788becada76 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -272,7 +272,6 @@ struct fuse_req { | |||
272 | struct fuse_init_in init_in; | 272 | struct fuse_init_in init_in; |
273 | struct fuse_init_out init_out; | 273 | struct fuse_init_out init_out; |
274 | struct cuse_init_in cuse_init_in; | 274 | struct cuse_init_in cuse_init_in; |
275 | struct cuse_init_out cuse_init_out; | ||
276 | struct { | 275 | struct { |
277 | struct fuse_read_in in; | 276 | struct fuse_read_in in; |
278 | u64 attr_ver; | 277 | u64 attr_ver; |