mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2025-04-06 17:49:11 +03:00
Fix taskq_wait_id()
The existing taskq_wait_id() function can incorrectly block indefinitely. Reimplement it more simply using wait_event() in a similar fashion to taskq_wait_all(). This flaw was uncovered in the context of moving vn_rdwr() to a taskq. Previously taskq_wait_id() had no consumers outside the SPLAT task framework which is why the issue went unnoticed. Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
parent
ab59be7bc7
commit
99c452bbba
@ -342,39 +342,27 @@ taskq_find(taskq_t *tq, taskqid_t id, int *active)
|
|||||||
SRETURN(NULL);
|
SRETURN(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
taskq_wait_id_check(taskq_t *tq, taskqid_t id)
|
||||||
|
{
|
||||||
|
int active = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
|
||||||
|
rc = (taskq_find(tq, id, &active) == NULL);
|
||||||
|
spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The taskq_wait_id() function blocks until the passed task id completes.
|
* The taskq_wait_id() function blocks until the passed task id completes.
|
||||||
* This does not guarantee that all lower task id's have completed.
|
* This does not guarantee that all lower task ids have completed.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
taskq_wait_id(taskq_t *tq, taskqid_t id)
|
taskq_wait_id(taskq_t *tq, taskqid_t id)
|
||||||
{
|
{
|
||||||
DEFINE_WAIT(wait);
|
wait_event(tq->tq_wait_waitq, taskq_wait_id_check(tq, id));
|
||||||
taskq_ent_t *t;
|
|
||||||
int active = 0;
|
|
||||||
SENTRY;
|
|
||||||
|
|
||||||
ASSERT(tq);
|
|
||||||
ASSERT(id > 0);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
|
|
||||||
t = taskq_find(tq, id, &active);
|
|
||||||
if (t)
|
|
||||||
prepare_to_wait(&t->tqent_waitq, &wait, TASK_UNINTERRUPTIBLE);
|
|
||||||
spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We rely on the kernels autoremove_wake_function() function to
|
|
||||||
* remove us from the wait queue in the context of wake_up().
|
|
||||||
* Once woken the taskq_ent_t pointer must never be accessed.
|
|
||||||
*/
|
|
||||||
if (t) {
|
|
||||||
t = NULL;
|
|
||||||
schedule();
|
|
||||||
__set_current_state(TASK_RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
SEXIT;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(taskq_wait_id);
|
EXPORT_SYMBOL(taskq_wait_id);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user