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