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
  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
  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
 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
 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
 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
 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
 705 _init(void)
 706 {
 707         return (mod_install(&modlinkage));
 708 }
 709 
 710 int
 711 _fini(void)
 712 {
 713         return (mod_remove(&modlinkage));
 714 }
 715 
 716 int
 717 _info(struct modinfo *modinfop)
 718 {
 719         return (mod_info(&modlinkage, modinfop));
 720 }