17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5989ae01eSgeorges * Common Development and Distribution License (the "License"). 6989ae01eSgeorges * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 227c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 237c478bd9Sstevel@tonic-gate 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 261908fb0eSRoamer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 277c478bd9Sstevel@tonic-gate * Use is subject to license terms. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/errno.h> 347c478bd9Sstevel@tonic-gate #include <sys/signal.h> 357c478bd9Sstevel@tonic-gate #include <sys/proc.h> 367c478bd9Sstevel@tonic-gate #include <sys/conf.h> 377c478bd9Sstevel@tonic-gate #include <sys/cred.h> 387c478bd9Sstevel@tonic-gate #include <sys/user.h> 397c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 407c478bd9Sstevel@tonic-gate #include <sys/file.h> 417c478bd9Sstevel@tonic-gate #include <sys/session.h> 427c478bd9Sstevel@tonic-gate #include <sys/stream.h> 437c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 447c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 457c478bd9Sstevel@tonic-gate #include <sys/poll.h> 467c478bd9Sstevel@tonic-gate #include <sys/systm.h> 477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 487c478bd9Sstevel@tonic-gate #include <sys/uio.h> 497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 507c478bd9Sstevel@tonic-gate #include <sys/priocntl.h> 517c478bd9Sstevel@tonic-gate #include <sys/procset.h> 527c478bd9Sstevel@tonic-gate #include <sys/vmem.h> 537c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 547c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 557c478bd9Sstevel@tonic-gate #include <sys/siginfo.h> 567c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 577c478bd9Sstevel@tonic-gate #include <sys/callb.h> 587c478bd9Sstevel@tonic-gate #include <sys/debug.h> 597c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 607c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 617c478bd9Sstevel@tonic-gate #include <vm/page.h> 627c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 637c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 647c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 657c478bd9Sstevel@tonic-gate #include <sys/promif.h> 667c478bd9Sstevel@tonic-gate #include <sys/project.h> 677c478bd9Sstevel@tonic-gate #include <sys/vm.h> 687c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 697c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 707c478bd9Sstevel@tonic-gate #include <sys/sunldi_impl.h> 717c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 727c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 737c478bd9Sstevel@tonic-gate #include <sys/multidata.h> 747c478bd9Sstevel@tonic-gate #include <sys/pattr.h> 757c478bd9Sstevel@tonic-gate #include <sys/strft.h> 76ad1660d0Smeem #include <sys/fs/snode.h> 777c478bd9Sstevel@tonic-gate #include <sys/zone.h> 78f4b3ec61Sdh155122 #include <sys/open.h> 79f4b3ec61Sdh155122 #include <sys/sunldi.h> 80f4b3ec61Sdh155122 #include <sys/sad.h> 81f4b3ec61Sdh155122 #include <sys/netstack.h> 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define O_SAMESTR(q) (((q)->q_next) && \ 847c478bd9Sstevel@tonic-gate (((q)->q_flag & QREADR) == ((q)->q_next->q_flag & QREADR))) 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * WARNING: 887c478bd9Sstevel@tonic-gate * The variables and routines in this file are private, belonging 897c478bd9Sstevel@tonic-gate * to the STREAMS subsystem. These should not be used by modules 907c478bd9Sstevel@tonic-gate * or drivers. Compatibility will not be guaranteed. 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * Id value used to distinguish between different multiplexor links. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static int32_t lnk_id = 0; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate #define STREAMS_LOPRI MINCLSYSPRI 997c478bd9Sstevel@tonic-gate static pri_t streams_lopri = STREAMS_LOPRI; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate #define STRSTAT(x) (str_statistics.x.value.ui64++) 1027c478bd9Sstevel@tonic-gate typedef struct str_stat { 1037c478bd9Sstevel@tonic-gate kstat_named_t sqenables; 1047c478bd9Sstevel@tonic-gate kstat_named_t stenables; 1057c478bd9Sstevel@tonic-gate kstat_named_t syncqservice; 1067c478bd9Sstevel@tonic-gate kstat_named_t freebs; 1077c478bd9Sstevel@tonic-gate kstat_named_t qwr_outer; 1087c478bd9Sstevel@tonic-gate kstat_named_t rservice; 1097c478bd9Sstevel@tonic-gate kstat_named_t strwaits; 1107c478bd9Sstevel@tonic-gate kstat_named_t taskqfails; 1117c478bd9Sstevel@tonic-gate kstat_named_t bufcalls; 1127c478bd9Sstevel@tonic-gate kstat_named_t qhelps; 1137c478bd9Sstevel@tonic-gate kstat_named_t qremoved; 1147c478bd9Sstevel@tonic-gate kstat_named_t sqremoved; 1157c478bd9Sstevel@tonic-gate kstat_named_t bcwaits; 1167c478bd9Sstevel@tonic-gate kstat_named_t sqtoomany; 1177c478bd9Sstevel@tonic-gate } str_stat_t; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate static str_stat_t str_statistics = { 1207c478bd9Sstevel@tonic-gate { "sqenables", KSTAT_DATA_UINT64 }, 1217c478bd9Sstevel@tonic-gate { "stenables", KSTAT_DATA_UINT64 }, 1227c478bd9Sstevel@tonic-gate { "syncqservice", KSTAT_DATA_UINT64 }, 1237c478bd9Sstevel@tonic-gate { "freebs", KSTAT_DATA_UINT64 }, 1247c478bd9Sstevel@tonic-gate { "qwr_outer", KSTAT_DATA_UINT64 }, 1257c478bd9Sstevel@tonic-gate { "rservice", KSTAT_DATA_UINT64 }, 1267c478bd9Sstevel@tonic-gate { "strwaits", KSTAT_DATA_UINT64 }, 1277c478bd9Sstevel@tonic-gate { "taskqfails", KSTAT_DATA_UINT64 }, 1287c478bd9Sstevel@tonic-gate { "bufcalls", KSTAT_DATA_UINT64 }, 1297c478bd9Sstevel@tonic-gate { "qhelps", KSTAT_DATA_UINT64 }, 1307c478bd9Sstevel@tonic-gate { "qremoved", KSTAT_DATA_UINT64 }, 1317c478bd9Sstevel@tonic-gate { "sqremoved", KSTAT_DATA_UINT64 }, 1327c478bd9Sstevel@tonic-gate { "bcwaits", KSTAT_DATA_UINT64 }, 1337c478bd9Sstevel@tonic-gate { "sqtoomany", KSTAT_DATA_UINT64 }, 1347c478bd9Sstevel@tonic-gate }; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate static kstat_t *str_kstat; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * qrunflag was used previously to control background scheduling of queues. It 1407c478bd9Sstevel@tonic-gate * is not used anymore, but kept here in case some module still wants to access 1417c478bd9Sstevel@tonic-gate * it via qready() and setqsched macros. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate char qrunflag; /* Unused */ 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * Most of the streams scheduling is done via task queues. Task queues may fail 1477c478bd9Sstevel@tonic-gate * for non-sleep dispatches, so there are two backup threads servicing failed 1487c478bd9Sstevel@tonic-gate * requests for queues and syncqs. Both of these threads also service failed 1497c478bd9Sstevel@tonic-gate * dispatches freebs requests. Queues are put in the list specified by `qhead' 1507c478bd9Sstevel@tonic-gate * and `qtail' pointers, syncqs use `sqhead' and `sqtail' pointers and freebs 1517c478bd9Sstevel@tonic-gate * requests are put into `freebs_list' which has no tail pointer. All three 1527c478bd9Sstevel@tonic-gate * lists are protected by a single `service_queue' lock and use 1537c478bd9Sstevel@tonic-gate * `services_to_run' condition variable for signaling background threads. Use of 1547c478bd9Sstevel@tonic-gate * a single lock should not be a problem because it is only used under heavy 1557c478bd9Sstevel@tonic-gate * loads when task queues start to fail and at that time it may be a good idea 1567c478bd9Sstevel@tonic-gate * to throttle scheduling requests. 1577c478bd9Sstevel@tonic-gate * 1587c478bd9Sstevel@tonic-gate * NOTE: queues and syncqs should be scheduled by two separate threads because 1597c478bd9Sstevel@tonic-gate * queue servicing may be blocked waiting for a syncq which may be also 1607c478bd9Sstevel@tonic-gate * scheduled for background execution. This may create a deadlock when only one 1617c478bd9Sstevel@tonic-gate * thread is used for both. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate static taskq_t *streams_taskq; /* Used for most STREAMS scheduling */ 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static kmutex_t service_queue; /* protects all of servicing vars */ 1677c478bd9Sstevel@tonic-gate static kcondvar_t services_to_run; /* wake up background service thread */ 1687c478bd9Sstevel@tonic-gate static kcondvar_t syncqs_to_run; /* wake up background service thread */ 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 17121804b56SBrian Ruthven * List of queues scheduled for background processing due to lack of resources 1727c478bd9Sstevel@tonic-gate * in the task queues. Protected by service_queue lock; 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static struct queue *qhead; 1757c478bd9Sstevel@tonic-gate static struct queue *qtail; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * Same list for syncqs 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate static syncq_t *sqhead; 1817c478bd9Sstevel@tonic-gate static syncq_t *sqtail; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate static mblk_t *freebs_list; /* list of buffers to free */ 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * Backup threads for servicing queues and syncqs 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate kthread_t *streams_qbkgrnd_thread; 1897c478bd9Sstevel@tonic-gate kthread_t *streams_sqbkgrnd_thread; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Bufcalls related variables. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate struct bclist strbcalls; /* list of waiting bufcalls */ 1957c478bd9Sstevel@tonic-gate kmutex_t strbcall_lock; /* protects bufcall list (strbcalls) */ 1967c478bd9Sstevel@tonic-gate kcondvar_t strbcall_cv; /* Signaling when a bufcall is added */ 1977c478bd9Sstevel@tonic-gate kmutex_t bcall_monitor; /* sleep/wakeup style monitor */ 1987c478bd9Sstevel@tonic-gate kcondvar_t bcall_cv; /* wait 'till executing bufcall completes */ 1997c478bd9Sstevel@tonic-gate kthread_t *bc_bkgrnd_thread; /* Thread to service bufcall requests */ 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate kmutex_t strresources; /* protects global resources */ 2027c478bd9Sstevel@tonic-gate kmutex_t muxifier; /* single-threads multiplexor creation */ 2037c478bd9Sstevel@tonic-gate 204f4b3ec61Sdh155122 static void *str_stack_init(netstackid_t stackid, netstack_t *ns); 205f4b3ec61Sdh155122 static void str_stack_shutdown(netstackid_t stackid, void *arg); 206f4b3ec61Sdh155122 static void str_stack_fini(netstackid_t stackid, void *arg); 207f4b3ec61Sdh155122 2087c478bd9Sstevel@tonic-gate /* 20921804b56SBrian Ruthven * run_queues is no longer used, but is kept in case some 3rd party 2107c478bd9Sstevel@tonic-gate * module/driver decides to use it. 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate int run_queues = 0; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * sq_max_size is the depth of the syncq (in number of messages) before 2167c478bd9Sstevel@tonic-gate * qfill_syncq() starts QFULL'ing destination queues. As its primary 2177c478bd9Sstevel@tonic-gate * consumer - IP is no longer D_MTPERMOD, but there may be other 2187c478bd9Sstevel@tonic-gate * modules/drivers depend on this syncq flow control, we prefer to 2197c478bd9Sstevel@tonic-gate * choose a large number as the default value. For potential 2207c478bd9Sstevel@tonic-gate * performance gain, this value is tunable in /etc/system. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate int sq_max_size = 10000; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 22521804b56SBrian Ruthven * The number of ciputctrl structures per syncq and stream we create when 2267c478bd9Sstevel@tonic-gate * needed. 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate int n_ciputctrl; 2297c478bd9Sstevel@tonic-gate int max_n_ciputctrl = 16; 2307c478bd9Sstevel@tonic-gate /* 23121804b56SBrian Ruthven * If n_ciputctrl is < min_n_ciputctrl don't even create ciputctrl_cache. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate int min_n_ciputctrl = 2; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Per-driver/module syncqs 2377c478bd9Sstevel@tonic-gate * ======================== 2387c478bd9Sstevel@tonic-gate * 2397c478bd9Sstevel@tonic-gate * For drivers/modules that use PERMOD or outer syncqs we keep a list of 2407c478bd9Sstevel@tonic-gate * perdm structures, new entries being added (and new syncqs allocated) when 2417c478bd9Sstevel@tonic-gate * setq() encounters a module/driver with a streamtab that it hasn't seen 2427c478bd9Sstevel@tonic-gate * before. 2437c478bd9Sstevel@tonic-gate * The reason for this mechanism is that some modules and drivers share a 2447c478bd9Sstevel@tonic-gate * common streamtab and it is necessary for those modules and drivers to also 2457c478bd9Sstevel@tonic-gate * share a common PERMOD syncq. 2467c478bd9Sstevel@tonic-gate * 2477c478bd9Sstevel@tonic-gate * perdm_list --> dm_str == streamtab_1 2487c478bd9Sstevel@tonic-gate * dm_sq == syncq_1 2497c478bd9Sstevel@tonic-gate * dm_ref 2507c478bd9Sstevel@tonic-gate * dm_next --> dm_str == streamtab_2 2517c478bd9Sstevel@tonic-gate * dm_sq == syncq_2 2527c478bd9Sstevel@tonic-gate * dm_ref 2537c478bd9Sstevel@tonic-gate * dm_next --> ... NULL 2547c478bd9Sstevel@tonic-gate * 2557c478bd9Sstevel@tonic-gate * The dm_ref field is incremented for each new driver/module that takes 2567c478bd9Sstevel@tonic-gate * a reference to the perdm structure and hence shares the syncq. 2577c478bd9Sstevel@tonic-gate * References are held in the fmodsw_impl_t structure for each STREAMS module 2587c478bd9Sstevel@tonic-gate * or the dev_impl array (indexed by device major number) for each driver. 2597c478bd9Sstevel@tonic-gate * 2607c478bd9Sstevel@tonic-gate * perdm_list -> [dm_ref == 1] -> [dm_ref == 2] -> [dm_ref == 1] -> NULL 2617c478bd9Sstevel@tonic-gate * ^ ^ ^ ^ 2627c478bd9Sstevel@tonic-gate * | ______________/ | | 2637c478bd9Sstevel@tonic-gate * | / | | 2647c478bd9Sstevel@tonic-gate * dev_impl: ...|x|y|... module A module B 2657c478bd9Sstevel@tonic-gate * 2667c478bd9Sstevel@tonic-gate * When a module/driver is unloaded the reference count is decremented and, 2677c478bd9Sstevel@tonic-gate * when it falls to zero, the perdm structure is removed from the list and 2687c478bd9Sstevel@tonic-gate * the syncq is freed (see rele_dm()). 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate perdm_t *perdm_list = NULL; 2717c478bd9Sstevel@tonic-gate static krwlock_t perdm_rwlock; 2727c478bd9Sstevel@tonic-gate cdevsw_impl_t *devimpl; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate extern struct qinit strdata; 2757c478bd9Sstevel@tonic-gate extern struct qinit stwdata; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate static void runservice(queue_t *); 2787c478bd9Sstevel@tonic-gate static void streams_bufcall_service(void); 2797c478bd9Sstevel@tonic-gate static void streams_qbkgrnd_service(void); 2807c478bd9Sstevel@tonic-gate static void streams_sqbkgrnd_service(void); 2817c478bd9Sstevel@tonic-gate static syncq_t *new_syncq(void); 2827c478bd9Sstevel@tonic-gate static void free_syncq(syncq_t *); 2837c478bd9Sstevel@tonic-gate static void outer_insert(syncq_t *, syncq_t *); 2847c478bd9Sstevel@tonic-gate static void outer_remove(syncq_t *, syncq_t *); 2857c478bd9Sstevel@tonic-gate static void write_now(syncq_t *); 2867c478bd9Sstevel@tonic-gate static void clr_qfull(queue_t *); 2877c478bd9Sstevel@tonic-gate static void runbufcalls(void); 2887c478bd9Sstevel@tonic-gate static void sqenable(syncq_t *); 2897c478bd9Sstevel@tonic-gate static void sqfill_events(syncq_t *, queue_t *, mblk_t *, void (*)()); 2907c478bd9Sstevel@tonic-gate static void wait_q_syncq(queue_t *); 291116094b2Smicheng static void backenable_insertedq(queue_t *); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate static void queue_service(queue_t *); 2947c478bd9Sstevel@tonic-gate static void stream_service(stdata_t *); 2957c478bd9Sstevel@tonic-gate static void syncq_service(syncq_t *); 2967c478bd9Sstevel@tonic-gate static void qwriter_outer_service(syncq_t *); 2977c478bd9Sstevel@tonic-gate static void mblk_free(mblk_t *); 2987c478bd9Sstevel@tonic-gate #ifdef DEBUG 2997c478bd9Sstevel@tonic-gate static int qprocsareon(queue_t *); 3007c478bd9Sstevel@tonic-gate #endif 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate static void set_nfsrv_ptr(queue_t *, queue_t *, queue_t *, queue_t *); 3037c478bd9Sstevel@tonic-gate static void reset_nfsrv_ptr(queue_t *, queue_t *); 3045ba3fab4Sjk115741 void set_qfull(queue_t *); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate static void sq_run_events(syncq_t *); 3077c478bd9Sstevel@tonic-gate static int propagate_syncq(queue_t *); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate static void blocksq(syncq_t *, ushort_t, int); 3107c478bd9Sstevel@tonic-gate static void unblocksq(syncq_t *, ushort_t, int); 3117c478bd9Sstevel@tonic-gate static int dropsq(syncq_t *, uint16_t); 3127c478bd9Sstevel@tonic-gate static void emptysq(syncq_t *); 3137c478bd9Sstevel@tonic-gate static sqlist_t *sqlist_alloc(struct stdata *, int); 3147c478bd9Sstevel@tonic-gate static void sqlist_free(sqlist_t *); 3157c478bd9Sstevel@tonic-gate static sqlist_t *sqlist_build(queue_t *, struct stdata *, boolean_t); 3167c478bd9Sstevel@tonic-gate static void sqlist_insert(sqlist_t *, syncq_t *); 3177c478bd9Sstevel@tonic-gate static void sqlist_insertall(sqlist_t *, queue_t *); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate static void strsetuio(stdata_t *); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate struct kmem_cache *stream_head_cache; 3227c478bd9Sstevel@tonic-gate struct kmem_cache *queue_cache; 3237c478bd9Sstevel@tonic-gate struct kmem_cache *syncq_cache; 3247c478bd9Sstevel@tonic-gate struct kmem_cache *qband_cache; 3257c478bd9Sstevel@tonic-gate struct kmem_cache *linkinfo_cache; 3267c478bd9Sstevel@tonic-gate struct kmem_cache *ciputctrl_cache = NULL; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate static linkinfo_t *linkinfo_list; 3297c478bd9Sstevel@tonic-gate 33021804b56SBrian Ruthven /* Global esballoc throttling queue */ 331e7d4b76fSss146032 static esb_queue_t system_esbq; 332e7d4b76fSss146032 333f4aaef0bSDavid Plauger /* Array of esballoc throttling queues, of length esbq_nelem */ 334f4aaef0bSDavid Plauger static esb_queue_t *volatile system_esbq_array; 335f4aaef0bSDavid Plauger static int esbq_nelem; 336f4aaef0bSDavid Plauger static kmutex_t esbq_lock; 337f4aaef0bSDavid Plauger static int esbq_log2_cpus_per_q = 0; 338f4aaef0bSDavid Plauger 339f4aaef0bSDavid Plauger /* Scale the system_esbq length by setting number of CPUs per queue. */ 340f4aaef0bSDavid Plauger uint_t esbq_cpus_per_q = 1; 341f4aaef0bSDavid Plauger 342e7d4b76fSss146032 /* 343e7d4b76fSss146032 * esballoc tunable parameters. 344e7d4b76fSss146032 */ 345e7d4b76fSss146032 int esbq_max_qlen = 0x16; /* throttled queue length */ 346e7d4b76fSss146032 clock_t esbq_timeout = 0x8; /* timeout to process esb queue */ 347e7d4b76fSss146032 348e7d4b76fSss146032 /* 34921804b56SBrian Ruthven * Routines to handle esballoc queueing. 350e7d4b76fSss146032 */ 351e7d4b76fSss146032 static void esballoc_process_queue(esb_queue_t *); 352e7d4b76fSss146032 static void esballoc_enqueue_mblk(mblk_t *); 353e7d4b76fSss146032 static void esballoc_timer(void *); 354e7d4b76fSss146032 static void esballoc_set_timer(esb_queue_t *, clock_t); 355e7d4b76fSss146032 static void esballoc_mblk_free(mblk_t *); 356e7d4b76fSss146032 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * Qinit structure and Module_info structures 3597c478bd9Sstevel@tonic-gate * for passthru read and write queues 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate static void pass_wput(queue_t *, mblk_t *); 3637c478bd9Sstevel@tonic-gate static queue_t *link_addpassthru(stdata_t *); 3647c478bd9Sstevel@tonic-gate static void link_rempassthru(queue_t *); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate struct module_info passthru_info = { 3677c478bd9Sstevel@tonic-gate 0, 3687c478bd9Sstevel@tonic-gate "passthru", 3697c478bd9Sstevel@tonic-gate 0, 3707c478bd9Sstevel@tonic-gate INFPSZ, 3717c478bd9Sstevel@tonic-gate STRHIGH, 3727c478bd9Sstevel@tonic-gate STRLOW 3737c478bd9Sstevel@tonic-gate }; 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate struct qinit passthru_rinit = { 3767c478bd9Sstevel@tonic-gate (int (*)())putnext, 3777c478bd9Sstevel@tonic-gate NULL, 3787c478bd9Sstevel@tonic-gate NULL, 3797c478bd9Sstevel@tonic-gate NULL, 3807c478bd9Sstevel@tonic-gate NULL, 3817c478bd9Sstevel@tonic-gate &passthru_info, 3827c478bd9Sstevel@tonic-gate NULL 3837c478bd9Sstevel@tonic-gate }; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate struct qinit passthru_winit = { 3867c478bd9Sstevel@tonic-gate (int (*)()) pass_wput, 3877c478bd9Sstevel@tonic-gate NULL, 3887c478bd9Sstevel@tonic-gate NULL, 3897c478bd9Sstevel@tonic-gate NULL, 3907c478bd9Sstevel@tonic-gate NULL, 3917c478bd9Sstevel@tonic-gate &passthru_info, 3927c478bd9Sstevel@tonic-gate NULL 3937c478bd9Sstevel@tonic-gate }; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Verify correctness of list head/tail pointers. 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate #define LISTCHECK(head, tail, link) { \ 3997c478bd9Sstevel@tonic-gate EQUIV(head, tail); \ 4007c478bd9Sstevel@tonic-gate IMPLY(tail != NULL, tail->link == NULL); \ 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * Enqueue a list element `el' in the end of a list denoted by `head' and `tail' 4057c478bd9Sstevel@tonic-gate * using a `link' field. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate #define ENQUEUE(el, head, tail, link) { \ 4087c478bd9Sstevel@tonic-gate ASSERT(el->link == NULL); \ 4097c478bd9Sstevel@tonic-gate LISTCHECK(head, tail, link); \ 4107c478bd9Sstevel@tonic-gate if (head == NULL) \ 4117c478bd9Sstevel@tonic-gate head = el; \ 4127c478bd9Sstevel@tonic-gate else \ 4137c478bd9Sstevel@tonic-gate tail->link = el; \ 4147c478bd9Sstevel@tonic-gate tail = el; \ 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * Dequeue the first element of the list denoted by `head' and `tail' pointers 4197c478bd9Sstevel@tonic-gate * using a `link' field and put result into `el'. 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate #define DQ(el, head, tail, link) { \ 4227c478bd9Sstevel@tonic-gate LISTCHECK(head, tail, link); \ 4237c478bd9Sstevel@tonic-gate el = head; \ 4247c478bd9Sstevel@tonic-gate if (head != NULL) { \ 4257c478bd9Sstevel@tonic-gate head = head->link; \ 4267c478bd9Sstevel@tonic-gate if (head == NULL) \ 4277c478bd9Sstevel@tonic-gate tail = NULL; \ 4287c478bd9Sstevel@tonic-gate el->link = NULL; \ 4297c478bd9Sstevel@tonic-gate } \ 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Remove `el' from the list using `chase' and `curr' pointers and return result 4347c478bd9Sstevel@tonic-gate * in `succeed'. 4357c478bd9Sstevel@tonic-gate */ 4367c478bd9Sstevel@tonic-gate #define RMQ(el, head, tail, link, chase, curr, succeed) { \ 4377c478bd9Sstevel@tonic-gate LISTCHECK(head, tail, link); \ 4387c478bd9Sstevel@tonic-gate chase = NULL; \ 4397c478bd9Sstevel@tonic-gate succeed = 0; \ 4407c478bd9Sstevel@tonic-gate for (curr = head; (curr != el) && (curr != NULL); curr = curr->link) \ 4417c478bd9Sstevel@tonic-gate chase = curr; \ 4427c478bd9Sstevel@tonic-gate if (curr != NULL) { \ 4437c478bd9Sstevel@tonic-gate succeed = 1; \ 4447c478bd9Sstevel@tonic-gate ASSERT(curr == el); \ 4457c478bd9Sstevel@tonic-gate if (chase != NULL) \ 4467c478bd9Sstevel@tonic-gate chase->link = curr->link; \ 4477c478bd9Sstevel@tonic-gate else \ 4487c478bd9Sstevel@tonic-gate head = curr->link; \ 4497c478bd9Sstevel@tonic-gate curr->link = NULL; \ 4507c478bd9Sstevel@tonic-gate if (curr == tail) \ 4517c478bd9Sstevel@tonic-gate tail = chase; \ 4527c478bd9Sstevel@tonic-gate } \ 4537c478bd9Sstevel@tonic-gate LISTCHECK(head, tail, link); \ 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* Handling of delayed messages on the inner syncq. */ 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate /* 4597c478bd9Sstevel@tonic-gate * DEBUG versions should use function versions (to simplify tracing) and 4607c478bd9Sstevel@tonic-gate * non-DEBUG kernels should use macro versions. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Put a queue on the syncq list of queues. 4657c478bd9Sstevel@tonic-gate * Assumes SQLOCK held. 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate #define SQPUT_Q(sq, qp) \ 4687c478bd9Sstevel@tonic-gate { \ 4697c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); \ 4707c478bd9Sstevel@tonic-gate if (!(qp->q_sqflags & Q_SQQUEUED)) { \ 4717c478bd9Sstevel@tonic-gate /* The queue should not be linked anywhere */ \ 4727c478bd9Sstevel@tonic-gate ASSERT((qp->q_sqprev == NULL) && (qp->q_sqnext == NULL)); \ 4737c478bd9Sstevel@tonic-gate /* Head and tail may only be NULL simultaneously */ \ 4747c478bd9Sstevel@tonic-gate EQUIV(sq->sq_head, sq->sq_tail); \ 47521804b56SBrian Ruthven /* Queue may be only enqueued on its syncq */ \ 4767c478bd9Sstevel@tonic-gate ASSERT(sq == qp->q_syncq); \ 4777c478bd9Sstevel@tonic-gate /* Check the correctness of SQ_MESSAGES flag */ \ 4787c478bd9Sstevel@tonic-gate EQUIV(sq->sq_head, (sq->sq_flags & SQ_MESSAGES)); \ 4797c478bd9Sstevel@tonic-gate /* Sanity check first/last elements of the list */ \ 4807c478bd9Sstevel@tonic-gate IMPLY(sq->sq_head != NULL, sq->sq_head->q_sqprev == NULL);\ 4817c478bd9Sstevel@tonic-gate IMPLY(sq->sq_tail != NULL, sq->sq_tail->q_sqnext == NULL);\ 4827c478bd9Sstevel@tonic-gate /* \ 4837c478bd9Sstevel@tonic-gate * Sanity check of priority field: empty queue should \ 4847c478bd9Sstevel@tonic-gate * have zero priority \ 4857c478bd9Sstevel@tonic-gate * and nqueues equal to zero. \ 4867c478bd9Sstevel@tonic-gate */ \ 4877c478bd9Sstevel@tonic-gate IMPLY(sq->sq_head == NULL, sq->sq_pri == 0); \ 4887c478bd9Sstevel@tonic-gate /* Sanity check of sq_nqueues field */ \ 4897c478bd9Sstevel@tonic-gate EQUIV(sq->sq_head, sq->sq_nqueues); \ 4907c478bd9Sstevel@tonic-gate if (sq->sq_head == NULL) { \ 4917c478bd9Sstevel@tonic-gate sq->sq_head = sq->sq_tail = qp; \ 4927c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_MESSAGES; \ 4937c478bd9Sstevel@tonic-gate } else if (qp->q_spri == 0) { \ 4947c478bd9Sstevel@tonic-gate qp->q_sqprev = sq->sq_tail; \ 4957c478bd9Sstevel@tonic-gate sq->sq_tail->q_sqnext = qp; \ 4967c478bd9Sstevel@tonic-gate sq->sq_tail = qp; \ 4977c478bd9Sstevel@tonic-gate } else { \ 4987c478bd9Sstevel@tonic-gate /* \ 4997c478bd9Sstevel@tonic-gate * Put this queue in priority order: higher \ 5007c478bd9Sstevel@tonic-gate * priority gets closer to the head. \ 5017c478bd9Sstevel@tonic-gate */ \ 5027c478bd9Sstevel@tonic-gate queue_t **qpp = &sq->sq_tail; \ 5037c478bd9Sstevel@tonic-gate queue_t *qnext = NULL; \ 5047c478bd9Sstevel@tonic-gate \ 5057c478bd9Sstevel@tonic-gate while (*qpp != NULL && qp->q_spri > (*qpp)->q_spri) { \ 5067c478bd9Sstevel@tonic-gate qnext = *qpp; \ 5077c478bd9Sstevel@tonic-gate qpp = &(*qpp)->q_sqprev; \ 5087c478bd9Sstevel@tonic-gate } \ 5097c478bd9Sstevel@tonic-gate qp->q_sqnext = qnext; \ 5107c478bd9Sstevel@tonic-gate qp->q_sqprev = *qpp; \ 5117c478bd9Sstevel@tonic-gate if (*qpp != NULL) { \ 5127c478bd9Sstevel@tonic-gate (*qpp)->q_sqnext = qp; \ 5137c478bd9Sstevel@tonic-gate } else { \ 5147c478bd9Sstevel@tonic-gate sq->sq_head = qp; \ 5157c478bd9Sstevel@tonic-gate sq->sq_pri = sq->sq_head->q_spri; \ 5167c478bd9Sstevel@tonic-gate } \ 5177c478bd9Sstevel@tonic-gate *qpp = qp; \ 5187c478bd9Sstevel@tonic-gate } \ 5197c478bd9Sstevel@tonic-gate qp->q_sqflags |= Q_SQQUEUED; \ 520d3d50737SRafael Vanoni qp->q_sqtstamp = ddi_get_lbolt(); \ 5217c478bd9Sstevel@tonic-gate sq->sq_nqueues++; \ 5227c478bd9Sstevel@tonic-gate } \ 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * Remove a queue from the syncq list 5277c478bd9Sstevel@tonic-gate * Assumes SQLOCK held. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate #define SQRM_Q(sq, qp) \ 5307c478bd9Sstevel@tonic-gate { \ 5317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); \ 5327c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqflags & Q_SQQUEUED); \ 5337c478bd9Sstevel@tonic-gate ASSERT(sq->sq_head != NULL && sq->sq_tail != NULL); \ 5347c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & SQ_MESSAGES) != 0); \ 5357c478bd9Sstevel@tonic-gate /* Check that the queue is actually in the list */ \ 5367c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqnext != NULL || sq->sq_tail == qp); \ 5377c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqprev != NULL || sq->sq_head == qp); \ 5387c478bd9Sstevel@tonic-gate ASSERT(sq->sq_nqueues != 0); \ 5397c478bd9Sstevel@tonic-gate if (qp->q_sqprev == NULL) { \ 5407c478bd9Sstevel@tonic-gate /* First queue on list, make head q_sqnext */ \ 5417c478bd9Sstevel@tonic-gate sq->sq_head = qp->q_sqnext; \ 5427c478bd9Sstevel@tonic-gate } else { \ 5437c478bd9Sstevel@tonic-gate /* Make prev->next == next */ \ 5447c478bd9Sstevel@tonic-gate qp->q_sqprev->q_sqnext = qp->q_sqnext; \ 5457c478bd9Sstevel@tonic-gate } \ 5467c478bd9Sstevel@tonic-gate if (qp->q_sqnext == NULL) { \ 5477c478bd9Sstevel@tonic-gate /* Last queue on list, make tail sqprev */ \ 5487c478bd9Sstevel@tonic-gate sq->sq_tail = qp->q_sqprev; \ 5497c478bd9Sstevel@tonic-gate } else { \ 5507c478bd9Sstevel@tonic-gate /* Make next->prev == prev */ \ 5517c478bd9Sstevel@tonic-gate qp->q_sqnext->q_sqprev = qp->q_sqprev; \ 5527c478bd9Sstevel@tonic-gate } \ 5537c478bd9Sstevel@tonic-gate /* clear out references on this queue */ \ 5547c478bd9Sstevel@tonic-gate qp->q_sqprev = qp->q_sqnext = NULL; \ 5557c478bd9Sstevel@tonic-gate qp->q_sqflags &= ~Q_SQQUEUED; \ 5567c478bd9Sstevel@tonic-gate /* If there is nothing queued, clear SQ_MESSAGES */ \ 5577c478bd9Sstevel@tonic-gate if (sq->sq_head != NULL) { \ 5587c478bd9Sstevel@tonic-gate sq->sq_pri = sq->sq_head->q_spri; \ 5597c478bd9Sstevel@tonic-gate } else { \ 5607c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_MESSAGES; \ 5617c478bd9Sstevel@tonic-gate sq->sq_pri = 0; \ 5627c478bd9Sstevel@tonic-gate } \ 5637c478bd9Sstevel@tonic-gate sq->sq_nqueues--; \ 5647c478bd9Sstevel@tonic-gate ASSERT(sq->sq_head != NULL || sq->sq_evhead != NULL || \ 5657c478bd9Sstevel@tonic-gate (sq->sq_flags & SQ_QUEUED) == 0); \ 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* Hide the definition from the header file. */ 5697c478bd9Sstevel@tonic-gate #ifdef SQPUT_MP 5707c478bd9Sstevel@tonic-gate #undef SQPUT_MP 5717c478bd9Sstevel@tonic-gate #endif 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * Put a message on the queue syncq. 5757c478bd9Sstevel@tonic-gate * Assumes QLOCK held. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate #define SQPUT_MP(qp, mp) \ 5787c478bd9Sstevel@tonic-gate { \ 5797c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(qp))); \ 5807c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqhead == NULL || \ 5817c478bd9Sstevel@tonic-gate (qp->q_sqtail != NULL && \ 5827c478bd9Sstevel@tonic-gate qp->q_sqtail->b_next == NULL)); \ 5837c478bd9Sstevel@tonic-gate qp->q_syncqmsgs++; \ 5847c478bd9Sstevel@tonic-gate ASSERT(qp->q_syncqmsgs != 0); /* Wraparound */ \ 5857c478bd9Sstevel@tonic-gate if (qp->q_sqhead == NULL) { \ 5867c478bd9Sstevel@tonic-gate qp->q_sqhead = qp->q_sqtail = mp; \ 5877c478bd9Sstevel@tonic-gate } else { \ 5887c478bd9Sstevel@tonic-gate qp->q_sqtail->b_next = mp; \ 5897c478bd9Sstevel@tonic-gate qp->q_sqtail = mp; \ 5907c478bd9Sstevel@tonic-gate } \ 5917c478bd9Sstevel@tonic-gate ASSERT(qp->q_syncqmsgs > 0); \ 5925ba3fab4Sjk115741 set_qfull(qp); \ 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate #define SQ_PUTCOUNT_SETFAST_LOCKED(sq) { \ 5967c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); \ 5977c478bd9Sstevel@tonic-gate if ((sq)->sq_ciputctrl != NULL) { \ 5987c478bd9Sstevel@tonic-gate int i; \ 5997c478bd9Sstevel@tonic-gate int nlocks = (sq)->sq_nciputctrl; \ 6007c478bd9Sstevel@tonic-gate ciputctrl_t *cip = (sq)->sq_ciputctrl; \ 6017c478bd9Sstevel@tonic-gate ASSERT((sq)->sq_type & SQ_CIPUT); \ 6027c478bd9Sstevel@tonic-gate for (i = 0; i <= nlocks; i++) { \ 6037c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cip[i].ciputctrl_lock)); \ 6047c478bd9Sstevel@tonic-gate cip[i].ciputctrl_count |= SQ_FASTPUT; \ 6057c478bd9Sstevel@tonic-gate } \ 6067c478bd9Sstevel@tonic-gate } \ 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate #define SQ_PUTCOUNT_CLRFAST_LOCKED(sq) { \ 6117c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); \ 6127c478bd9Sstevel@tonic-gate if ((sq)->sq_ciputctrl != NULL) { \ 6137c478bd9Sstevel@tonic-gate int i; \ 6147c478bd9Sstevel@tonic-gate int nlocks = (sq)->sq_nciputctrl; \ 6157c478bd9Sstevel@tonic-gate ciputctrl_t *cip = (sq)->sq_ciputctrl; \ 6167c478bd9Sstevel@tonic-gate ASSERT((sq)->sq_type & SQ_CIPUT); \ 6177c478bd9Sstevel@tonic-gate for (i = 0; i <= nlocks; i++) { \ 6187c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cip[i].ciputctrl_lock)); \ 6197c478bd9Sstevel@tonic-gate cip[i].ciputctrl_count &= ~SQ_FASTPUT; \ 6207c478bd9Sstevel@tonic-gate } \ 6217c478bd9Sstevel@tonic-gate } \ 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * Run service procedures for all queues in the stream head. 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate #define STR_SERVICE(stp, q) { \ 6287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&stp->sd_qlock)); \ 6297c478bd9Sstevel@tonic-gate while (stp->sd_qhead != NULL) { \ 6307c478bd9Sstevel@tonic-gate DQ(q, stp->sd_qhead, stp->sd_qtail, q_link); \ 6317c478bd9Sstevel@tonic-gate ASSERT(stp->sd_nqueues > 0); \ 6327c478bd9Sstevel@tonic-gate stp->sd_nqueues--; \ 6337c478bd9Sstevel@tonic-gate ASSERT(!(q->q_flag & QINSERVICE)); \ 6347c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_qlock); \ 6357c478bd9Sstevel@tonic-gate queue_service(q); \ 6367c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_qlock); \ 6377c478bd9Sstevel@tonic-gate } \ 6387c478bd9Sstevel@tonic-gate ASSERT(stp->sd_nqueues == 0); \ 6397c478bd9Sstevel@tonic-gate ASSERT((stp->sd_qhead == NULL) && (stp->sd_qtail == NULL)); \ 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* 64321804b56SBrian Ruthven * Constructor/destructor routines for the stream head cache 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6467c478bd9Sstevel@tonic-gate static int 6477c478bd9Sstevel@tonic-gate stream_head_constructor(void *buf, void *cdrarg, int kmflags) 6487c478bd9Sstevel@tonic-gate { 6497c478bd9Sstevel@tonic-gate stdata_t *stp = buf; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate mutex_init(&stp->sd_lock, NULL, MUTEX_DEFAULT, NULL); 6527c478bd9Sstevel@tonic-gate mutex_init(&stp->sd_reflock, NULL, MUTEX_DEFAULT, NULL); 6537c478bd9Sstevel@tonic-gate mutex_init(&stp->sd_qlock, NULL, MUTEX_DEFAULT, NULL); 6547c478bd9Sstevel@tonic-gate cv_init(&stp->sd_monitor, NULL, CV_DEFAULT, NULL); 6557c478bd9Sstevel@tonic-gate cv_init(&stp->sd_iocmonitor, NULL, CV_DEFAULT, NULL); 6566829c646Sxy158873 cv_init(&stp->sd_refmonitor, NULL, CV_DEFAULT, NULL); 6577c478bd9Sstevel@tonic-gate cv_init(&stp->sd_qcv, NULL, CV_DEFAULT, NULL); 6587c478bd9Sstevel@tonic-gate cv_init(&stp->sd_zcopy_wait, NULL, CV_DEFAULT, NULL); 6597c478bd9Sstevel@tonic-gate stp->sd_wrq = NULL; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate return (0); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6657c478bd9Sstevel@tonic-gate static void 6667c478bd9Sstevel@tonic-gate stream_head_destructor(void *buf, void *cdrarg) 6677c478bd9Sstevel@tonic-gate { 6687c478bd9Sstevel@tonic-gate stdata_t *stp = buf; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate mutex_destroy(&stp->sd_lock); 6717c478bd9Sstevel@tonic-gate mutex_destroy(&stp->sd_reflock); 6727c478bd9Sstevel@tonic-gate mutex_destroy(&stp->sd_qlock); 6737c478bd9Sstevel@tonic-gate cv_destroy(&stp->sd_monitor); 6747c478bd9Sstevel@tonic-gate cv_destroy(&stp->sd_iocmonitor); 6756829c646Sxy158873 cv_destroy(&stp->sd_refmonitor); 6767c478bd9Sstevel@tonic-gate cv_destroy(&stp->sd_qcv); 6777c478bd9Sstevel@tonic-gate cv_destroy(&stp->sd_zcopy_wait); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* 68121804b56SBrian Ruthven * Constructor/destructor routines for the queue cache 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6847c478bd9Sstevel@tonic-gate static int 6857c478bd9Sstevel@tonic-gate queue_constructor(void *buf, void *cdrarg, int kmflags) 6867c478bd9Sstevel@tonic-gate { 6877c478bd9Sstevel@tonic-gate queinfo_t *qip = buf; 6887c478bd9Sstevel@tonic-gate queue_t *qp = &qip->qu_rqueue; 6897c478bd9Sstevel@tonic-gate queue_t *wqp = &qip->qu_wqueue; 6907c478bd9Sstevel@tonic-gate syncq_t *sq = &qip->qu_syncq; 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate qp->q_first = NULL; 6937c478bd9Sstevel@tonic-gate qp->q_link = NULL; 6947c478bd9Sstevel@tonic-gate qp->q_count = 0; 6957c478bd9Sstevel@tonic-gate qp->q_mblkcnt = 0; 6967c478bd9Sstevel@tonic-gate qp->q_sqhead = NULL; 6977c478bd9Sstevel@tonic-gate qp->q_sqtail = NULL; 6987c478bd9Sstevel@tonic-gate qp->q_sqnext = NULL; 6997c478bd9Sstevel@tonic-gate qp->q_sqprev = NULL; 7007c478bd9Sstevel@tonic-gate qp->q_sqflags = 0; 7017c478bd9Sstevel@tonic-gate qp->q_rwcnt = 0; 7027c478bd9Sstevel@tonic-gate qp->q_spri = 0; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate mutex_init(QLOCK(qp), NULL, MUTEX_DEFAULT, NULL); 7057c478bd9Sstevel@tonic-gate cv_init(&qp->q_wait, NULL, CV_DEFAULT, NULL); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate wqp->q_first = NULL; 7087c478bd9Sstevel@tonic-gate wqp->q_link = NULL; 7097c478bd9Sstevel@tonic-gate wqp->q_count = 0; 7107c478bd9Sstevel@tonic-gate wqp->q_mblkcnt = 0; 7117c478bd9Sstevel@tonic-gate wqp->q_sqhead = NULL; 7127c478bd9Sstevel@tonic-gate wqp->q_sqtail = NULL; 7137c478bd9Sstevel@tonic-gate wqp->q_sqnext = NULL; 7147c478bd9Sstevel@tonic-gate wqp->q_sqprev = NULL; 7157c478bd9Sstevel@tonic-gate wqp->q_sqflags = 0; 7167c478bd9Sstevel@tonic-gate wqp->q_rwcnt = 0; 7177c478bd9Sstevel@tonic-gate wqp->q_spri = 0; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate mutex_init(QLOCK(wqp), NULL, MUTEX_DEFAULT, NULL); 7207c478bd9Sstevel@tonic-gate cv_init(&wqp->q_wait, NULL, CV_DEFAULT, NULL); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate sq->sq_head = NULL; 7237c478bd9Sstevel@tonic-gate sq->sq_tail = NULL; 7247c478bd9Sstevel@tonic-gate sq->sq_evhead = NULL; 7257c478bd9Sstevel@tonic-gate sq->sq_evtail = NULL; 7267c478bd9Sstevel@tonic-gate sq->sq_callbpend = NULL; 7277c478bd9Sstevel@tonic-gate sq->sq_outer = NULL; 7287c478bd9Sstevel@tonic-gate sq->sq_onext = NULL; 7297c478bd9Sstevel@tonic-gate sq->sq_oprev = NULL; 7307c478bd9Sstevel@tonic-gate sq->sq_next = NULL; 7317c478bd9Sstevel@tonic-gate sq->sq_svcflags = 0; 7327c478bd9Sstevel@tonic-gate sq->sq_servcount = 0; 7337c478bd9Sstevel@tonic-gate sq->sq_needexcl = 0; 7347c478bd9Sstevel@tonic-gate sq->sq_nqueues = 0; 7357c478bd9Sstevel@tonic-gate sq->sq_pri = 0; 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate mutex_init(&sq->sq_lock, NULL, MUTEX_DEFAULT, NULL); 7387c478bd9Sstevel@tonic-gate cv_init(&sq->sq_wait, NULL, CV_DEFAULT, NULL); 7397c478bd9Sstevel@tonic-gate cv_init(&sq->sq_exitwait, NULL, CV_DEFAULT, NULL); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate return (0); 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7457c478bd9Sstevel@tonic-gate static void 7467c478bd9Sstevel@tonic-gate queue_destructor(void *buf, void *cdrarg) 7477c478bd9Sstevel@tonic-gate { 7487c478bd9Sstevel@tonic-gate queinfo_t *qip = buf; 7497c478bd9Sstevel@tonic-gate queue_t *qp = &qip->qu_rqueue; 7507c478bd9Sstevel@tonic-gate queue_t *wqp = &qip->qu_wqueue; 7517c478bd9Sstevel@tonic-gate syncq_t *sq = &qip->qu_syncq; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqhead == NULL); 7547c478bd9Sstevel@tonic-gate ASSERT(wqp->q_sqhead == NULL); 7557c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqnext == NULL); 7567c478bd9Sstevel@tonic-gate ASSERT(wqp->q_sqnext == NULL); 7577c478bd9Sstevel@tonic-gate ASSERT(qp->q_rwcnt == 0); 7587c478bd9Sstevel@tonic-gate ASSERT(wqp->q_rwcnt == 0); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate mutex_destroy(&qp->q_lock); 7617c478bd9Sstevel@tonic-gate cv_destroy(&qp->q_wait); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate mutex_destroy(&wqp->q_lock); 7647c478bd9Sstevel@tonic-gate cv_destroy(&wqp->q_wait); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate mutex_destroy(&sq->sq_lock); 7677c478bd9Sstevel@tonic-gate cv_destroy(&sq->sq_wait); 7687c478bd9Sstevel@tonic-gate cv_destroy(&sq->sq_exitwait); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 77221804b56SBrian Ruthven * Constructor/destructor routines for the syncq cache 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7757c478bd9Sstevel@tonic-gate static int 7767c478bd9Sstevel@tonic-gate syncq_constructor(void *buf, void *cdrarg, int kmflags) 7777c478bd9Sstevel@tonic-gate { 7787c478bd9Sstevel@tonic-gate syncq_t *sq = buf; 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate bzero(buf, sizeof (syncq_t)); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate mutex_init(&sq->sq_lock, NULL, MUTEX_DEFAULT, NULL); 7837c478bd9Sstevel@tonic-gate cv_init(&sq->sq_wait, NULL, CV_DEFAULT, NULL); 7847c478bd9Sstevel@tonic-gate cv_init(&sq->sq_exitwait, NULL, CV_DEFAULT, NULL); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate return (0); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7907c478bd9Sstevel@tonic-gate static void 7917c478bd9Sstevel@tonic-gate syncq_destructor(void *buf, void *cdrarg) 7927c478bd9Sstevel@tonic-gate { 7937c478bd9Sstevel@tonic-gate syncq_t *sq = buf; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate ASSERT(sq->sq_head == NULL); 7967c478bd9Sstevel@tonic-gate ASSERT(sq->sq_tail == NULL); 7977c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evhead == NULL); 7987c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evtail == NULL); 7997c478bd9Sstevel@tonic-gate ASSERT(sq->sq_callbpend == NULL); 8007c478bd9Sstevel@tonic-gate ASSERT(sq->sq_callbflags == 0); 8017c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL); 8027c478bd9Sstevel@tonic-gate ASSERT(sq->sq_onext == NULL); 8037c478bd9Sstevel@tonic-gate ASSERT(sq->sq_oprev == NULL); 8047c478bd9Sstevel@tonic-gate ASSERT(sq->sq_next == NULL); 8057c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl == 0); 8067c478bd9Sstevel@tonic-gate ASSERT(sq->sq_svcflags == 0); 8077c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount == 0); 8087c478bd9Sstevel@tonic-gate ASSERT(sq->sq_nqueues == 0); 8097c478bd9Sstevel@tonic-gate ASSERT(sq->sq_pri == 0); 8107c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count == 0); 8117c478bd9Sstevel@tonic-gate ASSERT(sq->sq_rmqcount == 0); 8127c478bd9Sstevel@tonic-gate ASSERT(sq->sq_cancelid == 0); 8137c478bd9Sstevel@tonic-gate ASSERT(sq->sq_ciputctrl == NULL); 8147c478bd9Sstevel@tonic-gate ASSERT(sq->sq_nciputctrl == 0); 8157c478bd9Sstevel@tonic-gate ASSERT(sq->sq_type == 0); 8167c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags == 0); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate mutex_destroy(&sq->sq_lock); 8197c478bd9Sstevel@tonic-gate cv_destroy(&sq->sq_wait); 8207c478bd9Sstevel@tonic-gate cv_destroy(&sq->sq_exitwait); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8247c478bd9Sstevel@tonic-gate static int 8257c478bd9Sstevel@tonic-gate ciputctrl_constructor(void *buf, void *cdrarg, int kmflags) 8267c478bd9Sstevel@tonic-gate { 8277c478bd9Sstevel@tonic-gate ciputctrl_t *cip = buf; 8287c478bd9Sstevel@tonic-gate int i; 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate for (i = 0; i < n_ciputctrl; i++) { 8317c478bd9Sstevel@tonic-gate cip[i].ciputctrl_count = SQ_FASTPUT; 8327c478bd9Sstevel@tonic-gate mutex_init(&cip[i].ciputctrl_lock, NULL, MUTEX_DEFAULT, NULL); 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate return (0); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8397c478bd9Sstevel@tonic-gate static void 8407c478bd9Sstevel@tonic-gate ciputctrl_destructor(void *buf, void *cdrarg) 8417c478bd9Sstevel@tonic-gate { 8427c478bd9Sstevel@tonic-gate ciputctrl_t *cip = buf; 8437c478bd9Sstevel@tonic-gate int i; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate for (i = 0; i < n_ciputctrl; i++) { 8467c478bd9Sstevel@tonic-gate ASSERT(cip[i].ciputctrl_count & SQ_FASTPUT); 8477c478bd9Sstevel@tonic-gate mutex_destroy(&cip[i].ciputctrl_lock); 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Init routine run from main at boot time. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate void 8557c478bd9Sstevel@tonic-gate strinit(void) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate int ncpus = ((boot_max_ncpus == -1) ? max_ncpus : boot_max_ncpus); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate stream_head_cache = kmem_cache_create("stream_head_cache", 8607c478bd9Sstevel@tonic-gate sizeof (stdata_t), 0, 8617c478bd9Sstevel@tonic-gate stream_head_constructor, stream_head_destructor, NULL, 8627c478bd9Sstevel@tonic-gate NULL, NULL, 0); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate queue_cache = kmem_cache_create("queue_cache", sizeof (queinfo_t), 0, 8657c478bd9Sstevel@tonic-gate queue_constructor, queue_destructor, NULL, NULL, NULL, 0); 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate syncq_cache = kmem_cache_create("syncq_cache", sizeof (syncq_t), 0, 8687c478bd9Sstevel@tonic-gate syncq_constructor, syncq_destructor, NULL, NULL, NULL, 0); 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate qband_cache = kmem_cache_create("qband_cache", 8717c478bd9Sstevel@tonic-gate sizeof (qband_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate linkinfo_cache = kmem_cache_create("linkinfo_cache", 8747c478bd9Sstevel@tonic-gate sizeof (linkinfo_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate n_ciputctrl = ncpus; 8777c478bd9Sstevel@tonic-gate n_ciputctrl = 1 << highbit(n_ciputctrl - 1); 8787c478bd9Sstevel@tonic-gate ASSERT(n_ciputctrl >= 1); 8797c478bd9Sstevel@tonic-gate n_ciputctrl = MIN(n_ciputctrl, max_n_ciputctrl); 8807c478bd9Sstevel@tonic-gate if (n_ciputctrl >= min_n_ciputctrl) { 8817c478bd9Sstevel@tonic-gate ciputctrl_cache = kmem_cache_create("ciputctrl_cache", 8827c478bd9Sstevel@tonic-gate sizeof (ciputctrl_t) * n_ciputctrl, 8837c478bd9Sstevel@tonic-gate sizeof (ciputctrl_t), ciputctrl_constructor, 8847c478bd9Sstevel@tonic-gate ciputctrl_destructor, NULL, NULL, NULL, 0); 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate streams_taskq = system_taskq; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate if (streams_taskq == NULL) 8907c478bd9Sstevel@tonic-gate panic("strinit: no memory for streams taskq!"); 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate bc_bkgrnd_thread = thread_create(NULL, 0, 8937c478bd9Sstevel@tonic-gate streams_bufcall_service, NULL, 0, &p0, TS_RUN, streams_lopri); 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate streams_qbkgrnd_thread = thread_create(NULL, 0, 8967c478bd9Sstevel@tonic-gate streams_qbkgrnd_service, NULL, 0, &p0, TS_RUN, streams_lopri); 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate streams_sqbkgrnd_thread = thread_create(NULL, 0, 8997c478bd9Sstevel@tonic-gate streams_sqbkgrnd_service, NULL, 0, &p0, TS_RUN, streams_lopri); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * Create STREAMS kstats. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate str_kstat = kstat_create("streams", 0, "strstat", 9057c478bd9Sstevel@tonic-gate "net", KSTAT_TYPE_NAMED, 9067c478bd9Sstevel@tonic-gate sizeof (str_statistics) / sizeof (kstat_named_t), 9077c478bd9Sstevel@tonic-gate KSTAT_FLAG_VIRTUAL); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate if (str_kstat != NULL) { 9107c478bd9Sstevel@tonic-gate str_kstat->ks_data = &str_statistics; 9117c478bd9Sstevel@tonic-gate kstat_install(str_kstat); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* 9157c478bd9Sstevel@tonic-gate * TPI support routine initialisation. 9167c478bd9Sstevel@tonic-gate */ 9177c478bd9Sstevel@tonic-gate tpi_init(); 918f4b3ec61Sdh155122 919f4b3ec61Sdh155122 /* 920f4b3ec61Sdh155122 * Handle to have autopush and persistent link information per 921f4b3ec61Sdh155122 * zone. 922f4b3ec61Sdh155122 * Note: uses shutdown hook instead of destroy hook so that the 923f4b3ec61Sdh155122 * persistent links can be torn down before the destroy hooks 924f4b3ec61Sdh155122 * in the TCP/IP stack are called. 925f4b3ec61Sdh155122 */ 926f4b3ec61Sdh155122 netstack_register(NS_STR, str_stack_init, str_stack_shutdown, 927f4b3ec61Sdh155122 str_stack_fini); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate void 9317c478bd9Sstevel@tonic-gate str_sendsig(vnode_t *vp, int event, uchar_t band, int error) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate struct stdata *stp; 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate ASSERT(vp->v_stream); 9367c478bd9Sstevel@tonic-gate stp = vp->v_stream; 9377c478bd9Sstevel@tonic-gate /* Have to hold sd_lock to prevent siglist from changing */ 9387c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 9397c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & event) 9407c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, event, band, error); 9417c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate * Send the "sevent" set of signals to a process. 9467c478bd9Sstevel@tonic-gate * This might send more than one signal if the process is registered 9477c478bd9Sstevel@tonic-gate * for multiple events. The caller should pass in an sevent that only 9487c478bd9Sstevel@tonic-gate * includes the events for which the process has registered. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate static void 9517c478bd9Sstevel@tonic-gate dosendsig(proc_t *proc, int events, int sevent, k_siginfo_t *info, 9527c478bd9Sstevel@tonic-gate uchar_t band, int error) 9537c478bd9Sstevel@tonic-gate { 9547c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&proc->p_lock)); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate info->si_band = 0; 9577c478bd9Sstevel@tonic-gate info->si_errno = 0; 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (sevent & S_ERROR) { 9607c478bd9Sstevel@tonic-gate sevent &= ~S_ERROR; 9617c478bd9Sstevel@tonic-gate info->si_code = POLL_ERR; 9627c478bd9Sstevel@tonic-gate info->si_errno = error; 9637c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_STRSENDSIG, 9647c478bd9Sstevel@tonic-gate "strsendsig:proc %p info %p", proc, info); 9657c478bd9Sstevel@tonic-gate sigaddq(proc, NULL, info, KM_NOSLEEP); 9667c478bd9Sstevel@tonic-gate info->si_errno = 0; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate if (sevent & S_HANGUP) { 9697c478bd9Sstevel@tonic-gate sevent &= ~S_HANGUP; 9707c478bd9Sstevel@tonic-gate info->si_code = POLL_HUP; 9717c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_STRSENDSIG, 9727c478bd9Sstevel@tonic-gate "strsendsig:proc %p info %p", proc, info); 9737c478bd9Sstevel@tonic-gate sigaddq(proc, NULL, info, KM_NOSLEEP); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate if (sevent & S_HIPRI) { 9767c478bd9Sstevel@tonic-gate sevent &= ~S_HIPRI; 9777c478bd9Sstevel@tonic-gate info->si_code = POLL_PRI; 9787c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_STRSENDSIG, 9797c478bd9Sstevel@tonic-gate "strsendsig:proc %p info %p", proc, info); 9807c478bd9Sstevel@tonic-gate sigaddq(proc, NULL, info, KM_NOSLEEP); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate if (sevent & S_RDBAND) { 9837c478bd9Sstevel@tonic-gate sevent &= ~S_RDBAND; 9847c478bd9Sstevel@tonic-gate if (events & S_BANDURG) 9857c478bd9Sstevel@tonic-gate sigtoproc(proc, NULL, SIGURG); 9867c478bd9Sstevel@tonic-gate else 9877c478bd9Sstevel@tonic-gate sigtoproc(proc, NULL, SIGPOLL); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate if (sevent & S_WRBAND) { 9907c478bd9Sstevel@tonic-gate sevent &= ~S_WRBAND; 9917c478bd9Sstevel@tonic-gate sigtoproc(proc, NULL, SIGPOLL); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate if (sevent & S_INPUT) { 9947c478bd9Sstevel@tonic-gate sevent &= ~S_INPUT; 9957c478bd9Sstevel@tonic-gate info->si_code = POLL_IN; 9967c478bd9Sstevel@tonic-gate info->si_band = band; 9977c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_STRSENDSIG, 9987c478bd9Sstevel@tonic-gate "strsendsig:proc %p info %p", proc, info); 9997c478bd9Sstevel@tonic-gate sigaddq(proc, NULL, info, KM_NOSLEEP); 10007c478bd9Sstevel@tonic-gate info->si_band = 0; 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate if (sevent & S_OUTPUT) { 10037c478bd9Sstevel@tonic-gate sevent &= ~S_OUTPUT; 10047c478bd9Sstevel@tonic-gate info->si_code = POLL_OUT; 10057c478bd9Sstevel@tonic-gate info->si_band = band; 10067c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_STRSENDSIG, 10077c478bd9Sstevel@tonic-gate "strsendsig:proc %p info %p", proc, info); 10087c478bd9Sstevel@tonic-gate sigaddq(proc, NULL, info, KM_NOSLEEP); 10097c478bd9Sstevel@tonic-gate info->si_band = 0; 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate if (sevent & S_MSG) { 10127c478bd9Sstevel@tonic-gate sevent &= ~S_MSG; 10137c478bd9Sstevel@tonic-gate info->si_code = POLL_MSG; 10147c478bd9Sstevel@tonic-gate info->si_band = band; 10157c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_STRSENDSIG, 10167c478bd9Sstevel@tonic-gate "strsendsig:proc %p info %p", proc, info); 10177c478bd9Sstevel@tonic-gate sigaddq(proc, NULL, info, KM_NOSLEEP); 10187c478bd9Sstevel@tonic-gate info->si_band = 0; 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate if (sevent & S_RDNORM) { 10217c478bd9Sstevel@tonic-gate sevent &= ~S_RDNORM; 10227c478bd9Sstevel@tonic-gate sigtoproc(proc, NULL, SIGPOLL); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate if (sevent != 0) { 10257c478bd9Sstevel@tonic-gate panic("strsendsig: unknown event(s) %x", sevent); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate /* 10307c478bd9Sstevel@tonic-gate * Send SIGPOLL/SIGURG signal to all processes and process groups 10317c478bd9Sstevel@tonic-gate * registered on the given signal list that want a signal for at 10327c478bd9Sstevel@tonic-gate * least one of the specified events. 10337c478bd9Sstevel@tonic-gate * 10347c478bd9Sstevel@tonic-gate * Must be called with exclusive access to siglist (caller holding sd_lock). 10357c478bd9Sstevel@tonic-gate * 10367c478bd9Sstevel@tonic-gate * strioctl(I_SETSIG/I_ESETSIG) will only change siglist when holding 10377c478bd9Sstevel@tonic-gate * sd_lock and the ioctl code maintains a PID_HOLD on the pid structure 10387c478bd9Sstevel@tonic-gate * while it is in the siglist. 10397c478bd9Sstevel@tonic-gate * 10407c478bd9Sstevel@tonic-gate * For performance reasons (MP scalability) the code drops pidlock 10417c478bd9Sstevel@tonic-gate * when sending signals to a single process. 10427c478bd9Sstevel@tonic-gate * When sending to a process group the code holds 10437c478bd9Sstevel@tonic-gate * pidlock to prevent the membership in the process group from changing 10447c478bd9Sstevel@tonic-gate * while walking the p_pglink list. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate void 10477c478bd9Sstevel@tonic-gate strsendsig(strsig_t *siglist, int event, uchar_t band, int error) 10487c478bd9Sstevel@tonic-gate { 10497c478bd9Sstevel@tonic-gate strsig_t *ssp; 10507c478bd9Sstevel@tonic-gate k_siginfo_t info; 10517c478bd9Sstevel@tonic-gate struct pid *pidp; 10527c478bd9Sstevel@tonic-gate proc_t *proc; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate info.si_signo = SIGPOLL; 10557c478bd9Sstevel@tonic-gate info.si_errno = 0; 10567c478bd9Sstevel@tonic-gate for (ssp = siglist; ssp; ssp = ssp->ss_next) { 10577c478bd9Sstevel@tonic-gate int sevent; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate sevent = ssp->ss_events & event; 10607c478bd9Sstevel@tonic-gate if (sevent == 0) 10617c478bd9Sstevel@tonic-gate continue; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate if ((pidp = ssp->ss_pidp) == NULL) { 10647c478bd9Sstevel@tonic-gate /* pid was released but still on event list */ 10657c478bd9Sstevel@tonic-gate continue; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate if (ssp->ss_pid > 0) { 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * XXX This unfortunately still generates 10727c478bd9Sstevel@tonic-gate * a signal when a fd is closed but 10737c478bd9Sstevel@tonic-gate * the proc is active. 10747c478bd9Sstevel@tonic-gate */ 10757c478bd9Sstevel@tonic-gate ASSERT(ssp->ss_pid == pidp->pid_id); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 10787c478bd9Sstevel@tonic-gate proc = prfind_zone(pidp->pid_id, ALL_ZONES); 10797c478bd9Sstevel@tonic-gate if (proc == NULL) { 10807c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 10817c478bd9Sstevel@tonic-gate continue; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate mutex_enter(&proc->p_lock); 10847c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 10857c478bd9Sstevel@tonic-gate dosendsig(proc, ssp->ss_events, sevent, &info, 10867c478bd9Sstevel@tonic-gate band, error); 10877c478bd9Sstevel@tonic-gate mutex_exit(&proc->p_lock); 10887c478bd9Sstevel@tonic-gate } else { 10897c478bd9Sstevel@tonic-gate /* 10907c478bd9Sstevel@tonic-gate * Send to process group. Hold pidlock across 10917c478bd9Sstevel@tonic-gate * calls to dosendsig(). 10927c478bd9Sstevel@tonic-gate */ 10937c478bd9Sstevel@tonic-gate pid_t pgrp = -ssp->ss_pid; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 10967c478bd9Sstevel@tonic-gate proc = pgfind_zone(pgrp, ALL_ZONES); 10977c478bd9Sstevel@tonic-gate while (proc != NULL) { 10987c478bd9Sstevel@tonic-gate mutex_enter(&proc->p_lock); 10997c478bd9Sstevel@tonic-gate dosendsig(proc, ssp->ss_events, sevent, 11007c478bd9Sstevel@tonic-gate &info, band, error); 11017c478bd9Sstevel@tonic-gate mutex_exit(&proc->p_lock); 11027c478bd9Sstevel@tonic-gate proc = proc->p_pglink; 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate /* 11107c478bd9Sstevel@tonic-gate * Attach a stream device or module. 11117c478bd9Sstevel@tonic-gate * qp is a read queue; the new queue goes in so its next 11127c478bd9Sstevel@tonic-gate * read ptr is the argument, and the write queue corresponding 11137c478bd9Sstevel@tonic-gate * to the argument points to this queue. Return 0 on success, 11147c478bd9Sstevel@tonic-gate * or a non-zero errno on failure. 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate int 11177c478bd9Sstevel@tonic-gate qattach(queue_t *qp, dev_t *devp, int oflag, cred_t *crp, fmodsw_impl_t *fp, 11187c478bd9Sstevel@tonic-gate boolean_t is_insert) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate major_t major; 11217c478bd9Sstevel@tonic-gate cdevsw_impl_t *dp; 11227c478bd9Sstevel@tonic-gate struct streamtab *str; 11237c478bd9Sstevel@tonic-gate queue_t *rq; 11247c478bd9Sstevel@tonic-gate queue_t *wrq; 11257c478bd9Sstevel@tonic-gate uint32_t qflag; 11267c478bd9Sstevel@tonic-gate uint32_t sqtype; 11277c478bd9Sstevel@tonic-gate perdm_t *dmp; 11287c478bd9Sstevel@tonic-gate int error; 11297c478bd9Sstevel@tonic-gate int sflag; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate rq = allocq(); 11327c478bd9Sstevel@tonic-gate wrq = _WR(rq); 11337c478bd9Sstevel@tonic-gate STREAM(rq) = STREAM(wrq) = STREAM(qp); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (fp != NULL) { 11367c478bd9Sstevel@tonic-gate str = fp->f_str; 11377c478bd9Sstevel@tonic-gate qflag = fp->f_qflag; 11387c478bd9Sstevel@tonic-gate sqtype = fp->f_sqtype; 11397c478bd9Sstevel@tonic-gate dmp = fp->f_dmp; 11407c478bd9Sstevel@tonic-gate IMPLY((qflag & (QPERMOD | QMTOUTPERIM)), dmp != NULL); 11417c478bd9Sstevel@tonic-gate sflag = MODOPEN; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * stash away a pointer to the module structure so we can 11457c478bd9Sstevel@tonic-gate * unref it in qdetach. 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate rq->q_fp = fp; 11487c478bd9Sstevel@tonic-gate } else { 11497c478bd9Sstevel@tonic-gate ASSERT(!is_insert); 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate major = getmajor(*devp); 11527c478bd9Sstevel@tonic-gate dp = &devimpl[major]; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate str = dp->d_str; 11557c478bd9Sstevel@tonic-gate ASSERT(str == STREAMSTAB(major)); 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate qflag = dp->d_qflag; 11587c478bd9Sstevel@tonic-gate ASSERT(qflag & QISDRV); 11597c478bd9Sstevel@tonic-gate sqtype = dp->d_sqtype; 11607c478bd9Sstevel@tonic-gate 11617c478bd9Sstevel@tonic-gate /* create perdm_t if needed */ 11627c478bd9Sstevel@tonic-gate if (NEED_DM(dp->d_dmp, qflag)) 11637c478bd9Sstevel@tonic-gate dp->d_dmp = hold_dm(str, qflag, sqtype); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate dmp = dp->d_dmp; 11667c478bd9Sstevel@tonic-gate sflag = 0; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_QATTACH_FLAGS, 11707c478bd9Sstevel@tonic-gate "qattach:qflag == %X(%X)", qflag, *devp); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate /* setq might sleep in allocator - avoid holding locks. */ 11737c478bd9Sstevel@tonic-gate setq(rq, str->st_rdinit, str->st_wrinit, dmp, qflag, sqtype, B_FALSE); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * Before calling the module's open routine, set up the q_next 11777c478bd9Sstevel@tonic-gate * pointer for inserting a module in the middle of a stream. 11787c478bd9Sstevel@tonic-gate * 11797c478bd9Sstevel@tonic-gate * Note that we can always set _QINSERTING and set up q_next 11807c478bd9Sstevel@tonic-gate * pointer for both inserting and pushing a module. Then there 11817c478bd9Sstevel@tonic-gate * is no need for the is_insert parameter. In insertq(), called 11827c478bd9Sstevel@tonic-gate * by qprocson(), assume that q_next of the new module always points 11837c478bd9Sstevel@tonic-gate * to the correct queue and use it for insertion. Everything should 11847c478bd9Sstevel@tonic-gate * work out fine. But in the first release of _I_INSERT, we 11857c478bd9Sstevel@tonic-gate * distinguish between inserting and pushing to make sure that 11867c478bd9Sstevel@tonic-gate * pushing a module follows the same code path as before. 11877c478bd9Sstevel@tonic-gate */ 11887c478bd9Sstevel@tonic-gate if (is_insert) { 11897c478bd9Sstevel@tonic-gate rq->q_flag |= _QINSERTING; 11907c478bd9Sstevel@tonic-gate rq->q_next = qp; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* 11947c478bd9Sstevel@tonic-gate * If there is an outer perimeter get exclusive access during 11957c478bd9Sstevel@tonic-gate * the open procedure. Bump up the reference count on the queue. 11967c478bd9Sstevel@tonic-gate */ 11977c478bd9Sstevel@tonic-gate entersq(rq->q_syncq, SQ_OPENCLOSE); 11987c478bd9Sstevel@tonic-gate error = (*rq->q_qinfo->qi_qopen)(rq, devp, oflag, sflag, crp); 11997c478bd9Sstevel@tonic-gate if (error != 0) 12007c478bd9Sstevel@tonic-gate goto failed; 12017c478bd9Sstevel@tonic-gate leavesq(rq->q_syncq, SQ_OPENCLOSE); 12027c478bd9Sstevel@tonic-gate ASSERT(qprocsareon(rq)); 12037c478bd9Sstevel@tonic-gate return (0); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate failed: 12067c478bd9Sstevel@tonic-gate rq->q_flag &= ~_QINSERTING; 12077c478bd9Sstevel@tonic-gate if (backq(wrq) != NULL && backq(wrq)->q_next == wrq) 12087c478bd9Sstevel@tonic-gate qprocsoff(rq); 12097c478bd9Sstevel@tonic-gate leavesq(rq->q_syncq, SQ_OPENCLOSE); 12107c478bd9Sstevel@tonic-gate rq->q_next = wrq->q_next = NULL; 12117c478bd9Sstevel@tonic-gate qdetach(rq, 0, 0, crp, B_FALSE); 12127c478bd9Sstevel@tonic-gate return (error); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate /* 12167c478bd9Sstevel@tonic-gate * Handle second open of stream. For modules, set the 12177c478bd9Sstevel@tonic-gate * last argument to MODOPEN and do not pass any open flags. 12187c478bd9Sstevel@tonic-gate * Ignore dummydev since this is not the first open. 12197c478bd9Sstevel@tonic-gate */ 12207c478bd9Sstevel@tonic-gate int 12217c478bd9Sstevel@tonic-gate qreopen(queue_t *qp, dev_t *devp, int flag, cred_t *crp) 12227c478bd9Sstevel@tonic-gate { 12237c478bd9Sstevel@tonic-gate int error; 12247c478bd9Sstevel@tonic-gate dev_t dummydev; 12257c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate ASSERT(qp->q_flag & QREADR); 12287c478bd9Sstevel@tonic-gate entersq(qp->q_syncq, SQ_OPENCLOSE); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate dummydev = *devp; 12317c478bd9Sstevel@tonic-gate if (error = ((*qp->q_qinfo->qi_qopen)(qp, &dummydev, 12327c478bd9Sstevel@tonic-gate (wqp->q_next ? 0 : flag), (wqp->q_next ? MODOPEN : 0), crp))) { 12337c478bd9Sstevel@tonic-gate leavesq(qp->q_syncq, SQ_OPENCLOSE); 12347c478bd9Sstevel@tonic-gate mutex_enter(&STREAM(qp)->sd_lock); 12357c478bd9Sstevel@tonic-gate qp->q_stream->sd_flag |= STREOPENFAIL; 12367c478bd9Sstevel@tonic-gate mutex_exit(&STREAM(qp)->sd_lock); 12377c478bd9Sstevel@tonic-gate return (error); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate leavesq(qp->q_syncq, SQ_OPENCLOSE); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* 12427c478bd9Sstevel@tonic-gate * successful open should have done qprocson() 12437c478bd9Sstevel@tonic-gate */ 12447c478bd9Sstevel@tonic-gate ASSERT(qprocsareon(_RD(qp))); 12457c478bd9Sstevel@tonic-gate return (0); 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate /* 12497c478bd9Sstevel@tonic-gate * Detach a stream module or device. 12507c478bd9Sstevel@tonic-gate * If clmode == 1 then the module or driver was opened and its 12517c478bd9Sstevel@tonic-gate * close routine must be called. If clmode == 0, the module 12527c478bd9Sstevel@tonic-gate * or driver was never opened or the open failed, and so its close 12537c478bd9Sstevel@tonic-gate * should not be called. 12547c478bd9Sstevel@tonic-gate */ 12557c478bd9Sstevel@tonic-gate void 12567c478bd9Sstevel@tonic-gate qdetach(queue_t *qp, int clmode, int flag, cred_t *crp, boolean_t is_remove) 12577c478bd9Sstevel@tonic-gate { 12587c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 12597c478bd9Sstevel@tonic-gate ASSERT(STREAM(qp)->sd_flag & (STRCLOSE|STWOPEN|STRPLUMB)); 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate if (STREAM_NEEDSERVICE(STREAM(qp))) 12627c478bd9Sstevel@tonic-gate stream_runservice(STREAM(qp)); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate if (clmode) { 12657c478bd9Sstevel@tonic-gate /* 12667c478bd9Sstevel@tonic-gate * Make sure that all the messages on the write side syncq are 12677c478bd9Sstevel@tonic-gate * processed and nothing is left. Since we are closing, no new 12687c478bd9Sstevel@tonic-gate * messages may appear there. 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate wait_q_syncq(wqp); 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate entersq(qp->q_syncq, SQ_OPENCLOSE); 12737c478bd9Sstevel@tonic-gate if (is_remove) { 12747c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 12757c478bd9Sstevel@tonic-gate qp->q_flag |= _QREMOVING; 12767c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate (*qp->q_qinfo->qi_qclose)(qp, flag, crp); 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * Check that qprocsoff() was actually called. 12817c478bd9Sstevel@tonic-gate */ 12827c478bd9Sstevel@tonic-gate ASSERT((qp->q_flag & QWCLOSE) && (wqp->q_flag & QWCLOSE)); 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate leavesq(qp->q_syncq, SQ_OPENCLOSE); 12857c478bd9Sstevel@tonic-gate } else { 12867c478bd9Sstevel@tonic-gate disable_svc(qp); 12877c478bd9Sstevel@tonic-gate } 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* 12907c478bd9Sstevel@tonic-gate * Allow any threads blocked in entersq to proceed and discover 12917c478bd9Sstevel@tonic-gate * the QWCLOSE is set. 12927c478bd9Sstevel@tonic-gate * Note: This assumes that all users of entersq check QWCLOSE. 12937c478bd9Sstevel@tonic-gate * Currently runservice is the only entersq that can happen 12947c478bd9Sstevel@tonic-gate * after removeq has finished. 12957c478bd9Sstevel@tonic-gate * Removeq will have discarded all messages destined to the closing 12967c478bd9Sstevel@tonic-gate * pair of queues from the syncq. 12977c478bd9Sstevel@tonic-gate * NOTE: Calling a function inside an assert is unconventional. 12987c478bd9Sstevel@tonic-gate * However, it does not cause any problem since flush_syncq() does 12997c478bd9Sstevel@tonic-gate * not change any state except when it returns non-zero i.e. 13007c478bd9Sstevel@tonic-gate * when the assert will trigger. 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate ASSERT(flush_syncq(qp->q_syncq, qp) == 0); 13037c478bd9Sstevel@tonic-gate ASSERT(flush_syncq(wqp->q_syncq, wqp) == 0); 13047c478bd9Sstevel@tonic-gate ASSERT((qp->q_flag & QPERMOD) || 13057c478bd9Sstevel@tonic-gate ((qp->q_syncq->sq_head == NULL) && 13067c478bd9Sstevel@tonic-gate (wqp->q_syncq->sq_head == NULL))); 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate /* release any fmodsw_impl_t structure held on behalf of the queue */ 13097c478bd9Sstevel@tonic-gate ASSERT(qp->q_fp != NULL || qp->q_flag & QISDRV); 13107c478bd9Sstevel@tonic-gate if (qp->q_fp != NULL) 13117c478bd9Sstevel@tonic-gate fmodsw_rele(qp->q_fp); 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate /* freeq removes us from the outer perimeter if any */ 13147c478bd9Sstevel@tonic-gate freeq(qp); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate /* Prevent service procedures from being called */ 13187c478bd9Sstevel@tonic-gate void 13197c478bd9Sstevel@tonic-gate disable_svc(queue_t *qp) 13207c478bd9Sstevel@tonic-gate { 13217c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate ASSERT(qp->q_flag & QREADR); 13247c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 13257c478bd9Sstevel@tonic-gate qp->q_flag |= QWCLOSE; 13267c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 13277c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(wqp)); 13287c478bd9Sstevel@tonic-gate wqp->q_flag |= QWCLOSE; 13297c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(wqp)); 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 133221804b56SBrian Ruthven /* Allow service procedures to be called again */ 13337c478bd9Sstevel@tonic-gate void 13347c478bd9Sstevel@tonic-gate enable_svc(queue_t *qp) 13357c478bd9Sstevel@tonic-gate { 13367c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate ASSERT(qp->q_flag & QREADR); 13397c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 13407c478bd9Sstevel@tonic-gate qp->q_flag &= ~QWCLOSE; 13417c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 13427c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(wqp)); 13437c478bd9Sstevel@tonic-gate wqp->q_flag &= ~QWCLOSE; 13447c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(wqp)); 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate /* 13487c478bd9Sstevel@tonic-gate * Remove queue from qhead/qtail if it is enabled. 13497c478bd9Sstevel@tonic-gate * Only reset QENAB if the queue was removed from the runlist. 13507c478bd9Sstevel@tonic-gate * A queue goes through 3 stages: 13517c478bd9Sstevel@tonic-gate * It is on the service list and QENAB is set. 13527c478bd9Sstevel@tonic-gate * It is removed from the service list but QENAB is still set. 13537c478bd9Sstevel@tonic-gate * QENAB gets changed to QINSERVICE. 13547c478bd9Sstevel@tonic-gate * QINSERVICE is reset (when the service procedure is done) 13557c478bd9Sstevel@tonic-gate * Thus we can not reset QENAB unless we actually removed it from the service 13567c478bd9Sstevel@tonic-gate * queue. 13577c478bd9Sstevel@tonic-gate */ 13587c478bd9Sstevel@tonic-gate void 13597c478bd9Sstevel@tonic-gate remove_runlist(queue_t *qp) 13607c478bd9Sstevel@tonic-gate { 13617c478bd9Sstevel@tonic-gate if (qp->q_flag & QENAB && qhead != NULL) { 13627c478bd9Sstevel@tonic-gate queue_t *q_chase; 13637c478bd9Sstevel@tonic-gate queue_t *q_curr; 13647c478bd9Sstevel@tonic-gate int removed; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 13677c478bd9Sstevel@tonic-gate RMQ(qp, qhead, qtail, q_link, q_chase, q_curr, removed); 13687c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 13697c478bd9Sstevel@tonic-gate if (removed) { 13707c478bd9Sstevel@tonic-gate STRSTAT(qremoved); 13717c478bd9Sstevel@tonic-gate qp->q_flag &= ~QENAB; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 137821804b56SBrian Ruthven * Wait for any pending service processing to complete. 13797c478bd9Sstevel@tonic-gate * The removal of queues from the runlist is not atomic with the 13807c478bd9Sstevel@tonic-gate * clearing of the QENABLED flag and setting the INSERVICE flag. 13817c478bd9Sstevel@tonic-gate * consequently it is possible for remove_runlist in strclose 13827c478bd9Sstevel@tonic-gate * to not find the queue on the runlist but for it to be QENABLED 13837c478bd9Sstevel@tonic-gate * and not yet INSERVICE -> hence wait_svc needs to check QENABLED 13847c478bd9Sstevel@tonic-gate * as well as INSERVICE. 13857c478bd9Sstevel@tonic-gate */ 13867c478bd9Sstevel@tonic-gate void 13877c478bd9Sstevel@tonic-gate wait_svc(queue_t *qp) 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate ASSERT(qp->q_flag & QREADR); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * Try to remove queues from qhead/qtail list. 13957c478bd9Sstevel@tonic-gate */ 13967c478bd9Sstevel@tonic-gate if (qhead != NULL) { 13977c478bd9Sstevel@tonic-gate remove_runlist(qp); 13987c478bd9Sstevel@tonic-gate remove_runlist(wqp); 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate /* 140121804b56SBrian Ruthven * Wait till the syncqs associated with the queue disappear from the 140221804b56SBrian Ruthven * background processing list. 14037c478bd9Sstevel@tonic-gate * This only needs to be done for non-PERMOD perimeters since 14047c478bd9Sstevel@tonic-gate * for PERMOD perimeters the syncq may be shared and will only be freed 14057c478bd9Sstevel@tonic-gate * when the last module/driver is unloaded. 14067c478bd9Sstevel@tonic-gate * If for PERMOD perimeters queue was on the syncq list, removeq() 14077c478bd9Sstevel@tonic-gate * should call propagate_syncq() or drain_syncq() for it. Both of these 140821804b56SBrian Ruthven * functions remove the queue from its syncq list, so sqthread will not 14097c478bd9Sstevel@tonic-gate * try to access the queue. 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate if (!(qp->q_flag & QPERMOD)) { 14127c478bd9Sstevel@tonic-gate syncq_t *rsq = qp->q_syncq; 14137c478bd9Sstevel@tonic-gate syncq_t *wsq = wqp->q_syncq; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * Disable rsq and wsq and wait for any background processing of 14177c478bd9Sstevel@tonic-gate * syncq to complete. 14187c478bd9Sstevel@tonic-gate */ 14197c478bd9Sstevel@tonic-gate wait_sq_svc(rsq); 14207c478bd9Sstevel@tonic-gate if (wsq != rsq) 14217c478bd9Sstevel@tonic-gate wait_sq_svc(wsq); 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 14257c478bd9Sstevel@tonic-gate while (qp->q_flag & (QINSERVICE|QENAB)) 14267c478bd9Sstevel@tonic-gate cv_wait(&qp->q_wait, QLOCK(qp)); 14277c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 14287c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(wqp)); 14297c478bd9Sstevel@tonic-gate while (wqp->q_flag & (QINSERVICE|QENAB)) 14307c478bd9Sstevel@tonic-gate cv_wait(&wqp->q_wait, QLOCK(wqp)); 14317c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(wqp)); 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* 14357c478bd9Sstevel@tonic-gate * Put ioctl data from userland buffer `arg' into the mblk chain `bp'. 14367c478bd9Sstevel@tonic-gate * `flag' must always contain either K_TO_K or U_TO_K; STR_NOSIG may 14377c478bd9Sstevel@tonic-gate * also be set, and is passed through to allocb_cred_wait(). 14387c478bd9Sstevel@tonic-gate * 14397c478bd9Sstevel@tonic-gate * Returns errno on failure, zero on success. 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate int 14427c478bd9Sstevel@tonic-gate putiocd(mblk_t *bp, char *arg, int flag, cred_t *cr) 14437c478bd9Sstevel@tonic-gate { 14447c478bd9Sstevel@tonic-gate mblk_t *tmp; 14457c478bd9Sstevel@tonic-gate ssize_t count; 14467c478bd9Sstevel@tonic-gate int error = 0; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate ASSERT((flag & (U_TO_K | K_TO_K)) == U_TO_K || 14497c478bd9Sstevel@tonic-gate (flag & (U_TO_K | K_TO_K)) == K_TO_K); 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate if (bp->b_datap->db_type == M_IOCTL) { 14527c478bd9Sstevel@tonic-gate count = ((struct iocblk *)bp->b_rptr)->ioc_count; 14537c478bd9Sstevel@tonic-gate } else { 14547c478bd9Sstevel@tonic-gate ASSERT(bp->b_datap->db_type == M_COPYIN); 14557c478bd9Sstevel@tonic-gate count = ((struct copyreq *)bp->b_rptr)->cq_size; 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate /* 14587c478bd9Sstevel@tonic-gate * strdoioctl validates ioc_count, so if this assert fails it 14597c478bd9Sstevel@tonic-gate * cannot be due to user error. 14607c478bd9Sstevel@tonic-gate */ 14617c478bd9Sstevel@tonic-gate ASSERT(count >= 0); 14627c478bd9Sstevel@tonic-gate 1463de8c4a14SErik Nordmark if ((tmp = allocb_cred_wait(count, (flag & STR_NOSIG), &error, cr, 1464de8c4a14SErik Nordmark curproc->p_pid)) == NULL) { 14657c478bd9Sstevel@tonic-gate return (error); 14667c478bd9Sstevel@tonic-gate } 14678aa5c309Sgd78059 error = strcopyin(arg, tmp->b_wptr, count, flag & (U_TO_K|K_TO_K)); 14687c478bd9Sstevel@tonic-gate if (error != 0) { 14697c478bd9Sstevel@tonic-gate freeb(tmp); 14707c478bd9Sstevel@tonic-gate return (error); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate DB_CPID(tmp) = curproc->p_pid; 14738aa5c309Sgd78059 tmp->b_wptr += count; 14748aa5c309Sgd78059 bp->b_cont = tmp; 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate return (0); 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate /* 14807c478bd9Sstevel@tonic-gate * Copy ioctl data to user-land. Return non-zero errno on failure, 14817c478bd9Sstevel@tonic-gate * 0 for success. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate int 14847c478bd9Sstevel@tonic-gate getiocd(mblk_t *bp, char *arg, int copymode) 14857c478bd9Sstevel@tonic-gate { 14867c478bd9Sstevel@tonic-gate ssize_t count; 14877c478bd9Sstevel@tonic-gate size_t n; 14887c478bd9Sstevel@tonic-gate int error; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate if (bp->b_datap->db_type == M_IOCACK) 14917c478bd9Sstevel@tonic-gate count = ((struct iocblk *)bp->b_rptr)->ioc_count; 14927c478bd9Sstevel@tonic-gate else { 14937c478bd9Sstevel@tonic-gate ASSERT(bp->b_datap->db_type == M_COPYOUT); 14947c478bd9Sstevel@tonic-gate count = ((struct copyreq *)bp->b_rptr)->cq_size; 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate ASSERT(count >= 0); 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate for (bp = bp->b_cont; bp && count; 14997c478bd9Sstevel@tonic-gate count -= n, bp = bp->b_cont, arg += n) { 15007c478bd9Sstevel@tonic-gate n = MIN(count, bp->b_wptr - bp->b_rptr); 15017c478bd9Sstevel@tonic-gate error = strcopyout(bp->b_rptr, arg, n, copymode); 15027c478bd9Sstevel@tonic-gate if (error) 15037c478bd9Sstevel@tonic-gate return (error); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate ASSERT(count == 0); 15067c478bd9Sstevel@tonic-gate return (0); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate /* 15107c478bd9Sstevel@tonic-gate * Allocate a linkinfo entry given the write queue of the 15117c478bd9Sstevel@tonic-gate * bottom module of the top stream and the write queue of the 15127c478bd9Sstevel@tonic-gate * stream head of the bottom stream. 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate linkinfo_t * 15157c478bd9Sstevel@tonic-gate alloclink(queue_t *qup, queue_t *qdown, file_t *fpdown) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate linkinfo_t *linkp; 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate linkp = kmem_cache_alloc(linkinfo_cache, KM_SLEEP); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate linkp->li_lblk.l_qtop = qup; 15227c478bd9Sstevel@tonic-gate linkp->li_lblk.l_qbot = qdown; 15237c478bd9Sstevel@tonic-gate linkp->li_fpdown = fpdown; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate mutex_enter(&strresources); 15267c478bd9Sstevel@tonic-gate linkp->li_next = linkinfo_list; 15277c478bd9Sstevel@tonic-gate linkp->li_prev = NULL; 15287c478bd9Sstevel@tonic-gate if (linkp->li_next) 15297c478bd9Sstevel@tonic-gate linkp->li_next->li_prev = linkp; 15307c478bd9Sstevel@tonic-gate linkinfo_list = linkp; 15317c478bd9Sstevel@tonic-gate linkp->li_lblk.l_index = ++lnk_id; 15327c478bd9Sstevel@tonic-gate ASSERT(lnk_id != 0); /* this should never wrap in practice */ 15337c478bd9Sstevel@tonic-gate mutex_exit(&strresources); 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate return (linkp); 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate /* 15397c478bd9Sstevel@tonic-gate * Free a linkinfo entry. 15407c478bd9Sstevel@tonic-gate */ 15417c478bd9Sstevel@tonic-gate void 15427c478bd9Sstevel@tonic-gate lbfree(linkinfo_t *linkp) 15437c478bd9Sstevel@tonic-gate { 15447c478bd9Sstevel@tonic-gate mutex_enter(&strresources); 15457c478bd9Sstevel@tonic-gate if (linkp->li_next) 15467c478bd9Sstevel@tonic-gate linkp->li_next->li_prev = linkp->li_prev; 15477c478bd9Sstevel@tonic-gate if (linkp->li_prev) 15487c478bd9Sstevel@tonic-gate linkp->li_prev->li_next = linkp->li_next; 15497c478bd9Sstevel@tonic-gate else 15507c478bd9Sstevel@tonic-gate linkinfo_list = linkp->li_next; 15517c478bd9Sstevel@tonic-gate mutex_exit(&strresources); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate kmem_cache_free(linkinfo_cache, linkp); 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * Check for a potential linking cycle. 15587c478bd9Sstevel@tonic-gate * Return 1 if a link will result in a cycle, 15597c478bd9Sstevel@tonic-gate * and 0 otherwise. 15607c478bd9Sstevel@tonic-gate */ 15617c478bd9Sstevel@tonic-gate int 1562f4b3ec61Sdh155122 linkcycle(stdata_t *upstp, stdata_t *lostp, str_stack_t *ss) 15637c478bd9Sstevel@tonic-gate { 15647c478bd9Sstevel@tonic-gate struct mux_node *np; 15657c478bd9Sstevel@tonic-gate struct mux_edge *ep; 15667c478bd9Sstevel@tonic-gate int i; 15677c478bd9Sstevel@tonic-gate major_t lomaj; 15687c478bd9Sstevel@tonic-gate major_t upmaj; 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * if the lower stream is a pipe/FIFO, return, since link 15717c478bd9Sstevel@tonic-gate * cycles can not happen on pipes/FIFOs 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate if (lostp->sd_vnode->v_type == VFIFO) 15747c478bd9Sstevel@tonic-gate return (0); 15757c478bd9Sstevel@tonic-gate 1576f4b3ec61Sdh155122 for (i = 0; i < ss->ss_devcnt; i++) { 1577f4b3ec61Sdh155122 np = &ss->ss_mux_nodes[i]; 15787c478bd9Sstevel@tonic-gate MUX_CLEAR(np); 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate lomaj = getmajor(lostp->sd_vnode->v_rdev); 15817c478bd9Sstevel@tonic-gate upmaj = getmajor(upstp->sd_vnode->v_rdev); 1582f4b3ec61Sdh155122 np = &ss->ss_mux_nodes[lomaj]; 15837c478bd9Sstevel@tonic-gate for (;;) { 15847c478bd9Sstevel@tonic-gate if (!MUX_DIDVISIT(np)) { 15857c478bd9Sstevel@tonic-gate if (np->mn_imaj == upmaj) 15867c478bd9Sstevel@tonic-gate return (1); 15877c478bd9Sstevel@tonic-gate if (np->mn_outp == NULL) { 15887c478bd9Sstevel@tonic-gate MUX_VISIT(np); 15897c478bd9Sstevel@tonic-gate if (np->mn_originp == NULL) 15907c478bd9Sstevel@tonic-gate return (0); 15917c478bd9Sstevel@tonic-gate np = np->mn_originp; 15927c478bd9Sstevel@tonic-gate continue; 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate MUX_VISIT(np); 15957c478bd9Sstevel@tonic-gate np->mn_startp = np->mn_outp; 15967c478bd9Sstevel@tonic-gate } else { 15977c478bd9Sstevel@tonic-gate if (np->mn_startp == NULL) { 15987c478bd9Sstevel@tonic-gate if (np->mn_originp == NULL) 15997c478bd9Sstevel@tonic-gate return (0); 16007c478bd9Sstevel@tonic-gate else { 16017c478bd9Sstevel@tonic-gate np = np->mn_originp; 16027c478bd9Sstevel@tonic-gate continue; 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * If ep->me_nodep is a FIFO (me_nodep == NULL), 16077c478bd9Sstevel@tonic-gate * ignore the edge and move on. ep->me_nodep gets 16087c478bd9Sstevel@tonic-gate * set to NULL in mux_addedge() if it is a FIFO. 16097c478bd9Sstevel@tonic-gate * 16107c478bd9Sstevel@tonic-gate */ 16117c478bd9Sstevel@tonic-gate ep = np->mn_startp; 16127c478bd9Sstevel@tonic-gate np->mn_startp = ep->me_nextp; 16137c478bd9Sstevel@tonic-gate if (ep->me_nodep == NULL) 16147c478bd9Sstevel@tonic-gate continue; 16157c478bd9Sstevel@tonic-gate ep->me_nodep->mn_originp = np; 16167c478bd9Sstevel@tonic-gate np = ep->me_nodep; 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * Find linkinfo entry corresponding to the parameters. 16237c478bd9Sstevel@tonic-gate */ 16247c478bd9Sstevel@tonic-gate linkinfo_t * 1625f4b3ec61Sdh155122 findlinks(stdata_t *stp, int index, int type, str_stack_t *ss) 16267c478bd9Sstevel@tonic-gate { 16277c478bd9Sstevel@tonic-gate linkinfo_t *linkp; 16287c478bd9Sstevel@tonic-gate struct mux_edge *mep; 16297c478bd9Sstevel@tonic-gate struct mux_node *mnp; 16307c478bd9Sstevel@tonic-gate queue_t *qup; 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate mutex_enter(&strresources); 16337c478bd9Sstevel@tonic-gate if ((type & LINKTYPEMASK) == LINKNORMAL) { 16347c478bd9Sstevel@tonic-gate qup = getendq(stp->sd_wrq); 16357c478bd9Sstevel@tonic-gate for (linkp = linkinfo_list; linkp; linkp = linkp->li_next) { 16367c478bd9Sstevel@tonic-gate if ((qup == linkp->li_lblk.l_qtop) && 16377c478bd9Sstevel@tonic-gate (!index || (index == linkp->li_lblk.l_index))) { 16387c478bd9Sstevel@tonic-gate mutex_exit(&strresources); 16397c478bd9Sstevel@tonic-gate return (linkp); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate } else { 16437c478bd9Sstevel@tonic-gate ASSERT((type & LINKTYPEMASK) == LINKPERSIST); 1644f4b3ec61Sdh155122 mnp = &ss->ss_mux_nodes[getmajor(stp->sd_vnode->v_rdev)]; 16457c478bd9Sstevel@tonic-gate mep = mnp->mn_outp; 16467c478bd9Sstevel@tonic-gate while (mep) { 16477c478bd9Sstevel@tonic-gate if ((index == 0) || (index == mep->me_muxid)) 16487c478bd9Sstevel@tonic-gate break; 16497c478bd9Sstevel@tonic-gate mep = mep->me_nextp; 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate if (!mep) { 16527c478bd9Sstevel@tonic-gate mutex_exit(&strresources); 16537c478bd9Sstevel@tonic-gate return (NULL); 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate for (linkp = linkinfo_list; linkp; linkp = linkp->li_next) { 16567c478bd9Sstevel@tonic-gate if ((!linkp->li_lblk.l_qtop) && 16577c478bd9Sstevel@tonic-gate (mep->me_muxid == linkp->li_lblk.l_index)) { 16587c478bd9Sstevel@tonic-gate mutex_exit(&strresources); 16597c478bd9Sstevel@tonic-gate return (linkp); 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate mutex_exit(&strresources); 16647c478bd9Sstevel@tonic-gate return (NULL); 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate /* 16687c478bd9Sstevel@tonic-gate * Given a queue ptr, follow the chain of q_next pointers until you reach the 16697c478bd9Sstevel@tonic-gate * last queue on the chain and return it. 16707c478bd9Sstevel@tonic-gate */ 16717c478bd9Sstevel@tonic-gate queue_t * 16727c478bd9Sstevel@tonic-gate getendq(queue_t *q) 16737c478bd9Sstevel@tonic-gate { 16747c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 16757c478bd9Sstevel@tonic-gate while (_SAMESTR(q)) 16767c478bd9Sstevel@tonic-gate q = q->q_next; 16777c478bd9Sstevel@tonic-gate return (q); 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate /* 168121804b56SBrian Ruthven * Wait for the syncq count to drop to zero. 16827c478bd9Sstevel@tonic-gate * sq could be either outer or inner. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate static void 16867c478bd9Sstevel@tonic-gate wait_syncq(syncq_t *sq) 16877c478bd9Sstevel@tonic-gate { 16887c478bd9Sstevel@tonic-gate uint16_t count; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 16917c478bd9Sstevel@tonic-gate count = sq->sq_count; 16927c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 16937c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 16947c478bd9Sstevel@tonic-gate while (count != 0) { 16957c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 16967c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 16977c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 16987c478bd9Sstevel@tonic-gate count = sq->sq_count; 16997c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 17007c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 17017c478bd9Sstevel@tonic-gate } 17027c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 17037c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate /* 17077c478bd9Sstevel@tonic-gate * Wait while there are any messages for the queue in its syncq. 17087c478bd9Sstevel@tonic-gate */ 17097c478bd9Sstevel@tonic-gate static void 17107c478bd9Sstevel@tonic-gate wait_q_syncq(queue_t *q) 17117c478bd9Sstevel@tonic-gate { 17127c478bd9Sstevel@tonic-gate if ((q->q_sqflags & Q_SQQUEUED) || (q->q_syncqmsgs > 0)) { 17137c478bd9Sstevel@tonic-gate syncq_t *sq = q->q_syncq; 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 17167c478bd9Sstevel@tonic-gate while ((q->q_sqflags & Q_SQQUEUED) || (q->q_syncqmsgs > 0)) { 17177c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 17187c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate int 17267c478bd9Sstevel@tonic-gate mlink_file(vnode_t *vp, int cmd, struct file *fpdown, cred_t *crp, int *rvalp, 17277c478bd9Sstevel@tonic-gate int lhlink) 17287c478bd9Sstevel@tonic-gate { 17297c478bd9Sstevel@tonic-gate struct stdata *stp; 17307c478bd9Sstevel@tonic-gate struct strioctl strioc; 17317c478bd9Sstevel@tonic-gate struct linkinfo *linkp; 17327c478bd9Sstevel@tonic-gate struct stdata *stpdown; 17337c478bd9Sstevel@tonic-gate struct streamtab *str; 17347c478bd9Sstevel@tonic-gate queue_t *passq; 17357c478bd9Sstevel@tonic-gate syncq_t *passyncq; 17367c478bd9Sstevel@tonic-gate queue_t *rq; 17377c478bd9Sstevel@tonic-gate cdevsw_impl_t *dp; 17387c478bd9Sstevel@tonic-gate uint32_t qflag; 17397c478bd9Sstevel@tonic-gate uint32_t sqtype; 17407c478bd9Sstevel@tonic-gate perdm_t *dmp; 17417c478bd9Sstevel@tonic-gate int error = 0; 1742f4b3ec61Sdh155122 netstack_t *ns; 1743f4b3ec61Sdh155122 str_stack_t *ss; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate stp = vp->v_stream; 17467c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, 17477c478bd9Sstevel@tonic-gate TR_I_LINK, "I_LINK/I_PLINK:stp %p", stp); 17487c478bd9Sstevel@tonic-gate /* 17497c478bd9Sstevel@tonic-gate * Test for invalid upper stream 17507c478bd9Sstevel@tonic-gate */ 17517c478bd9Sstevel@tonic-gate if (stp->sd_flag & STRHUP) { 17527c478bd9Sstevel@tonic-gate return (ENXIO); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate if (vp->v_type == VFIFO) { 17557c478bd9Sstevel@tonic-gate return (EINVAL); 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate if (stp->sd_strtab == NULL) { 17587c478bd9Sstevel@tonic-gate return (EINVAL); 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate if (!stp->sd_strtab->st_muxwinit) { 17617c478bd9Sstevel@tonic-gate return (EINVAL); 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate if (fpdown == NULL) { 17647c478bd9Sstevel@tonic-gate return (EBADF); 17657c478bd9Sstevel@tonic-gate } 1766f4b3ec61Sdh155122 ns = netstack_find_by_cred(crp); 1767f4b3ec61Sdh155122 ASSERT(ns != NULL); 1768f4b3ec61Sdh155122 ss = ns->netstack_str; 1769f4b3ec61Sdh155122 ASSERT(ss != NULL); 1770f4b3ec61Sdh155122 1771f4b3ec61Sdh155122 if (getmajor(stp->sd_vnode->v_rdev) >= ss->ss_devcnt) { 1772f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 17737c478bd9Sstevel@tonic-gate return (EINVAL); 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate mutex_enter(&muxifier); 17767c478bd9Sstevel@tonic-gate if (stp->sd_flag & STPLEX) { 17777c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 1778f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 17797c478bd9Sstevel@tonic-gate return (ENXIO); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* 17837c478bd9Sstevel@tonic-gate * Test for invalid lower stream. 17847c478bd9Sstevel@tonic-gate * The check for the v_type != VFIFO and having a major 17857c478bd9Sstevel@tonic-gate * number not >= devcnt is done to avoid problems with 17867c478bd9Sstevel@tonic-gate * adding mux_node entry past the end of mux_nodes[]. 17877c478bd9Sstevel@tonic-gate * For FIFO's we don't add an entry so this isn't a 17887c478bd9Sstevel@tonic-gate * problem. 17897c478bd9Sstevel@tonic-gate */ 17907c478bd9Sstevel@tonic-gate if (((stpdown = fpdown->f_vnode->v_stream) == NULL) || 17917c478bd9Sstevel@tonic-gate (stpdown == stp) || (stpdown->sd_flag & 17927c478bd9Sstevel@tonic-gate (STPLEX|STRHUP|STRDERR|STWRERR|IOCWAIT|STRPLUMB)) || 17937c478bd9Sstevel@tonic-gate ((stpdown->sd_vnode->v_type != VFIFO) && 1794f4b3ec61Sdh155122 (getmajor(stpdown->sd_vnode->v_rdev) >= ss->ss_devcnt)) || 1795f4b3ec61Sdh155122 linkcycle(stp, stpdown, ss)) { 17967c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 1797f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 17987c478bd9Sstevel@tonic-gate return (EINVAL); 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, 18017c478bd9Sstevel@tonic-gate TR_STPDOWN, "stpdown:%p", stpdown); 18027c478bd9Sstevel@tonic-gate rq = getendq(stp->sd_wrq); 18037c478bd9Sstevel@tonic-gate if (cmd == I_PLINK) 18047c478bd9Sstevel@tonic-gate rq = NULL; 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate linkp = alloclink(rq, stpdown->sd_wrq, fpdown); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate strioc.ic_cmd = cmd; 18097c478bd9Sstevel@tonic-gate strioc.ic_timout = INFTIM; 18107c478bd9Sstevel@tonic-gate strioc.ic_len = sizeof (struct linkblk); 18117c478bd9Sstevel@tonic-gate strioc.ic_dp = (char *)&linkp->li_lblk; 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate /* 18147c478bd9Sstevel@tonic-gate * STRPLUMB protects plumbing changes and should be set before 18157c478bd9Sstevel@tonic-gate * link_addpassthru()/link_rempassthru() are called, so it is set here 18167c478bd9Sstevel@tonic-gate * and cleared in the end of mlink when passthru queue is removed. 18177c478bd9Sstevel@tonic-gate * Setting of STRPLUMB prevents reopens of the stream while passthru 18187c478bd9Sstevel@tonic-gate * queue is in-place (it is not a proper module and doesn't have open 18197c478bd9Sstevel@tonic-gate * entry point). 18207c478bd9Sstevel@tonic-gate * 18217c478bd9Sstevel@tonic-gate * STPLEX prevents any threads from entering the stream from above. It 18227c478bd9Sstevel@tonic-gate * can't be set before the call to link_addpassthru() because putnext 18237c478bd9Sstevel@tonic-gate * from below may cause stream head I/O routines to be called and these 18247c478bd9Sstevel@tonic-gate * routines assert that STPLEX is not set. After link_addpassthru() 18257c478bd9Sstevel@tonic-gate * nothing may come from below since the pass queue syncq is blocked. 18267c478bd9Sstevel@tonic-gate * Note also that STPLEX should be cleared before the call to 182721804b56SBrian Ruthven * link_rempassthru() since when messages start flowing to the stream 18287c478bd9Sstevel@tonic-gate * head (e.g. because of message propagation from the pass queue) stream 18297c478bd9Sstevel@tonic-gate * head I/O routines may be called with STPLEX flag set. 18307c478bd9Sstevel@tonic-gate * 18317c478bd9Sstevel@tonic-gate * When STPLEX is set, nothing may come into the stream from above and 18327c478bd9Sstevel@tonic-gate * it is safe to do a setq which will change stream head. So, the 18337c478bd9Sstevel@tonic-gate * correct sequence of actions is: 18347c478bd9Sstevel@tonic-gate * 18357c478bd9Sstevel@tonic-gate * 1) Set STRPLUMB 18367c478bd9Sstevel@tonic-gate * 2) Call link_addpassthru() 18377c478bd9Sstevel@tonic-gate * 3) Set STPLEX 18387c478bd9Sstevel@tonic-gate * 4) Call setq and update the stream state 18397c478bd9Sstevel@tonic-gate * 5) Clear STPLEX 18407c478bd9Sstevel@tonic-gate * 6) Call link_rempassthru() 18417c478bd9Sstevel@tonic-gate * 7) Clear STRPLUMB 18427c478bd9Sstevel@tonic-gate * 18437c478bd9Sstevel@tonic-gate * The same sequence applies to munlink() code. 18447c478bd9Sstevel@tonic-gate */ 18457c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 18467c478bd9Sstevel@tonic-gate stpdown->sd_flag |= STRPLUMB; 18477c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * Add passthru queue below lower mux. This will block 18507c478bd9Sstevel@tonic-gate * syncqs of lower muxs read queue during I_LINK/I_UNLINK. 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate passq = link_addpassthru(stpdown); 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 18557c478bd9Sstevel@tonic-gate stpdown->sd_flag |= STPLEX; 18567c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate rq = _RD(stpdown->sd_wrq); 18597c478bd9Sstevel@tonic-gate /* 18607c478bd9Sstevel@tonic-gate * There may be messages in the streamhead's syncq due to messages 18617c478bd9Sstevel@tonic-gate * that arrived before link_addpassthru() was done. To avoid 18627c478bd9Sstevel@tonic-gate * background processing of the syncq happening simultaneous with 18637c478bd9Sstevel@tonic-gate * setq processing, we disable the streamhead syncq and wait until 18647c478bd9Sstevel@tonic-gate * existing background thread finishes working on it. 18657c478bd9Sstevel@tonic-gate */ 18667c478bd9Sstevel@tonic-gate wait_sq_svc(rq->q_syncq); 18677c478bd9Sstevel@tonic-gate passyncq = passq->q_syncq; 18687c478bd9Sstevel@tonic-gate if (!(passyncq->sq_flags & SQ_BLOCKED)) 18697c478bd9Sstevel@tonic-gate blocksq(passyncq, SQ_BLOCKED, 0); 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate ASSERT((rq->q_flag & QMT_TYPEMASK) == QMTSAFE); 18727c478bd9Sstevel@tonic-gate ASSERT(rq->q_syncq == SQ(rq) && _WR(rq)->q_syncq == SQ(rq)); 18737c478bd9Sstevel@tonic-gate rq->q_ptr = _WR(rq)->q_ptr = NULL; 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate /* setq might sleep in allocator - avoid holding locks. */ 18767c478bd9Sstevel@tonic-gate /* Note: we are holding muxifier here. */ 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate str = stp->sd_strtab; 18797c478bd9Sstevel@tonic-gate dp = &devimpl[getmajor(vp->v_rdev)]; 18807c478bd9Sstevel@tonic-gate ASSERT(dp->d_str == str); 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate qflag = dp->d_qflag; 18837c478bd9Sstevel@tonic-gate sqtype = dp->d_sqtype; 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate /* create perdm_t if needed */ 18867c478bd9Sstevel@tonic-gate if (NEED_DM(dp->d_dmp, qflag)) 18877c478bd9Sstevel@tonic-gate dp->d_dmp = hold_dm(str, qflag, sqtype); 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate dmp = dp->d_dmp; 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate setq(rq, str->st_muxrinit, str->st_muxwinit, dmp, qflag, sqtype, 18927c478bd9Sstevel@tonic-gate B_TRUE); 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate /* 18957c478bd9Sstevel@tonic-gate * XXX Remove any "odd" messages from the queue. 18967c478bd9Sstevel@tonic-gate * Keep only M_DATA, M_PROTO, M_PCPROTO. 18977c478bd9Sstevel@tonic-gate */ 18987c478bd9Sstevel@tonic-gate error = strdoioctl(stp, &strioc, FNATIVE, 18997c478bd9Sstevel@tonic-gate K_TO_K | STR_NOERROR | STR_NOSIG, crp, rvalp); 19007c478bd9Sstevel@tonic-gate if (error != 0) { 19017c478bd9Sstevel@tonic-gate lbfree(linkp); 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate if (!(passyncq->sq_flags & SQ_BLOCKED)) 19047c478bd9Sstevel@tonic-gate blocksq(passyncq, SQ_BLOCKED, 0); 19057c478bd9Sstevel@tonic-gate /* 19067c478bd9Sstevel@tonic-gate * Restore the stream head queue and then remove 19077c478bd9Sstevel@tonic-gate * the passq. Turn off STPLEX before we turn on 19087c478bd9Sstevel@tonic-gate * the stream by removing the passq. 19097c478bd9Sstevel@tonic-gate */ 19107c478bd9Sstevel@tonic-gate rq->q_ptr = _WR(rq)->q_ptr = stpdown; 19117c478bd9Sstevel@tonic-gate setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, 19127c478bd9Sstevel@tonic-gate B_TRUE); 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 19157c478bd9Sstevel@tonic-gate stpdown->sd_flag &= ~STPLEX; 19167c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate link_rempassthru(passq); 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 19217c478bd9Sstevel@tonic-gate stpdown->sd_flag &= ~STRPLUMB; 19227c478bd9Sstevel@tonic-gate /* Wakeup anyone waiting for STRPLUMB to clear. */ 19237c478bd9Sstevel@tonic-gate cv_broadcast(&stpdown->sd_monitor); 19247c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 1927f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 19287c478bd9Sstevel@tonic-gate return (error); 19297c478bd9Sstevel@tonic-gate } 19307c478bd9Sstevel@tonic-gate mutex_enter(&fpdown->f_tlock); 19317c478bd9Sstevel@tonic-gate fpdown->f_count++; 19327c478bd9Sstevel@tonic-gate mutex_exit(&fpdown->f_tlock); 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate /* 19357c478bd9Sstevel@tonic-gate * if we've made it here the linkage is all set up so we should also 19367c478bd9Sstevel@tonic-gate * set up the layered driver linkages 19377c478bd9Sstevel@tonic-gate */ 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate ASSERT((cmd == I_LINK) || (cmd == I_PLINK)); 19407c478bd9Sstevel@tonic-gate if (cmd == I_LINK) { 19417c478bd9Sstevel@tonic-gate ldi_mlink_fp(stp, fpdown, lhlink, LINKNORMAL); 19427c478bd9Sstevel@tonic-gate } else { 19437c478bd9Sstevel@tonic-gate ldi_mlink_fp(stp, fpdown, lhlink, LINKPERSIST); 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate link_rempassthru(passq); 19477c478bd9Sstevel@tonic-gate 1948f4b3ec61Sdh155122 mux_addedge(stp, stpdown, linkp->li_lblk.l_index, ss); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate /* 19517c478bd9Sstevel@tonic-gate * Mark the upper stream as having dependent links 19527c478bd9Sstevel@tonic-gate * so that strclose can clean it up. 19537c478bd9Sstevel@tonic-gate */ 19547c478bd9Sstevel@tonic-gate if (cmd == I_LINK) { 19557c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 19567c478bd9Sstevel@tonic-gate stp->sd_flag |= STRHASLINKS; 19577c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate /* 19607c478bd9Sstevel@tonic-gate * Wake up any other processes that may have been 19617c478bd9Sstevel@tonic-gate * waiting on the lower stream. These will all 19627c478bd9Sstevel@tonic-gate * error out. 19637c478bd9Sstevel@tonic-gate */ 19647c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 19657c478bd9Sstevel@tonic-gate /* The passthru module is removed so we may release STRPLUMB */ 19667c478bd9Sstevel@tonic-gate stpdown->sd_flag &= ~STRPLUMB; 19677c478bd9Sstevel@tonic-gate cv_broadcast(&rq->q_wait); 19687c478bd9Sstevel@tonic-gate cv_broadcast(&_WR(rq)->q_wait); 19697c478bd9Sstevel@tonic-gate cv_broadcast(&stpdown->sd_monitor); 19707c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 19717c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 19727c478bd9Sstevel@tonic-gate *rvalp = linkp->li_lblk.l_index; 1973f4b3ec61Sdh155122 netstack_rele(ss->ss_netstack); 19747c478bd9Sstevel@tonic-gate return (0); 19757c478bd9Sstevel@tonic-gate } 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate int 19787c478bd9Sstevel@tonic-gate mlink(vnode_t *vp, int cmd, int arg, cred_t *crp, int *rvalp, int lhlink) 19797c478bd9Sstevel@tonic-gate { 19807c478bd9Sstevel@tonic-gate int ret; 19817c478bd9Sstevel@tonic-gate struct file *fpdown; 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate fpdown = getf(arg); 19847c478bd9Sstevel@tonic-gate ret = mlink_file(vp, cmd, fpdown, crp, rvalp, lhlink); 19857c478bd9Sstevel@tonic-gate if (fpdown != NULL) 19867c478bd9Sstevel@tonic-gate releasef(arg); 19877c478bd9Sstevel@tonic-gate return (ret); 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate /* 19917c478bd9Sstevel@tonic-gate * Unlink a multiplexor link. Stp is the controlling stream for the 19927c478bd9Sstevel@tonic-gate * link, and linkp points to the link's entry in the linkinfo list. 19937c478bd9Sstevel@tonic-gate * The muxifier lock must be held on entry and is dropped on exit. 19947c478bd9Sstevel@tonic-gate * 19957c478bd9Sstevel@tonic-gate * NOTE : Currently it is assumed that mux would process all the messages 19967c478bd9Sstevel@tonic-gate * sitting on it's queue before ACKing the UNLINK. It is the responsibility 19977c478bd9Sstevel@tonic-gate * of the mux to handle all the messages that arrive before UNLINK. 19987c478bd9Sstevel@tonic-gate * If the mux has to send down messages on its lower stream before 19997c478bd9Sstevel@tonic-gate * ACKing I_UNLINK, then it *should* know to handle messages even 20007c478bd9Sstevel@tonic-gate * after the UNLINK is acked (actually it should be able to handle till we 20017c478bd9Sstevel@tonic-gate * re-block the read side of the pass queue here). If the mux does not 20027c478bd9Sstevel@tonic-gate * open up the lower stream, any messages that arrive during UNLINK 20037c478bd9Sstevel@tonic-gate * will be put in the stream head. In the case of lower stream opening 20047c478bd9Sstevel@tonic-gate * up, some messages might land in the stream head depending on when 20057c478bd9Sstevel@tonic-gate * the message arrived and when the read side of the pass queue was 20067c478bd9Sstevel@tonic-gate * re-blocked. 20077c478bd9Sstevel@tonic-gate */ 20087c478bd9Sstevel@tonic-gate int 2009f4b3ec61Sdh155122 munlink(stdata_t *stp, linkinfo_t *linkp, int flag, cred_t *crp, int *rvalp, 2010f4b3ec61Sdh155122 str_stack_t *ss) 20117c478bd9Sstevel@tonic-gate { 20127c478bd9Sstevel@tonic-gate struct strioctl strioc; 20137c478bd9Sstevel@tonic-gate struct stdata *stpdown; 20147c478bd9Sstevel@tonic-gate queue_t *rq, *wrq; 20157c478bd9Sstevel@tonic-gate queue_t *passq; 20167c478bd9Sstevel@tonic-gate syncq_t *passyncq; 20177c478bd9Sstevel@tonic-gate int error = 0; 20187c478bd9Sstevel@tonic-gate file_t *fpdown; 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&muxifier)); 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate stpdown = linkp->li_fpdown->f_vnode->v_stream; 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate /* 20257c478bd9Sstevel@tonic-gate * See the comment in mlink() concerning STRPLUMB/STPLEX flags. 20267c478bd9Sstevel@tonic-gate */ 20277c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 20287c478bd9Sstevel@tonic-gate stpdown->sd_flag |= STRPLUMB; 20297c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate /* 20327c478bd9Sstevel@tonic-gate * Add passthru queue below lower mux. This will block 20337c478bd9Sstevel@tonic-gate * syncqs of lower muxs read queue during I_LINK/I_UNLINK. 20347c478bd9Sstevel@tonic-gate */ 20357c478bd9Sstevel@tonic-gate passq = link_addpassthru(stpdown); 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate if ((flag & LINKTYPEMASK) == LINKNORMAL) 20387c478bd9Sstevel@tonic-gate strioc.ic_cmd = I_UNLINK; 20397c478bd9Sstevel@tonic-gate else 20407c478bd9Sstevel@tonic-gate strioc.ic_cmd = I_PUNLINK; 20417c478bd9Sstevel@tonic-gate strioc.ic_timout = INFTIM; 20427c478bd9Sstevel@tonic-gate strioc.ic_len = sizeof (struct linkblk); 20437c478bd9Sstevel@tonic-gate strioc.ic_dp = (char *)&linkp->li_lblk; 20447c478bd9Sstevel@tonic-gate 20457c478bd9Sstevel@tonic-gate error = strdoioctl(stp, &strioc, FNATIVE, 20467c478bd9Sstevel@tonic-gate K_TO_K | STR_NOERROR | STR_NOSIG, crp, rvalp); 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate /* 20497c478bd9Sstevel@tonic-gate * If there was an error and this is not called via strclose, 20507c478bd9Sstevel@tonic-gate * return to the user. Otherwise, pretend there was no error 20517c478bd9Sstevel@tonic-gate * and close the link. 20527c478bd9Sstevel@tonic-gate */ 20537c478bd9Sstevel@tonic-gate if (error) { 20547c478bd9Sstevel@tonic-gate if (flag & LINKCLOSE) { 20557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "KERNEL: munlink: could not perform " 20567c478bd9Sstevel@tonic-gate "unlink ioctl, closing anyway (%d)\n", error); 20577c478bd9Sstevel@tonic-gate } else { 20587c478bd9Sstevel@tonic-gate link_rempassthru(passq); 20597c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 20607c478bd9Sstevel@tonic-gate stpdown->sd_flag &= ~STRPLUMB; 20617c478bd9Sstevel@tonic-gate cv_broadcast(&stpdown->sd_monitor); 20627c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 20637c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 20647c478bd9Sstevel@tonic-gate return (error); 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate 2068f4b3ec61Sdh155122 mux_rmvedge(stp, linkp->li_lblk.l_index, ss); 20697c478bd9Sstevel@tonic-gate fpdown = linkp->li_fpdown; 20707c478bd9Sstevel@tonic-gate lbfree(linkp); 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * We go ahead and drop muxifier here--it's a nasty global lock that 20747c478bd9Sstevel@tonic-gate * can slow others down. It's okay to since attempts to mlink() this 20757c478bd9Sstevel@tonic-gate * stream will be stopped because STPLEX is still set in the stdata 20767c478bd9Sstevel@tonic-gate * structure, and munlink() is stopped because mux_rmvedge() and 20777c478bd9Sstevel@tonic-gate * lbfree() have removed it from mux_nodes[] and linkinfo_list, 20787c478bd9Sstevel@tonic-gate * respectively. Note that we defer the closef() of fpdown until 20797c478bd9Sstevel@tonic-gate * after we drop muxifier since strclose() can call munlinkall(). 20807c478bd9Sstevel@tonic-gate */ 20817c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate wrq = stpdown->sd_wrq; 20847c478bd9Sstevel@tonic-gate rq = _RD(wrq); 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate /* 20877c478bd9Sstevel@tonic-gate * Get rid of outstanding service procedure runs, before we make 20887c478bd9Sstevel@tonic-gate * it a stream head, since a stream head doesn't have any service 20897c478bd9Sstevel@tonic-gate * procedure. 20907c478bd9Sstevel@tonic-gate */ 20917c478bd9Sstevel@tonic-gate disable_svc(rq); 20927c478bd9Sstevel@tonic-gate wait_svc(rq); 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate /* 20957c478bd9Sstevel@tonic-gate * Since we don't disable the syncq for QPERMOD, we wait for whatever 20967c478bd9Sstevel@tonic-gate * is queued up to be finished. mux should take care that nothing is 20977c478bd9Sstevel@tonic-gate * send down to this queue. We should do it now as we're going to block 20987c478bd9Sstevel@tonic-gate * passyncq if it was unblocked. 20997c478bd9Sstevel@tonic-gate */ 21007c478bd9Sstevel@tonic-gate if (wrq->q_flag & QPERMOD) { 21017c478bd9Sstevel@tonic-gate syncq_t *sq = wrq->q_syncq; 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 21047c478bd9Sstevel@tonic-gate while (wrq->q_sqflags & Q_SQQUEUED) { 21057c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 21067c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate passyncq = passq->q_syncq; 21117c478bd9Sstevel@tonic-gate if (!(passyncq->sq_flags & SQ_BLOCKED)) { 21127c478bd9Sstevel@tonic-gate 21137c478bd9Sstevel@tonic-gate syncq_t *sq, *outer; 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate /* 21167c478bd9Sstevel@tonic-gate * Messages could be flowing from underneath. We will 21177c478bd9Sstevel@tonic-gate * block the read side of the passq. This would be 21187c478bd9Sstevel@tonic-gate * sufficient for QPAIR and QPERQ muxes to ensure 21197c478bd9Sstevel@tonic-gate * that no data is flowing up into this queue 21207c478bd9Sstevel@tonic-gate * and hence no thread active in this instance of 21217c478bd9Sstevel@tonic-gate * lower mux. But for QPERMOD and QMTOUTPERIM there 21227c478bd9Sstevel@tonic-gate * could be messages on the inner and outer/inner 21237c478bd9Sstevel@tonic-gate * syncqs respectively. We will wait for them to drain. 21247c478bd9Sstevel@tonic-gate * Because passq is blocked messages end up in the syncq 21257c478bd9Sstevel@tonic-gate * And qfill_syncq could possibly end up setting QFULL 21267c478bd9Sstevel@tonic-gate * which will access the rq->q_flag. Hence, we have to 21277c478bd9Sstevel@tonic-gate * acquire the QLOCK in setq. 21287c478bd9Sstevel@tonic-gate * 21297c478bd9Sstevel@tonic-gate * XXX Messages can also flow from top into this 21307c478bd9Sstevel@tonic-gate * queue though the unlink is over (Ex. some instance 21317c478bd9Sstevel@tonic-gate * in putnext() called from top that has still not 21327c478bd9Sstevel@tonic-gate * accessed this queue. And also putq(lowerq) ?). 21337c478bd9Sstevel@tonic-gate * Solution : How about blocking the l_qtop queue ? 21347c478bd9Sstevel@tonic-gate * Do we really care about such pure D_MP muxes ? 21357c478bd9Sstevel@tonic-gate */ 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate blocksq(passyncq, SQ_BLOCKED, 0); 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate sq = rq->q_syncq; 21407c478bd9Sstevel@tonic-gate if ((outer = sq->sq_outer) != NULL) { 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate /* 21437c478bd9Sstevel@tonic-gate * We have to just wait for the outer sq_count 21447c478bd9Sstevel@tonic-gate * drop to zero. As this does not prevent new 21457c478bd9Sstevel@tonic-gate * messages to enter the outer perimeter, this 21467c478bd9Sstevel@tonic-gate * is subject to starvation. 21477c478bd9Sstevel@tonic-gate * 21487c478bd9Sstevel@tonic-gate * NOTE :Because of blocksq above, messages could 21497c478bd9Sstevel@tonic-gate * be in the inner syncq only because of some 21507c478bd9Sstevel@tonic-gate * thread holding the outer perimeter exclusively. 21517c478bd9Sstevel@tonic-gate * Hence it would be sufficient to wait for the 21527c478bd9Sstevel@tonic-gate * exclusive holder of the outer perimeter to drain 21537c478bd9Sstevel@tonic-gate * the inner and outer syncqs. But we will not depend 21547c478bd9Sstevel@tonic-gate * on this feature and hence check the inner syncqs 21557c478bd9Sstevel@tonic-gate * separately. 21567c478bd9Sstevel@tonic-gate */ 21577c478bd9Sstevel@tonic-gate wait_syncq(outer); 21587c478bd9Sstevel@tonic-gate } 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate /* 21627c478bd9Sstevel@tonic-gate * There could be messages destined for 21637c478bd9Sstevel@tonic-gate * this queue. Let the exclusive holder 21647c478bd9Sstevel@tonic-gate * drain it. 21657c478bd9Sstevel@tonic-gate */ 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate wait_syncq(sq); 21687c478bd9Sstevel@tonic-gate ASSERT((rq->q_flag & QPERMOD) || 21697c478bd9Sstevel@tonic-gate ((rq->q_syncq->sq_head == NULL) && 21707c478bd9Sstevel@tonic-gate (_WR(rq)->q_syncq->sq_head == NULL))); 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate /* 21747c478bd9Sstevel@tonic-gate * We haven't taken care of QPERMOD case yet. QPERMOD is a special 21757c478bd9Sstevel@tonic-gate * case as we don't disable its syncq or remove it off the syncq 21767c478bd9Sstevel@tonic-gate * service list. 21777c478bd9Sstevel@tonic-gate */ 21787c478bd9Sstevel@tonic-gate if (rq->q_flag & QPERMOD) { 21797c478bd9Sstevel@tonic-gate syncq_t *sq = rq->q_syncq; 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 21827c478bd9Sstevel@tonic-gate while (rq->q_sqflags & Q_SQQUEUED) { 21837c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 21847c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 21877c478bd9Sstevel@tonic-gate } 21887c478bd9Sstevel@tonic-gate 21897c478bd9Sstevel@tonic-gate /* 219021804b56SBrian Ruthven * flush_syncq changes states only when there are some messages to 219121804b56SBrian Ruthven * free, i.e. when it returns non-zero value to return. 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate ASSERT(flush_syncq(rq->q_syncq, rq) == 0); 21947c478bd9Sstevel@tonic-gate ASSERT(flush_syncq(wrq->q_syncq, wrq) == 0); 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate /* 21977c478bd9Sstevel@tonic-gate * Nobody else should know about this queue now. 21987c478bd9Sstevel@tonic-gate * If the mux did not process the messages before 21997c478bd9Sstevel@tonic-gate * acking the I_UNLINK, free them now. 22007c478bd9Sstevel@tonic-gate */ 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate flushq(rq, FLUSHALL); 22037c478bd9Sstevel@tonic-gate flushq(_WR(rq), FLUSHALL); 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate /* 22067c478bd9Sstevel@tonic-gate * Convert the mux lower queue into a stream head queue. 22077c478bd9Sstevel@tonic-gate * Turn off STPLEX before we turn on the stream by removing the passq. 22087c478bd9Sstevel@tonic-gate */ 22097c478bd9Sstevel@tonic-gate rq->q_ptr = wrq->q_ptr = stpdown; 22107c478bd9Sstevel@tonic-gate setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_TRUE); 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate ASSERT((rq->q_flag & QMT_TYPEMASK) == QMTSAFE); 22137c478bd9Sstevel@tonic-gate ASSERT(rq->q_syncq == SQ(rq) && _WR(rq)->q_syncq == SQ(rq)); 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate enable_svc(rq); 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate /* 22187c478bd9Sstevel@tonic-gate * Now it is a proper stream, so STPLEX is cleared. But STRPLUMB still 22197c478bd9Sstevel@tonic-gate * needs to be set to prevent reopen() of the stream - such reopen may 22207c478bd9Sstevel@tonic-gate * try to call non-existent pass queue open routine and panic. 22217c478bd9Sstevel@tonic-gate */ 22227c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 22237c478bd9Sstevel@tonic-gate stpdown->sd_flag &= ~STPLEX; 22247c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate ASSERT(((flag & LINKTYPEMASK) == LINKNORMAL) || 22277c478bd9Sstevel@tonic-gate ((flag & LINKTYPEMASK) == LINKPERSIST)); 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate /* clean up the layered driver linkages */ 22307c478bd9Sstevel@tonic-gate if ((flag & LINKTYPEMASK) == LINKNORMAL) { 22317c478bd9Sstevel@tonic-gate ldi_munlink_fp(stp, fpdown, LINKNORMAL); 22327c478bd9Sstevel@tonic-gate } else { 22337c478bd9Sstevel@tonic-gate ldi_munlink_fp(stp, fpdown, LINKPERSIST); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate link_rempassthru(passq); 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate /* 22397c478bd9Sstevel@tonic-gate * Now all plumbing changes are finished and STRPLUMB is no 22407c478bd9Sstevel@tonic-gate * longer needed. 22417c478bd9Sstevel@tonic-gate */ 22427c478bd9Sstevel@tonic-gate mutex_enter(&stpdown->sd_lock); 22437c478bd9Sstevel@tonic-gate stpdown->sd_flag &= ~STRPLUMB; 22447c478bd9Sstevel@tonic-gate cv_broadcast(&stpdown->sd_monitor); 22457c478bd9Sstevel@tonic-gate mutex_exit(&stpdown->sd_lock); 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate (void) closef(fpdown); 22487c478bd9Sstevel@tonic-gate return (0); 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * Unlink all multiplexor links for which stp is the controlling stream. 22537c478bd9Sstevel@tonic-gate * Return 0, or a non-zero errno on failure. 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate int 2256f4b3ec61Sdh155122 munlinkall(stdata_t *stp, int flag, cred_t *crp, int *rvalp, str_stack_t *ss) 22577c478bd9Sstevel@tonic-gate { 22587c478bd9Sstevel@tonic-gate linkinfo_t *linkp; 22597c478bd9Sstevel@tonic-gate int error = 0; 22607c478bd9Sstevel@tonic-gate 22617c478bd9Sstevel@tonic-gate mutex_enter(&muxifier); 2262f4b3ec61Sdh155122 while (linkp = findlinks(stp, 0, flag, ss)) { 22637c478bd9Sstevel@tonic-gate /* 22647c478bd9Sstevel@tonic-gate * munlink() releases the muxifier lock. 22657c478bd9Sstevel@tonic-gate */ 2266f4b3ec61Sdh155122 if (error = munlink(stp, linkp, flag, crp, rvalp, ss)) 22677c478bd9Sstevel@tonic-gate return (error); 22687c478bd9Sstevel@tonic-gate mutex_enter(&muxifier); 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate mutex_exit(&muxifier); 22717c478bd9Sstevel@tonic-gate return (0); 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate /* 22757c478bd9Sstevel@tonic-gate * A multiplexor link has been made. Add an 22767c478bd9Sstevel@tonic-gate * edge to the directed graph. 22777c478bd9Sstevel@tonic-gate */ 22787c478bd9Sstevel@tonic-gate void 2279f4b3ec61Sdh155122 mux_addedge(stdata_t *upstp, stdata_t *lostp, int muxid, str_stack_t *ss) 22807c478bd9Sstevel@tonic-gate { 22817c478bd9Sstevel@tonic-gate struct mux_node *np; 22827c478bd9Sstevel@tonic-gate struct mux_edge *ep; 22837c478bd9Sstevel@tonic-gate major_t upmaj; 22847c478bd9Sstevel@tonic-gate major_t lomaj; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate upmaj = getmajor(upstp->sd_vnode->v_rdev); 22877c478bd9Sstevel@tonic-gate lomaj = getmajor(lostp->sd_vnode->v_rdev); 2288f4b3ec61Sdh155122 np = &ss->ss_mux_nodes[upmaj]; 22897c478bd9Sstevel@tonic-gate if (np->mn_outp) { 22907c478bd9Sstevel@tonic-gate ep = np->mn_outp; 22917c478bd9Sstevel@tonic-gate while (ep->me_nextp) 22927c478bd9Sstevel@tonic-gate ep = ep->me_nextp; 22937c478bd9Sstevel@tonic-gate ep->me_nextp = kmem_alloc(sizeof (struct mux_edge), KM_SLEEP); 22947c478bd9Sstevel@tonic-gate ep = ep->me_nextp; 22957c478bd9Sstevel@tonic-gate } else { 22967c478bd9Sstevel@tonic-gate np->mn_outp = kmem_alloc(sizeof (struct mux_edge), KM_SLEEP); 22977c478bd9Sstevel@tonic-gate ep = np->mn_outp; 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate ep->me_nextp = NULL; 23007c478bd9Sstevel@tonic-gate ep->me_muxid = muxid; 2301f4b3ec61Sdh155122 /* 2302f4b3ec61Sdh155122 * Save the dev_t for the purposes of str_stack_shutdown. 2303f4b3ec61Sdh155122 * str_stack_shutdown assumes that the device allows reopen, since 2304f4b3ec61Sdh155122 * this dev_t is the one after any cloning by xx_open(). 2305f4b3ec61Sdh155122 * Would prefer finding the dev_t from before any cloning, 2306f4b3ec61Sdh155122 * but specfs doesn't retain that. 2307f4b3ec61Sdh155122 */ 2308f4b3ec61Sdh155122 ep->me_dev = upstp->sd_vnode->v_rdev; 23097c478bd9Sstevel@tonic-gate if (lostp->sd_vnode->v_type == VFIFO) 23107c478bd9Sstevel@tonic-gate ep->me_nodep = NULL; 23117c478bd9Sstevel@tonic-gate else 2312f4b3ec61Sdh155122 ep->me_nodep = &ss->ss_mux_nodes[lomaj]; 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * A multiplexor link has been removed. Remove the 23177c478bd9Sstevel@tonic-gate * edge in the directed graph. 23187c478bd9Sstevel@tonic-gate */ 23197c478bd9Sstevel@tonic-gate void 2320f4b3ec61Sdh155122 mux_rmvedge(stdata_t *upstp, int muxid, str_stack_t *ss) 23217c478bd9Sstevel@tonic-gate { 23227c478bd9Sstevel@tonic-gate struct mux_node *np; 23237c478bd9Sstevel@tonic-gate struct mux_edge *ep; 23247c478bd9Sstevel@tonic-gate struct mux_edge *pep = NULL; 23257c478bd9Sstevel@tonic-gate major_t upmaj; 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate upmaj = getmajor(upstp->sd_vnode->v_rdev); 2328f4b3ec61Sdh155122 np = &ss->ss_mux_nodes[upmaj]; 23297c478bd9Sstevel@tonic-gate ASSERT(np->mn_outp != NULL); 23307c478bd9Sstevel@tonic-gate ep = np->mn_outp; 23317c478bd9Sstevel@tonic-gate while (ep) { 23327c478bd9Sstevel@tonic-gate if (ep->me_muxid == muxid) { 23337c478bd9Sstevel@tonic-gate if (pep) 23347c478bd9Sstevel@tonic-gate pep->me_nextp = ep->me_nextp; 23357c478bd9Sstevel@tonic-gate else 23367c478bd9Sstevel@tonic-gate np->mn_outp = ep->me_nextp; 23377c478bd9Sstevel@tonic-gate kmem_free(ep, sizeof (struct mux_edge)); 23387c478bd9Sstevel@tonic-gate return; 23397c478bd9Sstevel@tonic-gate } 23407c478bd9Sstevel@tonic-gate pep = ep; 23417c478bd9Sstevel@tonic-gate ep = ep->me_nextp; 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate ASSERT(0); /* should not reach here */ 23447c478bd9Sstevel@tonic-gate } 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate /* 23477c478bd9Sstevel@tonic-gate * Translate the device flags (from conf.h) to the corresponding 23487c478bd9Sstevel@tonic-gate * qflag and sq_flag (type) values. 23497c478bd9Sstevel@tonic-gate */ 23507c478bd9Sstevel@tonic-gate int 23517c478bd9Sstevel@tonic-gate devflg_to_qflag(struct streamtab *stp, uint32_t devflag, uint32_t *qflagp, 23527c478bd9Sstevel@tonic-gate uint32_t *sqtypep) 23537c478bd9Sstevel@tonic-gate { 23547c478bd9Sstevel@tonic-gate uint32_t qflag = 0; 23557c478bd9Sstevel@tonic-gate uint32_t sqtype = 0; 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate if (devflag & _D_OLD) 23587c478bd9Sstevel@tonic-gate goto bad; 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate /* Inner perimeter presence and scope */ 23617c478bd9Sstevel@tonic-gate switch (devflag & D_MTINNER_MASK) { 23627c478bd9Sstevel@tonic-gate case D_MP: 23637c478bd9Sstevel@tonic-gate qflag |= QMTSAFE; 23647c478bd9Sstevel@tonic-gate sqtype |= SQ_CI; 23657c478bd9Sstevel@tonic-gate break; 23667c478bd9Sstevel@tonic-gate case D_MTPERQ|D_MP: 23677c478bd9Sstevel@tonic-gate qflag |= QPERQ; 23687c478bd9Sstevel@tonic-gate break; 23697c478bd9Sstevel@tonic-gate case D_MTQPAIR|D_MP: 23707c478bd9Sstevel@tonic-gate qflag |= QPAIR; 23717c478bd9Sstevel@tonic-gate break; 23727c478bd9Sstevel@tonic-gate case D_MTPERMOD|D_MP: 23737c478bd9Sstevel@tonic-gate qflag |= QPERMOD; 23747c478bd9Sstevel@tonic-gate break; 23757c478bd9Sstevel@tonic-gate default: 23767c478bd9Sstevel@tonic-gate goto bad; 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate /* Outer perimeter */ 23807c478bd9Sstevel@tonic-gate if (devflag & D_MTOUTPERIM) { 23817c478bd9Sstevel@tonic-gate switch (devflag & D_MTINNER_MASK) { 23827c478bd9Sstevel@tonic-gate case D_MP: 23837c478bd9Sstevel@tonic-gate case D_MTPERQ|D_MP: 23847c478bd9Sstevel@tonic-gate case D_MTQPAIR|D_MP: 23857c478bd9Sstevel@tonic-gate break; 23867c478bd9Sstevel@tonic-gate default: 23877c478bd9Sstevel@tonic-gate goto bad; 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate qflag |= QMTOUTPERIM; 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate /* Inner perimeter modifiers */ 23937c478bd9Sstevel@tonic-gate if (devflag & D_MTINNER_MOD) { 23947c478bd9Sstevel@tonic-gate switch (devflag & D_MTINNER_MASK) { 23957c478bd9Sstevel@tonic-gate case D_MP: 23967c478bd9Sstevel@tonic-gate goto bad; 23977c478bd9Sstevel@tonic-gate default: 23987c478bd9Sstevel@tonic-gate break; 23997c478bd9Sstevel@tonic-gate } 24007c478bd9Sstevel@tonic-gate if (devflag & D_MTPUTSHARED) 24017c478bd9Sstevel@tonic-gate sqtype |= SQ_CIPUT; 24027c478bd9Sstevel@tonic-gate if (devflag & _D_MTOCSHARED) { 24037c478bd9Sstevel@tonic-gate /* 24047c478bd9Sstevel@tonic-gate * The code in putnext assumes that it has the 24057c478bd9Sstevel@tonic-gate * highest concurrency by not checking sq_count. 24067c478bd9Sstevel@tonic-gate * Thus _D_MTOCSHARED can only be supported when 24077c478bd9Sstevel@tonic-gate * D_MTPUTSHARED is set. 24087c478bd9Sstevel@tonic-gate */ 24097c478bd9Sstevel@tonic-gate if (!(devflag & D_MTPUTSHARED)) 24107c478bd9Sstevel@tonic-gate goto bad; 24117c478bd9Sstevel@tonic-gate sqtype |= SQ_CIOC; 24127c478bd9Sstevel@tonic-gate } 24137c478bd9Sstevel@tonic-gate if (devflag & _D_MTCBSHARED) { 24147c478bd9Sstevel@tonic-gate /* 24157c478bd9Sstevel@tonic-gate * The code in putnext assumes that it has the 24167c478bd9Sstevel@tonic-gate * highest concurrency by not checking sq_count. 24177c478bd9Sstevel@tonic-gate * Thus _D_MTCBSHARED can only be supported when 24187c478bd9Sstevel@tonic-gate * D_MTPUTSHARED is set. 24197c478bd9Sstevel@tonic-gate */ 24207c478bd9Sstevel@tonic-gate if (!(devflag & D_MTPUTSHARED)) 24217c478bd9Sstevel@tonic-gate goto bad; 24227c478bd9Sstevel@tonic-gate sqtype |= SQ_CICB; 24237c478bd9Sstevel@tonic-gate } 24247c478bd9Sstevel@tonic-gate if (devflag & _D_MTSVCSHARED) { 24257c478bd9Sstevel@tonic-gate /* 24267c478bd9Sstevel@tonic-gate * The code in putnext assumes that it has the 24277c478bd9Sstevel@tonic-gate * highest concurrency by not checking sq_count. 24287c478bd9Sstevel@tonic-gate * Thus _D_MTSVCSHARED can only be supported when 24297c478bd9Sstevel@tonic-gate * D_MTPUTSHARED is set. Also _D_MTSVCSHARED is 24307c478bd9Sstevel@tonic-gate * supported only for QPERMOD. 24317c478bd9Sstevel@tonic-gate */ 24327c478bd9Sstevel@tonic-gate if (!(devflag & D_MTPUTSHARED) || !(qflag & QPERMOD)) 24337c478bd9Sstevel@tonic-gate goto bad; 24347c478bd9Sstevel@tonic-gate sqtype |= SQ_CISVC; 24357c478bd9Sstevel@tonic-gate } 24367c478bd9Sstevel@tonic-gate } 24377c478bd9Sstevel@tonic-gate 24387c478bd9Sstevel@tonic-gate /* Default outer perimeter concurrency */ 24397c478bd9Sstevel@tonic-gate sqtype |= SQ_CO; 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate /* Outer perimeter modifiers */ 24427c478bd9Sstevel@tonic-gate if (devflag & D_MTOCEXCL) { 24437c478bd9Sstevel@tonic-gate if (!(devflag & D_MTOUTPERIM)) { 24447c478bd9Sstevel@tonic-gate /* No outer perimeter */ 24457c478bd9Sstevel@tonic-gate goto bad; 24467c478bd9Sstevel@tonic-gate } 24477c478bd9Sstevel@tonic-gate sqtype &= ~SQ_COOC; 24487c478bd9Sstevel@tonic-gate } 24497c478bd9Sstevel@tonic-gate 24507c478bd9Sstevel@tonic-gate /* Synchronous Streams extended qinit structure */ 24517c478bd9Sstevel@tonic-gate if (devflag & D_SYNCSTR) 24527c478bd9Sstevel@tonic-gate qflag |= QSYNCSTR; 24537c478bd9Sstevel@tonic-gate 2454ff550d0eSmasputra /* 2455ff550d0eSmasputra * Private flag used by a transport module to indicate 2456ff550d0eSmasputra * to sockfs that it supports direct-access mode without 2457bbc000e5SAnders Persson * having to go through STREAMS. 2458ff550d0eSmasputra */ 2459bbc000e5SAnders Persson if (devflag & _D_DIRECT) { 2460ff550d0eSmasputra /* Reject unless the module is fully-MT (no perimeter) */ 2461ff550d0eSmasputra if ((qflag & QMT_TYPEMASK) != QMTSAFE) 2462ff550d0eSmasputra goto bad; 2463ff550d0eSmasputra qflag |= _QDIRECT; 2464ff550d0eSmasputra } 2465ff550d0eSmasputra 24667c478bd9Sstevel@tonic-gate *qflagp = qflag; 24677c478bd9Sstevel@tonic-gate *sqtypep = sqtype; 24687c478bd9Sstevel@tonic-gate return (0); 24697c478bd9Sstevel@tonic-gate 24707c478bd9Sstevel@tonic-gate bad: 24717c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 24727c478bd9Sstevel@tonic-gate "stropen: bad MT flags (0x%x) in driver '%s'", 24737c478bd9Sstevel@tonic-gate (int)(qflag & D_MTSAFETY_MASK), 24747c478bd9Sstevel@tonic-gate stp->st_rdinit->qi_minfo->mi_idname); 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate return (EINVAL); 24777c478bd9Sstevel@tonic-gate } 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate /* 24807c478bd9Sstevel@tonic-gate * Set the interface values for a pair of queues (qinit structure, 24817c478bd9Sstevel@tonic-gate * packet sizes, water marks). 24827c478bd9Sstevel@tonic-gate * setq assumes that the caller does not have a claim (entersq or claimq) 24837c478bd9Sstevel@tonic-gate * on the queue. 24847c478bd9Sstevel@tonic-gate */ 24857c478bd9Sstevel@tonic-gate void 24867c478bd9Sstevel@tonic-gate setq(queue_t *rq, struct qinit *rinit, struct qinit *winit, 24877c478bd9Sstevel@tonic-gate perdm_t *dmp, uint32_t qflag, uint32_t sqtype, boolean_t lock_needed) 24887c478bd9Sstevel@tonic-gate { 24897c478bd9Sstevel@tonic-gate queue_t *wq; 24907c478bd9Sstevel@tonic-gate syncq_t *sq, *outer; 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate ASSERT(rq->q_flag & QREADR); 24937c478bd9Sstevel@tonic-gate ASSERT((qflag & QMT_TYPEMASK) != 0); 24947c478bd9Sstevel@tonic-gate IMPLY((qflag & (QPERMOD | QMTOUTPERIM)), dmp != NULL); 24957c478bd9Sstevel@tonic-gate 24967c478bd9Sstevel@tonic-gate wq = _WR(rq); 24977c478bd9Sstevel@tonic-gate rq->q_qinfo = rinit; 24987c478bd9Sstevel@tonic-gate rq->q_hiwat = rinit->qi_minfo->mi_hiwat; 24997c478bd9Sstevel@tonic-gate rq->q_lowat = rinit->qi_minfo->mi_lowat; 25007c478bd9Sstevel@tonic-gate rq->q_minpsz = rinit->qi_minfo->mi_minpsz; 25017c478bd9Sstevel@tonic-gate rq->q_maxpsz = rinit->qi_minfo->mi_maxpsz; 25027c478bd9Sstevel@tonic-gate wq->q_qinfo = winit; 25037c478bd9Sstevel@tonic-gate wq->q_hiwat = winit->qi_minfo->mi_hiwat; 25047c478bd9Sstevel@tonic-gate wq->q_lowat = winit->qi_minfo->mi_lowat; 25057c478bd9Sstevel@tonic-gate wq->q_minpsz = winit->qi_minfo->mi_minpsz; 25067c478bd9Sstevel@tonic-gate wq->q_maxpsz = winit->qi_minfo->mi_maxpsz; 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate /* Remove old syncqs */ 25097c478bd9Sstevel@tonic-gate sq = rq->q_syncq; 25107c478bd9Sstevel@tonic-gate outer = sq->sq_outer; 25117c478bd9Sstevel@tonic-gate if (outer != NULL) { 25127c478bd9Sstevel@tonic-gate ASSERT(wq->q_syncq->sq_outer == outer); 25137c478bd9Sstevel@tonic-gate outer_remove(outer, rq->q_syncq); 25147c478bd9Sstevel@tonic-gate if (wq->q_syncq != rq->q_syncq) 25157c478bd9Sstevel@tonic-gate outer_remove(outer, wq->q_syncq); 25167c478bd9Sstevel@tonic-gate } 25177c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL); 25187c478bd9Sstevel@tonic-gate ASSERT(sq->sq_onext == NULL && sq->sq_oprev == NULL); 25197c478bd9Sstevel@tonic-gate 25207c478bd9Sstevel@tonic-gate if (sq != SQ(rq)) { 25217c478bd9Sstevel@tonic-gate if (!(rq->q_flag & QPERMOD)) 25227c478bd9Sstevel@tonic-gate free_syncq(sq); 25237c478bd9Sstevel@tonic-gate if (wq->q_syncq == rq->q_syncq) 25247c478bd9Sstevel@tonic-gate wq->q_syncq = NULL; 25257c478bd9Sstevel@tonic-gate rq->q_syncq = NULL; 25267c478bd9Sstevel@tonic-gate } 25277c478bd9Sstevel@tonic-gate if (wq->q_syncq != NULL && wq->q_syncq != sq && 25287c478bd9Sstevel@tonic-gate wq->q_syncq != SQ(rq)) { 25297c478bd9Sstevel@tonic-gate free_syncq(wq->q_syncq); 25307c478bd9Sstevel@tonic-gate wq->q_syncq = NULL; 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate ASSERT(rq->q_syncq == NULL || (rq->q_syncq->sq_head == NULL && 25337c478bd9Sstevel@tonic-gate rq->q_syncq->sq_tail == NULL)); 25347c478bd9Sstevel@tonic-gate ASSERT(wq->q_syncq == NULL || (wq->q_syncq->sq_head == NULL && 25357c478bd9Sstevel@tonic-gate wq->q_syncq->sq_tail == NULL)); 25367c478bd9Sstevel@tonic-gate 25377c478bd9Sstevel@tonic-gate if (!(rq->q_flag & QPERMOD) && 25387c478bd9Sstevel@tonic-gate rq->q_syncq != NULL && rq->q_syncq->sq_ciputctrl != NULL) { 25397c478bd9Sstevel@tonic-gate ASSERT(rq->q_syncq->sq_nciputctrl == n_ciputctrl - 1); 25407c478bd9Sstevel@tonic-gate SUMCHECK_CIPUTCTRL_COUNTS(rq->q_syncq->sq_ciputctrl, 25417c478bd9Sstevel@tonic-gate rq->q_syncq->sq_nciputctrl, 0); 25427c478bd9Sstevel@tonic-gate ASSERT(ciputctrl_cache != NULL); 25437c478bd9Sstevel@tonic-gate kmem_cache_free(ciputctrl_cache, rq->q_syncq->sq_ciputctrl); 25447c478bd9Sstevel@tonic-gate rq->q_syncq->sq_ciputctrl = NULL; 25457c478bd9Sstevel@tonic-gate rq->q_syncq->sq_nciputctrl = 0; 25467c478bd9Sstevel@tonic-gate } 25477c478bd9Sstevel@tonic-gate 25487c478bd9Sstevel@tonic-gate if (!(wq->q_flag & QPERMOD) && 25497c478bd9Sstevel@tonic-gate wq->q_syncq != NULL && wq->q_syncq->sq_ciputctrl != NULL) { 25507c478bd9Sstevel@tonic-gate ASSERT(wq->q_syncq->sq_nciputctrl == n_ciputctrl - 1); 25517c478bd9Sstevel@tonic-gate SUMCHECK_CIPUTCTRL_COUNTS(wq->q_syncq->sq_ciputctrl, 25527c478bd9Sstevel@tonic-gate wq->q_syncq->sq_nciputctrl, 0); 25537c478bd9Sstevel@tonic-gate ASSERT(ciputctrl_cache != NULL); 25547c478bd9Sstevel@tonic-gate kmem_cache_free(ciputctrl_cache, wq->q_syncq->sq_ciputctrl); 25557c478bd9Sstevel@tonic-gate wq->q_syncq->sq_ciputctrl = NULL; 25567c478bd9Sstevel@tonic-gate wq->q_syncq->sq_nciputctrl = 0; 25577c478bd9Sstevel@tonic-gate } 25587c478bd9Sstevel@tonic-gate 25597c478bd9Sstevel@tonic-gate sq = SQ(rq); 25607c478bd9Sstevel@tonic-gate ASSERT(sq->sq_head == NULL && sq->sq_tail == NULL); 25617c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL); 25627c478bd9Sstevel@tonic-gate ASSERT(sq->sq_onext == NULL && sq->sq_oprev == NULL); 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate /* 25657c478bd9Sstevel@tonic-gate * Create syncqs based on qflag and sqtype. Set the SQ_TYPES_IN_FLAGS 25667c478bd9Sstevel@tonic-gate * bits in sq_flag based on the sqtype. 25677c478bd9Sstevel@tonic-gate */ 25687c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & ~SQ_TYPES_IN_FLAGS) == 0); 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate rq->q_syncq = wq->q_syncq = sq; 25717c478bd9Sstevel@tonic-gate sq->sq_type = sqtype; 25727c478bd9Sstevel@tonic-gate sq->sq_flags = (sqtype & SQ_TYPES_IN_FLAGS); 25737c478bd9Sstevel@tonic-gate 25747c478bd9Sstevel@tonic-gate /* 25757c478bd9Sstevel@tonic-gate * We are making sq_svcflags zero, 25767c478bd9Sstevel@tonic-gate * resetting SQ_DISABLED in case it was set by 25777c478bd9Sstevel@tonic-gate * wait_svc() in the munlink path. 25787c478bd9Sstevel@tonic-gate * 25797c478bd9Sstevel@tonic-gate */ 25807c478bd9Sstevel@tonic-gate ASSERT((sq->sq_svcflags & SQ_SERVICE) == 0); 25817c478bd9Sstevel@tonic-gate sq->sq_svcflags = 0; 25827c478bd9Sstevel@tonic-gate 25837c478bd9Sstevel@tonic-gate /* 25847c478bd9Sstevel@tonic-gate * We need to acquire the lock here for the mlink and munlink case, 25857c478bd9Sstevel@tonic-gate * where canputnext, backenable, etc can access the q_flag. 25867c478bd9Sstevel@tonic-gate */ 25877c478bd9Sstevel@tonic-gate if (lock_needed) { 25887c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(rq)); 25897c478bd9Sstevel@tonic-gate rq->q_flag = (rq->q_flag & ~QMT_TYPEMASK) | QWANTR | qflag; 25907c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(rq)); 25917c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(wq)); 25927c478bd9Sstevel@tonic-gate wq->q_flag = (wq->q_flag & ~QMT_TYPEMASK) | QWANTR | qflag; 25937c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(wq)); 25947c478bd9Sstevel@tonic-gate } else { 25957c478bd9Sstevel@tonic-gate rq->q_flag = (rq->q_flag & ~QMT_TYPEMASK) | QWANTR | qflag; 25967c478bd9Sstevel@tonic-gate wq->q_flag = (wq->q_flag & ~QMT_TYPEMASK) | QWANTR | qflag; 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate if (qflag & QPERQ) { 26007c478bd9Sstevel@tonic-gate /* Allocate a separate syncq for the write side */ 26017c478bd9Sstevel@tonic-gate sq = new_syncq(); 26027c478bd9Sstevel@tonic-gate sq->sq_type = rq->q_syncq->sq_type; 26037c478bd9Sstevel@tonic-gate sq->sq_flags = rq->q_syncq->sq_flags; 26047c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL && sq->sq_onext == NULL && 26057c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL); 26067c478bd9Sstevel@tonic-gate wq->q_syncq = sq; 26077c478bd9Sstevel@tonic-gate } 26087c478bd9Sstevel@tonic-gate if (qflag & QPERMOD) { 26097c478bd9Sstevel@tonic-gate sq = dmp->dm_sq; 26107c478bd9Sstevel@tonic-gate 26117c478bd9Sstevel@tonic-gate /* 26127c478bd9Sstevel@tonic-gate * Assert that we do have an inner perimeter syncq and that it 26137c478bd9Sstevel@tonic-gate * does not have an outer perimeter associated with it. 26147c478bd9Sstevel@tonic-gate */ 26157c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL && sq->sq_onext == NULL && 26167c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL); 26177c478bd9Sstevel@tonic-gate rq->q_syncq = wq->q_syncq = sq; 26187c478bd9Sstevel@tonic-gate } 26197c478bd9Sstevel@tonic-gate if (qflag & QMTOUTPERIM) { 26207c478bd9Sstevel@tonic-gate outer = dmp->dm_sq; 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL); 26237c478bd9Sstevel@tonic-gate outer_insert(outer, rq->q_syncq); 26247c478bd9Sstevel@tonic-gate if (wq->q_syncq != rq->q_syncq) 26257c478bd9Sstevel@tonic-gate outer_insert(outer, wq->q_syncq); 26267c478bd9Sstevel@tonic-gate } 26277c478bd9Sstevel@tonic-gate ASSERT((rq->q_syncq->sq_flags & SQ_TYPES_IN_FLAGS) == 26287c478bd9Sstevel@tonic-gate (rq->q_syncq->sq_type & SQ_TYPES_IN_FLAGS)); 26297c478bd9Sstevel@tonic-gate ASSERT((wq->q_syncq->sq_flags & SQ_TYPES_IN_FLAGS) == 26307c478bd9Sstevel@tonic-gate (wq->q_syncq->sq_type & SQ_TYPES_IN_FLAGS)); 26317c478bd9Sstevel@tonic-gate ASSERT((rq->q_flag & QMT_TYPEMASK) == (qflag & QMT_TYPEMASK)); 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate /* 26347c478bd9Sstevel@tonic-gate * Initialize struio() types. 26357c478bd9Sstevel@tonic-gate */ 26367c478bd9Sstevel@tonic-gate rq->q_struiot = 26377c478bd9Sstevel@tonic-gate (rq->q_flag & QSYNCSTR) ? rinit->qi_struiot : STRUIOT_NONE; 26387c478bd9Sstevel@tonic-gate wq->q_struiot = 26397c478bd9Sstevel@tonic-gate (wq->q_flag & QSYNCSTR) ? winit->qi_struiot : STRUIOT_NONE; 26407c478bd9Sstevel@tonic-gate } 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate perdm_t * 26437c478bd9Sstevel@tonic-gate hold_dm(struct streamtab *str, uint32_t qflag, uint32_t sqtype) 26447c478bd9Sstevel@tonic-gate { 26457c478bd9Sstevel@tonic-gate syncq_t *sq; 26467c478bd9Sstevel@tonic-gate perdm_t **pp; 26477c478bd9Sstevel@tonic-gate perdm_t *p; 26487c478bd9Sstevel@tonic-gate perdm_t *dmp; 26497c478bd9Sstevel@tonic-gate 26507c478bd9Sstevel@tonic-gate ASSERT(str != NULL); 26517c478bd9Sstevel@tonic-gate ASSERT(qflag & (QPERMOD | QMTOUTPERIM)); 26527c478bd9Sstevel@tonic-gate 26537c478bd9Sstevel@tonic-gate rw_enter(&perdm_rwlock, RW_READER); 26547c478bd9Sstevel@tonic-gate for (p = perdm_list; p != NULL; p = p->dm_next) { 26557c478bd9Sstevel@tonic-gate if (p->dm_str == str) { /* found one */ 2656*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&(p->dm_ref)); 26577c478bd9Sstevel@tonic-gate rw_exit(&perdm_rwlock); 26587c478bd9Sstevel@tonic-gate return (p); 26597c478bd9Sstevel@tonic-gate } 26607c478bd9Sstevel@tonic-gate } 26617c478bd9Sstevel@tonic-gate rw_exit(&perdm_rwlock); 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate sq = new_syncq(); 26647c478bd9Sstevel@tonic-gate if (qflag & QPERMOD) { 26657c478bd9Sstevel@tonic-gate sq->sq_type = sqtype | SQ_PERMOD; 26667c478bd9Sstevel@tonic-gate sq->sq_flags = sqtype & SQ_TYPES_IN_FLAGS; 26677c478bd9Sstevel@tonic-gate } else { 26687c478bd9Sstevel@tonic-gate ASSERT(qflag & QMTOUTPERIM); 26697c478bd9Sstevel@tonic-gate sq->sq_onext = sq->sq_oprev = sq; 26707c478bd9Sstevel@tonic-gate } 26717c478bd9Sstevel@tonic-gate 26727c478bd9Sstevel@tonic-gate dmp = kmem_alloc(sizeof (perdm_t), KM_SLEEP); 26737c478bd9Sstevel@tonic-gate dmp->dm_sq = sq; 26747c478bd9Sstevel@tonic-gate dmp->dm_str = str; 26757c478bd9Sstevel@tonic-gate dmp->dm_ref = 1; 26767c478bd9Sstevel@tonic-gate dmp->dm_next = NULL; 26777c478bd9Sstevel@tonic-gate 26787c478bd9Sstevel@tonic-gate rw_enter(&perdm_rwlock, RW_WRITER); 26797c478bd9Sstevel@tonic-gate for (pp = &perdm_list; (p = *pp) != NULL; pp = &(p->dm_next)) { 26807c478bd9Sstevel@tonic-gate if (p->dm_str == str) { /* already present */ 26817c478bd9Sstevel@tonic-gate p->dm_ref++; 26827c478bd9Sstevel@tonic-gate rw_exit(&perdm_rwlock); 26837c478bd9Sstevel@tonic-gate free_syncq(sq); 26847c478bd9Sstevel@tonic-gate kmem_free(dmp, sizeof (perdm_t)); 26857c478bd9Sstevel@tonic-gate return (p); 26867c478bd9Sstevel@tonic-gate } 26877c478bd9Sstevel@tonic-gate } 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate *pp = dmp; 26907c478bd9Sstevel@tonic-gate rw_exit(&perdm_rwlock); 26917c478bd9Sstevel@tonic-gate return (dmp); 26927c478bd9Sstevel@tonic-gate } 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate void 26957c478bd9Sstevel@tonic-gate rele_dm(perdm_t *dmp) 26967c478bd9Sstevel@tonic-gate { 26977c478bd9Sstevel@tonic-gate perdm_t **pp; 26987c478bd9Sstevel@tonic-gate perdm_t *p; 26997c478bd9Sstevel@tonic-gate 27007c478bd9Sstevel@tonic-gate rw_enter(&perdm_rwlock, RW_WRITER); 27017c478bd9Sstevel@tonic-gate ASSERT(dmp->dm_ref > 0); 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate if (--dmp->dm_ref > 0) { 27047c478bd9Sstevel@tonic-gate rw_exit(&perdm_rwlock); 27057c478bd9Sstevel@tonic-gate return; 27067c478bd9Sstevel@tonic-gate } 27077c478bd9Sstevel@tonic-gate 27087c478bd9Sstevel@tonic-gate for (pp = &perdm_list; (p = *pp) != NULL; pp = &(p->dm_next)) 27097c478bd9Sstevel@tonic-gate if (p == dmp) 27107c478bd9Sstevel@tonic-gate break; 27117c478bd9Sstevel@tonic-gate ASSERT(p == dmp); 27127c478bd9Sstevel@tonic-gate *pp = p->dm_next; 27137c478bd9Sstevel@tonic-gate rw_exit(&perdm_rwlock); 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate /* 27167c478bd9Sstevel@tonic-gate * Wait for any background processing that relies on the 27177c478bd9Sstevel@tonic-gate * syncq to complete before it is freed. 27187c478bd9Sstevel@tonic-gate */ 27197c478bd9Sstevel@tonic-gate wait_sq_svc(p->dm_sq); 27207c478bd9Sstevel@tonic-gate free_syncq(p->dm_sq); 27217c478bd9Sstevel@tonic-gate kmem_free(p, sizeof (perdm_t)); 27227c478bd9Sstevel@tonic-gate } 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate /* 27257c478bd9Sstevel@tonic-gate * Make a protocol message given control and data buffers. 27267c478bd9Sstevel@tonic-gate * n.b., this can block; be careful of what locks you hold when calling it. 27277c478bd9Sstevel@tonic-gate * 27287c478bd9Sstevel@tonic-gate * If sd_maxblk is less than *iosize this routine can fail part way through 27297c478bd9Sstevel@tonic-gate * (due to an allocation failure). In this case on return *iosize will contain 27307c478bd9Sstevel@tonic-gate * the amount that was consumed. Otherwise *iosize will not be modified 27317c478bd9Sstevel@tonic-gate * i.e. it will contain the amount that was consumed. 27327c478bd9Sstevel@tonic-gate */ 27337c478bd9Sstevel@tonic-gate int 27347c478bd9Sstevel@tonic-gate strmakemsg( 27357c478bd9Sstevel@tonic-gate struct strbuf *mctl, 27367c478bd9Sstevel@tonic-gate ssize_t *iosize, 27377c478bd9Sstevel@tonic-gate struct uio *uiop, 27387c478bd9Sstevel@tonic-gate stdata_t *stp, 27397c478bd9Sstevel@tonic-gate int32_t flag, 27407c478bd9Sstevel@tonic-gate mblk_t **mpp) 27417c478bd9Sstevel@tonic-gate { 27427c478bd9Sstevel@tonic-gate mblk_t *mpctl = NULL; 27437c478bd9Sstevel@tonic-gate mblk_t *mpdata = NULL; 27447c478bd9Sstevel@tonic-gate int error; 27457c478bd9Sstevel@tonic-gate 27467c478bd9Sstevel@tonic-gate ASSERT(uiop != NULL); 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate *mpp = NULL; 27497c478bd9Sstevel@tonic-gate /* Create control part, if any */ 27507c478bd9Sstevel@tonic-gate if ((mctl != NULL) && (mctl->len >= 0)) { 27517c478bd9Sstevel@tonic-gate error = strmakectl(mctl, flag, uiop->uio_fmode, &mpctl); 27527c478bd9Sstevel@tonic-gate if (error) 27537c478bd9Sstevel@tonic-gate return (error); 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate /* Create data part, if any */ 27567c478bd9Sstevel@tonic-gate if (*iosize >= 0) { 27577c478bd9Sstevel@tonic-gate error = strmakedata(iosize, uiop, stp, flag, &mpdata); 27587c478bd9Sstevel@tonic-gate if (error) { 27597c478bd9Sstevel@tonic-gate freemsg(mpctl); 27607c478bd9Sstevel@tonic-gate return (error); 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate } 27637c478bd9Sstevel@tonic-gate if (mpctl != NULL) { 27647c478bd9Sstevel@tonic-gate if (mpdata != NULL) 27657c478bd9Sstevel@tonic-gate linkb(mpctl, mpdata); 27667c478bd9Sstevel@tonic-gate *mpp = mpctl; 27677c478bd9Sstevel@tonic-gate } else { 27687c478bd9Sstevel@tonic-gate *mpp = mpdata; 27697c478bd9Sstevel@tonic-gate } 27707c478bd9Sstevel@tonic-gate return (0); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate /* 27747c478bd9Sstevel@tonic-gate * Make the control part of a protocol message given a control buffer. 27757c478bd9Sstevel@tonic-gate * n.b., this can block; be careful of what locks you hold when calling it. 27767c478bd9Sstevel@tonic-gate */ 27777c478bd9Sstevel@tonic-gate int 27787c478bd9Sstevel@tonic-gate strmakectl( 27797c478bd9Sstevel@tonic-gate struct strbuf *mctl, 27807c478bd9Sstevel@tonic-gate int32_t flag, 27817c478bd9Sstevel@tonic-gate int32_t fflag, 27827c478bd9Sstevel@tonic-gate mblk_t **mpp) 27837c478bd9Sstevel@tonic-gate { 27847c478bd9Sstevel@tonic-gate mblk_t *bp = NULL; 27857c478bd9Sstevel@tonic-gate unsigned char msgtype; 27867c478bd9Sstevel@tonic-gate int error = 0; 2787de8c4a14SErik Nordmark cred_t *cr = CRED(); 2788de8c4a14SErik Nordmark 2789de8c4a14SErik Nordmark /* We do not support interrupt threads using the stream head to send */ 2790de8c4a14SErik Nordmark ASSERT(cr != NULL); 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate *mpp = NULL; 27937c478bd9Sstevel@tonic-gate /* 27947c478bd9Sstevel@tonic-gate * Create control part of message, if any. 27957c478bd9Sstevel@tonic-gate */ 27967c478bd9Sstevel@tonic-gate if ((mctl != NULL) && (mctl->len >= 0)) { 27977c478bd9Sstevel@tonic-gate caddr_t base; 27987c478bd9Sstevel@tonic-gate int ctlcount; 27997c478bd9Sstevel@tonic-gate int allocsz; 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate if (flag & RS_HIPRI) 28027c478bd9Sstevel@tonic-gate msgtype = M_PCPROTO; 28037c478bd9Sstevel@tonic-gate else 28047c478bd9Sstevel@tonic-gate msgtype = M_PROTO; 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate ctlcount = mctl->len; 28077c478bd9Sstevel@tonic-gate base = mctl->buf; 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate /* 28107c478bd9Sstevel@tonic-gate * Give modules a better chance to reuse M_PROTO/M_PCPROTO 28117c478bd9Sstevel@tonic-gate * blocks by increasing the size to something more usable. 28127c478bd9Sstevel@tonic-gate */ 28137c478bd9Sstevel@tonic-gate allocsz = MAX(ctlcount, 64); 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate /* 28167c478bd9Sstevel@tonic-gate * Range checking has already been done; simply try 28177c478bd9Sstevel@tonic-gate * to allocate a message block for the ctl part. 28187c478bd9Sstevel@tonic-gate */ 2819de8c4a14SErik Nordmark while ((bp = allocb_cred(allocsz, cr, 2820de8c4a14SErik Nordmark curproc->p_pid)) == NULL) { 28217c478bd9Sstevel@tonic-gate if (fflag & (FNDELAY|FNONBLOCK)) 28227c478bd9Sstevel@tonic-gate return (EAGAIN); 28237c478bd9Sstevel@tonic-gate if (error = strwaitbuf(allocsz, BPRI_MED)) 28247c478bd9Sstevel@tonic-gate return (error); 28257c478bd9Sstevel@tonic-gate } 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate bp->b_datap->db_type = msgtype; 28287c478bd9Sstevel@tonic-gate if (copyin(base, bp->b_wptr, ctlcount)) { 28297c478bd9Sstevel@tonic-gate freeb(bp); 28307c478bd9Sstevel@tonic-gate return (EFAULT); 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate bp->b_wptr += ctlcount; 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate *mpp = bp; 28357c478bd9Sstevel@tonic-gate return (0); 28367c478bd9Sstevel@tonic-gate } 28377c478bd9Sstevel@tonic-gate 28387c478bd9Sstevel@tonic-gate /* 28397c478bd9Sstevel@tonic-gate * Make a protocol message given data buffers. 28407c478bd9Sstevel@tonic-gate * n.b., this can block; be careful of what locks you hold when calling it. 28417c478bd9Sstevel@tonic-gate * 28427c478bd9Sstevel@tonic-gate * If sd_maxblk is less than *iosize this routine can fail part way through 28437c478bd9Sstevel@tonic-gate * (due to an allocation failure). In this case on return *iosize will contain 28447c478bd9Sstevel@tonic-gate * the amount that was consumed. Otherwise *iosize will not be modified 28457c478bd9Sstevel@tonic-gate * i.e. it will contain the amount that was consumed. 28467c478bd9Sstevel@tonic-gate */ 28477c478bd9Sstevel@tonic-gate int 28487c478bd9Sstevel@tonic-gate strmakedata( 28497c478bd9Sstevel@tonic-gate ssize_t *iosize, 28507c478bd9Sstevel@tonic-gate struct uio *uiop, 28517c478bd9Sstevel@tonic-gate stdata_t *stp, 28527c478bd9Sstevel@tonic-gate int32_t flag, 28537c478bd9Sstevel@tonic-gate mblk_t **mpp) 28547c478bd9Sstevel@tonic-gate { 28557c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 28567c478bd9Sstevel@tonic-gate mblk_t *bp; 28577c478bd9Sstevel@tonic-gate int wroff = (int)stp->sd_wroff; 2858c28749e9Skais int tail_len = (int)stp->sd_tail; 2859c28749e9Skais int extra = wroff + tail_len; 28607c478bd9Sstevel@tonic-gate int error = 0; 28617c478bd9Sstevel@tonic-gate ssize_t maxblk; 28627c478bd9Sstevel@tonic-gate ssize_t count = *iosize; 2863de8c4a14SErik Nordmark cred_t *cr; 28647c478bd9Sstevel@tonic-gate 28657c478bd9Sstevel@tonic-gate *mpp = NULL; 28667c478bd9Sstevel@tonic-gate if (count < 0) 28677c478bd9Sstevel@tonic-gate return (0); 28687c478bd9Sstevel@tonic-gate 2869de8c4a14SErik Nordmark /* We do not support interrupt threads using the stream head to send */ 2870de8c4a14SErik Nordmark cr = CRED(); 2871de8c4a14SErik Nordmark ASSERT(cr != NULL); 2872de8c4a14SErik Nordmark 28737c478bd9Sstevel@tonic-gate maxblk = stp->sd_maxblk; 28747c478bd9Sstevel@tonic-gate if (maxblk == INFPSZ) 28757c478bd9Sstevel@tonic-gate maxblk = count; 28767c478bd9Sstevel@tonic-gate 28777c478bd9Sstevel@tonic-gate /* 28787c478bd9Sstevel@tonic-gate * Create data part of message, if any. 28797c478bd9Sstevel@tonic-gate */ 28807c478bd9Sstevel@tonic-gate do { 28817c478bd9Sstevel@tonic-gate ssize_t size; 28827c478bd9Sstevel@tonic-gate dblk_t *dp; 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate ASSERT(uiop); 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate size = MIN(count, maxblk); 28877c478bd9Sstevel@tonic-gate 2888de8c4a14SErik Nordmark while ((bp = allocb_cred(size + extra, cr, 2889de8c4a14SErik Nordmark curproc->p_pid)) == NULL) { 28907c478bd9Sstevel@tonic-gate error = EAGAIN; 28917c478bd9Sstevel@tonic-gate if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) || 2892c28749e9Skais (error = strwaitbuf(size + extra, BPRI_MED)) != 0) { 28937c478bd9Sstevel@tonic-gate if (count == *iosize) { 28947c478bd9Sstevel@tonic-gate freemsg(mp); 28957c478bd9Sstevel@tonic-gate return (error); 28967c478bd9Sstevel@tonic-gate } else { 28977c478bd9Sstevel@tonic-gate *iosize -= count; 28987c478bd9Sstevel@tonic-gate *mpp = mp; 28997c478bd9Sstevel@tonic-gate return (0); 29007c478bd9Sstevel@tonic-gate } 29017c478bd9Sstevel@tonic-gate } 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate dp = bp->b_datap; 29047c478bd9Sstevel@tonic-gate dp->db_cpid = curproc->p_pid; 29057c478bd9Sstevel@tonic-gate ASSERT(wroff <= dp->db_lim - bp->b_wptr); 29067c478bd9Sstevel@tonic-gate bp->b_wptr = bp->b_rptr = bp->b_rptr + wroff; 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate if (flag & STRUIO_POSTPONE) { 29097c478bd9Sstevel@tonic-gate /* 29107c478bd9Sstevel@tonic-gate * Setup the stream uio portion of the 29117c478bd9Sstevel@tonic-gate * dblk for subsequent use by struioget(). 29127c478bd9Sstevel@tonic-gate */ 29137c478bd9Sstevel@tonic-gate dp->db_struioflag = STRUIO_SPEC; 29147c478bd9Sstevel@tonic-gate dp->db_cksumstart = 0; 29157c478bd9Sstevel@tonic-gate dp->db_cksumstuff = 0; 29167c478bd9Sstevel@tonic-gate dp->db_cksumend = size; 29177c478bd9Sstevel@tonic-gate *(long long *)dp->db_struioun.data = 0ll; 2918c28749e9Skais bp->b_wptr += size; 29197c478bd9Sstevel@tonic-gate } else { 29207c478bd9Sstevel@tonic-gate if (stp->sd_copyflag & STRCOPYCACHED) 29217c478bd9Sstevel@tonic-gate uiop->uio_extflg |= UIO_COPY_CACHED; 29227c478bd9Sstevel@tonic-gate 29237c478bd9Sstevel@tonic-gate if (size != 0) { 29247c478bd9Sstevel@tonic-gate error = uiomove(bp->b_wptr, size, UIO_WRITE, 29257c478bd9Sstevel@tonic-gate uiop); 29267c478bd9Sstevel@tonic-gate if (error != 0) { 29277c478bd9Sstevel@tonic-gate freeb(bp); 29287c478bd9Sstevel@tonic-gate freemsg(mp); 29297c478bd9Sstevel@tonic-gate return (error); 29307c478bd9Sstevel@tonic-gate } 29317c478bd9Sstevel@tonic-gate } 2932c28749e9Skais bp->b_wptr += size; 2933c28749e9Skais 2934c28749e9Skais if (stp->sd_wputdatafunc != NULL) { 2935c28749e9Skais mblk_t *newbp; 2936c28749e9Skais 2937c28749e9Skais newbp = (stp->sd_wputdatafunc)(stp->sd_vnode, 2938c28749e9Skais bp, NULL, NULL, NULL, NULL); 2939c28749e9Skais if (newbp == NULL) { 2940c28749e9Skais freeb(bp); 2941c28749e9Skais freemsg(mp); 2942c28749e9Skais return (ECOMM); 2943c28749e9Skais } 2944c28749e9Skais bp = newbp; 2945c28749e9Skais } 29467c478bd9Sstevel@tonic-gate } 29477c478bd9Sstevel@tonic-gate 29487c478bd9Sstevel@tonic-gate count -= size; 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate if (mp == NULL) 29517c478bd9Sstevel@tonic-gate mp = bp; 29527c478bd9Sstevel@tonic-gate else 29537c478bd9Sstevel@tonic-gate linkb(mp, bp); 29547c478bd9Sstevel@tonic-gate } while (count > 0); 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate *mpp = mp; 29577c478bd9Sstevel@tonic-gate return (0); 29587c478bd9Sstevel@tonic-gate } 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate /* 29617c478bd9Sstevel@tonic-gate * Wait for a buffer to become available. Return non-zero errno 29627c478bd9Sstevel@tonic-gate * if not able to wait, 0 if buffer is probably there. 29637c478bd9Sstevel@tonic-gate */ 29647c478bd9Sstevel@tonic-gate int 29657c478bd9Sstevel@tonic-gate strwaitbuf(size_t size, int pri) 29667c478bd9Sstevel@tonic-gate { 29677c478bd9Sstevel@tonic-gate bufcall_id_t id; 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate mutex_enter(&bcall_monitor); 29707c478bd9Sstevel@tonic-gate if ((id = bufcall(size, pri, (void (*)(void *))cv_broadcast, 29717c478bd9Sstevel@tonic-gate &ttoproc(curthread)->p_flag_cv)) == 0) { 29727c478bd9Sstevel@tonic-gate mutex_exit(&bcall_monitor); 29737c478bd9Sstevel@tonic-gate return (ENOSR); 29747c478bd9Sstevel@tonic-gate } 29757c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&(ttoproc(curthread)->p_flag_cv), &bcall_monitor)) { 29767c478bd9Sstevel@tonic-gate unbufcall(id); 29777c478bd9Sstevel@tonic-gate mutex_exit(&bcall_monitor); 29787c478bd9Sstevel@tonic-gate return (EINTR); 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate unbufcall(id); 29817c478bd9Sstevel@tonic-gate mutex_exit(&bcall_monitor); 29827c478bd9Sstevel@tonic-gate return (0); 29837c478bd9Sstevel@tonic-gate } 29847c478bd9Sstevel@tonic-gate 29857c478bd9Sstevel@tonic-gate /* 29867c478bd9Sstevel@tonic-gate * This function waits for a read or write event to happen on a stream. 29877c478bd9Sstevel@tonic-gate * fmode can specify FNDELAY and/or FNONBLOCK. 29887c478bd9Sstevel@tonic-gate * The timeout is in ms with -1 meaning infinite. 29897c478bd9Sstevel@tonic-gate * The flag values work as follows: 29907c478bd9Sstevel@tonic-gate * READWAIT Check for read side errors, send M_READ 29917c478bd9Sstevel@tonic-gate * GETWAIT Check for read side errors, no M_READ 29927c478bd9Sstevel@tonic-gate * WRITEWAIT Check for write side errors. 29937c478bd9Sstevel@tonic-gate * NOINTR Do not return error if nonblocking or timeout. 29947c478bd9Sstevel@tonic-gate * STR_NOERROR Ignore all errors except STPLEX. 29957c478bd9Sstevel@tonic-gate * STR_NOSIG Ignore/hold signals during the duration of the call. 29967c478bd9Sstevel@tonic-gate * STR_PEEK Pass through the strgeterr(). 29977c478bd9Sstevel@tonic-gate */ 29987c478bd9Sstevel@tonic-gate int 29997c478bd9Sstevel@tonic-gate strwaitq(stdata_t *stp, int flag, ssize_t count, int fmode, clock_t timout, 30007c478bd9Sstevel@tonic-gate int *done) 30017c478bd9Sstevel@tonic-gate { 30027c478bd9Sstevel@tonic-gate int slpflg, errs; 30037c478bd9Sstevel@tonic-gate int error; 30047c478bd9Sstevel@tonic-gate kcondvar_t *sleepon; 30057c478bd9Sstevel@tonic-gate mblk_t *mp; 30067c478bd9Sstevel@tonic-gate ssize_t *rd_count; 30077c478bd9Sstevel@tonic-gate clock_t rval; 30087c478bd9Sstevel@tonic-gate 30097c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&stp->sd_lock)); 30107c478bd9Sstevel@tonic-gate if ((flag & READWAIT) || (flag & GETWAIT)) { 30117c478bd9Sstevel@tonic-gate slpflg = RSLEEP; 30127c478bd9Sstevel@tonic-gate sleepon = &_RD(stp->sd_wrq)->q_wait; 30137c478bd9Sstevel@tonic-gate errs = STRDERR|STPLEX; 30147c478bd9Sstevel@tonic-gate } else { 30157c478bd9Sstevel@tonic-gate slpflg = WSLEEP; 30167c478bd9Sstevel@tonic-gate sleepon = &stp->sd_wrq->q_wait; 30177c478bd9Sstevel@tonic-gate errs = STWRERR|STRHUP|STPLEX; 30187c478bd9Sstevel@tonic-gate } 30197c478bd9Sstevel@tonic-gate if (flag & STR_NOERROR) 30207c478bd9Sstevel@tonic-gate errs = STPLEX; 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate if (stp->sd_wakeq & slpflg) { 30237c478bd9Sstevel@tonic-gate /* 30247c478bd9Sstevel@tonic-gate * A strwakeq() is pending, no need to sleep. 30257c478bd9Sstevel@tonic-gate */ 30267c478bd9Sstevel@tonic-gate stp->sd_wakeq &= ~slpflg; 30277c478bd9Sstevel@tonic-gate *done = 0; 30287c478bd9Sstevel@tonic-gate return (0); 30297c478bd9Sstevel@tonic-gate } 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate if (stp->sd_flag & errs) { 30327c478bd9Sstevel@tonic-gate /* 30337c478bd9Sstevel@tonic-gate * Check for errors before going to sleep since the 30347c478bd9Sstevel@tonic-gate * caller might not have checked this while holding 30357c478bd9Sstevel@tonic-gate * sd_lock. 30367c478bd9Sstevel@tonic-gate */ 30377c478bd9Sstevel@tonic-gate error = strgeterr(stp, errs, (flag & STR_PEEK)); 30387c478bd9Sstevel@tonic-gate if (error != 0) { 30397c478bd9Sstevel@tonic-gate *done = 1; 30407c478bd9Sstevel@tonic-gate return (error); 30417c478bd9Sstevel@tonic-gate } 30427c478bd9Sstevel@tonic-gate } 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate /* 30457c478bd9Sstevel@tonic-gate * If any module downstream has requested read notification 30467c478bd9Sstevel@tonic-gate * by setting SNDMREAD flag using M_SETOPTS, send a message 30477c478bd9Sstevel@tonic-gate * down stream. 30487c478bd9Sstevel@tonic-gate */ 30497c478bd9Sstevel@tonic-gate if ((flag & READWAIT) && (stp->sd_flag & SNDMREAD)) { 30507c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 30517c478bd9Sstevel@tonic-gate if (!(mp = allocb_wait(sizeof (ssize_t), BPRI_MED, 30527c478bd9Sstevel@tonic-gate (flag & STR_NOSIG), &error))) { 30537c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 30547c478bd9Sstevel@tonic-gate *done = 1; 30557c478bd9Sstevel@tonic-gate return (error); 30567c478bd9Sstevel@tonic-gate } 30577c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_READ; 30587c478bd9Sstevel@tonic-gate rd_count = (ssize_t *)mp->b_wptr; 30597c478bd9Sstevel@tonic-gate *rd_count = count; 30607c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (ssize_t); 30617c478bd9Sstevel@tonic-gate /* 30627c478bd9Sstevel@tonic-gate * Send the number of bytes requested by the 30637c478bd9Sstevel@tonic-gate * read as the argument to M_READ. 30647c478bd9Sstevel@tonic-gate */ 30657c478bd9Sstevel@tonic-gate stream_willservice(stp); 30667c478bd9Sstevel@tonic-gate putnext(stp->sd_wrq, mp); 30677c478bd9Sstevel@tonic-gate stream_runservice(stp); 30687c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate /* 30717c478bd9Sstevel@tonic-gate * If any data arrived due to inline processing 30727c478bd9Sstevel@tonic-gate * of putnext(), don't sleep. 30737c478bd9Sstevel@tonic-gate */ 30747c478bd9Sstevel@tonic-gate if (_RD(stp->sd_wrq)->q_first != NULL) { 30757c478bd9Sstevel@tonic-gate *done = 0; 30767c478bd9Sstevel@tonic-gate return (0); 30777c478bd9Sstevel@tonic-gate } 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate 3080fcb46be3SGarrett D'Amore if (fmode & (FNDELAY|FNONBLOCK)) { 3081fcb46be3SGarrett D'Amore if (!(flag & NOINTR)) 3082fcb46be3SGarrett D'Amore error = EAGAIN; 3083fcb46be3SGarrett D'Amore else 3084fcb46be3SGarrett D'Amore error = 0; 3085fcb46be3SGarrett D'Amore *done = 1; 3086fcb46be3SGarrett D'Amore return (error); 3087fcb46be3SGarrett D'Amore } 3088fcb46be3SGarrett D'Amore 30897c478bd9Sstevel@tonic-gate stp->sd_flag |= slpflg; 30907c478bd9Sstevel@tonic-gate TRACE_5(TR_FAC_STREAMS_FR, TR_STRWAITQ_WAIT2, 30917c478bd9Sstevel@tonic-gate "strwaitq sleeps (2):%p, %X, %lX, %X, %p", 30927c478bd9Sstevel@tonic-gate stp, flag, count, fmode, done); 30937c478bd9Sstevel@tonic-gate 30947c478bd9Sstevel@tonic-gate rval = str_cv_wait(sleepon, &stp->sd_lock, timout, flag & STR_NOSIG); 30957c478bd9Sstevel@tonic-gate if (rval > 0) { 30967c478bd9Sstevel@tonic-gate /* EMPTY */ 30977c478bd9Sstevel@tonic-gate TRACE_5(TR_FAC_STREAMS_FR, TR_STRWAITQ_WAKE2, 30987c478bd9Sstevel@tonic-gate "strwaitq awakes(2):%X, %X, %X, %X, %X", 30997c478bd9Sstevel@tonic-gate stp, flag, count, fmode, done); 31007c478bd9Sstevel@tonic-gate } else if (rval == 0) { 31017c478bd9Sstevel@tonic-gate TRACE_5(TR_FAC_STREAMS_FR, TR_STRWAITQ_INTR2, 31027c478bd9Sstevel@tonic-gate "strwaitq interrupt #2:%p, %X, %lX, %X, %p", 31037c478bd9Sstevel@tonic-gate stp, flag, count, fmode, done); 31047c478bd9Sstevel@tonic-gate stp->sd_flag &= ~slpflg; 31057c478bd9Sstevel@tonic-gate cv_broadcast(sleepon); 31067c478bd9Sstevel@tonic-gate if (!(flag & NOINTR)) 31077c478bd9Sstevel@tonic-gate error = EINTR; 31087c478bd9Sstevel@tonic-gate else 31097c478bd9Sstevel@tonic-gate error = 0; 31107c478bd9Sstevel@tonic-gate *done = 1; 31117c478bd9Sstevel@tonic-gate return (error); 31127c478bd9Sstevel@tonic-gate } else { 31137c478bd9Sstevel@tonic-gate /* timeout */ 31147c478bd9Sstevel@tonic-gate TRACE_5(TR_FAC_STREAMS_FR, TR_STRWAITQ_TIME, 31157c478bd9Sstevel@tonic-gate "strwaitq timeout:%p, %X, %lX, %X, %p", 31167c478bd9Sstevel@tonic-gate stp, flag, count, fmode, done); 31177c478bd9Sstevel@tonic-gate *done = 1; 31187c478bd9Sstevel@tonic-gate if (!(flag & NOINTR)) 31197c478bd9Sstevel@tonic-gate return (ETIME); 31207c478bd9Sstevel@tonic-gate else 31217c478bd9Sstevel@tonic-gate return (0); 31227c478bd9Sstevel@tonic-gate } 31237c478bd9Sstevel@tonic-gate /* 31247c478bd9Sstevel@tonic-gate * If the caller implements delayed errors (i.e. queued after data) 31257c478bd9Sstevel@tonic-gate * we can not check for errors here since data as well as an 31267c478bd9Sstevel@tonic-gate * error might have arrived at the stream head. We return to 31277c478bd9Sstevel@tonic-gate * have the caller check the read queue before checking for errors. 31287c478bd9Sstevel@tonic-gate */ 31297c478bd9Sstevel@tonic-gate if ((stp->sd_flag & errs) && !(flag & STR_DELAYERR)) { 31307c478bd9Sstevel@tonic-gate error = strgeterr(stp, errs, (flag & STR_PEEK)); 31317c478bd9Sstevel@tonic-gate if (error != 0) { 31327c478bd9Sstevel@tonic-gate *done = 1; 31337c478bd9Sstevel@tonic-gate return (error); 31347c478bd9Sstevel@tonic-gate } 31357c478bd9Sstevel@tonic-gate } 31367c478bd9Sstevel@tonic-gate *done = 0; 31377c478bd9Sstevel@tonic-gate return (0); 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate /* 31417c478bd9Sstevel@tonic-gate * Perform job control discipline access checks. 31427c478bd9Sstevel@tonic-gate * Return 0 for success and the errno for failure. 31437c478bd9Sstevel@tonic-gate */ 31447c478bd9Sstevel@tonic-gate 31457c478bd9Sstevel@tonic-gate #define cantsend(p, t, sig) \ 31467c478bd9Sstevel@tonic-gate (sigismember(&(p)->p_ignore, sig) || signal_is_blocked((t), sig)) 31477c478bd9Sstevel@tonic-gate 31487c478bd9Sstevel@tonic-gate int 31497c478bd9Sstevel@tonic-gate straccess(struct stdata *stp, enum jcaccess mode) 31507c478bd9Sstevel@tonic-gate { 31517c478bd9Sstevel@tonic-gate extern kcondvar_t lbolt_cv; /* XXX: should be in a header file */ 31527c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 31537c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(t); 31547c478bd9Sstevel@tonic-gate sess_t *sp; 31557c478bd9Sstevel@tonic-gate 31569acbbeafSnn35248 ASSERT(mutex_owned(&stp->sd_lock)); 31579acbbeafSnn35248 31587c478bd9Sstevel@tonic-gate if (stp->sd_sidp == NULL || stp->sd_vnode->v_type == VFIFO) 31597c478bd9Sstevel@tonic-gate return (0); 31607c478bd9Sstevel@tonic-gate 31619acbbeafSnn35248 mutex_enter(&p->p_lock); /* protects p_pgidp */ 31627c478bd9Sstevel@tonic-gate 31637c478bd9Sstevel@tonic-gate for (;;) { 31649acbbeafSnn35248 mutex_enter(&p->p_splock); /* protects p->p_sessp */ 31659acbbeafSnn35248 sp = p->p_sessp; 31669acbbeafSnn35248 mutex_enter(&sp->s_lock); /* protects sp->* */ 31679acbbeafSnn35248 31687c478bd9Sstevel@tonic-gate /* 31697c478bd9Sstevel@tonic-gate * If this is not the calling process's controlling terminal 31707c478bd9Sstevel@tonic-gate * or if the calling process is already in the foreground 31717c478bd9Sstevel@tonic-gate * then allow access. 31727c478bd9Sstevel@tonic-gate */ 31737c478bd9Sstevel@tonic-gate if (sp->s_dev != stp->sd_vnode->v_rdev || 31747c478bd9Sstevel@tonic-gate p->p_pgidp == stp->sd_pgidp) { 31759acbbeafSnn35248 mutex_exit(&sp->s_lock); 31769acbbeafSnn35248 mutex_exit(&p->p_splock); 31777c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 31787c478bd9Sstevel@tonic-gate return (0); 31797c478bd9Sstevel@tonic-gate } 31807c478bd9Sstevel@tonic-gate 31817c478bd9Sstevel@tonic-gate /* 31827c478bd9Sstevel@tonic-gate * Check to see if controlling terminal has been deallocated. 31837c478bd9Sstevel@tonic-gate */ 31847c478bd9Sstevel@tonic-gate if (sp->s_vp == NULL) { 31857c478bd9Sstevel@tonic-gate if (!cantsend(p, t, SIGHUP)) 31867c478bd9Sstevel@tonic-gate sigtoproc(p, t, SIGHUP); 31879acbbeafSnn35248 mutex_exit(&sp->s_lock); 31889acbbeafSnn35248 mutex_exit(&p->p_splock); 31897c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 31907c478bd9Sstevel@tonic-gate return (EIO); 31917c478bd9Sstevel@tonic-gate } 31927c478bd9Sstevel@tonic-gate 31939acbbeafSnn35248 mutex_exit(&sp->s_lock); 31949acbbeafSnn35248 mutex_exit(&p->p_splock); 31959acbbeafSnn35248 31967c478bd9Sstevel@tonic-gate if (mode == JCGETP) { 31977c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 31987c478bd9Sstevel@tonic-gate return (0); 31997c478bd9Sstevel@tonic-gate } 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate if (mode == JCREAD) { 32027c478bd9Sstevel@tonic-gate if (p->p_detached || cantsend(p, t, SIGTTIN)) { 32037c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 32047c478bd9Sstevel@tonic-gate return (EIO); 32057c478bd9Sstevel@tonic-gate } 32067c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 32079acbbeafSnn35248 mutex_exit(&stp->sd_lock); 32087c478bd9Sstevel@tonic-gate pgsignal(p->p_pgidp, SIGTTIN); 32099acbbeafSnn35248 mutex_enter(&stp->sd_lock); 32107c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 32117c478bd9Sstevel@tonic-gate } else { /* mode == JCWRITE or JCSETP */ 32127c478bd9Sstevel@tonic-gate if ((mode == JCWRITE && !(stp->sd_flag & STRTOSTOP)) || 32137c478bd9Sstevel@tonic-gate cantsend(p, t, SIGTTOU)) { 32147c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 32157c478bd9Sstevel@tonic-gate return (0); 32167c478bd9Sstevel@tonic-gate } 32177c478bd9Sstevel@tonic-gate if (p->p_detached) { 32187c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 32197c478bd9Sstevel@tonic-gate return (EIO); 32207c478bd9Sstevel@tonic-gate } 32217c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 32229acbbeafSnn35248 mutex_exit(&stp->sd_lock); 32237c478bd9Sstevel@tonic-gate pgsignal(p->p_pgidp, SIGTTOU); 32249acbbeafSnn35248 mutex_enter(&stp->sd_lock); 32257c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 32267c478bd9Sstevel@tonic-gate } 32277c478bd9Sstevel@tonic-gate 32287c478bd9Sstevel@tonic-gate /* 32297c478bd9Sstevel@tonic-gate * We call cv_wait_sig_swap() to cause the appropriate 32307c478bd9Sstevel@tonic-gate * action for the jobcontrol signal to take place. 32317c478bd9Sstevel@tonic-gate * If the signal is being caught, we will take the 32327c478bd9Sstevel@tonic-gate * EINTR error return. Otherwise, the default action 32337c478bd9Sstevel@tonic-gate * of causing the process to stop will take place. 32347c478bd9Sstevel@tonic-gate * In this case, we rely on the periodic cv_broadcast() on 32357c478bd9Sstevel@tonic-gate * &lbolt_cv to wake us up to loop around and test again. 32367c478bd9Sstevel@tonic-gate * We can't get here if the signal is ignored or 32377c478bd9Sstevel@tonic-gate * if the current thread is blocking the signal. 32387c478bd9Sstevel@tonic-gate */ 32399acbbeafSnn35248 mutex_exit(&stp->sd_lock); 32407c478bd9Sstevel@tonic-gate if (!cv_wait_sig_swap(&lbolt_cv, &p->p_lock)) { 32417c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 32429acbbeafSnn35248 mutex_enter(&stp->sd_lock); 32437c478bd9Sstevel@tonic-gate return (EINTR); 32447c478bd9Sstevel@tonic-gate } 32459acbbeafSnn35248 mutex_exit(&p->p_lock); 32469acbbeafSnn35248 mutex_enter(&stp->sd_lock); 32479acbbeafSnn35248 mutex_enter(&p->p_lock); 32487c478bd9Sstevel@tonic-gate } 32497c478bd9Sstevel@tonic-gate } 32507c478bd9Sstevel@tonic-gate 32517c478bd9Sstevel@tonic-gate /* 32527c478bd9Sstevel@tonic-gate * Return size of message of block type (bp->b_datap->db_type) 32537c478bd9Sstevel@tonic-gate */ 32547c478bd9Sstevel@tonic-gate size_t 32557c478bd9Sstevel@tonic-gate xmsgsize(mblk_t *bp) 32567c478bd9Sstevel@tonic-gate { 32577c478bd9Sstevel@tonic-gate unsigned char type; 32587c478bd9Sstevel@tonic-gate size_t count = 0; 32597c478bd9Sstevel@tonic-gate 32607c478bd9Sstevel@tonic-gate type = bp->b_datap->db_type; 32617c478bd9Sstevel@tonic-gate 32627c478bd9Sstevel@tonic-gate for (; bp; bp = bp->b_cont) { 32637c478bd9Sstevel@tonic-gate if (type != bp->b_datap->db_type) 32647c478bd9Sstevel@tonic-gate break; 32657c478bd9Sstevel@tonic-gate ASSERT(bp->b_wptr >= bp->b_rptr); 32667c478bd9Sstevel@tonic-gate count += bp->b_wptr - bp->b_rptr; 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate return (count); 32697c478bd9Sstevel@tonic-gate } 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate /* 32727c478bd9Sstevel@tonic-gate * Allocate a stream head. 32737c478bd9Sstevel@tonic-gate */ 32747c478bd9Sstevel@tonic-gate struct stdata * 32757c478bd9Sstevel@tonic-gate shalloc(queue_t *qp) 32767c478bd9Sstevel@tonic-gate { 32777c478bd9Sstevel@tonic-gate stdata_t *stp; 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate stp = kmem_cache_alloc(stream_head_cache, KM_SLEEP); 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate stp->sd_wrq = _WR(qp); 32827c478bd9Sstevel@tonic-gate stp->sd_strtab = NULL; 32837c478bd9Sstevel@tonic-gate stp->sd_iocid = 0; 32847c478bd9Sstevel@tonic-gate stp->sd_mate = NULL; 32857c478bd9Sstevel@tonic-gate stp->sd_freezer = NULL; 32867c478bd9Sstevel@tonic-gate stp->sd_refcnt = 0; 32877c478bd9Sstevel@tonic-gate stp->sd_wakeq = 0; 32887c478bd9Sstevel@tonic-gate stp->sd_anchor = 0; 32897c478bd9Sstevel@tonic-gate stp->sd_struiowrq = NULL; 32907c478bd9Sstevel@tonic-gate stp->sd_struiordq = NULL; 32917c478bd9Sstevel@tonic-gate stp->sd_struiodnak = 0; 32927c478bd9Sstevel@tonic-gate stp->sd_struionak = NULL; 32937c478bd9Sstevel@tonic-gate stp->sd_t_audit_data = NULL; 32947c478bd9Sstevel@tonic-gate stp->sd_rput_opt = 0; 32957c478bd9Sstevel@tonic-gate stp->sd_wput_opt = 0; 32967c478bd9Sstevel@tonic-gate stp->sd_read_opt = 0; 32977c478bd9Sstevel@tonic-gate stp->sd_rprotofunc = strrput_proto; 32987c478bd9Sstevel@tonic-gate stp->sd_rmiscfunc = strrput_misc; 32997c478bd9Sstevel@tonic-gate stp->sd_rderrfunc = stp->sd_wrerrfunc = NULL; 3300c28749e9Skais stp->sd_rputdatafunc = stp->sd_wputdatafunc = NULL; 33017c478bd9Sstevel@tonic-gate stp->sd_ciputctrl = NULL; 33027c478bd9Sstevel@tonic-gate stp->sd_nciputctrl = 0; 33037c478bd9Sstevel@tonic-gate stp->sd_qhead = NULL; 33047c478bd9Sstevel@tonic-gate stp->sd_qtail = NULL; 33057c478bd9Sstevel@tonic-gate stp->sd_servid = NULL; 33067c478bd9Sstevel@tonic-gate stp->sd_nqueues = 0; 33077c478bd9Sstevel@tonic-gate stp->sd_svcflags = 0; 33087c478bd9Sstevel@tonic-gate stp->sd_copyflag = 0; 3309c28749e9Skais 33107c478bd9Sstevel@tonic-gate return (stp); 33117c478bd9Sstevel@tonic-gate } 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate /* 33147c478bd9Sstevel@tonic-gate * Free a stream head. 33157c478bd9Sstevel@tonic-gate */ 33167c478bd9Sstevel@tonic-gate void 33177c478bd9Sstevel@tonic-gate shfree(stdata_t *stp) 33187c478bd9Sstevel@tonic-gate { 33197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&stp->sd_lock)); 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate stp->sd_wrq = NULL; 33227c478bd9Sstevel@tonic-gate 33237c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_qlock); 33247c478bd9Sstevel@tonic-gate while (stp->sd_svcflags & STRS_SCHEDULED) { 33257c478bd9Sstevel@tonic-gate STRSTAT(strwaits); 33267c478bd9Sstevel@tonic-gate cv_wait(&stp->sd_qcv, &stp->sd_qlock); 33277c478bd9Sstevel@tonic-gate } 33287c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_qlock); 33297c478bd9Sstevel@tonic-gate 33307c478bd9Sstevel@tonic-gate if (stp->sd_ciputctrl != NULL) { 33317c478bd9Sstevel@tonic-gate ASSERT(stp->sd_nciputctrl == n_ciputctrl - 1); 33327c478bd9Sstevel@tonic-gate SUMCHECK_CIPUTCTRL_COUNTS(stp->sd_ciputctrl, 33337c478bd9Sstevel@tonic-gate stp->sd_nciputctrl, 0); 33347c478bd9Sstevel@tonic-gate ASSERT(ciputctrl_cache != NULL); 33357c478bd9Sstevel@tonic-gate kmem_cache_free(ciputctrl_cache, stp->sd_ciputctrl); 33367c478bd9Sstevel@tonic-gate stp->sd_ciputctrl = NULL; 33377c478bd9Sstevel@tonic-gate stp->sd_nciputctrl = 0; 33387c478bd9Sstevel@tonic-gate } 33397c478bd9Sstevel@tonic-gate ASSERT(stp->sd_qhead == NULL); 33407c478bd9Sstevel@tonic-gate ASSERT(stp->sd_qtail == NULL); 33417c478bd9Sstevel@tonic-gate ASSERT(stp->sd_nqueues == 0); 33427c478bd9Sstevel@tonic-gate kmem_cache_free(stream_head_cache, stp); 33437c478bd9Sstevel@tonic-gate } 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate /* 33467c478bd9Sstevel@tonic-gate * Allocate a pair of queues and a syncq for the pair 33477c478bd9Sstevel@tonic-gate */ 33487c478bd9Sstevel@tonic-gate queue_t * 33497c478bd9Sstevel@tonic-gate allocq(void) 33507c478bd9Sstevel@tonic-gate { 33517c478bd9Sstevel@tonic-gate queinfo_t *qip; 33527c478bd9Sstevel@tonic-gate queue_t *qp, *wqp; 33537c478bd9Sstevel@tonic-gate syncq_t *sq; 33547c478bd9Sstevel@tonic-gate 33557c478bd9Sstevel@tonic-gate qip = kmem_cache_alloc(queue_cache, KM_SLEEP); 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate qp = &qip->qu_rqueue; 33587c478bd9Sstevel@tonic-gate wqp = &qip->qu_wqueue; 33597c478bd9Sstevel@tonic-gate sq = &qip->qu_syncq; 33607c478bd9Sstevel@tonic-gate 33617c478bd9Sstevel@tonic-gate qp->q_last = NULL; 33627c478bd9Sstevel@tonic-gate qp->q_next = NULL; 33637c478bd9Sstevel@tonic-gate qp->q_ptr = NULL; 33647c478bd9Sstevel@tonic-gate qp->q_flag = QUSE | QREADR; 33657c478bd9Sstevel@tonic-gate qp->q_bandp = NULL; 33667c478bd9Sstevel@tonic-gate qp->q_stream = NULL; 33677c478bd9Sstevel@tonic-gate qp->q_syncq = sq; 33687c478bd9Sstevel@tonic-gate qp->q_nband = 0; 33697c478bd9Sstevel@tonic-gate qp->q_nfsrv = NULL; 33707c478bd9Sstevel@tonic-gate qp->q_draining = 0; 33717c478bd9Sstevel@tonic-gate qp->q_syncqmsgs = 0; 33727c478bd9Sstevel@tonic-gate qp->q_spri = 0; 33737c478bd9Sstevel@tonic-gate qp->q_qtstamp = 0; 33747c478bd9Sstevel@tonic-gate qp->q_sqtstamp = 0; 33757c478bd9Sstevel@tonic-gate qp->q_fp = NULL; 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate wqp->q_last = NULL; 33787c478bd9Sstevel@tonic-gate wqp->q_next = NULL; 33797c478bd9Sstevel@tonic-gate wqp->q_ptr = NULL; 33807c478bd9Sstevel@tonic-gate wqp->q_flag = QUSE; 33817c478bd9Sstevel@tonic-gate wqp->q_bandp = NULL; 33827c478bd9Sstevel@tonic-gate wqp->q_stream = NULL; 33837c478bd9Sstevel@tonic-gate wqp->q_syncq = sq; 33847c478bd9Sstevel@tonic-gate wqp->q_nband = 0; 33857c478bd9Sstevel@tonic-gate wqp->q_nfsrv = NULL; 33867c478bd9Sstevel@tonic-gate wqp->q_draining = 0; 33877c478bd9Sstevel@tonic-gate wqp->q_syncqmsgs = 0; 33887c478bd9Sstevel@tonic-gate wqp->q_qtstamp = 0; 33897c478bd9Sstevel@tonic-gate wqp->q_sqtstamp = 0; 33907c478bd9Sstevel@tonic-gate wqp->q_spri = 0; 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate sq->sq_count = 0; 33937c478bd9Sstevel@tonic-gate sq->sq_rmqcount = 0; 33947c478bd9Sstevel@tonic-gate sq->sq_flags = 0; 33957c478bd9Sstevel@tonic-gate sq->sq_type = 0; 33967c478bd9Sstevel@tonic-gate sq->sq_callbflags = 0; 33977c478bd9Sstevel@tonic-gate sq->sq_cancelid = 0; 33987c478bd9Sstevel@tonic-gate sq->sq_ciputctrl = NULL; 33997c478bd9Sstevel@tonic-gate sq->sq_nciputctrl = 0; 34007c478bd9Sstevel@tonic-gate sq->sq_needexcl = 0; 34017c478bd9Sstevel@tonic-gate sq->sq_svcflags = 0; 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate return (qp); 34047c478bd9Sstevel@tonic-gate } 34057c478bd9Sstevel@tonic-gate 34067c478bd9Sstevel@tonic-gate /* 34077c478bd9Sstevel@tonic-gate * Free a pair of queues and the "attached" syncq. 34087c478bd9Sstevel@tonic-gate * Discard any messages left on the syncq(s), remove the syncq(s) from the 34097c478bd9Sstevel@tonic-gate * outer perimeter, and free the syncq(s) if they are not the "attached" syncq. 34107c478bd9Sstevel@tonic-gate */ 34117c478bd9Sstevel@tonic-gate void 34127c478bd9Sstevel@tonic-gate freeq(queue_t *qp) 34137c478bd9Sstevel@tonic-gate { 34147c478bd9Sstevel@tonic-gate qband_t *qbp, *nqbp; 34157c478bd9Sstevel@tonic-gate syncq_t *sq, *outer; 34167c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate ASSERT(qp->q_flag & QREADR); 34197c478bd9Sstevel@tonic-gate 3420989ae01eSgeorges /* 3421989ae01eSgeorges * If a previously dispatched taskq job is scheduled to run 3422989ae01eSgeorges * sync_service() or a service routine is scheduled for the 3423989ae01eSgeorges * queues about to be freed, wait here until all service is 3424989ae01eSgeorges * done on the queue and all associated queues and syncqs. 3425989ae01eSgeorges */ 3426989ae01eSgeorges wait_svc(qp); 3427989ae01eSgeorges 34287c478bd9Sstevel@tonic-gate (void) flush_syncq(qp->q_syncq, qp); 34297c478bd9Sstevel@tonic-gate (void) flush_syncq(wqp->q_syncq, wqp); 34307c478bd9Sstevel@tonic-gate ASSERT(qp->q_syncqmsgs == 0 && wqp->q_syncqmsgs == 0); 34317c478bd9Sstevel@tonic-gate 3432989ae01eSgeorges /* 3433989ae01eSgeorges * Flush the queues before q_next is set to NULL This is needed 3434989ae01eSgeorges * in order to backenable any downstream queue before we go away. 3435989ae01eSgeorges * Note: we are already removed from the stream so that the 3436989ae01eSgeorges * backenabling will not cause any messages to be delivered to our 3437989ae01eSgeorges * put procedures. 3438989ae01eSgeorges */ 3439989ae01eSgeorges flushq(qp, FLUSHALL); 3440989ae01eSgeorges flushq(wqp, FLUSHALL); 3441989ae01eSgeorges 3442989ae01eSgeorges /* Tidy up - removeq only does a half-remove from stream */ 3443989ae01eSgeorges qp->q_next = wqp->q_next = NULL; 3444989ae01eSgeorges ASSERT(!(qp->q_flag & QENAB)); 3445989ae01eSgeorges ASSERT(!(wqp->q_flag & QENAB)); 3446989ae01eSgeorges 34477c478bd9Sstevel@tonic-gate outer = qp->q_syncq->sq_outer; 34487c478bd9Sstevel@tonic-gate if (outer != NULL) { 34497c478bd9Sstevel@tonic-gate outer_remove(outer, qp->q_syncq); 34507c478bd9Sstevel@tonic-gate if (wqp->q_syncq != qp->q_syncq) 34517c478bd9Sstevel@tonic-gate outer_remove(outer, wqp->q_syncq); 34527c478bd9Sstevel@tonic-gate } 34537c478bd9Sstevel@tonic-gate /* 34547c478bd9Sstevel@tonic-gate * Free any syncqs that are outside what allocq returned. 34557c478bd9Sstevel@tonic-gate */ 34567c478bd9Sstevel@tonic-gate if (qp->q_syncq != SQ(qp) && !(qp->q_flag & QPERMOD)) 34577c478bd9Sstevel@tonic-gate free_syncq(qp->q_syncq); 34587c478bd9Sstevel@tonic-gate if (qp->q_syncq != wqp->q_syncq && wqp->q_syncq != SQ(qp)) 34597c478bd9Sstevel@tonic-gate free_syncq(wqp->q_syncq); 34607c478bd9Sstevel@tonic-gate 34617c478bd9Sstevel@tonic-gate ASSERT((qp->q_sqflags & (Q_SQQUEUED | Q_SQDRAINING)) == 0); 34627c478bd9Sstevel@tonic-gate ASSERT((wqp->q_sqflags & (Q_SQQUEUED | Q_SQDRAINING)) == 0); 34637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(qp))); 34647c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(wqp))); 34657c478bd9Sstevel@tonic-gate sq = SQ(qp); 34667c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 34677c478bd9Sstevel@tonic-gate ASSERT(sq->sq_head == NULL && sq->sq_tail == NULL); 34687c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL); 34697c478bd9Sstevel@tonic-gate ASSERT(sq->sq_onext == NULL && sq->sq_oprev == NULL); 34707c478bd9Sstevel@tonic-gate ASSERT(sq->sq_callbpend == NULL); 34717c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl == 0); 34727c478bd9Sstevel@tonic-gate 34737c478bd9Sstevel@tonic-gate if (sq->sq_ciputctrl != NULL) { 34747c478bd9Sstevel@tonic-gate ASSERT(sq->sq_nciputctrl == n_ciputctrl - 1); 34757c478bd9Sstevel@tonic-gate SUMCHECK_CIPUTCTRL_COUNTS(sq->sq_ciputctrl, 34767c478bd9Sstevel@tonic-gate sq->sq_nciputctrl, 0); 34777c478bd9Sstevel@tonic-gate ASSERT(ciputctrl_cache != NULL); 34787c478bd9Sstevel@tonic-gate kmem_cache_free(ciputctrl_cache, sq->sq_ciputctrl); 34797c478bd9Sstevel@tonic-gate sq->sq_ciputctrl = NULL; 34807c478bd9Sstevel@tonic-gate sq->sq_nciputctrl = 0; 34817c478bd9Sstevel@tonic-gate } 34827c478bd9Sstevel@tonic-gate 34837c478bd9Sstevel@tonic-gate ASSERT(qp->q_first == NULL && wqp->q_first == NULL); 34847c478bd9Sstevel@tonic-gate ASSERT(qp->q_count == 0 && wqp->q_count == 0); 34857c478bd9Sstevel@tonic-gate ASSERT(qp->q_mblkcnt == 0 && wqp->q_mblkcnt == 0); 34867c478bd9Sstevel@tonic-gate 34877c478bd9Sstevel@tonic-gate qp->q_flag &= ~QUSE; 34887c478bd9Sstevel@tonic-gate wqp->q_flag &= ~QUSE; 34897c478bd9Sstevel@tonic-gate 34907c478bd9Sstevel@tonic-gate /* NOTE: Uncomment the assert below once bugid 1159635 is fixed. */ 34917c478bd9Sstevel@tonic-gate /* ASSERT((qp->q_flag & QWANTW) == 0 && (wqp->q_flag & QWANTW) == 0); */ 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate qbp = qp->q_bandp; 34947c478bd9Sstevel@tonic-gate while (qbp) { 34957c478bd9Sstevel@tonic-gate nqbp = qbp->qb_next; 34967c478bd9Sstevel@tonic-gate freeband(qbp); 34977c478bd9Sstevel@tonic-gate qbp = nqbp; 34987c478bd9Sstevel@tonic-gate } 34997c478bd9Sstevel@tonic-gate qbp = wqp->q_bandp; 35007c478bd9Sstevel@tonic-gate while (qbp) { 35017c478bd9Sstevel@tonic-gate nqbp = qbp->qb_next; 35027c478bd9Sstevel@tonic-gate freeband(qbp); 35037c478bd9Sstevel@tonic-gate qbp = nqbp; 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate kmem_cache_free(queue_cache, qp); 35067c478bd9Sstevel@tonic-gate } 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate /* 35097c478bd9Sstevel@tonic-gate * Allocate a qband structure. 35107c478bd9Sstevel@tonic-gate */ 35117c478bd9Sstevel@tonic-gate qband_t * 35127c478bd9Sstevel@tonic-gate allocband(void) 35137c478bd9Sstevel@tonic-gate { 35147c478bd9Sstevel@tonic-gate qband_t *qbp; 35157c478bd9Sstevel@tonic-gate 35167c478bd9Sstevel@tonic-gate qbp = kmem_cache_alloc(qband_cache, KM_NOSLEEP); 35177c478bd9Sstevel@tonic-gate if (qbp == NULL) 35187c478bd9Sstevel@tonic-gate return (NULL); 35197c478bd9Sstevel@tonic-gate 35207c478bd9Sstevel@tonic-gate qbp->qb_next = NULL; 35217c478bd9Sstevel@tonic-gate qbp->qb_count = 0; 35227c478bd9Sstevel@tonic-gate qbp->qb_mblkcnt = 0; 35237c478bd9Sstevel@tonic-gate qbp->qb_first = NULL; 35247c478bd9Sstevel@tonic-gate qbp->qb_last = NULL; 35257c478bd9Sstevel@tonic-gate qbp->qb_flag = 0; 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate return (qbp); 35287c478bd9Sstevel@tonic-gate } 35297c478bd9Sstevel@tonic-gate 35307c478bd9Sstevel@tonic-gate /* 35317c478bd9Sstevel@tonic-gate * Free a qband structure. 35327c478bd9Sstevel@tonic-gate */ 35337c478bd9Sstevel@tonic-gate void 35347c478bd9Sstevel@tonic-gate freeband(qband_t *qbp) 35357c478bd9Sstevel@tonic-gate { 35367c478bd9Sstevel@tonic-gate kmem_cache_free(qband_cache, qbp); 35377c478bd9Sstevel@tonic-gate } 35387c478bd9Sstevel@tonic-gate 35397c478bd9Sstevel@tonic-gate /* 35407c478bd9Sstevel@tonic-gate * Just like putnextctl(9F), except that allocb_wait() is used. 35417c478bd9Sstevel@tonic-gate * 35427c478bd9Sstevel@tonic-gate * Consolidation Private, and of course only callable from the stream head or 35437c478bd9Sstevel@tonic-gate * routines that may block. 35447c478bd9Sstevel@tonic-gate */ 35457c478bd9Sstevel@tonic-gate int 35467c478bd9Sstevel@tonic-gate putnextctl_wait(queue_t *q, int type) 35477c478bd9Sstevel@tonic-gate { 35487c478bd9Sstevel@tonic-gate mblk_t *bp; 35497c478bd9Sstevel@tonic-gate int error; 35507c478bd9Sstevel@tonic-gate 35517c478bd9Sstevel@tonic-gate if ((datamsg(type) && (type != M_DELAY)) || 35527c478bd9Sstevel@tonic-gate (bp = allocb_wait(0, BPRI_HI, 0, &error)) == NULL) 35537c478bd9Sstevel@tonic-gate return (0); 35547c478bd9Sstevel@tonic-gate 35557c478bd9Sstevel@tonic-gate bp->b_datap->db_type = (unsigned char)type; 35567c478bd9Sstevel@tonic-gate putnext(q, bp); 35577c478bd9Sstevel@tonic-gate return (1); 35587c478bd9Sstevel@tonic-gate } 35597c478bd9Sstevel@tonic-gate 35607c478bd9Sstevel@tonic-gate /* 356121804b56SBrian Ruthven * Run any possible bufcalls. 35627c478bd9Sstevel@tonic-gate */ 35637c478bd9Sstevel@tonic-gate void 35647c478bd9Sstevel@tonic-gate runbufcalls(void) 35657c478bd9Sstevel@tonic-gate { 35667c478bd9Sstevel@tonic-gate strbufcall_t *bcp; 35677c478bd9Sstevel@tonic-gate 35687c478bd9Sstevel@tonic-gate mutex_enter(&bcall_monitor); 35697c478bd9Sstevel@tonic-gate mutex_enter(&strbcall_lock); 35707c478bd9Sstevel@tonic-gate 35717c478bd9Sstevel@tonic-gate if (strbcalls.bc_head) { 35727c478bd9Sstevel@tonic-gate size_t count; 35737c478bd9Sstevel@tonic-gate int nevent; 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate /* 35767c478bd9Sstevel@tonic-gate * count how many events are on the list 35777c478bd9Sstevel@tonic-gate * now so we can check to avoid looping 35787c478bd9Sstevel@tonic-gate * in low memory situations 35797c478bd9Sstevel@tonic-gate */ 35807c478bd9Sstevel@tonic-gate nevent = 0; 35817c478bd9Sstevel@tonic-gate for (bcp = strbcalls.bc_head; bcp; bcp = bcp->bc_next) 35827c478bd9Sstevel@tonic-gate nevent++; 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate /* 35857c478bd9Sstevel@tonic-gate * get estimate of available memory from kmem_avail(). 35867c478bd9Sstevel@tonic-gate * awake all bufcall functions waiting for 35877c478bd9Sstevel@tonic-gate * memory whose request could be satisfied 35887c478bd9Sstevel@tonic-gate * by 'count' memory and let 'em fight for it. 35897c478bd9Sstevel@tonic-gate */ 35907c478bd9Sstevel@tonic-gate count = kmem_avail(); 35917c478bd9Sstevel@tonic-gate while ((bcp = strbcalls.bc_head) != NULL && nevent) { 35927c478bd9Sstevel@tonic-gate STRSTAT(bufcalls); 35937c478bd9Sstevel@tonic-gate --nevent; 35947c478bd9Sstevel@tonic-gate if (bcp->bc_size <= count) { 35957c478bd9Sstevel@tonic-gate bcp->bc_executor = curthread; 35967c478bd9Sstevel@tonic-gate mutex_exit(&strbcall_lock); 35977c478bd9Sstevel@tonic-gate (*bcp->bc_func)(bcp->bc_arg); 35987c478bd9Sstevel@tonic-gate mutex_enter(&strbcall_lock); 35997c478bd9Sstevel@tonic-gate bcp->bc_executor = NULL; 36007c478bd9Sstevel@tonic-gate cv_broadcast(&bcall_cv); 36017c478bd9Sstevel@tonic-gate strbcalls.bc_head = bcp->bc_next; 36027c478bd9Sstevel@tonic-gate kmem_free(bcp, sizeof (strbufcall_t)); 36037c478bd9Sstevel@tonic-gate } else { 36047c478bd9Sstevel@tonic-gate /* 36057c478bd9Sstevel@tonic-gate * too big, try again later - note 36067c478bd9Sstevel@tonic-gate * that nevent was decremented above 36077c478bd9Sstevel@tonic-gate * so we won't retry this one on this 36087c478bd9Sstevel@tonic-gate * iteration of the loop 36097c478bd9Sstevel@tonic-gate */ 36107c478bd9Sstevel@tonic-gate if (bcp->bc_next != NULL) { 36117c478bd9Sstevel@tonic-gate strbcalls.bc_head = bcp->bc_next; 36127c478bd9Sstevel@tonic-gate bcp->bc_next = NULL; 36137c478bd9Sstevel@tonic-gate strbcalls.bc_tail->bc_next = bcp; 36147c478bd9Sstevel@tonic-gate strbcalls.bc_tail = bcp; 36157c478bd9Sstevel@tonic-gate } 36167c478bd9Sstevel@tonic-gate } 36177c478bd9Sstevel@tonic-gate } 36187c478bd9Sstevel@tonic-gate if (strbcalls.bc_head == NULL) 36197c478bd9Sstevel@tonic-gate strbcalls.bc_tail = NULL; 36207c478bd9Sstevel@tonic-gate } 36217c478bd9Sstevel@tonic-gate 36227c478bd9Sstevel@tonic-gate mutex_exit(&strbcall_lock); 36237c478bd9Sstevel@tonic-gate mutex_exit(&bcall_monitor); 36247c478bd9Sstevel@tonic-gate } 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate 36277c478bd9Sstevel@tonic-gate /* 362821804b56SBrian Ruthven * Actually run queue's service routine. 36297c478bd9Sstevel@tonic-gate */ 36307c478bd9Sstevel@tonic-gate static void 36317c478bd9Sstevel@tonic-gate runservice(queue_t *q) 36327c478bd9Sstevel@tonic-gate { 36337c478bd9Sstevel@tonic-gate qband_t *qbp; 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate ASSERT(q->q_qinfo->qi_srvp); 36367c478bd9Sstevel@tonic-gate again: 36377c478bd9Sstevel@tonic-gate entersq(q->q_syncq, SQ_SVC); 36387c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, TR_QRUNSERVICE_START, 36397c478bd9Sstevel@tonic-gate "runservice starts:%p", q); 36407c478bd9Sstevel@tonic-gate 36417c478bd9Sstevel@tonic-gate if (!(q->q_flag & QWCLOSE)) 36427c478bd9Sstevel@tonic-gate (*q->q_qinfo->qi_srvp)(q); 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, TR_QRUNSERVICE_END, 36457c478bd9Sstevel@tonic-gate "runservice ends:(%p)", q); 36467c478bd9Sstevel@tonic-gate 36477c478bd9Sstevel@tonic-gate leavesq(q->q_syncq, SQ_SVC); 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 36507c478bd9Sstevel@tonic-gate if (q->q_flag & QENAB) { 36517c478bd9Sstevel@tonic-gate q->q_flag &= ~QENAB; 36527c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 36537c478bd9Sstevel@tonic-gate goto again; 36547c478bd9Sstevel@tonic-gate } 36557c478bd9Sstevel@tonic-gate q->q_flag &= ~QINSERVICE; 36567c478bd9Sstevel@tonic-gate q->q_flag &= ~QBACK; 36577c478bd9Sstevel@tonic-gate for (qbp = q->q_bandp; qbp; qbp = qbp->qb_next) 36587c478bd9Sstevel@tonic-gate qbp->qb_flag &= ~QB_BACK; 36597c478bd9Sstevel@tonic-gate /* 36607c478bd9Sstevel@tonic-gate * Wakeup thread waiting for the service procedure 36617c478bd9Sstevel@tonic-gate * to be run (strclose and qdetach). 36627c478bd9Sstevel@tonic-gate */ 36637c478bd9Sstevel@tonic-gate cv_broadcast(&q->q_wait); 36647c478bd9Sstevel@tonic-gate 36657c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 36667c478bd9Sstevel@tonic-gate } 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate /* 36697c478bd9Sstevel@tonic-gate * Background processing of bufcalls. 36707c478bd9Sstevel@tonic-gate */ 36717c478bd9Sstevel@tonic-gate void 36727c478bd9Sstevel@tonic-gate streams_bufcall_service(void) 36737c478bd9Sstevel@tonic-gate { 36747c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 36757c478bd9Sstevel@tonic-gate 36767c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &strbcall_lock, callb_generic_cpr, 36777c478bd9Sstevel@tonic-gate "streams_bufcall_service"); 36787c478bd9Sstevel@tonic-gate 36797c478bd9Sstevel@tonic-gate mutex_enter(&strbcall_lock); 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate for (;;) { 36827c478bd9Sstevel@tonic-gate if (strbcalls.bc_head != NULL && kmem_avail() > 0) { 36837c478bd9Sstevel@tonic-gate mutex_exit(&strbcall_lock); 36847c478bd9Sstevel@tonic-gate runbufcalls(); 36857c478bd9Sstevel@tonic-gate mutex_enter(&strbcall_lock); 36867c478bd9Sstevel@tonic-gate } 36877c478bd9Sstevel@tonic-gate if (strbcalls.bc_head != NULL) { 36887c478bd9Sstevel@tonic-gate STRSTAT(bcwaits); 36897c478bd9Sstevel@tonic-gate /* Wait for memory to become available */ 36907c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 3691d3d50737SRafael Vanoni (void) cv_reltimedwait(&memavail_cv, &strbcall_lock, 3692d3d50737SRafael Vanoni SEC_TO_TICK(60), TR_CLOCK_TICK); 36937c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &strbcall_lock); 36947c478bd9Sstevel@tonic-gate } 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate /* Wait for new work to arrive */ 36977c478bd9Sstevel@tonic-gate if (strbcalls.bc_head == NULL) { 36987c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 36997c478bd9Sstevel@tonic-gate cv_wait(&strbcall_cv, &strbcall_lock); 37007c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &strbcall_lock); 37017c478bd9Sstevel@tonic-gate } 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate /* 37067c478bd9Sstevel@tonic-gate * Background processing of streams background tasks which failed 37077c478bd9Sstevel@tonic-gate * taskq_dispatch. 37087c478bd9Sstevel@tonic-gate */ 37097c478bd9Sstevel@tonic-gate static void 37107c478bd9Sstevel@tonic-gate streams_qbkgrnd_service(void) 37117c478bd9Sstevel@tonic-gate { 37127c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 37137c478bd9Sstevel@tonic-gate queue_t *q; 37147c478bd9Sstevel@tonic-gate 37157c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &service_queue, callb_generic_cpr, 37167c478bd9Sstevel@tonic-gate "streams_bkgrnd_service"); 37177c478bd9Sstevel@tonic-gate 37187c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 37197c478bd9Sstevel@tonic-gate 37207c478bd9Sstevel@tonic-gate for (;;) { 37217c478bd9Sstevel@tonic-gate /* 37227c478bd9Sstevel@tonic-gate * Wait for work to arrive. 37237c478bd9Sstevel@tonic-gate */ 37247c478bd9Sstevel@tonic-gate while ((freebs_list == NULL) && (qhead == NULL)) { 37257c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 37267c478bd9Sstevel@tonic-gate cv_wait(&services_to_run, &service_queue); 37277c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &service_queue); 37287c478bd9Sstevel@tonic-gate } 37297c478bd9Sstevel@tonic-gate /* 37307c478bd9Sstevel@tonic-gate * Handle all pending freebs requests to free memory. 37317c478bd9Sstevel@tonic-gate */ 37327c478bd9Sstevel@tonic-gate while (freebs_list != NULL) { 37337c478bd9Sstevel@tonic-gate mblk_t *mp = freebs_list; 37347c478bd9Sstevel@tonic-gate freebs_list = mp->b_next; 37357c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 37367c478bd9Sstevel@tonic-gate mblk_free(mp); 37377c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 37387c478bd9Sstevel@tonic-gate } 37397c478bd9Sstevel@tonic-gate /* 37407c478bd9Sstevel@tonic-gate * Run pending queues. 37417c478bd9Sstevel@tonic-gate */ 37427c478bd9Sstevel@tonic-gate while (qhead != NULL) { 37437c478bd9Sstevel@tonic-gate DQ(q, qhead, qtail, q_link); 37447c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 37457c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 37467c478bd9Sstevel@tonic-gate queue_service(q); 37477c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 37487c478bd9Sstevel@tonic-gate } 37497c478bd9Sstevel@tonic-gate ASSERT(qhead == NULL && qtail == NULL); 37507c478bd9Sstevel@tonic-gate } 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate 37537c478bd9Sstevel@tonic-gate /* 37547c478bd9Sstevel@tonic-gate * Background processing of streams background tasks which failed 37557c478bd9Sstevel@tonic-gate * taskq_dispatch. 37567c478bd9Sstevel@tonic-gate */ 37577c478bd9Sstevel@tonic-gate static void 37587c478bd9Sstevel@tonic-gate streams_sqbkgrnd_service(void) 37597c478bd9Sstevel@tonic-gate { 37607c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 37617c478bd9Sstevel@tonic-gate syncq_t *sq; 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &service_queue, callb_generic_cpr, 37647c478bd9Sstevel@tonic-gate "streams_sqbkgrnd_service"); 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 37677c478bd9Sstevel@tonic-gate 37687c478bd9Sstevel@tonic-gate for (;;) { 37697c478bd9Sstevel@tonic-gate /* 37707c478bd9Sstevel@tonic-gate * Wait for work to arrive. 37717c478bd9Sstevel@tonic-gate */ 37727c478bd9Sstevel@tonic-gate while (sqhead == NULL) { 37737c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 37747c478bd9Sstevel@tonic-gate cv_wait(&syncqs_to_run, &service_queue); 37757c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &service_queue); 37767c478bd9Sstevel@tonic-gate } 37777c478bd9Sstevel@tonic-gate 37787c478bd9Sstevel@tonic-gate /* 37797c478bd9Sstevel@tonic-gate * Run pending syncqs. 37807c478bd9Sstevel@tonic-gate */ 37817c478bd9Sstevel@tonic-gate while (sqhead != NULL) { 37827c478bd9Sstevel@tonic-gate DQ(sq, sqhead, sqtail, sq_next); 37837c478bd9Sstevel@tonic-gate ASSERT(sq != NULL); 37847c478bd9Sstevel@tonic-gate ASSERT(sq->sq_svcflags & SQ_BGTHREAD); 37857c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 37867c478bd9Sstevel@tonic-gate syncq_service(sq); 37877c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 37887c478bd9Sstevel@tonic-gate } 37897c478bd9Sstevel@tonic-gate } 37907c478bd9Sstevel@tonic-gate } 37917c478bd9Sstevel@tonic-gate 37927c478bd9Sstevel@tonic-gate /* 37937c478bd9Sstevel@tonic-gate * Disable the syncq and wait for background syncq processing to complete. 37947c478bd9Sstevel@tonic-gate * If the syncq is placed on the sqhead/sqtail queue, try to remove it from the 37957c478bd9Sstevel@tonic-gate * list. 37967c478bd9Sstevel@tonic-gate */ 37977c478bd9Sstevel@tonic-gate void 37987c478bd9Sstevel@tonic-gate wait_sq_svc(syncq_t *sq) 37997c478bd9Sstevel@tonic-gate { 38007c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 38017c478bd9Sstevel@tonic-gate sq->sq_svcflags |= SQ_DISABLED; 38027c478bd9Sstevel@tonic-gate if (sq->sq_svcflags & SQ_BGTHREAD) { 38037c478bd9Sstevel@tonic-gate syncq_t *sq_chase; 38047c478bd9Sstevel@tonic-gate syncq_t *sq_curr; 38057c478bd9Sstevel@tonic-gate int removed; 38067c478bd9Sstevel@tonic-gate 38077c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount == 1); 38087c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 38097c478bd9Sstevel@tonic-gate RMQ(sq, sqhead, sqtail, sq_next, sq_chase, sq_curr, removed); 38107c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 38117c478bd9Sstevel@tonic-gate if (removed) { 38127c478bd9Sstevel@tonic-gate sq->sq_svcflags &= ~SQ_BGTHREAD; 38137c478bd9Sstevel@tonic-gate sq->sq_servcount = 0; 38147c478bd9Sstevel@tonic-gate STRSTAT(sqremoved); 38157c478bd9Sstevel@tonic-gate goto done; 38167c478bd9Sstevel@tonic-gate } 38177c478bd9Sstevel@tonic-gate } 38187c478bd9Sstevel@tonic-gate while (sq->sq_servcount != 0) { 38197c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 38207c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 38217c478bd9Sstevel@tonic-gate } 38227c478bd9Sstevel@tonic-gate done: 38237c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 38247c478bd9Sstevel@tonic-gate } 38257c478bd9Sstevel@tonic-gate 38267c478bd9Sstevel@tonic-gate /* 38277c478bd9Sstevel@tonic-gate * Put a syncq on the list of syncq's to be serviced by the sqthread. 38287c478bd9Sstevel@tonic-gate * Add the argument to the end of the sqhead list and set the flag 38297c478bd9Sstevel@tonic-gate * indicating this syncq has been enabled. If it has already been 38307c478bd9Sstevel@tonic-gate * enabled, don't do anything. 38317c478bd9Sstevel@tonic-gate * This routine assumes that SQLOCK is held. 38327c478bd9Sstevel@tonic-gate * NOTE that the lock order is to have the SQLOCK first, 38337c478bd9Sstevel@tonic-gate * so if the service_syncq lock is held, we need to release it 383421804b56SBrian Ruthven * before acquiring the SQLOCK (mostly relevant for the background 38357c478bd9Sstevel@tonic-gate * thread, and this seems to be common among the STREAMS global locks). 383621804b56SBrian Ruthven * Note that the sq_svcflags are protected by the SQLOCK. 38377c478bd9Sstevel@tonic-gate */ 38387c478bd9Sstevel@tonic-gate void 38397c478bd9Sstevel@tonic-gate sqenable(syncq_t *sq) 38407c478bd9Sstevel@tonic-gate { 38417c478bd9Sstevel@tonic-gate /* 38427c478bd9Sstevel@tonic-gate * This is probably not important except for where I believe it 38437c478bd9Sstevel@tonic-gate * is being called. At that point, it should be held (and it 38447c478bd9Sstevel@tonic-gate * is a pain to release it just for this routine, so don't do 38457c478bd9Sstevel@tonic-gate * it). 38467c478bd9Sstevel@tonic-gate */ 38477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate IMPLY(sq->sq_servcount == 0, sq->sq_next == NULL); 38507c478bd9Sstevel@tonic-gate IMPLY(sq->sq_next != NULL, sq->sq_svcflags & SQ_BGTHREAD); 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate /* 38537c478bd9Sstevel@tonic-gate * Do not put on list if background thread is scheduled or 38547c478bd9Sstevel@tonic-gate * syncq is disabled. 38557c478bd9Sstevel@tonic-gate */ 38567c478bd9Sstevel@tonic-gate if (sq->sq_svcflags & (SQ_DISABLED | SQ_BGTHREAD)) 38577c478bd9Sstevel@tonic-gate return; 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate /* 38607c478bd9Sstevel@tonic-gate * Check whether we should enable sq at all. 38617c478bd9Sstevel@tonic-gate * Non PERMOD syncqs may be drained by at most one thread. 38627c478bd9Sstevel@tonic-gate * PERMOD syncqs may be drained by several threads but we limit the 38637c478bd9Sstevel@tonic-gate * total amount to the lesser of 38647c478bd9Sstevel@tonic-gate * Number of queues on the squeue and 38657c478bd9Sstevel@tonic-gate * Number of CPUs. 38667c478bd9Sstevel@tonic-gate */ 38677c478bd9Sstevel@tonic-gate if (sq->sq_servcount != 0) { 38687c478bd9Sstevel@tonic-gate if (((sq->sq_type & SQ_PERMOD) == 0) || 38697c478bd9Sstevel@tonic-gate (sq->sq_servcount >= MIN(sq->sq_nqueues, ncpus_online))) { 38707c478bd9Sstevel@tonic-gate STRSTAT(sqtoomany); 38717c478bd9Sstevel@tonic-gate return; 38727c478bd9Sstevel@tonic-gate } 38737c478bd9Sstevel@tonic-gate } 38747c478bd9Sstevel@tonic-gate 3875d3d50737SRafael Vanoni sq->sq_tstamp = ddi_get_lbolt(); 38767c478bd9Sstevel@tonic-gate STRSTAT(sqenables); 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate /* Attempt a taskq dispatch */ 38797c478bd9Sstevel@tonic-gate sq->sq_servid = (void *)taskq_dispatch(streams_taskq, 38807c478bd9Sstevel@tonic-gate (task_func_t *)syncq_service, sq, TQ_NOSLEEP | TQ_NOQUEUE); 38817c478bd9Sstevel@tonic-gate if (sq->sq_servid != NULL) { 38827c478bd9Sstevel@tonic-gate sq->sq_servcount++; 38837c478bd9Sstevel@tonic-gate return; 38847c478bd9Sstevel@tonic-gate } 38857c478bd9Sstevel@tonic-gate 38867c478bd9Sstevel@tonic-gate /* 38877c478bd9Sstevel@tonic-gate * This taskq dispatch failed, but a previous one may have succeeded. 38887c478bd9Sstevel@tonic-gate * Don't try to schedule on the background thread whilst there is 38897c478bd9Sstevel@tonic-gate * outstanding taskq processing. 38907c478bd9Sstevel@tonic-gate */ 38917c478bd9Sstevel@tonic-gate if (sq->sq_servcount != 0) 38927c478bd9Sstevel@tonic-gate return; 38937c478bd9Sstevel@tonic-gate 38947c478bd9Sstevel@tonic-gate /* 38957c478bd9Sstevel@tonic-gate * System is low on resources and can't perform a non-sleeping 38967c478bd9Sstevel@tonic-gate * dispatch. Schedule the syncq for a background thread and mark the 38977c478bd9Sstevel@tonic-gate * syncq to avoid any further taskq dispatch attempts. 38987c478bd9Sstevel@tonic-gate */ 38997c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 39007c478bd9Sstevel@tonic-gate STRSTAT(taskqfails); 39017c478bd9Sstevel@tonic-gate ENQUEUE(sq, sqhead, sqtail, sq_next); 39027c478bd9Sstevel@tonic-gate sq->sq_svcflags |= SQ_BGTHREAD; 39037c478bd9Sstevel@tonic-gate sq->sq_servcount = 1; 39047c478bd9Sstevel@tonic-gate cv_signal(&syncqs_to_run); 39057c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 39067c478bd9Sstevel@tonic-gate } 39077c478bd9Sstevel@tonic-gate 39087c478bd9Sstevel@tonic-gate /* 39097c478bd9Sstevel@tonic-gate * Note: fifo_close() depends on the mblk_t on the queue being freed 39107c478bd9Sstevel@tonic-gate * asynchronously. The asynchronous freeing of messages breaks the 39117c478bd9Sstevel@tonic-gate * recursive call chain of fifo_close() while there are I_SENDFD type of 391221804b56SBrian Ruthven * messages referring to other file pointers on the queue. Then when 39137c478bd9Sstevel@tonic-gate * closing pipes it can avoid stack overflow in case of daisy-chained 39147c478bd9Sstevel@tonic-gate * pipes, and also avoid deadlock in case of fifonode_t pairs (which 39157c478bd9Sstevel@tonic-gate * share the same fifolock_t). 3916f4aaef0bSDavid Plauger * 3917f4aaef0bSDavid Plauger * No need to kpreempt_disable to access cpu_seqid. If we migrate and 3918f4aaef0bSDavid Plauger * the esb queue does not match the new CPU, that is OK. 39197c478bd9Sstevel@tonic-gate */ 39207c478bd9Sstevel@tonic-gate void 39217c478bd9Sstevel@tonic-gate freebs_enqueue(mblk_t *mp, dblk_t *dbp) 39227c478bd9Sstevel@tonic-gate { 3923f4aaef0bSDavid Plauger int qindex = CPU->cpu_seqid >> esbq_log2_cpus_per_q; 3924f4aaef0bSDavid Plauger esb_queue_t *eqp; 3925e7d4b76fSss146032 39267c478bd9Sstevel@tonic-gate ASSERT(dbp->db_mblk == mp); 3927f4aaef0bSDavid Plauger ASSERT(qindex < esbq_nelem); 3928f4aaef0bSDavid Plauger 3929f4aaef0bSDavid Plauger eqp = system_esbq_array; 3930f4aaef0bSDavid Plauger if (eqp != NULL) { 3931f4aaef0bSDavid Plauger eqp += qindex; 3932f4aaef0bSDavid Plauger } else { 3933f4aaef0bSDavid Plauger mutex_enter(&esbq_lock); 3934f4aaef0bSDavid Plauger if (kmem_ready && system_esbq_array == NULL) 3935f4aaef0bSDavid Plauger system_esbq_array = (esb_queue_t *)kmem_zalloc( 3936f4aaef0bSDavid Plauger esbq_nelem * sizeof (esb_queue_t), KM_NOSLEEP); 3937f4aaef0bSDavid Plauger mutex_exit(&esbq_lock); 3938f4aaef0bSDavid Plauger eqp = system_esbq_array; 3939f4aaef0bSDavid Plauger if (eqp != NULL) 3940f4aaef0bSDavid Plauger eqp += qindex; 3941f4aaef0bSDavid Plauger else 3942f4aaef0bSDavid Plauger eqp = &system_esbq; 3943f4aaef0bSDavid Plauger } 39447c478bd9Sstevel@tonic-gate 39457c478bd9Sstevel@tonic-gate /* 39467c478bd9Sstevel@tonic-gate * Check data sanity. The dblock should have non-empty free function. 39477c478bd9Sstevel@tonic-gate * It is better to panic here then later when the dblock is freed 39487c478bd9Sstevel@tonic-gate * asynchronously when the context is lost. 39497c478bd9Sstevel@tonic-gate */ 39507c478bd9Sstevel@tonic-gate if (dbp->db_frtnp->free_func == NULL) { 39517c478bd9Sstevel@tonic-gate panic("freebs_enqueue: dblock %p has a NULL free callback", 39527c478bd9Sstevel@tonic-gate (void *)dbp); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate 3955e7d4b76fSss146032 mutex_enter(&eqp->eq_lock); 3956e7d4b76fSss146032 /* queue the new mblk on the esballoc queue */ 3957e7d4b76fSss146032 if (eqp->eq_head == NULL) { 3958e7d4b76fSss146032 eqp->eq_head = eqp->eq_tail = mp; 3959e7d4b76fSss146032 } else { 3960e7d4b76fSss146032 eqp->eq_tail->b_next = mp; 3961e7d4b76fSss146032 eqp->eq_tail = mp; 3962e7d4b76fSss146032 } 3963e7d4b76fSss146032 eqp->eq_len++; 3964e7d4b76fSss146032 3965e7d4b76fSss146032 /* If we're the first thread to reach the threshold, process */ 3966e7d4b76fSss146032 if (eqp->eq_len >= esbq_max_qlen && 3967e7d4b76fSss146032 !(eqp->eq_flags & ESBQ_PROCESSING)) 3968e7d4b76fSss146032 esballoc_process_queue(eqp); 3969e7d4b76fSss146032 3970e7d4b76fSss146032 esballoc_set_timer(eqp, esbq_timeout); 3971e7d4b76fSss146032 mutex_exit(&eqp->eq_lock); 3972e7d4b76fSss146032 } 3973e7d4b76fSss146032 3974e7d4b76fSss146032 static void 3975e7d4b76fSss146032 esballoc_process_queue(esb_queue_t *eqp) 3976e7d4b76fSss146032 { 3977e7d4b76fSss146032 mblk_t *mp; 3978e7d4b76fSss146032 3979e7d4b76fSss146032 ASSERT(MUTEX_HELD(&eqp->eq_lock)); 3980e7d4b76fSss146032 3981e7d4b76fSss146032 eqp->eq_flags |= ESBQ_PROCESSING; 3982e7d4b76fSss146032 3983e7d4b76fSss146032 do { 3984e7d4b76fSss146032 /* 3985e7d4b76fSss146032 * Detach the message chain for processing. 3986e7d4b76fSss146032 */ 3987e7d4b76fSss146032 mp = eqp->eq_head; 3988e7d4b76fSss146032 eqp->eq_tail->b_next = NULL; 3989e7d4b76fSss146032 eqp->eq_head = eqp->eq_tail = NULL; 3990e7d4b76fSss146032 eqp->eq_len = 0; 3991e7d4b76fSss146032 mutex_exit(&eqp->eq_lock); 3992e7d4b76fSss146032 3993e7d4b76fSss146032 /* 3994e7d4b76fSss146032 * Process the message chain. 3995e7d4b76fSss146032 */ 3996e7d4b76fSss146032 esballoc_enqueue_mblk(mp); 3997e7d4b76fSss146032 mutex_enter(&eqp->eq_lock); 3998e7d4b76fSss146032 } while ((eqp->eq_len >= esbq_max_qlen) && (eqp->eq_len > 0)); 3999e7d4b76fSss146032 4000e7d4b76fSss146032 eqp->eq_flags &= ~ESBQ_PROCESSING; 4001e7d4b76fSss146032 } 4002e7d4b76fSss146032 4003e7d4b76fSss146032 /* 4004e7d4b76fSss146032 * taskq callback routine to free esballoced mblk's 4005e7d4b76fSss146032 */ 4006e7d4b76fSss146032 static void 4007e7d4b76fSss146032 esballoc_mblk_free(mblk_t *mp) 4008e7d4b76fSss146032 { 4009e7d4b76fSss146032 mblk_t *nextmp; 4010e7d4b76fSss146032 4011e7d4b76fSss146032 for (; mp != NULL; mp = nextmp) { 4012e7d4b76fSss146032 nextmp = mp->b_next; 4013e7d4b76fSss146032 mp->b_next = NULL; 4014e7d4b76fSss146032 mblk_free(mp); 4015e7d4b76fSss146032 } 4016e7d4b76fSss146032 } 4017e7d4b76fSss146032 4018e7d4b76fSss146032 static void 4019e7d4b76fSss146032 esballoc_enqueue_mblk(mblk_t *mp) 4020e7d4b76fSss146032 { 4021e7d4b76fSss146032 4022e7d4b76fSss146032 if (taskq_dispatch(system_taskq, (task_func_t *)esballoc_mblk_free, mp, 40237c478bd9Sstevel@tonic-gate TQ_NOSLEEP) == NULL) { 4024e7d4b76fSss146032 mblk_t *first_mp = mp; 40257c478bd9Sstevel@tonic-gate /* 40267c478bd9Sstevel@tonic-gate * System is low on resources and can't perform a non-sleeping 40277c478bd9Sstevel@tonic-gate * dispatch. Schedule for a background thread. 40287c478bd9Sstevel@tonic-gate */ 40297c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 40307c478bd9Sstevel@tonic-gate STRSTAT(taskqfails); 4031e7d4b76fSss146032 4032e7d4b76fSss146032 while (mp->b_next != NULL) 4033e7d4b76fSss146032 mp = mp->b_next; 4034e7d4b76fSss146032 40357c478bd9Sstevel@tonic-gate mp->b_next = freebs_list; 4036e7d4b76fSss146032 freebs_list = first_mp; 40377c478bd9Sstevel@tonic-gate cv_signal(&services_to_run); 40387c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 40397c478bd9Sstevel@tonic-gate } 40407c478bd9Sstevel@tonic-gate } 40417c478bd9Sstevel@tonic-gate 4042e7d4b76fSss146032 static void 4043e7d4b76fSss146032 esballoc_timer(void *arg) 4044e7d4b76fSss146032 { 4045e7d4b76fSss146032 esb_queue_t *eqp = arg; 4046e7d4b76fSss146032 4047e7d4b76fSss146032 mutex_enter(&eqp->eq_lock); 4048e7d4b76fSss146032 eqp->eq_flags &= ~ESBQ_TIMER; 4049e7d4b76fSss146032 4050e7d4b76fSss146032 if (!(eqp->eq_flags & ESBQ_PROCESSING) && 4051e7d4b76fSss146032 eqp->eq_len > 0) 4052e7d4b76fSss146032 esballoc_process_queue(eqp); 4053e7d4b76fSss146032 4054e7d4b76fSss146032 esballoc_set_timer(eqp, esbq_timeout); 4055e7d4b76fSss146032 mutex_exit(&eqp->eq_lock); 4056e7d4b76fSss146032 } 4057e7d4b76fSss146032 4058e7d4b76fSss146032 static void 4059e7d4b76fSss146032 esballoc_set_timer(esb_queue_t *eqp, clock_t eq_timeout) 4060e7d4b76fSss146032 { 4061e7d4b76fSss146032 ASSERT(MUTEX_HELD(&eqp->eq_lock)); 4062e7d4b76fSss146032 4063e7d4b76fSss146032 if (eqp->eq_len > 0 && !(eqp->eq_flags & ESBQ_TIMER)) { 4064e7d4b76fSss146032 (void) timeout(esballoc_timer, eqp, eq_timeout); 4065e7d4b76fSss146032 eqp->eq_flags |= ESBQ_TIMER; 4066e7d4b76fSss146032 } 4067e7d4b76fSss146032 } 4068e7d4b76fSss146032 4069f4aaef0bSDavid Plauger /* 4070f4aaef0bSDavid Plauger * Setup esbq array length based upon NCPU scaled by CPUs per 4071f4aaef0bSDavid Plauger * queue. Use static system_esbq until kmem_ready and we can 4072f4aaef0bSDavid Plauger * create an array in freebs_enqueue(). 4073f4aaef0bSDavid Plauger */ 4074e7d4b76fSss146032 void 4075e7d4b76fSss146032 esballoc_queue_init(void) 4076e7d4b76fSss146032 { 4077f4aaef0bSDavid Plauger esbq_log2_cpus_per_q = highbit(esbq_cpus_per_q - 1); 4078f4aaef0bSDavid Plauger esbq_cpus_per_q = 1 << esbq_log2_cpus_per_q; 4079f4aaef0bSDavid Plauger esbq_nelem = howmany(NCPU, esbq_cpus_per_q); 4080e7d4b76fSss146032 system_esbq.eq_len = 0; 4081e7d4b76fSss146032 system_esbq.eq_head = system_esbq.eq_tail = NULL; 4082e7d4b76fSss146032 system_esbq.eq_flags = 0; 4083e7d4b76fSss146032 } 4084e7d4b76fSss146032 40857c478bd9Sstevel@tonic-gate /* 40867c478bd9Sstevel@tonic-gate * Set the QBACK or QB_BACK flag in the given queue for 40877c478bd9Sstevel@tonic-gate * the given priority band. 40887c478bd9Sstevel@tonic-gate */ 40897c478bd9Sstevel@tonic-gate void 40907c478bd9Sstevel@tonic-gate setqback(queue_t *q, unsigned char pri) 40917c478bd9Sstevel@tonic-gate { 40927c478bd9Sstevel@tonic-gate int i; 40937c478bd9Sstevel@tonic-gate qband_t *qbp; 40947c478bd9Sstevel@tonic-gate qband_t **qbpp; 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(q))); 40977c478bd9Sstevel@tonic-gate if (pri != 0) { 40987c478bd9Sstevel@tonic-gate if (pri > q->q_nband) { 40997c478bd9Sstevel@tonic-gate qbpp = &q->q_bandp; 41007c478bd9Sstevel@tonic-gate while (*qbpp) 41017c478bd9Sstevel@tonic-gate qbpp = &(*qbpp)->qb_next; 41027c478bd9Sstevel@tonic-gate while (pri > q->q_nband) { 41037c478bd9Sstevel@tonic-gate if ((*qbpp = allocband()) == NULL) { 41047c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 41057c478bd9Sstevel@tonic-gate "setqback: can't allocate qband\n"); 41067c478bd9Sstevel@tonic-gate return; 41077c478bd9Sstevel@tonic-gate } 41087c478bd9Sstevel@tonic-gate (*qbpp)->qb_hiwat = q->q_hiwat; 41097c478bd9Sstevel@tonic-gate (*qbpp)->qb_lowat = q->q_lowat; 41107c478bd9Sstevel@tonic-gate q->q_nband++; 41117c478bd9Sstevel@tonic-gate qbpp = &(*qbpp)->qb_next; 41127c478bd9Sstevel@tonic-gate } 41137c478bd9Sstevel@tonic-gate } 41147c478bd9Sstevel@tonic-gate qbp = q->q_bandp; 41157c478bd9Sstevel@tonic-gate i = pri; 41167c478bd9Sstevel@tonic-gate while (--i) 41177c478bd9Sstevel@tonic-gate qbp = qbp->qb_next; 41187c478bd9Sstevel@tonic-gate qbp->qb_flag |= QB_BACK; 41197c478bd9Sstevel@tonic-gate } else { 41207c478bd9Sstevel@tonic-gate q->q_flag |= QBACK; 41217c478bd9Sstevel@tonic-gate } 41227c478bd9Sstevel@tonic-gate } 41237c478bd9Sstevel@tonic-gate 41247c478bd9Sstevel@tonic-gate int 41257c478bd9Sstevel@tonic-gate strcopyin(void *from, void *to, size_t len, int copyflag) 41267c478bd9Sstevel@tonic-gate { 41277c478bd9Sstevel@tonic-gate if (copyflag & U_TO_K) { 41287c478bd9Sstevel@tonic-gate ASSERT((copyflag & K_TO_K) == 0); 41297c478bd9Sstevel@tonic-gate if (copyin(from, to, len)) 41307c478bd9Sstevel@tonic-gate return (EFAULT); 41317c478bd9Sstevel@tonic-gate } else { 41327c478bd9Sstevel@tonic-gate ASSERT(copyflag & K_TO_K); 41337c478bd9Sstevel@tonic-gate bcopy(from, to, len); 41347c478bd9Sstevel@tonic-gate } 41357c478bd9Sstevel@tonic-gate return (0); 41367c478bd9Sstevel@tonic-gate } 41377c478bd9Sstevel@tonic-gate 41387c478bd9Sstevel@tonic-gate int 41397c478bd9Sstevel@tonic-gate strcopyout(void *from, void *to, size_t len, int copyflag) 41407c478bd9Sstevel@tonic-gate { 41417c478bd9Sstevel@tonic-gate if (copyflag & U_TO_K) { 41427c478bd9Sstevel@tonic-gate if (copyout(from, to, len)) 41437c478bd9Sstevel@tonic-gate return (EFAULT); 41447c478bd9Sstevel@tonic-gate } else { 41457c478bd9Sstevel@tonic-gate ASSERT(copyflag & K_TO_K); 41467c478bd9Sstevel@tonic-gate bcopy(from, to, len); 41477c478bd9Sstevel@tonic-gate } 41487c478bd9Sstevel@tonic-gate return (0); 41497c478bd9Sstevel@tonic-gate } 41507c478bd9Sstevel@tonic-gate 41517c478bd9Sstevel@tonic-gate /* 41527c478bd9Sstevel@tonic-gate * strsignal_nolock() posts a signal to the process(es) at the stream head. 41537c478bd9Sstevel@tonic-gate * It assumes that the stream head lock is already held, whereas strsignal() 41547c478bd9Sstevel@tonic-gate * acquires the lock first. This routine was created because a few callers 41557c478bd9Sstevel@tonic-gate * release the stream head lock before calling only to re-acquire it after 41567c478bd9Sstevel@tonic-gate * it returns. 41577c478bd9Sstevel@tonic-gate */ 41587c478bd9Sstevel@tonic-gate void 4159a45f3f93Smeem strsignal_nolock(stdata_t *stp, int sig, uchar_t band) 41607c478bd9Sstevel@tonic-gate { 41617c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&stp->sd_lock)); 41627c478bd9Sstevel@tonic-gate switch (sig) { 41637c478bd9Sstevel@tonic-gate case SIGPOLL: 41647c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_MSG) 4165a45f3f93Smeem strsendsig(stp->sd_siglist, S_MSG, band, 0); 41667c478bd9Sstevel@tonic-gate break; 41677c478bd9Sstevel@tonic-gate default: 4168a45f3f93Smeem if (stp->sd_pgidp) 41697c478bd9Sstevel@tonic-gate pgsignal(stp->sd_pgidp, sig); 41707c478bd9Sstevel@tonic-gate break; 41717c478bd9Sstevel@tonic-gate } 41727c478bd9Sstevel@tonic-gate } 41737c478bd9Sstevel@tonic-gate 41747c478bd9Sstevel@tonic-gate void 41757c478bd9Sstevel@tonic-gate strsignal(stdata_t *stp, int sig, int32_t band) 41767c478bd9Sstevel@tonic-gate { 41777c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_SENDSIG, 41787c478bd9Sstevel@tonic-gate "strsignal:%p, %X, %X", stp, sig, band); 41797c478bd9Sstevel@tonic-gate 41807c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 41817c478bd9Sstevel@tonic-gate switch (sig) { 41827c478bd9Sstevel@tonic-gate case SIGPOLL: 41837c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_MSG) 41847c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_MSG, (uchar_t)band, 0); 41857c478bd9Sstevel@tonic-gate break; 41867c478bd9Sstevel@tonic-gate 41877c478bd9Sstevel@tonic-gate default: 41887c478bd9Sstevel@tonic-gate if (stp->sd_pgidp) { 41897c478bd9Sstevel@tonic-gate pgsignal(stp->sd_pgidp, sig); 41907c478bd9Sstevel@tonic-gate } 41917c478bd9Sstevel@tonic-gate break; 41927c478bd9Sstevel@tonic-gate } 41937c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 41947c478bd9Sstevel@tonic-gate } 41957c478bd9Sstevel@tonic-gate 41967c478bd9Sstevel@tonic-gate void 41977c478bd9Sstevel@tonic-gate strhup(stdata_t *stp) 41987c478bd9Sstevel@tonic-gate { 41999acbbeafSnn35248 ASSERT(mutex_owned(&stp->sd_lock)); 42007c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLHUP); 42017c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_HANGUP) 42027c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_HANGUP, 0, 0); 42037c478bd9Sstevel@tonic-gate } 42047c478bd9Sstevel@tonic-gate 42057c478bd9Sstevel@tonic-gate /* 4206ad1660d0Smeem * Backenable the first queue upstream from `q' with a service procedure. 42077c478bd9Sstevel@tonic-gate */ 42087c478bd9Sstevel@tonic-gate void 4209116094b2Smicheng backenable(queue_t *q, uchar_t pri) 42107c478bd9Sstevel@tonic-gate { 42117c478bd9Sstevel@tonic-gate queue_t *nq; 42127c478bd9Sstevel@tonic-gate 42137c478bd9Sstevel@tonic-gate /* 421421804b56SBrian Ruthven * Our presence might not prevent other modules in our own 42157c478bd9Sstevel@tonic-gate * stream from popping/pushing since the caller of getq might not 42167c478bd9Sstevel@tonic-gate * have a claim on the queue (some drivers do a getq on somebody 42177c478bd9Sstevel@tonic-gate * else's queue - they know that the queue itself is not going away 421821804b56SBrian Ruthven * but the framework has to guarantee q_next in that stream). 42197c478bd9Sstevel@tonic-gate */ 42207c478bd9Sstevel@tonic-gate claimstr(q); 42217c478bd9Sstevel@tonic-gate 422221804b56SBrian Ruthven /* Find nearest back queue with service proc */ 42237c478bd9Sstevel@tonic-gate for (nq = backq(q); nq && !nq->q_qinfo->qi_srvp; nq = backq(nq)) { 42247c478bd9Sstevel@tonic-gate ASSERT(STRMATED(q->q_stream) || STREAM(q) == STREAM(nq)); 42257c478bd9Sstevel@tonic-gate } 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate if (nq) { 42287c478bd9Sstevel@tonic-gate kthread_t *freezer; 42297c478bd9Sstevel@tonic-gate /* 42307c478bd9Sstevel@tonic-gate * backenable can be called either with no locks held 42317c478bd9Sstevel@tonic-gate * or with the stream frozen (the latter occurs when a module 423221804b56SBrian Ruthven * calls rmvq with the stream frozen). If the stream is frozen 42337c478bd9Sstevel@tonic-gate * by the caller the caller will hold all qlocks in the stream. 4234f4b3ec61Sdh155122 * Note that a frozen stream doesn't freeze a mated stream, 4235f4b3ec61Sdh155122 * so we explicitly check for that. 42367c478bd9Sstevel@tonic-gate */ 42377c478bd9Sstevel@tonic-gate freezer = STREAM(q)->sd_freezer; 4238f4b3ec61Sdh155122 if (freezer != curthread || STREAM(q) != STREAM(nq)) { 42397c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(nq)); 42407c478bd9Sstevel@tonic-gate } 42417c478bd9Sstevel@tonic-gate #ifdef DEBUG 42427c478bd9Sstevel@tonic-gate else { 42437c478bd9Sstevel@tonic-gate ASSERT(frozenstr(q)); 42447c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(q))); 42457c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(nq))); 42467c478bd9Sstevel@tonic-gate } 42477c478bd9Sstevel@tonic-gate #endif 42487c478bd9Sstevel@tonic-gate setqback(nq, pri); 42497c478bd9Sstevel@tonic-gate qenable_locked(nq); 4250f4b3ec61Sdh155122 if (freezer != curthread || STREAM(q) != STREAM(nq)) 42517c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(nq)); 42527c478bd9Sstevel@tonic-gate } 42537c478bd9Sstevel@tonic-gate releasestr(q); 42547c478bd9Sstevel@tonic-gate } 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate /* 42577c478bd9Sstevel@tonic-gate * Return the appropriate errno when one of flags_to_check is set 42587c478bd9Sstevel@tonic-gate * in sd_flags. Uses the exported error routines if they are set. 42597c478bd9Sstevel@tonic-gate * Will return 0 if non error is set (or if the exported error routines 42607c478bd9Sstevel@tonic-gate * do not return an error). 42617c478bd9Sstevel@tonic-gate * 426221804b56SBrian Ruthven * If there is both a read and write error to check, we prefer the read error. 42637c478bd9Sstevel@tonic-gate * Also, give preference to recorded errno's over the error functions. 42647c478bd9Sstevel@tonic-gate * The flags that are handled are: 42657c478bd9Sstevel@tonic-gate * STPLEX return EINVAL 42667c478bd9Sstevel@tonic-gate * STRDERR return sd_rerror (and clear if STRDERRNONPERSIST) 42677c478bd9Sstevel@tonic-gate * STWRERR return sd_werror (and clear if STWRERRNONPERSIST) 42687c478bd9Sstevel@tonic-gate * STRHUP return sd_werror 42697c478bd9Sstevel@tonic-gate * 427021804b56SBrian Ruthven * If the caller indicates that the operation is a peek, a nonpersistent error 42717c478bd9Sstevel@tonic-gate * is not cleared. 42727c478bd9Sstevel@tonic-gate */ 42737c478bd9Sstevel@tonic-gate int 42747c478bd9Sstevel@tonic-gate strgeterr(stdata_t *stp, int32_t flags_to_check, int ispeek) 42757c478bd9Sstevel@tonic-gate { 42767c478bd9Sstevel@tonic-gate int32_t sd_flag = stp->sd_flag & flags_to_check; 42777c478bd9Sstevel@tonic-gate int error = 0; 42787c478bd9Sstevel@tonic-gate 42797c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&stp->sd_lock)); 42807c478bd9Sstevel@tonic-gate ASSERT((flags_to_check & ~(STRDERR|STWRERR|STRHUP|STPLEX)) == 0); 42817c478bd9Sstevel@tonic-gate if (sd_flag & STPLEX) 42827c478bd9Sstevel@tonic-gate error = EINVAL; 42837c478bd9Sstevel@tonic-gate else if (sd_flag & STRDERR) { 42847c478bd9Sstevel@tonic-gate error = stp->sd_rerror; 42857c478bd9Sstevel@tonic-gate if ((stp->sd_flag & STRDERRNONPERSIST) && !ispeek) { 42867c478bd9Sstevel@tonic-gate /* 42877c478bd9Sstevel@tonic-gate * Read errors are non-persistent i.e. discarded once 42887c478bd9Sstevel@tonic-gate * returned to a non-peeking caller, 42897c478bd9Sstevel@tonic-gate */ 42907c478bd9Sstevel@tonic-gate stp->sd_rerror = 0; 42917c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STRDERR; 42927c478bd9Sstevel@tonic-gate } 42937c478bd9Sstevel@tonic-gate if (error == 0 && stp->sd_rderrfunc != NULL) { 42947c478bd9Sstevel@tonic-gate int clearerr = 0; 42957c478bd9Sstevel@tonic-gate 42967c478bd9Sstevel@tonic-gate error = (*stp->sd_rderrfunc)(stp->sd_vnode, ispeek, 42977c478bd9Sstevel@tonic-gate &clearerr); 42987c478bd9Sstevel@tonic-gate if (clearerr) { 42997c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STRDERR; 43007c478bd9Sstevel@tonic-gate stp->sd_rderrfunc = NULL; 43017c478bd9Sstevel@tonic-gate } 43027c478bd9Sstevel@tonic-gate } 43037c478bd9Sstevel@tonic-gate } else if (sd_flag & STWRERR) { 43047c478bd9Sstevel@tonic-gate error = stp->sd_werror; 43057c478bd9Sstevel@tonic-gate if ((stp->sd_flag & STWRERRNONPERSIST) && !ispeek) { 43067c478bd9Sstevel@tonic-gate /* 43077c478bd9Sstevel@tonic-gate * Write errors are non-persistent i.e. discarded once 43087c478bd9Sstevel@tonic-gate * returned to a non-peeking caller, 43097c478bd9Sstevel@tonic-gate */ 43107c478bd9Sstevel@tonic-gate stp->sd_werror = 0; 43117c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STWRERR; 43127c478bd9Sstevel@tonic-gate } 43137c478bd9Sstevel@tonic-gate if (error == 0 && stp->sd_wrerrfunc != NULL) { 43147c478bd9Sstevel@tonic-gate int clearerr = 0; 43157c478bd9Sstevel@tonic-gate 43167c478bd9Sstevel@tonic-gate error = (*stp->sd_wrerrfunc)(stp->sd_vnode, ispeek, 43177c478bd9Sstevel@tonic-gate &clearerr); 43187c478bd9Sstevel@tonic-gate if (clearerr) { 43197c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STWRERR; 43207c478bd9Sstevel@tonic-gate stp->sd_wrerrfunc = NULL; 43217c478bd9Sstevel@tonic-gate } 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate } else if (sd_flag & STRHUP) { 43247c478bd9Sstevel@tonic-gate /* sd_werror set when STRHUP */ 43257c478bd9Sstevel@tonic-gate error = stp->sd_werror; 43267c478bd9Sstevel@tonic-gate } 43277c478bd9Sstevel@tonic-gate return (error); 43287c478bd9Sstevel@tonic-gate } 43297c478bd9Sstevel@tonic-gate 43307c478bd9Sstevel@tonic-gate 43317c478bd9Sstevel@tonic-gate /* 433221804b56SBrian Ruthven * Single-thread open/close/push/pop 43337c478bd9Sstevel@tonic-gate * for twisted streams also 43347c478bd9Sstevel@tonic-gate */ 43357c478bd9Sstevel@tonic-gate int 43367c478bd9Sstevel@tonic-gate strstartplumb(stdata_t *stp, int flag, int cmd) 43377c478bd9Sstevel@tonic-gate { 43387c478bd9Sstevel@tonic-gate int waited = 1; 43397c478bd9Sstevel@tonic-gate int error = 0; 43407c478bd9Sstevel@tonic-gate 43417c478bd9Sstevel@tonic-gate if (STRMATED(stp)) { 43427c478bd9Sstevel@tonic-gate struct stdata *stmatep = stp->sd_mate; 43437c478bd9Sstevel@tonic-gate 43447c478bd9Sstevel@tonic-gate STRLOCKMATES(stp); 43457c478bd9Sstevel@tonic-gate while (waited) { 43467c478bd9Sstevel@tonic-gate waited = 0; 43477c478bd9Sstevel@tonic-gate while (stmatep->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) { 43487c478bd9Sstevel@tonic-gate if ((cmd == I_POP) && 43497c478bd9Sstevel@tonic-gate (flag & (FNDELAY|FNONBLOCK))) { 43507c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 43517c478bd9Sstevel@tonic-gate return (EAGAIN); 43527c478bd9Sstevel@tonic-gate } 43537c478bd9Sstevel@tonic-gate waited = 1; 43547c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 43557c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&stmatep->sd_monitor, 43567c478bd9Sstevel@tonic-gate &stmatep->sd_lock)) { 43577c478bd9Sstevel@tonic-gate mutex_exit(&stmatep->sd_lock); 43587c478bd9Sstevel@tonic-gate return (EINTR); 43597c478bd9Sstevel@tonic-gate } 43607c478bd9Sstevel@tonic-gate mutex_exit(&stmatep->sd_lock); 43617c478bd9Sstevel@tonic-gate STRLOCKMATES(stp); 43627c478bd9Sstevel@tonic-gate } 43637c478bd9Sstevel@tonic-gate while (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) { 43647c478bd9Sstevel@tonic-gate if ((cmd == I_POP) && 43657c478bd9Sstevel@tonic-gate (flag & (FNDELAY|FNONBLOCK))) { 43667c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 43677c478bd9Sstevel@tonic-gate return (EAGAIN); 43687c478bd9Sstevel@tonic-gate } 43697c478bd9Sstevel@tonic-gate waited = 1; 43707c478bd9Sstevel@tonic-gate mutex_exit(&stmatep->sd_lock); 43717c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&stp->sd_monitor, 43727c478bd9Sstevel@tonic-gate &stp->sd_lock)) { 43737c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 43747c478bd9Sstevel@tonic-gate return (EINTR); 43757c478bd9Sstevel@tonic-gate } 43767c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 43777c478bd9Sstevel@tonic-gate STRLOCKMATES(stp); 43787c478bd9Sstevel@tonic-gate } 43797c478bd9Sstevel@tonic-gate if (stp->sd_flag & (STRDERR|STWRERR|STRHUP|STPLEX)) { 43807c478bd9Sstevel@tonic-gate error = strgeterr(stp, 43817c478bd9Sstevel@tonic-gate STRDERR|STWRERR|STRHUP|STPLEX, 0); 43827c478bd9Sstevel@tonic-gate if (error != 0) { 43837c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 43847c478bd9Sstevel@tonic-gate return (error); 43857c478bd9Sstevel@tonic-gate } 43867c478bd9Sstevel@tonic-gate } 43877c478bd9Sstevel@tonic-gate } 43887c478bd9Sstevel@tonic-gate stp->sd_flag |= STRPLUMB; 43897c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 43907c478bd9Sstevel@tonic-gate } else { 43917c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 43927c478bd9Sstevel@tonic-gate while (stp->sd_flag & (STWOPEN|STRCLOSE|STRPLUMB)) { 43937c478bd9Sstevel@tonic-gate if (((cmd == I_POP) || (cmd == _I_REMOVE)) && 43947c478bd9Sstevel@tonic-gate (flag & (FNDELAY|FNONBLOCK))) { 43957c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 43967c478bd9Sstevel@tonic-gate return (EAGAIN); 43977c478bd9Sstevel@tonic-gate } 43987c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&stp->sd_monitor, &stp->sd_lock)) { 43997c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 44007c478bd9Sstevel@tonic-gate return (EINTR); 44017c478bd9Sstevel@tonic-gate } 44027c478bd9Sstevel@tonic-gate if (stp->sd_flag & (STRDERR|STWRERR|STRHUP|STPLEX)) { 44037c478bd9Sstevel@tonic-gate error = strgeterr(stp, 44047c478bd9Sstevel@tonic-gate STRDERR|STWRERR|STRHUP|STPLEX, 0); 44057c478bd9Sstevel@tonic-gate if (error != 0) { 44067c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 44077c478bd9Sstevel@tonic-gate return (error); 44087c478bd9Sstevel@tonic-gate } 44097c478bd9Sstevel@tonic-gate } 44107c478bd9Sstevel@tonic-gate } 44117c478bd9Sstevel@tonic-gate stp->sd_flag |= STRPLUMB; 44127c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 44137c478bd9Sstevel@tonic-gate } 44147c478bd9Sstevel@tonic-gate return (0); 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate 44177c478bd9Sstevel@tonic-gate /* 44187c478bd9Sstevel@tonic-gate * Complete the plumbing operation associated with stream `stp'. 44197c478bd9Sstevel@tonic-gate */ 44207c478bd9Sstevel@tonic-gate void 44217c478bd9Sstevel@tonic-gate strendplumb(stdata_t *stp) 44227c478bd9Sstevel@tonic-gate { 44237c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&stp->sd_lock)); 44247c478bd9Sstevel@tonic-gate ASSERT(stp->sd_flag & STRPLUMB); 44257c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STRPLUMB; 44267c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_monitor); 44277c478bd9Sstevel@tonic-gate } 44287c478bd9Sstevel@tonic-gate 44297c478bd9Sstevel@tonic-gate /* 44307c478bd9Sstevel@tonic-gate * This describes how the STREAMS framework handles synchronization 44317c478bd9Sstevel@tonic-gate * during open/push and close/pop. 44327c478bd9Sstevel@tonic-gate * The key interfaces for open and close are qprocson and qprocsoff, 44337c478bd9Sstevel@tonic-gate * respectively. While the close case in general is harder both open 44347c478bd9Sstevel@tonic-gate * have close have significant similarities. 44357c478bd9Sstevel@tonic-gate * 44367c478bd9Sstevel@tonic-gate * During close the STREAMS framework has to both ensure that there 44377c478bd9Sstevel@tonic-gate * are no stale references to the queue pair (and syncq) that 44387c478bd9Sstevel@tonic-gate * are being closed and also provide the guarantees that are documented 44397c478bd9Sstevel@tonic-gate * in qprocsoff(9F). 44407c478bd9Sstevel@tonic-gate * If there are stale references to the queue that is closing it can 44417c478bd9Sstevel@tonic-gate * result in kernel memory corruption or kernel panics. 44427c478bd9Sstevel@tonic-gate * 44437c478bd9Sstevel@tonic-gate * Note that is it up to the module/driver to ensure that it itself 44447c478bd9Sstevel@tonic-gate * does not have any stale references to the closing queues once its close 44457c478bd9Sstevel@tonic-gate * routine returns. This includes: 44467c478bd9Sstevel@tonic-gate * - Cancelling any timeout/bufcall/qtimeout/qbufcall callback routines 44477c478bd9Sstevel@tonic-gate * associated with the queues. For timeout and bufcall callbacks the 44487c478bd9Sstevel@tonic-gate * module/driver also has to ensure (or wait for) any callbacks that 44497c478bd9Sstevel@tonic-gate * are in progress. 44507c478bd9Sstevel@tonic-gate * - If the module/driver is using esballoc it has to ensure that any 44517c478bd9Sstevel@tonic-gate * esballoc free functions do not refer to a queue that has closed. 44527c478bd9Sstevel@tonic-gate * (Note that in general the close routine can not wait for the esballoc'ed 44537c478bd9Sstevel@tonic-gate * messages to be freed since that can cause a deadlock.) 44547c478bd9Sstevel@tonic-gate * - Cancelling any interrupts that refer to the closing queues and 44557c478bd9Sstevel@tonic-gate * also ensuring that there are no interrupts in progress that will 44567c478bd9Sstevel@tonic-gate * refer to the closing queues once the close routine returns. 44577c478bd9Sstevel@tonic-gate * - For multiplexors removing any driver global state that refers to 44587c478bd9Sstevel@tonic-gate * the closing queue and also ensuring that there are no threads in 44597c478bd9Sstevel@tonic-gate * the multiplexor that has picked up a queue pointer but not yet 44607c478bd9Sstevel@tonic-gate * finished using it. 44617c478bd9Sstevel@tonic-gate * 44627c478bd9Sstevel@tonic-gate * In addition, a driver/module can only reference the q_next pointer 44637c478bd9Sstevel@tonic-gate * in its open, close, put, or service procedures or in a 44647c478bd9Sstevel@tonic-gate * qtimeout/qbufcall callback procedure executing "on" the correct 44657c478bd9Sstevel@tonic-gate * stream. Thus it can not reference the q_next pointer in an interrupt 44667c478bd9Sstevel@tonic-gate * routine or a timeout, bufcall or esballoc callback routine. Likewise 44677c478bd9Sstevel@tonic-gate * it can not reference q_next of a different queue e.g. in a mux that 44687c478bd9Sstevel@tonic-gate * passes messages from one queues put/service procedure to another queue. 44697c478bd9Sstevel@tonic-gate * In all the cases when the driver/module can not access the q_next 44707c478bd9Sstevel@tonic-gate * field it must use the *next* versions e.g. canputnext instead of 44717c478bd9Sstevel@tonic-gate * canput(q->q_next) and putnextctl instead of putctl(q->q_next, ...). 44727c478bd9Sstevel@tonic-gate * 44737c478bd9Sstevel@tonic-gate * 44747c478bd9Sstevel@tonic-gate * Assuming that the driver/module conforms to the above constraints 44757c478bd9Sstevel@tonic-gate * the STREAMS framework has to avoid stale references to q_next for all 44767c478bd9Sstevel@tonic-gate * the framework internal cases which include (but are not limited to): 44777c478bd9Sstevel@tonic-gate * - Threads in canput/canputnext/backenable and elsewhere that are 44787c478bd9Sstevel@tonic-gate * walking q_next. 44797c478bd9Sstevel@tonic-gate * - Messages on a syncq that have a reference to the queue through b_queue. 44807c478bd9Sstevel@tonic-gate * - Messages on an outer perimeter (syncq) that have a reference to the 44817c478bd9Sstevel@tonic-gate * queue through b_queue. 44827c478bd9Sstevel@tonic-gate * - Threads that use q_nfsrv (e.g. canput) to find a queue. 44837c478bd9Sstevel@tonic-gate * Note that only canput and bcanput use q_nfsrv without any locking. 44847c478bd9Sstevel@tonic-gate * 44857c478bd9Sstevel@tonic-gate * The STREAMS framework providing the qprocsoff(9F) guarantees means that 44867c478bd9Sstevel@tonic-gate * after qprocsoff returns, the framework has to ensure that no threads can 44877c478bd9Sstevel@tonic-gate * enter the put or service routines for the closing read or write-side queue. 44887c478bd9Sstevel@tonic-gate * In addition to preventing "direct" entry into the put procedures 44897c478bd9Sstevel@tonic-gate * the framework also has to prevent messages being drained from 44907c478bd9Sstevel@tonic-gate * the syncq or the outer perimeter. 44917c478bd9Sstevel@tonic-gate * XXX Note that currently qdetach does relies on D_MTOCEXCL as the only 44927c478bd9Sstevel@tonic-gate * mechanism to prevent qwriter(PERIM_OUTER) from running after 44937c478bd9Sstevel@tonic-gate * qprocsoff has returned. 44947c478bd9Sstevel@tonic-gate * Note that if a module/driver uses put(9F) on one of its own queues 44957c478bd9Sstevel@tonic-gate * it is up to the module/driver to ensure that the put() doesn't 44967c478bd9Sstevel@tonic-gate * get called when the queue is closing. 44977c478bd9Sstevel@tonic-gate * 44987c478bd9Sstevel@tonic-gate * 44997c478bd9Sstevel@tonic-gate * The framework aspects of the above "contract" is implemented by 45007c478bd9Sstevel@tonic-gate * qprocsoff, removeq, and strlock: 45017c478bd9Sstevel@tonic-gate * - qprocsoff (disable_svc) sets QWCLOSE to prevent runservice from 45027c478bd9Sstevel@tonic-gate * entering the service procedures. 45037c478bd9Sstevel@tonic-gate * - strlock acquires the sd_lock and sd_reflock to prevent putnext, 45047c478bd9Sstevel@tonic-gate * canputnext, backenable etc from dereferencing the q_next that will 45057c478bd9Sstevel@tonic-gate * soon change. 45067c478bd9Sstevel@tonic-gate * - strlock waits for sd_refcnt to be zero to wait for e.g. any canputnext 45077c478bd9Sstevel@tonic-gate * or other q_next walker that uses claimstr/releasestr to finish. 45087c478bd9Sstevel@tonic-gate * - optionally for every syncq in the stream strlock acquires all the 45097c478bd9Sstevel@tonic-gate * sq_lock's and waits for all sq_counts to drop to a value that indicates 45107c478bd9Sstevel@tonic-gate * that no thread executes in the put or service procedures and that no 45117c478bd9Sstevel@tonic-gate * thread is draining into the module/driver. This ensures that no 45127c478bd9Sstevel@tonic-gate * open, close, put, service, or qtimeout/qbufcall callback procedure is 45137c478bd9Sstevel@tonic-gate * currently executing hence no such thread can end up with the old stale 45147c478bd9Sstevel@tonic-gate * q_next value and no canput/backenable can have the old stale 45157c478bd9Sstevel@tonic-gate * q_nfsrv/q_next. 45167c478bd9Sstevel@tonic-gate * - qdetach (wait_svc) makes sure that any scheduled or running threads 45177c478bd9Sstevel@tonic-gate * have either finished or observed the QWCLOSE flag and gone away. 45187c478bd9Sstevel@tonic-gate */ 45197c478bd9Sstevel@tonic-gate 45207c478bd9Sstevel@tonic-gate 45217c478bd9Sstevel@tonic-gate /* 45227c478bd9Sstevel@tonic-gate * Get all the locks necessary to change q_next. 45237c478bd9Sstevel@tonic-gate * 45247c478bd9Sstevel@tonic-gate * Wait for sd_refcnt to reach 0 and, if sqlist is present, wait for the 45257c478bd9Sstevel@tonic-gate * sq_count of each syncq in the list to drop to sq_rmqcount, indicating that 452621804b56SBrian Ruthven * the only threads inside the syncq are threads currently calling removeq(). 45277c478bd9Sstevel@tonic-gate * Since threads calling removeq() are in the process of removing their queues 45287c478bd9Sstevel@tonic-gate * from the stream, we do not need to worry about them accessing a stale q_next 45297c478bd9Sstevel@tonic-gate * pointer and thus we do not need to wait for them to exit (in fact, waiting 45307c478bd9Sstevel@tonic-gate * for them can cause deadlock). 45317c478bd9Sstevel@tonic-gate * 45327c478bd9Sstevel@tonic-gate * This routine is subject to starvation since it does not set any flag to 45337c478bd9Sstevel@tonic-gate * prevent threads from entering a module in the stream (i.e. sq_count can 453421804b56SBrian Ruthven * increase on some syncq while it is waiting on some other syncq). 45357c478bd9Sstevel@tonic-gate * 45367c478bd9Sstevel@tonic-gate * Assumes that only one thread attempts to call strlock for a given 45377c478bd9Sstevel@tonic-gate * stream. If this is not the case the two threads would deadlock. 45387c478bd9Sstevel@tonic-gate * This assumption is guaranteed since strlock is only called by insertq 45397c478bd9Sstevel@tonic-gate * and removeq and streams plumbing changes are single-threaded for 45407c478bd9Sstevel@tonic-gate * a given stream using the STWOPEN, STRCLOSE, and STRPLUMB flags. 45417c478bd9Sstevel@tonic-gate * 45427c478bd9Sstevel@tonic-gate * For pipes, it is not difficult to atomically designate a pair of streams 45437c478bd9Sstevel@tonic-gate * to be mated. Once mated atomically by the framework the twisted pair remain 45447c478bd9Sstevel@tonic-gate * configured that way until dismantled atomically by the framework. 45457c478bd9Sstevel@tonic-gate * When plumbing takes place on a twisted stream it is necessary to ensure that 45467c478bd9Sstevel@tonic-gate * this operation is done exclusively on the twisted stream since two such 45477c478bd9Sstevel@tonic-gate * operations, each initiated on different ends of the pipe will deadlock 45487c478bd9Sstevel@tonic-gate * waiting for each other to complete. 45497c478bd9Sstevel@tonic-gate * 45507c478bd9Sstevel@tonic-gate * On entry, no locks should be held. 45517c478bd9Sstevel@tonic-gate * The locks acquired and held by strlock depends on a few factors. 45527c478bd9Sstevel@tonic-gate * - If sqlist is non-NULL all the syncq locks in the sqlist will be acquired 45537c478bd9Sstevel@tonic-gate * and held on exit and all sq_count are at an acceptable level. 45547c478bd9Sstevel@tonic-gate * - In all cases, sd_lock and sd_reflock are acquired and held on exit with 45557c478bd9Sstevel@tonic-gate * sd_refcnt being zero. 45567c478bd9Sstevel@tonic-gate */ 45577c478bd9Sstevel@tonic-gate 45587c478bd9Sstevel@tonic-gate static void 45597c478bd9Sstevel@tonic-gate strlock(struct stdata *stp, sqlist_t *sqlist) 45607c478bd9Sstevel@tonic-gate { 45617c478bd9Sstevel@tonic-gate syncql_t *sql, *sql2; 45627c478bd9Sstevel@tonic-gate retry: 45637c478bd9Sstevel@tonic-gate /* 45647c478bd9Sstevel@tonic-gate * Wait for any claimstr to go away. 45657c478bd9Sstevel@tonic-gate */ 45667c478bd9Sstevel@tonic-gate if (STRMATED(stp)) { 45677c478bd9Sstevel@tonic-gate struct stdata *stp1, *stp2; 45687c478bd9Sstevel@tonic-gate 45697c478bd9Sstevel@tonic-gate STRLOCKMATES(stp); 45707c478bd9Sstevel@tonic-gate /* 45717c478bd9Sstevel@tonic-gate * Note that the selection of locking order is not 457221804b56SBrian Ruthven * important, just that they are always acquired in 45737c478bd9Sstevel@tonic-gate * the same order. To assure this, we choose this 45747c478bd9Sstevel@tonic-gate * order based on the value of the pointer, and since 45757c478bd9Sstevel@tonic-gate * the pointer will not change for the life of this 45767c478bd9Sstevel@tonic-gate * pair, we will always grab the locks in the same 45777c478bd9Sstevel@tonic-gate * order (and hence, prevent deadlocks). 45787c478bd9Sstevel@tonic-gate */ 45797c478bd9Sstevel@tonic-gate if (&(stp->sd_lock) > &((stp->sd_mate)->sd_lock)) { 45807c478bd9Sstevel@tonic-gate stp1 = stp; 45817c478bd9Sstevel@tonic-gate stp2 = stp->sd_mate; 45827c478bd9Sstevel@tonic-gate } else { 45837c478bd9Sstevel@tonic-gate stp2 = stp; 45847c478bd9Sstevel@tonic-gate stp1 = stp->sd_mate; 45857c478bd9Sstevel@tonic-gate } 45867c478bd9Sstevel@tonic-gate mutex_enter(&stp1->sd_reflock); 45877c478bd9Sstevel@tonic-gate if (stp1->sd_refcnt > 0) { 45887c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 45896829c646Sxy158873 cv_wait(&stp1->sd_refmonitor, &stp1->sd_reflock); 45907c478bd9Sstevel@tonic-gate mutex_exit(&stp1->sd_reflock); 45917c478bd9Sstevel@tonic-gate goto retry; 45927c478bd9Sstevel@tonic-gate } 45937c478bd9Sstevel@tonic-gate mutex_enter(&stp2->sd_reflock); 45947c478bd9Sstevel@tonic-gate if (stp2->sd_refcnt > 0) { 45957c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 45967c478bd9Sstevel@tonic-gate mutex_exit(&stp1->sd_reflock); 45976829c646Sxy158873 cv_wait(&stp2->sd_refmonitor, &stp2->sd_reflock); 45987c478bd9Sstevel@tonic-gate mutex_exit(&stp2->sd_reflock); 45997c478bd9Sstevel@tonic-gate goto retry; 46007c478bd9Sstevel@tonic-gate } 46017c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_ENTER(stp1); 46027c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_ENTER(stp2); 46037c478bd9Sstevel@tonic-gate } else { 46047c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 46057c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_reflock); 46067c478bd9Sstevel@tonic-gate while (stp->sd_refcnt > 0) { 46077c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 46086829c646Sxy158873 cv_wait(&stp->sd_refmonitor, &stp->sd_reflock); 46097c478bd9Sstevel@tonic-gate if (mutex_tryenter(&stp->sd_lock) == 0) { 46107c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 46117c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 46127c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_reflock); 46137c478bd9Sstevel@tonic-gate } 46147c478bd9Sstevel@tonic-gate } 46157c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_ENTER(stp); 46167c478bd9Sstevel@tonic-gate } 46177c478bd9Sstevel@tonic-gate 46187c478bd9Sstevel@tonic-gate if (sqlist == NULL) 46197c478bd9Sstevel@tonic-gate return; 46207c478bd9Sstevel@tonic-gate 46217c478bd9Sstevel@tonic-gate for (sql = sqlist->sqlist_head; sql; sql = sql->sql_next) { 46227c478bd9Sstevel@tonic-gate syncq_t *sq = sql->sql_sq; 46237c478bd9Sstevel@tonic-gate uint16_t count; 46247c478bd9Sstevel@tonic-gate 46257c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 46267c478bd9Sstevel@tonic-gate count = sq->sq_count; 46277c478bd9Sstevel@tonic-gate ASSERT(sq->sq_rmqcount <= count); 46287c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 46297c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 46307c478bd9Sstevel@tonic-gate if (count == sq->sq_rmqcount) 46317c478bd9Sstevel@tonic-gate continue; 46327c478bd9Sstevel@tonic-gate 46337c478bd9Sstevel@tonic-gate /* Failed - drop all locks that we have acquired so far */ 46347c478bd9Sstevel@tonic-gate if (STRMATED(stp)) { 46357c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_EXIT(stp); 46367c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_EXIT(stp->sd_mate); 46377c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 46387c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 46397c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_mate->sd_reflock); 46407c478bd9Sstevel@tonic-gate } else { 46417c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_EXIT(stp); 46427c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 46437c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 46447c478bd9Sstevel@tonic-gate } 46457c478bd9Sstevel@tonic-gate for (sql2 = sqlist->sqlist_head; sql2 != sql; 46467c478bd9Sstevel@tonic-gate sql2 = sql2->sql_next) { 46477c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sql2->sql_sq); 46487c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sql2->sql_sq)); 46497c478bd9Sstevel@tonic-gate } 46507c478bd9Sstevel@tonic-gate 46517c478bd9Sstevel@tonic-gate /* 46527c478bd9Sstevel@tonic-gate * The wait loop below may starve when there are many threads 46537c478bd9Sstevel@tonic-gate * claiming the syncq. This is especially a problem with permod 46547c478bd9Sstevel@tonic-gate * syncqs (IP). To lessen the impact of the problem we increment 46557c478bd9Sstevel@tonic-gate * sq_needexcl and clear fastbits so that putnexts will slow 46567c478bd9Sstevel@tonic-gate * down and call sqenable instead of draining right away. 46577c478bd9Sstevel@tonic-gate */ 46587c478bd9Sstevel@tonic-gate sq->sq_needexcl++; 46597c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_CLRFAST_LOCKED(sq); 46607c478bd9Sstevel@tonic-gate while (count > sq->sq_rmqcount) { 46617c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 46627c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 46637c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 46647c478bd9Sstevel@tonic-gate count = sq->sq_count; 46657c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 46667c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 46677c478bd9Sstevel@tonic-gate } 46687c478bd9Sstevel@tonic-gate sq->sq_needexcl--; 46697c478bd9Sstevel@tonic-gate if (sq->sq_needexcl == 0) 46707c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_SETFAST_LOCKED(sq); 46717c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 46727c478bd9Sstevel@tonic-gate ASSERT(count == sq->sq_rmqcount); 46737c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 46747c478bd9Sstevel@tonic-gate goto retry; 46757c478bd9Sstevel@tonic-gate } 46767c478bd9Sstevel@tonic-gate } 46777c478bd9Sstevel@tonic-gate 46787c478bd9Sstevel@tonic-gate /* 46797c478bd9Sstevel@tonic-gate * Drop all the locks that strlock acquired. 46807c478bd9Sstevel@tonic-gate */ 46817c478bd9Sstevel@tonic-gate static void 46827c478bd9Sstevel@tonic-gate strunlock(struct stdata *stp, sqlist_t *sqlist) 46837c478bd9Sstevel@tonic-gate { 46847c478bd9Sstevel@tonic-gate syncql_t *sql; 46857c478bd9Sstevel@tonic-gate 46867c478bd9Sstevel@tonic-gate if (STRMATED(stp)) { 46877c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_EXIT(stp); 46887c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_EXIT(stp->sd_mate); 46897c478bd9Sstevel@tonic-gate STRUNLOCKMATES(stp); 46907c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 46917c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_mate->sd_reflock); 46927c478bd9Sstevel@tonic-gate } else { 46937c478bd9Sstevel@tonic-gate STREAM_PUTLOCKS_EXIT(stp); 46947c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 46957c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 46967c478bd9Sstevel@tonic-gate } 46977c478bd9Sstevel@tonic-gate 46987c478bd9Sstevel@tonic-gate if (sqlist == NULL) 46997c478bd9Sstevel@tonic-gate return; 47007c478bd9Sstevel@tonic-gate 47017c478bd9Sstevel@tonic-gate for (sql = sqlist->sqlist_head; sql; sql = sql->sql_next) { 47027c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sql->sql_sq); 47037c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sql->sql_sq)); 47047c478bd9Sstevel@tonic-gate } 47057c478bd9Sstevel@tonic-gate } 47067c478bd9Sstevel@tonic-gate 4707116094b2Smicheng /* 4708116094b2Smicheng * When the module has service procedure, we need check if the next 4709116094b2Smicheng * module which has service procedure is in flow control to trigger 4710116094b2Smicheng * the backenable. 4711116094b2Smicheng */ 4712116094b2Smicheng static void 4713116094b2Smicheng backenable_insertedq(queue_t *q) 4714116094b2Smicheng { 4715116094b2Smicheng qband_t *qbp; 4716116094b2Smicheng 4717116094b2Smicheng claimstr(q); 4718116094b2Smicheng if (q->q_qinfo->qi_srvp != NULL && q->q_next != NULL) { 4719116094b2Smicheng if (q->q_next->q_nfsrv->q_flag & QWANTW) 4720116094b2Smicheng backenable(q, 0); 4721116094b2Smicheng 4722116094b2Smicheng qbp = q->q_next->q_nfsrv->q_bandp; 4723116094b2Smicheng for (; qbp != NULL; qbp = qbp->qb_next) 4724116094b2Smicheng if ((qbp->qb_flag & QB_WANTW) && qbp->qb_first != NULL) 4725116094b2Smicheng backenable(q, qbp->qb_first->b_band); 4726116094b2Smicheng } 4727116094b2Smicheng releasestr(q); 4728116094b2Smicheng } 47297c478bd9Sstevel@tonic-gate 47307c478bd9Sstevel@tonic-gate /* 47317c478bd9Sstevel@tonic-gate * Given two read queues, insert a new single one after another. 47327c478bd9Sstevel@tonic-gate * 47337c478bd9Sstevel@tonic-gate * This routine acquires all the necessary locks in order to change 47347c478bd9Sstevel@tonic-gate * q_next and related pointer using strlock(). 47357c478bd9Sstevel@tonic-gate * It depends on the stream head ensuring that there are no concurrent 47367c478bd9Sstevel@tonic-gate * insertq or removeq on the same stream. The stream head ensures this 47377c478bd9Sstevel@tonic-gate * using the flags STWOPEN, STRCLOSE, and STRPLUMB. 47387c478bd9Sstevel@tonic-gate * 47397c478bd9Sstevel@tonic-gate * Note that no syncq locks are held during the q_next change. This is 47407c478bd9Sstevel@tonic-gate * applied to all streams since, unlike removeq, there is no problem of stale 47417c478bd9Sstevel@tonic-gate * pointers when adding a module to the stream. Thus drivers/modules that do a 47427c478bd9Sstevel@tonic-gate * canput(rq->q_next) would never get a closed/freed queue pointer even if we 47437c478bd9Sstevel@tonic-gate * applied this optimization to all streams. 47447c478bd9Sstevel@tonic-gate */ 47457c478bd9Sstevel@tonic-gate void 47467c478bd9Sstevel@tonic-gate insertq(struct stdata *stp, queue_t *new) 47477c478bd9Sstevel@tonic-gate { 47487c478bd9Sstevel@tonic-gate queue_t *after; 47497c478bd9Sstevel@tonic-gate queue_t *wafter; 47507c478bd9Sstevel@tonic-gate queue_t *wnew = _WR(new); 47517c478bd9Sstevel@tonic-gate boolean_t have_fifo = B_FALSE; 47527c478bd9Sstevel@tonic-gate 47537c478bd9Sstevel@tonic-gate if (new->q_flag & _QINSERTING) { 47547c478bd9Sstevel@tonic-gate ASSERT(stp->sd_vnode->v_type != VFIFO); 47557c478bd9Sstevel@tonic-gate after = new->q_next; 47567c478bd9Sstevel@tonic-gate wafter = _WR(new->q_next); 47577c478bd9Sstevel@tonic-gate } else { 47587c478bd9Sstevel@tonic-gate after = _RD(stp->sd_wrq); 47597c478bd9Sstevel@tonic-gate wafter = stp->sd_wrq; 47607c478bd9Sstevel@tonic-gate } 47617c478bd9Sstevel@tonic-gate 47627c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_INSERTQ, 47637c478bd9Sstevel@tonic-gate "insertq:%p, %p", after, new); 47647c478bd9Sstevel@tonic-gate ASSERT(after->q_flag & QREADR); 47657c478bd9Sstevel@tonic-gate ASSERT(new->q_flag & QREADR); 47667c478bd9Sstevel@tonic-gate 47677c478bd9Sstevel@tonic-gate strlock(stp, NULL); 47687c478bd9Sstevel@tonic-gate 47697c478bd9Sstevel@tonic-gate /* Do we have a FIFO? */ 47707c478bd9Sstevel@tonic-gate if (wafter->q_next == after) { 47717c478bd9Sstevel@tonic-gate have_fifo = B_TRUE; 47727c478bd9Sstevel@tonic-gate wnew->q_next = new; 47737c478bd9Sstevel@tonic-gate } else { 47747c478bd9Sstevel@tonic-gate wnew->q_next = wafter->q_next; 47757c478bd9Sstevel@tonic-gate } 47767c478bd9Sstevel@tonic-gate new->q_next = after; 47777c478bd9Sstevel@tonic-gate 47787c478bd9Sstevel@tonic-gate set_nfsrv_ptr(new, wnew, after, wafter); 47797c478bd9Sstevel@tonic-gate /* 47807c478bd9Sstevel@tonic-gate * set_nfsrv_ptr() needs to know if this is an insertion or not, 47817c478bd9Sstevel@tonic-gate * so only reset this flag after calling it. 47827c478bd9Sstevel@tonic-gate */ 47837c478bd9Sstevel@tonic-gate new->q_flag &= ~_QINSERTING; 47847c478bd9Sstevel@tonic-gate 47857c478bd9Sstevel@tonic-gate if (have_fifo) { 47867c478bd9Sstevel@tonic-gate wafter->q_next = wnew; 47877c478bd9Sstevel@tonic-gate } else { 47887c478bd9Sstevel@tonic-gate if (wafter->q_next) 47897c478bd9Sstevel@tonic-gate _OTHERQ(wafter->q_next)->q_next = new; 47907c478bd9Sstevel@tonic-gate wafter->q_next = wnew; 47917c478bd9Sstevel@tonic-gate } 47927c478bd9Sstevel@tonic-gate 47937c478bd9Sstevel@tonic-gate set_qend(new); 47947c478bd9Sstevel@tonic-gate /* The QEND flag might have to be updated for the upstream guy */ 47957c478bd9Sstevel@tonic-gate set_qend(after); 47967c478bd9Sstevel@tonic-gate 47977c478bd9Sstevel@tonic-gate ASSERT(_SAMESTR(new) == O_SAMESTR(new)); 47987c478bd9Sstevel@tonic-gate ASSERT(_SAMESTR(wnew) == O_SAMESTR(wnew)); 47997c478bd9Sstevel@tonic-gate ASSERT(_SAMESTR(after) == O_SAMESTR(after)); 48007c478bd9Sstevel@tonic-gate ASSERT(_SAMESTR(wafter) == O_SAMESTR(wafter)); 48017c478bd9Sstevel@tonic-gate strsetuio(stp); 48027c478bd9Sstevel@tonic-gate 48037c478bd9Sstevel@tonic-gate /* 48047c478bd9Sstevel@tonic-gate * If this was a module insertion, bump the push count. 48057c478bd9Sstevel@tonic-gate */ 48067c478bd9Sstevel@tonic-gate if (!(new->q_flag & QISDRV)) 48077c478bd9Sstevel@tonic-gate stp->sd_pushcnt++; 48087c478bd9Sstevel@tonic-gate 48097c478bd9Sstevel@tonic-gate strunlock(stp, NULL); 4810116094b2Smicheng 4811116094b2Smicheng /* check if the write Q needs backenable */ 4812116094b2Smicheng backenable_insertedq(wnew); 4813116094b2Smicheng 4814116094b2Smicheng /* check if the read Q needs backenable */ 4815116094b2Smicheng backenable_insertedq(new); 48167c478bd9Sstevel@tonic-gate } 48177c478bd9Sstevel@tonic-gate 48187c478bd9Sstevel@tonic-gate /* 48197c478bd9Sstevel@tonic-gate * Given a read queue, unlink it from any neighbors. 48207c478bd9Sstevel@tonic-gate * 48217c478bd9Sstevel@tonic-gate * This routine acquires all the necessary locks in order to 48227c478bd9Sstevel@tonic-gate * change q_next and related pointers and also guard against 48237c478bd9Sstevel@tonic-gate * stale references (e.g. through q_next) to the queue that 48247c478bd9Sstevel@tonic-gate * is being removed. It also plays part of the role in ensuring 48257c478bd9Sstevel@tonic-gate * that the module's/driver's put procedure doesn't get called 48267c478bd9Sstevel@tonic-gate * after qprocsoff returns. 48277c478bd9Sstevel@tonic-gate * 48287c478bd9Sstevel@tonic-gate * Removeq depends on the stream head ensuring that there are 48297c478bd9Sstevel@tonic-gate * no concurrent insertq or removeq on the same stream. The 48307c478bd9Sstevel@tonic-gate * stream head ensures this using the flags STWOPEN, STRCLOSE and 48317c478bd9Sstevel@tonic-gate * STRPLUMB. 48327c478bd9Sstevel@tonic-gate * 48337c478bd9Sstevel@tonic-gate * The set of locks needed to remove the queue is different in 48347c478bd9Sstevel@tonic-gate * different cases: 48357c478bd9Sstevel@tonic-gate * 48367c478bd9Sstevel@tonic-gate * Acquire sd_lock, sd_reflock, and all the syncq locks in the stream after 48377c478bd9Sstevel@tonic-gate * waiting for the syncq reference count to drop to 0 indicating that no 48387c478bd9Sstevel@tonic-gate * non-close threads are present anywhere in the stream. This ensures that any 48397c478bd9Sstevel@tonic-gate * module/driver can reference q_next in its open, close, put, or service 48407c478bd9Sstevel@tonic-gate * procedures. 48417c478bd9Sstevel@tonic-gate * 48427c478bd9Sstevel@tonic-gate * The sq_rmqcount counter tracks the number of threads inside removeq(). 48437c478bd9Sstevel@tonic-gate * strlock() ensures that there is either no threads executing inside perimeter 48447c478bd9Sstevel@tonic-gate * or there is only a thread calling qprocsoff(). 48457c478bd9Sstevel@tonic-gate * 48467c478bd9Sstevel@tonic-gate * strlock() compares the value of sq_count with the number of threads inside 48477c478bd9Sstevel@tonic-gate * removeq() and waits until sq_count is equal to sq_rmqcount. We need to wakeup 48487c478bd9Sstevel@tonic-gate * any threads waiting in strlock() when the sq_rmqcount increases. 48497c478bd9Sstevel@tonic-gate */ 48507c478bd9Sstevel@tonic-gate 48517c478bd9Sstevel@tonic-gate void 48527c478bd9Sstevel@tonic-gate removeq(queue_t *qp) 48537c478bd9Sstevel@tonic-gate { 48547c478bd9Sstevel@tonic-gate queue_t *wqp = _WR(qp); 48557c478bd9Sstevel@tonic-gate struct stdata *stp = STREAM(qp); 48567c478bd9Sstevel@tonic-gate sqlist_t *sqlist = NULL; 48577c478bd9Sstevel@tonic-gate boolean_t isdriver; 48587c478bd9Sstevel@tonic-gate int moved; 48597c478bd9Sstevel@tonic-gate syncq_t *sq = qp->q_syncq; 48607c478bd9Sstevel@tonic-gate syncq_t *wsq = wqp->q_syncq; 48617c478bd9Sstevel@tonic-gate 48627c478bd9Sstevel@tonic-gate ASSERT(stp); 48637c478bd9Sstevel@tonic-gate 48647c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_STREAMS_FR, TR_REMOVEQ, 48657c478bd9Sstevel@tonic-gate "removeq:%p %p", qp, wqp); 48667c478bd9Sstevel@tonic-gate ASSERT(qp->q_flag&QREADR); 48677c478bd9Sstevel@tonic-gate 48687c478bd9Sstevel@tonic-gate /* 48697c478bd9Sstevel@tonic-gate * For queues using Synchronous streams, we must wait for all threads in 48707c478bd9Sstevel@tonic-gate * rwnext() to drain out before proceeding. 48717c478bd9Sstevel@tonic-gate */ 48727c478bd9Sstevel@tonic-gate if (qp->q_flag & QSYNCSTR) { 48737c478bd9Sstevel@tonic-gate /* First, we need wakeup any threads blocked in rwnext() */ 48747c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 48757c478bd9Sstevel@tonic-gate if (sq->sq_flags & SQ_WANTWAKEUP) { 48767c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_WANTWAKEUP; 48777c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 48787c478bd9Sstevel@tonic-gate } 48797c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 48807c478bd9Sstevel@tonic-gate 48817c478bd9Sstevel@tonic-gate if (wsq != sq) { 48827c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(wsq)); 48837c478bd9Sstevel@tonic-gate if (wsq->sq_flags & SQ_WANTWAKEUP) { 48847c478bd9Sstevel@tonic-gate wsq->sq_flags &= ~SQ_WANTWAKEUP; 48857c478bd9Sstevel@tonic-gate cv_broadcast(&wsq->sq_wait); 48867c478bd9Sstevel@tonic-gate } 48877c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(wsq)); 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate 48907c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 48917c478bd9Sstevel@tonic-gate while (qp->q_rwcnt > 0) { 48927c478bd9Sstevel@tonic-gate qp->q_flag |= QWANTRMQSYNC; 48937c478bd9Sstevel@tonic-gate cv_wait(&qp->q_wait, QLOCK(qp)); 48947c478bd9Sstevel@tonic-gate } 48957c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(qp)); 48967c478bd9Sstevel@tonic-gate 48977c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(wqp)); 48987c478bd9Sstevel@tonic-gate while (wqp->q_rwcnt > 0) { 48997c478bd9Sstevel@tonic-gate wqp->q_flag |= QWANTRMQSYNC; 49007c478bd9Sstevel@tonic-gate cv_wait(&wqp->q_wait, QLOCK(wqp)); 49017c478bd9Sstevel@tonic-gate } 49027c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(wqp)); 49037c478bd9Sstevel@tonic-gate } 49047c478bd9Sstevel@tonic-gate 49057c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 49067c478bd9Sstevel@tonic-gate sq->sq_rmqcount++; 49077c478bd9Sstevel@tonic-gate if (sq->sq_flags & SQ_WANTWAKEUP) { 49087c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_WANTWAKEUP; 49097c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 49107c478bd9Sstevel@tonic-gate } 49117c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 49127c478bd9Sstevel@tonic-gate 49137c478bd9Sstevel@tonic-gate isdriver = (qp->q_flag & QISDRV); 49147c478bd9Sstevel@tonic-gate 49157c478bd9Sstevel@tonic-gate sqlist = sqlist_build(qp, stp, STRMATED(stp)); 49167c478bd9Sstevel@tonic-gate strlock(stp, sqlist); 49177c478bd9Sstevel@tonic-gate 49187c478bd9Sstevel@tonic-gate reset_nfsrv_ptr(qp, wqp); 49197c478bd9Sstevel@tonic-gate 49207c478bd9Sstevel@tonic-gate ASSERT(wqp->q_next == NULL || backq(qp)->q_next == qp); 49217c478bd9Sstevel@tonic-gate ASSERT(qp->q_next == NULL || backq(wqp)->q_next == wqp); 49227c478bd9Sstevel@tonic-gate /* Do we have a FIFO? */ 49237c478bd9Sstevel@tonic-gate if (wqp->q_next == qp) { 49247c478bd9Sstevel@tonic-gate stp->sd_wrq->q_next = _RD(stp->sd_wrq); 49257c478bd9Sstevel@tonic-gate } else { 49267c478bd9Sstevel@tonic-gate if (wqp->q_next) 49277c478bd9Sstevel@tonic-gate backq(qp)->q_next = qp->q_next; 49287c478bd9Sstevel@tonic-gate if (qp->q_next) 49297c478bd9Sstevel@tonic-gate backq(wqp)->q_next = wqp->q_next; 49307c478bd9Sstevel@tonic-gate } 49317c478bd9Sstevel@tonic-gate 49327c478bd9Sstevel@tonic-gate /* The QEND flag might have to be updated for the upstream guy */ 49337c478bd9Sstevel@tonic-gate if (qp->q_next) 49347c478bd9Sstevel@tonic-gate set_qend(qp->q_next); 49357c478bd9Sstevel@tonic-gate 49367c478bd9Sstevel@tonic-gate ASSERT(_SAMESTR(stp->sd_wrq) == O_SAMESTR(stp->sd_wrq)); 49377c478bd9Sstevel@tonic-gate ASSERT(_SAMESTR(_RD(stp->sd_wrq)) == O_SAMESTR(_RD(stp->sd_wrq))); 49387c478bd9Sstevel@tonic-gate 49397c478bd9Sstevel@tonic-gate /* 49407c478bd9Sstevel@tonic-gate * Move any messages destined for the put procedures to the next 49417c478bd9Sstevel@tonic-gate * syncq in line. Otherwise free them. 49427c478bd9Sstevel@tonic-gate */ 49437c478bd9Sstevel@tonic-gate moved = 0; 49447c478bd9Sstevel@tonic-gate /* 49457c478bd9Sstevel@tonic-gate * Quick check to see whether there are any messages or events. 49467c478bd9Sstevel@tonic-gate */ 49477c478bd9Sstevel@tonic-gate if (qp->q_syncqmsgs != 0 || (qp->q_syncq->sq_flags & SQ_EVENTS)) 49487c478bd9Sstevel@tonic-gate moved += propagate_syncq(qp); 49497c478bd9Sstevel@tonic-gate if (wqp->q_syncqmsgs != 0 || 49507c478bd9Sstevel@tonic-gate (wqp->q_syncq->sq_flags & SQ_EVENTS)) 49517c478bd9Sstevel@tonic-gate moved += propagate_syncq(wqp); 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate strsetuio(stp); 49547c478bd9Sstevel@tonic-gate 49557c478bd9Sstevel@tonic-gate /* 49567c478bd9Sstevel@tonic-gate * If this was a module removal, decrement the push count. 49577c478bd9Sstevel@tonic-gate */ 49587c478bd9Sstevel@tonic-gate if (!isdriver) 49597c478bd9Sstevel@tonic-gate stp->sd_pushcnt--; 49607c478bd9Sstevel@tonic-gate 49617c478bd9Sstevel@tonic-gate strunlock(stp, sqlist); 49627c478bd9Sstevel@tonic-gate sqlist_free(sqlist); 49637c478bd9Sstevel@tonic-gate 49647c478bd9Sstevel@tonic-gate /* 49657c478bd9Sstevel@tonic-gate * Make sure any messages that were propagated are drained. 49667c478bd9Sstevel@tonic-gate * Also clear any QFULL bit caused by messages that were propagated. 49677c478bd9Sstevel@tonic-gate */ 49687c478bd9Sstevel@tonic-gate 49697c478bd9Sstevel@tonic-gate if (qp->q_next != NULL) { 49707c478bd9Sstevel@tonic-gate clr_qfull(qp); 49717c478bd9Sstevel@tonic-gate /* 49727c478bd9Sstevel@tonic-gate * For the driver calling qprocsoff, propagate_syncq 49737c478bd9Sstevel@tonic-gate * frees all the messages instead of putting it in 49747c478bd9Sstevel@tonic-gate * the stream head 49757c478bd9Sstevel@tonic-gate */ 49767c478bd9Sstevel@tonic-gate if (!isdriver && (moved > 0)) 49777c478bd9Sstevel@tonic-gate emptysq(qp->q_next->q_syncq); 49787c478bd9Sstevel@tonic-gate } 49797c478bd9Sstevel@tonic-gate if (wqp->q_next != NULL) { 49807c478bd9Sstevel@tonic-gate clr_qfull(wqp); 49817c478bd9Sstevel@tonic-gate /* 49827c478bd9Sstevel@tonic-gate * We come here for any pop of a module except for the 49837c478bd9Sstevel@tonic-gate * case of driver being removed. We don't call emptysq 49847c478bd9Sstevel@tonic-gate * if we did not move any messages. This will avoid holding 49857c478bd9Sstevel@tonic-gate * PERMOD syncq locks in emptysq 49867c478bd9Sstevel@tonic-gate */ 49877c478bd9Sstevel@tonic-gate if (moved > 0) 49887c478bd9Sstevel@tonic-gate emptysq(wqp->q_next->q_syncq); 49897c478bd9Sstevel@tonic-gate } 49907c478bd9Sstevel@tonic-gate 49917c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 49927c478bd9Sstevel@tonic-gate sq->sq_rmqcount--; 49937c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 49947c478bd9Sstevel@tonic-gate } 49957c478bd9Sstevel@tonic-gate 49967c478bd9Sstevel@tonic-gate /* 49977c478bd9Sstevel@tonic-gate * Prevent further entry by setting a flag (like SQ_FROZEN, SQ_BLOCKED or 49987c478bd9Sstevel@tonic-gate * SQ_WRITER) on a syncq. 49997c478bd9Sstevel@tonic-gate * If maxcnt is not -1 it assumes that caller has "maxcnt" claim(s) on the 50007c478bd9Sstevel@tonic-gate * sync queue and waits until sq_count reaches maxcnt. 50017c478bd9Sstevel@tonic-gate * 500221804b56SBrian Ruthven * If maxcnt is -1 there's no need to grab sq_putlocks since the caller 50037c478bd9Sstevel@tonic-gate * does not care about putnext threads that are in the middle of calling put 50047c478bd9Sstevel@tonic-gate * entry points. 50057c478bd9Sstevel@tonic-gate * 50067c478bd9Sstevel@tonic-gate * This routine is used for both inner and outer syncqs. 50077c478bd9Sstevel@tonic-gate */ 50087c478bd9Sstevel@tonic-gate static void 50097c478bd9Sstevel@tonic-gate blocksq(syncq_t *sq, ushort_t flag, int maxcnt) 50107c478bd9Sstevel@tonic-gate { 50117c478bd9Sstevel@tonic-gate uint16_t count = 0; 50127c478bd9Sstevel@tonic-gate 50137c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 50147c478bd9Sstevel@tonic-gate /* 50157c478bd9Sstevel@tonic-gate * Wait for SQ_FROZEN/SQ_BLOCKED to be reset. 50167c478bd9Sstevel@tonic-gate * SQ_FROZEN will be set if there is a frozen stream that has a 50177c478bd9Sstevel@tonic-gate * queue which also refers to this "shared" syncq. 50187c478bd9Sstevel@tonic-gate * SQ_BLOCKED will be set if there is "off" queue which also 50197c478bd9Sstevel@tonic-gate * refers to this "shared" syncq. 50207c478bd9Sstevel@tonic-gate */ 50217c478bd9Sstevel@tonic-gate if (maxcnt != -1) { 50227c478bd9Sstevel@tonic-gate count = sq->sq_count; 50237c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 50247c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_CLRFAST_LOCKED(sq); 50257c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 50267c478bd9Sstevel@tonic-gate } 50277c478bd9Sstevel@tonic-gate sq->sq_needexcl++; 50287c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl != 0); /* wraparound */ 50297c478bd9Sstevel@tonic-gate 50307c478bd9Sstevel@tonic-gate while ((sq->sq_flags & flag) || 50317c478bd9Sstevel@tonic-gate (maxcnt != -1 && count > (unsigned)maxcnt)) { 50327c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 50337c478bd9Sstevel@tonic-gate if (maxcnt != -1) { 50347c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 50357c478bd9Sstevel@tonic-gate } 50367c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 50377c478bd9Sstevel@tonic-gate if (maxcnt != -1) { 50387c478bd9Sstevel@tonic-gate count = sq->sq_count; 50397c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 50407c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 50417c478bd9Sstevel@tonic-gate } 50427c478bd9Sstevel@tonic-gate } 50437c478bd9Sstevel@tonic-gate sq->sq_needexcl--; 50447c478bd9Sstevel@tonic-gate sq->sq_flags |= flag; 50457c478bd9Sstevel@tonic-gate ASSERT(maxcnt == -1 || count == maxcnt); 50467c478bd9Sstevel@tonic-gate if (maxcnt != -1) { 50477c478bd9Sstevel@tonic-gate if (sq->sq_needexcl == 0) { 50487c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_SETFAST_LOCKED(sq); 50497c478bd9Sstevel@tonic-gate } 50507c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 50517c478bd9Sstevel@tonic-gate } else if (sq->sq_needexcl == 0) { 50527c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_SETFAST(sq); 50537c478bd9Sstevel@tonic-gate } 50547c478bd9Sstevel@tonic-gate 50557c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 50567c478bd9Sstevel@tonic-gate } 50577c478bd9Sstevel@tonic-gate 50587c478bd9Sstevel@tonic-gate /* 50597c478bd9Sstevel@tonic-gate * Reset a flag that was set with blocksq. 50607c478bd9Sstevel@tonic-gate * 50617c478bd9Sstevel@tonic-gate * Can not use this routine to reset SQ_WRITER. 50627c478bd9Sstevel@tonic-gate * 50637c478bd9Sstevel@tonic-gate * If "isouter" is set then the syncq is assumed to be an outer perimeter 50647c478bd9Sstevel@tonic-gate * and drain_syncq is not called. Instead we rely on the qwriter_outer thread 50657c478bd9Sstevel@tonic-gate * to handle the queued qwriter operations. 50667c478bd9Sstevel@tonic-gate * 506721804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 50687c478bd9Sstevel@tonic-gate * sq_putlocks are used. 50697c478bd9Sstevel@tonic-gate */ 50707c478bd9Sstevel@tonic-gate static void 50717c478bd9Sstevel@tonic-gate unblocksq(syncq_t *sq, uint16_t resetflag, int isouter) 50727c478bd9Sstevel@tonic-gate { 50737c478bd9Sstevel@tonic-gate uint16_t flags; 50747c478bd9Sstevel@tonic-gate 50757c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 50767c478bd9Sstevel@tonic-gate ASSERT(resetflag != SQ_WRITER); 50777c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & resetflag); 50787c478bd9Sstevel@tonic-gate flags = sq->sq_flags & ~resetflag; 50797c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 50807c478bd9Sstevel@tonic-gate if (flags & (SQ_QUEUED | SQ_WANTWAKEUP)) { 50817c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 50827c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 50837c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 50847c478bd9Sstevel@tonic-gate } 50857c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 50867c478bd9Sstevel@tonic-gate if ((flags & SQ_QUEUED) && !(flags & (SQ_STAYAWAY|SQ_EXCL))) { 50877c478bd9Sstevel@tonic-gate if (!isouter) { 50887c478bd9Sstevel@tonic-gate /* drain_syncq drops SQLOCK */ 50897c478bd9Sstevel@tonic-gate drain_syncq(sq); 50907c478bd9Sstevel@tonic-gate return; 50917c478bd9Sstevel@tonic-gate } 50927c478bd9Sstevel@tonic-gate } 50937c478bd9Sstevel@tonic-gate } 50947c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 50957c478bd9Sstevel@tonic-gate } 50967c478bd9Sstevel@tonic-gate 50977c478bd9Sstevel@tonic-gate /* 50987c478bd9Sstevel@tonic-gate * Reset a flag that was set with blocksq. 50997c478bd9Sstevel@tonic-gate * Does not drain the syncq. Use emptysq() for that. 51007c478bd9Sstevel@tonic-gate * Returns 1 if SQ_QUEUED is set. Otherwise 0. 51017c478bd9Sstevel@tonic-gate * 510221804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 51037c478bd9Sstevel@tonic-gate * sq_putlocks are used. 51047c478bd9Sstevel@tonic-gate */ 51057c478bd9Sstevel@tonic-gate static int 51067c478bd9Sstevel@tonic-gate dropsq(syncq_t *sq, uint16_t resetflag) 51077c478bd9Sstevel@tonic-gate { 51087c478bd9Sstevel@tonic-gate uint16_t flags; 51097c478bd9Sstevel@tonic-gate 51107c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 51117c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & resetflag); 51127c478bd9Sstevel@tonic-gate flags = sq->sq_flags & ~resetflag; 51137c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 51147c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 51157c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 51167c478bd9Sstevel@tonic-gate } 51177c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 51187c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 51197c478bd9Sstevel@tonic-gate if (flags & SQ_QUEUED) 51207c478bd9Sstevel@tonic-gate return (1); 51217c478bd9Sstevel@tonic-gate return (0); 51227c478bd9Sstevel@tonic-gate } 51237c478bd9Sstevel@tonic-gate 51247c478bd9Sstevel@tonic-gate /* 51257c478bd9Sstevel@tonic-gate * Empty all the messages on a syncq. 51267c478bd9Sstevel@tonic-gate * 512721804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 51287c478bd9Sstevel@tonic-gate * sq_putlocks are used. 51297c478bd9Sstevel@tonic-gate */ 51307c478bd9Sstevel@tonic-gate static void 51317c478bd9Sstevel@tonic-gate emptysq(syncq_t *sq) 51327c478bd9Sstevel@tonic-gate { 51337c478bd9Sstevel@tonic-gate uint16_t flags; 51347c478bd9Sstevel@tonic-gate 51357c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 51367c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 51377c478bd9Sstevel@tonic-gate if ((flags & SQ_QUEUED) && !(flags & (SQ_STAYAWAY|SQ_EXCL))) { 51387c478bd9Sstevel@tonic-gate /* 51397c478bd9Sstevel@tonic-gate * To prevent potential recursive invocation of drain_syncq we 51407c478bd9Sstevel@tonic-gate * do not call drain_syncq if count is non-zero. 51417c478bd9Sstevel@tonic-gate */ 51427c478bd9Sstevel@tonic-gate if (sq->sq_count == 0) { 51437c478bd9Sstevel@tonic-gate /* drain_syncq() drops SQLOCK */ 51447c478bd9Sstevel@tonic-gate drain_syncq(sq); 51457c478bd9Sstevel@tonic-gate return; 51467c478bd9Sstevel@tonic-gate } else 51477c478bd9Sstevel@tonic-gate sqenable(sq); 51487c478bd9Sstevel@tonic-gate } 51497c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 51507c478bd9Sstevel@tonic-gate } 51517c478bd9Sstevel@tonic-gate 51527c478bd9Sstevel@tonic-gate /* 51537c478bd9Sstevel@tonic-gate * Ordered insert while removing duplicates. 51547c478bd9Sstevel@tonic-gate */ 51557c478bd9Sstevel@tonic-gate static void 51567c478bd9Sstevel@tonic-gate sqlist_insert(sqlist_t *sqlist, syncq_t *sqp) 51577c478bd9Sstevel@tonic-gate { 51587c478bd9Sstevel@tonic-gate syncql_t *sqlp, **prev_sqlpp, *new_sqlp; 51597c478bd9Sstevel@tonic-gate 51607c478bd9Sstevel@tonic-gate prev_sqlpp = &sqlist->sqlist_head; 51617c478bd9Sstevel@tonic-gate while ((sqlp = *prev_sqlpp) != NULL) { 51627c478bd9Sstevel@tonic-gate if (sqlp->sql_sq >= sqp) { 51637c478bd9Sstevel@tonic-gate if (sqlp->sql_sq == sqp) /* duplicate */ 51647c478bd9Sstevel@tonic-gate return; 51657c478bd9Sstevel@tonic-gate break; 51667c478bd9Sstevel@tonic-gate } 51677c478bd9Sstevel@tonic-gate prev_sqlpp = &sqlp->sql_next; 51687c478bd9Sstevel@tonic-gate } 51697c478bd9Sstevel@tonic-gate new_sqlp = &sqlist->sqlist_array[sqlist->sqlist_index++]; 51707c478bd9Sstevel@tonic-gate ASSERT((char *)new_sqlp < (char *)sqlist + sqlist->sqlist_size); 51717c478bd9Sstevel@tonic-gate new_sqlp->sql_next = sqlp; 51727c478bd9Sstevel@tonic-gate new_sqlp->sql_sq = sqp; 51737c478bd9Sstevel@tonic-gate *prev_sqlpp = new_sqlp; 51747c478bd9Sstevel@tonic-gate } 51757c478bd9Sstevel@tonic-gate 51767c478bd9Sstevel@tonic-gate /* 51777c478bd9Sstevel@tonic-gate * Walk the write side queues until we hit either the driver 51787c478bd9Sstevel@tonic-gate * or a twist in the stream (_SAMESTR will return false in both 51797c478bd9Sstevel@tonic-gate * these cases) then turn around and walk the read side queues 51807c478bd9Sstevel@tonic-gate * back up to the stream head. 51817c478bd9Sstevel@tonic-gate */ 51827c478bd9Sstevel@tonic-gate static void 51837c478bd9Sstevel@tonic-gate sqlist_insertall(sqlist_t *sqlist, queue_t *q) 51847c478bd9Sstevel@tonic-gate { 51857c478bd9Sstevel@tonic-gate while (q != NULL) { 51867c478bd9Sstevel@tonic-gate sqlist_insert(sqlist, q->q_syncq); 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate if (_SAMESTR(q)) 51897c478bd9Sstevel@tonic-gate q = q->q_next; 51907c478bd9Sstevel@tonic-gate else if (!(q->q_flag & QREADR)) 51917c478bd9Sstevel@tonic-gate q = _RD(q); 51927c478bd9Sstevel@tonic-gate else 51937c478bd9Sstevel@tonic-gate q = NULL; 51947c478bd9Sstevel@tonic-gate } 51957c478bd9Sstevel@tonic-gate } 51967c478bd9Sstevel@tonic-gate 51977c478bd9Sstevel@tonic-gate /* 51987c478bd9Sstevel@tonic-gate * Allocate and build a list of all syncqs in a stream and the syncq(s) 51997c478bd9Sstevel@tonic-gate * associated with the "q" parameter. The resulting list is sorted in a 52007c478bd9Sstevel@tonic-gate * canonical order and is free of duplicates. 52017c478bd9Sstevel@tonic-gate * Assumes the passed queue is a _RD(q). 52027c478bd9Sstevel@tonic-gate */ 52037c478bd9Sstevel@tonic-gate static sqlist_t * 52047c478bd9Sstevel@tonic-gate sqlist_build(queue_t *q, struct stdata *stp, boolean_t do_twist) 52057c478bd9Sstevel@tonic-gate { 52067c478bd9Sstevel@tonic-gate sqlist_t *sqlist = sqlist_alloc(stp, KM_SLEEP); 52077c478bd9Sstevel@tonic-gate 52087c478bd9Sstevel@tonic-gate /* 52097c478bd9Sstevel@tonic-gate * start with the current queue/qpair 52107c478bd9Sstevel@tonic-gate */ 52117c478bd9Sstevel@tonic-gate ASSERT(q->q_flag & QREADR); 52127c478bd9Sstevel@tonic-gate 52137c478bd9Sstevel@tonic-gate sqlist_insert(sqlist, q->q_syncq); 52147c478bd9Sstevel@tonic-gate sqlist_insert(sqlist, _WR(q)->q_syncq); 52157c478bd9Sstevel@tonic-gate 52167c478bd9Sstevel@tonic-gate sqlist_insertall(sqlist, stp->sd_wrq); 52177c478bd9Sstevel@tonic-gate if (do_twist) 52187c478bd9Sstevel@tonic-gate sqlist_insertall(sqlist, stp->sd_mate->sd_wrq); 52197c478bd9Sstevel@tonic-gate 52207c478bd9Sstevel@tonic-gate return (sqlist); 52217c478bd9Sstevel@tonic-gate } 52227c478bd9Sstevel@tonic-gate 52237c478bd9Sstevel@tonic-gate static sqlist_t * 52247c478bd9Sstevel@tonic-gate sqlist_alloc(struct stdata *stp, int kmflag) 52257c478bd9Sstevel@tonic-gate { 52267c478bd9Sstevel@tonic-gate size_t sqlist_size; 52277c478bd9Sstevel@tonic-gate sqlist_t *sqlist; 52287c478bd9Sstevel@tonic-gate 52297c478bd9Sstevel@tonic-gate /* 52307c478bd9Sstevel@tonic-gate * Allocate 2 syncql_t's for each pushed module. Note that 52317c478bd9Sstevel@tonic-gate * the sqlist_t structure already has 4 syncql_t's built in: 52327c478bd9Sstevel@tonic-gate * 2 for the stream head, and 2 for the driver/other stream head. 52337c478bd9Sstevel@tonic-gate */ 52347c478bd9Sstevel@tonic-gate sqlist_size = 2 * sizeof (syncql_t) * stp->sd_pushcnt + 52357c478bd9Sstevel@tonic-gate sizeof (sqlist_t); 52367c478bd9Sstevel@tonic-gate if (STRMATED(stp)) 52377c478bd9Sstevel@tonic-gate sqlist_size += 2 * sizeof (syncql_t) * stp->sd_mate->sd_pushcnt; 52387c478bd9Sstevel@tonic-gate sqlist = kmem_alloc(sqlist_size, kmflag); 52397c478bd9Sstevel@tonic-gate 52407c478bd9Sstevel@tonic-gate sqlist->sqlist_head = NULL; 52417c478bd9Sstevel@tonic-gate sqlist->sqlist_size = sqlist_size; 52427c478bd9Sstevel@tonic-gate sqlist->sqlist_index = 0; 52437c478bd9Sstevel@tonic-gate 52447c478bd9Sstevel@tonic-gate return (sqlist); 52457c478bd9Sstevel@tonic-gate } 52467c478bd9Sstevel@tonic-gate 52477c478bd9Sstevel@tonic-gate /* 52487c478bd9Sstevel@tonic-gate * Free the list created by sqlist_alloc() 52497c478bd9Sstevel@tonic-gate */ 52507c478bd9Sstevel@tonic-gate static void 52517c478bd9Sstevel@tonic-gate sqlist_free(sqlist_t *sqlist) 52527c478bd9Sstevel@tonic-gate { 52537c478bd9Sstevel@tonic-gate kmem_free(sqlist, sqlist->sqlist_size); 52547c478bd9Sstevel@tonic-gate } 52557c478bd9Sstevel@tonic-gate 52567c478bd9Sstevel@tonic-gate /* 52577c478bd9Sstevel@tonic-gate * Prevent any new entries into any syncq in this stream. 52587c478bd9Sstevel@tonic-gate * Used by freezestr. 52597c478bd9Sstevel@tonic-gate */ 52607c478bd9Sstevel@tonic-gate void 52617c478bd9Sstevel@tonic-gate strblock(queue_t *q) 52627c478bd9Sstevel@tonic-gate { 52637c478bd9Sstevel@tonic-gate struct stdata *stp; 52647c478bd9Sstevel@tonic-gate syncql_t *sql; 52657c478bd9Sstevel@tonic-gate sqlist_t *sqlist; 52667c478bd9Sstevel@tonic-gate 52677c478bd9Sstevel@tonic-gate q = _RD(q); 52687c478bd9Sstevel@tonic-gate 52697c478bd9Sstevel@tonic-gate stp = STREAM(q); 52707c478bd9Sstevel@tonic-gate ASSERT(stp != NULL); 52717c478bd9Sstevel@tonic-gate 52727c478bd9Sstevel@tonic-gate /* 52737c478bd9Sstevel@tonic-gate * Get a sorted list with all the duplicates removed containing 52747c478bd9Sstevel@tonic-gate * all the syncqs referenced by this stream. 52757c478bd9Sstevel@tonic-gate */ 52767c478bd9Sstevel@tonic-gate sqlist = sqlist_build(q, stp, B_FALSE); 52777c478bd9Sstevel@tonic-gate for (sql = sqlist->sqlist_head; sql != NULL; sql = sql->sql_next) 52787c478bd9Sstevel@tonic-gate blocksq(sql->sql_sq, SQ_FROZEN, -1); 52797c478bd9Sstevel@tonic-gate sqlist_free(sqlist); 52807c478bd9Sstevel@tonic-gate } 52817c478bd9Sstevel@tonic-gate 52827c478bd9Sstevel@tonic-gate /* 52837c478bd9Sstevel@tonic-gate * Release the block on new entries into this stream 52847c478bd9Sstevel@tonic-gate */ 52857c478bd9Sstevel@tonic-gate void 52867c478bd9Sstevel@tonic-gate strunblock(queue_t *q) 52877c478bd9Sstevel@tonic-gate { 52887c478bd9Sstevel@tonic-gate struct stdata *stp; 52897c478bd9Sstevel@tonic-gate syncql_t *sql; 52907c478bd9Sstevel@tonic-gate sqlist_t *sqlist; 52917c478bd9Sstevel@tonic-gate int drain_needed; 52927c478bd9Sstevel@tonic-gate 52937c478bd9Sstevel@tonic-gate q = _RD(q); 52947c478bd9Sstevel@tonic-gate 52957c478bd9Sstevel@tonic-gate /* 52967c478bd9Sstevel@tonic-gate * Get a sorted list with all the duplicates removed containing 52977c478bd9Sstevel@tonic-gate * all the syncqs referenced by this stream. 52987c478bd9Sstevel@tonic-gate * Have to drop the SQ_FROZEN flag on all the syncqs before 52997c478bd9Sstevel@tonic-gate * starting to drain them; otherwise the draining might 53007c478bd9Sstevel@tonic-gate * cause a freezestr in some module on the stream (which 530121804b56SBrian Ruthven * would deadlock). 53027c478bd9Sstevel@tonic-gate */ 53037c478bd9Sstevel@tonic-gate stp = STREAM(q); 53047c478bd9Sstevel@tonic-gate ASSERT(stp != NULL); 53057c478bd9Sstevel@tonic-gate sqlist = sqlist_build(q, stp, B_FALSE); 53067c478bd9Sstevel@tonic-gate drain_needed = 0; 53077c478bd9Sstevel@tonic-gate for (sql = sqlist->sqlist_head; sql != NULL; sql = sql->sql_next) 53087c478bd9Sstevel@tonic-gate drain_needed += dropsq(sql->sql_sq, SQ_FROZEN); 53097c478bd9Sstevel@tonic-gate if (drain_needed) { 53107c478bd9Sstevel@tonic-gate for (sql = sqlist->sqlist_head; sql != NULL; 53117c478bd9Sstevel@tonic-gate sql = sql->sql_next) 53127c478bd9Sstevel@tonic-gate emptysq(sql->sql_sq); 53137c478bd9Sstevel@tonic-gate } 53147c478bd9Sstevel@tonic-gate sqlist_free(sqlist); 53157c478bd9Sstevel@tonic-gate } 53167c478bd9Sstevel@tonic-gate 53177c478bd9Sstevel@tonic-gate #ifdef DEBUG 53187c478bd9Sstevel@tonic-gate static int 53197c478bd9Sstevel@tonic-gate qprocsareon(queue_t *rq) 53207c478bd9Sstevel@tonic-gate { 53217c478bd9Sstevel@tonic-gate if (rq->q_next == NULL) 53227c478bd9Sstevel@tonic-gate return (0); 53237c478bd9Sstevel@tonic-gate return (_WR(rq->q_next)->q_next == _WR(rq)); 53247c478bd9Sstevel@tonic-gate } 53257c478bd9Sstevel@tonic-gate 53267c478bd9Sstevel@tonic-gate int 53277c478bd9Sstevel@tonic-gate qclaimed(queue_t *q) 53287c478bd9Sstevel@tonic-gate { 53297c478bd9Sstevel@tonic-gate uint_t count; 53307c478bd9Sstevel@tonic-gate 53317c478bd9Sstevel@tonic-gate count = q->q_syncq->sq_count; 53327c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(q->q_syncq, count); 53337c478bd9Sstevel@tonic-gate return (count != 0); 53347c478bd9Sstevel@tonic-gate } 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate /* 53377c478bd9Sstevel@tonic-gate * Check if anyone has frozen this stream with freezestr 53387c478bd9Sstevel@tonic-gate */ 53397c478bd9Sstevel@tonic-gate int 53407c478bd9Sstevel@tonic-gate frozenstr(queue_t *q) 53417c478bd9Sstevel@tonic-gate { 53427c478bd9Sstevel@tonic-gate return ((q->q_syncq->sq_flags & SQ_FROZEN) != 0); 53437c478bd9Sstevel@tonic-gate } 53447c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 53457c478bd9Sstevel@tonic-gate 53467c478bd9Sstevel@tonic-gate /* 53477c478bd9Sstevel@tonic-gate * Enter a queue. 53487c478bd9Sstevel@tonic-gate * Obsoleted interface. Should not be used. 53497c478bd9Sstevel@tonic-gate */ 53507c478bd9Sstevel@tonic-gate void 53517c478bd9Sstevel@tonic-gate enterq(queue_t *q) 53527c478bd9Sstevel@tonic-gate { 53537c478bd9Sstevel@tonic-gate entersq(q->q_syncq, SQ_CALLBACK); 53547c478bd9Sstevel@tonic-gate } 53557c478bd9Sstevel@tonic-gate 53567c478bd9Sstevel@tonic-gate void 53577c478bd9Sstevel@tonic-gate leaveq(queue_t *q) 53587c478bd9Sstevel@tonic-gate { 53597c478bd9Sstevel@tonic-gate leavesq(q->q_syncq, SQ_CALLBACK); 53607c478bd9Sstevel@tonic-gate } 53617c478bd9Sstevel@tonic-gate 53627c478bd9Sstevel@tonic-gate /* 53637c478bd9Sstevel@tonic-gate * Enter a perimeter. c_inner and c_outer specifies which concurrency bits 53647c478bd9Sstevel@tonic-gate * to check. 53657c478bd9Sstevel@tonic-gate * Wait if SQ_QUEUED is set to preserve ordering between messages and qwriter 53667c478bd9Sstevel@tonic-gate * calls and the running of open, close and service procedures. 53677c478bd9Sstevel@tonic-gate * 536821804b56SBrian Ruthven * If c_inner bit is set no need to grab sq_putlocks since we don't care 53697c478bd9Sstevel@tonic-gate * if other threads have entered or are entering put entry point. 53707c478bd9Sstevel@tonic-gate * 537121804b56SBrian Ruthven * If c_inner bit is set it might have been possible to use 53727c478bd9Sstevel@tonic-gate * sq_putlocks/sq_putcounts instead of SQLOCK/sq_count (e.g. to optimize 53737c478bd9Sstevel@tonic-gate * open/close path for IP) but since the count may need to be decremented in 53747c478bd9Sstevel@tonic-gate * qwait() we wouldn't know which counter to decrement. Currently counter is 53757c478bd9Sstevel@tonic-gate * selected by current cpu_seqid and current CPU can change at any moment. XXX 53767c478bd9Sstevel@tonic-gate * in the future we might use curthread id bits to select the counter and this 53777c478bd9Sstevel@tonic-gate * would stay constant across routine calls. 53787c478bd9Sstevel@tonic-gate */ 53797c478bd9Sstevel@tonic-gate void 53807c478bd9Sstevel@tonic-gate entersq(syncq_t *sq, int entrypoint) 53817c478bd9Sstevel@tonic-gate { 53827c478bd9Sstevel@tonic-gate uint16_t count = 0; 53837c478bd9Sstevel@tonic-gate uint16_t flags; 53847c478bd9Sstevel@tonic-gate uint16_t waitflags = SQ_STAYAWAY | SQ_EVENTS | SQ_EXCL; 53857c478bd9Sstevel@tonic-gate uint16_t type; 53867c478bd9Sstevel@tonic-gate uint_t c_inner = entrypoint & SQ_CI; 53877c478bd9Sstevel@tonic-gate uint_t c_outer = entrypoint & SQ_CO; 53887c478bd9Sstevel@tonic-gate 53897c478bd9Sstevel@tonic-gate /* 53907c478bd9Sstevel@tonic-gate * Increment ref count to keep closes out of this queue. 53917c478bd9Sstevel@tonic-gate */ 53927c478bd9Sstevel@tonic-gate ASSERT(sq); 53937c478bd9Sstevel@tonic-gate ASSERT(c_inner && c_outer); 53947c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 53957c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 53967c478bd9Sstevel@tonic-gate type = sq->sq_type; 53977c478bd9Sstevel@tonic-gate if (!(type & c_inner)) { 53987c478bd9Sstevel@tonic-gate /* Make sure all putcounts now use slowlock. */ 53997c478bd9Sstevel@tonic-gate count = sq->sq_count; 54007c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 54017c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_CLRFAST_LOCKED(sq); 54027c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 54037c478bd9Sstevel@tonic-gate sq->sq_needexcl++; 54047c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl != 0); /* wraparound */ 54057c478bd9Sstevel@tonic-gate waitflags |= SQ_MESSAGES; 54067c478bd9Sstevel@tonic-gate } 54077c478bd9Sstevel@tonic-gate /* 54087c478bd9Sstevel@tonic-gate * Wait until we can enter the inner perimeter. 54097c478bd9Sstevel@tonic-gate * If we want exclusive access we wait until sq_count is 0. 54107c478bd9Sstevel@tonic-gate * We have to do this before entering the outer perimeter in order 54117c478bd9Sstevel@tonic-gate * to preserve put/close message ordering. 54127c478bd9Sstevel@tonic-gate */ 54137c478bd9Sstevel@tonic-gate while ((flags & waitflags) || (!(type & c_inner) && count != 0)) { 54147c478bd9Sstevel@tonic-gate sq->sq_flags = flags | SQ_WANTWAKEUP; 54157c478bd9Sstevel@tonic-gate if (!(type & c_inner)) { 54167c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 54177c478bd9Sstevel@tonic-gate } 54187c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 54197c478bd9Sstevel@tonic-gate if (!(type & c_inner)) { 54207c478bd9Sstevel@tonic-gate count = sq->sq_count; 54217c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 54227c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 54237c478bd9Sstevel@tonic-gate } 54247c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 54257c478bd9Sstevel@tonic-gate } 54267c478bd9Sstevel@tonic-gate 54277c478bd9Sstevel@tonic-gate if (!(type & c_inner)) { 54287c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl > 0); 54297c478bd9Sstevel@tonic-gate sq->sq_needexcl--; 54307c478bd9Sstevel@tonic-gate if (sq->sq_needexcl == 0) { 54317c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_SETFAST_LOCKED(sq); 54327c478bd9Sstevel@tonic-gate } 54337c478bd9Sstevel@tonic-gate } 54347c478bd9Sstevel@tonic-gate 54357c478bd9Sstevel@tonic-gate /* Check if we need to enter the outer perimeter */ 54367c478bd9Sstevel@tonic-gate if (!(type & c_outer)) { 54377c478bd9Sstevel@tonic-gate /* 54387c478bd9Sstevel@tonic-gate * We have to enter the outer perimeter exclusively before 54397c478bd9Sstevel@tonic-gate * we can increment sq_count to avoid deadlock. This implies 54407c478bd9Sstevel@tonic-gate * that we have to re-check sq_flags and sq_count. 54417c478bd9Sstevel@tonic-gate * 54427c478bd9Sstevel@tonic-gate * is it possible to have c_inner set when c_outer is not set? 54437c478bd9Sstevel@tonic-gate */ 54447c478bd9Sstevel@tonic-gate if (!(type & c_inner)) { 54457c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 54467c478bd9Sstevel@tonic-gate } 54477c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 54487c478bd9Sstevel@tonic-gate outer_enter(sq->sq_outer, SQ_GOAWAY); 54497c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 54507c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 54517c478bd9Sstevel@tonic-gate /* 54527c478bd9Sstevel@tonic-gate * there should be no need to recheck sq_putcounts 54537c478bd9Sstevel@tonic-gate * because outer_enter() has already waited for them to clear 54547c478bd9Sstevel@tonic-gate * after setting SQ_WRITER. 54557c478bd9Sstevel@tonic-gate */ 54567c478bd9Sstevel@tonic-gate count = sq->sq_count; 54577c478bd9Sstevel@tonic-gate #ifdef DEBUG 54587c478bd9Sstevel@tonic-gate /* 54597c478bd9Sstevel@tonic-gate * SUMCHECK_SQ_PUTCOUNTS should return the sum instead 54607c478bd9Sstevel@tonic-gate * of doing an ASSERT internally. Others should do 54617c478bd9Sstevel@tonic-gate * something like 54627c478bd9Sstevel@tonic-gate * ASSERT(SUMCHECK_SQ_PUTCOUNTS(sq) == 0); 54637c478bd9Sstevel@tonic-gate * without the need to #ifdef DEBUG it. 54647c478bd9Sstevel@tonic-gate */ 54657c478bd9Sstevel@tonic-gate SUMCHECK_SQ_PUTCOUNTS(sq, 0); 54667c478bd9Sstevel@tonic-gate #endif 54677c478bd9Sstevel@tonic-gate while ((flags & (SQ_EXCL|SQ_BLOCKED|SQ_FROZEN)) || 54687c478bd9Sstevel@tonic-gate (!(type & c_inner) && count != 0)) { 54697c478bd9Sstevel@tonic-gate sq->sq_flags = flags | SQ_WANTWAKEUP; 54707c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 54717c478bd9Sstevel@tonic-gate count = sq->sq_count; 54727c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 54737c478bd9Sstevel@tonic-gate } 54747c478bd9Sstevel@tonic-gate } 54757c478bd9Sstevel@tonic-gate 54767c478bd9Sstevel@tonic-gate sq->sq_count++; 54777c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); /* Wraparound */ 54787c478bd9Sstevel@tonic-gate if (!(type & c_inner)) { 54797c478bd9Sstevel@tonic-gate /* Exclusive entry */ 54807c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count == 1); 54817c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 54827c478bd9Sstevel@tonic-gate if (type & c_outer) { 54837c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 54847c478bd9Sstevel@tonic-gate } 54857c478bd9Sstevel@tonic-gate } 54867c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 54877c478bd9Sstevel@tonic-gate } 54887c478bd9Sstevel@tonic-gate 54897c478bd9Sstevel@tonic-gate /* 549021804b56SBrian Ruthven * Leave a syncq. Announce to framework that closes may proceed. 549121804b56SBrian Ruthven * c_inner and c_outer specify which concurrency bits to check. 54927c478bd9Sstevel@tonic-gate * 549321804b56SBrian Ruthven * Must never be called from driver or module put entry point. 54947c478bd9Sstevel@tonic-gate * 549521804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 54967c478bd9Sstevel@tonic-gate * sq_putlocks are used. 54977c478bd9Sstevel@tonic-gate */ 54987c478bd9Sstevel@tonic-gate void 54997c478bd9Sstevel@tonic-gate leavesq(syncq_t *sq, int entrypoint) 55007c478bd9Sstevel@tonic-gate { 55017c478bd9Sstevel@tonic-gate uint16_t flags; 55027c478bd9Sstevel@tonic-gate uint16_t type; 55037c478bd9Sstevel@tonic-gate uint_t c_outer = entrypoint & SQ_CO; 55047c478bd9Sstevel@tonic-gate #ifdef DEBUG 55057c478bd9Sstevel@tonic-gate uint_t c_inner = entrypoint & SQ_CI; 55067c478bd9Sstevel@tonic-gate #endif 55077c478bd9Sstevel@tonic-gate 55087c478bd9Sstevel@tonic-gate /* 550921804b56SBrian Ruthven * Decrement ref count, drain the syncq if possible, and wake up 55107c478bd9Sstevel@tonic-gate * any waiting close. 55117c478bd9Sstevel@tonic-gate */ 55127c478bd9Sstevel@tonic-gate ASSERT(sq); 55137c478bd9Sstevel@tonic-gate ASSERT(c_inner && c_outer); 55147c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 55157c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 55167c478bd9Sstevel@tonic-gate type = sq->sq_type; 55177c478bd9Sstevel@tonic-gate if (flags & (SQ_QUEUED|SQ_WANTWAKEUP|SQ_WANTEXWAKEUP)) { 55187c478bd9Sstevel@tonic-gate 55197c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 55207c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 55217c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 55227c478bd9Sstevel@tonic-gate } 55237c478bd9Sstevel@tonic-gate if (flags & SQ_WANTEXWAKEUP) { 55247c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTEXWAKEUP; 55257c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_exitwait); 55267c478bd9Sstevel@tonic-gate } 55277c478bd9Sstevel@tonic-gate 55287c478bd9Sstevel@tonic-gate if ((flags & SQ_QUEUED) && !(flags & SQ_STAYAWAY)) { 55297c478bd9Sstevel@tonic-gate /* 55307c478bd9Sstevel@tonic-gate * The syncq needs to be drained. "Exit" the syncq 55317c478bd9Sstevel@tonic-gate * before calling drain_syncq. 55327c478bd9Sstevel@tonic-gate */ 55337c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); 55347c478bd9Sstevel@tonic-gate sq->sq_count--; 55357c478bd9Sstevel@tonic-gate ASSERT((flags & SQ_EXCL) || (type & c_inner)); 55367c478bd9Sstevel@tonic-gate sq->sq_flags = flags & ~SQ_EXCL; 55377c478bd9Sstevel@tonic-gate drain_syncq(sq); 55387c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 55397c478bd9Sstevel@tonic-gate /* Check if we need to exit the outer perimeter */ 55407c478bd9Sstevel@tonic-gate /* XXX will this ever be true? */ 55417c478bd9Sstevel@tonic-gate if (!(type & c_outer)) 55427c478bd9Sstevel@tonic-gate outer_exit(sq->sq_outer); 55437c478bd9Sstevel@tonic-gate return; 55447c478bd9Sstevel@tonic-gate } 55457c478bd9Sstevel@tonic-gate } 55467c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); 55477c478bd9Sstevel@tonic-gate sq->sq_count--; 55487c478bd9Sstevel@tonic-gate ASSERT((flags & SQ_EXCL) || (type & c_inner)); 55497c478bd9Sstevel@tonic-gate sq->sq_flags = flags & ~SQ_EXCL; 55507c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 55517c478bd9Sstevel@tonic-gate 55527c478bd9Sstevel@tonic-gate /* Check if we need to exit the outer perimeter */ 55537c478bd9Sstevel@tonic-gate if (!(sq->sq_type & c_outer)) 55547c478bd9Sstevel@tonic-gate outer_exit(sq->sq_outer); 55557c478bd9Sstevel@tonic-gate } 55567c478bd9Sstevel@tonic-gate 55577c478bd9Sstevel@tonic-gate /* 55587c478bd9Sstevel@tonic-gate * Prevent q_next from changing in this stream by incrementing sq_count. 55597c478bd9Sstevel@tonic-gate * 556021804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 55617c478bd9Sstevel@tonic-gate * sq_putlocks are used. 55627c478bd9Sstevel@tonic-gate */ 55637c478bd9Sstevel@tonic-gate void 55647c478bd9Sstevel@tonic-gate claimq(queue_t *qp) 55657c478bd9Sstevel@tonic-gate { 55667c478bd9Sstevel@tonic-gate syncq_t *sq = qp->q_syncq; 55677c478bd9Sstevel@tonic-gate 55687c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 55697c478bd9Sstevel@tonic-gate sq->sq_count++; 55707c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); /* Wraparound */ 55717c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 55727c478bd9Sstevel@tonic-gate } 55737c478bd9Sstevel@tonic-gate 55747c478bd9Sstevel@tonic-gate /* 55757c478bd9Sstevel@tonic-gate * Undo claimq. 55767c478bd9Sstevel@tonic-gate * 557721804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 55787c478bd9Sstevel@tonic-gate * sq_putlocks are used. 55797c478bd9Sstevel@tonic-gate */ 55807c478bd9Sstevel@tonic-gate void 55817c478bd9Sstevel@tonic-gate releaseq(queue_t *qp) 55827c478bd9Sstevel@tonic-gate { 55837c478bd9Sstevel@tonic-gate syncq_t *sq = qp->q_syncq; 55847c478bd9Sstevel@tonic-gate uint16_t flags; 55857c478bd9Sstevel@tonic-gate 55867c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 55877c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count > 0); 55887c478bd9Sstevel@tonic-gate sq->sq_count--; 55897c478bd9Sstevel@tonic-gate 55907c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 55917c478bd9Sstevel@tonic-gate if (flags & (SQ_WANTWAKEUP|SQ_QUEUED)) { 55927c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 55937c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 55947c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 55957c478bd9Sstevel@tonic-gate } 55967c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 55977c478bd9Sstevel@tonic-gate if ((flags & SQ_QUEUED) && !(flags & (SQ_STAYAWAY|SQ_EXCL))) { 55987c478bd9Sstevel@tonic-gate /* 55997c478bd9Sstevel@tonic-gate * To prevent potential recursive invocation of 56007c478bd9Sstevel@tonic-gate * drain_syncq we do not call drain_syncq if count is 56017c478bd9Sstevel@tonic-gate * non-zero. 56027c478bd9Sstevel@tonic-gate */ 56037c478bd9Sstevel@tonic-gate if (sq->sq_count == 0) { 56047c478bd9Sstevel@tonic-gate drain_syncq(sq); 56057c478bd9Sstevel@tonic-gate return; 56067c478bd9Sstevel@tonic-gate } else 56077c478bd9Sstevel@tonic-gate sqenable(sq); 56087c478bd9Sstevel@tonic-gate } 56097c478bd9Sstevel@tonic-gate } 56107c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 56117c478bd9Sstevel@tonic-gate } 56127c478bd9Sstevel@tonic-gate 56137c478bd9Sstevel@tonic-gate /* 56147c478bd9Sstevel@tonic-gate * Prevent q_next from changing in this stream by incrementing sd_refcnt. 56157c478bd9Sstevel@tonic-gate */ 56167c478bd9Sstevel@tonic-gate void 56177c478bd9Sstevel@tonic-gate claimstr(queue_t *qp) 56187c478bd9Sstevel@tonic-gate { 56197c478bd9Sstevel@tonic-gate struct stdata *stp = STREAM(qp); 56207c478bd9Sstevel@tonic-gate 56217c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_reflock); 56227c478bd9Sstevel@tonic-gate stp->sd_refcnt++; 56237c478bd9Sstevel@tonic-gate ASSERT(stp->sd_refcnt != 0); /* Wraparound */ 56247c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 56257c478bd9Sstevel@tonic-gate } 56267c478bd9Sstevel@tonic-gate 56277c478bd9Sstevel@tonic-gate /* 56287c478bd9Sstevel@tonic-gate * Undo claimstr. 56297c478bd9Sstevel@tonic-gate */ 56307c478bd9Sstevel@tonic-gate void 56317c478bd9Sstevel@tonic-gate releasestr(queue_t *qp) 56327c478bd9Sstevel@tonic-gate { 56337c478bd9Sstevel@tonic-gate struct stdata *stp = STREAM(qp); 56347c478bd9Sstevel@tonic-gate 56357c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_reflock); 56367c478bd9Sstevel@tonic-gate ASSERT(stp->sd_refcnt != 0); 56376829c646Sxy158873 if (--stp->sd_refcnt == 0) 56386829c646Sxy158873 cv_broadcast(&stp->sd_refmonitor); 56397c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_reflock); 56407c478bd9Sstevel@tonic-gate } 56417c478bd9Sstevel@tonic-gate 56427c478bd9Sstevel@tonic-gate static syncq_t * 56437c478bd9Sstevel@tonic-gate new_syncq(void) 56447c478bd9Sstevel@tonic-gate { 56457c478bd9Sstevel@tonic-gate return (kmem_cache_alloc(syncq_cache, KM_SLEEP)); 56467c478bd9Sstevel@tonic-gate } 56477c478bd9Sstevel@tonic-gate 56487c478bd9Sstevel@tonic-gate static void 56497c478bd9Sstevel@tonic-gate free_syncq(syncq_t *sq) 56507c478bd9Sstevel@tonic-gate { 56517c478bd9Sstevel@tonic-gate ASSERT(sq->sq_head == NULL); 56527c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL); 56537c478bd9Sstevel@tonic-gate ASSERT(sq->sq_callbpend == NULL); 56547c478bd9Sstevel@tonic-gate ASSERT((sq->sq_onext == NULL && sq->sq_oprev == NULL) || 56557c478bd9Sstevel@tonic-gate (sq->sq_onext == sq && sq->sq_oprev == sq)); 56567c478bd9Sstevel@tonic-gate 56577c478bd9Sstevel@tonic-gate if (sq->sq_ciputctrl != NULL) { 56587c478bd9Sstevel@tonic-gate ASSERT(sq->sq_nciputctrl == n_ciputctrl - 1); 56597c478bd9Sstevel@tonic-gate SUMCHECK_CIPUTCTRL_COUNTS(sq->sq_ciputctrl, 56607c478bd9Sstevel@tonic-gate sq->sq_nciputctrl, 0); 56617c478bd9Sstevel@tonic-gate ASSERT(ciputctrl_cache != NULL); 56627c478bd9Sstevel@tonic-gate kmem_cache_free(ciputctrl_cache, sq->sq_ciputctrl); 56637c478bd9Sstevel@tonic-gate } 56647c478bd9Sstevel@tonic-gate 56657c478bd9Sstevel@tonic-gate sq->sq_tail = NULL; 56667c478bd9Sstevel@tonic-gate sq->sq_evhead = NULL; 56677c478bd9Sstevel@tonic-gate sq->sq_evtail = NULL; 56687c478bd9Sstevel@tonic-gate sq->sq_ciputctrl = NULL; 56697c478bd9Sstevel@tonic-gate sq->sq_nciputctrl = 0; 56707c478bd9Sstevel@tonic-gate sq->sq_count = 0; 56717c478bd9Sstevel@tonic-gate sq->sq_rmqcount = 0; 56727c478bd9Sstevel@tonic-gate sq->sq_callbflags = 0; 56737c478bd9Sstevel@tonic-gate sq->sq_cancelid = 0; 56747c478bd9Sstevel@tonic-gate sq->sq_next = NULL; 56757c478bd9Sstevel@tonic-gate sq->sq_needexcl = 0; 56767c478bd9Sstevel@tonic-gate sq->sq_svcflags = 0; 56777c478bd9Sstevel@tonic-gate sq->sq_nqueues = 0; 56787c478bd9Sstevel@tonic-gate sq->sq_pri = 0; 56797c478bd9Sstevel@tonic-gate sq->sq_onext = NULL; 56807c478bd9Sstevel@tonic-gate sq->sq_oprev = NULL; 56817c478bd9Sstevel@tonic-gate sq->sq_flags = 0; 56827c478bd9Sstevel@tonic-gate sq->sq_type = 0; 56837c478bd9Sstevel@tonic-gate sq->sq_servcount = 0; 56847c478bd9Sstevel@tonic-gate 56857c478bd9Sstevel@tonic-gate kmem_cache_free(syncq_cache, sq); 56867c478bd9Sstevel@tonic-gate } 56877c478bd9Sstevel@tonic-gate 56887c478bd9Sstevel@tonic-gate /* Outer perimeter code */ 56897c478bd9Sstevel@tonic-gate 56907c478bd9Sstevel@tonic-gate /* 56917c478bd9Sstevel@tonic-gate * The outer syncq uses the fields and flags in the syncq slightly 56927c478bd9Sstevel@tonic-gate * differently from the inner syncqs. 56937c478bd9Sstevel@tonic-gate * sq_count Incremented when there are pending or running 56947c478bd9Sstevel@tonic-gate * writers at the outer perimeter to prevent the set of 56957c478bd9Sstevel@tonic-gate * inner syncqs that belong to the outer perimeter from 56967c478bd9Sstevel@tonic-gate * changing. 56977c478bd9Sstevel@tonic-gate * sq_head/tail List of deferred qwriter(OUTER) operations. 56987c478bd9Sstevel@tonic-gate * 56997c478bd9Sstevel@tonic-gate * SQ_BLOCKED Set to prevent traversing of sq_next,sq_prev while 57007c478bd9Sstevel@tonic-gate * inner syncqs are added to or removed from the 57017c478bd9Sstevel@tonic-gate * outer perimeter. 57027c478bd9Sstevel@tonic-gate * SQ_QUEUED sq_head/tail has messages or events queued. 57037c478bd9Sstevel@tonic-gate * 57047c478bd9Sstevel@tonic-gate * SQ_WRITER A thread is currently traversing all the inner syncqs 57057c478bd9Sstevel@tonic-gate * setting the SQ_WRITER flag. 57067c478bd9Sstevel@tonic-gate */ 57077c478bd9Sstevel@tonic-gate 57087c478bd9Sstevel@tonic-gate /* 57097c478bd9Sstevel@tonic-gate * Get write access at the outer perimeter. 57107c478bd9Sstevel@tonic-gate * Note that read access is done by entersq, putnext, and put by simply 57117c478bd9Sstevel@tonic-gate * incrementing sq_count in the inner syncq. 57127c478bd9Sstevel@tonic-gate * 57137c478bd9Sstevel@tonic-gate * Waits until "flags" is no longer set in the outer to prevent multiple 57147c478bd9Sstevel@tonic-gate * threads from having write access at the same time. SQ_WRITER has to be part 57157c478bd9Sstevel@tonic-gate * of "flags". 57167c478bd9Sstevel@tonic-gate * 57177c478bd9Sstevel@tonic-gate * Increases sq_count on the outer syncq to keep away outer_insert/remove 57187c478bd9Sstevel@tonic-gate * until the outer_exit is finished. 57197c478bd9Sstevel@tonic-gate * 57207c478bd9Sstevel@tonic-gate * outer_enter is vulnerable to starvation since it does not prevent new 57217c478bd9Sstevel@tonic-gate * threads from entering the inner syncqs while it is waiting for sq_count to 57227c478bd9Sstevel@tonic-gate * go to zero. 57237c478bd9Sstevel@tonic-gate */ 57247c478bd9Sstevel@tonic-gate void 57257c478bd9Sstevel@tonic-gate outer_enter(syncq_t *outer, uint16_t flags) 57267c478bd9Sstevel@tonic-gate { 57277c478bd9Sstevel@tonic-gate syncq_t *sq; 57287c478bd9Sstevel@tonic-gate int wait_needed; 57297c478bd9Sstevel@tonic-gate uint16_t count; 57307c478bd9Sstevel@tonic-gate 57317c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL && outer->sq_onext != NULL && 57327c478bd9Sstevel@tonic-gate outer->sq_oprev != NULL); 57337c478bd9Sstevel@tonic-gate ASSERT(flags & SQ_WRITER); 57347c478bd9Sstevel@tonic-gate 57357c478bd9Sstevel@tonic-gate retry: 57367c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 57377c478bd9Sstevel@tonic-gate while (outer->sq_flags & flags) { 57387c478bd9Sstevel@tonic-gate outer->sq_flags |= SQ_WANTWAKEUP; 57397c478bd9Sstevel@tonic-gate cv_wait(&outer->sq_wait, SQLOCK(outer)); 57407c478bd9Sstevel@tonic-gate } 57417c478bd9Sstevel@tonic-gate 57427c478bd9Sstevel@tonic-gate ASSERT(!(outer->sq_flags & SQ_WRITER)); 57437c478bd9Sstevel@tonic-gate outer->sq_flags |= SQ_WRITER; 57447c478bd9Sstevel@tonic-gate outer->sq_count++; 57457c478bd9Sstevel@tonic-gate ASSERT(outer->sq_count != 0); /* wraparound */ 57467c478bd9Sstevel@tonic-gate wait_needed = 0; 57477c478bd9Sstevel@tonic-gate /* 57487c478bd9Sstevel@tonic-gate * Set SQ_WRITER on all the inner syncqs while holding 57497c478bd9Sstevel@tonic-gate * the SQLOCK on the outer syncq. This ensures that the changing 57507c478bd9Sstevel@tonic-gate * of SQ_WRITER is atomic under the outer SQLOCK. 57517c478bd9Sstevel@tonic-gate */ 57527c478bd9Sstevel@tonic-gate for (sq = outer->sq_onext; sq != outer; sq = sq->sq_onext) { 57537c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 57547c478bd9Sstevel@tonic-gate count = sq->sq_count; 57557c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 57567c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WRITER; 57577c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 57587c478bd9Sstevel@tonic-gate if (count != 0) 57597c478bd9Sstevel@tonic-gate wait_needed = 1; 57607c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 57617c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 57627c478bd9Sstevel@tonic-gate } 57637c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 57647c478bd9Sstevel@tonic-gate 57657c478bd9Sstevel@tonic-gate /* 57667c478bd9Sstevel@tonic-gate * Get everybody out of the syncqs sequentially. 576721804b56SBrian Ruthven * Note that we don't actually need to acquire the PUTLOCKS, since 57687c478bd9Sstevel@tonic-gate * we have already cleared the fastbit, and set QWRITER. By 57697c478bd9Sstevel@tonic-gate * definition, the count can not increase since putnext will 577021804b56SBrian Ruthven * take the slowlock path (and the purpose of acquiring the 57717c478bd9Sstevel@tonic-gate * putlocks was to make sure it didn't increase while we were 57727c478bd9Sstevel@tonic-gate * waiting). 57737c478bd9Sstevel@tonic-gate * 577421804b56SBrian Ruthven * Note that we still acquire the PUTLOCKS to be safe. 57757c478bd9Sstevel@tonic-gate */ 57767c478bd9Sstevel@tonic-gate if (wait_needed) { 57777c478bd9Sstevel@tonic-gate for (sq = outer->sq_onext; sq != outer; sq = sq->sq_onext) { 57787c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 57797c478bd9Sstevel@tonic-gate count = sq->sq_count; 57807c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 57817c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 57827c478bd9Sstevel@tonic-gate while (count != 0) { 57837c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 57847c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 57857c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 57867c478bd9Sstevel@tonic-gate count = sq->sq_count; 57877c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 57887c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 57897c478bd9Sstevel@tonic-gate } 57907c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 57917c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 57927c478bd9Sstevel@tonic-gate } 57937c478bd9Sstevel@tonic-gate /* 57947c478bd9Sstevel@tonic-gate * Verify that none of the flags got set while we 57957c478bd9Sstevel@tonic-gate * were waiting for the sq_counts to drop. 57967c478bd9Sstevel@tonic-gate * If this happens we exit and retry entering the 57977c478bd9Sstevel@tonic-gate * outer perimeter. 57987c478bd9Sstevel@tonic-gate */ 57997c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 58007c478bd9Sstevel@tonic-gate if (outer->sq_flags & (flags & ~SQ_WRITER)) { 58017c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 58027c478bd9Sstevel@tonic-gate outer_exit(outer); 58037c478bd9Sstevel@tonic-gate goto retry; 58047c478bd9Sstevel@tonic-gate } 58057c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 58067c478bd9Sstevel@tonic-gate } 58077c478bd9Sstevel@tonic-gate } 58087c478bd9Sstevel@tonic-gate 58097c478bd9Sstevel@tonic-gate /* 58107c478bd9Sstevel@tonic-gate * Drop the write access at the outer perimeter. 58117c478bd9Sstevel@tonic-gate * Read access is dropped implicitly (by putnext, put, and leavesq) by 58127c478bd9Sstevel@tonic-gate * decrementing sq_count. 58137c478bd9Sstevel@tonic-gate */ 58147c478bd9Sstevel@tonic-gate void 58157c478bd9Sstevel@tonic-gate outer_exit(syncq_t *outer) 58167c478bd9Sstevel@tonic-gate { 58177c478bd9Sstevel@tonic-gate syncq_t *sq; 58187c478bd9Sstevel@tonic-gate int drain_needed; 58197c478bd9Sstevel@tonic-gate uint16_t flags; 58207c478bd9Sstevel@tonic-gate 58217c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL && outer->sq_onext != NULL && 58227c478bd9Sstevel@tonic-gate outer->sq_oprev != NULL); 58237c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(outer))); 58247c478bd9Sstevel@tonic-gate 58257c478bd9Sstevel@tonic-gate /* 58267c478bd9Sstevel@tonic-gate * Atomically (from the perspective of threads calling become_writer) 58277c478bd9Sstevel@tonic-gate * drop the write access at the outer perimeter by holding 58287c478bd9Sstevel@tonic-gate * SQLOCK(outer) across all the dropsq calls and the resetting of 58297c478bd9Sstevel@tonic-gate * SQ_WRITER. 58307c478bd9Sstevel@tonic-gate * This defines a locking order between the outer perimeter 58317c478bd9Sstevel@tonic-gate * SQLOCK and the inner perimeter SQLOCKs. 58327c478bd9Sstevel@tonic-gate */ 58337c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 58347c478bd9Sstevel@tonic-gate flags = outer->sq_flags; 58357c478bd9Sstevel@tonic-gate ASSERT(outer->sq_flags & SQ_WRITER); 58367c478bd9Sstevel@tonic-gate if (flags & SQ_QUEUED) { 58377c478bd9Sstevel@tonic-gate write_now(outer); 58387c478bd9Sstevel@tonic-gate flags = outer->sq_flags; 58397c478bd9Sstevel@tonic-gate } 58407c478bd9Sstevel@tonic-gate 58417c478bd9Sstevel@tonic-gate /* 58427c478bd9Sstevel@tonic-gate * sq_onext is stable since sq_count has not yet been decreased. 58437c478bd9Sstevel@tonic-gate * Reset the SQ_WRITER flags in all syncqs. 58447c478bd9Sstevel@tonic-gate * After dropping SQ_WRITER on the outer syncq we empty all the 58457c478bd9Sstevel@tonic-gate * inner syncqs. 58467c478bd9Sstevel@tonic-gate */ 58477c478bd9Sstevel@tonic-gate drain_needed = 0; 58487c478bd9Sstevel@tonic-gate for (sq = outer->sq_onext; sq != outer; sq = sq->sq_onext) 58497c478bd9Sstevel@tonic-gate drain_needed += dropsq(sq, SQ_WRITER); 58507c478bd9Sstevel@tonic-gate ASSERT(!(outer->sq_flags & SQ_QUEUED)); 58517c478bd9Sstevel@tonic-gate flags &= ~SQ_WRITER; 58527c478bd9Sstevel@tonic-gate if (drain_needed) { 58537c478bd9Sstevel@tonic-gate outer->sq_flags = flags; 58547c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 58557c478bd9Sstevel@tonic-gate for (sq = outer->sq_onext; sq != outer; sq = sq->sq_onext) 58567c478bd9Sstevel@tonic-gate emptysq(sq); 58577c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 58587c478bd9Sstevel@tonic-gate flags = outer->sq_flags; 58597c478bd9Sstevel@tonic-gate } 58607c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 58617c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 58627c478bd9Sstevel@tonic-gate cv_broadcast(&outer->sq_wait); 58637c478bd9Sstevel@tonic-gate } 58647c478bd9Sstevel@tonic-gate outer->sq_flags = flags; 58657c478bd9Sstevel@tonic-gate ASSERT(outer->sq_count > 0); 58667c478bd9Sstevel@tonic-gate outer->sq_count--; 58677c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 58687c478bd9Sstevel@tonic-gate } 58697c478bd9Sstevel@tonic-gate 58707c478bd9Sstevel@tonic-gate /* 58717c478bd9Sstevel@tonic-gate * Add another syncq to an outer perimeter. 58727c478bd9Sstevel@tonic-gate * Block out all other access to the outer perimeter while it is being 58737c478bd9Sstevel@tonic-gate * changed using blocksq. 58747c478bd9Sstevel@tonic-gate * Assumes that the caller has *not* done an outer_enter. 58757c478bd9Sstevel@tonic-gate * 58767c478bd9Sstevel@tonic-gate * Vulnerable to starvation in blocksq. 58777c478bd9Sstevel@tonic-gate */ 58787c478bd9Sstevel@tonic-gate static void 58797c478bd9Sstevel@tonic-gate outer_insert(syncq_t *outer, syncq_t *sq) 58807c478bd9Sstevel@tonic-gate { 58817c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL && outer->sq_onext != NULL && 58827c478bd9Sstevel@tonic-gate outer->sq_oprev != NULL); 58837c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == NULL && sq->sq_onext == NULL && 58847c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL); /* Can't be in an outer perimeter */ 58857c478bd9Sstevel@tonic-gate 58867c478bd9Sstevel@tonic-gate /* Get exclusive access to the outer perimeter list */ 58877c478bd9Sstevel@tonic-gate blocksq(outer, SQ_BLOCKED, 0); 58887c478bd9Sstevel@tonic-gate ASSERT(outer->sq_flags & SQ_BLOCKED); 58897c478bd9Sstevel@tonic-gate ASSERT(!(outer->sq_flags & SQ_WRITER)); 58907c478bd9Sstevel@tonic-gate 58917c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 58927c478bd9Sstevel@tonic-gate sq->sq_outer = outer; 58937c478bd9Sstevel@tonic-gate outer->sq_onext->sq_oprev = sq; 58947c478bd9Sstevel@tonic-gate sq->sq_onext = outer->sq_onext; 58957c478bd9Sstevel@tonic-gate outer->sq_onext = sq; 58967c478bd9Sstevel@tonic-gate sq->sq_oprev = outer; 58977c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 58987c478bd9Sstevel@tonic-gate unblocksq(outer, SQ_BLOCKED, 1); 58997c478bd9Sstevel@tonic-gate } 59007c478bd9Sstevel@tonic-gate 59017c478bd9Sstevel@tonic-gate /* 59027c478bd9Sstevel@tonic-gate * Remove a syncq from an outer perimeter. 59037c478bd9Sstevel@tonic-gate * Block out all other access to the outer perimeter while it is being 59047c478bd9Sstevel@tonic-gate * changed using blocksq. 59057c478bd9Sstevel@tonic-gate * Assumes that the caller has *not* done an outer_enter. 59067c478bd9Sstevel@tonic-gate * 59077c478bd9Sstevel@tonic-gate * Vulnerable to starvation in blocksq. 59087c478bd9Sstevel@tonic-gate */ 59097c478bd9Sstevel@tonic-gate static void 59107c478bd9Sstevel@tonic-gate outer_remove(syncq_t *outer, syncq_t *sq) 59117c478bd9Sstevel@tonic-gate { 59127c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL && outer->sq_onext != NULL && 59137c478bd9Sstevel@tonic-gate outer->sq_oprev != NULL); 59147c478bd9Sstevel@tonic-gate ASSERT(sq->sq_outer == outer); 59157c478bd9Sstevel@tonic-gate 59167c478bd9Sstevel@tonic-gate /* Get exclusive access to the outer perimeter list */ 59177c478bd9Sstevel@tonic-gate blocksq(outer, SQ_BLOCKED, 0); 59187c478bd9Sstevel@tonic-gate ASSERT(outer->sq_flags & SQ_BLOCKED); 59197c478bd9Sstevel@tonic-gate ASSERT(!(outer->sq_flags & SQ_WRITER)); 59207c478bd9Sstevel@tonic-gate 59217c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 59227c478bd9Sstevel@tonic-gate sq->sq_outer = NULL; 59237c478bd9Sstevel@tonic-gate sq->sq_onext->sq_oprev = sq->sq_oprev; 59247c478bd9Sstevel@tonic-gate sq->sq_oprev->sq_onext = sq->sq_onext; 59257c478bd9Sstevel@tonic-gate sq->sq_oprev = sq->sq_onext = NULL; 59267c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 59277c478bd9Sstevel@tonic-gate unblocksq(outer, SQ_BLOCKED, 1); 59287c478bd9Sstevel@tonic-gate } 59297c478bd9Sstevel@tonic-gate 59307c478bd9Sstevel@tonic-gate /* 59317c478bd9Sstevel@tonic-gate * Queue a deferred qwriter(OUTER) callback for this outer perimeter. 59327c478bd9Sstevel@tonic-gate * If this is the first callback for this outer perimeter then add 59337c478bd9Sstevel@tonic-gate * this outer perimeter to the list of outer perimeters that 59347c478bd9Sstevel@tonic-gate * the qwriter_outer_thread will process. 59357c478bd9Sstevel@tonic-gate * 59367c478bd9Sstevel@tonic-gate * Increments sq_count in the outer syncq to prevent the membership 59377c478bd9Sstevel@tonic-gate * of the outer perimeter (in terms of inner syncqs) to change while 59387c478bd9Sstevel@tonic-gate * the callback is pending. 59397c478bd9Sstevel@tonic-gate */ 59407c478bd9Sstevel@tonic-gate static void 59417c478bd9Sstevel@tonic-gate queue_writer(syncq_t *outer, void (*func)(), queue_t *q, mblk_t *mp) 59427c478bd9Sstevel@tonic-gate { 59437c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(outer))); 59447c478bd9Sstevel@tonic-gate 59457c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)func; 59467c478bd9Sstevel@tonic-gate mp->b_queue = q; 59477c478bd9Sstevel@tonic-gate mp->b_next = NULL; 59487c478bd9Sstevel@tonic-gate outer->sq_count++; /* Decremented when dequeued */ 59497c478bd9Sstevel@tonic-gate ASSERT(outer->sq_count != 0); /* Wraparound */ 59507c478bd9Sstevel@tonic-gate if (outer->sq_evhead == NULL) { 59517c478bd9Sstevel@tonic-gate /* First message. */ 59527c478bd9Sstevel@tonic-gate outer->sq_evhead = outer->sq_evtail = mp; 59537c478bd9Sstevel@tonic-gate outer->sq_flags |= SQ_EVENTS; 59547c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 59557c478bd9Sstevel@tonic-gate STRSTAT(qwr_outer); 59567c478bd9Sstevel@tonic-gate (void) taskq_dispatch(streams_taskq, 59577c478bd9Sstevel@tonic-gate (task_func_t *)qwriter_outer_service, outer, TQ_SLEEP); 59587c478bd9Sstevel@tonic-gate } else { 59597c478bd9Sstevel@tonic-gate ASSERT(outer->sq_flags & SQ_EVENTS); 59607c478bd9Sstevel@tonic-gate outer->sq_evtail->b_next = mp; 59617c478bd9Sstevel@tonic-gate outer->sq_evtail = mp; 59627c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 59637c478bd9Sstevel@tonic-gate } 59647c478bd9Sstevel@tonic-gate } 59657c478bd9Sstevel@tonic-gate 59667c478bd9Sstevel@tonic-gate /* 59677c478bd9Sstevel@tonic-gate * Try and upgrade to write access at the outer perimeter. If this can 59687c478bd9Sstevel@tonic-gate * not be done without blocking then queue the callback to be done 59697c478bd9Sstevel@tonic-gate * by the qwriter_outer_thread. 59707c478bd9Sstevel@tonic-gate * 59717c478bd9Sstevel@tonic-gate * This routine can only be called from put or service procedures plus 597221804b56SBrian Ruthven * asynchronous callback routines that have properly entered the queue (with 597321804b56SBrian Ruthven * entersq). Thus qwriter(OUTER) assumes the caller has one claim on the syncq 597421804b56SBrian Ruthven * associated with q. 59757c478bd9Sstevel@tonic-gate */ 59767c478bd9Sstevel@tonic-gate void 59777c478bd9Sstevel@tonic-gate qwriter_outer(queue_t *q, mblk_t *mp, void (*func)()) 59787c478bd9Sstevel@tonic-gate { 59797c478bd9Sstevel@tonic-gate syncq_t *osq, *sq, *outer; 59807c478bd9Sstevel@tonic-gate int failed; 59817c478bd9Sstevel@tonic-gate uint16_t flags; 59827c478bd9Sstevel@tonic-gate 59837c478bd9Sstevel@tonic-gate osq = q->q_syncq; 59847c478bd9Sstevel@tonic-gate outer = osq->sq_outer; 59857c478bd9Sstevel@tonic-gate if (outer == NULL) 59867c478bd9Sstevel@tonic-gate panic("qwriter(PERIM_OUTER): no outer perimeter"); 59877c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL && outer->sq_onext != NULL && 59887c478bd9Sstevel@tonic-gate outer->sq_oprev != NULL); 59897c478bd9Sstevel@tonic-gate 59907c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 59917c478bd9Sstevel@tonic-gate flags = outer->sq_flags; 59927c478bd9Sstevel@tonic-gate /* 59937c478bd9Sstevel@tonic-gate * If some thread is traversing sq_next, or if we are blocked by 59947c478bd9Sstevel@tonic-gate * outer_insert or outer_remove, or if the we already have queued 59957c478bd9Sstevel@tonic-gate * callbacks, then queue this callback for later processing. 59967c478bd9Sstevel@tonic-gate * 59977c478bd9Sstevel@tonic-gate * Also queue the qwriter for an interrupt thread in order 59987c478bd9Sstevel@tonic-gate * to reduce the time spent running at high IPL. 59997c478bd9Sstevel@tonic-gate * to identify there are events. 60007c478bd9Sstevel@tonic-gate */ 60017c478bd9Sstevel@tonic-gate if ((flags & SQ_GOAWAY) || (curthread->t_pri >= kpreemptpri)) { 60027c478bd9Sstevel@tonic-gate /* 60037c478bd9Sstevel@tonic-gate * Queue the become_writer request. 60047c478bd9Sstevel@tonic-gate * The queueing is atomic under SQLOCK(outer) in order 60057c478bd9Sstevel@tonic-gate * to synchronize with outer_exit. 60067c478bd9Sstevel@tonic-gate * queue_writer will drop the outer SQLOCK 60077c478bd9Sstevel@tonic-gate */ 60087c478bd9Sstevel@tonic-gate if (flags & SQ_BLOCKED) { 60097c478bd9Sstevel@tonic-gate /* Must set SQ_WRITER on inner perimeter */ 60107c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(osq)); 60117c478bd9Sstevel@tonic-gate osq->sq_flags |= SQ_WRITER; 60127c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(osq)); 60137c478bd9Sstevel@tonic-gate } else { 60147c478bd9Sstevel@tonic-gate if (!(flags & SQ_WRITER)) { 60157c478bd9Sstevel@tonic-gate /* 60167c478bd9Sstevel@tonic-gate * The outer could have been SQ_BLOCKED thus 60177c478bd9Sstevel@tonic-gate * SQ_WRITER might not be set on the inner. 60187c478bd9Sstevel@tonic-gate */ 60197c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(osq)); 60207c478bd9Sstevel@tonic-gate osq->sq_flags |= SQ_WRITER; 60217c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(osq)); 60227c478bd9Sstevel@tonic-gate } 60237c478bd9Sstevel@tonic-gate ASSERT(osq->sq_flags & SQ_WRITER); 60247c478bd9Sstevel@tonic-gate } 60257c478bd9Sstevel@tonic-gate queue_writer(outer, func, q, mp); 60267c478bd9Sstevel@tonic-gate return; 60277c478bd9Sstevel@tonic-gate } 60287c478bd9Sstevel@tonic-gate /* 60297c478bd9Sstevel@tonic-gate * We are half-way to exclusive access to the outer perimeter. 60307c478bd9Sstevel@tonic-gate * Prevent any outer_enter, qwriter(OUTER), or outer_insert/remove 60317c478bd9Sstevel@tonic-gate * while the inner syncqs are traversed. 60327c478bd9Sstevel@tonic-gate */ 60337c478bd9Sstevel@tonic-gate outer->sq_count++; 60347c478bd9Sstevel@tonic-gate ASSERT(outer->sq_count != 0); /* wraparound */ 60357c478bd9Sstevel@tonic-gate flags |= SQ_WRITER; 60367c478bd9Sstevel@tonic-gate /* 60377c478bd9Sstevel@tonic-gate * Check if we can run the function immediately. Mark all 60387c478bd9Sstevel@tonic-gate * syncqs with the writer flag to prevent new entries into 60397c478bd9Sstevel@tonic-gate * put and service procedures. 60407c478bd9Sstevel@tonic-gate * 60417c478bd9Sstevel@tonic-gate * Set SQ_WRITER on all the inner syncqs while holding 60427c478bd9Sstevel@tonic-gate * the SQLOCK on the outer syncq. This ensures that the changing 60437c478bd9Sstevel@tonic-gate * of SQ_WRITER is atomic under the outer SQLOCK. 60447c478bd9Sstevel@tonic-gate */ 60457c478bd9Sstevel@tonic-gate failed = 0; 60467c478bd9Sstevel@tonic-gate for (sq = outer->sq_onext; sq != outer; sq = sq->sq_onext) { 60477c478bd9Sstevel@tonic-gate uint16_t count; 60487c478bd9Sstevel@tonic-gate uint_t maxcnt = (sq == osq) ? 1 : 0; 60497c478bd9Sstevel@tonic-gate 60507c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 60517c478bd9Sstevel@tonic-gate count = sq->sq_count; 60527c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 60537c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 60547c478bd9Sstevel@tonic-gate if (sq->sq_count > maxcnt) 60557c478bd9Sstevel@tonic-gate failed = 1; 60567c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WRITER; 60577c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 60587c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 60597c478bd9Sstevel@tonic-gate } 60607c478bd9Sstevel@tonic-gate if (failed) { 60617c478bd9Sstevel@tonic-gate /* 60627c478bd9Sstevel@tonic-gate * Some other thread has a read claim on the outer perimeter. 60637c478bd9Sstevel@tonic-gate * Queue the callback for deferred processing. 60647c478bd9Sstevel@tonic-gate * 60657c478bd9Sstevel@tonic-gate * queue_writer will set SQ_QUEUED before we drop SQ_WRITER 60667c478bd9Sstevel@tonic-gate * so that other qwriter(OUTER) calls will queue their 60677c478bd9Sstevel@tonic-gate * callbacks as well. queue_writer increments sq_count so we 60687c478bd9Sstevel@tonic-gate * decrement to compensate for the our increment. 60697c478bd9Sstevel@tonic-gate * 60707c478bd9Sstevel@tonic-gate * Dropping SQ_WRITER enables the writer thread to work 60717c478bd9Sstevel@tonic-gate * on this outer perimeter. 60727c478bd9Sstevel@tonic-gate */ 60737c478bd9Sstevel@tonic-gate outer->sq_flags = flags; 60747c478bd9Sstevel@tonic-gate queue_writer(outer, func, q, mp); 60757c478bd9Sstevel@tonic-gate /* queue_writer dropper the lock */ 60767c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 60777c478bd9Sstevel@tonic-gate ASSERT(outer->sq_count > 0); 60787c478bd9Sstevel@tonic-gate outer->sq_count--; 60797c478bd9Sstevel@tonic-gate ASSERT(outer->sq_flags & SQ_WRITER); 60807c478bd9Sstevel@tonic-gate flags = outer->sq_flags; 60817c478bd9Sstevel@tonic-gate flags &= ~SQ_WRITER; 60827c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 60837c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 60847c478bd9Sstevel@tonic-gate cv_broadcast(&outer->sq_wait); 60857c478bd9Sstevel@tonic-gate } 60867c478bd9Sstevel@tonic-gate outer->sq_flags = flags; 60877c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 60887c478bd9Sstevel@tonic-gate return; 60897c478bd9Sstevel@tonic-gate } else { 60907c478bd9Sstevel@tonic-gate outer->sq_flags = flags; 60917c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 60927c478bd9Sstevel@tonic-gate } 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate /* Can run it immediately */ 60957c478bd9Sstevel@tonic-gate (*func)(q, mp); 60967c478bd9Sstevel@tonic-gate 60977c478bd9Sstevel@tonic-gate outer_exit(outer); 60987c478bd9Sstevel@tonic-gate } 60997c478bd9Sstevel@tonic-gate 61007c478bd9Sstevel@tonic-gate /* 61017c478bd9Sstevel@tonic-gate * Dequeue all writer callbacks from the outer perimeter and run them. 61027c478bd9Sstevel@tonic-gate */ 61037c478bd9Sstevel@tonic-gate static void 61047c478bd9Sstevel@tonic-gate write_now(syncq_t *outer) 61057c478bd9Sstevel@tonic-gate { 61067c478bd9Sstevel@tonic-gate mblk_t *mp; 61077c478bd9Sstevel@tonic-gate queue_t *q; 61087c478bd9Sstevel@tonic-gate void (*func)(); 61097c478bd9Sstevel@tonic-gate 61107c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(outer))); 61117c478bd9Sstevel@tonic-gate ASSERT(outer->sq_outer == NULL && outer->sq_onext != NULL && 61127c478bd9Sstevel@tonic-gate outer->sq_oprev != NULL); 61137c478bd9Sstevel@tonic-gate while ((mp = outer->sq_evhead) != NULL) { 61147c478bd9Sstevel@tonic-gate /* 61157c478bd9Sstevel@tonic-gate * queues cannot be placed on the queuelist on the outer 611621804b56SBrian Ruthven * perimeter. 61177c478bd9Sstevel@tonic-gate */ 61187c478bd9Sstevel@tonic-gate ASSERT(!(outer->sq_flags & SQ_MESSAGES)); 61197c478bd9Sstevel@tonic-gate ASSERT((outer->sq_flags & SQ_EVENTS)); 61207c478bd9Sstevel@tonic-gate 61217c478bd9Sstevel@tonic-gate outer->sq_evhead = mp->b_next; 61227c478bd9Sstevel@tonic-gate if (outer->sq_evhead == NULL) { 61237c478bd9Sstevel@tonic-gate outer->sq_evtail = NULL; 61247c478bd9Sstevel@tonic-gate outer->sq_flags &= ~SQ_EVENTS; 61257c478bd9Sstevel@tonic-gate } 61267c478bd9Sstevel@tonic-gate ASSERT(outer->sq_count != 0); 61277c478bd9Sstevel@tonic-gate outer->sq_count--; /* Incremented when enqueued. */ 61287c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(outer)); 61297c478bd9Sstevel@tonic-gate /* 61307c478bd9Sstevel@tonic-gate * Drop the message if the queue is closing. 61317c478bd9Sstevel@tonic-gate * Make sure that the queue is "claimed" when the callback 61327c478bd9Sstevel@tonic-gate * is run in order to satisfy various ASSERTs. 61337c478bd9Sstevel@tonic-gate */ 61347c478bd9Sstevel@tonic-gate q = mp->b_queue; 61357c478bd9Sstevel@tonic-gate func = (void (*)())mp->b_prev; 61367c478bd9Sstevel@tonic-gate ASSERT(func != NULL); 61377c478bd9Sstevel@tonic-gate mp->b_next = mp->b_prev = NULL; 61387c478bd9Sstevel@tonic-gate if (q->q_flag & QWCLOSE) { 61397c478bd9Sstevel@tonic-gate freemsg(mp); 61407c478bd9Sstevel@tonic-gate } else { 61417c478bd9Sstevel@tonic-gate claimq(q); 61427c478bd9Sstevel@tonic-gate (*func)(q, mp); 61437c478bd9Sstevel@tonic-gate releaseq(q); 61447c478bd9Sstevel@tonic-gate } 61457c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(outer)); 61467c478bd9Sstevel@tonic-gate } 61477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(outer))); 61487c478bd9Sstevel@tonic-gate } 61497c478bd9Sstevel@tonic-gate 61507c478bd9Sstevel@tonic-gate /* 61517c478bd9Sstevel@tonic-gate * The list of messages on the inner syncq is effectively hashed 61527c478bd9Sstevel@tonic-gate * by destination queue. These destination queues are doubly 61537c478bd9Sstevel@tonic-gate * linked lists (hopefully) in priority order. Messages are then 61547c478bd9Sstevel@tonic-gate * put on the queue referenced by the q_sqhead/q_sqtail elements. 61557c478bd9Sstevel@tonic-gate * Additional messages are linked together by the b_next/b_prev 61567c478bd9Sstevel@tonic-gate * elements in the mblk, with (similar to putq()) the first message 61577c478bd9Sstevel@tonic-gate * having a NULL b_prev and the last message having a NULL b_next. 61587c478bd9Sstevel@tonic-gate * 61597c478bd9Sstevel@tonic-gate * Events, such as qwriter callbacks, are put onto a list in FIFO 61607c478bd9Sstevel@tonic-gate * order referenced by sq_evhead, and sq_evtail. This is a singly 61617c478bd9Sstevel@tonic-gate * linked list, and messages here MUST be processed in the order queued. 61627c478bd9Sstevel@tonic-gate */ 61637c478bd9Sstevel@tonic-gate 61647c478bd9Sstevel@tonic-gate /* 61657c478bd9Sstevel@tonic-gate * Run the events on the syncq event list (sq_evhead). 61667c478bd9Sstevel@tonic-gate * Assumes there is only one claim on the syncq, it is 61677c478bd9Sstevel@tonic-gate * already exclusive (SQ_EXCL set), and the SQLOCK held. 61687c478bd9Sstevel@tonic-gate * Messages here are processed in order, with the SQ_EXCL bit 61697c478bd9Sstevel@tonic-gate * held all the way through till the last message is processed. 61707c478bd9Sstevel@tonic-gate */ 61717c478bd9Sstevel@tonic-gate void 61727c478bd9Sstevel@tonic-gate sq_run_events(syncq_t *sq) 61737c478bd9Sstevel@tonic-gate { 61747c478bd9Sstevel@tonic-gate mblk_t *bp; 61757c478bd9Sstevel@tonic-gate queue_t *qp; 61767c478bd9Sstevel@tonic-gate uint16_t flags = sq->sq_flags; 61777c478bd9Sstevel@tonic-gate void (*func)(); 61787c478bd9Sstevel@tonic-gate 61797c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 61807c478bd9Sstevel@tonic-gate ASSERT((sq->sq_outer == NULL && sq->sq_onext == NULL && 61817c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL) || 61827c478bd9Sstevel@tonic-gate (sq->sq_outer != NULL && sq->sq_onext != NULL && 61837c478bd9Sstevel@tonic-gate sq->sq_oprev != NULL)); 61847c478bd9Sstevel@tonic-gate 61857c478bd9Sstevel@tonic-gate ASSERT(flags & SQ_EXCL); 61867c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count == 1); 61877c478bd9Sstevel@tonic-gate 61887c478bd9Sstevel@tonic-gate /* 61897c478bd9Sstevel@tonic-gate * We need to process all of the events on this list. It 61907c478bd9Sstevel@tonic-gate * is possible that new events will be added while we are 61917c478bd9Sstevel@tonic-gate * away processing a callback, so on every loop, we start 61927c478bd9Sstevel@tonic-gate * back at the beginning of the list. 61937c478bd9Sstevel@tonic-gate */ 61947c478bd9Sstevel@tonic-gate /* 61957c478bd9Sstevel@tonic-gate * We have to reaccess sq_evhead since there is a 61967c478bd9Sstevel@tonic-gate * possibility of a new entry while we were running 61977c478bd9Sstevel@tonic-gate * the callback. 61987c478bd9Sstevel@tonic-gate */ 61997c478bd9Sstevel@tonic-gate for (bp = sq->sq_evhead; bp != NULL; bp = sq->sq_evhead) { 62007c478bd9Sstevel@tonic-gate ASSERT(bp->b_queue->q_syncq == sq); 62017c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_EVENTS); 62027c478bd9Sstevel@tonic-gate 62037c478bd9Sstevel@tonic-gate qp = bp->b_queue; 62047c478bd9Sstevel@tonic-gate func = (void (*)())bp->b_prev; 62057c478bd9Sstevel@tonic-gate ASSERT(func != NULL); 62067c478bd9Sstevel@tonic-gate 62077c478bd9Sstevel@tonic-gate /* 62087c478bd9Sstevel@tonic-gate * Messages from the event queue must be taken off in 62097c478bd9Sstevel@tonic-gate * FIFO order. 62107c478bd9Sstevel@tonic-gate */ 62117c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evhead == bp); 62127c478bd9Sstevel@tonic-gate sq->sq_evhead = bp->b_next; 62137c478bd9Sstevel@tonic-gate 62147c478bd9Sstevel@tonic-gate if (bp->b_next == NULL) { 62157c478bd9Sstevel@tonic-gate /* Deleting last */ 62167c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evtail == bp); 62177c478bd9Sstevel@tonic-gate sq->sq_evtail = NULL; 62187c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_EVENTS; 62197c478bd9Sstevel@tonic-gate } 62207c478bd9Sstevel@tonic-gate bp->b_prev = bp->b_next = NULL; 62217c478bd9Sstevel@tonic-gate ASSERT(bp->b_datap->db_ref != 0); 62227c478bd9Sstevel@tonic-gate 62237c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 62247c478bd9Sstevel@tonic-gate 62257c478bd9Sstevel@tonic-gate (*func)(qp, bp); 62267c478bd9Sstevel@tonic-gate 62277c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 62287c478bd9Sstevel@tonic-gate /* 62297c478bd9Sstevel@tonic-gate * re-read the flags, since they could have changed. 62307c478bd9Sstevel@tonic-gate */ 62317c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 62327c478bd9Sstevel@tonic-gate ASSERT(flags & SQ_EXCL); 62337c478bd9Sstevel@tonic-gate } 62347c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evhead == NULL && sq->sq_evtail == NULL); 62357c478bd9Sstevel@tonic-gate ASSERT(!(sq->sq_flags & SQ_EVENTS)); 62367c478bd9Sstevel@tonic-gate 62377c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 62387c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 62397c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 62407c478bd9Sstevel@tonic-gate } 62417c478bd9Sstevel@tonic-gate if (flags & SQ_WANTEXWAKEUP) { 62427c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTEXWAKEUP; 62437c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_exitwait); 62447c478bd9Sstevel@tonic-gate } 62457c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 62467c478bd9Sstevel@tonic-gate } 62477c478bd9Sstevel@tonic-gate 62487c478bd9Sstevel@tonic-gate /* 62497c478bd9Sstevel@tonic-gate * Put messages on the event list. 62507c478bd9Sstevel@tonic-gate * If we can go exclusive now, do so and process the event list, otherwise 62517c478bd9Sstevel@tonic-gate * let the last claim service this list (or wake the sqthread). 62527c478bd9Sstevel@tonic-gate * This procedure assumes SQLOCK is held. To run the event list, it 62537c478bd9Sstevel@tonic-gate * must be called with no claims. 62547c478bd9Sstevel@tonic-gate */ 62557c478bd9Sstevel@tonic-gate static void 62567c478bd9Sstevel@tonic-gate sqfill_events(syncq_t *sq, queue_t *q, mblk_t *mp, void (*func)()) 62577c478bd9Sstevel@tonic-gate { 62587c478bd9Sstevel@tonic-gate uint16_t count; 62597c478bd9Sstevel@tonic-gate 62607c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 62617c478bd9Sstevel@tonic-gate ASSERT(func != NULL); 62627c478bd9Sstevel@tonic-gate 62637c478bd9Sstevel@tonic-gate /* 62647c478bd9Sstevel@tonic-gate * This is a callback. Add it to the list of callbacks 62657c478bd9Sstevel@tonic-gate * and see about upgrading. 62667c478bd9Sstevel@tonic-gate */ 62677c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)func; 62687c478bd9Sstevel@tonic-gate mp->b_queue = q; 62697c478bd9Sstevel@tonic-gate mp->b_next = NULL; 62707c478bd9Sstevel@tonic-gate if (sq->sq_evhead == NULL) { 62717c478bd9Sstevel@tonic-gate sq->sq_evhead = sq->sq_evtail = mp; 62727c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EVENTS; 62737c478bd9Sstevel@tonic-gate } else { 62747c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evtail != NULL); 62757c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evtail->b_next == NULL); 62767c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_EVENTS); 62777c478bd9Sstevel@tonic-gate sq->sq_evtail->b_next = mp; 62787c478bd9Sstevel@tonic-gate sq->sq_evtail = mp; 62797c478bd9Sstevel@tonic-gate } 62807c478bd9Sstevel@tonic-gate /* 62817c478bd9Sstevel@tonic-gate * We have set SQ_EVENTS, so threads will have to 628221804b56SBrian Ruthven * unwind out of the perimeter, and new entries will 62837c478bd9Sstevel@tonic-gate * not grab a putlock. But we still need to know 62847c478bd9Sstevel@tonic-gate * how many threads have already made a claim to the 62857c478bd9Sstevel@tonic-gate * syncq, so grab the putlocks, and sum the counts. 62867c478bd9Sstevel@tonic-gate * If there are no claims on the syncq, we can upgrade 62877c478bd9Sstevel@tonic-gate * to exclusive, and run the event list. 62887c478bd9Sstevel@tonic-gate * NOTE: We hold the SQLOCK, so we can just grab the 62897c478bd9Sstevel@tonic-gate * putlocks. 62907c478bd9Sstevel@tonic-gate */ 62917c478bd9Sstevel@tonic-gate count = sq->sq_count; 62927c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 62937c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 62947c478bd9Sstevel@tonic-gate /* 62957c478bd9Sstevel@tonic-gate * We have no claim, so we need to check if there 62967c478bd9Sstevel@tonic-gate * are no others, then we can upgrade. 62977c478bd9Sstevel@tonic-gate */ 62987c478bd9Sstevel@tonic-gate /* 62997c478bd9Sstevel@tonic-gate * There are currently no claims on 63007c478bd9Sstevel@tonic-gate * the syncq by this thread (at least on this entry). The thread who has 63017c478bd9Sstevel@tonic-gate * the claim should drain syncq. 63027c478bd9Sstevel@tonic-gate */ 63037c478bd9Sstevel@tonic-gate if (count > 0) { 63047c478bd9Sstevel@tonic-gate /* 63057c478bd9Sstevel@tonic-gate * Can't upgrade - other threads inside. 63067c478bd9Sstevel@tonic-gate */ 63077c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 63087c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 63097c478bd9Sstevel@tonic-gate return; 63107c478bd9Sstevel@tonic-gate } 63117c478bd9Sstevel@tonic-gate /* 63127c478bd9Sstevel@tonic-gate * Need to set SQ_EXCL and make a claim on the syncq. 63137c478bd9Sstevel@tonic-gate */ 63147c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & SQ_EXCL) == 0); 63157c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 63167c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count == 0); 63177c478bd9Sstevel@tonic-gate sq->sq_count++; 63187c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 63197c478bd9Sstevel@tonic-gate 63207c478bd9Sstevel@tonic-gate /* Process the events list */ 63217c478bd9Sstevel@tonic-gate sq_run_events(sq); 63227c478bd9Sstevel@tonic-gate 63237c478bd9Sstevel@tonic-gate /* 63247c478bd9Sstevel@tonic-gate * Release our claim... 63257c478bd9Sstevel@tonic-gate */ 63267c478bd9Sstevel@tonic-gate sq->sq_count--; 63277c478bd9Sstevel@tonic-gate 63287c478bd9Sstevel@tonic-gate /* 63297c478bd9Sstevel@tonic-gate * And release SQ_EXCL. 63307c478bd9Sstevel@tonic-gate * We don't need to acquire the putlocks to release 63317c478bd9Sstevel@tonic-gate * SQ_EXCL, since we are exclusive, and hold the SQLOCK. 63327c478bd9Sstevel@tonic-gate */ 63337c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_EXCL; 63347c478bd9Sstevel@tonic-gate 63357c478bd9Sstevel@tonic-gate /* 63367c478bd9Sstevel@tonic-gate * sq_run_events should have released SQ_EXCL 63377c478bd9Sstevel@tonic-gate */ 63387c478bd9Sstevel@tonic-gate ASSERT(!(sq->sq_flags & SQ_EXCL)); 63397c478bd9Sstevel@tonic-gate 63407c478bd9Sstevel@tonic-gate /* 63417c478bd9Sstevel@tonic-gate * If anything happened while we were running the 63427c478bd9Sstevel@tonic-gate * events (or was there before), we need to process 63437c478bd9Sstevel@tonic-gate * them now. We shouldn't be exclusive sine we 634421804b56SBrian Ruthven * released the perimeter above (plus, we asserted 63457c478bd9Sstevel@tonic-gate * for it). 63467c478bd9Sstevel@tonic-gate */ 63477c478bd9Sstevel@tonic-gate if (!(sq->sq_flags & SQ_STAYAWAY) && (sq->sq_flags & SQ_QUEUED)) 63487c478bd9Sstevel@tonic-gate drain_syncq(sq); 63497c478bd9Sstevel@tonic-gate else 63507c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 63517c478bd9Sstevel@tonic-gate } 63527c478bd9Sstevel@tonic-gate 63537c478bd9Sstevel@tonic-gate /* 63547c478bd9Sstevel@tonic-gate * Perform delayed processing. The caller has to make sure that it is safe 63557c478bd9Sstevel@tonic-gate * to enter the syncq (e.g. by checking that none of the SQ_STAYAWAY bits are 635621804b56SBrian Ruthven * set). 63577c478bd9Sstevel@tonic-gate * 63587c478bd9Sstevel@tonic-gate * Assume that the caller has NO claims on the syncq. However, a claim 63597c478bd9Sstevel@tonic-gate * on the syncq does not indicate that a thread is draining the syncq. 63607c478bd9Sstevel@tonic-gate * There may be more claims on the syncq than there are threads draining 63617c478bd9Sstevel@tonic-gate * (i.e. #_threads_draining <= sq_count) 63627c478bd9Sstevel@tonic-gate * 63637c478bd9Sstevel@tonic-gate * drain_syncq has to terminate when one of the SQ_STAYAWAY bits gets set 63647c478bd9Sstevel@tonic-gate * in order to preserve qwriter(OUTER) ordering constraints. 63657c478bd9Sstevel@tonic-gate * 63667c478bd9Sstevel@tonic-gate * sq_putcount only needs to be checked when dispatching the queued 63677c478bd9Sstevel@tonic-gate * writer call for CIPUT sync queue, but this is handled in sq_run_events. 63687c478bd9Sstevel@tonic-gate */ 63697c478bd9Sstevel@tonic-gate void 63707c478bd9Sstevel@tonic-gate drain_syncq(syncq_t *sq) 63717c478bd9Sstevel@tonic-gate { 63727c478bd9Sstevel@tonic-gate queue_t *qp; 63737c478bd9Sstevel@tonic-gate uint16_t count; 63747c478bd9Sstevel@tonic-gate uint16_t type = sq->sq_type; 63757c478bd9Sstevel@tonic-gate uint16_t flags = sq->sq_flags; 63767c478bd9Sstevel@tonic-gate boolean_t bg_service = sq->sq_svcflags & SQ_SERVICE; 63777c478bd9Sstevel@tonic-gate 63787c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, TR_DRAIN_SYNCQ_START, 63797c478bd9Sstevel@tonic-gate "drain_syncq start:%p", sq); 63807c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 63817c478bd9Sstevel@tonic-gate ASSERT((sq->sq_outer == NULL && sq->sq_onext == NULL && 63827c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL) || 63837c478bd9Sstevel@tonic-gate (sq->sq_outer != NULL && sq->sq_onext != NULL && 63847c478bd9Sstevel@tonic-gate sq->sq_oprev != NULL)); 63857c478bd9Sstevel@tonic-gate 63867c478bd9Sstevel@tonic-gate /* 63877c478bd9Sstevel@tonic-gate * Drop SQ_SERVICE flag. 63887c478bd9Sstevel@tonic-gate */ 63897c478bd9Sstevel@tonic-gate if (bg_service) 63907c478bd9Sstevel@tonic-gate sq->sq_svcflags &= ~SQ_SERVICE; 63917c478bd9Sstevel@tonic-gate 63927c478bd9Sstevel@tonic-gate /* 63937c478bd9Sstevel@tonic-gate * If SQ_EXCL is set, someone else is processing this syncq - let him 63947c478bd9Sstevel@tonic-gate * finish the job. 63957c478bd9Sstevel@tonic-gate */ 63967c478bd9Sstevel@tonic-gate if (flags & SQ_EXCL) { 63977c478bd9Sstevel@tonic-gate if (bg_service) { 63987c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount != 0); 63997c478bd9Sstevel@tonic-gate sq->sq_servcount--; 64007c478bd9Sstevel@tonic-gate } 64017c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 64027c478bd9Sstevel@tonic-gate return; 64037c478bd9Sstevel@tonic-gate } 64047c478bd9Sstevel@tonic-gate 64057c478bd9Sstevel@tonic-gate /* 64067c478bd9Sstevel@tonic-gate * This routine can be called by a background thread if 64077c478bd9Sstevel@tonic-gate * it was scheduled by a hi-priority thread. SO, if there are 64087c478bd9Sstevel@tonic-gate * NOT messages queued, return (remember, we have the SQLOCK, 64097c478bd9Sstevel@tonic-gate * and it cannot change until we release it). Wakeup any waiters also. 64107c478bd9Sstevel@tonic-gate */ 64117c478bd9Sstevel@tonic-gate if (!(flags & SQ_QUEUED)) { 64127c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 64137c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 64147c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 64157c478bd9Sstevel@tonic-gate } 64167c478bd9Sstevel@tonic-gate if (flags & SQ_WANTEXWAKEUP) { 64177c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTEXWAKEUP; 64187c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_exitwait); 64197c478bd9Sstevel@tonic-gate } 64207c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 64217c478bd9Sstevel@tonic-gate if (bg_service) { 64227c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount != 0); 64237c478bd9Sstevel@tonic-gate sq->sq_servcount--; 64247c478bd9Sstevel@tonic-gate } 64257c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 64267c478bd9Sstevel@tonic-gate return; 64277c478bd9Sstevel@tonic-gate } 64287c478bd9Sstevel@tonic-gate 64297c478bd9Sstevel@tonic-gate /* 643021804b56SBrian Ruthven * If this is not a concurrent put perimeter, we need to 64317c478bd9Sstevel@tonic-gate * become exclusive to drain. Also, if not CIPUT, we would 64327c478bd9Sstevel@tonic-gate * not have acquired a putlock, so we don't need to check 64337c478bd9Sstevel@tonic-gate * the putcounts. If not entering with a claim, we test 64347c478bd9Sstevel@tonic-gate * for sq_count == 0. 64357c478bd9Sstevel@tonic-gate */ 64367c478bd9Sstevel@tonic-gate type = sq->sq_type; 64377c478bd9Sstevel@tonic-gate if (!(type & SQ_CIPUT)) { 64387c478bd9Sstevel@tonic-gate if (sq->sq_count > 1) { 64397c478bd9Sstevel@tonic-gate if (bg_service) { 64407c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount != 0); 64417c478bd9Sstevel@tonic-gate sq->sq_servcount--; 64427c478bd9Sstevel@tonic-gate } 64437c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 64447c478bd9Sstevel@tonic-gate return; 64457c478bd9Sstevel@tonic-gate } 64467c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 64477c478bd9Sstevel@tonic-gate } 64487c478bd9Sstevel@tonic-gate 64497c478bd9Sstevel@tonic-gate /* 64507c478bd9Sstevel@tonic-gate * This is where we make a claim to the syncq. 64517c478bd9Sstevel@tonic-gate * This can either be done by incrementing a putlock, or 64527c478bd9Sstevel@tonic-gate * the sq_count. But since we already have the SQLOCK 64537c478bd9Sstevel@tonic-gate * here, we just bump the sq_count. 64547c478bd9Sstevel@tonic-gate * 64557c478bd9Sstevel@tonic-gate * Note that after we make a claim, we need to let the code 64567c478bd9Sstevel@tonic-gate * fall through to the end of this routine to clean itself 64577c478bd9Sstevel@tonic-gate * up. A return in the while loop will put the syncq in a 64587c478bd9Sstevel@tonic-gate * very bad state. 64597c478bd9Sstevel@tonic-gate */ 64607c478bd9Sstevel@tonic-gate sq->sq_count++; 64617c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); /* wraparound */ 64627c478bd9Sstevel@tonic-gate 64637c478bd9Sstevel@tonic-gate while ((flags = sq->sq_flags) & SQ_QUEUED) { 64647c478bd9Sstevel@tonic-gate /* 64657c478bd9Sstevel@tonic-gate * If we are told to stayaway or went exclusive, 64667c478bd9Sstevel@tonic-gate * we are done. 64677c478bd9Sstevel@tonic-gate */ 64687c478bd9Sstevel@tonic-gate if (flags & (SQ_STAYAWAY)) { 64697c478bd9Sstevel@tonic-gate break; 64707c478bd9Sstevel@tonic-gate } 64717c478bd9Sstevel@tonic-gate 64727c478bd9Sstevel@tonic-gate /* 64737c478bd9Sstevel@tonic-gate * If there are events to run, do so. 64747c478bd9Sstevel@tonic-gate * We have one claim to the syncq, so if there are 64757c478bd9Sstevel@tonic-gate * more than one, other threads are running. 64767c478bd9Sstevel@tonic-gate */ 64777c478bd9Sstevel@tonic-gate if (sq->sq_evhead != NULL) { 64787c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_EVENTS); 64797c478bd9Sstevel@tonic-gate 64807c478bd9Sstevel@tonic-gate count = sq->sq_count; 64817c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 64827c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 64837c478bd9Sstevel@tonic-gate if (count > 1) { 64847c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 64857c478bd9Sstevel@tonic-gate /* Can't upgrade - other threads inside */ 64867c478bd9Sstevel@tonic-gate break; 64877c478bd9Sstevel@tonic-gate } 64887c478bd9Sstevel@tonic-gate ASSERT((flags & SQ_EXCL) == 0); 64897c478bd9Sstevel@tonic-gate sq->sq_flags = flags | SQ_EXCL; 64907c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 64917c478bd9Sstevel@tonic-gate /* 64927c478bd9Sstevel@tonic-gate * we have the only claim, run the events, 64937c478bd9Sstevel@tonic-gate * sq_run_events will clear the SQ_EXCL flag. 64947c478bd9Sstevel@tonic-gate */ 64957c478bd9Sstevel@tonic-gate sq_run_events(sq); 64967c478bd9Sstevel@tonic-gate 64977c478bd9Sstevel@tonic-gate /* 649821804b56SBrian Ruthven * If this is a CIPUT perimeter, we need 64997c478bd9Sstevel@tonic-gate * to drop the SQ_EXCL flag so we can properly 65007c478bd9Sstevel@tonic-gate * continue draining the syncq. 65017c478bd9Sstevel@tonic-gate */ 65027c478bd9Sstevel@tonic-gate if (type & SQ_CIPUT) { 65037c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_EXCL); 65047c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_EXCL; 65057c478bd9Sstevel@tonic-gate } 65067c478bd9Sstevel@tonic-gate 65077c478bd9Sstevel@tonic-gate /* 65087c478bd9Sstevel@tonic-gate * And go back to the beginning just in case 65097c478bd9Sstevel@tonic-gate * anything changed while we were away. 65107c478bd9Sstevel@tonic-gate */ 65117c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & SQ_EXCL) || (type & SQ_CIPUT)); 65127c478bd9Sstevel@tonic-gate continue; 65137c478bd9Sstevel@tonic-gate } 65147c478bd9Sstevel@tonic-gate 65157c478bd9Sstevel@tonic-gate ASSERT(sq->sq_evhead == NULL); 65167c478bd9Sstevel@tonic-gate ASSERT(!(sq->sq_flags & SQ_EVENTS)); 65177c478bd9Sstevel@tonic-gate 65187c478bd9Sstevel@tonic-gate /* 65197c478bd9Sstevel@tonic-gate * Find the queue that is not draining. 65207c478bd9Sstevel@tonic-gate * 65217c478bd9Sstevel@tonic-gate * q_draining is protected by QLOCK which we do not hold. 65227c478bd9Sstevel@tonic-gate * But if it was set, then a thread was draining, and if it gets 65237c478bd9Sstevel@tonic-gate * cleared, then it was because the thread has successfully 652421804b56SBrian Ruthven * drained the syncq, or a GOAWAY state occurred. For the GOAWAY 65257c478bd9Sstevel@tonic-gate * state to happen, a thread needs the SQLOCK which we hold, and 652621804b56SBrian Ruthven * if there was such a flag, we would have already seen it. 65277c478bd9Sstevel@tonic-gate */ 65287c478bd9Sstevel@tonic-gate 65297c478bd9Sstevel@tonic-gate for (qp = sq->sq_head; 65307c478bd9Sstevel@tonic-gate qp != NULL && (qp->q_draining || 65317c478bd9Sstevel@tonic-gate (qp->q_sqflags & Q_SQDRAINING)); 65327c478bd9Sstevel@tonic-gate qp = qp->q_sqnext) 65337c478bd9Sstevel@tonic-gate ; 65347c478bd9Sstevel@tonic-gate 65357c478bd9Sstevel@tonic-gate if (qp == NULL) 65367c478bd9Sstevel@tonic-gate break; 65377c478bd9Sstevel@tonic-gate 65387c478bd9Sstevel@tonic-gate /* 65397c478bd9Sstevel@tonic-gate * We have a queue to work on, and we hold the 65407c478bd9Sstevel@tonic-gate * SQLOCK and one claim, call qdrain_syncq. 65417c478bd9Sstevel@tonic-gate * This means we need to release the SQLOCK and 654221804b56SBrian Ruthven * acquire the QLOCK (OK since we have a claim). 65437c478bd9Sstevel@tonic-gate * Note that qdrain_syncq will actually dequeue 65447c478bd9Sstevel@tonic-gate * this queue from the sq_head list when it is 65457c478bd9Sstevel@tonic-gate * convinced all the work is done and release 65467c478bd9Sstevel@tonic-gate * the QLOCK before returning. 65477c478bd9Sstevel@tonic-gate */ 65487c478bd9Sstevel@tonic-gate qp->q_sqflags |= Q_SQDRAINING; 65497c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 65507c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(qp)); 65517c478bd9Sstevel@tonic-gate qdrain_syncq(sq, qp); 65527c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 65537c478bd9Sstevel@tonic-gate 65547c478bd9Sstevel@tonic-gate /* The queue is drained */ 65557c478bd9Sstevel@tonic-gate ASSERT(qp->q_sqflags & Q_SQDRAINING); 65567c478bd9Sstevel@tonic-gate qp->q_sqflags &= ~Q_SQDRAINING; 65577c478bd9Sstevel@tonic-gate /* 65587c478bd9Sstevel@tonic-gate * NOTE: After this point qp should not be used since it may be 65597c478bd9Sstevel@tonic-gate * closed. 65607c478bd9Sstevel@tonic-gate */ 65617c478bd9Sstevel@tonic-gate } 65627c478bd9Sstevel@tonic-gate 65637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 65647c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 65657c478bd9Sstevel@tonic-gate 65667c478bd9Sstevel@tonic-gate /* 65677c478bd9Sstevel@tonic-gate * sq->sq_head cannot change because we hold the 65687c478bd9Sstevel@tonic-gate * sqlock. However, a thread CAN decide that it is no longer 65697c478bd9Sstevel@tonic-gate * going to drain that queue. However, this should be due to 65707c478bd9Sstevel@tonic-gate * a GOAWAY state, and we should see that here. 65717c478bd9Sstevel@tonic-gate * 65727c478bd9Sstevel@tonic-gate * This loop is not very efficient. One solution may be adding a second 65737c478bd9Sstevel@tonic-gate * pointer to the "draining" queue, but it is difficult to do when 65747c478bd9Sstevel@tonic-gate * queues are inserted in the middle due to priority ordering. Another 65757c478bd9Sstevel@tonic-gate * possibility is to yank the queue out of the sq list and put it onto 65767c478bd9Sstevel@tonic-gate * the "draining list" and then put it back if it can't be drained. 65777c478bd9Sstevel@tonic-gate */ 65787c478bd9Sstevel@tonic-gate 65797c478bd9Sstevel@tonic-gate ASSERT((sq->sq_head == NULL) || (flags & SQ_GOAWAY) || 65807c478bd9Sstevel@tonic-gate (type & SQ_CI) || sq->sq_head->q_draining); 65817c478bd9Sstevel@tonic-gate 658221804b56SBrian Ruthven /* Drop SQ_EXCL for non-CIPUT perimeters */ 65837c478bd9Sstevel@tonic-gate if (!(type & SQ_CIPUT)) 65847c478bd9Sstevel@tonic-gate flags &= ~SQ_EXCL; 65857c478bd9Sstevel@tonic-gate ASSERT((flags & SQ_EXCL) == 0); 65867c478bd9Sstevel@tonic-gate 65877c478bd9Sstevel@tonic-gate /* Wake up any waiters. */ 65887c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 65897c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 65907c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 65917c478bd9Sstevel@tonic-gate } 65927c478bd9Sstevel@tonic-gate if (flags & SQ_WANTEXWAKEUP) { 65937c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTEXWAKEUP; 65947c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_exitwait); 65957c478bd9Sstevel@tonic-gate } 65967c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 65977c478bd9Sstevel@tonic-gate 65987c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); 65997c478bd9Sstevel@tonic-gate /* Release our claim. */ 66007c478bd9Sstevel@tonic-gate sq->sq_count--; 66017c478bd9Sstevel@tonic-gate 66027c478bd9Sstevel@tonic-gate if (bg_service) { 66037c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount != 0); 66047c478bd9Sstevel@tonic-gate sq->sq_servcount--; 66057c478bd9Sstevel@tonic-gate } 66067c478bd9Sstevel@tonic-gate 66077c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 66087c478bd9Sstevel@tonic-gate 66097c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, TR_DRAIN_SYNCQ_END, 66107c478bd9Sstevel@tonic-gate "drain_syncq end:%p", sq); 66117c478bd9Sstevel@tonic-gate } 66127c478bd9Sstevel@tonic-gate 66137c478bd9Sstevel@tonic-gate 66147c478bd9Sstevel@tonic-gate /* 66157c478bd9Sstevel@tonic-gate * 66167c478bd9Sstevel@tonic-gate * qdrain_syncq can be called (currently) from only one of two places: 66177c478bd9Sstevel@tonic-gate * drain_syncq 66187c478bd9Sstevel@tonic-gate * putnext (or some variation of it). 66197c478bd9Sstevel@tonic-gate * and eventually 66207c478bd9Sstevel@tonic-gate * qwait(_sig) 66217c478bd9Sstevel@tonic-gate * 662221804b56SBrian Ruthven * If called from drain_syncq, we found it in the list of queues needing 662321804b56SBrian Ruthven * service, so there is work to be done (or it wouldn't be in the list). 66247c478bd9Sstevel@tonic-gate * 66257c478bd9Sstevel@tonic-gate * If called from some putnext variation, it was because the 662621804b56SBrian Ruthven * perimeter is open, but messages are blocking a putnext and 66277c478bd9Sstevel@tonic-gate * there is not a thread working on it. Now a thread could start 66287c478bd9Sstevel@tonic-gate * working on it while we are getting ready to do so ourself, but 66297c478bd9Sstevel@tonic-gate * the thread would set the q_draining flag, and we can spin out. 66307c478bd9Sstevel@tonic-gate * 66317c478bd9Sstevel@tonic-gate * As for qwait(_sig), I think I shall let it continue to call 66327c478bd9Sstevel@tonic-gate * drain_syncq directly (after all, it will get here eventually). 66337c478bd9Sstevel@tonic-gate * 66347c478bd9Sstevel@tonic-gate * qdrain_syncq has to terminate when: 66357c478bd9Sstevel@tonic-gate * - one of the SQ_STAYAWAY bits gets set to preserve qwriter(OUTER) ordering 66367c478bd9Sstevel@tonic-gate * - SQ_EVENTS gets set to preserve qwriter(INNER) ordering 66377c478bd9Sstevel@tonic-gate * 66387c478bd9Sstevel@tonic-gate * ASSUMES: 66397c478bd9Sstevel@tonic-gate * One claim 66407c478bd9Sstevel@tonic-gate * QLOCK held 66417c478bd9Sstevel@tonic-gate * SQLOCK not held 66427c478bd9Sstevel@tonic-gate * Will release QLOCK before returning 66437c478bd9Sstevel@tonic-gate */ 66447c478bd9Sstevel@tonic-gate void 66457c478bd9Sstevel@tonic-gate qdrain_syncq(syncq_t *sq, queue_t *q) 66467c478bd9Sstevel@tonic-gate { 66477c478bd9Sstevel@tonic-gate mblk_t *bp; 66487c478bd9Sstevel@tonic-gate #ifdef DEBUG 66497c478bd9Sstevel@tonic-gate uint16_t count; 66507c478bd9Sstevel@tonic-gate #endif 66517c478bd9Sstevel@tonic-gate 66527c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, TR_DRAIN_SYNCQ_START, 66537c478bd9Sstevel@tonic-gate "drain_syncq start:%p", sq); 66547c478bd9Sstevel@tonic-gate ASSERT(q->q_syncq == sq); 66557c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(q))); 66567c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 66577c478bd9Sstevel@tonic-gate /* 665821804b56SBrian Ruthven * For non-CIPUT perimeters, we should be called with the exclusive bit 665921804b56SBrian Ruthven * set already. For CIPUT perimeters, we will be doing a concurrent 666021804b56SBrian Ruthven * drain, so it better not be set. 66617c478bd9Sstevel@tonic-gate */ 66627c478bd9Sstevel@tonic-gate ASSERT((sq->sq_flags & (SQ_EXCL|SQ_CIPUT))); 66637c478bd9Sstevel@tonic-gate ASSERT(!((sq->sq_type & SQ_CIPUT) && (sq->sq_flags & SQ_EXCL))); 66647c478bd9Sstevel@tonic-gate ASSERT((sq->sq_type & SQ_CIPUT) || (sq->sq_flags & SQ_EXCL)); 66657c478bd9Sstevel@tonic-gate /* 66667c478bd9Sstevel@tonic-gate * All outer pointers are set, or none of them are 66677c478bd9Sstevel@tonic-gate */ 66687c478bd9Sstevel@tonic-gate ASSERT((sq->sq_outer == NULL && sq->sq_onext == NULL && 66697c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL) || 66707c478bd9Sstevel@tonic-gate (sq->sq_outer != NULL && sq->sq_onext != NULL && 66717c478bd9Sstevel@tonic-gate sq->sq_oprev != NULL)); 66727c478bd9Sstevel@tonic-gate #ifdef DEBUG 66737c478bd9Sstevel@tonic-gate count = sq->sq_count; 66747c478bd9Sstevel@tonic-gate /* 66757c478bd9Sstevel@tonic-gate * This is OK without the putlocks, because we have one 66767c478bd9Sstevel@tonic-gate * claim either from the sq_count, or a putcount. We could 66777c478bd9Sstevel@tonic-gate * get an erroneous value from other counts, but ours won't 66787c478bd9Sstevel@tonic-gate * change, so one way or another, we will have at least a 66797c478bd9Sstevel@tonic-gate * value of one. 66807c478bd9Sstevel@tonic-gate */ 66817c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 66827c478bd9Sstevel@tonic-gate ASSERT(count >= 1); 66837c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 66847c478bd9Sstevel@tonic-gate 66857c478bd9Sstevel@tonic-gate /* 668621804b56SBrian Ruthven * The first thing to do is find out if a thread is already draining 668721804b56SBrian Ruthven * this queue. If so, we are done, just return. 66887c478bd9Sstevel@tonic-gate */ 668921804b56SBrian Ruthven if (q->q_draining) { 66907c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 66917c478bd9Sstevel@tonic-gate return; 66927c478bd9Sstevel@tonic-gate } 66937c478bd9Sstevel@tonic-gate 66947c478bd9Sstevel@tonic-gate /* 669521804b56SBrian Ruthven * If the perimeter is exclusive, there is nothing we can do right now, 669621804b56SBrian Ruthven * go away. Note that there is nothing to prevent this case from 669721804b56SBrian Ruthven * changing right after this check, but the spin-out will catch it. 66987c478bd9Sstevel@tonic-gate */ 66997c478bd9Sstevel@tonic-gate 67007c478bd9Sstevel@tonic-gate /* Tell other threads that we are draining this queue */ 67017c478bd9Sstevel@tonic-gate q->q_draining = 1; /* Protected by QLOCK */ 67027c478bd9Sstevel@tonic-gate 670321804b56SBrian Ruthven /* 670421804b56SBrian Ruthven * If there is nothing to do, clear QFULL as necessary. This caters for 670521804b56SBrian Ruthven * the case where an empty queue was enqueued onto the syncq. 670621804b56SBrian Ruthven */ 670721804b56SBrian Ruthven if (q->q_sqhead == NULL) { 670821804b56SBrian Ruthven ASSERT(q->q_syncqmsgs == 0); 670921804b56SBrian Ruthven mutex_exit(QLOCK(q)); 671021804b56SBrian Ruthven clr_qfull(q); 671121804b56SBrian Ruthven mutex_enter(QLOCK(q)); 671221804b56SBrian Ruthven } 67137c478bd9Sstevel@tonic-gate 67147c478bd9Sstevel@tonic-gate /* 671521804b56SBrian Ruthven * Note that q_sqhead must be re-checked here in case another message 671621804b56SBrian Ruthven * was enqueued whilst QLOCK was dropped during the call to clr_qfull. 671721804b56SBrian Ruthven */ 671821804b56SBrian Ruthven for (bp = q->q_sqhead; bp != NULL; bp = q->q_sqhead) { 671921804b56SBrian Ruthven /* 672021804b56SBrian Ruthven * Because we can enter this routine just because a putnext is 672121804b56SBrian Ruthven * blocked, we need to spin out if the perimeter wants to go 672221804b56SBrian Ruthven * exclusive as well as just blocked. We need to spin out also 672321804b56SBrian Ruthven * if events are queued on the syncq. 672421804b56SBrian Ruthven * Don't check for SQ_EXCL, because non-CIPUT perimeters would 672521804b56SBrian Ruthven * set it, and it can't become exclusive while we hold a claim. 67267c478bd9Sstevel@tonic-gate */ 67277c478bd9Sstevel@tonic-gate if (sq->sq_flags & (SQ_STAYAWAY | SQ_EVENTS)) { 67287c478bd9Sstevel@tonic-gate break; 67297c478bd9Sstevel@tonic-gate } 67307c478bd9Sstevel@tonic-gate 67317c478bd9Sstevel@tonic-gate #ifdef DEBUG 67327c478bd9Sstevel@tonic-gate /* 67337c478bd9Sstevel@tonic-gate * Since we are in qdrain_syncq, we already know the queue, 67347c478bd9Sstevel@tonic-gate * but for sanity, we want to check this against the qp that 67357c478bd9Sstevel@tonic-gate * was passed in by bp->b_queue. 67367c478bd9Sstevel@tonic-gate */ 67377c478bd9Sstevel@tonic-gate 67387c478bd9Sstevel@tonic-gate ASSERT(bp->b_queue == q); 67397c478bd9Sstevel@tonic-gate ASSERT(bp->b_queue->q_syncq == sq); 67407c478bd9Sstevel@tonic-gate bp->b_queue = NULL; 67417c478bd9Sstevel@tonic-gate 67427c478bd9Sstevel@tonic-gate /* 67437c478bd9Sstevel@tonic-gate * We would have the following check in the DEBUG code: 67447c478bd9Sstevel@tonic-gate * 67457c478bd9Sstevel@tonic-gate * if (bp->b_prev != NULL) { 67467c478bd9Sstevel@tonic-gate * ASSERT(bp->b_prev == (void (*)())q->q_qinfo->qi_putp); 67477c478bd9Sstevel@tonic-gate * } 67487c478bd9Sstevel@tonic-gate * 67497c478bd9Sstevel@tonic-gate * This can't be done, however, since IP modifies qinfo 67507c478bd9Sstevel@tonic-gate * structure at run-time (switching between IPv4 qinfo and IPv6 67517c478bd9Sstevel@tonic-gate * qinfo), invalidating the check. 67527c478bd9Sstevel@tonic-gate * So the assignment to func is left here, but the ASSERT itself 67537c478bd9Sstevel@tonic-gate * is removed until the whole issue is resolved. 67547c478bd9Sstevel@tonic-gate */ 67557c478bd9Sstevel@tonic-gate #endif 67567c478bd9Sstevel@tonic-gate ASSERT(q->q_sqhead == bp); 67577c478bd9Sstevel@tonic-gate q->q_sqhead = bp->b_next; 67587c478bd9Sstevel@tonic-gate bp->b_prev = bp->b_next = NULL; 67597c478bd9Sstevel@tonic-gate ASSERT(q->q_syncqmsgs > 0); 67607c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 67617c478bd9Sstevel@tonic-gate 67627c478bd9Sstevel@tonic-gate ASSERT(bp->b_datap->db_ref != 0); 67637c478bd9Sstevel@tonic-gate 67647c478bd9Sstevel@tonic-gate (void) (*q->q_qinfo->qi_putp)(q, bp); 67657c478bd9Sstevel@tonic-gate 67667c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 67677c478bd9Sstevel@tonic-gate 67687c478bd9Sstevel@tonic-gate /* 676921804b56SBrian Ruthven * q_syncqmsgs should only be decremented after executing the 677021804b56SBrian Ruthven * put procedure to avoid message re-ordering. This is due to an 677121804b56SBrian Ruthven * optimisation in putnext() which can call the put procedure 677221804b56SBrian Ruthven * directly if it sees q_syncqmsgs == 0 (despite Q_SQQUEUED 677321804b56SBrian Ruthven * being set). 67747c478bd9Sstevel@tonic-gate * 677521804b56SBrian Ruthven * We also need to clear QFULL in the next service procedure 677621804b56SBrian Ruthven * queue if this is the last message destined for that queue. 677721804b56SBrian Ruthven * 677821804b56SBrian Ruthven * It would make better sense to have some sort of tunable for 677921804b56SBrian Ruthven * the low water mark, but these semantics are not yet defined. 678021804b56SBrian Ruthven * So, alas, we use a constant. 67817c478bd9Sstevel@tonic-gate */ 678221804b56SBrian Ruthven if (--q->q_syncqmsgs == 0) { 67837c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 67847c478bd9Sstevel@tonic-gate clr_qfull(q); 67857c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 678621804b56SBrian Ruthven } 678721804b56SBrian Ruthven 67887c478bd9Sstevel@tonic-gate /* 67897c478bd9Sstevel@tonic-gate * Always clear SQ_EXCL when CIPUT in order to handle 679021804b56SBrian Ruthven * qwriter(INNER). The putp() can call qwriter and get exclusive 679121804b56SBrian Ruthven * access IFF this is the only claim. So, we need to test for 679221804b56SBrian Ruthven * this possibility, acquire the mutex and clear the bit. 67937c478bd9Sstevel@tonic-gate */ 67947c478bd9Sstevel@tonic-gate if ((sq->sq_type & SQ_CIPUT) && (sq->sq_flags & SQ_EXCL)) { 67957c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 67967c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_EXCL; 67977c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 67987c478bd9Sstevel@tonic-gate } 67997c478bd9Sstevel@tonic-gate } 68007c478bd9Sstevel@tonic-gate 68017c478bd9Sstevel@tonic-gate /* 680221804b56SBrian Ruthven * We should either have no messages on this queue, or we were told to 680321804b56SBrian Ruthven * goaway by a waiter (which we will wake up at the end of this 680421804b56SBrian Ruthven * function). 68057c478bd9Sstevel@tonic-gate */ 68067c478bd9Sstevel@tonic-gate ASSERT((q->q_sqhead == NULL) || 68077c478bd9Sstevel@tonic-gate (sq->sq_flags & (SQ_STAYAWAY | SQ_EVENTS))); 68087c478bd9Sstevel@tonic-gate 68097c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(q))); 68107c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 68117c478bd9Sstevel@tonic-gate 681221804b56SBrian Ruthven /* Remove the q from the syncq list if all the messages are drained. */ 68137c478bd9Sstevel@tonic-gate if (q->q_sqhead == NULL) { 681421804b56SBrian Ruthven ASSERT(q->q_syncqmsgs == 0); 68157c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 68167c478bd9Sstevel@tonic-gate if (q->q_sqflags & Q_SQQUEUED) 68177c478bd9Sstevel@tonic-gate SQRM_Q(sq, q); 68187c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 68197c478bd9Sstevel@tonic-gate /* 68207c478bd9Sstevel@tonic-gate * Since the queue is removed from the list, reset its priority. 68217c478bd9Sstevel@tonic-gate */ 68227c478bd9Sstevel@tonic-gate q->q_spri = 0; 68237c478bd9Sstevel@tonic-gate } 68247c478bd9Sstevel@tonic-gate 68257c478bd9Sstevel@tonic-gate /* 682621804b56SBrian Ruthven * Remember, the q_draining flag is used to let another thread know 682721804b56SBrian Ruthven * that there is a thread currently draining the messages for a queue. 682821804b56SBrian Ruthven * Since we are now done with this queue (even if there may be messages 682921804b56SBrian Ruthven * still there), we need to clear this flag so some thread will work on 683021804b56SBrian Ruthven * it if needed. 68317c478bd9Sstevel@tonic-gate */ 68327c478bd9Sstevel@tonic-gate ASSERT(q->q_draining); 68337c478bd9Sstevel@tonic-gate q->q_draining = 0; 68347c478bd9Sstevel@tonic-gate 683521804b56SBrian Ruthven /* Called with a claim, so OK to drop all locks. */ 68367c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 68377c478bd9Sstevel@tonic-gate 68387c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_STREAMS_FR, TR_DRAIN_SYNCQ_END, 68397c478bd9Sstevel@tonic-gate "drain_syncq end:%p", sq); 68407c478bd9Sstevel@tonic-gate } 68417c478bd9Sstevel@tonic-gate /* END OF QDRAIN_SYNCQ */ 68427c478bd9Sstevel@tonic-gate 68437c478bd9Sstevel@tonic-gate 68447c478bd9Sstevel@tonic-gate /* 684521804b56SBrian Ruthven * This is the mate to qdrain_syncq, except that it is putting the message onto 684621804b56SBrian Ruthven * the queue instead of draining. Since the message is destined for the queue 684721804b56SBrian Ruthven * that is selected, there is no need to identify the function because the 684821804b56SBrian Ruthven * message is intended for the put routine for the queue. For debug kernels, 684921804b56SBrian Ruthven * this routine will do it anyway just in case. 68507c478bd9Sstevel@tonic-gate * 68517c478bd9Sstevel@tonic-gate * After the message is enqueued on the syncq, it calls putnext_tail() 68527c478bd9Sstevel@tonic-gate * which will schedule a background thread to actually process the message. 68537c478bd9Sstevel@tonic-gate * 68547c478bd9Sstevel@tonic-gate * Assumes that there is a claim on the syncq (sq->sq_count > 0) and 68557c478bd9Sstevel@tonic-gate * SQLOCK(sq) and QLOCK(q) are not held. 68567c478bd9Sstevel@tonic-gate */ 68577c478bd9Sstevel@tonic-gate void 68587c478bd9Sstevel@tonic-gate qfill_syncq(syncq_t *sq, queue_t *q, mblk_t *mp) 68597c478bd9Sstevel@tonic-gate { 68607c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(SQLOCK(sq))); 68617c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(q))); 68627c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count > 0); 68637c478bd9Sstevel@tonic-gate ASSERT(q->q_syncq == sq); 68647c478bd9Sstevel@tonic-gate ASSERT((sq->sq_outer == NULL && sq->sq_onext == NULL && 68657c478bd9Sstevel@tonic-gate sq->sq_oprev == NULL) || 68667c478bd9Sstevel@tonic-gate (sq->sq_outer != NULL && sq->sq_onext != NULL && 68677c478bd9Sstevel@tonic-gate sq->sq_oprev != NULL)); 68687c478bd9Sstevel@tonic-gate 68697c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 68707c478bd9Sstevel@tonic-gate 68717c478bd9Sstevel@tonic-gate #ifdef DEBUG 68727c478bd9Sstevel@tonic-gate /* 68737c478bd9Sstevel@tonic-gate * This is used for debug in the qfill_syncq/qdrain_syncq case 68747c478bd9Sstevel@tonic-gate * to trace the queue that the message is intended for. Note 68757c478bd9Sstevel@tonic-gate * that the original use was to identify the queue and function 68767c478bd9Sstevel@tonic-gate * to call on the drain. In the new syncq, we have the context 68777c478bd9Sstevel@tonic-gate * of the queue that we are draining, so call it's putproc and 68787c478bd9Sstevel@tonic-gate * don't rely on the saved values. But for debug this is still 687921804b56SBrian Ruthven * useful information. 68807c478bd9Sstevel@tonic-gate */ 68817c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)q->q_qinfo->qi_putp; 68827c478bd9Sstevel@tonic-gate mp->b_queue = q; 68837c478bd9Sstevel@tonic-gate mp->b_next = NULL; 68847c478bd9Sstevel@tonic-gate #endif 68857c478bd9Sstevel@tonic-gate ASSERT(q->q_syncq == sq); 68867c478bd9Sstevel@tonic-gate /* 68877c478bd9Sstevel@tonic-gate * Enqueue the message on the list. 68887c478bd9Sstevel@tonic-gate * SQPUT_MP() accesses q_syncqmsgs. We are already holding QLOCK to 688921804b56SBrian Ruthven * protect it. So it's ok to acquire SQLOCK after SQPUT_MP(). 68907c478bd9Sstevel@tonic-gate */ 68917c478bd9Sstevel@tonic-gate SQPUT_MP(q, mp); 68927c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 68937c478bd9Sstevel@tonic-gate 68947c478bd9Sstevel@tonic-gate /* 68957c478bd9Sstevel@tonic-gate * And queue on syncq for scheduling, if not already queued. 68967c478bd9Sstevel@tonic-gate * Note that we need the SQLOCK for this, and for testing flags 68977c478bd9Sstevel@tonic-gate * at the end to see if we will drain. So grab it now, and 68987c478bd9Sstevel@tonic-gate * release it before we call qdrain_syncq or return. 68997c478bd9Sstevel@tonic-gate */ 69007c478bd9Sstevel@tonic-gate if (!(q->q_sqflags & Q_SQQUEUED)) { 69017c478bd9Sstevel@tonic-gate q->q_spri = curthread->t_pri; 69027c478bd9Sstevel@tonic-gate SQPUT_Q(sq, q); 69037c478bd9Sstevel@tonic-gate } 69047c478bd9Sstevel@tonic-gate #ifdef DEBUG 69057c478bd9Sstevel@tonic-gate else { 69067c478bd9Sstevel@tonic-gate /* 69077c478bd9Sstevel@tonic-gate * All of these conditions MUST be true! 69087c478bd9Sstevel@tonic-gate */ 69097c478bd9Sstevel@tonic-gate ASSERT(sq->sq_tail != NULL); 69107c478bd9Sstevel@tonic-gate if (sq->sq_tail == sq->sq_head) { 69117c478bd9Sstevel@tonic-gate ASSERT((q->q_sqprev == NULL) && 69127c478bd9Sstevel@tonic-gate (q->q_sqnext == NULL)); 69137c478bd9Sstevel@tonic-gate } else { 69147c478bd9Sstevel@tonic-gate ASSERT((q->q_sqprev != NULL) || 69157c478bd9Sstevel@tonic-gate (q->q_sqnext != NULL)); 69167c478bd9Sstevel@tonic-gate } 69177c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_QUEUED); 69187c478bd9Sstevel@tonic-gate ASSERT(q->q_syncqmsgs != 0); 69197c478bd9Sstevel@tonic-gate ASSERT(q->q_sqflags & Q_SQQUEUED); 69207c478bd9Sstevel@tonic-gate } 69217c478bd9Sstevel@tonic-gate #endif 69227c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 69237c478bd9Sstevel@tonic-gate /* 69247c478bd9Sstevel@tonic-gate * SQLOCK is still held, so sq_count can be safely decremented. 69257c478bd9Sstevel@tonic-gate */ 69267c478bd9Sstevel@tonic-gate sq->sq_count--; 69277c478bd9Sstevel@tonic-gate 69287c478bd9Sstevel@tonic-gate putnext_tail(sq, q, 0); 69297c478bd9Sstevel@tonic-gate /* Should not reference sq or q after this point. */ 69307c478bd9Sstevel@tonic-gate } 69317c478bd9Sstevel@tonic-gate 69327c478bd9Sstevel@tonic-gate /* End of qfill_syncq */ 69337c478bd9Sstevel@tonic-gate 69347c478bd9Sstevel@tonic-gate /* 69357c478bd9Sstevel@tonic-gate * Remove all messages from a syncq (if qp is NULL) or remove all messages 69367c478bd9Sstevel@tonic-gate * that would be put into qp by drain_syncq. 69377c478bd9Sstevel@tonic-gate * Used when deleting the syncq (qp == NULL) or when detaching 69387c478bd9Sstevel@tonic-gate * a queue (qp != NULL). 69397c478bd9Sstevel@tonic-gate * Return non-zero if one or more messages were freed. 69407c478bd9Sstevel@tonic-gate * 694121804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that explains when 69427c478bd9Sstevel@tonic-gate * sq_putlocks are used. 69437c478bd9Sstevel@tonic-gate * 69447c478bd9Sstevel@tonic-gate * NOTE: This function assumes that it is called from the close() context and 694521804b56SBrian Ruthven * that all the queues in the syncq are going away. For this reason it doesn't 69467c478bd9Sstevel@tonic-gate * acquire QLOCK for modifying q_sqhead/q_sqtail fields. This assumption is 69477c478bd9Sstevel@tonic-gate * currently valid, but it is useful to rethink this function to behave properly 69487c478bd9Sstevel@tonic-gate * in other cases. 69497c478bd9Sstevel@tonic-gate */ 69507c478bd9Sstevel@tonic-gate int 69517c478bd9Sstevel@tonic-gate flush_syncq(syncq_t *sq, queue_t *qp) 69527c478bd9Sstevel@tonic-gate { 69537c478bd9Sstevel@tonic-gate mblk_t *bp, *mp_head, *mp_next, *mp_prev; 69547c478bd9Sstevel@tonic-gate queue_t *q; 69557c478bd9Sstevel@tonic-gate int ret = 0; 69567c478bd9Sstevel@tonic-gate 69577c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 69587c478bd9Sstevel@tonic-gate 69597c478bd9Sstevel@tonic-gate /* 69607c478bd9Sstevel@tonic-gate * Before we leave, we need to make sure there are no 69617c478bd9Sstevel@tonic-gate * events listed for this queue. All events for this queue 69627c478bd9Sstevel@tonic-gate * will just be freed. 69637c478bd9Sstevel@tonic-gate */ 69647c478bd9Sstevel@tonic-gate if (qp != NULL && sq->sq_evhead != NULL) { 69657c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_EVENTS); 69667c478bd9Sstevel@tonic-gate 69677c478bd9Sstevel@tonic-gate mp_prev = NULL; 69687c478bd9Sstevel@tonic-gate for (bp = sq->sq_evhead; bp != NULL; bp = mp_next) { 69697c478bd9Sstevel@tonic-gate mp_next = bp->b_next; 69707c478bd9Sstevel@tonic-gate if (bp->b_queue == qp) { 69717c478bd9Sstevel@tonic-gate /* Delete this message */ 69727c478bd9Sstevel@tonic-gate if (mp_prev != NULL) { 69737c478bd9Sstevel@tonic-gate mp_prev->b_next = mp_next; 69747c478bd9Sstevel@tonic-gate /* 69757c478bd9Sstevel@tonic-gate * Update sq_evtail if the last element 69767c478bd9Sstevel@tonic-gate * is removed. 69777c478bd9Sstevel@tonic-gate */ 69787c478bd9Sstevel@tonic-gate if (bp == sq->sq_evtail) { 69797c478bd9Sstevel@tonic-gate ASSERT(mp_next == NULL); 69807c478bd9Sstevel@tonic-gate sq->sq_evtail = mp_prev; 69817c478bd9Sstevel@tonic-gate } 69827c478bd9Sstevel@tonic-gate } else 69837c478bd9Sstevel@tonic-gate sq->sq_evhead = mp_next; 69847c478bd9Sstevel@tonic-gate if (sq->sq_evhead == NULL) 69857c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_EVENTS; 69867c478bd9Sstevel@tonic-gate bp->b_prev = bp->b_next = NULL; 69877c478bd9Sstevel@tonic-gate freemsg(bp); 69887c478bd9Sstevel@tonic-gate ret++; 69897c478bd9Sstevel@tonic-gate } else { 69907c478bd9Sstevel@tonic-gate mp_prev = bp; 69917c478bd9Sstevel@tonic-gate } 69927c478bd9Sstevel@tonic-gate } 69937c478bd9Sstevel@tonic-gate } 69947c478bd9Sstevel@tonic-gate 69957c478bd9Sstevel@tonic-gate /* 69967c478bd9Sstevel@tonic-gate * Walk sq_head and: 69977c478bd9Sstevel@tonic-gate * - match qp if qp is set, remove it's messages 69987c478bd9Sstevel@tonic-gate * - all if qp is not set 69997c478bd9Sstevel@tonic-gate */ 70007c478bd9Sstevel@tonic-gate q = sq->sq_head; 70017c478bd9Sstevel@tonic-gate while (q != NULL) { 70027c478bd9Sstevel@tonic-gate ASSERT(q->q_syncq == sq); 70037c478bd9Sstevel@tonic-gate if ((qp == NULL) || (qp == q)) { 70047c478bd9Sstevel@tonic-gate /* 70057c478bd9Sstevel@tonic-gate * Yank the messages as a list off the queue 70067c478bd9Sstevel@tonic-gate */ 70077c478bd9Sstevel@tonic-gate mp_head = q->q_sqhead; 70087c478bd9Sstevel@tonic-gate /* 70097c478bd9Sstevel@tonic-gate * We do not have QLOCK(q) here (which is safe due to 70107c478bd9Sstevel@tonic-gate * assumptions mentioned above). To obtain the lock we 70117c478bd9Sstevel@tonic-gate * need to release SQLOCK which may allow lots of things 70127c478bd9Sstevel@tonic-gate * to change upon us. This place requires more analysis. 70137c478bd9Sstevel@tonic-gate */ 70147c478bd9Sstevel@tonic-gate q->q_sqhead = q->q_sqtail = NULL; 70157c478bd9Sstevel@tonic-gate ASSERT(mp_head->b_queue && 70167c478bd9Sstevel@tonic-gate mp_head->b_queue->q_syncq == sq); 70177c478bd9Sstevel@tonic-gate 70187c478bd9Sstevel@tonic-gate /* 70197c478bd9Sstevel@tonic-gate * Free each of the messages. 70207c478bd9Sstevel@tonic-gate */ 70217c478bd9Sstevel@tonic-gate for (bp = mp_head; bp != NULL; bp = mp_next) { 70227c478bd9Sstevel@tonic-gate mp_next = bp->b_next; 70237c478bd9Sstevel@tonic-gate bp->b_prev = bp->b_next = NULL; 70247c478bd9Sstevel@tonic-gate freemsg(bp); 70257c478bd9Sstevel@tonic-gate ret++; 70267c478bd9Sstevel@tonic-gate } 70277c478bd9Sstevel@tonic-gate /* 70287c478bd9Sstevel@tonic-gate * Now remove the queue from the syncq. 70297c478bd9Sstevel@tonic-gate */ 70307c478bd9Sstevel@tonic-gate ASSERT(q->q_sqflags & Q_SQQUEUED); 70317c478bd9Sstevel@tonic-gate SQRM_Q(sq, q); 70327c478bd9Sstevel@tonic-gate q->q_spri = 0; 70337c478bd9Sstevel@tonic-gate q->q_syncqmsgs = 0; 70347c478bd9Sstevel@tonic-gate 70357c478bd9Sstevel@tonic-gate /* 70367c478bd9Sstevel@tonic-gate * If qp was specified, we are done with it and are 70377c478bd9Sstevel@tonic-gate * going to drop SQLOCK(sq) and return. We wakeup syncq 70387c478bd9Sstevel@tonic-gate * waiters while we still have the SQLOCK. 70397c478bd9Sstevel@tonic-gate */ 70407c478bd9Sstevel@tonic-gate if ((qp != NULL) && (sq->sq_flags & SQ_WANTWAKEUP)) { 70417c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_WANTWAKEUP; 70427c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 70437c478bd9Sstevel@tonic-gate } 70447c478bd9Sstevel@tonic-gate /* Drop SQLOCK across clr_qfull */ 70457c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 70467c478bd9Sstevel@tonic-gate 70477c478bd9Sstevel@tonic-gate /* 70487c478bd9Sstevel@tonic-gate * We avoid doing the test that drain_syncq does and 70497c478bd9Sstevel@tonic-gate * unconditionally clear qfull for every flushed 70507c478bd9Sstevel@tonic-gate * message. Since flush_syncq is only called during 70517c478bd9Sstevel@tonic-gate * close this should not be a problem. 70527c478bd9Sstevel@tonic-gate */ 70537c478bd9Sstevel@tonic-gate clr_qfull(q); 70547c478bd9Sstevel@tonic-gate if (qp != NULL) { 70557c478bd9Sstevel@tonic-gate return (ret); 70567c478bd9Sstevel@tonic-gate } else { 70577c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 70587c478bd9Sstevel@tonic-gate /* 70597c478bd9Sstevel@tonic-gate * The head was removed by SQRM_Q above. 70607c478bd9Sstevel@tonic-gate * reread the new head and flush it. 70617c478bd9Sstevel@tonic-gate */ 70627c478bd9Sstevel@tonic-gate q = sq->sq_head; 70637c478bd9Sstevel@tonic-gate } 70647c478bd9Sstevel@tonic-gate } else { 70657c478bd9Sstevel@tonic-gate q = q->q_sqnext; 70667c478bd9Sstevel@tonic-gate } 70677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 70687c478bd9Sstevel@tonic-gate } 70697c478bd9Sstevel@tonic-gate 70707c478bd9Sstevel@tonic-gate if (sq->sq_flags & SQ_WANTWAKEUP) { 70717c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_WANTWAKEUP; 70727c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 70737c478bd9Sstevel@tonic-gate } 70747c478bd9Sstevel@tonic-gate 70757c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 70767c478bd9Sstevel@tonic-gate return (ret); 70777c478bd9Sstevel@tonic-gate } 70787c478bd9Sstevel@tonic-gate 70797c478bd9Sstevel@tonic-gate /* 70807c478bd9Sstevel@tonic-gate * Propagate all messages from a syncq to the next syncq that are associated 70817c478bd9Sstevel@tonic-gate * with the specified queue. If the queue is attached to a driver or if the 70827c478bd9Sstevel@tonic-gate * messages have been added due to a qwriter(PERIM_INNER), free the messages. 70837c478bd9Sstevel@tonic-gate * 70847c478bd9Sstevel@tonic-gate * Assumes that the stream is strlock()'ed. We don't come here if there 70857c478bd9Sstevel@tonic-gate * are no messages to propagate. 70867c478bd9Sstevel@tonic-gate * 70877c478bd9Sstevel@tonic-gate * NOTE : If the queue is attached to a driver, all the messages are freed 70887c478bd9Sstevel@tonic-gate * as there is no point in propagating the messages from the driver syncq 70897c478bd9Sstevel@tonic-gate * to the closing stream head which will in turn get freed later. 70907c478bd9Sstevel@tonic-gate */ 70917c478bd9Sstevel@tonic-gate static int 70927c478bd9Sstevel@tonic-gate propagate_syncq(queue_t *qp) 70937c478bd9Sstevel@tonic-gate { 70947c478bd9Sstevel@tonic-gate mblk_t *bp, *head, *tail, *prev, *next; 70957c478bd9Sstevel@tonic-gate syncq_t *sq; 70967c478bd9Sstevel@tonic-gate queue_t *nqp; 70977c478bd9Sstevel@tonic-gate syncq_t *nsq; 70987c478bd9Sstevel@tonic-gate boolean_t isdriver; 70997c478bd9Sstevel@tonic-gate int moved = 0; 71007c478bd9Sstevel@tonic-gate uint16_t flags; 71017c478bd9Sstevel@tonic-gate pri_t priority = curthread->t_pri; 71027c478bd9Sstevel@tonic-gate #ifdef DEBUG 71037c478bd9Sstevel@tonic-gate void (*func)(); 71047c478bd9Sstevel@tonic-gate #endif 71057c478bd9Sstevel@tonic-gate 71067c478bd9Sstevel@tonic-gate sq = qp->q_syncq; 71077c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 71087c478bd9Sstevel@tonic-gate /* debug macro */ 71097c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_HELD(sq); 71107c478bd9Sstevel@tonic-gate /* 71117c478bd9Sstevel@tonic-gate * As entersq() does not increment the sq_count for 71127c478bd9Sstevel@tonic-gate * the write side, check sq_count for non-QPERQ 71137c478bd9Sstevel@tonic-gate * perimeters alone. 71147c478bd9Sstevel@tonic-gate */ 71157c478bd9Sstevel@tonic-gate ASSERT((qp->q_flag & QPERQ) || (sq->sq_count >= 1)); 71167c478bd9Sstevel@tonic-gate 71177c478bd9Sstevel@tonic-gate /* 71187c478bd9Sstevel@tonic-gate * propagate_syncq() can be called because of either messages on the 71197c478bd9Sstevel@tonic-gate * queue syncq or because on events on the queue syncq. Do actual 71207c478bd9Sstevel@tonic-gate * message propagations if there are any messages. 71217c478bd9Sstevel@tonic-gate */ 71227c478bd9Sstevel@tonic-gate if (qp->q_syncqmsgs) { 71237c478bd9Sstevel@tonic-gate isdriver = (qp->q_flag & QISDRV); 71247c478bd9Sstevel@tonic-gate 71257c478bd9Sstevel@tonic-gate if (!isdriver) { 71267c478bd9Sstevel@tonic-gate nqp = qp->q_next; 71277c478bd9Sstevel@tonic-gate nsq = nqp->q_syncq; 71287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(nsq))); 71297c478bd9Sstevel@tonic-gate /* debug macro */ 71307c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_HELD(nsq); 71317c478bd9Sstevel@tonic-gate #ifdef DEBUG 71327c478bd9Sstevel@tonic-gate func = (void (*)())nqp->q_qinfo->qi_putp; 71337c478bd9Sstevel@tonic-gate #endif 71347c478bd9Sstevel@tonic-gate } 71357c478bd9Sstevel@tonic-gate 71367c478bd9Sstevel@tonic-gate SQRM_Q(sq, qp); 71377c478bd9Sstevel@tonic-gate priority = MAX(qp->q_spri, priority); 71387c478bd9Sstevel@tonic-gate qp->q_spri = 0; 71397c478bd9Sstevel@tonic-gate head = qp->q_sqhead; 71407c478bd9Sstevel@tonic-gate tail = qp->q_sqtail; 71417c478bd9Sstevel@tonic-gate qp->q_sqhead = qp->q_sqtail = NULL; 71427c478bd9Sstevel@tonic-gate qp->q_syncqmsgs = 0; 71437c478bd9Sstevel@tonic-gate 71447c478bd9Sstevel@tonic-gate /* 71457c478bd9Sstevel@tonic-gate * Walk the list of messages, and free them if this is a driver, 71467c478bd9Sstevel@tonic-gate * otherwise reset the b_prev and b_queue value to the new putp. 71477c478bd9Sstevel@tonic-gate * Afterward, we will just add the head to the end of the next 71487c478bd9Sstevel@tonic-gate * syncq, and point the tail to the end of this one. 71497c478bd9Sstevel@tonic-gate */ 71507c478bd9Sstevel@tonic-gate 71517c478bd9Sstevel@tonic-gate for (bp = head; bp != NULL; bp = next) { 71527c478bd9Sstevel@tonic-gate next = bp->b_next; 71537c478bd9Sstevel@tonic-gate if (isdriver) { 71547c478bd9Sstevel@tonic-gate bp->b_prev = bp->b_next = NULL; 71557c478bd9Sstevel@tonic-gate freemsg(bp); 71567c478bd9Sstevel@tonic-gate continue; 71577c478bd9Sstevel@tonic-gate } 71587c478bd9Sstevel@tonic-gate /* Change the q values for this message */ 71597c478bd9Sstevel@tonic-gate bp->b_queue = nqp; 71607c478bd9Sstevel@tonic-gate #ifdef DEBUG 71617c478bd9Sstevel@tonic-gate bp->b_prev = (mblk_t *)func; 71627c478bd9Sstevel@tonic-gate #endif 71637c478bd9Sstevel@tonic-gate moved++; 71647c478bd9Sstevel@tonic-gate } 71657c478bd9Sstevel@tonic-gate /* 71667c478bd9Sstevel@tonic-gate * Attach list of messages to the end of the new queue (if there 71677c478bd9Sstevel@tonic-gate * is a list of messages). 71687c478bd9Sstevel@tonic-gate */ 71697c478bd9Sstevel@tonic-gate 71707c478bd9Sstevel@tonic-gate if (!isdriver && head != NULL) { 71717c478bd9Sstevel@tonic-gate ASSERT(tail != NULL); 71727c478bd9Sstevel@tonic-gate if (nqp->q_sqhead == NULL) { 71737c478bd9Sstevel@tonic-gate nqp->q_sqhead = head; 71747c478bd9Sstevel@tonic-gate } else { 71757c478bd9Sstevel@tonic-gate ASSERT(nqp->q_sqtail != NULL); 71767c478bd9Sstevel@tonic-gate nqp->q_sqtail->b_next = head; 71777c478bd9Sstevel@tonic-gate } 71787c478bd9Sstevel@tonic-gate nqp->q_sqtail = tail; 71797c478bd9Sstevel@tonic-gate /* 71807c478bd9Sstevel@tonic-gate * When messages are moved from high priority queue to 71817c478bd9Sstevel@tonic-gate * another queue, the destination queue priority is 71827c478bd9Sstevel@tonic-gate * upgraded. 71837c478bd9Sstevel@tonic-gate */ 71847c478bd9Sstevel@tonic-gate 71857c478bd9Sstevel@tonic-gate if (priority > nqp->q_spri) 71867c478bd9Sstevel@tonic-gate nqp->q_spri = priority; 71877c478bd9Sstevel@tonic-gate 71887c478bd9Sstevel@tonic-gate SQPUT_Q(nsq, nqp); 71897c478bd9Sstevel@tonic-gate 71907c478bd9Sstevel@tonic-gate nqp->q_syncqmsgs += moved; 71917c478bd9Sstevel@tonic-gate ASSERT(nqp->q_syncqmsgs != 0); 71927c478bd9Sstevel@tonic-gate } 71937c478bd9Sstevel@tonic-gate } 71947c478bd9Sstevel@tonic-gate 71957c478bd9Sstevel@tonic-gate /* 71967c478bd9Sstevel@tonic-gate * Before we leave, we need to make sure there are no 71977c478bd9Sstevel@tonic-gate * events listed for this queue. All events for this queue 71987c478bd9Sstevel@tonic-gate * will just be freed. 71997c478bd9Sstevel@tonic-gate */ 72007c478bd9Sstevel@tonic-gate if (sq->sq_evhead != NULL) { 72017c478bd9Sstevel@tonic-gate ASSERT(sq->sq_flags & SQ_EVENTS); 72027c478bd9Sstevel@tonic-gate prev = NULL; 72037c478bd9Sstevel@tonic-gate for (bp = sq->sq_evhead; bp != NULL; bp = next) { 72047c478bd9Sstevel@tonic-gate next = bp->b_next; 72057c478bd9Sstevel@tonic-gate if (bp->b_queue == qp) { 72067c478bd9Sstevel@tonic-gate /* Delete this message */ 72077c478bd9Sstevel@tonic-gate if (prev != NULL) { 72087c478bd9Sstevel@tonic-gate prev->b_next = next; 72097c478bd9Sstevel@tonic-gate /* 72107c478bd9Sstevel@tonic-gate * Update sq_evtail if the last element 72117c478bd9Sstevel@tonic-gate * is removed. 72127c478bd9Sstevel@tonic-gate */ 72137c478bd9Sstevel@tonic-gate if (bp == sq->sq_evtail) { 72147c478bd9Sstevel@tonic-gate ASSERT(next == NULL); 72157c478bd9Sstevel@tonic-gate sq->sq_evtail = prev; 72167c478bd9Sstevel@tonic-gate } 72177c478bd9Sstevel@tonic-gate } else 72187c478bd9Sstevel@tonic-gate sq->sq_evhead = next; 72197c478bd9Sstevel@tonic-gate if (sq->sq_evhead == NULL) 72207c478bd9Sstevel@tonic-gate sq->sq_flags &= ~SQ_EVENTS; 72217c478bd9Sstevel@tonic-gate bp->b_prev = bp->b_next = NULL; 72227c478bd9Sstevel@tonic-gate freemsg(bp); 72237c478bd9Sstevel@tonic-gate } else { 72247c478bd9Sstevel@tonic-gate prev = bp; 72257c478bd9Sstevel@tonic-gate } 72267c478bd9Sstevel@tonic-gate } 72277c478bd9Sstevel@tonic-gate } 72287c478bd9Sstevel@tonic-gate 72297c478bd9Sstevel@tonic-gate flags = sq->sq_flags; 72307c478bd9Sstevel@tonic-gate 72317c478bd9Sstevel@tonic-gate /* Wake up any waiter before leaving. */ 72327c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 72337c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 72347c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 72357c478bd9Sstevel@tonic-gate } 72367c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 72377c478bd9Sstevel@tonic-gate 72387c478bd9Sstevel@tonic-gate return (moved); 72397c478bd9Sstevel@tonic-gate } 72407c478bd9Sstevel@tonic-gate 72417c478bd9Sstevel@tonic-gate /* 72427c478bd9Sstevel@tonic-gate * Try and upgrade to exclusive access at the inner perimeter. If this can 72437c478bd9Sstevel@tonic-gate * not be done without blocking then request will be queued on the syncq 72447c478bd9Sstevel@tonic-gate * and drain_syncq will run it later. 72457c478bd9Sstevel@tonic-gate * 72467c478bd9Sstevel@tonic-gate * This routine can only be called from put or service procedures plus 724721804b56SBrian Ruthven * asynchronous callback routines that have properly entered the queue (with 724821804b56SBrian Ruthven * entersq). Thus qwriter_inner assumes the caller has one claim on the syncq 724921804b56SBrian Ruthven * associated with q. 72507c478bd9Sstevel@tonic-gate */ 72517c478bd9Sstevel@tonic-gate void 72527c478bd9Sstevel@tonic-gate qwriter_inner(queue_t *q, mblk_t *mp, void (*func)()) 72537c478bd9Sstevel@tonic-gate { 72547c478bd9Sstevel@tonic-gate syncq_t *sq = q->q_syncq; 72557c478bd9Sstevel@tonic-gate uint16_t count; 72567c478bd9Sstevel@tonic-gate 72577c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 72587c478bd9Sstevel@tonic-gate count = sq->sq_count; 72597c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 72607c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 72617c478bd9Sstevel@tonic-gate ASSERT(count >= 1); 72627c478bd9Sstevel@tonic-gate ASSERT(sq->sq_type & (SQ_CIPUT|SQ_CISVC)); 72637c478bd9Sstevel@tonic-gate 72647c478bd9Sstevel@tonic-gate if (count == 1) { 72657c478bd9Sstevel@tonic-gate /* 72667c478bd9Sstevel@tonic-gate * Can upgrade. This case also handles nested qwriter calls 72677c478bd9Sstevel@tonic-gate * (when the qwriter callback function calls qwriter). In that 72687c478bd9Sstevel@tonic-gate * case SQ_EXCL is already set. 72697c478bd9Sstevel@tonic-gate */ 72707c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 72717c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 72727c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 72737c478bd9Sstevel@tonic-gate (*func)(q, mp); 72747c478bd9Sstevel@tonic-gate /* 72757c478bd9Sstevel@tonic-gate * Assumes that leavesq, putnext, and drain_syncq will reset 72767c478bd9Sstevel@tonic-gate * SQ_EXCL for SQ_CIPUT/SQ_CISVC queues. We leave SQ_EXCL on 72777c478bd9Sstevel@tonic-gate * until putnext, leavesq, or drain_syncq drops it. 72787c478bd9Sstevel@tonic-gate * That way we handle nested qwriter(INNER) without dropping 72797c478bd9Sstevel@tonic-gate * SQ_EXCL until the outermost qwriter callback routine is 72807c478bd9Sstevel@tonic-gate * done. 72817c478bd9Sstevel@tonic-gate */ 72827c478bd9Sstevel@tonic-gate return; 72837c478bd9Sstevel@tonic-gate } 72847c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 72857c478bd9Sstevel@tonic-gate sqfill_events(sq, q, mp, func); 72867c478bd9Sstevel@tonic-gate } 72877c478bd9Sstevel@tonic-gate 72887c478bd9Sstevel@tonic-gate /* 72897c478bd9Sstevel@tonic-gate * Synchronous callback support functions 72907c478bd9Sstevel@tonic-gate */ 72917c478bd9Sstevel@tonic-gate 72927c478bd9Sstevel@tonic-gate /* 72937c478bd9Sstevel@tonic-gate * Allocate a callback parameter structure. 72947c478bd9Sstevel@tonic-gate * Assumes that caller initializes the flags and the id. 72957c478bd9Sstevel@tonic-gate * Acquires SQLOCK(sq) if non-NULL is returned. 72967c478bd9Sstevel@tonic-gate */ 72977c478bd9Sstevel@tonic-gate callbparams_t * 72987c478bd9Sstevel@tonic-gate callbparams_alloc(syncq_t *sq, void (*func)(void *), void *arg, int kmflags) 72997c478bd9Sstevel@tonic-gate { 73007c478bd9Sstevel@tonic-gate callbparams_t *cbp; 73017c478bd9Sstevel@tonic-gate size_t size = sizeof (callbparams_t); 73027c478bd9Sstevel@tonic-gate 73037c478bd9Sstevel@tonic-gate cbp = kmem_alloc(size, kmflags & ~KM_PANIC); 73047c478bd9Sstevel@tonic-gate 73057c478bd9Sstevel@tonic-gate /* 73067c478bd9Sstevel@tonic-gate * Only try tryhard allocation if the caller is ready to panic. 73077c478bd9Sstevel@tonic-gate * Otherwise just fail. 73087c478bd9Sstevel@tonic-gate */ 73097c478bd9Sstevel@tonic-gate if (cbp == NULL) { 73107c478bd9Sstevel@tonic-gate if (kmflags & KM_PANIC) 73117c478bd9Sstevel@tonic-gate cbp = kmem_alloc_tryhard(sizeof (callbparams_t), 73127c478bd9Sstevel@tonic-gate &size, kmflags); 73137c478bd9Sstevel@tonic-gate else 73147c478bd9Sstevel@tonic-gate return (NULL); 73157c478bd9Sstevel@tonic-gate } 73167c478bd9Sstevel@tonic-gate 73177c478bd9Sstevel@tonic-gate ASSERT(size >= sizeof (callbparams_t)); 73187c478bd9Sstevel@tonic-gate cbp->cbp_size = size; 73197c478bd9Sstevel@tonic-gate cbp->cbp_sq = sq; 73207c478bd9Sstevel@tonic-gate cbp->cbp_func = func; 73217c478bd9Sstevel@tonic-gate cbp->cbp_arg = arg; 73227c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 73237c478bd9Sstevel@tonic-gate cbp->cbp_next = sq->sq_callbpend; 73247c478bd9Sstevel@tonic-gate sq->sq_callbpend = cbp; 73257c478bd9Sstevel@tonic-gate return (cbp); 73267c478bd9Sstevel@tonic-gate } 73277c478bd9Sstevel@tonic-gate 73287c478bd9Sstevel@tonic-gate void 73297c478bd9Sstevel@tonic-gate callbparams_free(syncq_t *sq, callbparams_t *cbp) 73307c478bd9Sstevel@tonic-gate { 73317c478bd9Sstevel@tonic-gate callbparams_t **pp, *p; 73327c478bd9Sstevel@tonic-gate 73337c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 73347c478bd9Sstevel@tonic-gate 73357c478bd9Sstevel@tonic-gate for (pp = &sq->sq_callbpend; (p = *pp) != NULL; pp = &p->cbp_next) { 73367c478bd9Sstevel@tonic-gate if (p == cbp) { 73377c478bd9Sstevel@tonic-gate *pp = p->cbp_next; 73387c478bd9Sstevel@tonic-gate kmem_free(p, p->cbp_size); 73397c478bd9Sstevel@tonic-gate return; 73407c478bd9Sstevel@tonic-gate } 73417c478bd9Sstevel@tonic-gate } 73427c478bd9Sstevel@tonic-gate (void) (STRLOG(0, 0, 0, SL_CONSOLE, 73437c478bd9Sstevel@tonic-gate "callbparams_free: not found\n")); 73447c478bd9Sstevel@tonic-gate } 73457c478bd9Sstevel@tonic-gate 73467c478bd9Sstevel@tonic-gate void 73477c478bd9Sstevel@tonic-gate callbparams_free_id(syncq_t *sq, callbparams_id_t id, int32_t flag) 73487c478bd9Sstevel@tonic-gate { 73497c478bd9Sstevel@tonic-gate callbparams_t **pp, *p; 73507c478bd9Sstevel@tonic-gate 73517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 73527c478bd9Sstevel@tonic-gate 73537c478bd9Sstevel@tonic-gate for (pp = &sq->sq_callbpend; (p = *pp) != NULL; pp = &p->cbp_next) { 73547c478bd9Sstevel@tonic-gate if (p->cbp_id == id && p->cbp_flags == flag) { 73557c478bd9Sstevel@tonic-gate *pp = p->cbp_next; 73567c478bd9Sstevel@tonic-gate kmem_free(p, p->cbp_size); 73577c478bd9Sstevel@tonic-gate return; 73587c478bd9Sstevel@tonic-gate } 73597c478bd9Sstevel@tonic-gate } 73607c478bd9Sstevel@tonic-gate (void) (STRLOG(0, 0, 0, SL_CONSOLE, 73617c478bd9Sstevel@tonic-gate "callbparams_free_id: not found\n")); 73627c478bd9Sstevel@tonic-gate } 73637c478bd9Sstevel@tonic-gate 73647c478bd9Sstevel@tonic-gate /* 73657c478bd9Sstevel@tonic-gate * Callback wrapper function used by once-only callbacks that can be 73667c478bd9Sstevel@tonic-gate * cancelled (qtimeout and qbufcall) 73677c478bd9Sstevel@tonic-gate * Contains inline version of entersq(sq, SQ_CALLBACK) that can be 73687c478bd9Sstevel@tonic-gate * cancelled by the qun* functions. 73697c478bd9Sstevel@tonic-gate */ 73707c478bd9Sstevel@tonic-gate void 73717c478bd9Sstevel@tonic-gate qcallbwrapper(void *arg) 73727c478bd9Sstevel@tonic-gate { 73737c478bd9Sstevel@tonic-gate callbparams_t *cbp = arg; 73747c478bd9Sstevel@tonic-gate syncq_t *sq; 73757c478bd9Sstevel@tonic-gate uint16_t count = 0; 73767c478bd9Sstevel@tonic-gate uint16_t waitflags = SQ_STAYAWAY | SQ_EVENTS | SQ_EXCL; 73777c478bd9Sstevel@tonic-gate uint16_t type; 73787c478bd9Sstevel@tonic-gate 73797c478bd9Sstevel@tonic-gate sq = cbp->cbp_sq; 73807c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 73817c478bd9Sstevel@tonic-gate type = sq->sq_type; 73827c478bd9Sstevel@tonic-gate if (!(type & SQ_CICB)) { 73837c478bd9Sstevel@tonic-gate count = sq->sq_count; 73847c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 73857c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_CLRFAST_LOCKED(sq); 73867c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 73877c478bd9Sstevel@tonic-gate sq->sq_needexcl++; 73887c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl != 0); /* wraparound */ 73897c478bd9Sstevel@tonic-gate waitflags |= SQ_MESSAGES; 73907c478bd9Sstevel@tonic-gate } 739121804b56SBrian Ruthven /* Can not handle exclusive entry at outer perimeter */ 73927c478bd9Sstevel@tonic-gate ASSERT(type & SQ_COCB); 73937c478bd9Sstevel@tonic-gate 73947c478bd9Sstevel@tonic-gate while ((sq->sq_flags & waitflags) || (!(type & SQ_CICB) &&count != 0)) { 73957c478bd9Sstevel@tonic-gate if ((sq->sq_callbflags & cbp->cbp_flags) && 73967c478bd9Sstevel@tonic-gate (sq->sq_cancelid == cbp->cbp_id)) { 73977c478bd9Sstevel@tonic-gate /* timeout has been cancelled */ 73987c478bd9Sstevel@tonic-gate sq->sq_callbflags |= SQ_CALLB_BYPASSED; 73997c478bd9Sstevel@tonic-gate callbparams_free(sq, cbp); 74007c478bd9Sstevel@tonic-gate if (!(type & SQ_CICB)) { 74017c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl > 0); 74027c478bd9Sstevel@tonic-gate sq->sq_needexcl--; 74037c478bd9Sstevel@tonic-gate if (sq->sq_needexcl == 0) { 74047c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_SETFAST_LOCKED(sq); 74057c478bd9Sstevel@tonic-gate } 74067c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 74077c478bd9Sstevel@tonic-gate } 74087c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 74097c478bd9Sstevel@tonic-gate return; 74107c478bd9Sstevel@tonic-gate } 74117c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_WANTWAKEUP; 74127c478bd9Sstevel@tonic-gate if (!(type & SQ_CICB)) { 74137c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 74147c478bd9Sstevel@tonic-gate } 74157c478bd9Sstevel@tonic-gate cv_wait(&sq->sq_wait, SQLOCK(sq)); 74167c478bd9Sstevel@tonic-gate if (!(type & SQ_CICB)) { 74177c478bd9Sstevel@tonic-gate count = sq->sq_count; 74187c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_ENTER(sq); 74197c478bd9Sstevel@tonic-gate SUM_SQ_PUTCOUNTS(sq, count); 74207c478bd9Sstevel@tonic-gate } 74217c478bd9Sstevel@tonic-gate } 74227c478bd9Sstevel@tonic-gate 74237c478bd9Sstevel@tonic-gate sq->sq_count++; 74247c478bd9Sstevel@tonic-gate ASSERT(sq->sq_count != 0); /* Wraparound */ 74257c478bd9Sstevel@tonic-gate if (!(type & SQ_CICB)) { 74267c478bd9Sstevel@tonic-gate ASSERT(count == 0); 74277c478bd9Sstevel@tonic-gate sq->sq_flags |= SQ_EXCL; 74287c478bd9Sstevel@tonic-gate ASSERT(sq->sq_needexcl > 0); 74297c478bd9Sstevel@tonic-gate sq->sq_needexcl--; 74307c478bd9Sstevel@tonic-gate if (sq->sq_needexcl == 0) { 74317c478bd9Sstevel@tonic-gate SQ_PUTCOUNT_SETFAST_LOCKED(sq); 74327c478bd9Sstevel@tonic-gate } 74337c478bd9Sstevel@tonic-gate SQ_PUTLOCKS_EXIT(sq); 74347c478bd9Sstevel@tonic-gate } 74357c478bd9Sstevel@tonic-gate 74367c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 74377c478bd9Sstevel@tonic-gate 74387c478bd9Sstevel@tonic-gate cbp->cbp_func(cbp->cbp_arg); 74397c478bd9Sstevel@tonic-gate 74407c478bd9Sstevel@tonic-gate /* 74417c478bd9Sstevel@tonic-gate * We drop the lock only for leavesq to re-acquire it. 74427c478bd9Sstevel@tonic-gate * Possible optimization is inline of leavesq. 74437c478bd9Sstevel@tonic-gate */ 74447c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 74457c478bd9Sstevel@tonic-gate callbparams_free(sq, cbp); 74467c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 74477c478bd9Sstevel@tonic-gate leavesq(sq, SQ_CALLBACK); 74487c478bd9Sstevel@tonic-gate } 74497c478bd9Sstevel@tonic-gate 74507c478bd9Sstevel@tonic-gate /* 745121804b56SBrian Ruthven * No need to grab sq_putlocks here. See comment in strsubr.h that 74527c478bd9Sstevel@tonic-gate * explains when sq_putlocks are used. 74537c478bd9Sstevel@tonic-gate * 74547c478bd9Sstevel@tonic-gate * sq_count (or one of the sq_putcounts) has already been 74557c478bd9Sstevel@tonic-gate * decremented by the caller, and if SQ_QUEUED, we need to call 74567c478bd9Sstevel@tonic-gate * drain_syncq (the global syncq drain). 74577c478bd9Sstevel@tonic-gate * If putnext_tail is called with the SQ_EXCL bit set, we are in 745821804b56SBrian Ruthven * one of two states, non-CIPUT perimeter, and we need to clear 74597c478bd9Sstevel@tonic-gate * it, or we went exclusive in the put procedure. In any case, 74607c478bd9Sstevel@tonic-gate * we want to clear the bit now, and it is probably easier to do 74617c478bd9Sstevel@tonic-gate * this at the beginning of this function (remember, we hold 74627c478bd9Sstevel@tonic-gate * the SQLOCK). Lastly, if there are other messages queued 74637c478bd9Sstevel@tonic-gate * on the syncq (and not for our destination), enable the syncq 74647c478bd9Sstevel@tonic-gate * for background work. 74657c478bd9Sstevel@tonic-gate */ 74667c478bd9Sstevel@tonic-gate 74677c478bd9Sstevel@tonic-gate /* ARGSUSED */ 74687c478bd9Sstevel@tonic-gate void 74697c478bd9Sstevel@tonic-gate putnext_tail(syncq_t *sq, queue_t *qp, uint32_t passflags) 74707c478bd9Sstevel@tonic-gate { 74717c478bd9Sstevel@tonic-gate uint16_t flags = sq->sq_flags; 74727c478bd9Sstevel@tonic-gate 74737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(SQLOCK(sq))); 74747c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(QLOCK(qp))); 74757c478bd9Sstevel@tonic-gate 74767c478bd9Sstevel@tonic-gate /* Clear SQ_EXCL if set in passflags */ 74777c478bd9Sstevel@tonic-gate if (passflags & SQ_EXCL) { 74787c478bd9Sstevel@tonic-gate flags &= ~SQ_EXCL; 74797c478bd9Sstevel@tonic-gate } 74807c478bd9Sstevel@tonic-gate if (flags & SQ_WANTWAKEUP) { 74817c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTWAKEUP; 74827c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_wait); 74837c478bd9Sstevel@tonic-gate } 74847c478bd9Sstevel@tonic-gate if (flags & SQ_WANTEXWAKEUP) { 74857c478bd9Sstevel@tonic-gate flags &= ~SQ_WANTEXWAKEUP; 74867c478bd9Sstevel@tonic-gate cv_broadcast(&sq->sq_exitwait); 74877c478bd9Sstevel@tonic-gate } 74887c478bd9Sstevel@tonic-gate sq->sq_flags = flags; 74897c478bd9Sstevel@tonic-gate 74907c478bd9Sstevel@tonic-gate /* 74917c478bd9Sstevel@tonic-gate * We have cleared SQ_EXCL if we were asked to, and started 74927c478bd9Sstevel@tonic-gate * the wakeup process for waiters. If there are no writers 74937c478bd9Sstevel@tonic-gate * then we need to drain the syncq if we were told to, or 74947c478bd9Sstevel@tonic-gate * enable the background thread to do it. 74957c478bd9Sstevel@tonic-gate */ 74967c478bd9Sstevel@tonic-gate if (!(flags & (SQ_STAYAWAY|SQ_EXCL))) { 74977c478bd9Sstevel@tonic-gate if ((passflags & SQ_QUEUED) || 74987c478bd9Sstevel@tonic-gate (sq->sq_svcflags & SQ_DISABLED)) { 74997c478bd9Sstevel@tonic-gate /* drain_syncq will take care of events in the list */ 75007c478bd9Sstevel@tonic-gate drain_syncq(sq); 75017c478bd9Sstevel@tonic-gate return; 75027c478bd9Sstevel@tonic-gate } else if (flags & SQ_QUEUED) { 75037c478bd9Sstevel@tonic-gate sqenable(sq); 75047c478bd9Sstevel@tonic-gate } 75057c478bd9Sstevel@tonic-gate } 75067c478bd9Sstevel@tonic-gate /* Drop the SQLOCK on exit */ 75077c478bd9Sstevel@tonic-gate mutex_exit(SQLOCK(sq)); 75087c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_STREAMS_FR, TR_PUTNEXT_END, 75097c478bd9Sstevel@tonic-gate "putnext_end:(%p, %p, %p) done", NULL, qp, sq); 75107c478bd9Sstevel@tonic-gate } 75117c478bd9Sstevel@tonic-gate 75127c478bd9Sstevel@tonic-gate void 75137c478bd9Sstevel@tonic-gate set_qend(queue_t *q) 75147c478bd9Sstevel@tonic-gate { 75157c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 75167c478bd9Sstevel@tonic-gate if (!O_SAMESTR(q)) 75177c478bd9Sstevel@tonic-gate q->q_flag |= QEND; 75187c478bd9Sstevel@tonic-gate else 75197c478bd9Sstevel@tonic-gate q->q_flag &= ~QEND; 75207c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 75217c478bd9Sstevel@tonic-gate q = _OTHERQ(q); 75227c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 75237c478bd9Sstevel@tonic-gate if (!O_SAMESTR(q)) 75247c478bd9Sstevel@tonic-gate q->q_flag |= QEND; 75257c478bd9Sstevel@tonic-gate else 75267c478bd9Sstevel@tonic-gate q->q_flag &= ~QEND; 75277c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 75287c478bd9Sstevel@tonic-gate } 75297c478bd9Sstevel@tonic-gate 75305ba3fab4Sjk115741 /* 75315ba3fab4Sjk115741 * Set QFULL in next service procedure queue (that cares) if not already 75325ba3fab4Sjk115741 * set and if there are already more messages on the syncq than 75335ba3fab4Sjk115741 * sq_max_size. If sq_max_size is 0, no flow control will be asserted on 75345ba3fab4Sjk115741 * any syncq. 75355ba3fab4Sjk115741 * 75365ba3fab4Sjk115741 * The fq here is the next queue with a service procedure. This is where 75375ba3fab4Sjk115741 * we would fail canputnext, so this is where we need to set QFULL. 75385ba3fab4Sjk115741 * In the case when fq != q we need to take QLOCK(fq) to set QFULL flag. 75395ba3fab4Sjk115741 * 75405ba3fab4Sjk115741 * We already have QLOCK at this point. To avoid cross-locks with 75415ba3fab4Sjk115741 * freezestr() which grabs all QLOCKs and with strlock() which grabs both 75425ba3fab4Sjk115741 * SQLOCK and sd_reflock, we need to drop respective locks first. 75435ba3fab4Sjk115741 */ 75445ba3fab4Sjk115741 void 75455ba3fab4Sjk115741 set_qfull(queue_t *q) 75465ba3fab4Sjk115741 { 75475ba3fab4Sjk115741 queue_t *fq = NULL; 75485ba3fab4Sjk115741 75495ba3fab4Sjk115741 ASSERT(MUTEX_HELD(QLOCK(q))); 75505ba3fab4Sjk115741 if ((sq_max_size != 0) && (!(q->q_nfsrv->q_flag & QFULL)) && 75515ba3fab4Sjk115741 (q->q_syncqmsgs > sq_max_size)) { 75525ba3fab4Sjk115741 if ((fq = q->q_nfsrv) == q) { 75535ba3fab4Sjk115741 fq->q_flag |= QFULL; 75545ba3fab4Sjk115741 } else { 75555ba3fab4Sjk115741 mutex_exit(QLOCK(q)); 75565ba3fab4Sjk115741 mutex_enter(QLOCK(fq)); 75575ba3fab4Sjk115741 fq->q_flag |= QFULL; 75585ba3fab4Sjk115741 mutex_exit(QLOCK(fq)); 75595ba3fab4Sjk115741 mutex_enter(QLOCK(q)); 75605ba3fab4Sjk115741 } 75615ba3fab4Sjk115741 } 75625ba3fab4Sjk115741 } 75637c478bd9Sstevel@tonic-gate 75647c478bd9Sstevel@tonic-gate void 75657c478bd9Sstevel@tonic-gate clr_qfull(queue_t *q) 75667c478bd9Sstevel@tonic-gate { 75677c478bd9Sstevel@tonic-gate queue_t *oq = q; 75687c478bd9Sstevel@tonic-gate 75697c478bd9Sstevel@tonic-gate q = q->q_nfsrv; 75707c478bd9Sstevel@tonic-gate /* Fast check if there is any work to do before getting the lock. */ 75717c478bd9Sstevel@tonic-gate if ((q->q_flag & (QFULL|QWANTW)) == 0) { 75727c478bd9Sstevel@tonic-gate return; 75737c478bd9Sstevel@tonic-gate } 75747c478bd9Sstevel@tonic-gate 75757c478bd9Sstevel@tonic-gate /* 75767c478bd9Sstevel@tonic-gate * Do not reset QFULL (and backenable) if the q_count is the reason 75777c478bd9Sstevel@tonic-gate * for QFULL being set. 75787c478bd9Sstevel@tonic-gate */ 75797c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 75807c478bd9Sstevel@tonic-gate /* 7581ba464308Srk129064 * If queue is empty i.e q_mblkcnt is zero, queue can not be full. 7582ba464308Srk129064 * Hence clear the QFULL. 7583ba464308Srk129064 * If both q_count and q_mblkcnt are less than the hiwat mark, 7584ba464308Srk129064 * clear the QFULL. 75857c478bd9Sstevel@tonic-gate */ 7586ba464308Srk129064 if (q->q_mblkcnt == 0 || ((q->q_count < q->q_hiwat) && 7587ba464308Srk129064 (q->q_mblkcnt < q->q_hiwat))) { 75887c478bd9Sstevel@tonic-gate q->q_flag &= ~QFULL; 75897c478bd9Sstevel@tonic-gate /* 75907c478bd9Sstevel@tonic-gate * A little more confusing, how about this way: 75917c478bd9Sstevel@tonic-gate * if someone wants to write, 75927c478bd9Sstevel@tonic-gate * AND 75937c478bd9Sstevel@tonic-gate * both counts are less than the lowat mark 75947c478bd9Sstevel@tonic-gate * OR 75957c478bd9Sstevel@tonic-gate * the lowat mark is zero 75967c478bd9Sstevel@tonic-gate * THEN 75977c478bd9Sstevel@tonic-gate * backenable 75987c478bd9Sstevel@tonic-gate */ 75997c478bd9Sstevel@tonic-gate if ((q->q_flag & QWANTW) && 76007c478bd9Sstevel@tonic-gate (((q->q_count < q->q_lowat) && 76017c478bd9Sstevel@tonic-gate (q->q_mblkcnt < q->q_lowat)) || q->q_lowat == 0)) { 76027c478bd9Sstevel@tonic-gate q->q_flag &= ~QWANTW; 76037c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 76047c478bd9Sstevel@tonic-gate backenable(oq, 0); 76057c478bd9Sstevel@tonic-gate } else 76067c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 76077c478bd9Sstevel@tonic-gate } else 76087c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 76097c478bd9Sstevel@tonic-gate } 76107c478bd9Sstevel@tonic-gate 76117c478bd9Sstevel@tonic-gate /* 76127c478bd9Sstevel@tonic-gate * Set the forward service procedure pointer. 76137c478bd9Sstevel@tonic-gate * 76147c478bd9Sstevel@tonic-gate * Called at insert-time to cache a queue's next forward service procedure in 76157c478bd9Sstevel@tonic-gate * q_nfsrv; used by canput() and canputnext(). If the queue to be inserted 76167c478bd9Sstevel@tonic-gate * has a service procedure then q_nfsrv points to itself. If the queue to be 76177c478bd9Sstevel@tonic-gate * inserted does not have a service procedure, then q_nfsrv points to the next 76187c478bd9Sstevel@tonic-gate * queue forward that has a service procedure. If the queue is at the logical 76197c478bd9Sstevel@tonic-gate * end of the stream (driver for write side, stream head for the read side) 76207c478bd9Sstevel@tonic-gate * and does not have a service procedure, then q_nfsrv also points to itself. 76217c478bd9Sstevel@tonic-gate */ 76227c478bd9Sstevel@tonic-gate void 76237c478bd9Sstevel@tonic-gate set_nfsrv_ptr( 76247c478bd9Sstevel@tonic-gate queue_t *rnew, /* read queue pointer to new module */ 76257c478bd9Sstevel@tonic-gate queue_t *wnew, /* write queue pointer to new module */ 76267c478bd9Sstevel@tonic-gate queue_t *prev_rq, /* read queue pointer to the module above */ 76277c478bd9Sstevel@tonic-gate queue_t *prev_wq) /* write queue pointer to the module above */ 76287c478bd9Sstevel@tonic-gate { 76297c478bd9Sstevel@tonic-gate queue_t *qp; 76307c478bd9Sstevel@tonic-gate 76317c478bd9Sstevel@tonic-gate if (prev_wq->q_next == NULL) { 76327c478bd9Sstevel@tonic-gate /* 76337c478bd9Sstevel@tonic-gate * Insert the driver, initialize the driver and stream head. 76347c478bd9Sstevel@tonic-gate * In this case, prev_rq/prev_wq should be the stream head. 76357c478bd9Sstevel@tonic-gate * _I_INSERT does not allow inserting a driver. Make sure 76367c478bd9Sstevel@tonic-gate * that it is not an insertion. 76377c478bd9Sstevel@tonic-gate */ 76387c478bd9Sstevel@tonic-gate ASSERT(!(rnew->q_flag & _QINSERTING)); 76397c478bd9Sstevel@tonic-gate wnew->q_nfsrv = wnew; 76407c478bd9Sstevel@tonic-gate if (rnew->q_qinfo->qi_srvp) 76417c478bd9Sstevel@tonic-gate rnew->q_nfsrv = rnew; 76427c478bd9Sstevel@tonic-gate else 76437c478bd9Sstevel@tonic-gate rnew->q_nfsrv = prev_rq; 76447c478bd9Sstevel@tonic-gate prev_rq->q_nfsrv = prev_rq; 76457c478bd9Sstevel@tonic-gate prev_wq->q_nfsrv = prev_wq; 76467c478bd9Sstevel@tonic-gate } else { 76477c478bd9Sstevel@tonic-gate /* 76487c478bd9Sstevel@tonic-gate * set up read side q_nfsrv pointer. This MUST be done 76497c478bd9Sstevel@tonic-gate * before setting the write side, because the setting of 76507c478bd9Sstevel@tonic-gate * the write side for a fifo may depend on it. 76517c478bd9Sstevel@tonic-gate * 76527c478bd9Sstevel@tonic-gate * Suppose we have a fifo that only has pipemod pushed. 76537c478bd9Sstevel@tonic-gate * pipemod has no read or write service procedures, so 76547c478bd9Sstevel@tonic-gate * nfsrv for both pipemod queues points to prev_rq (the 76557c478bd9Sstevel@tonic-gate * stream read head). Now push bufmod (which has only a 76567c478bd9Sstevel@tonic-gate * read service procedure). Doing the write side first, 76577c478bd9Sstevel@tonic-gate * wnew->q_nfsrv is set to pipemod's writeq nfsrv, which 76587c478bd9Sstevel@tonic-gate * is WRONG; the next queue forward from wnew with a 76597c478bd9Sstevel@tonic-gate * service procedure will be rnew, not the stream read head. 76607c478bd9Sstevel@tonic-gate * Since the downstream queue (which in the case of a fifo 76617c478bd9Sstevel@tonic-gate * is the read queue rnew) can affect upstream queues, it 76627c478bd9Sstevel@tonic-gate * needs to be done first. Setting up the read side first 76637c478bd9Sstevel@tonic-gate * sets nfsrv for both pipemod queues to rnew and then 76647c478bd9Sstevel@tonic-gate * when the write side is set up, wnew-q_nfsrv will also 76657c478bd9Sstevel@tonic-gate * point to rnew. 76667c478bd9Sstevel@tonic-gate */ 76677c478bd9Sstevel@tonic-gate if (rnew->q_qinfo->qi_srvp) { 76687c478bd9Sstevel@tonic-gate /* 76697c478bd9Sstevel@tonic-gate * use _OTHERQ() because, if this is a pipe, next 76707c478bd9Sstevel@tonic-gate * module may have been pushed from other end and 76717c478bd9Sstevel@tonic-gate * q_next could be a read queue. 76727c478bd9Sstevel@tonic-gate */ 76737c478bd9Sstevel@tonic-gate qp = _OTHERQ(prev_wq->q_next); 76747c478bd9Sstevel@tonic-gate while (qp && qp->q_nfsrv != qp) { 76757c478bd9Sstevel@tonic-gate qp->q_nfsrv = rnew; 76767c478bd9Sstevel@tonic-gate qp = backq(qp); 76777c478bd9Sstevel@tonic-gate } 76787c478bd9Sstevel@tonic-gate rnew->q_nfsrv = rnew; 76797c478bd9Sstevel@tonic-gate } else 76807c478bd9Sstevel@tonic-gate rnew->q_nfsrv = prev_rq->q_nfsrv; 76817c478bd9Sstevel@tonic-gate 76827c478bd9Sstevel@tonic-gate /* set up write side q_nfsrv pointer */ 76837c478bd9Sstevel@tonic-gate if (wnew->q_qinfo->qi_srvp) { 76847c478bd9Sstevel@tonic-gate wnew->q_nfsrv = wnew; 76857c478bd9Sstevel@tonic-gate 76867c478bd9Sstevel@tonic-gate /* 76877c478bd9Sstevel@tonic-gate * For insertion, need to update nfsrv of the modules 76887c478bd9Sstevel@tonic-gate * above which do not have a service routine. 76897c478bd9Sstevel@tonic-gate */ 76907c478bd9Sstevel@tonic-gate if (rnew->q_flag & _QINSERTING) { 76917c478bd9Sstevel@tonic-gate for (qp = prev_wq; 76927c478bd9Sstevel@tonic-gate qp != NULL && qp->q_nfsrv != qp; 76937c478bd9Sstevel@tonic-gate qp = backq(qp)) { 76947c478bd9Sstevel@tonic-gate qp->q_nfsrv = wnew->q_nfsrv; 76957c478bd9Sstevel@tonic-gate } 76967c478bd9Sstevel@tonic-gate } 76977c478bd9Sstevel@tonic-gate } else { 76987c478bd9Sstevel@tonic-gate if (prev_wq->q_next == prev_rq) 76997c478bd9Sstevel@tonic-gate /* 77007c478bd9Sstevel@tonic-gate * Since prev_wq/prev_rq are the middle of a 77017c478bd9Sstevel@tonic-gate * fifo, wnew/rnew will also be the middle of 77027c478bd9Sstevel@tonic-gate * a fifo and wnew's nfsrv is same as rnew's. 77037c478bd9Sstevel@tonic-gate */ 77047c478bd9Sstevel@tonic-gate wnew->q_nfsrv = rnew->q_nfsrv; 77057c478bd9Sstevel@tonic-gate else 77067c478bd9Sstevel@tonic-gate wnew->q_nfsrv = prev_wq->q_next->q_nfsrv; 77077c478bd9Sstevel@tonic-gate } 77087c478bd9Sstevel@tonic-gate } 77097c478bd9Sstevel@tonic-gate } 77107c478bd9Sstevel@tonic-gate 77117c478bd9Sstevel@tonic-gate /* 77127c478bd9Sstevel@tonic-gate * Reset the forward service procedure pointer; called at remove-time. 77137c478bd9Sstevel@tonic-gate */ 77147c478bd9Sstevel@tonic-gate void 77157c478bd9Sstevel@tonic-gate reset_nfsrv_ptr(queue_t *rqp, queue_t *wqp) 77167c478bd9Sstevel@tonic-gate { 77177c478bd9Sstevel@tonic-gate queue_t *tmp_qp; 77187c478bd9Sstevel@tonic-gate 77197c478bd9Sstevel@tonic-gate /* Reset the write side q_nfsrv pointer for _I_REMOVE */ 77207c478bd9Sstevel@tonic-gate if ((rqp->q_flag & _QREMOVING) && (wqp->q_qinfo->qi_srvp != NULL)) { 77217c478bd9Sstevel@tonic-gate for (tmp_qp = backq(wqp); 77227c478bd9Sstevel@tonic-gate tmp_qp != NULL && tmp_qp->q_nfsrv == wqp; 77237c478bd9Sstevel@tonic-gate tmp_qp = backq(tmp_qp)) { 77247c478bd9Sstevel@tonic-gate tmp_qp->q_nfsrv = wqp->q_nfsrv; 77257c478bd9Sstevel@tonic-gate } 77267c478bd9Sstevel@tonic-gate } 77277c478bd9Sstevel@tonic-gate 77287c478bd9Sstevel@tonic-gate /* reset the read side q_nfsrv pointer */ 77297c478bd9Sstevel@tonic-gate if (rqp->q_qinfo->qi_srvp) { 77307c478bd9Sstevel@tonic-gate if (wqp->q_next) { /* non-driver case */ 77317c478bd9Sstevel@tonic-gate tmp_qp = _OTHERQ(wqp->q_next); 77327c478bd9Sstevel@tonic-gate while (tmp_qp && tmp_qp->q_nfsrv == rqp) { 77337c478bd9Sstevel@tonic-gate /* Note that rqp->q_next cannot be NULL */ 77347c478bd9Sstevel@tonic-gate ASSERT(rqp->q_next != NULL); 77357c478bd9Sstevel@tonic-gate tmp_qp->q_nfsrv = rqp->q_next->q_nfsrv; 77367c478bd9Sstevel@tonic-gate tmp_qp = backq(tmp_qp); 77377c478bd9Sstevel@tonic-gate } 77387c478bd9Sstevel@tonic-gate } 77397c478bd9Sstevel@tonic-gate } 77407c478bd9Sstevel@tonic-gate } 77417c478bd9Sstevel@tonic-gate 77427c478bd9Sstevel@tonic-gate /* 77437c478bd9Sstevel@tonic-gate * This routine should be called after all stream geometry changes to update 77447c478bd9Sstevel@tonic-gate * the stream head cached struio() rd/wr queue pointers. Note must be called 77457c478bd9Sstevel@tonic-gate * with the streamlock()ed. 77467c478bd9Sstevel@tonic-gate * 77477c478bd9Sstevel@tonic-gate * Note: only enables Synchronous STREAMS for a side of a Stream which has 77487c478bd9Sstevel@tonic-gate * an explicit synchronous barrier module queue. That is, a queue that 77497c478bd9Sstevel@tonic-gate * has specified a struio() type. 77507c478bd9Sstevel@tonic-gate */ 77517c478bd9Sstevel@tonic-gate static void 77527c478bd9Sstevel@tonic-gate strsetuio(stdata_t *stp) 77537c478bd9Sstevel@tonic-gate { 77547c478bd9Sstevel@tonic-gate queue_t *wrq; 77557c478bd9Sstevel@tonic-gate 77567c478bd9Sstevel@tonic-gate if (stp->sd_flag & STPLEX) { 77577c478bd9Sstevel@tonic-gate /* 775821804b56SBrian Ruthven * Not streamhead, but a mux, so no Synchronous STREAMS. 77597c478bd9Sstevel@tonic-gate */ 77607c478bd9Sstevel@tonic-gate stp->sd_struiowrq = NULL; 77617c478bd9Sstevel@tonic-gate stp->sd_struiordq = NULL; 77627c478bd9Sstevel@tonic-gate return; 77637c478bd9Sstevel@tonic-gate } 77647c478bd9Sstevel@tonic-gate /* 77657c478bd9Sstevel@tonic-gate * Scan the write queue(s) while synchronous 77667c478bd9Sstevel@tonic-gate * until we find a qinfo uio type specified. 77677c478bd9Sstevel@tonic-gate */ 77687c478bd9Sstevel@tonic-gate wrq = stp->sd_wrq->q_next; 77697c478bd9Sstevel@tonic-gate while (wrq) { 77707c478bd9Sstevel@tonic-gate if (wrq->q_struiot == STRUIOT_NONE) { 77717c478bd9Sstevel@tonic-gate wrq = 0; 77727c478bd9Sstevel@tonic-gate break; 77737c478bd9Sstevel@tonic-gate } 77747c478bd9Sstevel@tonic-gate if (wrq->q_struiot != STRUIOT_DONTCARE) 77757c478bd9Sstevel@tonic-gate break; 77767c478bd9Sstevel@tonic-gate if (! _SAMESTR(wrq)) { 77777c478bd9Sstevel@tonic-gate wrq = 0; 77787c478bd9Sstevel@tonic-gate break; 77797c478bd9Sstevel@tonic-gate } 77807c478bd9Sstevel@tonic-gate wrq = wrq->q_next; 77817c478bd9Sstevel@tonic-gate } 77827c478bd9Sstevel@tonic-gate stp->sd_struiowrq = wrq; 77837c478bd9Sstevel@tonic-gate /* 77847c478bd9Sstevel@tonic-gate * Scan the read queue(s) while synchronous 77857c478bd9Sstevel@tonic-gate * until we find a qinfo uio type specified. 77867c478bd9Sstevel@tonic-gate */ 77877c478bd9Sstevel@tonic-gate wrq = stp->sd_wrq->q_next; 77887c478bd9Sstevel@tonic-gate while (wrq) { 77897c478bd9Sstevel@tonic-gate if (_RD(wrq)->q_struiot == STRUIOT_NONE) { 77907c478bd9Sstevel@tonic-gate wrq = 0; 77917c478bd9Sstevel@tonic-gate break; 77927c478bd9Sstevel@tonic-gate } 77937c478bd9Sstevel@tonic-gate if (_RD(wrq)->q_struiot != STRUIOT_DONTCARE) 77947c478bd9Sstevel@tonic-gate break; 77957c478bd9Sstevel@tonic-gate if (! _SAMESTR(wrq)) { 77967c478bd9Sstevel@tonic-gate wrq = 0; 77977c478bd9Sstevel@tonic-gate break; 77987c478bd9Sstevel@tonic-gate } 77997c478bd9Sstevel@tonic-gate wrq = wrq->q_next; 78007c478bd9Sstevel@tonic-gate } 78017c478bd9Sstevel@tonic-gate stp->sd_struiordq = wrq ? _RD(wrq) : 0; 78027c478bd9Sstevel@tonic-gate } 78037c478bd9Sstevel@tonic-gate 78047c478bd9Sstevel@tonic-gate /* 78057c478bd9Sstevel@tonic-gate * pass_wput, unblocks the passthru queues, so that 78067c478bd9Sstevel@tonic-gate * messages can arrive at muxs lower read queue, before 78077c478bd9Sstevel@tonic-gate * I_LINK/I_UNLINK is acked/nacked. 78087c478bd9Sstevel@tonic-gate */ 78097c478bd9Sstevel@tonic-gate static void 78107c478bd9Sstevel@tonic-gate pass_wput(queue_t *q, mblk_t *mp) 78117c478bd9Sstevel@tonic-gate { 78127c478bd9Sstevel@tonic-gate syncq_t *sq; 78137c478bd9Sstevel@tonic-gate 78147c478bd9Sstevel@tonic-gate sq = _RD(q)->q_syncq; 78157c478bd9Sstevel@tonic-gate if (sq->sq_flags & SQ_BLOCKED) 78167c478bd9Sstevel@tonic-gate unblocksq(sq, SQ_BLOCKED, 0); 78177c478bd9Sstevel@tonic-gate putnext(q, mp); 78187c478bd9Sstevel@tonic-gate } 78197c478bd9Sstevel@tonic-gate 78207c478bd9Sstevel@tonic-gate /* 78217c478bd9Sstevel@tonic-gate * Set up queues for the link/unlink. 78227c478bd9Sstevel@tonic-gate * Create a new queue and block it and then insert it 78237c478bd9Sstevel@tonic-gate * below the stream head on the lower stream. 78247c478bd9Sstevel@tonic-gate * This prevents any messages from arriving during the setq 78257c478bd9Sstevel@tonic-gate * as well as while the mux is processing the LINK/I_UNLINK. 78267c478bd9Sstevel@tonic-gate * The blocked passq is unblocked once the LINK/I_UNLINK has 78277c478bd9Sstevel@tonic-gate * been acked or nacked or if a message is generated and sent 78287c478bd9Sstevel@tonic-gate * down muxs write put procedure. 782921804b56SBrian Ruthven * See pass_wput(). 78307c478bd9Sstevel@tonic-gate * 78317c478bd9Sstevel@tonic-gate * After the new queue is inserted, all messages coming from below are 78327c478bd9Sstevel@tonic-gate * blocked. The call to strlock will ensure that all activity in the stream head 78337c478bd9Sstevel@tonic-gate * read queue syncq is stopped (sq_count drops to zero). 78347c478bd9Sstevel@tonic-gate */ 78357c478bd9Sstevel@tonic-gate static queue_t * 78367c478bd9Sstevel@tonic-gate link_addpassthru(stdata_t *stpdown) 78377c478bd9Sstevel@tonic-gate { 78387c478bd9Sstevel@tonic-gate queue_t *passq; 78397c478bd9Sstevel@tonic-gate sqlist_t sqlist; 78407c478bd9Sstevel@tonic-gate 78417c478bd9Sstevel@tonic-gate passq = allocq(); 78427c478bd9Sstevel@tonic-gate STREAM(passq) = STREAM(_WR(passq)) = stpdown; 78437c478bd9Sstevel@tonic-gate /* setq might sleep in allocator - avoid holding locks. */ 78447c478bd9Sstevel@tonic-gate setq(passq, &passthru_rinit, &passthru_winit, NULL, QPERQ, 78457c478bd9Sstevel@tonic-gate SQ_CI|SQ_CO, B_FALSE); 78467c478bd9Sstevel@tonic-gate claimq(passq); 78477c478bd9Sstevel@tonic-gate blocksq(passq->q_syncq, SQ_BLOCKED, 1); 78487c478bd9Sstevel@tonic-gate insertq(STREAM(passq), passq); 78497c478bd9Sstevel@tonic-gate 78507c478bd9Sstevel@tonic-gate /* 78517c478bd9Sstevel@tonic-gate * Use strlock() to wait for the stream head sq_count to drop to zero 78527c478bd9Sstevel@tonic-gate * since we are going to change q_ptr in the stream head. Note that 78537c478bd9Sstevel@tonic-gate * insertq() doesn't wait for any syncq counts to drop to zero. 78547c478bd9Sstevel@tonic-gate */ 78557c478bd9Sstevel@tonic-gate sqlist.sqlist_head = NULL; 78567c478bd9Sstevel@tonic-gate sqlist.sqlist_index = 0; 78577c478bd9Sstevel@tonic-gate sqlist.sqlist_size = sizeof (sqlist_t); 78587c478bd9Sstevel@tonic-gate sqlist_insert(&sqlist, _RD(stpdown->sd_wrq)->q_syncq); 78597c478bd9Sstevel@tonic-gate strlock(stpdown, &sqlist); 78607c478bd9Sstevel@tonic-gate strunlock(stpdown, &sqlist); 78617c478bd9Sstevel@tonic-gate 78627c478bd9Sstevel@tonic-gate releaseq(passq); 78637c478bd9Sstevel@tonic-gate return (passq); 78647c478bd9Sstevel@tonic-gate } 78657c478bd9Sstevel@tonic-gate 78667c478bd9Sstevel@tonic-gate /* 78677c478bd9Sstevel@tonic-gate * Let messages flow up into the mux by removing 78687c478bd9Sstevel@tonic-gate * the passq. 78697c478bd9Sstevel@tonic-gate */ 78707c478bd9Sstevel@tonic-gate static void 78717c478bd9Sstevel@tonic-gate link_rempassthru(queue_t *passq) 78727c478bd9Sstevel@tonic-gate { 78737c478bd9Sstevel@tonic-gate claimq(passq); 78747c478bd9Sstevel@tonic-gate removeq(passq); 78757c478bd9Sstevel@tonic-gate releaseq(passq); 78767c478bd9Sstevel@tonic-gate freeq(passq); 78777c478bd9Sstevel@tonic-gate } 78787c478bd9Sstevel@tonic-gate 78797c478bd9Sstevel@tonic-gate /* 7880e4506d67Smeem * Wait for the condition variable pointed to by `cvp' to be signaled, 7881e4506d67Smeem * or for `tim' milliseconds to elapse, whichever comes first. If `tim' 7882e4506d67Smeem * is negative, then there is no time limit. If `nosigs' is non-zero, 7883e4506d67Smeem * then the wait will be non-interruptible. 7884e4506d67Smeem * 7885e4506d67Smeem * Returns >0 if signaled, 0 if interrupted, or -1 upon timeout. 78867c478bd9Sstevel@tonic-gate */ 78877c478bd9Sstevel@tonic-gate clock_t 78887c478bd9Sstevel@tonic-gate str_cv_wait(kcondvar_t *cvp, kmutex_t *mp, clock_t tim, int nosigs) 78897c478bd9Sstevel@tonic-gate { 7890d3d50737SRafael Vanoni clock_t ret; 78917c478bd9Sstevel@tonic-gate 78927c478bd9Sstevel@tonic-gate if (tim < 0) { 78937c478bd9Sstevel@tonic-gate if (nosigs) { 78947c478bd9Sstevel@tonic-gate cv_wait(cvp, mp); 78957c478bd9Sstevel@tonic-gate ret = 1; 78967c478bd9Sstevel@tonic-gate } else { 78977c478bd9Sstevel@tonic-gate ret = cv_wait_sig(cvp, mp); 78987c478bd9Sstevel@tonic-gate } 78997c478bd9Sstevel@tonic-gate } else if (tim > 0) { 79007c478bd9Sstevel@tonic-gate /* 79017c478bd9Sstevel@tonic-gate * convert milliseconds to clock ticks 79027c478bd9Sstevel@tonic-gate */ 79037c478bd9Sstevel@tonic-gate if (nosigs) { 7904d3d50737SRafael Vanoni ret = cv_reltimedwait(cvp, mp, 7905d3d50737SRafael Vanoni MSEC_TO_TICK_ROUNDUP(tim), TR_CLOCK_TICK); 79067c478bd9Sstevel@tonic-gate } else { 7907d3d50737SRafael Vanoni ret = cv_reltimedwait_sig(cvp, mp, 7908d3d50737SRafael Vanoni MSEC_TO_TICK_ROUNDUP(tim), TR_CLOCK_TICK); 79097c478bd9Sstevel@tonic-gate } 79107c478bd9Sstevel@tonic-gate } else { 79117c478bd9Sstevel@tonic-gate ret = -1; 79127c478bd9Sstevel@tonic-gate } 79137c478bd9Sstevel@tonic-gate return (ret); 79147c478bd9Sstevel@tonic-gate } 79157c478bd9Sstevel@tonic-gate 79167c478bd9Sstevel@tonic-gate /* 79177c478bd9Sstevel@tonic-gate * Wait until the stream head can determine if it is at the mark but 79187c478bd9Sstevel@tonic-gate * don't wait forever to prevent a race condition between the "mark" state 79197c478bd9Sstevel@tonic-gate * in the stream head and any mark state in the caller/user of this routine. 79207c478bd9Sstevel@tonic-gate * 79217c478bd9Sstevel@tonic-gate * This is used by sockets and for a socket it would be incorrect 79227c478bd9Sstevel@tonic-gate * to return a failure for SIOCATMARK when there is no data in the receive 79237c478bd9Sstevel@tonic-gate * queue and the marked urgent data is traveling up the stream. 79247c478bd9Sstevel@tonic-gate * 79257c478bd9Sstevel@tonic-gate * This routine waits until the mark is known by waiting for one of these 79267c478bd9Sstevel@tonic-gate * three events: 792721804b56SBrian Ruthven * The stream head read queue becoming non-empty (including an EOF). 792821804b56SBrian Ruthven * The STRATMARK flag being set (due to a MSGMARKNEXT message). 79297c478bd9Sstevel@tonic-gate * The STRNOTATMARK flag being set (which indicates that the transport 79307c478bd9Sstevel@tonic-gate * has sent a MSGNOTMARKNEXT message to indicate that it is not at 79317c478bd9Sstevel@tonic-gate * the mark). 79327c478bd9Sstevel@tonic-gate * 79337c478bd9Sstevel@tonic-gate * The routine returns 1 if the stream is at the mark; 0 if it can 79347c478bd9Sstevel@tonic-gate * be determined that the stream is not at the mark. 79357c478bd9Sstevel@tonic-gate * If the wait times out and it can't determine 79367c478bd9Sstevel@tonic-gate * whether or not the stream might be at the mark the routine will return -1. 79377c478bd9Sstevel@tonic-gate * 79387c478bd9Sstevel@tonic-gate * Note: This routine should only be used when a mark is pending i.e., 79397c478bd9Sstevel@tonic-gate * in the socket case the SIGURG has been posted. 79407c478bd9Sstevel@tonic-gate * Note2: This can not wakeup just because synchronous streams indicate 79417c478bd9Sstevel@tonic-gate * that data is available since it is not possible to use the synchronous 79427c478bd9Sstevel@tonic-gate * streams interfaces to determine the b_flag value for the data queued below 79437c478bd9Sstevel@tonic-gate * the stream head. 79447c478bd9Sstevel@tonic-gate */ 79457c478bd9Sstevel@tonic-gate int 79467c478bd9Sstevel@tonic-gate strwaitmark(vnode_t *vp) 79477c478bd9Sstevel@tonic-gate { 79487c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 79497c478bd9Sstevel@tonic-gate queue_t *rq = _RD(stp->sd_wrq); 79507c478bd9Sstevel@tonic-gate int mark; 79517c478bd9Sstevel@tonic-gate 79527c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 79537c478bd9Sstevel@tonic-gate while (rq->q_first == NULL && 79547c478bd9Sstevel@tonic-gate !(stp->sd_flag & (STRATMARK|STRNOTATMARK|STREOF))) { 79557c478bd9Sstevel@tonic-gate stp->sd_flag |= RSLEEP; 79567c478bd9Sstevel@tonic-gate 79577c478bd9Sstevel@tonic-gate /* Wait for 100 milliseconds for any state change. */ 79587c478bd9Sstevel@tonic-gate if (str_cv_wait(&rq->q_wait, &stp->sd_lock, 100, 1) == -1) { 79597c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 79607c478bd9Sstevel@tonic-gate return (-1); 79617c478bd9Sstevel@tonic-gate } 79627c478bd9Sstevel@tonic-gate } 79637c478bd9Sstevel@tonic-gate if (stp->sd_flag & STRATMARK) 79647c478bd9Sstevel@tonic-gate mark = 1; 79657c478bd9Sstevel@tonic-gate else if (rq->q_first != NULL && (rq->q_first->b_flag & MSGMARK)) 79667c478bd9Sstevel@tonic-gate mark = 1; 79677c478bd9Sstevel@tonic-gate else 79687c478bd9Sstevel@tonic-gate mark = 0; 79697c478bd9Sstevel@tonic-gate 79707c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 79717c478bd9Sstevel@tonic-gate return (mark); 79727c478bd9Sstevel@tonic-gate } 79737c478bd9Sstevel@tonic-gate 79747c478bd9Sstevel@tonic-gate /* 79757c478bd9Sstevel@tonic-gate * Set a read side error. If persist is set change the socket error 79767c478bd9Sstevel@tonic-gate * to persistent. If errfunc is set install the function as the exported 79777c478bd9Sstevel@tonic-gate * error handler. 79787c478bd9Sstevel@tonic-gate */ 79797c478bd9Sstevel@tonic-gate void 79807c478bd9Sstevel@tonic-gate strsetrerror(vnode_t *vp, int error, int persist, errfunc_t errfunc) 79817c478bd9Sstevel@tonic-gate { 79827c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 79837c478bd9Sstevel@tonic-gate 79847c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 79857c478bd9Sstevel@tonic-gate stp->sd_rerror = error; 79867c478bd9Sstevel@tonic-gate if (error == 0 && errfunc == NULL) 79877c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STRDERR; 79887c478bd9Sstevel@tonic-gate else 79897c478bd9Sstevel@tonic-gate stp->sd_flag |= STRDERR; 79907c478bd9Sstevel@tonic-gate if (persist) { 79917c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STRDERRNONPERSIST; 79927c478bd9Sstevel@tonic-gate } else { 79937c478bd9Sstevel@tonic-gate stp->sd_flag |= STRDERRNONPERSIST; 79947c478bd9Sstevel@tonic-gate } 79957c478bd9Sstevel@tonic-gate stp->sd_rderrfunc = errfunc; 79967c478bd9Sstevel@tonic-gate if (error != 0 || errfunc != NULL) { 79977c478bd9Sstevel@tonic-gate cv_broadcast(&_RD(stp->sd_wrq)->q_wait); /* readers */ 79987c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_wrq->q_wait); /* writers */ 79997c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_monitor); /* ioctllers */ 80007c478bd9Sstevel@tonic-gate 80017c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80027c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLERR); 80037c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80047c478bd9Sstevel@tonic-gate 80057c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_ERROR) 80067c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_ERROR, 0, error); 80077c478bd9Sstevel@tonic-gate } 80087c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80097c478bd9Sstevel@tonic-gate } 80107c478bd9Sstevel@tonic-gate 80117c478bd9Sstevel@tonic-gate /* 80127c478bd9Sstevel@tonic-gate * Set a write side error. If persist is set change the socket error 80137c478bd9Sstevel@tonic-gate * to persistent. 80147c478bd9Sstevel@tonic-gate */ 80157c478bd9Sstevel@tonic-gate void 80167c478bd9Sstevel@tonic-gate strsetwerror(vnode_t *vp, int error, int persist, errfunc_t errfunc) 80177c478bd9Sstevel@tonic-gate { 80187c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 80197c478bd9Sstevel@tonic-gate 80207c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80217c478bd9Sstevel@tonic-gate stp->sd_werror = error; 80227c478bd9Sstevel@tonic-gate if (error == 0 && errfunc == NULL) 80237c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STWRERR; 80247c478bd9Sstevel@tonic-gate else 80257c478bd9Sstevel@tonic-gate stp->sd_flag |= STWRERR; 80267c478bd9Sstevel@tonic-gate if (persist) { 80277c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STWRERRNONPERSIST; 80287c478bd9Sstevel@tonic-gate } else { 80297c478bd9Sstevel@tonic-gate stp->sd_flag |= STWRERRNONPERSIST; 80307c478bd9Sstevel@tonic-gate } 80317c478bd9Sstevel@tonic-gate stp->sd_wrerrfunc = errfunc; 80327c478bd9Sstevel@tonic-gate if (error != 0 || errfunc != NULL) { 80337c478bd9Sstevel@tonic-gate cv_broadcast(&_RD(stp->sd_wrq)->q_wait); /* readers */ 80347c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_wrq->q_wait); /* writers */ 80357c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_monitor); /* ioctllers */ 80367c478bd9Sstevel@tonic-gate 80377c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80387c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLERR); 80397c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80407c478bd9Sstevel@tonic-gate 80417c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_ERROR) 80427c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_ERROR, 0, error); 80437c478bd9Sstevel@tonic-gate } 80447c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80457c478bd9Sstevel@tonic-gate } 80467c478bd9Sstevel@tonic-gate 80477c478bd9Sstevel@tonic-gate /* 80487c478bd9Sstevel@tonic-gate * Make the stream return 0 (EOF) when all data has been read. 80497c478bd9Sstevel@tonic-gate * No effect on write side. 80507c478bd9Sstevel@tonic-gate */ 80517c478bd9Sstevel@tonic-gate void 80527c478bd9Sstevel@tonic-gate strseteof(vnode_t *vp, int eof) 80537c478bd9Sstevel@tonic-gate { 80547c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 80557c478bd9Sstevel@tonic-gate 80567c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80577c478bd9Sstevel@tonic-gate if (!eof) { 80587c478bd9Sstevel@tonic-gate stp->sd_flag &= ~STREOF; 80597c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80607c478bd9Sstevel@tonic-gate return; 80617c478bd9Sstevel@tonic-gate } 80627c478bd9Sstevel@tonic-gate stp->sd_flag |= STREOF; 80637c478bd9Sstevel@tonic-gate if (stp->sd_flag & RSLEEP) { 80647c478bd9Sstevel@tonic-gate stp->sd_flag &= ~RSLEEP; 80657c478bd9Sstevel@tonic-gate cv_broadcast(&_RD(stp->sd_wrq)->q_wait); 80667c478bd9Sstevel@tonic-gate } 80677c478bd9Sstevel@tonic-gate 80687c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80697c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLIN|POLLRDNORM); 80707c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80717c478bd9Sstevel@tonic-gate 80727c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & (S_INPUT|S_RDNORM)) 80737c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_INPUT|S_RDNORM, 0, 0); 80747c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80757c478bd9Sstevel@tonic-gate } 80767c478bd9Sstevel@tonic-gate 80777c478bd9Sstevel@tonic-gate void 80787c478bd9Sstevel@tonic-gate strflushrq(vnode_t *vp, int flag) 80797c478bd9Sstevel@tonic-gate { 80807c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 80817c478bd9Sstevel@tonic-gate 80827c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80837c478bd9Sstevel@tonic-gate flushq(_RD(stp->sd_wrq), flag); 80847c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 80857c478bd9Sstevel@tonic-gate } 80867c478bd9Sstevel@tonic-gate 80877c478bd9Sstevel@tonic-gate void 80887c478bd9Sstevel@tonic-gate strsetrputhooks(vnode_t *vp, uint_t flags, 80897c478bd9Sstevel@tonic-gate msgfunc_t protofunc, msgfunc_t miscfunc) 80907c478bd9Sstevel@tonic-gate { 80917c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 80927c478bd9Sstevel@tonic-gate 80937c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 80947c478bd9Sstevel@tonic-gate 80957c478bd9Sstevel@tonic-gate if (protofunc == NULL) 80967c478bd9Sstevel@tonic-gate stp->sd_rprotofunc = strrput_proto; 80977c478bd9Sstevel@tonic-gate else 80987c478bd9Sstevel@tonic-gate stp->sd_rprotofunc = protofunc; 80997c478bd9Sstevel@tonic-gate 81007c478bd9Sstevel@tonic-gate if (miscfunc == NULL) 81017c478bd9Sstevel@tonic-gate stp->sd_rmiscfunc = strrput_misc; 81027c478bd9Sstevel@tonic-gate else 81037c478bd9Sstevel@tonic-gate stp->sd_rmiscfunc = miscfunc; 81047c478bd9Sstevel@tonic-gate 81057c478bd9Sstevel@tonic-gate if (flags & SH_CONSOL_DATA) 81067c478bd9Sstevel@tonic-gate stp->sd_rput_opt |= SR_CONSOL_DATA; 81077c478bd9Sstevel@tonic-gate else 81087c478bd9Sstevel@tonic-gate stp->sd_rput_opt &= ~SR_CONSOL_DATA; 81097c478bd9Sstevel@tonic-gate 81107c478bd9Sstevel@tonic-gate if (flags & SH_SIGALLDATA) 81117c478bd9Sstevel@tonic-gate stp->sd_rput_opt |= SR_SIGALLDATA; 81127c478bd9Sstevel@tonic-gate else 81137c478bd9Sstevel@tonic-gate stp->sd_rput_opt &= ~SR_SIGALLDATA; 81147c478bd9Sstevel@tonic-gate 81157c478bd9Sstevel@tonic-gate if (flags & SH_IGN_ZEROLEN) 81167c478bd9Sstevel@tonic-gate stp->sd_rput_opt |= SR_IGN_ZEROLEN; 81177c478bd9Sstevel@tonic-gate else 81187c478bd9Sstevel@tonic-gate stp->sd_rput_opt &= ~SR_IGN_ZEROLEN; 81197c478bd9Sstevel@tonic-gate 81207c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 81217c478bd9Sstevel@tonic-gate } 81227c478bd9Sstevel@tonic-gate 81237c478bd9Sstevel@tonic-gate void 81247c478bd9Sstevel@tonic-gate strsetwputhooks(vnode_t *vp, uint_t flags, clock_t closetime) 81257c478bd9Sstevel@tonic-gate { 81267c478bd9Sstevel@tonic-gate struct stdata *stp = vp->v_stream; 81277c478bd9Sstevel@tonic-gate 81287c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 81297c478bd9Sstevel@tonic-gate stp->sd_closetime = closetime; 81307c478bd9Sstevel@tonic-gate 81317c478bd9Sstevel@tonic-gate if (flags & SH_SIGPIPE) 81327c478bd9Sstevel@tonic-gate stp->sd_wput_opt |= SW_SIGPIPE; 81337c478bd9Sstevel@tonic-gate else 81347c478bd9Sstevel@tonic-gate stp->sd_wput_opt &= ~SW_SIGPIPE; 81357c478bd9Sstevel@tonic-gate if (flags & SH_RECHECK_ERR) 81367c478bd9Sstevel@tonic-gate stp->sd_wput_opt |= SW_RECHECK_ERR; 81377c478bd9Sstevel@tonic-gate else 81387c478bd9Sstevel@tonic-gate stp->sd_wput_opt &= ~SW_RECHECK_ERR; 81397c478bd9Sstevel@tonic-gate 81407c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 81417c478bd9Sstevel@tonic-gate } 81427c478bd9Sstevel@tonic-gate 8143c28749e9Skais void 8144c28749e9Skais strsetrwputdatahooks(vnode_t *vp, msgfunc_t rdatafunc, msgfunc_t wdatafunc) 8145c28749e9Skais { 8146c28749e9Skais struct stdata *stp = vp->v_stream; 8147c28749e9Skais 8148c28749e9Skais mutex_enter(&stp->sd_lock); 8149c28749e9Skais 8150c28749e9Skais stp->sd_rputdatafunc = rdatafunc; 8151c28749e9Skais stp->sd_wputdatafunc = wdatafunc; 8152c28749e9Skais 8153c28749e9Skais mutex_exit(&stp->sd_lock); 8154c28749e9Skais } 8155c28749e9Skais 81567c478bd9Sstevel@tonic-gate /* Used within framework when the queue is already locked */ 81577c478bd9Sstevel@tonic-gate void 81587c478bd9Sstevel@tonic-gate qenable_locked(queue_t *q) 81597c478bd9Sstevel@tonic-gate { 81607c478bd9Sstevel@tonic-gate stdata_t *stp = STREAM(q); 81617c478bd9Sstevel@tonic-gate 81627c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(QLOCK(q))); 81637c478bd9Sstevel@tonic-gate 81647c478bd9Sstevel@tonic-gate if (!q->q_qinfo->qi_srvp) 81657c478bd9Sstevel@tonic-gate return; 81667c478bd9Sstevel@tonic-gate 81677c478bd9Sstevel@tonic-gate /* 81687c478bd9Sstevel@tonic-gate * Do not place on run queue if already enabled or closing. 81697c478bd9Sstevel@tonic-gate */ 81707c478bd9Sstevel@tonic-gate if (q->q_flag & (QWCLOSE|QENAB)) 81717c478bd9Sstevel@tonic-gate return; 81727c478bd9Sstevel@tonic-gate 81737c478bd9Sstevel@tonic-gate /* 81747c478bd9Sstevel@tonic-gate * mark queue enabled and place on run list if it is not already being 81757c478bd9Sstevel@tonic-gate * serviced. If it is serviced, the runservice() function will detect 81767c478bd9Sstevel@tonic-gate * that QENAB is set and call service procedure before clearing 81777c478bd9Sstevel@tonic-gate * QINSERVICE flag. 81787c478bd9Sstevel@tonic-gate */ 81797c478bd9Sstevel@tonic-gate q->q_flag |= QENAB; 81807c478bd9Sstevel@tonic-gate if (q->q_flag & QINSERVICE) 81817c478bd9Sstevel@tonic-gate return; 81827c478bd9Sstevel@tonic-gate 81837c478bd9Sstevel@tonic-gate /* Record the time of qenable */ 8184d3d50737SRafael Vanoni q->q_qtstamp = ddi_get_lbolt(); 81857c478bd9Sstevel@tonic-gate 81867c478bd9Sstevel@tonic-gate /* 81877c478bd9Sstevel@tonic-gate * Put the queue in the stp list and schedule it for background 81887c478bd9Sstevel@tonic-gate * processing if it is not already scheduled or if stream head does not 81897c478bd9Sstevel@tonic-gate * intent to process it in the foreground later by setting 81907c478bd9Sstevel@tonic-gate * STRS_WILLSERVICE flag. 81917c478bd9Sstevel@tonic-gate */ 81927c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_qlock); 81937c478bd9Sstevel@tonic-gate /* 81947c478bd9Sstevel@tonic-gate * If there are already something on the list, stp flags should show 81957c478bd9Sstevel@tonic-gate * intention to drain it. 81967c478bd9Sstevel@tonic-gate */ 81977c478bd9Sstevel@tonic-gate IMPLY(STREAM_NEEDSERVICE(stp), 81987c478bd9Sstevel@tonic-gate (stp->sd_svcflags & (STRS_WILLSERVICE | STRS_SCHEDULED))); 81997c478bd9Sstevel@tonic-gate 82007c478bd9Sstevel@tonic-gate ENQUEUE(q, stp->sd_qhead, stp->sd_qtail, q_link); 82017c478bd9Sstevel@tonic-gate stp->sd_nqueues++; 82027c478bd9Sstevel@tonic-gate 82037c478bd9Sstevel@tonic-gate /* 82047c478bd9Sstevel@tonic-gate * If no one will drain this stream we are the first producer and 82057c478bd9Sstevel@tonic-gate * need to schedule it for background thread. 82067c478bd9Sstevel@tonic-gate */ 82077c478bd9Sstevel@tonic-gate if (!(stp->sd_svcflags & (STRS_WILLSERVICE | STRS_SCHEDULED))) { 82087c478bd9Sstevel@tonic-gate /* 82097c478bd9Sstevel@tonic-gate * No one will service this stream later, so we have to 82107c478bd9Sstevel@tonic-gate * schedule it now. 82117c478bd9Sstevel@tonic-gate */ 82127c478bd9Sstevel@tonic-gate STRSTAT(stenables); 82137c478bd9Sstevel@tonic-gate stp->sd_svcflags |= STRS_SCHEDULED; 82147c478bd9Sstevel@tonic-gate stp->sd_servid = (void *)taskq_dispatch(streams_taskq, 82157c478bd9Sstevel@tonic-gate (task_func_t *)stream_service, stp, TQ_NOSLEEP|TQ_NOQUEUE); 82167c478bd9Sstevel@tonic-gate 82177c478bd9Sstevel@tonic-gate if (stp->sd_servid == NULL) { 82187c478bd9Sstevel@tonic-gate /* 82197c478bd9Sstevel@tonic-gate * Task queue failed so fail over to the backup 82207c478bd9Sstevel@tonic-gate * servicing thread. 82217c478bd9Sstevel@tonic-gate */ 82227c478bd9Sstevel@tonic-gate STRSTAT(taskqfails); 82237c478bd9Sstevel@tonic-gate /* 82247c478bd9Sstevel@tonic-gate * It is safe to clear STRS_SCHEDULED flag because it 82257c478bd9Sstevel@tonic-gate * was set by this thread above. 82267c478bd9Sstevel@tonic-gate */ 82277c478bd9Sstevel@tonic-gate stp->sd_svcflags &= ~STRS_SCHEDULED; 82287c478bd9Sstevel@tonic-gate 82297c478bd9Sstevel@tonic-gate /* 82307c478bd9Sstevel@tonic-gate * Failover scheduling is protected by service_queue 82317c478bd9Sstevel@tonic-gate * lock. 82327c478bd9Sstevel@tonic-gate */ 82337c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 82347c478bd9Sstevel@tonic-gate ASSERT((stp->sd_qhead == q) && (stp->sd_qtail == q)); 82357c478bd9Sstevel@tonic-gate ASSERT(q->q_link == NULL); 82367c478bd9Sstevel@tonic-gate /* 82377c478bd9Sstevel@tonic-gate * Append the queue to qhead/qtail list. 82387c478bd9Sstevel@tonic-gate */ 82397c478bd9Sstevel@tonic-gate if (qhead == NULL) 82407c478bd9Sstevel@tonic-gate qhead = q; 82417c478bd9Sstevel@tonic-gate else 82427c478bd9Sstevel@tonic-gate qtail->q_link = q; 82437c478bd9Sstevel@tonic-gate qtail = q; 82447c478bd9Sstevel@tonic-gate /* 82457c478bd9Sstevel@tonic-gate * Clear stp queue list. 82467c478bd9Sstevel@tonic-gate */ 82477c478bd9Sstevel@tonic-gate stp->sd_qhead = stp->sd_qtail = NULL; 82487c478bd9Sstevel@tonic-gate stp->sd_nqueues = 0; 82497c478bd9Sstevel@tonic-gate /* 82507c478bd9Sstevel@tonic-gate * Wakeup background queue processing thread. 82517c478bd9Sstevel@tonic-gate */ 82527c478bd9Sstevel@tonic-gate cv_signal(&services_to_run); 82537c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 82547c478bd9Sstevel@tonic-gate } 82557c478bd9Sstevel@tonic-gate } 82567c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_qlock); 82577c478bd9Sstevel@tonic-gate } 82587c478bd9Sstevel@tonic-gate 82597c478bd9Sstevel@tonic-gate static void 82607c478bd9Sstevel@tonic-gate queue_service(queue_t *q) 82617c478bd9Sstevel@tonic-gate { 82627c478bd9Sstevel@tonic-gate /* 82637c478bd9Sstevel@tonic-gate * The queue in the list should have 82647c478bd9Sstevel@tonic-gate * QENAB flag set and should not have 82657c478bd9Sstevel@tonic-gate * QINSERVICE flag set. QINSERVICE is 82667c478bd9Sstevel@tonic-gate * set when the queue is dequeued and 82677c478bd9Sstevel@tonic-gate * qenable_locked doesn't enqueue a 82687c478bd9Sstevel@tonic-gate * queue with QINSERVICE set. 82697c478bd9Sstevel@tonic-gate */ 82707c478bd9Sstevel@tonic-gate 82717c478bd9Sstevel@tonic-gate ASSERT(!(q->q_flag & QINSERVICE)); 82727c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QENAB)); 82737c478bd9Sstevel@tonic-gate mutex_enter(QLOCK(q)); 82747c478bd9Sstevel@tonic-gate q->q_flag &= ~QENAB; 82757c478bd9Sstevel@tonic-gate q->q_flag |= QINSERVICE; 82767c478bd9Sstevel@tonic-gate mutex_exit(QLOCK(q)); 82777c478bd9Sstevel@tonic-gate runservice(q); 82787c478bd9Sstevel@tonic-gate } 82797c478bd9Sstevel@tonic-gate 82807c478bd9Sstevel@tonic-gate static void 82817c478bd9Sstevel@tonic-gate syncq_service(syncq_t *sq) 82827c478bd9Sstevel@tonic-gate { 82837c478bd9Sstevel@tonic-gate STRSTAT(syncqservice); 82847c478bd9Sstevel@tonic-gate mutex_enter(SQLOCK(sq)); 82857c478bd9Sstevel@tonic-gate ASSERT(!(sq->sq_svcflags & SQ_SERVICE)); 82867c478bd9Sstevel@tonic-gate ASSERT(sq->sq_servcount != 0); 82877c478bd9Sstevel@tonic-gate ASSERT(sq->sq_next == NULL); 82887c478bd9Sstevel@tonic-gate 82897c478bd9Sstevel@tonic-gate /* if we came here from the background thread, clear the flag */ 82907c478bd9Sstevel@tonic-gate if (sq->sq_svcflags & SQ_BGTHREAD) 82917c478bd9Sstevel@tonic-gate sq->sq_svcflags &= ~SQ_BGTHREAD; 82927c478bd9Sstevel@tonic-gate 82937c478bd9Sstevel@tonic-gate /* let drain_syncq know that it's being called in the background */ 82947c478bd9Sstevel@tonic-gate sq->sq_svcflags |= SQ_SERVICE; 82957c478bd9Sstevel@tonic-gate drain_syncq(sq); 82967c478bd9Sstevel@tonic-gate } 82977c478bd9Sstevel@tonic-gate 82987c478bd9Sstevel@tonic-gate static void 82997c478bd9Sstevel@tonic-gate qwriter_outer_service(syncq_t *outer) 83007c478bd9Sstevel@tonic-gate { 83017c478bd9Sstevel@tonic-gate /* 83027c478bd9Sstevel@tonic-gate * Note that SQ_WRITER is used on the outer perimeter 83037c478bd9Sstevel@tonic-gate * to signal that a qwriter(OUTER) is either investigating 83047c478bd9Sstevel@tonic-gate * running or that it is actually running a function. 83057c478bd9Sstevel@tonic-gate */ 83067c478bd9Sstevel@tonic-gate outer_enter(outer, SQ_BLOCKED|SQ_WRITER); 83077c478bd9Sstevel@tonic-gate 83087c478bd9Sstevel@tonic-gate /* 83097c478bd9Sstevel@tonic-gate * All inner syncq are empty and have SQ_WRITER set 83107c478bd9Sstevel@tonic-gate * to block entering the outer perimeter. 83117c478bd9Sstevel@tonic-gate * 83127c478bd9Sstevel@tonic-gate * We do not need to explicitly call write_now since 83137c478bd9Sstevel@tonic-gate * outer_exit does it for us. 83147c478bd9Sstevel@tonic-gate */ 83157c478bd9Sstevel@tonic-gate outer_exit(outer); 83167c478bd9Sstevel@tonic-gate } 83177c478bd9Sstevel@tonic-gate 83187c478bd9Sstevel@tonic-gate static void 83197c478bd9Sstevel@tonic-gate mblk_free(mblk_t *mp) 83207c478bd9Sstevel@tonic-gate { 83217c478bd9Sstevel@tonic-gate dblk_t *dbp = mp->b_datap; 83227c478bd9Sstevel@tonic-gate frtn_t *frp = dbp->db_frtnp; 83237c478bd9Sstevel@tonic-gate 83247c478bd9Sstevel@tonic-gate mp->b_next = NULL; 83257c478bd9Sstevel@tonic-gate if (dbp->db_fthdr != NULL) 83267c478bd9Sstevel@tonic-gate str_ftfree(dbp); 83277c478bd9Sstevel@tonic-gate 83287c478bd9Sstevel@tonic-gate ASSERT(dbp->db_fthdr == NULL); 83297c478bd9Sstevel@tonic-gate frp->free_func(frp->free_arg); 83307c478bd9Sstevel@tonic-gate ASSERT(dbp->db_mblk == mp); 83317c478bd9Sstevel@tonic-gate 83327c478bd9Sstevel@tonic-gate if (dbp->db_credp != NULL) { 83337c478bd9Sstevel@tonic-gate crfree(dbp->db_credp); 83347c478bd9Sstevel@tonic-gate dbp->db_credp = NULL; 83357c478bd9Sstevel@tonic-gate } 83367c478bd9Sstevel@tonic-gate dbp->db_cpid = -1; 83377c478bd9Sstevel@tonic-gate dbp->db_struioflag = 0; 83387c478bd9Sstevel@tonic-gate dbp->db_struioun.cksum.flags = 0; 83397c478bd9Sstevel@tonic-gate 83407c478bd9Sstevel@tonic-gate kmem_cache_free(dbp->db_cache, dbp); 83417c478bd9Sstevel@tonic-gate } 83427c478bd9Sstevel@tonic-gate 83437c478bd9Sstevel@tonic-gate /* 83447c478bd9Sstevel@tonic-gate * Background processing of the stream queue list. 83457c478bd9Sstevel@tonic-gate */ 83467c478bd9Sstevel@tonic-gate static void 83477c478bd9Sstevel@tonic-gate stream_service(stdata_t *stp) 83487c478bd9Sstevel@tonic-gate { 83497c478bd9Sstevel@tonic-gate queue_t *q; 83507c478bd9Sstevel@tonic-gate 83517c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_qlock); 83527c478bd9Sstevel@tonic-gate 83537c478bd9Sstevel@tonic-gate STR_SERVICE(stp, q); 83547c478bd9Sstevel@tonic-gate 83557c478bd9Sstevel@tonic-gate stp->sd_svcflags &= ~STRS_SCHEDULED; 83567c478bd9Sstevel@tonic-gate stp->sd_servid = NULL; 83577c478bd9Sstevel@tonic-gate cv_signal(&stp->sd_qcv); 83587c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_qlock); 83597c478bd9Sstevel@tonic-gate } 83607c478bd9Sstevel@tonic-gate 83617c478bd9Sstevel@tonic-gate /* 83627c478bd9Sstevel@tonic-gate * Foreground processing of the stream queue list. 83637c478bd9Sstevel@tonic-gate */ 83647c478bd9Sstevel@tonic-gate void 83657c478bd9Sstevel@tonic-gate stream_runservice(stdata_t *stp) 83667c478bd9Sstevel@tonic-gate { 83677c478bd9Sstevel@tonic-gate queue_t *q; 83687c478bd9Sstevel@tonic-gate 83697c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_qlock); 83707c478bd9Sstevel@tonic-gate STRSTAT(rservice); 83717c478bd9Sstevel@tonic-gate /* 83727c478bd9Sstevel@tonic-gate * We are going to drain this stream queue list, so qenable_locked will 83737c478bd9Sstevel@tonic-gate * not schedule it until we finish. 83747c478bd9Sstevel@tonic-gate */ 83757c478bd9Sstevel@tonic-gate stp->sd_svcflags |= STRS_WILLSERVICE; 83767c478bd9Sstevel@tonic-gate 83777c478bd9Sstevel@tonic-gate STR_SERVICE(stp, q); 83787c478bd9Sstevel@tonic-gate 83797c478bd9Sstevel@tonic-gate stp->sd_svcflags &= ~STRS_WILLSERVICE; 83807c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_qlock); 83817c478bd9Sstevel@tonic-gate /* 83827c478bd9Sstevel@tonic-gate * Help backup background thread to drain the qhead/qtail list. 83837c478bd9Sstevel@tonic-gate */ 83847c478bd9Sstevel@tonic-gate while (qhead != NULL) { 83857c478bd9Sstevel@tonic-gate STRSTAT(qhelps); 83867c478bd9Sstevel@tonic-gate mutex_enter(&service_queue); 83877c478bd9Sstevel@tonic-gate DQ(q, qhead, qtail, q_link); 83887c478bd9Sstevel@tonic-gate mutex_exit(&service_queue); 83897c478bd9Sstevel@tonic-gate if (q != NULL) 83907c478bd9Sstevel@tonic-gate queue_service(q); 83917c478bd9Sstevel@tonic-gate } 83927c478bd9Sstevel@tonic-gate } 83937c478bd9Sstevel@tonic-gate 83947c478bd9Sstevel@tonic-gate void 83957c478bd9Sstevel@tonic-gate stream_willservice(stdata_t *stp) 83967c478bd9Sstevel@tonic-gate { 83977c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_qlock); 83987c478bd9Sstevel@tonic-gate stp->sd_svcflags |= STRS_WILLSERVICE; 83997c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_qlock); 84007c478bd9Sstevel@tonic-gate } 84017c478bd9Sstevel@tonic-gate 84027c478bd9Sstevel@tonic-gate /* 84037c478bd9Sstevel@tonic-gate * Replace the cred currently in the mblk with a different one. 8404de8c4a14SErik Nordmark * Also update db_cpid. 84057c478bd9Sstevel@tonic-gate */ 84067c478bd9Sstevel@tonic-gate void 8407de8c4a14SErik Nordmark mblk_setcred(mblk_t *mp, cred_t *cr, pid_t cpid) 84087c478bd9Sstevel@tonic-gate { 8409de8c4a14SErik Nordmark dblk_t *dbp = mp->b_datap; 8410de8c4a14SErik Nordmark cred_t *ocr = dbp->db_credp; 84117c478bd9Sstevel@tonic-gate 84127c478bd9Sstevel@tonic-gate ASSERT(cr != NULL); 84137c478bd9Sstevel@tonic-gate 84147c478bd9Sstevel@tonic-gate if (cr != ocr) { 8415de8c4a14SErik Nordmark crhold(dbp->db_credp = cr); 84167c478bd9Sstevel@tonic-gate if (ocr != NULL) 84177c478bd9Sstevel@tonic-gate crfree(ocr); 84187c478bd9Sstevel@tonic-gate } 8419de8c4a14SErik Nordmark /* Don't overwrite with NOPID */ 8420de8c4a14SErik Nordmark if (cpid != NOPID) 8421de8c4a14SErik Nordmark dbp->db_cpid = cpid; 84227c478bd9Sstevel@tonic-gate } 84237c478bd9Sstevel@tonic-gate 84240f1702c5SYu Xiangning /* 8425de8c4a14SErik Nordmark * If the src message has a cred, then replace the cred currently in the mblk 8426de8c4a14SErik Nordmark * with it. 8427de8c4a14SErik Nordmark * Also update db_cpid. 84280f1702c5SYu Xiangning */ 84290f1702c5SYu Xiangning void 8430de8c4a14SErik Nordmark mblk_copycred(mblk_t *mp, const mblk_t *src) 84310f1702c5SYu Xiangning { 8432de8c4a14SErik Nordmark dblk_t *dbp = mp->b_datap; 8433de8c4a14SErik Nordmark cred_t *cr, *ocr; 8434de8c4a14SErik Nordmark pid_t cpid; 8435de8c4a14SErik Nordmark 8436de8c4a14SErik Nordmark cr = msg_getcred(src, &cpid); 8437de8c4a14SErik Nordmark if (cr == NULL) 8438de8c4a14SErik Nordmark return; 8439de8c4a14SErik Nordmark 8440de8c4a14SErik Nordmark ocr = dbp->db_credp; 8441de8c4a14SErik Nordmark if (cr != ocr) { 8442de8c4a14SErik Nordmark crhold(dbp->db_credp = cr); 8443de8c4a14SErik Nordmark if (ocr != NULL) 8444de8c4a14SErik Nordmark crfree(ocr); 84450f1702c5SYu Xiangning } 8446de8c4a14SErik Nordmark /* Don't overwrite with NOPID */ 8447de8c4a14SErik Nordmark if (cpid != NOPID) 8448de8c4a14SErik Nordmark dbp->db_cpid = cpid; 84490f1702c5SYu Xiangning } 84500f1702c5SYu Xiangning 84517c478bd9Sstevel@tonic-gate int 84527c478bd9Sstevel@tonic-gate hcksum_assoc(mblk_t *mp, multidata_t *mmd, pdesc_t *pd, 84537c478bd9Sstevel@tonic-gate uint32_t start, uint32_t stuff, uint32_t end, uint32_t value, 84547c478bd9Sstevel@tonic-gate uint32_t flags, int km_flags) 84557c478bd9Sstevel@tonic-gate { 84567c478bd9Sstevel@tonic-gate int rc = 0; 84577c478bd9Sstevel@tonic-gate 84587c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_MULTIDATA); 84597c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) { 84607c478bd9Sstevel@tonic-gate /* Associate values for M_DATA type */ 8461ff550d0eSmasputra DB_CKSUMSTART(mp) = (intptr_t)start; 8462ff550d0eSmasputra DB_CKSUMSTUFF(mp) = (intptr_t)stuff; 8463ff550d0eSmasputra DB_CKSUMEND(mp) = (intptr_t)end; 8464ff550d0eSmasputra DB_CKSUMFLAGS(mp) = flags; 8465ff550d0eSmasputra DB_CKSUM16(mp) = (uint16_t)value; 84667c478bd9Sstevel@tonic-gate 84677c478bd9Sstevel@tonic-gate } else { 84687c478bd9Sstevel@tonic-gate pattrinfo_t pa_info; 84697c478bd9Sstevel@tonic-gate 84707c478bd9Sstevel@tonic-gate ASSERT(mmd != NULL); 84717c478bd9Sstevel@tonic-gate 84727c478bd9Sstevel@tonic-gate pa_info.type = PATTR_HCKSUM; 84737c478bd9Sstevel@tonic-gate pa_info.len = sizeof (pattr_hcksum_t); 84747c478bd9Sstevel@tonic-gate 84757c478bd9Sstevel@tonic-gate if (mmd_addpattr(mmd, pd, &pa_info, B_TRUE, km_flags) != NULL) { 84767c478bd9Sstevel@tonic-gate pattr_hcksum_t *hck = (pattr_hcksum_t *)pa_info.buf; 84777c478bd9Sstevel@tonic-gate 84787c478bd9Sstevel@tonic-gate hck->hcksum_start_offset = start; 84797c478bd9Sstevel@tonic-gate hck->hcksum_stuff_offset = stuff; 84807c478bd9Sstevel@tonic-gate hck->hcksum_end_offset = end; 84817c478bd9Sstevel@tonic-gate hck->hcksum_cksum_val.inet_cksum = (uint16_t)value; 84827c478bd9Sstevel@tonic-gate hck->hcksum_flags = flags; 8483ff550d0eSmasputra } else { 8484ff550d0eSmasputra rc = -1; 84857c478bd9Sstevel@tonic-gate } 84867c478bd9Sstevel@tonic-gate } 84877c478bd9Sstevel@tonic-gate return (rc); 84887c478bd9Sstevel@tonic-gate } 84897c478bd9Sstevel@tonic-gate 84907c478bd9Sstevel@tonic-gate void 84917c478bd9Sstevel@tonic-gate hcksum_retrieve(mblk_t *mp, multidata_t *mmd, pdesc_t *pd, 84927c478bd9Sstevel@tonic-gate uint32_t *start, uint32_t *stuff, uint32_t *end, 84937c478bd9Sstevel@tonic-gate uint32_t *value, uint32_t *flags) 84947c478bd9Sstevel@tonic-gate { 84957c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_MULTIDATA); 84967c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) { 84977c478bd9Sstevel@tonic-gate if (flags != NULL) { 8498bd670b35SErik Nordmark *flags = DB_CKSUMFLAGS(mp) & HCK_FLAGS; 8499da14cebeSEric Cheng if ((*flags & (HCK_PARTIALCKSUM | 8500da14cebeSEric Cheng HCK_FULLCKSUM)) != 0) { 85017c478bd9Sstevel@tonic-gate if (value != NULL) 8502ff550d0eSmasputra *value = (uint32_t)DB_CKSUM16(mp); 8503da14cebeSEric Cheng if ((*flags & HCK_PARTIALCKSUM) != 0) { 8504da14cebeSEric Cheng if (start != NULL) 8505da14cebeSEric Cheng *start = 8506da14cebeSEric Cheng (uint32_t)DB_CKSUMSTART(mp); 8507da14cebeSEric Cheng if (stuff != NULL) 8508da14cebeSEric Cheng *stuff = 8509da14cebeSEric Cheng (uint32_t)DB_CKSUMSTUFF(mp); 8510da14cebeSEric Cheng if (end != NULL) 8511da14cebeSEric Cheng *end = 8512da14cebeSEric Cheng (uint32_t)DB_CKSUMEND(mp); 8513da14cebeSEric Cheng } 8514da14cebeSEric Cheng } 85157c478bd9Sstevel@tonic-gate } 85167c478bd9Sstevel@tonic-gate } else { 85177c478bd9Sstevel@tonic-gate pattrinfo_t hck_attr = {PATTR_HCKSUM}; 85187c478bd9Sstevel@tonic-gate 85197c478bd9Sstevel@tonic-gate ASSERT(mmd != NULL); 85207c478bd9Sstevel@tonic-gate 85217c478bd9Sstevel@tonic-gate /* get hardware checksum attribute */ 85227c478bd9Sstevel@tonic-gate if (mmd_getpattr(mmd, pd, &hck_attr) != NULL) { 85237c478bd9Sstevel@tonic-gate pattr_hcksum_t *hck = (pattr_hcksum_t *)hck_attr.buf; 85247c478bd9Sstevel@tonic-gate 85257c478bd9Sstevel@tonic-gate ASSERT(hck_attr.len >= sizeof (pattr_hcksum_t)); 85267c478bd9Sstevel@tonic-gate if (flags != NULL) 85277c478bd9Sstevel@tonic-gate *flags = hck->hcksum_flags; 85287c478bd9Sstevel@tonic-gate if (start != NULL) 85297c478bd9Sstevel@tonic-gate *start = hck->hcksum_start_offset; 85307c478bd9Sstevel@tonic-gate if (stuff != NULL) 85317c478bd9Sstevel@tonic-gate *stuff = hck->hcksum_stuff_offset; 85327c478bd9Sstevel@tonic-gate if (end != NULL) 85337c478bd9Sstevel@tonic-gate *end = hck->hcksum_end_offset; 85347c478bd9Sstevel@tonic-gate if (value != NULL) 85357c478bd9Sstevel@tonic-gate *value = (uint32_t) 85367c478bd9Sstevel@tonic-gate hck->hcksum_cksum_val.inet_cksum; 85377c478bd9Sstevel@tonic-gate } 85387c478bd9Sstevel@tonic-gate } 85397c478bd9Sstevel@tonic-gate } 85407c478bd9Sstevel@tonic-gate 8541da14cebeSEric Cheng void 8542da14cebeSEric Cheng lso_info_set(mblk_t *mp, uint32_t mss, uint32_t flags) 8543da14cebeSEric Cheng { 8544da14cebeSEric Cheng ASSERT(DB_TYPE(mp) == M_DATA); 85451908fb0eSRoamer ASSERT((flags & ~HW_LSO_FLAGS) == 0); 8546da14cebeSEric Cheng 8547da14cebeSEric Cheng /* Set the flags */ 8548da14cebeSEric Cheng DB_LSOFLAGS(mp) |= flags; 8549da14cebeSEric Cheng DB_LSOMSS(mp) = mss; 8550da14cebeSEric Cheng } 8551da14cebeSEric Cheng 8552da14cebeSEric Cheng void 85531908fb0eSRoamer lso_info_cleanup(mblk_t *mp) 85541908fb0eSRoamer { 85551908fb0eSRoamer ASSERT(DB_TYPE(mp) == M_DATA); 85561908fb0eSRoamer 85571908fb0eSRoamer /* Clear the flags */ 85581908fb0eSRoamer DB_LSOFLAGS(mp) &= ~HW_LSO_FLAGS; 85591908fb0eSRoamer DB_LSOMSS(mp) = 0; 85601908fb0eSRoamer } 85611908fb0eSRoamer 85627c478bd9Sstevel@tonic-gate /* 85637c478bd9Sstevel@tonic-gate * Checksum buffer *bp for len bytes with psum partial checksum, 85647c478bd9Sstevel@tonic-gate * or 0 if none, and return the 16 bit partial checksum. 85657c478bd9Sstevel@tonic-gate */ 85667c478bd9Sstevel@tonic-gate unsigned 85677c478bd9Sstevel@tonic-gate bcksum(uchar_t *bp, int len, unsigned int psum) 85687c478bd9Sstevel@tonic-gate { 85697c478bd9Sstevel@tonic-gate int odd = len & 1; 85707c478bd9Sstevel@tonic-gate extern unsigned int ip_ocsum(); 85717c478bd9Sstevel@tonic-gate 85727c478bd9Sstevel@tonic-gate if (((intptr_t)bp & 1) == 0 && !odd) { 85737c478bd9Sstevel@tonic-gate /* 85747c478bd9Sstevel@tonic-gate * Bp is 16 bit aligned and len is multiple of 16 bit word. 85757c478bd9Sstevel@tonic-gate */ 85767c478bd9Sstevel@tonic-gate return (ip_ocsum((ushort_t *)bp, len >> 1, psum)); 85777c478bd9Sstevel@tonic-gate } 85787c478bd9Sstevel@tonic-gate if (((intptr_t)bp & 1) != 0) { 85797c478bd9Sstevel@tonic-gate /* 85807c478bd9Sstevel@tonic-gate * Bp isn't 16 bit aligned. 85817c478bd9Sstevel@tonic-gate */ 85827c478bd9Sstevel@tonic-gate unsigned int tsum; 85837c478bd9Sstevel@tonic-gate 85847c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 85857c478bd9Sstevel@tonic-gate psum += *bp; 85867c478bd9Sstevel@tonic-gate #else 85877c478bd9Sstevel@tonic-gate psum += *bp << 8; 85887c478bd9Sstevel@tonic-gate #endif 85897c478bd9Sstevel@tonic-gate len--; 85907c478bd9Sstevel@tonic-gate bp++; 85917c478bd9Sstevel@tonic-gate tsum = ip_ocsum((ushort_t *)bp, len >> 1, 0); 85927c478bd9Sstevel@tonic-gate psum += (tsum << 8) & 0xffff | (tsum >> 8); 85937c478bd9Sstevel@tonic-gate if (len & 1) { 85947c478bd9Sstevel@tonic-gate bp += len - 1; 85957c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 85967c478bd9Sstevel@tonic-gate psum += *bp << 8; 85977c478bd9Sstevel@tonic-gate #else 85987c478bd9Sstevel@tonic-gate psum += *bp; 85997c478bd9Sstevel@tonic-gate #endif 86007c478bd9Sstevel@tonic-gate } 86017c478bd9Sstevel@tonic-gate } else { 86027c478bd9Sstevel@tonic-gate /* 86037c478bd9Sstevel@tonic-gate * Bp is 16 bit aligned. 86047c478bd9Sstevel@tonic-gate */ 86057c478bd9Sstevel@tonic-gate psum = ip_ocsum((ushort_t *)bp, len >> 1, psum); 86067c478bd9Sstevel@tonic-gate if (odd) { 86077c478bd9Sstevel@tonic-gate bp += len - 1; 86087c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 86097c478bd9Sstevel@tonic-gate psum += *bp; 86107c478bd9Sstevel@tonic-gate #else 86117c478bd9Sstevel@tonic-gate psum += *bp << 8; 86127c478bd9Sstevel@tonic-gate #endif 86137c478bd9Sstevel@tonic-gate } 86147c478bd9Sstevel@tonic-gate } 86157c478bd9Sstevel@tonic-gate /* 86167c478bd9Sstevel@tonic-gate * Normalize psum to 16 bits before returning the new partial 86177c478bd9Sstevel@tonic-gate * checksum. The max psum value before normalization is 0x3FDFE. 86187c478bd9Sstevel@tonic-gate */ 86197c478bd9Sstevel@tonic-gate return ((psum >> 16) + (psum & 0xFFFF)); 86207c478bd9Sstevel@tonic-gate } 86217c478bd9Sstevel@tonic-gate 86227c478bd9Sstevel@tonic-gate boolean_t 86237c478bd9Sstevel@tonic-gate is_vmloaned_mblk(mblk_t *mp, multidata_t *mmd, pdesc_t *pd) 86247c478bd9Sstevel@tonic-gate { 86257c478bd9Sstevel@tonic-gate boolean_t rc; 86267c478bd9Sstevel@tonic-gate 86277c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_MULTIDATA); 86287c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_DATA) { 86297c478bd9Sstevel@tonic-gate rc = (((mp)->b_datap->db_struioflag & STRUIO_ZC) != 0); 86307c478bd9Sstevel@tonic-gate } else { 86317c478bd9Sstevel@tonic-gate pattrinfo_t zcopy_attr = {PATTR_ZCOPY}; 86327c478bd9Sstevel@tonic-gate 86337c478bd9Sstevel@tonic-gate ASSERT(mmd != NULL); 86347c478bd9Sstevel@tonic-gate rc = (mmd_getpattr(mmd, pd, &zcopy_attr) != NULL); 86357c478bd9Sstevel@tonic-gate } 86367c478bd9Sstevel@tonic-gate return (rc); 86377c478bd9Sstevel@tonic-gate } 86387c478bd9Sstevel@tonic-gate 86397c478bd9Sstevel@tonic-gate void 86407c478bd9Sstevel@tonic-gate freemsgchain(mblk_t *mp) 86417c478bd9Sstevel@tonic-gate { 86427c478bd9Sstevel@tonic-gate mblk_t *next; 86437c478bd9Sstevel@tonic-gate 86447c478bd9Sstevel@tonic-gate while (mp != NULL) { 86457c478bd9Sstevel@tonic-gate next = mp->b_next; 86467c478bd9Sstevel@tonic-gate mp->b_next = NULL; 86477c478bd9Sstevel@tonic-gate 86487c478bd9Sstevel@tonic-gate freemsg(mp); 86497c478bd9Sstevel@tonic-gate mp = next; 86507c478bd9Sstevel@tonic-gate } 86517c478bd9Sstevel@tonic-gate } 86527c478bd9Sstevel@tonic-gate 86537c478bd9Sstevel@tonic-gate mblk_t * 86547c478bd9Sstevel@tonic-gate copymsgchain(mblk_t *mp) 86557c478bd9Sstevel@tonic-gate { 86567c478bd9Sstevel@tonic-gate mblk_t *nmp = NULL; 86577c478bd9Sstevel@tonic-gate mblk_t **nmpp = &nmp; 86587c478bd9Sstevel@tonic-gate 86597c478bd9Sstevel@tonic-gate for (; mp != NULL; mp = mp->b_next) { 86607c478bd9Sstevel@tonic-gate if ((*nmpp = copymsg(mp)) == NULL) { 86617c478bd9Sstevel@tonic-gate freemsgchain(nmp); 86627c478bd9Sstevel@tonic-gate return (NULL); 86637c478bd9Sstevel@tonic-gate } 86647c478bd9Sstevel@tonic-gate 86657c478bd9Sstevel@tonic-gate nmpp = &((*nmpp)->b_next); 86667c478bd9Sstevel@tonic-gate } 86677c478bd9Sstevel@tonic-gate 86687c478bd9Sstevel@tonic-gate return (nmp); 86697c478bd9Sstevel@tonic-gate } 86707c478bd9Sstevel@tonic-gate 86717c478bd9Sstevel@tonic-gate /* NOTE: Do not add code after this point. */ 86727c478bd9Sstevel@tonic-gate #undef QLOCK 86737c478bd9Sstevel@tonic-gate 86747c478bd9Sstevel@tonic-gate /* 867521804b56SBrian Ruthven * Replacement for QLOCK macro for those that can't use it. 86767c478bd9Sstevel@tonic-gate */ 86777c478bd9Sstevel@tonic-gate kmutex_t * 86787c478bd9Sstevel@tonic-gate QLOCK(queue_t *q) 86797c478bd9Sstevel@tonic-gate { 86807c478bd9Sstevel@tonic-gate return (&(q)->q_lock); 86817c478bd9Sstevel@tonic-gate } 86827c478bd9Sstevel@tonic-gate 86837c478bd9Sstevel@tonic-gate /* 86847c478bd9Sstevel@tonic-gate * Dummy runqueues/queuerun functions functions for backwards compatibility. 86857c478bd9Sstevel@tonic-gate */ 86867c478bd9Sstevel@tonic-gate #undef runqueues 86877c478bd9Sstevel@tonic-gate void 86887c478bd9Sstevel@tonic-gate runqueues(void) 86897c478bd9Sstevel@tonic-gate { 86907c478bd9Sstevel@tonic-gate } 86917c478bd9Sstevel@tonic-gate 86927c478bd9Sstevel@tonic-gate #undef queuerun 86937c478bd9Sstevel@tonic-gate void 86947c478bd9Sstevel@tonic-gate queuerun(void) 86957c478bd9Sstevel@tonic-gate { 86967c478bd9Sstevel@tonic-gate } 8697f4b3ec61Sdh155122 8698f4b3ec61Sdh155122 /* 8699f4b3ec61Sdh155122 * Initialize the STR stack instance, which tracks autopush and persistent 8700f4b3ec61Sdh155122 * links. 8701f4b3ec61Sdh155122 */ 8702f4b3ec61Sdh155122 /* ARGSUSED */ 8703f4b3ec61Sdh155122 static void * 8704f4b3ec61Sdh155122 str_stack_init(netstackid_t stackid, netstack_t *ns) 8705f4b3ec61Sdh155122 { 8706f4b3ec61Sdh155122 str_stack_t *ss; 8707f4b3ec61Sdh155122 int i; 8708f4b3ec61Sdh155122 8709f4b3ec61Sdh155122 ss = (str_stack_t *)kmem_zalloc(sizeof (*ss), KM_SLEEP); 8710f4b3ec61Sdh155122 ss->ss_netstack = ns; 8711f4b3ec61Sdh155122 8712f4b3ec61Sdh155122 /* 8713f4b3ec61Sdh155122 * set up autopush 8714f4b3ec61Sdh155122 */ 8715f4b3ec61Sdh155122 sad_initspace(ss); 8716f4b3ec61Sdh155122 8717f4b3ec61Sdh155122 /* 8718f4b3ec61Sdh155122 * set up mux_node structures. 8719f4b3ec61Sdh155122 */ 8720f4b3ec61Sdh155122 ss->ss_devcnt = devcnt; /* In case it should change before free */ 8721f4b3ec61Sdh155122 ss->ss_mux_nodes = kmem_zalloc((sizeof (struct mux_node) * 8722f4b3ec61Sdh155122 ss->ss_devcnt), KM_SLEEP); 8723f4b3ec61Sdh155122 for (i = 0; i < ss->ss_devcnt; i++) 8724f4b3ec61Sdh155122 ss->ss_mux_nodes[i].mn_imaj = i; 8725f4b3ec61Sdh155122 return (ss); 8726f4b3ec61Sdh155122 } 8727f4b3ec61Sdh155122 8728f4b3ec61Sdh155122 /* 8729f4b3ec61Sdh155122 * Note: run at zone shutdown and not destroy so that the PLINKs are 8730f4b3ec61Sdh155122 * gone by the time other cleanup happens from the destroy callbacks. 8731f4b3ec61Sdh155122 */ 8732f4b3ec61Sdh155122 static void 8733f4b3ec61Sdh155122 str_stack_shutdown(netstackid_t stackid, void *arg) 8734f4b3ec61Sdh155122 { 8735f4b3ec61Sdh155122 str_stack_t *ss = (str_stack_t *)arg; 8736f4b3ec61Sdh155122 int i; 8737f4b3ec61Sdh155122 cred_t *cr; 8738f4b3ec61Sdh155122 8739f4b3ec61Sdh155122 cr = zone_get_kcred(netstackid_to_zoneid(stackid)); 8740f4b3ec61Sdh155122 ASSERT(cr != NULL); 8741f4b3ec61Sdh155122 8742f4b3ec61Sdh155122 /* Undo all the I_PLINKs for this zone */ 8743f4b3ec61Sdh155122 for (i = 0; i < ss->ss_devcnt; i++) { 8744f4b3ec61Sdh155122 struct mux_edge *ep; 8745f4b3ec61Sdh155122 ldi_handle_t lh; 8746f4b3ec61Sdh155122 ldi_ident_t li; 8747f4b3ec61Sdh155122 int ret; 8748f4b3ec61Sdh155122 int rval; 8749f4b3ec61Sdh155122 dev_t rdev; 8750f4b3ec61Sdh155122 8751f4b3ec61Sdh155122 ep = ss->ss_mux_nodes[i].mn_outp; 8752f4b3ec61Sdh155122 if (ep == NULL) 8753f4b3ec61Sdh155122 continue; 8754f4b3ec61Sdh155122 ret = ldi_ident_from_major((major_t)i, &li); 8755f4b3ec61Sdh155122 if (ret != 0) { 8756f4b3ec61Sdh155122 continue; 8757f4b3ec61Sdh155122 } 8758f4b3ec61Sdh155122 rdev = ep->me_dev; 8759f4b3ec61Sdh155122 ret = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD|FWRITE, 8760f4b3ec61Sdh155122 cr, &lh, li); 8761f4b3ec61Sdh155122 if (ret != 0) { 8762f4b3ec61Sdh155122 ldi_ident_release(li); 8763f4b3ec61Sdh155122 continue; 8764f4b3ec61Sdh155122 } 8765f4b3ec61Sdh155122 8766f4b3ec61Sdh155122 ret = ldi_ioctl(lh, I_PUNLINK, (intptr_t)MUXID_ALL, FKIOCTL, 8767f4b3ec61Sdh155122 cr, &rval); 8768f4b3ec61Sdh155122 if (ret) { 8769f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 8770f4b3ec61Sdh155122 ldi_ident_release(li); 8771f4b3ec61Sdh155122 continue; 8772f4b3ec61Sdh155122 } 8773f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 8774f4b3ec61Sdh155122 8775f4b3ec61Sdh155122 /* Close layered handles */ 8776f4b3ec61Sdh155122 ldi_ident_release(li); 8777f4b3ec61Sdh155122 } 8778f4b3ec61Sdh155122 crfree(cr); 8779f4b3ec61Sdh155122 8780f4b3ec61Sdh155122 sad_freespace(ss); 8781f4b3ec61Sdh155122 8782f4b3ec61Sdh155122 kmem_free(ss->ss_mux_nodes, sizeof (struct mux_node) * ss->ss_devcnt); 8783f4b3ec61Sdh155122 ss->ss_mux_nodes = NULL; 8784f4b3ec61Sdh155122 } 8785f4b3ec61Sdh155122 8786f4b3ec61Sdh155122 /* 8787f4b3ec61Sdh155122 * Free the structure; str_stack_shutdown did the other cleanup work. 8788f4b3ec61Sdh155122 */ 8789f4b3ec61Sdh155122 /* ARGSUSED */ 8790f4b3ec61Sdh155122 static void 8791f4b3ec61Sdh155122 str_stack_fini(netstackid_t stackid, void *arg) 8792f4b3ec61Sdh155122 { 8793f4b3ec61Sdh155122 str_stack_t *ss = (str_stack_t *)arg; 8794f4b3ec61Sdh155122 8795f4b3ec61Sdh155122 kmem_free(ss, sizeof (*ss)); 8796f4b3ec61Sdh155122 } 8797