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