linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / autofs4 / root.c
index 1ff9adb..62d8d4a 100644 (file)
@@ -12,6 +12,7 @@
  *
  * ------------------------------------------------------------------------- */
 
+#include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/param.h>
@@ -19,7 +20,6 @@
 #include <linux/smp_lock.h>
 #include "autofs_i.h"
 
-static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *, struct nameidata *);
 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
 static int autofs4_dir_unlink(struct inode *,struct dentry *);
 static int autofs4_dir_rmdir(struct inode *,struct dentry *);
@@ -29,7 +29,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file);
 static int autofs4_dir_close(struct inode *inode, struct file *file);
 static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir);
-static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *, struct nameidata *);
+static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
 static int autofs4_dcache_readdir(struct file *, void *, filldir_t);
 
 struct file_operations autofs4_root_operations = {
@@ -48,7 +48,7 @@ struct file_operations autofs4_dir_operations = {
 };
 
 struct inode_operations autofs4_root_inode_operations = {
-       .lookup         = autofs4_root_lookup,
+       .lookup         = autofs4_lookup,
        .unlink         = autofs4_dir_unlink,
        .symlink        = autofs4_dir_symlink,
        .mkdir          = autofs4_dir_mkdir,
@@ -56,7 +56,7 @@ struct inode_operations autofs4_root_inode_operations = {
 };
 
 struct inode_operations autofs4_dir_inode_operations = {
-       .lookup         = autofs4_dir_lookup,
+       .lookup         = autofs4_lookup,
        .unlink         = autofs4_dir_unlink,
        .symlink        = autofs4_dir_symlink,
        .mkdir          = autofs4_dir_mkdir,
@@ -87,7 +87,7 @@ static int autofs4_root_readdir(struct file *file, void *dirent,
 
 /* 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;
 
@@ -96,7 +96,7 @@ static void autofs4_update_usage(struct dentry *dentry)
                struct autofs_info *ino = autofs4_dentry_ino(dentry);
 
                if (ino) {
-                       update_atime(dentry->d_inode);
+                       touch_atime(mnt, dentry);
                        ino->last_used = jiffies;
                }
        }
@@ -144,7 +144,8 @@ static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t f
                        }
 
                        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);
@@ -194,6 +195,8 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
                if (!empty)
                        d_invalidate(dentry);
 
+               nd.dentry = dentry;
+               nd.mnt = mnt;
                nd.flags = LOOKUP_DIRECTORY;
                status = (dentry->d_op->d_revalidate)(dentry, &nd);
 
@@ -206,7 +209,11 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
                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);
@@ -285,10 +292,10 @@ out:
        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 super_block *sb = mnt->mnt_sb;
+       struct autofs_sb_info *sbi = autofs4_sbi(sb);
        struct autofs_info *de_info = autofs4_dentry_ino(dentry);
        int status = 0;
 
@@ -303,7 +310,14 @@ static int try_to_fill_dentry(struct dentry *dentry,
                
                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",
@@ -356,7 +370,7 @@ static int try_to_fill_dentry(struct dentry *dentry,
        /* 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;
@@ -381,7 +395,7 @@ static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd)
        /* 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;
        }
 
@@ -398,14 +412,14 @@ static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd)
                         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;
 }
@@ -439,23 +453,8 @@ static struct dentry_operations autofs4_dentry_operations = {
        .d_release      = autofs4_dentry_release,
 };
 
-/* Lookups in non-root dirs never find anything - if it's there, it's
-   already in the dcache */
-static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
-{
-#if 0
-       DPRINTK("ignoring lookup of %.*s/%.*s",
-                dentry->d_parent->d_name.len, dentry->d_parent->d_name.name,
-                dentry->d_name.len, dentry->d_name.name);
-#endif
-
-       dentry->d_fsdata = NULL;
-       d_add(dentry, NULL);
-       return NULL;
-}
-
 /* Lookups in the root directory */
-static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
        struct autofs_sb_info *sbi;
        int oz_mode;
@@ -493,9 +492,9 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent
        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);
        }
 
        /*
@@ -621,7 +620,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
                spin_unlock(&dcache_lock);
                return -ENOTEMPTY;
        }
+       spin_lock(&dentry->d_lock);
        __d_drop(dentry);
+       spin_unlock(&dentry->d_lock);
        spin_unlock(&dcache_lock);
 
        dput(ino->dentry);