xref: /illumos-gate/usr/src/uts/common/io/devpool.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/file.h>
31 #include <sys/errno.h>
32 #include <sys/open.h>
33 #include <sys/cred.h>
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/stat.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/policy.h>
40 #include <sys/pool.h>
41 #include <sys/pool_impl.h>
42 
43 /*
44  * The kernel pools subsystem is accessed and manipulated through the pool
45  * device, which has two minor nodes /dev/pool, and /dev/poolctl.  User
46  * processes can comminicate with pools through ioctls on these devices.
47  *
48  * The poolctl device (POOL_CTL_PARENT) can be used to modify and take
49  * snapshot of the current configuration.  Only one process on the system
50  * can have it open at any given time.  This device is also used to enable
51  * or disable pools.  If pools are disabled, the pool driver can be unloaded
52  * and completely removed from the system.
53  *
54  * The pool "info" device (POOL_INFO_PARENT) can only be used to obtain
55  * snapshots of the current configuration and change/query pool bindings.
56  * While some reconfiguration transaction via the poolctl device is in
57  * progress, all processes using this "info" device will be provided with
58  * the snapshot taken at the beginning of that transaction.
59  */
60 
61 #define	POOL_CTL_PARENT		0
62 #define	POOL_INFO_PARENT	1
63 
64 static dev_info_t *pool_devi;	/* pool device information */
65 static int pool_openctl;	/* poolctl device is already open */
66 
67 /*ARGSUSED*/
68 static int
69 pool_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
70 {
71 	int error = DDI_FAILURE;
72 
73 	switch (infocmd) {
74 	case DDI_INFO_DEVT2DEVINFO:
75 		*result = pool_devi;
76 		error = DDI_SUCCESS;
77 		break;
78 	case DDI_INFO_DEVT2INSTANCE:
79 		/*
80 		 * All dev_t's map to the same, single instance.
81 		 */
82 		*result = NULL;
83 		error = DDI_SUCCESS;
84 		break;
85 	default:
86 		break;
87 	}
88 	return (error);
89 }
90 
91 static int
92 pool_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
93 {
94 	int ret = DDI_SUCCESS;
95 
96 	switch (cmd) {
97 	case DDI_DETACH:
98 		pool_lock();
99 		if (pool_state == POOL_ENABLED) {
100 			ret = DDI_FAILURE;
101 			pool_unlock();
102 			break;
103 		}
104 		ddi_remove_minor_node(devi, NULL);
105 		pool_devi = NULL;
106 		pool_unlock();
107 		break;
108 	default:
109 		ret = DDI_FAILURE;
110 	}
111 	return (ret);
112 }
113 
114 static int
115 pool_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
116 {
117 	switch (cmd) {
118 	case DDI_ATTACH:
119 		if (pool_devi != NULL)
120 			return (DDI_FAILURE);
121 		if (ddi_create_minor_node(devi, "poolctl", S_IFCHR,
122 		    POOL_CTL_PARENT, DDI_PSEUDO, 0) == DDI_FAILURE ||
123 		    ddi_create_minor_node(devi, "pool", S_IFCHR,
124 		    POOL_INFO_PARENT, DDI_PSEUDO, 0) == DDI_FAILURE) {
125 			ddi_remove_minor_node(devi, NULL);
126 			return (DDI_FAILURE);
127 		}
128 		pool_devi = devi;
129 		ddi_report_dev(devi);
130 		break;
131 	case DDI_RESUME:
132 		break;
133 	default:
134 		return (DDI_FAILURE);
135 	}
136 	return (DDI_SUCCESS);
137 
138 }
139 
140 /*
141  * There is only one instance of the pool control device, poolctl,
142  * and multiple instances of the pool info device, pool.
143  */
144 /*ARGSUSED*/
145 static int
146 pool_open(dev_t *devp, int flag, int otype, cred_t *credp)
147 {
148 	minor_t minor = getminor(*devp);
149 
150 	if (otype != OTYP_CHR)
151 		return (EINVAL);
152 
153 	switch (minor) {
154 	case POOL_CTL_PARENT:
155 		if (secpolicy_pool(CRED()) != 0)
156 			return (EPERM);
157 		if (pool_lock_intr() != 0)
158 			return (EINTR);
159 		if (pool_openctl == 1) {
160 			pool_unlock();
161 			return (EBUSY);
162 		}
163 		pool_openctl = 1;
164 		pool_unlock();
165 		break;
166 	case POOL_INFO_PARENT:
167 		break;
168 	default:
169 		return (ENXIO);
170 	}
171 	return (0);
172 }
173 
174 /*ARGSUSED*/
175 static int
176 pool_close(dev_t dev, int flag, int otype, cred_t *credp)
177 {
178 	if (otype != OTYP_CHR)
179 		return (EINVAL);
180 	if (getminor(dev) == 0) {
181 		/*
182 		 * We could be closing the poolctl device without finishing
183 		 * the commit transaction first, so do that now.
184 		 */
185 		pool_lock();
186 		(void) pool_commit(0);	/* cannot fail since arg is 0 */
187 		pool_openctl = 0;
188 		pool_unlock();
189 	}
190 	return (0);
191 }
192 
193 /*
194  * Main pool interface.
195  */
196 /* ARGSUSED4 */
197 static int
198 pool_ioctl(dev_t dev, int cmd, intptr_t arg, int  mode, cred_t *credp,
199     int *rvalp)
200 {
201 	pool_xtransfer_t xtransfer;
202 	pool_transfer_t transfer;
203 	pool_destroy_t destroy;
204 	pool_propget_t propget;
205 	pool_propput_t propput;
206 	pool_proprm_t proprm;
207 	pool_status_t status;
208 	pool_dissoc_t dissoc;
209 	pool_create_t create;
210 	pool_assoc_t assoc;
211 	pool_bindq_t bindq;
212 	pool_query_t query;
213 	pool_bind_t bind;
214 #ifdef	_MULTI_DATAMODEL
215 	pool_xtransfer32_t xtransfer32;
216 	pool_propput32_t propput32;
217 	pool_propget32_t propget32;
218 	pool_proprm32_t proprm32;
219 	pool_query32_t query32;
220 #endif	/* _MULTI_DATAMODEL */
221 	char *kbuf = NULL;
222 	size_t kbufsz = 0;
223 	int snapshot = 0;
224 	char *prop_name;
225 	size_t size = 0;
226 	nvlist_t *list;
227 	nvpair_t *pair;
228 	char *listbuf;
229 	minor_t minor;
230 	uint_t model;
231 	id_t *id_buf;
232 	int ret = 0;
233 
234 	model = ddi_model_convert_from(mode & FMODELS);
235 	minor = getminor(dev);
236 
237 	/*
238 	 * Check basic permissions first.
239 	 */
240 	switch (cmd) {
241 	case POOL_STATUS:
242 	case POOL_CREATE:
243 	case POOL_ASSOC:
244 	case POOL_DISSOC:
245 	case POOL_DESTROY:
246 	case POOL_TRANSFER:
247 	case POOL_XTRANSFER:
248 	case POOL_PROPPUT:
249 	case POOL_PROPRM:
250 	case POOL_COMMIT:
251 		if (minor != POOL_CTL_PARENT)
252 			return (EINVAL);
253 		/*FALLTHROUGH*/
254 	case POOL_BIND:
255 		if (secpolicy_pool(CRED()) != 0)
256 			return (EPERM);
257 		break;
258 	}
259 
260 	switch (cmd) {
261 	case POOL_STATUS:
262 		if (ddi_copyin((void *)arg, &status,
263 		    sizeof (pool_status_t), mode) != 0)
264 			return (EFAULT);
265 		if (pool_lock_intr() != 0)
266 			return (EINTR);
267 		ret = pool_status(status.ps_io_state);
268 		pool_unlock();
269 		break;
270 	case POOL_STATUSQ:
271 		/*
272 		 * No need to grab pool_lock() to look at the current state.
273 		 */
274 		status.ps_io_state = pool_state;
275 		if (ddi_copyout(&status, (void *)arg,
276 		    sizeof (pool_status_t), mode) != 0)
277 			return (EFAULT);
278 		break;
279 	case POOL_QUERY:
280 		switch (model) {
281 #ifdef _MULTI_DATAMODEL
282 		case DDI_MODEL_ILP32:
283 			if (ddi_copyin((void *)arg, &query32,
284 			    sizeof (pool_query32_t), mode) != 0)
285 				return (EFAULT);
286 			query.pq_io_bufsize = query32.pq_io_bufsize;
287 			query.pq_io_buf = (char *)(uintptr_t)query32.pq_io_buf;
288 			break;
289 #endif	/* _MULTI_DATAMODEL */
290 		default:
291 		case DDI_MODEL_NONE:
292 			if (ddi_copyin((void *)arg, &query,
293 			    sizeof (pool_query_t), mode) != 0)
294 				return (EFAULT);
295 		}
296 		if (pool_lock_intr() != 0)
297 			return (EINTR);
298 		if (pool_state == POOL_DISABLED) {
299 			pool_unlock();
300 			return (ENOTACTIVE);
301 		}
302 		if (minor != 0 && pool_buf != NULL) {
303 			/*
304 			 * Return last snapshot if some
305 			 * transaction is still in progress
306 			 */
307 			if (kbufsz != 0 && pool_bufsz > kbufsz) {
308 				pool_unlock();
309 				return (ENOMEM);
310 			}
311 			kbuf = pool_buf;
312 			kbufsz = size = pool_bufsz;
313 			snapshot = 1;
314 		} else if (query.pq_io_bufsize != 0) {
315 			kbufsz = query.pq_io_bufsize;
316 			kbuf = kmem_alloc(kbufsz, KM_NOSLEEP);
317 			if (kbuf == NULL) {
318 				pool_unlock();
319 				return (ENOMEM);
320 			}
321 			ret = pool_pack_conf(kbuf, kbufsz, &size);
322 		} else {
323 			ret = pool_pack_conf(NULL, 0, &size);
324 		}
325 		if (ret == 0) {
326 			switch (model) {
327 #ifdef	_MULTI_DATAMODEL
328 			case DDI_MODEL_ILP32:
329 				query32.pq_io_bufsize = size;
330 				if (ddi_copyout((caddr_t)&query32, (void *)arg,
331 				    sizeof (pool_query32_t), mode) != 0)
332 					ret = EFAULT;
333 				break;
334 #endif	/* _MULTI_DATAMODEL */
335 			default:
336 			case DDI_MODEL_NONE:
337 				query.pq_io_bufsize = size;
338 				if (ddi_copyout(&query, (void *)arg,
339 				    sizeof (pool_query_t), mode) != 0)
340 					ret = EFAULT;
341 			}
342 			if (ret == 0 && query.pq_io_buf != NULL &&
343 			    ddi_copyout(kbuf, query.pq_io_buf, size, mode) != 0)
344 				ret = EFAULT;
345 		}
346 		pool_unlock();
347 		if (snapshot == 0)
348 			kmem_free(kbuf, kbufsz);
349 		break;
350 	case POOL_CREATE:
351 		if (ddi_copyin((void *)arg,
352 		    &create, sizeof (pool_create_t), mode) != 0)
353 			return (EFAULT);
354 		if (pool_lock_intr() != 0)
355 			return (EINTR);
356 		ret = pool_create(create.pc_o_type,
357 		    create.pc_o_sub_type, &create.pc_i_id);
358 		pool_unlock();
359 		if (ret == 0 && ddi_copyout(&create, (void *)arg,
360 		    sizeof (pool_create_t), mode) != 0)
361 			ret = EFAULT;
362 		break;
363 	case POOL_ASSOC:
364 		if (ddi_copyin((void *)arg, &assoc,
365 		    sizeof (pool_assoc_t), mode) != 0)
366 			return (EFAULT);
367 		if (pool_lock_intr() != 0)
368 			return (EINTR);
369 		ret = pool_assoc(assoc.pa_o_pool_id,
370 		    assoc.pa_o_id_type, assoc.pa_o_res_id);
371 		pool_unlock();
372 		break;
373 	case POOL_DISSOC:
374 		if (ddi_copyin((void *)arg, &dissoc,
375 		    sizeof (pool_dissoc_t), mode) != 0)
376 			return (EFAULT);
377 		if (pool_lock_intr() != 0)
378 			return (EINTR);
379 		ret = pool_dissoc(dissoc.pd_o_pool_id, dissoc.pd_o_id_type);
380 		pool_unlock();
381 		break;
382 	case POOL_DESTROY:
383 		if (ddi_copyin((void *)arg, &destroy,
384 		    sizeof (pool_destroy_t), mode) != 0)
385 			return (EFAULT);
386 		if (pool_lock_intr() != 0)
387 			return (EINTR);
388 		ret = pool_destroy(destroy.pd_o_type, destroy.pd_o_sub_type,
389 		    destroy.pd_o_id);
390 		pool_unlock();
391 		break;
392 	case POOL_TRANSFER:
393 		if (ddi_copyin((void *)arg, &transfer,
394 		    sizeof (pool_transfer_t), mode) != 0)
395 			return (EFAULT);
396 		if (pool_lock_intr() != 0)
397 			return (EINTR);
398 		ret = pool_transfer(transfer.pt_o_id_type, transfer.pt_o_src_id,
399 		    transfer.pt_o_tgt_id, transfer.pt_o_qty);
400 		pool_unlock();
401 		break;
402 	case POOL_XTRANSFER:
403 		switch (model) {
404 #ifdef _MULTI_DATAMODEL
405 		case DDI_MODEL_ILP32:
406 			if (ddi_copyin((void *)arg, &xtransfer32,
407 			    sizeof (pool_xtransfer32_t), mode) != 0)
408 				return (EFAULT);
409 			xtransfer.px_o_id_type = xtransfer32.px_o_id_type;
410 			xtransfer.px_o_src_id = xtransfer32.px_o_src_id;
411 			xtransfer.px_o_tgt_id = xtransfer32.px_o_tgt_id;
412 			xtransfer.px_o_complist_size =
413 				xtransfer32.px_o_complist_size;
414 			xtransfer.px_o_comp_list =
415 				(id_t *)(uintptr_t)xtransfer32.px_o_comp_list;
416 			break;
417 #endif /* _MULTI_DATAMODEL */
418 		default:
419 		case DDI_MODEL_NONE:
420 			if (ddi_copyin((void *)arg, &xtransfer,
421 			    sizeof (pool_xtransfer_t), mode) != 0)
422 				return (EFAULT);
423 		}
424 		/*
425 		 * Copy in IDs to transfer from the userland
426 		 */
427 		if (xtransfer.px_o_complist_size > POOL_IDLIST_SIZE)
428 			return (EINVAL);
429 		id_buf = kmem_alloc(xtransfer.px_o_complist_size *
430 		    sizeof (id_t), KM_SLEEP);
431 		if (ddi_copyin((void *)xtransfer.px_o_comp_list, id_buf,
432 		    xtransfer.px_o_complist_size * sizeof (id_t), mode) != 0) {
433 			kmem_free(id_buf, xtransfer.px_o_complist_size *
434 			    sizeof (id_t));
435 			return (EFAULT);
436 		}
437 		if (pool_lock_intr() != 0) {
438 			kmem_free(id_buf, xtransfer.px_o_complist_size *
439 			    sizeof (id_t));
440 			return (EINTR);
441 		}
442 		ret = pool_xtransfer(xtransfer.px_o_id_type,
443 		    xtransfer.px_o_src_id, xtransfer.px_o_tgt_id,
444 		    xtransfer.px_o_complist_size, id_buf);
445 		pool_unlock();
446 		kmem_free(id_buf, xtransfer.px_o_complist_size *
447 		    sizeof (id_t));
448 		break;
449 	case POOL_BIND:
450 		if (ddi_copyin((void *)arg, &bind,
451 		    sizeof (pool_bind_t), mode) != 0)
452 			return (EFAULT);
453 		if (pool_lock_intr() != 0)
454 			return (EINTR);
455 		ret = pool_bind(bind.pb_o_pool_id, bind.pb_o_id_type,
456 		    bind.pb_o_id);
457 		pool_unlock();
458 		break;
459 	case POOL_BINDQ:
460 		if (ddi_copyin((void *)arg, &bindq,
461 		    sizeof (pool_bindq_t), mode) != 0) {
462 			return (EFAULT);
463 		}
464 		if (pool_lock_intr() != 0)
465 			return (EINTR);
466 		if ((ret = pool_query_binding(bindq.pb_o_id_type,
467 		    bindq.pb_o_id, &bindq.pb_i_id)) == 0 &&
468 		    ddi_copyout(&bindq, (void *)arg,
469 		    sizeof (pool_bindq_t), mode) != 0)
470 			ret = EFAULT;
471 		pool_unlock();
472 		break;
473 	case POOL_PROPGET:
474 		switch (model) {
475 #ifdef _MULTI_DATAMODEL
476 		case DDI_MODEL_ILP32:
477 			if (ddi_copyin((void *)arg, &propget32,
478 			    sizeof (pool_propget32_t), mode) != 0)
479 				return (EFAULT);
480 			propget.pp_o_id = propget32.pp_o_id;
481 			propget.pp_o_id_type = propget32.pp_o_id_type;
482 			propget.pp_o_id_subtype = propget32.pp_o_id_subtype;
483 			propget.pp_o_prop_name =
484 			    (char *)(uintptr_t)propget32.pp_o_prop_name;
485 			propget.pp_o_prop_name_size =
486 			    propget32.pp_o_prop_name_size;
487 			propget.pp_i_buf =
488 			    (char *)(uintptr_t)propget32.pp_i_buf;
489 			propget.pp_i_bufsize = propget32.pp_i_bufsize;
490 			break;
491 #endif	/* _MULTI_DATAMODEL */
492 		default:
493 		case DDI_MODEL_NONE:
494 			if (ddi_copyin((void *)arg, &propget,
495 			    sizeof (pool_propget_t), mode) != 0)
496 				return (EFAULT);
497 		}
498 		if (propget.pp_o_prop_name_size + 1 > POOL_PROPNAME_SIZE)
499 			return (EINVAL);
500 		prop_name = kmem_alloc(propget.pp_o_prop_name_size + 1,
501 		    KM_SLEEP);
502 		if (ddi_copyin(propget.pp_o_prop_name, prop_name,
503 		    propget.pp_o_prop_name_size + 1, mode) != 0) {
504 			kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
505 			return (EFAULT);
506 		}
507 		list = NULL;
508 		if (pool_lock_intr() != 0) {
509 			kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
510 			return (EINTR);
511 		}
512 		ret = pool_propget(prop_name, propget.pp_o_id_type,
513 		    propget.pp_o_id_subtype, propget.pp_o_id, &list);
514 		pool_unlock();
515 		kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
516 		if (ret != 0)
517 			return (ret);
518 		ret = nvlist_pack(list, &kbuf, &kbufsz, NV_ENCODE_NATIVE, 0);
519 		if (ret != 0) {
520 			nvlist_free(list);
521 			return (ret);
522 		}
523 		switch (model) {
524 #ifdef	_MULTI_DATAMODEL
525 		case DDI_MODEL_ILP32:
526 			propget32.pp_i_bufsize = kbufsz;
527 			if (ddi_copyout((caddr_t)&propget32, (void *)arg,
528 			    sizeof (pool_propget32_t), mode) != 0)
529 				ret = EFAULT;
530 			break;
531 #endif	/* _MULTI_DATAMODEL */
532 		default:
533 		case DDI_MODEL_NONE:
534 			if (ddi_copyout(&propget, (void *)arg,
535 			    sizeof (pool_propget_t), mode) != 0)
536 				ret = EFAULT;
537 		}
538 		if (ret == 0) {
539 			if (propget.pp_i_buf == NULL) {
540 				ret = 0;
541 			} else if (propget.pp_i_bufsize >= kbufsz) {
542 				if (ddi_copyout(kbuf, propget.pp_i_buf,
543 				    kbufsz, mode) != 0)
544 					ret = EFAULT;
545 			} else {
546 				ret = ENOMEM;
547 			}
548 		}
549 		kmem_free(kbuf, kbufsz);
550 		nvlist_free(list);
551 		break;
552 	case POOL_PROPPUT:
553 		switch (model) {
554 #ifdef _MULTI_DATAMODEL
555 		case DDI_MODEL_ILP32:
556 			if (ddi_copyin((void *)arg, &propput32,
557 			    sizeof (pool_propput32_t), mode) != 0)
558 				return (EFAULT);
559 			propput.pp_o_id_type = propput32.pp_o_id_type;
560 			propput.pp_o_id_sub_type = propput32.pp_o_id_sub_type;
561 			propput.pp_o_id = propput32.pp_o_id;
562 			propput.pp_o_bufsize = propput32.pp_o_bufsize;
563 			propput.pp_o_buf =
564 			    (char *)(uintptr_t)propput32.pp_o_buf;
565 			break;
566 #endif	/* _MULTI_DATAMODEL */
567 		default:
568 		case DDI_MODEL_NONE:
569 			if (ddi_copyin((void *)arg, &propput,
570 			    sizeof (pool_propput_t), mode) != 0)
571 				return (EFAULT);
572 		}
573 		if (propput.pp_o_bufsize > POOL_PROPBUF_SIZE)
574 			return (EINVAL);
575 		listbuf = kmem_alloc(propput.pp_o_bufsize, KM_SLEEP);
576 		if (ddi_copyin(propput.pp_o_buf, listbuf,
577 		    propput.pp_o_bufsize, mode) != 0) {
578 			kmem_free(listbuf, propput.pp_o_bufsize);
579 			return (EFAULT);
580 		}
581 		if (nvlist_unpack(listbuf, propput.pp_o_bufsize,
582 			&list, KM_SLEEP) != 0) {
583 			kmem_free(listbuf, propput.pp_o_bufsize);
584 			return (EFAULT);
585 		}
586 		if (pool_lock_intr() != 0) {
587 			nvlist_free(list);
588 			kmem_free(listbuf, propput.pp_o_bufsize);
589 			return (EINTR);
590 		}
591 		/*
592 		 * Extract the nvpair from the list. The list may
593 		 * contain multiple properties.
594 		 */
595 		for (pair = nvlist_next_nvpair(list, NULL); pair != NULL;
596 		    pair = nvlist_next_nvpair(list, pair)) {
597 			if ((ret = pool_propput(propput.pp_o_id_type,
598 			    propput.pp_o_id_sub_type,
599 			    propput.pp_o_id, pair)) != 0)
600 				break;
601 		}
602 		pool_unlock();
603 		nvlist_free(list);
604 		kmem_free(listbuf, propput.pp_o_bufsize);
605 		break;
606 	case POOL_PROPRM:
607 		switch (model) {
608 #ifdef _MULTI_DATAMODEL
609 		case DDI_MODEL_ILP32:
610 			if (ddi_copyin((void *)arg, &proprm32,
611 			    sizeof (pool_proprm32_t), mode) != 0)
612 				return (EFAULT);
613 			proprm.pp_o_id_type = proprm32.pp_o_id_type;
614 			proprm.pp_o_id_sub_type = proprm32.pp_o_id_sub_type;
615 			proprm.pp_o_id = proprm32.pp_o_id;
616 			proprm.pp_o_prop_name_size =
617 			    proprm32.pp_o_prop_name_size;
618 			proprm.pp_o_prop_name =
619 			    (void *)(uintptr_t)proprm32.pp_o_prop_name;
620 			break;
621 #endif	/* _MULTI_DATAMODEL */
622 		default:
623 		case DDI_MODEL_NONE:
624 			if (ddi_copyin((void *)arg, &proprm,
625 			    sizeof (pool_proprm_t), mode) != 0)
626 				return (EFAULT);
627 		}
628 		if (proprm.pp_o_prop_name_size + 1 > POOL_PROPNAME_SIZE)
629 			return (EINVAL);
630 		prop_name = kmem_alloc(proprm.pp_o_prop_name_size + 1,
631 		    KM_SLEEP);
632 		if (ddi_copyin(proprm.pp_o_prop_name, prop_name,
633 		    proprm.pp_o_prop_name_size + 1, mode) != 0) {
634 			kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
635 			return (EFAULT);
636 		}
637 		if (pool_lock_intr() != 0) {
638 			kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
639 			return (EINTR);
640 		}
641 		ret = pool_proprm(proprm.pp_o_id_type,
642 		    proprm.pp_o_id_sub_type, proprm.pp_o_id, prop_name);
643 		pool_unlock();
644 		kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
645 		break;
646 	case POOL_COMMIT:
647 		if (pool_lock_intr() != 0)
648 			return (EINTR);
649 		ret = pool_commit((int)arg);
650 		pool_unlock();
651 		break;
652 	default:
653 		return (EINVAL);
654 	}
655 	return (ret);
656 }
657 
658 static struct cb_ops pool_cb_ops = {
659 	pool_open,		/* open */
660 	pool_close,		/* close */
661 	nodev,			/* strategy */
662 	nodev,			/* print */
663 	nodev,			/* dump */
664 	nodev,			/* read */
665 	nodev,			/* write */
666 	pool_ioctl,		/* ioctl */
667 	nodev,			/* devmap */
668 	nodev,			/* mmap */
669 	nodev,			/* segmap */
670 	nochpoll,		/* poll */
671 	nodev,			/* cb_prop_op */
672 	(struct streamtab *)0,	/* streamtab */
673 	D_NEW | D_MP		/* driver compatibility flags */
674 };
675 
676 static struct dev_ops pool_ops = {
677 	DEVO_REV,		/* devo_rev */
678 	0,			/* refcnt */
679 	pool_info,		/* info */
680 	nulldev,		/* identify */
681 	nulldev,		/* probe */
682 	pool_attach,		/* attach */
683 	pool_detach,		/* detach */
684 	nodev,			/* reset */
685 	&pool_cb_ops,		/* cb_ops */
686 	(struct bus_ops *)NULL,	/* bus_ops */
687 	nulldev			/* power */
688 };
689 
690 /*
691  * Module linkage information for the kernel
692  */
693 static struct modldrv modldrv = {
694 	&mod_driverops,		/* this one is a pseudo driver */
695 	"pool driver %I%",
696 	&pool_ops
697 };
698 
699 static struct modlinkage modlinkage = {
700 	MODREV_1,
701 	&modldrv,
702 	NULL
703 };
704 
705 int
706 _init(void)
707 {
708 	return (mod_install(&modlinkage));
709 }
710 
711 int
712 _fini(void)
713 {
714 	return (mod_remove(&modlinkage));
715 }
716 
717 int
718 _info(struct modinfo *modinfop)
719 {
720 	return (mod_info(&modlinkage, modinfop));
721 }
722