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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/errno.h>
33 #include <sys/modctl.h>
36 #include <sys/sunddi.h>
37 #include <sys/policy.h>
39 #include <sys/pool_impl.h>
42 * The kernel pools subsystem is accessed and manipulated through the pool
43 * device, which has two minor nodes /dev/pool, and /dev/poolctl. User
44 * processes can comminicate with pools through ioctls on these devices.
46 * The poolctl device (POOL_CTL_PARENT) can be used to modify and take
47 * snapshot of the current configuration. Only one process on the system
48 * can have it open at any given time. This device is also used to enable
49 * or disable pools. If pools are disabled, the pool driver can be unloaded
50 * and completely removed from the system.
52 * The pool "info" device (POOL_INFO_PARENT) can only be used to obtain
53 * snapshots of the current configuration and change/query pool bindings.
54 * While some reconfiguration transaction via the poolctl device is in
55 * progress, all processes using this "info" device will be provided with
56 * the snapshot taken at the beginning of that transaction.
59 #define POOL_CTL_PARENT 0
60 #define POOL_INFO_PARENT 1
62 static dev_info_t
*pool_devi
; /* pool device information */
63 static int pool_openctl
; /* poolctl device is already open */
67 pool_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
69 int error
= DDI_FAILURE
;
72 case DDI_INFO_DEVT2DEVINFO
:
76 case DDI_INFO_DEVT2INSTANCE
:
78 * All dev_t's map to the same, single instance.
90 pool_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
92 int ret
= DDI_SUCCESS
;
97 if (pool_state
== POOL_ENABLED
) {
102 ddi_remove_minor_node(devi
, NULL
);
113 pool_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
117 if (pool_devi
!= NULL
)
118 return (DDI_FAILURE
);
119 if (ddi_create_minor_node(devi
, "poolctl", S_IFCHR
,
120 POOL_CTL_PARENT
, DDI_PSEUDO
, 0) == DDI_FAILURE
||
121 ddi_create_minor_node(devi
, "pool", S_IFCHR
,
122 POOL_INFO_PARENT
, DDI_PSEUDO
, 0) == DDI_FAILURE
) {
123 ddi_remove_minor_node(devi
, NULL
);
124 return (DDI_FAILURE
);
127 ddi_report_dev(devi
);
132 return (DDI_FAILURE
);
134 return (DDI_SUCCESS
);
139 * There is only one instance of the pool control device, poolctl,
140 * and multiple instances of the pool info device, pool.
144 pool_open(dev_t
*devp
, int flag
, int otype
, cred_t
*credp
)
146 minor_t minor
= getminor(*devp
);
148 if (otype
!= OTYP_CHR
)
152 case POOL_CTL_PARENT
:
153 if (secpolicy_pool(CRED()) != 0)
155 if (pool_lock_intr() != 0)
157 if (pool_openctl
== 1) {
164 case POOL_INFO_PARENT
:
174 pool_close(dev_t dev
, int flag
, int otype
, cred_t
*credp
)
176 if (otype
!= OTYP_CHR
)
178 if (getminor(dev
) == 0) {
180 * We could be closing the poolctl device without finishing
181 * the commit transaction first, so do that now.
184 (void) pool_commit(0); /* cannot fail since arg is 0 */
192 * Main pool interface.
196 pool_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
199 pool_xtransfer_t xtransfer
;
200 pool_transfer_t transfer
;
201 pool_destroy_t destroy
;
202 pool_propget_t propget
;
203 pool_propput_t propput
;
204 pool_proprm_t proprm
;
205 pool_status_t status
;
206 pool_dissoc_t dissoc
;
207 pool_create_t create
;
212 #ifdef _MULTI_DATAMODEL
213 pool_xtransfer32_t xtransfer32
;
214 pool_propput32_t propput32
;
215 pool_propget32_t propget32
;
216 pool_proprm32_t proprm32
;
217 pool_query32_t query32
;
218 #endif /* _MULTI_DATAMODEL */
232 model
= ddi_model_convert_from(mode
& FMODELS
);
233 minor
= getminor(dev
);
236 * Check basic permissions first.
249 if (minor
!= POOL_CTL_PARENT
)
253 if (secpolicy_pool(CRED()) != 0)
260 if (ddi_copyin((void *)arg
, &status
,
261 sizeof (pool_status_t
), mode
) != 0)
263 if (pool_lock_intr() != 0)
265 ret
= pool_status(status
.ps_io_state
);
270 * No need to grab pool_lock() to look at the current state.
272 status
.ps_io_state
= pool_state
;
273 if (ddi_copyout(&status
, (void *)arg
,
274 sizeof (pool_status_t
), mode
) != 0)
279 #ifdef _MULTI_DATAMODEL
280 case DDI_MODEL_ILP32
:
281 if (ddi_copyin((void *)arg
, &query32
,
282 sizeof (pool_query32_t
), mode
) != 0)
284 query
.pq_io_bufsize
= query32
.pq_io_bufsize
;
285 query
.pq_io_buf
= (char *)(uintptr_t)query32
.pq_io_buf
;
287 #endif /* _MULTI_DATAMODEL */
290 if (ddi_copyin((void *)arg
, &query
,
291 sizeof (pool_query_t
), mode
) != 0)
294 if (pool_lock_intr() != 0)
296 if (pool_state
== POOL_DISABLED
) {
300 if (minor
!= 0 && pool_buf
!= NULL
) {
302 * Return last snapshot if some
303 * transaction is still in progress
305 if (kbufsz
!= 0 && pool_bufsz
> kbufsz
) {
310 kbufsz
= size
= pool_bufsz
;
312 } else if (query
.pq_io_bufsize
!= 0) {
313 kbufsz
= query
.pq_io_bufsize
;
314 kbuf
= kmem_alloc(kbufsz
, KM_NOSLEEP
);
319 ret
= pool_pack_conf(kbuf
, kbufsz
, &size
);
321 ret
= pool_pack_conf(NULL
, 0, &size
);
325 #ifdef _MULTI_DATAMODEL
326 case DDI_MODEL_ILP32
:
327 query32
.pq_io_bufsize
= size
;
328 if (ddi_copyout((caddr_t
)&query32
, (void *)arg
,
329 sizeof (pool_query32_t
), mode
) != 0)
332 #endif /* _MULTI_DATAMODEL */
335 query
.pq_io_bufsize
= size
;
336 if (ddi_copyout(&query
, (void *)arg
,
337 sizeof (pool_query_t
), mode
) != 0)
340 if (ret
== 0 && query
.pq_io_buf
!= NULL
&&
341 ddi_copyout(kbuf
, query
.pq_io_buf
, size
, mode
) != 0)
346 kmem_free(kbuf
, kbufsz
);
349 if (ddi_copyin((void *)arg
,
350 &create
, sizeof (pool_create_t
), mode
) != 0)
352 if (pool_lock_intr() != 0)
354 ret
= pool_create(create
.pc_o_type
,
355 create
.pc_o_sub_type
, &create
.pc_i_id
);
357 if (ret
== 0 && ddi_copyout(&create
, (void *)arg
,
358 sizeof (pool_create_t
), mode
) != 0)
362 if (ddi_copyin((void *)arg
, &assoc
,
363 sizeof (pool_assoc_t
), mode
) != 0)
365 if (pool_lock_intr() != 0)
367 ret
= pool_assoc(assoc
.pa_o_pool_id
,
368 assoc
.pa_o_id_type
, assoc
.pa_o_res_id
);
372 if (ddi_copyin((void *)arg
, &dissoc
,
373 sizeof (pool_dissoc_t
), mode
) != 0)
375 if (pool_lock_intr() != 0)
377 ret
= pool_dissoc(dissoc
.pd_o_pool_id
, dissoc
.pd_o_id_type
);
381 if (ddi_copyin((void *)arg
, &destroy
,
382 sizeof (pool_destroy_t
), mode
) != 0)
384 if (pool_lock_intr() != 0)
386 ret
= pool_destroy(destroy
.pd_o_type
, destroy
.pd_o_sub_type
,
391 if (ddi_copyin((void *)arg
, &transfer
,
392 sizeof (pool_transfer_t
), mode
) != 0)
394 if (pool_lock_intr() != 0)
396 ret
= pool_transfer(transfer
.pt_o_id_type
, transfer
.pt_o_src_id
,
397 transfer
.pt_o_tgt_id
, transfer
.pt_o_qty
);
402 #ifdef _MULTI_DATAMODEL
403 case DDI_MODEL_ILP32
:
404 if (ddi_copyin((void *)arg
, &xtransfer32
,
405 sizeof (pool_xtransfer32_t
), mode
) != 0)
407 xtransfer
.px_o_id_type
= xtransfer32
.px_o_id_type
;
408 xtransfer
.px_o_src_id
= xtransfer32
.px_o_src_id
;
409 xtransfer
.px_o_tgt_id
= xtransfer32
.px_o_tgt_id
;
410 xtransfer
.px_o_complist_size
=
411 xtransfer32
.px_o_complist_size
;
412 xtransfer
.px_o_comp_list
=
413 (id_t
*)(uintptr_t)xtransfer32
.px_o_comp_list
;
415 #endif /* _MULTI_DATAMODEL */
418 if (ddi_copyin((void *)arg
, &xtransfer
,
419 sizeof (pool_xtransfer_t
), mode
) != 0)
423 * Copy in IDs to transfer from the userland
425 if (xtransfer
.px_o_complist_size
> POOL_IDLIST_SIZE
)
427 id_buf
= kmem_alloc(xtransfer
.px_o_complist_size
*
428 sizeof (id_t
), KM_SLEEP
);
429 if (ddi_copyin((void *)xtransfer
.px_o_comp_list
, id_buf
,
430 xtransfer
.px_o_complist_size
* sizeof (id_t
), mode
) != 0) {
431 kmem_free(id_buf
, xtransfer
.px_o_complist_size
*
435 if (pool_lock_intr() != 0) {
436 kmem_free(id_buf
, xtransfer
.px_o_complist_size
*
440 ret
= pool_xtransfer(xtransfer
.px_o_id_type
,
441 xtransfer
.px_o_src_id
, xtransfer
.px_o_tgt_id
,
442 xtransfer
.px_o_complist_size
, id_buf
);
444 kmem_free(id_buf
, xtransfer
.px_o_complist_size
*
448 if (ddi_copyin((void *)arg
, &bind
,
449 sizeof (pool_bind_t
), mode
) != 0)
451 if (pool_lock_intr() != 0)
453 ret
= pool_bind(bind
.pb_o_pool_id
, bind
.pb_o_id_type
,
458 if (ddi_copyin((void *)arg
, &bindq
,
459 sizeof (pool_bindq_t
), mode
) != 0) {
462 if (pool_lock_intr() != 0)
464 if ((ret
= pool_query_binding(bindq
.pb_o_id_type
,
465 bindq
.pb_o_id
, &bindq
.pb_i_id
)) == 0 &&
466 ddi_copyout(&bindq
, (void *)arg
,
467 sizeof (pool_bindq_t
), mode
) != 0)
473 #ifdef _MULTI_DATAMODEL
474 case DDI_MODEL_ILP32
:
475 if (ddi_copyin((void *)arg
, &propget32
,
476 sizeof (pool_propget32_t
), mode
) != 0)
478 propget
.pp_o_id
= propget32
.pp_o_id
;
479 propget
.pp_o_id_type
= propget32
.pp_o_id_type
;
480 propget
.pp_o_id_subtype
= propget32
.pp_o_id_subtype
;
481 propget
.pp_o_prop_name
=
482 (char *)(uintptr_t)propget32
.pp_o_prop_name
;
483 propget
.pp_o_prop_name_size
=
484 propget32
.pp_o_prop_name_size
;
486 (char *)(uintptr_t)propget32
.pp_i_buf
;
487 propget
.pp_i_bufsize
= propget32
.pp_i_bufsize
;
489 #endif /* _MULTI_DATAMODEL */
492 if (ddi_copyin((void *)arg
, &propget
,
493 sizeof (pool_propget_t
), mode
) != 0)
496 if (propget
.pp_o_prop_name_size
+ 1 > POOL_PROPNAME_SIZE
)
498 prop_name
= kmem_alloc(propget
.pp_o_prop_name_size
+ 1,
500 if (ddi_copyin(propget
.pp_o_prop_name
, prop_name
,
501 propget
.pp_o_prop_name_size
+ 1, mode
) != 0) {
502 kmem_free(prop_name
, propget
.pp_o_prop_name_size
+ 1);
506 if (pool_lock_intr() != 0) {
507 kmem_free(prop_name
, propget
.pp_o_prop_name_size
+ 1);
510 ret
= pool_propget(prop_name
, propget
.pp_o_id_type
,
511 propget
.pp_o_id_subtype
, propget
.pp_o_id
, &list
);
513 kmem_free(prop_name
, propget
.pp_o_prop_name_size
+ 1);
516 ret
= nvlist_pack(list
, &kbuf
, &kbufsz
, NV_ENCODE_NATIVE
, 0);
522 #ifdef _MULTI_DATAMODEL
523 case DDI_MODEL_ILP32
:
524 propget32
.pp_i_bufsize
= kbufsz
;
525 if (ddi_copyout((caddr_t
)&propget32
, (void *)arg
,
526 sizeof (pool_propget32_t
), mode
) != 0)
529 #endif /* _MULTI_DATAMODEL */
532 if (ddi_copyout(&propget
, (void *)arg
,
533 sizeof (pool_propget_t
), mode
) != 0)
537 if (propget
.pp_i_buf
== NULL
) {
539 } else if (propget
.pp_i_bufsize
>= kbufsz
) {
540 if (ddi_copyout(kbuf
, propget
.pp_i_buf
,
547 kmem_free(kbuf
, kbufsz
);
552 #ifdef _MULTI_DATAMODEL
553 case DDI_MODEL_ILP32
:
554 if (ddi_copyin((void *)arg
, &propput32
,
555 sizeof (pool_propput32_t
), mode
) != 0)
557 propput
.pp_o_id_type
= propput32
.pp_o_id_type
;
558 propput
.pp_o_id_sub_type
= propput32
.pp_o_id_sub_type
;
559 propput
.pp_o_id
= propput32
.pp_o_id
;
560 propput
.pp_o_bufsize
= propput32
.pp_o_bufsize
;
562 (char *)(uintptr_t)propput32
.pp_o_buf
;
564 #endif /* _MULTI_DATAMODEL */
567 if (ddi_copyin((void *)arg
, &propput
,
568 sizeof (pool_propput_t
), mode
) != 0)
571 if (propput
.pp_o_bufsize
> POOL_PROPBUF_SIZE
)
573 listbuf
= kmem_alloc(propput
.pp_o_bufsize
, KM_SLEEP
);
574 if (ddi_copyin(propput
.pp_o_buf
, listbuf
,
575 propput
.pp_o_bufsize
, mode
) != 0) {
576 kmem_free(listbuf
, propput
.pp_o_bufsize
);
579 if (nvlist_unpack(listbuf
, propput
.pp_o_bufsize
,
580 &list
, KM_SLEEP
) != 0) {
581 kmem_free(listbuf
, propput
.pp_o_bufsize
);
584 if (pool_lock_intr() != 0) {
586 kmem_free(listbuf
, propput
.pp_o_bufsize
);
590 * Extract the nvpair from the list. The list may
591 * contain multiple properties.
593 for (pair
= nvlist_next_nvpair(list
, NULL
); pair
!= NULL
;
594 pair
= nvlist_next_nvpair(list
, pair
)) {
595 if ((ret
= pool_propput(propput
.pp_o_id_type
,
596 propput
.pp_o_id_sub_type
,
597 propput
.pp_o_id
, pair
)) != 0)
602 kmem_free(listbuf
, propput
.pp_o_bufsize
);
606 #ifdef _MULTI_DATAMODEL
607 case DDI_MODEL_ILP32
:
608 if (ddi_copyin((void *)arg
, &proprm32
,
609 sizeof (pool_proprm32_t
), mode
) != 0)
611 proprm
.pp_o_id_type
= proprm32
.pp_o_id_type
;
612 proprm
.pp_o_id_sub_type
= proprm32
.pp_o_id_sub_type
;
613 proprm
.pp_o_id
= proprm32
.pp_o_id
;
614 proprm
.pp_o_prop_name_size
=
615 proprm32
.pp_o_prop_name_size
;
616 proprm
.pp_o_prop_name
=
617 (void *)(uintptr_t)proprm32
.pp_o_prop_name
;
619 #endif /* _MULTI_DATAMODEL */
622 if (ddi_copyin((void *)arg
, &proprm
,
623 sizeof (pool_proprm_t
), mode
) != 0)
626 if (proprm
.pp_o_prop_name_size
+ 1 > POOL_PROPNAME_SIZE
)
628 prop_name
= kmem_alloc(proprm
.pp_o_prop_name_size
+ 1,
630 if (ddi_copyin(proprm
.pp_o_prop_name
, prop_name
,
631 proprm
.pp_o_prop_name_size
+ 1, mode
) != 0) {
632 kmem_free(prop_name
, proprm
.pp_o_prop_name_size
+ 1);
635 if (pool_lock_intr() != 0) {
636 kmem_free(prop_name
, proprm
.pp_o_prop_name_size
+ 1);
639 ret
= pool_proprm(proprm
.pp_o_id_type
,
640 proprm
.pp_o_id_sub_type
, proprm
.pp_o_id
, prop_name
);
642 kmem_free(prop_name
, proprm
.pp_o_prop_name_size
+ 1);
645 if (pool_lock_intr() != 0)
647 ret
= pool_commit((int)arg
);
656 static struct cb_ops pool_cb_ops
= {
657 pool_open
, /* open */
658 pool_close
, /* close */
659 nodev
, /* strategy */
664 pool_ioctl
, /* ioctl */
669 nodev
, /* cb_prop_op */
670 (struct streamtab
*)0, /* streamtab */
671 D_NEW
| D_MP
/* driver compatibility flags */
674 static struct dev_ops pool_ops
= {
675 DEVO_REV
, /* devo_rev */
677 pool_info
, /* info */
678 nulldev
, /* identify */
680 pool_attach
, /* attach */
681 pool_detach
, /* detach */
683 &pool_cb_ops
, /* cb_ops */
684 (struct bus_ops
*)NULL
, /* bus_ops */
686 ddi_quiesce_not_needed
, /* quiesce */
690 * Module linkage information for the kernel
692 static struct modldrv modldrv
= {
693 &mod_driverops
, /* this one is a pseudo driver */
698 static struct modlinkage modlinkage
= {
707 return (mod_install(&modlinkage
));
713 return (mod_remove(&modlinkage
));
717 _info(struct modinfo
*modinfop
)
719 return (mod_info(&modlinkage
, modinfop
));