new helper: iterate_supers()
[safe/jmp/linux-2.6] / fs / autofs4 / waitq.c
index dd2914d..2341375 100644 (file)
@@ -46,6 +46,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
                        kfree(wq->name.name);
                        wq->name.name = NULL;
                }
+               wq->wait_ctr--;
                wake_up_interruptible(&wq->queue);
                wq = nwq;
        }
@@ -296,20 +297,14 @@ static int validate_request(struct autofs_wait_queue **wait,
         */
        if (notify == NFY_MOUNT) {
                /*
-                * If the dentry isn't hashed just go ahead and try the
-                * mount again with a new wait (not much else we can do).
-               */
-               if (!d_unhashed(dentry)) {
-                       /*
-                        * But if the dentry is hashed, that means that we
-                        * got here through the revalidate path.  Thus, we
-                        * need to check if the dentry has been mounted
-                        * while we waited on the wq_mutex. If it has,
-                        * simply return success.
-                        */
-                       if (d_mountpoint(dentry))
-                               return 0;
-               }
+                * If the dentry was successfully mounted while we slept
+                * on the wait queue mutex we can return success. If it
+                * isn't mounted (doesn't have submounts for the case of
+                * a multi-mount with no mount at it's base) we can
+                * continue on and create a new request.
+                */
+               if (have_submounts(dentry))
+                       return 0;
        }
 
        return 1;
@@ -327,12 +322,27 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
        if (sbi->catatonic)
                return -ENOENT;
 
+       if (!dentry->d_inode) {
+               /*
+                * A wait for a negative dentry is invalid for certain
+                * cases. A direct or offset mount "always" has its mount
+                * point directory created and so the request dentry must
+                * be positive or the map key doesn't exist. The situation
+                * is very similar for indirect mounts except only dentrys
+                * in the root of the autofs file system may be negative.
+                */
+               if (autofs_type_trigger(sbi->type))
+                       return -ENOENT;
+               else if (!IS_ROOT(dentry->d_parent))
+                       return -ENOENT;
+       }
+
        name = kmalloc(NAME_MAX + 1, GFP_KERNEL);
        if (!name)
                return -ENOMEM;
 
        /* If this is a direct mount request create a dummy name */
-       if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT))
+       if (IS_ROOT(dentry) && autofs_type_trigger(sbi->type))
                qstr.len = sprintf(name, "%p", dentry);
        else {
                qstr.len = autofs4_getpath(sbi, dentry, &name);
@@ -375,12 +385,12 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                memcpy(&wq->name, &qstr, sizeof(struct qstr));
                wq->dev = autofs4_get_dev(sbi);
                wq->ino = autofs4_get_ino(sbi);
-               wq->uid = current->uid;
-               wq->gid = current->gid;
+               wq->uid = current_uid();
+               wq->gid = current_gid();
                wq->pid = current->pid;
                wq->tgid = current->tgid;
                wq->status = -EINTR; /* Status return if interrupted */
-               atomic_set(&wq->wait_ctr, 2);
+               wq->wait_ctr = 2;
                mutex_unlock(&sbi->wq_mutex);
 
                if (sbi->version < 5) {
@@ -390,11 +400,11 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                                type = autofs_ptype_expire_multi;
                } else {
                        if (notify == NFY_MOUNT)
-                               type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+                               type = autofs_type_trigger(sbi->type) ?
                                        autofs_ptype_missing_direct :
                                         autofs_ptype_missing_indirect;
                        else
-                               type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+                               type = autofs_type_trigger(sbi->type) ?
                                        autofs_ptype_expire_direct :
                                        autofs_ptype_expire_indirect;
                }
@@ -406,7 +416,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                /* autofs4_notify_daemon() may block */
                autofs4_notify_daemon(sbi, wq, type);
        } else {
-               atomic_inc(&wq->wait_ctr);
+               wq->wait_ctr++;
                mutex_unlock(&sbi->wq_mutex);
                kfree(qstr.name);
                DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
@@ -441,9 +451,45 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
 
        status = wq->status;
 
+       /*
+        * For direct and offset mounts we need to track the requester's
+        * uid and gid in the dentry info struct. This is so it can be
+        * supplied, on request, by the misc device ioctl interface.
+        * This is needed during daemon resatart when reconnecting
+        * to existing, active, autofs mounts. The uid and gid (and
+        * related string values) may be used for macro substitution
+        * in autofs mount maps.
+        */
+       if (!status) {
+               struct autofs_info *ino;
+               struct dentry *de = NULL;
+
+               /* direct mount or browsable map */
+               ino = autofs4_dentry_ino(dentry);
+               if (!ino) {
+                       /* If not lookup actual dentry used */
+                       de = d_lookup(dentry->d_parent, &dentry->d_name);
+                       if (de)
+                               ino = autofs4_dentry_ino(de);
+               }
+
+               /* Set mount requester */
+               if (ino) {
+                       spin_lock(&sbi->fs_lock);
+                       ino->uid = wq->uid;
+                       ino->gid = wq->gid;
+                       spin_unlock(&sbi->fs_lock);
+               }
+
+               if (de)
+                       dput(de);
+       }
+
        /* Are we the last process to need status? */
-       if (atomic_dec_and_test(&wq->wait_ctr))
+       mutex_lock(&sbi->wq_mutex);
+       if (!--wq->wait_ctr)
                kfree(wq);
+       mutex_unlock(&sbi->wq_mutex);
 
        return status;
 }
@@ -467,14 +513,11 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok
        *wql = wq->next;        /* Unlink from chain */
        kfree(wq->name.name);
        wq->name.name = NULL;   /* Do not wait on this queue */
-       mutex_unlock(&sbi->wq_mutex);
-
        wq->status = status;
-
-       if (atomic_dec_and_test(&wq->wait_ctr)) /* Is anyone still waiting for this guy? */
+       wake_up_interruptible(&wq->queue);
+       if (!--wq->wait_ctr)
                kfree(wq);
-       else
-               wake_up_interruptible(&wq->queue);
+       mutex_unlock(&sbi->wq_mutex);
 
        return 0;
 }