]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/autofs4/waitq.c
autofs4: track uid and gid of last mount requester
[linux-2.6-omap-h63xx.git] / fs / autofs4 / waitq.c
index dd2914d7ad7f858f73fd44cf34d2d32354c38556..4b67c2a2d77c51fcc93193dbdd6e31dea2defc14 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;
        }
@@ -327,12 +328,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 (sbi->type & AUTOFS_TYPE_TRIGGER)
+                       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) && sbi->type & AUTOFS_TYPE_TRIGGER)
                qstr.len = sprintf(name, "%p", dentry);
        else {
                qstr.len = autofs4_getpath(sbi, dentry, &name);
@@ -380,7 +396,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                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 +406,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 = (sbi->type & AUTOFS_TYPE_TRIGGER) ?
                                        autofs_ptype_missing_direct :
                                         autofs_ptype_missing_indirect;
                        else
-                               type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+                               type = (sbi->type & AUTOFS_TYPE_TRIGGER) ?
                                        autofs_ptype_expire_direct :
                                        autofs_ptype_expire_indirect;
                }
@@ -406,7 +422,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 +457,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 +519,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;
 }