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