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