Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/doorfs/door_sys.c
+++ new/usr/src/uts/common/fs/doorfs/door_sys.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
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 /*
23 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * System call I/F to doors (outside of vnodes I/F) and misc support
28 28 * routines
29 29 */
30 30 #include <sys/types.h>
31 31 #include <sys/systm.h>
32 32 #include <sys/door.h>
33 33 #include <sys/door_data.h>
34 34 #include <sys/proc.h>
35 35 #include <sys/thread.h>
36 36 #include <sys/prsystm.h>
37 37 #include <sys/procfs.h>
38 38 #include <sys/class.h>
39 39 #include <sys/cred.h>
40 40 #include <sys/kmem.h>
41 41 #include <sys/cmn_err.h>
42 42 #include <sys/stack.h>
43 43 #include <sys/debug.h>
44 44 #include <sys/cpuvar.h>
45 45 #include <sys/file.h>
46 46 #include <sys/fcntl.h>
47 47 #include <sys/vnode.h>
48 48 #include <sys/vfs.h>
49 49 #include <sys/vfs_opreg.h>
50 50 #include <sys/sobject.h>
51 51 #include <sys/schedctl.h>
52 52 #include <sys/callb.h>
53 53 #include <sys/ucred.h>
54 54
55 55 #include <sys/mman.h>
56 56 #include <sys/sysmacros.h>
57 57 #include <sys/vmsystm.h>
58 58 #include <vm/as.h>
59 59 #include <vm/hat.h>
60 60 #include <vm/page.h>
61 61 #include <vm/seg.h>
62 62 #include <vm/seg_vn.h>
63 63 #include <vm/seg_vn.h>
64 64 #include <vm/seg_kpm.h>
65 65
66 66 #include <sys/modctl.h>
67 67 #include <sys/syscall.h>
68 68 #include <sys/pathname.h>
69 69 #include <sys/rctl.h>
70 70
71 71 /*
72 72 * The maximum amount of data (in bytes) that will be transferred using
73 73 * an intermediate kernel buffer. For sizes greater than this we map
74 74 * in the destination pages and perform a 1-copy transfer.
75 75 */
76 76 size_t door_max_arg = 16 * 1024;
77 77
78 78 /*
79 79 * Maximum amount of data that will be transferred in a reply to a
80 80 * door_upcall. Need to guard against a process returning huge amounts
81 81 * of data and getting the kernel stuck in kmem_alloc.
82 82 */
83 83 size_t door_max_upcall_reply = 1024 * 1024;
84 84
85 85 /*
86 86 * Maximum number of descriptors allowed to be passed in a single
87 87 * door_call or door_return. We need to allocate kernel memory
88 88 * for all of them at once, so we can't let it scale without limit.
89 89 */
90 90 uint_t door_max_desc = 1024;
91 91
92 92 /*
93 93 * Definition of a door handle, used by other kernel subsystems when
94 94 * calling door functions. This is really a file structure but we
95 95 * want to hide that fact.
96 96 */
97 97 struct __door_handle {
98 98 file_t dh_file;
99 99 };
100 100
101 101 #define DHTOF(dh) ((file_t *)(dh))
102 102 #define FTODH(fp) ((door_handle_t)(fp))
103 103
104 104 static int doorfs(long, long, long, long, long, long);
105 105
106 106 static struct sysent door_sysent = {
107 107 6,
108 108 SE_ARGC | SE_NOUNLOAD,
109 109 (int (*)())doorfs,
110 110 };
111 111
112 112 static struct modlsys modlsys = {
113 113 &mod_syscallops, "doors", &door_sysent
114 114 };
115 115
116 116 #ifdef _SYSCALL32_IMPL
117 117
118 118 static int
119 119 doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
120 120 int32_t arg5, int32_t subcode);
121 121
122 122 static struct sysent door_sysent32 = {
123 123 6,
124 124 SE_ARGC | SE_NOUNLOAD,
125 125 (int (*)())doorfs32,
126 126 };
↓ open down ↓ |
126 lines elided |
↑ open up ↑ |
127 127
128 128 static struct modlsys modlsys32 = {
129 129 &mod_syscallops32,
130 130 "32-bit door syscalls",
131 131 &door_sysent32
132 132 };
133 133 #endif
134 134
135 135 static struct modlinkage modlinkage = {
136 136 MODREV_1,
137 - &modlsys,
137 + { &modlsys,
138 138 #ifdef _SYSCALL32_IMPL
139 - &modlsys32,
139 + &modlsys32,
140 140 #endif
141 - NULL
141 + NULL
142 + }
142 143 };
143 144
144 145 dev_t doordev;
145 146
146 147 extern struct vfs door_vfs;
147 148 extern struct vnodeops *door_vnodeops;
148 149
149 150 int
150 151 _init(void)
151 152 {
152 153 static const fs_operation_def_t door_vfsops_template[] = {
153 - NULL, NULL
154 + { NULL, { NULL } }
154 155 };
155 156 extern const fs_operation_def_t door_vnodeops_template[];
156 157 vfsops_t *door_vfsops;
157 158 major_t major;
158 159 int error;
159 160
160 161 mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL);
161 162 if ((major = getudev()) == (major_t)-1)
162 163 return (ENXIO);
163 164 doordev = makedevice(major, 0);
164 165
165 166 /* Create a dummy vfs */
166 167 error = vfs_makefsops(door_vfsops_template, &door_vfsops);
167 168 if (error != 0) {
168 169 cmn_err(CE_WARN, "door init: bad vfs ops");
169 170 return (error);
170 171 }
171 172 VFS_INIT(&door_vfs, door_vfsops, NULL);
172 173 door_vfs.vfs_flag = VFS_RDONLY;
173 174 door_vfs.vfs_dev = doordev;
174 175 vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
175 176
176 177 error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops);
177 178 if (error != 0) {
178 179 vfs_freevfsops(door_vfsops);
179 180 cmn_err(CE_WARN, "door init: bad vnode ops");
180 181 return (error);
181 182 }
182 183 return (mod_install(&modlinkage));
183 184 }
184 185
185 186 int
186 187 _info(struct modinfo *modinfop)
187 188 {
188 189 return (mod_info(&modlinkage, modinfop));
189 190 }
190 191
191 192 /* system call functions */
192 193 static int door_call(int, void *);
193 194 static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t);
194 195 static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *,
195 196 uint_t), void *data_cookie, uint_t);
196 197 static int door_revoke(int);
197 198 static int door_info(int, struct door_info *);
198 199 static int door_ucred(struct ucred_s *);
199 200 static int door_bind(int);
200 201 static int door_unbind(void);
201 202 static int door_unref(void);
202 203 static int door_getparam(int, int, size_t *);
203 204 static int door_setparam(int, int, size_t);
204 205
205 206 #define DOOR_RETURN_OLD 4 /* historic value, for s10 */
206 207
207 208 /*
208 209 * System call wrapper for all door related system calls
209 210 */
210 211 static int
211 212 doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode)
212 213 {
213 214 switch (subcode) {
214 215 case DOOR_CALL:
215 216 return (door_call(arg1, (void *)arg2));
216 217 case DOOR_RETURN: {
217 218 door_return_desc_t *drdp = (door_return_desc_t *)arg3;
218 219
219 220 if (drdp != NULL) {
220 221 door_return_desc_t drd;
221 222 if (copyin(drdp, &drd, sizeof (drd)))
222 223 return (EFAULT);
223 224 return (door_return((caddr_t)arg1, arg2, drd.desc_ptr,
224 225 drd.desc_num, (caddr_t)arg4, arg5));
225 226 }
226 227 return (door_return((caddr_t)arg1, arg2, NULL,
227 228 0, (caddr_t)arg4, arg5));
228 229 }
229 230 case DOOR_RETURN_OLD:
230 231 /*
231 232 * In order to support the S10 runtime environment, we
232 233 * still respond to the old syscall subcode for door_return.
233 234 * We treat it as having no stack limits. This code should
234 235 * be removed when such support is no longer needed.
235 236 */
236 237 return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3,
237 238 arg4, (caddr_t)arg5, 0));
238 239 case DOOR_CREATE:
239 240 return (door_create((void (*)())arg1, (void *)arg2, arg3));
240 241 case DOOR_REVOKE:
241 242 return (door_revoke(arg1));
242 243 case DOOR_INFO:
243 244 return (door_info(arg1, (struct door_info *)arg2));
244 245 case DOOR_BIND:
245 246 return (door_bind(arg1));
246 247 case DOOR_UNBIND:
247 248 return (door_unbind());
248 249 case DOOR_UNREFSYS:
249 250 return (door_unref());
250 251 case DOOR_UCRED:
251 252 return (door_ucred((struct ucred_s *)arg1));
252 253 case DOOR_GETPARAM:
253 254 return (door_getparam(arg1, arg2, (size_t *)arg3));
254 255 case DOOR_SETPARAM:
255 256 return (door_setparam(arg1, arg2, arg3));
256 257 default:
257 258 return (set_errno(EINVAL));
258 259 }
259 260 }
260 261
261 262 #ifdef _SYSCALL32_IMPL
262 263 /*
263 264 * System call wrapper for all door related system calls from 32-bit programs.
264 265 * Needed at the moment because of the casts - they undo some damage
265 266 * that truss causes (sign-extending the stack pointer) when truss'ing
266 267 * a 32-bit program using doors.
267 268 */
268 269 static int
269 270 doorfs32(int32_t arg1, int32_t arg2, int32_t arg3,
270 271 int32_t arg4, int32_t arg5, int32_t subcode)
271 272 {
272 273 switch (subcode) {
273 274 case DOOR_CALL:
274 275 return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2));
275 276 case DOOR_RETURN: {
276 277 door_return_desc32_t *drdp =
277 278 (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3;
278 279 if (drdp != NULL) {
279 280 door_return_desc32_t drd;
280 281 if (copyin(drdp, &drd, sizeof (drd)))
281 282 return (EFAULT);
282 283 return (door_return(
283 284 (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
284 285 (door_desc_t *)(uintptr_t)drd.desc_ptr,
285 286 drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4,
286 287 (size_t)(uintptr_t)(size32_t)arg5));
287 288 }
288 289 return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1,
289 290 arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4,
290 291 (size_t)(uintptr_t)(size32_t)arg5));
291 292 }
292 293 case DOOR_RETURN_OLD:
293 294 /*
294 295 * In order to support the S10 runtime environment, we
295 296 * still respond to the old syscall subcode for door_return.
296 297 * We treat it as having no stack limits. This code should
297 298 * be removed when such support is no longer needed.
298 299 */
299 300 return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
300 301 (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4,
301 302 (caddr_t)(uintptr_t)(caddr32_t)arg5, 0));
302 303 case DOOR_CREATE:
303 304 return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1,
304 305 (void *)(uintptr_t)(caddr32_t)arg2, arg3));
305 306 case DOOR_REVOKE:
306 307 return (door_revoke(arg1));
307 308 case DOOR_INFO:
308 309 return (door_info(arg1,
309 310 (struct door_info *)(uintptr_t)(caddr32_t)arg2));
310 311 case DOOR_BIND:
311 312 return (door_bind(arg1));
312 313 case DOOR_UNBIND:
313 314 return (door_unbind());
314 315 case DOOR_UNREFSYS:
315 316 return (door_unref());
316 317 case DOOR_UCRED:
317 318 return (door_ucred(
318 319 (struct ucred_s *)(uintptr_t)(caddr32_t)arg1));
319 320 case DOOR_GETPARAM:
320 321 return (door_getparam(arg1, arg2,
321 322 (size_t *)(uintptr_t)(caddr32_t)arg3));
322 323 case DOOR_SETPARAM:
323 324 return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3));
324 325
325 326 default:
326 327 return (set_errno(EINVAL));
327 328 }
328 329 }
329 330 #endif
330 331
331 332 void shuttle_resume(kthread_t *, kmutex_t *);
332 333 void shuttle_swtch(kmutex_t *);
333 334 void shuttle_sleep(kthread_t *);
334 335
335 336 /*
336 337 * Support routines
337 338 */
338 339 static int door_create_common(void (*)(), void *, uint_t, int, int *,
339 340 file_t **);
340 341 static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
341 342 static int door_args(kthread_t *, int);
342 343 static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
343 344 static int door_copy(struct as *, caddr_t, caddr_t, uint_t);
344 345 static void door_server_exit(proc_t *, kthread_t *);
345 346 static void door_release_server(door_node_t *, kthread_t *);
346 347 static kthread_t *door_get_server(door_node_t *);
347 348 static door_node_t *door_lookup(int, file_t **);
348 349 static int door_translate_in(void);
349 350 static int door_translate_out(void);
350 351 static void door_fd_rele(door_desc_t *, uint_t, int);
351 352 static void door_list_insert(door_node_t *);
352 353 static void door_info_common(door_node_t *, door_info_t *, file_t *);
353 354 static int door_release_fds(door_desc_t *, uint_t);
354 355 static void door_fd_close(door_desc_t *, uint_t);
355 356 static void door_fp_close(struct file **, uint_t);
356 357
357 358 static door_data_t *
358 359 door_my_data(int create_if_missing)
359 360 {
360 361 door_data_t *ddp;
361 362
362 363 ddp = curthread->t_door;
363 364 if (create_if_missing && ddp == NULL)
364 365 ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP);
365 366
366 367 return (ddp);
367 368 }
368 369
369 370 static door_server_t *
370 371 door_my_server(int create_if_missing)
371 372 {
372 373 door_data_t *ddp = door_my_data(create_if_missing);
373 374
374 375 return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL);
375 376 }
376 377
377 378 static door_client_t *
378 379 door_my_client(int create_if_missing)
379 380 {
380 381 door_data_t *ddp = door_my_data(create_if_missing);
381 382
382 383 return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL);
383 384 }
384 385
385 386 /*
386 387 * System call to create a door
387 388 */
388 389 int
389 390 door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes)
390 391 {
391 392 int fd;
392 393 int err;
393 394
394 395 if ((attributes & ~DOOR_CREATE_MASK) ||
395 396 ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
396 397 (DOOR_UNREF | DOOR_UNREF_MULTI)))
397 398 return (set_errno(EINVAL));
398 399
399 400 if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0,
400 401 &fd, NULL)) != 0)
401 402 return (set_errno(err));
402 403
403 404 f_setfd(fd, FD_CLOEXEC);
404 405 return (fd);
405 406 }
406 407
407 408 /*
408 409 * Common code for creating user and kernel doors. If a door was
409 410 * created, stores a file structure pointer in the location pointed
410 411 * to by fpp (if fpp is non-NULL) and returns 0. Also, if a non-NULL
411 412 * pointer to a file descriptor is passed in as fdp, allocates a file
412 413 * descriptor representing the door. If a door could not be created,
413 414 * returns an error.
414 415 */
415 416 static int
416 417 door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
417 418 int from_kernel, int *fdp, file_t **fpp)
418 419 {
419 420 door_node_t *dp;
420 421 vnode_t *vp;
421 422 struct file *fp;
422 423 static door_id_t index = 0;
423 424 proc_t *p = (from_kernel)? &p0 : curproc;
424 425
425 426 dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP);
426 427
427 428 dp->door_vnode = vn_alloc(KM_SLEEP);
428 429 dp->door_target = p;
429 430 dp->door_data = data_cookie;
430 431 dp->door_pc = pc_cookie;
431 432 dp->door_flags = attributes;
432 433 #ifdef _SYSCALL32_IMPL
433 434 if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE)
434 435 dp->door_data_max = UINT32_MAX;
435 436 else
436 437 #endif
437 438 dp->door_data_max = SIZE_MAX;
438 439 dp->door_data_min = 0UL;
439 440 dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX;
440 441
441 442 vp = DTOV(dp);
442 443 vn_setops(vp, door_vnodeops);
443 444 vp->v_type = VDOOR;
444 445 vp->v_vfsp = &door_vfs;
445 446 vp->v_data = (caddr_t)dp;
446 447 mutex_enter(&door_knob);
447 448 dp->door_index = index++;
448 449 /* add to per-process door list */
449 450 door_list_insert(dp);
450 451 mutex_exit(&door_knob);
451 452
452 453 if (falloc(vp, FREAD | FWRITE, &fp, fdp)) {
453 454 /*
454 455 * If the file table is full, remove the door from the
455 456 * per-process list, free the door, and return NULL.
456 457 */
457 458 mutex_enter(&door_knob);
458 459 door_list_delete(dp);
459 460 mutex_exit(&door_knob);
460 461 vn_free(vp);
461 462 kmem_free(dp, sizeof (door_node_t));
462 463 return (EMFILE);
463 464 }
464 465 vn_exists(vp);
465 466 if (fdp != NULL)
466 467 setf(*fdp, fp);
467 468 mutex_exit(&fp->f_tlock);
468 469
469 470 if (fpp != NULL)
470 471 *fpp = fp;
471 472 return (0);
472 473 }
473 474
474 475 static int
475 476 door_check_limits(door_node_t *dp, door_arg_t *da, int upcall)
476 477 {
477 478 ASSERT(MUTEX_HELD(&door_knob));
478 479
479 480 /* we allow unref upcalls through, despite any minimum */
480 481 if (da->data_size < dp->door_data_min &&
481 482 !(upcall && da->data_ptr == DOOR_UNREF_DATA))
482 483 return (ENOBUFS);
483 484
484 485 if (da->data_size > dp->door_data_max)
485 486 return (ENOBUFS);
486 487
487 488 if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC))
488 489 return (ENOTSUP);
489 490
490 491 if (da->desc_num > dp->door_desc_max)
491 492 return (ENFILE);
492 493
493 494 return (0);
494 495 }
495 496
496 497 /*
497 498 * Door invocation.
498 499 */
499 500 int
500 501 door_call(int did, void *args)
501 502 {
502 503 /* Locals */
503 504 door_node_t *dp;
504 505 kthread_t *server_thread;
505 506 int error = 0;
506 507 klwp_t *lwp;
507 508 door_client_t *ct; /* curthread door_data */
508 509 door_server_t *st; /* server thread door_data */
509 510 door_desc_t *start = NULL;
510 511 uint_t ncopied = 0;
511 512 size_t dsize;
512 513 /* destructor for data returned by a kernel server */
513 514 void (*destfn)() = NULL;
514 515 void *destarg;
515 516 model_t datamodel;
516 517 int gotresults = 0;
517 518 int needcleanup = 0;
518 519 int cancel_pending;
519 520
520 521 lwp = ttolwp(curthread);
521 522 datamodel = lwp_getdatamodel(lwp);
522 523
523 524 ct = door_my_client(1);
524 525
525 526 /*
526 527 * Get the arguments
527 528 */
528 529 if (args) {
529 530 if (datamodel == DATAMODEL_NATIVE) {
530 531 if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0)
531 532 return (set_errno(EFAULT));
532 533 } else {
533 534 door_arg32_t da32;
534 535
535 536 if (copyin(args, &da32, sizeof (door_arg32_t)) != 0)
536 537 return (set_errno(EFAULT));
537 538 ct->d_args.data_ptr =
538 539 (char *)(uintptr_t)da32.data_ptr;
539 540 ct->d_args.data_size = da32.data_size;
540 541 ct->d_args.desc_ptr =
541 542 (door_desc_t *)(uintptr_t)da32.desc_ptr;
542 543 ct->d_args.desc_num = da32.desc_num;
543 544 ct->d_args.rbuf =
544 545 (char *)(uintptr_t)da32.rbuf;
545 546 ct->d_args.rsize = da32.rsize;
546 547 }
547 548 } else {
548 549 /* No arguments, and no results allowed */
549 550 ct->d_noresults = 1;
550 551 ct->d_args.data_size = 0;
551 552 ct->d_args.desc_num = 0;
552 553 ct->d_args.rsize = 0;
553 554 }
554 555
555 556 if ((dp = door_lookup(did, NULL)) == NULL)
556 557 return (set_errno(EBADF));
557 558
558 559 /*
559 560 * We don't want to hold the door FD over the entire operation;
560 561 * instead, we put a hold on the door vnode and release the FD
561 562 * immediately
562 563 */
563 564 VN_HOLD(DTOV(dp));
564 565 releasef(did);
565 566
566 567 /*
567 568 * This should be done in shuttle_resume(), just before going to
568 569 * sleep, but we want to avoid overhead while holding door_knob.
569 570 * prstop() is just a no-op if we don't really go to sleep.
570 571 * We test not-kernel-address-space for the sake of clustering code.
571 572 */
572 573 if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
573 574 prstop(PR_REQUESTED, 0);
574 575
575 576 mutex_enter(&door_knob);
576 577 if (DOOR_INVALID(dp)) {
577 578 mutex_exit(&door_knob);
578 579 error = EBADF;
579 580 goto out;
580 581 }
581 582
582 583 /*
583 584 * before we do anything, check that we are not overflowing the
584 585 * required limits.
585 586 */
586 587 error = door_check_limits(dp, &ct->d_args, 0);
587 588 if (error != 0) {
588 589 mutex_exit(&door_knob);
589 590 goto out;
590 591 }
591 592
592 593 /*
593 594 * Check for in-kernel door server.
594 595 */
595 596 if (dp->door_target == &p0) {
596 597 caddr_t rbuf = ct->d_args.rbuf;
597 598 size_t rsize = ct->d_args.rsize;
598 599
599 600 dp->door_active++;
600 601 ct->d_kernel = 1;
601 602 ct->d_error = DOOR_WAIT;
602 603 mutex_exit(&door_knob);
603 604 /* translate file descriptors to vnodes */
604 605 if (ct->d_args.desc_num) {
605 606 error = door_translate_in();
606 607 if (error)
607 608 goto out;
608 609 }
609 610 /*
610 611 * Call kernel door server. Arguments are passed and
611 612 * returned as a door_arg pointer. When called, data_ptr
612 613 * points to user data and desc_ptr points to a kernel list
613 614 * of door descriptors that have been converted to file
614 615 * structure pointers. It's the server function's
615 616 * responsibility to copyin the data pointed to by data_ptr
616 617 * (this avoids extra copying in some cases). On return,
617 618 * data_ptr points to a user buffer of data, and desc_ptr
618 619 * points to a kernel list of door descriptors representing
619 620 * files. When a reference is passed to a kernel server,
620 621 * it is the server's responsibility to release the reference
621 622 * (by calling closef). When the server includes a
622 623 * reference in its reply, it is released as part of the
623 624 * the call (the server must duplicate the reference if
624 625 * it wants to retain a copy). The destfn, if set to
625 626 * non-NULL, is a destructor to be called when the returned
626 627 * kernel data (if any) is no longer needed (has all been
627 628 * translated and copied to user level).
628 629 */
629 630 (*(dp->door_pc))(dp->door_data, &ct->d_args,
630 631 &destfn, &destarg, &error);
631 632 mutex_enter(&door_knob);
632 633 /* not implemented yet */
633 634 if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
634 635 door_deliver_unref(dp);
635 636 mutex_exit(&door_knob);
636 637 if (error)
637 638 goto out;
638 639
639 640 /* translate vnodes to files */
640 641 if (ct->d_args.desc_num) {
641 642 error = door_translate_out();
642 643 if (error)
643 644 goto out;
644 645 }
645 646 ct->d_buf = ct->d_args.rbuf;
646 647 ct->d_bufsize = ct->d_args.rsize;
647 648 if (rsize < (ct->d_args.data_size +
648 649 (ct->d_args.desc_num * sizeof (door_desc_t)))) {
649 650 /* handle overflow */
650 651 error = door_overflow(curthread, ct->d_args.data_ptr,
651 652 ct->d_args.data_size, ct->d_args.desc_ptr,
652 653 ct->d_args.desc_num);
653 654 if (error)
654 655 goto out;
655 656 /* door_overflow sets d_args rbuf and rsize */
656 657 } else {
657 658 ct->d_args.rbuf = rbuf;
658 659 ct->d_args.rsize = rsize;
659 660 }
660 661 goto results;
661 662 }
662 663
663 664 /*
664 665 * Get a server thread from the target domain
665 666 */
666 667 if ((server_thread = door_get_server(dp)) == NULL) {
667 668 if (DOOR_INVALID(dp))
668 669 error = EBADF;
669 670 else
670 671 error = EAGAIN;
671 672 mutex_exit(&door_knob);
672 673 goto out;
673 674 }
674 675
675 676 st = DOOR_SERVER(server_thread->t_door);
676 677 if (ct->d_args.desc_num || ct->d_args.data_size) {
677 678 int is_private = (dp->door_flags & DOOR_PRIVATE);
678 679 /*
679 680 * Move data from client to server
680 681 */
681 682 DOOR_T_HOLD(st);
682 683 mutex_exit(&door_knob);
683 684 error = door_args(server_thread, is_private);
684 685 mutex_enter(&door_knob);
685 686 DOOR_T_RELEASE(st);
686 687 if (error) {
687 688 /*
688 689 * We're not going to resume this thread after all
689 690 */
690 691 door_release_server(dp, server_thread);
691 692 shuttle_sleep(server_thread);
692 693 mutex_exit(&door_knob);
693 694 goto out;
694 695 }
695 696 }
696 697
697 698 dp->door_active++;
698 699 ct->d_error = DOOR_WAIT;
699 700 ct->d_args_done = 0;
700 701 st->d_caller = curthread;
701 702 st->d_active = dp;
702 703
703 704 shuttle_resume(server_thread, &door_knob);
704 705
705 706 mutex_enter(&door_knob);
706 707 shuttle_return:
707 708 if ((error = ct->d_error) < 0) { /* DOOR_WAIT or DOOR_EXIT */
708 709 /*
709 710 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
710 711 */
711 712 mutex_exit(&door_knob); /* May block in ISSIG */
712 713 cancel_pending = 0;
713 714 if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
714 715 MUSTRETURN(curproc, curthread) ||
715 716 (cancel_pending = schedctl_cancel_pending()) != 0) {
716 717 /* Signal, forkall, ... */
717 718 lwp->lwp_sysabort = 0;
718 719 if (cancel_pending)
719 720 schedctl_cancel_eintr();
720 721 mutex_enter(&door_knob);
721 722 error = EINTR;
722 723 /*
723 724 * If the server has finished processing our call,
724 725 * or exited (calling door_slam()), then d_error
725 726 * will have changed. If the server hasn't finished
726 727 * yet, d_error will still be DOOR_WAIT, and we
727 728 * let it know we are not interested in any
728 729 * results by sending a SIGCANCEL, unless the door
729 730 * is marked with DOOR_NO_CANCEL.
730 731 */
731 732 if (ct->d_error == DOOR_WAIT &&
732 733 st->d_caller == curthread) {
733 734 proc_t *p = ttoproc(server_thread);
734 735
735 736 st->d_active = NULL;
736 737 st->d_caller = NULL;
737 738
738 739 if (!(dp->door_flags & DOOR_NO_CANCEL)) {
739 740 DOOR_T_HOLD(st);
740 741 mutex_exit(&door_knob);
741 742
742 743 mutex_enter(&p->p_lock);
743 744 sigtoproc(p, server_thread, SIGCANCEL);
744 745 mutex_exit(&p->p_lock);
745 746
746 747 mutex_enter(&door_knob);
747 748 DOOR_T_RELEASE(st);
748 749 }
749 750 }
750 751 } else {
751 752 /*
752 753 * Return from stop(), server exit...
753 754 *
754 755 * Note that the server could have done a
755 756 * door_return while the client was in stop state
756 757 * (ISSIG), in which case the error condition
757 758 * is updated by the server.
758 759 */
759 760 mutex_enter(&door_knob);
760 761 if (ct->d_error == DOOR_WAIT) {
761 762 /* Still waiting for a reply */
762 763 shuttle_swtch(&door_knob);
763 764 mutex_enter(&door_knob);
764 765 lwp->lwp_asleep = 0;
765 766 goto shuttle_return;
766 767 } else if (ct->d_error == DOOR_EXIT) {
767 768 /* Server exit */
768 769 error = EINTR;
769 770 } else {
770 771 /* Server did a door_return during ISSIG */
771 772 error = ct->d_error;
772 773 }
773 774 }
774 775 /*
775 776 * Can't exit if the server is currently copying
776 777 * results for me.
777 778 */
778 779 while (DOOR_T_HELD(ct))
779 780 cv_wait(&ct->d_cv, &door_knob);
780 781
781 782 /*
782 783 * If the server has not processed our message, free the
783 784 * descriptors.
784 785 */
785 786 if (!ct->d_args_done) {
786 787 needcleanup = 1;
787 788 ct->d_args_done = 1;
788 789 }
789 790
790 791 /*
791 792 * Find out if results were successfully copied.
792 793 */
793 794 if (ct->d_error == 0)
794 795 gotresults = 1;
795 796 }
796 797 ASSERT(ct->d_args_done);
797 798 lwp->lwp_asleep = 0; /* /proc */
798 799 lwp->lwp_sysabort = 0; /* /proc */
799 800 if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
800 801 door_deliver_unref(dp);
801 802 mutex_exit(&door_knob);
802 803
803 804 if (needcleanup)
804 805 door_fp_close(ct->d_fpp, ct->d_args.desc_num);
805 806
806 807 results:
807 808 /*
808 809 * Move the results to userland (if any)
809 810 */
810 811
811 812 if (ct->d_noresults)
812 813 goto out;
813 814
814 815 if (error) {
815 816 /*
816 817 * If server returned results successfully, then we've
817 818 * been interrupted and may need to clean up.
818 819 */
819 820 if (gotresults) {
820 821 ASSERT(error == EINTR);
821 822 door_fp_close(ct->d_fpp, ct->d_args.desc_num);
822 823 }
823 824 goto out;
824 825 }
825 826
826 827 /*
827 828 * Copy back data if we haven't caused an overflow (already
828 829 * handled) and we are using a 2 copy transfer, or we are
829 830 * returning data from a kernel server.
830 831 */
831 832 if (ct->d_args.data_size) {
832 833 ct->d_args.data_ptr = ct->d_args.rbuf;
833 834 if (ct->d_kernel || (!ct->d_overflow &&
834 835 ct->d_args.data_size <= door_max_arg)) {
835 836 if (copyout_nowatch(ct->d_buf, ct->d_args.rbuf,
836 837 ct->d_args.data_size)) {
837 838 door_fp_close(ct->d_fpp, ct->d_args.desc_num);
838 839 error = EFAULT;
839 840 goto out;
840 841 }
841 842 }
842 843 }
843 844
844 845 /*
845 846 * stuff returned doors into our proc, copyout the descriptors
846 847 */
847 848 if (ct->d_args.desc_num) {
848 849 struct file **fpp;
849 850 door_desc_t *didpp;
850 851 uint_t n = ct->d_args.desc_num;
851 852
852 853 dsize = n * sizeof (door_desc_t);
853 854 start = didpp = kmem_alloc(dsize, KM_SLEEP);
854 855 fpp = ct->d_fpp;
855 856
856 857 while (n--) {
857 858 if (door_insert(*fpp, didpp) == -1) {
858 859 /* Close remaining files */
859 860 door_fp_close(fpp, n + 1);
860 861 error = EMFILE;
861 862 goto out;
862 863 }
863 864 fpp++; didpp++; ncopied++;
864 865 }
865 866
866 867 ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
867 868 roundup(ct->d_args.data_size, sizeof (door_desc_t)));
868 869
869 870 if (copyout_nowatch(start, ct->d_args.desc_ptr, dsize)) {
870 871 error = EFAULT;
871 872 goto out;
872 873 }
873 874 }
874 875
875 876 /*
876 877 * Return the results
877 878 */
878 879 if (datamodel == DATAMODEL_NATIVE) {
879 880 if (copyout_nowatch(&ct->d_args, args,
880 881 sizeof (door_arg_t)) != 0)
881 882 error = EFAULT;
882 883 } else {
883 884 door_arg32_t da32;
884 885
885 886 da32.data_ptr = (caddr32_t)(uintptr_t)ct->d_args.data_ptr;
886 887 da32.data_size = ct->d_args.data_size;
887 888 da32.desc_ptr = (caddr32_t)(uintptr_t)ct->d_args.desc_ptr;
888 889 da32.desc_num = ct->d_args.desc_num;
889 890 da32.rbuf = (caddr32_t)(uintptr_t)ct->d_args.rbuf;
890 891 da32.rsize = ct->d_args.rsize;
891 892 if (copyout_nowatch(&da32, args, sizeof (door_arg32_t)) != 0) {
892 893 error = EFAULT;
893 894 }
894 895 }
895 896
896 897 out:
897 898 ct->d_noresults = 0;
898 899
899 900 /* clean up the overflow buffer if an error occurred */
900 901 if (error != 0 && ct->d_overflow) {
901 902 (void) as_unmap(curproc->p_as, ct->d_args.rbuf,
902 903 ct->d_args.rsize);
903 904 }
904 905 ct->d_overflow = 0;
905 906
906 907 /* call destructor */
907 908 if (destfn) {
908 909 ASSERT(ct->d_kernel);
909 910 (*destfn)(dp->door_data, destarg);
910 911 ct->d_buf = NULL;
911 912 ct->d_bufsize = 0;
912 913 }
913 914
914 915 if (dp)
915 916 VN_RELE(DTOV(dp));
916 917
917 918 if (ct->d_buf) {
918 919 ASSERT(!ct->d_kernel);
919 920 kmem_free(ct->d_buf, ct->d_bufsize);
920 921 ct->d_buf = NULL;
921 922 ct->d_bufsize = 0;
922 923 }
923 924 ct->d_kernel = 0;
924 925
925 926 /* clean up the descriptor copyout buffer */
926 927 if (start != NULL) {
927 928 if (error != 0)
928 929 door_fd_close(start, ncopied);
929 930 kmem_free(start, dsize);
930 931 }
931 932
932 933 if (ct->d_fpp) {
933 934 kmem_free(ct->d_fpp, ct->d_fpp_size);
934 935 ct->d_fpp = NULL;
935 936 ct->d_fpp_size = 0;
936 937 }
937 938
938 939 if (error)
939 940 return (set_errno(error));
940 941
941 942 return (0);
942 943 }
943 944
944 945 static int
945 946 door_setparam_common(door_node_t *dp, int from_kernel, int type, size_t val)
946 947 {
947 948 int error = 0;
948 949
949 950 mutex_enter(&door_knob);
950 951
951 952 if (DOOR_INVALID(dp)) {
952 953 mutex_exit(&door_knob);
953 954 return (EBADF);
954 955 }
955 956
956 957 /*
957 958 * door_ki_setparam() can only affect kernel doors.
958 959 * door_setparam() can only affect doors attached to the current
959 960 * process.
960 961 */
961 962 if ((from_kernel && dp->door_target != &p0) ||
962 963 (!from_kernel && dp->door_target != curproc)) {
963 964 mutex_exit(&door_knob);
964 965 return (EPERM);
965 966 }
966 967
967 968 switch (type) {
968 969 case DOOR_PARAM_DESC_MAX:
969 970 if (val > INT_MAX)
970 971 error = ERANGE;
971 972 else if ((dp->door_flags & DOOR_REFUSE_DESC) && val != 0)
972 973 error = ENOTSUP;
973 974 else
974 975 dp->door_desc_max = (uint_t)val;
975 976 break;
976 977
977 978 case DOOR_PARAM_DATA_MIN:
978 979 if (val > dp->door_data_max)
979 980 error = EINVAL;
980 981 else
981 982 dp->door_data_min = val;
982 983 break;
983 984
984 985 case DOOR_PARAM_DATA_MAX:
985 986 if (val < dp->door_data_min)
986 987 error = EINVAL;
987 988 else
988 989 dp->door_data_max = val;
989 990 break;
990 991
991 992 default:
992 993 error = EINVAL;
993 994 break;
994 995 }
995 996
996 997 mutex_exit(&door_knob);
997 998 return (error);
998 999 }
999 1000
1000 1001 static int
1001 1002 door_getparam_common(door_node_t *dp, int type, size_t *out)
1002 1003 {
1003 1004 int error = 0;
1004 1005
1005 1006 mutex_enter(&door_knob);
1006 1007 switch (type) {
1007 1008 case DOOR_PARAM_DESC_MAX:
1008 1009 *out = (size_t)dp->door_desc_max;
1009 1010 break;
1010 1011 case DOOR_PARAM_DATA_MIN:
1011 1012 *out = dp->door_data_min;
1012 1013 break;
1013 1014 case DOOR_PARAM_DATA_MAX:
1014 1015 *out = dp->door_data_max;
1015 1016 break;
1016 1017 default:
1017 1018 error = EINVAL;
1018 1019 break;
1019 1020 }
1020 1021 mutex_exit(&door_knob);
1021 1022 return (error);
1022 1023 }
1023 1024
1024 1025 int
1025 1026 door_setparam(int did, int type, size_t val)
1026 1027 {
1027 1028 door_node_t *dp;
1028 1029 int error = 0;
1029 1030
1030 1031 if ((dp = door_lookup(did, NULL)) == NULL)
1031 1032 return (set_errno(EBADF));
1032 1033
1033 1034 error = door_setparam_common(dp, 0, type, val);
1034 1035
1035 1036 releasef(did);
1036 1037
1037 1038 if (error)
1038 1039 return (set_errno(error));
1039 1040
1040 1041 return (0);
1041 1042 }
1042 1043
1043 1044 int
1044 1045 door_getparam(int did, int type, size_t *out)
1045 1046 {
1046 1047 door_node_t *dp;
1047 1048 size_t val = 0;
1048 1049 int error = 0;
1049 1050
1050 1051 if ((dp = door_lookup(did, NULL)) == NULL)
1051 1052 return (set_errno(EBADF));
1052 1053
1053 1054 error = door_getparam_common(dp, type, &val);
1054 1055
1055 1056 releasef(did);
1056 1057
1057 1058 if (error)
1058 1059 return (set_errno(error));
1059 1060
1060 1061 if (get_udatamodel() == DATAMODEL_NATIVE) {
1061 1062 if (copyout(&val, out, sizeof (val)))
1062 1063 return (set_errno(EFAULT));
1063 1064 #ifdef _SYSCALL32_IMPL
1064 1065 } else {
1065 1066 size32_t val32 = (size32_t)val;
1066 1067
1067 1068 if (val != val32)
1068 1069 return (set_errno(EOVERFLOW));
1069 1070
1070 1071 if (copyout(&val32, out, sizeof (val32)))
1071 1072 return (set_errno(EFAULT));
1072 1073 #endif /* _SYSCALL32_IMPL */
1073 1074 }
1074 1075
1075 1076 return (0);
1076 1077 }
1077 1078
1078 1079 /*
1079 1080 * A copyout() which proceeds from high addresses to low addresses. This way,
1080 1081 * stack guard pages are effective.
1081 1082 *
1082 1083 * Note that we use copyout_nowatch(); this is called while the client is
1083 1084 * held.
1084 1085 */
1085 1086 static int
1086 1087 door_stack_copyout(const void *kaddr, void *uaddr, size_t count)
1087 1088 {
1088 1089 const char *kbase = (const char *)kaddr;
1089 1090 uintptr_t ubase = (uintptr_t)uaddr;
1090 1091 size_t pgsize = PAGESIZE;
1091 1092
1092 1093 if (count <= pgsize)
1093 1094 return (copyout_nowatch(kaddr, uaddr, count));
1094 1095
1095 1096 while (count > 0) {
1096 1097 uintptr_t start, end, offset, amount;
1097 1098
1098 1099 end = ubase + count;
1099 1100 start = P2ALIGN(end - 1, pgsize);
1100 1101 if (P2ALIGN(ubase, pgsize) == start)
1101 1102 start = ubase;
1102 1103
1103 1104 offset = start - ubase;
1104 1105 amount = end - start;
1105 1106
1106 1107 ASSERT(amount > 0 && amount <= count && amount <= pgsize);
1107 1108
1108 1109 if (copyout_nowatch(kbase + offset, (void *)start, amount))
1109 1110 return (1);
1110 1111 count -= amount;
1111 1112 }
1112 1113 return (0);
1113 1114 }
1114 1115
1115 1116 /*
1116 1117 * Writes the stack layout for door_return() into the door_server_t of the
1117 1118 * server thread.
1118 1119 */
1119 1120 static int
1120 1121 door_layout(kthread_t *tp, size_t data_size, uint_t ndesc, int info_needed)
1121 1122 {
1122 1123 door_server_t *st = DOOR_SERVER(tp->t_door);
1123 1124 door_layout_t *out = &st->d_layout;
1124 1125 uintptr_t base_sp = (uintptr_t)st->d_sp;
1125 1126 size_t ssize = st->d_ssize;
1126 1127 size_t descsz;
1127 1128 uintptr_t descp, datap, infop, resultsp, finalsp;
1128 1129 size_t align = STACK_ALIGN;
1129 1130 size_t results_sz = sizeof (struct door_results);
1130 1131 model_t datamodel = lwp_getdatamodel(ttolwp(tp));
1131 1132
1132 1133 ASSERT(!st->d_layout_done);
1133 1134
1134 1135 #ifndef _STACK_GROWS_DOWNWARD
1135 1136 #error stack does not grow downward, door_layout() must change
1136 1137 #endif
1137 1138
1138 1139 #ifdef _SYSCALL32_IMPL
1139 1140 if (datamodel != DATAMODEL_NATIVE) {
1140 1141 align = STACK_ALIGN32;
1141 1142 results_sz = sizeof (struct door_results32);
1142 1143 }
1143 1144 #endif
1144 1145
1145 1146 descsz = ndesc * sizeof (door_desc_t);
1146 1147
1147 1148 /*
1148 1149 * To speed up the overflow checking, we do an initial check
1149 1150 * that the passed in data size won't cause us to wrap past
1150 1151 * base_sp. Since door_max_desc limits descsz, we can
1151 1152 * safely use it here. 65535 is an arbitrary 'bigger than
1152 1153 * we need, small enough to not cause trouble' constant;
1153 1154 * the only constraint is that it must be > than:
1154 1155 *
1155 1156 * 5 * STACK_ALIGN +
1156 1157 * sizeof (door_info_t) +
1157 1158 * sizeof (door_results_t) +
1158 1159 * (max adjustment from door_final_sp())
1159 1160 *
1160 1161 * After we compute the layout, we can safely do a "did we wrap
1161 1162 * around" check, followed by a check against the recorded
1162 1163 * stack size.
1163 1164 */
1164 1165 if (data_size >= SIZE_MAX - (size_t)65535UL - descsz)
1165 1166 return (E2BIG); /* overflow */
1166 1167
1167 1168 descp = P2ALIGN(base_sp - descsz, align);
1168 1169 datap = P2ALIGN(descp - data_size, align);
1169 1170
1170 1171 if (info_needed)
1171 1172 infop = P2ALIGN(datap - sizeof (door_info_t), align);
1172 1173 else
1173 1174 infop = datap;
1174 1175
1175 1176 resultsp = P2ALIGN(infop - results_sz, align);
1176 1177 finalsp = door_final_sp(resultsp, align, datamodel);
1177 1178
1178 1179 if (finalsp > base_sp)
1179 1180 return (E2BIG); /* overflow */
1180 1181
1181 1182 if (ssize != 0 && (base_sp - finalsp) > ssize)
1182 1183 return (E2BIG); /* doesn't fit in stack */
1183 1184
1184 1185 out->dl_descp = (ndesc != 0)? (caddr_t)descp : 0;
1185 1186 out->dl_datap = (data_size != 0)? (caddr_t)datap : 0;
1186 1187 out->dl_infop = info_needed? (caddr_t)infop : 0;
1187 1188 out->dl_resultsp = (caddr_t)resultsp;
1188 1189 out->dl_sp = (caddr_t)finalsp;
1189 1190
1190 1191 st->d_layout_done = 1;
1191 1192 return (0);
1192 1193 }
1193 1194
1194 1195 static int
1195 1196 door_server_dispatch(door_client_t *ct, door_node_t *dp)
1196 1197 {
1197 1198 door_server_t *st = DOOR_SERVER(curthread->t_door);
1198 1199 door_layout_t *layout = &st->d_layout;
1199 1200 int error = 0;
1200 1201
1201 1202 int is_private = (dp->door_flags & DOOR_PRIVATE);
1202 1203
1203 1204 door_pool_t *pool = (is_private)? &dp->door_servers :
1204 1205 &curproc->p_server_threads;
1205 1206
1206 1207 int empty_pool = (pool->dp_threads == NULL);
1207 1208
1208 1209 caddr_t infop = NULL;
1209 1210 char *datap = NULL;
1210 1211 size_t datasize = 0;
1211 1212 size_t descsize;
1212 1213
1213 1214 file_t **fpp = ct->d_fpp;
1214 1215 door_desc_t *start = NULL;
1215 1216 uint_t ndesc = 0;
1216 1217 uint_t ncopied = 0;
1217 1218
1218 1219 if (ct != NULL) {
1219 1220 datap = ct->d_args.data_ptr;
1220 1221 datasize = ct->d_args.data_size;
1221 1222 ndesc = ct->d_args.desc_num;
1222 1223 }
1223 1224
1224 1225 descsize = ndesc * sizeof (door_desc_t);
1225 1226
1226 1227 /*
1227 1228 * Reset datap to NULL if we aren't passing any data. Be careful
1228 1229 * to let unref notifications through, though.
1229 1230 */
1230 1231 if (datap == DOOR_UNREF_DATA) {
1231 1232 if (ct->d_upcall != NULL)
1232 1233 datasize = 0;
1233 1234 else
1234 1235 datap = NULL;
1235 1236 } else if (datasize == 0) {
1236 1237 datap = NULL;
1237 1238 }
1238 1239
1239 1240 /*
1240 1241 * Get the stack layout, if it hasn't already been done.
1241 1242 */
1242 1243 if (!st->d_layout_done) {
1243 1244 error = door_layout(curthread, datasize, ndesc,
1244 1245 (is_private && empty_pool));
1245 1246 if (error != 0)
1246 1247 goto fail;
1247 1248 }
1248 1249
1249 1250 /*
1250 1251 * fill out the stack, starting from the top. Layout was already
1251 1252 * filled in by door_args() or door_translate_out().
1252 1253 */
1253 1254 if (layout->dl_descp != NULL) {
1254 1255 ASSERT(ndesc != 0);
1255 1256 start = kmem_alloc(descsize, KM_SLEEP);
1256 1257
1257 1258 while (ndesc > 0) {
1258 1259 if (door_insert(*fpp, &start[ncopied]) == -1) {
1259 1260 error = EMFILE;
1260 1261 goto fail;
1261 1262 }
1262 1263 ndesc--;
1263 1264 ncopied++;
1264 1265 fpp++;
1265 1266 }
1266 1267 if (door_stack_copyout(start, layout->dl_descp, descsize)) {
1267 1268 error = E2BIG;
1268 1269 goto fail;
1269 1270 }
1270 1271 }
1271 1272 fpp = NULL; /* finished processing */
1272 1273
1273 1274 if (layout->dl_datap != NULL) {
1274 1275 ASSERT(datasize != 0);
1275 1276 datap = layout->dl_datap;
1276 1277 if (ct->d_upcall != NULL || datasize <= door_max_arg) {
1277 1278 if (door_stack_copyout(ct->d_buf, datap, datasize)) {
1278 1279 error = E2BIG;
1279 1280 goto fail;
1280 1281 }
1281 1282 }
1282 1283 }
1283 1284
1284 1285 if (is_private && empty_pool) {
1285 1286 door_info_t di;
1286 1287
1287 1288 infop = layout->dl_infop;
1288 1289 ASSERT(infop != NULL);
1289 1290
1290 1291 di.di_target = curproc->p_pid;
1291 1292 di.di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
1292 1293 di.di_data = (door_ptr_t)(uintptr_t)dp->door_data;
1293 1294 di.di_uniquifier = dp->door_index;
1294 1295 di.di_attributes = (dp->door_flags & DOOR_ATTR_MASK) |
1295 1296 DOOR_LOCAL;
1296 1297
1297 1298 if (door_stack_copyout(&di, infop, sizeof (di))) {
1298 1299 error = E2BIG;
1299 1300 goto fail;
1300 1301 }
1301 1302 }
1302 1303
1303 1304 if (get_udatamodel() == DATAMODEL_NATIVE) {
1304 1305 struct door_results dr;
1305 1306
1306 1307 dr.cookie = dp->door_data;
1307 1308 dr.data_ptr = datap;
1308 1309 dr.data_size = datasize;
1309 1310 dr.desc_ptr = (door_desc_t *)layout->dl_descp;
1310 1311 dr.desc_num = ncopied;
1311 1312 dr.pc = dp->door_pc;
1312 1313 dr.nservers = !empty_pool;
1313 1314 dr.door_info = (door_info_t *)infop;
1314 1315
1315 1316 if (door_stack_copyout(&dr, layout->dl_resultsp, sizeof (dr))) {
1316 1317 error = E2BIG;
1317 1318 goto fail;
1318 1319 }
1319 1320 #ifdef _SYSCALL32_IMPL
1320 1321 } else {
1321 1322 struct door_results32 dr32;
1322 1323
1323 1324 dr32.cookie = (caddr32_t)(uintptr_t)dp->door_data;
1324 1325 dr32.data_ptr = (caddr32_t)(uintptr_t)datap;
1325 1326 dr32.data_size = (size32_t)datasize;
1326 1327 dr32.desc_ptr = (caddr32_t)(uintptr_t)layout->dl_descp;
1327 1328 dr32.desc_num = ncopied;
1328 1329 dr32.pc = (caddr32_t)(uintptr_t)dp->door_pc;
1329 1330 dr32.nservers = !empty_pool;
1330 1331 dr32.door_info = (caddr32_t)(uintptr_t)infop;
1331 1332
1332 1333 if (door_stack_copyout(&dr32, layout->dl_resultsp,
1333 1334 sizeof (dr32))) {
1334 1335 error = E2BIG;
1335 1336 goto fail;
1336 1337 }
1337 1338 #endif
1338 1339 }
1339 1340
1340 1341 error = door_finish_dispatch(layout->dl_sp);
1341 1342 fail:
1342 1343 if (start != NULL) {
1343 1344 if (error != 0)
1344 1345 door_fd_close(start, ncopied);
1345 1346 kmem_free(start, descsize);
1346 1347 }
1347 1348 if (fpp != NULL)
1348 1349 door_fp_close(fpp, ndesc);
1349 1350
1350 1351 return (error);
1351 1352 }
1352 1353
1353 1354 /*
1354 1355 * Return the results (if any) to the caller (if any) and wait for the
1355 1356 * next invocation on a door.
1356 1357 */
1357 1358 int
1358 1359 door_return(caddr_t data_ptr, size_t data_size,
1359 1360 door_desc_t *desc_ptr, uint_t desc_num, caddr_t sp, size_t ssize)
1360 1361 {
1361 1362 kthread_t *caller;
1362 1363 klwp_t *lwp;
1363 1364 int error = 0;
1364 1365 door_node_t *dp;
1365 1366 door_server_t *st; /* curthread door_data */
1366 1367 door_client_t *ct; /* caller door_data */
1367 1368 int cancel_pending;
1368 1369
1369 1370 st = door_my_server(1);
1370 1371
1371 1372 /*
1372 1373 * If thread was bound to a door that no longer exists, return
1373 1374 * an error. This can happen if a thread is bound to a door
1374 1375 * before the process calls forkall(); in the child, the door
1375 1376 * doesn't exist and door_fork() sets the d_invbound flag.
1376 1377 */
1377 1378 if (st->d_invbound)
1378 1379 return (set_errno(EINVAL));
1379 1380
1380 1381 st->d_sp = sp; /* Save base of stack. */
1381 1382 st->d_ssize = ssize; /* and its size */
1382 1383
1383 1384 /*
1384 1385 * This should be done in shuttle_resume(), just before going to
1385 1386 * sleep, but we want to avoid overhead while holding door_knob.
1386 1387 * prstop() is just a no-op if we don't really go to sleep.
1387 1388 * We test not-kernel-address-space for the sake of clustering code.
1388 1389 */
1389 1390 lwp = ttolwp(curthread);
1390 1391 if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
1391 1392 prstop(PR_REQUESTED, 0);
1392 1393
1393 1394 /* Make sure the caller hasn't gone away */
1394 1395 mutex_enter(&door_knob);
1395 1396 if ((caller = st->d_caller) == NULL || caller->t_door == NULL) {
1396 1397 if (desc_num != 0) {
1397 1398 /* close any DOOR_RELEASE descriptors */
1398 1399 mutex_exit(&door_knob);
1399 1400 error = door_release_fds(desc_ptr, desc_num);
1400 1401 if (error)
1401 1402 return (set_errno(error));
1402 1403 mutex_enter(&door_knob);
1403 1404 }
1404 1405 goto out;
1405 1406 }
1406 1407 ct = DOOR_CLIENT(caller->t_door);
1407 1408
1408 1409 ct->d_args.data_size = data_size;
1409 1410 ct->d_args.desc_num = desc_num;
1410 1411 /*
1411 1412 * Transfer results, if any, to the client
1412 1413 */
1413 1414 if (data_size != 0 || desc_num != 0) {
1414 1415 /*
1415 1416 * Prevent the client from exiting until we have finished
1416 1417 * moving results.
1417 1418 */
1418 1419 DOOR_T_HOLD(ct);
1419 1420 mutex_exit(&door_knob);
1420 1421 error = door_results(caller, data_ptr, data_size,
1421 1422 desc_ptr, desc_num);
1422 1423 mutex_enter(&door_knob);
1423 1424 DOOR_T_RELEASE(ct);
1424 1425 /*
1425 1426 * Pass EOVERFLOW errors back to the client
1426 1427 */
1427 1428 if (error && error != EOVERFLOW) {
1428 1429 mutex_exit(&door_knob);
1429 1430 return (set_errno(error));
1430 1431 }
1431 1432 }
1432 1433 out:
1433 1434 /* Put ourselves on the available server thread list */
1434 1435 door_release_server(st->d_pool, curthread);
1435 1436
1436 1437 /*
1437 1438 * Make sure the caller is still waiting to be resumed
1438 1439 */
1439 1440 if (caller) {
1440 1441 disp_lock_t *tlp;
1441 1442
1442 1443 thread_lock(caller);
1443 1444 ct->d_error = error; /* Return any errors */
1444 1445 if (caller->t_state == TS_SLEEP &&
1445 1446 SOBJ_TYPE(caller->t_sobj_ops) == SOBJ_SHUTTLE) {
1446 1447 cpu_t *cp = CPU;
1447 1448
1448 1449 tlp = caller->t_lockp;
1449 1450 /*
1450 1451 * Setting t_disp_queue prevents erroneous preemptions
1451 1452 * if this thread is still in execution on another
1452 1453 * processor
1453 1454 */
1454 1455 caller->t_disp_queue = cp->cpu_disp;
1455 1456 CL_ACTIVE(caller);
1456 1457 /*
1457 1458 * We are calling thread_onproc() instead of
1458 1459 * THREAD_ONPROC() because compiler can reorder
1459 1460 * the two stores of t_state and t_lockp in
1460 1461 * THREAD_ONPROC().
1461 1462 */
1462 1463 thread_onproc(caller, cp);
1463 1464 disp_lock_exit_high(tlp);
1464 1465 shuttle_resume(caller, &door_knob);
1465 1466 } else {
1466 1467 /* May have been setrun or in stop state */
1467 1468 thread_unlock(caller);
1468 1469 shuttle_swtch(&door_knob);
1469 1470 }
1470 1471 } else {
1471 1472 shuttle_swtch(&door_knob);
1472 1473 }
1473 1474
1474 1475 /*
1475 1476 * We've sprung to life. Determine if we are part of a door
1476 1477 * invocation, or just interrupted
1477 1478 */
1478 1479 mutex_enter(&door_knob);
1479 1480 if ((dp = st->d_active) != NULL) {
1480 1481 /*
1481 1482 * Normal door invocation. Return any error condition
1482 1483 * encountered while trying to pass args to the server
1483 1484 * thread.
1484 1485 */
1485 1486 lwp->lwp_asleep = 0;
1486 1487 /*
1487 1488 * Prevent the caller from leaving us while we
1488 1489 * are copying out the arguments from it's buffer.
1489 1490 */
1490 1491 ASSERT(st->d_caller != NULL);
1491 1492 ct = DOOR_CLIENT(st->d_caller->t_door);
1492 1493
1493 1494 DOOR_T_HOLD(ct);
1494 1495 mutex_exit(&door_knob);
1495 1496 error = door_server_dispatch(ct, dp);
1496 1497 mutex_enter(&door_knob);
1497 1498 DOOR_T_RELEASE(ct);
1498 1499
1499 1500 /* let the client know we have processed his message */
1500 1501 ct->d_args_done = 1;
1501 1502
1502 1503 if (error) {
1503 1504 caller = st->d_caller;
1504 1505 if (caller)
1505 1506 ct = DOOR_CLIENT(caller->t_door);
1506 1507 else
1507 1508 ct = NULL;
1508 1509 goto out;
1509 1510 }
1510 1511 mutex_exit(&door_knob);
1511 1512 return (0);
1512 1513 } else {
1513 1514 /*
1514 1515 * We are not involved in a door_invocation.
1515 1516 * Check for /proc related activity...
1516 1517 */
1517 1518 st->d_caller = NULL;
1518 1519 door_server_exit(curproc, curthread);
1519 1520 mutex_exit(&door_knob);
1520 1521 cancel_pending = 0;
1521 1522 if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
1522 1523 MUSTRETURN(curproc, curthread) ||
1523 1524 (cancel_pending = schedctl_cancel_pending()) != 0) {
1524 1525 if (cancel_pending)
1525 1526 schedctl_cancel_eintr();
1526 1527 lwp->lwp_asleep = 0;
1527 1528 lwp->lwp_sysabort = 0;
1528 1529 return (set_errno(EINTR));
1529 1530 }
1530 1531 /* Go back and wait for another request */
1531 1532 lwp->lwp_asleep = 0;
1532 1533 mutex_enter(&door_knob);
1533 1534 caller = NULL;
1534 1535 goto out;
1535 1536 }
1536 1537 }
1537 1538
1538 1539 /*
1539 1540 * Revoke any future invocations on this door
1540 1541 */
1541 1542 int
1542 1543 door_revoke(int did)
1543 1544 {
1544 1545 door_node_t *d;
1545 1546 int error;
1546 1547
1547 1548 if ((d = door_lookup(did, NULL)) == NULL)
1548 1549 return (set_errno(EBADF));
1549 1550
1550 1551 mutex_enter(&door_knob);
1551 1552 if (d->door_target != curproc) {
1552 1553 mutex_exit(&door_knob);
1553 1554 releasef(did);
1554 1555 return (set_errno(EPERM));
1555 1556 }
1556 1557 d->door_flags |= DOOR_REVOKED;
1557 1558 if (d->door_flags & DOOR_PRIVATE)
1558 1559 cv_broadcast(&d->door_servers.dp_cv);
1559 1560 else
1560 1561 cv_broadcast(&curproc->p_server_threads.dp_cv);
1561 1562 mutex_exit(&door_knob);
1562 1563 releasef(did);
1563 1564 /* Invalidate the descriptor */
1564 1565 if ((error = closeandsetf(did, NULL)) != 0)
1565 1566 return (set_errno(error));
1566 1567 return (0);
1567 1568 }
1568 1569
1569 1570 int
1570 1571 door_info(int did, struct door_info *d_info)
1571 1572 {
1572 1573 door_node_t *dp;
1573 1574 door_info_t di;
1574 1575 door_server_t *st;
1575 1576 file_t *fp = NULL;
1576 1577
1577 1578 if (did == DOOR_QUERY) {
1578 1579 /* Get information on door current thread is bound to */
1579 1580 if ((st = door_my_server(0)) == NULL ||
1580 1581 (dp = st->d_pool) == NULL)
1581 1582 /* Thread isn't bound to a door */
1582 1583 return (set_errno(EBADF));
1583 1584 } else if ((dp = door_lookup(did, &fp)) == NULL) {
1584 1585 /* Not a door */
1585 1586 return (set_errno(EBADF));
1586 1587 }
1587 1588
1588 1589 door_info_common(dp, &di, fp);
1589 1590
1590 1591 if (did != DOOR_QUERY)
1591 1592 releasef(did);
1592 1593
1593 1594 if (copyout(&di, d_info, sizeof (struct door_info)))
1594 1595 return (set_errno(EFAULT));
1595 1596 return (0);
1596 1597 }
1597 1598
1598 1599 /*
1599 1600 * Common code for getting information about a door either via the
1600 1601 * door_info system call or the door_ki_info kernel call.
1601 1602 */
1602 1603 void
1603 1604 door_info_common(door_node_t *dp, struct door_info *dip, file_t *fp)
1604 1605 {
1605 1606 int unref_count;
1606 1607
1607 1608 bzero(dip, sizeof (door_info_t));
1608 1609
1609 1610 mutex_enter(&door_knob);
1610 1611 if (dp->door_target == NULL)
1611 1612 dip->di_target = -1;
1612 1613 else
1613 1614 dip->di_target = dp->door_target->p_pid;
1614 1615
1615 1616 dip->di_attributes = dp->door_flags & DOOR_ATTR_MASK;
1616 1617 if (dp->door_target == curproc)
1617 1618 dip->di_attributes |= DOOR_LOCAL;
1618 1619 dip->di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
1619 1620 dip->di_data = (door_ptr_t)(uintptr_t)dp->door_data;
1620 1621 dip->di_uniquifier = dp->door_index;
1621 1622 /*
1622 1623 * If this door is in the middle of having an unreferenced
1623 1624 * notification delivered, don't count the VN_HOLD by
1624 1625 * door_deliver_unref in determining if it is unreferenced.
1625 1626 * This handles the case where door_info is called from the
1626 1627 * thread delivering the unref notification.
1627 1628 */
1628 1629 if (dp->door_flags & DOOR_UNREF_ACTIVE)
1629 1630 unref_count = 2;
1630 1631 else
1631 1632 unref_count = 1;
1632 1633 mutex_exit(&door_knob);
1633 1634
1634 1635 if (fp == NULL) {
1635 1636 /*
1636 1637 * If this thread is bound to the door, then we can just
1637 1638 * check the vnode; a ref count of 1 (or 2 if this is
1638 1639 * handling an unref notification) means that the hold
1639 1640 * from the door_bind is the only reference to the door
1640 1641 * (no file descriptor refers to it).
1641 1642 */
1642 1643 if (DTOV(dp)->v_count == unref_count)
1643 1644 dip->di_attributes |= DOOR_IS_UNREF;
1644 1645 } else {
1645 1646 /*
1646 1647 * If we're working from a file descriptor or door handle
1647 1648 * we need to look at the file structure count. We don't
1648 1649 * need to hold the vnode lock since this is just a snapshot.
1649 1650 */
1650 1651 mutex_enter(&fp->f_tlock);
1651 1652 if (fp->f_count == 1 && DTOV(dp)->v_count == unref_count)
1652 1653 dip->di_attributes |= DOOR_IS_UNREF;
1653 1654 mutex_exit(&fp->f_tlock);
1654 1655 }
1655 1656 }
1656 1657
1657 1658 /*
1658 1659 * Return credentials of the door caller (if any) for this invocation
1659 1660 */
1660 1661 int
1661 1662 door_ucred(struct ucred_s *uch)
1662 1663 {
1663 1664 kthread_t *caller;
1664 1665 door_server_t *st;
1665 1666 door_client_t *ct;
1666 1667 door_upcall_t *dup;
1667 1668 struct proc *p;
1668 1669 struct ucred_s *res;
1669 1670 int err;
1670 1671
1671 1672 mutex_enter(&door_knob);
1672 1673 if ((st = door_my_server(0)) == NULL ||
1673 1674 (caller = st->d_caller) == NULL) {
1674 1675 mutex_exit(&door_knob);
1675 1676 return (set_errno(EINVAL));
1676 1677 }
1677 1678
1678 1679 ASSERT(caller->t_door != NULL);
1679 1680 ct = DOOR_CLIENT(caller->t_door);
1680 1681
1681 1682 /* Prevent caller from exiting while we examine the cred */
1682 1683 DOOR_T_HOLD(ct);
1683 1684 mutex_exit(&door_knob);
1684 1685
1685 1686 p = ttoproc(caller);
1686 1687
1687 1688 /*
1688 1689 * If the credentials are not specified by the client, get the one
1689 1690 * associated with the calling process.
1690 1691 */
1691 1692 if ((dup = ct->d_upcall) != NULL)
1692 1693 res = cred2ucred(dup->du_cred, p0.p_pid, NULL, CRED());
1693 1694 else
1694 1695 res = cred2ucred(caller->t_cred, p->p_pid, NULL, CRED());
1695 1696
1696 1697 mutex_enter(&door_knob);
1697 1698 DOOR_T_RELEASE(ct);
1698 1699 mutex_exit(&door_knob);
1699 1700
1700 1701 err = copyout(res, uch, res->uc_size);
1701 1702
1702 1703 kmem_free(res, res->uc_size);
1703 1704
1704 1705 if (err != 0)
1705 1706 return (set_errno(EFAULT));
1706 1707
1707 1708 return (0);
1708 1709 }
1709 1710
1710 1711 /*
1711 1712 * Bind the current lwp to the server thread pool associated with 'did'
1712 1713 */
1713 1714 int
1714 1715 door_bind(int did)
1715 1716 {
1716 1717 door_node_t *dp;
1717 1718 door_server_t *st;
1718 1719
1719 1720 if ((dp = door_lookup(did, NULL)) == NULL) {
1720 1721 /* Not a door */
1721 1722 return (set_errno(EBADF));
1722 1723 }
1723 1724
1724 1725 /*
1725 1726 * Can't bind to a non-private door, and can't bind to a door
1726 1727 * served by another process.
1727 1728 */
1728 1729 if ((dp->door_flags & DOOR_PRIVATE) == 0 ||
1729 1730 dp->door_target != curproc) {
1730 1731 releasef(did);
1731 1732 return (set_errno(EINVAL));
1732 1733 }
1733 1734
1734 1735 st = door_my_server(1);
1735 1736 if (st->d_pool)
1736 1737 door_unbind_thread(st->d_pool);
1737 1738 st->d_pool = dp;
1738 1739 st->d_invbound = 0;
1739 1740 door_bind_thread(dp);
1740 1741 releasef(did);
1741 1742
1742 1743 return (0);
1743 1744 }
1744 1745
1745 1746 /*
1746 1747 * Unbind the current lwp from it's server thread pool
1747 1748 */
1748 1749 int
1749 1750 door_unbind(void)
1750 1751 {
1751 1752 door_server_t *st;
1752 1753
1753 1754 if ((st = door_my_server(0)) == NULL)
1754 1755 return (set_errno(EBADF));
1755 1756
1756 1757 if (st->d_invbound) {
1757 1758 ASSERT(st->d_pool == NULL);
1758 1759 st->d_invbound = 0;
1759 1760 return (0);
1760 1761 }
1761 1762 if (st->d_pool == NULL)
1762 1763 return (set_errno(EBADF));
1763 1764 door_unbind_thread(st->d_pool);
1764 1765 st->d_pool = NULL;
1765 1766 return (0);
1766 1767 }
1767 1768
1768 1769 /*
1769 1770 * Create a descriptor for the associated file and fill in the
1770 1771 * attributes associated with it.
1771 1772 *
1772 1773 * Return 0 for success, -1 otherwise;
1773 1774 */
1774 1775 int
1775 1776 door_insert(struct file *fp, door_desc_t *dp)
1776 1777 {
1777 1778 struct vnode *vp;
1778 1779 int fd;
1779 1780 door_attr_t attributes = DOOR_DESCRIPTOR;
1780 1781
1781 1782 ASSERT(MUTEX_NOT_HELD(&door_knob));
1782 1783 if ((fd = ufalloc(0)) == -1)
1783 1784 return (-1);
1784 1785 setf(fd, fp);
1785 1786 dp->d_data.d_desc.d_descriptor = fd;
1786 1787
1787 1788 /* Fill in the attributes */
1788 1789 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
1789 1790 vp = fp->f_vnode;
1790 1791 if (vp && vp->v_type == VDOOR) {
1791 1792 if (VTOD(vp)->door_target == curproc)
1792 1793 attributes |= DOOR_LOCAL;
1793 1794 attributes |= VTOD(vp)->door_flags & DOOR_ATTR_MASK;
1794 1795 dp->d_data.d_desc.d_id = VTOD(vp)->door_index;
1795 1796 }
1796 1797 dp->d_attributes = attributes;
1797 1798 return (0);
1798 1799 }
1799 1800
1800 1801 /*
1801 1802 * Return an available thread for this server. A NULL return value indicates
1802 1803 * that either:
1803 1804 * The door has been revoked, or
1804 1805 * a signal was received.
1805 1806 * The two conditions can be differentiated using DOOR_INVALID(dp).
1806 1807 */
1807 1808 static kthread_t *
1808 1809 door_get_server(door_node_t *dp)
1809 1810 {
1810 1811 kthread_t **ktp;
1811 1812 kthread_t *server_t;
1812 1813 door_pool_t *pool;
1813 1814 door_server_t *st;
1814 1815 int signalled;
1815 1816
1816 1817 disp_lock_t *tlp;
1817 1818 cpu_t *cp;
1818 1819
1819 1820 ASSERT(MUTEX_HELD(&door_knob));
1820 1821
1821 1822 if (dp->door_flags & DOOR_PRIVATE)
1822 1823 pool = &dp->door_servers;
1823 1824 else
1824 1825 pool = &dp->door_target->p_server_threads;
1825 1826
1826 1827 for (;;) {
1827 1828 /*
1828 1829 * We search the thread pool, looking for a server thread
1829 1830 * ready to take an invocation (i.e. one which is still
1830 1831 * sleeping on a shuttle object). If none are available,
1831 1832 * we sleep on the pool's CV, and will be signaled when a
1832 1833 * thread is added to the pool.
1833 1834 *
1834 1835 * This relies on the fact that once a thread in the thread
1835 1836 * pool wakes up, it *must* remove and add itself to the pool
1836 1837 * before it can receive door calls.
1837 1838 */
1838 1839 if (DOOR_INVALID(dp))
1839 1840 return (NULL); /* Target has become invalid */
1840 1841
1841 1842 for (ktp = &pool->dp_threads;
1842 1843 (server_t = *ktp) != NULL;
1843 1844 ktp = &st->d_servers) {
1844 1845 st = DOOR_SERVER(server_t->t_door);
1845 1846
1846 1847 thread_lock(server_t);
1847 1848 if (server_t->t_state == TS_SLEEP &&
1848 1849 SOBJ_TYPE(server_t->t_sobj_ops) == SOBJ_SHUTTLE)
1849 1850 break;
1850 1851 thread_unlock(server_t);
1851 1852 }
1852 1853 if (server_t != NULL)
1853 1854 break; /* we've got a live one! */
1854 1855
1855 1856 if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
1856 1857 &signalled)) {
1857 1858 /*
1858 1859 * If we were signaled and the door is still
1859 1860 * valid, pass the signal on to another waiter.
1860 1861 */
1861 1862 if (signalled && !DOOR_INVALID(dp))
1862 1863 cv_signal(&pool->dp_cv);
1863 1864 return (NULL); /* Got a signal */
1864 1865 }
1865 1866 }
1866 1867
1867 1868 /*
1868 1869 * We've got a thread_lock()ed thread which is still on the
1869 1870 * shuttle. Take it off the list of available server threads
1870 1871 * and mark it as ONPROC. We are committed to resuming this
1871 1872 * thread now.
1872 1873 */
1873 1874 tlp = server_t->t_lockp;
1874 1875 cp = CPU;
1875 1876
1876 1877 *ktp = st->d_servers;
1877 1878 st->d_servers = NULL;
1878 1879 /*
1879 1880 * Setting t_disp_queue prevents erroneous preemptions
1880 1881 * if this thread is still in execution on another processor
1881 1882 */
1882 1883 server_t->t_disp_queue = cp->cpu_disp;
1883 1884 CL_ACTIVE(server_t);
1884 1885 /*
1885 1886 * We are calling thread_onproc() instead of
1886 1887 * THREAD_ONPROC() because compiler can reorder
1887 1888 * the two stores of t_state and t_lockp in
1888 1889 * THREAD_ONPROC().
1889 1890 */
1890 1891 thread_onproc(server_t, cp);
1891 1892 disp_lock_exit(tlp);
1892 1893 return (server_t);
1893 1894 }
1894 1895
1895 1896 /*
1896 1897 * Put a server thread back in the pool.
1897 1898 */
1898 1899 static void
1899 1900 door_release_server(door_node_t *dp, kthread_t *t)
1900 1901 {
1901 1902 door_server_t *st = DOOR_SERVER(t->t_door);
1902 1903 door_pool_t *pool;
1903 1904
1904 1905 ASSERT(MUTEX_HELD(&door_knob));
1905 1906 st->d_active = NULL;
1906 1907 st->d_caller = NULL;
1907 1908 st->d_layout_done = 0;
1908 1909 if (dp && (dp->door_flags & DOOR_PRIVATE)) {
1909 1910 ASSERT(dp->door_target == NULL ||
1910 1911 dp->door_target == ttoproc(t));
1911 1912 pool = &dp->door_servers;
1912 1913 } else {
1913 1914 pool = &ttoproc(t)->p_server_threads;
1914 1915 }
1915 1916
1916 1917 st->d_servers = pool->dp_threads;
1917 1918 pool->dp_threads = t;
1918 1919
1919 1920 /* If someone is waiting for a server thread, wake him up */
1920 1921 cv_signal(&pool->dp_cv);
1921 1922 }
1922 1923
1923 1924 /*
1924 1925 * Remove a server thread from the pool if present.
1925 1926 */
1926 1927 static void
1927 1928 door_server_exit(proc_t *p, kthread_t *t)
1928 1929 {
1929 1930 door_pool_t *pool;
1930 1931 kthread_t **next;
1931 1932 door_server_t *st = DOOR_SERVER(t->t_door);
1932 1933
1933 1934 ASSERT(MUTEX_HELD(&door_knob));
1934 1935 if (st->d_pool != NULL) {
1935 1936 ASSERT(st->d_pool->door_flags & DOOR_PRIVATE);
1936 1937 pool = &st->d_pool->door_servers;
1937 1938 } else {
1938 1939 pool = &p->p_server_threads;
1939 1940 }
1940 1941
1941 1942 next = &pool->dp_threads;
1942 1943 while (*next != NULL) {
1943 1944 if (*next == t) {
1944 1945 *next = DOOR_SERVER(t->t_door)->d_servers;
1945 1946 return;
1946 1947 }
1947 1948 next = &(DOOR_SERVER((*next)->t_door)->d_servers);
1948 1949 }
1949 1950 }
1950 1951
1951 1952 /*
1952 1953 * Lookup the door descriptor. Caller must call releasef when finished
1953 1954 * with associated door.
1954 1955 */
1955 1956 static door_node_t *
1956 1957 door_lookup(int did, file_t **fpp)
1957 1958 {
1958 1959 vnode_t *vp;
1959 1960 file_t *fp;
1960 1961
1961 1962 ASSERT(MUTEX_NOT_HELD(&door_knob));
1962 1963 if ((fp = getf(did)) == NULL)
1963 1964 return (NULL);
1964 1965 /*
1965 1966 * Use the underlying vnode (we may be namefs mounted)
1966 1967 */
1967 1968 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
1968 1969 vp = fp->f_vnode;
1969 1970
1970 1971 if (vp == NULL || vp->v_type != VDOOR) {
1971 1972 releasef(did);
1972 1973 return (NULL);
1973 1974 }
1974 1975
1975 1976 if (fpp)
1976 1977 *fpp = fp;
1977 1978
1978 1979 return (VTOD(vp));
1979 1980 }
1980 1981
1981 1982 /*
1982 1983 * The current thread is exiting, so clean up any pending
1983 1984 * invocation details
1984 1985 */
1985 1986 void
1986 1987 door_slam(void)
1987 1988 {
1988 1989 door_node_t *dp;
1989 1990 door_data_t *dt;
1990 1991 door_client_t *ct;
1991 1992 door_server_t *st;
1992 1993
1993 1994 /*
1994 1995 * If we are an active door server, notify our
1995 1996 * client that we are exiting and revoke our door.
1996 1997 */
1997 1998 if ((dt = door_my_data(0)) == NULL)
1998 1999 return;
1999 2000 ct = DOOR_CLIENT(dt);
2000 2001 st = DOOR_SERVER(dt);
2001 2002
2002 2003 mutex_enter(&door_knob);
2003 2004 for (;;) {
2004 2005 if (DOOR_T_HELD(ct))
2005 2006 cv_wait(&ct->d_cv, &door_knob);
2006 2007 else if (DOOR_T_HELD(st))
2007 2008 cv_wait(&st->d_cv, &door_knob);
2008 2009 else
2009 2010 break; /* neither flag is set */
2010 2011 }
2011 2012 curthread->t_door = NULL;
2012 2013 if ((dp = st->d_active) != NULL) {
2013 2014 kthread_t *t = st->d_caller;
2014 2015 proc_t *p = curproc;
2015 2016
2016 2017 /* Revoke our door if the process is exiting */
2017 2018 if (dp->door_target == p && (p->p_flag & SEXITING)) {
2018 2019 door_list_delete(dp);
2019 2020 dp->door_target = NULL;
2020 2021 dp->door_flags |= DOOR_REVOKED;
2021 2022 if (dp->door_flags & DOOR_PRIVATE)
2022 2023 cv_broadcast(&dp->door_servers.dp_cv);
2023 2024 else
2024 2025 cv_broadcast(&p->p_server_threads.dp_cv);
2025 2026 }
2026 2027
2027 2028 if (t != NULL) {
2028 2029 /*
2029 2030 * Let the caller know we are gone
2030 2031 */
2031 2032 DOOR_CLIENT(t->t_door)->d_error = DOOR_EXIT;
2032 2033 thread_lock(t);
2033 2034 if (t->t_state == TS_SLEEP &&
2034 2035 SOBJ_TYPE(t->t_sobj_ops) == SOBJ_SHUTTLE)
2035 2036 setrun_locked(t);
2036 2037 thread_unlock(t);
2037 2038 }
2038 2039 }
2039 2040 mutex_exit(&door_knob);
2040 2041 if (st->d_pool)
2041 2042 door_unbind_thread(st->d_pool); /* Implicit door_unbind */
2042 2043 kmem_free(dt, sizeof (door_data_t));
2043 2044 }
2044 2045
2045 2046 /*
2046 2047 * Set DOOR_REVOKED for all doors of the current process. This is called
2047 2048 * on exit before all lwp's are being terminated so that door calls will
2048 2049 * return with an error.
2049 2050 */
2050 2051 void
2051 2052 door_revoke_all()
2052 2053 {
2053 2054 door_node_t *dp;
2054 2055 proc_t *p = ttoproc(curthread);
2055 2056
2056 2057 mutex_enter(&door_knob);
2057 2058 for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
2058 2059 ASSERT(dp->door_target == p);
2059 2060 dp->door_flags |= DOOR_REVOKED;
2060 2061 if (dp->door_flags & DOOR_PRIVATE)
2061 2062 cv_broadcast(&dp->door_servers.dp_cv);
2062 2063 }
2063 2064 cv_broadcast(&p->p_server_threads.dp_cv);
2064 2065 mutex_exit(&door_knob);
2065 2066 }
2066 2067
2067 2068 /*
2068 2069 * The process is exiting, and all doors it created need to be revoked.
2069 2070 */
2070 2071 void
2071 2072 door_exit(void)
2072 2073 {
2073 2074 door_node_t *dp;
2074 2075 proc_t *p = ttoproc(curthread);
2075 2076
2076 2077 ASSERT(p->p_lwpcnt == 1);
2077 2078 /*
2078 2079 * Walk the list of active doors created by this process and
2079 2080 * revoke them all.
2080 2081 */
2081 2082 mutex_enter(&door_knob);
2082 2083 for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
2083 2084 dp->door_target = NULL;
2084 2085 dp->door_flags |= DOOR_REVOKED;
2085 2086 if (dp->door_flags & DOOR_PRIVATE)
2086 2087 cv_broadcast(&dp->door_servers.dp_cv);
2087 2088 }
2088 2089 cv_broadcast(&p->p_server_threads.dp_cv);
2089 2090 /* Clear the list */
2090 2091 p->p_door_list = NULL;
2091 2092
2092 2093 /* Clean up the unref list */
2093 2094 while ((dp = p->p_unref_list) != NULL) {
2094 2095 p->p_unref_list = dp->door_ulist;
2095 2096 dp->door_ulist = NULL;
2096 2097 mutex_exit(&door_knob);
2097 2098 VN_RELE(DTOV(dp));
2098 2099 mutex_enter(&door_knob);
2099 2100 }
2100 2101 mutex_exit(&door_knob);
2101 2102 }
2102 2103
2103 2104
2104 2105 /*
2105 2106 * The process is executing forkall(), and we need to flag threads that
2106 2107 * are bound to a door in the child. This will make the child threads
2107 2108 * return an error to door_return unless they call door_unbind first.
2108 2109 */
2109 2110 void
2110 2111 door_fork(kthread_t *parent, kthread_t *child)
2111 2112 {
2112 2113 door_data_t *pt = parent->t_door;
2113 2114 door_server_t *st = DOOR_SERVER(pt);
2114 2115 door_data_t *dt;
2115 2116
2116 2117 ASSERT(MUTEX_NOT_HELD(&door_knob));
2117 2118 if (pt != NULL && (st->d_pool != NULL || st->d_invbound)) {
2118 2119 /* parent thread is bound to a door */
2119 2120 dt = child->t_door =
2120 2121 kmem_zalloc(sizeof (door_data_t), KM_SLEEP);
2121 2122 DOOR_SERVER(dt)->d_invbound = 1;
2122 2123 }
2123 2124 }
2124 2125
2125 2126 /*
2126 2127 * Deliver queued unrefs to appropriate door server.
2127 2128 */
2128 2129 static int
2129 2130 door_unref(void)
2130 2131 {
2131 2132 door_node_t *dp;
2132 2133 static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
2133 2134 proc_t *p = ttoproc(curthread);
2134 2135
2135 2136 /* make sure there's only one unref thread per process */
2136 2137 mutex_enter(&door_knob);
2137 2138 if (p->p_unref_thread) {
2138 2139 mutex_exit(&door_knob);
2139 2140 return (set_errno(EALREADY));
2140 2141 }
2141 2142 p->p_unref_thread = 1;
2142 2143 mutex_exit(&door_knob);
2143 2144
2144 2145 (void) door_my_data(1); /* create info, if necessary */
2145 2146
2146 2147 for (;;) {
2147 2148 mutex_enter(&door_knob);
2148 2149
2149 2150 /* Grab a queued request */
2150 2151 while ((dp = p->p_unref_list) == NULL) {
2151 2152 if (!cv_wait_sig(&p->p_unref_cv, &door_knob)) {
2152 2153 /*
2153 2154 * Interrupted.
2154 2155 * Return so we can finish forkall() or exit().
2155 2156 */
2156 2157 p->p_unref_thread = 0;
2157 2158 mutex_exit(&door_knob);
2158 2159 return (set_errno(EINTR));
2159 2160 }
2160 2161 }
2161 2162 p->p_unref_list = dp->door_ulist;
2162 2163 dp->door_ulist = NULL;
2163 2164 dp->door_flags |= DOOR_UNREF_ACTIVE;
2164 2165 mutex_exit(&door_knob);
2165 2166
2166 2167 (void) door_upcall(DTOV(dp), &unref_args, NULL, SIZE_MAX, 0);
2167 2168
2168 2169 if (unref_args.rbuf != 0) {
2169 2170 kmem_free(unref_args.rbuf, unref_args.rsize);
2170 2171 unref_args.rbuf = NULL;
2171 2172 unref_args.rsize = 0;
2172 2173 }
2173 2174
2174 2175 mutex_enter(&door_knob);
2175 2176 ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
2176 2177 dp->door_flags &= ~DOOR_UNREF_ACTIVE;
2177 2178 mutex_exit(&door_knob);
2178 2179 VN_RELE(DTOV(dp));
2179 2180 }
2180 2181 }
2181 2182
2182 2183
2183 2184 /*
2184 2185 * Deliver queued unrefs to kernel door server.
2185 2186 */
2186 2187 /* ARGSUSED */
2187 2188 static void
2188 2189 door_unref_kernel(caddr_t arg)
2189 2190 {
2190 2191 door_node_t *dp;
2191 2192 static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
2192 2193 proc_t *p = ttoproc(curthread);
2193 2194 callb_cpr_t cprinfo;
2194 2195
2195 2196 /* should only be one of these */
2196 2197 mutex_enter(&door_knob);
2197 2198 if (p->p_unref_thread) {
2198 2199 mutex_exit(&door_knob);
2199 2200 return;
2200 2201 }
2201 2202 p->p_unref_thread = 1;
2202 2203 mutex_exit(&door_knob);
2203 2204
2204 2205 (void) door_my_data(1); /* make sure we have a door_data_t */
2205 2206
2206 2207 CALLB_CPR_INIT(&cprinfo, &door_knob, callb_generic_cpr, "door_unref");
2207 2208 for (;;) {
2208 2209 mutex_enter(&door_knob);
2209 2210 /* Grab a queued request */
2210 2211 while ((dp = p->p_unref_list) == NULL) {
2211 2212 CALLB_CPR_SAFE_BEGIN(&cprinfo);
2212 2213 cv_wait(&p->p_unref_cv, &door_knob);
2213 2214 CALLB_CPR_SAFE_END(&cprinfo, &door_knob);
2214 2215 }
2215 2216 p->p_unref_list = dp->door_ulist;
2216 2217 dp->door_ulist = NULL;
2217 2218 dp->door_flags |= DOOR_UNREF_ACTIVE;
2218 2219 mutex_exit(&door_knob);
2219 2220
2220 2221 (*(dp->door_pc))(dp->door_data, &unref_args, NULL, NULL, NULL);
2221 2222
2222 2223 mutex_enter(&door_knob);
2223 2224 ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
2224 2225 dp->door_flags &= ~DOOR_UNREF_ACTIVE;
2225 2226 mutex_exit(&door_knob);
2226 2227 VN_RELE(DTOV(dp));
2227 2228 }
2228 2229 }
2229 2230
2230 2231
2231 2232 /*
2232 2233 * Queue an unref invocation for processing for the current process
2233 2234 * The door may or may not be revoked at this point.
2234 2235 */
2235 2236 void
2236 2237 door_deliver_unref(door_node_t *d)
2237 2238 {
2238 2239 struct proc *server = d->door_target;
2239 2240
2240 2241 ASSERT(MUTEX_HELD(&door_knob));
2241 2242 ASSERT(d->door_active == 0);
2242 2243
2243 2244 if (server == NULL)
2244 2245 return;
2245 2246 /*
2246 2247 * Create a lwp to deliver unref calls if one isn't already running.
2247 2248 *
2248 2249 * A separate thread is used to deliver unrefs since the current
2249 2250 * thread may be holding resources (e.g. locks) in user land that
2250 2251 * may be needed by the unref processing. This would cause a
2251 2252 * deadlock.
2252 2253 */
2253 2254 if (d->door_flags & DOOR_UNREF_MULTI) {
2254 2255 /* multiple unrefs */
2255 2256 d->door_flags &= ~DOOR_DELAY;
2256 2257 } else {
2257 2258 /* Only 1 unref per door */
2258 2259 d->door_flags &= ~(DOOR_UNREF|DOOR_DELAY);
2259 2260 }
2260 2261 mutex_exit(&door_knob);
2261 2262
2262 2263 /*
2263 2264 * Need to bump the vnode count before putting the door on the
2264 2265 * list so it doesn't get prematurely released by door_unref.
2265 2266 */
2266 2267 VN_HOLD(DTOV(d));
2267 2268
2268 2269 mutex_enter(&door_knob);
2269 2270 /* is this door already on the unref list? */
2270 2271 if (d->door_flags & DOOR_UNREF_MULTI) {
2271 2272 door_node_t *dp;
2272 2273 for (dp = server->p_unref_list; dp != NULL;
2273 2274 dp = dp->door_ulist) {
2274 2275 if (d == dp) {
2275 2276 /* already there, don't need to add another */
2276 2277 mutex_exit(&door_knob);
2277 2278 VN_RELE(DTOV(d));
2278 2279 mutex_enter(&door_knob);
2279 2280 return;
2280 2281 }
2281 2282 }
2282 2283 }
2283 2284 ASSERT(d->door_ulist == NULL);
2284 2285 d->door_ulist = server->p_unref_list;
2285 2286 server->p_unref_list = d;
2286 2287 cv_broadcast(&server->p_unref_cv);
2287 2288 }
2288 2289
2289 2290 /*
2290 2291 * The callers buffer isn't big enough for all of the data/fd's. Allocate
2291 2292 * space in the callers address space for the results and copy the data
2292 2293 * there.
2293 2294 *
2294 2295 * For EOVERFLOW, we must clean up the server's door descriptors.
2295 2296 */
2296 2297 static int
2297 2298 door_overflow(
2298 2299 kthread_t *caller,
2299 2300 caddr_t data_ptr, /* data location */
2300 2301 size_t data_size, /* data size */
2301 2302 door_desc_t *desc_ptr, /* descriptor location */
2302 2303 uint_t desc_num) /* descriptor size */
2303 2304 {
2304 2305 proc_t *callerp = ttoproc(caller);
2305 2306 struct as *as = callerp->p_as;
2306 2307 door_client_t *ct = DOOR_CLIENT(caller->t_door);
2307 2308 caddr_t addr; /* Resulting address in target */
2308 2309 size_t rlen; /* Rounded len */
2309 2310 size_t len;
2310 2311 uint_t i;
2311 2312 size_t ds = desc_num * sizeof (door_desc_t);
2312 2313
2313 2314 ASSERT(MUTEX_NOT_HELD(&door_knob));
2314 2315 ASSERT(DOOR_T_HELD(ct) || ct->d_kernel);
2315 2316
2316 2317 /* Do initial overflow check */
2317 2318 if (!ufcanalloc(callerp, desc_num))
2318 2319 return (EMFILE);
2319 2320
2320 2321 /*
2321 2322 * Allocate space for this stuff in the callers address space
2322 2323 */
2323 2324 rlen = roundup(data_size + ds, PAGESIZE);
2324 2325 as_rangelock(as);
2325 2326 map_addr_proc(&addr, rlen, 0, 1, as->a_userlimit, ttoproc(caller), 0);
2326 2327 if (addr == NULL ||
2327 2328 as_map(as, addr, rlen, segvn_create, zfod_argsp) != 0) {
2328 2329 /* No virtual memory available, or anon mapping failed */
2329 2330 as_rangeunlock(as);
2330 2331 if (!ct->d_kernel && desc_num > 0) {
2331 2332 int error = door_release_fds(desc_ptr, desc_num);
2332 2333 if (error)
2333 2334 return (error);
2334 2335 }
2335 2336 return (EOVERFLOW);
2336 2337 }
2337 2338 as_rangeunlock(as);
2338 2339
2339 2340 if (ct->d_kernel)
2340 2341 goto out;
2341 2342
2342 2343 if (data_size != 0) {
2343 2344 caddr_t src = data_ptr;
2344 2345 caddr_t saddr = addr;
2345 2346
2346 2347 /* Copy any data */
2347 2348 len = data_size;
2348 2349 while (len != 0) {
2349 2350 int amount;
2350 2351 int error;
2351 2352
2352 2353 amount = len > PAGESIZE ? PAGESIZE : len;
2353 2354 if ((error = door_copy(as, src, saddr, amount)) != 0) {
2354 2355 (void) as_unmap(as, addr, rlen);
2355 2356 return (error);
2356 2357 }
2357 2358 saddr += amount;
2358 2359 src += amount;
2359 2360 len -= amount;
2360 2361 }
2361 2362 }
2362 2363 /* Copy any fd's */
2363 2364 if (desc_num != 0) {
2364 2365 door_desc_t *didpp, *start;
2365 2366 struct file **fpp;
2366 2367 int fpp_size;
2367 2368
2368 2369 start = didpp = kmem_alloc(ds, KM_SLEEP);
2369 2370 if (copyin_nowatch(desc_ptr, didpp, ds)) {
2370 2371 kmem_free(start, ds);
2371 2372 (void) as_unmap(as, addr, rlen);
2372 2373 return (EFAULT);
2373 2374 }
2374 2375
2375 2376 fpp_size = desc_num * sizeof (struct file *);
2376 2377 if (fpp_size > ct->d_fpp_size) {
2377 2378 /* make more space */
2378 2379 if (ct->d_fpp_size)
2379 2380 kmem_free(ct->d_fpp, ct->d_fpp_size);
2380 2381 ct->d_fpp_size = fpp_size;
2381 2382 ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
2382 2383 }
2383 2384 fpp = ct->d_fpp;
2384 2385
2385 2386 for (i = 0; i < desc_num; i++) {
2386 2387 struct file *fp;
2387 2388 int fd = didpp->d_data.d_desc.d_descriptor;
2388 2389
2389 2390 if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
2390 2391 (fp = getf(fd)) == NULL) {
2391 2392 /* close translated references */
2392 2393 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2393 2394 /* close untranslated references */
2394 2395 door_fd_rele(didpp, desc_num - i, 0);
2395 2396 kmem_free(start, ds);
2396 2397 (void) as_unmap(as, addr, rlen);
2397 2398 return (EINVAL);
2398 2399 }
2399 2400 mutex_enter(&fp->f_tlock);
2400 2401 fp->f_count++;
2401 2402 mutex_exit(&fp->f_tlock);
2402 2403
2403 2404 *fpp = fp;
2404 2405 releasef(fd);
2405 2406
2406 2407 if (didpp->d_attributes & DOOR_RELEASE) {
2407 2408 /* release passed reference */
2408 2409 (void) closeandsetf(fd, NULL);
2409 2410 }
2410 2411
2411 2412 fpp++; didpp++;
2412 2413 }
2413 2414 kmem_free(start, ds);
2414 2415 }
2415 2416
2416 2417 out:
2417 2418 ct->d_overflow = 1;
2418 2419 ct->d_args.rbuf = addr;
2419 2420 ct->d_args.rsize = rlen;
2420 2421 return (0);
2421 2422 }
2422 2423
2423 2424 /*
2424 2425 * Transfer arguments from the client to the server.
2425 2426 */
2426 2427 static int
2427 2428 door_args(kthread_t *server, int is_private)
2428 2429 {
2429 2430 door_server_t *st = DOOR_SERVER(server->t_door);
2430 2431 door_client_t *ct = DOOR_CLIENT(curthread->t_door);
2431 2432 uint_t ndid;
2432 2433 size_t dsize;
2433 2434 int error;
2434 2435
2435 2436 ASSERT(DOOR_T_HELD(st));
2436 2437 ASSERT(MUTEX_NOT_HELD(&door_knob));
2437 2438
2438 2439 ndid = ct->d_args.desc_num;
2439 2440 if (ndid > door_max_desc)
2440 2441 return (E2BIG);
2441 2442
2442 2443 /*
2443 2444 * Get the stack layout, and fail now if it won't fit.
2444 2445 */
2445 2446 error = door_layout(server, ct->d_args.data_size, ndid, is_private);
2446 2447 if (error != 0)
2447 2448 return (error);
2448 2449
2449 2450 dsize = ndid * sizeof (door_desc_t);
2450 2451 if (ct->d_args.data_size != 0) {
2451 2452 if (ct->d_args.data_size <= door_max_arg) {
2452 2453 /*
2453 2454 * Use a 2 copy method for small amounts of data
2454 2455 *
2455 2456 * Allocate a little more than we need for the
2456 2457 * args, in the hope that the results will fit
2457 2458 * without having to reallocate a buffer
2458 2459 */
2459 2460 ASSERT(ct->d_buf == NULL);
2460 2461 ct->d_bufsize = roundup(ct->d_args.data_size,
2461 2462 DOOR_ROUND);
2462 2463 ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2463 2464 if (copyin_nowatch(ct->d_args.data_ptr,
2464 2465 ct->d_buf, ct->d_args.data_size) != 0) {
2465 2466 kmem_free(ct->d_buf, ct->d_bufsize);
2466 2467 ct->d_buf = NULL;
2467 2468 ct->d_bufsize = 0;
2468 2469 return (EFAULT);
2469 2470 }
2470 2471 } else {
2471 2472 struct as *as;
2472 2473 caddr_t src;
2473 2474 caddr_t dest;
2474 2475 size_t len = ct->d_args.data_size;
2475 2476 uintptr_t base;
2476 2477
2477 2478 /*
2478 2479 * Use a 1 copy method
2479 2480 */
2480 2481 as = ttoproc(server)->p_as;
2481 2482 src = ct->d_args.data_ptr;
2482 2483
2483 2484 dest = st->d_layout.dl_datap;
2484 2485 base = (uintptr_t)dest;
2485 2486
2486 2487 /*
2487 2488 * Copy data directly into server. We proceed
2488 2489 * downward from the top of the stack, to mimic
2489 2490 * normal stack usage. This allows the guard page
2490 2491 * to stop us before we corrupt anything.
2491 2492 */
2492 2493 while (len != 0) {
2493 2494 uintptr_t start;
2494 2495 uintptr_t end;
2495 2496 uintptr_t offset;
2496 2497 size_t amount;
2497 2498
2498 2499 /*
2499 2500 * Locate the next part to copy.
2500 2501 */
2501 2502 end = base + len;
2502 2503 start = P2ALIGN(end - 1, PAGESIZE);
2503 2504
2504 2505 /*
2505 2506 * if we are on the final (first) page, fix
2506 2507 * up the start position.
2507 2508 */
2508 2509 if (P2ALIGN(base, PAGESIZE) == start)
2509 2510 start = base;
2510 2511
2511 2512 offset = start - base; /* the copy offset */
2512 2513 amount = end - start; /* # bytes to copy */
2513 2514
2514 2515 ASSERT(amount > 0 && amount <= len &&
2515 2516 amount <= PAGESIZE);
2516 2517
2517 2518 error = door_copy(as, src + offset,
2518 2519 dest + offset, amount);
2519 2520 if (error != 0)
2520 2521 return (error);
2521 2522 len -= amount;
2522 2523 }
2523 2524 }
2524 2525 }
2525 2526 /*
2526 2527 * Copyin the door args and translate them into files
2527 2528 */
2528 2529 if (ndid != 0) {
2529 2530 door_desc_t *didpp;
2530 2531 door_desc_t *start;
2531 2532 struct file **fpp;
2532 2533
2533 2534 start = didpp = kmem_alloc(dsize, KM_SLEEP);
2534 2535
2535 2536 if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
2536 2537 kmem_free(start, dsize);
2537 2538 return (EFAULT);
2538 2539 }
2539 2540 ct->d_fpp_size = ndid * sizeof (struct file *);
2540 2541 ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
2541 2542 fpp = ct->d_fpp;
2542 2543 while (ndid--) {
2543 2544 struct file *fp;
2544 2545 int fd = didpp->d_data.d_desc.d_descriptor;
2545 2546
2546 2547 /* We only understand file descriptors as passed objs */
2547 2548 if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
2548 2549 (fp = getf(fd)) == NULL) {
2549 2550 /* close translated references */
2550 2551 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2551 2552 /* close untranslated references */
2552 2553 door_fd_rele(didpp, ndid + 1, 0);
2553 2554 kmem_free(start, dsize);
2554 2555 kmem_free(ct->d_fpp, ct->d_fpp_size);
2555 2556 ct->d_fpp = NULL;
2556 2557 ct->d_fpp_size = 0;
2557 2558 return (EINVAL);
2558 2559 }
2559 2560 /* Hold the fp */
2560 2561 mutex_enter(&fp->f_tlock);
2561 2562 fp->f_count++;
2562 2563 mutex_exit(&fp->f_tlock);
2563 2564
2564 2565 *fpp = fp;
2565 2566 releasef(fd);
2566 2567
2567 2568 if (didpp->d_attributes & DOOR_RELEASE) {
2568 2569 /* release passed reference */
2569 2570 (void) closeandsetf(fd, NULL);
2570 2571 }
2571 2572
2572 2573 fpp++; didpp++;
2573 2574 }
2574 2575 kmem_free(start, dsize);
2575 2576 }
2576 2577 return (0);
2577 2578 }
2578 2579
2579 2580 /*
2580 2581 * Transfer arguments from a user client to a kernel server. This copies in
2581 2582 * descriptors and translates them into door handles. It doesn't touch the
2582 2583 * other data, letting the kernel server deal with that (to avoid needing
2583 2584 * to copy the data twice).
2584 2585 */
2585 2586 static int
2586 2587 door_translate_in(void)
2587 2588 {
2588 2589 door_client_t *ct = DOOR_CLIENT(curthread->t_door);
2589 2590 uint_t ndid;
2590 2591
2591 2592 ASSERT(MUTEX_NOT_HELD(&door_knob));
2592 2593 ndid = ct->d_args.desc_num;
2593 2594 if (ndid > door_max_desc)
2594 2595 return (E2BIG);
2595 2596 /*
2596 2597 * Copyin the door args and translate them into door handles.
2597 2598 */
2598 2599 if (ndid != 0) {
2599 2600 door_desc_t *didpp;
2600 2601 door_desc_t *start;
2601 2602 size_t dsize = ndid * sizeof (door_desc_t);
2602 2603 struct file *fp;
2603 2604
2604 2605 start = didpp = kmem_alloc(dsize, KM_SLEEP);
2605 2606
2606 2607 if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
2607 2608 kmem_free(start, dsize);
2608 2609 return (EFAULT);
2609 2610 }
2610 2611 while (ndid--) {
2611 2612 vnode_t *vp;
2612 2613 int fd = didpp->d_data.d_desc.d_descriptor;
2613 2614
2614 2615 /*
2615 2616 * We only understand file descriptors as passed objs
2616 2617 */
2617 2618 if ((didpp->d_attributes & DOOR_DESCRIPTOR) &&
2618 2619 (fp = getf(fd)) != NULL) {
2619 2620 didpp->d_data.d_handle = FTODH(fp);
2620 2621 /* Hold the door */
2621 2622 door_ki_hold(didpp->d_data.d_handle);
2622 2623
2623 2624 releasef(fd);
2624 2625
2625 2626 if (didpp->d_attributes & DOOR_RELEASE) {
2626 2627 /* release passed reference */
2627 2628 (void) closeandsetf(fd, NULL);
2628 2629 }
2629 2630
2630 2631 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
2631 2632 vp = fp->f_vnode;
2632 2633
2633 2634 /* Set attributes */
2634 2635 didpp->d_attributes = DOOR_HANDLE |
2635 2636 (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
2636 2637 } else {
2637 2638 /* close translated references */
2638 2639 door_fd_close(start, didpp - start);
2639 2640 /* close untranslated references */
2640 2641 door_fd_rele(didpp, ndid + 1, 0);
2641 2642 kmem_free(start, dsize);
2642 2643 return (EINVAL);
2643 2644 }
2644 2645 didpp++;
2645 2646 }
2646 2647 ct->d_args.desc_ptr = start;
2647 2648 }
2648 2649 return (0);
2649 2650 }
2650 2651
2651 2652 /*
2652 2653 * Translate door arguments from kernel to user. This copies the passed
2653 2654 * door handles. It doesn't touch other data. It is used by door_upcall,
2654 2655 * and for data returned by a door_call to a kernel server.
2655 2656 */
2656 2657 static int
2657 2658 door_translate_out(void)
2658 2659 {
2659 2660 door_client_t *ct = DOOR_CLIENT(curthread->t_door);
2660 2661 uint_t ndid;
2661 2662
2662 2663 ASSERT(MUTEX_NOT_HELD(&door_knob));
2663 2664 ndid = ct->d_args.desc_num;
2664 2665 if (ndid > door_max_desc) {
2665 2666 door_fd_rele(ct->d_args.desc_ptr, ndid, 1);
2666 2667 return (E2BIG);
2667 2668 }
2668 2669 /*
2669 2670 * Translate the door args into files
2670 2671 */
2671 2672 if (ndid != 0) {
2672 2673 door_desc_t *didpp = ct->d_args.desc_ptr;
2673 2674 struct file **fpp;
2674 2675
2675 2676 ct->d_fpp_size = ndid * sizeof (struct file *);
2676 2677 fpp = ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
2677 2678 while (ndid--) {
2678 2679 struct file *fp = NULL;
2679 2680 int fd = -1;
2680 2681
2681 2682 /*
2682 2683 * We understand file descriptors and door
2683 2684 * handles as passed objs.
2684 2685 */
2685 2686 if (didpp->d_attributes & DOOR_DESCRIPTOR) {
2686 2687 fd = didpp->d_data.d_desc.d_descriptor;
2687 2688 fp = getf(fd);
2688 2689 } else if (didpp->d_attributes & DOOR_HANDLE)
2689 2690 fp = DHTOF(didpp->d_data.d_handle);
2690 2691 if (fp != NULL) {
2691 2692 /* Hold the fp */
2692 2693 mutex_enter(&fp->f_tlock);
2693 2694 fp->f_count++;
2694 2695 mutex_exit(&fp->f_tlock);
2695 2696
2696 2697 *fpp = fp;
2697 2698 if (didpp->d_attributes & DOOR_DESCRIPTOR)
2698 2699 releasef(fd);
2699 2700 if (didpp->d_attributes & DOOR_RELEASE) {
2700 2701 /* release passed reference */
2701 2702 if (fd >= 0)
2702 2703 (void) closeandsetf(fd, NULL);
2703 2704 else
2704 2705 (void) closef(fp);
2705 2706 }
2706 2707 } else {
2707 2708 /* close translated references */
2708 2709 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2709 2710 /* close untranslated references */
2710 2711 door_fd_rele(didpp, ndid + 1, 1);
2711 2712 kmem_free(ct->d_fpp, ct->d_fpp_size);
2712 2713 ct->d_fpp = NULL;
2713 2714 ct->d_fpp_size = 0;
2714 2715 return (EINVAL);
2715 2716 }
2716 2717 fpp++; didpp++;
2717 2718 }
2718 2719 }
2719 2720 return (0);
2720 2721 }
2721 2722
2722 2723 /*
2723 2724 * Move the results from the server to the client
2724 2725 */
2725 2726 static int
2726 2727 door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size,
2727 2728 door_desc_t *desc_ptr, uint_t desc_num)
2728 2729 {
2729 2730 door_client_t *ct = DOOR_CLIENT(caller->t_door);
2730 2731 door_upcall_t *dup = ct->d_upcall;
2731 2732 size_t dsize;
2732 2733 size_t rlen;
2733 2734 size_t result_size;
2734 2735
2735 2736 ASSERT(DOOR_T_HELD(ct));
2736 2737 ASSERT(MUTEX_NOT_HELD(&door_knob));
2737 2738
2738 2739 if (ct->d_noresults)
2739 2740 return (E2BIG); /* No results expected */
2740 2741
2741 2742 if (desc_num > door_max_desc)
2742 2743 return (E2BIG); /* Too many descriptors */
2743 2744
2744 2745 dsize = desc_num * sizeof (door_desc_t);
2745 2746 /*
2746 2747 * Check if the results are bigger than the clients buffer
2747 2748 */
2748 2749 if (dsize)
2749 2750 rlen = roundup(data_size, sizeof (door_desc_t));
2750 2751 else
2751 2752 rlen = data_size;
2752 2753 if ((result_size = rlen + dsize) == 0)
2753 2754 return (0);
2754 2755
2755 2756 if (dup != NULL) {
2756 2757 if (desc_num > dup->du_max_descs)
2757 2758 return (EMFILE);
2758 2759
2759 2760 if (data_size > dup->du_max_data)
2760 2761 return (E2BIG);
2761 2762
2762 2763 /*
2763 2764 * Handle upcalls
2764 2765 */
2765 2766 if (ct->d_args.rbuf == NULL || ct->d_args.rsize < result_size) {
2766 2767 /*
2767 2768 * If there's no return buffer or the buffer is too
2768 2769 * small, allocate a new one. The old buffer (if it
2769 2770 * exists) will be freed by the upcall client.
2770 2771 */
2771 2772 if (result_size > door_max_upcall_reply)
2772 2773 return (E2BIG);
2773 2774 ct->d_args.rsize = result_size;
2774 2775 ct->d_args.rbuf = kmem_alloc(result_size, KM_SLEEP);
2775 2776 }
2776 2777 ct->d_args.data_ptr = ct->d_args.rbuf;
2777 2778 if (data_size != 0 &&
2778 2779 copyin_nowatch(data_ptr, ct->d_args.data_ptr,
2779 2780 data_size) != 0)
2780 2781 return (EFAULT);
2781 2782 } else if (result_size > ct->d_args.rsize) {
2782 2783 return (door_overflow(caller, data_ptr, data_size,
2783 2784 desc_ptr, desc_num));
2784 2785 } else if (data_size != 0) {
2785 2786 if (data_size <= door_max_arg) {
2786 2787 /*
2787 2788 * Use a 2 copy method for small amounts of data
2788 2789 */
2789 2790 if (ct->d_buf == NULL) {
2790 2791 ct->d_bufsize = data_size;
2791 2792 ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2792 2793 } else if (ct->d_bufsize < data_size) {
2793 2794 kmem_free(ct->d_buf, ct->d_bufsize);
2794 2795 ct->d_bufsize = data_size;
2795 2796 ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2796 2797 }
2797 2798 if (copyin_nowatch(data_ptr, ct->d_buf, data_size) != 0)
2798 2799 return (EFAULT);
2799 2800 } else {
2800 2801 struct as *as = ttoproc(caller)->p_as;
2801 2802 caddr_t dest = ct->d_args.rbuf;
2802 2803 caddr_t src = data_ptr;
2803 2804 size_t len = data_size;
2804 2805
2805 2806 /* Copy data directly into client */
2806 2807 while (len != 0) {
2807 2808 uint_t amount;
2808 2809 uint_t max;
2809 2810 uint_t off;
2810 2811 int error;
2811 2812
2812 2813 off = (uintptr_t)dest & PAGEOFFSET;
2813 2814 if (off)
2814 2815 max = PAGESIZE - off;
2815 2816 else
2816 2817 max = PAGESIZE;
2817 2818 amount = len > max ? max : len;
2818 2819 error = door_copy(as, src, dest, amount);
2819 2820 if (error != 0)
2820 2821 return (error);
2821 2822 dest += amount;
2822 2823 src += amount;
2823 2824 len -= amount;
2824 2825 }
2825 2826 }
2826 2827 }
2827 2828
2828 2829 /*
2829 2830 * Copyin the returned door ids and translate them into door_node_t
2830 2831 */
2831 2832 if (desc_num != 0) {
2832 2833 door_desc_t *start;
2833 2834 door_desc_t *didpp;
2834 2835 struct file **fpp;
2835 2836 size_t fpp_size;
2836 2837 uint_t i;
2837 2838
2838 2839 /* First, check if we would overflow client */
2839 2840 if (!ufcanalloc(ttoproc(caller), desc_num))
2840 2841 return (EMFILE);
2841 2842
2842 2843 start = didpp = kmem_alloc(dsize, KM_SLEEP);
2843 2844 if (copyin_nowatch(desc_ptr, didpp, dsize)) {
2844 2845 kmem_free(start, dsize);
2845 2846 return (EFAULT);
2846 2847 }
2847 2848 fpp_size = desc_num * sizeof (struct file *);
2848 2849 if (fpp_size > ct->d_fpp_size) {
2849 2850 /* make more space */
2850 2851 if (ct->d_fpp_size)
2851 2852 kmem_free(ct->d_fpp, ct->d_fpp_size);
2852 2853 ct->d_fpp_size = fpp_size;
2853 2854 ct->d_fpp = kmem_alloc(fpp_size, KM_SLEEP);
2854 2855 }
2855 2856 fpp = ct->d_fpp;
2856 2857
2857 2858 for (i = 0; i < desc_num; i++) {
2858 2859 struct file *fp;
2859 2860 int fd = didpp->d_data.d_desc.d_descriptor;
2860 2861
2861 2862 /* Only understand file descriptor results */
2862 2863 if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
2863 2864 (fp = getf(fd)) == NULL) {
2864 2865 /* close translated references */
2865 2866 door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
2866 2867 /* close untranslated references */
2867 2868 door_fd_rele(didpp, desc_num - i, 0);
2868 2869 kmem_free(start, dsize);
2869 2870 return (EINVAL);
2870 2871 }
2871 2872
2872 2873 mutex_enter(&fp->f_tlock);
2873 2874 fp->f_count++;
2874 2875 mutex_exit(&fp->f_tlock);
2875 2876
2876 2877 *fpp = fp;
2877 2878 releasef(fd);
2878 2879
2879 2880 if (didpp->d_attributes & DOOR_RELEASE) {
2880 2881 /* release passed reference */
2881 2882 (void) closeandsetf(fd, NULL);
2882 2883 }
2883 2884
2884 2885 fpp++; didpp++;
2885 2886 }
2886 2887 kmem_free(start, dsize);
2887 2888 }
2888 2889 return (0);
2889 2890 }
2890 2891
2891 2892 /*
2892 2893 * Close all the descriptors.
2893 2894 */
2894 2895 static void
2895 2896 door_fd_close(door_desc_t *d, uint_t n)
2896 2897 {
2897 2898 uint_t i;
2898 2899
2899 2900 ASSERT(MUTEX_NOT_HELD(&door_knob));
2900 2901 for (i = 0; i < n; i++) {
2901 2902 if (d->d_attributes & DOOR_DESCRIPTOR) {
2902 2903 (void) closeandsetf(
2903 2904 d->d_data.d_desc.d_descriptor, NULL);
2904 2905 } else if (d->d_attributes & DOOR_HANDLE) {
2905 2906 door_ki_rele(d->d_data.d_handle);
2906 2907 }
2907 2908 d++;
2908 2909 }
2909 2910 }
2910 2911
2911 2912 /*
2912 2913 * Close descriptors that have the DOOR_RELEASE attribute set.
2913 2914 */
2914 2915 void
2915 2916 door_fd_rele(door_desc_t *d, uint_t n, int from_kernel)
2916 2917 {
2917 2918 uint_t i;
2918 2919
2919 2920 ASSERT(MUTEX_NOT_HELD(&door_knob));
2920 2921 for (i = 0; i < n; i++) {
2921 2922 if (d->d_attributes & DOOR_RELEASE) {
2922 2923 if (d->d_attributes & DOOR_DESCRIPTOR) {
2923 2924 (void) closeandsetf(
2924 2925 d->d_data.d_desc.d_descriptor, NULL);
2925 2926 } else if (from_kernel &&
2926 2927 (d->d_attributes & DOOR_HANDLE)) {
2927 2928 door_ki_rele(d->d_data.d_handle);
2928 2929 }
2929 2930 }
2930 2931 d++;
2931 2932 }
2932 2933 }
2933 2934
2934 2935 /*
2935 2936 * Copy descriptors into the kernel so we can release any marked
2936 2937 * DOOR_RELEASE.
2937 2938 */
2938 2939 int
2939 2940 door_release_fds(door_desc_t *desc_ptr, uint_t ndesc)
2940 2941 {
2941 2942 size_t dsize;
2942 2943 door_desc_t *didpp;
2943 2944 uint_t desc_num;
2944 2945
2945 2946 ASSERT(MUTEX_NOT_HELD(&door_knob));
2946 2947 ASSERT(ndesc != 0);
2947 2948
2948 2949 desc_num = MIN(ndesc, door_max_desc);
2949 2950
2950 2951 dsize = desc_num * sizeof (door_desc_t);
2951 2952 didpp = kmem_alloc(dsize, KM_SLEEP);
2952 2953
2953 2954 while (ndesc > 0) {
2954 2955 uint_t count = MIN(ndesc, desc_num);
2955 2956
2956 2957 if (copyin_nowatch(desc_ptr, didpp,
2957 2958 count * sizeof (door_desc_t))) {
2958 2959 kmem_free(didpp, dsize);
2959 2960 return (EFAULT);
2960 2961 }
2961 2962 door_fd_rele(didpp, count, 0);
2962 2963
2963 2964 ndesc -= count;
2964 2965 desc_ptr += count;
2965 2966 }
2966 2967 kmem_free(didpp, dsize);
2967 2968 return (0);
2968 2969 }
2969 2970
2970 2971 /*
2971 2972 * Decrement ref count on all the files passed
2972 2973 */
2973 2974 static void
2974 2975 door_fp_close(struct file **fp, uint_t n)
2975 2976 {
2976 2977 uint_t i;
2977 2978
2978 2979 ASSERT(MUTEX_NOT_HELD(&door_knob));
2979 2980
2980 2981 for (i = 0; i < n; i++)
2981 2982 (void) closef(fp[i]);
2982 2983 }
2983 2984
2984 2985 /*
2985 2986 * Copy data from 'src' in current address space to 'dest' in 'as' for 'len'
2986 2987 * bytes.
2987 2988 *
2988 2989 * Performs this using 1 mapin and 1 copy operation.
2989 2990 *
2990 2991 * We really should do more than 1 page at a time to improve
2991 2992 * performance, but for now this is treated as an anomalous condition.
2992 2993 */
2993 2994 static int
2994 2995 door_copy(struct as *as, caddr_t src, caddr_t dest, uint_t len)
2995 2996 {
2996 2997 caddr_t kaddr;
2997 2998 caddr_t rdest;
2998 2999 uint_t off;
2999 3000 page_t **pplist;
3000 3001 page_t *pp = NULL;
3001 3002 int error = 0;
3002 3003
3003 3004 ASSERT(len <= PAGESIZE);
3004 3005 off = (uintptr_t)dest & PAGEOFFSET; /* offset within the page */
3005 3006 rdest = (caddr_t)((uintptr_t)dest &
3006 3007 (uintptr_t)PAGEMASK); /* Page boundary */
3007 3008 ASSERT(off + len <= PAGESIZE);
3008 3009
3009 3010 /*
3010 3011 * Lock down destination page.
3011 3012 */
3012 3013 if (as_pagelock(as, &pplist, rdest, PAGESIZE, S_WRITE))
3013 3014 return (E2BIG);
3014 3015 /*
3015 3016 * Check if we have a shadow page list from as_pagelock. If not,
3016 3017 * we took the slow path and have to find our page struct the hard
3017 3018 * way.
3018 3019 */
3019 3020 if (pplist == NULL) {
3020 3021 pfn_t pfnum;
3021 3022
3022 3023 /* MMU mapping is already locked down */
3023 3024 AS_LOCK_ENTER(as, RW_READER);
3024 3025 pfnum = hat_getpfnum(as->a_hat, rdest);
3025 3026 AS_LOCK_EXIT(as);
3026 3027
3027 3028 /*
3028 3029 * TODO: The pfn step should not be necessary - need
3029 3030 * a hat_getpp() function.
3030 3031 */
3031 3032 if (pf_is_memory(pfnum)) {
3032 3033 pp = page_numtopp_nolock(pfnum);
3033 3034 ASSERT(pp == NULL || PAGE_LOCKED(pp));
3034 3035 } else
3035 3036 pp = NULL;
3036 3037 if (pp == NULL) {
3037 3038 as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
3038 3039 return (E2BIG);
3039 3040 }
3040 3041 } else {
3041 3042 pp = *pplist;
3042 3043 }
3043 3044 /*
3044 3045 * Map destination page into kernel address
3045 3046 */
3046 3047 if (kpm_enable)
3047 3048 kaddr = (caddr_t)hat_kpm_mapin(pp, (struct kpme *)NULL);
3048 3049 else
3049 3050 kaddr = (caddr_t)ppmapin(pp, PROT_READ | PROT_WRITE,
3050 3051 (caddr_t)-1);
3051 3052
3052 3053 /*
3053 3054 * Copy from src to dest
3054 3055 */
3055 3056 if (copyin_nowatch(src, kaddr + off, len) != 0)
3056 3057 error = EFAULT;
3057 3058 /*
3058 3059 * Unmap destination page from kernel
3059 3060 */
3060 3061 if (kpm_enable)
3061 3062 hat_kpm_mapout(pp, (struct kpme *)NULL, kaddr);
3062 3063 else
3063 3064 ppmapout(kaddr);
3064 3065 /*
3065 3066 * Unlock destination page
3066 3067 */
3067 3068 as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
3068 3069 return (error);
3069 3070 }
3070 3071
3071 3072 /*
3072 3073 * General kernel upcall using doors
3073 3074 * Returns 0 on success, errno for failures.
3074 3075 * Caller must have a hold on the door based vnode, and on any
3075 3076 * references passed in desc_ptr. The references are released
3076 3077 * in the event of an error, and passed without duplication
3077 3078 * otherwise. Note that param->rbuf must be 64-bit aligned in
3078 3079 * a 64-bit kernel, since it may be used to store door descriptors
3079 3080 * if they are returned by the server. The caller is responsible
3080 3081 * for holding a reference to the cred passed in.
3081 3082 */
3082 3083 int
3083 3084 door_upcall(vnode_t *vp, door_arg_t *param, struct cred *cred,
3084 3085 size_t max_data, uint_t max_descs)
3085 3086 {
3086 3087 /* Locals */
3087 3088 door_upcall_t *dup;
3088 3089 door_node_t *dp;
3089 3090 kthread_t *server_thread;
3090 3091 int error = 0;
3091 3092 klwp_t *lwp;
3092 3093 door_client_t *ct; /* curthread door_data */
3093 3094 door_server_t *st; /* server thread door_data */
3094 3095 int gotresults = 0;
3095 3096 int cancel_pending;
3096 3097
3097 3098 if (vp->v_type != VDOOR) {
3098 3099 if (param->desc_num)
3099 3100 door_fd_rele(param->desc_ptr, param->desc_num, 1);
3100 3101 return (EINVAL);
3101 3102 }
3102 3103
3103 3104 lwp = ttolwp(curthread);
3104 3105 ct = door_my_client(1);
3105 3106 dp = VTOD(vp); /* Convert to a door_node_t */
3106 3107
3107 3108 dup = kmem_zalloc(sizeof (*dup), KM_SLEEP);
3108 3109 dup->du_cred = (cred != NULL) ? cred : curthread->t_cred;
3109 3110 dup->du_max_data = max_data;
3110 3111 dup->du_max_descs = max_descs;
3111 3112
3112 3113 /*
3113 3114 * This should be done in shuttle_resume(), just before going to
3114 3115 * sleep, but we want to avoid overhead while holding door_knob.
3115 3116 * prstop() is just a no-op if we don't really go to sleep.
3116 3117 * We test not-kernel-address-space for the sake of clustering code.
3117 3118 */
3118 3119 if (lwp && lwp->lwp_nostop == 0 && curproc->p_as != &kas)
3119 3120 prstop(PR_REQUESTED, 0);
3120 3121
3121 3122 mutex_enter(&door_knob);
3122 3123 if (DOOR_INVALID(dp)) {
3123 3124 mutex_exit(&door_knob);
3124 3125 if (param->desc_num)
3125 3126 door_fd_rele(param->desc_ptr, param->desc_num, 1);
3126 3127 error = EBADF;
3127 3128 goto out;
3128 3129 }
3129 3130
3130 3131 if (dp->door_target == &p0) {
3131 3132 /* Can't do an upcall to a kernel server */
3132 3133 mutex_exit(&door_knob);
3133 3134 if (param->desc_num)
3134 3135 door_fd_rele(param->desc_ptr, param->desc_num, 1);
3135 3136 error = EINVAL;
3136 3137 goto out;
3137 3138 }
3138 3139
3139 3140 error = door_check_limits(dp, param, 1);
3140 3141 if (error != 0) {
3141 3142 mutex_exit(&door_knob);
3142 3143 if (param->desc_num)
3143 3144 door_fd_rele(param->desc_ptr, param->desc_num, 1);
3144 3145 goto out;
3145 3146 }
3146 3147
3147 3148 /*
3148 3149 * Get a server thread from the target domain
3149 3150 */
3150 3151 if ((server_thread = door_get_server(dp)) == NULL) {
3151 3152 if (DOOR_INVALID(dp))
3152 3153 error = EBADF;
3153 3154 else
3154 3155 error = EAGAIN;
3155 3156 mutex_exit(&door_knob);
3156 3157 if (param->desc_num)
3157 3158 door_fd_rele(param->desc_ptr, param->desc_num, 1);
3158 3159 goto out;
3159 3160 }
3160 3161
3161 3162 st = DOOR_SERVER(server_thread->t_door);
3162 3163 ct->d_buf = param->data_ptr;
3163 3164 ct->d_bufsize = param->data_size;
3164 3165 ct->d_args = *param; /* structure assignment */
3165 3166
3166 3167 if (ct->d_args.desc_num) {
3167 3168 /*
3168 3169 * Move data from client to server
3169 3170 */
3170 3171 DOOR_T_HOLD(st);
3171 3172 mutex_exit(&door_knob);
3172 3173 error = door_translate_out();
3173 3174 mutex_enter(&door_knob);
3174 3175 DOOR_T_RELEASE(st);
3175 3176 if (error) {
3176 3177 /*
3177 3178 * We're not going to resume this thread after all
3178 3179 */
3179 3180 door_release_server(dp, server_thread);
3180 3181 shuttle_sleep(server_thread);
3181 3182 mutex_exit(&door_knob);
3182 3183 goto out;
3183 3184 }
3184 3185 }
3185 3186
3186 3187 ct->d_upcall = dup;
3187 3188 if (param->rsize == 0)
3188 3189 ct->d_noresults = 1;
3189 3190 else
3190 3191 ct->d_noresults = 0;
3191 3192
3192 3193 dp->door_active++;
3193 3194
3194 3195 ct->d_error = DOOR_WAIT;
3195 3196 st->d_caller = curthread;
3196 3197 st->d_active = dp;
3197 3198
3198 3199 shuttle_resume(server_thread, &door_knob);
3199 3200
3200 3201 mutex_enter(&door_knob);
3201 3202 shuttle_return:
3202 3203 if ((error = ct->d_error) < 0) { /* DOOR_WAIT or DOOR_EXIT */
3203 3204 /*
3204 3205 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
3205 3206 */
3206 3207 mutex_exit(&door_knob); /* May block in ISSIG */
3207 3208 cancel_pending = 0;
3208 3209 if (lwp && (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
3209 3210 MUSTRETURN(curproc, curthread) ||
3210 3211 (cancel_pending = schedctl_cancel_pending()) != 0)) {
3211 3212 /* Signal, forkall, ... */
3212 3213 if (cancel_pending)
3213 3214 schedctl_cancel_eintr();
3214 3215 lwp->lwp_sysabort = 0;
3215 3216 mutex_enter(&door_knob);
3216 3217 error = EINTR;
3217 3218 /*
3218 3219 * If the server has finished processing our call,
3219 3220 * or exited (calling door_slam()), then d_error
3220 3221 * will have changed. If the server hasn't finished
3221 3222 * yet, d_error will still be DOOR_WAIT, and we
3222 3223 * let it know we are not interested in any
3223 3224 * results by sending a SIGCANCEL, unless the door
3224 3225 * is marked with DOOR_NO_CANCEL.
3225 3226 */
3226 3227 if (ct->d_error == DOOR_WAIT &&
3227 3228 st->d_caller == curthread) {
3228 3229 proc_t *p = ttoproc(server_thread);
3229 3230
3230 3231 st->d_active = NULL;
3231 3232 st->d_caller = NULL;
3232 3233 if (!(dp->door_flags & DOOR_NO_CANCEL)) {
3233 3234 DOOR_T_HOLD(st);
3234 3235 mutex_exit(&door_knob);
3235 3236
3236 3237 mutex_enter(&p->p_lock);
3237 3238 sigtoproc(p, server_thread, SIGCANCEL);
3238 3239 mutex_exit(&p->p_lock);
3239 3240
3240 3241 mutex_enter(&door_knob);
3241 3242 DOOR_T_RELEASE(st);
3242 3243 }
3243 3244 }
3244 3245 } else {
3245 3246 /*
3246 3247 * Return from stop(), server exit...
3247 3248 *
3248 3249 * Note that the server could have done a
3249 3250 * door_return while the client was in stop state
3250 3251 * (ISSIG), in which case the error condition
3251 3252 * is updated by the server.
3252 3253 */
3253 3254 mutex_enter(&door_knob);
3254 3255 if (ct->d_error == DOOR_WAIT) {
3255 3256 /* Still waiting for a reply */
3256 3257 shuttle_swtch(&door_knob);
3257 3258 mutex_enter(&door_knob);
3258 3259 if (lwp)
3259 3260 lwp->lwp_asleep = 0;
3260 3261 goto shuttle_return;
3261 3262 } else if (ct->d_error == DOOR_EXIT) {
3262 3263 /* Server exit */
3263 3264 error = EINTR;
3264 3265 } else {
3265 3266 /* Server did a door_return during ISSIG */
3266 3267 error = ct->d_error;
3267 3268 }
3268 3269 }
3269 3270 /*
3270 3271 * Can't exit if the server is currently copying
3271 3272 * results for me
3272 3273 */
3273 3274 while (DOOR_T_HELD(ct))
3274 3275 cv_wait(&ct->d_cv, &door_knob);
3275 3276
3276 3277 /*
3277 3278 * Find out if results were successfully copied.
3278 3279 */
3279 3280 if (ct->d_error == 0)
3280 3281 gotresults = 1;
3281 3282 }
3282 3283 if (lwp) {
3283 3284 lwp->lwp_asleep = 0; /* /proc */
3284 3285 lwp->lwp_sysabort = 0; /* /proc */
3285 3286 }
3286 3287 if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
3287 3288 door_deliver_unref(dp);
3288 3289 mutex_exit(&door_knob);
3289 3290
3290 3291 /*
3291 3292 * Translate returned doors (if any)
3292 3293 */
3293 3294
3294 3295 if (ct->d_noresults)
3295 3296 goto out;
3296 3297
3297 3298 if (error) {
3298 3299 /*
3299 3300 * If server returned results successfully, then we've
3300 3301 * been interrupted and may need to clean up.
3301 3302 */
3302 3303 if (gotresults) {
3303 3304 ASSERT(error == EINTR);
3304 3305 door_fp_close(ct->d_fpp, ct->d_args.desc_num);
3305 3306 }
3306 3307 goto out;
3307 3308 }
3308 3309
3309 3310 if (ct->d_args.desc_num) {
3310 3311 struct file **fpp;
3311 3312 door_desc_t *didpp;
3312 3313 vnode_t *vp;
3313 3314 uint_t n = ct->d_args.desc_num;
3314 3315
3315 3316 didpp = ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
3316 3317 roundup(ct->d_args.data_size, sizeof (door_desc_t)));
3317 3318 fpp = ct->d_fpp;
3318 3319
3319 3320 while (n--) {
3320 3321 struct file *fp;
3321 3322
3322 3323 fp = *fpp;
3323 3324 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3324 3325 vp = fp->f_vnode;
3325 3326
3326 3327 didpp->d_attributes = DOOR_HANDLE |
3327 3328 (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
3328 3329 didpp->d_data.d_handle = FTODH(fp);
3329 3330
3330 3331 fpp++; didpp++;
3331 3332 }
3332 3333 }
3333 3334
3334 3335 /* on return data is in rbuf */
3335 3336 *param = ct->d_args; /* structure assignment */
3336 3337
3337 3338 out:
3338 3339 kmem_free(dup, sizeof (*dup));
3339 3340
3340 3341 if (ct->d_fpp) {
3341 3342 kmem_free(ct->d_fpp, ct->d_fpp_size);
3342 3343 ct->d_fpp = NULL;
3343 3344 ct->d_fpp_size = 0;
3344 3345 }
3345 3346
3346 3347 ct->d_upcall = NULL;
3347 3348 ct->d_noresults = 0;
3348 3349 ct->d_buf = NULL;
3349 3350 ct->d_bufsize = 0;
3350 3351 return (error);
3351 3352 }
3352 3353
3353 3354 /*
3354 3355 * Add a door to the per-process list of active doors for which the
3355 3356 * process is a server.
3356 3357 */
3357 3358 static void
3358 3359 door_list_insert(door_node_t *dp)
3359 3360 {
3360 3361 proc_t *p = dp->door_target;
3361 3362
3362 3363 ASSERT(MUTEX_HELD(&door_knob));
3363 3364 dp->door_list = p->p_door_list;
3364 3365 p->p_door_list = dp;
3365 3366 }
3366 3367
3367 3368 /*
3368 3369 * Remove a door from the per-process list of active doors.
3369 3370 */
3370 3371 void
3371 3372 door_list_delete(door_node_t *dp)
3372 3373 {
3373 3374 door_node_t **pp;
3374 3375
3375 3376 ASSERT(MUTEX_HELD(&door_knob));
3376 3377 /*
3377 3378 * Find the door in the list. If the door belongs to another process,
3378 3379 * it's OK to use p_door_list since that process can't exit until all
3379 3380 * doors have been taken off the list (see door_exit).
3380 3381 */
3381 3382 pp = &(dp->door_target->p_door_list);
3382 3383 while (*pp != dp)
3383 3384 pp = &((*pp)->door_list);
3384 3385
3385 3386 /* found it, take it off the list */
3386 3387 *pp = dp->door_list;
3387 3388 }
3388 3389
3389 3390
3390 3391 /*
3391 3392 * External kernel interfaces for doors. These functions are available
3392 3393 * outside the doorfs module for use in creating and using doors from
3393 3394 * within the kernel.
3394 3395 */
3395 3396
3396 3397 /*
3397 3398 * door_ki_upcall invokes a user-level door server from the kernel, with
3398 3399 * the credentials associated with curthread.
3399 3400 */
3400 3401 int
3401 3402 door_ki_upcall(door_handle_t dh, door_arg_t *param)
3402 3403 {
3403 3404 return (door_ki_upcall_limited(dh, param, NULL, SIZE_MAX, UINT_MAX));
3404 3405 }
3405 3406
3406 3407 /*
3407 3408 * door_ki_upcall_limited invokes a user-level door server from the
3408 3409 * kernel with the given credentials and reply limits. If the "cred"
3409 3410 * argument is NULL, uses the credentials associated with current
3410 3411 * thread. max_data limits the maximum length of the returned data (the
3411 3412 * client will get E2BIG if they go over), and max_desc limits the
3412 3413 * number of returned descriptors (the client will get EMFILE if they
3413 3414 * go over).
3414 3415 */
3415 3416 int
3416 3417 door_ki_upcall_limited(door_handle_t dh, door_arg_t *param, struct cred *cred,
3417 3418 size_t max_data, uint_t max_desc)
3418 3419 {
3419 3420 file_t *fp = DHTOF(dh);
3420 3421 vnode_t *realvp;
3421 3422
3422 3423 if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
3423 3424 realvp = fp->f_vnode;
3424 3425 return (door_upcall(realvp, param, cred, max_data, max_desc));
3425 3426 }
3426 3427
3427 3428 /*
3428 3429 * Function call to create a "kernel" door server. A kernel door
3429 3430 * server provides a way for a user-level process to invoke a function
3430 3431 * in the kernel through a door_call. From the caller's point of
3431 3432 * view, a kernel door server looks the same as a user-level one
3432 3433 * (except the server pid is 0). Unlike normal door calls, the
3433 3434 * kernel door function is invoked via a normal function call in the
3434 3435 * same thread and context as the caller.
3435 3436 */
3436 3437 int
3437 3438 door_ki_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
3438 3439 door_handle_t *dhp)
3439 3440 {
3440 3441 int err;
3441 3442 file_t *fp;
3442 3443
3443 3444 /* no DOOR_PRIVATE */
3444 3445 if ((attributes & ~DOOR_KI_CREATE_MASK) ||
3445 3446 (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
3446 3447 (DOOR_UNREF | DOOR_UNREF_MULTI))
3447 3448 return (EINVAL);
3448 3449
3449 3450 err = door_create_common(pc_cookie, data_cookie, attributes,
3450 3451 1, NULL, &fp);
3451 3452 if (err == 0 && (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) &&
3452 3453 p0.p_unref_thread == 0) {
3453 3454 /* need to create unref thread for process 0 */
3454 3455 (void) thread_create(NULL, 0, door_unref_kernel, NULL, 0, &p0,
3455 3456 TS_RUN, minclsyspri);
3456 3457 }
3457 3458 if (err == 0) {
3458 3459 *dhp = FTODH(fp);
3459 3460 }
3460 3461 return (err);
3461 3462 }
3462 3463
3463 3464 void
3464 3465 door_ki_hold(door_handle_t dh)
3465 3466 {
3466 3467 file_t *fp = DHTOF(dh);
3467 3468
3468 3469 mutex_enter(&fp->f_tlock);
3469 3470 fp->f_count++;
3470 3471 mutex_exit(&fp->f_tlock);
3471 3472 }
3472 3473
3473 3474 void
3474 3475 door_ki_rele(door_handle_t dh)
3475 3476 {
3476 3477 file_t *fp = DHTOF(dh);
3477 3478
3478 3479 (void) closef(fp);
3479 3480 }
3480 3481
3481 3482 int
3482 3483 door_ki_open(char *pathname, door_handle_t *dhp)
3483 3484 {
3484 3485 file_t *fp;
3485 3486 vnode_t *vp;
3486 3487 int err;
3487 3488
3488 3489 if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
3489 3490 return (err);
3490 3491 if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
3491 3492 VN_RELE(vp);
3492 3493 return (err);
3493 3494 }
3494 3495 if (vp->v_type != VDOOR) {
3495 3496 VN_RELE(vp);
3496 3497 return (EINVAL);
3497 3498 }
3498 3499 if ((err = falloc(vp, FREAD | FWRITE, &fp, NULL)) != 0) {
3499 3500 VN_RELE(vp);
3500 3501 return (err);
3501 3502 }
3502 3503 /* falloc returns with f_tlock held on success */
3503 3504 mutex_exit(&fp->f_tlock);
3504 3505 *dhp = FTODH(fp);
3505 3506 return (0);
3506 3507 }
3507 3508
3508 3509 int
3509 3510 door_ki_info(door_handle_t dh, struct door_info *dip)
3510 3511 {
3511 3512 file_t *fp = DHTOF(dh);
3512 3513 vnode_t *vp;
3513 3514
3514 3515 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3515 3516 vp = fp->f_vnode;
3516 3517 if (vp->v_type != VDOOR)
3517 3518 return (EINVAL);
3518 3519 door_info_common(VTOD(vp), dip, fp);
3519 3520 return (0);
3520 3521 }
3521 3522
3522 3523 door_handle_t
3523 3524 door_ki_lookup(int did)
3524 3525 {
3525 3526 file_t *fp;
3526 3527 door_handle_t dh;
3527 3528
3528 3529 /* is the descriptor really a door? */
3529 3530 if (door_lookup(did, &fp) == NULL)
3530 3531 return (NULL);
3531 3532 /* got the door, put a hold on it and release the fd */
3532 3533 dh = FTODH(fp);
3533 3534 door_ki_hold(dh);
3534 3535 releasef(did);
3535 3536 return (dh);
3536 3537 }
3537 3538
3538 3539 int
3539 3540 door_ki_setparam(door_handle_t dh, int type, size_t val)
3540 3541 {
3541 3542 file_t *fp = DHTOF(dh);
3542 3543 vnode_t *vp;
3543 3544
3544 3545 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3545 3546 vp = fp->f_vnode;
3546 3547 if (vp->v_type != VDOOR)
3547 3548 return (EINVAL);
3548 3549 return (door_setparam_common(VTOD(vp), 1, type, val));
3549 3550 }
3550 3551
3551 3552 int
3552 3553 door_ki_getparam(door_handle_t dh, int type, size_t *out)
3553 3554 {
3554 3555 file_t *fp = DHTOF(dh);
3555 3556 vnode_t *vp;
3556 3557
3557 3558 if (VOP_REALVP(fp->f_vnode, &vp, NULL))
3558 3559 vp = fp->f_vnode;
3559 3560 if (vp->v_type != VDOOR)
3560 3561 return (EINVAL);
3561 3562 return (door_getparam_common(VTOD(vp), type, out));
3562 3563 }
↓ open down ↓ |
3399 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX