diff options
author | Prakash Surya <[email protected]> | 2011-12-16 14:57:31 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2011-12-16 16:54:00 -0800 |
commit | 8f2503e0af490ea253d6db1a15b4901437171cc1 (patch) | |
tree | 5aa2d69dd5838d2495d698595b9ff11a2e8f5335 /include/sys | |
parent | e7e5f78e7bf6dc86337483f4d9f01becc017d185 (diff) |
Store copy of tqent_flags prior to servicing task
A preallocated taskq_ent_t's tqent_flags must be checked prior to
servicing the taskq_ent_t. Once a preallocated taskq entry is serviced,
the ownership of the entry is handed back to the caller of
taskq_dispatch, thus the entry's contents can potentially be mangled.
In particular, this is a problem in the case where a preallocated taskq
entry is serviced, and the caller clears it's tqent_flags field. Thus,
when the function returns and task_done is called, it looks as though
the entry is **not** a preallocated task (when in fact it **is** a
preallocated task).
In this situation, task_done will place the preallocated taskq_ent_t
structure onto the taskq_t's free list. This is a **huge** mistake. If
the taskq_ent_t is then freed by the caller of taskq_dispatch, the
taskq_t's free list will hold a pointer to garbage data. Even worse, if
nothing has over written the freed memory before the pointer is
dereferenced, it may still look as though it points to a valid list_head
belonging to a taskq_ent_t structure.
Thus, the task entry's flags are now copied prior to servicing the task.
This copy is then checked to see if it is a preallocated task, and
determine if the entry needs to be passed down to the task_done
function.
Signed-off-by: Prakash Surya <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #71
Diffstat (limited to 'include/sys')
-rw-r--r-- | include/sys/taskq.h | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/include/sys/taskq.h b/include/sys/taskq.h index 0a7143375..fec4de8ca 100644 --- a/include/sys/taskq.h +++ b/include/sys/taskq.h @@ -97,6 +97,7 @@ typedef struct taskq_thread { struct task_struct *tqt_thread; taskq_t *tqt_tq; taskqid_t tqt_id; + uintptr_t tqt_flags; } taskq_thread_t; /* Global system-wide dynamic task queue available for all consumers */ |