stop shipping useless ksh93 builtins into /usr/bin
[unleashed.git] / kernel / fs / fs_subr.c
blob8ab849bcf3d729770d0e961afdefaee28ab31348
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 2015 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)
340 *reventsp = 0;
341 if (events & POLLIN)
342 *reventsp |= POLLIN;
343 if (events & POLLRDNORM)
344 *reventsp |= POLLRDNORM;
345 if (events & POLLRDBAND)
346 *reventsp |= POLLRDBAND;
347 if (events & POLLOUT)
348 *reventsp |= POLLOUT;
349 if (events & POLLWRBAND)
350 *reventsp |= POLLWRBAND;
351 *phpp = !anyyet && !*reventsp ? &fs_pollhd : NULL;
352 return (0);
356 * POSIX pathconf() support.
358 /* ARGSUSED */
360 fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
361 caller_context_t *ct)
363 ulong_t val;
364 int error = 0;
365 struct statvfs64 vfsbuf;
367 switch (cmd) {
369 case _PC_LINK_MAX:
370 val = MAXLINK;
371 break;
373 case _PC_MAX_CANON:
374 val = MAX_CANON;
375 break;
377 case _PC_MAX_INPUT:
378 val = MAX_INPUT;
379 break;
381 case _PC_NAME_MAX:
382 bzero(&vfsbuf, sizeof (vfsbuf));
383 if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf))
384 break;
385 val = vfsbuf.f_namemax;
386 break;
388 case _PC_PATH_MAX:
389 case _PC_SYMLINK_MAX:
390 val = MAXPATHLEN;
391 break;
393 case _PC_PIPE_BUF:
394 val = PIPE_BUF;
395 break;
397 case _PC_NO_TRUNC:
398 if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC)
399 val = 1; /* NOTRUNC is enabled for vp */
400 else
401 val = (ulong_t)-1;
402 break;
404 case _PC_VDISABLE:
405 val = _POSIX_VDISABLE;
406 break;
408 case _PC_CHOWN_RESTRICTED:
409 if (rstchown)
410 val = rstchown; /* chown restricted enabled */
411 else
412 val = (ulong_t)-1;
413 break;
415 case _PC_FILESIZEBITS:
418 * If ever we come here it means that underlying file system
419 * does not recognise the command and therefore this
420 * configurable limit cannot be determined. We return -1
421 * and don't change errno.
424 val = (ulong_t)-1; /* large file support */
425 break;
427 case _PC_ACL_ENABLED:
428 val = 0;
429 break;
431 case _PC_CASE_BEHAVIOR:
432 val = _CASE_SENSITIVE;
433 if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
434 val |= _CASE_INSENSITIVE;
435 if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
436 val &= ~_CASE_SENSITIVE;
437 break;
439 case _PC_SATTR_ENABLED:
440 case _PC_SATTR_EXISTS:
441 val = 0;
442 break;
444 case _PC_ACCESS_FILTERING:
445 val = 0;
446 break;
448 default:
449 error = EINVAL;
450 break;
453 if (error == 0)
454 *valp = val;
455 return (error);
459 * Dispose of a page.
461 /* ARGSUSED */
462 void
463 fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
464 caller_context_t *ct)
467 ASSERT(fl == B_FREE || fl == B_INVAL);
469 if (fl == B_FREE)
470 page_free(pp, dn);
471 else
472 page_destroy(pp, dn);
475 /* ARGSUSED */
476 void
477 fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
478 caller_context_t *ct)
480 cmn_err(CE_PANIC, "fs_nodispose invoked");
484 * fabricate acls for file systems that do not support acls.
486 /* ARGSUSED */
488 fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
489 caller_context_t *ct)
491 aclent_t *aclentp;
492 struct vattr vattr;
493 int error;
494 size_t aclsize;
496 vsecattr->vsa_aclcnt = 0;
497 vsecattr->vsa_aclentsz = 0;
498 vsecattr->vsa_aclentp = NULL;
499 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
500 vsecattr->vsa_dfaclentp = NULL;
502 vattr.va_mask = AT_MODE | AT_UID | AT_GID;
503 if (error = fop_getattr(vp, &vattr, 0, cr, ct))
504 return (error);
506 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
507 aclsize = 4 * sizeof (aclent_t);
508 vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */
509 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
510 aclentp = vsecattr->vsa_aclentp;
512 aclentp->a_type = USER_OBJ; /* Owner */
513 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6;
514 aclentp->a_id = vattr.va_uid; /* Really undefined */
515 aclentp++;
517 aclentp->a_type = GROUP_OBJ; /* Group */
518 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3;
519 aclentp->a_id = vattr.va_gid; /* Really undefined */
520 aclentp++;
522 aclentp->a_type = OTHER_OBJ; /* Other */
523 aclentp->a_perm = vattr.va_mode & 0007;
524 aclentp->a_id = (gid_t)-1; /* Really undefined */
525 aclentp++;
527 aclentp->a_type = CLASS_OBJ; /* Class */
528 aclentp->a_perm = (ushort_t)(0007);
529 aclentp->a_id = (gid_t)-1; /* Really undefined */
530 } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
531 VERIFY(0 == acl_trivial_create(vattr.va_mode,
532 (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
533 &vsecattr->vsa_aclcnt));
534 vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
537 return (error);
541 * Common code for implementing DOS share reservations
543 /* ARGSUSED4 */
545 fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
546 caller_context_t *ct)
548 int error;
551 * Make sure that the file was opened with permissions appropriate
552 * for the request, and make sure the caller isn't trying to sneak
553 * in an NBMAND request.
555 if (cmd == F_SHARE) {
556 if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
557 ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
558 return (EBADF);
559 if (shr->s_access & (F_RMACC | F_MDACC))
560 return (EINVAL);
561 if (shr->s_deny & (F_MANDDNY | F_RMDNY))
562 return (EINVAL);
564 if (cmd == F_SHARE_NBMAND) {
565 /* make sure nbmand is allowed on the file */
566 if (!vp->v_vfsp ||
567 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
568 return (EINVAL);
570 if (vp->v_type != VREG) {
571 return (EINVAL);
575 nbl_start_crit(vp, RW_WRITER);
577 switch (cmd) {
579 case F_SHARE_NBMAND:
580 shr->s_deny |= F_MANDDNY;
581 /*FALLTHROUGH*/
582 case F_SHARE:
583 error = add_share(vp, shr);
584 break;
586 case F_UNSHARE:
587 error = del_share(vp, shr);
588 break;
590 case F_HASREMOTELOCKS:
592 * We are overloading this command to refer to remote
593 * shares as well as remote locks, despite its name.
595 shr->s_access = shr_has_remote_shares(vp, shr->s_sysid);
596 error = 0;
597 break;
599 default:
600 error = EINVAL;
601 break;
604 nbl_end_crit(vp);
605 return (error);
608 /*ARGSUSED1*/
610 fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
611 caller_context_t *ct)
613 ASSERT(vp != NULL);
614 return (0);
618 * return 1 for non-trivial ACL.
620 * NB: It is not necessary for the caller to fop_rwlock since
621 * we only issue fop_getsecattr.
623 * Returns 0 == trivial
624 * 1 == NOT Trivial
625 * <0 could not determine.
628 fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
630 ulong_t acl_styles;
631 ulong_t acl_flavor;
632 vsecattr_t vsecattr;
633 int error;
634 int isnontrivial;
636 /* determine the forms of ACLs maintained */
637 error = fop_pathconf(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
639 /* clear bits we don't understand and establish default acl_style */
640 acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
641 if (error || (acl_styles == 0))
642 acl_styles = _ACL_ACLENT_ENABLED;
644 vsecattr.vsa_aclentp = NULL;
645 vsecattr.vsa_dfaclentp = NULL;
646 vsecattr.vsa_aclcnt = 0;
647 vsecattr.vsa_dfaclcnt = 0;
649 while (acl_styles) {
650 /* select one of the styles as current flavor */
651 acl_flavor = 0;
652 if (acl_styles & _ACL_ACLENT_ENABLED) {
653 acl_flavor = _ACL_ACLENT_ENABLED;
654 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
655 } else if (acl_styles & _ACL_ACE_ENABLED) {
656 acl_flavor = _ACL_ACE_ENABLED;
657 vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE;
660 ASSERT(vsecattr.vsa_mask && acl_flavor);
661 error = fop_getsecattr(vp, &vsecattr, 0, cr, NULL);
662 if (error == 0)
663 break;
665 /* that flavor failed */
666 acl_styles &= ~acl_flavor;
669 /* if all styles fail then assume trivial */
670 if (acl_styles == 0)
671 return (0);
673 /* process the flavor that worked */
674 isnontrivial = 0;
675 if (acl_flavor & _ACL_ACLENT_ENABLED) {
676 if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES)
677 isnontrivial = 1;
678 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
679 kmem_free(vsecattr.vsa_aclentp,
680 vsecattr.vsa_aclcnt * sizeof (aclent_t));
681 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL)
682 kmem_free(vsecattr.vsa_dfaclentp,
683 vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
685 if (acl_flavor & _ACL_ACE_ENABLED) {
686 isnontrivial = ace_trivial(vsecattr.vsa_aclentp,
687 vsecattr.vsa_aclcnt);
689 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL)
690 kmem_free(vsecattr.vsa_aclentp,
691 vsecattr.vsa_aclcnt * sizeof (ace_t));
692 /* ACE has no vsecattr.vsa_dfaclcnt */
694 return (isnontrivial);
698 * Check whether we need a retry to recover from STALE error.
701 fs_need_estale_retry(int retry_count)
703 if (retry_count < fs_estale_retry)
704 return (1);
705 else
706 return (0);
710 static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
713 * Routine for anti-virus scanner to call to register its scanning routine.
715 void
716 fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
718 fs_av_scan = av_scan;
722 * Routine for file systems to call to initiate anti-virus scanning.
723 * Scanning will only be done on REGular files (currently).
726 fs_vscan(vnode_t *vp, cred_t *cr, int async)
728 int ret = 0;
730 if (fs_av_scan && vp->v_type == VREG)
731 ret = (*fs_av_scan)(vp, cr, async);
733 return (ret);
737 * support functions for reparse point
740 * reparse_vnode_parse
742 * Read the symlink data of a reparse point specified by the vnode
743 * and return the reparse data as name-value pair in the nvlist.
746 reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl)
748 int err;
749 char *lkdata;
750 struct uio uio;
751 struct iovec iov;
753 if (vp == NULL || nvl == NULL)
754 return (EINVAL);
756 lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP);
759 * Set up io vector to read sym link data
761 iov.iov_base = lkdata;
762 iov.iov_len = MAXREPARSELEN;
763 uio.uio_iov = &iov;
764 uio.uio_iovcnt = 1;
765 uio.uio_segflg = UIO_SYSSPACE;
766 uio.uio_extflg = UIO_COPY_CACHED;
767 uio.uio_loffset = 0;
768 uio.uio_resid = MAXREPARSELEN;
770 if ((err = fop_readlink(vp, &uio, kcred, NULL)) == 0) {
771 *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0';
772 err = reparse_parse(lkdata, nvl);
774 kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */
776 return (err);
779 void
780 reparse_point_init()
782 mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL);
785 static door_handle_t
786 reparse_door_get_handle()
788 door_handle_t dh;
790 mutex_enter(&reparsed_door_lock);
791 if ((dh = reparsed_door) == NULL) {
792 if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) {
793 reparsed_door = NULL;
794 dh = NULL;
795 } else
796 dh = reparsed_door;
798 mutex_exit(&reparsed_door_lock);
799 return (dh);
802 static void
803 reparse_door_reset_handle()
805 mutex_enter(&reparsed_door_lock);
806 reparsed_door = NULL;
807 mutex_exit(&reparsed_door_lock);
811 * reparse_kderef
813 * Accepts the service-specific item from the reparse point and returns
814 * the service-specific data requested. The caller specifies the size of
815 * the buffer provided via *bufsz; the routine will fail with EOVERFLOW
816 * if the results will not fit in the buffer, in which case, *bufsz will
817 * contain the number of bytes needed to hold the results.
819 * if ok return 0 and update *bufsize with length of actual result
820 * else return error code.
823 reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
824 size_t *bufsize)
826 int err, retries, need_free, retried_doorhd;
827 size_t dlen, res_len;
828 char *darg;
829 door_arg_t door_args;
830 reparsed_door_res_t *resp;
831 door_handle_t rp_door;
833 if (svc_type == NULL || svc_data == NULL || buf == NULL ||
834 bufsize == NULL)
835 return (EINVAL);
837 /* get reparsed's door handle */
838 if ((rp_door = reparse_door_get_handle()) == NULL)
839 return (EBADF);
841 /* setup buffer for door_call args and results */
842 dlen = strlen(svc_type) + strlen(svc_data) + 2;
843 if (*bufsize < dlen) {
844 darg = kmem_alloc(dlen, KM_SLEEP);
845 need_free = 1;
846 } else {
847 darg = buf; /* use same buffer for door's args & results */
848 need_free = 0;
851 /* build argument string of door call */
852 (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data);
854 /* setup args for door call */
855 door_args.data_ptr = darg;
856 door_args.data_size = dlen;
857 door_args.desc_ptr = NULL;
858 door_args.desc_num = 0;
859 door_args.rbuf = buf;
860 door_args.rsize = *bufsize;
862 /* do the door_call */
863 retried_doorhd = 0;
864 retries = 0;
865 door_ki_hold(rp_door);
866 while ((err = door_ki_upcall_limited(rp_door, &door_args,
867 NULL, SIZE_MAX, 0)) != 0) {
868 if (err == EAGAIN || err == EINTR) {
869 if (++retries < REPARSED_DOORCALL_MAX_RETRY) {
870 ddi_sleep(1);
871 continue;
873 } else if (err == EBADF) {
874 /* door server goes away... */
875 reparse_door_reset_handle();
877 if (retried_doorhd == 0) {
878 door_ki_rele(rp_door);
879 retried_doorhd++;
880 rp_door = reparse_door_get_handle();
881 if (rp_door != NULL) {
882 door_ki_hold(rp_door);
883 continue;
887 break;
890 if (rp_door)
891 door_ki_rele(rp_door);
893 if (need_free)
894 kmem_free(darg, dlen); /* done with args buffer */
896 if (err != 0)
897 return (err);
899 resp = (reparsed_door_res_t *)door_args.rbuf;
900 if ((err = resp->res_status) == 0) {
902 * have to save the length of the results before the
903 * bcopy below since it's can be an overlap copy that
904 * overwrites the reparsed_door_res_t structure at
905 * the beginning of the buffer.
907 res_len = (size_t)resp->res_len;
909 /* deref call is ok */
910 if (res_len > *bufsize)
911 err = EOVERFLOW;
912 else
913 bcopy(resp->res_data, buf, res_len);
914 *bufsize = res_len;
916 if (door_args.rbuf != buf)
917 kmem_free(door_args.rbuf, door_args.rsize);
919 return (err);