Print this page
fixup .text where possible
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/ctfs/ctfs_event.c
+++ new/usr/src/uts/common/fs/ctfs/ctfs_event.c
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.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
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 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 26
27 +
28 28 #include <sys/types.h>
29 29 #include <sys/param.h>
30 30 #include <sys/time.h>
31 31 #include <sys/cred.h>
32 32 #include <sys/vfs.h>
33 33 #include <sys/vfs_opreg.h>
34 34 #include <sys/gfs.h>
35 35 #include <sys/vnode.h>
36 36 #include <sys/systm.h>
37 37 #include <sys/errno.h>
38 38 #include <sys/sysmacros.h>
39 39 #include <fs/fs_subr.h>
40 40 #include <sys/contract.h>
41 41 #include <sys/contract_impl.h>
42 42 #include <sys/ctfs.h>
43 43 #include <sys/ctfs_impl.h>
44 44 #include <sys/file.h>
45 45 #include <sys/policy.h>
46 46
47 47 /*
48 48 * CTFS routines for the /system/contract/<type>/bundle vnode.
49 49 * CTFS routines for the /system/contract/<type>/pbundle vnode.
50 50 * CTFS routines for the /system/contract/<type>/<ctid>/events vnode.
51 51 */
52 52
53 53 /*
54 54 * ctfs_endpoint_open
55 55 *
56 56 * Called by the VOP_OPEN entry points to perform some common checks
57 57 * and set up the endpoint listener, if not already done.
58 58 */
59 59 static int
60 60 ctfs_endpoint_open(ctfs_endpoint_t *endpt, ct_equeue_t *q, int flag)
61 61 {
62 62 if ((flag & ~FNONBLOCK) != (FREAD | FOFFMAX))
63 63 return (EINVAL);
64 64
65 65 mutex_enter(&endpt->ctfs_endpt_lock);
66 66 if ((endpt->ctfs_endpt_flags & CTFS_ENDPT_SETUP) == 0) {
67 67 endpt->ctfs_endpt_flags |= CTFS_ENDPT_SETUP;
68 68 if (flag & FNONBLOCK)
69 69 endpt->ctfs_endpt_flags |= CTFS_ENDPT_NBLOCK;
70 70 cte_add_listener(q, &endpt->ctfs_endpt_listener);
71 71 }
72 72 mutex_exit(&endpt->ctfs_endpt_lock);
73 73
74 74 return (0);
75 75 }
76 76
77 77 /*
78 78 * ctfs_endpoint inactive
79 79 *
80 80 * Called by the VOP_INACTIVE entry points to perform common listener
81 81 * cleanup.
82 82 */
83 83 static void
84 84 ctfs_endpoint_inactive(ctfs_endpoint_t *endpt)
85 85 {
86 86 mutex_enter(&endpt->ctfs_endpt_lock);
87 87 if (endpt->ctfs_endpt_flags & CTFS_ENDPT_SETUP) {
88 88 endpt->ctfs_endpt_flags = 0;
89 89 cte_remove_listener(&endpt->ctfs_endpt_listener);
90 90 }
91 91 mutex_exit(&endpt->ctfs_endpt_lock);
92 92 }
93 93
94 94 /*
95 95 * ctfs_endpoint_ioctl
96 96 *
97 97 * Implements the common VOP_IOCTL handling for the event endpoints.
98 98 * rprivchk, if true, indicates that event receive requests should
99 99 * check the provided credentials. This distinction exists because
100 100 * contract endpoints perform their privilege checks at open-time, and
101 101 * process bundle queue listeners by definition may view all events
102 102 * their queues contain.
103 103 */
104 104 static int
105 105 ctfs_endpoint_ioctl(ctfs_endpoint_t *endpt, int cmd, intptr_t arg, cred_t *cr,
106 106 zone_t *zone, int rprivchk)
107 107 {
108 108 uint64_t id, zuniqid;
109 109
110 110 zuniqid = zone->zone_uniqid;
111 111
112 112 switch (cmd) {
113 113 case CT_ERESET:
114 114 cte_reset_listener(&endpt->ctfs_endpt_listener);
115 115 break;
116 116 case CT_ERECV:
117 117 /*
118 118 * We pass in NULL for the cred when reading from
119 119 * process bundle queues and contract queues because
120 120 * the privilege check was performed at open time.
121 121 */
122 122 return (cte_get_event(&endpt->ctfs_endpt_listener,
123 123 endpt->ctfs_endpt_flags & CTFS_ENDPT_NBLOCK,
124 124 (void *)arg, rprivchk ? cr : NULL, zuniqid, 0));
125 125 case CT_ECRECV:
126 126 return (cte_get_event(&endpt->ctfs_endpt_listener,
127 127 endpt->ctfs_endpt_flags & CTFS_ENDPT_NBLOCK,
128 128 (void *)arg, rprivchk ? cr : NULL, zuniqid, 1));
129 129 case CT_ENEXT:
130 130 if (copyin((void *)arg, &id, sizeof (uint64_t)))
131 131 return (EFAULT);
132 132 return (cte_next_event(&endpt->ctfs_endpt_listener, id));
133 133 case CT_ERELIABLE:
134 134 return (cte_set_reliable(&endpt->ctfs_endpt_listener, cr));
135 135 default:
136 136 return (EINVAL);
137 137 }
138 138
139 139 return (0);
140 140 }
141 141
142 142 /*
143 143 * ctfs_endpoint_poll
144 144 *
145 145 * Called by the VOP_POLL entry points.
146 146 */
147 147 static int
148 148 ctfs_endpoint_poll(ctfs_endpoint_t *endpt, short events, int anyyet,
149 149 short *reventsp, pollhead_t **php)
150 150 {
151 151 if ((events & POLLIN) && endpt->ctfs_endpt_listener.ctl_position) {
152 152 *reventsp = POLLIN;
153 153 } else {
154 154 *reventsp = 0;
155 155 if (!anyyet)
156 156 *php = &endpt->ctfs_endpt_listener.ctl_pollhead;
157 157 }
158 158
159 159 return (0);
160 160 }
161 161
162 162 /*
163 163 * ctfs_create_evnode
164 164 *
165 165 * Creates and returns a new evnode.
166 166 */
167 167 vnode_t *
168 168 ctfs_create_evnode(vnode_t *pvp)
169 169 {
170 170 vnode_t *vp;
171 171 ctfs_evnode_t *evnode;
172 172 ctfs_cdirnode_t *cdirnode = pvp->v_data;
173 173
174 174 vp = gfs_file_create(sizeof (ctfs_evnode_t), pvp, ctfs_ops_event);
175 175 evnode = vp->v_data;
176 176
177 177 /*
178 178 * We transitively have a hold on the contract through our
179 179 * parent directory.
180 180 */
181 181 evnode->ctfs_ev_contract = cdirnode->ctfs_cn_contract;
182 182
183 183 return (vp);
184 184 }
185 185
186 186 /*
187 187 * ctfs_ev_access - VOP_ACCESS entry point
188 188 *
189 189 * You only get to access event files for contracts you or your
190 190 * effective user id owns, unless you have a privilege.
191 191 */
192 192 /*ARGSUSED*/
193 193 static int
194 194 ctfs_ev_access(
195 195 vnode_t *vp,
196 196 int mode,
197 197 int flags,
198 198 cred_t *cr,
199 199 caller_context_t *cct)
200 200 {
201 201 ctfs_evnode_t *evnode = vp->v_data;
202 202 contract_t *ct = evnode->ctfs_ev_contract;
203 203 int error;
204 204
205 205 if (mode & (VWRITE | VEXEC))
206 206 return (EACCES);
207 207
208 208 if (error = secpolicy_contract_observer(cr, ct))
209 209 return (error);
210 210
211 211 return (0);
212 212 }
213 213
214 214 /*
215 215 * ctfs_ev_open - VOP_OPEN entry point
216 216 *
217 217 * Performs the same privilege checks as ctfs_ev_access, and then calls
218 218 * ctfs_endpoint_open to perform the common endpoint initialization.
219 219 */
220 220 /* ARGSUSED */
221 221 static int
222 222 ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *cct)
223 223 {
224 224 ctfs_evnode_t *evnode = (*vpp)->v_data;
225 225 contract_t *ct = evnode->ctfs_ev_contract;
226 226 int error;
227 227
228 228 if (error = secpolicy_contract_observer(cr, ct))
229 229 return (error);
230 230
231 231 /*
232 232 * See comment in ctfs_bu_open.
233 233 */
234 234 return (ctfs_endpoint_open(&evnode->ctfs_ev_listener,
235 235 &evnode->ctfs_ev_contract->ct_events, flag));
236 236 }
237 237
238 238 /*
239 239 * ctfs_ev_inactive - VOP_INACTIVE entry point
240 240 */
241 241 /* ARGSUSED */
242 242 static void
243 243 ctfs_ev_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
244 244 {
245 245 ctfs_evnode_t *evnode;
246 246 vnode_t *pvp = gfs_file_parent(vp);
247 247
248 248 /*
249 249 * We must destroy the endpoint before releasing the parent; otherwise
250 250 * we will try to destroy a contract with active listeners. To prevent
251 251 * this, we grab an extra hold on the parent.
252 252 */
253 253 VN_HOLD(pvp);
254 254 if ((evnode = gfs_file_inactive(vp)) != NULL) {
255 255 ctfs_endpoint_inactive(&evnode->ctfs_ev_listener);
256 256 kmem_free(evnode, sizeof (ctfs_evnode_t));
257 257 }
258 258 VN_RELE(pvp);
259 259 }
260 260
261 261 /*
262 262 * ctfs_ev_getattr - VOP_GETATTR entry point
263 263 */
264 264 /* ARGSUSED */
265 265 static int
266 266 ctfs_ev_getattr(
267 267 vnode_t *vp,
268 268 vattr_t *vap,
269 269 int flags,
270 270 cred_t *cr,
271 271 caller_context_t *ct)
272 272 {
273 273 ctfs_evnode_t *evnode = vp->v_data;
274 274
275 275 vap->va_type = VREG;
276 276 vap->va_mode = 0444;
277 277 vap->va_nlink = 1;
278 278 vap->va_size = 0;
279 279 vap->va_ctime = evnode->ctfs_ev_contract->ct_ctime;
280 280 mutex_enter(&evnode->ctfs_ev_contract->ct_events.ctq_lock);
281 281 vap->va_atime = vap->va_mtime =
282 282 evnode->ctfs_ev_contract->ct_events.ctq_atime;
283 283 mutex_exit(&evnode->ctfs_ev_contract->ct_events.ctq_lock);
284 284 ctfs_common_getattr(vp, vap);
285 285
286 286 return (0);
287 287 }
288 288
289 289 /*
290 290 * ctfs_ev_ioctl - VOP_IOCTL entry point
291 291 */
292 292 /* ARGSUSED */
293 293 static int
294 294 ctfs_ev_ioctl(
295 295 vnode_t *vp,
296 296 int cmd,
297 297 intptr_t arg,
298 298 int flag,
299 299 cred_t *cr,
300 300 int *rvalp,
301 301 caller_context_t *ct)
302 302 {
303 303 ctfs_evnode_t *evnode = vp->v_data;
304 304
305 305 return (ctfs_endpoint_ioctl(&evnode->ctfs_ev_listener, cmd, arg, cr,
306 306 VTOZONE(vp), 0));
307 307 }
308 308
309 309 /*
310 310 * ctfs_ev_poll - VOP_POLL entry point
311 311 */
312 312 /*ARGSUSED*/
313 313 static int
314 314 ctfs_ev_poll(
315 315 vnode_t *vp,
316 316 short events,
317 317 int anyyet,
318 318 short *reventsp,
319 319 pollhead_t **php,
320 320 caller_context_t *ct)
321 321 {
322 322 ctfs_evnode_t *evnode = vp->v_data;
323 323
324 324 return (ctfs_endpoint_poll(&evnode->ctfs_ev_listener, events, anyyet,
325 325 reventsp, php));
326 326 }
327 327
↓ open down ↓ |
290 lines elided |
↑ open up ↑ |
328 328 const fs_operation_def_t ctfs_tops_event[] = {
329 329 { VOPNAME_OPEN, { .vop_open = ctfs_ev_open } },
330 330 { VOPNAME_CLOSE, { .vop_close = ctfs_close } },
331 331 { VOPNAME_IOCTL, { .vop_ioctl = ctfs_ev_ioctl } },
332 332 { VOPNAME_GETATTR, { .vop_getattr = ctfs_ev_getattr } },
333 333 { VOPNAME_ACCESS, { .vop_access = ctfs_ev_access } },
334 334 { VOPNAME_READDIR, { .error = fs_notdir } },
335 335 { VOPNAME_LOOKUP, { .error = fs_notdir } },
336 336 { VOPNAME_INACTIVE, { .vop_inactive = ctfs_ev_inactive } },
337 337 { VOPNAME_POLL, { .vop_poll = ctfs_ev_poll } },
338 - { NULL, NULL }
338 + { NULL, { NULL } }
339 339 };
340 340
341 341 /*
342 342 * ctfs_create_pbundle
343 343 *
344 344 * Creates and returns a bunode for a /system/contract/<type>/pbundle
345 345 * file.
346 346 */
347 347 vnode_t *
348 348 ctfs_create_pbundle(vnode_t *pvp)
349 349 {
350 350 vnode_t *vp;
351 351 ctfs_bunode_t *bundle;
352 352
353 353 vp = gfs_file_create(sizeof (ctfs_bunode_t), pvp, ctfs_ops_bundle);
354 354 bundle = vp->v_data;
355 355 bundle->ctfs_bu_queue =
356 356 contract_type_pbundle(ct_types[gfs_file_index(pvp)], curproc);
357 357
358 358 return (vp);
359 359 }
360 360
361 361 /*
362 362 * ctfs_create_bundle
363 363 *
364 364 * Creates and returns a bunode for a /system/contract/<type>/bundle
365 365 * file.
366 366 */
367 367 vnode_t *
368 368 ctfs_create_bundle(vnode_t *pvp)
369 369 {
370 370 vnode_t *vp;
371 371 ctfs_bunode_t *bundle;
372 372
373 373 vp = gfs_file_create(sizeof (ctfs_bunode_t), pvp, ctfs_ops_bundle);
374 374 bundle = vp->v_data;
375 375 bundle->ctfs_bu_queue =
376 376 contract_type_bundle(ct_types[gfs_file_index(pvp)]);
377 377
378 378 return (vp);
379 379 }
380 380
381 381 /*
382 382 * ctfs_bu_open - VOP_OPEN entry point
383 383 */
384 384 /* ARGSUSED */
385 385 static int
386 386 ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
387 387 {
388 388 ctfs_bunode_t *bunode = (*vpp)->v_data;
389 389
390 390 /*
391 391 * This assumes we are only ever called immediately after a
392 392 * VOP_LOOKUP. We could clone ourselves here, but doing so
393 393 * would make /proc/pid/fd accesses less useful.
394 394 */
395 395 return (ctfs_endpoint_open(&bunode->ctfs_bu_listener,
396 396 bunode->ctfs_bu_queue, flag));
397 397 }
398 398
399 399 /*
400 400 * ctfs_bu_inactive - VOP_INACTIVE entry point
401 401 */
402 402 /* ARGSUSED */
403 403 static void
404 404 ctfs_bu_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
405 405 {
406 406 ctfs_bunode_t *bunode;
407 407 vnode_t *pvp = gfs_file_parent(vp);
408 408
409 409 /*
410 410 * See comments in ctfs_ev_inactive() above.
411 411 */
412 412 VN_HOLD(pvp);
413 413 if ((bunode = gfs_file_inactive(vp)) != NULL) {
414 414 ctfs_endpoint_inactive(&bunode->ctfs_bu_listener);
415 415 kmem_free(bunode, sizeof (ctfs_bunode_t));
416 416 }
417 417 VN_RELE(pvp);
418 418 }
419 419
420 420 /*
421 421 * ctfs_bu_getattr - VOP_GETATTR entry point
422 422 */
423 423 /* ARGSUSED */
424 424 static int
425 425 ctfs_bu_getattr(
426 426 vnode_t *vp,
427 427 vattr_t *vap,
428 428 int flags,
429 429 cred_t *cr,
430 430 caller_context_t *ct)
431 431 {
432 432 ctfs_bunode_t *bunode = vp->v_data;
433 433
434 434 vap->va_type = VREG;
435 435 vap->va_mode = 0444;
436 436 vap->va_nodeid = gfs_file_index(vp);
437 437 vap->va_nlink = 1;
438 438 vap->va_size = 0;
439 439 vap->va_ctime.tv_sec = vp->v_vfsp->vfs_mtime;
440 440 vap->va_ctime.tv_nsec = 0;
441 441 mutex_enter(&bunode->ctfs_bu_queue->ctq_lock);
442 442 vap->va_mtime = vap->va_atime = bunode->ctfs_bu_queue->ctq_atime;
443 443 mutex_exit(&bunode->ctfs_bu_queue->ctq_lock);
444 444 ctfs_common_getattr(vp, vap);
445 445
446 446 return (0);
447 447 }
448 448
449 449 /*
450 450 * ctfs_bu_ioctl - VOP_IOCTL entry point
451 451 */
452 452 /* ARGSUSED */
453 453 static int
454 454 ctfs_bu_ioctl(
455 455 vnode_t *vp,
456 456 int cmd,
457 457 intptr_t arg,
458 458 int flag,
459 459 cred_t *cr,
460 460 int *rvalp,
461 461 caller_context_t *ct)
462 462 {
463 463 ctfs_bunode_t *bunode = vp->v_data;
464 464
465 465 return (ctfs_endpoint_ioctl(&bunode->ctfs_bu_listener, cmd, arg, cr,
466 466 VTOZONE(vp), bunode->ctfs_bu_queue->ctq_listno == CTEL_BUNDLE));
467 467 }
468 468
469 469 /*
470 470 * ctfs_bu_poll - VOP_POLL entry point
471 471 */
472 472 /*ARGSUSED*/
473 473 static int
474 474 ctfs_bu_poll(
475 475 vnode_t *vp,
476 476 short events,
477 477 int anyyet,
478 478 short *reventsp,
479 479 pollhead_t **php,
480 480 caller_context_t *ct)
481 481 {
482 482 ctfs_bunode_t *bunode = vp->v_data;
483 483
484 484 return (ctfs_endpoint_poll(&bunode->ctfs_bu_listener, events, anyyet,
485 485 reventsp, php));
486 486 }
487 487
↓ open down ↓ |
139 lines elided |
↑ open up ↑ |
488 488 const fs_operation_def_t ctfs_tops_bundle[] = {
489 489 { VOPNAME_OPEN, { .vop_open = ctfs_bu_open } },
490 490 { VOPNAME_CLOSE, { .vop_close = ctfs_close } },
491 491 { VOPNAME_IOCTL, { .vop_ioctl = ctfs_bu_ioctl } },
492 492 { VOPNAME_GETATTR, { .vop_getattr = ctfs_bu_getattr } },
493 493 { VOPNAME_ACCESS, { .vop_access = ctfs_access_readonly } },
494 494 { VOPNAME_READDIR, { .error = fs_notdir } },
495 495 { VOPNAME_LOOKUP, { .error = fs_notdir } },
496 496 { VOPNAME_INACTIVE, { .vop_inactive = ctfs_bu_inactive } },
497 497 { VOPNAME_POLL, { .vop_poll = ctfs_bu_poll } },
498 - { NULL, NULL }
498 + { NULL, { NULL } }
499 499 };
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX