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