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