Date: Wed, 20 May 2009 21:04:41 +0000 (UTC) From: Kip Macy <kmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r192475 - in stable/7/sys: conf kern sys Message-ID: <200905202104.n4KL4fOc043655@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kmacy Date: Wed May 20 21:04:41 2009 New Revision: 192475 URL: http://svn.freebsd.org/changeset/base/192475 Log: - MFC "object specific data" support with rmlocks replaced with rwlocks - ZFS MFC dependency Added: stable/7/sys/kern/kern_osd.c (contents, props changed) stable/7/sys/sys/osd.h (contents, props changed) Modified: stable/7/sys/conf/files stable/7/sys/kern/kern_proc.c stable/7/sys/kern/kern_thread.c stable/7/sys/sys/jail.h stable/7/sys/sys/proc.h Modified: stable/7/sys/conf/files ============================================================================== --- stable/7/sys/conf/files Wed May 20 20:57:40 2009 (r192474) +++ stable/7/sys/conf/files Wed May 20 21:04:41 2009 (r192475) @@ -1620,6 +1620,7 @@ kern/kern_module.c standard kern/kern_mtxpool.c standard kern/kern_mutex.c standard kern/kern_ntptime.c standard +kern/kern_osd.c standard kern/kern_physio.c standard kern/kern_pmc.c standard kern/kern_poll.c optional device_polling Added: stable/7/sys/kern/kern_osd.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/7/sys/kern/kern_osd.c Wed May 20 21:04:41 2009 (r192475) @@ -0,0 +1,406 @@ +/*- + * Copyright (c) 2007 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/errno.h> +#include <sys/jail.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/rwlock.h> +#include <sys/sx.h> +#include <sys/queue.h> +#include <sys/proc.h> +#include <sys/osd.h> + +/* OSD (Object Specific Data) */ + +static MALLOC_DEFINE(M_OSD, "osd", "Object Specific Data"); + +static int osd_debug = 0; +TUNABLE_INT("debug.osd", &osd_debug); +SYSCTL_INT(_debug, OID_AUTO, osd, CTLFLAG_RW, &osd_debug, 0, "OSD debug level"); + +#define OSD_DEBUG(...) do { \ + if (osd_debug) { \ + printf("OSD (%s:%u): ", __func__, __LINE__); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } \ +} while (0) + +static void do_osd_del(u_int type, struct osd *osd, u_int slot); +static void do_osd_del_locked(u_int type, struct osd *osd, u_int slot); + +/* + * Lists of objects with OSD. + * + * Lock key: + * (m) osd_module_lock + * (o) osd_object_lock + * (l) osd_list_lock + */ +static LIST_HEAD(, osd) osd_list[OSD_LAST + 1]; /* (m) */ +static osd_method_t *osd_methods[OSD_LAST + 1]; /* (m) */ +static u_int osd_nslots[OSD_LAST + 1]; /* (m) */ +static osd_destructor_t *osd_destructors[OSD_LAST + 1]; /* (o) */ +static const u_int osd_nmethods[OSD_LAST + 1] = { + [OSD_JAIL] = PR_MAXMETHOD, +}; + +static struct sx osd_module_lock[OSD_LAST + 1]; +static struct rwlock osd_object_lock[OSD_LAST + 1]; +static struct mtx osd_list_lock[OSD_LAST + 1]; + +static void +osd_default_destructor(void *value __unused) +{ + /* Do nothing. */ +} + +int +osd_register(u_int type, osd_destructor_t destructor, osd_method_t *methods) +{ + void *newptr; + u_int i, m; + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + + /* + * If no destructor is given, use default one. We need to use some + * destructor, because NULL destructor means unused slot. + */ + if (destructor == NULL) + destructor = osd_default_destructor; + + sx_xlock(&osd_module_lock[type]); + /* + * First, we try to find unused slot. + */ + for (i = 0; i < osd_nslots[type]; i++) { + if (osd_destructors[type][i] == NULL) { + OSD_DEBUG("Unused slot found (type=%u, slot=%u).", + type, i); + break; + } + } + /* + * If no unused slot was found, allocate one. + */ + if (i == osd_nslots[type]) { + osd_nslots[type]++; + if (osd_nmethods[type] != 0) + osd_methods[type] = realloc(osd_methods[type], + sizeof(osd_method_t) * osd_nslots[type] * + osd_nmethods[type], M_OSD, M_WAITOK); + newptr = malloc(sizeof(osd_destructor_t) * osd_nslots[type], + M_OSD, M_WAITOK); + rw_wlock(&osd_object_lock[type]); + bcopy(osd_destructors[type], newptr, + sizeof(osd_destructor_t) * i); + free(osd_destructors[type], M_OSD); + osd_destructors[type] = newptr; + rw_wunlock(&osd_object_lock[type]); + OSD_DEBUG("New slot allocated (type=%u, slot=%u).", + type, i + 1); + } + + osd_destructors[type][i] = destructor; + if (osd_nmethods[type] != 0) { + for (m = 0; m < osd_nmethods[type]; m++) + osd_methods[type][i * osd_nmethods[type] + m] = + methods != NULL ? methods[m] : NULL; + } + sx_xunlock(&osd_module_lock[type]); + return (i + 1); +} + +void +osd_deregister(u_int type, u_int slot) +{ + struct osd *osd, *tosd; + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + KASSERT(slot > 0, ("Invalid slot.")); + KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot.")); + + sx_xlock(&osd_module_lock[type]); + rw_wlock(&osd_object_lock[type]); + /* + * Free all OSD for the given slot. + */ + mtx_lock(&osd_list_lock[type]); + LIST_FOREACH_SAFE(osd, &osd_list[type], osd_next, tosd) + do_osd_del_locked(type, osd, slot); + mtx_unlock(&osd_list_lock[type]); + /* + * Set destructor to NULL to free the slot. + */ + osd_destructors[type][slot - 1] = NULL; + if (slot == osd_nslots[type]) { + osd_nslots[type]--; + osd_destructors[type] = realloc(osd_destructors[type], + sizeof(osd_destructor_t) * osd_nslots[type], M_OSD, + M_NOWAIT | M_ZERO); + if (osd_nmethods[type] != 0) + osd_methods[type] = realloc(osd_methods[type], + sizeof(osd_method_t) * osd_nslots[type] * + osd_nmethods[type], M_OSD, M_NOWAIT | M_ZERO); + /* + * We always reallocate to smaller size, so we assume it will + * always succeed. + */ + KASSERT(osd_destructors[type] != NULL && + (osd_nmethods[type] == 0 || osd_methods[type] != NULL), + ("realloc() failed")); + OSD_DEBUG("Deregistration of the last slot (type=%u, slot=%u).", + type, slot); + } else { + OSD_DEBUG("Slot deregistration (type=%u, slot=%u).", + type, slot); + } + rw_wunlock(&osd_object_lock[type]); + sx_xunlock(&osd_module_lock[type]); +} + +int +osd_set(u_int type, struct osd *osd, u_int slot, void *value) +{ + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + KASSERT(slot > 0, ("Invalid slot.")); + KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot.")); + + rw_rlock(&osd_object_lock[type]); + if (slot > osd->osd_nslots) { + if (value == NULL) { + OSD_DEBUG( + "Not allocating null slot (type=%u, slot=%u).", + type, slot); + rw_runlock(&osd_object_lock[type]); + return (0); + } else if (osd->osd_nslots == 0) { + /* + * First OSD for this object, so we need to allocate + * space and put it onto the list. + */ + osd->osd_slots = malloc(sizeof(void *) * slot, M_OSD, + M_NOWAIT | M_ZERO); + if (osd->osd_slots == NULL) { + rw_runlock(&osd_object_lock[type]); + return (ENOMEM); + } + osd->osd_nslots = slot; + mtx_lock(&osd_list_lock[type]); + LIST_INSERT_HEAD(&osd_list[type], osd, osd_next); + mtx_unlock(&osd_list_lock[type]); + OSD_DEBUG("Setting first slot (type=%u).", type); + } else { + void *newptr; + + /* + * Too few slots allocated here, needs to extend + * the array. + */ + newptr = realloc(osd->osd_slots, sizeof(void *) * slot, + M_OSD, M_NOWAIT | M_ZERO); + if (newptr == NULL) { + rw_runlock(&osd_object_lock[type]); + return (ENOMEM); + } + osd->osd_slots = newptr; + osd->osd_nslots = slot; + OSD_DEBUG("Growing slots array (type=%u).", type); + } + } + OSD_DEBUG("Setting slot value (type=%u, slot=%u, value=%p).", type, + slot, value); + osd->osd_slots[slot - 1] = value; + rw_runlock(&osd_object_lock[type]); + return (0); +} + +void * +osd_get(u_int type, struct osd *osd, u_int slot) +{ + void *value; + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + KASSERT(slot > 0, ("Invalid slot.")); + KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot.")); + + rw_rlock(&osd_object_lock[type]); + if (slot > osd->osd_nslots) { + value = NULL; + OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot); + } else { + value = osd->osd_slots[slot - 1]; + OSD_DEBUG("Returning slot value (type=%u, slot=%u, value=%p).", + type, slot, value); + } + rw_runlock(&osd_object_lock[type]); + return (value); +} + +static void +do_osd_del_locked(u_int type, struct osd *osd, u_int slot) +{ + int i; + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + KASSERT(slot > 0, ("Invalid slot.")); + KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot.")); + mtx_assert(&osd_list_lock[type], MA_OWNED); + + OSD_DEBUG("Deleting slot (type=%u, slot=%u).", type, slot); + + if (slot > osd->osd_nslots) { + OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot); + return; + } + if (osd->osd_slots[slot - 1] != NULL) { + osd_destructors[type][slot - 1](osd->osd_slots[slot - 1]); + osd->osd_slots[slot - 1] = NULL; + } + for (i = osd->osd_nslots - 1; i >= 0; i--) { + if (osd->osd_slots[i] != NULL) { + OSD_DEBUG("Slot still has a value (type=%u, slot=%u).", + type, i + 1); + break; + } + } + if (i == -1) { + /* No values left for this object. */ + OSD_DEBUG("No more slots left (type=%u).", type); + LIST_REMOVE(osd, osd_next); + free(osd->osd_slots, M_OSD); + osd->osd_slots = NULL; + osd->osd_nslots = 0; + } else if (slot == osd->osd_nslots) { + /* This was the last slot. */ + osd->osd_slots = realloc(osd->osd_slots, + sizeof(void *) * (i + 1), M_OSD, M_NOWAIT | M_ZERO); + /* + * We always reallocate to smaller size, so we assume it will + * always succeed. + */ + KASSERT(osd->osd_slots != NULL, ("realloc() failed")); + osd->osd_nslots = i + 1; + OSD_DEBUG("Reducing slots array to %u (type=%u).", + osd->osd_nslots, type); + } +} + +static void +do_osd_del(u_int type, struct osd *osd, u_int slot) +{ + mtx_lock(&osd_list_lock[type]); + do_osd_del_locked(type, osd, slot); + mtx_unlock(&osd_list_lock[type]); +} + +void +osd_del(u_int type, struct osd *osd, u_int slot) +{ + + rw_rlock(&osd_object_lock[type]); + do_osd_del(type, osd, slot); + rw_runlock(&osd_object_lock[type]); +} + + + +int +osd_call(u_int type, u_int method, void *obj, void *data) +{ + osd_method_t methodfun; + int error, i; + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + KASSERT(method < osd_nmethods[type], ("Invalid method.")); + + /* + * Call this method for every slot that defines it, stopping if an + * error is encountered. + */ + error = 0; + sx_slock(&osd_module_lock[type]); + for (i = 0; i < osd_nslots[type]; i++) { + methodfun = + osd_methods[type][i * osd_nmethods[type] + method]; + if (methodfun != NULL && (error = methodfun(obj, data)) != 0) + break; + } + sx_sunlock(&osd_module_lock[type]); + return (error); +} + +void +osd_exit(u_int type, struct osd *osd) +{ + u_int i; + + KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); + + if (osd->osd_nslots == 0) { + KASSERT(osd->osd_slots == NULL, ("Non-null osd_slots.")); + /* No OSD attached, just leave. */ + return; + } + + rw_rlock(&osd_object_lock[type]); + for (i = 1; i <= osd->osd_nslots; i++) { + if (osd_destructors[type][i - 1] != NULL) + do_osd_del(type, osd, i); + else + OSD_DEBUG("Unused slot (type=%u, slot=%u).", type, i); + } + rw_runlock(&osd_object_lock[type]); + OSD_DEBUG("Object exit (type=%u).", type); +} + +static void +osd_init(void *arg __unused) +{ + u_int i; + + for (i = OSD_FIRST; i <= OSD_LAST; i++) { + osd_nslots[i] = 0; + LIST_INIT(&osd_list[i]); + sx_init(&osd_module_lock[i], "osd_module"); + rw_init(&osd_object_lock[i], "osd_object"); + mtx_init(&osd_list_lock[i], "osd_list", NULL, MTX_DEF); + osd_destructors[i] = NULL; + osd_methods[i] = NULL; + } +} +SYSINIT(osd, SI_SUB_LOCK, SI_ORDER_ANY, osd_init, NULL); Modified: stable/7/sys/kern/kern_proc.c ============================================================================== --- stable/7/sys/kern/kern_proc.c Wed May 20 20:57:40 2009 (r192474) +++ stable/7/sys/kern/kern_proc.c Wed May 20 21:04:41 2009 (r192475) @@ -200,6 +200,8 @@ proc_dtor(void *mem, int size, void *arg ("bad number of threads in exiting process")); KASSERT(STAILQ_EMPTY(&p->p_ktr), ("proc_dtor: non-empty p_ktr")); #endif + /* Free all OSD associated to this thread. */ + osd_thread_exit(td); /* Dispose of an alternate kstack, if it exists. * XXX What if there are more than one thread in the proc? Modified: stable/7/sys/kern/kern_thread.c ============================================================================== --- stable/7/sys/kern/kern_thread.c Wed May 20 20:57:40 2009 (r192474) +++ stable/7/sys/kern/kern_thread.c Wed May 20 21:04:41 2009 (r192475) @@ -133,6 +133,9 @@ thread_ctor(void *mem, int size, void *a #ifdef AUDIT audit_thread_alloc(td); #endif + /* Free all OSD associated to this thread. */ + osd_thread_exit(td); + umtx_thread_alloc(td); return (0); } Modified: stable/7/sys/sys/jail.h ============================================================================== --- stable/7/sys/sys/jail.h Wed May 20 20:57:40 2009 (r192474) +++ stable/7/sys/sys/jail.h Wed May 20 21:04:41 2009 (r192475) @@ -14,6 +14,8 @@ #define _SYS_JAIL_H_ #ifdef _KERNEL +#include <sys/osd.h> + struct jail_v0 { u_int32_t version; char *path; @@ -136,11 +138,28 @@ struct prison { struct in_addr *pr_ip4; /* (c) v4 IPs of jail */ int pr_ip6s; /* (c) number of v6 IPs */ struct in6_addr *pr_ip6; /* (c) v6 IPs of jail */ + struct osd pr_osd; }; #endif /* _KERNEL || _WANT_PRISON */ #ifdef _KERNEL /* + * Flag bits set via options or internally + */ +#define PR_PERSIST 0x00000001 /* Can exist without processes */ +#define PR_REMOVE 0x01000000 /* In process of being removed */ + +/* + * OSD methods + */ +#define PR_METHOD_CREATE 0 +#define PR_METHOD_GET 1 +#define PR_METHOD_SET 2 +#define PR_METHOD_CHECK 3 +#define PR_METHOD_ATTACH 4 +#define PR_MAXMETHOD 5 + +/* * Sysctl-set variables that determine global jail policy * * XXX MIB entries will need to be protected by a mutex. Added: stable/7/sys/sys/osd.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/7/sys/sys/osd.h Wed May 20 21:04:41 2009 (r192475) @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2007 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 _SYS_OSD_H_ +#define _SYS_OSD_H_ + +#include <sys/queue.h> + +/* + * Lock key: + * (c) container lock (e.g. jail's pr_mtx) and/or osd_object_lock + * (l) osd_list_lock + */ +struct osd { + u_int osd_nslots; /* (c) */ + void **osd_slots; /* (c) */ + LIST_ENTRY(osd) osd_next; /* (l) */ +}; + +#ifdef _KERNEL + +#define OSD_THREAD 0 +#define OSD_JAIL 1 + +#define OSD_FIRST OSD_THREAD +#define OSD_LAST OSD_JAIL + +typedef void (*osd_destructor_t)(void *value); +typedef int (*osd_method_t)(void *obj, void *data); + +int osd_register(u_int type, osd_destructor_t destructor, + osd_method_t *methods); +void osd_deregister(u_int type, u_int slot); + +int osd_set(u_int type, struct osd *osd, u_int slot, void *value); +void *osd_get(u_int type, struct osd *osd, u_int slot); +void osd_del(u_int type, struct osd *osd, u_int slot); +int osd_call(u_int type, u_int method, void *obj, void *data); + +void osd_exit(u_int type, struct osd *osd); + +#define osd_thread_register(destructor) \ + osd_register(OSD_THREAD, (destructor), NULL) +#define osd_thread_deregister(slot) \ + osd_deregister(OSD_THREAD, (slot)) +#define osd_thread_set(td, slot, value) \ + osd_set(OSD_THREAD, &(td)->td_osd, (slot), (value)) +#define osd_thread_get(td, slot) \ + osd_get(OSD_THREAD, &(td)->td_osd, (slot)) +#define osd_thread_del(td, slot) do { \ + KASSERT((td) == curthread, ("Not curthread.")); \ + osd_del(OSD_THREAD, &(td)->td_osd, (slot)); \ +} while (0) +#define osd_thread_call(td, method, data) \ + osd_call(OSD_THREAD, (method), (td), (data)) +#define osd_thread_exit(td) \ + osd_exit(OSD_THREAD, &(td)->td_osd) + +#define osd_jail_register(destructor, methods) \ + osd_register(OSD_JAIL, (destructor), (methods)) +#define osd_jail_deregister(slot) \ + osd_deregister(OSD_JAIL, (slot)) +#define osd_jail_set(pr, slot, value) \ + osd_set(OSD_JAIL, &(pr)->pr_osd, (slot), (value)) +#define osd_jail_get(pr, slot) \ + osd_get(OSD_JAIL, &(pr)->pr_osd, (slot)) +#define osd_jail_del(pr, slot) \ + osd_del(OSD_JAIL, &(pr)->pr_osd, (slot)) +#define osd_jail_call(pr, method, data) \ + osd_call(OSD_JAIL, (method), (pr), (data)) +#define osd_jail_exit(pr) \ + osd_exit(OSD_JAIL, &(pr)->pr_osd) + +#endif /* _KERNEL */ + +#endif /* !_SYS_OSD_H_ */ Modified: stable/7/sys/sys/proc.h ============================================================================== --- stable/7/sys/sys/proc.h Wed May 20 20:57:40 2009 (r192474) +++ stable/7/sys/sys/proc.h Wed May 20 21:04:41 2009 (r192475) @@ -46,6 +46,7 @@ #include <sys/queue.h> #include <sys/_lock.h> #include <sys/_mutex.h> +#include <sys/osd.h> #include <sys/priority.h> #include <sys/rtprio.h> /* XXX. */ #include <sys/runq.h> @@ -305,6 +306,7 @@ struct thread { struct file *td_fpop; /* (k) file referencing cdev under op */ struct kdtrace_thread *td_dtrace; /* (*) DTrace-specific data. */ int td_errno; /* Error returned by last syscall. */ + struct osd td_osd; /* (k) Object specific data. */ }; struct mtx *thread_lock_block(struct thread *);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905202104.n4KL4fOc043655>