Commit 6f9f1180 authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Linus Torvalds

[PATCH] fuse: add code documentation

Document some not-so-trivial functions.
Signed-off-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8cbdf1e6
...@@ -14,6 +14,15 @@ ...@@ -14,6 +14,15 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/namei.h> #include <linux/namei.h>
/*
* FUSE caches dentries and attributes with separate timeout. The
* time in jiffies until the dentry/attributes are valid is stored in
* dentry->d_time and fuse_inode->i_time respectively.
*/
/*
* Calculate the time in jiffies until a dentry/attributes are valid
*/
static inline unsigned long time_to_jiffies(unsigned long sec, static inline unsigned long time_to_jiffies(unsigned long sec,
unsigned long nsec) unsigned long nsec)
{ {
...@@ -21,6 +30,10 @@ static inline unsigned long time_to_jiffies(unsigned long sec, ...@@ -21,6 +30,10 @@ static inline unsigned long time_to_jiffies(unsigned long sec,
return jiffies + timespec_to_jiffies(&ts); return jiffies + timespec_to_jiffies(&ts);
} }
/*
* Set dentry and possibly attribute timeouts from the lookup/mk*
* replies
*/
static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
{ {
entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); 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,16 +42,32 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
time_to_jiffies(o->attr_valid, o->attr_valid_nsec); time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
} }
/*
* Mark the attributes as stale, so that at the next call to
* ->getattr() they will be fetched from userspace
*/
void fuse_invalidate_attr(struct inode *inode) void fuse_invalidate_attr(struct inode *inode)
{ {
get_fuse_inode(inode)->i_time = jiffies - 1; get_fuse_inode(inode)->i_time = jiffies - 1;
} }
/*
* Just mark the entry as stale, so that a next attempt to look it up
* will result in a new lookup call to userspace
*
* This is called when a dentry is about to become negative and the
* timeout is unknown (unlink, rmdir, rename and in some cases
* lookup)
*/
static void fuse_invalidate_entry_cache(struct dentry *entry) static void fuse_invalidate_entry_cache(struct dentry *entry)
{ {
entry->d_time = jiffies - 1; entry->d_time = jiffies - 1;
} }
/*
* Same as fuse_invalidate_entry_cache(), but also try to remove the
* dentry from the hash
*/
static void fuse_invalidate_entry(struct dentry *entry) static void fuse_invalidate_entry(struct dentry *entry)
{ {
d_invalidate(entry); d_invalidate(entry);
...@@ -60,6 +89,15 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, ...@@ -60,6 +89,15 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
req->out.args[0].value = outarg; req->out.args[0].value = outarg;
} }
/*
* Check whether the dentry is still valid
*
* If the entry validity timeout has expired and the dentry is
* positive, try to redo the lookup. If the lookup results in a
* different inode, then let the VFS invalidate the dentry and redo
* the lookup once more. If the lookup results in the same inode,
* then refresh the attributes, timeouts and mark the dentry valid.
*/
static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
{ {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
...@@ -72,6 +110,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) ...@@ -72,6 +110,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
struct fuse_conn *fc; struct fuse_conn *fc;
struct fuse_req *req; struct fuse_req *req;
/* Doesn't hurt to "reset" the validity timeout */
fuse_invalidate_entry_cache(entry); fuse_invalidate_entry_cache(entry);
if (!inode) if (!inode)
return 0; return 0;
...@@ -102,10 +141,13 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) ...@@ -102,10 +141,13 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
return 1; return 1;
} }
/*
* Check if there's already a hashed alias of this directory inode.
* If yes, then lookup and mkdir must not create a new alias.
*/
static int dir_alias(struct inode *inode) static int dir_alias(struct inode *inode)
{ {
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
/* Don't allow creating an alias to a directory */
struct dentry *alias = d_find_alias(inode); struct dentry *alias = d_find_alias(inode);
if (alias) { if (alias) {
dput(alias); dput(alias);
...@@ -170,6 +212,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, ...@@ -170,6 +212,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
return NULL; return NULL;
} }
/*
* Atomic create+open operation
*
* If the filesystem doesn't support this, then fall back to separate
* 'mknod' + 'open' requests.
*/
static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
struct nameidata *nd) struct nameidata *nd)
{ {
...@@ -236,6 +284,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, ...@@ -236,6 +284,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
if (!inode) { if (!inode) {
flags &= ~(O_CREAT | O_EXCL | O_TRUNC); flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
ff->fh = outopen.fh; ff->fh = outopen.fh;
/* Special release, with inode = NULL, this will
trigger a 'forget' request when the release is
complete */
fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
goto out_put_request; goto out_put_request;
} }
...@@ -259,6 +310,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, ...@@ -259,6 +310,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
return err; return err;
} }
/*
* Code shared between mknod, mkdir, symlink and link
*/
static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
struct inode *dir, struct dentry *entry, struct inode *dir, struct dentry *entry,
int mode) int mode)
...@@ -576,6 +630,15 @@ static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) ...@@ -576,6 +630,15 @@ static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
return 0; return 0;
} }
/*
* Check whether the inode attributes are still valid
*
* If the attribute validity timeout has expired, then fetch the fresh
* attributes with a 'getattr' request
*
* I'm not sure why cached attributes are never returned for the root
* inode, this is probably being too cautious.
*/
static int fuse_revalidate(struct dentry *entry) static int fuse_revalidate(struct dentry *entry)
{ {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
...@@ -623,6 +686,19 @@ static int fuse_access(struct inode *inode, int mask) ...@@ -623,6 +686,19 @@ static int fuse_access(struct inode *inode, int mask)
return err; return err;
} }
/*
* Check permission. The two basic access models of FUSE are:
*
* 1) Local access checking ('default_permissions' mount option) based
* on file mode. This is the plain old disk filesystem permission
* modell.
*
* 2) "Remote" access checking, where server is responsible for
* checking permission in each inode operation. An exception to this
* is if ->permission() was invoked from sys_access() in which case an
* access request is sent. Execute permission is still checked
* locally based on file mode.
*/
static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); 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,14 +717,10 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
err = generic_permission(inode, mask, NULL); err = generic_permission(inode, mask, NULL);
} }
/* FIXME: Need some mechanism to revoke permissions: /* Note: the opposite of the above test does not
currently if the filesystem suddenly changes the exist. So if permissions are revoked this won't be
file mode, we will not be informed about it, and noticed immediately, only after the attribute
continue to allow access to the file/directory. timeout has expired */
This is actually not so grave, since the user can
simply keep access to the file/directory anyway by
keeping it open... */
return err; return err;
} else { } else {
...@@ -816,6 +888,15 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) ...@@ -816,6 +888,15 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
} }
} }
/*
* Set attributes, and at the same time refresh them.
*
* Truncation is slightly complicated, because the 'truncate' request
* may fail, in which case we don't want to touch the mapping.
* vmtruncate() doesn't allow for this case. So do the rlimit
* checking by hand and call vmtruncate() only after the file has
* actually been truncated.
*/
static int fuse_setattr(struct dentry *entry, struct iattr *attr) static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{ {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment