diff options
Diffstat (limited to 'usr/src/uts/common/os/strsubr.c')
-rw-r--r-- | usr/src/uts/common/os/strsubr.c | 197 |
1 files changed, 164 insertions, 33 deletions
diff --git a/usr/src/uts/common/os/strsubr.c b/usr/src/uts/common/os/strsubr.c index db039e241e..37302b67e4 100644 --- a/usr/src/uts/common/os/strsubr.c +++ b/usr/src/uts/common/os/strsubr.c @@ -23,7 +23,7 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -77,6 +77,10 @@ #include <sys/strft.h> #include <sys/fs/snode.h> #include <sys/zone.h> +#include <sys/open.h> +#include <sys/sunldi.h> +#include <sys/sad.h> +#include <sys/netstack.h> #define O_SAMESTR(q) (((q)->q_next) && \ (((q)->q_flag & QREADR) == ((q)->q_next->q_flag & QREADR))) @@ -199,6 +203,10 @@ kthread_t *bc_bkgrnd_thread; /* Thread to service bufcall requests */ kmutex_t strresources; /* protects global resources */ kmutex_t muxifier; /* single-threads multiplexor creation */ +static void *str_stack_init(netstackid_t stackid, netstack_t *ns); +static void str_stack_shutdown(netstackid_t stackid, void *arg); +static void str_stack_fini(netstackid_t stackid, void *arg); + extern void time_to_wait(clock_t *, clock_t); /* @@ -228,8 +236,6 @@ int max_n_ciputctrl = 16; */ int min_n_ciputctrl = 2; -static struct mux_node *mux_nodes; /* mux info for cycle checking */ - /* * Per-driver/module syncqs * ======================== @@ -835,16 +841,8 @@ ciputctrl_destructor(void *buf, void *cdrarg) void strinit(void) { - int i; int ncpus = ((boot_max_ncpus == -1) ? max_ncpus : boot_max_ncpus); - /* - * Set up mux_node structures. - */ - mux_nodes = kmem_zalloc((sizeof (struct mux_node) * devcnt), KM_SLEEP); - for (i = 0; i < devcnt; i++) - mux_nodes[i].mn_imaj = i; - stream_head_cache = kmem_cache_create("stream_head_cache", sizeof (stdata_t), 0, stream_head_constructor, stream_head_destructor, NULL, @@ -904,6 +902,16 @@ strinit(void) * TPI support routine initialisation. */ tpi_init(); + + /* + * Handle to have autopush and persistent link information per + * zone. + * Note: uses shutdown hook instead of destroy hook so that the + * persistent links can be torn down before the destroy hooks + * in the TCP/IP stack are called. + */ + netstack_register(NS_STR, str_stack_init, str_stack_shutdown, + str_stack_fini); } void @@ -1544,7 +1552,7 @@ lbfree(linkinfo_t *linkp) * and 0 otherwise. */ int -linkcycle(stdata_t *upstp, stdata_t *lostp) +linkcycle(stdata_t *upstp, stdata_t *lostp, str_stack_t *ss) { struct mux_node *np; struct mux_edge *ep; @@ -1558,13 +1566,13 @@ linkcycle(stdata_t *upstp, stdata_t *lostp) if (lostp->sd_vnode->v_type == VFIFO) return (0); - for (i = 0; i < devcnt; i++) { - np = &mux_nodes[i]; + for (i = 0; i < ss->ss_devcnt; i++) { + np = &ss->ss_mux_nodes[i]; MUX_CLEAR(np); } lomaj = getmajor(lostp->sd_vnode->v_rdev); upmaj = getmajor(upstp->sd_vnode->v_rdev); - np = &mux_nodes[lomaj]; + np = &ss->ss_mux_nodes[lomaj]; for (;;) { if (!MUX_DIDVISIT(np)) { if (np->mn_imaj == upmaj) @@ -1607,7 +1615,7 @@ linkcycle(stdata_t *upstp, stdata_t *lostp) * Find linkinfo entry corresponding to the parameters. */ linkinfo_t * -findlinks(stdata_t *stp, int index, int type) +findlinks(stdata_t *stp, int index, int type, str_stack_t *ss) { linkinfo_t *linkp; struct mux_edge *mep; @@ -1626,7 +1634,7 @@ findlinks(stdata_t *stp, int index, int type) } } else { ASSERT((type & LINKTYPEMASK) == LINKPERSIST); - mnp = &mux_nodes[getmajor(stp->sd_vnode->v_rdev)]; + mnp = &ss->ss_mux_nodes[getmajor(stp->sd_vnode->v_rdev)]; mep = mnp->mn_outp; while (mep) { if ((index == 0) || (index == mep->me_muxid)) @@ -1724,6 +1732,8 @@ mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, uint32_t sqtype; perdm_t *dmp; int error = 0; + netstack_t *ns; + str_stack_t *ss; stp = vp->v_stream; TRACE_1(TR_FAC_STREAMS_FR, @@ -1746,12 +1756,19 @@ mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, if (fpdown == NULL) { return (EBADF); } - if (getmajor(stp->sd_vnode->v_rdev) >= devcnt) { + ns = netstack_find_by_cred(crp); + ASSERT(ns != NULL); + ss = ns->netstack_str; + ASSERT(ss != NULL); + + if (getmajor(stp->sd_vnode->v_rdev) >= ss->ss_devcnt) { + netstack_rele(ss->ss_netstack); return (EINVAL); } mutex_enter(&muxifier); if (stp->sd_flag & STPLEX) { mutex_exit(&muxifier); + netstack_rele(ss->ss_netstack); return (ENXIO); } @@ -1767,9 +1784,10 @@ mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, (stpdown == stp) || (stpdown->sd_flag & (STPLEX|STRHUP|STRDERR|STWRERR|IOCWAIT|STRPLUMB)) || ((stpdown->sd_vnode->v_type != VFIFO) && - (getmajor(stpdown->sd_vnode->v_rdev) >= devcnt)) || - linkcycle(stp, stpdown)) { + (getmajor(stpdown->sd_vnode->v_rdev) >= ss->ss_devcnt)) || + linkcycle(stp, stpdown, ss)) { mutex_exit(&muxifier); + netstack_rele(ss->ss_netstack); return (EINVAL); } TRACE_1(TR_FAC_STREAMS_FR, @@ -1899,6 +1917,7 @@ mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, mutex_exit(&stpdown->sd_lock); mutex_exit(&muxifier); + netstack_rele(ss->ss_netstack); return (error); } mutex_enter(&fpdown->f_tlock); @@ -1919,7 +1938,7 @@ mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, link_rempassthru(passq); - mux_addedge(stp, stpdown, linkp->li_lblk.l_index); + mux_addedge(stp, stpdown, linkp->li_lblk.l_index, ss); /* * Mark the upper stream as having dependent links @@ -1944,6 +1963,7 @@ mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, mutex_exit(&stpdown->sd_lock); mutex_exit(&muxifier); *rvalp = linkp->li_lblk.l_index; + netstack_rele(ss->ss_netstack); return (0); } @@ -1979,7 +1999,8 @@ mlink(vnode_t *vp, int cmd, int arg, cred_t *crp, int *rvalp, int lhlink) * re-blocked. */ int -munlink(stdata_t *stp, linkinfo_t *linkp, int flag, cred_t *crp, int *rvalp) +munlink(stdata_t *stp, linkinfo_t *linkp, int flag, cred_t *crp, int *rvalp, + str_stack_t *ss) { struct strioctl strioc; struct stdata *stpdown; @@ -2037,7 +2058,7 @@ munlink(stdata_t *stp, linkinfo_t *linkp, int flag, cred_t *crp, int *rvalp) } } - mux_rmvedge(stp, linkp->li_lblk.l_index); + mux_rmvedge(stp, linkp->li_lblk.l_index, ss); fpdown = linkp->li_fpdown; lbfree(linkp); @@ -2225,17 +2246,17 @@ munlink(stdata_t *stp, linkinfo_t *linkp, int flag, cred_t *crp, int *rvalp) * Return 0, or a non-zero errno on failure. */ int -munlinkall(stdata_t *stp, int flag, cred_t *crp, int *rvalp) +munlinkall(stdata_t *stp, int flag, cred_t *crp, int *rvalp, str_stack_t *ss) { linkinfo_t *linkp; int error = 0; mutex_enter(&muxifier); - while (linkp = findlinks(stp, 0, flag)) { + while (linkp = findlinks(stp, 0, flag, ss)) { /* * munlink() releases the muxifier lock. */ - if (error = munlink(stp, linkp, flag, crp, rvalp)) + if (error = munlink(stp, linkp, flag, crp, rvalp, ss)) return (error); mutex_enter(&muxifier); } @@ -2248,7 +2269,7 @@ munlinkall(stdata_t *stp, int flag, cred_t *crp, int *rvalp) * edge to the directed graph. */ void -mux_addedge(stdata_t *upstp, stdata_t *lostp, int muxid) +mux_addedge(stdata_t *upstp, stdata_t *lostp, int muxid, str_stack_t *ss) { struct mux_node *np; struct mux_edge *ep; @@ -2257,7 +2278,7 @@ mux_addedge(stdata_t *upstp, stdata_t *lostp, int muxid) upmaj = getmajor(upstp->sd_vnode->v_rdev); lomaj = getmajor(lostp->sd_vnode->v_rdev); - np = &mux_nodes[upmaj]; + np = &ss->ss_mux_nodes[upmaj]; if (np->mn_outp) { ep = np->mn_outp; while (ep->me_nextp) @@ -2270,10 +2291,18 @@ mux_addedge(stdata_t *upstp, stdata_t *lostp, int muxid) } ep->me_nextp = NULL; ep->me_muxid = muxid; + /* + * Save the dev_t for the purposes of str_stack_shutdown. + * str_stack_shutdown assumes that the device allows reopen, since + * this dev_t is the one after any cloning by xx_open(). + * Would prefer finding the dev_t from before any cloning, + * but specfs doesn't retain that. + */ + ep->me_dev = upstp->sd_vnode->v_rdev; if (lostp->sd_vnode->v_type == VFIFO) ep->me_nodep = NULL; else - ep->me_nodep = &mux_nodes[lomaj]; + ep->me_nodep = &ss->ss_mux_nodes[lomaj]; } /* @@ -2281,7 +2310,7 @@ mux_addedge(stdata_t *upstp, stdata_t *lostp, int muxid) * edge in the directed graph. */ void -mux_rmvedge(stdata_t *upstp, int muxid) +mux_rmvedge(stdata_t *upstp, int muxid, str_stack_t *ss) { struct mux_node *np; struct mux_edge *ep; @@ -2289,7 +2318,7 @@ mux_rmvedge(stdata_t *upstp, int muxid) major_t upmaj; upmaj = getmajor(upstp->sd_vnode->v_rdev); - np = &mux_nodes[upmaj]; + np = &ss->ss_mux_nodes[upmaj]; ASSERT(np->mn_outp != NULL); ep = np->mn_outp; while (ep) { @@ -4057,9 +4086,11 @@ backenable(queue_t *q, uchar_t pri) * or with the stream frozen (the latter occurs when a module * calls rmvq with the stream frozen.) If the stream is frozen * by the caller the caller will hold all qlocks in the stream. + * Note that a frozen stream doesn't freeze a mated stream, + * so we explicitly check for that. */ freezer = STREAM(q)->sd_freezer; - if (freezer != curthread) { + if (freezer != curthread || STREAM(q) != STREAM(nq)) { mutex_enter(QLOCK(nq)); } #ifdef DEBUG @@ -4071,7 +4102,7 @@ backenable(queue_t *q, uchar_t pri) #endif setqback(nq, pri); qenable_locked(nq); - if (freezer != curthread) + if (freezer != curthread || STREAM(q) != STREAM(nq)) mutex_exit(QLOCK(nq)); } releasestr(q); @@ -8464,3 +8495,103 @@ void queuerun(void) { } + +/* + * Initialize the STR stack instance, which tracks autopush and persistent + * links. + */ +/* ARGSUSED */ +static void * +str_stack_init(netstackid_t stackid, netstack_t *ns) +{ + str_stack_t *ss; + int i; + + ss = (str_stack_t *)kmem_zalloc(sizeof (*ss), KM_SLEEP); + ss->ss_netstack = ns; + + /* + * set up autopush + */ + sad_initspace(ss); + + /* + * set up mux_node structures. + */ + ss->ss_devcnt = devcnt; /* In case it should change before free */ + ss->ss_mux_nodes = kmem_zalloc((sizeof (struct mux_node) * + ss->ss_devcnt), KM_SLEEP); + for (i = 0; i < ss->ss_devcnt; i++) + ss->ss_mux_nodes[i].mn_imaj = i; + return (ss); +} + +/* + * Note: run at zone shutdown and not destroy so that the PLINKs are + * gone by the time other cleanup happens from the destroy callbacks. + */ +static void +str_stack_shutdown(netstackid_t stackid, void *arg) +{ + str_stack_t *ss = (str_stack_t *)arg; + int i; + cred_t *cr; + + cr = zone_get_kcred(netstackid_to_zoneid(stackid)); + ASSERT(cr != NULL); + + /* Undo all the I_PLINKs for this zone */ + for (i = 0; i < ss->ss_devcnt; i++) { + struct mux_edge *ep; + ldi_handle_t lh; + ldi_ident_t li; + int ret; + int rval; + dev_t rdev; + + ep = ss->ss_mux_nodes[i].mn_outp; + if (ep == NULL) + continue; + ret = ldi_ident_from_major((major_t)i, &li); + if (ret != 0) { + continue; + } + rdev = ep->me_dev; + ret = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD|FWRITE, + cr, &lh, li); + if (ret != 0) { + ldi_ident_release(li); + continue; + } + + ret = ldi_ioctl(lh, I_PUNLINK, (intptr_t)MUXID_ALL, FKIOCTL, + cr, &rval); + if (ret) { + (void) ldi_close(lh, FREAD|FWRITE, cr); + ldi_ident_release(li); + continue; + } + (void) ldi_close(lh, FREAD|FWRITE, cr); + + /* Close layered handles */ + ldi_ident_release(li); + } + crfree(cr); + + sad_freespace(ss); + + kmem_free(ss->ss_mux_nodes, sizeof (struct mux_node) * ss->ss_devcnt); + ss->ss_mux_nodes = NULL; +} + +/* + * Free the structure; str_stack_shutdown did the other cleanup work. + */ +/* ARGSUSED */ +static void +str_stack_fini(netstackid_t stackid, void *arg) +{ + str_stack_t *ss = (str_stack_t *)arg; + + kmem_free(ss, sizeof (*ss)); +} |