*
* ------------------------------------------------------------------------- */
+#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/param.h>
/* Update usage from here to top of tree, so that scan of
top-level directories will give a useful result */
-static void autofs4_update_usage(struct dentry *dentry)
+static void autofs4_update_usage(struct vfsmount *mnt, struct dentry *dentry)
{
struct dentry *top = dentry->d_sb->s_root;
struct autofs_info *ino = autofs4_dentry_ino(dentry);
if (ino) {
- update_atime(dentry->d_inode);
+ touch_atime(mnt, dentry);
ino->last_used = jiffies;
}
}
}
while(1) {
- struct dentry *de = list_entry(list, struct dentry, d_child);
+ struct dentry *de = list_entry(list,
+ struct dentry, d_u.d_child);
if (!d_unhashed(de) && de->d_inode) {
spin_unlock(&dcache_lock);
if (!empty)
d_invalidate(dentry);
+ nd.dentry = dentry;
+ nd.mnt = mnt;
nd.flags = LOOKUP_DIRECTORY;
status = (dentry->d_op->d_revalidate)(dentry, &nd);
struct vfsmount *fp_mnt = mntget(mnt);
struct dentry *fp_dentry = dget(dentry);
- while (follow_down(&fp_mnt, &fp_dentry) && d_mountpoint(fp_dentry));
+ if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
+ dput(fp_dentry);
+ mntput(fp_mnt);
+ return -ENOENT;
+ }
fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
status = PTR_ERR(fp);
return autofs4_dcache_readdir(file, dirent, filldir);
}
-static int try_to_fill_dentry(struct dentry *dentry,
- struct super_block *sb,
- struct autofs_sb_info *sbi, int flags)
+static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int flags)
{
- struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+ struct super_block *sb = mnt->mnt_sb;
+ struct autofs_sb_info *sbi = autofs4_sbi(sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status = 0;
/* Block on any pending expiry here; invalidate the dentry
when expiration is done to trigger mount request with a new
dentry */
- if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
+ if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
DPRINTK("waiting for expire %p name=%.*s",
dentry, dentry->d_name.len, dentry->d_name.name);
status = autofs4_wait(sbi, dentry, NFY_NONE);
-
+
DPRINTK("expire done status=%d", status);
-
- return 0;
+
+ /*
+ * If the directory still exists the mount request must
+ * continue otherwise it can't be followed at the right
+ * time during the walk.
+ */
+ status = d_invalidate(dentry);
+ if (status != -EBUSY)
+ return 0;
}
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 */
+ /*
+ * 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);
if (status && dentry->d_inode)
return 0; /* Try to get the kernel to invalidate this dentry */
-
+
/* Turn this into a real negative dentry? */
if (status == -ENOENT) {
dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
}
}
- /* We don't update the usages for the autofs daemon itself, this
- is necessary for recursive autofs mounts */
+ /*
+ * We don't update the usages for the autofs daemon itself, this
+ * is necessary for recursive autofs mounts
+ */
if (!autofs4_oz_mode(sbi))
- autofs4_update_usage(dentry);
+ autofs4_update_usage(mnt, dentry);
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
* yet completely filled in, and revalidate has to delay such
* lookups..
*/
-static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd)
+static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
{
- struct inode * dir = dentry->d_parent->d_inode;
+ 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;
/* Pending dentry */
if (autofs4_ispending(dentry)) {
if (!oz_mode)
- status = try_to_fill_dentry(dentry, dir->i_sb, sbi, flags);
+ status = try_to_fill_dentry(nd->mnt, dentry, flags);
return status;
}
dentry, dentry->d_name.len, dentry->d_name.name);
spin_unlock(&dcache_lock);
if (!oz_mode)
- status = try_to_fill_dentry(dentry, dir->i_sb, sbi, flags);
+ status = try_to_fill_dentry(nd->mnt, dentry, flags);
return status;
}
spin_unlock(&dcache_lock);
/* Update the usage list */
if (!oz_mode)
- autofs4_update_usage(dentry);
+ autofs4_update_usage(nd->mnt, dentry);
return 1;
}
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);/* File name too long to exist */
+ 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, process_group(current), sbi->catatonic, oz_mode);
d_add(dentry, NULL);
if (dentry->d_op && dentry->d_op->d_revalidate) {
- up(&dir->i_sem);
+ mutex_unlock(&dir->i_mutex);
(dentry->d_op->d_revalidate)(dentry, nd);
- down(&dir->i_sem);
+ mutex_lock(&dir->i_mutex);
}
/*
* doesn't do the right thing for all system calls, but it should
* be OK for the operations we permit from an autofs.
*/
- if ( dentry->d_inode && d_unhashed(dentry) )
+ if (dentry->d_inode && d_unhashed(dentry))
return ERR_PTR(-ENOENT);
return NULL;