17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
525e8c5aaSvikram * Common Development and Distribution License (the "License").
625e8c5aaSvikram * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
227b209c2cSacruz * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
25ade42b55SSebastien Roy /*
26ade42b55SSebastien Roy * Copyright (c) 2017 by Delphix. All rights reserved.
27ade42b55SSebastien Roy */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * Contracts
317c478bd9Sstevel@tonic-gate * ---------
327c478bd9Sstevel@tonic-gate *
337c478bd9Sstevel@tonic-gate * Contracts are a primitive which enrich the relationships between
347c478bd9Sstevel@tonic-gate * processes and system resources. The primary purpose of contracts is
357c478bd9Sstevel@tonic-gate * to provide a means for the system to negotiate the departure from a
367c478bd9Sstevel@tonic-gate * binding relationship (e.g. pages locked in memory or a thread bound
377c478bd9Sstevel@tonic-gate * to processor), but they can also be used as a purely asynchronous
387c478bd9Sstevel@tonic-gate * error reporting mechanism as they are with process contracts.
397c478bd9Sstevel@tonic-gate *
407c478bd9Sstevel@tonic-gate * More information on how one interfaces with contracts and what
417c478bd9Sstevel@tonic-gate * contracts can do for you can be found in:
427c478bd9Sstevel@tonic-gate * PSARC 2003/193 Solaris Contracts
437c478bd9Sstevel@tonic-gate * PSARC 2004/460 Contracts addendum
447c478bd9Sstevel@tonic-gate *
457c478bd9Sstevel@tonic-gate * This file contains the core contracts framework. By itself it is
467c478bd9Sstevel@tonic-gate * useless: it depends the contracts filesystem (ctfs) to provide an
477c478bd9Sstevel@tonic-gate * interface to user processes and individual contract types to
487c478bd9Sstevel@tonic-gate * implement the process/resource relationships.
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * Data structure overview
517c478bd9Sstevel@tonic-gate * -----------------------
527c478bd9Sstevel@tonic-gate *
537c478bd9Sstevel@tonic-gate * A contract is represented by a contract_t, which itself points to an
547c478bd9Sstevel@tonic-gate * encapsulating contract-type specific contract object. A contract_t
557c478bd9Sstevel@tonic-gate * contains the contract's static identity (including its terms), its
567c478bd9Sstevel@tonic-gate * linkage to various bookkeeping structures, the contract-specific
577c478bd9Sstevel@tonic-gate * event queue, and a reference count.
587c478bd9Sstevel@tonic-gate *
597c478bd9Sstevel@tonic-gate * A contract template is represented by a ct_template_t, which, like a
607c478bd9Sstevel@tonic-gate * contract, points to an encapsulating contract-type specific template
617c478bd9Sstevel@tonic-gate * object. A ct_template_t contains the template's terms.
627c478bd9Sstevel@tonic-gate *
637c478bd9Sstevel@tonic-gate * An event queue is represented by a ct_equeue_t, and consists of a
647c478bd9Sstevel@tonic-gate * list of events, a list of listeners, and a list of listeners who are
657c478bd9Sstevel@tonic-gate * waiting for new events (affectionately referred to as "tail
667c478bd9Sstevel@tonic-gate * listeners"). There are three queue types, defined by ct_listnum_t
677c478bd9Sstevel@tonic-gate * (an enum). An event may be on one of each type of queue
687c478bd9Sstevel@tonic-gate * simultaneously; the list linkage used by a queue is determined by
697c478bd9Sstevel@tonic-gate * its type.
707c478bd9Sstevel@tonic-gate *
717c478bd9Sstevel@tonic-gate * An event is represented by a ct_kevent_t, which contains mostly
727c478bd9Sstevel@tonic-gate * static event data (e.g. id, payload). It also has an array of
737c478bd9Sstevel@tonic-gate * ct_member_t structures, each of which contains a list_node_t and
747c478bd9Sstevel@tonic-gate * represent the event's linkage in a specific event queue.
757c478bd9Sstevel@tonic-gate *
767c478bd9Sstevel@tonic-gate * Each open of an event endpoint results in the creation of a new
777c478bd9Sstevel@tonic-gate * listener, represented by a ct_listener_t. In addition to linkage
787c478bd9Sstevel@tonic-gate * into the aforementioned lists in the event_queue, a ct_listener_t
797c478bd9Sstevel@tonic-gate * contains a pointer to the ct_kevent_t it is currently positioned at
807c478bd9Sstevel@tonic-gate * as well as a set of status flags and other administrative data.
817c478bd9Sstevel@tonic-gate *
827c478bd9Sstevel@tonic-gate * Each process has a list of contracts it owns, p_ct_held; a pointer
837c478bd9Sstevel@tonic-gate * to the process contract it is a member of, p_ct_process; the linkage
847c478bd9Sstevel@tonic-gate * for that membership, p_ct_member; and an array of event queue
857c478bd9Sstevel@tonic-gate * structures representing the process bundle queues.
867c478bd9Sstevel@tonic-gate *
877c478bd9Sstevel@tonic-gate * Each LWP has an array of its active templates, lwp_ct_active; and
887c478bd9Sstevel@tonic-gate * the most recently created contracts, lwp_ct_latest.
897c478bd9Sstevel@tonic-gate *
907c478bd9Sstevel@tonic-gate * A process contract has a list of member processes and a list of
917c478bd9Sstevel@tonic-gate * inherited contracts.
927c478bd9Sstevel@tonic-gate *
937c478bd9Sstevel@tonic-gate * There is a system-wide list of all contracts, as well as per-type
947c478bd9Sstevel@tonic-gate * lists of contracts.
957c478bd9Sstevel@tonic-gate *
967c478bd9Sstevel@tonic-gate * Lock ordering overview
977c478bd9Sstevel@tonic-gate * ----------------------
987c478bd9Sstevel@tonic-gate *
997c478bd9Sstevel@tonic-gate * Locks at the top are taken first:
1007c478bd9Sstevel@tonic-gate *
1017c478bd9Sstevel@tonic-gate * ct_evtlock
1027c478bd9Sstevel@tonic-gate * regent ct_lock
1037c478bd9Sstevel@tonic-gate * member ct_lock
1047c478bd9Sstevel@tonic-gate * pidlock
1057c478bd9Sstevel@tonic-gate * p_lock
1067c478bd9Sstevel@tonic-gate * contract ctq_lock contract_lock
1077c478bd9Sstevel@tonic-gate * pbundle ctq_lock
1087c478bd9Sstevel@tonic-gate * cte_lock
1097c478bd9Sstevel@tonic-gate * ct_reflock
1107c478bd9Sstevel@tonic-gate *
1117c478bd9Sstevel@tonic-gate * contract_lock and ctq_lock/cte_lock are not currently taken at the
1127c478bd9Sstevel@tonic-gate * same time.
1137c478bd9Sstevel@tonic-gate *
1147c478bd9Sstevel@tonic-gate * Reference counting and locking
1157c478bd9Sstevel@tonic-gate * ------------------------------
1167c478bd9Sstevel@tonic-gate *
1177c478bd9Sstevel@tonic-gate * A contract has a reference count, protected by ct_reflock.
1187c478bd9Sstevel@tonic-gate * (ct_reflock is also used in a couple other places where atomic
1197c478bd9Sstevel@tonic-gate * access to a variable is needed in an innermost context). A process
1207c478bd9Sstevel@tonic-gate * maintains a hold on each contract it owns. A process contract has a
1217c478bd9Sstevel@tonic-gate * hold on each contract is has inherited. Each event has a hold on
1227c478bd9Sstevel@tonic-gate * the contract which generated it. Process contract templates have
1237c478bd9Sstevel@tonic-gate * holds on the contracts referred to by their transfer terms. CTFS
1247c478bd9Sstevel@tonic-gate * contract directory nodes have holds on contracts. Lastly, various
1257c478bd9Sstevel@tonic-gate * code paths may temporarily take holds on contracts to prevent them
1267c478bd9Sstevel@tonic-gate * from disappearing while other processing is going on. It is
1277c478bd9Sstevel@tonic-gate * important to note that the global contract lists do not hold
1287c478bd9Sstevel@tonic-gate * references on contracts; a contract is removed from these structures
1297c478bd9Sstevel@tonic-gate * atomically with the release of its last reference.
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * At a given point in time, a contract can either be owned by a
1327c478bd9Sstevel@tonic-gate * process, inherited by a regent process contract, or orphaned. A
1337c478bd9Sstevel@tonic-gate * contract_t's owner and regent pointers, ct_owner and ct_regent, are
1347c478bd9Sstevel@tonic-gate * protected by its ct_lock. The linkage in the holder's (holder =
1357c478bd9Sstevel@tonic-gate * owner or regent) list of contracts, ct_ctlist, is protected by
1367c478bd9Sstevel@tonic-gate * whatever lock protects the holder's data structure. In order for
1377c478bd9Sstevel@tonic-gate * these two directions to remain consistent, changing the holder of a
1387c478bd9Sstevel@tonic-gate * contract requires that both locks be held.
1397c478bd9Sstevel@tonic-gate *
1407c478bd9Sstevel@tonic-gate * Events also have reference counts. There is one hold on an event
1417c478bd9Sstevel@tonic-gate * per queue it is present on, in addition to those needed for the
1427c478bd9Sstevel@tonic-gate * usual sundry reasons. Individual listeners are associated with
1437c478bd9Sstevel@tonic-gate * specific queues, and increase a queue-specific reference count
1447c478bd9Sstevel@tonic-gate * stored in the ct_member_t structure.
1457c478bd9Sstevel@tonic-gate *
1467c478bd9Sstevel@tonic-gate * The dynamic contents of an event (reference count and flags) are
1477c478bd9Sstevel@tonic-gate * protected by its cte_lock, while the contents of the embedded
1487c478bd9Sstevel@tonic-gate * ct_member_t structures are protected by the locks of the queues they
1497c478bd9Sstevel@tonic-gate * are linked into. A ct_listener_t's contents are also protected by
1507c478bd9Sstevel@tonic-gate * its event queue's ctq_lock.
1517c478bd9Sstevel@tonic-gate *
1527c478bd9Sstevel@tonic-gate * Resource controls
1537c478bd9Sstevel@tonic-gate * -----------------
1547c478bd9Sstevel@tonic-gate *
1557c478bd9Sstevel@tonic-gate * Control: project.max-contracts (rc_project_contract)
1567c478bd9Sstevel@tonic-gate * Description: Maximum number of contracts allowed a project.
1577c478bd9Sstevel@tonic-gate *
1587c478bd9Sstevel@tonic-gate * When a contract is created, the project's allocation is tested and
1597c478bd9Sstevel@tonic-gate * (assuming success) increased. When the last reference to a
1607c478bd9Sstevel@tonic-gate * contract is released, the creating project's allocation is
1617c478bd9Sstevel@tonic-gate * decreased.
1627c478bd9Sstevel@tonic-gate */
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
1657c478bd9Sstevel@tonic-gate #include <sys/debug.h>
1667c478bd9Sstevel@tonic-gate #include <sys/types.h>
1677c478bd9Sstevel@tonic-gate #include <sys/param.h>
1687c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
1697c478bd9Sstevel@tonic-gate #include <sys/thread.h>
1707c478bd9Sstevel@tonic-gate #include <sys/id_space.h>
1717c478bd9Sstevel@tonic-gate #include <sys/avl.h>
1727c478bd9Sstevel@tonic-gate #include <sys/list.h>
1737c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
1747c478bd9Sstevel@tonic-gate #include <sys/proc.h>
175c5a9a4fcSAntonello Cruz #include <sys/ctfs.h>
1767c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h>
1777c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
17825e8c5aaSvikram #include <sys/dditypes.h>
17925e8c5aaSvikram #include <sys/contract/device_impl.h>
1807c478bd9Sstevel@tonic-gate #include <sys/systm.h>
1817c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
1827c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
1837c478bd9Sstevel@tonic-gate #include <sys/model.h>
1847c478bd9Sstevel@tonic-gate #include <sys/policy.h>
1857c478bd9Sstevel@tonic-gate #include <sys/zone.h>
1867c478bd9Sstevel@tonic-gate #include <sys/task.h>
18725e8c5aaSvikram #include <sys/ddi.h>
18825e8c5aaSvikram #include <sys/sunddi.h>
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_project_contract;
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate static id_space_t *contract_ids;
1937c478bd9Sstevel@tonic-gate static avl_tree_t contract_avl;
1947c478bd9Sstevel@tonic-gate static kmutex_t contract_lock;
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate int ct_ntypes = CTT_MAXTYPE;
1977c478bd9Sstevel@tonic-gate static ct_type_t *ct_types_static[CTT_MAXTYPE];
1987c478bd9Sstevel@tonic-gate ct_type_t **ct_types = ct_types_static;
19925e8c5aaSvikram int ct_debug;
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate static void cte_queue_create(ct_equeue_t *, ct_listnum_t, int, int);
2027c478bd9Sstevel@tonic-gate static void cte_queue_destroy(ct_equeue_t *);
2037c478bd9Sstevel@tonic-gate static void cte_queue_drain(ct_equeue_t *, int);
2047c478bd9Sstevel@tonic-gate static void cte_trim(ct_equeue_t *, contract_t *);
2057c478bd9Sstevel@tonic-gate static void cte_copy(ct_equeue_t *, ct_equeue_t *);
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate * contract_compar
2097c478bd9Sstevel@tonic-gate *
2107c478bd9Sstevel@tonic-gate * A contract comparator which sorts on contract ID.
2117c478bd9Sstevel@tonic-gate */
2127c478bd9Sstevel@tonic-gate int
contract_compar(const void * x,const void * y)2137c478bd9Sstevel@tonic-gate contract_compar(const void *x, const void *y)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate const contract_t *ct1 = x;
2167c478bd9Sstevel@tonic-gate const contract_t *ct2 = y;
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate if (ct1->ct_id < ct2->ct_id)
2197c478bd9Sstevel@tonic-gate return (-1);
2207c478bd9Sstevel@tonic-gate if (ct1->ct_id > ct2->ct_id)
2217c478bd9Sstevel@tonic-gate return (1);
2227c478bd9Sstevel@tonic-gate return (0);
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate * contract_init
2277c478bd9Sstevel@tonic-gate *
2287c478bd9Sstevel@tonic-gate * Initializes the contract subsystem, the specific contract types, and
2297c478bd9Sstevel@tonic-gate * process 0.
2307c478bd9Sstevel@tonic-gate */
2317c478bd9Sstevel@tonic-gate void
contract_init(void)2327c478bd9Sstevel@tonic-gate contract_init(void)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate * Initialize contract subsystem.
2367c478bd9Sstevel@tonic-gate */
2377c478bd9Sstevel@tonic-gate contract_ids = id_space_create("contracts", 1, INT_MAX);
2387c478bd9Sstevel@tonic-gate avl_create(&contract_avl, contract_compar, sizeof (contract_t),
2397c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_ctavl));
2407c478bd9Sstevel@tonic-gate mutex_init(&contract_lock, NULL, MUTEX_DEFAULT, NULL);
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate * Initialize contract types.
2447c478bd9Sstevel@tonic-gate */
2457c478bd9Sstevel@tonic-gate contract_process_init();
24625e8c5aaSvikram contract_device_init();
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate * Initialize p0/lwp0 contract state.
2507c478bd9Sstevel@tonic-gate */
2517c478bd9Sstevel@tonic-gate avl_create(&p0.p_ct_held, contract_compar, sizeof (contract_t),
2527c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_ctlist));
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate /*
2567c478bd9Sstevel@tonic-gate * contract_dtor
2577c478bd9Sstevel@tonic-gate *
2587c478bd9Sstevel@tonic-gate * Performs basic destruction of the common portions of a contract.
2597c478bd9Sstevel@tonic-gate * Called from the failure path of contract_ctor and from
2607c478bd9Sstevel@tonic-gate * contract_rele.
2617c478bd9Sstevel@tonic-gate */
2627c478bd9Sstevel@tonic-gate static void
contract_dtor(contract_t * ct)2637c478bd9Sstevel@tonic-gate contract_dtor(contract_t *ct)
2647c478bd9Sstevel@tonic-gate {
2657c478bd9Sstevel@tonic-gate cte_queue_destroy(&ct->ct_events);
2667c478bd9Sstevel@tonic-gate list_destroy(&ct->ct_vnodes);
2677c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_reflock);
2687c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_lock);
2697c478bd9Sstevel@tonic-gate mutex_destroy(&ct->ct_evtlock);
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate * contract_ctor
2747c478bd9Sstevel@tonic-gate *
2757c478bd9Sstevel@tonic-gate * Called by a contract type to initialize a contract. Fails if the
2767c478bd9Sstevel@tonic-gate * max-contract resource control would have been exceeded. After a
2777c478bd9Sstevel@tonic-gate * successful call to contract_ctor, the contract is unlocked and
2787c478bd9Sstevel@tonic-gate * visible in all namespaces; any type-specific initialization should
2797c478bd9Sstevel@tonic-gate * be completed before calling contract_ctor. Returns 0 on success.
2807c478bd9Sstevel@tonic-gate *
2817c478bd9Sstevel@tonic-gate * Because not all callers can tolerate failure, a 0 value for canfail
2827c478bd9Sstevel@tonic-gate * instructs contract_ctor to ignore the project.max-contracts resource
2837c478bd9Sstevel@tonic-gate * control. Obviously, this "out" should only be employed by callers
2847c478bd9Sstevel@tonic-gate * who are sufficiently constrained in other ways (e.g. newproc).
2857c478bd9Sstevel@tonic-gate */
2867c478bd9Sstevel@tonic-gate int
contract_ctor(contract_t * ct,ct_type_t * type,ct_template_t * tmpl,void * data,ctflags_t flags,proc_t * author,int canfail)2877c478bd9Sstevel@tonic-gate contract_ctor(contract_t *ct, ct_type_t *type, ct_template_t *tmpl, void *data,
2887c478bd9Sstevel@tonic-gate ctflags_t flags, proc_t *author, int canfail)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate avl_index_t where;
2917c478bd9Sstevel@tonic-gate klwp_t *curlwp = ttolwp(curthread);
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate ASSERT(author == curproc);
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_lock, NULL, MUTEX_DEFAULT, NULL);
2967c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_reflock, NULL, MUTEX_DEFAULT, NULL);
2977c478bd9Sstevel@tonic-gate mutex_init(&ct->ct_evtlock, NULL, MUTEX_DEFAULT, NULL);
2987c478bd9Sstevel@tonic-gate ct->ct_id = id_alloc(contract_ids);
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate cte_queue_create(&ct->ct_events, CTEL_CONTRACT, 20, 0);
3017c478bd9Sstevel@tonic-gate list_create(&ct->ct_vnodes, sizeof (contract_vnode_t),
3027c478bd9Sstevel@tonic-gate offsetof(contract_vnode_t, ctv_node));
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate * Instance data
3067c478bd9Sstevel@tonic-gate */
3077c478bd9Sstevel@tonic-gate ct->ct_ref = 2; /* one for the holder, one for "latest" */
3087c478bd9Sstevel@tonic-gate ct->ct_cuid = crgetuid(CRED());
3097c478bd9Sstevel@tonic-gate ct->ct_type = type;
3107c478bd9Sstevel@tonic-gate ct->ct_data = data;
3117c478bd9Sstevel@tonic-gate gethrestime(&ct->ct_ctime);
3127c478bd9Sstevel@tonic-gate ct->ct_state = CTS_OWNED;
3137c478bd9Sstevel@tonic-gate ct->ct_flags = flags;
3147c478bd9Sstevel@tonic-gate ct->ct_regent = author->p_ct_process ?
3157c478bd9Sstevel@tonic-gate &author->p_ct_process->conp_contract : NULL;
3167c478bd9Sstevel@tonic-gate ct->ct_ev_info = tmpl->ctmpl_ev_info;
3177c478bd9Sstevel@tonic-gate ct->ct_ev_crit = tmpl->ctmpl_ev_crit;
3187c478bd9Sstevel@tonic-gate ct->ct_cookie = tmpl->ctmpl_cookie;
3197c478bd9Sstevel@tonic-gate ct->ct_owner = author;
32025e8c5aaSvikram ct->ct_ntime.ctm_total = -1;
32125e8c5aaSvikram ct->ct_qtime.ctm_total = -1;
32225e8c5aaSvikram ct->ct_nevent = NULL;
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate * Test project.max-contracts.
3267c478bd9Sstevel@tonic-gate */
3277c478bd9Sstevel@tonic-gate mutex_enter(&author->p_lock);
3287c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
3297c478bd9Sstevel@tonic-gate if (canfail && rctl_test(rc_project_contract,
3307c478bd9Sstevel@tonic-gate author->p_task->tk_proj->kpj_rctls, author, 1,
3317c478bd9Sstevel@tonic-gate RCA_SAFE) & RCT_DENY) {
3327c478bd9Sstevel@tonic-gate id_free(contract_ids, ct->ct_id);
3337c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
3347c478bd9Sstevel@tonic-gate mutex_exit(&author->p_lock);
3357c478bd9Sstevel@tonic-gate ct->ct_events.ctq_flags |= CTQ_DEAD;
3367c478bd9Sstevel@tonic-gate contract_dtor(ct);
3377c478bd9Sstevel@tonic-gate return (1);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate ct->ct_proj = author->p_task->tk_proj;
3407c478bd9Sstevel@tonic-gate ct->ct_proj->kpj_data.kpd_contract++;
3417c478bd9Sstevel@tonic-gate (void) project_hold(ct->ct_proj);
3427c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate * Insert into holder's avl of contracts.
3467c478bd9Sstevel@tonic-gate * We use an avl not because order is important, but because
3477c478bd9Sstevel@tonic-gate * readdir of /proc/contracts requires we be able to use a
3487c478bd9Sstevel@tonic-gate * scalar as an index into the process's list of contracts
3497c478bd9Sstevel@tonic-gate */
3507c478bd9Sstevel@tonic-gate ct->ct_zoneid = author->p_zone->zone_id;
3517c478bd9Sstevel@tonic-gate ct->ct_czuniqid = ct->ct_mzuniqid = author->p_zone->zone_uniqid;
3527c478bd9Sstevel@tonic-gate VERIFY(avl_find(&author->p_ct_held, ct, &where) == NULL);
3537c478bd9Sstevel@tonic-gate avl_insert(&author->p_ct_held, ct, where);
3547c478bd9Sstevel@tonic-gate mutex_exit(&author->p_lock);
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate * Insert into global contract AVL
3587c478bd9Sstevel@tonic-gate */
3597c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
3607c478bd9Sstevel@tonic-gate VERIFY(avl_find(&contract_avl, ct, &where) == NULL);
3617c478bd9Sstevel@tonic-gate avl_insert(&contract_avl, ct, where);
3627c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate * Insert into type AVL
3667c478bd9Sstevel@tonic-gate */
3677c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock);
3687c478bd9Sstevel@tonic-gate VERIFY(avl_find(&type->ct_type_avl, ct, &where) == NULL);
3697c478bd9Sstevel@tonic-gate avl_insert(&type->ct_type_avl, ct, where);
3707c478bd9Sstevel@tonic-gate type->ct_type_timestruc = ct->ct_ctime;
3717c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock);
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate if (curlwp->lwp_ct_latest[type->ct_type_index])
3747c478bd9Sstevel@tonic-gate contract_rele(curlwp->lwp_ct_latest[type->ct_type_index]);
3757c478bd9Sstevel@tonic-gate curlwp->lwp_ct_latest[type->ct_type_index] = ct;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate return (0);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate * contract_rele
3827c478bd9Sstevel@tonic-gate *
3837c478bd9Sstevel@tonic-gate * Releases a reference to a contract. If the caller had the last
3847c478bd9Sstevel@tonic-gate * reference, the contract is removed from all namespaces, its
3857c478bd9Sstevel@tonic-gate * allocation against the max-contracts resource control is released,
3867c478bd9Sstevel@tonic-gate * and the contract type's free entry point is invoked for any
3877c478bd9Sstevel@tonic-gate * type-specific deconstruction and to (presumably) free the object.
3887c478bd9Sstevel@tonic-gate */
3897c478bd9Sstevel@tonic-gate void
contract_rele(contract_t * ct)3907c478bd9Sstevel@tonic-gate contract_rele(contract_t *ct)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate uint64_t nref;
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock);
3957c478bd9Sstevel@tonic-gate ASSERT(ct->ct_ref > 0);
3967c478bd9Sstevel@tonic-gate nref = --ct->ct_ref;
3977c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock);
3987c478bd9Sstevel@tonic-gate if (nref == 0) {
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * ct_owner is cleared when it drops its reference.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner == NULL);
4037c478bd9Sstevel@tonic-gate ASSERT(ct->ct_evcnt == 0);
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate * Remove from global contract AVL
4077c478bd9Sstevel@tonic-gate */
4087c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
4097c478bd9Sstevel@tonic-gate avl_remove(&contract_avl, ct);
4107c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate * Remove from type AVL
4147c478bd9Sstevel@tonic-gate */
4157c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_type->ct_type_lock);
4167c478bd9Sstevel@tonic-gate avl_remove(&ct->ct_type->ct_type_avl, ct);
4177c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_type->ct_type_lock);
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * Release the contract's ID
4217c478bd9Sstevel@tonic-gate */
4227c478bd9Sstevel@tonic-gate id_free(contract_ids, ct->ct_id);
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate * Release project hold
4267c478bd9Sstevel@tonic-gate */
4277c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
4287c478bd9Sstevel@tonic-gate ct->ct_proj->kpj_data.kpd_contract--;
4297c478bd9Sstevel@tonic-gate project_rele(ct->ct_proj);
4307c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate * Free the contract
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate contract_dtor(ct);
4367c478bd9Sstevel@tonic-gate ct->ct_type->ct_type_ops->contop_free(ct);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate * contract_hold
4427c478bd9Sstevel@tonic-gate *
4437c478bd9Sstevel@tonic-gate * Adds a reference to a contract
4447c478bd9Sstevel@tonic-gate */
4457c478bd9Sstevel@tonic-gate void
contract_hold(contract_t * ct)4467c478bd9Sstevel@tonic-gate contract_hold(contract_t *ct)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock);
4497c478bd9Sstevel@tonic-gate ASSERT(ct->ct_ref < UINT64_MAX);
4507c478bd9Sstevel@tonic-gate ct->ct_ref++;
4517c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate * contract_getzuniqid
4567c478bd9Sstevel@tonic-gate *
4577c478bd9Sstevel@tonic-gate * Get a contract's zone unique ID. Needed because 64-bit reads and
4587c478bd9Sstevel@tonic-gate * writes aren't atomic on x86. Since there are contexts where we are
4597c478bd9Sstevel@tonic-gate * unable to take ct_lock, we instead use ct_reflock; in actuality any
4607c478bd9Sstevel@tonic-gate * lock would do.
4617c478bd9Sstevel@tonic-gate */
4627c478bd9Sstevel@tonic-gate uint64_t
contract_getzuniqid(contract_t * ct)4637c478bd9Sstevel@tonic-gate contract_getzuniqid(contract_t *ct)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate uint64_t zuniqid;
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock);
4687c478bd9Sstevel@tonic-gate zuniqid = ct->ct_mzuniqid;
4697c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock);
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate return (zuniqid);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate * contract_setzuniqid
4767c478bd9Sstevel@tonic-gate *
4777c478bd9Sstevel@tonic-gate * Sets a contract's zone unique ID. See contract_getzuniqid.
4787c478bd9Sstevel@tonic-gate */
4797c478bd9Sstevel@tonic-gate void
contract_setzuniqid(contract_t * ct,uint64_t zuniqid)4807c478bd9Sstevel@tonic-gate contract_setzuniqid(contract_t *ct, uint64_t zuniqid)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock);
4837c478bd9Sstevel@tonic-gate ct->ct_mzuniqid = zuniqid;
4847c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock);
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate * contract_abandon
4897c478bd9Sstevel@tonic-gate *
4907c478bd9Sstevel@tonic-gate * Abandons the specified contract. If "explicit" is clear, the
4917c478bd9Sstevel@tonic-gate * contract was implicitly abandoned (by process exit) and should be
4927c478bd9Sstevel@tonic-gate * inherited if its terms allow it and its owner was a member of a
4937c478bd9Sstevel@tonic-gate * regent contract. Otherwise, the contract type's abandon entry point
4947c478bd9Sstevel@tonic-gate * is invoked to either destroy or orphan the contract.
4957c478bd9Sstevel@tonic-gate */
4967c478bd9Sstevel@tonic-gate int
contract_abandon(contract_t * ct,proc_t * p,int explicit)4977c478bd9Sstevel@tonic-gate contract_abandon(contract_t *ct, proc_t *p, int explicit)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate ct_equeue_t *q = NULL;
5007c478bd9Sstevel@tonic-gate contract_t *parent = &p->p_ct_process->conp_contract;
5017c478bd9Sstevel@tonic-gate int inherit = 0;
5027c478bd9Sstevel@tonic-gate
503a81df0a5SJerry Jelinek VERIFY(p == curproc);
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate * Multiple contract locks are taken contract -> subcontract.
5097c478bd9Sstevel@tonic-gate * Check if the contract will be inherited so we can acquire
5107c478bd9Sstevel@tonic-gate * all the necessary locks before making sensitive changes.
5117c478bd9Sstevel@tonic-gate */
5127c478bd9Sstevel@tonic-gate if (!explicit && (ct->ct_flags & CTF_INHERIT) &&
5137c478bd9Sstevel@tonic-gate contract_process_accept(parent)) {
5147c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
5157c478bd9Sstevel@tonic-gate mutex_enter(&parent->ct_lock);
5167c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
5177c478bd9Sstevel@tonic-gate inherit = 1;
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate if (ct->ct_owner != p) {
5217c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
5227c478bd9Sstevel@tonic-gate if (inherit)
5237c478bd9Sstevel@tonic-gate mutex_exit(&parent->ct_lock);
5247c478bd9Sstevel@tonic-gate return (EINVAL);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
5287c478bd9Sstevel@tonic-gate if (explicit)
5297c478bd9Sstevel@tonic-gate avl_remove(&p->p_ct_held, ct);
5307c478bd9Sstevel@tonic-gate ct->ct_owner = NULL;
5317c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate * Since we can't call cte_trim with the contract lock held,
5357c478bd9Sstevel@tonic-gate * we grab the queue pointer here.
5367c478bd9Sstevel@tonic-gate */
5377c478bd9Sstevel@tonic-gate if (p->p_ct_equeue)
5387c478bd9Sstevel@tonic-gate q = p->p_ct_equeue[ct->ct_type->ct_type_index];
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate * contop_abandon may destroy the contract so we rely on it to
5427c478bd9Sstevel@tonic-gate * drop ct_lock. We retain a reference on the contract so that
5437c478bd9Sstevel@tonic-gate * the cte_trim which follows functions properly. Even though
5447c478bd9Sstevel@tonic-gate * cte_trim doesn't dereference the contract pointer, it is
5457c478bd9Sstevel@tonic-gate * still necessary to retain a reference to the contract so
5467c478bd9Sstevel@tonic-gate * that we don't trim events which are sent by a subsequently
5477c478bd9Sstevel@tonic-gate * allocated contract infortuitously located at the same address.
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate contract_hold(ct);
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate if (inherit) {
5527c478bd9Sstevel@tonic-gate ct->ct_state = CTS_INHERITED;
553a81df0a5SJerry Jelinek VERIFY(ct->ct_regent == parent);
5547c478bd9Sstevel@tonic-gate contract_process_take(parent, ct);
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate * We are handing off the process's reference to the
5587c478bd9Sstevel@tonic-gate * parent contract. For this reason, the order in
5597c478bd9Sstevel@tonic-gate * which we drop the contract locks is also important.
5607c478bd9Sstevel@tonic-gate */
5617c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
5627c478bd9Sstevel@tonic-gate mutex_exit(&parent->ct_lock);
5637c478bd9Sstevel@tonic-gate } else {
5647c478bd9Sstevel@tonic-gate ct->ct_regent = NULL;
5657c478bd9Sstevel@tonic-gate ct->ct_type->ct_type_ops->contop_abandon(ct);
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate /*
5697c478bd9Sstevel@tonic-gate * ct_lock has been dropped; we can safely trim the event
5707c478bd9Sstevel@tonic-gate * queue now.
5717c478bd9Sstevel@tonic-gate */
5727c478bd9Sstevel@tonic-gate if (q) {
5737c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
5747c478bd9Sstevel@tonic-gate cte_trim(q, ct);
5757c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate contract_rele(ct);
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate return (0);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate
58325e8c5aaSvikram int
contract_newct(contract_t * ct)58425e8c5aaSvikram contract_newct(contract_t *ct)
58525e8c5aaSvikram {
58625e8c5aaSvikram return (ct->ct_type->ct_type_ops->contop_newct(ct));
58725e8c5aaSvikram }
58825e8c5aaSvikram
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate * contract_adopt
5917c478bd9Sstevel@tonic-gate *
5927c478bd9Sstevel@tonic-gate * Adopts a contract. After a successful call to this routine, the
5937c478bd9Sstevel@tonic-gate * previously inherited contract will belong to the calling process,
5947c478bd9Sstevel@tonic-gate * and its events will have been appended to its new owner's process
5957c478bd9Sstevel@tonic-gate * bundle queue.
5967c478bd9Sstevel@tonic-gate */
5977c478bd9Sstevel@tonic-gate int
contract_adopt(contract_t * ct,proc_t * p)5987c478bd9Sstevel@tonic-gate contract_adopt(contract_t *ct, proc_t *p)
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate avl_index_t where;
6017c478bd9Sstevel@tonic-gate ct_equeue_t *q;
6027c478bd9Sstevel@tonic-gate contract_t *parent;
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate ASSERT(p == curproc);
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate * Ensure the process has an event queue. Checked by ASSERTs
6087c478bd9Sstevel@tonic-gate * below.
6097c478bd9Sstevel@tonic-gate */
6107c478bd9Sstevel@tonic-gate (void) contract_type_pbundle(ct->ct_type, p);
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
6137c478bd9Sstevel@tonic-gate parent = ct->ct_regent;
6147c478bd9Sstevel@tonic-gate if (ct->ct_state != CTS_INHERITED ||
6157c478bd9Sstevel@tonic-gate &p->p_ct_process->conp_contract != parent ||
6167c478bd9Sstevel@tonic-gate p->p_zone->zone_uniqid != ct->ct_czuniqid) {
6177c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
6187c478bd9Sstevel@tonic-gate return (EINVAL);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate * Multiple contract locks are taken contract -> subcontract.
6237c478bd9Sstevel@tonic-gate */
6247c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
6257c478bd9Sstevel@tonic-gate mutex_enter(&parent->ct_lock);
6267c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate /*
6297c478bd9Sstevel@tonic-gate * It is possible that the contract was adopted by someone else
6307c478bd9Sstevel@tonic-gate * while its lock was dropped. It isn't possible for the
6317c478bd9Sstevel@tonic-gate * contract to have been inherited by a different regent
6327c478bd9Sstevel@tonic-gate * contract.
6337c478bd9Sstevel@tonic-gate */
6347c478bd9Sstevel@tonic-gate if (ct->ct_state != CTS_INHERITED) {
6357c478bd9Sstevel@tonic-gate mutex_exit(&parent->ct_lock);
6367c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
6377c478bd9Sstevel@tonic-gate return (EBUSY);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate ASSERT(ct->ct_regent == parent);
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate ct->ct_state = CTS_OWNED;
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate contract_process_adopt(ct, p);
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
6467c478bd9Sstevel@tonic-gate ct->ct_owner = p;
6477c478bd9Sstevel@tonic-gate VERIFY(avl_find(&p->p_ct_held, ct, &where) == NULL);
6487c478bd9Sstevel@tonic-gate avl_insert(&p->p_ct_held, ct, where);
6497c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue);
6527c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index]);
6537c478bd9Sstevel@tonic-gate q = ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index];
6547c478bd9Sstevel@tonic-gate cte_copy(&ct->ct_events, q);
6557c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate return (0);
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate * contract_ack
6627c478bd9Sstevel@tonic-gate *
6637c478bd9Sstevel@tonic-gate * Acknowledges receipt of a critical event.
6647c478bd9Sstevel@tonic-gate */
6657c478bd9Sstevel@tonic-gate int
contract_ack(contract_t * ct,uint64_t evid,int ack)66625e8c5aaSvikram contract_ack(contract_t *ct, uint64_t evid, int ack)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate ct_kevent_t *ev;
6697c478bd9Sstevel@tonic-gate list_t *queue = &ct->ct_events.ctq_events;
6707c478bd9Sstevel@tonic-gate int error = ESRCH;
67125e8c5aaSvikram int nego = 0;
67225e8c5aaSvikram uint_t evtype;
67325e8c5aaSvikram
67425e8c5aaSvikram ASSERT(ack == CT_ACK || ack == CT_NACK);
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
6777c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_events.ctq_lock);
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate * We are probably ACKing something near the head of the queue.
6807c478bd9Sstevel@tonic-gate */
6817c478bd9Sstevel@tonic-gate for (ev = list_head(queue); ev; ev = list_next(queue, ev)) {
6827c478bd9Sstevel@tonic-gate if (ev->cte_id == evid) {
68325e8c5aaSvikram if (ev->cte_flags & CTE_NEG)
68425e8c5aaSvikram nego = 1;
68525e8c5aaSvikram else if (ack == CT_NACK)
68625e8c5aaSvikram break;
6877c478bd9Sstevel@tonic-gate if ((ev->cte_flags & (CTE_INFO | CTE_ACK)) == 0) {
6887c478bd9Sstevel@tonic-gate ev->cte_flags |= CTE_ACK;
6897c478bd9Sstevel@tonic-gate ct->ct_evcnt--;
69025e8c5aaSvikram evtype = ev->cte_type;
6917c478bd9Sstevel@tonic-gate error = 0;
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate break;
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_events.ctq_lock);
6977c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
6987c478bd9Sstevel@tonic-gate
69925e8c5aaSvikram /*
70025e8c5aaSvikram * Not all critical events are negotiation events, however
70125e8c5aaSvikram * every negotiation event is a critical event. NEGEND events
70225e8c5aaSvikram * are critical events but are not negotiation events
70325e8c5aaSvikram */
70425e8c5aaSvikram if (error || !nego)
7057c478bd9Sstevel@tonic-gate return (error);
70625e8c5aaSvikram
70725e8c5aaSvikram if (ack == CT_ACK)
70825e8c5aaSvikram error = ct->ct_type->ct_type_ops->contop_ack(ct, evtype, evid);
70925e8c5aaSvikram else
71025e8c5aaSvikram error = ct->ct_type->ct_type_ops->contop_nack(ct, evtype, evid);
71125e8c5aaSvikram
71225e8c5aaSvikram return (error);
71325e8c5aaSvikram }
71425e8c5aaSvikram
71525e8c5aaSvikram /*ARGSUSED*/
71625e8c5aaSvikram int
contract_ack_inval(contract_t * ct,uint_t evtype,uint64_t evid)71725e8c5aaSvikram contract_ack_inval(contract_t *ct, uint_t evtype, uint64_t evid)
71825e8c5aaSvikram {
71925e8c5aaSvikram cmn_err(CE_PANIC, "contract_ack_inval: unsupported call: ctid: %u",
72025e8c5aaSvikram ct->ct_id);
72125e8c5aaSvikram return (ENOSYS);
72225e8c5aaSvikram }
72325e8c5aaSvikram
72425e8c5aaSvikram /*ARGSUSED*/
72525e8c5aaSvikram int
contract_qack_inval(contract_t * ct,uint_t evtype,uint64_t evid)72625e8c5aaSvikram contract_qack_inval(contract_t *ct, uint_t evtype, uint64_t evid)
72725e8c5aaSvikram {
72825e8c5aaSvikram cmn_err(CE_PANIC, "contract_ack_inval: unsupported call: ctid: %u",
72925e8c5aaSvikram ct->ct_id);
73025e8c5aaSvikram return (ENOSYS);
73125e8c5aaSvikram }
73225e8c5aaSvikram
73325e8c5aaSvikram /*ARGSUSED*/
73425e8c5aaSvikram int
contract_qack_notsup(contract_t * ct,uint_t evtype,uint64_t evid)73525e8c5aaSvikram contract_qack_notsup(contract_t *ct, uint_t evtype, uint64_t evid)
73625e8c5aaSvikram {
73725e8c5aaSvikram return (ERANGE);
73825e8c5aaSvikram }
73925e8c5aaSvikram
74025e8c5aaSvikram /*
74125e8c5aaSvikram * contract_qack
74225e8c5aaSvikram *
74325e8c5aaSvikram * Asks that negotiations be extended by another time quantum
74425e8c5aaSvikram */
74525e8c5aaSvikram int
contract_qack(contract_t * ct,uint64_t evid)74625e8c5aaSvikram contract_qack(contract_t *ct, uint64_t evid)
74725e8c5aaSvikram {
74825e8c5aaSvikram ct_kevent_t *ev;
74925e8c5aaSvikram list_t *queue = &ct->ct_events.ctq_events;
75025e8c5aaSvikram int nego = 0;
75125e8c5aaSvikram uint_t evtype;
75225e8c5aaSvikram
75325e8c5aaSvikram mutex_enter(&ct->ct_lock);
75425e8c5aaSvikram mutex_enter(&ct->ct_events.ctq_lock);
75525e8c5aaSvikram
75625e8c5aaSvikram for (ev = list_head(queue); ev; ev = list_next(queue, ev)) {
75725e8c5aaSvikram if (ev->cte_id == evid) {
75825e8c5aaSvikram if ((ev->cte_flags & (CTE_NEG | CTE_ACK)) == CTE_NEG) {
75925e8c5aaSvikram evtype = ev->cte_type;
76025e8c5aaSvikram nego = 1;
76125e8c5aaSvikram }
76225e8c5aaSvikram break;
76325e8c5aaSvikram }
76425e8c5aaSvikram }
76525e8c5aaSvikram mutex_exit(&ct->ct_events.ctq_lock);
76625e8c5aaSvikram mutex_exit(&ct->ct_lock);
76725e8c5aaSvikram
76825e8c5aaSvikram /*
76925e8c5aaSvikram * Only a negotiated event (which is by definition also a critical
77025e8c5aaSvikram * event) which has not yet been acknowledged can provide
77125e8c5aaSvikram * time quanta to a negotiating owner process.
77225e8c5aaSvikram */
77325e8c5aaSvikram if (!nego)
77425e8c5aaSvikram return (ESRCH);
77525e8c5aaSvikram
77625e8c5aaSvikram return (ct->ct_type->ct_type_ops->contop_qack(ct, evtype, evid));
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate /*
7807c478bd9Sstevel@tonic-gate * contract_orphan
7817c478bd9Sstevel@tonic-gate *
7827c478bd9Sstevel@tonic-gate * Icky-poo. This is a process-contract special, used to ACK all
7837c478bd9Sstevel@tonic-gate * critical messages when a contract is orphaned.
7847c478bd9Sstevel@tonic-gate */
7857c478bd9Sstevel@tonic-gate void
contract_orphan(contract_t * ct)7867c478bd9Sstevel@tonic-gate contract_orphan(contract_t *ct)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate ct_kevent_t *ev;
7897c478bd9Sstevel@tonic-gate list_t *queue = &ct->ct_events.ctq_events;
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_lock));
7927c478bd9Sstevel@tonic-gate ASSERT(ct->ct_state != CTS_ORPHAN);
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_events.ctq_lock);
7957c478bd9Sstevel@tonic-gate ct->ct_state = CTS_ORPHAN;
7967c478bd9Sstevel@tonic-gate for (ev = list_head(queue); ev; ev = list_next(queue, ev)) {
7977c478bd9Sstevel@tonic-gate if ((ev->cte_flags & (CTE_INFO | CTE_ACK)) == 0) {
7987c478bd9Sstevel@tonic-gate ev->cte_flags |= CTE_ACK;
7997c478bd9Sstevel@tonic-gate ct->ct_evcnt--;
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_events.ctq_lock);
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate ASSERT(ct->ct_evcnt == 0);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate /*
8087c478bd9Sstevel@tonic-gate * contract_destroy
8097c478bd9Sstevel@tonic-gate *
8107c478bd9Sstevel@tonic-gate * Explicit contract destruction. Called when contract is empty.
8117c478bd9Sstevel@tonic-gate * The contract will actually stick around until all of its events are
8127c478bd9Sstevel@tonic-gate * removed from the bundle and and process bundle queues, and all fds
8137c478bd9Sstevel@tonic-gate * which refer to it are closed. See contract_dtor if you are looking
8147c478bd9Sstevel@tonic-gate * for what destroys the contract structure.
8157c478bd9Sstevel@tonic-gate */
8167c478bd9Sstevel@tonic-gate void
contract_destroy(contract_t * ct)8177c478bd9Sstevel@tonic-gate contract_destroy(contract_t *ct)
8187c478bd9Sstevel@tonic-gate {
8197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_lock));
8207c478bd9Sstevel@tonic-gate ASSERT(ct->ct_state != CTS_DEAD);
8217c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner == NULL);
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate ct->ct_state = CTS_DEAD;
8247c478bd9Sstevel@tonic-gate cte_queue_drain(&ct->ct_events, 1);
8257c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
8267c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_type->ct_type_events.ctq_lock);
8277c478bd9Sstevel@tonic-gate cte_trim(&ct->ct_type->ct_type_events, ct);
8287c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_type->ct_type_events.ctq_lock);
8297c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
8307c478bd9Sstevel@tonic-gate ct->ct_type->ct_type_ops->contop_destroy(ct);
8317c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
8327c478bd9Sstevel@tonic-gate contract_rele(ct);
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate /*
8367c478bd9Sstevel@tonic-gate * contract_vnode_get
8377c478bd9Sstevel@tonic-gate *
8387c478bd9Sstevel@tonic-gate * Obtains the contract directory vnode for this contract, if there is
8397c478bd9Sstevel@tonic-gate * one. The caller must VN_RELE the vnode when they are through using
8407c478bd9Sstevel@tonic-gate * it.
8417c478bd9Sstevel@tonic-gate */
8427c478bd9Sstevel@tonic-gate vnode_t *
contract_vnode_get(contract_t * ct,vfs_t * vfsp)8437c478bd9Sstevel@tonic-gate contract_vnode_get(contract_t *ct, vfs_t *vfsp)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate contract_vnode_t *ctv;
8467c478bd9Sstevel@tonic-gate vnode_t *vp = NULL;
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
8497c478bd9Sstevel@tonic-gate for (ctv = list_head(&ct->ct_vnodes); ctv != NULL;
8507c478bd9Sstevel@tonic-gate ctv = list_next(&ct->ct_vnodes, ctv))
8517c478bd9Sstevel@tonic-gate if (ctv->ctv_vnode->v_vfsp == vfsp) {
8527c478bd9Sstevel@tonic-gate vp = ctv->ctv_vnode;
8537c478bd9Sstevel@tonic-gate VN_HOLD(vp);
8547c478bd9Sstevel@tonic-gate break;
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
8577c478bd9Sstevel@tonic-gate return (vp);
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate
8607c478bd9Sstevel@tonic-gate /*
8617c478bd9Sstevel@tonic-gate * contract_vnode_set
8627c478bd9Sstevel@tonic-gate *
8637c478bd9Sstevel@tonic-gate * Sets the contract directory vnode for this contract. We don't hold
8647c478bd9Sstevel@tonic-gate * a reference on the vnode because we don't want to prevent it from
8657c478bd9Sstevel@tonic-gate * being freed. The vnode's inactive entry point will take care of
8667c478bd9Sstevel@tonic-gate * notifying us when it should be removed.
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate void
contract_vnode_set(contract_t * ct,contract_vnode_t * ctv,vnode_t * vnode)8697c478bd9Sstevel@tonic-gate contract_vnode_set(contract_t *ct, contract_vnode_t *ctv, vnode_t *vnode)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
8727c478bd9Sstevel@tonic-gate ctv->ctv_vnode = vnode;
8737c478bd9Sstevel@tonic-gate list_insert_head(&ct->ct_vnodes, ctv);
8747c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate /*
8787c478bd9Sstevel@tonic-gate * contract_vnode_clear
8797c478bd9Sstevel@tonic-gate *
8807c478bd9Sstevel@tonic-gate * Removes this vnode as the contract directory vnode for this
8817c478bd9Sstevel@tonic-gate * contract. Called from a contract directory's inactive entry point,
8827c478bd9Sstevel@tonic-gate * this may return 0 indicating that the vnode gained another reference
8837c478bd9Sstevel@tonic-gate * because of a simultaneous call to contract_vnode_get.
8847c478bd9Sstevel@tonic-gate */
8857c478bd9Sstevel@tonic-gate int
contract_vnode_clear(contract_t * ct,contract_vnode_t * ctv)8867c478bd9Sstevel@tonic-gate contract_vnode_clear(contract_t *ct, contract_vnode_t *ctv)
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate vnode_t *vp = ctv->ctv_vnode;
8897c478bd9Sstevel@tonic-gate int result;
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
8927c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock);
8937c478bd9Sstevel@tonic-gate if (vp->v_count == 1) {
8947c478bd9Sstevel@tonic-gate list_remove(&ct->ct_vnodes, ctv);
8957c478bd9Sstevel@tonic-gate result = 1;
8967c478bd9Sstevel@tonic-gate } else {
897ade42b55SSebastien Roy VN_RELE_LOCKED(vp);
8987c478bd9Sstevel@tonic-gate result = 0;
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock);
9017c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate return (result);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate /*
9077c478bd9Sstevel@tonic-gate * contract_exit
9087c478bd9Sstevel@tonic-gate *
9097c478bd9Sstevel@tonic-gate * Abandons all contracts held by process p, and drains process p's
9107c478bd9Sstevel@tonic-gate * bundle queues. Called on process exit.
9117c478bd9Sstevel@tonic-gate */
9127c478bd9Sstevel@tonic-gate void
contract_exit(proc_t * p)9137c478bd9Sstevel@tonic-gate contract_exit(proc_t *p)
9147c478bd9Sstevel@tonic-gate {
9157c478bd9Sstevel@tonic-gate contract_t *ct;
9167c478bd9Sstevel@tonic-gate void *cookie = NULL;
9177c478bd9Sstevel@tonic-gate int i;
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate ASSERT(p == curproc);
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate /*
9227c478bd9Sstevel@tonic-gate * Abandon held contracts. contract_abandon knows enough not
9237c478bd9Sstevel@tonic-gate * to remove the contract from the list a second time. We are
9247c478bd9Sstevel@tonic-gate * exiting, so no locks are needed here. But because
9257c478bd9Sstevel@tonic-gate * contract_abandon will take p_lock, we need to make sure we
9267c478bd9Sstevel@tonic-gate * aren't holding it.
9277c478bd9Sstevel@tonic-gate */
9287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&p->p_lock));
9297c478bd9Sstevel@tonic-gate while ((ct = avl_destroy_nodes(&p->p_ct_held, &cookie)) != NULL)
9307c478bd9Sstevel@tonic-gate VERIFY(contract_abandon(ct, p, 0) == 0);
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate /*
9337c478bd9Sstevel@tonic-gate * Drain pbundles. Because a process bundle queue could have
9347c478bd9Sstevel@tonic-gate * been passed to another process, they may not be freed right
9357c478bd9Sstevel@tonic-gate * away.
9367c478bd9Sstevel@tonic-gate */
9377c478bd9Sstevel@tonic-gate if (p->p_ct_equeue) {
9387c478bd9Sstevel@tonic-gate for (i = 0; i < CTT_MAXTYPE; i++)
9397c478bd9Sstevel@tonic-gate if (p->p_ct_equeue[i])
9407c478bd9Sstevel@tonic-gate cte_queue_drain(p->p_ct_equeue[i], 0);
9417c478bd9Sstevel@tonic-gate kmem_free(p->p_ct_equeue, CTT_MAXTYPE * sizeof (ct_equeue_t *));
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate
94525e8c5aaSvikram static int
get_time_left(struct ct_time * t)94625e8c5aaSvikram get_time_left(struct ct_time *t)
94725e8c5aaSvikram {
94825e8c5aaSvikram clock_t ticks_elapsed;
94925e8c5aaSvikram int secs_elapsed;
95025e8c5aaSvikram
95125e8c5aaSvikram if (t->ctm_total == -1)
95225e8c5aaSvikram return (-1);
95325e8c5aaSvikram
95425e8c5aaSvikram ticks_elapsed = ddi_get_lbolt() - t->ctm_start;
95525e8c5aaSvikram secs_elapsed = t->ctm_total - (drv_hztousec(ticks_elapsed)/MICROSEC);
95625e8c5aaSvikram return (secs_elapsed > 0 ? secs_elapsed : 0);
95725e8c5aaSvikram }
95825e8c5aaSvikram
9597c478bd9Sstevel@tonic-gate /*
9607c478bd9Sstevel@tonic-gate * contract_status_common
9617c478bd9Sstevel@tonic-gate *
9627c478bd9Sstevel@tonic-gate * Populates a ct_status structure. Used by contract types in their
9637c478bd9Sstevel@tonic-gate * status entry points and ctfs when only common information is
9647c478bd9Sstevel@tonic-gate * requested.
9657c478bd9Sstevel@tonic-gate */
9667c478bd9Sstevel@tonic-gate void
contract_status_common(contract_t * ct,zone_t * zone,void * status,model_t model)9677c478bd9Sstevel@tonic-gate contract_status_common(contract_t *ct, zone_t *zone, void *status,
9687c478bd9Sstevel@tonic-gate model_t model)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate STRUCT_HANDLE(ct_status, lstatus);
9717c478bd9Sstevel@tonic-gate
9727c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(lstatus, model, status);
9737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ct->ct_lock));
9747c478bd9Sstevel@tonic-gate if (zone->zone_uniqid == GLOBAL_ZONEUNIQID ||
9757c478bd9Sstevel@tonic-gate zone->zone_uniqid == ct->ct_czuniqid) {
9767c478bd9Sstevel@tonic-gate zone_t *czone;
9777c478bd9Sstevel@tonic-gate zoneid_t zoneid = -1;
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /*
9807c478bd9Sstevel@tonic-gate * Contracts don't have holds on the zones they were
9817c478bd9Sstevel@tonic-gate * created by. If the contract's zone no longer
9827c478bd9Sstevel@tonic-gate * exists, we say its zoneid is -1.
9837c478bd9Sstevel@tonic-gate */
9847c478bd9Sstevel@tonic-gate if (zone->zone_uniqid == ct->ct_czuniqid ||
9857c478bd9Sstevel@tonic-gate ct->ct_czuniqid == GLOBAL_ZONEUNIQID) {
9867c478bd9Sstevel@tonic-gate zoneid = ct->ct_zoneid;
9877c478bd9Sstevel@tonic-gate } else if ((czone = zone_find_by_id(ct->ct_zoneid)) != NULL) {
9887c478bd9Sstevel@tonic-gate if (czone->zone_uniqid == ct->ct_mzuniqid)
9897c478bd9Sstevel@tonic-gate zoneid = ct->ct_zoneid;
9907c478bd9Sstevel@tonic-gate zone_rele(czone);
9917c478bd9Sstevel@tonic-gate }
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_zoneid, zoneid);
9947c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_holder,
9957c478bd9Sstevel@tonic-gate (ct->ct_state == CTS_OWNED) ? ct->ct_owner->p_pid :
9967c478bd9Sstevel@tonic-gate (ct->ct_state == CTS_INHERITED) ? ct->ct_regent->ct_id : 0);
9977c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_state, ct->ct_state);
9987c478bd9Sstevel@tonic-gate } else {
9997c478bd9Sstevel@tonic-gate /*
10007c478bd9Sstevel@tonic-gate * We are looking at a contract which was created by a
10017c478bd9Sstevel@tonic-gate * process outside of our zone. We provide fake zone,
10027c478bd9Sstevel@tonic-gate * holder, and state information.
10037c478bd9Sstevel@tonic-gate */
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_zoneid, zone->zone_id);
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate * Since "zone" can't disappear until the calling ctfs
10087c478bd9Sstevel@tonic-gate * is unmounted, zone_zsched must be valid.
10097c478bd9Sstevel@tonic-gate */
10107c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_holder, (ct->ct_state < CTS_ORPHAN) ?
10117c478bd9Sstevel@tonic-gate zone->zone_zsched->p_pid : 0);
10127c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_state, (ct->ct_state < CTS_ORPHAN) ?
10137c478bd9Sstevel@tonic-gate CTS_OWNED : ct->ct_state);
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_nevents, ct->ct_evcnt);
101625e8c5aaSvikram STRUCT_FSET(lstatus, ctst_ntime, get_time_left(&ct->ct_ntime));
101725e8c5aaSvikram STRUCT_FSET(lstatus, ctst_qtime, get_time_left(&ct->ct_qtime));
10187c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_nevid,
10197c478bd9Sstevel@tonic-gate ct->ct_nevent ? ct->ct_nevent->cte_id : 0);
10207c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_critical, ct->ct_ev_crit);
10217c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_informative, ct->ct_ev_info);
10227c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_cookie, ct->ct_cookie);
10237c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_type, ct->ct_type->ct_type_index);
10247c478bd9Sstevel@tonic-gate STRUCT_FSET(lstatus, ctst_id, ct->ct_id);
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate /*
10287c478bd9Sstevel@tonic-gate * contract_checkcred
10297c478bd9Sstevel@tonic-gate *
10307c478bd9Sstevel@tonic-gate * Determines if the specified contract is owned by a process with the
10317c478bd9Sstevel@tonic-gate * same effective uid as the specified credential. The caller must
10327c478bd9Sstevel@tonic-gate * ensure that the uid spaces are the same. Returns 1 on success.
10337c478bd9Sstevel@tonic-gate */
10347c478bd9Sstevel@tonic-gate static int
contract_checkcred(contract_t * ct,const cred_t * cr)10357c478bd9Sstevel@tonic-gate contract_checkcred(contract_t *ct, const cred_t *cr)
10367c478bd9Sstevel@tonic-gate {
10377c478bd9Sstevel@tonic-gate proc_t *p;
10387c478bd9Sstevel@tonic-gate int fail = 1;
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
10417c478bd9Sstevel@tonic-gate if ((p = ct->ct_owner) != NULL) {
10427c478bd9Sstevel@tonic-gate mutex_enter(&p->p_crlock);
10437c478bd9Sstevel@tonic-gate fail = crgetuid(cr) != crgetuid(p->p_cred);
10447c478bd9Sstevel@tonic-gate mutex_exit(&p->p_crlock);
10457c478bd9Sstevel@tonic-gate }
10467c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate return (!fail);
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate * contract_owned
10537c478bd9Sstevel@tonic-gate *
10547c478bd9Sstevel@tonic-gate * Determines if the specified credential can view an event generated
10557c478bd9Sstevel@tonic-gate * by the specified contract. If locked is set, the contract's ct_lock
10567c478bd9Sstevel@tonic-gate * is held and the caller will need to do additional work to determine
10577c478bd9Sstevel@tonic-gate * if they truly can see the event. Returns 1 on success.
10587c478bd9Sstevel@tonic-gate */
10597c478bd9Sstevel@tonic-gate int
contract_owned(contract_t * ct,const cred_t * cr,int locked)10607c478bd9Sstevel@tonic-gate contract_owned(contract_t *ct, const cred_t *cr, int locked)
10617c478bd9Sstevel@tonic-gate {
10627c478bd9Sstevel@tonic-gate int owner, cmatch, zmatch;
10637c478bd9Sstevel@tonic-gate uint64_t zuniqid, mzuniqid;
10647c478bd9Sstevel@tonic-gate uid_t euid;
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate ASSERT(locked || MUTEX_NOT_HELD(&ct->ct_lock));
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate zuniqid = curproc->p_zone->zone_uniqid;
10697c478bd9Sstevel@tonic-gate mzuniqid = contract_getzuniqid(ct);
10707c478bd9Sstevel@tonic-gate euid = crgetuid(cr);
10717c478bd9Sstevel@tonic-gate
10727c478bd9Sstevel@tonic-gate /*
10737c478bd9Sstevel@tonic-gate * owner: we own the contract
10747c478bd9Sstevel@tonic-gate * cmatch: we are in the creator's (and holder's) zone and our
10757c478bd9Sstevel@tonic-gate * uid matches the creator's or holder's
10767c478bd9Sstevel@tonic-gate * zmatch: we are in the effective zone of a contract created
10777c478bd9Sstevel@tonic-gate * in the global zone, and our uid matches that of the
10787c478bd9Sstevel@tonic-gate * virtualized holder's (zsched/kcred)
10797c478bd9Sstevel@tonic-gate */
10807c478bd9Sstevel@tonic-gate owner = (ct->ct_owner == curproc);
10817c478bd9Sstevel@tonic-gate cmatch = (zuniqid == ct->ct_czuniqid) &&
10827c478bd9Sstevel@tonic-gate ((ct->ct_cuid == euid) || (!locked && contract_checkcred(ct, cr)));
10837c478bd9Sstevel@tonic-gate zmatch = (ct->ct_czuniqid != mzuniqid) && (zuniqid == mzuniqid) &&
10847c478bd9Sstevel@tonic-gate (crgetuid(kcred) == euid);
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate return (owner || cmatch || zmatch);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate /*
10917c478bd9Sstevel@tonic-gate * contract_type_init
10927c478bd9Sstevel@tonic-gate *
10937c478bd9Sstevel@tonic-gate * Called by contract types to register themselves with the contracts
10947c478bd9Sstevel@tonic-gate * framework.
10957c478bd9Sstevel@tonic-gate */
10967c478bd9Sstevel@tonic-gate ct_type_t *
contract_type_init(ct_typeid_t type,const char * name,contops_t * ops,ct_f_default_t * dfault)10977c478bd9Sstevel@tonic-gate contract_type_init(ct_typeid_t type, const char *name, contops_t *ops,
10987c478bd9Sstevel@tonic-gate ct_f_default_t *dfault)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate ct_type_t *result;
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate ASSERT(type < CTT_MAXTYPE);
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate result = kmem_alloc(sizeof (ct_type_t), KM_SLEEP);
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate mutex_init(&result->ct_type_lock, NULL, MUTEX_DEFAULT, NULL);
11077c478bd9Sstevel@tonic-gate avl_create(&result->ct_type_avl, contract_compar, sizeof (contract_t),
11087c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_cttavl));
11097c478bd9Sstevel@tonic-gate cte_queue_create(&result->ct_type_events, CTEL_BUNDLE, 20, 0);
11107c478bd9Sstevel@tonic-gate result->ct_type_name = name;
11117c478bd9Sstevel@tonic-gate result->ct_type_ops = ops;
11127c478bd9Sstevel@tonic-gate result->ct_type_default = dfault;
11137c478bd9Sstevel@tonic-gate result->ct_type_evid = 0;
11147c478bd9Sstevel@tonic-gate gethrestime(&result->ct_type_timestruc);
11157c478bd9Sstevel@tonic-gate result->ct_type_index = type;
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate ct_types[type] = result;
11187c478bd9Sstevel@tonic-gate
11197c478bd9Sstevel@tonic-gate return (result);
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate
11227c478bd9Sstevel@tonic-gate /*
11237c478bd9Sstevel@tonic-gate * contract_type_count
11247c478bd9Sstevel@tonic-gate *
11257c478bd9Sstevel@tonic-gate * Obtains the number of contracts of a particular type.
11267c478bd9Sstevel@tonic-gate */
11277c478bd9Sstevel@tonic-gate int
contract_type_count(ct_type_t * type)11287c478bd9Sstevel@tonic-gate contract_type_count(ct_type_t *type)
11297c478bd9Sstevel@tonic-gate {
11307c478bd9Sstevel@tonic-gate ulong_t count;
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock);
11337c478bd9Sstevel@tonic-gate count = avl_numnodes(&type->ct_type_avl);
11347c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock);
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate return (count);
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate /*
11407c478bd9Sstevel@tonic-gate * contract_type_max
11417c478bd9Sstevel@tonic-gate *
11427c478bd9Sstevel@tonic-gate * Obtains the maximum contract id of of a particular type.
11437c478bd9Sstevel@tonic-gate */
11447c478bd9Sstevel@tonic-gate ctid_t
contract_type_max(ct_type_t * type)11457c478bd9Sstevel@tonic-gate contract_type_max(ct_type_t *type)
11467c478bd9Sstevel@tonic-gate {
11477c478bd9Sstevel@tonic-gate contract_t *ct;
11487c478bd9Sstevel@tonic-gate ctid_t res;
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock);
11517c478bd9Sstevel@tonic-gate ct = avl_last(&type->ct_type_avl);
11527c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1;
11537c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock);
11547c478bd9Sstevel@tonic-gate
11557c478bd9Sstevel@tonic-gate return (res);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate * contract_max
11607c478bd9Sstevel@tonic-gate *
11617c478bd9Sstevel@tonic-gate * Obtains the maximum contract id.
11627c478bd9Sstevel@tonic-gate */
11637c478bd9Sstevel@tonic-gate ctid_t
contract_max(void)11647c478bd9Sstevel@tonic-gate contract_max(void)
11657c478bd9Sstevel@tonic-gate {
11667c478bd9Sstevel@tonic-gate contract_t *ct;
11677c478bd9Sstevel@tonic-gate ctid_t res;
11687c478bd9Sstevel@tonic-gate
11697c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
11707c478bd9Sstevel@tonic-gate ct = avl_last(&contract_avl);
11717c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1;
11727c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate return (res);
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate /*
11787c478bd9Sstevel@tonic-gate * contract_lookup_common
11797c478bd9Sstevel@tonic-gate *
11807c478bd9Sstevel@tonic-gate * Common code for contract_lookup and contract_type_lookup. Takes a
11817c478bd9Sstevel@tonic-gate * pointer to an AVL tree to search in. Should be called with the
11827c478bd9Sstevel@tonic-gate * appropriate tree-protecting lock held (unfortunately unassertable).
11837c478bd9Sstevel@tonic-gate */
11847c478bd9Sstevel@tonic-gate static ctid_t
contract_lookup_common(avl_tree_t * tree,uint64_t zuniqid,ctid_t current)11857c478bd9Sstevel@tonic-gate contract_lookup_common(avl_tree_t *tree, uint64_t zuniqid, ctid_t current)
11867c478bd9Sstevel@tonic-gate {
11877c478bd9Sstevel@tonic-gate contract_t template, *ct;
11887c478bd9Sstevel@tonic-gate avl_index_t where;
11897c478bd9Sstevel@tonic-gate ctid_t res;
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate template.ct_id = current;
11927c478bd9Sstevel@tonic-gate ct = avl_find(tree, &template, &where);
11937c478bd9Sstevel@tonic-gate if (ct == NULL)
11947c478bd9Sstevel@tonic-gate ct = avl_nearest(tree, where, AVL_AFTER);
11957c478bd9Sstevel@tonic-gate if (zuniqid != GLOBAL_ZONEUNIQID)
11967c478bd9Sstevel@tonic-gate while (ct && (contract_getzuniqid(ct) != zuniqid))
11977c478bd9Sstevel@tonic-gate ct = AVL_NEXT(tree, ct);
11987c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1;
11997c478bd9Sstevel@tonic-gate
12007c478bd9Sstevel@tonic-gate return (res);
12017c478bd9Sstevel@tonic-gate }
12027c478bd9Sstevel@tonic-gate
12037c478bd9Sstevel@tonic-gate /*
12047c478bd9Sstevel@tonic-gate * contract_type_lookup
12057c478bd9Sstevel@tonic-gate *
12067c478bd9Sstevel@tonic-gate * Returns the next type contract after the specified id, visible from
12077c478bd9Sstevel@tonic-gate * the specified zone.
12087c478bd9Sstevel@tonic-gate */
12097c478bd9Sstevel@tonic-gate ctid_t
contract_type_lookup(ct_type_t * type,uint64_t zuniqid,ctid_t current)12107c478bd9Sstevel@tonic-gate contract_type_lookup(ct_type_t *type, uint64_t zuniqid, ctid_t current)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate ctid_t res;
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock);
12157c478bd9Sstevel@tonic-gate res = contract_lookup_common(&type->ct_type_avl, zuniqid, current);
12167c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock);
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate return (res);
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate
12217c478bd9Sstevel@tonic-gate /*
12227c478bd9Sstevel@tonic-gate * contract_lookup
12237c478bd9Sstevel@tonic-gate *
12247c478bd9Sstevel@tonic-gate * Returns the next contract after the specified id, visible from the
12257c478bd9Sstevel@tonic-gate * specified zone.
12267c478bd9Sstevel@tonic-gate */
12277c478bd9Sstevel@tonic-gate ctid_t
contract_lookup(uint64_t zuniqid,ctid_t current)12287c478bd9Sstevel@tonic-gate contract_lookup(uint64_t zuniqid, ctid_t current)
12297c478bd9Sstevel@tonic-gate {
12307c478bd9Sstevel@tonic-gate ctid_t res;
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
12337c478bd9Sstevel@tonic-gate res = contract_lookup_common(&contract_avl, zuniqid, current);
12347c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate return (res);
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate * contract_plookup
12417c478bd9Sstevel@tonic-gate *
12427c478bd9Sstevel@tonic-gate * Returns the next contract held by process p after the specified id,
12437c478bd9Sstevel@tonic-gate * visible from the specified zone. Made complicated by the fact that
12447c478bd9Sstevel@tonic-gate * contracts visible in a zone but held by processes outside of the
12457c478bd9Sstevel@tonic-gate * zone need to appear as being held by zsched to zone members.
12467c478bd9Sstevel@tonic-gate */
12477c478bd9Sstevel@tonic-gate ctid_t
contract_plookup(proc_t * p,ctid_t current,uint64_t zuniqid)12487c478bd9Sstevel@tonic-gate contract_plookup(proc_t *p, ctid_t current, uint64_t zuniqid)
12497c478bd9Sstevel@tonic-gate {
12507c478bd9Sstevel@tonic-gate contract_t template, *ct;
12517c478bd9Sstevel@tonic-gate avl_index_t where;
12527c478bd9Sstevel@tonic-gate ctid_t res;
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate template.ct_id = current;
12557c478bd9Sstevel@tonic-gate if (zuniqid != GLOBAL_ZONEUNIQID &&
12567c478bd9Sstevel@tonic-gate (p->p_flag & (SSYS|SZONETOP)) == (SSYS|SZONETOP)) {
12577c478bd9Sstevel@tonic-gate /* This is inelegant. */
12587c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
12597c478bd9Sstevel@tonic-gate ct = avl_find(&contract_avl, &template, &where);
12607c478bd9Sstevel@tonic-gate if (ct == NULL)
12617c478bd9Sstevel@tonic-gate ct = avl_nearest(&contract_avl, where, AVL_AFTER);
12627c478bd9Sstevel@tonic-gate while (ct && !(ct->ct_state < CTS_ORPHAN &&
12637c478bd9Sstevel@tonic-gate contract_getzuniqid(ct) == zuniqid &&
12647c478bd9Sstevel@tonic-gate ct->ct_czuniqid == GLOBAL_ZONEUNIQID))
12657c478bd9Sstevel@tonic-gate ct = AVL_NEXT(&contract_avl, ct);
12667c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1;
12677c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
12687c478bd9Sstevel@tonic-gate } else {
12697c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
12707c478bd9Sstevel@tonic-gate ct = avl_find(&p->p_ct_held, &template, &where);
12717c478bd9Sstevel@tonic-gate if (ct == NULL)
12727c478bd9Sstevel@tonic-gate ct = avl_nearest(&p->p_ct_held, where, AVL_AFTER);
12737c478bd9Sstevel@tonic-gate res = ct ? ct->ct_id : -1;
12747c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
12757c478bd9Sstevel@tonic-gate }
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate return (res);
12787c478bd9Sstevel@tonic-gate }
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate /*
12817c478bd9Sstevel@tonic-gate * contract_ptr_common
12827c478bd9Sstevel@tonic-gate *
12837c478bd9Sstevel@tonic-gate * Common code for contract_ptr and contract_type_ptr. Takes a pointer
12847c478bd9Sstevel@tonic-gate * to an AVL tree to search in. Should be called with the appropriate
12857c478bd9Sstevel@tonic-gate * tree-protecting lock held (unfortunately unassertable).
12867c478bd9Sstevel@tonic-gate */
12877c478bd9Sstevel@tonic-gate static contract_t *
contract_ptr_common(avl_tree_t * tree,ctid_t id,uint64_t zuniqid)12887c478bd9Sstevel@tonic-gate contract_ptr_common(avl_tree_t *tree, ctid_t id, uint64_t zuniqid)
12897c478bd9Sstevel@tonic-gate {
12907c478bd9Sstevel@tonic-gate contract_t template, *ct;
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate template.ct_id = id;
12937c478bd9Sstevel@tonic-gate ct = avl_find(tree, &template, NULL);
12947c478bd9Sstevel@tonic-gate if (ct == NULL || (zuniqid != GLOBAL_ZONEUNIQID &&
12957c478bd9Sstevel@tonic-gate contract_getzuniqid(ct) != zuniqid)) {
12967c478bd9Sstevel@tonic-gate return (NULL);
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate /*
13007c478bd9Sstevel@tonic-gate * Check to see if a thread is in the window in contract_rele
13017c478bd9Sstevel@tonic-gate * between dropping the reference count and removing the
13027c478bd9Sstevel@tonic-gate * contract from the type AVL.
13037c478bd9Sstevel@tonic-gate */
13047c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_reflock);
13057c478bd9Sstevel@tonic-gate if (ct->ct_ref) {
13067c478bd9Sstevel@tonic-gate ct->ct_ref++;
13077c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock);
13087c478bd9Sstevel@tonic-gate } else {
13097c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_reflock);
13107c478bd9Sstevel@tonic-gate ct = NULL;
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate
13137c478bd9Sstevel@tonic-gate return (ct);
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate /*
13177c478bd9Sstevel@tonic-gate * contract_type_ptr
13187c478bd9Sstevel@tonic-gate *
13197c478bd9Sstevel@tonic-gate * Returns a pointer to the contract with the specified id. The
13207c478bd9Sstevel@tonic-gate * contract is held, so the caller needs to release the reference when
13217c478bd9Sstevel@tonic-gate * it is through with the contract.
13227c478bd9Sstevel@tonic-gate */
13237c478bd9Sstevel@tonic-gate contract_t *
contract_type_ptr(ct_type_t * type,ctid_t id,uint64_t zuniqid)13247c478bd9Sstevel@tonic-gate contract_type_ptr(ct_type_t *type, ctid_t id, uint64_t zuniqid)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate contract_t *ct;
13277c478bd9Sstevel@tonic-gate
13287c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock);
13297c478bd9Sstevel@tonic-gate ct = contract_ptr_common(&type->ct_type_avl, id, zuniqid);
13307c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock);
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate return (ct);
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate /*
13367c478bd9Sstevel@tonic-gate * contract_ptr
13377c478bd9Sstevel@tonic-gate *
13387c478bd9Sstevel@tonic-gate * Returns a pointer to the contract with the specified id. The
13397c478bd9Sstevel@tonic-gate * contract is held, so the caller needs to release the reference when
13407c478bd9Sstevel@tonic-gate * it is through with the contract.
13417c478bd9Sstevel@tonic-gate */
13427c478bd9Sstevel@tonic-gate contract_t *
contract_ptr(ctid_t id,uint64_t zuniqid)13437c478bd9Sstevel@tonic-gate contract_ptr(ctid_t id, uint64_t zuniqid)
13447c478bd9Sstevel@tonic-gate {
13457c478bd9Sstevel@tonic-gate contract_t *ct;
13467c478bd9Sstevel@tonic-gate
13477c478bd9Sstevel@tonic-gate mutex_enter(&contract_lock);
13487c478bd9Sstevel@tonic-gate ct = contract_ptr_common(&contract_avl, id, zuniqid);
13497c478bd9Sstevel@tonic-gate mutex_exit(&contract_lock);
13507c478bd9Sstevel@tonic-gate
13517c478bd9Sstevel@tonic-gate return (ct);
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate /*
13557c478bd9Sstevel@tonic-gate * contract_type_time
13567c478bd9Sstevel@tonic-gate *
13577c478bd9Sstevel@tonic-gate * Obtains the last time a contract of a particular type was created.
13587c478bd9Sstevel@tonic-gate */
13597c478bd9Sstevel@tonic-gate void
contract_type_time(ct_type_t * type,timestruc_t * time)13607c478bd9Sstevel@tonic-gate contract_type_time(ct_type_t *type, timestruc_t *time)
13617c478bd9Sstevel@tonic-gate {
13627c478bd9Sstevel@tonic-gate mutex_enter(&type->ct_type_lock);
13637c478bd9Sstevel@tonic-gate *time = type->ct_type_timestruc;
13647c478bd9Sstevel@tonic-gate mutex_exit(&type->ct_type_lock);
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate
13677c478bd9Sstevel@tonic-gate /*
13687c478bd9Sstevel@tonic-gate * contract_type_bundle
13697c478bd9Sstevel@tonic-gate *
13707c478bd9Sstevel@tonic-gate * Obtains a type's bundle queue.
13717c478bd9Sstevel@tonic-gate */
13727c478bd9Sstevel@tonic-gate ct_equeue_t *
contract_type_bundle(ct_type_t * type)13737c478bd9Sstevel@tonic-gate contract_type_bundle(ct_type_t *type)
13747c478bd9Sstevel@tonic-gate {
13757c478bd9Sstevel@tonic-gate return (&type->ct_type_events);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate * contract_type_pbundle
13807c478bd9Sstevel@tonic-gate *
13817c478bd9Sstevel@tonic-gate * Obtain's a process's bundle queue. If one doesn't exist, one is
13827c478bd9Sstevel@tonic-gate * created. Often used simply to ensure that a bundle queue is
13837c478bd9Sstevel@tonic-gate * allocated.
13847c478bd9Sstevel@tonic-gate */
13857c478bd9Sstevel@tonic-gate ct_equeue_t *
contract_type_pbundle(ct_type_t * type,proc_t * pp)13867c478bd9Sstevel@tonic-gate contract_type_pbundle(ct_type_t *type, proc_t *pp)
13877c478bd9Sstevel@tonic-gate {
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate * If there isn't an array of bundle queues, allocate one.
13907c478bd9Sstevel@tonic-gate */
13917c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue == NULL) {
13927c478bd9Sstevel@tonic-gate size_t size = CTT_MAXTYPE * sizeof (ct_equeue_t *);
13937c478bd9Sstevel@tonic-gate ct_equeue_t **qa = kmem_zalloc(size, KM_SLEEP);
13947c478bd9Sstevel@tonic-gate
13957c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock);
13967c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue)
13977c478bd9Sstevel@tonic-gate kmem_free(qa, size);
13987c478bd9Sstevel@tonic-gate else
13997c478bd9Sstevel@tonic-gate pp->p_ct_equeue = qa;
14007c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock);
14017c478bd9Sstevel@tonic-gate }
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate /*
14047c478bd9Sstevel@tonic-gate * If there isn't a bundle queue of the required type, allocate
14057c478bd9Sstevel@tonic-gate * one.
14067c478bd9Sstevel@tonic-gate */
14077c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue[type->ct_type_index] == NULL) {
14087c478bd9Sstevel@tonic-gate ct_equeue_t *q = kmem_zalloc(sizeof (ct_equeue_t), KM_SLEEP);
14097c478bd9Sstevel@tonic-gate cte_queue_create(q, CTEL_PBUNDLE, 20, 1);
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock);
14127c478bd9Sstevel@tonic-gate if (pp->p_ct_equeue[type->ct_type_index])
14137c478bd9Sstevel@tonic-gate cte_queue_drain(q, 0);
14147c478bd9Sstevel@tonic-gate else
14157c478bd9Sstevel@tonic-gate pp->p_ct_equeue[type->ct_type_index] = q;
14167c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock);
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate return (pp->p_ct_equeue[type->ct_type_index]);
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate
14227c478bd9Sstevel@tonic-gate /*
1423c5a9a4fcSAntonello Cruz * ctparam_copyin
1424c5a9a4fcSAntonello Cruz *
1425c5a9a4fcSAntonello Cruz * copyin a ct_param_t for CT_TSET or CT_TGET commands.
1426c5a9a4fcSAntonello Cruz * If ctparam_copyout() is not called after ctparam_copyin(), then
1427c5a9a4fcSAntonello Cruz * the caller must kmem_free() the buffer pointed by kparam->ctpm_kbuf.
1428c5a9a4fcSAntonello Cruz *
1429c5a9a4fcSAntonello Cruz * The copyin/out of ct_param_t is not done in ctmpl_set() and ctmpl_get()
1430c5a9a4fcSAntonello Cruz * because prctioctl() calls ctmpl_set() and ctmpl_get() while holding a
1431c5a9a4fcSAntonello Cruz * process lock.
1432c5a9a4fcSAntonello Cruz */
1433c5a9a4fcSAntonello Cruz int
ctparam_copyin(const void * uaddr,ct_kparam_t * kparam,int flag,int cmd)1434c5a9a4fcSAntonello Cruz ctparam_copyin(const void *uaddr, ct_kparam_t *kparam, int flag, int cmd)
1435c5a9a4fcSAntonello Cruz {
1436c5a9a4fcSAntonello Cruz uint32_t size;
1437c5a9a4fcSAntonello Cruz void *ubuf;
1438c5a9a4fcSAntonello Cruz ct_param_t *param = &kparam->param;
1439c5a9a4fcSAntonello Cruz STRUCT_DECL(ct_param, uarg);
1440c5a9a4fcSAntonello Cruz
1441c5a9a4fcSAntonello Cruz STRUCT_INIT(uarg, flag);
1442c5a9a4fcSAntonello Cruz if (copyin(uaddr, STRUCT_BUF(uarg), STRUCT_SIZE(uarg)))
1443c5a9a4fcSAntonello Cruz return (EFAULT);
1444c5a9a4fcSAntonello Cruz size = STRUCT_FGET(uarg, ctpm_size);
1445c5a9a4fcSAntonello Cruz ubuf = STRUCT_FGETP(uarg, ctpm_value);
1446c5a9a4fcSAntonello Cruz
1447c5a9a4fcSAntonello Cruz if (size > CT_PARAM_MAX_SIZE || size == 0)
1448c5a9a4fcSAntonello Cruz return (EINVAL);
1449c5a9a4fcSAntonello Cruz
1450c5a9a4fcSAntonello Cruz kparam->ctpm_kbuf = kmem_alloc(size, KM_SLEEP);
1451c5a9a4fcSAntonello Cruz if (cmd == CT_TSET) {
1452c5a9a4fcSAntonello Cruz if (copyin(ubuf, kparam->ctpm_kbuf, size)) {
1453c5a9a4fcSAntonello Cruz kmem_free(kparam->ctpm_kbuf, size);
1454c5a9a4fcSAntonello Cruz return (EFAULT);
1455c5a9a4fcSAntonello Cruz }
1456c5a9a4fcSAntonello Cruz }
1457c5a9a4fcSAntonello Cruz param->ctpm_id = STRUCT_FGET(uarg, ctpm_id);
1458c5a9a4fcSAntonello Cruz param->ctpm_size = size;
1459c5a9a4fcSAntonello Cruz param->ctpm_value = ubuf;
1460c5a9a4fcSAntonello Cruz kparam->ret_size = 0;
1461c5a9a4fcSAntonello Cruz
1462c5a9a4fcSAntonello Cruz return (0);
1463c5a9a4fcSAntonello Cruz }
1464c5a9a4fcSAntonello Cruz
1465c5a9a4fcSAntonello Cruz /*
1466c5a9a4fcSAntonello Cruz * ctparam_copyout
1467c5a9a4fcSAntonello Cruz *
1468c5a9a4fcSAntonello Cruz * copyout a ct_kparam_t and frees the buffer pointed by the member
1469c5a9a4fcSAntonello Cruz * ctpm_kbuf of ct_kparam_t
1470c5a9a4fcSAntonello Cruz */
1471c5a9a4fcSAntonello Cruz int
ctparam_copyout(ct_kparam_t * kparam,void * uaddr,int flag)1472c5a9a4fcSAntonello Cruz ctparam_copyout(ct_kparam_t *kparam, void *uaddr, int flag)
1473c5a9a4fcSAntonello Cruz {
1474c5a9a4fcSAntonello Cruz int r = 0;
1475c5a9a4fcSAntonello Cruz ct_param_t *param = &kparam->param;
1476c5a9a4fcSAntonello Cruz STRUCT_DECL(ct_param, uarg);
1477c5a9a4fcSAntonello Cruz
1478c5a9a4fcSAntonello Cruz STRUCT_INIT(uarg, flag);
1479c5a9a4fcSAntonello Cruz
1480c5a9a4fcSAntonello Cruz STRUCT_FSET(uarg, ctpm_id, param->ctpm_id);
1481c5a9a4fcSAntonello Cruz STRUCT_FSET(uarg, ctpm_size, kparam->ret_size);
1482c5a9a4fcSAntonello Cruz STRUCT_FSETP(uarg, ctpm_value, param->ctpm_value);
1483c5a9a4fcSAntonello Cruz if (copyout(STRUCT_BUF(uarg), uaddr, STRUCT_SIZE(uarg))) {
1484c5a9a4fcSAntonello Cruz r = EFAULT;
1485c5a9a4fcSAntonello Cruz goto error;
1486c5a9a4fcSAntonello Cruz }
1487c5a9a4fcSAntonello Cruz if (copyout(kparam->ctpm_kbuf, param->ctpm_value,
1488c5a9a4fcSAntonello Cruz MIN(kparam->ret_size, param->ctpm_size))) {
1489c5a9a4fcSAntonello Cruz r = EFAULT;
1490c5a9a4fcSAntonello Cruz }
1491c5a9a4fcSAntonello Cruz
1492c5a9a4fcSAntonello Cruz error:
1493c5a9a4fcSAntonello Cruz kmem_free(kparam->ctpm_kbuf, param->ctpm_size);
1494c5a9a4fcSAntonello Cruz
1495c5a9a4fcSAntonello Cruz return (r);
1496c5a9a4fcSAntonello Cruz }
1497c5a9a4fcSAntonello Cruz
1498c5a9a4fcSAntonello Cruz /*
14997c478bd9Sstevel@tonic-gate * ctmpl_free
15007c478bd9Sstevel@tonic-gate *
15017c478bd9Sstevel@tonic-gate * Frees a template.
15027c478bd9Sstevel@tonic-gate */
15037c478bd9Sstevel@tonic-gate void
ctmpl_free(ct_template_t * template)15047c478bd9Sstevel@tonic-gate ctmpl_free(ct_template_t *template)
15057c478bd9Sstevel@tonic-gate {
15067c478bd9Sstevel@tonic-gate mutex_destroy(&template->ctmpl_lock);
15077c478bd9Sstevel@tonic-gate template->ctmpl_ops->ctop_free(template);
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate /*
15117c478bd9Sstevel@tonic-gate * ctmpl_dup
15127c478bd9Sstevel@tonic-gate *
15137c478bd9Sstevel@tonic-gate * Creates a copy of a template.
15147c478bd9Sstevel@tonic-gate */
15157c478bd9Sstevel@tonic-gate ct_template_t *
ctmpl_dup(ct_template_t * template)15167c478bd9Sstevel@tonic-gate ctmpl_dup(ct_template_t *template)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate ct_template_t *new;
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate if (template == NULL)
15217c478bd9Sstevel@tonic-gate return (NULL);
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate new = template->ctmpl_ops->ctop_dup(template);
15247c478bd9Sstevel@tonic-gate /*
15257c478bd9Sstevel@tonic-gate * ctmpl_lock was taken by ctop_dup's call to ctmpl_copy and
15267c478bd9Sstevel@tonic-gate * should have remain held until now.
15277c478bd9Sstevel@tonic-gate */
15287c478bd9Sstevel@tonic-gate mutex_exit(&template->ctmpl_lock);
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate return (new);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate * ctmpl_set
15357c478bd9Sstevel@tonic-gate *
15367c478bd9Sstevel@tonic-gate * Sets the requested terms of a template.
15377c478bd9Sstevel@tonic-gate */
15387c478bd9Sstevel@tonic-gate int
ctmpl_set(ct_template_t * template,ct_kparam_t * kparam,const cred_t * cr)1539c5a9a4fcSAntonello Cruz ctmpl_set(ct_template_t *template, ct_kparam_t *kparam, const cred_t *cr)
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate int result = 0;
1542c5a9a4fcSAntonello Cruz ct_param_t *param = &kparam->param;
1543d170b13aSacruz uint64_t param_value;
1544d170b13aSacruz
1545*c6f039c7SToomas Soome param_value = 0;
1546d170b13aSacruz if (param->ctpm_id == CTP_COOKIE ||
1547d170b13aSacruz param->ctpm_id == CTP_EV_INFO ||
1548d170b13aSacruz param->ctpm_id == CTP_EV_CRITICAL) {
1549d170b13aSacruz if (param->ctpm_size < sizeof (uint64_t)) {
1550d170b13aSacruz return (EINVAL);
1551d170b13aSacruz } else {
1552c5a9a4fcSAntonello Cruz param_value = *(uint64_t *)kparam->ctpm_kbuf;
1553d170b13aSacruz }
1554d170b13aSacruz }
15557c478bd9Sstevel@tonic-gate
15567c478bd9Sstevel@tonic-gate mutex_enter(&template->ctmpl_lock);
15577c478bd9Sstevel@tonic-gate switch (param->ctpm_id) {
15587c478bd9Sstevel@tonic-gate case CTP_COOKIE:
15597b209c2cSacruz template->ctmpl_cookie = param_value;
15607c478bd9Sstevel@tonic-gate break;
15617c478bd9Sstevel@tonic-gate case CTP_EV_INFO:
15627b209c2cSacruz if (param_value & ~(uint64_t)template->ctmpl_ops->allevents)
15637c478bd9Sstevel@tonic-gate result = EINVAL;
15647c478bd9Sstevel@tonic-gate else
15657b209c2cSacruz template->ctmpl_ev_info = param_value;
15667c478bd9Sstevel@tonic-gate break;
15677c478bd9Sstevel@tonic-gate case CTP_EV_CRITICAL:
15687b209c2cSacruz if (param_value & ~(uint64_t)template->ctmpl_ops->allevents) {
15697c478bd9Sstevel@tonic-gate result = EINVAL;
15707c478bd9Sstevel@tonic-gate break;
15717b209c2cSacruz } else if ((~template->ctmpl_ev_crit & param_value) == 0) {
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate * Assume that a pure reduction of the critical
15747c478bd9Sstevel@tonic-gate * set is allowed by the contract type.
15757c478bd9Sstevel@tonic-gate */
15767b209c2cSacruz template->ctmpl_ev_crit = param_value;
15777c478bd9Sstevel@tonic-gate break;
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate /*
15807c478bd9Sstevel@tonic-gate * There may be restrictions on what we can make
15817c478bd9Sstevel@tonic-gate * critical, so we defer to the judgement of the
15827c478bd9Sstevel@tonic-gate * contract type.
15837c478bd9Sstevel@tonic-gate */
15847c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
15857c478bd9Sstevel@tonic-gate default:
1586c5a9a4fcSAntonello Cruz result = template->ctmpl_ops->ctop_set(template, kparam, cr);
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate mutex_exit(&template->ctmpl_lock);
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate return (result);
15917c478bd9Sstevel@tonic-gate }
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate /*
15947c478bd9Sstevel@tonic-gate * ctmpl_get
15957c478bd9Sstevel@tonic-gate *
15967c478bd9Sstevel@tonic-gate * Obtains the requested terms from a template.
1597d170b13aSacruz *
1598d170b13aSacruz * If the term requested is a variable-sized term and the buffer
1599d170b13aSacruz * provided is too small for the data, we truncate the data and return
1600c5a9a4fcSAntonello Cruz * the buffer size necessary to fit the term in kparam->ret_size. If the
1601d170b13aSacruz * term requested is fix-sized (uint64_t) and the buffer provided is too
1602d170b13aSacruz * small, we return EINVAL. This should never happen if you're using
1603d170b13aSacruz * libcontract(3LIB), only if you call ioctl with a hand constructed
1604d170b13aSacruz * ct_param_t argument.
1605d170b13aSacruz *
1606d170b13aSacruz * Currently, only contract specific parameters have variable-sized
1607d170b13aSacruz * parameters.
16087c478bd9Sstevel@tonic-gate */
16097c478bd9Sstevel@tonic-gate int
ctmpl_get(ct_template_t * template,ct_kparam_t * kparam)1610c5a9a4fcSAntonello Cruz ctmpl_get(ct_template_t *template, ct_kparam_t *kparam)
16117c478bd9Sstevel@tonic-gate {
16127c478bd9Sstevel@tonic-gate int result = 0;
1613c5a9a4fcSAntonello Cruz ct_param_t *param = &kparam->param;
1614d170b13aSacruz uint64_t *param_value;
1615d170b13aSacruz
1616*c6f039c7SToomas Soome param_value = NULL;
1617d170b13aSacruz if (param->ctpm_id == CTP_COOKIE ||
1618d170b13aSacruz param->ctpm_id == CTP_EV_INFO ||
1619d170b13aSacruz param->ctpm_id == CTP_EV_CRITICAL) {
1620d170b13aSacruz if (param->ctpm_size < sizeof (uint64_t)) {
1621d170b13aSacruz return (EINVAL);
1622d170b13aSacruz } else {
1623c5a9a4fcSAntonello Cruz param_value = kparam->ctpm_kbuf;
1624c5a9a4fcSAntonello Cruz kparam->ret_size = sizeof (uint64_t);
1625d170b13aSacruz }
1626d170b13aSacruz }
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate mutex_enter(&template->ctmpl_lock);
16297c478bd9Sstevel@tonic-gate switch (param->ctpm_id) {
16307c478bd9Sstevel@tonic-gate case CTP_COOKIE:
1631*c6f039c7SToomas Soome if (param_value != NULL)
16327b209c2cSacruz *param_value = template->ctmpl_cookie;
16337c478bd9Sstevel@tonic-gate break;
16347c478bd9Sstevel@tonic-gate case CTP_EV_INFO:
1635*c6f039c7SToomas Soome if (param_value != NULL)
16367b209c2cSacruz *param_value = template->ctmpl_ev_info;
16377c478bd9Sstevel@tonic-gate break;
16387c478bd9Sstevel@tonic-gate case CTP_EV_CRITICAL:
1639*c6f039c7SToomas Soome if (param_value != NULL)
16407b209c2cSacruz *param_value = template->ctmpl_ev_crit;
16417c478bd9Sstevel@tonic-gate break;
16427c478bd9Sstevel@tonic-gate default:
1643c5a9a4fcSAntonello Cruz result = template->ctmpl_ops->ctop_get(template, kparam);
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate mutex_exit(&template->ctmpl_lock);
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate return (result);
16487c478bd9Sstevel@tonic-gate }
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate /*
16517c478bd9Sstevel@tonic-gate * ctmpl_makecurrent
16527c478bd9Sstevel@tonic-gate *
16537c478bd9Sstevel@tonic-gate * Used by ctmpl_activate and ctmpl_clear to set the current thread's
16547c478bd9Sstevel@tonic-gate * active template. Frees the old active template, if there was one.
16557c478bd9Sstevel@tonic-gate */
16567c478bd9Sstevel@tonic-gate static void
ctmpl_makecurrent(ct_template_t * template,ct_template_t * new)16577c478bd9Sstevel@tonic-gate ctmpl_makecurrent(ct_template_t *template, ct_template_t *new)
16587c478bd9Sstevel@tonic-gate {
16597c478bd9Sstevel@tonic-gate klwp_t *curlwp = ttolwp(curthread);
16607c478bd9Sstevel@tonic-gate proc_t *p = curproc;
16617c478bd9Sstevel@tonic-gate ct_template_t *old;
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
16647c478bd9Sstevel@tonic-gate old = curlwp->lwp_ct_active[template->ctmpl_type->ct_type_index];
16657c478bd9Sstevel@tonic-gate curlwp->lwp_ct_active[template->ctmpl_type->ct_type_index] = new;
16667c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
16677c478bd9Sstevel@tonic-gate
16687c478bd9Sstevel@tonic-gate if (old)
16697c478bd9Sstevel@tonic-gate ctmpl_free(old);
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate /*
16737c478bd9Sstevel@tonic-gate * ctmpl_activate
16747c478bd9Sstevel@tonic-gate *
16757c478bd9Sstevel@tonic-gate * Copy the specified template as the current thread's activate
16767c478bd9Sstevel@tonic-gate * template of that type.
16777c478bd9Sstevel@tonic-gate */
16787c478bd9Sstevel@tonic-gate void
ctmpl_activate(ct_template_t * template)16797c478bd9Sstevel@tonic-gate ctmpl_activate(ct_template_t *template)
16807c478bd9Sstevel@tonic-gate {
16817c478bd9Sstevel@tonic-gate ctmpl_makecurrent(template, ctmpl_dup(template));
16827c478bd9Sstevel@tonic-gate }
16837c478bd9Sstevel@tonic-gate
16847c478bd9Sstevel@tonic-gate /*
16857c478bd9Sstevel@tonic-gate * ctmpl_clear
16867c478bd9Sstevel@tonic-gate *
16877c478bd9Sstevel@tonic-gate * Clears the current thread's activate template of the same type as
16887c478bd9Sstevel@tonic-gate * the specified template.
16897c478bd9Sstevel@tonic-gate */
16907c478bd9Sstevel@tonic-gate void
ctmpl_clear(ct_template_t * template)16917c478bd9Sstevel@tonic-gate ctmpl_clear(ct_template_t *template)
16927c478bd9Sstevel@tonic-gate {
16937c478bd9Sstevel@tonic-gate ctmpl_makecurrent(template, NULL);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate * ctmpl_create
16987c478bd9Sstevel@tonic-gate *
16997c478bd9Sstevel@tonic-gate * Creates a new contract using the specified template.
17007c478bd9Sstevel@tonic-gate */
17017c478bd9Sstevel@tonic-gate int
ctmpl_create(ct_template_t * template,ctid_t * ctidp)170225e8c5aaSvikram ctmpl_create(ct_template_t *template, ctid_t *ctidp)
17037c478bd9Sstevel@tonic-gate {
170425e8c5aaSvikram return (template->ctmpl_ops->ctop_create(template, ctidp));
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate
17077c478bd9Sstevel@tonic-gate /*
17087c478bd9Sstevel@tonic-gate * ctmpl_init
17097c478bd9Sstevel@tonic-gate *
17107c478bd9Sstevel@tonic-gate * Initializes the common portion of a new contract template.
17117c478bd9Sstevel@tonic-gate */
17127c478bd9Sstevel@tonic-gate void
ctmpl_init(ct_template_t * new,ctmplops_t * ops,ct_type_t * type,void * data)17137c478bd9Sstevel@tonic-gate ctmpl_init(ct_template_t *new, ctmplops_t *ops, ct_type_t *type, void *data)
17147c478bd9Sstevel@tonic-gate {
17157c478bd9Sstevel@tonic-gate mutex_init(&new->ctmpl_lock, NULL, MUTEX_DEFAULT, NULL);
17167c478bd9Sstevel@tonic-gate new->ctmpl_ops = ops;
17177c478bd9Sstevel@tonic-gate new->ctmpl_type = type;
17187c478bd9Sstevel@tonic-gate new->ctmpl_data = data;
17197c478bd9Sstevel@tonic-gate new->ctmpl_ev_info = new->ctmpl_ev_crit = 0;
17207c478bd9Sstevel@tonic-gate new->ctmpl_cookie = 0;
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate /*
17247c478bd9Sstevel@tonic-gate * ctmpl_copy
17257c478bd9Sstevel@tonic-gate *
17267c478bd9Sstevel@tonic-gate * Copies the common portions of a contract template. Intended for use
17277c478bd9Sstevel@tonic-gate * by a contract type's ctop_dup template op. Returns with the old
17287c478bd9Sstevel@tonic-gate * template's lock held, which will should remain held until the
17297c478bd9Sstevel@tonic-gate * template op returns (it is dropped by ctmpl_dup).
17307c478bd9Sstevel@tonic-gate */
17317c478bd9Sstevel@tonic-gate void
ctmpl_copy(ct_template_t * new,ct_template_t * old)17327c478bd9Sstevel@tonic-gate ctmpl_copy(ct_template_t *new, ct_template_t *old)
17337c478bd9Sstevel@tonic-gate {
17347c478bd9Sstevel@tonic-gate mutex_init(&new->ctmpl_lock, NULL, MUTEX_DEFAULT, NULL);
17357c478bd9Sstevel@tonic-gate mutex_enter(&old->ctmpl_lock);
17367c478bd9Sstevel@tonic-gate new->ctmpl_ops = old->ctmpl_ops;
17377c478bd9Sstevel@tonic-gate new->ctmpl_type = old->ctmpl_type;
17387c478bd9Sstevel@tonic-gate new->ctmpl_ev_crit = old->ctmpl_ev_crit;
17397c478bd9Sstevel@tonic-gate new->ctmpl_ev_info = old->ctmpl_ev_info;
17407c478bd9Sstevel@tonic-gate new->ctmpl_cookie = old->ctmpl_cookie;
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate /*
17447c478bd9Sstevel@tonic-gate * ctmpl_create_inval
17457c478bd9Sstevel@tonic-gate *
17467c478bd9Sstevel@tonic-gate * Returns EINVAL. Provided for the convenience of those contract
17477c478bd9Sstevel@tonic-gate * types which don't support ct_tmpl_create(3contract) and would
17487c478bd9Sstevel@tonic-gate * otherwise need to create their own stub for the ctop_create template
17497c478bd9Sstevel@tonic-gate * op.
17507c478bd9Sstevel@tonic-gate */
17517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17527c478bd9Sstevel@tonic-gate int
ctmpl_create_inval(ct_template_t * template,ctid_t * ctidp)175325e8c5aaSvikram ctmpl_create_inval(ct_template_t *template, ctid_t *ctidp)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate return (EINVAL);
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate /*
17607c478bd9Sstevel@tonic-gate * cte_queue_create
17617c478bd9Sstevel@tonic-gate *
17627c478bd9Sstevel@tonic-gate * Initializes a queue of a particular type. If dynamic is set, the
17637c478bd9Sstevel@tonic-gate * queue is to be freed when its last listener is removed after being
17647c478bd9Sstevel@tonic-gate * drained.
17657c478bd9Sstevel@tonic-gate */
17667c478bd9Sstevel@tonic-gate static void
cte_queue_create(ct_equeue_t * q,ct_listnum_t list,int maxinf,int dynamic)17677c478bd9Sstevel@tonic-gate cte_queue_create(ct_equeue_t *q, ct_listnum_t list, int maxinf, int dynamic)
17687c478bd9Sstevel@tonic-gate {
17697c478bd9Sstevel@tonic-gate mutex_init(&q->ctq_lock, NULL, MUTEX_DEFAULT, NULL);
17707c478bd9Sstevel@tonic-gate q->ctq_listno = list;
17717c478bd9Sstevel@tonic-gate list_create(&q->ctq_events, sizeof (ct_kevent_t),
17727c478bd9Sstevel@tonic-gate offsetof(ct_kevent_t, cte_nodes[list].ctm_node));
17737c478bd9Sstevel@tonic-gate list_create(&q->ctq_listeners, sizeof (ct_listener_t),
17747c478bd9Sstevel@tonic-gate offsetof(ct_listener_t, ctl_allnode));
17757c478bd9Sstevel@tonic-gate list_create(&q->ctq_tail, sizeof (ct_listener_t),
17767c478bd9Sstevel@tonic-gate offsetof(ct_listener_t, ctl_tailnode));
17777c478bd9Sstevel@tonic-gate gethrestime(&q->ctq_atime);
17787c478bd9Sstevel@tonic-gate q->ctq_nlisteners = 0;
17797c478bd9Sstevel@tonic-gate q->ctq_nreliable = 0;
17807c478bd9Sstevel@tonic-gate q->ctq_ninf = 0;
17817c478bd9Sstevel@tonic-gate q->ctq_max = maxinf;
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate /*
17847c478bd9Sstevel@tonic-gate * Bundle queues and contract queues are embedded in other
17857c478bd9Sstevel@tonic-gate * structures and are implicitly referenced counted by virtue
17867c478bd9Sstevel@tonic-gate * of their vnodes' indirect hold on their contracts. Process
17877c478bd9Sstevel@tonic-gate * bundle queues are dynamically allocated and may persist
17887c478bd9Sstevel@tonic-gate * after the death of the process, so they must be explicitly
17897c478bd9Sstevel@tonic-gate * reference counted.
17907c478bd9Sstevel@tonic-gate */
17917c478bd9Sstevel@tonic-gate q->ctq_flags = dynamic ? CTQ_REFFED : 0;
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate
17947c478bd9Sstevel@tonic-gate /*
17957c478bd9Sstevel@tonic-gate * cte_queue_destroy
17967c478bd9Sstevel@tonic-gate *
17977c478bd9Sstevel@tonic-gate * Destroys the specified queue. The queue is freed if referenced
17987c478bd9Sstevel@tonic-gate * counted.
17997c478bd9Sstevel@tonic-gate */
18007c478bd9Sstevel@tonic-gate static void
cte_queue_destroy(ct_equeue_t * q)18017c478bd9Sstevel@tonic-gate cte_queue_destroy(ct_equeue_t *q)
18027c478bd9Sstevel@tonic-gate {
18037c478bd9Sstevel@tonic-gate ASSERT(q->ctq_flags & CTQ_DEAD);
18047c478bd9Sstevel@tonic-gate ASSERT(q->ctq_nlisteners == 0);
18057c478bd9Sstevel@tonic-gate ASSERT(q->ctq_nreliable == 0);
18067c478bd9Sstevel@tonic-gate list_destroy(&q->ctq_events);
18077c478bd9Sstevel@tonic-gate list_destroy(&q->ctq_listeners);
18087c478bd9Sstevel@tonic-gate list_destroy(&q->ctq_tail);
18097c478bd9Sstevel@tonic-gate mutex_destroy(&q->ctq_lock);
18107c478bd9Sstevel@tonic-gate if (q->ctq_flags & CTQ_REFFED)
18117c478bd9Sstevel@tonic-gate kmem_free(q, sizeof (ct_equeue_t));
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate
18147c478bd9Sstevel@tonic-gate /*
18157c478bd9Sstevel@tonic-gate * cte_hold
18167c478bd9Sstevel@tonic-gate *
18177c478bd9Sstevel@tonic-gate * Takes a hold on the specified event.
18187c478bd9Sstevel@tonic-gate */
18197c478bd9Sstevel@tonic-gate static void
cte_hold(ct_kevent_t * e)18207c478bd9Sstevel@tonic-gate cte_hold(ct_kevent_t *e)
18217c478bd9Sstevel@tonic-gate {
18227c478bd9Sstevel@tonic-gate mutex_enter(&e->cte_lock);
18237c478bd9Sstevel@tonic-gate ASSERT(e->cte_refs > 0);
18247c478bd9Sstevel@tonic-gate e->cte_refs++;
18257c478bd9Sstevel@tonic-gate mutex_exit(&e->cte_lock);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate
18287c478bd9Sstevel@tonic-gate /*
18297c478bd9Sstevel@tonic-gate * cte_rele
18307c478bd9Sstevel@tonic-gate *
18317c478bd9Sstevel@tonic-gate * Releases a hold on the specified event. If the caller had the last
18327c478bd9Sstevel@tonic-gate * reference, frees the event and releases its hold on the contract
18337c478bd9Sstevel@tonic-gate * that generated it.
18347c478bd9Sstevel@tonic-gate */
18357c478bd9Sstevel@tonic-gate static void
cte_rele(ct_kevent_t * e)18367c478bd9Sstevel@tonic-gate cte_rele(ct_kevent_t *e)
18377c478bd9Sstevel@tonic-gate {
18387c478bd9Sstevel@tonic-gate mutex_enter(&e->cte_lock);
18397c478bd9Sstevel@tonic-gate ASSERT(e->cte_refs > 0);
18407c478bd9Sstevel@tonic-gate if (--e->cte_refs) {
18417c478bd9Sstevel@tonic-gate mutex_exit(&e->cte_lock);
18427c478bd9Sstevel@tonic-gate return;
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate
18457c478bd9Sstevel@tonic-gate contract_rele(e->cte_contract);
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate mutex_destroy(&e->cte_lock);
18487c478bd9Sstevel@tonic-gate nvlist_free(e->cte_data);
18497c478bd9Sstevel@tonic-gate nvlist_free(e->cte_gdata);
18507c478bd9Sstevel@tonic-gate kmem_free(e, sizeof (ct_kevent_t));
18517c478bd9Sstevel@tonic-gate }
18527c478bd9Sstevel@tonic-gate
18537c478bd9Sstevel@tonic-gate /*
18547c478bd9Sstevel@tonic-gate * cte_qrele
18557c478bd9Sstevel@tonic-gate *
18567c478bd9Sstevel@tonic-gate * Remove this listener's hold on the specified event, removing and
18577c478bd9Sstevel@tonic-gate * releasing the queue's hold on the event if appropriate.
18587c478bd9Sstevel@tonic-gate */
18597c478bd9Sstevel@tonic-gate static void
cte_qrele(ct_equeue_t * q,ct_listener_t * l,ct_kevent_t * e)18607c478bd9Sstevel@tonic-gate cte_qrele(ct_equeue_t *q, ct_listener_t *l, ct_kevent_t *e)
18617c478bd9Sstevel@tonic-gate {
18627c478bd9Sstevel@tonic-gate ct_member_t *member = &e->cte_nodes[q->ctq_listno];
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock));
18657c478bd9Sstevel@tonic-gate
18667c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE)
18677c478bd9Sstevel@tonic-gate member->ctm_nreliable--;
18687c478bd9Sstevel@tonic-gate if ((--member->ctm_refs == 0) && member->ctm_trimmed) {
18697c478bd9Sstevel@tonic-gate member->ctm_trimmed = 0;
18707c478bd9Sstevel@tonic-gate list_remove(&q->ctq_events, e);
18717c478bd9Sstevel@tonic-gate cte_rele(e);
18727c478bd9Sstevel@tonic-gate }
18737c478bd9Sstevel@tonic-gate }
18747c478bd9Sstevel@tonic-gate
18757c478bd9Sstevel@tonic-gate /*
18767c478bd9Sstevel@tonic-gate * cte_qmove
18777c478bd9Sstevel@tonic-gate *
18787c478bd9Sstevel@tonic-gate * Move this listener to the specified event in the queue.
18797c478bd9Sstevel@tonic-gate */
18807c478bd9Sstevel@tonic-gate static ct_kevent_t *
cte_qmove(ct_equeue_t * q,ct_listener_t * l,ct_kevent_t * e)18817c478bd9Sstevel@tonic-gate cte_qmove(ct_equeue_t *q, ct_listener_t *l, ct_kevent_t *e)
18827c478bd9Sstevel@tonic-gate {
18837c478bd9Sstevel@tonic-gate ct_kevent_t *olde;
18847c478bd9Sstevel@tonic-gate
18857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock));
18867c478bd9Sstevel@tonic-gate ASSERT(l->ctl_equeue == q);
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate if ((olde = l->ctl_position) == NULL)
18897c478bd9Sstevel@tonic-gate list_remove(&q->ctq_tail, l);
18907c478bd9Sstevel@tonic-gate
18917c478bd9Sstevel@tonic-gate while (e != NULL && e->cte_nodes[q->ctq_listno].ctm_trimmed)
18927c478bd9Sstevel@tonic-gate e = list_next(&q->ctq_events, e);
18937c478bd9Sstevel@tonic-gate
18947c478bd9Sstevel@tonic-gate if (e != NULL) {
18957c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_refs++;
18967c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE)
18977c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_nreliable++;
18987c478bd9Sstevel@tonic-gate } else {
18997c478bd9Sstevel@tonic-gate list_insert_tail(&q->ctq_tail, l);
19007c478bd9Sstevel@tonic-gate }
19017c478bd9Sstevel@tonic-gate
19027c478bd9Sstevel@tonic-gate l->ctl_position = e;
19037c478bd9Sstevel@tonic-gate if (olde)
19047c478bd9Sstevel@tonic-gate cte_qrele(q, l, olde);
19057c478bd9Sstevel@tonic-gate
19067c478bd9Sstevel@tonic-gate return (e);
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate
19097c478bd9Sstevel@tonic-gate /*
19107c478bd9Sstevel@tonic-gate * cte_checkcred
19117c478bd9Sstevel@tonic-gate *
19127c478bd9Sstevel@tonic-gate * Determines if the specified event's contract is owned by a process
19137c478bd9Sstevel@tonic-gate * with the same effective uid as the specified credential. Called
19147c478bd9Sstevel@tonic-gate * after a failed call to contract_owned with locked set. Because it
19157c478bd9Sstevel@tonic-gate * drops the queue lock, its caller (cte_qreadable) needs to make sure
19167c478bd9Sstevel@tonic-gate * we're still in the same place after we return. Returns 1 on
19177c478bd9Sstevel@tonic-gate * success.
19187c478bd9Sstevel@tonic-gate */
19197c478bd9Sstevel@tonic-gate static int
cte_checkcred(ct_equeue_t * q,ct_kevent_t * e,const cred_t * cr)19207c478bd9Sstevel@tonic-gate cte_checkcred(ct_equeue_t *q, ct_kevent_t *e, const cred_t *cr)
19217c478bd9Sstevel@tonic-gate {
19227c478bd9Sstevel@tonic-gate int result;
19237c478bd9Sstevel@tonic-gate contract_t *ct = e->cte_contract;
19247c478bd9Sstevel@tonic-gate
19257c478bd9Sstevel@tonic-gate cte_hold(e);
19267c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
19277c478bd9Sstevel@tonic-gate result = curproc->p_zone->zone_uniqid == ct->ct_czuniqid &&
19287c478bd9Sstevel@tonic-gate contract_checkcred(ct, cr);
19297c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
19307c478bd9Sstevel@tonic-gate cte_rele(e);
19317c478bd9Sstevel@tonic-gate
19327c478bd9Sstevel@tonic-gate return (result);
19337c478bd9Sstevel@tonic-gate }
19347c478bd9Sstevel@tonic-gate
19357c478bd9Sstevel@tonic-gate /*
19367c478bd9Sstevel@tonic-gate * cte_qreadable
19377c478bd9Sstevel@tonic-gate *
19387c478bd9Sstevel@tonic-gate * Ensures that the listener is pointing to a valid event that the
19397c478bd9Sstevel@tonic-gate * caller has the credentials to read. Returns 0 if we can read the
19407c478bd9Sstevel@tonic-gate * event we're pointing to.
19417c478bd9Sstevel@tonic-gate */
19427c478bd9Sstevel@tonic-gate static int
cte_qreadable(ct_equeue_t * q,ct_listener_t * l,const cred_t * cr,uint64_t zuniqid,int crit)19437c478bd9Sstevel@tonic-gate cte_qreadable(ct_equeue_t *q, ct_listener_t *l, const cred_t *cr,
19447c478bd9Sstevel@tonic-gate uint64_t zuniqid, int crit)
19457c478bd9Sstevel@tonic-gate {
19467c478bd9Sstevel@tonic-gate ct_kevent_t *e, *next;
19477c478bd9Sstevel@tonic-gate contract_t *ct;
19487c478bd9Sstevel@tonic-gate
19497c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock));
19507c478bd9Sstevel@tonic-gate ASSERT(l->ctl_equeue == q);
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_COPYOUT)
19537c478bd9Sstevel@tonic-gate return (1);
19547c478bd9Sstevel@tonic-gate
19557c478bd9Sstevel@tonic-gate next = l->ctl_position;
19567c478bd9Sstevel@tonic-gate while (e = cte_qmove(q, l, next)) {
19577c478bd9Sstevel@tonic-gate ct = e->cte_contract;
19587c478bd9Sstevel@tonic-gate /*
19597c478bd9Sstevel@tonic-gate * Check obvious things first. If we are looking for a
19607c478bd9Sstevel@tonic-gate * critical message, is this one? If we aren't in the
19617c478bd9Sstevel@tonic-gate * global zone, is this message meant for us?
19627c478bd9Sstevel@tonic-gate */
19637c478bd9Sstevel@tonic-gate if ((crit && (e->cte_flags & (CTE_INFO | CTE_ACK))) ||
19647c478bd9Sstevel@tonic-gate (cr != NULL && zuniqid != GLOBAL_ZONEUNIQID &&
19657c478bd9Sstevel@tonic-gate zuniqid != contract_getzuniqid(ct))) {
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e);
19687c478bd9Sstevel@tonic-gate
19697c478bd9Sstevel@tonic-gate /*
19707c478bd9Sstevel@tonic-gate * Next, see if our effective uid equals that of owner
19717c478bd9Sstevel@tonic-gate * or author of the contract. Since we are holding the
19727c478bd9Sstevel@tonic-gate * queue lock, contract_owned can't always check if we
19737c478bd9Sstevel@tonic-gate * have the same effective uid as the contract's
19747c478bd9Sstevel@tonic-gate * owner. If it comes to that, it fails and we take
19757c478bd9Sstevel@tonic-gate * the slow(er) path.
19767c478bd9Sstevel@tonic-gate */
19777c478bd9Sstevel@tonic-gate } else if (cr != NULL && !contract_owned(ct, cr, B_TRUE)) {
19787c478bd9Sstevel@tonic-gate
19797c478bd9Sstevel@tonic-gate /*
19807c478bd9Sstevel@tonic-gate * At this point we either don't have any claim
19817c478bd9Sstevel@tonic-gate * to this contract or we match the effective
19827c478bd9Sstevel@tonic-gate * uid of the owner but couldn't tell. We
19837c478bd9Sstevel@tonic-gate * first test for a NULL holder so that events
19847c478bd9Sstevel@tonic-gate * from orphans and inherited contracts avoid
19857c478bd9Sstevel@tonic-gate * the penalty phase.
19867c478bd9Sstevel@tonic-gate */
19877c478bd9Sstevel@tonic-gate if (e->cte_contract->ct_owner == NULL &&
19887c478bd9Sstevel@tonic-gate !secpolicy_contract_observer_choice(cr))
19897c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e);
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate /*
19927c478bd9Sstevel@tonic-gate * cte_checkcred will juggle locks to see if we
19937c478bd9Sstevel@tonic-gate * have the same uid as the event's contract's
19947c478bd9Sstevel@tonic-gate * current owner. If it succeeds, we have to
19957c478bd9Sstevel@tonic-gate * make sure we are in the same point in the
19967c478bd9Sstevel@tonic-gate * queue.
19977c478bd9Sstevel@tonic-gate */
19987c478bd9Sstevel@tonic-gate else if (cte_checkcred(q, e, cr) &&
19997c478bd9Sstevel@tonic-gate l->ctl_position == e)
20007c478bd9Sstevel@tonic-gate break;
20017c478bd9Sstevel@tonic-gate
20027c478bd9Sstevel@tonic-gate /*
20037c478bd9Sstevel@tonic-gate * cte_checkcred failed; see if we're in the
20047c478bd9Sstevel@tonic-gate * same place.
20057c478bd9Sstevel@tonic-gate */
20067c478bd9Sstevel@tonic-gate else if (l->ctl_position == e)
20077c478bd9Sstevel@tonic-gate if (secpolicy_contract_observer_choice(cr))
20087c478bd9Sstevel@tonic-gate break;
20097c478bd9Sstevel@tonic-gate else
20107c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e);
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate /*
20137c478bd9Sstevel@tonic-gate * cte_checkcred failed, and our position was
20147c478bd9Sstevel@tonic-gate * changed. Start from there.
20157c478bd9Sstevel@tonic-gate */
20167c478bd9Sstevel@tonic-gate else
20177c478bd9Sstevel@tonic-gate next = l->ctl_position;
20187c478bd9Sstevel@tonic-gate } else {
20197c478bd9Sstevel@tonic-gate break;
20207c478bd9Sstevel@tonic-gate }
20217c478bd9Sstevel@tonic-gate }
20227c478bd9Sstevel@tonic-gate
20237c478bd9Sstevel@tonic-gate /*
20247c478bd9Sstevel@tonic-gate * We check for CTLF_COPYOUT again in case we dropped the queue
20257c478bd9Sstevel@tonic-gate * lock in cte_checkcred.
20267c478bd9Sstevel@tonic-gate */
20277c478bd9Sstevel@tonic-gate return ((l->ctl_flags & CTLF_COPYOUT) || (l->ctl_position == NULL));
20287c478bd9Sstevel@tonic-gate }
20297c478bd9Sstevel@tonic-gate
20307c478bd9Sstevel@tonic-gate /*
20317c478bd9Sstevel@tonic-gate * cte_qwakeup
20327c478bd9Sstevel@tonic-gate *
20337c478bd9Sstevel@tonic-gate * Wakes up any waiting listeners and points them at the specified event.
20347c478bd9Sstevel@tonic-gate */
20357c478bd9Sstevel@tonic-gate static void
cte_qwakeup(ct_equeue_t * q,ct_kevent_t * e)20367c478bd9Sstevel@tonic-gate cte_qwakeup(ct_equeue_t *q, ct_kevent_t *e)
20377c478bd9Sstevel@tonic-gate {
20387c478bd9Sstevel@tonic-gate ct_listener_t *l;
20397c478bd9Sstevel@tonic-gate
20407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock));
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate while (l = list_head(&q->ctq_tail)) {
20437c478bd9Sstevel@tonic-gate list_remove(&q->ctq_tail, l);
20447c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_refs++;
20457c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE)
20467c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_nreliable++;
20477c478bd9Sstevel@tonic-gate l->ctl_position = e;
20487c478bd9Sstevel@tonic-gate cv_signal(&l->ctl_cv);
20497c478bd9Sstevel@tonic-gate pollwakeup(&l->ctl_pollhead, POLLIN);
20507c478bd9Sstevel@tonic-gate }
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate
20537c478bd9Sstevel@tonic-gate /*
20547c478bd9Sstevel@tonic-gate * cte_copy
20557c478bd9Sstevel@tonic-gate *
20567c478bd9Sstevel@tonic-gate * Copies events from the specified contract event queue to the
20577c478bd9Sstevel@tonic-gate * end of the specified process bundle queue. Only called from
20587c478bd9Sstevel@tonic-gate * contract_adopt.
20597c478bd9Sstevel@tonic-gate *
20607c478bd9Sstevel@tonic-gate * We copy to the end of the target queue instead of mixing the events
20617c478bd9Sstevel@tonic-gate * in their proper order because otherwise the act of adopting a
20627c478bd9Sstevel@tonic-gate * contract would require a process to reset all process bundle
20637c478bd9Sstevel@tonic-gate * listeners it needed to see the new events. This would, in turn,
20647c478bd9Sstevel@tonic-gate * require the process to keep track of which preexisting events had
20657c478bd9Sstevel@tonic-gate * already been processed.
20667c478bd9Sstevel@tonic-gate */
20677c478bd9Sstevel@tonic-gate static void
cte_copy(ct_equeue_t * q,ct_equeue_t * newq)20687c478bd9Sstevel@tonic-gate cte_copy(ct_equeue_t *q, ct_equeue_t *newq)
20697c478bd9Sstevel@tonic-gate {
20707c478bd9Sstevel@tonic-gate ct_kevent_t *e, *first = NULL;
20717c478bd9Sstevel@tonic-gate
2072a81df0a5SJerry Jelinek VERIFY(q->ctq_listno == CTEL_CONTRACT);
2073a81df0a5SJerry Jelinek VERIFY(newq->ctq_listno == CTEL_PBUNDLE);
20747c478bd9Sstevel@tonic-gate
20757c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
20767c478bd9Sstevel@tonic-gate mutex_enter(&newq->ctq_lock);
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate /*
20797c478bd9Sstevel@tonic-gate * For now, only copy critical events.
20807c478bd9Sstevel@tonic-gate */
20817c478bd9Sstevel@tonic-gate for (e = list_head(&q->ctq_events); e != NULL;
20827c478bd9Sstevel@tonic-gate e = list_next(&q->ctq_events, e)) {
20837c478bd9Sstevel@tonic-gate if ((e->cte_flags & (CTE_INFO | CTE_ACK)) == 0) {
20847c478bd9Sstevel@tonic-gate if (first == NULL)
20857c478bd9Sstevel@tonic-gate first = e;
2086a81df0a5SJerry Jelinek /*
2087a81df0a5SJerry Jelinek * It is possible for adoption to race with an owner's
2088a81df0a5SJerry Jelinek * cte_publish_all(); we must only enqueue events that
2089a81df0a5SJerry Jelinek * have not already been enqueued.
2090a81df0a5SJerry Jelinek */
2091a81df0a5SJerry Jelinek if (!list_link_active((list_node_t *)
2092a81df0a5SJerry Jelinek ((uintptr_t)e + newq->ctq_events.list_offset))) {
20937c478bd9Sstevel@tonic-gate list_insert_tail(&newq->ctq_events, e);
20947c478bd9Sstevel@tonic-gate cte_hold(e);
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate }
2097a81df0a5SJerry Jelinek }
20987c478bd9Sstevel@tonic-gate
20997c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
21007c478bd9Sstevel@tonic-gate
21017c478bd9Sstevel@tonic-gate if (first)
21027c478bd9Sstevel@tonic-gate cte_qwakeup(newq, first);
21037c478bd9Sstevel@tonic-gate
21047c478bd9Sstevel@tonic-gate mutex_exit(&newq->ctq_lock);
21057c478bd9Sstevel@tonic-gate }
21067c478bd9Sstevel@tonic-gate
21077c478bd9Sstevel@tonic-gate /*
21087c478bd9Sstevel@tonic-gate * cte_trim
21097c478bd9Sstevel@tonic-gate *
21107c478bd9Sstevel@tonic-gate * Trims unneeded events from an event queue. Algorithm works as
21117c478bd9Sstevel@tonic-gate * follows:
21127c478bd9Sstevel@tonic-gate *
21137c478bd9Sstevel@tonic-gate * Removes all informative and acknowledged critical events until the
21147c478bd9Sstevel@tonic-gate * first referenced event is found.
21157c478bd9Sstevel@tonic-gate *
21167c478bd9Sstevel@tonic-gate * If a contract is specified, removes all events (regardless of
21177c478bd9Sstevel@tonic-gate * acknowledgement) generated by that contract until the first event
21187c478bd9Sstevel@tonic-gate * referenced by a reliable listener is found. Reference events are
21197c478bd9Sstevel@tonic-gate * removed by marking them "trimmed". Such events will be removed
21207c478bd9Sstevel@tonic-gate * when the last reference is dropped and will be skipped by future
21217c478bd9Sstevel@tonic-gate * listeners.
21227c478bd9Sstevel@tonic-gate *
21237c478bd9Sstevel@tonic-gate * This is pretty basic. Ideally this should remove from the middle of
21247c478bd9Sstevel@tonic-gate * the list (i.e. beyond the first referenced event), and even
21257c478bd9Sstevel@tonic-gate * referenced events.
21267c478bd9Sstevel@tonic-gate */
21277c478bd9Sstevel@tonic-gate static void
cte_trim(ct_equeue_t * q,contract_t * ct)21287c478bd9Sstevel@tonic-gate cte_trim(ct_equeue_t *q, contract_t *ct)
21297c478bd9Sstevel@tonic-gate {
21307c478bd9Sstevel@tonic-gate ct_kevent_t *e, *next;
21317c478bd9Sstevel@tonic-gate int flags, stopper;
21327c478bd9Sstevel@tonic-gate int start = 1;
21337c478bd9Sstevel@tonic-gate
2134a81df0a5SJerry Jelinek VERIFY(MUTEX_HELD(&q->ctq_lock));
21357c478bd9Sstevel@tonic-gate
21367c478bd9Sstevel@tonic-gate for (e = list_head(&q->ctq_events); e != NULL; e = next) {
21377c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e);
21387c478bd9Sstevel@tonic-gate flags = e->cte_flags;
21397c478bd9Sstevel@tonic-gate stopper = (q->ctq_listno != CTEL_PBUNDLE) &&
21407c478bd9Sstevel@tonic-gate (e->cte_nodes[q->ctq_listno].ctm_nreliable > 0);
21417c478bd9Sstevel@tonic-gate if (e->cte_nodes[q->ctq_listno].ctm_refs == 0) {
21427c478bd9Sstevel@tonic-gate if ((start && (flags & (CTE_INFO | CTE_ACK))) ||
21437c478bd9Sstevel@tonic-gate (e->cte_contract == ct)) {
21447c478bd9Sstevel@tonic-gate /*
21457c478bd9Sstevel@tonic-gate * Toss informative and ACKed critical messages.
21467c478bd9Sstevel@tonic-gate */
21477c478bd9Sstevel@tonic-gate list_remove(&q->ctq_events, e);
21487c478bd9Sstevel@tonic-gate cte_rele(e);
21497c478bd9Sstevel@tonic-gate }
21507c478bd9Sstevel@tonic-gate } else if ((e->cte_contract == ct) && !stopper) {
21517c478bd9Sstevel@tonic-gate ASSERT(q->ctq_nlisteners != 0);
21527c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_trimmed = 1;
21537c478bd9Sstevel@tonic-gate } else if (ct && !stopper) {
21547c478bd9Sstevel@tonic-gate start = 0;
21557c478bd9Sstevel@tonic-gate } else {
21567c478bd9Sstevel@tonic-gate /*
21577c478bd9Sstevel@tonic-gate * Don't free messages past the first reader.
21587c478bd9Sstevel@tonic-gate */
21597c478bd9Sstevel@tonic-gate break;
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate }
21627c478bd9Sstevel@tonic-gate }
21637c478bd9Sstevel@tonic-gate
21647c478bd9Sstevel@tonic-gate /*
21657c478bd9Sstevel@tonic-gate * cte_queue_drain
21667c478bd9Sstevel@tonic-gate *
21677c478bd9Sstevel@tonic-gate * Drain all events from the specified queue, and mark it dead. If
21687c478bd9Sstevel@tonic-gate * "ack" is set, acknowledge any critical events we find along the
21697c478bd9Sstevel@tonic-gate * way.
21707c478bd9Sstevel@tonic-gate */
21717c478bd9Sstevel@tonic-gate static void
cte_queue_drain(ct_equeue_t * q,int ack)21727c478bd9Sstevel@tonic-gate cte_queue_drain(ct_equeue_t *q, int ack)
21737c478bd9Sstevel@tonic-gate {
21747c478bd9Sstevel@tonic-gate ct_kevent_t *e, *next;
21757c478bd9Sstevel@tonic-gate ct_listener_t *l;
21767c478bd9Sstevel@tonic-gate
21777c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
21787c478bd9Sstevel@tonic-gate
21797c478bd9Sstevel@tonic-gate for (e = list_head(&q->ctq_events); e != NULL; e = next) {
21807c478bd9Sstevel@tonic-gate next = list_next(&q->ctq_events, e);
21817c478bd9Sstevel@tonic-gate if (ack && ((e->cte_flags & (CTE_INFO | CTE_ACK)) == 0)) {
21827c478bd9Sstevel@tonic-gate /*
21837c478bd9Sstevel@tonic-gate * Make sure critical messages are eventually
21847c478bd9Sstevel@tonic-gate * removed from the bundle queues.
21857c478bd9Sstevel@tonic-gate */
21867c478bd9Sstevel@tonic-gate mutex_enter(&e->cte_lock);
21877c478bd9Sstevel@tonic-gate e->cte_flags |= CTE_ACK;
21887c478bd9Sstevel@tonic-gate mutex_exit(&e->cte_lock);
21897c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&e->cte_contract->ct_lock));
21907c478bd9Sstevel@tonic-gate e->cte_contract->ct_evcnt--;
21917c478bd9Sstevel@tonic-gate }
21927c478bd9Sstevel@tonic-gate list_remove(&q->ctq_events, e);
21937c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_refs = 0;
21947c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_nreliable = 0;
21957c478bd9Sstevel@tonic-gate e->cte_nodes[q->ctq_listno].ctm_trimmed = 0;
21967c478bd9Sstevel@tonic-gate cte_rele(e);
21977c478bd9Sstevel@tonic-gate }
21987c478bd9Sstevel@tonic-gate
21997c478bd9Sstevel@tonic-gate /*
22007c478bd9Sstevel@tonic-gate * This is necessary only because of CTEL_PBUNDLE listeners;
22017c478bd9Sstevel@tonic-gate * the events they point to can move from one pbundle to
22027c478bd9Sstevel@tonic-gate * another. Fortunately, this only happens if the contract is
22037c478bd9Sstevel@tonic-gate * inherited, which (in turn) only happens if the process
22047c478bd9Sstevel@tonic-gate * exits, which means it's an all-or-nothing deal. If this
22057c478bd9Sstevel@tonic-gate * wasn't the case, we would instead need to keep track of
22067c478bd9Sstevel@tonic-gate * listeners on a per-event basis, not just a per-queue basis.
22077c478bd9Sstevel@tonic-gate * This would have the side benefit of letting us clean up
22087c478bd9Sstevel@tonic-gate * trimmed events sooner (i.e. immediately), but would
22097c478bd9Sstevel@tonic-gate * unfortunately make events even bigger than they already
22107c478bd9Sstevel@tonic-gate * are.
22117c478bd9Sstevel@tonic-gate */
22127c478bd9Sstevel@tonic-gate for (l = list_head(&q->ctq_listeners); l;
22137c478bd9Sstevel@tonic-gate l = list_next(&q->ctq_listeners, l)) {
22147c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_DEAD;
22157c478bd9Sstevel@tonic-gate if (l->ctl_position) {
22167c478bd9Sstevel@tonic-gate l->ctl_position = NULL;
22177c478bd9Sstevel@tonic-gate list_insert_tail(&q->ctq_tail, l);
22187c478bd9Sstevel@tonic-gate }
22197c478bd9Sstevel@tonic-gate cv_broadcast(&l->ctl_cv);
22207c478bd9Sstevel@tonic-gate }
22217c478bd9Sstevel@tonic-gate
22227c478bd9Sstevel@tonic-gate /*
22237c478bd9Sstevel@tonic-gate * Disallow events.
22247c478bd9Sstevel@tonic-gate */
22257c478bd9Sstevel@tonic-gate q->ctq_flags |= CTQ_DEAD;
22267c478bd9Sstevel@tonic-gate
22277c478bd9Sstevel@tonic-gate /*
22287c478bd9Sstevel@tonic-gate * If we represent the last reference to a reference counted
22297c478bd9Sstevel@tonic-gate * process bundle queue, free it.
22307c478bd9Sstevel@tonic-gate */
22317c478bd9Sstevel@tonic-gate if ((q->ctq_flags & CTQ_REFFED) && (q->ctq_nlisteners == 0))
22327c478bd9Sstevel@tonic-gate cte_queue_destroy(q);
22337c478bd9Sstevel@tonic-gate else
22347c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate
22377c478bd9Sstevel@tonic-gate /*
22387c478bd9Sstevel@tonic-gate * cte_publish
22397c478bd9Sstevel@tonic-gate *
22407c478bd9Sstevel@tonic-gate * Publishes an event to a specific queue. Only called by
22417c478bd9Sstevel@tonic-gate * cte_publish_all.
22427c478bd9Sstevel@tonic-gate */
22437c478bd9Sstevel@tonic-gate static void
cte_publish(ct_equeue_t * q,ct_kevent_t * e,timespec_t * tsp,boolean_t mayexist)2244a81df0a5SJerry Jelinek cte_publish(ct_equeue_t *q, ct_kevent_t *e, timespec_t *tsp, boolean_t mayexist)
22457c478bd9Sstevel@tonic-gate {
22467c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&q->ctq_lock));
22477c478bd9Sstevel@tonic-gate
22487c478bd9Sstevel@tonic-gate q->ctq_atime = *tsp;
22497c478bd9Sstevel@tonic-gate
22507c478bd9Sstevel@tonic-gate /*
2251a81df0a5SJerry Jelinek * If this event may already exist on this queue, check to see if it
2252a81df0a5SJerry Jelinek * is already there and return if so.
2253a81df0a5SJerry Jelinek */
2254a81df0a5SJerry Jelinek if (mayexist && list_link_active((list_node_t *)((uintptr_t)e +
2255a81df0a5SJerry Jelinek q->ctq_events.list_offset))) {
2256a81df0a5SJerry Jelinek mutex_exit(&q->ctq_lock);
2257a81df0a5SJerry Jelinek cte_rele(e);
2258a81df0a5SJerry Jelinek return;
2259a81df0a5SJerry Jelinek }
2260a81df0a5SJerry Jelinek
2261a81df0a5SJerry Jelinek /*
22627c478bd9Sstevel@tonic-gate * Don't publish if the event is informative and there aren't
22637c478bd9Sstevel@tonic-gate * any listeners, or if the queue has been shut down.
22647c478bd9Sstevel@tonic-gate */
22657c478bd9Sstevel@tonic-gate if (((q->ctq_nlisteners == 0) && (e->cte_flags & (CTE_INFO|CTE_ACK))) ||
22667c478bd9Sstevel@tonic-gate (q->ctq_flags & CTQ_DEAD)) {
22677c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
22687c478bd9Sstevel@tonic-gate cte_rele(e);
22697c478bd9Sstevel@tonic-gate return;
22707c478bd9Sstevel@tonic-gate }
22717c478bd9Sstevel@tonic-gate
22727c478bd9Sstevel@tonic-gate /*
22737c478bd9Sstevel@tonic-gate * Enqueue event
22747c478bd9Sstevel@tonic-gate */
2275a81df0a5SJerry Jelinek VERIFY(!list_link_active((list_node_t *)
2276a81df0a5SJerry Jelinek ((uintptr_t)e + q->ctq_events.list_offset)));
22777c478bd9Sstevel@tonic-gate list_insert_tail(&q->ctq_events, e);
22787c478bd9Sstevel@tonic-gate
22797c478bd9Sstevel@tonic-gate /*
22807c478bd9Sstevel@tonic-gate * Check for waiting listeners
22817c478bd9Sstevel@tonic-gate */
22827c478bd9Sstevel@tonic-gate cte_qwakeup(q, e);
22837c478bd9Sstevel@tonic-gate
22847c478bd9Sstevel@tonic-gate /*
22857c478bd9Sstevel@tonic-gate * Trim unnecessary events from the queue.
22867c478bd9Sstevel@tonic-gate */
22877c478bd9Sstevel@tonic-gate cte_trim(q, NULL);
22887c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
22897c478bd9Sstevel@tonic-gate }
22907c478bd9Sstevel@tonic-gate
22917c478bd9Sstevel@tonic-gate /*
22927c478bd9Sstevel@tonic-gate * cte_publish_all
22937c478bd9Sstevel@tonic-gate *
22947c478bd9Sstevel@tonic-gate * Publish an event to all necessary event queues. The event, e, must
22957c478bd9Sstevel@tonic-gate * be zallocated by the caller, and the event's flags and type must be
22967c478bd9Sstevel@tonic-gate * set. The rest of the event's fields are initialized here.
22977c478bd9Sstevel@tonic-gate */
229825e8c5aaSvikram uint64_t
cte_publish_all(contract_t * ct,ct_kevent_t * e,nvlist_t * data,nvlist_t * gdata)22997c478bd9Sstevel@tonic-gate cte_publish_all(contract_t *ct, ct_kevent_t *e, nvlist_t *data, nvlist_t *gdata)
23007c478bd9Sstevel@tonic-gate {
23017c478bd9Sstevel@tonic-gate ct_equeue_t *q;
23027c478bd9Sstevel@tonic-gate timespec_t ts;
230325e8c5aaSvikram uint64_t evid;
230425e8c5aaSvikram ct_kevent_t *negev;
230525e8c5aaSvikram int negend;
23067c478bd9Sstevel@tonic-gate
23077c478bd9Sstevel@tonic-gate e->cte_contract = ct;
23087c478bd9Sstevel@tonic-gate e->cte_data = data;
23097c478bd9Sstevel@tonic-gate e->cte_gdata = gdata;
23107c478bd9Sstevel@tonic-gate e->cte_refs = 3;
23111a5e258fSJosef 'Jeff' Sipek evid = e->cte_id = atomic_inc_64_nv(&ct->ct_type->ct_type_evid);
23127c478bd9Sstevel@tonic-gate contract_hold(ct);
23137c478bd9Sstevel@tonic-gate
231425e8c5aaSvikram /*
231525e8c5aaSvikram * For a negotiation event we set the ct->ct_nevent field of the
231625e8c5aaSvikram * contract for the duration of the negotiation
231725e8c5aaSvikram */
231825e8c5aaSvikram negend = 0;
231925e8c5aaSvikram if (e->cte_flags & CTE_NEG) {
232025e8c5aaSvikram cte_hold(e);
232125e8c5aaSvikram ct->ct_nevent = e;
232225e8c5aaSvikram } else if (e->cte_type == CT_EV_NEGEND) {
232325e8c5aaSvikram negend = 1;
232425e8c5aaSvikram }
232525e8c5aaSvikram
23267c478bd9Sstevel@tonic-gate gethrestime(&ts);
23277c478bd9Sstevel@tonic-gate
23287c478bd9Sstevel@tonic-gate /*
23297c478bd9Sstevel@tonic-gate * ct_evtlock simply (and only) ensures that two events sent
23307c478bd9Sstevel@tonic-gate * from the same contract are delivered to all queues in the
23317c478bd9Sstevel@tonic-gate * same order.
23327c478bd9Sstevel@tonic-gate */
23337c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_evtlock);
23347c478bd9Sstevel@tonic-gate
23357c478bd9Sstevel@tonic-gate /*
23367c478bd9Sstevel@tonic-gate * CTEL_CONTRACT - First deliver to the contract queue, acking
23377c478bd9Sstevel@tonic-gate * the event if the contract has been orphaned.
23387c478bd9Sstevel@tonic-gate */
23397c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
23407c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_events.ctq_lock);
23417c478bd9Sstevel@tonic-gate if ((e->cte_flags & CTE_INFO) == 0) {
23427c478bd9Sstevel@tonic-gate if (ct->ct_state >= CTS_ORPHAN)
23437c478bd9Sstevel@tonic-gate e->cte_flags |= CTE_ACK;
23447c478bd9Sstevel@tonic-gate else
23457c478bd9Sstevel@tonic-gate ct->ct_evcnt++;
23467c478bd9Sstevel@tonic-gate }
23477c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
2348a81df0a5SJerry Jelinek cte_publish(&ct->ct_events, e, &ts, B_FALSE);
23497c478bd9Sstevel@tonic-gate
23507c478bd9Sstevel@tonic-gate /*
23517c478bd9Sstevel@tonic-gate * CTEL_BUNDLE - Next deliver to the contract type's bundle
23527c478bd9Sstevel@tonic-gate * queue.
23537c478bd9Sstevel@tonic-gate */
23547c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_type->ct_type_events.ctq_lock);
2355a81df0a5SJerry Jelinek cte_publish(&ct->ct_type->ct_type_events, e, &ts, B_FALSE);
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate /*
23587c478bd9Sstevel@tonic-gate * CTEL_PBUNDLE - Finally, if the contract has an owner,
23597c478bd9Sstevel@tonic-gate * deliver to the owner's process bundle queue.
23607c478bd9Sstevel@tonic-gate */
23617c478bd9Sstevel@tonic-gate mutex_enter(&ct->ct_lock);
23627c478bd9Sstevel@tonic-gate if (ct->ct_owner) {
23637c478bd9Sstevel@tonic-gate /*
23647c478bd9Sstevel@tonic-gate * proc_exit doesn't free event queues until it has
23657c478bd9Sstevel@tonic-gate * abandoned all contracts.
23667c478bd9Sstevel@tonic-gate */
23677c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue);
23687c478bd9Sstevel@tonic-gate ASSERT(ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index]);
23697c478bd9Sstevel@tonic-gate q = ct->ct_owner->p_ct_equeue[ct->ct_type->ct_type_index];
23707c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
23717c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
2372a81df0a5SJerry Jelinek
2373a81df0a5SJerry Jelinek /*
2374a81df0a5SJerry Jelinek * It is possible for this code to race with adoption; we
2375a81df0a5SJerry Jelinek * publish the event indicating that the event may already
2376a81df0a5SJerry Jelinek * be enqueued because adoption beat us to it (in which case
2377a81df0a5SJerry Jelinek * cte_pubish() does nothing).
2378a81df0a5SJerry Jelinek */
2379a81df0a5SJerry Jelinek cte_publish(q, e, &ts, B_TRUE);
23807c478bd9Sstevel@tonic-gate } else {
23817c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_lock);
23827c478bd9Sstevel@tonic-gate cte_rele(e);
23837c478bd9Sstevel@tonic-gate }
23847c478bd9Sstevel@tonic-gate
238525e8c5aaSvikram if (negend) {
238625e8c5aaSvikram mutex_enter(&ct->ct_lock);
238725e8c5aaSvikram negev = ct->ct_nevent;
238825e8c5aaSvikram ct->ct_nevent = NULL;
238925e8c5aaSvikram cte_rele(negev);
239025e8c5aaSvikram mutex_exit(&ct->ct_lock);
239125e8c5aaSvikram }
239225e8c5aaSvikram
23937c478bd9Sstevel@tonic-gate mutex_exit(&ct->ct_evtlock);
239425e8c5aaSvikram
239525e8c5aaSvikram return (evid);
23967c478bd9Sstevel@tonic-gate }
23977c478bd9Sstevel@tonic-gate
23987c478bd9Sstevel@tonic-gate /*
23997c478bd9Sstevel@tonic-gate * cte_add_listener
24007c478bd9Sstevel@tonic-gate *
24017c478bd9Sstevel@tonic-gate * Add a new listener to an event queue.
24027c478bd9Sstevel@tonic-gate */
24037c478bd9Sstevel@tonic-gate void
cte_add_listener(ct_equeue_t * q,ct_listener_t * l)24047c478bd9Sstevel@tonic-gate cte_add_listener(ct_equeue_t *q, ct_listener_t *l)
24057c478bd9Sstevel@tonic-gate {
24067c478bd9Sstevel@tonic-gate cv_init(&l->ctl_cv, NULL, CV_DEFAULT, NULL);
24077c478bd9Sstevel@tonic-gate l->ctl_equeue = q;
24087c478bd9Sstevel@tonic-gate l->ctl_position = NULL;
24097c478bd9Sstevel@tonic-gate l->ctl_flags = 0;
24107c478bd9Sstevel@tonic-gate
24117c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
24127c478bd9Sstevel@tonic-gate list_insert_head(&q->ctq_tail, l);
24137c478bd9Sstevel@tonic-gate list_insert_head(&q->ctq_listeners, l);
24147c478bd9Sstevel@tonic-gate q->ctq_nlisteners++;
24157c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
24167c478bd9Sstevel@tonic-gate }
24177c478bd9Sstevel@tonic-gate
24187c478bd9Sstevel@tonic-gate /*
24197c478bd9Sstevel@tonic-gate * cte_remove_listener
24207c478bd9Sstevel@tonic-gate *
24217c478bd9Sstevel@tonic-gate * Remove a listener from an event queue. No other queue activities
24227c478bd9Sstevel@tonic-gate * (e.g. cte_get event) may be in progress at this endpoint when this
24237c478bd9Sstevel@tonic-gate * is called.
24247c478bd9Sstevel@tonic-gate */
24257c478bd9Sstevel@tonic-gate void
cte_remove_listener(ct_listener_t * l)24267c478bd9Sstevel@tonic-gate cte_remove_listener(ct_listener_t *l)
24277c478bd9Sstevel@tonic-gate {
24287c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue;
24297c478bd9Sstevel@tonic-gate ct_kevent_t *e;
24307c478bd9Sstevel@tonic-gate
24317c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
24327c478bd9Sstevel@tonic-gate
24337c478bd9Sstevel@tonic-gate ASSERT((l->ctl_flags & (CTLF_COPYOUT|CTLF_RESET)) == 0);
24347c478bd9Sstevel@tonic-gate
24357c478bd9Sstevel@tonic-gate if ((e = l->ctl_position) != NULL)
24367c478bd9Sstevel@tonic-gate cte_qrele(q, l, e);
24377c478bd9Sstevel@tonic-gate else
24387c478bd9Sstevel@tonic-gate list_remove(&q->ctq_tail, l);
24397c478bd9Sstevel@tonic-gate l->ctl_position = NULL;
24407c478bd9Sstevel@tonic-gate
24417c478bd9Sstevel@tonic-gate q->ctq_nlisteners--;
24427c478bd9Sstevel@tonic-gate list_remove(&q->ctq_listeners, l);
24437c478bd9Sstevel@tonic-gate
24447c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_RELIABLE)
24457c478bd9Sstevel@tonic-gate q->ctq_nreliable--;
24467c478bd9Sstevel@tonic-gate
24477c478bd9Sstevel@tonic-gate /*
24487c478bd9Sstevel@tonic-gate * If we are a the last listener of a dead reference counted
24497c478bd9Sstevel@tonic-gate * queue (i.e. a process bundle) we free it. Otherwise we just
24507c478bd9Sstevel@tonic-gate * trim any events which may have been kept around for our
24517c478bd9Sstevel@tonic-gate * benefit.
24527c478bd9Sstevel@tonic-gate */
24537c478bd9Sstevel@tonic-gate if ((q->ctq_flags & CTQ_REFFED) && (q->ctq_flags & CTQ_DEAD) &&
24547c478bd9Sstevel@tonic-gate (q->ctq_nlisteners == 0)) {
24557c478bd9Sstevel@tonic-gate cte_queue_destroy(q);
24567c478bd9Sstevel@tonic-gate } else {
24577c478bd9Sstevel@tonic-gate cte_trim(q, NULL);
24587c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
24597c478bd9Sstevel@tonic-gate }
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate /*
24637c478bd9Sstevel@tonic-gate * cte_reset_listener
24647c478bd9Sstevel@tonic-gate *
24657c478bd9Sstevel@tonic-gate * Moves a listener's queue pointer to the beginning of the queue.
24667c478bd9Sstevel@tonic-gate */
24677c478bd9Sstevel@tonic-gate void
cte_reset_listener(ct_listener_t * l)24687c478bd9Sstevel@tonic-gate cte_reset_listener(ct_listener_t *l)
24697c478bd9Sstevel@tonic-gate {
24707c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue;
24717c478bd9Sstevel@tonic-gate
24727c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
24737c478bd9Sstevel@tonic-gate
24747c478bd9Sstevel@tonic-gate /*
24757c478bd9Sstevel@tonic-gate * We allow an asynchronous reset because it doesn't make a
24767c478bd9Sstevel@tonic-gate * whole lot of sense to make reset block or fail. We already
24777c478bd9Sstevel@tonic-gate * have most of the mechanism needed thanks to queue trimming,
24787c478bd9Sstevel@tonic-gate * so implementing it isn't a big deal.
24797c478bd9Sstevel@tonic-gate */
24807c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_COPYOUT)
24817c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_RESET;
24827c478bd9Sstevel@tonic-gate
24837c478bd9Sstevel@tonic-gate (void) cte_qmove(q, l, list_head(&q->ctq_events));
24847c478bd9Sstevel@tonic-gate
24857c478bd9Sstevel@tonic-gate /*
24867c478bd9Sstevel@tonic-gate * Inform blocked readers.
24877c478bd9Sstevel@tonic-gate */
24887c478bd9Sstevel@tonic-gate cv_broadcast(&l->ctl_cv);
24897c478bd9Sstevel@tonic-gate pollwakeup(&l->ctl_pollhead, POLLIN);
24907c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
24917c478bd9Sstevel@tonic-gate }
24927c478bd9Sstevel@tonic-gate
24937c478bd9Sstevel@tonic-gate /*
24947c478bd9Sstevel@tonic-gate * cte_next_event
24957c478bd9Sstevel@tonic-gate *
24967c478bd9Sstevel@tonic-gate * Moves the event pointer for the specified listener to the next event
24977c478bd9Sstevel@tonic-gate * on the queue. To avoid races, this movement only occurs if the
24987c478bd9Sstevel@tonic-gate * specified event id matches that of the current event. This is used
24997c478bd9Sstevel@tonic-gate * primarily to skip events that have been read but whose extended data
25007c478bd9Sstevel@tonic-gate * haven't been copied out.
25017c478bd9Sstevel@tonic-gate */
25027c478bd9Sstevel@tonic-gate int
cte_next_event(ct_listener_t * l,uint64_t id)25037c478bd9Sstevel@tonic-gate cte_next_event(ct_listener_t *l, uint64_t id)
25047c478bd9Sstevel@tonic-gate {
25057c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue;
25067c478bd9Sstevel@tonic-gate ct_kevent_t *old;
25077c478bd9Sstevel@tonic-gate
25087c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
25097c478bd9Sstevel@tonic-gate
25107c478bd9Sstevel@tonic-gate if (l->ctl_flags & CTLF_COPYOUT)
25117c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_RESET;
25127c478bd9Sstevel@tonic-gate
25137c478bd9Sstevel@tonic-gate if (((old = l->ctl_position) != NULL) && (old->cte_id == id))
25147c478bd9Sstevel@tonic-gate (void) cte_qmove(q, l, list_next(&q->ctq_events, old));
25157c478bd9Sstevel@tonic-gate
25167c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
25177c478bd9Sstevel@tonic-gate
25187c478bd9Sstevel@tonic-gate return (0);
25197c478bd9Sstevel@tonic-gate }
25207c478bd9Sstevel@tonic-gate
25217c478bd9Sstevel@tonic-gate /*
25227c478bd9Sstevel@tonic-gate * cte_get_event
25237c478bd9Sstevel@tonic-gate *
25247c478bd9Sstevel@tonic-gate * Reads an event from an event endpoint. If "nonblock" is clear, we
25257c478bd9Sstevel@tonic-gate * block until a suitable event is ready. If "crit" is set, we only
25267c478bd9Sstevel@tonic-gate * read critical events. Note that while "cr" is the caller's cred,
25277c478bd9Sstevel@tonic-gate * "zuniqid" is the unique id of the zone the calling contract
25287c478bd9Sstevel@tonic-gate * filesystem was mounted in.
25297c478bd9Sstevel@tonic-gate */
25307c478bd9Sstevel@tonic-gate int
cte_get_event(ct_listener_t * l,int nonblock,void * uaddr,const cred_t * cr,uint64_t zuniqid,int crit)25317c478bd9Sstevel@tonic-gate cte_get_event(ct_listener_t *l, int nonblock, void *uaddr, const cred_t *cr,
25327c478bd9Sstevel@tonic-gate uint64_t zuniqid, int crit)
25337c478bd9Sstevel@tonic-gate {
25347c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue;
25357c478bd9Sstevel@tonic-gate ct_kevent_t *temp;
25367c478bd9Sstevel@tonic-gate int result = 0;
25377c478bd9Sstevel@tonic-gate int partial = 0;
25387c478bd9Sstevel@tonic-gate size_t size, gsize, len;
25397c478bd9Sstevel@tonic-gate model_t mdl = get_udatamodel();
25407c478bd9Sstevel@tonic-gate STRUCT_DECL(ct_event, ev);
25417c478bd9Sstevel@tonic-gate STRUCT_INIT(ev, mdl);
25427c478bd9Sstevel@tonic-gate
25437c478bd9Sstevel@tonic-gate /*
25447c478bd9Sstevel@tonic-gate * cte_qreadable checks for CTLF_COPYOUT as well as ensures
25457c478bd9Sstevel@tonic-gate * that there exists, and we are pointing to, an appropriate
25467c478bd9Sstevel@tonic-gate * event. It may temporarily drop ctq_lock, but that doesn't
25477c478bd9Sstevel@tonic-gate * really matter to us.
25487c478bd9Sstevel@tonic-gate */
25497c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
25507c478bd9Sstevel@tonic-gate while (cte_qreadable(q, l, cr, zuniqid, crit)) {
25517c478bd9Sstevel@tonic-gate if (nonblock) {
25527c478bd9Sstevel@tonic-gate result = EAGAIN;
25537c478bd9Sstevel@tonic-gate goto error;
25547c478bd9Sstevel@tonic-gate }
25557c478bd9Sstevel@tonic-gate if (q->ctq_flags & CTQ_DEAD) {
25567c478bd9Sstevel@tonic-gate result = EIDRM;
25577c478bd9Sstevel@tonic-gate goto error;
25587c478bd9Sstevel@tonic-gate }
25597c478bd9Sstevel@tonic-gate result = cv_wait_sig(&l->ctl_cv, &q->ctq_lock);
25607c478bd9Sstevel@tonic-gate if (result == 0) {
25617c478bd9Sstevel@tonic-gate result = EINTR;
25627c478bd9Sstevel@tonic-gate goto error;
25637c478bd9Sstevel@tonic-gate }
25647c478bd9Sstevel@tonic-gate }
25657c478bd9Sstevel@tonic-gate temp = l->ctl_position;
25667c478bd9Sstevel@tonic-gate cte_hold(temp);
25677c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_COPYOUT;
25687c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
25697c478bd9Sstevel@tonic-gate
25707c478bd9Sstevel@tonic-gate /*
25717c478bd9Sstevel@tonic-gate * We now have an event. Copy in the user event structure to
25727c478bd9Sstevel@tonic-gate * see how much space we have to work with.
25737c478bd9Sstevel@tonic-gate */
25747c478bd9Sstevel@tonic-gate result = copyin(uaddr, STRUCT_BUF(ev), STRUCT_SIZE(ev));
25757c478bd9Sstevel@tonic-gate if (result)
25767c478bd9Sstevel@tonic-gate goto copyerr;
25777c478bd9Sstevel@tonic-gate
25787c478bd9Sstevel@tonic-gate /*
25797c478bd9Sstevel@tonic-gate * Determine what data we have and what the user should be
25807c478bd9Sstevel@tonic-gate * allowed to see.
25817c478bd9Sstevel@tonic-gate */
25827c478bd9Sstevel@tonic-gate size = gsize = 0;
25837c478bd9Sstevel@tonic-gate if (temp->cte_data) {
25847c478bd9Sstevel@tonic-gate VERIFY(nvlist_size(temp->cte_data, &size,
25857c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE) == 0);
25867c478bd9Sstevel@tonic-gate ASSERT(size != 0);
25877c478bd9Sstevel@tonic-gate }
25887c478bd9Sstevel@tonic-gate if (zuniqid == GLOBAL_ZONEUNIQID && temp->cte_gdata) {
25897c478bd9Sstevel@tonic-gate VERIFY(nvlist_size(temp->cte_gdata, &gsize,
25907c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE) == 0);
25917c478bd9Sstevel@tonic-gate ASSERT(gsize != 0);
25927c478bd9Sstevel@tonic-gate }
25937c478bd9Sstevel@tonic-gate
25947c478bd9Sstevel@tonic-gate /*
25957c478bd9Sstevel@tonic-gate * If we have enough space, copy out the extended event data.
25967c478bd9Sstevel@tonic-gate */
25977c478bd9Sstevel@tonic-gate len = size + gsize;
25987c478bd9Sstevel@tonic-gate if (len) {
25997c478bd9Sstevel@tonic-gate if (STRUCT_FGET(ev, ctev_nbytes) >= len) {
26007c478bd9Sstevel@tonic-gate char *buf = kmem_alloc(len, KM_SLEEP);
26017c478bd9Sstevel@tonic-gate
26027c478bd9Sstevel@tonic-gate if (size)
26037c478bd9Sstevel@tonic-gate VERIFY(nvlist_pack(temp->cte_data, &buf, &size,
26047c478bd9Sstevel@tonic-gate NV_ENCODE_NATIVE, KM_SLEEP) == 0);
26057c478bd9Sstevel@tonic-gate if (gsize) {
26067c478bd9Sstevel@tonic-gate char *tmp = buf + size;
26077c478bd9Sstevel@tonic-gate
26087c478bd9Sstevel@tonic-gate VERIFY(nvlist_pack(temp->cte_gdata, &tmp,
26097c478bd9Sstevel@tonic-gate &gsize, NV_ENCODE_NATIVE, KM_SLEEP) == 0);
26107c478bd9Sstevel@tonic-gate }
26117c478bd9Sstevel@tonic-gate
26127c478bd9Sstevel@tonic-gate /* This shouldn't have changed */
26137c478bd9Sstevel@tonic-gate ASSERT(size + gsize == len);
26147c478bd9Sstevel@tonic-gate result = copyout(buf, STRUCT_FGETP(ev, ctev_buffer),
26157c478bd9Sstevel@tonic-gate len);
26167c478bd9Sstevel@tonic-gate kmem_free(buf, len);
26177c478bd9Sstevel@tonic-gate if (result)
26187c478bd9Sstevel@tonic-gate goto copyerr;
26197c478bd9Sstevel@tonic-gate } else {
26207c478bd9Sstevel@tonic-gate partial = 1;
26217c478bd9Sstevel@tonic-gate }
26227c478bd9Sstevel@tonic-gate }
26237c478bd9Sstevel@tonic-gate
26247c478bd9Sstevel@tonic-gate /*
26257c478bd9Sstevel@tonic-gate * Copy out the common event data.
26267c478bd9Sstevel@tonic-gate */
26277c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_id, temp->cte_contract->ct_id);
26287c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_evid, temp->cte_id);
26297c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_cttype,
26307c478bd9Sstevel@tonic-gate temp->cte_contract->ct_type->ct_type_index);
263125e8c5aaSvikram STRUCT_FSET(ev, ctev_flags, temp->cte_flags &
263225e8c5aaSvikram (CTE_ACK|CTE_INFO|CTE_NEG));
26337c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_type, temp->cte_type);
26347c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_nbytes, len);
26357c478bd9Sstevel@tonic-gate STRUCT_FSET(ev, ctev_goffset, size);
26367c478bd9Sstevel@tonic-gate result = copyout(STRUCT_BUF(ev), uaddr, STRUCT_SIZE(ev));
26377c478bd9Sstevel@tonic-gate
26387c478bd9Sstevel@tonic-gate copyerr:
26397c478bd9Sstevel@tonic-gate /*
26407c478bd9Sstevel@tonic-gate * Only move our location in the queue if all copyouts were
26417c478bd9Sstevel@tonic-gate * successful, the caller provided enough space for the entire
26427c478bd9Sstevel@tonic-gate * event, and our endpoint wasn't reset or otherwise moved by
26437c478bd9Sstevel@tonic-gate * another thread.
26447c478bd9Sstevel@tonic-gate */
26457c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
26467c478bd9Sstevel@tonic-gate if (result)
26477c478bd9Sstevel@tonic-gate result = EFAULT;
26487c478bd9Sstevel@tonic-gate else if (!partial && ((l->ctl_flags & CTLF_RESET) == 0) &&
26497c478bd9Sstevel@tonic-gate (l->ctl_position == temp))
26507c478bd9Sstevel@tonic-gate (void) cte_qmove(q, l, list_next(&q->ctq_events, temp));
26517c478bd9Sstevel@tonic-gate l->ctl_flags &= ~(CTLF_COPYOUT|CTLF_RESET);
26527c478bd9Sstevel@tonic-gate /*
26537c478bd9Sstevel@tonic-gate * Signal any readers blocked on our CTLF_COPYOUT.
26547c478bd9Sstevel@tonic-gate */
26557c478bd9Sstevel@tonic-gate cv_signal(&l->ctl_cv);
26567c478bd9Sstevel@tonic-gate cte_rele(temp);
26577c478bd9Sstevel@tonic-gate
26587c478bd9Sstevel@tonic-gate error:
26597c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
26607c478bd9Sstevel@tonic-gate return (result);
26617c478bd9Sstevel@tonic-gate }
26627c478bd9Sstevel@tonic-gate
26637c478bd9Sstevel@tonic-gate /*
26647c478bd9Sstevel@tonic-gate * cte_set_reliable
26657c478bd9Sstevel@tonic-gate *
26667c478bd9Sstevel@tonic-gate * Requests that events be reliably delivered to an event endpoint.
26677c478bd9Sstevel@tonic-gate * Unread informative and acknowledged critical events will not be
26687c478bd9Sstevel@tonic-gate * removed from the queue until this listener reads or skips them.
26697c478bd9Sstevel@tonic-gate * Because a listener could maliciously request reliable delivery and
26707c478bd9Sstevel@tonic-gate * then do nothing, this requires that PRIV_CONTRACT_EVENT be in the
26717c478bd9Sstevel@tonic-gate * caller's effective set.
26727c478bd9Sstevel@tonic-gate */
26737c478bd9Sstevel@tonic-gate int
cte_set_reliable(ct_listener_t * l,const cred_t * cr)26747c478bd9Sstevel@tonic-gate cte_set_reliable(ct_listener_t *l, const cred_t *cr)
26757c478bd9Sstevel@tonic-gate {
26767c478bd9Sstevel@tonic-gate ct_equeue_t *q = l->ctl_equeue;
26777c478bd9Sstevel@tonic-gate int error;
26787c478bd9Sstevel@tonic-gate
26797c478bd9Sstevel@tonic-gate if ((error = secpolicy_contract_event(cr)) != 0)
26807c478bd9Sstevel@tonic-gate return (error);
26817c478bd9Sstevel@tonic-gate
26827c478bd9Sstevel@tonic-gate mutex_enter(&q->ctq_lock);
26837c478bd9Sstevel@tonic-gate if ((l->ctl_flags & CTLF_RELIABLE) == 0) {
26847c478bd9Sstevel@tonic-gate l->ctl_flags |= CTLF_RELIABLE;
26857c478bd9Sstevel@tonic-gate q->ctq_nreliable++;
26867c478bd9Sstevel@tonic-gate if (l->ctl_position != NULL)
26877c478bd9Sstevel@tonic-gate l->ctl_position->cte_nodes[q->ctq_listno].
26887c478bd9Sstevel@tonic-gate ctm_nreliable++;
26897c478bd9Sstevel@tonic-gate }
26907c478bd9Sstevel@tonic-gate mutex_exit(&q->ctq_lock);
26917c478bd9Sstevel@tonic-gate
26927c478bd9Sstevel@tonic-gate return (0);
26937c478bd9Sstevel@tonic-gate }
2694