1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Contracts 31*7c478bd9Sstevel@tonic-gate * --------- 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * Contracts are a primitive which enrich the relationships between 34*7c478bd9Sstevel@tonic-gate * processes and system resources. The primary purpose of contracts is 35*7c478bd9Sstevel@tonic-gate * to provide a means for the system to negotiate the departure from a 36*7c478bd9Sstevel@tonic-gate * binding relationship (e.g. pages locked in memory or a thread bound 37*7c478bd9Sstevel@tonic-gate * to processor), but they can also be used as a purely asynchronous 38*7c478bd9Sstevel@tonic-gate * error reporting mechanism as they are with process contracts. 39*7c478bd9Sstevel@tonic-gate * 40*7c478bd9Sstevel@tonic-gate * More information on how one interfaces with contracts and what 41*7c478bd9Sstevel@tonic-gate * contracts can do for you can be found in: 42*7c478bd9Sstevel@tonic-gate * PSARC 2003/193 Solaris Contracts 43*7c478bd9Sstevel@tonic-gate * PSARC 2004/460 Contracts addendum 44*7c478bd9Sstevel@tonic-gate * 45*7c478bd9Sstevel@tonic-gate * This file contains the core contracts framework. By itself it is 46*7c478bd9Sstevel@tonic-gate * useless: it depends the contracts filesystem (ctfs) to provide an 47*7c478bd9Sstevel@tonic-gate * interface to user processes and individual contract types to 48*7c478bd9Sstevel@tonic-gate * implement the process/resource relationships. 49*7c478bd9Sstevel@tonic-gate * 50*7c478bd9Sstevel@tonic-gate * Data structure overview 51*7c478bd9Sstevel@tonic-gate * ----------------------- 52*7c478bd9Sstevel@tonic-gate * 53*7c478bd9Sstevel@tonic-gate * A contract is represented by a contract_t, which itself points to an 54*7c478bd9Sstevel@tonic-gate * encapsulating contract-type specific contract object. A contract_t 55*7c478bd9Sstevel@tonic-gate * contains the contract's static identity (including its terms), its 56*7c478bd9Sstevel@tonic-gate * linkage to various bookkeeping structures, the contract-specific 57*7c478bd9Sstevel@tonic-gate * event queue, and a reference count. 58*7c478bd9Sstevel@tonic-gate * 59*7c478bd9Sstevel@tonic-gate * A contract template is represented by a ct_template_t, which, like a 60*7c478bd9Sstevel@tonic-gate * contract, points to an encapsulating contract-type specific template 61*7c478bd9Sstevel@tonic-gate * object. A ct_template_t contains the template's terms. 62*7c478bd9Sstevel@tonic-gate * 63*7c478bd9Sstevel@tonic-gate * An event queue is represented by a ct_equeue_t, and consists of a 64*7c478bd9Sstevel@tonic-gate * list of events, a list of listeners, and a list of listeners who are 65*7c478bd9Sstevel@tonic-gate * waiting for new events (affectionately referred to as "tail 66*7c478bd9Sstevel@tonic-gate * listeners"). There are three queue types, defined by ct_listnum_t 67*7c478bd9Sstevel@tonic-gate * (an enum). An event may be on one of each type of queue 68*7c478bd9Sstevel@tonic-gate * simultaneously; the list linkage used by a queue is determined by 69*7c478bd9Sstevel@tonic-gate * its type. 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * An event is represented by a ct_kevent_t, which contains mostly 72*7c478bd9Sstevel@tonic-gate * static event data (e.g. id, payload). It also has an array of 73*7c478bd9Sstevel@tonic-gate * ct_member_t structures, each of which contains a list_node_t and 74*7c478bd9Sstevel@tonic-gate * represent the event's linkage in a specific event queue. 75*7c478bd9Sstevel@tonic-gate * 76*7c478bd9Sstevel@tonic-gate * Each open of an event endpoint results in the creation of a new 77*7c478bd9Sstevel@tonic-gate * listener, represented by a ct_listener_t. In addition to linkage 78*7c478bd9Sstevel@tonic-gate * into the aforementioned lists in the event_queue, a ct_listener_t 79*7c478bd9Sstevel@tonic-gate * contains a pointer to the ct_kevent_t it is currently positioned at 80*7c478bd9Sstevel@tonic-gate * as well as a set of status flags and other administrative data. 81*7c478bd9Sstevel@tonic-gate * 82*7c478bd9Sstevel@tonic-gate * Each process has a list of contracts it owns, p_ct_held; a pointer 83*7c478bd9Sstevel@tonic-gate * to the process contract it is a member of, p_ct_process; the linkage 84*7c478bd9Sstevel@tonic-gate * for that membership, p_ct_member; and an array of event queue 85*7c478bd9Sstevel@tonic-gate * structures representing the process bundle queues. 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * Each LWP has an array of its active templates, lwp_ct_active; and 88*7c478bd9Sstevel@tonic-gate * the most recently created contracts, lwp_ct_latest. 89*7c478bd9Sstevel@tonic-gate * 90*7c478bd9Sstevel@tonic-gate * A process contract has a list of member processes and a list of 91*7c478bd9Sstevel@tonic-gate * inherited contracts. 92*7c478bd9Sstevel@tonic-gate * 93*7c478bd9Sstevel@tonic-gate * There is a system-wide list of all contracts, as well as per-type 94*7c478bd9Sstevel@tonic-gate * lists of contracts. 95*7c478bd9Sstevel@tonic-gate * 96*7c478bd9Sstevel@tonic-gate * Lock ordering overview 97*7c478bd9Sstevel@tonic-gate * ---------------------- 98*7c478bd9Sstevel@tonic-gate * 99*7c478bd9Sstevel@tonic-gate * Locks at the top are taken first: 100*7c478bd9Sstevel@tonic-gate * 101*7c478bd9Sstevel@tonic-gate * ct_evtlock 102*7c478bd9Sstevel@tonic-gate * regent ct_lock 103*7c478bd9Sstevel@tonic-gate * member ct_lock 104*7c478bd9Sstevel@tonic-gate * pidlock 105*7c478bd9Sstevel@tonic-gate * p_lock 106*7c478bd9Sstevel@tonic-gate * contract ctq_lock contract_lock 107*7c478bd9Sstevel@tonic-gate * pbundle ctq_lock 108*7c478bd9Sstevel@tonic-gate * cte_lock 109*7c478bd9Sstevel@tonic-gate * ct_reflock 110*7c478bd9Sstevel@tonic-gate * 111*7c478bd9Sstevel@tonic-gate * contract_lock and ctq_lock/cte_lock are not currently taken at the 112*7c478bd9Sstevel@tonic-gate * same time. 113*7c478bd9Sstevel@tonic-gate * 114*7c478bd9Sstevel@tonic-gate * Reference counting and locking 115*7c478bd9Sstevel@tonic-gate * ------------------------------ 116*7c478bd9Sstevel@tonic-gate * 117*7c478bd9Sstevel@tonic-gate * A contract has a reference count, protected by ct_reflock. 118*7c478bd9Sstevel@tonic-gate * (ct_reflock is also used in a couple other places where atomic 119*7c478bd9Sstevel@tonic-gate * access to a variable is needed in an innermost context). A process 120*7c478bd9Sstevel@tonic-gate * maintains a hold on each contract it owns. A process contract has a 121*7c478bd9Sstevel@tonic-gate * hold on each contract is has inherited. Each event has a hold on 122*7c478bd9Sstevel@tonic-gate * the contract which generated it. Process contract templates have 123*7c478bd9Sstevel@tonic-gate * holds on the contracts referred to by their transfer terms. CTFS 124*7c478bd9Sstevel@tonic-gate * contract directory nodes have holds on contracts. Lastly, various 125*7c478bd9Sstevel@tonic-gate * code paths may temporarily take holds on contracts to prevent them 126*7c478bd9Sstevel@tonic-gate * from disappearing while other processing is going on. It is 127*7c478bd9Sstevel@tonic-gate * important to note that the global contract lists do not hold 128*7c478bd9Sstevel@tonic-gate * references on contracts; a contract is removed from these structures 129*7c478bd9Sstevel@tonic-gate * atomically with the release of its last reference. 130*7c478bd9Sstevel@tonic-gate * 131*7c478bd9Sstevel@tonic-gate * At a given point in time, a contract can either be owned by a 132*7c478bd9Sstevel@tonic-gate * process, inherited by a regent process contract, or orphaned. A 133*7c478bd9Sstevel@tonic-gate * contract_t's owner and regent pointers, ct_owner and ct_regent, are 134*7c478bd9Sstevel@tonic-gate * protected by its ct_lock. The linkage in the holder's (holder = 135*7c478bd9Sstevel@tonic-gate * owner or regent) list of contracts, ct_ctlist, is protected by 136*7c478bd9Sstevel@tonic-gate * whatever lock protects the holder's data structure. In order for 137*7c478bd9Sstevel@tonic-gate * these two directions to remain consistent, changing the holder of a 138*7c478bd9Sstevel@tonic-gate * contract requires that both locks be held. 139*7c478bd9Sstevel@tonic-gate * 140*7c478bd9Sstevel@tonic-gate * Events also have reference counts. There is one hold on an event 141*7c478bd9Sstevel@tonic-gate * per queue it is present on, in addition to those needed for the 142*7c478bd9Sstevel@tonic-gate * usual sundry reasons. Individual listeners are associated with 143*7c478bd9Sstevel@tonic-gate * specific queues, and increase a queue-specific reference count 144*7c478bd9Sstevel@tonic-gate * stored in the ct_member_t structure. 145*7c478bd9Sstevel@tonic-gate * 146*7c478bd9Sstevel@tonic-gate * The dynamic contents of an event (reference count and flags) are 147*7c478bd9Sstevel@tonic-gate * protected by its cte_lock, while the contents of the embedded 148*7c478bd9Sstevel@tonic-gate * ct_member_t structures are protected by the locks of the queues they 149*7c478bd9Sstevel@tonic-gate * are linked into. A ct_listener_t's contents are also protected by 150*7c478bd9Sstevel@tonic-gate * its event queue's ctq_lock. 151*7c478bd9Sstevel@tonic-gate * 152*7c478bd9Sstevel@tonic-gate * Resource controls 153*7c478bd9Sstevel@tonic-gate * ----------------- 154*7c478bd9Sstevel@tonic-gate * 155*7c478bd9Sstevel@tonic-gate * Control: project.max-contracts (rc_project_contract) 156*7c478bd9Sstevel@tonic-gate * Description: Maximum number of contracts allowed a project. 157*7c478bd9Sstevel@tonic-gate * 158*7c478bd9Sstevel@tonic-gate * When a contract is created, the project's allocation is tested and 159*7c478bd9Sstevel@tonic-gate * (assuming success) increased. When the last reference to a 160*7c478bd9Sstevel@tonic-gate * contract is released, the creating project's allocation is 161*7c478bd9Sstevel@tonic-gate * decreased. 162*7c478bd9Sstevel@tonic-gate */ 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate #include <sys/mutex.h> 165*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 166*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 167*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 168*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 169*7c478bd9Sstevel@tonic-gate #include <sys/thread.h> 170*7c478bd9Sstevel@tonic-gate #include <sys/id_space.h> 171*7c478bd9Sstevel@tonic-gate #include <sys/avl.h> 172*7c478bd9Sstevel@tonic-gate #include <sys/list.h> 173*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 174*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 175*7c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h> 176*7c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 177*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 178*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 179*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 180*7c478bd9Sstevel@tonic-gate #include <sys/model.h> 181*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 182*7c478bd9Sstevel@tonic-gate #include <sys/zone.h> 183*7c478bd9Sstevel@tonic-gate #include <sys/task.h> 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_project_contract; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate static id_space_t *contract_ids; 188*7c478bd9Sstevel@tonic-gate static avl_tree_t contract_avl; 189*7c478bd9Sstevel@tonic-gate static kmutex_t contract_lock; 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate int ct_ntypes = CTT_MAXTYPE; 192*7c478bd9Sstevel@tonic-gate static ct_type_t *ct_types_static[CTT_MAXTYPE]; 193*7c478bd9Sstevel@tonic-gate ct_type_t **ct_types = ct_types_static; 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate static void cte_queue_create(ct_equeue_t *, ct_listnum_t, int, int); 196*7c478bd9Sstevel@tonic-gate static void cte_queue_destroy(ct_equeue_t *); 197*7c478bd9Sstevel@tonic-gate static void cte_queue_drain(ct_equeue_t *, int); 198*7c478bd9Sstevel@tonic-gate static void cte_trim(ct_equeue_t *, contract_t *); 199*7c478bd9Sstevel@tonic-gate static void cte_copy(ct_equeue_t *, ct_equeue_t *); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * contract_compar 203*7c478bd9Sstevel@tonic-gate * 204*7c478bd9Sstevel@tonic-gate * A contract comparator which sorts on contract ID. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate int 207*7c478bd9Sstevel@tonic-gate contract_compar(const void *x, const void *y) 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate const contract_t *ct1 = x; 210*7c478bd9Sstevel@tonic-gate const contract_t *ct2 = y; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate if (ct1->ct_id < ct2->ct_id) 213*7c478bd9Sstevel@tonic-gate return (-1); 214*7c478bd9Sstevel@tonic-gate if (ct1->ct_id > ct2->ct_id) 215*7c478bd9Sstevel@tonic-gate return (1); 216*7c478bd9Sstevel@tonic-gate return (0); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * contract_init 221*7c478bd9Sstevel@tonic-gate * 222*7c478bd9Sstevel@tonic-gate * Initializes the contract subsystem, the specific contract types, and 223*7c478bd9Sstevel@tonic-gate * process 0. 224*7c478bd9Sstevel@tonic-gate */ 225*7c478bd9Sstevel@tonic-gate void 226*7c478bd9Sstevel@tonic-gate contract_init(void) 227*7c478bd9Sstevel@tonic-gate { 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * Initialize contract subsystem. 230*7c478bd9Sstevel@tonic-gate */ 231*7c478bd9Sstevel@tonic-gate contract_ids = id_space_create("contracts", 1, INT_MAX); 232*7c478bd9Sstevel@tonic-gate avl_create(&contract_avl, contract_compar, sizeof (contract_t), 233*7c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_ctavl)); 234*7c478bd9Sstevel@tonic-gate mutex_init(&contract_lock, NULL, MUTEX_DEFAULT, NULL); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * Initialize contract types. 238*7c478bd9Sstevel@tonic-gate */ 239*7c478bd9Sstevel@tonic-gate contract_process_init(); 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate /* 242*7c478bd9Sstevel@tonic-gate * Initialize p0/lwp0 contract state. 243*7c478bd9Sstevel@tonic-gate */ 244*7c478bd9Sstevel@tonic-gate avl_create(&p0.p_ct_held, contract_compar, sizeof (contract_t), 245*7c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_ctlist)); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate /* 249*7c478bd9Sstevel@tonic-gate * contract_dtor 250*7c478bd9Sstevel@tonic-gate * 251*7c478bd9Sstevel@tonic-gate * Performs basic destruction of the common portions of a contract. 252*7c478bd9Sstevel@tonic-gate * Called from the failure path of contract_ctor and from 253*7c478bd9Sstevel@tonic-gate * contract_rele. 254*7c478bd9Sstevel@tonic-gate */ 255*7c478bd9Sstevel@tonic-gate static void 256*7c478bd9Sstevel@tonic-gate contract_dtor(contract_t *ct) 257*7c478bd9Sstevel@tonic-gate { 258*7c478bd9Sstevel@tonic-gate cte_queue_destroy(&ct->ct_events); 259*7c478bd9Sstevel@tonic-gate list_destroy(&ct->ct_vnodes); 260*7c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_reflock); 261*7c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_lock); 262*7c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_evtlock); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate /* 266*7c478bd9Sstevel@tonic-gate * contract_ctor 267*7c478bd9Sstevel@tonic-gate * 268*7c478bd9Sstevel@tonic-gate * Called by a contract type to initialize a contract. Fails if the 269*7c478bd9Sstevel@tonic-gate * max-contract resource control would have been exceeded. After a 270*7c478bd9Sstevel@tonic-gate * successful call to contract_ctor, the contract is unlocked and 271*7c478bd9Sstevel@tonic-gate * visible in all namespaces; any type-specific initialization should 272*7c478bd9Sstevel@tonic-gate * be completed before calling contract_ctor. Returns 0 on success. 273*7c478bd9Sstevel@tonic-gate * 274*7c478bd9Sstevel@tonic-gate * Because not all callers can tolerate failure, a 0 value for canfail 275*7c478bd9Sstevel@tonic-gate * instructs contract_ctor to ignore the project.max-contracts resource 276*7c478bd9Sstevel@tonic-gate * control. Obviously, this "out" should only be employed by callers 277*7c478bd9Sstevel@tonic-gate * who are sufficiently constrained in other ways (e.g. newproc). 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate int 280*7c478bd9Sstevel@tonic-gate contract_ctor(contract_t *ct, ct_type_t *type, ct_template_t *tmpl, void *data, 281*7c478bd9Sstevel@tonic-gate ctflags_t flags, proc_t *author, int canfail) 282*7c478bd9Sstevel@tonic-gate { 283*7c478bd9Sstevel@tonic-gate avl_index_t where; 284*7c478bd9Sstevel@tonic-gate klwp_t *curlwp = ttolwp(curthread); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate ASSERT(author == curproc); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_lock, NULL, MUTEX_DEFAULT, NULL); 289*7c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_reflock, NULL, MUTEX_DEFAULT, NULL); 290*7c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_evtlock, NULL, MUTEX_DEFAULT, NULL); 291*7c478bd9Sstevel@tonic-gate ct->ct_id = id_alloc(contract_ids); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate cte_queue_create(&ct->ct_events, CTEL_CONTRACT, 20, 0); 294*7c478bd9Sstevel@tonic-gate list_create(&ct->ct_vnodes, sizeof (contract_vnode_t), 295*7c478bd9Sstevel@tonic-gate offsetof(contract_vnode_t, ctv_node)); 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate /* 298*7c478bd9Sstevel@tonic-gate * Instance data 299*7c478bd9Sstevel@tonic-gate */ 300*7c478bd9Sstevel@tonic-gate ct->ct_ref = 2; /* one for the holder, one for "latest" */ 301*7c478bd9Sstevel@tonic-gate ct->ct_cuid = crgetuid(CRED()); 302*7c478bd9Sstevel@tonic-gate ct->ct_type = type; 303*7c478bd9Sstevel@tonic-gate ct->ct_data = data; 304*7c478bd9Sstevel@tonic-gate gethrestime(&ct->ct_ctime); 305*7c478bd9Sstevel@tonic-gate ct->ct_state = CTS_OWNED; 306*7c478bd9Sstevel@tonic-gate ct->ct_flags = flags; 307*7c478bd9Sstevel@tonic-gate ct->ct_regent = author->p_ct_process ? 308*7c478bd9Sstevel@tonic-gate &author->p_ct_process->conp_contract : NULL; 309*7c478bd9Sstevel@tonic-gate ct->ct_ev_info = tmpl->ctmpl_ev_info; 310*7c478bd9Sstevel@tonic-gate ct->ct_ev_crit = tmpl->ctmpl_ev_crit; 311*7c478bd9Sstevel@tonic-gate ct->ct_cookie = tmpl->ctmpl_cookie; 312*7c478bd9Sstevel@tonic-gate ct->ct_owner = author; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate /* 315*7c478bd9Sstevel@tonic-gate * Test project.max-contracts. 316*7c478bd9Sstevel@tonic-gate */ 317*7c478bd9Sstevel@tonic-gate mutex_enter(&author->p_lock); 318*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 319*7c478bd9Sstevel@tonic-gate if (canfail && rctl_test(rc_project_contract, 320*7c478bd9Sstevel@tonic-gate author->p_task->tk_proj->kpj_rctls, author, 1, 321*7c478bd9Sstevel@tonic-gate RCA_SAFE) & RCT_DENY) { 322*7c478bd9Sstevel@tonic-gate id_free(contract_ids, ct->ct_id); 323*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 324*7c478bd9Sstevel@tonic-gate mutex_exit(&author->p_lock); 325*7c478bd9Sstevel@tonic-gate ct->ct_events.ctq_flags |= CTQ_DEAD; 326*7c478bd9Sstevel@tonic-gate contract_dtor(ct); 327*7c478bd9Sstevel@tonic-gate return (1); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate ct->ct_proj = author->p_task->tk_proj; 330*7c478bd9Sstevel@tonic-gate ct->ct_proj->kpj_data.kpd_contract++; 331*7c478bd9Sstevel@tonic-gate (void) project_hold(ct->ct_proj); 332*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate /* 335*7c478bd9Sstevel@tonic-gate * Insert into holder's avl of contracts. 336*7c478bd9Sstevel@tonic-gate * We use an avl not because order is important, but because 337*7c478bd9Sstevel@tonic-gate * readdir of /proc/contracts requires we be able to use a 338*7c478bd9Sstevel@tonic-gate * scalar as an index into the process's list of contracts 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate ct->ct_zoneid = author->p_zone->zone_id; 341*7c478bd9Sstevel@tonic-gate ct->ct_czuniqid = ct->ct_mzuniqid = author->p_zone->zone_uniqid; 342*7c478bd9Sstevel@tonic-gate VERIFY(avl_find(&author->p_ct_held, ct, &where) == NULL); 343*7c478bd9Sstevel@tonic-gate avl_insert(&author->p_ct_held, ct, where); 344*7c478bd9Sstevel@tonic-gate mutex_exit(&author->p_lock); 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * Insert into global contract AVL 348*7c478bd9Sstevel@tonic-gate */ 349*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 350*7c478bd9Sstevel@tonic-gate VERIFY(avl_find(&contract_avl, ct, &where) == NULL); 351*7c478bd9Sstevel@tonic-gate avl_insert(&contract_avl, ct, where); 352*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate /* 355*7c478bd9Sstevel@tonic-gate * Insert into type AVL 356*7c478bd9Sstevel@tonic-gate */ 357*7c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock); 358*7c478bd9Sstevel@tonic-gate VERIFY(avl_find(&type->ct_type_avl, ct, &where) == NULL); 359*7c478bd9Sstevel@tonic-gate avl_insert(&type->ct_type_avl, ct, where); 360*7c478bd9Sstevel@tonic-gate type->ct_type_timestruc = ct->ct_ctime; 361*7c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock); 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate if (curlwp->lwp_ct_latest[type->ct_type_index]) 364*7c478bd9Sstevel@tonic-gate contract_rele(curlwp->lwp_ct_latest[type->ct_type_index]); 365*7c478bd9Sstevel@tonic-gate curlwp->lwp_ct_latest[type->ct_type_index] = ct; 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate return (0); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate /* 371*7c478bd9Sstevel@tonic-gate * contract_rele 372*7c478bd9Sstevel@tonic-gate * 373*7c478bd9Sstevel@tonic-gate * Releases a reference to a contract. If the caller had the last 374*7c478bd9Sstevel@tonic-gate * reference, the contract is removed from all namespaces, its 375*7c478bd9Sstevel@tonic-gate * allocation against the max-contracts resource control is released, 376*7c478bd9Sstevel@tonic-gate * and the contract type's free entry point is invoked for any 377*7c478bd9Sstevel@tonic-gate * type-specific deconstruction and to (presumably) free the object. 378*7c478bd9Sstevel@tonic-gate */ 379*7c478bd9Sstevel@tonic-gate void 380*7c478bd9Sstevel@tonic-gate contract_rele(contract_t *ct) 381*7c478bd9Sstevel@tonic-gate { 382*7c478bd9Sstevel@tonic-gate uint64_t nref; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock); 385*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_ref > 0); 386*7c478bd9Sstevel@tonic-gate nref = --ct->ct_ref; 387*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock); 388*7c478bd9Sstevel@tonic-gate if (nref == 0) { 389*7c478bd9Sstevel@tonic-gate /* 390*7c478bd9Sstevel@tonic-gate * ct_owner is cleared when it drops its reference. 391*7c478bd9Sstevel@tonic-gate */ 392*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner == NULL); 393*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_evcnt == 0); 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * Remove from global contract AVL 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 399*7c478bd9Sstevel@tonic-gate avl_remove(&contract_avl, ct); 400*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* 403*7c478bd9Sstevel@tonic-gate * Remove from type AVL 404*7c478bd9Sstevel@tonic-gate */ 405*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_type->ct_type_lock); 406*7c478bd9Sstevel@tonic-gate avl_remove(&ct->ct_type->ct_type_avl, ct); 407*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_type->ct_type_lock); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate * Release the contract's ID 411*7c478bd9Sstevel@tonic-gate */ 412*7c478bd9Sstevel@tonic-gate id_free(contract_ids, ct->ct_id); 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate /* 415*7c478bd9Sstevel@tonic-gate * Release project hold 416*7c478bd9Sstevel@tonic-gate */ 417*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 418*7c478bd9Sstevel@tonic-gate ct->ct_proj->kpj_data.kpd_contract--; 419*7c478bd9Sstevel@tonic-gate project_rele(ct->ct_proj); 420*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate /* 423*7c478bd9Sstevel@tonic-gate * Free the contract 424*7c478bd9Sstevel@tonic-gate */ 425*7c478bd9Sstevel@tonic-gate contract_dtor(ct); 426*7c478bd9Sstevel@tonic-gate ct->ct_type->ct_type_ops->contop_free(ct); 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate /* 431*7c478bd9Sstevel@tonic-gate * contract_hold 432*7c478bd9Sstevel@tonic-gate * 433*7c478bd9Sstevel@tonic-gate * Adds a reference to a contract 434*7c478bd9Sstevel@tonic-gate */ 435*7c478bd9Sstevel@tonic-gate void 436*7c478bd9Sstevel@tonic-gate contract_hold(contract_t *ct) 437*7c478bd9Sstevel@tonic-gate { 438*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock); 439*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_ref < UINT64_MAX); 440*7c478bd9Sstevel@tonic-gate ct->ct_ref++; 441*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock); 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate /* 445*7c478bd9Sstevel@tonic-gate * contract_getzuniqid 446*7c478bd9Sstevel@tonic-gate * 447*7c478bd9Sstevel@tonic-gate * Get a contract's zone unique ID. Needed because 64-bit reads and 448*7c478bd9Sstevel@tonic-gate * writes aren't atomic on x86. Since there are contexts where we are 449*7c478bd9Sstevel@tonic-gate * unable to take ct_lock, we instead use ct_reflock; in actuality any 450*7c478bd9Sstevel@tonic-gate * lock would do. 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate uint64_t 453*7c478bd9Sstevel@tonic-gate contract_getzuniqid(contract_t *ct) 454*7c478bd9Sstevel@tonic-gate { 455*7c478bd9Sstevel@tonic-gate uint64_t zuniqid; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock); 458*7c478bd9Sstevel@tonic-gate zuniqid = ct->ct_mzuniqid; 459*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate return (zuniqid); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * contract_setzuniqid 466*7c478bd9Sstevel@tonic-gate * 467*7c478bd9Sstevel@tonic-gate * Sets a contract's zone unique ID. See contract_getzuniqid. 468*7c478bd9Sstevel@tonic-gate */ 469*7c478bd9Sstevel@tonic-gate void 470*7c478bd9Sstevel@tonic-gate contract_setzuniqid(contract_t *ct, uint64_t zuniqid) 471*7c478bd9Sstevel@tonic-gate { 472*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock); 473*7c478bd9Sstevel@tonic-gate ct->ct_mzuniqid = zuniqid; 474*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate /* 478*7c478bd9Sstevel@tonic-gate * contract_abandon 479*7c478bd9Sstevel@tonic-gate * 480*7c478bd9Sstevel@tonic-gate * Abandons the specified contract. If "explicit" is clear, the 481*7c478bd9Sstevel@tonic-gate * contract was implicitly abandoned (by process exit) and should be 482*7c478bd9Sstevel@tonic-gate * inherited if its terms allow it and its owner was a member of a 483*7c478bd9Sstevel@tonic-gate * regent contract. Otherwise, the contract type's abandon entry point 484*7c478bd9Sstevel@tonic-gate * is invoked to either destroy or orphan the contract. 485*7c478bd9Sstevel@tonic-gate */ 486*7c478bd9Sstevel@tonic-gate int 487*7c478bd9Sstevel@tonic-gate contract_abandon(contract_t *ct, proc_t *p, int explicit) 488*7c478bd9Sstevel@tonic-gate { 489*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = NULL; 490*7c478bd9Sstevel@tonic-gate contract_t *parent = &p->p_ct_process->conp_contract; 491*7c478bd9Sstevel@tonic-gate int inherit = 0; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate ASSERT(p == curproc); 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate /* 498*7c478bd9Sstevel@tonic-gate * Multiple contract locks are taken contract -> subcontract. 499*7c478bd9Sstevel@tonic-gate * Check if the contract will be inherited so we can acquire 500*7c478bd9Sstevel@tonic-gate * all the necessary locks before making sensitive changes. 501*7c478bd9Sstevel@tonic-gate */ 502*7c478bd9Sstevel@tonic-gate if (!explicit && (ct->ct_flags & CTF_INHERIT) && 503*7c478bd9Sstevel@tonic-gate contract_process_accept(parent)) { 504*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 505*7c478bd9Sstevel@tonic-gate mutex_enter(&parent->ct_lock); 506*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 507*7c478bd9Sstevel@tonic-gate inherit = 1; 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate if (ct->ct_owner != p) { 511*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 512*7c478bd9Sstevel@tonic-gate if (inherit) 513*7c478bd9Sstevel@tonic-gate mutex_exit(&parent->ct_lock); 514*7c478bd9Sstevel@tonic-gate return (EINVAL); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 518*7c478bd9Sstevel@tonic-gate if (explicit) 519*7c478bd9Sstevel@tonic-gate avl_remove(&p->p_ct_held, ct); 520*7c478bd9Sstevel@tonic-gate ct->ct_owner = NULL; 521*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * Since we can't call cte_trim with the contract lock held, 525*7c478bd9Sstevel@tonic-gate * we grab the queue pointer here. 526*7c478bd9Sstevel@tonic-gate */ 527*7c478bd9Sstevel@tonic-gate if (p->p_ct_equeue) 528*7c478bd9Sstevel@tonic-gate q = p->p_ct_equeue[ct->ct_type->ct_type_index]; 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate /* 531*7c478bd9Sstevel@tonic-gate * contop_abandon may destroy the contract so we rely on it to 532*7c478bd9Sstevel@tonic-gate * drop ct_lock. We retain a reference on the contract so that 533*7c478bd9Sstevel@tonic-gate * the cte_trim which follows functions properly. Even though 534*7c478bd9Sstevel@tonic-gate * cte_trim doesn't dereference the contract pointer, it is 535*7c478bd9Sstevel@tonic-gate * still necessary to retain a reference to the contract so 536*7c478bd9Sstevel@tonic-gate * that we don't trim events which are sent by a subsequently 537*7c478bd9Sstevel@tonic-gate * allocated contract infortuitously located at the same address. 538*7c478bd9Sstevel@tonic-gate */ 539*7c478bd9Sstevel@tonic-gate contract_hold(ct); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate if (inherit) { 542*7c478bd9Sstevel@tonic-gate ct->ct_state = CTS_INHERITED; 543*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_regent == parent); 544*7c478bd9Sstevel@tonic-gate contract_process_take(parent, ct); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* 547*7c478bd9Sstevel@tonic-gate * We are handing off the process's reference to the 548*7c478bd9Sstevel@tonic-gate * parent contract. For this reason, the order in 549*7c478bd9Sstevel@tonic-gate * which we drop the contract locks is also important. 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 552*7c478bd9Sstevel@tonic-gate mutex_exit(&parent->ct_lock); 553*7c478bd9Sstevel@tonic-gate } else { 554*7c478bd9Sstevel@tonic-gate ct->ct_regent = NULL; 555*7c478bd9Sstevel@tonic-gate ct->ct_type->ct_type_ops->contop_abandon(ct); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * ct_lock has been dropped; we can safely trim the event 560*7c478bd9Sstevel@tonic-gate * queue now. 561*7c478bd9Sstevel@tonic-gate */ 562*7c478bd9Sstevel@tonic-gate if (q) { 563*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 564*7c478bd9Sstevel@tonic-gate cte_trim(q, ct); 565*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate contract_rele(ct); 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate return (0); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * contract_adopt 575*7c478bd9Sstevel@tonic-gate * 576*7c478bd9Sstevel@tonic-gate * Adopts a contract. After a successful call to this routine, the 577*7c478bd9Sstevel@tonic-gate * previously inherited contract will belong to the calling process, 578*7c478bd9Sstevel@tonic-gate * and its events will have been appended to its new owner's process 579*7c478bd9Sstevel@tonic-gate * bundle queue. 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate int 582*7c478bd9Sstevel@tonic-gate contract_adopt(contract_t *ct, proc_t *p) 583*7c478bd9Sstevel@tonic-gate { 584*7c478bd9Sstevel@tonic-gate avl_index_t where; 585*7c478bd9Sstevel@tonic-gate ct_equeue_t *q; 586*7c478bd9Sstevel@tonic-gate contract_t *parent; 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate ASSERT(p == curproc); 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate /* 591*7c478bd9Sstevel@tonic-gate * Ensure the process has an event queue. Checked by ASSERTs 592*7c478bd9Sstevel@tonic-gate * below. 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate (void) contract_type_pbundle(ct->ct_type, p); 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 597*7c478bd9Sstevel@tonic-gate parent = ct->ct_regent; 598*7c478bd9Sstevel@tonic-gate if (ct->ct_state != CTS_INHERITED || 599*7c478bd9Sstevel@tonic-gate &p->p_ct_process->conp_contract != parent || 600*7c478bd9Sstevel@tonic-gate p->p_zone->zone_uniqid != ct->ct_czuniqid) { 601*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 602*7c478bd9Sstevel@tonic-gate return (EINVAL); 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate /* 606*7c478bd9Sstevel@tonic-gate * Multiple contract locks are taken contract -> subcontract. 607*7c478bd9Sstevel@tonic-gate */ 608*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 609*7c478bd9Sstevel@tonic-gate mutex_enter(&parent->ct_lock); 610*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * It is possible that the contract was adopted by someone else 614*7c478bd9Sstevel@tonic-gate * while its lock was dropped. It isn't possible for the 615*7c478bd9Sstevel@tonic-gate * contract to have been inherited by a different regent 616*7c478bd9Sstevel@tonic-gate * contract. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate if (ct->ct_state != CTS_INHERITED) { 619*7c478bd9Sstevel@tonic-gate mutex_exit(&parent->ct_lock); 620*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 621*7c478bd9Sstevel@tonic-gate return (EBUSY); 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_regent == parent); 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate ct->ct_state = CTS_OWNED; 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate contract_process_adopt(ct, p); 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 630*7c478bd9Sstevel@tonic-gate ct->ct_owner = p; 631*7c478bd9Sstevel@tonic-gate VERIFY(avl_find(&p->p_ct_held, ct, &where) == NULL); 632*7c478bd9Sstevel@tonic-gate avl_insert(&p->p_ct_held, ct, where); 633*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue); 636*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index]); 637*7c478bd9Sstevel@tonic-gate q = ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index]; 638*7c478bd9Sstevel@tonic-gate cte_copy(&ct->ct_events, q); 639*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate return (0); 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate /* 645*7c478bd9Sstevel@tonic-gate * contract_ack 646*7c478bd9Sstevel@tonic-gate * 647*7c478bd9Sstevel@tonic-gate * Acknowledges receipt of a critical event. 648*7c478bd9Sstevel@tonic-gate */ 649*7c478bd9Sstevel@tonic-gate int 650*7c478bd9Sstevel@tonic-gate contract_ack(contract_t *ct, uint64_t evid) 651*7c478bd9Sstevel@tonic-gate { 652*7c478bd9Sstevel@tonic-gate ct_kevent_t *ev; 653*7c478bd9Sstevel@tonic-gate list_t *queue = &ct->ct_events.ctq_events; 654*7c478bd9Sstevel@tonic-gate int error = ESRCH; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 657*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_events.ctq_lock); 658*7c478bd9Sstevel@tonic-gate /* 659*7c478bd9Sstevel@tonic-gate * We are probably ACKing something near the head of the queue. 660*7c478bd9Sstevel@tonic-gate */ 661*7c478bd9Sstevel@tonic-gate for (ev = list_head(queue); ev; ev = list_next(queue, ev)) { 662*7c478bd9Sstevel@tonic-gate if (ev->cte_id == evid) { 663*7c478bd9Sstevel@tonic-gate if ((ev->cte_flags & (CTE_INFO | CTE_ACK)) == 0) { 664*7c478bd9Sstevel@tonic-gate ev->cte_flags |= CTE_ACK; 665*7c478bd9Sstevel@tonic-gate ct->ct_evcnt--; 666*7c478bd9Sstevel@tonic-gate error = 0; 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate break; 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_events.ctq_lock); 672*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate return (error); 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* 678*7c478bd9Sstevel@tonic-gate * contract_orphan 679*7c478bd9Sstevel@tonic-gate * 680*7c478bd9Sstevel@tonic-gate * Icky-poo. This is a process-contract special, used to ACK all 681*7c478bd9Sstevel@tonic-gate * critical messages when a contract is orphaned. 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate void 684*7c478bd9Sstevel@tonic-gate contract_orphan(contract_t *ct) 685*7c478bd9Sstevel@tonic-gate { 686*7c478bd9Sstevel@tonic-gate ct_kevent_t *ev; 687*7c478bd9Sstevel@tonic-gate list_t *queue = &ct->ct_events.ctq_events; 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_lock)); 690*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_state != CTS_ORPHAN); 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_events.ctq_lock); 693*7c478bd9Sstevel@tonic-gate ct->ct_state = CTS_ORPHAN; 694*7c478bd9Sstevel@tonic-gate for (ev = list_head(queue); ev; ev = list_next(queue, ev)) { 695*7c478bd9Sstevel@tonic-gate if ((ev->cte_flags & (CTE_INFO | CTE_ACK)) == 0) { 696*7c478bd9Sstevel@tonic-gate ev->cte_flags |= CTE_ACK; 697*7c478bd9Sstevel@tonic-gate ct->ct_evcnt--; 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_events.ctq_lock); 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_evcnt == 0); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate /* 706*7c478bd9Sstevel@tonic-gate * contract_destroy 707*7c478bd9Sstevel@tonic-gate * 708*7c478bd9Sstevel@tonic-gate * Explicit contract destruction. Called when contract is empty. 709*7c478bd9Sstevel@tonic-gate * The contract will actually stick around until all of its events are 710*7c478bd9Sstevel@tonic-gate * removed from the bundle and and process bundle queues, and all fds 711*7c478bd9Sstevel@tonic-gate * which refer to it are closed. See contract_dtor if you are looking 712*7c478bd9Sstevel@tonic-gate * for what destroys the contract structure. 713*7c478bd9Sstevel@tonic-gate */ 714*7c478bd9Sstevel@tonic-gate void 715*7c478bd9Sstevel@tonic-gate contract_destroy(contract_t *ct) 716*7c478bd9Sstevel@tonic-gate { 717*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_lock)); 718*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_state != CTS_DEAD); 719*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner == NULL); 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate ct->ct_state = CTS_DEAD; 722*7c478bd9Sstevel@tonic-gate cte_queue_drain(&ct->ct_events, 1); 723*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 724*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_type->ct_type_events.ctq_lock); 725*7c478bd9Sstevel@tonic-gate cte_trim(&ct->ct_type->ct_type_events, ct); 726*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_type->ct_type_events.ctq_lock); 727*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 728*7c478bd9Sstevel@tonic-gate ct->ct_type->ct_type_ops->contop_destroy(ct); 729*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 730*7c478bd9Sstevel@tonic-gate contract_rele(ct); 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate /* 734*7c478bd9Sstevel@tonic-gate * contract_vnode_get 735*7c478bd9Sstevel@tonic-gate * 736*7c478bd9Sstevel@tonic-gate * Obtains the contract directory vnode for this contract, if there is 737*7c478bd9Sstevel@tonic-gate * one. The caller must VN_RELE the vnode when they are through using 738*7c478bd9Sstevel@tonic-gate * it. 739*7c478bd9Sstevel@tonic-gate */ 740*7c478bd9Sstevel@tonic-gate vnode_t * 741*7c478bd9Sstevel@tonic-gate contract_vnode_get(contract_t *ct, vfs_t *vfsp) 742*7c478bd9Sstevel@tonic-gate { 743*7c478bd9Sstevel@tonic-gate contract_vnode_t *ctv; 744*7c478bd9Sstevel@tonic-gate vnode_t *vp = NULL; 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 747*7c478bd9Sstevel@tonic-gate for (ctv = list_head(&ct->ct_vnodes); ctv != NULL; 748*7c478bd9Sstevel@tonic-gate ctv = list_next(&ct->ct_vnodes, ctv)) 749*7c478bd9Sstevel@tonic-gate if (ctv->ctv_vnode->v_vfsp == vfsp) { 750*7c478bd9Sstevel@tonic-gate vp = ctv->ctv_vnode; 751*7c478bd9Sstevel@tonic-gate VN_HOLD(vp); 752*7c478bd9Sstevel@tonic-gate break; 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 755*7c478bd9Sstevel@tonic-gate return (vp); 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* 759*7c478bd9Sstevel@tonic-gate * contract_vnode_set 760*7c478bd9Sstevel@tonic-gate * 761*7c478bd9Sstevel@tonic-gate * Sets the contract directory vnode for this contract. We don't hold 762*7c478bd9Sstevel@tonic-gate * a reference on the vnode because we don't want to prevent it from 763*7c478bd9Sstevel@tonic-gate * being freed. The vnode's inactive entry point will take care of 764*7c478bd9Sstevel@tonic-gate * notifying us when it should be removed. 765*7c478bd9Sstevel@tonic-gate */ 766*7c478bd9Sstevel@tonic-gate void 767*7c478bd9Sstevel@tonic-gate contract_vnode_set(contract_t *ct, contract_vnode_t *ctv, vnode_t *vnode) 768*7c478bd9Sstevel@tonic-gate { 769*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 770*7c478bd9Sstevel@tonic-gate ctv->ctv_vnode = vnode; 771*7c478bd9Sstevel@tonic-gate list_insert_head(&ct->ct_vnodes, ctv); 772*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate /* 776*7c478bd9Sstevel@tonic-gate * contract_vnode_clear 777*7c478bd9Sstevel@tonic-gate * 778*7c478bd9Sstevel@tonic-gate * Removes this vnode as the contract directory vnode for this 779*7c478bd9Sstevel@tonic-gate * contract. Called from a contract directory's inactive entry point, 780*7c478bd9Sstevel@tonic-gate * this may return 0 indicating that the vnode gained another reference 781*7c478bd9Sstevel@tonic-gate * because of a simultaneous call to contract_vnode_get. 782*7c478bd9Sstevel@tonic-gate */ 783*7c478bd9Sstevel@tonic-gate int 784*7c478bd9Sstevel@tonic-gate contract_vnode_clear(contract_t *ct, contract_vnode_t *ctv) 785*7c478bd9Sstevel@tonic-gate { 786*7c478bd9Sstevel@tonic-gate vnode_t *vp = ctv->ctv_vnode; 787*7c478bd9Sstevel@tonic-gate int result; 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 790*7c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 791*7c478bd9Sstevel@tonic-gate if (vp->v_count == 1) { 792*7c478bd9Sstevel@tonic-gate list_remove(&ct->ct_vnodes, ctv); 793*7c478bd9Sstevel@tonic-gate result = 1; 794*7c478bd9Sstevel@tonic-gate } else { 795*7c478bd9Sstevel@tonic-gate vp->v_count--; 796*7c478bd9Sstevel@tonic-gate result = 0; 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 799*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate return (result); 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate /* 805*7c478bd9Sstevel@tonic-gate * contract_exit 806*7c478bd9Sstevel@tonic-gate * 807*7c478bd9Sstevel@tonic-gate * Abandons all contracts held by process p, and drains process p's 808*7c478bd9Sstevel@tonic-gate * bundle queues. Called on process exit. 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate void 811*7c478bd9Sstevel@tonic-gate contract_exit(proc_t *p) 812*7c478bd9Sstevel@tonic-gate { 813*7c478bd9Sstevel@tonic-gate contract_t *ct; 814*7c478bd9Sstevel@tonic-gate void *cookie = NULL; 815*7c478bd9Sstevel@tonic-gate int i; 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate ASSERT(p == curproc); 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate /* 820*7c478bd9Sstevel@tonic-gate * Abandon held contracts. contract_abandon knows enough not 821*7c478bd9Sstevel@tonic-gate * to remove the contract from the list a second time. We are 822*7c478bd9Sstevel@tonic-gate * exiting, so no locks are needed here. But because 823*7c478bd9Sstevel@tonic-gate * contract_abandon will take p_lock, we need to make sure we 824*7c478bd9Sstevel@tonic-gate * aren't holding it. 825*7c478bd9Sstevel@tonic-gate */ 826*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&p->p_lock)); 827*7c478bd9Sstevel@tonic-gate while ((ct = avl_destroy_nodes(&p->p_ct_held, &cookie)) != NULL) 828*7c478bd9Sstevel@tonic-gate VERIFY(contract_abandon(ct, p, 0) == 0); 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate /* 831*7c478bd9Sstevel@tonic-gate * Drain pbundles. Because a process bundle queue could have 832*7c478bd9Sstevel@tonic-gate * been passed to another process, they may not be freed right 833*7c478bd9Sstevel@tonic-gate * away. 834*7c478bd9Sstevel@tonic-gate */ 835*7c478bd9Sstevel@tonic-gate if (p->p_ct_equeue) { 836*7c478bd9Sstevel@tonic-gate for (i = 0; i < CTT_MAXTYPE; i++) 837*7c478bd9Sstevel@tonic-gate if (p->p_ct_equeue[i]) 838*7c478bd9Sstevel@tonic-gate cte_queue_drain(p->p_ct_equeue[i], 0); 839*7c478bd9Sstevel@tonic-gate kmem_free(p->p_ct_equeue, CTT_MAXTYPE * sizeof (ct_equeue_t *)); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate /* 844*7c478bd9Sstevel@tonic-gate * contract_status_common 845*7c478bd9Sstevel@tonic-gate * 846*7c478bd9Sstevel@tonic-gate * Populates a ct_status structure. Used by contract types in their 847*7c478bd9Sstevel@tonic-gate * status entry points and ctfs when only common information is 848*7c478bd9Sstevel@tonic-gate * requested. 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate void 851*7c478bd9Sstevel@tonic-gate contract_status_common(contract_t *ct, zone_t *zone, void *status, 852*7c478bd9Sstevel@tonic-gate model_t model) 853*7c478bd9Sstevel@tonic-gate { 854*7c478bd9Sstevel@tonic-gate STRUCT_HANDLE(ct_status, lstatus); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(lstatus, model, status); 857*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_lock)); 858*7c478bd9Sstevel@tonic-gate if (zone->zone_uniqid == GLOBAL_ZONEUNIQID || 859*7c478bd9Sstevel@tonic-gate zone->zone_uniqid == ct->ct_czuniqid) { 860*7c478bd9Sstevel@tonic-gate zone_t *czone; 861*7c478bd9Sstevel@tonic-gate zoneid_t zoneid = -1; 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate /* 864*7c478bd9Sstevel@tonic-gate * Contracts don't have holds on the zones they were 865*7c478bd9Sstevel@tonic-gate * created by. If the contract's zone no longer 866*7c478bd9Sstevel@tonic-gate * exists, we say its zoneid is -1. 867*7c478bd9Sstevel@tonic-gate */ 868*7c478bd9Sstevel@tonic-gate if (zone->zone_uniqid == ct->ct_czuniqid || 869*7c478bd9Sstevel@tonic-gate ct->ct_czuniqid == GLOBAL_ZONEUNIQID) { 870*7c478bd9Sstevel@tonic-gate zoneid = ct->ct_zoneid; 871*7c478bd9Sstevel@tonic-gate } else if ((czone = zone_find_by_id(ct->ct_zoneid)) != NULL) { 872*7c478bd9Sstevel@tonic-gate if (czone->zone_uniqid == ct->ct_mzuniqid) 873*7c478bd9Sstevel@tonic-gate zoneid = ct->ct_zoneid; 874*7c478bd9Sstevel@tonic-gate zone_rele(czone); 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_zoneid, zoneid); 878*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_holder, 879*7c478bd9Sstevel@tonic-gate (ct->ct_state == CTS_OWNED) ? ct->ct_owner->p_pid : 880*7c478bd9Sstevel@tonic-gate (ct->ct_state == CTS_INHERITED) ? ct->ct_regent->ct_id : 0); 881*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_state, ct->ct_state); 882*7c478bd9Sstevel@tonic-gate } else { 883*7c478bd9Sstevel@tonic-gate /* 884*7c478bd9Sstevel@tonic-gate * We are looking at a contract which was created by a 885*7c478bd9Sstevel@tonic-gate * process outside of our zone. We provide fake zone, 886*7c478bd9Sstevel@tonic-gate * holder, and state information. 887*7c478bd9Sstevel@tonic-gate */ 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_zoneid, zone->zone_id); 890*7c478bd9Sstevel@tonic-gate /* 891*7c478bd9Sstevel@tonic-gate * Since "zone" can't disappear until the calling ctfs 892*7c478bd9Sstevel@tonic-gate * is unmounted, zone_zsched must be valid. 893*7c478bd9Sstevel@tonic-gate */ 894*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_holder, (ct->ct_state < CTS_ORPHAN) ? 895*7c478bd9Sstevel@tonic-gate zone->zone_zsched->p_pid : 0); 896*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_state, (ct->ct_state < CTS_ORPHAN) ? 897*7c478bd9Sstevel@tonic-gate CTS_OWNED : ct->ct_state); 898*7c478bd9Sstevel@tonic-gate } 899*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_nevents, ct->ct_evcnt); 900*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_ntime, -1); 901*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_qtime, -1); 902*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_nevid, 903*7c478bd9Sstevel@tonic-gate ct->ct_nevent ? ct->ct_nevent->cte_id : 0); 904*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_critical, ct->ct_ev_crit); 905*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_informative, ct->ct_ev_info); 906*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_cookie, ct->ct_cookie); 907*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_type, ct->ct_type->ct_type_index); 908*7c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_id, ct->ct_id); 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate /* 912*7c478bd9Sstevel@tonic-gate * contract_checkcred 913*7c478bd9Sstevel@tonic-gate * 914*7c478bd9Sstevel@tonic-gate * Determines if the specified contract is owned by a process with the 915*7c478bd9Sstevel@tonic-gate * same effective uid as the specified credential. The caller must 916*7c478bd9Sstevel@tonic-gate * ensure that the uid spaces are the same. Returns 1 on success. 917*7c478bd9Sstevel@tonic-gate */ 918*7c478bd9Sstevel@tonic-gate static int 919*7c478bd9Sstevel@tonic-gate contract_checkcred(contract_t *ct, const cred_t *cr) 920*7c478bd9Sstevel@tonic-gate { 921*7c478bd9Sstevel@tonic-gate proc_t *p; 922*7c478bd9Sstevel@tonic-gate int fail = 1; 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 925*7c478bd9Sstevel@tonic-gate if ((p = ct->ct_owner) != NULL) { 926*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock); 927*7c478bd9Sstevel@tonic-gate fail = crgetuid(cr) != crgetuid(p->p_cred); 928*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock); 929*7c478bd9Sstevel@tonic-gate } 930*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate return (!fail); 933*7c478bd9Sstevel@tonic-gate } 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate /* 936*7c478bd9Sstevel@tonic-gate * contract_owned 937*7c478bd9Sstevel@tonic-gate * 938*7c478bd9Sstevel@tonic-gate * Determines if the specified credential can view an event generated 939*7c478bd9Sstevel@tonic-gate * by the specified contract. If locked is set, the contract's ct_lock 940*7c478bd9Sstevel@tonic-gate * is held and the caller will need to do additional work to determine 941*7c478bd9Sstevel@tonic-gate * if they truly can see the event. Returns 1 on success. 942*7c478bd9Sstevel@tonic-gate */ 943*7c478bd9Sstevel@tonic-gate int 944*7c478bd9Sstevel@tonic-gate contract_owned(contract_t *ct, const cred_t *cr, int locked) 945*7c478bd9Sstevel@tonic-gate { 946*7c478bd9Sstevel@tonic-gate int owner, cmatch, zmatch; 947*7c478bd9Sstevel@tonic-gate uint64_t zuniqid, mzuniqid; 948*7c478bd9Sstevel@tonic-gate uid_t euid; 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate ASSERT(locked || MUTEX_NOT_HELD(&ct->ct_lock)); 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate zuniqid = curproc->p_zone->zone_uniqid; 953*7c478bd9Sstevel@tonic-gate mzuniqid = contract_getzuniqid(ct); 954*7c478bd9Sstevel@tonic-gate euid = crgetuid(cr); 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate /* 957*7c478bd9Sstevel@tonic-gate * owner: we own the contract 958*7c478bd9Sstevel@tonic-gate * cmatch: we are in the creator's (and holder's) zone and our 959*7c478bd9Sstevel@tonic-gate * uid matches the creator's or holder's 960*7c478bd9Sstevel@tonic-gate * zmatch: we are in the effective zone of a contract created 961*7c478bd9Sstevel@tonic-gate * in the global zone, and our uid matches that of the 962*7c478bd9Sstevel@tonic-gate * virtualized holder's (zsched/kcred) 963*7c478bd9Sstevel@tonic-gate */ 964*7c478bd9Sstevel@tonic-gate owner = (ct->ct_owner == curproc); 965*7c478bd9Sstevel@tonic-gate cmatch = (zuniqid == ct->ct_czuniqid) && 966*7c478bd9Sstevel@tonic-gate ((ct->ct_cuid == euid) || (!locked && contract_checkcred(ct, cr))); 967*7c478bd9Sstevel@tonic-gate zmatch = (ct->ct_czuniqid != mzuniqid) && (zuniqid == mzuniqid) && 968*7c478bd9Sstevel@tonic-gate (crgetuid(kcred) == euid); 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate return (owner || cmatch || zmatch); 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * contract_type_init 976*7c478bd9Sstevel@tonic-gate * 977*7c478bd9Sstevel@tonic-gate * Called by contract types to register themselves with the contracts 978*7c478bd9Sstevel@tonic-gate * framework. 979*7c478bd9Sstevel@tonic-gate */ 980*7c478bd9Sstevel@tonic-gate ct_type_t * 981*7c478bd9Sstevel@tonic-gate contract_type_init(ct_typeid_t type, const char *name, contops_t *ops, 982*7c478bd9Sstevel@tonic-gate ct_f_default_t *dfault) 983*7c478bd9Sstevel@tonic-gate { 984*7c478bd9Sstevel@tonic-gate ct_type_t *result; 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate ASSERT(type < CTT_MAXTYPE); 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate result = kmem_alloc(sizeof (ct_type_t), KM_SLEEP); 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate mutex_init(&result->ct_type_lock, NULL, MUTEX_DEFAULT, NULL); 991*7c478bd9Sstevel@tonic-gate avl_create(&result->ct_type_avl, contract_compar, sizeof (contract_t), 992*7c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_cttavl)); 993*7c478bd9Sstevel@tonic-gate cte_queue_create(&result->ct_type_events, CTEL_BUNDLE, 20, 0); 994*7c478bd9Sstevel@tonic-gate result->ct_type_name = name; 995*7c478bd9Sstevel@tonic-gate result->ct_type_ops = ops; 996*7c478bd9Sstevel@tonic-gate result->ct_type_default = dfault; 997*7c478bd9Sstevel@tonic-gate result->ct_type_evid = 0; 998*7c478bd9Sstevel@tonic-gate gethrestime(&result->ct_type_timestruc); 999*7c478bd9Sstevel@tonic-gate result->ct_type_index = type; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate ct_types[type] = result; 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate return (result); 1004*7c478bd9Sstevel@tonic-gate } 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate /* 1007*7c478bd9Sstevel@tonic-gate * contract_type_count 1008*7c478bd9Sstevel@tonic-gate * 1009*7c478bd9Sstevel@tonic-gate * Obtains the number of contracts of a particular type. 1010*7c478bd9Sstevel@tonic-gate */ 1011*7c478bd9Sstevel@tonic-gate int 1012*7c478bd9Sstevel@tonic-gate contract_type_count(ct_type_t *type) 1013*7c478bd9Sstevel@tonic-gate { 1014*7c478bd9Sstevel@tonic-gate ulong_t count; 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock); 1017*7c478bd9Sstevel@tonic-gate count = avl_numnodes(&type->ct_type_avl); 1018*7c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock); 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate return (count); 1021*7c478bd9Sstevel@tonic-gate } 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate /* 1024*7c478bd9Sstevel@tonic-gate * contract_type_max 1025*7c478bd9Sstevel@tonic-gate * 1026*7c478bd9Sstevel@tonic-gate * Obtains the maximum contract id of of a particular type. 1027*7c478bd9Sstevel@tonic-gate */ 1028*7c478bd9Sstevel@tonic-gate ctid_t 1029*7c478bd9Sstevel@tonic-gate contract_type_max(ct_type_t *type) 1030*7c478bd9Sstevel@tonic-gate { 1031*7c478bd9Sstevel@tonic-gate contract_t *ct; 1032*7c478bd9Sstevel@tonic-gate ctid_t res; 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock); 1035*7c478bd9Sstevel@tonic-gate ct = avl_last(&type->ct_type_avl); 1036*7c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1; 1037*7c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock); 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate return (res); 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate /* 1043*7c478bd9Sstevel@tonic-gate * contract_max 1044*7c478bd9Sstevel@tonic-gate * 1045*7c478bd9Sstevel@tonic-gate * Obtains the maximum contract id. 1046*7c478bd9Sstevel@tonic-gate */ 1047*7c478bd9Sstevel@tonic-gate ctid_t 1048*7c478bd9Sstevel@tonic-gate contract_max(void) 1049*7c478bd9Sstevel@tonic-gate { 1050*7c478bd9Sstevel@tonic-gate contract_t *ct; 1051*7c478bd9Sstevel@tonic-gate ctid_t res; 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 1054*7c478bd9Sstevel@tonic-gate ct = avl_last(&contract_avl); 1055*7c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1; 1056*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 1057*7c478bd9Sstevel@tonic-gate 1058*7c478bd9Sstevel@tonic-gate return (res); 1059*7c478bd9Sstevel@tonic-gate } 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate /* 1062*7c478bd9Sstevel@tonic-gate * contract_lookup_common 1063*7c478bd9Sstevel@tonic-gate * 1064*7c478bd9Sstevel@tonic-gate * Common code for contract_lookup and contract_type_lookup. Takes a 1065*7c478bd9Sstevel@tonic-gate * pointer to an AVL tree to search in. Should be called with the 1066*7c478bd9Sstevel@tonic-gate * appropriate tree-protecting lock held (unfortunately unassertable). 1067*7c478bd9Sstevel@tonic-gate */ 1068*7c478bd9Sstevel@tonic-gate static ctid_t 1069*7c478bd9Sstevel@tonic-gate contract_lookup_common(avl_tree_t *tree, uint64_t zuniqid, ctid_t current) 1070*7c478bd9Sstevel@tonic-gate { 1071*7c478bd9Sstevel@tonic-gate contract_t template, *ct; 1072*7c478bd9Sstevel@tonic-gate avl_index_t where; 1073*7c478bd9Sstevel@tonic-gate ctid_t res; 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate template.ct_id = current; 1076*7c478bd9Sstevel@tonic-gate ct = avl_find(tree, &template, &where); 1077*7c478bd9Sstevel@tonic-gate if (ct == NULL) 1078*7c478bd9Sstevel@tonic-gate ct = avl_nearest(tree, where, AVL_AFTER); 1079*7c478bd9Sstevel@tonic-gate if (zuniqid != GLOBAL_ZONEUNIQID) 1080*7c478bd9Sstevel@tonic-gate while (ct && (contract_getzuniqid(ct) != zuniqid)) 1081*7c478bd9Sstevel@tonic-gate ct = AVL_NEXT(tree, ct); 1082*7c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1; 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate return (res); 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate 1087*7c478bd9Sstevel@tonic-gate /* 1088*7c478bd9Sstevel@tonic-gate * contract_type_lookup 1089*7c478bd9Sstevel@tonic-gate * 1090*7c478bd9Sstevel@tonic-gate * Returns the next type contract after the specified id, visible from 1091*7c478bd9Sstevel@tonic-gate * the specified zone. 1092*7c478bd9Sstevel@tonic-gate */ 1093*7c478bd9Sstevel@tonic-gate ctid_t 1094*7c478bd9Sstevel@tonic-gate contract_type_lookup(ct_type_t *type, uint64_t zuniqid, ctid_t current) 1095*7c478bd9Sstevel@tonic-gate { 1096*7c478bd9Sstevel@tonic-gate ctid_t res; 1097*7c478bd9Sstevel@tonic-gate 1098*7c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock); 1099*7c478bd9Sstevel@tonic-gate res = contract_lookup_common(&type->ct_type_avl, zuniqid, current); 1100*7c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock); 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate return (res); 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate /* 1106*7c478bd9Sstevel@tonic-gate * contract_lookup 1107*7c478bd9Sstevel@tonic-gate * 1108*7c478bd9Sstevel@tonic-gate * Returns the next contract after the specified id, visible from the 1109*7c478bd9Sstevel@tonic-gate * specified zone. 1110*7c478bd9Sstevel@tonic-gate */ 1111*7c478bd9Sstevel@tonic-gate ctid_t 1112*7c478bd9Sstevel@tonic-gate contract_lookup(uint64_t zuniqid, ctid_t current) 1113*7c478bd9Sstevel@tonic-gate { 1114*7c478bd9Sstevel@tonic-gate ctid_t res; 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 1117*7c478bd9Sstevel@tonic-gate res = contract_lookup_common(&contract_avl, zuniqid, current); 1118*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate return (res); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate /* 1124*7c478bd9Sstevel@tonic-gate * contract_plookup 1125*7c478bd9Sstevel@tonic-gate * 1126*7c478bd9Sstevel@tonic-gate * Returns the next contract held by process p after the specified id, 1127*7c478bd9Sstevel@tonic-gate * visible from the specified zone. Made complicated by the fact that 1128*7c478bd9Sstevel@tonic-gate * contracts visible in a zone but held by processes outside of the 1129*7c478bd9Sstevel@tonic-gate * zone need to appear as being held by zsched to zone members. 1130*7c478bd9Sstevel@tonic-gate */ 1131*7c478bd9Sstevel@tonic-gate ctid_t 1132*7c478bd9Sstevel@tonic-gate contract_plookup(proc_t *p, ctid_t current, uint64_t zuniqid) 1133*7c478bd9Sstevel@tonic-gate { 1134*7c478bd9Sstevel@tonic-gate contract_t template, *ct; 1135*7c478bd9Sstevel@tonic-gate avl_index_t where; 1136*7c478bd9Sstevel@tonic-gate ctid_t res; 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate template.ct_id = current; 1139*7c478bd9Sstevel@tonic-gate if (zuniqid != GLOBAL_ZONEUNIQID && 1140*7c478bd9Sstevel@tonic-gate (p->p_flag & (SSYS|SZONETOP)) == (SSYS|SZONETOP)) { 1141*7c478bd9Sstevel@tonic-gate /* This is inelegant. */ 1142*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 1143*7c478bd9Sstevel@tonic-gate ct = avl_find(&contract_avl, &template, &where); 1144*7c478bd9Sstevel@tonic-gate if (ct == NULL) 1145*7c478bd9Sstevel@tonic-gate ct = avl_nearest(&contract_avl, where, AVL_AFTER); 1146*7c478bd9Sstevel@tonic-gate while (ct && !(ct->ct_state < CTS_ORPHAN && 1147*7c478bd9Sstevel@tonic-gate contract_getzuniqid(ct) == zuniqid && 1148*7c478bd9Sstevel@tonic-gate ct->ct_czuniqid == GLOBAL_ZONEUNIQID)) 1149*7c478bd9Sstevel@tonic-gate ct = AVL_NEXT(&contract_avl, ct); 1150*7c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1; 1151*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 1152*7c478bd9Sstevel@tonic-gate } else { 1153*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1154*7c478bd9Sstevel@tonic-gate ct = avl_find(&p->p_ct_held, &template, &where); 1155*7c478bd9Sstevel@tonic-gate if (ct == NULL) 1156*7c478bd9Sstevel@tonic-gate ct = avl_nearest(&p->p_ct_held, where, AVL_AFTER); 1157*7c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1; 1158*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate return (res); 1162*7c478bd9Sstevel@tonic-gate } 1163*7c478bd9Sstevel@tonic-gate 1164*7c478bd9Sstevel@tonic-gate /* 1165*7c478bd9Sstevel@tonic-gate * contract_ptr_common 1166*7c478bd9Sstevel@tonic-gate * 1167*7c478bd9Sstevel@tonic-gate * Common code for contract_ptr and contract_type_ptr. Takes a pointer 1168*7c478bd9Sstevel@tonic-gate * to an AVL tree to search in. Should be called with the appropriate 1169*7c478bd9Sstevel@tonic-gate * tree-protecting lock held (unfortunately unassertable). 1170*7c478bd9Sstevel@tonic-gate */ 1171*7c478bd9Sstevel@tonic-gate static contract_t * 1172*7c478bd9Sstevel@tonic-gate contract_ptr_common(avl_tree_t *tree, ctid_t id, uint64_t zuniqid) 1173*7c478bd9Sstevel@tonic-gate { 1174*7c478bd9Sstevel@tonic-gate contract_t template, *ct; 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate template.ct_id = id; 1177*7c478bd9Sstevel@tonic-gate ct = avl_find(tree, &template, NULL); 1178*7c478bd9Sstevel@tonic-gate if (ct == NULL || (zuniqid != GLOBAL_ZONEUNIQID && 1179*7c478bd9Sstevel@tonic-gate contract_getzuniqid(ct) != zuniqid)) { 1180*7c478bd9Sstevel@tonic-gate return (NULL); 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate /* 1184*7c478bd9Sstevel@tonic-gate * Check to see if a thread is in the window in contract_rele 1185*7c478bd9Sstevel@tonic-gate * between dropping the reference count and removing the 1186*7c478bd9Sstevel@tonic-gate * contract from the type AVL. 1187*7c478bd9Sstevel@tonic-gate */ 1188*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock); 1189*7c478bd9Sstevel@tonic-gate if (ct->ct_ref) { 1190*7c478bd9Sstevel@tonic-gate ct->ct_ref++; 1191*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock); 1192*7c478bd9Sstevel@tonic-gate } else { 1193*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock); 1194*7c478bd9Sstevel@tonic-gate ct = NULL; 1195*7c478bd9Sstevel@tonic-gate } 1196*7c478bd9Sstevel@tonic-gate 1197*7c478bd9Sstevel@tonic-gate return (ct); 1198*7c478bd9Sstevel@tonic-gate } 1199*7c478bd9Sstevel@tonic-gate 1200*7c478bd9Sstevel@tonic-gate /* 1201*7c478bd9Sstevel@tonic-gate * contract_type_ptr 1202*7c478bd9Sstevel@tonic-gate * 1203*7c478bd9Sstevel@tonic-gate * Returns a pointer to the contract with the specified id. The 1204*7c478bd9Sstevel@tonic-gate * contract is held, so the caller needs to release the reference when 1205*7c478bd9Sstevel@tonic-gate * it is through with the contract. 1206*7c478bd9Sstevel@tonic-gate */ 1207*7c478bd9Sstevel@tonic-gate contract_t * 1208*7c478bd9Sstevel@tonic-gate contract_type_ptr(ct_type_t *type, ctid_t id, uint64_t zuniqid) 1209*7c478bd9Sstevel@tonic-gate { 1210*7c478bd9Sstevel@tonic-gate contract_t *ct; 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock); 1213*7c478bd9Sstevel@tonic-gate ct = contract_ptr_common(&type->ct_type_avl, id, zuniqid); 1214*7c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock); 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate return (ct); 1217*7c478bd9Sstevel@tonic-gate } 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate /* 1220*7c478bd9Sstevel@tonic-gate * contract_ptr 1221*7c478bd9Sstevel@tonic-gate * 1222*7c478bd9Sstevel@tonic-gate * Returns a pointer to the contract with the specified id. The 1223*7c478bd9Sstevel@tonic-gate * contract is held, so the caller needs to release the reference when 1224*7c478bd9Sstevel@tonic-gate * it is through with the contract. 1225*7c478bd9Sstevel@tonic-gate */ 1226*7c478bd9Sstevel@tonic-gate contract_t * 1227*7c478bd9Sstevel@tonic-gate contract_ptr(ctid_t id, uint64_t zuniqid) 1228*7c478bd9Sstevel@tonic-gate { 1229*7c478bd9Sstevel@tonic-gate contract_t *ct; 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock); 1232*7c478bd9Sstevel@tonic-gate ct = contract_ptr_common(&contract_avl, id, zuniqid); 1233*7c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock); 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate return (ct); 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate /* 1239*7c478bd9Sstevel@tonic-gate * contract_type_time 1240*7c478bd9Sstevel@tonic-gate * 1241*7c478bd9Sstevel@tonic-gate * Obtains the last time a contract of a particular type was created. 1242*7c478bd9Sstevel@tonic-gate */ 1243*7c478bd9Sstevel@tonic-gate void 1244*7c478bd9Sstevel@tonic-gate contract_type_time(ct_type_t *type, timestruc_t *time) 1245*7c478bd9Sstevel@tonic-gate { 1246*7c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock); 1247*7c478bd9Sstevel@tonic-gate *time = type->ct_type_timestruc; 1248*7c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock); 1249*7c478bd9Sstevel@tonic-gate } 1250*7c478bd9Sstevel@tonic-gate 1251*7c478bd9Sstevel@tonic-gate /* 1252*7c478bd9Sstevel@tonic-gate * contract_type_bundle 1253*7c478bd9Sstevel@tonic-gate * 1254*7c478bd9Sstevel@tonic-gate * Obtains a type's bundle queue. 1255*7c478bd9Sstevel@tonic-gate */ 1256*7c478bd9Sstevel@tonic-gate ct_equeue_t * 1257*7c478bd9Sstevel@tonic-gate contract_type_bundle(ct_type_t *type) 1258*7c478bd9Sstevel@tonic-gate { 1259*7c478bd9Sstevel@tonic-gate return (&type->ct_type_events); 1260*7c478bd9Sstevel@tonic-gate } 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate /* 1263*7c478bd9Sstevel@tonic-gate * contract_type_pbundle 1264*7c478bd9Sstevel@tonic-gate * 1265*7c478bd9Sstevel@tonic-gate * Obtain's a process's bundle queue. If one doesn't exist, one is 1266*7c478bd9Sstevel@tonic-gate * created. Often used simply to ensure that a bundle queue is 1267*7c478bd9Sstevel@tonic-gate * allocated. 1268*7c478bd9Sstevel@tonic-gate */ 1269*7c478bd9Sstevel@tonic-gate ct_equeue_t * 1270*7c478bd9Sstevel@tonic-gate contract_type_pbundle(ct_type_t *type, proc_t *pp) 1271*7c478bd9Sstevel@tonic-gate { 1272*7c478bd9Sstevel@tonic-gate /* 1273*7c478bd9Sstevel@tonic-gate * If there isn't an array of bundle queues, allocate one. 1274*7c478bd9Sstevel@tonic-gate */ 1275*7c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue == NULL) { 1276*7c478bd9Sstevel@tonic-gate size_t size = CTT_MAXTYPE * sizeof (ct_equeue_t *); 1277*7c478bd9Sstevel@tonic-gate ct_equeue_t **qa = kmem_zalloc(size, KM_SLEEP); 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 1280*7c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue) 1281*7c478bd9Sstevel@tonic-gate kmem_free(qa, size); 1282*7c478bd9Sstevel@tonic-gate else 1283*7c478bd9Sstevel@tonic-gate pp->p_ct_equeue = qa; 1284*7c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate /* 1288*7c478bd9Sstevel@tonic-gate * If there isn't a bundle queue of the required type, allocate 1289*7c478bd9Sstevel@tonic-gate * one. 1290*7c478bd9Sstevel@tonic-gate */ 1291*7c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue[type->ct_type_index] == NULL) { 1292*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = kmem_zalloc(sizeof (ct_equeue_t), KM_SLEEP); 1293*7c478bd9Sstevel@tonic-gate cte_queue_create(q, CTEL_PBUNDLE, 20, 1); 1294*7c478bd9Sstevel@tonic-gate 1295*7c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 1296*7c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue[type->ct_type_index]) 1297*7c478bd9Sstevel@tonic-gate cte_queue_drain(q, 0); 1298*7c478bd9Sstevel@tonic-gate else 1299*7c478bd9Sstevel@tonic-gate pp->p_ct_equeue[type->ct_type_index] = q; 1300*7c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 1301*7c478bd9Sstevel@tonic-gate } 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate return (pp->p_ct_equeue[type->ct_type_index]); 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate /* 1307*7c478bd9Sstevel@tonic-gate * ctmpl_free 1308*7c478bd9Sstevel@tonic-gate * 1309*7c478bd9Sstevel@tonic-gate * Frees a template. 1310*7c478bd9Sstevel@tonic-gate */ 1311*7c478bd9Sstevel@tonic-gate void 1312*7c478bd9Sstevel@tonic-gate ctmpl_free(ct_template_t *template) 1313*7c478bd9Sstevel@tonic-gate { 1314*7c478bd9Sstevel@tonic-gate mutex_destroy(&template->ctmpl_lock); 1315*7c478bd9Sstevel@tonic-gate template->ctmpl_ops->ctop_free(template); 1316*7c478bd9Sstevel@tonic-gate } 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate /* 1319*7c478bd9Sstevel@tonic-gate * ctmpl_dup 1320*7c478bd9Sstevel@tonic-gate * 1321*7c478bd9Sstevel@tonic-gate * Creates a copy of a template. 1322*7c478bd9Sstevel@tonic-gate */ 1323*7c478bd9Sstevel@tonic-gate ct_template_t * 1324*7c478bd9Sstevel@tonic-gate ctmpl_dup(ct_template_t *template) 1325*7c478bd9Sstevel@tonic-gate { 1326*7c478bd9Sstevel@tonic-gate ct_template_t *new; 1327*7c478bd9Sstevel@tonic-gate 1328*7c478bd9Sstevel@tonic-gate if (template == NULL) 1329*7c478bd9Sstevel@tonic-gate return (NULL); 1330*7c478bd9Sstevel@tonic-gate 1331*7c478bd9Sstevel@tonic-gate new = template->ctmpl_ops->ctop_dup(template); 1332*7c478bd9Sstevel@tonic-gate /* 1333*7c478bd9Sstevel@tonic-gate * ctmpl_lock was taken by ctop_dup's call to ctmpl_copy and 1334*7c478bd9Sstevel@tonic-gate * should have remain held until now. 1335*7c478bd9Sstevel@tonic-gate */ 1336*7c478bd9Sstevel@tonic-gate mutex_exit(&template->ctmpl_lock); 1337*7c478bd9Sstevel@tonic-gate 1338*7c478bd9Sstevel@tonic-gate return (new); 1339*7c478bd9Sstevel@tonic-gate } 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate /* 1342*7c478bd9Sstevel@tonic-gate * ctmpl_set 1343*7c478bd9Sstevel@tonic-gate * 1344*7c478bd9Sstevel@tonic-gate * Sets the requested terms of a template. 1345*7c478bd9Sstevel@tonic-gate */ 1346*7c478bd9Sstevel@tonic-gate int 1347*7c478bd9Sstevel@tonic-gate ctmpl_set(ct_template_t *template, ct_param_t *param, const cred_t *cr) 1348*7c478bd9Sstevel@tonic-gate { 1349*7c478bd9Sstevel@tonic-gate int result = 0; 1350*7c478bd9Sstevel@tonic-gate 1351*7c478bd9Sstevel@tonic-gate mutex_enter(&template->ctmpl_lock); 1352*7c478bd9Sstevel@tonic-gate switch (param->ctpm_id) { 1353*7c478bd9Sstevel@tonic-gate case CTP_COOKIE: 1354*7c478bd9Sstevel@tonic-gate template->ctmpl_cookie = param->ctpm_value; 1355*7c478bd9Sstevel@tonic-gate break; 1356*7c478bd9Sstevel@tonic-gate case CTP_EV_INFO: 1357*7c478bd9Sstevel@tonic-gate if (param->ctpm_value & 1358*7c478bd9Sstevel@tonic-gate ~(uint64_t)template->ctmpl_ops->allevents) 1359*7c478bd9Sstevel@tonic-gate result = EINVAL; 1360*7c478bd9Sstevel@tonic-gate else 1361*7c478bd9Sstevel@tonic-gate template->ctmpl_ev_info = param->ctpm_value; 1362*7c478bd9Sstevel@tonic-gate break; 1363*7c478bd9Sstevel@tonic-gate case CTP_EV_CRITICAL: 1364*7c478bd9Sstevel@tonic-gate if (param->ctpm_value & 1365*7c478bd9Sstevel@tonic-gate ~(uint64_t)template->ctmpl_ops->allevents) { 1366*7c478bd9Sstevel@tonic-gate result = EINVAL; 1367*7c478bd9Sstevel@tonic-gate break; 1368*7c478bd9Sstevel@tonic-gate } else if ((~template->ctmpl_ev_crit & 1369*7c478bd9Sstevel@tonic-gate param->ctpm_value) == 0) { 1370*7c478bd9Sstevel@tonic-gate /* 1371*7c478bd9Sstevel@tonic-gate * Assume that a pure reduction of the critical 1372*7c478bd9Sstevel@tonic-gate * set is allowed by the contract type. 1373*7c478bd9Sstevel@tonic-gate */ 1374*7c478bd9Sstevel@tonic-gate template->ctmpl_ev_crit = param->ctpm_value; 1375*7c478bd9Sstevel@tonic-gate break; 1376*7c478bd9Sstevel@tonic-gate } 1377*7c478bd9Sstevel@tonic-gate /* 1378*7c478bd9Sstevel@tonic-gate * There may be restrictions on what we can make 1379*7c478bd9Sstevel@tonic-gate * critical, so we defer to the judgement of the 1380*7c478bd9Sstevel@tonic-gate * contract type. 1381*7c478bd9Sstevel@tonic-gate */ 1382*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1383*7c478bd9Sstevel@tonic-gate default: 1384*7c478bd9Sstevel@tonic-gate result = template->ctmpl_ops->ctop_set(template, param, cr); 1385*7c478bd9Sstevel@tonic-gate } 1386*7c478bd9Sstevel@tonic-gate mutex_exit(&template->ctmpl_lock); 1387*7c478bd9Sstevel@tonic-gate 1388*7c478bd9Sstevel@tonic-gate return (result); 1389*7c478bd9Sstevel@tonic-gate } 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate /* 1392*7c478bd9Sstevel@tonic-gate * ctmpl_get 1393*7c478bd9Sstevel@tonic-gate * 1394*7c478bd9Sstevel@tonic-gate * Obtains the requested terms from a template. 1395*7c478bd9Sstevel@tonic-gate */ 1396*7c478bd9Sstevel@tonic-gate int 1397*7c478bd9Sstevel@tonic-gate ctmpl_get(ct_template_t *template, ct_param_t *param) 1398*7c478bd9Sstevel@tonic-gate { 1399*7c478bd9Sstevel@tonic-gate int result = 0; 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate mutex_enter(&template->ctmpl_lock); 1402*7c478bd9Sstevel@tonic-gate switch (param->ctpm_id) { 1403*7c478bd9Sstevel@tonic-gate case CTP_COOKIE: 1404*7c478bd9Sstevel@tonic-gate param->ctpm_value = template->ctmpl_cookie; 1405*7c478bd9Sstevel@tonic-gate break; 1406*7c478bd9Sstevel@tonic-gate case CTP_EV_INFO: 1407*7c478bd9Sstevel@tonic-gate param->ctpm_value = template->ctmpl_ev_info; 1408*7c478bd9Sstevel@tonic-gate break; 1409*7c478bd9Sstevel@tonic-gate case CTP_EV_CRITICAL: 1410*7c478bd9Sstevel@tonic-gate param->ctpm_value = template->ctmpl_ev_crit; 1411*7c478bd9Sstevel@tonic-gate break; 1412*7c478bd9Sstevel@tonic-gate default: 1413*7c478bd9Sstevel@tonic-gate result = template->ctmpl_ops->ctop_get(template, param); 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate mutex_exit(&template->ctmpl_lock); 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate return (result); 1418*7c478bd9Sstevel@tonic-gate } 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate /* 1421*7c478bd9Sstevel@tonic-gate * ctmpl_makecurrent 1422*7c478bd9Sstevel@tonic-gate * 1423*7c478bd9Sstevel@tonic-gate * Used by ctmpl_activate and ctmpl_clear to set the current thread's 1424*7c478bd9Sstevel@tonic-gate * active template. Frees the old active template, if there was one. 1425*7c478bd9Sstevel@tonic-gate */ 1426*7c478bd9Sstevel@tonic-gate static void 1427*7c478bd9Sstevel@tonic-gate ctmpl_makecurrent(ct_template_t *template, ct_template_t *new) 1428*7c478bd9Sstevel@tonic-gate { 1429*7c478bd9Sstevel@tonic-gate klwp_t *curlwp = ttolwp(curthread); 1430*7c478bd9Sstevel@tonic-gate proc_t *p = curproc; 1431*7c478bd9Sstevel@tonic-gate ct_template_t *old; 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1434*7c478bd9Sstevel@tonic-gate old = curlwp->lwp_ct_active[template->ctmpl_type->ct_type_index]; 1435*7c478bd9Sstevel@tonic-gate curlwp->lwp_ct_active[template->ctmpl_type->ct_type_index] = new; 1436*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate if (old) 1439*7c478bd9Sstevel@tonic-gate ctmpl_free(old); 1440*7c478bd9Sstevel@tonic-gate } 1441*7c478bd9Sstevel@tonic-gate 1442*7c478bd9Sstevel@tonic-gate /* 1443*7c478bd9Sstevel@tonic-gate * ctmpl_activate 1444*7c478bd9Sstevel@tonic-gate * 1445*7c478bd9Sstevel@tonic-gate * Copy the specified template as the current thread's activate 1446*7c478bd9Sstevel@tonic-gate * template of that type. 1447*7c478bd9Sstevel@tonic-gate */ 1448*7c478bd9Sstevel@tonic-gate void 1449*7c478bd9Sstevel@tonic-gate ctmpl_activate(ct_template_t *template) 1450*7c478bd9Sstevel@tonic-gate { 1451*7c478bd9Sstevel@tonic-gate ctmpl_makecurrent(template, ctmpl_dup(template)); 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate 1454*7c478bd9Sstevel@tonic-gate /* 1455*7c478bd9Sstevel@tonic-gate * ctmpl_clear 1456*7c478bd9Sstevel@tonic-gate * 1457*7c478bd9Sstevel@tonic-gate * Clears the current thread's activate template of the same type as 1458*7c478bd9Sstevel@tonic-gate * the specified template. 1459*7c478bd9Sstevel@tonic-gate */ 1460*7c478bd9Sstevel@tonic-gate void 1461*7c478bd9Sstevel@tonic-gate ctmpl_clear(ct_template_t *template) 1462*7c478bd9Sstevel@tonic-gate { 1463*7c478bd9Sstevel@tonic-gate ctmpl_makecurrent(template, NULL); 1464*7c478bd9Sstevel@tonic-gate } 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate /* 1467*7c478bd9Sstevel@tonic-gate * ctmpl_create 1468*7c478bd9Sstevel@tonic-gate * 1469*7c478bd9Sstevel@tonic-gate * Creates a new contract using the specified template. 1470*7c478bd9Sstevel@tonic-gate */ 1471*7c478bd9Sstevel@tonic-gate int 1472*7c478bd9Sstevel@tonic-gate ctmpl_create(ct_template_t *template) 1473*7c478bd9Sstevel@tonic-gate { 1474*7c478bd9Sstevel@tonic-gate return (template->ctmpl_ops->ctop_create(template)); 1475*7c478bd9Sstevel@tonic-gate } 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate /* 1478*7c478bd9Sstevel@tonic-gate * ctmpl_init 1479*7c478bd9Sstevel@tonic-gate * 1480*7c478bd9Sstevel@tonic-gate * Initializes the common portion of a new contract template. 1481*7c478bd9Sstevel@tonic-gate */ 1482*7c478bd9Sstevel@tonic-gate void 1483*7c478bd9Sstevel@tonic-gate ctmpl_init(ct_template_t *new, ctmplops_t *ops, ct_type_t *type, void *data) 1484*7c478bd9Sstevel@tonic-gate { 1485*7c478bd9Sstevel@tonic-gate mutex_init(&new->ctmpl_lock, NULL, MUTEX_DEFAULT, NULL); 1486*7c478bd9Sstevel@tonic-gate new->ctmpl_ops = ops; 1487*7c478bd9Sstevel@tonic-gate new->ctmpl_type = type; 1488*7c478bd9Sstevel@tonic-gate new->ctmpl_data = data; 1489*7c478bd9Sstevel@tonic-gate new->ctmpl_ev_info = new->ctmpl_ev_crit = 0; 1490*7c478bd9Sstevel@tonic-gate new->ctmpl_cookie = 0; 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate /* 1494*7c478bd9Sstevel@tonic-gate * ctmpl_copy 1495*7c478bd9Sstevel@tonic-gate * 1496*7c478bd9Sstevel@tonic-gate * Copies the common portions of a contract template. Intended for use 1497*7c478bd9Sstevel@tonic-gate * by a contract type's ctop_dup template op. Returns with the old 1498*7c478bd9Sstevel@tonic-gate * template's lock held, which will should remain held until the 1499*7c478bd9Sstevel@tonic-gate * template op returns (it is dropped by ctmpl_dup). 1500*7c478bd9Sstevel@tonic-gate */ 1501*7c478bd9Sstevel@tonic-gate void 1502*7c478bd9Sstevel@tonic-gate ctmpl_copy(ct_template_t *new, ct_template_t *old) 1503*7c478bd9Sstevel@tonic-gate { 1504*7c478bd9Sstevel@tonic-gate mutex_init(&new->ctmpl_lock, NULL, MUTEX_DEFAULT, NULL); 1505*7c478bd9Sstevel@tonic-gate mutex_enter(&old->ctmpl_lock); 1506*7c478bd9Sstevel@tonic-gate new->ctmpl_ops = old->ctmpl_ops; 1507*7c478bd9Sstevel@tonic-gate new->ctmpl_type = old->ctmpl_type; 1508*7c478bd9Sstevel@tonic-gate new->ctmpl_ev_crit = old->ctmpl_ev_crit; 1509*7c478bd9Sstevel@tonic-gate new->ctmpl_ev_info = old->ctmpl_ev_info; 1510*7c478bd9Sstevel@tonic-gate new->ctmpl_cookie = old->ctmpl_cookie; 1511*7c478bd9Sstevel@tonic-gate } 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate /* 1514*7c478bd9Sstevel@tonic-gate * ctmpl_create_inval 1515*7c478bd9Sstevel@tonic-gate * 1516*7c478bd9Sstevel@tonic-gate * Returns EINVAL. Provided for the convenience of those contract 1517*7c478bd9Sstevel@tonic-gate * types which don't support ct_tmpl_create(3contract) and would 1518*7c478bd9Sstevel@tonic-gate * otherwise need to create their own stub for the ctop_create template 1519*7c478bd9Sstevel@tonic-gate * op. 1520*7c478bd9Sstevel@tonic-gate */ 1521*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1522*7c478bd9Sstevel@tonic-gate int 1523*7c478bd9Sstevel@tonic-gate ctmpl_create_inval(ct_template_t *template) 1524*7c478bd9Sstevel@tonic-gate { 1525*7c478bd9Sstevel@tonic-gate return (EINVAL); 1526*7c478bd9Sstevel@tonic-gate } 1527*7c478bd9Sstevel@tonic-gate 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate /* 1530*7c478bd9Sstevel@tonic-gate * cte_queue_create 1531*7c478bd9Sstevel@tonic-gate * 1532*7c478bd9Sstevel@tonic-gate * Initializes a queue of a particular type. If dynamic is set, the 1533*7c478bd9Sstevel@tonic-gate * queue is to be freed when its last listener is removed after being 1534*7c478bd9Sstevel@tonic-gate * drained. 1535*7c478bd9Sstevel@tonic-gate */ 1536*7c478bd9Sstevel@tonic-gate static void 1537*7c478bd9Sstevel@tonic-gate cte_queue_create(ct_equeue_t *q, ct_listnum_t list, int maxinf, int dynamic) 1538*7c478bd9Sstevel@tonic-gate { 1539*7c478bd9Sstevel@tonic-gate mutex_init(&q->ctq_lock, NULL, MUTEX_DEFAULT, NULL); 1540*7c478bd9Sstevel@tonic-gate q->ctq_listno = list; 1541*7c478bd9Sstevel@tonic-gate list_create(&q->ctq_events, sizeof (ct_kevent_t), 1542*7c478bd9Sstevel@tonic-gate offsetof(ct_kevent_t, cte_nodes[list].ctm_node)); 1543*7c478bd9Sstevel@tonic-gate list_create(&q->ctq_listeners, sizeof (ct_listener_t), 1544*7c478bd9Sstevel@tonic-gate offsetof(ct_listener_t, ctl_allnode)); 1545*7c478bd9Sstevel@tonic-gate list_create(&q->ctq_tail, sizeof (ct_listener_t), 1546*7c478bd9Sstevel@tonic-gate offsetof(ct_listener_t, ctl_tailnode)); 1547*7c478bd9Sstevel@tonic-gate gethrestime(&q->ctq_atime); 1548*7c478bd9Sstevel@tonic-gate q->ctq_nlisteners = 0; 1549*7c478bd9Sstevel@tonic-gate q->ctq_nreliable = 0; 1550*7c478bd9Sstevel@tonic-gate q->ctq_ninf = 0; 1551*7c478bd9Sstevel@tonic-gate q->ctq_max = maxinf; 1552*7c478bd9Sstevel@tonic-gate 1553*7c478bd9Sstevel@tonic-gate /* 1554*7c478bd9Sstevel@tonic-gate * Bundle queues and contract queues are embedded in other 1555*7c478bd9Sstevel@tonic-gate * structures and are implicitly referenced counted by virtue 1556*7c478bd9Sstevel@tonic-gate * of their vnodes' indirect hold on their contracts. Process 1557*7c478bd9Sstevel@tonic-gate * bundle queues are dynamically allocated and may persist 1558*7c478bd9Sstevel@tonic-gate * after the death of the process, so they must be explicitly 1559*7c478bd9Sstevel@tonic-gate * reference counted. 1560*7c478bd9Sstevel@tonic-gate */ 1561*7c478bd9Sstevel@tonic-gate q->ctq_flags = dynamic ? CTQ_REFFED : 0; 1562*7c478bd9Sstevel@tonic-gate } 1563*7c478bd9Sstevel@tonic-gate 1564*7c478bd9Sstevel@tonic-gate /* 1565*7c478bd9Sstevel@tonic-gate * cte_queue_destroy 1566*7c478bd9Sstevel@tonic-gate * 1567*7c478bd9Sstevel@tonic-gate * Destroys the specified queue. The queue is freed if referenced 1568*7c478bd9Sstevel@tonic-gate * counted. 1569*7c478bd9Sstevel@tonic-gate */ 1570*7c478bd9Sstevel@tonic-gate static void 1571*7c478bd9Sstevel@tonic-gate cte_queue_destroy(ct_equeue_t *q) 1572*7c478bd9Sstevel@tonic-gate { 1573*7c478bd9Sstevel@tonic-gate ASSERT(q->ctq_flags & CTQ_DEAD); 1574*7c478bd9Sstevel@tonic-gate ASSERT(q->ctq_nlisteners == 0); 1575*7c478bd9Sstevel@tonic-gate ASSERT(q->ctq_nreliable == 0); 1576*7c478bd9Sstevel@tonic-gate list_destroy(&q->ctq_events); 1577*7c478bd9Sstevel@tonic-gate list_destroy(&q->ctq_listeners); 1578*7c478bd9Sstevel@tonic-gate list_destroy(&q->ctq_tail); 1579*7c478bd9Sstevel@tonic-gate mutex_destroy(&q->ctq_lock); 1580*7c478bd9Sstevel@tonic-gate if (q->ctq_flags & CTQ_REFFED) 1581*7c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (ct_equeue_t)); 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate /* 1585*7c478bd9Sstevel@tonic-gate * cte_hold 1586*7c478bd9Sstevel@tonic-gate * 1587*7c478bd9Sstevel@tonic-gate * Takes a hold on the specified event. 1588*7c478bd9Sstevel@tonic-gate */ 1589*7c478bd9Sstevel@tonic-gate static void 1590*7c478bd9Sstevel@tonic-gate cte_hold(ct_kevent_t *e) 1591*7c478bd9Sstevel@tonic-gate { 1592*7c478bd9Sstevel@tonic-gate mutex_enter(&e->cte_lock); 1593*7c478bd9Sstevel@tonic-gate ASSERT(e->cte_refs > 0); 1594*7c478bd9Sstevel@tonic-gate e->cte_refs++; 1595*7c478bd9Sstevel@tonic-gate mutex_exit(&e->cte_lock); 1596*7c478bd9Sstevel@tonic-gate } 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate /* 1599*7c478bd9Sstevel@tonic-gate * cte_rele 1600*7c478bd9Sstevel@tonic-gate * 1601*7c478bd9Sstevel@tonic-gate * Releases a hold on the specified event. If the caller had the last 1602*7c478bd9Sstevel@tonic-gate * reference, frees the event and releases its hold on the contract 1603*7c478bd9Sstevel@tonic-gate * that generated it. 1604*7c478bd9Sstevel@tonic-gate */ 1605*7c478bd9Sstevel@tonic-gate static void 1606*7c478bd9Sstevel@tonic-gate cte_rele(ct_kevent_t *e) 1607*7c478bd9Sstevel@tonic-gate { 1608*7c478bd9Sstevel@tonic-gate mutex_enter(&e->cte_lock); 1609*7c478bd9Sstevel@tonic-gate ASSERT(e->cte_refs > 0); 1610*7c478bd9Sstevel@tonic-gate if (--e->cte_refs) { 1611*7c478bd9Sstevel@tonic-gate mutex_exit(&e->cte_lock); 1612*7c478bd9Sstevel@tonic-gate return; 1613*7c478bd9Sstevel@tonic-gate } 1614*7c478bd9Sstevel@tonic-gate 1615*7c478bd9Sstevel@tonic-gate contract_rele(e->cte_contract); 1616*7c478bd9Sstevel@tonic-gate 1617*7c478bd9Sstevel@tonic-gate mutex_destroy(&e->cte_lock); 1618*7c478bd9Sstevel@tonic-gate if (e->cte_data) 1619*7c478bd9Sstevel@tonic-gate nvlist_free(e->cte_data); 1620*7c478bd9Sstevel@tonic-gate if (e->cte_gdata) 1621*7c478bd9Sstevel@tonic-gate nvlist_free(e->cte_gdata); 1622*7c478bd9Sstevel@tonic-gate kmem_free(e, sizeof (ct_kevent_t)); 1623*7c478bd9Sstevel@tonic-gate } 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate /* 1626*7c478bd9Sstevel@tonic-gate * cte_qrele 1627*7c478bd9Sstevel@tonic-gate * 1628*7c478bd9Sstevel@tonic-gate * Remove this listener's hold on the specified event, removing and 1629*7c478bd9Sstevel@tonic-gate * releasing the queue's hold on the event if appropriate. 1630*7c478bd9Sstevel@tonic-gate */ 1631*7c478bd9Sstevel@tonic-gate static void 1632*7c478bd9Sstevel@tonic-gate cte_qrele(ct_equeue_t *q, ct_listener_t *l, ct_kevent_t *e) 1633*7c478bd9Sstevel@tonic-gate { 1634*7c478bd9Sstevel@tonic-gate ct_member_t *member = &e->cte_nodes[q->ctq_listno]; 1635*7c478bd9Sstevel@tonic-gate 1636*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock)); 1637*7c478bd9Sstevel@tonic-gate 1638*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE) 1639*7c478bd9Sstevel@tonic-gate member->ctm_nreliable--; 1640*7c478bd9Sstevel@tonic-gate if ((--member->ctm_refs == 0) && member->ctm_trimmed) { 1641*7c478bd9Sstevel@tonic-gate member->ctm_trimmed = 0; 1642*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_events, e); 1643*7c478bd9Sstevel@tonic-gate cte_rele(e); 1644*7c478bd9Sstevel@tonic-gate } 1645*7c478bd9Sstevel@tonic-gate } 1646*7c478bd9Sstevel@tonic-gate 1647*7c478bd9Sstevel@tonic-gate /* 1648*7c478bd9Sstevel@tonic-gate * cte_qmove 1649*7c478bd9Sstevel@tonic-gate * 1650*7c478bd9Sstevel@tonic-gate * Move this listener to the specified event in the queue. 1651*7c478bd9Sstevel@tonic-gate */ 1652*7c478bd9Sstevel@tonic-gate static ct_kevent_t * 1653*7c478bd9Sstevel@tonic-gate cte_qmove(ct_equeue_t *q, ct_listener_t *l, ct_kevent_t *e) 1654*7c478bd9Sstevel@tonic-gate { 1655*7c478bd9Sstevel@tonic-gate ct_kevent_t *olde; 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock)); 1658*7c478bd9Sstevel@tonic-gate ASSERT(l->ctl_equeue == q); 1659*7c478bd9Sstevel@tonic-gate 1660*7c478bd9Sstevel@tonic-gate if ((olde = l->ctl_position) == NULL) 1661*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_tail, l); 1662*7c478bd9Sstevel@tonic-gate 1663*7c478bd9Sstevel@tonic-gate while (e != NULL && e->cte_nodes[q->ctq_listno].ctm_trimmed) 1664*7c478bd9Sstevel@tonic-gate e = list_next(&q->ctq_events, e); 1665*7c478bd9Sstevel@tonic-gate 1666*7c478bd9Sstevel@tonic-gate if (e != NULL) { 1667*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_refs++; 1668*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE) 1669*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_nreliable++; 1670*7c478bd9Sstevel@tonic-gate } else { 1671*7c478bd9Sstevel@tonic-gate list_insert_tail(&q->ctq_tail, l); 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate l->ctl_position = e; 1675*7c478bd9Sstevel@tonic-gate if (olde) 1676*7c478bd9Sstevel@tonic-gate cte_qrele(q, l, olde); 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate return (e); 1679*7c478bd9Sstevel@tonic-gate } 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate /* 1682*7c478bd9Sstevel@tonic-gate * cte_checkcred 1683*7c478bd9Sstevel@tonic-gate * 1684*7c478bd9Sstevel@tonic-gate * Determines if the specified event's contract is owned by a process 1685*7c478bd9Sstevel@tonic-gate * with the same effective uid as the specified credential. Called 1686*7c478bd9Sstevel@tonic-gate * after a failed call to contract_owned with locked set. Because it 1687*7c478bd9Sstevel@tonic-gate * drops the queue lock, its caller (cte_qreadable) needs to make sure 1688*7c478bd9Sstevel@tonic-gate * we're still in the same place after we return. Returns 1 on 1689*7c478bd9Sstevel@tonic-gate * success. 1690*7c478bd9Sstevel@tonic-gate */ 1691*7c478bd9Sstevel@tonic-gate static int 1692*7c478bd9Sstevel@tonic-gate cte_checkcred(ct_equeue_t *q, ct_kevent_t *e, const cred_t *cr) 1693*7c478bd9Sstevel@tonic-gate { 1694*7c478bd9Sstevel@tonic-gate int result; 1695*7c478bd9Sstevel@tonic-gate contract_t *ct = e->cte_contract; 1696*7c478bd9Sstevel@tonic-gate 1697*7c478bd9Sstevel@tonic-gate cte_hold(e); 1698*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 1699*7c478bd9Sstevel@tonic-gate result = curproc->p_zone->zone_uniqid == ct->ct_czuniqid && 1700*7c478bd9Sstevel@tonic-gate contract_checkcred(ct, cr); 1701*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 1702*7c478bd9Sstevel@tonic-gate cte_rele(e); 1703*7c478bd9Sstevel@tonic-gate 1704*7c478bd9Sstevel@tonic-gate return (result); 1705*7c478bd9Sstevel@tonic-gate } 1706*7c478bd9Sstevel@tonic-gate 1707*7c478bd9Sstevel@tonic-gate /* 1708*7c478bd9Sstevel@tonic-gate * cte_qreadable 1709*7c478bd9Sstevel@tonic-gate * 1710*7c478bd9Sstevel@tonic-gate * Ensures that the listener is pointing to a valid event that the 1711*7c478bd9Sstevel@tonic-gate * caller has the credentials to read. Returns 0 if we can read the 1712*7c478bd9Sstevel@tonic-gate * event we're pointing to. 1713*7c478bd9Sstevel@tonic-gate */ 1714*7c478bd9Sstevel@tonic-gate static int 1715*7c478bd9Sstevel@tonic-gate cte_qreadable(ct_equeue_t *q, ct_listener_t *l, const cred_t *cr, 1716*7c478bd9Sstevel@tonic-gate uint64_t zuniqid, int crit) 1717*7c478bd9Sstevel@tonic-gate { 1718*7c478bd9Sstevel@tonic-gate ct_kevent_t *e, *next; 1719*7c478bd9Sstevel@tonic-gate contract_t *ct; 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock)); 1722*7c478bd9Sstevel@tonic-gate ASSERT(l->ctl_equeue == q); 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_COPYOUT) 1725*7c478bd9Sstevel@tonic-gate return (1); 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate next = l->ctl_position; 1728*7c478bd9Sstevel@tonic-gate while (e = cte_qmove(q, l, next)) { 1729*7c478bd9Sstevel@tonic-gate ct = e->cte_contract; 1730*7c478bd9Sstevel@tonic-gate /* 1731*7c478bd9Sstevel@tonic-gate * Check obvious things first. If we are looking for a 1732*7c478bd9Sstevel@tonic-gate * critical message, is this one? If we aren't in the 1733*7c478bd9Sstevel@tonic-gate * global zone, is this message meant for us? 1734*7c478bd9Sstevel@tonic-gate */ 1735*7c478bd9Sstevel@tonic-gate if ((crit && (e->cte_flags & (CTE_INFO | CTE_ACK))) || 1736*7c478bd9Sstevel@tonic-gate (cr != NULL && zuniqid != GLOBAL_ZONEUNIQID && 1737*7c478bd9Sstevel@tonic-gate zuniqid != contract_getzuniqid(ct))) { 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e); 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate /* 1742*7c478bd9Sstevel@tonic-gate * Next, see if our effective uid equals that of owner 1743*7c478bd9Sstevel@tonic-gate * or author of the contract. Since we are holding the 1744*7c478bd9Sstevel@tonic-gate * queue lock, contract_owned can't always check if we 1745*7c478bd9Sstevel@tonic-gate * have the same effective uid as the contract's 1746*7c478bd9Sstevel@tonic-gate * owner. If it comes to that, it fails and we take 1747*7c478bd9Sstevel@tonic-gate * the slow(er) path. 1748*7c478bd9Sstevel@tonic-gate */ 1749*7c478bd9Sstevel@tonic-gate } else if (cr != NULL && !contract_owned(ct, cr, B_TRUE)) { 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate /* 1752*7c478bd9Sstevel@tonic-gate * At this point we either don't have any claim 1753*7c478bd9Sstevel@tonic-gate * to this contract or we match the effective 1754*7c478bd9Sstevel@tonic-gate * uid of the owner but couldn't tell. We 1755*7c478bd9Sstevel@tonic-gate * first test for a NULL holder so that events 1756*7c478bd9Sstevel@tonic-gate * from orphans and inherited contracts avoid 1757*7c478bd9Sstevel@tonic-gate * the penalty phase. 1758*7c478bd9Sstevel@tonic-gate */ 1759*7c478bd9Sstevel@tonic-gate if (e->cte_contract->ct_owner == NULL && 1760*7c478bd9Sstevel@tonic-gate !secpolicy_contract_observer_choice(cr)) 1761*7c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e); 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate /* 1764*7c478bd9Sstevel@tonic-gate * cte_checkcred will juggle locks to see if we 1765*7c478bd9Sstevel@tonic-gate * have the same uid as the event's contract's 1766*7c478bd9Sstevel@tonic-gate * current owner. If it succeeds, we have to 1767*7c478bd9Sstevel@tonic-gate * make sure we are in the same point in the 1768*7c478bd9Sstevel@tonic-gate * queue. 1769*7c478bd9Sstevel@tonic-gate */ 1770*7c478bd9Sstevel@tonic-gate else if (cte_checkcred(q, e, cr) && 1771*7c478bd9Sstevel@tonic-gate l->ctl_position == e) 1772*7c478bd9Sstevel@tonic-gate break; 1773*7c478bd9Sstevel@tonic-gate 1774*7c478bd9Sstevel@tonic-gate /* 1775*7c478bd9Sstevel@tonic-gate * cte_checkcred failed; see if we're in the 1776*7c478bd9Sstevel@tonic-gate * same place. 1777*7c478bd9Sstevel@tonic-gate */ 1778*7c478bd9Sstevel@tonic-gate else if (l->ctl_position == e) 1779*7c478bd9Sstevel@tonic-gate if (secpolicy_contract_observer_choice(cr)) 1780*7c478bd9Sstevel@tonic-gate break; 1781*7c478bd9Sstevel@tonic-gate else 1782*7c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e); 1783*7c478bd9Sstevel@tonic-gate 1784*7c478bd9Sstevel@tonic-gate /* 1785*7c478bd9Sstevel@tonic-gate * cte_checkcred failed, and our position was 1786*7c478bd9Sstevel@tonic-gate * changed. Start from there. 1787*7c478bd9Sstevel@tonic-gate */ 1788*7c478bd9Sstevel@tonic-gate else 1789*7c478bd9Sstevel@tonic-gate next = l->ctl_position; 1790*7c478bd9Sstevel@tonic-gate } else { 1791*7c478bd9Sstevel@tonic-gate break; 1792*7c478bd9Sstevel@tonic-gate } 1793*7c478bd9Sstevel@tonic-gate } 1794*7c478bd9Sstevel@tonic-gate 1795*7c478bd9Sstevel@tonic-gate /* 1796*7c478bd9Sstevel@tonic-gate * We check for CTLF_COPYOUT again in case we dropped the queue 1797*7c478bd9Sstevel@tonic-gate * lock in cte_checkcred. 1798*7c478bd9Sstevel@tonic-gate */ 1799*7c478bd9Sstevel@tonic-gate return ((l->ctl_flags & CTLF_COPYOUT) || (l->ctl_position == NULL)); 1800*7c478bd9Sstevel@tonic-gate } 1801*7c478bd9Sstevel@tonic-gate 1802*7c478bd9Sstevel@tonic-gate /* 1803*7c478bd9Sstevel@tonic-gate * cte_qwakeup 1804*7c478bd9Sstevel@tonic-gate * 1805*7c478bd9Sstevel@tonic-gate * Wakes up any waiting listeners and points them at the specified event. 1806*7c478bd9Sstevel@tonic-gate */ 1807*7c478bd9Sstevel@tonic-gate static void 1808*7c478bd9Sstevel@tonic-gate cte_qwakeup(ct_equeue_t *q, ct_kevent_t *e) 1809*7c478bd9Sstevel@tonic-gate { 1810*7c478bd9Sstevel@tonic-gate ct_listener_t *l; 1811*7c478bd9Sstevel@tonic-gate 1812*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock)); 1813*7c478bd9Sstevel@tonic-gate 1814*7c478bd9Sstevel@tonic-gate while (l = list_head(&q->ctq_tail)) { 1815*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_tail, l); 1816*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_refs++; 1817*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE) 1818*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_nreliable++; 1819*7c478bd9Sstevel@tonic-gate l->ctl_position = e; 1820*7c478bd9Sstevel@tonic-gate cv_signal(&l->ctl_cv); 1821*7c478bd9Sstevel@tonic-gate pollwakeup(&l->ctl_pollhead, POLLIN); 1822*7c478bd9Sstevel@tonic-gate } 1823*7c478bd9Sstevel@tonic-gate } 1824*7c478bd9Sstevel@tonic-gate 1825*7c478bd9Sstevel@tonic-gate /* 1826*7c478bd9Sstevel@tonic-gate * cte_copy 1827*7c478bd9Sstevel@tonic-gate * 1828*7c478bd9Sstevel@tonic-gate * Copies events from the specified contract event queue to the 1829*7c478bd9Sstevel@tonic-gate * end of the specified process bundle queue. Only called from 1830*7c478bd9Sstevel@tonic-gate * contract_adopt. 1831*7c478bd9Sstevel@tonic-gate * 1832*7c478bd9Sstevel@tonic-gate * We copy to the end of the target queue instead of mixing the events 1833*7c478bd9Sstevel@tonic-gate * in their proper order because otherwise the act of adopting a 1834*7c478bd9Sstevel@tonic-gate * contract would require a process to reset all process bundle 1835*7c478bd9Sstevel@tonic-gate * listeners it needed to see the new events. This would, in turn, 1836*7c478bd9Sstevel@tonic-gate * require the process to keep track of which preexisting events had 1837*7c478bd9Sstevel@tonic-gate * already been processed. 1838*7c478bd9Sstevel@tonic-gate */ 1839*7c478bd9Sstevel@tonic-gate static void 1840*7c478bd9Sstevel@tonic-gate cte_copy(ct_equeue_t *q, ct_equeue_t *newq) 1841*7c478bd9Sstevel@tonic-gate { 1842*7c478bd9Sstevel@tonic-gate ct_kevent_t *e, *first = NULL; 1843*7c478bd9Sstevel@tonic-gate 1844*7c478bd9Sstevel@tonic-gate ASSERT(q->ctq_listno == CTEL_CONTRACT); 1845*7c478bd9Sstevel@tonic-gate ASSERT(newq->ctq_listno == CTEL_PBUNDLE); 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 1848*7c478bd9Sstevel@tonic-gate mutex_enter(&newq->ctq_lock); 1849*7c478bd9Sstevel@tonic-gate 1850*7c478bd9Sstevel@tonic-gate /* 1851*7c478bd9Sstevel@tonic-gate * For now, only copy critical events. 1852*7c478bd9Sstevel@tonic-gate */ 1853*7c478bd9Sstevel@tonic-gate for (e = list_head(&q->ctq_events); e != NULL; 1854*7c478bd9Sstevel@tonic-gate e = list_next(&q->ctq_events, e)) { 1855*7c478bd9Sstevel@tonic-gate if ((e->cte_flags & (CTE_INFO | CTE_ACK)) == 0) { 1856*7c478bd9Sstevel@tonic-gate if (first == NULL) 1857*7c478bd9Sstevel@tonic-gate first = e; 1858*7c478bd9Sstevel@tonic-gate list_insert_tail(&newq->ctq_events, e); 1859*7c478bd9Sstevel@tonic-gate cte_hold(e); 1860*7c478bd9Sstevel@tonic-gate } 1861*7c478bd9Sstevel@tonic-gate } 1862*7c478bd9Sstevel@tonic-gate 1863*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate if (first) 1866*7c478bd9Sstevel@tonic-gate cte_qwakeup(newq, first); 1867*7c478bd9Sstevel@tonic-gate 1868*7c478bd9Sstevel@tonic-gate mutex_exit(&newq->ctq_lock); 1869*7c478bd9Sstevel@tonic-gate } 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate /* 1872*7c478bd9Sstevel@tonic-gate * cte_trim 1873*7c478bd9Sstevel@tonic-gate * 1874*7c478bd9Sstevel@tonic-gate * Trims unneeded events from an event queue. Algorithm works as 1875*7c478bd9Sstevel@tonic-gate * follows: 1876*7c478bd9Sstevel@tonic-gate * 1877*7c478bd9Sstevel@tonic-gate * Removes all informative and acknowledged critical events until the 1878*7c478bd9Sstevel@tonic-gate * first referenced event is found. 1879*7c478bd9Sstevel@tonic-gate * 1880*7c478bd9Sstevel@tonic-gate * If a contract is specified, removes all events (regardless of 1881*7c478bd9Sstevel@tonic-gate * acknowledgement) generated by that contract until the first event 1882*7c478bd9Sstevel@tonic-gate * referenced by a reliable listener is found. Reference events are 1883*7c478bd9Sstevel@tonic-gate * removed by marking them "trimmed". Such events will be removed 1884*7c478bd9Sstevel@tonic-gate * when the last reference is dropped and will be skipped by future 1885*7c478bd9Sstevel@tonic-gate * listeners. 1886*7c478bd9Sstevel@tonic-gate * 1887*7c478bd9Sstevel@tonic-gate * This is pretty basic. Ideally this should remove from the middle of 1888*7c478bd9Sstevel@tonic-gate * the list (i.e. beyond the first referenced event), and even 1889*7c478bd9Sstevel@tonic-gate * referenced events. 1890*7c478bd9Sstevel@tonic-gate */ 1891*7c478bd9Sstevel@tonic-gate static void 1892*7c478bd9Sstevel@tonic-gate cte_trim(ct_equeue_t *q, contract_t *ct) 1893*7c478bd9Sstevel@tonic-gate { 1894*7c478bd9Sstevel@tonic-gate ct_kevent_t *e, *next; 1895*7c478bd9Sstevel@tonic-gate int flags, stopper; 1896*7c478bd9Sstevel@tonic-gate int start = 1; 1897*7c478bd9Sstevel@tonic-gate 1898*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock)); 1899*7c478bd9Sstevel@tonic-gate 1900*7c478bd9Sstevel@tonic-gate for (e = list_head(&q->ctq_events); e != NULL; e = next) { 1901*7c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e); 1902*7c478bd9Sstevel@tonic-gate flags = e->cte_flags; 1903*7c478bd9Sstevel@tonic-gate stopper = (q->ctq_listno != CTEL_PBUNDLE) && 1904*7c478bd9Sstevel@tonic-gate (e->cte_nodes[q->ctq_listno].ctm_nreliable > 0); 1905*7c478bd9Sstevel@tonic-gate if (e->cte_nodes[q->ctq_listno].ctm_refs == 0) { 1906*7c478bd9Sstevel@tonic-gate if ((start && (flags & (CTE_INFO | CTE_ACK))) || 1907*7c478bd9Sstevel@tonic-gate (e->cte_contract == ct)) { 1908*7c478bd9Sstevel@tonic-gate /* 1909*7c478bd9Sstevel@tonic-gate * Toss informative and ACKed critical messages. 1910*7c478bd9Sstevel@tonic-gate */ 1911*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_events, e); 1912*7c478bd9Sstevel@tonic-gate cte_rele(e); 1913*7c478bd9Sstevel@tonic-gate } 1914*7c478bd9Sstevel@tonic-gate } else if ((e->cte_contract == ct) && !stopper) { 1915*7c478bd9Sstevel@tonic-gate ASSERT(q->ctq_nlisteners != 0); 1916*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_trimmed = 1; 1917*7c478bd9Sstevel@tonic-gate } else if (ct && !stopper) { 1918*7c478bd9Sstevel@tonic-gate start = 0; 1919*7c478bd9Sstevel@tonic-gate } else { 1920*7c478bd9Sstevel@tonic-gate /* 1921*7c478bd9Sstevel@tonic-gate * Don't free messages past the first reader. 1922*7c478bd9Sstevel@tonic-gate */ 1923*7c478bd9Sstevel@tonic-gate break; 1924*7c478bd9Sstevel@tonic-gate } 1925*7c478bd9Sstevel@tonic-gate } 1926*7c478bd9Sstevel@tonic-gate } 1927*7c478bd9Sstevel@tonic-gate 1928*7c478bd9Sstevel@tonic-gate /* 1929*7c478bd9Sstevel@tonic-gate * cte_queue_drain 1930*7c478bd9Sstevel@tonic-gate * 1931*7c478bd9Sstevel@tonic-gate * Drain all events from the specified queue, and mark it dead. If 1932*7c478bd9Sstevel@tonic-gate * "ack" is set, acknowledge any critical events we find along the 1933*7c478bd9Sstevel@tonic-gate * way. 1934*7c478bd9Sstevel@tonic-gate */ 1935*7c478bd9Sstevel@tonic-gate static void 1936*7c478bd9Sstevel@tonic-gate cte_queue_drain(ct_equeue_t *q, int ack) 1937*7c478bd9Sstevel@tonic-gate { 1938*7c478bd9Sstevel@tonic-gate ct_kevent_t *e, *next; 1939*7c478bd9Sstevel@tonic-gate ct_listener_t *l; 1940*7c478bd9Sstevel@tonic-gate 1941*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 1942*7c478bd9Sstevel@tonic-gate 1943*7c478bd9Sstevel@tonic-gate for (e = list_head(&q->ctq_events); e != NULL; e = next) { 1944*7c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e); 1945*7c478bd9Sstevel@tonic-gate if (ack && ((e->cte_flags & (CTE_INFO | CTE_ACK)) == 0)) { 1946*7c478bd9Sstevel@tonic-gate /* 1947*7c478bd9Sstevel@tonic-gate * Make sure critical messages are eventually 1948*7c478bd9Sstevel@tonic-gate * removed from the bundle queues. 1949*7c478bd9Sstevel@tonic-gate */ 1950*7c478bd9Sstevel@tonic-gate mutex_enter(&e->cte_lock); 1951*7c478bd9Sstevel@tonic-gate e->cte_flags |= CTE_ACK; 1952*7c478bd9Sstevel@tonic-gate mutex_exit(&e->cte_lock); 1953*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&e->cte_contract->ct_lock)); 1954*7c478bd9Sstevel@tonic-gate e->cte_contract->ct_evcnt--; 1955*7c478bd9Sstevel@tonic-gate } 1956*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_events, e); 1957*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_refs = 0; 1958*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_nreliable = 0; 1959*7c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_trimmed = 0; 1960*7c478bd9Sstevel@tonic-gate cte_rele(e); 1961*7c478bd9Sstevel@tonic-gate } 1962*7c478bd9Sstevel@tonic-gate 1963*7c478bd9Sstevel@tonic-gate /* 1964*7c478bd9Sstevel@tonic-gate * This is necessary only because of CTEL_PBUNDLE listeners; 1965*7c478bd9Sstevel@tonic-gate * the events they point to can move from one pbundle to 1966*7c478bd9Sstevel@tonic-gate * another. Fortunately, this only happens if the contract is 1967*7c478bd9Sstevel@tonic-gate * inherited, which (in turn) only happens if the process 1968*7c478bd9Sstevel@tonic-gate * exits, which means it's an all-or-nothing deal. If this 1969*7c478bd9Sstevel@tonic-gate * wasn't the case, we would instead need to keep track of 1970*7c478bd9Sstevel@tonic-gate * listeners on a per-event basis, not just a per-queue basis. 1971*7c478bd9Sstevel@tonic-gate * This would have the side benefit of letting us clean up 1972*7c478bd9Sstevel@tonic-gate * trimmed events sooner (i.e. immediately), but would 1973*7c478bd9Sstevel@tonic-gate * unfortunately make events even bigger than they already 1974*7c478bd9Sstevel@tonic-gate * are. 1975*7c478bd9Sstevel@tonic-gate */ 1976*7c478bd9Sstevel@tonic-gate for (l = list_head(&q->ctq_listeners); l; 1977*7c478bd9Sstevel@tonic-gate l = list_next(&q->ctq_listeners, l)) { 1978*7c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_DEAD; 1979*7c478bd9Sstevel@tonic-gate if (l->ctl_position) { 1980*7c478bd9Sstevel@tonic-gate l->ctl_position = NULL; 1981*7c478bd9Sstevel@tonic-gate list_insert_tail(&q->ctq_tail, l); 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate cv_broadcast(&l->ctl_cv); 1984*7c478bd9Sstevel@tonic-gate } 1985*7c478bd9Sstevel@tonic-gate 1986*7c478bd9Sstevel@tonic-gate /* 1987*7c478bd9Sstevel@tonic-gate * Disallow events. 1988*7c478bd9Sstevel@tonic-gate */ 1989*7c478bd9Sstevel@tonic-gate q->ctq_flags |= CTQ_DEAD; 1990*7c478bd9Sstevel@tonic-gate 1991*7c478bd9Sstevel@tonic-gate /* 1992*7c478bd9Sstevel@tonic-gate * If we represent the last reference to a reference counted 1993*7c478bd9Sstevel@tonic-gate * process bundle queue, free it. 1994*7c478bd9Sstevel@tonic-gate */ 1995*7c478bd9Sstevel@tonic-gate if ((q->ctq_flags & CTQ_REFFED) && (q->ctq_nlisteners == 0)) 1996*7c478bd9Sstevel@tonic-gate cte_queue_destroy(q); 1997*7c478bd9Sstevel@tonic-gate else 1998*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 1999*7c478bd9Sstevel@tonic-gate } 2000*7c478bd9Sstevel@tonic-gate 2001*7c478bd9Sstevel@tonic-gate /* 2002*7c478bd9Sstevel@tonic-gate * cte_publish 2003*7c478bd9Sstevel@tonic-gate * 2004*7c478bd9Sstevel@tonic-gate * Publishes an event to a specific queue. Only called by 2005*7c478bd9Sstevel@tonic-gate * cte_publish_all. 2006*7c478bd9Sstevel@tonic-gate */ 2007*7c478bd9Sstevel@tonic-gate static void 2008*7c478bd9Sstevel@tonic-gate cte_publish(ct_equeue_t *q, ct_kevent_t *e, timespec_t *tsp) 2009*7c478bd9Sstevel@tonic-gate { 2010*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock)); 2011*7c478bd9Sstevel@tonic-gate 2012*7c478bd9Sstevel@tonic-gate q->ctq_atime = *tsp; 2013*7c478bd9Sstevel@tonic-gate 2014*7c478bd9Sstevel@tonic-gate /* 2015*7c478bd9Sstevel@tonic-gate * Don't publish if the event is informative and there aren't 2016*7c478bd9Sstevel@tonic-gate * any listeners, or if the queue has been shut down. 2017*7c478bd9Sstevel@tonic-gate */ 2018*7c478bd9Sstevel@tonic-gate if (((q->ctq_nlisteners == 0) && (e->cte_flags & (CTE_INFO|CTE_ACK))) || 2019*7c478bd9Sstevel@tonic-gate (q->ctq_flags & CTQ_DEAD)) { 2020*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2021*7c478bd9Sstevel@tonic-gate cte_rele(e); 2022*7c478bd9Sstevel@tonic-gate return; 2023*7c478bd9Sstevel@tonic-gate } 2024*7c478bd9Sstevel@tonic-gate 2025*7c478bd9Sstevel@tonic-gate /* 2026*7c478bd9Sstevel@tonic-gate * Enqueue event 2027*7c478bd9Sstevel@tonic-gate */ 2028*7c478bd9Sstevel@tonic-gate list_insert_tail(&q->ctq_events, e); 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate /* 2031*7c478bd9Sstevel@tonic-gate * Check for waiting listeners 2032*7c478bd9Sstevel@tonic-gate */ 2033*7c478bd9Sstevel@tonic-gate cte_qwakeup(q, e); 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate /* 2036*7c478bd9Sstevel@tonic-gate * Trim unnecessary events from the queue. 2037*7c478bd9Sstevel@tonic-gate */ 2038*7c478bd9Sstevel@tonic-gate cte_trim(q, NULL); 2039*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2040*7c478bd9Sstevel@tonic-gate } 2041*7c478bd9Sstevel@tonic-gate 2042*7c478bd9Sstevel@tonic-gate /* 2043*7c478bd9Sstevel@tonic-gate * cte_publish_all 2044*7c478bd9Sstevel@tonic-gate * 2045*7c478bd9Sstevel@tonic-gate * Publish an event to all necessary event queues. The event, e, must 2046*7c478bd9Sstevel@tonic-gate * be zallocated by the caller, and the event's flags and type must be 2047*7c478bd9Sstevel@tonic-gate * set. The rest of the event's fields are initialized here. 2048*7c478bd9Sstevel@tonic-gate */ 2049*7c478bd9Sstevel@tonic-gate void 2050*7c478bd9Sstevel@tonic-gate cte_publish_all(contract_t *ct, ct_kevent_t *e, nvlist_t *data, nvlist_t *gdata) 2051*7c478bd9Sstevel@tonic-gate { 2052*7c478bd9Sstevel@tonic-gate ct_equeue_t *q; 2053*7c478bd9Sstevel@tonic-gate timespec_t ts; 2054*7c478bd9Sstevel@tonic-gate 2055*7c478bd9Sstevel@tonic-gate e->cte_contract = ct; 2056*7c478bd9Sstevel@tonic-gate e->cte_data = data; 2057*7c478bd9Sstevel@tonic-gate e->cte_gdata = gdata; 2058*7c478bd9Sstevel@tonic-gate e->cte_refs = 3; 2059*7c478bd9Sstevel@tonic-gate e->cte_id = atomic_add_64_nv(&ct->ct_type->ct_type_evid, 1); 2060*7c478bd9Sstevel@tonic-gate contract_hold(ct); 2061*7c478bd9Sstevel@tonic-gate 2062*7c478bd9Sstevel@tonic-gate gethrestime(&ts); 2063*7c478bd9Sstevel@tonic-gate 2064*7c478bd9Sstevel@tonic-gate /* 2065*7c478bd9Sstevel@tonic-gate * ct_evtlock simply (and only) ensures that two events sent 2066*7c478bd9Sstevel@tonic-gate * from the same contract are delivered to all queues in the 2067*7c478bd9Sstevel@tonic-gate * same order. 2068*7c478bd9Sstevel@tonic-gate */ 2069*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_evtlock); 2070*7c478bd9Sstevel@tonic-gate 2071*7c478bd9Sstevel@tonic-gate /* 2072*7c478bd9Sstevel@tonic-gate * CTEL_CONTRACT - First deliver to the contract queue, acking 2073*7c478bd9Sstevel@tonic-gate * the event if the contract has been orphaned. 2074*7c478bd9Sstevel@tonic-gate */ 2075*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 2076*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_events.ctq_lock); 2077*7c478bd9Sstevel@tonic-gate if ((e->cte_flags & CTE_INFO) == 0) { 2078*7c478bd9Sstevel@tonic-gate if (ct->ct_state >= CTS_ORPHAN) 2079*7c478bd9Sstevel@tonic-gate e->cte_flags |= CTE_ACK; 2080*7c478bd9Sstevel@tonic-gate else 2081*7c478bd9Sstevel@tonic-gate ct->ct_evcnt++; 2082*7c478bd9Sstevel@tonic-gate } 2083*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 2084*7c478bd9Sstevel@tonic-gate cte_publish(&ct->ct_events, e, &ts); 2085*7c478bd9Sstevel@tonic-gate 2086*7c478bd9Sstevel@tonic-gate /* 2087*7c478bd9Sstevel@tonic-gate * CTEL_BUNDLE - Next deliver to the contract type's bundle 2088*7c478bd9Sstevel@tonic-gate * queue. 2089*7c478bd9Sstevel@tonic-gate */ 2090*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_type->ct_type_events.ctq_lock); 2091*7c478bd9Sstevel@tonic-gate cte_publish(&ct->ct_type->ct_type_events, e, &ts); 2092*7c478bd9Sstevel@tonic-gate 2093*7c478bd9Sstevel@tonic-gate /* 2094*7c478bd9Sstevel@tonic-gate * CTEL_PBUNDLE - Finally, if the contract has an owner, 2095*7c478bd9Sstevel@tonic-gate * deliver to the owner's process bundle queue. 2096*7c478bd9Sstevel@tonic-gate */ 2097*7c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock); 2098*7c478bd9Sstevel@tonic-gate if (ct->ct_owner) { 2099*7c478bd9Sstevel@tonic-gate /* 2100*7c478bd9Sstevel@tonic-gate * proc_exit doesn't free event queues until it has 2101*7c478bd9Sstevel@tonic-gate * abandoned all contracts. 2102*7c478bd9Sstevel@tonic-gate */ 2103*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue); 2104*7c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index]); 2105*7c478bd9Sstevel@tonic-gate q = ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index]; 2106*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2107*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 2108*7c478bd9Sstevel@tonic-gate cte_publish(q, e, &ts); 2109*7c478bd9Sstevel@tonic-gate } else { 2110*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock); 2111*7c478bd9Sstevel@tonic-gate cte_rele(e); 2112*7c478bd9Sstevel@tonic-gate } 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_evtlock); 2115*7c478bd9Sstevel@tonic-gate } 2116*7c478bd9Sstevel@tonic-gate 2117*7c478bd9Sstevel@tonic-gate /* 2118*7c478bd9Sstevel@tonic-gate * cte_add_listener 2119*7c478bd9Sstevel@tonic-gate * 2120*7c478bd9Sstevel@tonic-gate * Add a new listener to an event queue. 2121*7c478bd9Sstevel@tonic-gate */ 2122*7c478bd9Sstevel@tonic-gate void 2123*7c478bd9Sstevel@tonic-gate cte_add_listener(ct_equeue_t *q, ct_listener_t *l) 2124*7c478bd9Sstevel@tonic-gate { 2125*7c478bd9Sstevel@tonic-gate cv_init(&l->ctl_cv, NULL, CV_DEFAULT, NULL); 2126*7c478bd9Sstevel@tonic-gate l->ctl_equeue = q; 2127*7c478bd9Sstevel@tonic-gate l->ctl_position = NULL; 2128*7c478bd9Sstevel@tonic-gate l->ctl_flags = 0; 2129*7c478bd9Sstevel@tonic-gate 2130*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2131*7c478bd9Sstevel@tonic-gate list_insert_head(&q->ctq_tail, l); 2132*7c478bd9Sstevel@tonic-gate list_insert_head(&q->ctq_listeners, l); 2133*7c478bd9Sstevel@tonic-gate q->ctq_nlisteners++; 2134*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2135*7c478bd9Sstevel@tonic-gate } 2136*7c478bd9Sstevel@tonic-gate 2137*7c478bd9Sstevel@tonic-gate /* 2138*7c478bd9Sstevel@tonic-gate * cte_remove_listener 2139*7c478bd9Sstevel@tonic-gate * 2140*7c478bd9Sstevel@tonic-gate * Remove a listener from an event queue. No other queue activities 2141*7c478bd9Sstevel@tonic-gate * (e.g. cte_get event) may be in progress at this endpoint when this 2142*7c478bd9Sstevel@tonic-gate * is called. 2143*7c478bd9Sstevel@tonic-gate */ 2144*7c478bd9Sstevel@tonic-gate void 2145*7c478bd9Sstevel@tonic-gate cte_remove_listener(ct_listener_t *l) 2146*7c478bd9Sstevel@tonic-gate { 2147*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue; 2148*7c478bd9Sstevel@tonic-gate ct_kevent_t *e; 2149*7c478bd9Sstevel@tonic-gate 2150*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2151*7c478bd9Sstevel@tonic-gate 2152*7c478bd9Sstevel@tonic-gate ASSERT((l->ctl_flags & (CTLF_COPYOUT|CTLF_RESET)) == 0); 2153*7c478bd9Sstevel@tonic-gate 2154*7c478bd9Sstevel@tonic-gate if ((e = l->ctl_position) != NULL) 2155*7c478bd9Sstevel@tonic-gate cte_qrele(q, l, e); 2156*7c478bd9Sstevel@tonic-gate else 2157*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_tail, l); 2158*7c478bd9Sstevel@tonic-gate l->ctl_position = NULL; 2159*7c478bd9Sstevel@tonic-gate 2160*7c478bd9Sstevel@tonic-gate q->ctq_nlisteners--; 2161*7c478bd9Sstevel@tonic-gate list_remove(&q->ctq_listeners, l); 2162*7c478bd9Sstevel@tonic-gate 2163*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE) 2164*7c478bd9Sstevel@tonic-gate q->ctq_nreliable--; 2165*7c478bd9Sstevel@tonic-gate 2166*7c478bd9Sstevel@tonic-gate /* 2167*7c478bd9Sstevel@tonic-gate * If we are a the last listener of a dead reference counted 2168*7c478bd9Sstevel@tonic-gate * queue (i.e. a process bundle) we free it. Otherwise we just 2169*7c478bd9Sstevel@tonic-gate * trim any events which may have been kept around for our 2170*7c478bd9Sstevel@tonic-gate * benefit. 2171*7c478bd9Sstevel@tonic-gate */ 2172*7c478bd9Sstevel@tonic-gate if ((q->ctq_flags & CTQ_REFFED) && (q->ctq_flags & CTQ_DEAD) && 2173*7c478bd9Sstevel@tonic-gate (q->ctq_nlisteners == 0)) { 2174*7c478bd9Sstevel@tonic-gate cte_queue_destroy(q); 2175*7c478bd9Sstevel@tonic-gate } else { 2176*7c478bd9Sstevel@tonic-gate cte_trim(q, NULL); 2177*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2178*7c478bd9Sstevel@tonic-gate } 2179*7c478bd9Sstevel@tonic-gate } 2180*7c478bd9Sstevel@tonic-gate 2181*7c478bd9Sstevel@tonic-gate /* 2182*7c478bd9Sstevel@tonic-gate * cte_reset_listener 2183*7c478bd9Sstevel@tonic-gate * 2184*7c478bd9Sstevel@tonic-gate * Moves a listener's queue pointer to the beginning of the queue. 2185*7c478bd9Sstevel@tonic-gate */ 2186*7c478bd9Sstevel@tonic-gate void 2187*7c478bd9Sstevel@tonic-gate cte_reset_listener(ct_listener_t *l) 2188*7c478bd9Sstevel@tonic-gate { 2189*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue; 2190*7c478bd9Sstevel@tonic-gate 2191*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2192*7c478bd9Sstevel@tonic-gate 2193*7c478bd9Sstevel@tonic-gate /* 2194*7c478bd9Sstevel@tonic-gate * We allow an asynchronous reset because it doesn't make a 2195*7c478bd9Sstevel@tonic-gate * whole lot of sense to make reset block or fail. We already 2196*7c478bd9Sstevel@tonic-gate * have most of the mechanism needed thanks to queue trimming, 2197*7c478bd9Sstevel@tonic-gate * so implementing it isn't a big deal. 2198*7c478bd9Sstevel@tonic-gate */ 2199*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_COPYOUT) 2200*7c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_RESET; 2201*7c478bd9Sstevel@tonic-gate 2202*7c478bd9Sstevel@tonic-gate (void) cte_qmove(q, l, list_head(&q->ctq_events)); 2203*7c478bd9Sstevel@tonic-gate 2204*7c478bd9Sstevel@tonic-gate /* 2205*7c478bd9Sstevel@tonic-gate * Inform blocked readers. 2206*7c478bd9Sstevel@tonic-gate */ 2207*7c478bd9Sstevel@tonic-gate cv_broadcast(&l->ctl_cv); 2208*7c478bd9Sstevel@tonic-gate pollwakeup(&l->ctl_pollhead, POLLIN); 2209*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2210*7c478bd9Sstevel@tonic-gate } 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate /* 2213*7c478bd9Sstevel@tonic-gate * cte_next_event 2214*7c478bd9Sstevel@tonic-gate * 2215*7c478bd9Sstevel@tonic-gate * Moves the event pointer for the specified listener to the next event 2216*7c478bd9Sstevel@tonic-gate * on the queue. To avoid races, this movement only occurs if the 2217*7c478bd9Sstevel@tonic-gate * specified event id matches that of the current event. This is used 2218*7c478bd9Sstevel@tonic-gate * primarily to skip events that have been read but whose extended data 2219*7c478bd9Sstevel@tonic-gate * haven't been copied out. 2220*7c478bd9Sstevel@tonic-gate */ 2221*7c478bd9Sstevel@tonic-gate int 2222*7c478bd9Sstevel@tonic-gate cte_next_event(ct_listener_t *l, uint64_t id) 2223*7c478bd9Sstevel@tonic-gate { 2224*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue; 2225*7c478bd9Sstevel@tonic-gate ct_kevent_t *old; 2226*7c478bd9Sstevel@tonic-gate 2227*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2228*7c478bd9Sstevel@tonic-gate 2229*7c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_COPYOUT) 2230*7c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_RESET; 2231*7c478bd9Sstevel@tonic-gate 2232*7c478bd9Sstevel@tonic-gate if (((old = l->ctl_position) != NULL) && (old->cte_id == id)) 2233*7c478bd9Sstevel@tonic-gate (void) cte_qmove(q, l, list_next(&q->ctq_events, old)); 2234*7c478bd9Sstevel@tonic-gate 2235*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2236*7c478bd9Sstevel@tonic-gate 2237*7c478bd9Sstevel@tonic-gate return (0); 2238*7c478bd9Sstevel@tonic-gate } 2239*7c478bd9Sstevel@tonic-gate 2240*7c478bd9Sstevel@tonic-gate /* 2241*7c478bd9Sstevel@tonic-gate * cte_get_event 2242*7c478bd9Sstevel@tonic-gate * 2243*7c478bd9Sstevel@tonic-gate * Reads an event from an event endpoint. If "nonblock" is clear, we 2244*7c478bd9Sstevel@tonic-gate * block until a suitable event is ready. If "crit" is set, we only 2245*7c478bd9Sstevel@tonic-gate * read critical events. Note that while "cr" is the caller's cred, 2246*7c478bd9Sstevel@tonic-gate * "zuniqid" is the unique id of the zone the calling contract 2247*7c478bd9Sstevel@tonic-gate * filesystem was mounted in. 2248*7c478bd9Sstevel@tonic-gate */ 2249*7c478bd9Sstevel@tonic-gate int 2250*7c478bd9Sstevel@tonic-gate cte_get_event(ct_listener_t *l, int nonblock, void *uaddr, const cred_t *cr, 2251*7c478bd9Sstevel@tonic-gate uint64_t zuniqid, int crit) 2252*7c478bd9Sstevel@tonic-gate { 2253*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue; 2254*7c478bd9Sstevel@tonic-gate ct_kevent_t *temp; 2255*7c478bd9Sstevel@tonic-gate int result = 0; 2256*7c478bd9Sstevel@tonic-gate int partial = 0; 2257*7c478bd9Sstevel@tonic-gate size_t size, gsize, len; 2258*7c478bd9Sstevel@tonic-gate model_t mdl = get_udatamodel(); 2259*7c478bd9Sstevel@tonic-gate STRUCT_DECL(ct_event, ev); 2260*7c478bd9Sstevel@tonic-gate STRUCT_INIT(ev, mdl); 2261*7c478bd9Sstevel@tonic-gate 2262*7c478bd9Sstevel@tonic-gate /* 2263*7c478bd9Sstevel@tonic-gate * cte_qreadable checks for CTLF_COPYOUT as well as ensures 2264*7c478bd9Sstevel@tonic-gate * that there exists, and we are pointing to, an appropriate 2265*7c478bd9Sstevel@tonic-gate * event. It may temporarily drop ctq_lock, but that doesn't 2266*7c478bd9Sstevel@tonic-gate * really matter to us. 2267*7c478bd9Sstevel@tonic-gate */ 2268*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2269*7c478bd9Sstevel@tonic-gate while (cte_qreadable(q, l, cr, zuniqid, crit)) { 2270*7c478bd9Sstevel@tonic-gate if (nonblock) { 2271*7c478bd9Sstevel@tonic-gate result = EAGAIN; 2272*7c478bd9Sstevel@tonic-gate goto error; 2273*7c478bd9Sstevel@tonic-gate } 2274*7c478bd9Sstevel@tonic-gate if (q->ctq_flags & CTQ_DEAD) { 2275*7c478bd9Sstevel@tonic-gate result = EIDRM; 2276*7c478bd9Sstevel@tonic-gate goto error; 2277*7c478bd9Sstevel@tonic-gate } 2278*7c478bd9Sstevel@tonic-gate result = cv_wait_sig(&l->ctl_cv, &q->ctq_lock); 2279*7c478bd9Sstevel@tonic-gate if (result == 0) { 2280*7c478bd9Sstevel@tonic-gate result = EINTR; 2281*7c478bd9Sstevel@tonic-gate goto error; 2282*7c478bd9Sstevel@tonic-gate } 2283*7c478bd9Sstevel@tonic-gate } 2284*7c478bd9Sstevel@tonic-gate temp = l->ctl_position; 2285*7c478bd9Sstevel@tonic-gate cte_hold(temp); 2286*7c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_COPYOUT; 2287*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2288*7c478bd9Sstevel@tonic-gate 2289*7c478bd9Sstevel@tonic-gate /* 2290*7c478bd9Sstevel@tonic-gate * We now have an event. Copy in the user event structure to 2291*7c478bd9Sstevel@tonic-gate * see how much space we have to work with. 2292*7c478bd9Sstevel@tonic-gate */ 2293*7c478bd9Sstevel@tonic-gate result = copyin(uaddr, STRUCT_BUF(ev), STRUCT_SIZE(ev)); 2294*7c478bd9Sstevel@tonic-gate if (result) 2295*7c478bd9Sstevel@tonic-gate goto copyerr; 2296*7c478bd9Sstevel@tonic-gate 2297*7c478bd9Sstevel@tonic-gate /* 2298*7c478bd9Sstevel@tonic-gate * Determine what data we have and what the user should be 2299*7c478bd9Sstevel@tonic-gate * allowed to see. 2300*7c478bd9Sstevel@tonic-gate */ 2301*7c478bd9Sstevel@tonic-gate size = gsize = 0; 2302*7c478bd9Sstevel@tonic-gate if (temp->cte_data) { 2303*7c478bd9Sstevel@tonic-gate VERIFY(nvlist_size(temp->cte_data, &size, 2304*7c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE) == 0); 2305*7c478bd9Sstevel@tonic-gate ASSERT(size != 0); 2306*7c478bd9Sstevel@tonic-gate } 2307*7c478bd9Sstevel@tonic-gate if (zuniqid == GLOBAL_ZONEUNIQID && temp->cte_gdata) { 2308*7c478bd9Sstevel@tonic-gate VERIFY(nvlist_size(temp->cte_gdata, &gsize, 2309*7c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE) == 0); 2310*7c478bd9Sstevel@tonic-gate ASSERT(gsize != 0); 2311*7c478bd9Sstevel@tonic-gate } 2312*7c478bd9Sstevel@tonic-gate 2313*7c478bd9Sstevel@tonic-gate /* 2314*7c478bd9Sstevel@tonic-gate * If we have enough space, copy out the extended event data. 2315*7c478bd9Sstevel@tonic-gate */ 2316*7c478bd9Sstevel@tonic-gate len = size + gsize; 2317*7c478bd9Sstevel@tonic-gate if (len) { 2318*7c478bd9Sstevel@tonic-gate if (STRUCT_FGET(ev, ctev_nbytes) >= len) { 2319*7c478bd9Sstevel@tonic-gate char *buf = kmem_alloc(len, KM_SLEEP); 2320*7c478bd9Sstevel@tonic-gate 2321*7c478bd9Sstevel@tonic-gate if (size) 2322*7c478bd9Sstevel@tonic-gate VERIFY(nvlist_pack(temp->cte_data, &buf, &size, 2323*7c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP) == 0); 2324*7c478bd9Sstevel@tonic-gate if (gsize) { 2325*7c478bd9Sstevel@tonic-gate char *tmp = buf + size; 2326*7c478bd9Sstevel@tonic-gate 2327*7c478bd9Sstevel@tonic-gate VERIFY(nvlist_pack(temp->cte_gdata, &tmp, 2328*7c478bd9Sstevel@tonic-gate &gsize, NV_ENCODE_NATIVE, KM_SLEEP) == 0); 2329*7c478bd9Sstevel@tonic-gate } 2330*7c478bd9Sstevel@tonic-gate 2331*7c478bd9Sstevel@tonic-gate /* This shouldn't have changed */ 2332*7c478bd9Sstevel@tonic-gate ASSERT(size + gsize == len); 2333*7c478bd9Sstevel@tonic-gate result = copyout(buf, STRUCT_FGETP(ev, ctev_buffer), 2334*7c478bd9Sstevel@tonic-gate len); 2335*7c478bd9Sstevel@tonic-gate kmem_free(buf, len); 2336*7c478bd9Sstevel@tonic-gate if (result) 2337*7c478bd9Sstevel@tonic-gate goto copyerr; 2338*7c478bd9Sstevel@tonic-gate } else { 2339*7c478bd9Sstevel@tonic-gate partial = 1; 2340*7c478bd9Sstevel@tonic-gate } 2341*7c478bd9Sstevel@tonic-gate } 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate /* 2344*7c478bd9Sstevel@tonic-gate * Copy out the common event data. 2345*7c478bd9Sstevel@tonic-gate */ 2346*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_id, temp->cte_contract->ct_id); 2347*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_evid, temp->cte_id); 2348*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_cttype, 2349*7c478bd9Sstevel@tonic-gate temp->cte_contract->ct_type->ct_type_index); 2350*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_flags, temp->cte_flags & (CTE_ACK|CTE_INFO)); 2351*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_type, temp->cte_type); 2352*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_nbytes, len); 2353*7c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_goffset, size); 2354*7c478bd9Sstevel@tonic-gate result = copyout(STRUCT_BUF(ev), uaddr, STRUCT_SIZE(ev)); 2355*7c478bd9Sstevel@tonic-gate 2356*7c478bd9Sstevel@tonic-gate copyerr: 2357*7c478bd9Sstevel@tonic-gate /* 2358*7c478bd9Sstevel@tonic-gate * Only move our location in the queue if all copyouts were 2359*7c478bd9Sstevel@tonic-gate * successful, the caller provided enough space for the entire 2360*7c478bd9Sstevel@tonic-gate * event, and our endpoint wasn't reset or otherwise moved by 2361*7c478bd9Sstevel@tonic-gate * another thread. 2362*7c478bd9Sstevel@tonic-gate */ 2363*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2364*7c478bd9Sstevel@tonic-gate if (result) 2365*7c478bd9Sstevel@tonic-gate result = EFAULT; 2366*7c478bd9Sstevel@tonic-gate else if (!partial && ((l->ctl_flags & CTLF_RESET) == 0) && 2367*7c478bd9Sstevel@tonic-gate (l->ctl_position == temp)) 2368*7c478bd9Sstevel@tonic-gate (void) cte_qmove(q, l, list_next(&q->ctq_events, temp)); 2369*7c478bd9Sstevel@tonic-gate l->ctl_flags &= ~(CTLF_COPYOUT|CTLF_RESET); 2370*7c478bd9Sstevel@tonic-gate /* 2371*7c478bd9Sstevel@tonic-gate * Signal any readers blocked on our CTLF_COPYOUT. 2372*7c478bd9Sstevel@tonic-gate */ 2373*7c478bd9Sstevel@tonic-gate cv_signal(&l->ctl_cv); 2374*7c478bd9Sstevel@tonic-gate cte_rele(temp); 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate error: 2377*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2378*7c478bd9Sstevel@tonic-gate return (result); 2379*7c478bd9Sstevel@tonic-gate } 2380*7c478bd9Sstevel@tonic-gate 2381*7c478bd9Sstevel@tonic-gate /* 2382*7c478bd9Sstevel@tonic-gate * cte_set_reliable 2383*7c478bd9Sstevel@tonic-gate * 2384*7c478bd9Sstevel@tonic-gate * Requests that events be reliably delivered to an event endpoint. 2385*7c478bd9Sstevel@tonic-gate * Unread informative and acknowledged critical events will not be 2386*7c478bd9Sstevel@tonic-gate * removed from the queue until this listener reads or skips them. 2387*7c478bd9Sstevel@tonic-gate * Because a listener could maliciously request reliable delivery and 2388*7c478bd9Sstevel@tonic-gate * then do nothing, this requires that PRIV_CONTRACT_EVENT be in the 2389*7c478bd9Sstevel@tonic-gate * caller's effective set. 2390*7c478bd9Sstevel@tonic-gate */ 2391*7c478bd9Sstevel@tonic-gate int 2392*7c478bd9Sstevel@tonic-gate cte_set_reliable(ct_listener_t *l, const cred_t *cr) 2393*7c478bd9Sstevel@tonic-gate { 2394*7c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue; 2395*7c478bd9Sstevel@tonic-gate int error; 2396*7c478bd9Sstevel@tonic-gate 2397*7c478bd9Sstevel@tonic-gate if ((error = secpolicy_contract_event(cr)) != 0) 2398*7c478bd9Sstevel@tonic-gate return (error); 2399*7c478bd9Sstevel@tonic-gate 2400*7c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock); 2401*7c478bd9Sstevel@tonic-gate if ((l->ctl_flags & CTLF_RELIABLE) == 0) { 2402*7c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_RELIABLE; 2403*7c478bd9Sstevel@tonic-gate q->ctq_nreliable++; 2404*7c478bd9Sstevel@tonic-gate if (l->ctl_position != NULL) 2405*7c478bd9Sstevel@tonic-gate l->ctl_position->cte_nodes[q->ctq_listno]. 2406*7c478bd9Sstevel@tonic-gate ctm_nreliable++; 2407*7c478bd9Sstevel@tonic-gate } 2408*7c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock); 2409*7c478bd9Sstevel@tonic-gate 2410*7c478bd9Sstevel@tonic-gate return (0); 2411*7c478bd9Sstevel@tonic-gate } 2412