]> Pileus Git - ~andy/linux/blobdiff - fs/autofs4/root.c
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
[~andy/linux] / fs / autofs4 / root.c
index 47adf270106a656ea98b54cf6875a66cfae70ab5..2d4c8a3e604e776a8a5fe680d5e974c729770dd0 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/stat.h>
 #include <linux/param.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include "autofs_i.h"
 
 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
@@ -470,9 +469,6 @@ void autofs4_dentry_release(struct dentry *de)
        if (inf) {
                struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb);
 
-               inf->dentry = NULL;
-               inf->inode = NULL;
-
                if (sbi) {
                        spin_lock(&sbi->rehash_lock);
                        if (!list_empty(&inf->rehash))
@@ -480,6 +476,9 @@ void autofs4_dentry_release(struct dentry *de)
                        spin_unlock(&sbi->rehash_lock);
                }
 
+               inf->dentry = NULL;
+               inf->inode = NULL;
+
                autofs4_free_ino(inf);
        }
 }
@@ -655,14 +654,29 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
 
        /*
         * If this dentry is unhashed, then we shouldn't honour this
-        * lookup even if the dentry is positive.  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.
+        * 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 (dentry->d_inode && 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 (unhashed)
                        dput(unhashed);
-               return ERR_PTR(-ENOENT);
+
+               return dentry;
        }
 
        if (unhashed)
@@ -745,7 +759,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
        struct autofs_info *p_ino;
        
        /* This allows root to remove symlinks */
-       if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EACCES;
 
        if (atomic_dec_and_test(&ino->count)) {
@@ -819,7 +833,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct autofs_info *p_ino;
        struct inode *inode;
 
-       if ( !autofs4_oz_mode(sbi) )
+       if (!autofs4_oz_mode(sbi))
                return -EACCES;
 
        DPRINTK("dentry %p, creating %.*s",
@@ -857,11 +871,11 @@ static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,
        int rv;
        unsigned long ntimeout;
 
-       if ( (rv = get_user(ntimeout, p)) ||
-            (rv = put_user(sbi->exp_timeout/HZ, p)) )
+       if ((rv = get_user(ntimeout, p)) ||
+            (rv = put_user(sbi->exp_timeout/HZ, p)))
                return rv;
 
-       if ( ntimeout > ULONG_MAX/HZ )
+       if (ntimeout > ULONG_MAX/HZ)
                sbi->exp_timeout = 0;
        else
                sbi->exp_timeout = ntimeout * HZ;
@@ -892,7 +906,7 @@ static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p)
        DPRINTK("returning %d", sbi->needs_reghost);
 
        status = put_user(sbi->needs_reghost, p);
-       if ( status )
+       if (status)
                return status;
 
        sbi->needs_reghost = 0;
@@ -961,11 +975,11 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
        DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u",
                cmd,arg,sbi,process_group(current));
 
-       if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
-            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+       if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
                return -ENOTTY;
        
-       if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
        
        switch(cmd) {