Print this page
OS-1988 Make ldi_ev_remove_callbacks safe to use in LDI callbacks
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/sys/sunldi_impl.h
+++ new/usr/src/uts/common/sys/sunldi_impl.h
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 +/*
26 + * Copyright (c) 2013, Joyent, Inc. All rights reserved.
27 + */
25 28
26 29 #ifndef _SYS_SUNLDI_IMPL_H
27 30 #define _SYS_SUNLDI_IMPL_H
28 31
29 -#pragma ident "%Z%%M% %I% %E% SMI"
30 -
31 32 #ifdef __cplusplus
32 33 extern "C" {
33 34 #endif
34 35
35 36 #include <sys/dditypes.h>
36 37 #include <sys/vnode.h>
37 38
38 39 /*
39 40 * NOTE
40 41 *
41 42 * The contents of this file are private to this implementation
42 43 * of Solaris and are subject to change at any time without notice.
43 44 *
44 45 * Applications and drivers using these interfaces will fail
45 46 * to run on future releases.
46 47 */
47 48
48 49 /*
49 50 * LDI hash definitions
50 51 */
51 52 #define LH_HASH_SZ 32
52 53 #define LI_HASH_SZ 32
53 54
54 55 /*
55 56 * Obsolete LDI event interfaces are available for now but are deprecated and a
56 57 * warning will be issued to consumers.
57 58 */
58 59 #define LDI_OBSOLETE_EVENT 1
59 60
60 61 /*
61 62 * Flag for LDI handle's lh_flags field
62 63 */
63 64 #define LH_FLAGS_NOTIFY 0x0001 /* invoked in context of a notify */
64 65
65 66 /*
66 67 * LDI initialization function
67 68 */
68 69 void ldi_init(void);
69 70
70 71 /*
71 72 * LDI streams linking interfaces
72 73 */
73 74 extern int ldi_mlink_lh(vnode_t *, int, intptr_t, cred_t *, int *);
74 75 extern void ldi_mlink_fp(struct stdata *, struct file *, int, int);
75 76 extern void ldi_munlink_fp(struct stdata *, struct file *, int);
76 77
77 78 /*
78 79 * LDI module identifier
79 80 */
80 81 struct ldi_ident {
81 82 /* protected by ldi_ident_hash_lock */
82 83 struct ldi_ident *li_next;
83 84 uint_t li_ref;
84 85
85 86 /* unique/static fields in the ident */
86 87 char li_modname[MODMAXNAMELEN];
87 88 modid_t li_modid;
88 89 major_t li_major;
89 90 dev_info_t *li_dip;
90 91 dev_t li_dev;
91 92 };
92 93
93 94 /*
94 95 * LDI handle
95 96 */
96 97 struct ldi_handle {
97 98 /* protected by ldi_handle_hash_lock */
98 99 struct ldi_handle *lh_next;
99 100 uint_t lh_ref;
100 101 uint_t lh_flags;
101 102
102 103 /* unique/static fields in the handle */
103 104 uint_t lh_type;
104 105 struct ldi_ident *lh_ident;
105 106 vnode_t *lh_vp;
106 107
107 108 #ifdef LDI_OBSOLETE_EVENT
108 109 /* fields protected by lh_lock */
109 110 kmutex_t lh_lock[1];
110 111 struct ldi_event *lh_events;
111 112 #endif
112 113 };
113 114
114 115 /*
115 116 * LDI event information
116 117 */
117 118 #ifdef LDI_OBSOLETE_EVENT
118 119 typedef struct ldi_event {
119 120 /* fields protected by le_lhp->lh_lock */
120 121 struct ldi_event *le_next;
121 122 struct ldi_event *le_prev;
122 123
123 124 /* unique/static fields in the handle */
124 125 struct ldi_handle *le_lhp;
125 126 void (*le_handler)();
126 127 void *le_arg;
127 128 ddi_callback_id_t le_id;
128 129 } ldi_event_t;
129 130 #endif
130 131
131 132 typedef struct ldi_ev_callback_impl {
132 133 struct ldi_handle *lec_lhp;
133 134 dev_info_t *lec_dip;
↓ open down ↓ |
93 lines elided |
↑ open up ↑ |
134 135 dev_t lec_dev;
135 136 int lec_spec;
136 137 int (*lec_notify)();
137 138 void (*lec_finalize)();
138 139 void *lec_arg;
139 140 void *lec_cookie;
140 141 void *lec_id;
141 142 list_node_t lec_list;
142 143 } ldi_ev_callback_impl_t;
143 144
145 +/*
146 + * Members of "struct ldi_ev_callback_list" are protected by their le_lock
147 + * member. The struct is currently only used once, as a file-level global,
148 + * and the locking protocol is currently implemented in ldi_ev_lock() and
149 + * ldi_ev_unlock().
150 + *
151 + * When delivering events to subscribers, ldi_invoke_notify() and
152 + * ldi_invoke_finalize() will walk the list of callbacks: le_head. It is
153 + * possible that an invoked callback function will need to unregister an
154 + * arbitrary number of callbacks from this list.
155 + *
156 + * To enable ldi_ev_remove_callbacks() to remove elements from the list
157 + * without breaking the walk-in-progress, we store the next element in the
158 + * walk direction on the struct as le_walker_next and le_walker_prev.
159 + */
144 160 struct ldi_ev_callback_list {
145 - kmutex_t le_lock;
146 - kcondvar_t le_cv;
147 - int le_busy;
148 - void *le_thread;
149 - list_t le_head;
161 + kmutex_t le_lock;
162 + kcondvar_t le_cv;
163 + int le_busy;
164 + void *le_thread;
165 + list_t le_head;
166 + ldi_ev_callback_impl_t *le_walker_next;
167 + ldi_ev_callback_impl_t *le_walker_prev;
150 168 };
151 169
152 170 int ldi_invoke_notify(dev_info_t *dip, dev_t dev, int spec_type, char *event,
153 171 void *ev_data);
154 172 void ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
155 173 int ldi_result, void *ev_data);
156 174 int e_ddi_offline_notify(dev_info_t *dip);
157 175 void e_ddi_offline_finalize(dev_info_t *dip, int result);
158 176
159 177
160 178 /*
161 179 * LDI device usage interfaces
162 180 *
163 181 * ldi_usage_count(), ldi_usage_walker(), and ldi_usage_t
164 182 *
165 183 * These functions are used by the devinfo driver and fuser to get a
166 184 * device usage information from the LDI. These functions along with
167 185 * the ldi_usage_t data structure allow these other subsystems to have
168 186 * no knowledge of how the LDI stores it's internal state.
169 187 *
170 188 * ldi_usage_count() provides an count of how many kernel
171 189 * device clients currently exist.
172 190 *
173 191 * ldi_usage_walker() reports all kernel device usage information.
174 192 */
175 193 #define LDI_USAGE_CONTINUE 0
176 194 #define LDI_USAGE_TERMINATE 1
177 195
178 196 typedef struct ldi_usage {
179 197 /*
180 198 * information about the kernel subsystem that is accessing
181 199 * the target device
182 200 */
183 201 modid_t src_modid;
184 202 char *src_name;
185 203 dev_info_t *src_dip;
186 204 dev_t src_devt;
187 205
188 206 /*
189 207 * information about the target device that is open
190 208 */
191 209 modid_t tgt_modid;
192 210 char *tgt_name;
193 211 dev_info_t *tgt_dip;
194 212 dev_t tgt_devt;
195 213 int tgt_spec_type;
196 214 } ldi_usage_t;
197 215
198 216 int ldi_usage_count();
199 217 void ldi_usage_walker(void *arg,
200 218 int (*callback)(const ldi_usage_t *ldi_usage, void *arg));
201 219
202 220 #ifdef __cplusplus
203 221 }
204 222 #endif
205 223
206 224 #endif /* _SYS_SUNLDI_IMPL_H */
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX