]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/autofs4/waitq.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / fs / autofs4 / waitq.c
index 2341375386f891e9361ce191e54f9fd3867d1466..56010056b2e6d9001280597b73146ccb839d1b87 100644 (file)
@@ -186,16 +186,26 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
 {
        struct dentry *root = sbi->sb->s_root;
        struct dentry *tmp;
-       char *buf = *name;
+       char *buf;
        char *p;
-       int len = 0;
+       int len;
+       unsigned seq;
 
-       spin_lock(&dcache_lock);
+rename_retry:
+       buf = *name;
+       len = 0;
+
+       seq = read_seqbegin(&rename_lock);
+       rcu_read_lock();
+       spin_lock(&autofs4_lock);
        for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
                len += tmp->d_name.len + 1;
 
        if (!len || --len > NAME_MAX) {
-               spin_unlock(&dcache_lock);
+               spin_unlock(&autofs4_lock);
+               rcu_read_unlock();
+               if (read_seqretry(&rename_lock, seq))
+                       goto rename_retry;
                return 0;
        }
 
@@ -208,7 +218,10 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
                p -= tmp->d_name.len;
                strncpy(p, tmp->d_name.name, tmp->d_name.len);
        }
-       spin_unlock(&dcache_lock);
+       spin_unlock(&autofs4_lock);
+       rcu_read_unlock();
+       if (read_seqretry(&rename_lock, seq))
+               goto rename_retry;
 
        return len;
 }
@@ -296,6 +309,9 @@ static int validate_request(struct autofs_wait_queue **wait,
         * completed while we waited on the mutex ...
         */
        if (notify == NFY_MOUNT) {
+               struct dentry *new = NULL;
+               int valid = 1;
+
                /*
                 * If the dentry was successfully mounted while we slept
                 * on the wait queue mutex we can return success. If it
@@ -303,8 +319,20 @@ static int validate_request(struct autofs_wait_queue **wait,
                 * a multi-mount with no mount at it's base) we can
                 * continue on and create a new request.
                 */
+               if (!IS_ROOT(dentry)) {
+                       if (dentry->d_inode && d_unhashed(dentry)) {
+                               struct dentry *parent = dentry->d_parent;
+                               new = d_lookup(parent, &dentry->d_name);
+                               if (new)
+                                       dentry = new;
+                       }
+               }
                if (have_submounts(dentry))
-                       return 0;
+                       valid = 0;
+
+               if (new)
+                       dput(new);
+               return valid;
        }
 
        return 1;