|
@@ -36,9 +36,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,
|
|
@@ -114,14 +111,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;
|
|
@@ -156,238 +145,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(&autofs4_lock);
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
- if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) {
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
- spin_unlock(&autofs4_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(&dentry->d_lock);
|
|
|
- spin_unlock(&autofs4_lock);
|
|
|
- spin_unlock(&sbi->fs_lock);
|
|
|
-
|
|
|
- status = try_to_fill_dentry(dentry, nd->flags);
|
|
|
- if (status)
|
|
|
- goto out_error;
|
|
|
-
|
|
|
- goto follow;
|
|
|
- }
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
- spin_unlock(&autofs4_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;
|
|
|
- struct autofs_sb_info *sbi;
|
|
|
- int oz_mode;
|
|
|
- int flags = nd ? nd->flags : 0;
|
|
|
- int status = 1;
|
|
|
-
|
|
|
- if (flags & LOOKUP_RCU)
|
|
|
- return -ECHILD;
|
|
|
-
|
|
|
- dir = dentry->d_parent->d_inode;
|
|
|
- sbi = autofs4_sbi(dir->i_sb);
|
|
|
- oz_mode = autofs4_oz_mode(sbi);
|
|
|
-
|
|
|
- /* 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(&autofs4_lock);
|
|
|
- spin_lock(&dentry->d_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(&dentry->d_lock);
|
|
|
- spin_unlock(&autofs4_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(&dentry->d_lock);
|
|
|
- spin_unlock(&autofs4_lock);
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
void autofs4_dentry_release(struct dentry *de)
|
|
|
{
|
|
|
struct autofs_info *inf;
|