* [PATCH 01/17] Add a dentry op to handle automounting rather than abusing follow_link()
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
@ 2010-09-30 18:15 ` David Howells
2010-09-30 18:15 ` [PATCH 02/17] AFS: Use d_automount() " David Howells
` (8 subsequent siblings)
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:15 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Howells, Ian Kent
Add a dentry op (d_automount) to handle automounting directories rather than
abusing the follow_link() inode operation. The operation is keyed off a new
inode flag (S_AUTOMOUNT).
This makes it easier to add an AT_ flag to suppress terminal segment automount
during pathwalk. It should also remove the need for the kludge code in the
pathwalk algorithm to handle directories with follow_link() semantics.
A new pathwalk subroutine, follow_automount() is added to handle mountpoints.
It will return -EREMOTE if the S_AUTOMOUNT was set, but no d_automount() op was
supplied, -ELOOP if we've encountered too many symlinks or mountpoints, -EISDIR
if the walk point should be used without mounting and 0 if successful. path
will be updated if an automount took place to point to the mounted filesystem.
I've only changed __follow_mount() to handle call follow_automount(), but it
might be necessary to change follow_mount() too. The latter is only called
from follow_dotdot(), but any automounts on ".." should be pinned whilst we're
using a child of it.
I've also extracted the mount/don't-mount logic from autofs4 and included it
here. It makes the mount go ahead anyway if someone calls open() or creat(),
tries to traverse the directory, tries to chdir/chroot/etc. into the directory,
or sticks a '/' on the end of the pathname. If they do a stat(), however,
they'll only trigger the automount if they didn't also say O_NOFOLLOW.
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Acked-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
---
Documentation/filesystems/Locking | 2 +
Documentation/filesystems/vfs.txt | 13 +++++
fs/namei.c | 101 ++++++++++++++++++++++++++++++-------
include/linux/dcache.h | 5 ++
include/linux/fs.h | 2 +
5 files changed, 104 insertions(+), 19 deletions(-)
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 2db4283..35fd21c 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -16,6 +16,7 @@ prototypes:
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
+ struct vfsmount *(*d_automount)(struct path *path);
locking rules:
none have BKL
@@ -27,6 +28,7 @@ d_delete: yes no yes no
d_release: no no no yes
d_iput: no no no yes
d_dname: no no no no
+d_automount: no no no yes
--------------------------- inode_operations ---------------------------
prototypes:
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index ed7e5ef..ff4bf82 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -847,6 +847,7 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
+ struct vfsmount *(*d_automount)(struct path *);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -881,6 +882,18 @@ struct dentry_operations {
at the end of the buffer, and returns a pointer to the first char.
dynamic_dname() helper function is provided to take care of this.
+ d_automount: called when an automount dentry is to be traversed (optional).
+ This should create a new VFS mount record, mount it on the directory
+ and return the record to the caller. The caller is supplied with a
+ path parameter giving the automount directory to describe the automount
+ target and the parent VFS mount record to provide inheritable mount
+ parameters. NULL should be returned if someone else managed to make
+ the automount first. If the automount failed, then an error code
+ should be returned.
+
+ This function is only used if S_AUTOMOUNT is set on the inode to which
+ the dentry refers.
+
Example :
static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
diff --git a/fs/namei.c b/fs/namei.c
index 24896e8..c50b9d7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -612,24 +612,85 @@ int follow_up(struct path *path)
return 1;
}
+/*
+ * Perform an automount
+ * - return -EISDIR to tell __follow_mount() to stop and return the path we
+ * were called with.
+ */
+static int follow_automount(struct path *path, unsigned flags,
+ bool *need_mntput)
+{
+ struct vfsmount *mnt;
+
+ if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
+ return -EREMOTE;
+
+ /* We want to mount if someone is trying to open/create a file of any
+ * type under the mountpoint, wants to traverse through the mountpoint
+ * or wants to open the mounted directory.
+ *
+ * We don't want to mount if someone's just doing a stat and they've
+ * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
+ * appended a '/' to the name.
+ */
+ if (!(flags & LOOKUP_FOLLOW) &&
+ !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
+ LOOKUP_OPEN | LOOKUP_CREATE)))
+ return -EISDIR;
+
+ current->total_link_count++;
+ if (current->total_link_count >= 40)
+ return -ELOOP;
+
+ mnt = path->dentry->d_op->d_automount(path);
+ if (IS_ERR(mnt))
+ return PTR_ERR(mnt);
+ if (!mnt) /* mount collision */
+ return 0;
+
+ if (mnt->mnt_sb == path->mnt->mnt_sb &&
+ mnt->mnt_root == path->dentry) {
+ mntput(mnt);
+ return -ELOOP;
+ }
+
+ dput(path->dentry);
+ if (*need_mntput)
+ mntput(path->mnt);
+ path->mnt = mnt;
+ path->dentry = dget(mnt->mnt_root);
+ *need_mntput = true;
+ return 0;
+}
+
/* no need for dcache_lock, as serialization is taken care in
* namespace.c
*/
-static int __follow_mount(struct path *path)
+static int __follow_mount(struct path *path, unsigned flags)
{
- int res = 0;
- while (d_mountpoint(path->dentry)) {
- struct vfsmount *mounted = lookup_mnt(path);
- if (!mounted)
+ struct vfsmount *mounted;
+ bool need_mntput = false;
+ int ret;
+
+ for (;;) {
+ while (d_mountpoint(path->dentry)) {
+ mounted = lookup_mnt(path);
+ if (!mounted)
+ break;
+ dput(path->dentry);
+ if (need_mntput)
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ need_mntput = true;
+ }
+ if (!d_automount_point(path->dentry))
break;
- dput(path->dentry);
- if (res)
- mntput(path->mnt);
- path->mnt = mounted;
- path->dentry = dget(mounted->mnt_root);
- res = 1;
+ ret = follow_automount(path, flags, &need_mntput);
+ if (ret < 0)
+ return ret == -EISDIR ? 0 : ret;
}
- return res;
+ return 0;
}
static void follow_mount(struct path *path)
@@ -726,6 +787,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
struct vfsmount *mnt = nd->path.mnt;
struct dentry *dentry, *parent;
struct inode *dir;
+ int ret;
+
/*
* See if the low-level filesystem might want
* to use its own hash..
@@ -750,8 +813,10 @@ found:
done:
path->mnt = mnt;
path->dentry = dentry;
- __follow_mount(path);
- return 0;
+ ret = __follow_mount(path, nd->flags);
+ if (unlikely(ret < 0))
+ path_put_conditional(path, nd);
+ return ret;
need_lookup:
parent = nd->path.dentry;
@@ -1701,11 +1766,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
if (open_flag & O_EXCL)
goto exit_dput;
- if (__follow_mount(path)) {
- error = -ELOOP;
- if (open_flag & O_NOFOLLOW)
- goto exit_dput;
- }
+ error = __follow_mount(path, nd->flags);
+ if (error < 0)
+ goto exit_dput;
error = -ENOENT;
if (!path->dentry->d_inode)
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 6a4aea3..ab62055 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -139,6 +139,7 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
+ struct vfsmount *(*d_automount)(struct path *);
};
/* the dentry parameter passed to d_hash and d_compare is the parent
@@ -157,6 +158,7 @@ d_compare: no yes yes no
d_delete: no yes no no
d_release: no no no yes
d_iput: no no no yes
+d_automount: no no no yes
*/
/* d_flags entries */
@@ -391,6 +393,9 @@ static inline int d_mountpoint(struct dentry *dentry)
return dentry->d_mounted;
}
+#define d_automount_point(dentry) \
+ (dentry->d_inode && IS_AUTOMOUNT(dentry->d_inode))
+
extern struct vfsmount *lookup_mnt(struct path *);
extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 63d069b..29ef320 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -235,6 +235,7 @@ struct inodes_stat_t {
#define S_NOCMTIME 128 /* Do not update file c/mtime */
#define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */
#define S_PRIVATE 512 /* Inode is fs-internal */
+#define S_AUTOMOUNT 1024 /* Automount/referral quasi-directory */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -269,6 +270,7 @@ struct inodes_stat_t {
#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME)
#define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE)
#define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE)
+#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT)
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 02/17] AFS: Use d_automount() rather than abusing follow_link()
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2010-09-30 18:15 ` [PATCH 01/17] Add a dentry op to handle automounting rather than abusing follow_link() David Howells
@ 2010-09-30 18:15 ` David Howells
2010-09-30 18:15 ` [PATCH 03/17] NFS: " David Howells
` (7 subsequent siblings)
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:15 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Howells
Make AFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/afs/dir.c | 1 +
fs/afs/inode.c | 3 ++-
fs/afs/internal.h | 1 +
fs/afs/mntpt.c | 47 +++++++++++++++--------------------------------
4 files changed, 19 insertions(+), 33 deletions(-)
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 0d38c09..23395e9 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -65,6 +65,7 @@ static const struct dentry_operations afs_fs_dentry_operations = {
.d_revalidate = afs_d_revalidate,
.d_delete = afs_d_delete,
.d_release = afs_d_release,
+ .d_automount = afs_d_automount,
};
#define AFS_DIR_HASHTBL_SIZE 128
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 0747339..db66c52 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -184,7 +184,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
inode->i_generation = 0;
set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
- inode->i_flags |= S_NOATIME;
+ set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
+ inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
unlock_new_inode(inode);
_leave(" = %p", inode);
return inode;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index cca8eef..085cfcf 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -590,6 +590,7 @@ extern const struct inode_operations afs_mntpt_inode_operations;
extern const struct inode_operations afs_autocell_inode_operations;
extern const struct file_operations afs_mntpt_file_operations;
+extern struct vfsmount *afs_d_automount(struct path *);
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
extern void afs_mntpt_kill_timer(void);
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 6d55268..7d190cf 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -24,7 +24,6 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
struct dentry *dentry,
struct nameidata *nd);
static int afs_mntpt_open(struct inode *inode, struct file *file);
-static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
static void afs_mntpt_expiry_timed_out(struct work_struct *work);
const struct file_operations afs_mntpt_file_operations = {
@@ -33,13 +32,11 @@ const struct file_operations afs_mntpt_file_operations = {
const struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup,
- .follow_link = afs_mntpt_follow_link,
.readlink = page_readlink,
.getattr = afs_getattr,
};
const struct inode_operations afs_autocell_inode_operations = {
- .follow_link = afs_mntpt_follow_link,
.getattr = afs_getattr,
};
@@ -87,6 +84,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
_debug("symlink is a mountpoint");
spin_lock(&vnode->lock);
set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
+ vnode->vfs_inode.i_flags |= S_AUTOMOUNT;
spin_unlock(&vnode->lock);
}
@@ -237,52 +235,37 @@ error_no_devname:
}
/*
- * follow a link from a mountpoint directory, thus causing it to be mounted
+ * handle an automount point
*/
-static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
+struct vfsmount *afs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
int err;
- _enter("%p{%s},{%s:%p{%s},}",
- dentry,
- dentry->d_name.name,
- nd->path.mnt->mnt_devname,
- dentry,
- nd->path.dentry->d_name.name);
-
- dput(nd->path.dentry);
- nd->path.dentry = dget(dentry);
+ _enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name);
- newmnt = afs_mntpt_do_automount(nd->path.dentry);
- if (IS_ERR(newmnt)) {
- path_put(&nd->path);
- return (void *)newmnt;
- }
+ newmnt = afs_mntpt_do_automount(path->dentry);
+ if (IS_ERR(newmnt))
+ return newmnt;
mntget(newmnt);
- err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts);
+ err = do_add_mount(newmnt, path, MNT_SHRINKABLE, &afs_vfsmounts);
switch (err) {
case 0:
- path_put(&nd->path);
- nd->path.mnt = newmnt;
- nd->path.dentry = dget(newmnt->mnt_root);
schedule_delayed_work(&afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
- break;
+ _leave(" = %p {%s}", newmnt, newmnt->mnt_devname);
+ return newmnt;
case -EBUSY:
/* someone else made a mount here whilst we were busy */
- while (d_mountpoint(nd->path.dentry) &&
- follow_down(&nd->path))
- ;
- err = 0;
+ mntput(newmnt);
+ _leave(" = NULL [EBUSY]");
+ return NULL;
default:
mntput(newmnt);
- break;
+ _leave(" = %d", err);
+ return ERR_PTR(err);
}
-
- _leave(" = %d", err);
- return ERR_PTR(err);
}
/*
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 03/17] NFS: Use d_automount() rather than abusing follow_link()
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2010-09-30 18:15 ` [PATCH 01/17] Add a dentry op to handle automounting rather than abusing follow_link() David Howells
2010-09-30 18:15 ` [PATCH 02/17] AFS: Use d_automount() " David Howells
@ 2010-09-30 18:15 ` David Howells
2010-09-30 18:15 ` [PATCH 07/17] Make dentry::d_mounted into a more general field for special function dirs David Howells
` (6 subsequent siblings)
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:15 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Howells, Trond Myklebust,
Ian Kent
Make NFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Acked-by: Trond Myklebust <Trond.Myklebust-HgOvQuBEEgTQT0dZR+AlfA@public.gmane.org>
Acked-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
---
fs/nfs/dir.c | 4 ++
fs/nfs/inode.c | 4 +-
fs/nfs/internal.h | 1 +
fs/nfs/namespace.c | 87 ++++++++++++++++++++++--------------------------
include/linux/nfs_fs.h | 1 -
5 files changed, 46 insertions(+), 51 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e257172..46f2e12 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -734,7 +734,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
{
struct nfs_server *server = NFS_SERVER(inode);
- if (test_bit(NFS_INO_MOUNTPOINT, &NFS_I(inode)->flags))
+ if (IS_AUTOMOUNT(inode))
return 0;
if (nd != NULL) {
/* VFS wants an on-the-wire revalidation */
@@ -934,6 +934,7 @@ const struct dentry_operations nfs_dentry_operations = {
.d_revalidate = nfs_lookup_revalidate,
.d_delete = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+ .d_automount = nfs_d_automount,
};
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
@@ -1009,6 +1010,7 @@ const struct dentry_operations nfs4_dentry_operations = {
.d_revalidate = nfs_open_revalidate,
.d_delete = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+ .d_automount = nfs_d_automount,
};
/*
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7d2d6c7..d554949 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -302,7 +302,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
else
inode->i_op = &nfs_mountpoint_inode_operations;
inode->i_fop = NULL;
- set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags);
+ inode->i_flags |= S_AUTOMOUNT;
}
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
@@ -1205,7 +1205,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Update the fsid? */
if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
!nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
- !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
+ !IS_AUTOMOUNT(inode))
server->fsid = fattr->fsid;
/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index c961bc9..45b98e7 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -239,6 +239,7 @@ extern char *nfs_path(const char *base,
const struct dentry *droot,
const struct dentry *dentry,
char *buffer, ssize_t buflen);
+extern struct vfsmount *nfs_d_automount(struct path *path);
/* getroot.c */
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index db6aa36..bf80079 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -88,9 +88,8 @@ Elong:
}
/*
- * nfs_follow_mountpoint - handle crossing a mountpoint on the server
- * @dentry - dentry of mountpoint
- * @nd - nameidata info
+ * nfs_d_automount - Handle crossing a mountpoint on the server
+ * @path - The mountpoint
*
* When we encounter a mountpoint on the server, we want to set up
* a mountpoint on the client too, to prevent inode numbers from
@@ -100,87 +99,81 @@ Elong:
* situation, and that different filesystems may want to use
* different security flavours.
*/
-static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+struct vfsmount *nfs_d_automount(struct path *path)
{
struct vfsmount *mnt;
- struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+ struct nfs_server *server = NFS_SERVER(path->dentry->d_inode);
struct dentry *parent;
struct nfs_fh *fh = NULL;
struct nfs_fattr *fattr = NULL;
int err;
- dprintk("--> nfs_follow_mountpoint()\n");
+ dprintk("--> nfs_d_automount()\n");
- err = -ESTALE;
- if (IS_ROOT(dentry))
- goto out_err;
+ mnt = ERR_PTR(-ESTALE);
+ if (IS_ROOT(path->dentry))
+ goto out_nofree;
- err = -ENOMEM;
+ mnt = ERR_PTR(-ENOMEM);
fh = nfs_alloc_fhandle();
fattr = nfs_alloc_fattr();
if (fh == NULL || fattr == NULL)
- goto out_err;
+ goto out;
dprintk("%s: enter\n", __func__);
- dput(nd->path.dentry);
- nd->path.dentry = dget(dentry);
- /* Look it up again */
- parent = dget_parent(nd->path.dentry);
+ /* Look it up again to get its attributes */
+ parent = dget_parent(path->dentry);
err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
- &nd->path.dentry->d_name,
+ &path->dentry->d_name,
fh, fattr);
dput(parent);
- if (err != 0)
- goto out_err;
+ if (err != 0) {
+ mnt = ERR_PTR(err);
+ goto out;
+ }
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
- mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry);
+ mnt = nfs_do_refmount(path->mnt, path->dentry);
else
- mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh,
- fattr);
- err = PTR_ERR(mnt);
+ mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr);
if (IS_ERR(mnt))
- goto out_err;
+ goto out;
mntget(mnt);
- err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE,
+ err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE,
&nfs_automount_list);
- if (err < 0) {
+ switch (err) {
+ case 0:
+ dprintk("%s: done, success\n", __func__);
+ schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+ break;
+ case -EBUSY:
+ /* someone else made a mount here whilst we were busy */
mntput(mnt);
- if (err == -EBUSY)
- goto out_follow;
- goto out_err;
+ dprintk("%s: done, collision\n", __func__);
+ mnt = NULL;
+ break;
+ default:
+ mntput(mnt);
+ dprintk("%s: done, error %d\n", __func__, err);
+ mnt = ERR_PTR(err);
+ break;
}
- path_put(&nd->path);
- nd->path.mnt = mnt;
- nd->path.dentry = dget(mnt->mnt_root);
- schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+
out:
nfs_free_fattr(fattr);
nfs_free_fhandle(fh);
- dprintk("%s: done, returned %d\n", __func__, err);
-
- dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
- return ERR_PTR(err);
-out_err:
- path_put(&nd->path);
- goto out;
-out_follow:
- while (d_mountpoint(nd->path.dentry) &&
- follow_down(&nd->path))
- ;
- err = 0;
- goto out;
+out_nofree:
+ dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt);
+ return mnt;
}
const struct inode_operations nfs_mountpoint_inode_operations = {
- .follow_link = nfs_follow_mountpoint,
.getattr = nfs_getattr,
};
const struct inode_operations nfs_referral_inode_operations = {
- .follow_link = nfs_follow_mountpoint,
};
static void nfs_expire_automounts(struct work_struct *work)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 508f8cf..df7ba50 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -212,7 +212,6 @@ struct nfs_inode {
#define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */
#define NFS_INO_STALE (1) /* possible stale inode */
#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
-#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 07/17] Make dentry::d_mounted into a more general field for special function dirs
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (2 preceding siblings ...)
2010-09-30 18:15 ` [PATCH 03/17] NFS: " David Howells
@ 2010-09-30 18:15 ` David Howells
[not found] ` <20100930181531.30939.10438.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2010-09-30 18:15 ` [PATCH 09/17] autofs4: add d_automount() dentry operation David Howells
` (5 subsequent siblings)
9 siblings, 1 reply; 28+ messages in thread
From: David Howells @ 2010-09-30 18:15 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, David Howells, Ian Kent
Make the d_mounted field in struct dentry into a more general field for special
function directories such as mountpoints and autofs substructures.
d_mounted is renamed d_managed, and that is split into three fields:
(*) #define DMANAGED_MOUNTPOINT 0x0fffffff
This is the mounted-on-this-dentry count as per d_mounted.
(*) #define DMANAGED_AUTOMOUNT 0x10000000
This is a reflection of the S_AUTOMOUNT inode flag. This is reflected by
__d_instantiate(). follow_automount() is now keyed off of this rather
than being keyed off S_AUTOMOUNT directly. Possibly S_AUTOMOUNT should
shift to the dentry entirely.
(*) #define DMANAGED_TRANSIT 0x20000000
This is an indicator that the filesystem that owns the dentry wants to
manage processes transiting away from that dentry. If this is set on a
dentry, then a new dentry op:
int (*d_manage)(struct path *);
is invoked. This is allowed to sleep and is allowed to return an error.
This allows autofs to hold non-Oz-mode processes here without any
filesystem locks being held.
Since d_managed is just an integer, all three fields can be tested in one go,
reducing the amount of intrusion into the normal path. __follow_mount() is
replaced by managed_dentry() which now handles transit to a mountpoint's root
dentry, automount points and points that the filesystem wants to manage.
==========================
WHAT THIS MEANS FOR AUTOFS
==========================
autofs currently uses the lookup() inode op and the d_revalidate() dentry op to
trigger the automounting of indirect mounts, and both of these can be called
with i_mutex held.
autofs knows that the i_mutex will be held by the caller in lookup(), and so
can drop it before invoking the daemon - but this isn't so for d_revalidate(),
since the lock is only held on _some_ of the code paths that call it. This
means that autofs can't risk dropping i_mutex from its d_revalidate() function
before it calls the daemon.
The bug could manifest itself as, for example, a process that's trying to
validate an automount dentry that gets made to wait because that dentry is
expired and needs cleaning up:
mkdir S ffffffff8014e05a 0 32580 24956
Call Trace:
[<ffffffff885371fd>] :autofs4:autofs4_wait+0x674/0x897
[<ffffffff80127f7d>] avc_has_perm+0x46/0x58
[<ffffffff8009fdcf>] autoremove_wake_function+0x0/0x2e
[<ffffffff88537be6>] :autofs4:autofs4_expire_wait+0x41/0x6b
[<ffffffff88535cfc>] :autofs4:autofs4_revalidate+0x91/0x149
[<ffffffff80036d96>] __lookup_hash+0xa0/0x12f
[<ffffffff80057a2f>] lookup_create+0x46/0x80
[<ffffffff800e6e31>] sys_mkdirat+0x56/0xe4
versus the automount daemon which wants to remove that dentry, but can't
because the normal process is holding the i_mutex lock:
automount D ffffffff8014e05a 0 32581 1 32561
Call Trace:
[<ffffffff80063c3f>] __mutex_lock_slowpath+0x60/0x9b
[<ffffffff8000ccf1>] do_path_lookup+0x2ca/0x2f1
[<ffffffff80063c89>] .text.lock.mutex+0xf/0x14
[<ffffffff800e6d55>] do_rmdir+0x77/0xde
[<ffffffff8005d229>] tracesys+0x71/0xe0
[<ffffffff8005d28d>] tracesys+0xd5/0xe0
which means that the system is deadlocked.
This patch allows autofs to hold up normal processes whilst the daemon goes
ahead and does things to the dentry tree behind the automouter point without
risking a deadlock as no locks are held in d_manage() or d_automount().
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Acked-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
---
Documentation/filesystems/vfs.txt | 13 +++-
fs/autofs4/expire.c | 4 +
fs/dcache.c | 7 ++
fs/namei.c | 118 +++++++++++++++++++++++++------------
fs/namespace.c | 6 +-
include/linux/dcache.h | 15 +++--
6 files changed, 110 insertions(+), 53 deletions(-)
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index ff4bf82..fc27e43 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -848,6 +848,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
+ int (*d_manage)(struct path *);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -891,8 +892,16 @@ struct dentry_operations {
the automount first. If the automount failed, then an error code
should be returned.
- This function is only used if S_AUTOMOUNT is set on the inode to which
- the dentry refers.
+ This function is only used if DMANAGED_AUTOMOUNT is set on the dentry.
+ This is set by d_add() if S_AUTOMOUNT is set on the inode being added.
+
+ d_manage: called to allow the filesystem to manage the transition from a
+ dentry (optional). This allows autofs, for example, to hold up clients
+ waiting to explore behind a 'mountpoint', whilst letting the daemon go
+ past and construct the subtree there.
+
+ This function is only used if DMANAGED_TRANSIT is set on the dentry
+ being transited from.
Example :
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index a796c94..9f5bde2 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -276,7 +276,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
struct autofs_info *ino = autofs4_dentry_ino(root);
if (d_mountpoint(root)) {
ino->flags |= AUTOFS_INF_MOUNTPOINT;
- root->d_mounted--;
+ root->d_managed--;
}
ino->flags |= AUTOFS_INF_EXPIRING;
init_completion(&ino->expire_complete);
@@ -499,7 +499,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
spin_lock(&sbi->fs_lock);
if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
- sb->s_root->d_mounted++;
+ sb->s_root->d_managed++;
ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
}
ino->flags &= ~AUTOFS_INF_EXPIRING;
diff --git a/fs/dcache.c b/fs/dcache.c
index 83293be..35e5a54 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -956,7 +956,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
dentry->d_sb = NULL;
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
- dentry->d_mounted = 0;
+ dentry->d_managed = 0;
INIT_HLIST_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -993,8 +993,11 @@ EXPORT_SYMBOL(d_alloc_name);
/* the caller must hold dcache_lock */
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
{
- if (inode)
+ if (inode) {
list_add(&dentry->d_alias, &inode->i_dentry);
+ if (IS_AUTOMOUNT(inode))
+ dentry->d_managed |= DMANAGED_AUTOMOUNT;
+ }
dentry->d_inode = inode;
fsnotify_d_instantiate(dentry, inode);
}
diff --git a/fs/namei.c b/fs/namei.c
index 74bce3a..1bbd2d4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -614,7 +614,7 @@ int follow_up(struct path *path)
/*
* Perform an automount
- * - return -EISDIR to tell __follow_mount() to stop and return the path we
+ * - return -EISDIR to tell managed_dentry() to stop and return the path we
* were called with.
*/
static int follow_automount(struct path *path, unsigned flags,
@@ -629,7 +629,7 @@ static int follow_automount(struct path *path, unsigned flags,
* and this is the terminal part of the path.
*/
if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE))
- return -EXDEV; /* we actually want to stop here */
+ return -EISDIR; /* we actually want to stop here */
/* We want to mount if someone is trying to open/create a file of any
* type under the mountpoint, wants to traverse through the mountpoint
@@ -649,8 +649,20 @@ static int follow_automount(struct path *path, unsigned flags,
return -ELOOP;
mnt = path->dentry->d_op->d_automount(path);
- if (IS_ERR(mnt))
+ if (IS_ERR(mnt)) {
+ /*
+ * The filesystem is allowed to return -EISDIR here to indicate
+ * it doesn't want to automount. For instance, autofs would do
+ * this so that its userspace daemon can mount on this dentry.
+ *
+ * However, we can only permit this if it's a terminal point in
+ * the path being looked up; if it wasn't then the remainder of
+ * the path is inaccessible and we should say so.
+ */
+ if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE))
+ return -EREMOTE;
return PTR_ERR(mnt);
+ }
if (!mnt) /* mount collision */
return 0;
@@ -669,47 +681,61 @@ static int follow_automount(struct path *path, unsigned flags,
return 0;
}
-/* no need for dcache_lock, as serialization is taken care in
- * namespace.c
+/*
+ * Handle a dentry that is managed in some way.
+ * - Flagged for transit management (autofs)
+ * - Flagged as mountpoint
+ * - Flagged as automount point
*/
-static int __follow_mount(struct path *path, unsigned flags)
+static int managed_dentry(struct path *path, unsigned flags)
{
- struct vfsmount *mounted;
+ unsigned d_managed;
bool need_mntput = false;
int ret;
- for (;;) {
- while (d_mountpoint(path->dentry)) {
- mounted = lookup_mnt(path);
- if (!mounted)
- break;
- dput(path->dentry);
- if (need_mntput)
- mntput(path->mnt);
- path->mnt = mounted;
- path->dentry = dget(mounted->mnt_root);
- need_mntput = true;
+ while (d_managed = path->dentry->d_managed,
+ unlikely(d_managed != 0)) {
+ /* Allow the filesystem to manage the transit without i_mutex
+ * being held. */
+ if (d_managed & DMANAGED_TRANSIT) {
+ BUG_ON(!path->dentry->d_op);
+ BUG_ON(!path->dentry->d_op->d_manage);
+ ret = path->dentry->d_op->d_manage(path);
+ if (ret < 0)
+ return ret;
}
- if (!d_automount_point(path->dentry))
- break;
- ret = follow_automount(path, flags, &need_mntput);
- if (ret < 0)
- return ret == -EISDIR ? 0 : ret;
- }
- return 0;
-}
-static void follow_mount(struct path *path)
-{
- while (d_mountpoint(path->dentry)) {
- struct vfsmount *mounted = lookup_mnt(path);
- if (!mounted)
- break;
- dput(path->dentry);
- mntput(path->mnt);
- path->mnt = mounted;
- path->dentry = dget(mounted->mnt_root);
+ /* Transit to a mounted filesystem. */
+ if (d_managed & DMANAGED_MOUNTPOINT) {
+ struct vfsmount *mounted = lookup_mnt(path);
+ if (mounted) {
+ dput(path->dentry);
+ if (need_mntput)
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ need_mntput = true;
+ continue;
+ }
+
+ /* Something is mounted on this dentry in another
+ * namespace and/or whatever was mounted there in this
+ * namespace got unmounted before we managed to get the
+ * vfsmount_lock */
+ }
+
+ /* Handle an automount point */
+ if (d_managed & DMANAGED_AUTOMOUNT) {
+ ret = follow_automount(path, flags, &need_mntput);
+ if (ret < 0)
+ return ret == -EISDIR ? 0 : ret;
+ continue;
+ }
+
+ /* We didn't change the current path point */
+ break;
}
+ return 0;
}
/* no need for dcache_lock, as serialization is taken care in
@@ -730,6 +756,22 @@ int follow_down(struct path *path)
return 0;
}
+/*
+ * Skip to top of mountpoint pile for follow_dotdot().
+ */
+static void follow_mount(struct path *path)
+{
+ while (d_mountpoint(path->dentry)) {
+ struct vfsmount *mounted = lookup_mnt(path);
+ if (!mounted)
+ break;
+ dput(path->dentry);
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ }
+}
+
static __always_inline void follow_dotdot(struct nameidata *nd)
{
set_root(nd);
@@ -819,7 +861,7 @@ found:
done:
path->mnt = mnt;
path->dentry = dentry;
- ret = __follow_mount(path, nd->flags);
+ ret = managed_dentry(path, nd->flags);
if (unlikely(ret < 0))
path_put_conditional(path, nd);
return ret;
@@ -1762,7 +1804,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
if (open_flag & O_EXCL)
goto exit_dput;
- error = __follow_mount(path, nd->flags);
+ error = managed_dentry(path, nd->flags);
if (error < 0)
goto exit_dput;
diff --git a/fs/namespace.c b/fs/namespace.c
index a72eaab..e72b7b9 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -503,7 +503,7 @@ static void detach_mnt(struct vfsmount *mnt, struct path *old_path)
mnt->mnt_mountpoint = mnt->mnt_root;
list_del_init(&mnt->mnt_child);
list_del_init(&mnt->mnt_hash);
- old_path->dentry->d_mounted--;
+ old_path->dentry->d_managed--;
}
/*
@@ -514,7 +514,7 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
{
child_mnt->mnt_parent = mntget(mnt);
child_mnt->mnt_mountpoint = dget(dentry);
- dentry->d_mounted++;
+ dentry->d_managed++;
}
/*
@@ -1074,7 +1074,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
list_del_init(&p->mnt_child);
if (p->mnt_parent != p) {
p->mnt_parent->mnt_ghosts++;
- p->mnt_mountpoint->d_mounted--;
+ p->mnt_mountpoint->d_managed--;
}
change_mnt_propagation(p, MS_PRIVATE);
}
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index ab62055..2da5aa4 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -90,7 +90,11 @@ struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
- int d_mounted;
+ unsigned d_managed; /* >0 if we want to manage the
+ * pathwalk at this point */
+#define DMANAGED_MOUNTPOINT 0x0fffffff /* mountpoint count */
+#define DMANAGED_AUTOMOUNT 0x10000000 /* handle automount flag */
+#define DMANAGED_TRANSIT 0x20000000 /* managed transit */
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
@@ -140,6 +144,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
+ int (*d_manage)(struct path *);
};
/* the dentry parameter passed to d_hash and d_compare is the parent
@@ -159,6 +164,7 @@ d_delete: no yes no no
d_release: no no no yes
d_iput: no no no yes
d_automount: no no no yes
+d_manage: no no no yes
*/
/* d_flags entries */
@@ -388,14 +394,11 @@ static inline struct dentry *dget_parent(struct dentry *dentry)
extern void dput(struct dentry *);
-static inline int d_mountpoint(struct dentry *dentry)
+static inline bool d_mountpoint(struct dentry *dentry)
{
- return dentry->d_mounted;
+ return (dentry->d_managed & DMANAGED_MOUNTPOINT) != 0;
}
-#define d_automount_point(dentry) \
- (dentry->d_inode && IS_AUTOMOUNT(dentry->d_inode))
-
extern struct vfsmount *lookup_mnt(struct path *);
extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 09/17] autofs4: add d_automount() dentry operation
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (3 preceding siblings ...)
2010-09-30 18:15 ` [PATCH 07/17] Make dentry::d_mounted into a more general field for special function dirs David Howells
@ 2010-09-30 18:15 ` David Howells
2010-09-30 18:15 ` [PATCH 11/17] autofs4: removed unused code David Howells
` (4 subsequent siblings)
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:15 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, Ian Kent, David Howells
From: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Add a function to use the newly defined ->d_automount() dentry operation
for triggering mounts instead of doing the user space callback in ->lookup()
and ->d_revalidate().
Note, to be useful the subsequent patch to add the ->d_manage() dentry
operation is also needed so the discussion of functionality is deferred to
that patch.
Signed-off-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/autofs4/autofs_i.h | 30 ++++++
fs/autofs4/expire.c | 6 +
fs/autofs4/inode.c | 4 +
fs/autofs4/root.c | 262 ++++++++++++++++++++++++++++---------------------
4 files changed, 190 insertions(+), 112 deletions(-)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 08af160..079206c 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -215,6 +215,36 @@ extern const struct inode_operations autofs4_direct_root_inode_operations;
extern const struct file_operations autofs4_dir_operations;
extern const struct file_operations autofs4_root_operations;
+/* Operations methods */
+
+struct vfsmount *autofs4_d_automount(struct path *);
+
+/* VFS automount flags management functions */
+
+static inline void __managed_dentry_set_automount(struct dentry *dentry)
+{
+ dentry->d_managed |= DMANAGED_AUTOMOUNT;
+}
+
+static inline void managed_dentry_set_automount(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_set_automount(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+static inline void __managed_dentry_clear_automount(struct dentry *dentry)
+{
+ dentry->d_managed &= ~DMANAGED_AUTOMOUNT;
+}
+
+static inline void managed_dentry_clear_automount(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_clear_automount(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
/* Initializing function */
int autofs4_fill_super(struct super_block *, void *, int);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 47feba9..c366dac 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -279,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
root->d_managed--;
}
ino->flags |= AUTOFS_INF_EXPIRING;
+ managed_dentry_set_automount(root);
init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
return root;
@@ -406,6 +407,7 @@ found:
expired, (int)expired->d_name.len, expired->d_name.name);
ino = autofs4_dentry_ino(expired);
ino->flags |= AUTOFS_INF_EXPIRING;
+ managed_dentry_set_automount(expired);
init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
spin_lock(&dcache_lock);
@@ -473,6 +475,8 @@ int autofs4_expire_run(struct super_block *sb,
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
ino->flags &= ~AUTOFS_INF_EXPIRING;
+ if (!d_unhashed(dentry))
+ managed_dentry_clear_automount(dentry);
complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
@@ -503,6 +507,8 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
}
ino->flags &= ~AUTOFS_INF_EXPIRING;
+ if (ret)
+ managed_dentry_clear_automount(dentry);
complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
dput(dentry);
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 821b2b9..41b7ad1 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -252,6 +252,7 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi)
}
static const struct dentry_operations autofs4_sb_dentry_operations = {
+ .d_automount = autofs4_d_automount,
.d_release = autofs4_dentry_release,
};
@@ -320,6 +321,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
goto fail_dput;
}
+ if (autofs_type_trigger(sbi->type))
+ __managed_dentry_set_automount(root);
+
root_inode->i_fop = &autofs4_root_operations;
root_inode->i_op = autofs_type_trigger(sbi->type) ?
&autofs4_direct_root_inode_operations :
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 7dd218b..22dc4c0 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -31,7 +31,6 @@ static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
-static void *autofs4_follow_link(struct dentry *, struct nameidata *);
#define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY)
#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE)
@@ -69,7 +68,6 @@ const struct inode_operations autofs4_direct_root_inode_operations = {
.unlink = autofs4_dir_unlink,
.mkdir = autofs4_dir_mkdir,
.rmdir = autofs4_dir_rmdir,
- .follow_link = autofs4_follow_link,
};
const struct inode_operations autofs4_dir_inode_operations = {
@@ -399,13 +397,12 @@ void autofs4_dentry_release(struct dentry *de)
/* For dentries of directories in the root dir */
static const struct dentry_operations autofs4_root_dentry_operations = {
- .d_revalidate = autofs4_revalidate,
.d_release = autofs4_dentry_release,
};
/* For other dentries */
static const struct dentry_operations autofs4_dentry_operations = {
- .d_revalidate = autofs4_revalidate,
+ .d_automount = autofs4_d_automount,
.d_release = autofs4_dentry_release,
};
@@ -519,50 +516,176 @@ next:
return NULL;
}
+static int autofs4_mount_wait(struct dentry *dentry)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ int status;
+
+ if (ino->flags & AUTOFS_INF_PENDING) {
+ DPRINTK("waiting for mount name=%.*s",
+ dentry->d_name.len, dentry->d_name.name);
+ status = autofs4_wait(sbi, dentry, NFY_MOUNT);
+ DPRINTK("mount wait done status=%d", status);
+ ino->last_used = jiffies;
+ return status;
+ }
+ return 0;
+}
+
+static int do_expire_wait(struct dentry *dentry)
+{
+ struct dentry *expiring;
+
+ expiring = autofs4_lookup_expiring(dentry);
+ if (!expiring)
+ return autofs4_expire_wait(dentry);
+ else {
+ /*
+ * If we are racing with expire the request might not
+ * be quite complete, but the directory has been removed
+ * so it must have been successful, just wait for it.
+ */
+ autofs4_expire_wait(expiring);
+ autofs4_del_expiring(expiring);
+ dput(expiring);
+ }
+ return 0;
+}
+
+static struct dentry *autofs4_mountpoint_changed(struct path *path)
+{
+ struct dentry *dentry = path->dentry;
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+
+ /*
+ * If this is an indirect mount the dentry could have gone away
+ * as a result of an expire and a new one created.
+ */
+ if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) {
+ struct dentry *parent = dentry->d_parent;
+ struct dentry *new = d_lookup(parent, &dentry->d_name);
+ if (!new)
+ return NULL;
+ dput(path->dentry);
+ path->dentry = new;
+ }
+ return path->dentry;
+}
+
+struct vfsmount *autofs4_d_automount(struct path *path)
+{
+ struct dentry *dentry = path->dentry;
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ int status;
+
+ DPRINTK("dentry=%p %.*s",
+ dentry, dentry->d_name.len, dentry->d_name.name);
+
+ /* The daemon never triggers a mount. */
+ if (autofs4_oz_mode(sbi))
+ return NULL;
+
+ /*
+ * If an expire request is pending everyone must wait.
+ * If the expire fails we're still mounted so continue
+ * the follow and return. A return of -EAGAIN (which only
+ * happens with indirect mounts) means the expire completed
+ * and the directory was removed, so just go ahead and try
+ * the mount.
+ */
+ status = do_expire_wait(dentry);
+ if (status && status != -EAGAIN)
+ return NULL;
+
+ /* Callback to the daemon to perform the mount or wait */
+ spin_lock(&sbi->fs_lock);
+ if (ino->flags & AUTOFS_INF_PENDING) {
+ spin_unlock(&sbi->fs_lock);
+ status = autofs4_mount_wait(dentry);
+ if (status)
+ return ERR_PTR(status);
+ spin_lock(&sbi->fs_lock);
+ goto done;
+ }
+
+ /*
+ * If the dentry is a symlink it's equivalent to a directory
+ * having d_mounted() true, so there's no need to call back
+ * to the daemon.
+ */
+ if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))
+ goto done;
+ spin_lock(&dcache_lock);
+ if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
+ ino->flags |= AUTOFS_INF_PENDING;
+ spin_unlock(&dcache_lock);
+ spin_unlock(&sbi->fs_lock);
+ status = autofs4_mount_wait(dentry);
+ if (status)
+ return ERR_PTR(status);
+ spin_lock(&sbi->fs_lock);
+ ino->flags &= ~AUTOFS_INF_PENDING;
+ goto done;
+ }
+ spin_unlock(&dcache_lock);
+done:
+ /*
+ * Any needed mounting has been completed and the path updated
+ * so turn this into a normal dentry so we don't continually
+ * call ->d_automount().
+ */
+ managed_dentry_clear_automount(dentry);
+ spin_unlock(&sbi->fs_lock);
+
+ /* Mount succeeded, check if we ended up with a new dentry */
+ dentry = autofs4_mountpoint_changed(path);
+ if (!dentry)
+ return ERR_PTR(-ENOENT);
+
+ return NULL;
+}
+
/* Lookups in the root directory */
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
struct autofs_sb_info *sbi;
struct autofs_info *ino;
- struct dentry *expiring, *active;
- int oz_mode;
+ struct dentry *active;
- DPRINTK("name = %.*s",
- dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name);
/* File name too long to exist */
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
sbi = autofs4_sbi(dir->i_sb);
- oz_mode = autofs4_oz_mode(sbi);
DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
active = autofs4_lookup_active(dentry);
- if (active) {
- dentry = active;
- ino = autofs4_dentry_ino(dentry);
- } else {
- /*
- * Mark the dentry incomplete but don't hash it. We do this
- * to serialize our inode creation operations (symlink and
- * mkdir) which prevents deadlock during the callback to
- * the daemon. Subsequent user space lookups for the same
- * dentry are placed on the wait queue while the daemon
- * itself is allowed passage unresticted so the create
- * operation itself can then hash the dentry. Finally,
- * we check for the hashed dentry and return the newly
- * hashed dentry.
- */
+ if (active)
+ return active;
+ else {
dentry->d_op = &autofs4_root_dentry_operations;
/*
- * And we need to ensure that the same dentry is used for
- * all following lookup calls until it is hashed so that
- * the dentry flags are persistent throughout the request.
+ * A dentry that is not within the root can never trigger
+ * a mount operation, unless the directory already exists,
+ * so we can return fail immediately. The daemon however
+ * does need to create directories within the file system.
*/
+ if (!autofs4_oz_mode(sbi) && !IS_ROOT(dentry->d_parent))
+ return ERR_PTR(-ENOENT);
+
+ /* Mark entries in the root as mount triggers */
+ if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) {
+ dentry->d_op = &autofs4_dentry_operations;
+ managed_dentry_set_automount(dentry);
+ }
+
ino = autofs4_init_ino(NULL, sbi, 0555);
if (!ino)
return ERR_PTR(-ENOMEM);
@@ -575,81 +698,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
d_instantiate(dentry, NULL);
}
- if (!oz_mode) {
- mutex_unlock(&dir->i_mutex);
- expiring = autofs4_lookup_expiring(dentry);
- if (expiring) {
- /*
- * If we are racing with expire the request might not
- * be quite complete but the directory has been removed
- * so it must have been successful, so just wait for it.
- */
- autofs4_expire_wait(expiring);
- autofs4_del_expiring(expiring);
- dput(expiring);
- }
-
- spin_lock(&sbi->fs_lock);
- ino->flags |= AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- if (dentry->d_op && dentry->d_op->d_revalidate)
- (dentry->d_op->d_revalidate)(dentry, nd);
- mutex_lock(&dir->i_mutex);
- }
-
- /*
- * If we are still pending, check if we had to handle
- * a signal. If so we can force a restart..
- */
- if (ino->flags & AUTOFS_INF_PENDING) {
- /* See if we were interrupted */
- if (signal_pending(current)) {
- sigset_t *sigset = ¤t->pending.signal;
- if (sigismember (sigset, SIGKILL) ||
- sigismember (sigset, SIGQUIT) ||
- sigismember (sigset, SIGINT)) {
- if (active)
- dput(active);
- return ERR_PTR(-ERESTARTNOINTR);
- }
- }
- if (!oz_mode) {
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- }
- }
-
- /*
- * If this dentry is unhashed, then we shouldn't honour this
- * lookup. Returning ENOENT here doesn't do the right thing
- * for all system calls, but it should be OK for the operations
- * we permit from an autofs.
- */
- if (!oz_mode && d_unhashed(dentry)) {
- /*
- * A user space application can (and has done in the past)
- * remove and re-create this directory during the callback.
- * This can leave us with an unhashed dentry, but a
- * successful mount! So we need to perform another
- * cached lookup in case the dentry now exists.
- */
- struct dentry *parent = dentry->d_parent;
- struct dentry *new = d_lookup(parent, &dentry->d_name);
- if (new != NULL)
- dentry = new;
- else
- dentry = ERR_PTR(-ENOENT);
-
- if (active)
- dput(active);
-
- return dentry;
- }
-
- if (active)
- return active;
-
return NULL;
}
@@ -694,11 +742,6 @@ static int autofs4_dir_symlink(struct inode *dir,
}
d_add(dentry, inode);
- if (dir == dir->i_sb->s_root->d_inode)
- dentry->d_op = &autofs4_root_dentry_operations;
- else
- dentry->d_op = &autofs4_dentry_operations;
-
dentry->d_fsdata = ino;
ino->dentry = dget(dentry);
atomic_inc(&ino->count);
@@ -825,11 +868,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
}
d_add(dentry, inode);
- if (dir == dir->i_sb->s_root->d_inode)
- dentry->d_op = &autofs4_root_dentry_operations;
- else
- dentry->d_op = &autofs4_dentry_operations;
-
dentry->d_fsdata = ino;
ino->dentry = dget(dentry);
atomic_inc(&ino->count);
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 11/17] autofs4: removed unused code
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (4 preceding siblings ...)
2010-09-30 18:15 ` [PATCH 09/17] autofs4: add d_automount() dentry operation David Howells
@ 2010-09-30 18:15 ` David Howells
2010-09-30 18:16 ` [PATCH 13/17] autofs4: cleanup dentry operations David Howells
` (3 subsequent siblings)
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:15 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, Ian Kent, David Howells
From: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Remove code that is not used due to the use of ->d_automount()
and ->d_manage().
Signed-off-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/autofs4/autofs_i.h | 7 -
fs/autofs4/root.c | 229 -------------------------------------------------
2 files changed, 0 insertions(+), 236 deletions(-)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 48f8248..cb86036 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -172,13 +172,6 @@ static inline int autofs4_ispending(struct dentry *dentry)
return 0;
}
-static inline void autofs4_copy_atime(struct file *src, struct file *dst)
-{
- dst->f_path.dentry->d_inode->i_atime =
- src->f_path.dentry->d_inode->i_atime;
- return;
-}
-
struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *);
void autofs4_free_ino(struct autofs_info *);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 3e71e4c..77257dd 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -32,9 +32,6 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
-#define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY)
-#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE)
-
const struct file_operations autofs4_root_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
@@ -110,14 +107,6 @@ static void autofs4_del_active(struct dentry *dentry)
return;
}
-static unsigned int autofs4_need_mount(unsigned int flags)
-{
- unsigned int res = 0;
- if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS))
- res = 1;
- return res;
-}
-
static int autofs4_dir_open(struct inode *inode, struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
@@ -149,224 +138,6 @@ out:
return dcache_dir_open(inode, file);
}
-static int try_to_fill_dentry(struct dentry *dentry, int flags)
-{
- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
- int status;
-
- DPRINTK("dentry=%p %.*s ino=%p",
- dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
-
- /*
- * Wait for a pending mount, triggering one if there
- * isn't one already
- */
- if (dentry->d_inode == NULL) {
- DPRINTK("waiting for mount name=%.*s",
- dentry->d_name.len, dentry->d_name.name);
-
- status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
- DPRINTK("mount done status=%d", status);
-
- /* Turn this into a real negative dentry? */
- if (status == -ENOENT) {
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- return status;
- } else if (status) {
- /* Return a negative dentry, but leave it "pending" */
- return status;
- }
- /* Trigger mount for path component or follow link */
- } else if (ino->flags & AUTOFS_INF_PENDING ||
- autofs4_need_mount(flags)) {
- DPRINTK("waiting for mount name=%.*s",
- dentry->d_name.len, dentry->d_name.name);
-
- spin_lock(&sbi->fs_lock);
- ino->flags |= AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
- DPRINTK("mount done status=%d", status);
-
- if (status) {
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- return status;
- }
- }
-
- /* Initialize expiry counter after successful mount */
- ino->last_used = jiffies;
-
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
-
- return 0;
-}
-
-/* For autofs direct mounts the follow link triggers the mount */
-static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
- int oz_mode = autofs4_oz_mode(sbi);
- unsigned int lookup_type;
- int status;
-
- DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d",
- dentry, dentry->d_name.len, dentry->d_name.name, oz_mode,
- nd->flags);
- /*
- * For an expire of a covered direct or offset mount we need
- * to break out of follow_down_one() at the autofs mount trigger
- * (d_mounted--), so we can see the expiring flag, and manage
- * the blocking and following here until the expire is completed.
- */
- if (oz_mode) {
- spin_lock(&sbi->fs_lock);
- if (ino->flags & AUTOFS_INF_EXPIRING) {
- spin_unlock(&sbi->fs_lock);
- /* Follow down to our covering mount. */
- if (!follow_down_one(&nd->path))
- goto done;
- goto follow;
- }
- spin_unlock(&sbi->fs_lock);
- goto done;
- }
-
- /* If an expire request is pending everyone must wait. */
- autofs4_expire_wait(dentry);
-
- /* We trigger a mount for almost all flags */
- lookup_type = autofs4_need_mount(nd->flags);
- spin_lock(&sbi->fs_lock);
- spin_lock(&dcache_lock);
- if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) {
- spin_unlock(&dcache_lock);
- spin_unlock(&sbi->fs_lock);
- goto follow;
- }
-
- /*
- * If the dentry contains directories then it is an autofs
- * multi-mount with no root mount offset. So don't try to
- * mount it again.
- */
- if (ino->flags & AUTOFS_INF_PENDING ||
- (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
- spin_unlock(&dcache_lock);
- spin_unlock(&sbi->fs_lock);
-
- status = try_to_fill_dentry(dentry, nd->flags);
- if (status)
- goto out_error;
-
- goto follow;
- }
- spin_unlock(&dcache_lock);
- spin_unlock(&sbi->fs_lock);
-follow:
- /*
- * If there is no root mount it must be an autofs
- * multi-mount with no root offset so we don't need
- * to follow it.
- */
- if (d_managed(dentry)) {
- status = follow_down(&nd->path, false);
- if (status < 0)
- goto out_error;
- }
-
-done:
- return NULL;
-
-out_error:
- path_put(&nd->path);
- return ERR_PTR(status);
-}
-
-/*
- * Revalidate is called on every cache lookup. Some of those
- * cache lookups may actually happen while the dentry is not
- * yet completely filled in, and revalidate has to delay such
- * lookups..
- */
-static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
- struct inode *dir = dentry->d_parent->d_inode;
- struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
- int oz_mode = autofs4_oz_mode(sbi);
- int flags = nd ? nd->flags : 0;
- int status = 1;
-
- /* Pending dentry */
- spin_lock(&sbi->fs_lock);
- if (autofs4_ispending(dentry)) {
- /* The daemon never causes a mount to trigger */
- spin_unlock(&sbi->fs_lock);
-
- if (oz_mode)
- return 1;
-
- /*
- * If the directory has gone away due to an expire
- * we have been called as ->d_revalidate() and so
- * we need to return false and proceed to ->lookup().
- */
- if (autofs4_expire_wait(dentry) == -EAGAIN)
- return 0;
-
- /*
- * A zero status is success otherwise we have a
- * negative error code.
- */
- status = try_to_fill_dentry(dentry, flags);
- if (status == 0)
- return 1;
-
- return status;
- }
- spin_unlock(&sbi->fs_lock);
-
- /* Negative dentry.. invalidate if "old" */
- if (dentry->d_inode == NULL)
- return 0;
-
- /* Check for a non-mountpoint directory with no contents */
- spin_lock(&dcache_lock);
- if (S_ISDIR(dentry->d_inode->i_mode) &&
- !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
- DPRINTK("dentry=%p %.*s, emptydir",
- dentry, dentry->d_name.len, dentry->d_name.name);
- spin_unlock(&dcache_lock);
-
- /* The daemon never causes a mount to trigger */
- if (oz_mode)
- return 1;
-
- /*
- * A zero status is success otherwise we have a
- * negative error code.
- */
- status = try_to_fill_dentry(dentry, flags);
- if (status == 0)
- return 1;
-
- return status;
- }
- spin_unlock(&dcache_lock);
-
- return 1;
-}
-
void autofs4_dentry_release(struct dentry *de)
{
struct autofs_info *inf;
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 13/17] autofs4: cleanup dentry operations
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (5 preceding siblings ...)
2010-09-30 18:15 ` [PATCH 11/17] autofs4: removed unused code David Howells
@ 2010-09-30 18:16 ` David Howells
2010-09-30 18:16 ` [PATCH 14/17] autofs4: cleanup autofs4_free_ino() David Howells
` (2 subsequent siblings)
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:16 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, Ian Kent, David Howells
From: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
There are now two distinct dentry operations uses. One for dentrys
that trigger mounts and one for dentrys that do not.
Rationalize the use of these dentry operations and rename them to
reflect their function.
Signed-off-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/autofs4/autofs_i.h | 7 ++-----
fs/autofs4/inode.c | 12 ++++--------
fs/autofs4/root.c | 36 ++++++++++++++++++++----------------
3 files changed, 26 insertions(+), 29 deletions(-)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 8710878..8b1c0bc 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -203,11 +203,8 @@ extern const struct inode_operations autofs4_symlink_inode_operations;
extern const struct inode_operations autofs4_dir_inode_operations;
extern const struct file_operations autofs4_dir_operations;
extern const struct file_operations autofs4_root_operations;
-
-/* Operations methods */
-
-struct vfsmount *autofs4_d_automount(struct path *);
-int autofs4_d_manage(struct path *, bool);
+extern const struct dentry_operations autofs4_dentry_operations;
+extern const struct dentry_operations autofs4_mount_dentry_operations;
/* VFS automount flags management functions */
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 80cdffd..8eaa723 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -251,12 +251,6 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi)
return ino;
}
-static const struct dentry_operations autofs4_sb_dentry_operations = {
- .d_automount = autofs4_d_automount,
- .d_manage = autofs4_d_manage,
- .d_release = autofs4_dentry_release,
-};
-
int autofs4_fill_super(struct super_block *s, void *data, int silent)
{
struct inode * root_inode;
@@ -311,7 +305,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
goto fail_iput;
pipe = NULL;
- root->d_op = &autofs4_sb_dentry_operations;
+ root->d_op = &autofs4_dentry_operations;
root->d_fsdata = ino;
/* Can this call block? */
@@ -322,8 +316,10 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
goto fail_dput;
}
- if (autofs_type_trigger(sbi->type))
+ if (autofs_type_trigger(sbi->type)) {
+ root->d_op = &autofs4_mount_dentry_operations;
__managed_dentry_set_managed(root);
+ }
root_inode->i_fop = &autofs4_root_operations;
root_inode->i_op = &autofs4_dir_inode_operations;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 2856a0c..cb168ba 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -31,6 +31,8 @@ static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
+static struct vfsmount *autofs4_d_automount(struct path *);
+static int autofs4_d_manage(struct path *, bool);
const struct file_operations autofs4_root_operations = {
.open = dcache_dir_open,
@@ -60,6 +62,18 @@ const struct inode_operations autofs4_dir_inode_operations = {
.rmdir = autofs4_dir_rmdir,
};
+/* For dentries that don't initiate mounting */
+const struct dentry_operations autofs4_dentry_operations = {
+ .d_release = autofs4_dentry_release,
+};
+
+/* For dentries that do initiate mounting */
+const struct dentry_operations autofs4_mount_dentry_operations = {
+ .d_automount = autofs4_d_automount,
+ .d_manage = autofs4_d_manage,
+ .d_release = autofs4_dentry_release,
+};
+
static void autofs4_add_active(struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
@@ -151,18 +165,6 @@ void autofs4_dentry_release(struct dentry *de)
}
}
-/* For dentries of directories in the root dir */
-static const struct dentry_operations autofs4_root_dentry_operations = {
- .d_release = autofs4_dentry_release,
-};
-
-/* For other dentries */
-static const struct dentry_operations autofs4_dentry_operations = {
- .d_automount = autofs4_d_automount,
- .d_manage = autofs4_d_manage,
- .d_release = autofs4_dentry_release,
-};
-
static struct dentry *autofs4_lookup_active(struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
@@ -330,7 +332,7 @@ static struct dentry *autofs4_mountpoint_changed(struct path *path)
return path->dentry;
}
-struct vfsmount *autofs4_d_automount(struct path *path)
+static struct vfsmount *autofs4_d_automount(struct path *path)
{
struct dentry *dentry = path->dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
@@ -499,7 +501,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
if (active)
return active;
else {
- dentry->d_op = &autofs4_root_dentry_operations;
+ dentry->d_op = &autofs4_dentry_operations;
/*
* A dentry that is not within the root can never trigger
@@ -512,7 +514,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
/* Mark entries in the root as mount triggers */
if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) {
- dentry->d_op = &autofs4_dentry_operations;
+ dentry->d_op = &autofs4_mount_dentry_operations;
__managed_dentry_set_managed(dentry);
}
@@ -572,6 +574,8 @@ static int autofs4_dir_symlink(struct inode *dir,
}
d_add(dentry, inode);
+ dentry->d_op = &autofs4_dentry_operations;
+
dentry->d_fsdata = ino;
ino->dentry = dget(dentry);
atomic_inc(&ino->count);
@@ -786,7 +790,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p)
int is_autofs4_dentry(struct dentry *dentry)
{
return dentry && dentry->d_inode &&
- (dentry->d_op == &autofs4_root_dentry_operations ||
+ (dentry->d_op == &autofs4_mount_dentry_operations ||
dentry->d_op == &autofs4_dentry_operations) &&
dentry->d_fsdata != NULL;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 14/17] autofs4: cleanup autofs4_free_ino()
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (6 preceding siblings ...)
2010-09-30 18:16 ` [PATCH 13/17] autofs4: cleanup dentry operations David Howells
@ 2010-09-30 18:16 ` David Howells
2010-09-30 18:16 ` [PATCH 17/17] autofs4 - bump version David Howells
2010-10-01 7:57 ` [autofs] [PATCH 00/17] Introduce automounter dentry ops Stef Bon
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:16 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, Ian Kent, David Howells
From: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
When this function is called the local reference count does't need to
be updated since the dentry is going away and dput definitely must
not be called here.
Also the autofs info struct field inode isn't used so remove it.
Signed-off-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/autofs4/inode.c | 13 -------------
fs/autofs4/root.c | 9 ---------
2 files changed, 0 insertions(+), 22 deletions(-)
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 8eaa723..ebc6354 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -45,7 +45,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
if (!reinit) {
ino->flags = 0;
- ino->inode = NULL;
ino->dentry = NULL;
ino->size = 0;
INIT_LIST_HEAD(&ino->active);
@@ -76,19 +75,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
void autofs4_free_ino(struct autofs_info *ino)
{
- struct autofs_info *p_ino;
-
if (ino->dentry) {
ino->dentry->d_fsdata = NULL;
- if (ino->dentry->d_inode) {
- struct dentry *parent = ino->dentry->d_parent;
- if (atomic_dec_and_test(&ino->count)) {
- p_ino = autofs4_dentry_ino(parent);
- if (p_ino && parent != ino->dentry)
- atomic_dec(&p_ino->count);
- }
- dput(ino->dentry);
- }
ino->dentry = NULL;
}
if (ino->free)
@@ -390,7 +378,6 @@ struct inode *autofs4_get_inode(struct super_block *sb,
if (inode == NULL)
return NULL;
- inf->inode = inode;
inode->i_mode = inf->mode;
if (sb->s_root) {
inode->i_uid = sb->s_root->d_inode->i_uid;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index cb168ba..3b38794 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -144,11 +144,8 @@ void autofs4_dentry_release(struct dentry *de)
DPRINTK("releasing %p", de);
inf = autofs4_dentry_ino(de);
- de->d_fsdata = NULL;
-
if (inf) {
struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb);
-
if (sbi) {
spin_lock(&sbi->lookup_lock);
if (!list_empty(&inf->active))
@@ -157,10 +154,6 @@ void autofs4_dentry_release(struct dentry *de)
list_del(&inf->expiring);
spin_unlock(&sbi->lookup_lock);
}
-
- inf->dentry = NULL;
- inf->inode = NULL;
-
autofs4_free_ino(inf);
}
}
@@ -582,7 +575,6 @@ static int autofs4_dir_symlink(struct inode *dir,
p_ino = autofs4_dentry_ino(dentry->d_parent);
if (p_ino && dentry->d_parent != dentry)
atomic_inc(&p_ino->count);
- ino->inode = inode;
ino->u.symlink = cp;
dir->i_mtime = CURRENT_TIME;
@@ -708,7 +700,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
p_ino = autofs4_dentry_ino(dentry->d_parent);
if (p_ino && dentry->d_parent != dentry)
atomic_inc(&p_ino->count);
- ino->inode = inode;
inc_nlink(dir);
dir->i_mtime = CURRENT_TIME;
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH 17/17] autofs4 - bump version
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (7 preceding siblings ...)
2010-09-30 18:16 ` [PATCH 14/17] autofs4: cleanup autofs4_free_ino() David Howells
@ 2010-09-30 18:16 ` David Howells
2010-10-01 7:57 ` [autofs] [PATCH 00/17] Introduce automounter dentry ops Stef Bon
9 siblings, 0 replies; 28+ messages in thread
From: David Howells @ 2010-09-30 18:16 UTC (permalink / raw)
To: viro-rfM+Q5joDG/XmaaqVzeoHQ, jmoyer-H+wXaHxf7aLQT0dZR+AlfA
Cc: linux-fs-u79uwXL29TY76Z2rM5mHXA, autofs-CPWUtch7KCBzeIdxy0IIJw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA, Ian Kent, David Howells
From: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Increase the autofs module sub-version so we can tell what kernel
implementation is being used from user space debug logging.
Signed-off-by: Ian Kent <raven-PKsaG3nR2I+sTnJN9+BGXg@public.gmane.org>
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
include/linux/auto_fs4.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h
index 8b49ac4..e02982f 100644
--- a/include/linux/auto_fs4.h
+++ b/include/linux/auto_fs4.h
@@ -24,7 +24,7 @@
#define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 5
-#define AUTOFS_PROTO_SUBVERSION 1
+#define AUTOFS_PROTO_SUBVERSION 2
/* Mask for expire behaviour */
#define AUTOFS_EXP_IMMEDIATE 1
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [autofs] [PATCH 00/17] Introduce automounter dentry ops
[not found] ` <20100930181455.30939.53914.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
` (8 preceding siblings ...)
2010-09-30 18:16 ` [PATCH 17/17] autofs4 - bump version David Howells
@ 2010-10-01 7:57 ` Stef Bon
2010-10-01 11:49 ` Ian Kent
9 siblings, 1 reply; 28+ messages in thread
From: Stef Bon @ 2010-10-01 7:57 UTC (permalink / raw)
To: David Howells
Cc: autofs-CPWUtch7KCBzeIdxy0IIJw, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On 09/30/2010 08:14 PM, David Howells wrote:
> The attached patches introduce a couple of new dentry operations for use by
> automounters and make AFS, NFS, CIFS and autofs4 use them. This means that
> these filesystems no longer have to abuse lookup(), follow_link() and
> d_revalidate() to achieve the desired effect.
Improvments are always welcome as I look at it, but for my understanding,
how do these new dentry operations cooperate with cifs?
Cifs is the target filesystem, and handled by the automounter, thus the
automounter is the initiator, not cifs.
As you describe it (well it looks like it, I may not understand...) cifs
is the initiator, and the patches to the automounter make autofs handle
cifs requests handle better?
What is now the case here?? I cannot understand.
Any explanation is appreciated.
Stef Bon
the Netherlands
> There are two dentry operations provided:
>
> (1) struct vfsmount *(*d_automount)(struct path *path);
>
> This is used by follow_automount() in fs/namei.c to ask the filesystem
> that owns the dentry at the current path point to mount something on
> @path.
>
> It is called if either the inode belonging to the given dentry is flagged
> S_AUTOMOUNT or the dentry is flagged DMANAGED_AUTOMOUNT, and if the dentry
> has nothing mounted on it in the current namespace when someone attempts
> to use that dentry.
>
> No locks will be held when this is called.
>
> d_op->d_automount() may return one of:
>
> (a) The vfsmount mounted upon that dentry, in which case pathwalk will
> move to the root dentry of that vfsmount.
>
> (b) NULL if something was already mounted there, in which case pathwalk
> will loop around and recheck the mountings.
>
> (c) -EISDIR, in which case pathwalk will stop at this point and attempt to
> use that dentry as the object of interest. If the current dentry is
> not terminal within the path, -EREMOTE will be returned.
>
> (d) An error value, to be returned immediately.
>
> Automount transits are counted as symlinks to prevent circular references
> from being a problem. If one is detected, -ELOOP will be returned.
>
> If stat() is given AT_NO_AUTOMOUNT then d_op->d_automount() will not be
> invoked on a terminal dentry; instead that dentry will be returned by
> pathwalk.
>
> follow_automount() also does not invoke d_op->d_automount() if the caller
> gave AT_SYMLINK_NOFOLLOW to stat(), but rather returns the base dentry.
>
>
> (2) int (*d_manage)(struct path *path, bool mounting_here);
>
> This is called by managed_dentry() or follow_down() in fs/namei.c to
> indicate to a filesystem that pathwalk is about to step off of the current
> path point and walk to another point in the path.
>
> This is called if DMANAGED_TRANSIT is set on a dentry.
>
> This can then be used by autofs to stop non-daemon processes from walking
> until it has finished constructing or expiring the tree behind the dentry.
> It could also be used to prevent undesirables from mounting on this
> dentry.
>
> @mounting_here is true if called from follow_down() from mount, in which
> case namespace_sem is held exclusively by the caller of follow_down().
> Otherwise, no locks are held.
>
> d_op->d_manage() may return one of:
>
> (a) 0 to continue the pathwalk as normal.
>
> (b) -EISDIR to prevent managed_dentry() from crossing to a mounted
> filesystem or calling d_op->d_automount(), in which case the dentry
> will be treated as an ordinary directory.
>
> (c) An error to abort the pathwalk completely.
>
>
> To make this work for autofs, d_mounted in struct dentry has become d_managed.
> This used to be a count of the number of mounts on this dentry. The bottom 28
> bits are still that (DMANAGED_MOUNTPOINT). The upper four bits contain a
> couple of flags, DMANAGED_TRANSIT and DMANAGED_AUTOMOUNT. This allows
> managed_dentry() to test all three conditions with minimumal overhead if none
> of them are true.
>
> For other filesystems, setting S_AUTOMOUNT is sufficient. This is noted by
> __d_instantiate() which will set DMANAGED_AUTOMOUNT automatically if it is
> seen. Checking S_AUTOMOUNT doesn't work for autofs, however, since the dentry
> might not have an inode, hence why a dentry flag also.
>
> S_AUTOMOUNT and d_automount() are introduced in patch 1; d_manage(), d_managed
> and DMANAGED_* are introduced in patch 7.
>
> David
> ---
>
> David Howells (8):
> Make follow_down() handle d_manage()
> Make dentry::d_mounted into a more general field for special function dirs
> Add an AT_NO_AUTOMOUNT flag to suppress terminal automount
> Remove the automount through follow_link() kludge code from pathwalk
> CIFS: Use d_automount() rather than abusing follow_link()
> NFS: Use d_automount() rather than abusing follow_link()
> AFS: Use d_automount() rather than abusing follow_link()
> Add a dentry op to handle automounting rather than abusing follow_link()
>
> Ian Kent (9):
> autofs4 - bump version
> autofs4 - add v4 pseudo direct mount support
> autofs4 - fix wait validation
> autofs4: cleanup autofs4_free_ino()
> autofs4: cleanup dentry operations
> autofs4: cleanup inode operations
> autofs4: removed unused code
> autofs4: add d_manage() dentry operation
> autofs4: add d_automount() dentry operation
>
>
> Documentation/filesystems/Locking | 2
> Documentation/filesystems/vfs.txt | 22 +
> fs/afs/dir.c | 1
> fs/afs/inode.c | 3
> fs/afs/internal.h | 1
> fs/afs/mntpt.c | 47 +--
> fs/autofs/dirhash.c | 5
> fs/autofs4/autofs_i.h | 100 ++++--
> fs/autofs4/dev-ioctl.c | 2
> fs/autofs4/expire.c | 42 ++
> fs/autofs4/inode.c | 28 --
> fs/autofs4/root.c | 668 ++++++++++++++++---------------------
> fs/autofs4/waitq.c | 17 +
> fs/cifs/cifs_dfs_ref.c | 134 ++++---
> fs/cifs/cifsfs.h | 6
> fs/cifs/dir.c | 2
> fs/cifs/inode.c | 8
> fs/dcache.c | 7
> fs/namei.c | 243 +++++++++++--
> fs/namespace.c | 20 +
> fs/nfs/dir.c | 4
> fs/nfs/inode.c | 4
> fs/nfs/internal.h | 1
> fs/nfs/namespace.c | 87 ++---
> fs/nfsd/vfs.c | 5
> fs/stat.c | 4
> include/linux/auto_fs4.h | 2
> include/linux/dcache.h | 19 +
> include/linux/fcntl.h | 1
> include/linux/fs.h | 2
> include/linux/namei.h | 5
> include/linux/nfs_fs.h | 1
> 32 files changed, 836 insertions(+), 657 deletions(-)
>
> _______________________________________________
> autofs mailing list
> autofs-CPWUtch7KCBzeIdxy0IIJw@public.gmane.org
> http://linux.kernel.org/mailman/listinfo/autofs
>
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH 00/17] Introduce automounter dentry ops
2010-10-01 7:57 ` [autofs] [PATCH 00/17] Introduce automounter dentry ops Stef Bon
@ 2010-10-01 11:49 ` Ian Kent
0 siblings, 0 replies; 28+ messages in thread
From: Ian Kent @ 2010-10-01 11:49 UTC (permalink / raw)
To: Stef Bon; +Cc: David Howells, autofs, linux-cifs
On Fri, 2010-10-01 at 09:57 +0200, Stef Bon wrote:
> On 09/30/2010 08:14 PM, David Howells wrote:
> > The attached patches introduce a couple of new dentry operations for use by
> > automounters and make AFS, NFS, CIFS and autofs4 use them. This means that
> > these filesystems no longer have to abuse lookup(), follow_link() and
> > d_revalidate() to achieve the desired effect.
>
> Improvments are always welcome as I look at it, but for my understanding,
> how do these new dentry operations cooperate with cifs?
>
> Cifs is the target filesystem, and handled by the automounter, thus the
> automounter is the initiator, not cifs.
>
> As you describe it (well it looks like it, I may not understand...) cifs
> is the initiator, and the patches to the automounter make autofs handle
> cifs requests handle better?
>
> What is now the case here?? I cannot understand.
> Any explanation is appreciated.
The point here is that David has implemented VFS support for
automounting which several file systems, including autofs, can use to
resolve problems with their current implementation. Probably the most
significant advantage for autofs is a long standing potential deadlock
can be removed which otherwise cannot be resolved. The motivation is to
allow file systems that need to perform some sort of automatic mounting
to not use existing kernel facilities in ways they are not meant to be
used.
>
> Stef Bon
> the Netherlands
>
> > There are two dentry operations provided:
> >
> > (1) struct vfsmount *(*d_automount)(struct path *path);
> >
> > This is used by follow_automount() in fs/namei.c to ask the filesystem
> > that owns the dentry at the current path point to mount something on
> > @path.
> >
> > It is called if either the inode belonging to the given dentry is flagged
> > S_AUTOMOUNT or the dentry is flagged DMANAGED_AUTOMOUNT, and if the dentry
> > has nothing mounted on it in the current namespace when someone attempts
> > to use that dentry.
> >
> > No locks will be held when this is called.
> >
> > d_op->d_automount() may return one of:
> >
> > (a) The vfsmount mounted upon that dentry, in which case pathwalk will
> > move to the root dentry of that vfsmount.
> >
> > (b) NULL if something was already mounted there, in which case pathwalk
> > will loop around and recheck the mountings.
> >
> > (c) -EISDIR, in which case pathwalk will stop at this point and attempt to
> > use that dentry as the object of interest. If the current dentry is
> > not terminal within the path, -EREMOTE will be returned.
> >
> > (d) An error value, to be returned immediately.
> >
> > Automount transits are counted as symlinks to prevent circular references
> > from being a problem. If one is detected, -ELOOP will be returned.
> >
> > If stat() is given AT_NO_AUTOMOUNT then d_op->d_automount() will not be
> > invoked on a terminal dentry; instead that dentry will be returned by
> > pathwalk.
> >
> > follow_automount() also does not invoke d_op->d_automount() if the caller
> > gave AT_SYMLINK_NOFOLLOW to stat(), but rather returns the base dentry.
> >
> >
> > (2) int (*d_manage)(struct path *path, bool mounting_here);
> >
> > This is called by managed_dentry() or follow_down() in fs/namei.c to
> > indicate to a filesystem that pathwalk is about to step off of the current
> > path point and walk to another point in the path.
> >
> > This is called if DMANAGED_TRANSIT is set on a dentry.
> >
> > This can then be used by autofs to stop non-daemon processes from walking
> > until it has finished constructing or expiring the tree behind the dentry.
> > It could also be used to prevent undesirables from mounting on this
> > dentry.
> >
> > @mounting_here is true if called from follow_down() from mount, in which
> > case namespace_sem is held exclusively by the caller of follow_down().
> > Otherwise, no locks are held.
> >
> > d_op->d_manage() may return one of:
> >
> > (a) 0 to continue the pathwalk as normal.
> >
> > (b) -EISDIR to prevent managed_dentry() from crossing to a mounted
> > filesystem or calling d_op->d_automount(), in which case the dentry
> > will be treated as an ordinary directory.
> >
> > (c) An error to abort the pathwalk completely.
> >
> >
> > To make this work for autofs, d_mounted in struct dentry has become d_managed.
> > This used to be a count of the number of mounts on this dentry. The bottom 28
> > bits are still that (DMANAGED_MOUNTPOINT). The upper four bits contain a
> > couple of flags, DMANAGED_TRANSIT and DMANAGED_AUTOMOUNT. This allows
> > managed_dentry() to test all three conditions with minimumal overhead if none
> > of them are true.
> >
> > For other filesystems, setting S_AUTOMOUNT is sufficient. This is noted by
> > __d_instantiate() which will set DMANAGED_AUTOMOUNT automatically if it is
> > seen. Checking S_AUTOMOUNT doesn't work for autofs, however, since the dentry
> > might not have an inode, hence why a dentry flag also.
> >
> > S_AUTOMOUNT and d_automount() are introduced in patch 1; d_manage(), d_managed
> > and DMANAGED_* are introduced in patch 7.
> >
> > David
> > ---
> >
> > David Howells (8):
> > Make follow_down() handle d_manage()
> > Make dentry::d_mounted into a more general field for special function dirs
> > Add an AT_NO_AUTOMOUNT flag to suppress terminal automount
> > Remove the automount through follow_link() kludge code from pathwalk
> > CIFS: Use d_automount() rather than abusing follow_link()
> > NFS: Use d_automount() rather than abusing follow_link()
> > AFS: Use d_automount() rather than abusing follow_link()
> > Add a dentry op to handle automounting rather than abusing follow_link()
> >
> > Ian Kent (9):
> > autofs4 - bump version
> > autofs4 - add v4 pseudo direct mount support
> > autofs4 - fix wait validation
> > autofs4: cleanup autofs4_free_ino()
> > autofs4: cleanup dentry operations
> > autofs4: cleanup inode operations
> > autofs4: removed unused code
> > autofs4: add d_manage() dentry operation
> > autofs4: add d_automount() dentry operation
> >
> >
> > Documentation/filesystems/Locking | 2
> > Documentation/filesystems/vfs.txt | 22 +
> > fs/afs/dir.c | 1
> > fs/afs/inode.c | 3
> > fs/afs/internal.h | 1
> > fs/afs/mntpt.c | 47 +--
> > fs/autofs/dirhash.c | 5
> > fs/autofs4/autofs_i.h | 100 ++++--
> > fs/autofs4/dev-ioctl.c | 2
> > fs/autofs4/expire.c | 42 ++
> > fs/autofs4/inode.c | 28 --
> > fs/autofs4/root.c | 668 ++++++++++++++++---------------------
> > fs/autofs4/waitq.c | 17 +
> > fs/cifs/cifs_dfs_ref.c | 134 ++++---
> > fs/cifs/cifsfs.h | 6
> > fs/cifs/dir.c | 2
> > fs/cifs/inode.c | 8
> > fs/dcache.c | 7
> > fs/namei.c | 243 +++++++++++--
> > fs/namespace.c | 20 +
> > fs/nfs/dir.c | 4
> > fs/nfs/inode.c | 4
> > fs/nfs/internal.h | 1
> > fs/nfs/namespace.c | 87 ++---
> > fs/nfsd/vfs.c | 5
> > fs/stat.c | 4
> > include/linux/auto_fs4.h | 2
> > include/linux/dcache.h | 19 +
> > include/linux/fcntl.h | 1
> > include/linux/fs.h | 2
> > include/linux/namei.h | 5
> > include/linux/nfs_fs.h | 1
> > 32 files changed, 836 insertions(+), 657 deletions(-)
> >
> > _______________________________________________
> > autofs mailing list
> > autofs@linux.kernel.org
> > http://linux.kernel.org/mailman/listinfo/autofs
> >
>
> _______________________________________________
> autofs mailing list
> autofs@linux.kernel.org
> http://linux.kernel.org/mailman/listinfo/autofs
^ permalink raw reply [flat|nested] 28+ messages in thread