autofs4: autofs4_wait() vs. autofs4_catatonic_mode() race
Al Viro [Wed, 11 Jan 2012 03:20:12 +0000 (22:20 -0500)]
We need to recheck ->catatonic after autofs4_wait() got ->wq_mutex
for good, or we might end up with wq inserted into queue after
autofs4_catatonic_mode() had done its thing.  It will stick there
forever, since there won't be anything to clear its ->name.name.

A bit of a complication: validate_request() drops and regains ->wq_mutex.
It actually ends up the most convenient place to stick the check into...

Acked-by: Ian Kent <raven@themaw.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

fs/autofs4/waitq.c

index e1fbdee..c13273a 100644 (file)
@@ -257,6 +257,9 @@ static int validate_request(struct autofs_wait_queue **wait,
        struct autofs_wait_queue *wq;
        struct autofs_info *ino;
 
+       if (sbi->catatonic)
+               return -ENOENT;
+
        /* Wait in progress, continue; */
        wq = autofs4_find_wait(sbi, qstr);
        if (wq) {
@@ -289,6 +292,9 @@ static int validate_request(struct autofs_wait_queue **wait,
                        if (mutex_lock_interruptible(&sbi->wq_mutex))
                                return -EINTR;
 
+                       if (sbi->catatonic)
+                               return -ENOENT;
+
                        wq = autofs4_find_wait(sbi, qstr);
                        if (wq) {
                                *wait = wq;
@@ -389,7 +395,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
 
        ret = validate_request(&wq, sbi, &qstr, dentry, notify);
        if (ret <= 0) {
-               if (ret == 0)
+               if (ret != -EINTR)
                        mutex_unlock(&sbi->wq_mutex);
                kfree(qstr.name);
                return ret;