dir.c (8cbdf1e6f6876b37d2a0d96fd15ea9f90f7d51c1) | dir.c (6f9f11806af8ad3a107714a3ece56c1c4fafd047) |
---|---|
1/* 2 FUSE: Filesystem in Userspace 3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> 4 5 This program can be distributed under the terms of the GNU GPL. 6 See the file COPYING. 7*/ 8 9#include "fuse_i.h" 10 11#include <linux/pagemap.h> 12#include <linux/file.h> 13#include <linux/gfp.h> 14#include <linux/sched.h> 15#include <linux/namei.h> 16 | 1/* 2 FUSE: Filesystem in Userspace 3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> 4 5 This program can be distributed under the terms of the GNU GPL. 6 See the file COPYING. 7*/ 8 9#include "fuse_i.h" 10 11#include <linux/pagemap.h> 12#include <linux/file.h> 13#include <linux/gfp.h> 14#include <linux/sched.h> 15#include <linux/namei.h> 16 |
17/* 18 * FUSE caches dentries and attributes with separate timeout. The 19 * time in jiffies until the dentry/attributes are valid is stored in 20 * dentry->d_time and fuse_inode->i_time respectively. 21 */ 22 23/* 24 * Calculate the time in jiffies until a dentry/attributes are valid 25 */ |
|
17static inline unsigned long time_to_jiffies(unsigned long sec, 18 unsigned long nsec) 19{ 20 struct timespec ts = {sec, nsec}; 21 return jiffies + timespec_to_jiffies(&ts); 22} 23 | 26static inline unsigned long time_to_jiffies(unsigned long sec, 27 unsigned long nsec) 28{ 29 struct timespec ts = {sec, nsec}; 30 return jiffies + timespec_to_jiffies(&ts); 31} 32 |
33/* 34 * Set dentry and possibly attribute timeouts from the lookup/mk* 35 * replies 36 */ |
|
24static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) 25{ 26 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); 27 if (entry->d_inode) 28 get_fuse_inode(entry->d_inode)->i_time = 29 time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 30} 31 | 37static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) 38{ 39 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); 40 if (entry->d_inode) 41 get_fuse_inode(entry->d_inode)->i_time = 42 time_to_jiffies(o->attr_valid, o->attr_valid_nsec); 43} 44 |
45/* 46 * Mark the attributes as stale, so that at the next call to 47 * ->getattr() they will be fetched from userspace 48 */ |
|
32void fuse_invalidate_attr(struct inode *inode) 33{ 34 get_fuse_inode(inode)->i_time = jiffies - 1; 35} 36 | 49void fuse_invalidate_attr(struct inode *inode) 50{ 51 get_fuse_inode(inode)->i_time = jiffies - 1; 52} 53 |
54/* 55 * Just mark the entry as stale, so that a next attempt to look it up 56 * will result in a new lookup call to userspace 57 * 58 * This is called when a dentry is about to become negative and the 59 * timeout is unknown (unlink, rmdir, rename and in some cases 60 * lookup) 61 */ |
|
37static void fuse_invalidate_entry_cache(struct dentry *entry) 38{ 39 entry->d_time = jiffies - 1; 40} 41 | 62static void fuse_invalidate_entry_cache(struct dentry *entry) 63{ 64 entry->d_time = jiffies - 1; 65} 66 |
67/* 68 * Same as fuse_invalidate_entry_cache(), but also try to remove the 69 * dentry from the hash 70 */ |
|
42static void fuse_invalidate_entry(struct dentry *entry) 43{ 44 d_invalidate(entry); 45 fuse_invalidate_entry_cache(entry); 46} 47 48static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 49 struct dentry *entry, --- 5 unchanged lines hidden (view full) --- 55 req->in.numargs = 1; 56 req->in.args[0].size = entry->d_name.len + 1; 57 req->in.args[0].value = entry->d_name.name; 58 req->out.numargs = 1; 59 req->out.args[0].size = sizeof(struct fuse_entry_out); 60 req->out.args[0].value = outarg; 61} 62 | 71static void fuse_invalidate_entry(struct dentry *entry) 72{ 73 d_invalidate(entry); 74 fuse_invalidate_entry_cache(entry); 75} 76 77static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 78 struct dentry *entry, --- 5 unchanged lines hidden (view full) --- 84 req->in.numargs = 1; 85 req->in.args[0].size = entry->d_name.len + 1; 86 req->in.args[0].value = entry->d_name.name; 87 req->out.numargs = 1; 88 req->out.args[0].size = sizeof(struct fuse_entry_out); 89 req->out.args[0].value = outarg; 90} 91 |
92/* 93 * Check whether the dentry is still valid 94 * 95 * If the entry validity timeout has expired and the dentry is 96 * positive, try to redo the lookup. If the lookup results in a 97 * different inode, then let the VFS invalidate the dentry and redo 98 * the lookup once more. If the lookup results in the same inode, 99 * then refresh the attributes, timeouts and mark the dentry valid. 100 */ |
|
63static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 64{ 65 struct inode *inode = entry->d_inode; 66 67 if (inode && is_bad_inode(inode)) 68 return 0; 69 else if (time_after(jiffies, entry->d_time)) { 70 int err; 71 struct fuse_entry_out outarg; 72 struct fuse_conn *fc; 73 struct fuse_req *req; 74 | 101static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 102{ 103 struct inode *inode = entry->d_inode; 104 105 if (inode && is_bad_inode(inode)) 106 return 0; 107 else if (time_after(jiffies, entry->d_time)) { 108 int err; 109 struct fuse_entry_out outarg; 110 struct fuse_conn *fc; 111 struct fuse_req *req; 112 |
113 /* Doesn't hurt to "reset" the validity timeout */ |
|
75 fuse_invalidate_entry_cache(entry); 76 if (!inode) 77 return 0; 78 79 fc = get_fuse_conn(inode); 80 req = fuse_get_request(fc); 81 if (!req) 82 return 0; --- 14 unchanged lines hidden (view full) --- 97 return 0; 98 99 fuse_change_attributes(inode, &outarg.attr); 100 fuse_change_timeout(entry, &outarg); 101 } 102 return 1; 103} 104 | 114 fuse_invalidate_entry_cache(entry); 115 if (!inode) 116 return 0; 117 118 fc = get_fuse_conn(inode); 119 req = fuse_get_request(fc); 120 if (!req) 121 return 0; --- 14 unchanged lines hidden (view full) --- 136 return 0; 137 138 fuse_change_attributes(inode, &outarg.attr); 139 fuse_change_timeout(entry, &outarg); 140 } 141 return 1; 142} 143 |
144/* 145 * Check if there's already a hashed alias of this directory inode. 146 * If yes, then lookup and mkdir must not create a new alias. 147 */ |
|
105static int dir_alias(struct inode *inode) 106{ 107 if (S_ISDIR(inode->i_mode)) { | 148static int dir_alias(struct inode *inode) 149{ 150 if (S_ISDIR(inode->i_mode)) { |
108 /* Don't allow creating an alias to a directory */ | |
109 struct dentry *alias = d_find_alias(inode); 110 if (alias) { 111 dput(alias); 112 return 1; 113 } 114 } 115 return 0; 116} --- 48 unchanged lines hidden (view full) --- 165 entry->d_op = &fuse_dentry_operations; 166 if (!err) 167 fuse_change_timeout(entry, &outarg); 168 else 169 fuse_invalidate_entry_cache(entry); 170 return NULL; 171} 172 | 151 struct dentry *alias = d_find_alias(inode); 152 if (alias) { 153 dput(alias); 154 return 1; 155 } 156 } 157 return 0; 158} --- 48 unchanged lines hidden (view full) --- 207 entry->d_op = &fuse_dentry_operations; 208 if (!err) 209 fuse_change_timeout(entry, &outarg); 210 else 211 fuse_invalidate_entry_cache(entry); 212 return NULL; 213} 214 |
215/* 216 * Atomic create+open operation 217 * 218 * If the filesystem doesn't support this, then fall back to separate 219 * 'mknod' + 'open' requests. 220 */ |
|
173static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 174 struct nameidata *nd) 175{ 176 int err; 177 struct inode *inode; 178 struct fuse_conn *fc = get_fuse_conn(dir); 179 struct fuse_req *req; 180 struct fuse_open_in inarg; --- 50 unchanged lines hidden (view full) --- 231 goto out_free_ff; 232 233 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 234 &outentry.attr); 235 err = -ENOMEM; 236 if (!inode) { 237 flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 238 ff->fh = outopen.fh; | 221static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 222 struct nameidata *nd) 223{ 224 int err; 225 struct inode *inode; 226 struct fuse_conn *fc = get_fuse_conn(dir); 227 struct fuse_req *req; 228 struct fuse_open_in inarg; --- 50 unchanged lines hidden (view full) --- 279 goto out_free_ff; 280 281 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 282 &outentry.attr); 283 err = -ENOMEM; 284 if (!inode) { 285 flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 286 ff->fh = outopen.fh; |
287 /* Special release, with inode = NULL, this will 288 trigger a 'forget' request when the release is 289 complete */ |
|
239 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); 240 goto out_put_request; 241 } 242 fuse_put_request(fc, req); 243 d_instantiate(entry, inode); 244 fuse_change_timeout(entry, &outentry); 245 file = lookup_instantiate_filp(nd, entry, generic_file_open); 246 if (IS_ERR(file)) { --- 7 unchanged lines hidden (view full) --- 254 out_free_ff: 255 fuse_file_free(ff); 256 out_put_request: 257 fuse_put_request(fc, req); 258 out: 259 return err; 260} 261 | 290 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); 291 goto out_put_request; 292 } 293 fuse_put_request(fc, req); 294 d_instantiate(entry, inode); 295 fuse_change_timeout(entry, &outentry); 296 file = lookup_instantiate_filp(nd, entry, generic_file_open); 297 if (IS_ERR(file)) { --- 7 unchanged lines hidden (view full) --- 305 out_free_ff: 306 fuse_file_free(ff); 307 out_put_request: 308 fuse_put_request(fc, req); 309 out: 310 return err; 311} 312 |
313/* 314 * Code shared between mknod, mkdir, symlink and link 315 */ |
|
262static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 263 struct inode *dir, struct dentry *entry, 264 int mode) 265{ 266 struct fuse_entry_out outarg; 267 struct inode *inode; 268 int err; 269 --- 301 unchanged lines hidden (view full) --- 571 task->egid == fc->group_id && 572 task->sgid == fc->group_id && 573 task->gid == fc->group_id) 574 return 1; 575 576 return 0; 577} 578 | 316static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, 317 struct inode *dir, struct dentry *entry, 318 int mode) 319{ 320 struct fuse_entry_out outarg; 321 struct inode *inode; 322 int err; 323 --- 301 unchanged lines hidden (view full) --- 625 task->egid == fc->group_id && 626 task->sgid == fc->group_id && 627 task->gid == fc->group_id) 628 return 1; 629 630 return 0; 631} 632 |
633/* 634 * Check whether the inode attributes are still valid 635 * 636 * If the attribute validity timeout has expired, then fetch the fresh 637 * attributes with a 'getattr' request 638 * 639 * I'm not sure why cached attributes are never returned for the root 640 * inode, this is probably being too cautious. 641 */ |
|
579static int fuse_revalidate(struct dentry *entry) 580{ 581 struct inode *inode = entry->d_inode; 582 struct fuse_inode *fi = get_fuse_inode(inode); 583 struct fuse_conn *fc = get_fuse_conn(inode); 584 585 if (!fuse_allow_task(fc, current)) 586 return -EACCES; --- 31 unchanged lines hidden (view full) --- 618 fuse_put_request(fc, req); 619 if (err == -ENOSYS) { 620 fc->no_access = 1; 621 err = 0; 622 } 623 return err; 624} 625 | 642static int fuse_revalidate(struct dentry *entry) 643{ 644 struct inode *inode = entry->d_inode; 645 struct fuse_inode *fi = get_fuse_inode(inode); 646 struct fuse_conn *fc = get_fuse_conn(inode); 647 648 if (!fuse_allow_task(fc, current)) 649 return -EACCES; --- 31 unchanged lines hidden (view full) --- 681 fuse_put_request(fc, req); 682 if (err == -ENOSYS) { 683 fc->no_access = 1; 684 err = 0; 685 } 686 return err; 687} 688 |
689/* 690 * Check permission. The two basic access models of FUSE are: 691 * 692 * 1) Local access checking ('default_permissions' mount option) based 693 * on file mode. This is the plain old disk filesystem permission 694 * modell. 695 * 696 * 2) "Remote" access checking, where server is responsible for 697 * checking permission in each inode operation. An exception to this 698 * is if ->permission() was invoked from sys_access() in which case an 699 * access request is sent. Execute permission is still checked 700 * locally based on file mode. 701 */ |
|
626static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 627{ 628 struct fuse_conn *fc = get_fuse_conn(inode); 629 630 if (!fuse_allow_task(fc, current)) 631 return -EACCES; 632 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 633 int err = generic_permission(inode, mask, NULL); 634 635 /* If permission is denied, try to refresh file 636 attributes. This is also needed, because the root 637 node will at first have no permissions */ 638 if (err == -EACCES) { 639 err = fuse_do_getattr(inode); 640 if (!err) 641 err = generic_permission(inode, mask, NULL); 642 } 643 | 702static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) 703{ 704 struct fuse_conn *fc = get_fuse_conn(inode); 705 706 if (!fuse_allow_task(fc, current)) 707 return -EACCES; 708 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 709 int err = generic_permission(inode, mask, NULL); 710 711 /* If permission is denied, try to refresh file 712 attributes. This is also needed, because the root 713 node will at first have no permissions */ 714 if (err == -EACCES) { 715 err = fuse_do_getattr(inode); 716 if (!err) 717 err = generic_permission(inode, mask, NULL); 718 } 719 |
644 /* FIXME: Need some mechanism to revoke permissions: 645 currently if the filesystem suddenly changes the 646 file mode, we will not be informed about it, and 647 continue to allow access to the file/directory. | 720 /* Note: the opposite of the above test does not 721 exist. So if permissions are revoked this won't be 722 noticed immediately, only after the attribute 723 timeout has expired */ |
648 | 724 |
649 This is actually not so grave, since the user can 650 simply keep access to the file/directory anyway by 651 keeping it open... */ 652 | |
653 return err; 654 } else { 655 int mode = inode->i_mode; 656 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 657 return -EACCES; 658 659 if (nd && (nd->flags & LOOKUP_ACCESS)) 660 return fuse_access(inode, mask); --- 150 unchanged lines hidden (view full) --- 811 } 812 if (ivalid & ATTR_FILE) { 813 struct fuse_file *ff = iattr->ia_file->private_data; 814 arg->valid |= FATTR_FH; 815 arg->fh = ff->fh; 816 } 817} 818 | 725 return err; 726 } else { 727 int mode = inode->i_mode; 728 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) 729 return -EACCES; 730 731 if (nd && (nd->flags & LOOKUP_ACCESS)) 732 return fuse_access(inode, mask); --- 150 unchanged lines hidden (view full) --- 883 } 884 if (ivalid & ATTR_FILE) { 885 struct fuse_file *ff = iattr->ia_file->private_data; 886 arg->valid |= FATTR_FH; 887 arg->fh = ff->fh; 888 } 889} 890 |
891/* 892 * Set attributes, and at the same time refresh them. 893 * 894 * Truncation is slightly complicated, because the 'truncate' request 895 * may fail, in which case we don't want to touch the mapping. 896 * vmtruncate() doesn't allow for this case. So do the rlimit 897 * checking by hand and call vmtruncate() only after the file has 898 * actually been truncated. 899 */ |
|
819static int fuse_setattr(struct dentry *entry, struct iattr *attr) 820{ 821 struct inode *inode = entry->d_inode; 822 struct fuse_conn *fc = get_fuse_conn(inode); 823 struct fuse_inode *fi = get_fuse_inode(inode); 824 struct fuse_req *req; 825 struct fuse_setattr_in inarg; 826 struct fuse_attr_out outarg; --- 305 unchanged lines hidden --- | 900static int fuse_setattr(struct dentry *entry, struct iattr *attr) 901{ 902 struct inode *inode = entry->d_inode; 903 struct fuse_conn *fc = get_fuse_conn(inode); 904 struct fuse_inode *fi = get_fuse_inode(inode); 905 struct fuse_req *req; 906 struct fuse_setattr_in inarg; 907 struct fuse_attr_out outarg; --- 305 unchanged lines hidden --- |