xref: /illumos-gate/usr/src/lib/libds/common/libds.c (revision 125be069be21bcb7b94bd4525c19eb424bc56276)
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 <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/sysevent.h>
34 #include <libsysevent.h>
35 #include <sys/vlds.h>
36 #include "libds.h"
37 
38 #define	PTRTOUINT64(ptr)	((uint64_t)((uintptr_t)(ptr)))
39 static char vlds_device[] =
40 	"/devices/virtual-devices@100/channel-devices@200/"
41 	"virtual-domain-service@0:vlds";
42 
43 typedef struct dslibentry {
44 	ds_hdl_t dsl_hdl;
45 	uint32_t dsl_flags;
46 	uint32_t dsl_tflags;
47 	char *dsl_service;
48 	ds_ops_t dsl_ops;
49 } dslibentry_t;
50 
51 /* dsl_tflags */
52 #define	DSL_ENTRY_INUSE		0x0001	/* handle is currently active */
53 
54 #define	MIN_DSLIB_ENTRIES	64
55 static dslibentry_t *dslibtab;
56 static int ndslib;
57 
58 /*
59  * Lock to protect the dslibtab table.  We only need to protect this
60  * table for those functions which actually look at or modify the table:
61  * service registration (ds_svc_reg/ds_clnt_reg), service unregistration
62  * (ds_hdl_unreg) or during callbacks (ds_recv)
63  */
64 static mutex_t dslib_lock;
65 
66 static int ds_fd = -1;
67 
68 static char *ds_sid_name = "vlds";
69 
70 static evchan_t *ds_evchan;
71 
72 /*
73  * Static functions internal to dslib.
74  */
75 static dslibentry_t *ds_hdl_to_dslibentry(ds_hdl_t hdl);
76 static dslibentry_t *ds_new_dslibentry(void);
77 static uint_t ds_service_count(char *service, boolean_t is_client);
78 static dslibentry_t *ds_lookup_dslibentry(char *service, boolean_t is_client);
79 static dslibentry_t *ds_register_dslibentry(ds_hdl_t hdl, char *service,
80     boolean_t is_client);
81 static void ds_free_dslibentry(dslibentry_t *dsp, int force_unreg);
82 static int ds_recv(sysevent_t *sep, void *arg);
83 static void ds_string_arg(vlds_string_t *dsp, char *str);
84 static int ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags);
85 
86 static dslibentry_t *
87 ds_hdl_to_dslibentry(ds_hdl_t hdl)
88 {
89 	int i;
90 	dslibentry_t *dsp;
91 
92 	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
93 		if (hdl == dsp->dsl_hdl)
94 			return (dsp);
95 	}
96 	return (NULL);
97 }
98 
99 static dslibentry_t *
100 ds_new_dslibentry(void)
101 {
102 	int newndslib;
103 	dslibentry_t *dsp;
104 
105 	if ((dsp = ds_hdl_to_dslibentry(NULL)) != NULL)
106 		return (dsp);
107 
108 	/* double the size */
109 	newndslib = ndslib << 1;
110 	if ((dslibtab = realloc(dslibtab, newndslib * sizeof (dslibentry_t)))
111 	    == NULL)
112 		return (NULL);
113 	dsp = &dslibtab[ndslib];
114 	(void) memset(dsp, 0, (newndslib - ndslib) * sizeof (dslibentry_t));
115 	ndslib = newndslib;
116 	return (dsp);
117 }
118 
119 static uint_t
120 ds_service_count(char *service, boolean_t is_client)
121 {
122 	int i;
123 	dslibentry_t *dsp;
124 	uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
125 	uint_t count = 0;
126 
127 	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
128 		if (dsp->dsl_hdl != NULL &&
129 		    strcmp(dsp->dsl_service, service) == 0 &&
130 		    (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
131 			count++;
132 		}
133 	}
134 	return (count);
135 }
136 
137 static dslibentry_t *
138 ds_lookup_dslibentry(char *service, boolean_t is_client)
139 {
140 	int i;
141 	dslibentry_t *dsp;
142 	uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
143 
144 	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
145 		if (dsp->dsl_hdl != NULL &&
146 		    strcmp(dsp->dsl_service, service) == 0 &&
147 		    (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
148 			return (dsp);
149 		}
150 	}
151 	return (NULL);
152 }
153 
154 static dslibentry_t *
155 ds_register_dslibentry(ds_hdl_t hdl, char *service, boolean_t is_client)
156 {
157 	dslibentry_t *dsp, *orig_dsp;
158 
159 	if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
160 		dsp->dsl_tflags |= DSL_ENTRY_INUSE;
161 		return (dsp);
162 	}
163 
164 	if ((orig_dsp = ds_lookup_dslibentry(service, is_client)) == NULL) {
165 		return (NULL);
166 	}
167 
168 	if ((orig_dsp->dsl_tflags & DSL_ENTRY_INUSE) == 0) {
169 		/* use the original structure entry */
170 		orig_dsp->dsl_tflags |= DSL_ENTRY_INUSE;
171 		orig_dsp->dsl_hdl = hdl;
172 		return (orig_dsp);
173 	}
174 
175 	/* allocate a new structure entry */
176 	if ((dsp = ds_new_dslibentry()) == NULL)
177 		return (NULL);
178 
179 	*dsp = *orig_dsp;
180 	dsp->dsl_service = strdup(orig_dsp->dsl_service);
181 	dsp->dsl_hdl = hdl;
182 	return (dsp);
183 }
184 
185 /*
186  * Want to leave an entry in the dslib table even though all the
187  * handles may have been unregistered for it.
188  */
189 static void
190 ds_free_dslibentry(dslibentry_t *dsp, int force_unreg)
191 {
192 	uint_t nhdls;
193 
194 	/*
195 	 * Find out if we have 1 or 2 or more handles for the given
196 	 * service.  Having one implies that we want to leave the entry
197 	 * intact but marked as not in use unless this is a ds_unreg_hdl
198 	 * (force_unreg is true).
199 	 */
200 	nhdls = ds_service_count(dsp->dsl_service,
201 	    (dsp->dsl_flags & VLDS_REG_CLIENT) != 0);
202 
203 	if ((nhdls == 1 && force_unreg) || nhdls >= 2) {
204 		dsp->dsl_hdl = NULL;
205 		if (dsp->dsl_service) {
206 			free(dsp->dsl_service);
207 		}
208 		(void) memset(dsp, 0, sizeof (dslibentry_t));
209 	} else if (nhdls == 1) {
210 		dsp->dsl_tflags &= ~DSL_ENTRY_INUSE;
211 	}
212 }
213 
214 /*ARGSUSED*/
215 static int
216 ds_recv(sysevent_t *sep, void *arg)
217 {
218 	nvlist_t *nvl;
219 	uint64_t hdl;
220 	ds_ver_t ver;
221 	ds_domain_hdl_t dhdl;
222 	uchar_t *bufp;
223 	boolean_t is_client;
224 	uint_t buflen;
225 	char *subclass;
226 	char *servicep;
227 	dslibentry_t *dsp;
228 	ds_cb_arg_t cb_arg;
229 
230 	subclass = sysevent_get_subclass_name(sep);
231 	if (sysevent_get_attr_list(sep, &nvl) != 0) {
232 		return (0);
233 	}
234 
235 	if (nvlist_lookup_uint64(nvl, VLDS_HDL, &hdl) == 0) {
236 		if (strcmp(subclass, ESC_VLDS_REGISTER) == 0) {
237 			void (*reg_cb)(ds_hdl_t, ds_cb_arg_t, ds_ver_t *,
238 			    ds_domain_hdl_t) = NULL;
239 
240 			if (nvlist_lookup_string(nvl, VLDS_SERVICE_ID,
241 			    &servicep) == 0 &&
242 			    nvlist_lookup_boolean_value(nvl, VLDS_ISCLIENT,
243 			    &is_client) == 0) {
244 				(void) mutex_lock(&dslib_lock);
245 				if ((dsp = ds_register_dslibentry(hdl,
246 				    servicep, is_client)) != NULL) {
247 					reg_cb = dsp->dsl_ops.ds_reg_cb;
248 					cb_arg = dsp->dsl_ops.cb_arg;
249 				}
250 				(void) mutex_unlock(&dslib_lock);
251 				if (reg_cb != NULL &&
252 				    nvlist_lookup_uint64(nvl, VLDS_DOMAIN_HDL,
253 				    &dhdl) == 0 &&
254 				    nvlist_lookup_uint16(nvl, VLDS_VER_MAJOR,
255 				    &ver.major) == 0 &&
256 				    nvlist_lookup_uint16(nvl, VLDS_VER_MINOR,
257 				    &ver.minor) == 0) {
258 					(reg_cb)((ds_hdl_t)hdl, cb_arg, &ver,
259 					    dhdl);
260 				}
261 			}
262 		} else if (strcmp(subclass, ESC_VLDS_UNREGISTER) == 0) {
263 			void (*unreg_cb)(ds_hdl_t, ds_cb_arg_t) = NULL;
264 
265 			(void) mutex_lock(&dslib_lock);
266 			if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
267 				unreg_cb = dsp->dsl_ops.ds_unreg_cb;
268 				cb_arg = dsp->dsl_ops.cb_arg;
269 				ds_free_dslibentry(dsp, 0);
270 			}
271 			(void) mutex_unlock(&dslib_lock);
272 			if (unreg_cb != NULL) {
273 				(unreg_cb)((ds_hdl_t)hdl, cb_arg);
274 			}
275 		} else if (strcmp(subclass, ESC_VLDS_DATA) == 0) {
276 			void (*data_cb)(ds_hdl_t, ds_cb_arg_t, void *,
277 			    size_t) = NULL;
278 
279 			(void) mutex_lock(&dslib_lock);
280 			if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
281 				data_cb = dsp->dsl_ops.ds_data_cb;
282 				cb_arg = dsp->dsl_ops.cb_arg;
283 			}
284 			(void) mutex_unlock(&dslib_lock);
285 			if (data_cb != NULL &&
286 			    nvlist_lookup_byte_array(nvl, VLDS_DATA, &bufp,
287 			    &buflen) == 0) {
288 				(data_cb)((ds_hdl_t)hdl, cb_arg, bufp, buflen);
289 			}
290 		}
291 	}
292 	nvlist_free(nvl);
293 	return (0);
294 }
295 
296 static void
297 ds_string_arg(vlds_string_t *dsp, char *str)
298 {
299 	if (str == NULL) {
300 		dsp->vlds_strp = NULL;
301 		dsp->vlds_strlen = 0;
302 	} else {
303 		dsp->vlds_strp = PTRTOUINT64(str);
304 		dsp->vlds_strlen = strlen(str) + 1;
305 	}
306 }
307 
308 static int
309 ds_init_sysev(void)
310 {
311 	char evchan_name[MAX_CHNAME_LEN];
312 
313 	(void) sprintf(evchan_name, VLDS_SYSEV_CHAN_FMT, (int)getpid());
314 	if (sysevent_evc_bind(evchan_name, &ds_evchan, 0) != 0) {
315 		return (errno);
316 	}
317 	if (sysevent_evc_subscribe(ds_evchan, ds_sid_name, EC_VLDS,
318 	    ds_recv, NULL, 0) != 0) {
319 		sysevent_evc_unbind(ds_evchan);
320 		ds_evchan = NULL;
321 		return (errno);
322 	}
323 	return (0);
324 }
325 
326 int
327 ds_init(void)
328 {
329 	if (ds_fd >= 0)
330 		return (0);
331 
332 	if ((ds_fd = open(vlds_device, 0)) < 0)
333 		return (errno);
334 
335 	if (dslibtab == NULL) {
336 		dslibtab = malloc(sizeof (dslibentry_t) * MIN_DSLIB_ENTRIES);
337 		if (dslibtab == NULL)
338 			return (errno = ENOMEM);
339 		ndslib = MIN_DSLIB_ENTRIES;
340 		(void) memset(dslibtab, 0, sizeof (dslibentry_t) * ndslib);
341 	}
342 
343 	(void) mutex_init(&dslib_lock, USYNC_THREAD, NULL);
344 	return (0);
345 }
346 
347 static int
348 ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags)
349 {
350 	dslibentry_t *dsp;
351 	vlds_svc_reg_arg_t vlds_arg;
352 	vlds_cap_t vlds_cap;
353 	vlds_ver_t vlds_vers[VLDS_MAX_VERS];
354 	uint64_t hdl_arg;
355 	ds_hdl_t hdl;
356 	uint_t nhdls;
357 	int i;
358 
359 	if (cap == NULL || ops == NULL || cap->svc_id == NULL ||
360 	    cap->vers == NULL || (flags & (~VLDS_REG_CLIENT)) != 0) {
361 		return (errno = EINVAL);
362 	}
363 
364 	if (cap->nvers > VLDS_MAX_VERS) {
365 		return (errno = EINVAL);
366 	}
367 
368 	if (ds_fd < 0 && (errno = ds_init()) != 0) {
369 		return (errno);
370 	}
371 
372 	if (ds_hdl_lookup(cap->svc_id, (flags & VLDS_REG_CLIENT), NULL, 1,
373 	    &nhdls) == 0 && nhdls == 1) {
374 		return (errno = EALREADY);
375 	}
376 
377 	(void) mutex_lock(&dslib_lock);
378 	if ((dsp = ds_new_dslibentry()) == NULL) {
379 		(void) mutex_unlock(&dslib_lock);
380 		return (errno = ENOMEM);
381 	}
382 
383 	/* Setup device driver capability structure. */
384 
385 	/* service string */
386 	ds_string_arg(&vlds_cap.vlds_service, cap->svc_id);
387 
388 	/* version array */
389 	for (i = 0; i < cap->nvers; i++) {
390 		vlds_vers[i].vlds_major = cap->vers[i].major;
391 		vlds_vers[i].vlds_minor = cap->vers[i].minor;
392 	}
393 	vlds_cap.vlds_versp = PTRTOUINT64(vlds_vers);
394 	vlds_cap.vlds_nver = cap->nvers;
395 
396 	/*
397 	 * Format args for VLDS_SVC_REG ioctl.
398 	 */
399 
400 	vlds_arg.vlds_capp = PTRTOUINT64(&vlds_cap);
401 
402 	/* op flags */
403 	if (ops->ds_reg_cb != NULL)
404 		flags |= VLDS_REGCB_VALID;
405 	if (ops->ds_unreg_cb != NULL)
406 		flags |= VLDS_UNREGCB_VALID;
407 	if (ops->ds_data_cb != NULL)
408 		flags |= VLDS_DATACB_VALID;
409 	vlds_arg.vlds_reg_flags = flags;
410 
411 	/* returned handle */
412 	vlds_arg.vlds_hdlp = PTRTOUINT64(&hdl_arg);
413 
414 	if (ioctl(ds_fd, VLDS_SVC_REG, &vlds_arg) < 0) {
415 		(void) mutex_unlock(&dslib_lock);
416 		return (errno);
417 	}
418 
419 	/*
420 	 * Setup user callback sysevent channel.
421 	 */
422 	if ((flags & VLDS_ANYCB_VALID) != 0 && ds_evchan == NULL &&
423 	    ds_init_sysev() != 0) {
424 		(void) mutex_unlock(&dslib_lock);
425 		(void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
426 		return (errno);
427 	}
428 
429 	hdl = hdl_arg;
430 
431 	/*
432 	 * Set entry values in dslibtab.
433 	 */
434 	dsp->dsl_hdl = hdl;
435 	dsp->dsl_flags = flags;
436 	dsp->dsl_tflags = 0;
437 	dsp->dsl_service = strdup(cap->svc_id);
438 	dsp->dsl_ops = *ops;
439 	(void) mutex_unlock(&dslib_lock);
440 	return (0);
441 }
442 
443 /*
444  * Registers a service provider.  Kicks off the handshake with other
445  * domain(s) to announce servce.  Callback events are as described above.
446  */
447 int
448 ds_svc_reg(ds_capability_t *cap, ds_ops_t *ops)
449 {
450 	return (ds_register(cap, ops, 0));
451 }
452 
453 /*
454  * Registers interest in a service from a specific domain.  When that
455  * service is registered, the register callback is invoked.  When that
456  * service is unregistered, the unregister callback is invoked.  When
457  * data is received, the receive data callback is invoked.
458  */
459 int
460 ds_clnt_reg(ds_capability_t *cap, ds_ops_t *ops)
461 {
462 	return (ds_register(cap, ops, VLDS_REG_CLIENT));
463 }
464 
465 /*
466  * Given a service name and type, returns the existing handle(s), if
467  * one or more exist.  This could be used to poll for the connection being
468  * registered or unregistered, rather than using the register/unregister
469  * callbacks.
470  */
471 int
472 ds_hdl_lookup(char *service, boolean_t is_client, ds_hdl_t *hdlsp,
473     uint_t maxhdls, uint_t *nhdlsp)
474 {
475 	vlds_hdl_lookup_arg_t vlds_arg;
476 	uint64_t nhdls_arg;
477 
478 	errno = 0;
479 	if (ds_fd < 0) {
480 		return (errno = EBADF);
481 	}
482 
483 	if (service == NULL) {
484 		return (errno = EINVAL);
485 	}
486 
487 	ds_string_arg(&vlds_arg.vlds_service, service);
488 	vlds_arg.vlds_isclient = is_client ? VLDS_REG_CLIENT : 0;
489 	vlds_arg.vlds_hdlsp = PTRTOUINT64(hdlsp);
490 	vlds_arg.vlds_maxhdls = maxhdls;
491 	vlds_arg.vlds_nhdlsp = PTRTOUINT64(&nhdls_arg);
492 
493 	if (ioctl(ds_fd, VLDS_HDL_LOOKUP, &vlds_arg) < 0) {
494 		return (errno);
495 	}
496 
497 	*nhdlsp = nhdls_arg;
498 	return (0);
499 }
500 
501 /*
502  * Given a handle, return its associated domain.
503  */
504 int
505 ds_domain_lookup(ds_hdl_t hdl, ds_domain_hdl_t *dhdlp)
506 {
507 	vlds_dmn_lookup_arg_t vlds_arg;
508 	uint64_t dhdl_arg;
509 
510 	if (ds_fd < 0) {
511 		return (errno = EBADF);
512 	}
513 
514 	vlds_arg.vlds_hdl = hdl;
515 	vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
516 
517 	if (ioctl(ds_fd, VLDS_DMN_LOOKUP, &vlds_arg) < 0) {
518 		return (errno);
519 	}
520 
521 	if (dhdlp) {
522 		*dhdlp = dhdl_arg;
523 	}
524 
525 	return (0);
526 }
527 
528 /*
529  * Unregisters either a service or an interest in that service
530  * indicated by the supplied handle.
531  */
532 int
533 ds_unreg_hdl(ds_hdl_t hdl)
534 {
535 	dslibentry_t *dsp;
536 	vlds_unreg_hdl_arg_t vlds_arg;
537 
538 	(void) mutex_lock(&dslib_lock);
539 	if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
540 		ds_free_dslibentry(dsp, 1);
541 	}
542 	(void) mutex_unlock(&dslib_lock);
543 
544 	if (ds_fd >= 0) {
545 		vlds_arg.vlds_hdl = hdl;
546 		(void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
547 	}
548 
549 	return (0);
550 }
551 
552 /*
553  * Send data to the appropriate service provider or client
554  * indicated by the provided handle.  The sender will block
555  * until the message has been sent.  There is no guarantee
556  * that multiple calls to ds_send_msg by the same thread
557  * will result in the data showing up at the receiver in
558  * the same order as sent.  If multiple messages are required,
559  * it will be up to the sender and receiver to implement a
560  * protocol.
561  */
562 int
563 ds_send_msg(ds_hdl_t hdl, void *buf, size_t buflen)
564 {
565 	vlds_send_msg_arg_t vlds_arg;
566 
567 	if (ds_fd < 0) {
568 		return (errno = EBADF);
569 	}
570 
571 	vlds_arg.vlds_hdl = hdl;
572 	vlds_arg.vlds_bufp = PTRTOUINT64(buf);
573 	vlds_arg.vlds_buflen = buflen;
574 
575 	if (ioctl(ds_fd, VLDS_SEND_MSG, &vlds_arg) < 0) {
576 		return (errno);
577 	}
578 
579 	return (0);
580 }
581 
582 /*
583  * Receive data from the appropriate service provider or client
584  * indicated by the provided handle.  The sender will block
585  * until a message has been received.
586  */
587 int
588 ds_recv_msg(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen)
589 {
590 	vlds_recv_msg_arg_t vlds_arg;
591 	uint64_t msglen_arg;
592 
593 	if (ds_fd < 0) {
594 		return (errno = EBADF);
595 	}
596 
597 	vlds_arg.vlds_hdl = hdl;
598 	vlds_arg.vlds_bufp = PTRTOUINT64(buf);
599 	vlds_arg.vlds_buflen = buflen;
600 	vlds_arg.vlds_msglenp = PTRTOUINT64(&msglen_arg);
601 
602 	if (ioctl(ds_fd, VLDS_RECV_MSG, &vlds_arg) < 0) {
603 		if (errno == EFBIG && msglen) {
604 			*msglen = msglen_arg;
605 		}
606 		return (errno);
607 	}
608 
609 	if (msglen) {
610 		*msglen = msglen_arg;
611 	}
612 
613 	return (0);
614 }
615 
616 int
617 ds_isready(ds_hdl_t hdl, boolean_t *is_ready)
618 {
619 	vlds_hdl_isready_arg_t vlds_arg;
620 	uint64_t is_ready_arg;
621 
622 	if (ds_fd < 0) {
623 		return (errno = EBADF);
624 	}
625 
626 	vlds_arg.vlds_hdl = hdl;
627 	vlds_arg.vlds_isreadyp = PTRTOUINT64(&is_ready_arg);
628 
629 	if (ioctl(ds_fd, VLDS_HDL_ISREADY, &vlds_arg) < 0) {
630 		return (errno);
631 	}
632 
633 	*is_ready = (is_ready_arg != 0);
634 	return (0);
635 }
636 
637 /*
638  * Given a domain name, return its associated domain handle.
639  */
640 int
641 ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp)
642 {
643 	vlds_dom_nam2hdl_arg_t vlds_arg;
644 	uint64_t dhdl_arg;
645 
646 	if (ds_fd < 0) {
647 		return (errno = EBADF);
648 	}
649 
650 	ds_string_arg(&vlds_arg.vlds_domain_name, domain_name);
651 	vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
652 
653 	if (ioctl(ds_fd, VLDS_DOM_NAM2HDL, &vlds_arg) < 0) {
654 		return (errno);
655 	}
656 
657 	if (dhdlp) {
658 		*dhdlp = dhdl_arg;
659 	}
660 
661 	return (0);
662 }
663 
664 /*
665  * Given a domain handle, return its associated domain name.
666  */
667 int
668 ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char *domain_name, uint_t maxnamlen)
669 {
670 	vlds_dom_hdl2nam_arg_t vlds_arg;
671 
672 	if (ds_fd < 0) {
673 		return (errno = EBADF);
674 	}
675 
676 	vlds_arg.vlds_dhdl = dhdl;
677 	vlds_arg.vlds_domain_name.vlds_strp = PTRTOUINT64(domain_name);
678 	vlds_arg.vlds_domain_name.vlds_strlen = maxnamlen;
679 
680 	if (ioctl(ds_fd, VLDS_DOM_HDL2NAM, &vlds_arg) < 0) {
681 		return (errno);
682 	}
683 
684 	return (0);
685 }
686 
687 void
688 ds_unreg_svc(char *service, boolean_t is_client)
689 {
690 	ds_hdl_t hdl;
691 	uint_t nhdls;
692 
693 	while (ds_hdl_lookup(service, is_client, &hdl, 1, &nhdls) == 0 &&
694 	    nhdls == 1) {
695 		(void) ds_unreg_hdl(hdl);
696 	}
697 }
698 
699 void
700 ds_fini(void)
701 {
702 	int i;
703 	dslibentry_t *dsp;
704 
705 	if (ds_fd >= 0) {
706 		(void) close(ds_fd);
707 		ds_fd = -1;
708 	}
709 	if (ds_evchan) {
710 		(void) sysevent_evc_unsubscribe(ds_evchan, ds_sid_name);
711 		(void) sysevent_evc_unbind(ds_evchan);
712 		ds_evchan = NULL;
713 	}
714 	if (ndslib > 0) {
715 		(void) mutex_lock(&dslib_lock);
716 		for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
717 			if (dsp->dsl_hdl == NULL)
718 				continue;
719 			if (dsp->dsl_service) {
720 				free(dsp->dsl_service);
721 			}
722 		}
723 		free(dslibtab);
724 		ndslib = 0;
725 		dslibtab = NULL;
726 		(void) mutex_unlock(&dslib_lock);
727 		(void) mutex_destroy(&dslib_lock);
728 	}
729 }
730