Home | History | Annotate | Download | only in smbsrv
      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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/kmem.h>
     28 #include <sys/ddi.h>
     29 #include <sys/sunddi.h>
     30 #include <sys/cmn_err.h>
     31 #include <sys/door.h>
     32 #include <smbsrv/smb_door_svc.h>
     33 #include <smbsrv/smb_common_door.h>
     34 
     35 #define	SMB_KDOOR_RETRIES	3
     36 
     37 static char *smb_kdoor_upcall(char *, size_t, door_desc_t *, uint_t, size_t *);
     38 
     39 door_handle_t smb_kdoor_clnt_hd = NULL;
     40 static int smb_kdoor_clnt_id = -1;
     41 static uint64_t smb_kdoor_clnt_ncall = 0;
     42 static kmutex_t smb_kdoor_clnt_mutex;
     43 static kcondvar_t smb_kdoor_clnt_cv;
     44 
     45 void
     46 smb_kdoor_clnt_init(void)
     47 {
     48 	mutex_init(&smb_kdoor_clnt_mutex, NULL, MUTEX_DEFAULT, NULL);
     49 	cv_init(&smb_kdoor_clnt_cv, NULL, CV_DEFAULT, NULL);
     50 }
     51 
     52 void
     53 smb_kdoor_clnt_fini(void)
     54 {
     55 	smb_kdoor_clnt_close();
     56 	cv_destroy(&smb_kdoor_clnt_cv);
     57 	mutex_destroy(&smb_kdoor_clnt_mutex);
     58 }
     59 
     60 /*
     61  * Open the door.  If the door is already open, close it first
     62  * because the door-id has probably changed.
     63  */
     64 int
     65 smb_kdoor_clnt_open(int door_id)
     66 {
     67 	int rc;
     68 
     69 	smb_kdoor_clnt_close();
     70 
     71 	mutex_enter(&smb_kdoor_clnt_mutex);
     72 	smb_kdoor_clnt_ncall = 0;
     73 
     74 	if (smb_kdoor_clnt_hd == NULL) {
     75 		smb_kdoor_clnt_id = door_id;
     76 		smb_kdoor_clnt_hd = door_ki_lookup(door_id);
     77 	}
     78 
     79 	rc = (smb_kdoor_clnt_hd == NULL)  ? -1 : 0;
     80 	mutex_exit(&smb_kdoor_clnt_mutex);
     81 	return (rc);
     82 }
     83 
     84 /*
     85  * Close the door.
     86  */
     87 void
     88 smb_kdoor_clnt_close(void)
     89 {
     90 	mutex_enter(&smb_kdoor_clnt_mutex);
     91 
     92 	if (smb_kdoor_clnt_hd != NULL) {
     93 		while (smb_kdoor_clnt_ncall > 0)
     94 			cv_wait(&smb_kdoor_clnt_cv, &smb_kdoor_clnt_mutex);
     95 
     96 		door_ki_rele(smb_kdoor_clnt_hd);
     97 		smb_kdoor_clnt_hd = NULL;
     98 	}
     99 
    100 	mutex_exit(&smb_kdoor_clnt_mutex);
    101 }
    102 
    103 /*
    104  * smb_kdoor_clnt_upcall
    105  *
    106  * Wrapper to handle door call reference counting.
    107  */
    108 char *
    109 smb_kdoor_clnt_upcall(char *argp, size_t arg_size, door_desc_t *dp,
    110     uint_t desc_num, size_t *rbufsize)
    111 {
    112 	char *rbufp;
    113 
    114 	if (argp == NULL)
    115 		return (NULL);
    116 
    117 	mutex_enter(&smb_kdoor_clnt_mutex);
    118 
    119 	if (smb_kdoor_clnt_hd == NULL) {
    120 		mutex_exit(&smb_kdoor_clnt_mutex);
    121 
    122 		if (smb_kdoor_clnt_open(smb_kdoor_clnt_id) != 0)
    123 			return (NULL);
    124 
    125 		mutex_enter(&smb_kdoor_clnt_mutex);
    126 	}
    127 
    128 	++smb_kdoor_clnt_ncall;
    129 	mutex_exit(&smb_kdoor_clnt_mutex);
    130 
    131 	rbufp = smb_kdoor_upcall(argp, arg_size, dp, desc_num, rbufsize);
    132 
    133 	mutex_enter(&smb_kdoor_clnt_mutex);
    134 	--smb_kdoor_clnt_ncall;
    135 	cv_signal(&smb_kdoor_clnt_cv);
    136 	mutex_exit(&smb_kdoor_clnt_mutex);
    137 	return (rbufp);
    138 }
    139 
    140 /*
    141  * On success, the result buffer is returned, with rbufsize set to the
    142  * size of the result buffer.  Otherwise, a NULL pointer is returned.
    143  */
    144 static char *
    145 smb_kdoor_upcall(char *argp, size_t arg_size, door_desc_t *dp,
    146     uint_t desc_num, size_t *rbufsize)
    147 {
    148 	door_arg_t door_arg;
    149 	int i;
    150 	int rc;
    151 
    152 	door_arg.data_ptr = argp;
    153 	door_arg.data_size = arg_size;
    154 	door_arg.desc_ptr = dp;
    155 	door_arg.desc_num = desc_num;
    156 	door_arg.rbuf = argp;
    157 	door_arg.rsize = arg_size;
    158 
    159 	for (i = 0; i < SMB_KDOOR_RETRIES; ++i) {
    160 		if ((rc = door_ki_upcall_limited(smb_kdoor_clnt_hd, &door_arg,
    161 		    NULL, SIZE_MAX, 0)) == 0)
    162 			break;
    163 
    164 		if (rc != EAGAIN && rc != EINTR)
    165 			return (NULL);
    166 	}
    167 
    168 	if (rc != 0)
    169 		return (NULL);
    170 
    171 	rc = smb_dr_get_res_stat(door_arg.data_ptr, door_arg.rsize);
    172 	if (rc != SMB_DR_OP_SUCCESS)
    173 		return (NULL);
    174 
    175 	*rbufsize = door_arg.rsize;
    176 	return (door_arg.data_ptr);
    177 }
    178 
    179 /*
    180  * smb_kdoor_clnt_free
    181  *
    182  * This function should be invoked to free both the argument/result door buffer
    183  * regardless of the status of the up-call.
    184  *
    185  * The doorfs allocates a new buffer if the result buffer passed by the client
    186  * is too small. This function will deallocate that buffer as well.
    187  */
    188 void
    189 smb_kdoor_clnt_free(char *argp, size_t arg_size, char *rbufp, size_t rbuf_size)
    190 {
    191 	if (argp)
    192 		kmem_free(argp, arg_size);
    193 
    194 	if (rbufp && rbufp != argp)
    195 		kmem_free(rbufp, rbuf_size);
    196 }
    197