734 taskq_dispatch_prealloc() desired
943 zio_interrupt ends up calling taskq_dispatch with TQ_SLEEP illumos/illumos-gate@5aeb94743e Essentially FreeBSD taskqueues already operate in a mode that was added to Illumos with taskq_dispatch_ent change. We even exposed the superior FreeBSD interface as taskq_dispatch_safe. Now we just rename taskq_dispatch_safe to taskq_dispatch_ent and struct struct ostask to taskq_ent_t, so that code differences will be minimal. After this change sys/cddl/compat/opensolaris/sys/taskq.h header is no longer needed. Note that this commit is not an MFV because the upstream change was not individually committed to the vendor area. MFC after: 8 days
This commit is contained in:
parent
cfab30ba16
commit
34140e78ab
@ -23,6 +23,9 @@
|
|||||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef _SYS_ZFS_CONTEXT_H
|
#ifndef _SYS_ZFS_CONTEXT_H
|
||||||
#define _SYS_ZFS_CONTEXT_H
|
#define _SYS_ZFS_CONTEXT_H
|
||||||
@ -367,6 +370,16 @@ typedef struct taskq taskq_t;
|
|||||||
typedef uintptr_t taskqid_t;
|
typedef uintptr_t taskqid_t;
|
||||||
typedef void (task_func_t)(void *);
|
typedef void (task_func_t)(void *);
|
||||||
|
|
||||||
|
typedef struct taskq_ent {
|
||||||
|
struct taskq_ent *tqent_next;
|
||||||
|
struct taskq_ent *tqent_prev;
|
||||||
|
task_func_t *tqent_func;
|
||||||
|
void *tqent_arg;
|
||||||
|
uintptr_t tqent_flags;
|
||||||
|
} taskq_ent_t;
|
||||||
|
|
||||||
|
#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */
|
||||||
|
|
||||||
#define TASKQ_PREPOPULATE 0x0001
|
#define TASKQ_PREPOPULATE 0x0001
|
||||||
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
|
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
|
||||||
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
|
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
|
||||||
@ -378,6 +391,7 @@ typedef void (task_func_t)(void *);
|
|||||||
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
|
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
|
||||||
#define TQ_FRONT 0x08 /* Queue in front */
|
#define TQ_FRONT 0x08 /* Queue in front */
|
||||||
|
|
||||||
|
|
||||||
extern taskq_t *system_taskq;
|
extern taskq_t *system_taskq;
|
||||||
|
|
||||||
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
|
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
|
||||||
@ -386,6 +400,8 @@ extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
|
|||||||
#define taskq_create_sysdc(a, b, d, e, p, dc, f) \
|
#define taskq_create_sysdc(a, b, d, e, p, dc, f) \
|
||||||
(taskq_create(a, b, maxclsyspri, d, e, f))
|
(taskq_create(a, b, maxclsyspri, d, e, f))
|
||||||
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
||||||
|
extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
|
||||||
|
taskq_ent_t *);
|
||||||
extern void taskq_destroy(taskq_t *);
|
extern void taskq_destroy(taskq_t *);
|
||||||
extern void taskq_wait(taskq_t *);
|
extern void taskq_wait(taskq_t *);
|
||||||
extern int taskq_member(taskq_t *, void *);
|
extern int taskq_member(taskq_t *, void *);
|
||||||
|
@ -22,19 +22,15 @@
|
|||||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||||
* Use is subject to license terms.
|
* Use is subject to license terms.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <sys/zfs_context.h>
|
#include <sys/zfs_context.h>
|
||||||
|
|
||||||
int taskq_now;
|
int taskq_now;
|
||||||
taskq_t *system_taskq;
|
taskq_t *system_taskq;
|
||||||
|
|
||||||
typedef struct task {
|
|
||||||
struct task *task_next;
|
|
||||||
struct task *task_prev;
|
|
||||||
task_func_t *task_func;
|
|
||||||
void *task_arg;
|
|
||||||
} task_t;
|
|
||||||
|
|
||||||
#define TASKQ_ACTIVE 0x00010000
|
#define TASKQ_ACTIVE 0x00010000
|
||||||
|
|
||||||
struct taskq {
|
struct taskq {
|
||||||
@ -51,18 +47,18 @@ struct taskq {
|
|||||||
int tq_maxalloc;
|
int tq_maxalloc;
|
||||||
kcondvar_t tq_maxalloc_cv;
|
kcondvar_t tq_maxalloc_cv;
|
||||||
int tq_maxalloc_wait;
|
int tq_maxalloc_wait;
|
||||||
task_t *tq_freelist;
|
taskq_ent_t *tq_freelist;
|
||||||
task_t tq_task;
|
taskq_ent_t tq_task;
|
||||||
};
|
};
|
||||||
|
|
||||||
static task_t *
|
static taskq_ent_t *
|
||||||
task_alloc(taskq_t *tq, int tqflags)
|
task_alloc(taskq_t *tq, int tqflags)
|
||||||
{
|
{
|
||||||
task_t *t;
|
taskq_ent_t *t;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
||||||
tq->tq_freelist = t->task_next;
|
tq->tq_freelist = t->tqent_next;
|
||||||
} else {
|
} else {
|
||||||
if (tq->tq_nalloc >= tq->tq_maxalloc) {
|
if (tq->tq_nalloc >= tq->tq_maxalloc) {
|
||||||
if (!(tqflags & KM_SLEEP))
|
if (!(tqflags & KM_SLEEP))
|
||||||
@ -87,7 +83,7 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
|||||||
}
|
}
|
||||||
mutex_exit(&tq->tq_lock);
|
mutex_exit(&tq->tq_lock);
|
||||||
|
|
||||||
t = kmem_alloc(sizeof (task_t), tqflags & KM_SLEEP);
|
t = kmem_alloc(sizeof (taskq_ent_t), tqflags & KM_SLEEP);
|
||||||
|
|
||||||
mutex_enter(&tq->tq_lock);
|
mutex_enter(&tq->tq_lock);
|
||||||
if (t != NULL)
|
if (t != NULL)
|
||||||
@ -97,15 +93,15 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
task_free(taskq_t *tq, task_t *t)
|
task_free(taskq_t *tq, taskq_ent_t *t)
|
||||||
{
|
{
|
||||||
if (tq->tq_nalloc <= tq->tq_minalloc) {
|
if (tq->tq_nalloc <= tq->tq_minalloc) {
|
||||||
t->task_next = tq->tq_freelist;
|
t->tqent_next = tq->tq_freelist;
|
||||||
tq->tq_freelist = t;
|
tq->tq_freelist = t;
|
||||||
} else {
|
} else {
|
||||||
tq->tq_nalloc--;
|
tq->tq_nalloc--;
|
||||||
mutex_exit(&tq->tq_lock);
|
mutex_exit(&tq->tq_lock);
|
||||||
kmem_free(t, sizeof (task_t));
|
kmem_free(t, sizeof (taskq_ent_t));
|
||||||
mutex_enter(&tq->tq_lock);
|
mutex_enter(&tq->tq_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +112,7 @@ task_free(taskq_t *tq, task_t *t)
|
|||||||
taskqid_t
|
taskqid_t
|
||||||
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
|
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
|
||||||
{
|
{
|
||||||
task_t *t;
|
taskq_ent_t *t;
|
||||||
|
|
||||||
if (taskq_now) {
|
if (taskq_now) {
|
||||||
func(arg);
|
func(arg);
|
||||||
@ -130,26 +126,58 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (tqflags & TQ_FRONT) {
|
if (tqflags & TQ_FRONT) {
|
||||||
t->task_next = tq->tq_task.task_next;
|
t->tqent_next = tq->tq_task.tqent_next;
|
||||||
t->task_prev = &tq->tq_task;
|
t->tqent_prev = &tq->tq_task;
|
||||||
} else {
|
} else {
|
||||||
t->task_next = &tq->tq_task;
|
t->tqent_next = &tq->tq_task;
|
||||||
t->task_prev = tq->tq_task.task_prev;
|
t->tqent_prev = tq->tq_task.tqent_prev;
|
||||||
}
|
}
|
||||||
t->task_next->task_prev = t;
|
t->tqent_next->tqent_prev = t;
|
||||||
t->task_prev->task_next = t;
|
t->tqent_prev->tqent_next = t;
|
||||||
t->task_func = func;
|
t->tqent_func = func;
|
||||||
t->task_arg = arg;
|
t->tqent_arg = arg;
|
||||||
cv_signal(&tq->tq_dispatch_cv);
|
cv_signal(&tq->tq_dispatch_cv);
|
||||||
mutex_exit(&tq->tq_lock);
|
mutex_exit(&tq->tq_lock);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
|
||||||
|
taskq_ent_t *t)
|
||||||
|
{
|
||||||
|
ASSERT(func != NULL);
|
||||||
|
ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark it as a prealloc'd task. This is important
|
||||||
|
* to ensure that we don't free it later.
|
||||||
|
*/
|
||||||
|
t->tqent_flags |= TQENT_FLAG_PREALLOC;
|
||||||
|
/*
|
||||||
|
* Enqueue the task to the underlying queue.
|
||||||
|
*/
|
||||||
|
mutex_enter(&tq->tq_lock);
|
||||||
|
|
||||||
|
if (flags & TQ_FRONT) {
|
||||||
|
t->tqent_next = tq->tq_task.tqent_next;
|
||||||
|
t->tqent_prev = &tq->tq_task;
|
||||||
|
} else {
|
||||||
|
t->tqent_next = &tq->tq_task;
|
||||||
|
t->tqent_prev = tq->tq_task.tqent_prev;
|
||||||
|
}
|
||||||
|
t->tqent_next->tqent_prev = t;
|
||||||
|
t->tqent_prev->tqent_next = t;
|
||||||
|
t->tqent_func = func;
|
||||||
|
t->tqent_arg = arg;
|
||||||
|
cv_signal(&tq->tq_dispatch_cv);
|
||||||
|
mutex_exit(&tq->tq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
taskq_wait(taskq_t *tq)
|
taskq_wait(taskq_t *tq)
|
||||||
{
|
{
|
||||||
mutex_enter(&tq->tq_lock);
|
mutex_enter(&tq->tq_lock);
|
||||||
while (tq->tq_task.task_next != &tq->tq_task || tq->tq_active != 0)
|
while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
|
||||||
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
|
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
|
||||||
mutex_exit(&tq->tq_lock);
|
mutex_exit(&tq->tq_lock);
|
||||||
}
|
}
|
||||||
@ -158,27 +186,32 @@ static void *
|
|||||||
taskq_thread(void *arg)
|
taskq_thread(void *arg)
|
||||||
{
|
{
|
||||||
taskq_t *tq = arg;
|
taskq_t *tq = arg;
|
||||||
task_t *t;
|
taskq_ent_t *t;
|
||||||
|
boolean_t prealloc;
|
||||||
|
|
||||||
mutex_enter(&tq->tq_lock);
|
mutex_enter(&tq->tq_lock);
|
||||||
while (tq->tq_flags & TASKQ_ACTIVE) {
|
while (tq->tq_flags & TASKQ_ACTIVE) {
|
||||||
if ((t = tq->tq_task.task_next) == &tq->tq_task) {
|
if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
|
||||||
if (--tq->tq_active == 0)
|
if (--tq->tq_active == 0)
|
||||||
cv_broadcast(&tq->tq_wait_cv);
|
cv_broadcast(&tq->tq_wait_cv);
|
||||||
cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
|
cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
|
||||||
tq->tq_active++;
|
tq->tq_active++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
t->task_prev->task_next = t->task_next;
|
t->tqent_prev->tqent_next = t->tqent_next;
|
||||||
t->task_next->task_prev = t->task_prev;
|
t->tqent_next->tqent_prev = t->tqent_prev;
|
||||||
|
t->tqent_next = NULL;
|
||||||
|
t->tqent_prev = NULL;
|
||||||
|
prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
|
||||||
mutex_exit(&tq->tq_lock);
|
mutex_exit(&tq->tq_lock);
|
||||||
|
|
||||||
rw_enter(&tq->tq_threadlock, RW_READER);
|
rw_enter(&tq->tq_threadlock, RW_READER);
|
||||||
t->task_func(t->task_arg);
|
t->tqent_func(t->tqent_arg);
|
||||||
rw_exit(&tq->tq_threadlock);
|
rw_exit(&tq->tq_threadlock);
|
||||||
|
|
||||||
mutex_enter(&tq->tq_lock);
|
mutex_enter(&tq->tq_lock);
|
||||||
task_free(tq, t);
|
if (!prealloc)
|
||||||
|
task_free(tq, t);
|
||||||
}
|
}
|
||||||
tq->tq_nthreads--;
|
tq->tq_nthreads--;
|
||||||
cv_broadcast(&tq->tq_wait_cv);
|
cv_broadcast(&tq->tq_wait_cv);
|
||||||
@ -217,8 +250,8 @@ taskq_create(const char *name, int nthreads, pri_t pri,
|
|||||||
tq->tq_nthreads = nthreads;
|
tq->tq_nthreads = nthreads;
|
||||||
tq->tq_minalloc = minalloc;
|
tq->tq_minalloc = minalloc;
|
||||||
tq->tq_maxalloc = maxalloc;
|
tq->tq_maxalloc = maxalloc;
|
||||||
tq->tq_task.task_next = &tq->tq_task;
|
tq->tq_task.tqent_next = &tq->tq_task;
|
||||||
tq->tq_task.task_prev = &tq->tq_task;
|
tq->tq_task.tqent_prev = &tq->tq_task;
|
||||||
tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
|
tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
|
||||||
|
|
||||||
if (flags & TASKQ_PREPOPULATE) {
|
if (flags & TASKQ_PREPOPULATE) {
|
||||||
|
@ -46,7 +46,7 @@ static void
|
|||||||
system_taskq_init(void *arg)
|
system_taskq_init(void *arg)
|
||||||
{
|
{
|
||||||
|
|
||||||
taskq_zone = uma_zcreate("taskq_zone", sizeof(struct ostask),
|
taskq_zone = uma_zcreate("taskq_zone", sizeof(taskq_ent_t),
|
||||||
NULL, NULL, NULL, NULL, 0, 0);
|
NULL, NULL, NULL, NULL, 0, 0);
|
||||||
system_taskq = taskq_create("system_taskq", mp_ncpus, 0, 0, 0, 0);
|
system_taskq = taskq_create("system_taskq", mp_ncpus, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
@ -104,9 +104,9 @@ taskq_member(taskq_t *tq, kthread_t *thread)
|
|||||||
static void
|
static void
|
||||||
taskq_run(void *arg, int pending __unused)
|
taskq_run(void *arg, int pending __unused)
|
||||||
{
|
{
|
||||||
struct ostask *task = arg;
|
taskq_ent_t *task = arg;
|
||||||
|
|
||||||
task->ost_func(task->ost_arg);
|
task->tqent_func(task->tqent_arg);
|
||||||
|
|
||||||
uma_zfree(taskq_zone, task);
|
uma_zfree(taskq_zone, task);
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ taskq_run(void *arg, int pending __unused)
|
|||||||
taskqid_t
|
taskqid_t
|
||||||
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
|
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
|
||||||
{
|
{
|
||||||
struct ostask *task;
|
taskq_ent_t *task;
|
||||||
int mflag, prio;
|
int mflag, prio;
|
||||||
|
|
||||||
if ((flags & (TQ_SLEEP | TQ_NOQUEUE)) == TQ_SLEEP)
|
if ((flags & (TQ_SLEEP | TQ_NOQUEUE)) == TQ_SLEEP)
|
||||||
@ -131,26 +131,26 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
|
|||||||
if (task == NULL)
|
if (task == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
task->ost_func = func;
|
task->tqent_func = func;
|
||||||
task->ost_arg = arg;
|
task->tqent_arg = arg;
|
||||||
|
|
||||||
TASK_INIT(&task->ost_task, prio, taskq_run, task);
|
TASK_INIT(&task->tqent_task, prio, taskq_run, task);
|
||||||
taskqueue_enqueue(tq->tq_queue, &task->ost_task);
|
taskqueue_enqueue(tq->tq_queue, &task->tqent_task);
|
||||||
|
|
||||||
return ((taskqid_t)(void *)task);
|
return ((taskqid_t)(void *)task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
taskq_run_safe(void *arg, int pending __unused)
|
taskq_run_ent(void *arg, int pending __unused)
|
||||||
{
|
{
|
||||||
struct ostask *task = arg;
|
taskq_ent_t *task = arg;
|
||||||
|
|
||||||
task->ost_func(task->ost_arg);
|
task->tqent_func(task->tqent_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
taskqid_t
|
void
|
||||||
taskq_dispatch_safe(taskq_t *tq, task_func_t func, void *arg, u_int flags,
|
taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, u_int flags,
|
||||||
struct ostask *task)
|
taskq_ent_t *task)
|
||||||
{
|
{
|
||||||
int prio;
|
int prio;
|
||||||
|
|
||||||
@ -160,11 +160,9 @@ taskq_dispatch_safe(taskq_t *tq, task_func_t func, void *arg, u_int flags,
|
|||||||
*/
|
*/
|
||||||
prio = !!(flags & TQ_FRONT);
|
prio = !!(flags & TQ_FRONT);
|
||||||
|
|
||||||
task->ost_func = func;
|
task->tqent_func = func;
|
||||||
task->ost_arg = arg;
|
task->tqent_arg = arg;
|
||||||
|
|
||||||
TASK_INIT(&task->ost_task, prio, taskq_run_safe, task);
|
TASK_INIT(&task->tqent_task, prio, taskq_run_ent, task);
|
||||||
taskqueue_enqueue(tq->tq_queue, &task->ost_task);
|
taskqueue_enqueue(tq->tq_queue, &task->tqent_task);
|
||||||
|
|
||||||
return ((taskqid_t)(void *)task);
|
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* $FreeBSD$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _OPENSOLARIS_SYS_TASKQ_H_
|
|
||||||
#define _OPENSOLARIS_SYS_TASKQ_H_
|
|
||||||
|
|
||||||
#include_next <sys/taskq.h>
|
|
||||||
|
|
||||||
struct ostask {
|
|
||||||
struct task ost_task;
|
|
||||||
task_func_t *ost_func;
|
|
||||||
void *ost_arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
taskqid_t taskq_dispatch_safe(taskq_t *tq, task_func_t func, void *arg,
|
|
||||||
u_int flags, struct ostask *task);
|
|
||||||
|
|
||||||
#endif /* _OPENSOLARIS_SYS_TASKQ_H_ */
|
|
@ -825,7 +825,7 @@ static taskq_t *
|
|||||||
spa_taskq_create(spa_t *spa, const char *name, enum zti_modes mode,
|
spa_taskq_create(spa_t *spa, const char *name, enum zti_modes mode,
|
||||||
uint_t value)
|
uint_t value)
|
||||||
{
|
{
|
||||||
uint_t flags = TASKQ_PREPOPULATE;
|
uint_t flags = 0;
|
||||||
boolean_t batch = B_FALSE;
|
boolean_t batch = B_FALSE;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||||
|
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _ZIO_H
|
#ifndef _ZIO_H
|
||||||
@ -474,10 +475,9 @@ struct zio {
|
|||||||
zio_cksum_report_t *io_cksum_report;
|
zio_cksum_report_t *io_cksum_report;
|
||||||
uint64_t io_ena;
|
uint64_t io_ena;
|
||||||
|
|
||||||
#ifdef _KERNEL
|
/* Taskq dispatching state */
|
||||||
/* FreeBSD only. */
|
taskq_ent_t io_tqent;
|
||||||
struct ostask io_task;
|
|
||||||
#endif
|
|
||||||
avl_node_t io_trim_node;
|
avl_node_t io_trim_node;
|
||||||
list_node_t io_trim_link;
|
list_node_t io_trim_link;
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
|
* Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/zfs_context.h>
|
#include <sys/zfs_context.h>
|
||||||
@ -1224,7 +1225,7 @@ zio_taskq_dispatch(zio_t *zio, enum zio_taskq_type q, boolean_t cutinline)
|
|||||||
{
|
{
|
||||||
spa_t *spa = zio->io_spa;
|
spa_t *spa = zio->io_spa;
|
||||||
zio_type_t t = zio->io_type;
|
zio_type_t t = zio->io_type;
|
||||||
int flags = TQ_SLEEP | (cutinline ? TQ_FRONT : 0);
|
int flags = (cutinline ? TQ_FRONT : 0);
|
||||||
|
|
||||||
ASSERT(q == ZIO_TASKQ_ISSUE || q == ZIO_TASKQ_INTERRUPT);
|
ASSERT(q == ZIO_TASKQ_ISSUE || q == ZIO_TASKQ_INTERRUPT);
|
||||||
|
|
||||||
@ -1250,13 +1251,19 @@ zio_taskq_dispatch(zio_t *zio, enum zio_taskq_type q, boolean_t cutinline)
|
|||||||
q++;
|
q++;
|
||||||
|
|
||||||
ASSERT3U(q, <, ZIO_TASKQ_TYPES);
|
ASSERT3U(q, <, ZIO_TASKQ_TYPES);
|
||||||
#ifdef _KERNEL
|
|
||||||
(void) taskq_dispatch_safe(spa->spa_zio_taskq[t][q],
|
/*
|
||||||
(task_func_t *)zio_execute, zio, flags, &zio->io_task);
|
* NB: We are assuming that the zio can only be dispatched
|
||||||
|
* to a single taskq at a time. It would be a grievous error
|
||||||
|
* to dispatch the zio to another taskq at the same time.
|
||||||
|
*/
|
||||||
|
#if defined(illumos) || !defined(_KERNEL)
|
||||||
|
ASSERT(zio->io_tqent.tqent_next == NULL);
|
||||||
#else
|
#else
|
||||||
(void) taskq_dispatch(spa->spa_zio_taskq[t][q],
|
ASSERT(zio->io_tqent.tqent_task.ta_pending == 0);
|
||||||
(task_func_t *)zio_execute, zio, flags);
|
|
||||||
#endif
|
#endif
|
||||||
|
taskq_dispatch_ent(spa->spa_zio_taskq[t][q],
|
||||||
|
(task_func_t *)zio_execute, zio, flags, &zio->io_tqent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean_t
|
static boolean_t
|
||||||
@ -3174,16 +3181,15 @@ zio_done(zio_t *zio)
|
|||||||
* Reexecution is potentially a huge amount of work.
|
* Reexecution is potentially a huge amount of work.
|
||||||
* Hand it off to the otherwise-unused claim taskq.
|
* Hand it off to the otherwise-unused claim taskq.
|
||||||
*/
|
*/
|
||||||
#ifdef _KERNEL
|
#if defined(illumos) || !defined(_KERNEL)
|
||||||
(void) taskq_dispatch_safe(
|
ASSERT(zio->io_tqent.tqent_next == NULL);
|
||||||
spa->spa_zio_taskq[ZIO_TYPE_CLAIM][ZIO_TASKQ_ISSUE],
|
|
||||||
(task_func_t *)zio_reexecute, zio, TQ_SLEEP,
|
|
||||||
&zio->io_task);
|
|
||||||
#else
|
#else
|
||||||
(void) taskq_dispatch(
|
ASSERT(zio->io_tqent.tqent_task.ta_pending == 0);
|
||||||
spa->spa_zio_taskq[ZIO_TYPE_CLAIM][ZIO_TASKQ_ISSUE],
|
|
||||||
(task_func_t *)zio_reexecute, zio, TQ_SLEEP);
|
|
||||||
#endif
|
#endif
|
||||||
|
(void) taskq_dispatch_ent(
|
||||||
|
spa->spa_zio_taskq[ZIO_TYPE_CLAIM][ZIO_TASKQ_ISSUE],
|
||||||
|
(task_func_t *)zio_reexecute, zio, 0,
|
||||||
|
&zio->io_tqent);
|
||||||
}
|
}
|
||||||
return (ZIO_PIPELINE_STOP);
|
return (ZIO_PIPELINE_STOP);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,12 @@ typedef struct taskq taskq_t;
|
|||||||
typedef uintptr_t taskqid_t;
|
typedef uintptr_t taskqid_t;
|
||||||
typedef void (task_func_t)(void *);
|
typedef void (task_func_t)(void *);
|
||||||
|
|
||||||
|
typedef struct taskq_ent {
|
||||||
|
struct task tqent_task;
|
||||||
|
task_func_t *tqent_func;
|
||||||
|
void *tqent_arg;
|
||||||
|
} taskq_ent_t;
|
||||||
|
|
||||||
struct proc;
|
struct proc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -80,6 +86,8 @@ taskq_t *taskq_create_proc(const char *, int, pri_t, int, int,
|
|||||||
taskq_t *taskq_create_sysdc(const char *, int, int, int,
|
taskq_t *taskq_create_sysdc(const char *, int, int, int,
|
||||||
struct proc *, uint_t, uint_t);
|
struct proc *, uint_t, uint_t);
|
||||||
taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
||||||
|
void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t,
|
||||||
|
taskq_ent_t *);
|
||||||
void nulltask(void *);
|
void nulltask(void *);
|
||||||
void taskq_destroy(taskq_t *);
|
void taskq_destroy(taskq_t *);
|
||||||
void taskq_wait(taskq_t *);
|
void taskq_wait(taskq_t *);
|
||||||
|
Loading…
Reference in New Issue
Block a user