diff options
author | Mark Johnson <Mark.Johnson@Sun.COM> | 2009-01-28 18:28:04 -0800 |
---|---|---|
committer | Mark Johnson <Mark.Johnson@Sun.COM> | 2009-01-28 18:28:04 -0800 |
commit | bc3489c0c3dc75477d8ebb93b7a202625bd8cbfd (patch) | |
tree | c7eb1a9d3fa3aa85d80b78b149f590e97fb4d749 /usr/src | |
parent | 0ba6f73dcd1c9160a44b2872ed0e0d81b51d168f (diff) | |
download | illumos-gate-bc3489c0c3dc75477d8ebb93b7a202625bd8cbfd.tar.gz |
6795914 xsvc driver not handling fork correctly
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/i86pc/io/xsvc/xsvc.c | 146 | ||||
-rw-r--r-- | usr/src/uts/i86pc/sys/xsvc.h | 6 |
2 files changed, 130 insertions, 22 deletions
diff --git a/usr/src/uts/i86pc/io/xsvc/xsvc.c b/usr/src/uts/i86pc/io/xsvc/xsvc.c index d21d48e646..1d0b9741b0 100644 --- a/usr/src/uts/i86pc/io/xsvc/xsvc.c +++ b/usr/src/uts/i86pc/io/xsvc/xsvc.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -122,9 +122,6 @@ static int xsvc_mnode_key_compare(const void *q, const void *e); static int xsvc_umem_cookie_alloc(caddr_t kva, size_t size, int flags, ddi_umem_cookie_t *cookiep); static void xsvc_umem_cookie_free(ddi_umem_cookie_t *cookiep); -static void xsvc_devmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, - size_t len, devmap_cookie_t new_dhp1, void **new_pvtp1, - devmap_cookie_t new_dhp2, void **new_pvtp2); void *xsvc_statep; @@ -135,11 +132,20 @@ static ddi_device_acc_attr_t xsvc_device_attr = { DDI_STRICTORDER_ACC }; +static int xsvc_devmap_map(devmap_cookie_t dhp, dev_t dev, uint_t flags, + offset_t off, size_t len, void **pvtp); +static int xsvc_devmap_dup(devmap_cookie_t dhp, void *pvtp, + devmap_cookie_t new_dhp, void **new_pvtp); +static void xsvc_devmap_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off, + size_t len, devmap_cookie_t new_dhp1, void **new_pvtp1, + devmap_cookie_t new_dhp2, void **new_pvtp2); + + static struct devmap_callback_ctl xsvc_callbk = { DEVMAP_OPS_REV, + xsvc_devmap_map, NULL, - NULL, - NULL, + xsvc_devmap_dup, xsvc_devmap_unmap }; @@ -237,6 +243,8 @@ xsvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) mutex_init(&state->xs_mutex, NULL, MUTEX_DRIVER, NULL); state->xs_currently_alloced = 0; + mutex_init(&state->xs_cookie_mutex, NULL, MUTEX_DRIVER, NULL); + /* create the minor node (for the ioctl) */ err = ddi_create_minor_node(dip, "xsvc", S_IFCHR, instance, DDI_PSEUDO, 0); @@ -265,6 +273,7 @@ xsvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) return (DDI_SUCCESS); attachfail_minor_node: + mutex_destroy(&state->xs_cookie_mutex); mutex_destroy(&state->xs_mutex); attachfail_get_soft_state: (void) ddi_soft_state_free(xsvc_statep, instance); @@ -314,6 +323,7 @@ xsvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) avl_destroy(&state->xs_mlist.ml_avl); mutex_destroy(&state->xs_mlist.ml_mutex); + mutex_destroy(&state->xs_cookie_mutex); mutex_destroy(&state->xs_mutex); (void) ddi_soft_state_free(xsvc_statep, state->xs_instance); return (DDI_SUCCESS); @@ -947,6 +957,77 @@ xsvc_umem_cookie_free(ddi_umem_cookie_t *cookiep) *cookiep = NULL; } + +/* + * xsvc_devmap_map() + * + */ +/*ARGSUSED*/ +static int +xsvc_devmap_map(devmap_cookie_t dhc, dev_t dev, uint_t flags, offset_t off, + size_t len, void **pvtp) +{ + struct ddi_umem_cookie *cp; + devmap_handle_t *dhp; + xsvc_state_t *state; + int instance; + + + instance = getminor(dev); + state = ddi_get_soft_state(xsvc_statep, instance); + if (state == NULL) { + return (ENXIO); + } + + dhp = (devmap_handle_t *)dhc; + /* This driver only supports MAP_SHARED, not MAP_PRIVATE */ + if (flags & MAP_PRIVATE) { + cmn_err(CE_WARN, "!xsvc driver doesn't support MAP_PRIVATE"); + return (EINVAL); + } + + cp = (struct ddi_umem_cookie *)dhp->dh_cookie; + cp->cook_refcnt = 1; + + *pvtp = state; + return (0); +} + + +/* + * xsvc_devmap_dup() + * + * keep a reference count for forks so we don't unmap if we have multiple + * mappings. + */ +/*ARGSUSED*/ +static int +xsvc_devmap_dup(devmap_cookie_t dhc, void *pvtp, devmap_cookie_t new_dhp, + void **new_pvtp) +{ + struct ddi_umem_cookie *cp; + devmap_handle_t *dhp; + xsvc_state_t *state; + + + state = (xsvc_state_t *)pvtp; + dhp = (devmap_handle_t *)dhc; + + mutex_enter(&state->xs_cookie_mutex); + cp = (struct ddi_umem_cookie *)dhp->dh_cookie; + if (cp == NULL) { + mutex_exit(&state->xs_cookie_mutex); + return (ENOMEM); + } + + cp->cook_refcnt++; + mutex_exit(&state->xs_cookie_mutex); + + *new_pvtp = state; + return (0); +} + + /* * xsvc_devmap_unmap() * @@ -962,8 +1043,11 @@ xsvc_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len, devmap_cookie_t new_dhp1, void **new_pvtp1, devmap_cookie_t new_dhp2, void **new_pvtp2) { + struct ddi_umem_cookie *ncp; struct ddi_umem_cookie *cp; + devmap_handle_t *ndhp; devmap_handle_t *dhp; + xsvc_state_t *state; size_t npages; caddr_t kvai; caddr_t kva; @@ -971,22 +1055,46 @@ xsvc_devmap_unmap(devmap_cookie_t dhc, void *pvtp, offset_t off, size_t len, int i; + state = (xsvc_state_t *)pvtp; + mutex_enter(&state->xs_cookie_mutex); + /* peek into the umem cookie to figure out what we need to free up */ dhp = (devmap_handle_t *)dhc; cp = (struct ddi_umem_cookie *)dhp->dh_cookie; - kva = cp->cvaddr; - size = cp->size; + ASSERT(cp != NULL); - /* - * free up the umem cookie, then unmap all the pages what we mapped - * in during devmap, then free up the kva space. - */ - npages = btop(size); - xsvc_umem_cookie_free(&dhp->dh_cookie); - kvai = kva; - for (i = 0; i < npages; i++) { - hat_unload(kas.a_hat, kvai, PAGESIZE, HAT_UNLOAD_UNLOCK); - kvai = (caddr_t)((uintptr_t)kvai + PAGESIZE); + if (new_dhp1 != NULL) { + ndhp = (devmap_handle_t *)new_dhp1; + ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie; + ncp->cook_refcnt++; + *new_pvtp1 = state; + } + if (new_dhp2 != NULL) { + ndhp = (devmap_handle_t *)new_dhp2; + ncp = (struct ddi_umem_cookie *)ndhp->dh_cookie; + ncp->cook_refcnt++; + *new_pvtp2 = state; } - vmem_free(heap_arena, kva, size); + + cp->cook_refcnt--; + if (cp->cook_refcnt == 0) { + kva = cp->cvaddr; + size = cp->size; + + /* + * free up the umem cookie, then unmap all the pages what we + * mapped in during devmap, then free up the kva space. + */ + npages = btop(size); + xsvc_umem_cookie_free(&dhp->dh_cookie); + kvai = kva; + for (i = 0; i < npages; i++) { + hat_unload(kas.a_hat, kvai, PAGESIZE, + HAT_UNLOAD_UNLOCK); + kvai = (caddr_t)((uintptr_t)kvai + PAGESIZE); + } + vmem_free(heap_arena, kva, size); + } + + mutex_exit(&state->xs_cookie_mutex); } diff --git a/usr/src/uts/i86pc/sys/xsvc.h b/usr/src/uts/i86pc/sys/xsvc.h index 1bf541e98d..2d63176849 100644 --- a/usr/src/uts/i86pc/sys/xsvc.h +++ b/usr/src/uts/i86pc/sys/xsvc.h @@ -20,15 +20,13 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_XSVC_H #define _SYS_XSVC_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -122,6 +120,8 @@ typedef struct xsvc_state_s { kmutex_t xs_mutex; uint64_t xs_currently_alloced; + kmutex_t xs_cookie_mutex; + xsvc_mlist_t xs_mlist; } xsvc_state_t; |