aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c35
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--include/linux/fuse.h8
3 files changed, 45 insertions, 1 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 61b58fdd973e..4bc1afcc476d 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -461,6 +461,38 @@ static int fuse_revalidate(struct dentry *entry)
461 return fuse_do_getattr(inode); 461 return fuse_do_getattr(inode);
462} 462}
463 463
464static int fuse_access(struct inode *inode, int mask)
465{
466 struct fuse_conn *fc = get_fuse_conn(inode);
467 struct fuse_req *req;
468 struct fuse_access_in inarg;
469 int err;
470
471 if (fc->no_access)
472 return 0;
473
474 req = fuse_get_request(fc);
475 if (!req)
476 return -EINTR;
477
478 memset(&inarg, 0, sizeof(inarg));
479 inarg.mask = mask;
480 req->in.h.opcode = FUSE_ACCESS;
481 req->in.h.nodeid = get_node_id(inode);
482 req->inode = inode;
483 req->in.numargs = 1;
484 req->in.args[0].size = sizeof(inarg);
485 req->in.args[0].value = &inarg;
486 request_send(fc, req);
487 err = req->out.h.error;
488 fuse_put_request(fc, req);
489 if (err == -ENOSYS) {
490 fc->no_access = 1;
491 err = 0;
492 }
493 return err;
494}
495
464static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 496static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
465{ 497{
466 struct fuse_conn *fc = get_fuse_conn(inode); 498 struct fuse_conn *fc = get_fuse_conn(inode);
@@ -493,6 +525,9 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
493 int mode = inode->i_mode; 525 int mode = inode->i_mode;
494 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 526 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
495 return -EACCES; 527 return -EACCES;
528
529 if (nd && (nd->flags & LOOKUP_ACCESS))
530 return fuse_access(inode, mask);
496 return 0; 531 return 0;
497 } 532 }
498} 533}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 5cb456f572c1..c4e8c3b47982 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -266,6 +266,9 @@ struct fuse_conn {
266 /** Is removexattr not implemented by fs? */ 266 /** Is removexattr not implemented by fs? */
267 unsigned no_removexattr : 1; 267 unsigned no_removexattr : 1;
268 268
269 /** Is access not implemented by fs? */
270 unsigned no_access : 1;
271
269 /** Backing dev info */ 272 /** Backing dev info */
270 struct backing_dev_info bdi; 273 struct backing_dev_info bdi;
271}; 274};
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 6e91c9a3a0b6..507913b65af0 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -99,7 +99,8 @@ enum fuse_opcode {
99 FUSE_OPENDIR = 27, 99 FUSE_OPENDIR = 27,
100 FUSE_READDIR = 28, 100 FUSE_READDIR = 28,
101 FUSE_RELEASEDIR = 29, 101 FUSE_RELEASEDIR = 29,
102 FUSE_FSYNCDIR = 30 102 FUSE_FSYNCDIR = 30,
103 FUSE_ACCESS = 34
103}; 104};
104 105
105/* Conservative buffer size for the client */ 106/* Conservative buffer size for the client */
@@ -222,6 +223,11 @@ struct fuse_getxattr_out {
222 __u32 padding; 223 __u32 padding;
223}; 224};
224 225
226struct fuse_access_in {
227 __u32 mask;
228 __u32 padding;
229};
230
225struct fuse_init_in_out { 231struct fuse_init_in_out {
226 __u32 major; 232 __u32 major;
227 __u32 minor; 233 __u32 minor;