提交 296f7bf7 编写于 作者: I Ian Kent 提交者: Linus Torvalds

autofs4: fix waitq memory leak

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: NIan Kent <raven@themaw.net>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 e64be33c
...@@ -84,7 +84,7 @@ struct autofs_wait_queue { ...@@ -84,7 +84,7 @@ struct autofs_wait_queue {
pid_t tgid; pid_t tgid;
/* This is for status reporting upon return */ /* This is for status reporting upon return */
int status; int status;
atomic_t wait_ctr; unsigned int wait_ctr;
}; };
#define AUTOFS_SBI_MAGIC 0x6d4a556d #define AUTOFS_SBI_MAGIC 0x6d4a556d
......
...@@ -46,6 +46,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) ...@@ -46,6 +46,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
kfree(wq->name.name); kfree(wq->name.name);
wq->name.name = NULL; wq->name.name = NULL;
} }
wq->wait_ctr--;
wake_up_interruptible(&wq->queue); wake_up_interruptible(&wq->queue);
wq = nwq; wq = nwq;
} }
...@@ -380,7 +381,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, ...@@ -380,7 +381,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
wq->pid = current->pid; wq->pid = current->pid;
wq->tgid = current->tgid; wq->tgid = current->tgid;
wq->status = -EINTR; /* Status return if interrupted */ wq->status = -EINTR; /* Status return if interrupted */
atomic_set(&wq->wait_ctr, 2); wq->wait_ctr = 2;
mutex_unlock(&sbi->wq_mutex); mutex_unlock(&sbi->wq_mutex);
if (sbi->version < 5) { if (sbi->version < 5) {
...@@ -406,7 +407,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, ...@@ -406,7 +407,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
/* autofs4_notify_daemon() may block */ /* autofs4_notify_daemon() may block */
autofs4_notify_daemon(sbi, wq, type); autofs4_notify_daemon(sbi, wq, type);
} else { } else {
atomic_inc(&wq->wait_ctr); wq->wait_ctr++;
mutex_unlock(&sbi->wq_mutex); mutex_unlock(&sbi->wq_mutex);
kfree(qstr.name); kfree(qstr.name);
DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
...@@ -442,8 +443,10 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, ...@@ -442,8 +443,10 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
status = wq->status; status = wq->status;
/* Are we the last process to need 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); kfree(wq);
mutex_unlock(&sbi->wq_mutex);
return status; return status;
} }
...@@ -467,14 +470,11 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok ...@@ -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 */ *wql = wq->next; /* Unlink from chain */
kfree(wq->name.name); kfree(wq->name.name);
wq->name.name = NULL; /* Do not wait on this queue */ wq->name.name = NULL; /* Do not wait on this queue */
mutex_unlock(&sbi->wq_mutex);
wq->status = status; wq->status = status;
if (atomic_dec_and_test(&wq->wait_ctr)) /* Is anyone still waiting for this guy? */
kfree(wq);
else
wake_up_interruptible(&wq->queue); wake_up_interruptible(&wq->queue);
if (!--wq->wait_ctr)
kfree(wq);
mutex_unlock(&sbi->wq_mutex);
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册