xref: /titanic_53/usr/src/uts/common/os/contract.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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