diff options
| author | Miklos Szeredi <miklos@szeredi.hu> | 2006-01-06 03:19:39 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:55 -0500 |
| commit | 6f9f11806af8ad3a107714a3ece56c1c4fafd047 (patch) | |
| tree | 175012a2f6bb9737f5eee127aa5ceece5899a657 | |
| parent | 8cbdf1e6f6876b37d2a0d96fd15ea9f90f7d51c1 (diff) | |
[PATCH] fuse: add code documentation
Document some not-so-trivial functions.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | fs/fuse/dir.c | 99 |
1 files changed, 90 insertions, 9 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 4c127f2bc814..fead7f49e2ca 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
| @@ -14,6 +14,15 @@ | |||
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <linux/namei.h> | 15 | #include <linux/namei.h> |
| 16 | 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 | */ | ||
| 17 | static inline unsigned long time_to_jiffies(unsigned long sec, | 26 | static inline unsigned long time_to_jiffies(unsigned long sec, |
| 18 | unsigned long nsec) | 27 | unsigned long nsec) |
| 19 | { | 28 | { |
| @@ -21,6 +30,10 @@ static inline unsigned long time_to_jiffies(unsigned long sec, | |||
| 21 | return jiffies + timespec_to_jiffies(&ts); | 30 | return jiffies + timespec_to_jiffies(&ts); |
| 22 | } | 31 | } |
| 23 | 32 | ||
| 33 | /* | ||
| 34 | * Set dentry and possibly attribute timeouts from the lookup/mk* | ||
| 35 | * replies | ||
| 36 | */ | ||
| 24 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | 37 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) |
| 25 | { | 38 | { |
| 26 | entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); | 39 | entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); |
| @@ -29,16 +42,32 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | |||
| 29 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | 42 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); |
| 30 | } | 43 | } |
| 31 | 44 | ||
| 45 | /* | ||
| 46 | * Mark the attributes as stale, so that at the next call to | ||
| 47 | * ->getattr() they will be fetched from userspace | ||
| 48 | */ | ||
| 32 | void fuse_invalidate_attr(struct inode *inode) | 49 | void fuse_invalidate_attr(struct inode *inode) |
| 33 | { | 50 | { |
| 34 | get_fuse_inode(inode)->i_time = jiffies - 1; | 51 | get_fuse_inode(inode)->i_time = jiffies - 1; |
| 35 | } | 52 | } |
| 36 | 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 | */ | ||
| 37 | static void fuse_invalidate_entry_cache(struct dentry *entry) | 62 | static void fuse_invalidate_entry_cache(struct dentry *entry) |
| 38 | { | 63 | { |
| 39 | entry->d_time = jiffies - 1; | 64 | entry->d_time = jiffies - 1; |
| 40 | } | 65 | } |
| 41 | 66 | ||
| 67 | /* | ||
| 68 | * Same as fuse_invalidate_entry_cache(), but also try to remove the | ||
| 69 | * dentry from the hash | ||
| 70 | */ | ||
| 42 | static void fuse_invalidate_entry(struct dentry *entry) | 71 | static void fuse_invalidate_entry(struct dentry *entry) |
| 43 | { | 72 | { |
| 44 | d_invalidate(entry); | 73 | d_invalidate(entry); |
| @@ -60,6 +89,15 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | |||
| 60 | req->out.args[0].value = outarg; | 89 | req->out.args[0].value = outarg; |
| 61 | } | 90 | } |
| 62 | 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 | */ | ||
| 63 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | 101 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) |
| 64 | { | 102 | { |
| 65 | struct inode *inode = entry->d_inode; | 103 | struct inode *inode = entry->d_inode; |
| @@ -72,6 +110,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
| 72 | struct fuse_conn *fc; | 110 | struct fuse_conn *fc; |
| 73 | struct fuse_req *req; | 111 | struct fuse_req *req; |
| 74 | 112 | ||
| 113 | /* Doesn't hurt to "reset" the validity timeout */ | ||
| 75 | fuse_invalidate_entry_cache(entry); | 114 | fuse_invalidate_entry_cache(entry); |
| 76 | if (!inode) | 115 | if (!inode) |
| 77 | return 0; | 116 | return 0; |
| @@ -102,10 +141,13 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
| 102 | return 1; | 141 | return 1; |
| 103 | } | 142 | } |
| 104 | 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 | */ | ||
| 105 | static int dir_alias(struct inode *inode) | 148 | static int dir_alias(struct inode *inode) |
| 106 | { | 149 | { |
| 107 | if (S_ISDIR(inode->i_mode)) { | 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); | 151 | struct dentry *alias = d_find_alias(inode); |
| 110 | if (alias) { | 152 | if (alias) { |
| 111 | dput(alias); | 153 | dput(alias); |
| @@ -170,6 +212,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
| 170 | return NULL; | 212 | return NULL; |
| 171 | } | 213 | } |
| 172 | 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 | */ | ||
| 173 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | 221 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, |
| 174 | struct nameidata *nd) | 222 | struct nameidata *nd) |
| 175 | { | 223 | { |
| @@ -236,6 +284,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
| 236 | if (!inode) { | 284 | if (!inode) { |
| 237 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 285 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
| 238 | ff->fh = outopen.fh; | 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); | 290 | fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); |
| 240 | goto out_put_request; | 291 | goto out_put_request; |
| 241 | } | 292 | } |
| @@ -259,6 +310,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
| 259 | return err; | 310 | return err; |
| 260 | } | 311 | } |
| 261 | 312 | ||
| 313 | /* | ||
| 314 | * Code shared between mknod, mkdir, symlink and link | ||
| 315 | */ | ||
| 262 | static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | 316 | static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, |
| 263 | struct inode *dir, struct dentry *entry, | 317 | struct inode *dir, struct dentry *entry, |
| 264 | int mode) | 318 | int mode) |
| @@ -576,6 +630,15 @@ static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) | |||
| 576 | return 0; | 630 | return 0; |
| 577 | } | 631 | } |
| 578 | 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 | */ | ||
| 579 | static int fuse_revalidate(struct dentry *entry) | 642 | static int fuse_revalidate(struct dentry *entry) |
| 580 | { | 643 | { |
| 581 | struct inode *inode = entry->d_inode; | 644 | struct inode *inode = entry->d_inode; |
| @@ -623,6 +686,19 @@ static int fuse_access(struct inode *inode, int mask) | |||
| 623 | return err; | 686 | return err; |
| 624 | } | 687 | } |
| 625 | 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 | */ | ||
| 626 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | 702 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) |
| 627 | { | 703 | { |
| 628 | struct fuse_conn *fc = get_fuse_conn(inode); | 704 | struct fuse_conn *fc = get_fuse_conn(inode); |
| @@ -641,14 +717,10 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 641 | err = generic_permission(inode, mask, NULL); | 717 | err = generic_permission(inode, mask, NULL); |
| 642 | } | 718 | } |
| 643 | 719 | ||
| 644 | /* FIXME: Need some mechanism to revoke permissions: | 720 | /* Note: the opposite of the above test does not |
| 645 | currently if the filesystem suddenly changes the | 721 | exist. So if permissions are revoked this won't be |
| 646 | file mode, we will not be informed about it, and | 722 | noticed immediately, only after the attribute |
| 647 | continue to allow access to the file/directory. | 723 | timeout has expired */ |
| 648 | |||
| 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 | 724 | ||
| 653 | return err; | 725 | return err; |
| 654 | } else { | 726 | } else { |
| @@ -816,6 +888,15 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) | |||
| 816 | } | 888 | } |
| 817 | } | 889 | } |
| 818 | 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 | */ | ||
| 819 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) | 900 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) |
| 820 | { | 901 | { |
| 821 | struct inode *inode = entry->d_inode; | 902 | struct inode *inode = entry->d_inode; |
