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
27 #include <sys/types.h>
28 #include <sys/file.h>
29 #include <sys/errno.h>
30 #include <sys/open.h>
31 #include <sys/cred.h>
32 #include <sys/conf.h>
33 #include <sys/modctl.h>
34 #include <sys/stat.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/policy.h>
38 #include <sys/pool.h>
39 #include <sys/pool_impl.h>
40
41 /*
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.
45 *
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.
51 *
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.
57 */
58
59 #define POOL_CTL_PARENT 0
60 #define POOL_INFO_PARENT 1
61
62 static dev_info_t *pool_devi; /* pool device information */
63 static int pool_openctl; /* poolctl device is already open */
64
65 /*ARGSUSED*/
66 static int
pool_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)67 pool_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
68 {
69 int error = DDI_FAILURE;
70
71 switch (infocmd) {
72 case DDI_INFO_DEVT2DEVINFO:
73 *result = pool_devi;
74 error = DDI_SUCCESS;
75 break;
76 case DDI_INFO_DEVT2INSTANCE:
77 /*
78 * All dev_t's map to the same, single instance.
79 */
80 *result = NULL;
81 error = DDI_SUCCESS;
82 break;
83 default:
84 break;
85 }
86 return (error);
87 }
88
89 static int
pool_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)90 pool_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
91 {
92 int ret = DDI_SUCCESS;
93
94 switch (cmd) {
95 case DDI_DETACH:
96 pool_lock();
97 if (pool_state == POOL_ENABLED) {
98 ret = DDI_FAILURE;
99 pool_unlock();
100 break;
101 }
102 ddi_remove_minor_node(devi, NULL);
103 pool_devi = NULL;
104 pool_unlock();
105 break;
106 default:
107 ret = DDI_FAILURE;
108 }
109 return (ret);
110 }
111
112 static int
pool_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)113 pool_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
114 {
115 switch (cmd) {
116 case DDI_ATTACH:
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);
125 }
126 pool_devi = devi;
127 ddi_report_dev(devi);
128 break;
129 case DDI_RESUME:
130 break;
131 default:
132 return (DDI_FAILURE);
133 }
134 return (DDI_SUCCESS);
135
136 }
137
138 /*
139 * There is only one instance of the pool control device, poolctl,
140 * and multiple instances of the pool info device, pool.
141 */
142 /*ARGSUSED*/
143 static int
pool_open(dev_t * devp,int flag,int otype,cred_t * credp)144 pool_open(dev_t *devp, int flag, int otype, cred_t *credp)
145 {
146 minor_t minor = getminor(*devp);
147
148 if (otype != OTYP_CHR)
149 return (EINVAL);
150
151 switch (minor) {
152 case POOL_CTL_PARENT:
153 if (secpolicy_pool(CRED()) != 0)
154 return (EPERM);
155 if (pool_lock_intr() != 0)
156 return (EINTR);
157 if (pool_openctl == 1) {
158 pool_unlock();
159 return (EBUSY);
160 }
161 pool_openctl = 1;
162 pool_unlock();
163 break;
164 case POOL_INFO_PARENT:
165 break;
166 default:
167 return (ENXIO);
168 }
169 return (0);
170 }
171
172 /*ARGSUSED*/
173 static int
pool_close(dev_t dev,int flag,int otype,cred_t * credp)174 pool_close(dev_t dev, int flag, int otype, cred_t *credp)
175 {
176 if (otype != OTYP_CHR)
177 return (EINVAL);
178 if (getminor(dev) == 0) {
179 /*
180 * We could be closing the poolctl device without finishing
181 * the commit transaction first, so do that now.
182 */
183 pool_lock();
184 (void) pool_commit(0); /* cannot fail since arg is 0 */
185 pool_openctl = 0;
186 pool_unlock();
187 }
188 return (0);
189 }
190
191 /*
192 * Main pool interface.
193 */
194 /* ARGSUSED4 */
195 static int
pool_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)196 pool_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
197 int *rvalp)
198 {
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;
208 pool_assoc_t assoc;
209 pool_bindq_t bindq;
210 pool_query_t query;
211 pool_bind_t bind;
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 */
219 char *kbuf = NULL;
220 size_t kbufsz = 0;
221 int snapshot = 0;
222 char *prop_name;
223 size_t size = 0;
224 nvlist_t *list;
225 nvpair_t *pair;
226 char *listbuf;
227 minor_t minor;
228 uint_t model;
229 id_t *id_buf;
230 int ret = 0;
231
232 model = ddi_model_convert_from(mode & FMODELS);
233 minor = getminor(dev);
234
235 /*
236 * Check basic permissions first.
237 */
238 switch (cmd) {
239 case POOL_STATUS:
240 case POOL_CREATE:
241 case POOL_ASSOC:
242 case POOL_DISSOC:
243 case POOL_DESTROY:
244 case POOL_TRANSFER:
245 case POOL_XTRANSFER:
246 case POOL_PROPPUT:
247 case POOL_PROPRM:
248 case POOL_COMMIT:
249 if (minor != POOL_CTL_PARENT)
250 return (EINVAL);
251 /*FALLTHROUGH*/
252 case POOL_BIND:
253 if (secpolicy_pool(CRED()) != 0)
254 return (EPERM);
255 break;
256 }
257
258 switch (cmd) {
259 case POOL_STATUS:
260 if (ddi_copyin((void *)arg, &status,
261 sizeof (pool_status_t), mode) != 0)
262 return (EFAULT);
263 if (pool_lock_intr() != 0)
264 return (EINTR);
265 ret = pool_status(status.ps_io_state);
266 pool_unlock();
267 break;
268 case POOL_STATUSQ:
269 /*
270 * No need to grab pool_lock() to look at the current state.
271 */
272 status.ps_io_state = pool_state;
273 if (ddi_copyout(&status, (void *)arg,
274 sizeof (pool_status_t), mode) != 0)
275 return (EFAULT);
276 break;
277 case POOL_QUERY:
278 switch (model) {
279 #ifdef _MULTI_DATAMODEL
280 case DDI_MODEL_ILP32:
281 if (ddi_copyin((void *)arg, &query32,
282 sizeof (pool_query32_t), mode) != 0)
283 return (EFAULT);
284 query.pq_io_bufsize = query32.pq_io_bufsize;
285 query.pq_io_buf = (char *)(uintptr_t)query32.pq_io_buf;
286 break;
287 #endif /* _MULTI_DATAMODEL */
288 default:
289 case DDI_MODEL_NONE:
290 if (ddi_copyin((void *)arg, &query,
291 sizeof (pool_query_t), mode) != 0)
292 return (EFAULT);
293 }
294 if (pool_lock_intr() != 0)
295 return (EINTR);
296 if (pool_state == POOL_DISABLED) {
297 pool_unlock();
298 return (ENOTACTIVE);
299 }
300 if (minor != 0 && pool_buf != NULL) {
301 /*
302 * Return last snapshot if some
303 * transaction is still in progress
304 */
305 if (kbufsz != 0 && pool_bufsz > kbufsz) {
306 pool_unlock();
307 return (ENOMEM);
308 }
309 kbuf = pool_buf;
310 kbufsz = size = pool_bufsz;
311 snapshot = 1;
312 } else if (query.pq_io_bufsize != 0) {
313 kbufsz = query.pq_io_bufsize;
314 kbuf = kmem_alloc(kbufsz, KM_NOSLEEP);
315 if (kbuf == NULL) {
316 pool_unlock();
317 return (ENOMEM);
318 }
319 ret = pool_pack_conf(kbuf, kbufsz, &size);
320 } else {
321 ret = pool_pack_conf(NULL, 0, &size);
322 }
323 if (ret == 0) {
324 switch (model) {
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)
330 ret = EFAULT;
331 break;
332 #endif /* _MULTI_DATAMODEL */
333 default:
334 case DDI_MODEL_NONE:
335 query.pq_io_bufsize = size;
336 if (ddi_copyout(&query, (void *)arg,
337 sizeof (pool_query_t), mode) != 0)
338 ret = EFAULT;
339 }
340 if (ret == 0 && query.pq_io_buf != NULL &&
341 ddi_copyout(kbuf, query.pq_io_buf, size, mode) != 0)
342 ret = EFAULT;
343 }
344 pool_unlock();
345 if (snapshot == 0)
346 kmem_free(kbuf, kbufsz);
347 break;
348 case POOL_CREATE:
349 if (ddi_copyin((void *)arg,
350 &create, sizeof (pool_create_t), mode) != 0)
351 return (EFAULT);
352 if (pool_lock_intr() != 0)
353 return (EINTR);
354 ret = pool_create(create.pc_o_type,
355 create.pc_o_sub_type, &create.pc_i_id);
356 pool_unlock();
357 if (ret == 0 && ddi_copyout(&create, (void *)arg,
358 sizeof (pool_create_t), mode) != 0)
359 ret = EFAULT;
360 break;
361 case POOL_ASSOC:
362 if (ddi_copyin((void *)arg, &assoc,
363 sizeof (pool_assoc_t), mode) != 0)
364 return (EFAULT);
365 if (pool_lock_intr() != 0)
366 return (EINTR);
367 ret = pool_assoc(assoc.pa_o_pool_id,
368 assoc.pa_o_id_type, assoc.pa_o_res_id);
369 pool_unlock();
370 break;
371 case POOL_DISSOC:
372 if (ddi_copyin((void *)arg, &dissoc,
373 sizeof (pool_dissoc_t), mode) != 0)
374 return (EFAULT);
375 if (pool_lock_intr() != 0)
376 return (EINTR);
377 ret = pool_dissoc(dissoc.pd_o_pool_id, dissoc.pd_o_id_type);
378 pool_unlock();
379 break;
380 case POOL_DESTROY:
381 if (ddi_copyin((void *)arg, &destroy,
382 sizeof (pool_destroy_t), mode) != 0)
383 return (EFAULT);
384 if (pool_lock_intr() != 0)
385 return (EINTR);
386 ret = pool_destroy(destroy.pd_o_type, destroy.pd_o_sub_type,
387 destroy.pd_o_id);
388 pool_unlock();
389 break;
390 case POOL_TRANSFER:
391 if (ddi_copyin((void *)arg, &transfer,
392 sizeof (pool_transfer_t), mode) != 0)
393 return (EFAULT);
394 if (pool_lock_intr() != 0)
395 return (EINTR);
396 ret = pool_transfer(transfer.pt_o_id_type, transfer.pt_o_src_id,
397 transfer.pt_o_tgt_id, transfer.pt_o_qty);
398 pool_unlock();
399 break;
400 case POOL_XTRANSFER:
401 switch (model) {
402 #ifdef _MULTI_DATAMODEL
403 case DDI_MODEL_ILP32:
404 if (ddi_copyin((void *)arg, &xtransfer32,
405 sizeof (pool_xtransfer32_t), mode) != 0)
406 return (EFAULT);
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;
414 break;
415 #endif /* _MULTI_DATAMODEL */
416 default:
417 case DDI_MODEL_NONE:
418 if (ddi_copyin((void *)arg, &xtransfer,
419 sizeof (pool_xtransfer_t), mode) != 0)
420 return (EFAULT);
421 }
422 /*
423 * Copy in IDs to transfer from the userland
424 */
425 if (xtransfer.px_o_complist_size > POOL_IDLIST_SIZE)
426 return (EINVAL);
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 *
432 sizeof (id_t));
433 return (EFAULT);
434 }
435 if (pool_lock_intr() != 0) {
436 kmem_free(id_buf, xtransfer.px_o_complist_size *
437 sizeof (id_t));
438 return (EINTR);
439 }
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);
443 pool_unlock();
444 kmem_free(id_buf, xtransfer.px_o_complist_size *
445 sizeof (id_t));
446 break;
447 case POOL_BIND:
448 if (ddi_copyin((void *)arg, &bind,
449 sizeof (pool_bind_t), mode) != 0)
450 return (EFAULT);
451 if (pool_lock_intr() != 0)
452 return (EINTR);
453 ret = pool_bind(bind.pb_o_pool_id, bind.pb_o_id_type,
454 bind.pb_o_id);
455 pool_unlock();
456 break;
457 case POOL_BINDQ:
458 if (ddi_copyin((void *)arg, &bindq,
459 sizeof (pool_bindq_t), mode) != 0) {
460 return (EFAULT);
461 }
462 if (pool_lock_intr() != 0)
463 return (EINTR);
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)
468 ret = EFAULT;
469 pool_unlock();
470 break;
471 case POOL_PROPGET:
472 switch (model) {
473 #ifdef _MULTI_DATAMODEL
474 case DDI_MODEL_ILP32:
475 if (ddi_copyin((void *)arg, &propget32,
476 sizeof (pool_propget32_t), mode) != 0)
477 return (EFAULT);
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;
485 propget.pp_i_buf =
486 (char *)(uintptr_t)propget32.pp_i_buf;
487 propget.pp_i_bufsize = propget32.pp_i_bufsize;
488 break;
489 #endif /* _MULTI_DATAMODEL */
490 default:
491 case DDI_MODEL_NONE:
492 if (ddi_copyin((void *)arg, &propget,
493 sizeof (pool_propget_t), mode) != 0)
494 return (EFAULT);
495 }
496 if (propget.pp_o_prop_name_size + 1 > POOL_PROPNAME_SIZE)
497 return (EINVAL);
498 prop_name = kmem_alloc(propget.pp_o_prop_name_size + 1,
499 KM_SLEEP);
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);
503 return (EFAULT);
504 }
505 list = NULL;
506 if (pool_lock_intr() != 0) {
507 kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
508 return (EINTR);
509 }
510 ret = pool_propget(prop_name, propget.pp_o_id_type,
511 propget.pp_o_id_subtype, propget.pp_o_id, &list);
512 pool_unlock();
513 kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
514 if (ret != 0)
515 return (ret);
516 ret = nvlist_pack(list, &kbuf, &kbufsz, NV_ENCODE_NATIVE, 0);
517 if (ret != 0) {
518 nvlist_free(list);
519 return (ret);
520 }
521 switch (model) {
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)
527 ret = EFAULT;
528 break;
529 #endif /* _MULTI_DATAMODEL */
530 default:
531 case DDI_MODEL_NONE:
532 if (ddi_copyout(&propget, (void *)arg,
533 sizeof (pool_propget_t), mode) != 0)
534 ret = EFAULT;
535 }
536 if (ret == 0) {
537 if (propget.pp_i_buf == NULL) {
538 ret = 0;
539 } else if (propget.pp_i_bufsize >= kbufsz) {
540 if (ddi_copyout(kbuf, propget.pp_i_buf,
541 kbufsz, mode) != 0)
542 ret = EFAULT;
543 } else {
544 ret = ENOMEM;
545 }
546 }
547 kmem_free(kbuf, kbufsz);
548 nvlist_free(list);
549 break;
550 case POOL_PROPPUT:
551 switch (model) {
552 #ifdef _MULTI_DATAMODEL
553 case DDI_MODEL_ILP32:
554 if (ddi_copyin((void *)arg, &propput32,
555 sizeof (pool_propput32_t), mode) != 0)
556 return (EFAULT);
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;
561 propput.pp_o_buf =
562 (char *)(uintptr_t)propput32.pp_o_buf;
563 break;
564 #endif /* _MULTI_DATAMODEL */
565 default:
566 case DDI_MODEL_NONE:
567 if (ddi_copyin((void *)arg, &propput,
568 sizeof (pool_propput_t), mode) != 0)
569 return (EFAULT);
570 }
571 if (propput.pp_o_bufsize > POOL_PROPBUF_SIZE)
572 return (EINVAL);
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);
577 return (EFAULT);
578 }
579 if (nvlist_unpack(listbuf, propput.pp_o_bufsize,
580 &list, KM_SLEEP) != 0) {
581 kmem_free(listbuf, propput.pp_o_bufsize);
582 return (EFAULT);
583 }
584 if (pool_lock_intr() != 0) {
585 nvlist_free(list);
586 kmem_free(listbuf, propput.pp_o_bufsize);
587 return (EINTR);
588 }
589 /*
590 * Extract the nvpair from the list. The list may
591 * contain multiple properties.
592 */
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)
598 break;
599 }
600 pool_unlock();
601 nvlist_free(list);
602 kmem_free(listbuf, propput.pp_o_bufsize);
603 break;
604 case POOL_PROPRM:
605 switch (model) {
606 #ifdef _MULTI_DATAMODEL
607 case DDI_MODEL_ILP32:
608 if (ddi_copyin((void *)arg, &proprm32,
609 sizeof (pool_proprm32_t), mode) != 0)
610 return (EFAULT);
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;
618 break;
619 #endif /* _MULTI_DATAMODEL */
620 default:
621 case DDI_MODEL_NONE:
622 if (ddi_copyin((void *)arg, &proprm,
623 sizeof (pool_proprm_t), mode) != 0)
624 return (EFAULT);
625 }
626 if (proprm.pp_o_prop_name_size + 1 > POOL_PROPNAME_SIZE)
627 return (EINVAL);
628 prop_name = kmem_alloc(proprm.pp_o_prop_name_size + 1,
629 KM_SLEEP);
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);
633 return (EFAULT);
634 }
635 if (pool_lock_intr() != 0) {
636 kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
637 return (EINTR);
638 }
639 ret = pool_proprm(proprm.pp_o_id_type,
640 proprm.pp_o_id_sub_type, proprm.pp_o_id, prop_name);
641 pool_unlock();
642 kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
643 break;
644 case POOL_COMMIT:
645 if (pool_lock_intr() != 0)
646 return (EINTR);
647 ret = pool_commit((int)arg);
648 pool_unlock();
649 break;
650 default:
651 return (EINVAL);
652 }
653 return (ret);
654 }
655
656 static struct cb_ops pool_cb_ops = {
657 pool_open, /* open */
658 pool_close, /* close */
659 nodev, /* strategy */
660 nodev, /* print */
661 nodev, /* dump */
662 nodev, /* read */
663 nodev, /* write */
664 pool_ioctl, /* ioctl */
665 nodev, /* devmap */
666 nodev, /* mmap */
667 nodev, /* segmap */
668 nochpoll, /* poll */
669 nodev, /* cb_prop_op */
670 (struct streamtab *)0, /* streamtab */
671 D_NEW | D_MP /* driver compatibility flags */
672 };
673
674 static struct dev_ops pool_ops = {
675 DEVO_REV, /* devo_rev */
676 0, /* refcnt */
677 pool_info, /* info */
678 nulldev, /* identify */
679 nulldev, /* probe */
680 pool_attach, /* attach */
681 pool_detach, /* detach */
682 nodev, /* reset */
683 &pool_cb_ops, /* cb_ops */
684 (struct bus_ops *)NULL, /* bus_ops */
685 nulldev, /* power */
686 ddi_quiesce_not_needed, /* quiesce */
687 };
688
689 /*
690 * Module linkage information for the kernel
691 */
692 static struct modldrv modldrv = {
693 &mod_driverops, /* this one is a pseudo driver */
694 "pool driver",
695 &pool_ops
696 };
697
698 static struct modlinkage modlinkage = {
699 MODREV_1,
700 &modldrv,
701 NULL
702 };
703
704 int
_init(void)705 _init(void)
706 {
707 return (mod_install(&modlinkage));
708 }
709
710 int
_fini(void)711 _fini(void)
712 {
713 return (mod_remove(&modlinkage));
714 }
715
716 int
_info(struct modinfo * modinfop)717 _info(struct modinfo *modinfop)
718 {
719 return (mod_info(&modlinkage, modinfop));
720 }
721