don't bother resolving onbld python module deps
[unleashed.git] / kernel / fs / fs_subr.c
blob9ecf92d1ea8888d5cd382bdc057a1ecde8f75823
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
26 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2017 Joyent, Inc.
32 * Generic vnode operations.
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/errno.h>
38 #include <sys/fcntl.h>
39 #include <sys/flock.h>
40 #include <sys/statvfs.h>
41 #include <sys/vfs.h>
42 #include <sys/vnode.h>
43 #include <sys/proc.h>
44 #include <sys/user.h>
45 #include <sys/unistd.h>
46 #include <sys/cred.h>
47 #include <sys/poll.h>
48 #include <sys/debug.h>
49 #include <sys/cmn_err.h>
50 #include <sys/stream.h>
51 #include <sys/fs_subr.h>
52 #include <sys/fs_reparse.h>
53 #include <sys/door.h>
54 #include <sys/acl.h>
55 #include <sys/share.h>
56 #include <sys/file.h>
57 #include <sys/kmem.h>
58 #include <sys/file.h>
59 #include <sys/nbmlock.h>
60 #include <acl/acl_common.h>
61 #include <sys/pathname.h>
63 static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *);
66 * Tunable to limit the number of retry to recover from STALE error.
68 int fs_estale_retry = 5;
71 * supports for reparse point door upcall
73 static door_handle_t reparsed_door;
74 static kmutex_t reparsed_door_lock;
77 * The associated operation is not supported by the file system.
79 int
80 fs_nosys()
82 return (ENOSYS);
86 * The associated operation is invalid (on this vnode).
88 int
89 fs_inval()
91 return (EINVAL);
95 * The associated operation is valid only for directories.
97 int
98 fs_notdir()
100 return (ENOTDIR);
104 * Free the file system specific resources. For the file systems that
105 * do not support the forced unmount, it will be a nop function.
108 /*ARGSUSED*/
109 void
110 fs_freevfs(vfs_t *vfsp)
114 /* ARGSUSED */
116 fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
117 struct pollhead **phpp, caller_context_t *ct)
119 return (ENOSYS);
124 * Does nothing but fop_fsync must not fail.
126 /* ARGSUSED */
128 fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
130 return (0);
134 * Does nothing but fop_putpage must not fail.
136 /* ARGSUSED */
138 fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
139 caller_context_t *ctp)
141 return (0);
145 * Does nothing but fop_ioctl must not fail.
147 /* ARGSUSED */
149 fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
150 int *rvalp, caller_context_t *ct)
152 return (0);
156 * No-op seek operation.
158 /* ARGSUSED */
160 fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
162 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
166 * File and record locking.
168 /* ARGSUSED */
170 fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
171 flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
173 int frcmd;
174 int error = 0;
175 boolean_t skip_lock = B_FALSE;
176 flk_callback_t serialize_callback;
177 int serialize = 0;
178 v_mode_t mode;
180 switch (cmd) {
182 case F_GETLK:
183 case F_O_GETLK:
184 if (flag & F_REMOTELOCK) {
185 frcmd = RCMDLCK;
186 } else {
187 frcmd = 0;
188 bfp->l_pid = ttoproc(curthread)->p_pid;
189 bfp->l_sysid = 0;
191 break;
193 case F_OFD_GETLK:
195 * TBD we do not support remote OFD locks at this time.
197 if (flag & F_REMOTELOCK) {
198 error = EINVAL;
199 goto done;
201 skip_lock = B_TRUE;
202 break;
204 case F_SETLK_NBMAND:
206 * Are NBMAND locks allowed on this file?
208 if (!vp->v_vfsp ||
209 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
210 error = EINVAL;
211 goto done;
213 if (vp->v_type != VREG) {
214 error = EINVAL;
215 goto done;
217 /*FALLTHROUGH*/
219 case F_SETLK:
220 if (flag & F_REMOTELOCK) {
221 frcmd = SETFLCK|RCMDLCK;
222 } else {
223 frcmd = SETFLCK;
224 bfp->l_pid = ttoproc(curthread)->p_pid;
225 bfp->l_sysid = 0;
227 if (cmd == F_SETLK_NBMAND &&
228 (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
229 frcmd |= NBMLCK;
232 if (nbl_need_check(vp)) {
233 nbl_start_crit(vp, RW_WRITER);
234 serialize = 1;
235 if (frcmd & NBMLCK) {
236 mode = (bfp->l_type == F_RDLCK) ?
237 V_READ : V_RDANDWR;
238 if (vn_is_mapped(vp, mode)) {
239 error = EAGAIN;
240 goto done;
244 break;
246 case F_SETLKW:
247 if (flag & F_REMOTELOCK) {
248 frcmd = SETFLCK|SLPFLCK|RCMDLCK;
249 } else {
250 frcmd = SETFLCK|SLPFLCK;
251 bfp->l_pid = ttoproc(curthread)->p_pid;
252 bfp->l_sysid = 0;
255 if (nbl_need_check(vp)) {
256 nbl_start_crit(vp, RW_WRITER);
257 serialize = 1;
259 break;
261 case F_OFD_SETLK:
262 case F_OFD_SETLKW:
263 case F_FLOCK:
264 case F_FLOCKW:
266 * TBD we do not support remote OFD locks at this time.
268 if (flag & F_REMOTELOCK) {
269 error = EINVAL;
270 goto done;
272 skip_lock = B_TRUE;
273 break;
275 case F_HASREMOTELOCKS:
276 l_has_rmt(bfp) = flk_has_remote_locks(vp);
277 goto done;
279 default:
280 error = EINVAL;
281 goto done;
285 * If this is a blocking lock request and we're serializing lock
286 * requests, modify the callback list to leave the critical region
287 * while we're waiting for the lock.
290 if (serialize && (frcmd & SLPFLCK) != 0) {
291 flk_add_callback(&serialize_callback,
292 frlock_serialize_blocked, vp, flk_cbp);
293 flk_cbp = &serialize_callback;
296 if (!skip_lock)
297 error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp);
299 if (serialize && (frcmd & SLPFLCK) != 0)
300 flk_del_callback(&serialize_callback);
302 done:
303 if (serialize)
304 nbl_end_crit(vp);
306 return (error);
310 * Callback when a lock request blocks and we are serializing requests. If
311 * before sleeping, leave the critical region. If after wakeup, reenter
312 * the critical region.
315 static callb_cpr_t *
316 frlock_serialize_blocked(flk_cb_when_t when, void *infop)
318 vnode_t *vp = (vnode_t *)infop;
320 if (when == FLK_BEFORE_SLEEP)
321 nbl_end_crit(vp);
322 else {
323 nbl_start_crit(vp, RW_WRITER);
326 return (NULL);
330 * Return the answer requested to poll() for non-device files.
331 * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
333 struct pollhead fs_pollhd;
335 /* ARGSUSED */
337 fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
338 struct pollhead **phpp, caller_context_t *ct)
341 * Reject all attempts for edge-triggered polling. These should only
342 * occur when regular files are added to a /dev/poll handle which is in
343 * epoll mode. The Linux epoll does not allow epoll-ing on regular
344 * files at all, so rejecting EPOLLET requests is congruent with those
345 * expectations.
347 if (events & POLLET) {
348 return (EPERM);
351 *reventsp = 0;
352 if (events & POLLIN)
353 *reventsp |= POLLIN;
354 if (events & POLLRDNORM)
355 *reventsp |= POLLRDNORM;
356 if (events & POLLRDBAND)
357 *reventsp |= POLLRDBAND;
358 if (events & POLLOUT)
359 *reventsp |= POLLOUT;
360 if (events & POLLWRBAND)
361 *reventsp |= POLLWRBAND;
363 * Emitting a pollhead without the intention of issuing pollwakeup()
364 * calls against it is a recipe for trouble. It's only acceptable in
365 * this case since the above logic matches practically all useful
366 * events.
368 if (*reventsp == 0 && !anyyet)
369 *phpp = &fs_pollhd;
370 return (0);
374 * POSIX pathconf() support.
376 /* ARGSUSED */
378 fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
379 caller_context_t *ct)
381 ulong_t val;
382 int error = 0;
383 struct statvfs64 vfsbuf;
385 switch (cmd) {
387 case _PC_LINK_MAX:
388 val = MAXLINK;
389 break;
391 case _PC_MAX_CANON:
392 val = MAX_CANON;
393 break;
395 case _PC_MAX_INPUT:
396 val = MAX_INPUT;
397 break;
399 case _PC_NAME_MAX:
400 bzero(&vfsbuf, sizeof (vfsbuf));
401 if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
402 break;
403 val = vfsbuf.f_namemax;
404 break;
406 case _PC_PATH_MAX:
407 case _PC_SYMLINK_MAX:
408 val = MAXPATHLEN;
409 break;
411 case _PC_PIPE_BUF:
412 val = PIPE_BUF;
413 break;
415 case _PC_NO_TRUNC:
416 if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
417 val = 1; /* NOTRUNC is enabled for vp */
418 else
419 val = (ulong_t)-1;
420 break;
422 case _PC_VDISABLE:
423 val = _POSIX_VDISABLE;
424 break;
426 case _PC_CHOWN_RESTRICTED:
427 if (rstchown)
428 val = rstchown; /* chown restricted enabled */
429 else
430 val = (ulong_t)-1;
431 break;
433 case _PC_FILESIZEBITS:
436 * If ever we come here it means that underlying file system
437 * does not recognise the command and therefore this
438 * configurable limit cannot be determined. We return -1
439 * and don't change errno.
442 val = (ulong_t)-1; /* large file support */
443 break;
445 case _PC_ACL_ENABLED:
446 val = 0;
447 break;
449 case _PC_CASE_BEHAVIOR:
450 val = _CASE_SENSITIVE;
451 if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
452 val |= _CASE_INSENSITIVE;
453 if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
454 val &= ~_CASE_SENSITIVE;
455 break;
457 case _PC_SATTR_ENABLED:
458 case _PC_SATTR_EXISTS:
459 val = 0;
460 break;
462 case _PC_ACCESS_FILTERING:
463 val = 0;
464 break;
466 default:
467 error = EINVAL;
468 break;
471 if (error == 0)
472 *valp = val;
473 return (error);
477 * Dispose of a page.
479 /* ARGSUSED */
480 void
481 fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
482 caller_context_t *ct)
485 ASSERT(fl == B_FREE || fl == B_INVAL);
487 if (fl == B_FREE)
488 page_free(pp, dn);
489 else
490 page_destroy(pp, dn);
493 /* ARGSUSED */
494 void
495 fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
496 caller_context_t *ct)
498 cmn_err(CE_PANIC, "fs_nodispose invoked");
502 * fabricate acls for file systems that do not support acls.
504 /* ARGSUSED */
506 fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
507 caller_context_t *ct)
509 aclent_t *aclentp;
510 struct vattr vattr;
511 int error;
512 size_t aclsize;
514 vsecattr->vsa_aclcnt = 0;
515 vsecattr->vsa_aclentsz = 0;
516 vsecattr->vsa_aclentp = NULL;
517 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
518 vsecattr->vsa_dfaclentp = NULL;
520 vattr.va_mask = AT_MODE | AT_UID | AT_GID;
521 if (error = fop_getattr(vp, &vattr, 0, cr, ct))
522 return (error);
524 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
525 aclsize = 4 * sizeof (aclent_t);
526 vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */
527 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
528 aclentp = vsecattr->vsa_aclentp;
530 aclentp->a_type = USER_OBJ; /* Owner */
531 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6;
532 aclentp->a_id = vattr.va_uid; /* Really undefined */
533 aclentp++;
535 aclentp->a_type = GROUP_OBJ; /* Group */
536 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3;
537 aclentp->a_id = vattr.va_gid; /* Really undefined */
538 aclentp++;
540 aclentp->a_type = OTHER_OBJ; /* Other */
541 aclentp->a_perm = vattr.va_mode & 0007;
542 aclentp->a_id = (gid_t)-1; /* Really undefined */
543 aclentp++;
545 aclentp->a_type = CLASS_OBJ; /* Class */
546 aclentp->a_perm = (ushort_t)(0007);
547 aclentp->a_id = (gid_t)-1; /* Really undefined */
548 } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
549 VERIFY(0 == acl_trivial_create(vattr.va_mode,
550 (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
551 &vsecattr->vsa_aclcnt));
552 vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
555 return (error);
559 * Common code for implementing DOS share reservations
561 /* ARGSUSED4 */
563 fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
564 caller_context_t *ct)
566 int error;
569 * Make sure that the file was opened with permissions appropriate
570 * for the request, and make sure the caller isn't trying to sneak
571 * in an NBMAND request.
573 if (cmd == F_SHARE) {
574 if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
575 ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
576 return (EBADF);
577 if (shr->s_access & (F_RMACC | F_MDACC))
578 return (EINVAL);
579 if (shr->s_deny & (F_MANDDNY | F_RMDNY))
580 return (EINVAL);
582 if (cmd == F_SHARE_NBMAND) {
583 /* make sure nbmand is allowed on the file */
584 if (!vp->v_vfsp ||
585 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
586 return (EINVAL);
588 if (vp->v_type != VREG) {
589 return (EINVAL);
593 nbl_start_crit(vp, RW_WRITER);
595 switch (cmd) {
597 case F_SHARE_NBMAND:
598 shr->s_deny |= F_MANDDNY;
599 /*FALLTHROUGH*/
600 case F_SHARE:
601 error = add_share(vp, shr);
602 break;
604 case F_UNSHARE:
605 error = del_share(vp, shr);
606 break;
608 case F_HASREMOTELOCKS:
610 * We are overloading this command to refer to remote
611 * shares as well as remote locks, despite its name.
613 shr->s_access = shr_has_remote_shares(vp, shr->s_sysid);
614 error = 0;
615 break;
617 default:
618 error = EINVAL;
619 break;
622 nbl_end_crit(vp);
623 return (error);
626 /*ARGSUSED1*/
628 fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
629 caller_context_t *ct)
631 ASSERT(vp != NULL);
632 return (0);
636 * return 1 for non-trivial ACL.
638 * NB: It is not necessary for the caller to fop_rwlock since
639 * we only issue fop_getsecattr.
641 * Returns 0 == trivial
642 * 1 == NOT Trivial
643 * <0 could not determine.
646 fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
648 ulong_t acl_styles;
649 ulong_t acl_flavor;
650 vsecattr_t vsecattr;
651 int error;
652 int isnontrivial;
654 /* determine the forms of ACLs maintained */
655 error = fop_pathconf(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
657 /* clear bits we don't understand and establish default acl_style */
658 acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
659 if (error || (acl_styles == 0))
660 acl_styles = _ACL_ACLENT_ENABLED;
662 vsecattr.vsa_aclentp = NULL;
663 vsecattr.vsa_dfaclentp = NULL;
664 vsecattr.vsa_aclcnt = 0;
665 vsecattr.vsa_dfaclcnt = 0;
667 while (acl_styles) {
668 /* select one of the styles as current flavor */
669 acl_flavor = 0;
670 if (acl_styles & _ACL_ACLENT_ENABLED) {
671 acl_flavor = _ACL_ACLENT_ENABLED;
672 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
673 } else if (acl_styles & _ACL_ACE_ENABLED) {
674 acl_flavor = _ACL_ACE_ENABLED;
675 vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE;
678 ASSERT(vsecattr.vsa_mask && acl_flavor);
679 error = fop_getsecattr(vp, &vsecattr, 0, cr, NULL);
680 if (error == 0)
681 break;
683 /* that flavor failed */
684 acl_styles &= ~acl_flavor;
687 /* if all styles fail then assume trivial */
688 if (acl_styles == 0)
689 return (0);
691 /* process the flavor that worked */
692 isnontrivial = 0;
693 if (acl_flavor & _ACL_ACLENT_ENABLED) {
694 if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES)
695 isnontrivial = 1;
696 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
697 kmem_free(vsecattr.vsa_aclentp,
698 vsecattr.vsa_aclcnt * sizeof (aclent_t));
699 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL)
700 kmem_free(vsecattr.vsa_dfaclentp,
701 vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
703 if (acl_flavor & _ACL_ACE_ENABLED) {
704 isnontrivial = ace_trivial(vsecattr.vsa_aclentp,
705 vsecattr.vsa_aclcnt);
707 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
708 kmem_free(vsecattr.vsa_aclentp,
709 vsecattr.vsa_aclcnt * sizeof (ace_t));
710 /* ACE has no vsecattr.vsa_dfaclcnt */
712 return (isnontrivial);
716 * Check whether we need a retry to recover from STALE error.
719 fs_need_estale_retry(int retry_count)
721 if (retry_count < fs_estale_retry)
722 return (1);
723 else
724 return (0);
728 static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
731 * Routine for anti-virus scanner to call to register its scanning routine.
733 void
734 fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
736 fs_av_scan = av_scan;
740 * Routine for file systems to call to initiate anti-virus scanning.
741 * Scanning will only be done on REGular files (currently).
744 fs_vscan(vnode_t *vp, cred_t *cr, int async)
746 int ret = 0;
748 if (fs_av_scan && vp->v_type == VREG)
749 ret = (*fs_av_scan)(vp, cr, async);
751 return (ret);
755 * support functions for reparse point
758 * reparse_vnode_parse
760 * Read the symlink data of a reparse point specified by the vnode
761 * and return the reparse data as name-value pair in the nvlist.
764 reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl)
766 int err;
767 char *lkdata;
768 struct uio uio;
769 struct iovec iov;
771 if (vp == NULL || nvl == NULL)
772 return (EINVAL);
774 lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP);
777 * Set up io vector to read sym link data
779 iov.iov_base = lkdata;
780 iov.iov_len = MAXREPARSELEN;
781 uio.uio_iov = &iov;
782 uio.uio_iovcnt = 1;
783 uio.uio_segflg = UIO_SYSSPACE;
784 uio.uio_extflg = UIO_COPY_CACHED;
785 uio.uio_loffset = 0;
786 uio.uio_resid = MAXREPARSELEN;
788 if ((err = fop_readlink(vp, &uio, kcred, NULL)) == 0) {
789 *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0';
790 err = reparse_parse(lkdata, nvl);
792 kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */
794 return (err);
797 void
798 reparse_point_init()
800 mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL);
803 static door_handle_t
804 reparse_door_get_handle()
806 door_handle_t dh;
808 mutex_enter(&reparsed_door_lock);
809 if ((dh = reparsed_door) == NULL) {
810 if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) {
811 reparsed_door = NULL;
812 dh = NULL;
813 } else
814 dh = reparsed_door;
816 mutex_exit(&reparsed_door_lock);
817 return (dh);
820 static void
821 reparse_door_reset_handle()
823 mutex_enter(&reparsed_door_lock);
824 reparsed_door = NULL;
825 mutex_exit(&reparsed_door_lock);
829 * reparse_kderef
831 * Accepts the service-specific item from the reparse point and returns
832 * the service-specific data requested. The caller specifies the size of
833 * the buffer provided via *bufsz; the routine will fail with EOVERFLOW
834 * if the results will not fit in the buffer, in which case, *bufsz will
835 * contain the number of bytes needed to hold the results.
837 * if ok return 0 and update *bufsize with length of actual result
838 * else return error code.
841 reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
842 size_t *bufsize)
844 int err, retries, need_free, retried_doorhd;
845 size_t dlen, res_len;
846 char *darg;
847 door_arg_t door_args;
848 reparsed_door_res_t *resp;
849 door_handle_t rp_door;
851 if (svc_type == NULL || svc_data == NULL || buf == NULL ||
852 bufsize == NULL)
853 return (EINVAL);
855 /* get reparsed's door handle */
856 if ((rp_door = reparse_door_get_handle()) == NULL)
857 return (EBADF);
859 /* setup buffer for door_call args and results */
860 dlen = strlen(svc_type) + strlen(svc_data) + 2;
861 if (*bufsize < dlen) {
862 darg = kmem_alloc(dlen, KM_SLEEP);
863 need_free = 1;
864 } else {
865 darg = buf; /* use same buffer for door's args & results */
866 need_free = 0;
869 /* build argument string of door call */
870 (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data);
872 /* setup args for door call */
873 door_args.data_ptr = darg;
874 door_args.data_size = dlen;
875 door_args.desc_ptr = NULL;
876 door_args.desc_num = 0;
877 door_args.rbuf = buf;
878 door_args.rsize = *bufsize;
880 /* do the door_call */
881 retried_doorhd = 0;
882 retries = 0;
883 door_ki_hold(rp_door);
884 while ((err = door_ki_upcall_limited(rp_door, &door_args,
885 NULL, SIZE_MAX, 0)) != 0) {
886 if (err == EAGAIN || err == EINTR) {
887 if (++retries < REPARSED_DOORCALL_MAX_RETRY) {
888 ddi_sleep(1);
889 continue;
891 } else if (err == EBADF) {
892 /* door server goes away... */
893 reparse_door_reset_handle();
895 if (retried_doorhd == 0) {
896 door_ki_rele(rp_door);
897 retried_doorhd++;
898 rp_door = reparse_door_get_handle();
899 if (rp_door != NULL) {
900 door_ki_hold(rp_door);
901 continue;
905 break;
908 if (rp_door)
909 door_ki_rele(rp_door);
911 if (need_free)
912 kmem_free(darg, dlen); /* done with args buffer */
914 if (err != 0)
915 return (err);
917 resp = (reparsed_door_res_t *)door_args.rbuf;
918 if ((err = resp->res_status) == 0) {
920 * have to save the length of the results before the
921 * bcopy below since it's can be an overlap copy that
922 * overwrites the reparsed_door_res_t structure at
923 * the beginning of the buffer.
925 res_len = (size_t)resp->res_len;
927 /* deref call is ok */
928 if (res_len > *bufsize)
929 err = EOVERFLOW;
930 else
931 bcopy(resp->res_data, buf, res_len);
932 *bufsize = res_len;
934 if (door_args.rbuf != buf)
935 kmem_free(door_args.rbuf, door_args.rsize);
937 return (err);