Skip to content

Commit

Permalink
autofs4: fix waitq memory leak
Browse files Browse the repository at this point in the history
If an autofs mount becomes catatonic before autofs4_wait_release() is
called the wait queue counter will not be decremented down to zero and the
entry will never be freed.  There are also races decrementing the wait
counter in the wait release function.  To deal with this the counter needs
to be updated while holding the wait queue mutex and waiters need to be
woken up unconditionally when the wait is removed from the queue to ensure
we eventually free the wait.

Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Ian Kent authored and Linus Torvalds committed Jul 24, 2008
1 parent e64be33 commit 296f7bf
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 10 deletions.
2 changes: 1 addition & 1 deletion fs/autofs4/autofs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct autofs_wait_queue {
pid_t tgid;
/* This is for status reporting upon return */
int status;
atomic_t wait_ctr;
unsigned int wait_ctr;
};

#define AUTOFS_SBI_MAGIC 0x6d4a556d
Expand Down
18 changes: 9 additions & 9 deletions fs/autofs4/waitq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -380,7 +381,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) {
Expand All @@ -406,7 +407,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",
Expand Down Expand Up @@ -442,8 +443,10 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
status = wq->status;

/* 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;
}
Expand All @@ -467,14 +470,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;
}
Expand Down

0 comments on commit 296f7bf

Please sign in to comment.