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 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright 2012 Milan Jurik. All rights reserved.
  26  */
  27 
  28 #include <assert.h>
  29 #include <errno.h>
  30 #include <exacct.h>
  31 #include <fcntl.h>
  32 #include <libnvpair.h>
  33 #include <limits.h>
  34 #include <poll.h>
  35 #include <pool.h>
  36 #include <stdlib.h>
  37 #include <stdio.h>
  38 #include <string.h>
  39 #include <strings.h>
  40 #include <stropts.h>
  41 #include <thread.h>
  42 #include <time.h>
  43 #include <unistd.h>
  44 
  45 #include <libxml/tree.h>
  46 
  47 #include <sys/mman.h>
  48 #include <sys/pool.h>
  49 #include <sys/pool_impl.h>
  50 #include <sys/priocntl.h>
  51 #include <sys/stat.h>
  52 #include <sys/time.h>
  53 #include <sys/types.h>
  54 
  55 #include "dict.h"
  56 
  57 #include "pool_internal.h"
  58 #include "pool_impl.h"
  59 #include "pool_kernel_impl.h"
  60 
  61 /*
  62  * libpool kernel Manipulation Routines
  63  *
  64  * pool_kernel.c implements the kernel manipulation routines used by the
  65  * libpool kernel datastore. The functions are grouped into the following
  66  * logical areas
  67  *
  68  */
  69 
  70 /*
  71  * Device snapshot transfer buffer size
  72  */
  73 #define KERNEL_SNAPSHOT_BUF_SZ  65535
  74 
  75 /*
  76  * Kernel result set's initial size. 8 is probably large enough for
  77  * most queries. Queries requiring more space are accomodated using
  78  * realloc on a per result set basis.
  79  */
  80 #define KERNEL_RS_INITIAL_SZ    8
  81 
  82 /*
  83  * Property manipulation macros
  84  */
  85 #define KERNEL_PROP_RDONLY      0x1
  86 
  87 /*
  88  * Information required to evaluate qualifying elements for a query
  89  */
  90 struct query_obj {
  91         const pool_conf_t *conf;
  92         const pool_elem_t *src;
  93         const char *src_attr;
  94         pool_elem_class_t classes;
  95         pool_value_t **props;
  96         pool_knl_result_set_t *rs;
  97 };
  98 
  99 /*
 100  * Identifies a pool element with a processor set id
 101  */
 102 typedef struct pool_set_xref {
 103         pool_knl_pool_t *psx_pool;
 104         uint_t          psx_pset_id;
 105         struct pool_set_xref *psx_next;
 106 } pool_set_xref_t;
 107 
 108 /*
 109  * Controls exacct snapshot load into libpool data structure
 110  */
 111 typedef struct pool_snap_load {
 112         int *psl_changed;
 113         pool_set_xref_t *psl_xref;
 114         pool_elem_t *psl_system;
 115         pool_knl_resource_t *psl_pset;
 116 } pool_snap_load_t;
 117 
 118 /*
 119  * Information about an XML document which is being constructed
 120  */
 121 struct knl_to_xml {
 122         xmlDocPtr ktx_doc;
 123         xmlNodePtr ktx_node;
 124 };
 125 
 126 /*
 127  * Undo structure processing. The following structures are all used to
 128  * allow changes to the libpool snapshot and kernel following an
 129  * unsuccessful commit.
 130  */
 131 typedef struct pool_create_undo {
 132         pool_create_t pcu_ioctl;
 133         pool_elem_t *pcu_elem;
 134 } pool_create_undo_t;
 135 
 136 typedef struct pool_destroy_undo {
 137         pool_destroy_t pdu_ioctl;
 138         pool_elem_t *pdu_elem;
 139 } pool_destroy_undo_t;
 140 
 141 typedef struct pool_assoc_undo {
 142         pool_assoc_t pau_ioctl;
 143         pool_elem_t *pau_assoc;
 144         pool_elem_t *pau_oldres;
 145         pool_elem_t *pau_newres;
 146 } pool_assoc_undo_t;
 147 
 148 typedef struct pool_dissoc_undo {
 149         pool_dissoc_t pdu_ioctl;
 150         pool_elem_t *pdu_dissoc;
 151         pool_elem_t *pdu_oldres;
 152         pool_elem_t *pdu_newres;
 153 } pool_dissoc_undo_t;
 154 
 155 typedef struct pool_xtransfer_undo {
 156         pool_xtransfer_t pxu_ioctl;
 157         pool_elem_t *pxu_src;
 158         pool_elem_t *pxu_tgt;
 159         pool_component_t **pxu_rl;
 160 } pool_xtransfer_undo_t;
 161 
 162 typedef struct pool_propput_undo {
 163         pool_propput_t ppu_ioctl;
 164         pool_elem_t *ppu_elem;
 165         nvlist_t *ppu_alist;
 166         nvlist_t *ppu_blist;
 167         uchar_t ppu_doioctl;
 168 } pool_propput_undo_t;
 169 
 170 typedef struct pool_proprm_undo {
 171         pool_proprm_t pru_ioctl;
 172         pool_elem_t *pru_elem;
 173         pool_value_t pru_oldval;
 174 } pool_proprm_undo_t;
 175 
 176 extern const char *dtd_location;
 177 
 178 extern const char *element_class_tags[];
 179 extern const char pool_info_location[];
 180 
 181 /*
 182  * These functions are defined in pool_xml.c and represent the minimum
 183  * XML support required to allow a pool kernel configuration to be
 184  * exported as an XML document.
 185  */
 186 extern int pool_xml_set_attr(xmlNodePtr, xmlChar *, const pool_value_t *);
 187 extern int pool_xml_set_prop(xmlNodePtr, xmlChar *, const pool_value_t *);
 188 extern void xml_init(void);
 189 extern xmlNodePtr node_create(xmlNodePtr, const xmlChar *);
 190 extern void pool_error_func(void *, const char *, ...);
 191 /*
 192  * Utilities
 193  */
 194 static int load_group(pool_conf_t *, pool_knl_elem_t *, ea_object_t *,
 195     pool_snap_load_t *);
 196 static void pool_knl_elem_free(pool_knl_elem_t *, int);
 197 static int pool_knl_put_xml_property(pool_elem_t *, xmlNodePtr, const char *,
 198     const pool_value_t *);
 199 static int pool_knl_snap_load_push(pool_snap_load_t *, pool_knl_pool_t *);
 200 static int pool_knl_snap_load_update(pool_snap_load_t *, int, uint_t);
 201 static int pool_knl_snap_load_remove(pool_snap_load_t *, int, uint_t);
 202 static nvpair_t *pool_knl_find_nvpair(nvlist_t *, const char *);
 203 static int pool_knl_nvlist_add_value(nvlist_t *, const char *,
 204     const pool_value_t *);
 205 static int pool_knl_recover(pool_conf_t *);
 206 static uint64_t hash_id(const pool_elem_t *);
 207 static int blocking_open(const char *, int);
 208 
 209 /*
 210  * Connections
 211  */
 212 static void pool_knl_connection_free(pool_knl_connection_t *);
 213 
 214 /*
 215  * Configuration
 216  */
 217 static int pool_knl_close(pool_conf_t *);
 218 static int pool_knl_validate(const pool_conf_t *, pool_valid_level_t);
 219 static int pool_knl_commit(pool_conf_t *);
 220 static int pool_knl_export(const pool_conf_t *, const char *,
 221     pool_export_format_t);
 222 static int pool_knl_rollback(pool_conf_t *);
 223 static pool_result_set_t *pool_knl_exec_query(const pool_conf_t *,
 224     const pool_elem_t *, const char *, pool_elem_class_t, pool_value_t **);
 225 static int pool_knl_remove(pool_conf_t *);
 226 static char *pool_knl_get_binding(pool_conf_t *, pid_t);
 227 static int pool_knl_set_binding(pool_conf_t *, const char *, idtype_t, id_t);
 228 static char *pool_knl_get_resource_binding(pool_conf_t *,
 229     pool_resource_elem_class_t, pid_t);
 230 static int pool_knl_res_transfer(pool_resource_t *, pool_resource_t *,
 231     uint64_t);
 232 static int pool_knl_res_xtransfer(pool_resource_t *, pool_resource_t *,
 233     pool_component_t **);
 234 
 235 /*
 236  * Result Sets
 237  */
 238 static pool_knl_result_set_t *pool_knl_result_set_alloc(const pool_conf_t *);
 239 static int pool_knl_result_set_append(pool_knl_result_set_t *,
 240     pool_knl_elem_t *);
 241 static int pool_knl_result_set_realloc(pool_knl_result_set_t *);
 242 static void pool_knl_result_set_free(pool_knl_result_set_t *);
 243 static pool_elem_t *pool_knl_rs_next(pool_result_set_t *);
 244 static pool_elem_t *pool_knl_rs_prev(pool_result_set_t *);
 245 static pool_elem_t *pool_knl_rs_first(pool_result_set_t *);
 246 static pool_elem_t *pool_knl_rs_last(pool_result_set_t *);
 247 static int pool_knl_rs_set_index(pool_result_set_t *, int);
 248 static int pool_knl_rs_get_index(pool_result_set_t *);
 249 static int pool_knl_rs_count(pool_result_set_t *);
 250 static int pool_knl_rs_close(pool_result_set_t *);
 251 
 252 /*
 253  * Element (and sub-type)
 254  */
 255 static pool_knl_elem_t *pool_knl_elem_wrap(pool_conf_t *, pool_elem_class_t,
 256     pool_resource_elem_class_t, pool_component_elem_class_t);
 257 static pool_elem_t *pool_knl_elem_create(pool_conf_t *, pool_elem_class_t,
 258     pool_resource_elem_class_t, pool_component_elem_class_t);
 259 static int pool_knl_elem_remove(pool_elem_t *);
 260 static int pool_knl_set_container(pool_elem_t *, pool_elem_t *);
 261 static pool_elem_t *pool_knl_get_container(const pool_elem_t *);
 262 /*
 263  * Pool element specific
 264  */
 265 static int pool_knl_pool_associate(pool_t *, const pool_resource_t *);
 266 static int pool_knl_pool_dissociate(pool_t *, const pool_resource_t *);
 267 
 268 /*
 269  * Resource elements specific
 270  */
 271 static int pool_knl_resource_is_system(const pool_resource_t *);
 272 static int pool_knl_resource_can_associate(const pool_resource_t *);
 273 
 274 /* Properties */
 275 static pool_value_class_t pool_knl_get_property(const pool_elem_t *,
 276     const char *, pool_value_t *);
 277 static pool_value_class_t pool_knl_get_dynamic_property(const pool_elem_t *,
 278     const char *, pool_value_t *);
 279 static int pool_knl_put_property(pool_elem_t *, const char *,
 280     const pool_value_t *);
 281 static int pool_knl_rm_property(pool_elem_t *, const char *);
 282 static pool_value_t **pool_knl_get_properties(const pool_elem_t *, uint_t *);
 283 
 284 /*
 285  * Logging
 286  */
 287 static int log_item_commit(log_item_t *);
 288 static int log_item_undo(log_item_t *);
 289 static int log_item_release(log_item_t *);
 290 
 291 /*
 292  * Utilities
 293  */
 294 
 295 /*
 296  * load_group() updates the library configuration with the kernel
 297  * snapshot supplied in ep. The function is designed to be called
 298  * recursively. This function depends implicitly on the ordering of
 299  * the data provided in ep. Changes to the ordering of data in ep must
 300  * be matched by changes to this function.
 301  */
 302 int
 303 load_group(pool_conf_t *conf, pool_knl_elem_t *elem, ea_object_t *ep,
 304     pool_snap_load_t *psl)
 305 {
 306         ea_object_t *eo;
 307         pool_knl_elem_t *old_elem;
 308         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
 309         int ret = PO_SUCCESS;
 310 
 311         if ((ep->eo_catalog & EXD_DATA_MASK) == EXD_GROUP_SYSTEM) {
 312                 if ((elem = pool_knl_elem_wrap(conf, PEC_SYSTEM, PREC_INVALID,
 313                     PCEC_INVALID)) == NULL)
 314                         return (PO_FAIL);
 315                 if (nvlist_alloc(&elem->pke_properties, NV_UNIQUE_NAME_TYPE,
 316                     0) != 0) {
 317                         pool_knl_elem_free(elem, PO_FALSE);
 318                         pool_seterror(POE_SYSTEM);
 319                         return (PO_FAIL);
 320                 }
 321                 /*
 322                  * Check to see if we already have an element
 323                  * for this data. If we have, free the newly
 324                  * created elem and continue with the old one
 325                  */
 326                 if ((old_elem = dict_get(prov->pkc_elements, elem)) != NULL) {
 327                         nvlist_free(old_elem->pke_properties);
 328                         old_elem->pke_properties = elem->pke_properties;
 329                         pool_knl_elem_free(elem, PO_FALSE);
 330                         elem = old_elem;
 331                 } else {
 332                         if (dict_put(prov->pkc_elements, elem, elem) != NULL) {
 333                                 pool_knl_elem_free(elem, PO_TRUE);
 334                                 pool_seterror(POE_SYSTEM);
 335                                 return (PO_FAIL);
 336                         }
 337                 }
 338                 psl->psl_system = (pool_elem_t *)elem;
 339         }
 340 
 341         for (eo = ep->eo_group.eg_objs; eo != NULL; eo = eo->eo_next) {
 342                 int data;
 343                 pool_knl_elem_t *prop_elem = NULL;
 344 
 345                 data = (eo->eo_catalog & EXD_DATA_MASK);
 346 
 347                 switch (data) {
 348                 case EXD_SYSTEM_TSTAMP:
 349                 case EXD_POOL_TSTAMP:
 350                 case EXD_PSET_TSTAMP:
 351                 case EXD_CPU_TSTAMP:
 352                         if (eo->eo_item.ei_uint64 > prov->pkc_lotime) {
 353                                 if (eo->eo_item.ei_uint64 > prov->pkc_ltime)
 354                                         prov->pkc_ltime = eo->eo_item.ei_uint64;
 355                                 if (psl->psl_changed) {
 356                                         switch (data) {
 357                                         case EXD_SYSTEM_TSTAMP:
 358                                                 *psl->psl_changed |= POU_SYSTEM;
 359                                                 break;
 360                                         case EXD_POOL_TSTAMP:
 361                                                 *psl->psl_changed |= POU_POOL;
 362                                                 break;
 363                                         case EXD_PSET_TSTAMP:
 364                                                 *psl->psl_changed |= POU_PSET;
 365                                                 break;
 366                                         case EXD_CPU_TSTAMP:
 367                                                 *psl->psl_changed |= POU_CPU;
 368                                                 break;
 369                                         }
 370                                 }
 371                         }
 372                         break;
 373                 case EXD_SYSTEM_PROP:
 374                 case EXD_POOL_PROP:
 375                 case EXD_PSET_PROP:
 376                 case EXD_CPU_PROP:
 377                         if (data == EXD_PSET_PROP) {
 378                                 prop_elem = elem;
 379                                 elem = (pool_knl_elem_t *)psl->psl_pset;
 380                         }
 381                         nvlist_free(elem->pke_properties);
 382                         if (nvlist_unpack(eo->eo_item.ei_raw,
 383                             eo->eo_item.ei_size, &elem->pke_properties, 0) !=
 384                             0) {
 385                                 pool_seterror(POE_SYSTEM);
 386                                 return (PO_FAIL);
 387                         }
 388                         elem->pke_ltime = prov->pkc_ltime;
 389                         if (data == EXD_PSET_PROP) {
 390                                 elem = prop_elem;
 391                         }
 392                         break;
 393                 case EXD_POOL_POOLID:
 394                         if (nvlist_alloc(&elem->pke_properties,
 395                             NV_UNIQUE_NAME_TYPE, 0) != 0) {
 396                                 pool_seterror(POE_SYSTEM);
 397                                 return (PO_FAIL);
 398                         }
 399                         if (nvlist_add_int64(elem->pke_properties,
 400                             "pool.sys_id",
 401                             (int64_t)eo->eo_item.ei_uint32) != 0) {
 402                                 pool_seterror(POE_SYSTEM);
 403                                 return (PO_FAIL);
 404                         }
 405                         if ((old_elem = dict_get(prov->pkc_elements, elem)) !=
 406                             NULL) {
 407                                 nvlist_free(old_elem->pke_properties);
 408                                 old_elem->pke_properties = elem->pke_properties;
 409                                 pool_knl_elem_free(elem, PO_FALSE);
 410                                 elem = old_elem;
 411                         } else {
 412                                 if (dict_put(prov->pkc_elements, elem, elem) !=
 413                                     NULL) {
 414                                         pool_knl_elem_free(elem, PO_TRUE);
 415                                         pool_seterror(POE_SYSTEM);
 416                                         return (PO_FAIL);
 417                                 }
 418                         }
 419                         if (pool_knl_snap_load_push(psl,
 420                             (pool_knl_pool_t *)elem) != PO_SUCCESS) {
 421                                 pool_seterror(POE_SYSTEM);
 422                                 return (PO_FAIL);
 423                         }
 424                         ((pool_knl_pool_t *)elem)->pkp_assoc[PREC_PSET] = NULL;
 425                         break;
 426                 case EXD_POOL_PSETID:
 427                         if (pool_knl_snap_load_update(psl, EXD_POOL_PSETID,
 428                             eo->eo_item.ei_uint32) != PO_SUCCESS) {
 429                                 pool_seterror(POE_SYSTEM);
 430                                 return (PO_FAIL);
 431                         }
 432                         break;
 433                 case EXD_PSET_PSETID:
 434                         if (nvlist_alloc(&elem->pke_properties,
 435                             NV_UNIQUE_NAME_TYPE, 0) != 0) {
 436                                 pool_seterror(POE_SYSTEM);
 437                                 return (PO_FAIL);
 438                         }
 439                         if (nvlist_add_int64(elem->pke_properties,
 440                             "pset.sys_id",
 441                             (int64_t)eo->eo_item.ei_uint32) != 0) {
 442                                 pool_seterror(POE_SYSTEM);
 443                                 return (PO_FAIL);
 444                         }
 445                         if ((old_elem = dict_get(prov->pkc_elements, elem)) !=
 446                             NULL) {
 447                                 nvlist_free(old_elem->pke_properties);
 448                                 old_elem->pke_properties = elem->pke_properties;
 449                                 pool_knl_elem_free(elem, PO_FALSE);
 450                                 elem = old_elem;
 451                         } else {
 452                                 if (dict_put(prov->pkc_elements, elem, elem) !=
 453                                     NULL) {
 454                                         pool_knl_elem_free(elem, PO_TRUE);
 455                                         pool_seterror(POE_SYSTEM);
 456                                         return (PO_FAIL);
 457                                 }
 458                         }
 459                         psl->psl_pset = (pool_knl_resource_t *)elem;
 460                         if (pool_knl_snap_load_remove(psl, data,
 461                             eo->eo_item.ei_uint32) != PO_SUCCESS) {
 462                                 pool_seterror(POE_SYSTEM);
 463                                 return (PO_FAIL);
 464                         }
 465                         break;
 466                 case EXD_CPU_CPUID:
 467                         if (nvlist_alloc(&elem->pke_properties,
 468                             NV_UNIQUE_NAME_TYPE, 0) != 0) {
 469                                 pool_seterror(POE_SYSTEM);
 470                                 return (PO_FAIL);
 471                         }
 472                         if (nvlist_add_int64(elem->pke_properties,
 473                             "cpu.sys_id",
 474                             (int64_t)eo->eo_item.ei_uint32) != 0) {
 475                                 pool_seterror(POE_SYSTEM);
 476                                 return (PO_FAIL);
 477                         }
 478                         if ((old_elem = dict_get(prov->pkc_elements, elem)) !=
 479                             NULL) {
 480                                 nvlist_free(old_elem->pke_properties);
 481                                 old_elem->pke_properties = elem->pke_properties;
 482                                 old_elem->pke_parent = elem->pke_parent;
 483                                 pool_knl_elem_free(elem, PO_FALSE);
 484                                 elem = old_elem;
 485                         } else {
 486                                 if (dict_put(prov->pkc_elements, elem, elem) !=
 487                                     NULL) {
 488                                         pool_knl_elem_free(elem, PO_TRUE);
 489                                         pool_seterror(POE_SYSTEM);
 490                                         return (PO_FAIL);
 491                                 }
 492                         }
 493                         break;
 494                 case EXD_GROUP_POOL:
 495                         if ((elem = pool_knl_elem_wrap(conf, PEC_POOL,
 496                             PREC_INVALID, PCEC_INVALID)) == NULL)
 497                                 return (PO_FAIL);
 498                         if (pool_set_container(psl->psl_system,
 499                             (pool_elem_t *)elem) != PO_SUCCESS) {
 500                                 pool_seterror(POE_SYSTEM);
 501                                 return (PO_FAIL);
 502                         }
 503                         break;
 504                 case EXD_GROUP_PSET:
 505                         if ((elem = pool_knl_elem_wrap(conf, PEC_RES_COMP,
 506                             PREC_PSET, PCEC_INVALID)) == NULL)
 507                                 return (PO_FAIL);
 508                         if (pool_set_container(psl->psl_system,
 509                             (pool_elem_t *)elem) != PO_SUCCESS) {
 510                                 pool_seterror(POE_SYSTEM);
 511                                 return (PO_FAIL);
 512                         }
 513                         break;
 514                 case EXD_GROUP_CPU:
 515                         if ((elem = pool_knl_elem_wrap(conf, PEC_COMP,
 516                             PREC_INVALID, PCEC_CPU)) == NULL)
 517                                 return (PO_FAIL);
 518                         if (pool_set_container((pool_elem_t *)psl->psl_pset,
 519                             (pool_elem_t *)elem) != PO_SUCCESS) {
 520                                 pool_seterror(POE_SYSTEM);
 521                                 return (PO_FAIL);
 522                         }
 523                         break;
 524                 default:
 525                         break;
 526                 }
 527 
 528 
 529                 if (eo->eo_type == EO_GROUP) {
 530                         if ((ret = load_group(conf, elem, eo, psl)) == PO_FAIL)
 531                                 break;
 532                 }
 533         }
 534         return (ret);
 535 }
 536 
 537 /*
 538  * Push a snapshot entry onto the list of pools in the snapshot.
 539  */
 540 int
 541 pool_knl_snap_load_push(pool_snap_load_t *psl, pool_knl_pool_t *pkp)
 542 {
 543         pool_set_xref_t *psx;
 544 
 545         if ((psx = malloc(sizeof (pool_set_xref_t))) == NULL) {
 546                 pool_seterror(POE_SYSTEM);
 547                 return (PO_FAIL);
 548         }
 549         (void) memset(psx, 0, sizeof (pool_set_xref_t));
 550         psx->psx_pool = pkp;
 551         /*
 552          * Push onto the list of pools
 553          */
 554         psx->psx_next = psl->psl_xref;
 555         psl->psl_xref = psx;
 556 
 557         return (PO_SUCCESS);
 558 }
 559 
 560 /*
 561  * Update the current cross-reference for the supplied type of
 562  * resource.
 563  */
 564 int
 565 pool_knl_snap_load_update(pool_snap_load_t *psl, int type, uint_t id)
 566 {
 567         switch (type) {
 568         case EXD_POOL_PSETID:
 569                 psl->psl_xref->psx_pset_id = id;
 570                 break;
 571         default:
 572                 return (PO_FAIL);
 573         }
 574 
 575         return (PO_SUCCESS);
 576 }
 577 
 578 /*
 579  * Remove a resource entry with the supplied type and id from the
 580  * snapshot list when it is no longer required.
 581  */
 582 int
 583 pool_knl_snap_load_remove(pool_snap_load_t *psl, int type, uint_t id)
 584 {
 585         pool_set_xref_t *current, *prev, *next;
 586 
 587         for (prev = NULL, current = psl->psl_xref; current != NULL;
 588             current = next) {
 589                 switch (type) {
 590                 case EXD_PSET_PSETID:
 591                         if (current->psx_pset_id == id)
 592                                 current->psx_pool->pkp_assoc[PREC_PSET] =
 593                                     psl->psl_pset;
 594                         break;
 595                 default:
 596                         return (PO_FAIL);
 597                 }
 598                 next = current->psx_next;
 599                 if (current->psx_pool->pkp_assoc[PREC_PSET] != NULL) {
 600                         if (prev != NULL) {
 601                                 prev->psx_next = current->psx_next;
 602                         } else {
 603                                 psl->psl_xref = current->psx_next;
 604                         }
 605                         free(current);
 606                 } else
 607                         prev = current;
 608         }
 609 
 610         return (PO_SUCCESS);
 611 }
 612 
 613 /*
 614  * Return the nvpair with the supplied name from the supplied list.
 615  *
 616  * NULL is returned if the name cannot be found in the list.
 617  */
 618 nvpair_t *
 619 pool_knl_find_nvpair(nvlist_t *l, const char *name)
 620 {
 621         nvpair_t *pair;
 622 
 623         for (pair = nvlist_next_nvpair(l, NULL); pair != NULL;
 624             pair = nvlist_next_nvpair(l, pair)) {
 625                 if (strcmp(nvpair_name(pair), name) == 0)
 626                         break;
 627         }
 628         return (pair);
 629 }
 630 
 631 /*
 632  * Close the configuration. There are a few steps to closing a configuration:
 633  * - Close the pseudo device
 634  * - Free the data provider
 635  * Returns PO_SUCCESS/PO_FAIL
 636  */
 637 int
 638 pool_knl_close(pool_conf_t *conf)
 639 {
 640         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
 641 
 642         if (close(prov->pkc_fd) < 0) {
 643                 pool_seterror(POE_SYSTEM);
 644                 return (PO_FAIL);
 645         }
 646         /*
 647          * Rollback any pending changes before freeing the prov. This
 648          * ensures there are no memory leaks from pending transactions.
 649          * However, don't rollback when we've done a temporary pool since the
 650          * pool/resources haven't really been committed in this case.
 651          * They will all be freed in pool_knl_connection_free and we don't
 652          * want to double free them.
 653          */
 654         if (!(conf->pc_prov->pc_oflags & PO_TEMP))
 655                 (void) pool_knl_rollback(conf);
 656         pool_knl_connection_free(prov);
 657         return (PO_SUCCESS);
 658 }
 659 
 660 /*
 661  * Remove elements in this map (previously identified as "dead") from
 662  * the configuration map (prov->pkc_elements).
 663  */
 664 
 665 /* ARGSUSED1 */
 666 static void
 667 remove_dead_elems(const void *key, void **value, void *cl)
 668 {
 669         pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
 670         pool_conf_t *conf = TO_CONF(TO_ELEM(pke));
 671         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
 672 
 673         assert(dict_remove(prov->pkc_elements, pke) != NULL);
 674 #ifdef DEBUG
 675         dprintf("remove_dead_elems:\n");
 676         pool_elem_dprintf(TO_ELEM(pke));
 677 #endif  /* DEBUG */
 678         pool_knl_elem_free(pke, PO_TRUE);
 679 }
 680 
 681 /*
 682  * Find elements which were not updated the last time that
 683  * load_group() was called. Add those elements into a separate map
 684  * (passed in cl) which will be later used to remove these elements
 685  * from the configuration map.
 686  */
 687 /* ARGSUSED1 */
 688 static void
 689 find_dead_elems(const void *key, void **value, void *cl)
 690 {
 691         pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
 692         pool_conf_t *conf = TO_CONF(TO_ELEM(pke));
 693         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
 694         dict_hdl_t *dead_map = (dict_hdl_t *)cl;
 695 
 696         if (pke->pke_ltime < prov->pkc_ltime)
 697                 (void) dict_put(dead_map, pke, pke);
 698 }
 699 
 700 /*
 701  * Update the snapshot held by the library. This function acts as the
 702  * controller for the snapshot update procedure. Then snapshot is
 703  * actually updated in multiple phases by the load_group() function
 704  * (which updates existing elements and creates new elements as
 705  * required) and then by find_dead_elems and remove_dead_elems
 706  * (respectively responsible for identifying elements which are to be
 707  * removed and then removing them).
 708  *
 709  * Returns PO_SUCCESS
 710  */
 711 int
 712 pool_knl_update(pool_conf_t *conf, int *changed)
 713 {
 714         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
 715         pool_query_t query = {0};
 716         ea_object_t *ep;
 717         dict_hdl_t *dead_map;
 718         pool_snap_load_t psl = { NULL };
 719 
 720         /*
 721          * Ensure the library snapshot is consistent, if there are any
 722          * outstanding transactions return failure.
 723          */
 724         if (log_size(prov->pkc_log) != 0) {
 725                 pool_seterror(POE_INVALID_CONF);
 726                 return (PO_FAIL);
 727         }
 728         /*
 729          * Query the kernel for a snapshot of the configuration state. Use
 730          * load_group to allocate the user-land representation of the
 731          * data returned in the snapshot.
 732          */
 733         /* LINTED E_CONSTANT_CONDITION */
 734         while (1) {
 735                 if (ioctl(prov->pkc_fd, POOL_QUERY, &query) < 0) {
 736                         pool_seterror(POE_SYSTEM);
 737                         return (PO_FAIL);
 738                 }
 739                 if ((query.pq_io_buf = calloc(1,
 740                     (query.pq_io_bufsize < KERNEL_SNAPSHOT_BUF_SZ) ?
 741                     query.pq_io_bufsize * 2 : query.pq_io_bufsize)) == NULL) {
 742                         pool_seterror(POE_SYSTEM);
 743                         return (PO_FAIL);
 744                 }
 745                 if (ioctl(prov->pkc_fd, POOL_QUERY, &query) < 0) {
 746                         free(query.pq_io_buf);
 747                         if (errno != ENOMEM) {
 748                                 pool_seterror(POE_SYSTEM);
 749                                 return (PO_FAIL);
 750                         }
 751                         query.pq_io_bufsize = 0;
 752                         query.pq_io_buf = NULL;
 753                 } else
 754                         break;
 755         }
 756         if (ea_unpack_object(&ep, EUP_NOALLOC, query.pq_io_buf,
 757             query.pq_io_bufsize) != EO_GROUP) {
 758                 free(query.pq_io_buf);
 759                 pool_seterror(POE_DATASTORE);
 760                 return (PO_FAIL);
 761         }
 762         /*
 763          * Update the library snapshot
 764          */
 765         psl.psl_changed = changed;
 766         prov->pkc_lotime = prov->pkc_ltime;
 767         if (load_group(conf, NULL, ep, &psl) != PO_SUCCESS) {
 768                 free(query.pq_io_buf);
 769                 ea_free_object(ep, EUP_NOALLOC);
 770                 return (PO_FAIL);
 771         }
 772 
 773         free(query.pq_io_buf);
 774         ea_free_object(ep, EUP_NOALLOC);
 775         /*
 776          * Now search the dictionary for items that must be removed because
 777          * they were neither created nor updated.
 778          */
 779         if ((dead_map = dict_new((int (*)(const void *, const void *))
 780             pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) {
 781                 pool_seterror(POE_SYSTEM);
 782                 return (PO_FAIL);
 783         }
 784         dict_map(prov->pkc_elements, find_dead_elems, dead_map);
 785 
 786         if (dict_length(dead_map) > 0) {
 787                 dict_map(dead_map, remove_dead_elems, NULL);
 788         }
 789         dict_free(&dead_map);
 790 
 791         return (PO_SUCCESS);
 792 }
 793 
 794 /*
 795  * Rely on the kernel to always keep a kernel configuration valid.
 796  * Returns PO_SUCCESS
 797  */
 798 /* ARGSUSED */
 799 int
 800 pool_knl_validate(const pool_conf_t *conf, pool_valid_level_t level)
 801 {
 802         return ((conf->pc_state == POF_INVALID) ? PO_FAIL : PO_SUCCESS);
 803 }
 804 
 805 /*
 806  * Process all the outstanding transactions in the log. If the processing
 807  * fails, then attempt to rollback and "undo" the changes.
 808  */
 809 int
 810 pool_knl_commit(pool_conf_t *conf)
 811 {
 812         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
 813         int lock = 1;
 814 
 815         /*
 816          * Lock the kernel state for the commit
 817          */
 818         if (ioctl(prov->pkc_fd, POOL_COMMIT, lock) < 0) {
 819                 pool_seterror(POE_SYSTEM);
 820                 return (PO_FAIL);
 821         }
 822         lock = 0;
 823         /*
 824          * If the state is LS_FAIL, then try to recover before
 825          * performing the commit.
 826          */
 827         if (prov->pkc_log->l_state == LS_FAIL) {
 828                 if (pool_knl_recover(conf) == PO_FAIL) {
 829                         /*
 830                          * Unlock the kernel state for the
 831                          * commit. Assert that this * can't fail,
 832                          * since if it ever does fail the library is
 833                          * unusable.
 834                          */
 835                         assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0);
 836                 }
 837         }
 838         /*
 839          * Commit the log
 840          */
 841         if (log_walk(prov->pkc_log, log_item_commit) != PO_SUCCESS) {
 842                 (void) pool_knl_recover(conf);
 843                 /*
 844                  * Unlock the kernel state for the commit. Assert that
 845                  * this can't fail, since if it ever does fail the
 846                  * library is unusable.
 847                  */
 848                 assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0);
 849                 pool_seterror(POE_SYSTEM);
 850                 return (PO_FAIL);
 851         }
 852         /*
 853          * Unlock the kernel state for the commit. Assert that this
 854          * can't fail, since if it ever does fail the library is
 855          * unusable.
 856          */
 857         assert(ioctl(prov->pkc_fd, POOL_COMMIT, lock) >= 0);
 858         /*
 859          * Release the log resources
 860          */
 861         (void) log_walk(prov->pkc_log, log_item_release);
 862         log_empty(prov->pkc_log);
 863         return (PO_SUCCESS);
 864 }
 865 
 866 /*
 867  * prop_build_cb() is designed to be called from
 868  * pool_walk_properties(). The property value is used to put an XML
 869  * property on the supplied ktx_node. This is an essential part of the
 870  * mechanism used to export a kernel configuration in libpool XML
 871  * form.
 872  */
 873 /* ARGSUSED */
 874 static int
 875 prop_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name,
 876     pool_value_t *pval, void *user)
 877 {
 878         struct knl_to_xml *info = (struct knl_to_xml *)user;
 879 
 880         return (pool_knl_put_xml_property((pool_elem_t *)pe, info->ktx_node,
 881             name, pval));
 882 }
 883 
 884 /*
 885  * Duplicate some of the functionality from pool_xml_put_property()
 886  * (see pool_xml.c) to allow a kernel configuration to add XML nodes
 887  * to an XML tree which represents the kernel configuration. This is
 888  * an essential part of the mechanism used to export a kernel
 889  * configuration in libpool XML form.
 890  */
 891 int
 892 pool_knl_put_xml_property(pool_elem_t *pe, xmlNodePtr node, const char *name,
 893     const pool_value_t *val)
 894 {
 895 
 896         /*
 897          * "type" is a special attribute which is not visible ever outside of
 898          * libpool. Use the specific type accessor function.
 899          */
 900         if (strcmp(name, c_type) == 0) {
 901                 return (pool_xml_set_attr(node, BAD_CAST name,
 902                     val));
 903         }
 904         if (is_ns_property(pe, name) != NULL) { /* in ns */
 905                 if (pool_xml_set_attr(node,
 906                     BAD_CAST property_name_minus_ns(pe, name), val) == PO_FAIL)
 907                         return (pool_xml_set_prop(node, BAD_CAST name,
 908                             val));
 909         } else
 910                 return (pool_xml_set_prop(node, BAD_CAST name, val));
 911         return (PO_SUCCESS);
 912 }
 913 
 914 /*
 915  * Export the kernel configuration as an XML file. The configuration
 916  * is used to build an XML document in memory. This document is then
 917  * saved to the supplied location.
 918  */
 919 int
 920 pool_knl_export(const pool_conf_t *conf, const char *location,
 921     pool_export_format_t fmt)
 922 {
 923         xmlNodePtr node_comment;
 924         xmlNodePtr system;
 925         int ret;
 926         pool_t **ps;
 927         pool_resource_t **rs;
 928         uint_t nelem;
 929         int i;
 930         struct knl_to_xml info;
 931         char_buf_t *cb = NULL;
 932         xmlValidCtxtPtr cvp;
 933 
 934         xml_init();
 935 
 936 
 937         switch (fmt) {
 938         case POX_NATIVE:
 939                 info.ktx_doc = xmlNewDoc(BAD_CAST "1.0");
 940                 (void) xmlCreateIntSubset(info.ktx_doc, BAD_CAST "system",
 941                     BAD_CAST "-//Sun Microsystems Inc//DTD Resource "
 942                     "Management All//EN",
 943                     BAD_CAST dtd_location);
 944 
 945                 if ((cvp = xmlNewValidCtxt()) == NULL) {
 946                         xmlFreeDoc(info.ktx_doc);
 947                         pool_seterror(POE_DATASTORE);
 948                         return (PO_FAIL);
 949                 }
 950                 /*
 951                  * Call xmlValidateDocument() to force the parsing of
 952                  * the DTD. Ignore errors and warning messages as we
 953                  * know the document isn't valid.
 954                  */
 955                 (void) xmlValidateDocument(cvp, info.ktx_doc);
 956                 xmlFreeValidCtxt(cvp);
 957                 if ((info.ktx_node = node_create(NULL, BAD_CAST "system")) ==
 958                     NULL) {
 959                         xmlFreeDoc(info.ktx_doc);
 960                         pool_seterror(POE_DATASTORE);
 961                         return (PO_FAIL);
 962                 }
 963 
 964                 system = info.ktx_node;
 965                 info.ktx_doc->_private = (void *)conf;
 966 
 967                 (void) xmlDocSetRootElement(info.ktx_doc, info.ktx_node);
 968                 (void) xmlSetProp(info.ktx_node, BAD_CAST c_ref_id,
 969                     BAD_CAST "dummy");
 970                 if ((node_comment = xmlNewDocComment(info.ktx_doc,
 971                     BAD_CAST "\nConfiguration for pools facility. Do NOT"
 972                     " edit this file by hand - use poolcfg(1)"
 973                     " or libpool(3POOL) instead.\n")) == NULL) {
 974                         xmlFreeDoc(info.ktx_doc);
 975                         pool_seterror(POE_DATASTORE);
 976                         return (PO_FAIL);
 977                 }
 978                 if (xmlAddPrevSibling(info.ktx_node, node_comment) == NULL) {
 979                         xmlFree(node_comment);
 980                         xmlFreeDoc(info.ktx_doc);
 981                         pool_seterror(POE_DATASTORE);
 982                         return (PO_FAIL);
 983                 }
 984                 if (pool_walk_any_properties((pool_conf_t *)conf,
 985                     pool_conf_to_elem(conf), &info, prop_build_cb, 1) ==
 986                     PO_FAIL) {
 987                         xmlFreeDoc(info.ktx_doc);
 988                         return (PO_FAIL);
 989                 }
 990                 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
 991                         xmlFreeDoc(info.ktx_doc);
 992                         return (PO_FAIL);
 993                 }
 994                 /*
 995                  * Now add pool details
 996                  */
 997                 if ((ps = pool_query_pools(conf, &nelem, NULL)) != NULL) {
 998                         for (i = 0; i < nelem; i++) {
 999                                 pool_elem_t *elem = TO_ELEM(ps[i]);
1000                                 uint_t nreselem;
1001                                 const char *sep = "";
1002                                 int j;
1003 
1004                                 if (elem_is_tmp(elem))
1005                                         continue;
1006 
1007                                 if ((info.ktx_node = node_create(system,
1008                                     BAD_CAST element_class_tags
1009                                     [pool_elem_class(elem)])) == NULL) {
1010                                         free(ps);
1011                                         free_char_buf(cb);
1012                                         xmlFreeDoc(info.ktx_doc);
1013                                         pool_seterror(POE_DATASTORE);
1014                                         return (PO_FAIL);
1015                                 }
1016                                 if (pool_walk_any_properties(
1017                                     (pool_conf_t *)conf,
1018                                     elem, &info, prop_build_cb, 1) == PO_FAIL) {
1019                                         free(ps);
1020                                         free_char_buf(cb);
1021                                         xmlFreeDoc(info.ktx_doc);
1022                                         return (PO_FAIL);
1023                                 }
1024                                 /*
1025                                  * TODO: pset specific res manipulation
1026                                  */
1027                                 if ((rs = pool_query_pool_resources(conf, ps[i],
1028                                     &nreselem, NULL)) == NULL) {
1029                                         free(ps);
1030                                         free_char_buf(cb);
1031                                         xmlFreeDoc(info.ktx_doc);
1032                                         pool_seterror(POE_INVALID_CONF);
1033                                         return (PO_FAIL);
1034                                 }
1035                                 if (set_char_buf(cb, "") == PO_FAIL) {
1036                                         free(rs);
1037                                         free(ps);
1038                                         free_char_buf(cb);
1039                                         xmlFreeDoc(info.ktx_doc);
1040                                         return (PO_FAIL);
1041                                 }
1042                                 for (j = 0; j < nreselem; j++) {
1043                                         pool_elem_t *reselem = TO_ELEM(rs[j]);
1044                                         if (append_char_buf(cb, "%s%s_%d", sep,
1045                                             pool_elem_class_string(reselem),
1046                                             (int)elem_get_sysid(reselem)) ==
1047                                             PO_FAIL) {
1048                                                 free(rs);
1049                                                 free(ps);
1050                                                 free_char_buf(cb);
1051                                                 xmlFreeDoc(info.ktx_doc);
1052                                                 return (PO_FAIL);
1053                                         }
1054                                         sep = " ";
1055                                 }
1056                                 free(rs);
1057                                 (void) xmlSetProp(info.ktx_node, BAD_CAST "res",
1058                                     BAD_CAST cb->cb_buf);
1059                                 if (set_char_buf(cb, "%s_%d",
1060                                     pool_elem_class_string(elem),
1061                                     (int)elem_get_sysid(elem)) == PO_FAIL) {
1062                                         free(ps);
1063                                         free_char_buf(cb);
1064                                         xmlFreeDoc(info.ktx_doc);
1065                                         return (PO_FAIL);
1066                                 }
1067                                 (void) xmlSetProp(info.ktx_node,
1068                                     BAD_CAST c_ref_id,
1069                                     BAD_CAST  cb->cb_buf);
1070                         }
1071                         free(ps);
1072                 }
1073                 /*
1074                  * Now add resource details (including components)
1075                  */
1076                 if ((rs = pool_query_resources(conf, &nelem, NULL)) != NULL) {
1077                         for (i = 0; i < nelem; i++) {
1078                                 pool_elem_t *elem = TO_ELEM(rs[i]);
1079                                 pool_component_t **cs = NULL;
1080                                 uint_t ncompelem;
1081                                 int j;
1082 
1083                                 if (elem_is_tmp(elem))
1084                                         continue;
1085 
1086                                 if ((info.ktx_node = node_create(system,
1087                                     BAD_CAST element_class_tags
1088                                     [pool_elem_class(elem)])) == NULL) {
1089                                         free(rs);
1090                                         free_char_buf(cb);
1091                                         xmlFreeDoc(info.ktx_doc);
1092                                         pool_seterror(POE_DATASTORE);
1093                                         return (PO_FAIL);
1094                                 }
1095                                 if (pool_walk_any_properties(
1096                                     (pool_conf_t *)conf,
1097                                     elem, &info, prop_build_cb, 1) == PO_FAIL) {
1098                                         free(rs);
1099                                         free_char_buf(cb);
1100                                         xmlFreeDoc(info.ktx_doc);
1101                                         return (PO_FAIL);
1102                                 }
1103                                 if (set_char_buf(cb, "%s_%d",
1104                                     pool_elem_class_string(elem),
1105                                     (int)elem_get_sysid(elem)) == PO_FAIL) {
1106                                         free(rs);
1107                                         free_char_buf(cb);
1108                                         xmlFreeDoc(info.ktx_doc);
1109                                         return (PO_FAIL);
1110                                 }
1111                                 (void) xmlSetProp(info.ktx_node,
1112                                     BAD_CAST c_ref_id,
1113                                     BAD_CAST  cb->cb_buf);
1114                                 if ((cs = pool_query_resource_components(conf,
1115                                     rs[i], &ncompelem, NULL)) != NULL) {
1116                                         xmlNodePtr resource = info.ktx_node;
1117 
1118                                         for (j = 0; j < ncompelem; j++) {
1119                                                 pool_elem_t *compelem =
1120                                                     TO_ELEM(cs[j]);
1121                                                 if ((info.ktx_node =
1122                                                     node_create(resource,
1123                                                     BAD_CAST element_class_tags
1124                                                     [pool_elem_class(
1125                                                     compelem)])) == NULL) {
1126                                                         pool_seterror(
1127                                                             POE_DATASTORE);
1128                                                         free(rs);
1129                                                         free(cs);
1130                                                         free_char_buf(cb);
1131                                                         xmlFreeDoc(info.
1132                                                             ktx_doc);
1133                                                         return (PO_FAIL);
1134                                                 }
1135                                                 if (pool_walk_any_properties(
1136                                                     (pool_conf_t *)conf,
1137                                                     compelem, &info,
1138                                                     prop_build_cb, 1) ==
1139                                                     PO_FAIL) {
1140                                                         free(rs);
1141                                                         free(cs);
1142                                                         free_char_buf(cb);
1143                                                         xmlFreeDoc(info.
1144                                                             ktx_doc);
1145                                                         return (PO_FAIL);
1146                                                 }
1147                                                 if (set_char_buf(cb, "%s_%d",
1148                                                     pool_elem_class_string(
1149                                                     compelem),
1150                                                     (int)elem_get_sysid(
1151                                                     compelem)) == PO_FAIL) {
1152                                                         free(rs);
1153                                                         free(cs);
1154                                                         free_char_buf(cb);
1155                                                         xmlFreeDoc(info.
1156                                                             ktx_doc);
1157                                                         return (PO_FAIL);
1158                                                 }
1159                                                 (void) xmlSetProp(info.ktx_node,
1160                                                     BAD_CAST c_ref_id,
1161                                                     BAD_CAST  cb->cb_buf);
1162                                         }
1163                                         free(cs);
1164                                 }
1165                         }
1166                         free(rs);
1167                 }
1168                 free_char_buf(cb);
1169                 /*
1170                  * Set up the message handlers prior to calling
1171                  * xmlValidateDocument()
1172                  */
1173                 if ((cvp = xmlNewValidCtxt()) == NULL) {
1174                         xmlFreeDoc(info.ktx_doc);
1175                         pool_seterror(POE_DATASTORE);
1176                         return (PO_FAIL);
1177                 }
1178                 cvp->error    = pool_error_func;
1179                 cvp->warning  = pool_error_func;
1180                 if (xmlValidateDocument(cvp, info.ktx_doc) == 0) {
1181                         xmlFreeValidCtxt(cvp);
1182                         xmlFreeDoc(info.ktx_doc);
1183                         pool_seterror(POE_INVALID_CONF);
1184                         return (PO_FAIL);
1185                 }
1186                 xmlFreeValidCtxt(cvp);
1187                 ret = xmlSaveFormatFile(location, info.ktx_doc, 1);
1188                 xmlFreeDoc(info.ktx_doc);
1189                 if (ret == -1) {
1190                         pool_seterror(POE_SYSTEM);
1191                         return (PO_FAIL);
1192                 }
1193                 return (PO_SUCCESS);
1194         default:
1195                 pool_seterror(POE_BADPARAM);
1196                 return (PO_FAIL);
1197         }
1198 }
1199 
1200 /*
1201  * Rollback the changes to the kernel
1202  */
1203 int
1204 pool_knl_recover(pool_conf_t *conf)
1205 {
1206         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1207 
1208         prov->pkc_log->l_state = LS_RECOVER;
1209         if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) {
1210                 dprintf("Library configuration consistency error\n");
1211                 prov->pkc_log->l_state = LS_FAIL;
1212                 pool_seterror(POE_INVALID_CONF);
1213                 return (PO_FAIL);
1214         }
1215         prov->pkc_log->l_state = LS_DO;
1216         return (PO_SUCCESS);
1217 }
1218 
1219 /*
1220  * Rollback the changes to the configuration
1221  */
1222 int
1223 pool_knl_rollback(pool_conf_t *conf)
1224 {
1225         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1226 
1227         prov->pkc_log->l_state = LS_UNDO;
1228         if (log_reverse_walk(prov->pkc_log, log_item_undo) != PO_SUCCESS) {
1229                 dprintf("Kernel configuration consistency error\n");
1230                 (void) log_walk(prov->pkc_log, log_item_release);
1231                 log_empty(prov->pkc_log);
1232                 prov->pkc_log->l_state = LS_FAIL;
1233                 pool_seterror(POE_INVALID_CONF);
1234                 return (PO_FAIL);
1235         }
1236         (void) log_walk(prov->pkc_log, log_item_release);
1237         log_empty(prov->pkc_log);
1238         prov->pkc_log->l_state = LS_DO;
1239         return (PO_SUCCESS);
1240 }
1241 
1242 /*
1243  * Callback used to build the result set for a query. Each invocation will
1244  * supply a candidate element for inclusion. The element is filtered by:
1245  * - class
1246  * - properties
1247  * If the element "matches" the target, then it is added to the result
1248  * set, otherwise it is ignored.
1249  */
1250 /* ARGSUSED1 */
1251 static void
1252 build_result_set(const void *key, void **value, void *cl)
1253 {
1254         struct query_obj *qo = (struct query_obj *)cl;
1255         pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
1256 
1257         /*
1258          * Check to see if it's the right class of element
1259          */
1260         if (qo->classes & (1 << pool_elem_class((pool_elem_t *)key))) {
1261                 int i;
1262                 /*
1263                  * Now check to see if the src element is correct. If no src
1264                  * element is supplied, ignore this check
1265                  */
1266                 if (qo->src) {
1267                         pool_knl_elem_t *parent;
1268 
1269                         for (parent = pke; parent != NULL;
1270                             parent = parent->pke_parent) {
1271                                 if (parent == (pool_knl_elem_t *)qo->src)
1272                                         break;
1273                         }
1274                         if (parent == NULL)
1275                                 return;
1276                 }
1277                 /*
1278                  * Now check for property matches (if there are any specified)
1279                  */
1280                 if (qo->props) {
1281                         int matched = PO_TRUE;
1282                         for (i = 0; qo->props[i] != NULL; i++) {
1283                                 pool_value_t val = POOL_VALUE_INITIALIZER;
1284 
1285                                 if (pool_get_property(TO_CONF(TO_ELEM(pke)),
1286                                     (pool_elem_t *)pke,
1287                                     pool_value_get_name(qo->props[i]), &val) ==
1288                                     POC_INVAL) {
1289                                         matched = PO_FALSE;
1290                                         break;
1291                                 } else {
1292                                         if (pool_value_equal(qo->props[i],
1293                                             &val) != PO_TRUE) {
1294                                                 matched = PO_FALSE;
1295                                                 break;
1296                                         }
1297                                 }
1298                         }
1299                         if (matched == PO_TRUE)
1300                                 (void) pool_knl_result_set_append(qo->rs,
1301                                     (pool_knl_elem_t *)key);
1302                 } else {
1303                         (void) pool_knl_result_set_append(qo->rs,
1304                             (pool_knl_elem_t *)key);
1305                 }
1306         }
1307 }
1308 
1309 /*
1310  * Execute the supplied query and return a result set which contains
1311  * all qualifying elements.
1312  */
1313 pool_result_set_t *
1314 pool_knl_exec_query(const pool_conf_t *conf, const pool_elem_t *src,
1315     const char *src_attr, pool_elem_class_t classes, pool_value_t **props)
1316 {
1317         pool_knl_result_set_t *rs;
1318         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1319         struct query_obj qo;
1320         int matched = PO_TRUE;
1321 
1322         /*
1323          * Have a buffer at this point, that we can use
1324          */
1325         if ((rs = pool_knl_result_set_alloc(conf)) == NULL) {
1326                 return (NULL);
1327         }
1328         qo.conf = conf;
1329         qo.src = src;
1330         qo.src_attr = src_attr;
1331         qo.classes = classes;
1332         qo.props = props;
1333         qo.rs = rs;
1334         if (src_attr != NULL) {
1335                 pool_knl_pool_t *pkp = (pool_knl_pool_t *)src;
1336 
1337                 /*
1338                  * Note: This logic is resource specific and must be
1339                  * extended for additional resource types.
1340                  */
1341                 /*
1342                  * Check for property matches (if there are any specified)
1343                  */
1344                 if (props) {
1345                         int i;
1346 
1347                         for (i = 0; props[i] != NULL; i++) {
1348                                 pool_value_t val = POOL_VALUE_INITIALIZER;
1349 
1350                                 if (pool_get_property(conf,
1351                                     (pool_elem_t *)pkp->pkp_assoc[PREC_PSET],
1352                                     pool_value_get_name(props[i]), &val) ==
1353                                     POC_INVAL) {
1354                                         matched = PO_FALSE;
1355                                         break;
1356                                 } else {
1357                                         if (pool_value_equal(props[i],
1358                                             &val) != PO_TRUE) {
1359                                                 matched = PO_FALSE;
1360                                                 break;
1361                                         }
1362                                 }
1363                         }
1364                 }
1365 
1366                 if (matched == PO_TRUE)
1367                         (void) pool_knl_result_set_append(rs,
1368                             (pool_knl_elem_t *)pkp->pkp_assoc[PREC_PSET]);
1369         } else
1370                 dict_map(prov->pkc_elements, build_result_set, &qo);
1371 
1372         if (rs->pkr_count == 0)
1373                 pool_seterror(POE_INVALID_SEARCH);
1374         return ((pool_result_set_t *)rs);
1375 }
1376 
1377 /*
1378  * Callback function intended to be used from pool_walk_pools(). If
1379  * the supplied pool is not the default pool attempt to destroy it.
1380  */
1381 /*ARGSUSED*/
1382 static int
1383 destroy_pool_cb(pool_conf_t *conf, pool_t *pool, void *unused)
1384 {
1385         if (elem_is_default(TO_ELEM(pool)) != PO_TRUE)
1386                 return (pool_destroy(conf, pool));
1387         /*
1388          * Return PO_SUCCESS even though we don't delete the default
1389          * pool so that the walk continues
1390          */
1391         return (PO_SUCCESS);
1392 }
1393 
1394 /*
1395  * Remove the configuration details. This means remove all elements
1396  * apart from the system elements.
1397  */
1398 int
1399 pool_knl_remove(pool_conf_t *conf)
1400 {
1401         uint_t i, nelem;
1402         pool_resource_t **resources;
1403 
1404         conf->pc_state = POF_DESTROY;
1405         if ((resources = pool_query_resources(conf, &nelem, NULL)) != NULL) {
1406                 for (i = 0; i < nelem; i++) {
1407                         if (resource_is_system(resources[i]) == PO_FALSE)
1408                                 if (pool_resource_destroy(conf, resources[i]) !=
1409                                     PO_SUCCESS) {
1410                                         pool_seterror(POE_INVALID_CONF);
1411                                         return (PO_FAIL);
1412                                 }
1413                 }
1414                 free(resources);
1415         }
1416         (void) pool_walk_pools(conf, conf, destroy_pool_cb);
1417         if (pool_conf_commit(conf, PO_FALSE) != PO_SUCCESS)
1418                 return (PO_FAIL);
1419 
1420         if (pool_conf_close(conf) != PO_SUCCESS)
1421                 return (PO_FAIL);
1422 
1423         return (PO_SUCCESS);
1424 }
1425 
1426 /*
1427  * Determine the name of the pool to which the supplied pid is
1428  * bound. If it cannot be determined return NULL.
1429  */
1430 char *
1431 pool_knl_get_binding(pool_conf_t *conf, pid_t pid)
1432 {
1433         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1434         const char *sval;
1435         char *name = NULL;
1436         pool_bindq_t bindq;
1437         pool_value_t *props[] = { NULL, NULL };
1438         uint_t nelem = 0;
1439         pool_t **pools;
1440         pool_value_t val = POOL_VALUE_INITIALIZER;
1441 
1442         props[0] = &val;
1443 
1444         bindq.pb_o_id_type = P_PID;
1445         bindq.pb_o_id = pid;
1446         if (ioctl(prov->pkc_fd, POOL_BINDQ, &bindq) < 0) {
1447                 pool_seterror(POE_SYSTEM);
1448                 return (NULL);
1449         }
1450 
1451         if (pool_value_set_name(props[0], "pool.sys_id") != PO_SUCCESS) {
1452                 return (NULL);
1453         }
1454         pool_value_set_int64(props[0], bindq.pb_i_id);
1455         if ((pools = pool_query_pools(conf, &nelem, props)) == NULL) {
1456                 pool_seterror(POE_BADPARAM);
1457                 return (NULL);
1458         }
1459 
1460         if (nelem != 1) {
1461                 free(pools);
1462                 pool_seterror(POE_INVALID_CONF);
1463                 return (NULL);
1464         }
1465         if (pool_get_ns_property(TO_ELEM(pools[0]), c_name, props[0])
1466             == POC_INVAL) {
1467                 free(pools);
1468                 return (NULL);
1469         }
1470         if (pool_value_get_string(props[0], &sval) != PO_SUCCESS) {
1471                 free(pools);
1472                 return (NULL);
1473         }
1474         if ((name = strdup(sval)) == NULL) {
1475                 free(pools);
1476                 pool_seterror(POE_SYSTEM);
1477                 return (NULL);
1478         }
1479         return (name);
1480 }
1481 
1482 /*
1483  * Bind idtype id to the pool name.
1484  */
1485 int
1486 pool_knl_set_binding(pool_conf_t *conf, const char *pool_name, idtype_t idtype,
1487     id_t id)
1488 {
1489         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1490         pool_bind_t bind;
1491         pool_t *pool;
1492         int ret;
1493 
1494         if ((pool = pool_get_pool(conf, pool_name)) == NULL)
1495                 return (PO_FAIL);
1496 
1497         bind.pb_o_id_type = idtype;
1498         bind.pb_o_id = id;
1499         bind.pb_o_pool_id = elem_get_sysid(TO_ELEM(pool));
1500 
1501         while ((ret = ioctl(prov->pkc_fd, POOL_BIND, &bind)) < 0 &&
1502             errno == EAGAIN)
1503                 ;
1504         if (ret < 0) {
1505                 pool_seterror(POE_SYSTEM);
1506                 return (PO_FAIL);
1507         }
1508         return (PO_SUCCESS);
1509 }
1510 
1511 /*
1512  * pool_knl_get_resource_binding() returns the binding for a pid to
1513  * the supplied type of resource. If a binding cannot be determined,
1514  * NULL is returned.
1515  */
1516 char *
1517 pool_knl_get_resource_binding(pool_conf_t *conf,
1518     pool_resource_elem_class_t type, pid_t pid)
1519 {
1520         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1521         const char *sval;
1522         char *name = NULL;
1523         pool_bindq_t bindq;
1524         pool_value_t *props[] = { NULL, NULL };
1525         uint_t nelem = 0;
1526         pool_t **pools;
1527         pool_resource_t **resources;
1528         pool_value_t val = POOL_VALUE_INITIALIZER;
1529 
1530         props[0] = &val;
1531         bindq.pb_o_id_type = P_PID;
1532         bindq.pb_o_id = pid;
1533         if (ioctl(prov->pkc_fd, POOL_BINDQ, &bindq) < 0) {
1534                 pool_seterror(POE_SYSTEM);
1535                 return (NULL);
1536         }
1537 
1538         if (pool_value_set_name(props[0], "pool.sys_id") != PO_SUCCESS) {
1539                 return (NULL);
1540         }
1541         pool_value_set_int64(props[0], bindq.pb_i_id);
1542         if ((pools = pool_query_pools(conf, &nelem, props)) == NULL) {
1543                 pool_seterror(POE_BADPARAM);
1544                 return (NULL);
1545         }
1546 
1547         if (nelem != 1) {
1548                 free(pools);
1549                 pool_seterror(POE_INVALID_CONF);
1550                 return (NULL);
1551         }
1552 
1553         if (pool_value_set_string(props[0], pool_resource_type_string(type)) !=
1554             PO_SUCCESS ||
1555             pool_value_set_name(props[0], c_type) != PO_SUCCESS) {
1556                 free(pools);
1557                 return (NULL);
1558         }
1559 
1560         if ((resources = pool_query_pool_resources(conf, pools[0], &nelem,
1561             NULL)) == NULL) {
1562                 free(pools);
1563                 pool_seterror(POE_INVALID_CONF);
1564                 return (NULL);
1565         }
1566         free(pools);
1567         if (nelem != 1) {
1568                 free(resources);
1569                 pool_seterror(POE_INVALID_CONF);
1570                 return (NULL);
1571         }
1572         if (pool_get_ns_property(TO_ELEM(resources[0]), c_name, props[0]) ==
1573             POC_INVAL) {
1574                 free(resources);
1575                 return (NULL);
1576         }
1577         free(resources);
1578         if (pool_value_get_string(props[0], &sval) != PO_SUCCESS) {
1579                 return (NULL);
1580         }
1581         if ((name = strdup(sval)) == NULL) {
1582                 pool_seterror(POE_SYSTEM);
1583                 return (NULL);
1584         }
1585         return (name);
1586 }
1587 
1588 /*
1589  * Allocate the required library data structure and initialise it.
1590  */
1591 pool_knl_elem_t *
1592 pool_knl_elem_wrap(pool_conf_t *conf, pool_elem_class_t class,
1593     pool_resource_elem_class_t res_class,
1594     pool_component_elem_class_t comp_class)
1595 {
1596         pool_knl_elem_t *elem;
1597         pool_elem_t *pe;
1598 
1599         switch (class) {
1600         case PEC_SYSTEM:
1601                 if ((elem = malloc(sizeof (pool_knl_system_t))) == NULL) {
1602                         pool_seterror(POE_SYSTEM);
1603                         return (NULL);
1604                 }
1605                 (void) memset(elem, 0, sizeof (pool_knl_system_t));
1606                 break;
1607         case PEC_POOL:
1608                 if ((elem = malloc(sizeof (pool_knl_pool_t))) == NULL) {
1609                         pool_seterror(POE_SYSTEM);
1610                         return (NULL);
1611                 }
1612                 (void) memset(elem, 0, sizeof (pool_knl_pool_t));
1613                 break;
1614         case PEC_RES_COMP:
1615         case PEC_RES_AGG:
1616                 if ((elem = malloc(sizeof (pool_knl_resource_t))) == NULL) {
1617                         pool_seterror(POE_SYSTEM);
1618                         return (NULL);
1619                 }
1620                 (void) memset(elem, 0, sizeof (pool_knl_resource_t));
1621                 break;
1622         case PEC_COMP:
1623                 if ((elem = malloc(sizeof (pool_knl_component_t))) == NULL) {
1624                         pool_seterror(POE_SYSTEM);
1625                         return (NULL);
1626                 }
1627                 (void) memset(elem, 0, sizeof (pool_knl_component_t));
1628                 break;
1629         default:
1630                 pool_seterror(POE_BADPARAM);
1631                 return (NULL);
1632         }
1633         pe = TO_ELEM(elem);
1634         pe->pe_conf = conf;
1635         pe->pe_class = class;
1636         pe->pe_resource_class = res_class;
1637         pe->pe_component_class = comp_class;
1638         /* Set up the function pointers for element manipulation */
1639         pe->pe_get_prop = pool_knl_get_property;
1640         pe->pe_put_prop = pool_knl_put_property;
1641         pe->pe_rm_prop = pool_knl_rm_property;
1642         pe->pe_get_props = pool_knl_get_properties;
1643         pe->pe_remove = pool_knl_elem_remove;
1644         pe->pe_get_container = pool_knl_get_container;
1645         pe->pe_set_container = pool_knl_set_container;
1646         /*
1647          * Specific initialisation for different types of element
1648          */
1649         if (class == PEC_POOL) {
1650                 pool_knl_pool_t *pp = (pool_knl_pool_t *)elem;
1651                 pp->pp_associate = pool_knl_pool_associate;
1652                 pp->pp_dissociate = pool_knl_pool_dissociate;
1653                 pp->pkp_assoc[PREC_PSET] = (pool_knl_resource_t *)
1654                     resource_by_sysid(conf, PS_NONE, "pset");
1655         }
1656         if (class == PEC_RES_COMP || class == PEC_RES_AGG) {
1657                 pool_knl_resource_t *pr = (pool_knl_resource_t *)elem;
1658                 pr->pr_is_system = pool_knl_resource_is_system;
1659                 pr->pr_can_associate = pool_knl_resource_can_associate;
1660         }
1661 #if DEBUG
1662         if (dict_put(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks,
1663             elem, elem) != NULL)
1664                 assert(!"leak map put failed");
1665         dprintf("allocated %p\n", elem);
1666 #endif  /* DEBUG */
1667         return (elem);
1668 }
1669 
1670 /*
1671  * Allocate a new pool_knl_elem_t in the supplied configuration of the
1672  * specified class.
1673  * Returns element pointer/NULL
1674  */
1675 pool_elem_t *
1676 pool_knl_elem_create(pool_conf_t *conf, pool_elem_class_t class,
1677     pool_resource_elem_class_t res_class,
1678     pool_component_elem_class_t comp_class)
1679 {
1680         pool_knl_elem_t *elem;
1681         pool_create_undo_t *create;
1682         pool_knl_connection_t *prov = (pool_knl_connection_t *)conf->pc_prov;
1683         static int id = -3;
1684         char_buf_t *cb;
1685 
1686         if ((elem = pool_knl_elem_wrap(conf, class, res_class, comp_class)) ==
1687             NULL)
1688                 return (NULL);
1689 
1690         /*
1691          * Allocate an nvlist to hold properties
1692          */
1693         if (nvlist_alloc(&elem->pke_properties, NV_UNIQUE_NAME_TYPE, 0) != 0) {
1694                 pool_knl_elem_free(elem, PO_FALSE);
1695                 pool_seterror(POE_SYSTEM);
1696                 return (NULL);
1697         }
1698         /*
1699          * Allocate a temporary ID and name until the element is
1700          * created for real
1701          */
1702         if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1703                 pool_knl_elem_free(elem, PO_TRUE);
1704                 return (NULL);
1705         }
1706         if (set_char_buf(cb, "%s.sys_id",
1707             pool_elem_class_string((pool_elem_t *)elem)) != PO_SUCCESS) {
1708                 pool_knl_elem_free(elem, PO_TRUE);
1709                 free_char_buf(cb);
1710                 return (NULL);
1711         }
1712         (void) nvlist_add_int64(elem->pke_properties, cb->cb_buf, id--);
1713         if (set_char_buf(cb, "%s.name",
1714             pool_elem_class_string((pool_elem_t *)elem)) != PO_SUCCESS) {
1715                 pool_knl_elem_free(elem, PO_TRUE);
1716                 free_char_buf(cb);
1717                 return (NULL);
1718         }
1719         (void) nvlist_add_string(elem->pke_properties, cb->cb_buf, "");
1720         /*
1721          * If it's a resource class, it will need an initial size
1722          */
1723         if (class == PEC_RES_COMP || class == PEC_RES_AGG) {
1724                 if (set_char_buf(cb, "%s.size",
1725                     pool_elem_class_string((pool_elem_t *)elem)) !=
1726                     PO_SUCCESS) {
1727                         pool_knl_elem_free(elem, PO_TRUE);
1728                         free_char_buf(cb);
1729                         return (NULL);
1730                 }
1731                 (void) nvlist_add_uint64(elem->pke_properties, cb->cb_buf, 0);
1732         }
1733         free_char_buf(cb);
1734 
1735         /*
1736          * Register the newly created element
1737          */
1738         if (dict_put(prov->pkc_elements, elem, elem) != NULL) {
1739                 pool_knl_elem_free(elem, PO_TRUE);
1740                 pool_seterror(POE_SYSTEM);
1741                 return (NULL);
1742         }
1743 
1744         if (prov->pkc_log->l_state != LS_DO)
1745                 return ((pool_elem_t *)elem);
1746 
1747         /*
1748          * The remaining logic is setting up the arguments for the
1749          * POOL_CREATE ioctl and appending the details into the log.
1750          */
1751         if ((create = malloc(sizeof (pool_create_undo_t))) == NULL) {
1752                 pool_seterror(POE_SYSTEM);
1753                 return (NULL);
1754         }
1755         create->pcu_ioctl.pc_o_type = class;
1756         switch (class) {
1757         case PEC_SYSTEM:
1758                 pool_seterror(POE_BADPARAM);
1759                 free(create);
1760                 return (NULL);
1761         case PEC_POOL: /* NO-OP */
1762                 break;
1763         case PEC_RES_COMP:
1764         case PEC_RES_AGG:
1765                 create->pcu_ioctl.pc_o_sub_type = res_class;
1766                 break;
1767         case PEC_COMP:
1768                 create->pcu_ioctl.pc_o_sub_type = comp_class;
1769                 break;
1770         default:
1771                 pool_seterror(POE_BADPARAM);
1772                 free(create);
1773                 return (NULL);
1774         }
1775 
1776         create->pcu_elem = (pool_elem_t *)elem;
1777 
1778         if (log_append(prov->pkc_log, POOL_CREATE, (void *)create) !=
1779             PO_SUCCESS) {
1780                 free(create);
1781                 return (NULL);
1782         }
1783         return ((pool_elem_t *)elem);
1784 }
1785 
1786 /*
1787  * Remove the details of the element from our userland copy and destroy
1788  * the element (if appropriate) in the kernel.
1789  */
1790 int
1791 pool_knl_elem_remove(pool_elem_t *pe)
1792 {
1793         pool_knl_connection_t *prov;
1794         pool_destroy_undo_t *destroy;
1795 
1796         prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
1797 
1798         if (dict_remove(prov->pkc_elements, pe) == NULL) {
1799                 pool_seterror(POE_SYSTEM);
1800                 return (PO_FAIL);
1801         }
1802         if (prov->pkc_log->l_state != LS_DO) {
1803                 return (PO_SUCCESS);
1804         }
1805 
1806         /*
1807          * The remaining logic is setting up the arguments for the
1808          * POOL_DESTROY ioctl and appending the details into the log.
1809          */
1810         if ((destroy = malloc(sizeof (pool_destroy_undo_t))) == NULL) {
1811                 pool_seterror(POE_SYSTEM);
1812                 return (PO_FAIL);
1813         }
1814         destroy->pdu_ioctl.pd_o_type = pool_elem_class(pe);
1815 
1816         if (destroy->pdu_ioctl.pd_o_type == PEC_RES_COMP ||
1817             destroy->pdu_ioctl.pd_o_type == PEC_RES_AGG)
1818                 destroy->pdu_ioctl.pd_o_sub_type = pool_resource_elem_class(pe);
1819 
1820         if (destroy->pdu_ioctl.pd_o_type == PEC_COMP)
1821                 destroy->pdu_ioctl.pd_o_sub_type =
1822                     pool_component_elem_class(pe);
1823 
1824         destroy->pdu_elem = pe;
1825 
1826         if (log_append(prov->pkc_log, POOL_DESTROY, (void *)destroy) !=
1827             PO_SUCCESS) {
1828                 free(destroy);
1829                 return (PO_FAIL);
1830         }
1831         return (PO_SUCCESS);
1832 }
1833 
1834 /*
1835  * Set the parent of the supplied child to the supplied parent
1836  */
1837 int
1838 pool_knl_set_container(pool_elem_t *pp, pool_elem_t *pc)
1839 {
1840         pool_knl_elem_t *pkp = (pool_knl_elem_t *)pp;
1841         pool_knl_elem_t *pkc = (pool_knl_elem_t *)pc;
1842 
1843         pkc->pke_parent = pkp;
1844         return (PO_SUCCESS);
1845 }
1846 
1847 /*
1848  * TODO: Needed for msets and ssets.
1849  */
1850 /* ARGSUSED */
1851 int
1852 pool_knl_res_transfer(pool_resource_t *src, pool_resource_t *tgt,
1853     uint64_t size) {
1854         return (PO_FAIL);
1855 }
1856 
1857 /*
1858  * Transfer resource components from one resource set to another.
1859  */
1860 int
1861 pool_knl_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt,
1862     pool_component_t **rl) {
1863         pool_elem_t *src_e = TO_ELEM(src);
1864         pool_elem_t *tgt_e = TO_ELEM(tgt);
1865         pool_xtransfer_undo_t *xtransfer;
1866         size_t size;
1867         pool_knl_connection_t *prov =
1868             (pool_knl_connection_t *)TO_CONF(src_e)->pc_prov;
1869 
1870         if (prov->pkc_log->l_state != LS_DO) {
1871                 /*
1872                  * Walk the Result Set and move the resource components
1873                  */
1874                 for (size = 0; rl[size] != NULL; size++) {
1875                         if (pool_set_container(TO_ELEM(tgt),
1876                             TO_ELEM(rl[size])) == PO_FAIL) {
1877                                 return (PO_FAIL);
1878                         }
1879                 }
1880                 return (PO_SUCCESS);
1881         }
1882 
1883         /*
1884          * The remaining logic is setting up the arguments for the
1885          * POOL_XTRANSFER ioctl and appending the details into the log.
1886          */
1887         if ((xtransfer = malloc(sizeof (pool_xtransfer_undo_t))) == NULL) {
1888                 pool_seterror(POE_SYSTEM);
1889                 return (PO_FAIL);
1890         }
1891 
1892         if (pool_elem_class(src_e) == PEC_RES_COMP) {
1893                 xtransfer->pxu_ioctl.px_o_id_type =
1894                     pool_resource_elem_class(src_e);
1895         } else {
1896                 pool_seterror(POE_BADPARAM);
1897                 return (PO_FAIL);
1898         }
1899 
1900 
1901         for (xtransfer->pxu_ioctl.px_o_complist_size = 0;
1902             rl[xtransfer->pxu_ioctl.px_o_complist_size] != NULL;
1903             xtransfer->pxu_ioctl.px_o_complist_size++)
1904                 /* calculate the size using the terminating NULL */;
1905         if ((xtransfer->pxu_ioctl.px_o_comp_list =
1906                 calloc(xtransfer->pxu_ioctl.px_o_complist_size,
1907                 sizeof (id_t))) == NULL) {
1908                 pool_seterror(POE_SYSTEM);
1909                 return (PO_FAIL);
1910         }
1911         if ((xtransfer->pxu_rl = calloc(
1912             xtransfer->pxu_ioctl.px_o_complist_size + 1,
1913             sizeof (pool_component_t *))) == NULL) {
1914                 pool_seterror(POE_SYSTEM);
1915                 return (PO_FAIL);
1916         }
1917         (void) memcpy(xtransfer->pxu_rl, rl,
1918             xtransfer->pxu_ioctl.px_o_complist_size *
1919             sizeof (pool_component_t *));
1920         xtransfer->pxu_src = src_e;
1921         xtransfer->pxu_tgt = tgt_e;
1922 
1923         if (log_append(prov->pkc_log, POOL_XTRANSFER, (void *)xtransfer) !=
1924             PO_SUCCESS) {
1925                 free(xtransfer);
1926                 return (PO_FAIL);
1927         }
1928         for (size = 0; rl[size] != NULL; size++) {
1929                 if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[size])) ==
1930                     PO_FAIL) {
1931                         return (PO_FAIL);
1932                 }
1933         }
1934         return (PO_SUCCESS);
1935 }
1936 
1937 /*
1938  * Return the parent of an element.
1939  */
1940 pool_elem_t *
1941 pool_knl_get_container(const pool_elem_t *pe)
1942 {
1943         pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
1944 
1945         return ((pool_elem_t *)pke->pke_parent);
1946 }
1947 
1948 /*
1949  * Note: This function is resource specific, needs extending for other
1950  * resource types
1951  */
1952 int
1953 pool_knl_resource_is_system(const pool_resource_t *pr)
1954 {
1955         switch (pool_resource_elem_class(TO_ELEM(pr))) {
1956         case PREC_PSET:
1957                 return (PSID_IS_SYSSET(
1958                     elem_get_sysid(TO_ELEM(pr))));
1959         default:
1960                 return (PO_FALSE);
1961         }
1962 }
1963 
1964 /*
1965  * Note: This function is resource specific, needs extending for other
1966  * resource types
1967  */
1968 int
1969 pool_knl_resource_can_associate(const pool_resource_t *pr)
1970 {
1971         switch (pool_resource_elem_class(TO_ELEM(pr))) {
1972         case PREC_PSET:
1973                 return (PO_TRUE);
1974         default:
1975                 return (PO_FALSE);
1976         }
1977 }
1978 
1979 /*
1980  * pool_knl_pool_associate() associates the supplied resource to the
1981  * supplied pool.
1982  *
1983  * Returns: PO_SUCCESS/PO_FAIL
1984  */
1985 int
1986 pool_knl_pool_associate(pool_t *pool, const pool_resource_t *resource)
1987 {
1988         pool_knl_connection_t *prov;
1989         pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool;
1990         pool_resource_elem_class_t res_class =
1991             pool_resource_elem_class(TO_ELEM(resource));
1992         pool_assoc_undo_t *assoc;
1993         pool_knl_resource_t *orig_res = pkp->pkp_assoc[res_class];
1994 
1995         /*
1996          * Are we allowed to associate with this target?
1997          */
1998         if (pool_knl_resource_can_associate(resource) == PO_FALSE) {
1999                 pool_seterror(POE_BADPARAM);
2000                 return (PO_FAIL);
2001         }
2002         prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov;
2003 
2004         if (prov->pkc_log->l_state != LS_DO) {
2005                 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource;
2006                 return (PO_SUCCESS);
2007         }
2008 
2009         /*
2010          * The remaining logic is setting up the arguments for the
2011          * POOL_ASSOC ioctl and appending the details into the log.
2012          */
2013         if ((assoc = malloc(sizeof (pool_assoc_undo_t))) == NULL) {
2014                 pool_seterror(POE_SYSTEM);
2015                 return (PO_FAIL);
2016         }
2017         assoc->pau_assoc = TO_ELEM(pool);
2018         assoc->pau_oldres = (pool_elem_t *)orig_res;
2019         assoc->pau_newres = TO_ELEM(resource);
2020 
2021         assoc->pau_ioctl.pa_o_id_type = res_class;
2022 
2023         if (log_append(prov->pkc_log, POOL_ASSOC, (void *)assoc) !=
2024             PO_SUCCESS) {
2025                 free(assoc);
2026                 pkp->pkp_assoc[res_class] = orig_res;
2027                 return (PO_FAIL);
2028         }
2029         pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource;
2030         return (PO_SUCCESS);
2031 }
2032 
2033 /*
2034  * pool_knl_pool_dissociate() dissociates the supplied resource from
2035  * the supplied pool.
2036  *
2037  * Returns: PO_SUCCESS/PO_FAIL
2038  */
2039 int
2040 pool_knl_pool_dissociate(pool_t *pool, const pool_resource_t *resource)
2041 {
2042         pool_knl_connection_t *prov;
2043         pool_dissoc_undo_t *dissoc;
2044         pool_knl_pool_t *pkp = (pool_knl_pool_t *)pool;
2045         pool_resource_t *default_res = (pool_resource_t *)get_default_resource(
2046             resource);
2047         pool_resource_elem_class_t res_class =
2048             pool_resource_elem_class(TO_ELEM(resource));
2049 
2050         prov = (pool_knl_connection_t *)(TO_CONF(TO_ELEM(pool)))->pc_prov;
2051 
2052         if (prov->pkc_log->l_state != LS_DO) {
2053                 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res;
2054                 return (PO_SUCCESS);
2055         }
2056         /*
2057          * The remaining logic is setting up the arguments for the
2058          * POOL_DISSOC ioctl and appending the details into the log.
2059          */
2060         if ((dissoc = malloc(sizeof (pool_dissoc_undo_t))) == NULL) {
2061                 pool_seterror(POE_SYSTEM);
2062                 return (PO_FAIL);
2063         }
2064         dissoc->pdu_dissoc = TO_ELEM(pool);
2065         dissoc->pdu_oldres = TO_ELEM(resource);
2066         dissoc->pdu_newres = TO_ELEM(default_res);
2067 
2068         dissoc->pdu_ioctl.pd_o_id_type = res_class;
2069 
2070         if (log_append(prov->pkc_log, POOL_DISSOC, (void *)dissoc) !=
2071             PO_SUCCESS) {
2072                 free(dissoc);
2073                 pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)resource;
2074                 return (PO_FAIL);
2075         }
2076 
2077         /*
2078          * Update our local copy
2079          */
2080         pkp->pkp_assoc[res_class] = (pool_knl_resource_t *)default_res;
2081         return (PO_SUCCESS);
2082 }
2083 
2084 /*
2085  * Allocate a data provider for the supplied configuration and optionally
2086  * discover resources.
2087  * The data provider is the cross over point from the "abstract" configuration
2088  * functions into the data representation specific manipulation routines.
2089  * This function sets up all the required pointers to create a kernel aware
2090  * data provider.
2091  * Returns PO_SUCCESS/PO_FAIL
2092  */
2093 int
2094 pool_knl_connection_alloc(pool_conf_t *conf, int oflags)
2095 {
2096         pool_knl_connection_t *prov;
2097 
2098         if ((prov = malloc(sizeof (pool_knl_connection_t))) == NULL) {
2099                 pool_seterror(POE_SYSTEM);
2100                 return (PO_FAIL);
2101         }
2102         (void) memset(prov, 0, sizeof (pool_knl_connection_t));
2103         /*
2104          * Initialise data members
2105          */
2106         prov->pc_name = strdup("kernel");
2107         prov->pc_store_type = KERNEL_DATA_STORE;
2108         prov->pc_oflags = oflags;
2109         /*
2110          * Initialise function pointers
2111          */
2112         prov->pc_close = pool_knl_close;
2113         prov->pc_validate = pool_knl_validate;
2114         prov->pc_commit = pool_knl_commit;
2115         prov->pc_export = pool_knl_export;
2116         prov->pc_rollback = pool_knl_rollback;
2117         prov->pc_exec_query = pool_knl_exec_query;
2118         prov->pc_elem_create = pool_knl_elem_create;
2119         prov->pc_remove = pool_knl_remove;
2120         prov->pc_res_xfer = pool_knl_res_transfer;
2121         prov->pc_res_xxfer = pool_knl_res_xtransfer;
2122         prov->pc_get_binding = pool_knl_get_binding;
2123         prov->pc_set_binding = pool_knl_set_binding;
2124         prov->pc_get_resource_binding = pool_knl_get_resource_binding;
2125         /*
2126          * Associate the provider to it's configuration
2127          */
2128         conf->pc_prov = (pool_connection_t *)prov;
2129         /*
2130          * End of common initialisation
2131          */
2132         /*
2133          * Attempt to open the pseudo device, if the configuration is opened
2134          * readonly then try to open an info device, otherwise try to open
2135          * the writeable device.
2136          */
2137         if (oflags & PO_RDWR) {
2138                 if ((prov->pkc_fd = blocking_open(pool_dynamic_location(),
2139                     O_RDWR)) < 0) {
2140                         free(prov);
2141                         conf->pc_prov = NULL;
2142                         pool_seterror(POE_SYSTEM);
2143                         return (PO_FAIL);
2144                 }
2145         } else {
2146                 if ((prov->pkc_fd = open(pool_info_location, O_RDWR)) < 0) {
2147                         free(prov);
2148                         conf->pc_prov = NULL;
2149                         pool_seterror(POE_SYSTEM);
2150                         return (PO_FAIL);
2151                 }
2152         }
2153         /*
2154          * Allocate the element dictionary
2155          */
2156         if ((prov->pkc_elements = dict_new((int (*)(const void *, const void *))
2157             pool_elem_compare, (uint64_t (*)(const void *))hash_id)) == NULL) {
2158                 (void) close(prov->pkc_fd);
2159                 free(prov);
2160                 conf->pc_prov = NULL;
2161                 pool_seterror(POE_SYSTEM);
2162                 return (PO_FAIL);
2163         }
2164 #if DEBUG
2165         if ((prov->pkc_leaks = dict_new(NULL, NULL)) == NULL) {
2166                 dict_free(&prov->pkc_elements);
2167                 (void) close(prov->pkc_fd);
2168                 free(prov);
2169                 conf->pc_prov = NULL;
2170                 pool_seterror(POE_SYSTEM);
2171                 return (PO_FAIL);
2172         }
2173 #endif  /* DEBUG */
2174         /*
2175          * Allocate the transaction log
2176          */
2177         if ((prov->pkc_log = log_alloc(conf)) == NULL) {
2178 #if DEBUG
2179                 dict_free(&prov->pkc_leaks);
2180 #endif  /* DEBUG */
2181                 dict_free(&prov->pkc_elements);
2182                 (void) close(prov->pkc_fd);
2183                 free(prov);
2184                 conf->pc_prov = NULL;
2185                 return (PO_FAIL);
2186         }
2187         /*
2188          * At this point the configuration provider has been initialized,
2189          * mark the configuration as valid so that the various routines
2190          * which rely on a valid configuration will work correctly.
2191          */
2192         conf->pc_state = POF_VALID;
2193         /*
2194          * Update the library snapshot from the kernel
2195          */
2196         if (pool_knl_update(conf, NULL) != PO_SUCCESS) {
2197 #if DEBUG
2198                 dict_free(&prov->pkc_leaks);
2199 #endif  /* DEBUG */
2200                 dict_free(&prov->pkc_elements);
2201                 (void) close(prov->pkc_fd);
2202                 free(prov);
2203                 conf->pc_prov = NULL;
2204                 conf->pc_state = POF_INVALID;
2205                 return (PO_FAIL);
2206         }
2207         return (PO_SUCCESS);
2208 }
2209 
2210 #if DEBUG
2211 static void
2212 pool_knl_elem_printf_cb(const void *key, void **value, void *cl)
2213 {
2214         pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
2215         dict_hdl_t *map = (dict_hdl_t *)cl;
2216 
2217         dprintf("leak elem:%p\n", pke);
2218         if (pke->pke_properties != NULL) {
2219                 nvlist_print(stdout, pke->pke_properties);
2220         } else
2221                 dprintf("no properties\n");
2222         assert(dict_get(map, pke) == NULL);
2223 }
2224 #endif  /* DEBUG */
2225 /*
2226  * pool_knl_elem_free() releases the resources associated with the
2227  * supplied element.
2228  */
2229 static void
2230 pool_knl_elem_free(pool_knl_elem_t *pke, int freeprop)
2231 {
2232 #if DEBUG
2233         pool_conf_t *conf = TO_CONF(TO_ELEM(pke));
2234         if (dict_remove(((pool_knl_connection_t *)conf->pc_prov)->pkc_leaks,
2235             pke) == NULL)
2236                 dprintf("%p, wasn't in the leak map\n", pke);
2237         if (freeprop == PO_TRUE) {
2238                 pool_elem_dprintf(TO_ELEM(pke));
2239         }
2240         dprintf("released %p\n", pke);
2241 #endif  /* DEBUG */
2242         if (freeprop == PO_TRUE) {
2243                 nvlist_free(pke->pke_properties);
2244         }
2245         free(pke);
2246 }
2247 
2248 /*
2249  * pool_knl_elem_free_cb() is designed to be used with
2250  * dict_map(). When a connection is freed, this function is used to
2251  * free all element resources.
2252  */
2253 /* ARGSUSED1 */
2254 static void
2255 pool_knl_elem_free_cb(const void *key, void **value, void *cl)
2256 {
2257         pool_knl_elem_t *pke = (pool_knl_elem_t *)key;
2258 
2259 #ifdef DEBUG
2260         dprintf("pool_knl_elem_free_cb:\n");
2261         dprintf("about to release %p ", pke);
2262         pool_elem_dprintf(TO_ELEM(pke));
2263 #endif  /* DEBUG */
2264         pool_knl_elem_free(pke, PO_TRUE);
2265 }
2266 
2267 /*
2268  * Free the resources for a kernel data provider.
2269  */
2270 void
2271 pool_knl_connection_free(pool_knl_connection_t *prov)
2272 {
2273         if (prov->pkc_log != NULL) {
2274                 (void) log_walk(prov->pkc_log, log_item_release);
2275                 log_free(prov->pkc_log);
2276         }
2277         if (prov->pkc_elements != NULL) {
2278                 dict_map(prov->pkc_elements, pool_knl_elem_free_cb, NULL);
2279 #if DEBUG
2280                 dprintf("dict length is %llu\n", dict_length(prov->pkc_leaks));
2281                 dict_map(prov->pkc_leaks, pool_knl_elem_printf_cb,
2282                     prov->pkc_elements);
2283                 assert(dict_length(prov->pkc_leaks) == 0);
2284                 dict_free(&prov->pkc_leaks);
2285 #endif  /* DEBUG */
2286                 dict_free(&prov->pkc_elements);
2287         }
2288         free((void *)prov->pc_name);
2289         free(prov);
2290 }
2291 
2292 /*
2293  * Return the specified property value.
2294  *
2295  * POC_INVAL is returned if an error is detected and the error code is updated
2296  * to indicate the cause of the error.
2297  */
2298 pool_value_class_t
2299 pool_knl_get_property(const pool_elem_t *pe, const char *name,
2300     pool_value_t *val)
2301 {
2302         pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2303         nvpair_t *pair;
2304         const pool_prop_t *prop;
2305 
2306         if ((prop = provider_get_prop(pe, name)) != NULL)
2307                 if (prop_is_stored(prop) == PO_FALSE)
2308                         return (pool_knl_get_dynamic_property(pe, name, val));
2309 
2310         if ((pair = pool_knl_find_nvpair(pke->pke_properties, name)) == NULL) {
2311                 pool_seterror(POE_BADPARAM);
2312                 return (POC_INVAL);
2313         }
2314 
2315         if (pool_value_from_nvpair(val, pair) == PO_FAIL) {
2316                 return (POC_INVAL);
2317         }
2318 
2319         return (pool_value_get_type(val));
2320 }
2321 
2322 /*
2323  * Return the specified property value.
2324  *
2325  * If a property is designated as dynamic, then this function will
2326  * always try to return the latest value of the property from the
2327  * kernel.
2328  *
2329  * POC_INVAL is returned if an error is detected and the error code is updated
2330  * to indicate the cause of the error.
2331  */
2332 pool_value_class_t
2333 pool_knl_get_dynamic_property(const pool_elem_t *pe, const char *name,
2334     pool_value_t *val)
2335 {
2336         pool_knl_connection_t *prov;
2337         pool_propget_t propget = { 0 };
2338         nvlist_t *proplist;
2339         nvpair_t *pair;
2340 
2341         propget.pp_o_id_type = pool_elem_class(pe);
2342         if (pool_elem_class(pe) == PEC_RES_COMP ||
2343             pool_elem_class(pe) == PEC_RES_AGG)
2344                 propget.pp_o_id_subtype = pool_resource_elem_class(pe);
2345         if (pool_elem_class(pe) == PEC_COMP)
2346                 propget.pp_o_id_subtype =
2347                     (pool_resource_elem_class_t)pool_component_elem_class(pe);
2348 
2349         propget.pp_o_id = elem_get_sysid(pe);
2350         propget.pp_o_prop_name_size = strlen(name);
2351         propget.pp_o_prop_name = (char *)name;
2352         propget.pp_i_bufsize = KERNEL_SNAPSHOT_BUF_SZ;
2353         propget.pp_i_buf = malloc(KERNEL_SNAPSHOT_BUF_SZ);
2354         bzero(propget.pp_i_buf, KERNEL_SNAPSHOT_BUF_SZ);
2355 
2356         prov = (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
2357         if (ioctl(prov->pkc_fd, POOL_PROPGET, &propget) < 0) {
2358                 free(propget.pp_i_buf);
2359                 pool_seterror(POE_SYSTEM);
2360                 return (POC_INVAL);
2361         }
2362         if (nvlist_unpack(propget.pp_i_buf, propget.pp_i_bufsize,
2363             &proplist, 0) != 0) {
2364                 free(propget.pp_i_buf);
2365                 pool_seterror(POE_SYSTEM);
2366                 return (POC_INVAL);
2367         }
2368         free(propget.pp_i_buf);
2369 
2370         if ((pair = nvlist_next_nvpair(proplist, NULL)) == NULL) {
2371                 nvlist_free(proplist);
2372                 pool_seterror(POE_SYSTEM);
2373                 return (POC_INVAL);
2374         }
2375 
2376         if (pool_value_from_nvpair(val, pair) == PO_FAIL) {
2377                 nvlist_free(proplist);
2378                 return (POC_INVAL);
2379         }
2380         nvlist_free(proplist);
2381         return (pool_value_get_type(val));
2382 }
2383 
2384 /*
2385  * Update the specified property value.
2386  *
2387  * PO_FAIL is returned if an error is detected and the error code is updated
2388  * to indicate the cause of the error.
2389  */
2390 int
2391 pool_knl_put_property(pool_elem_t *pe, const char *name,
2392     const pool_value_t *val)
2393 {
2394         pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2395         pool_knl_connection_t *prov =
2396             (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
2397         nvpair_t *bp, *ap;
2398         pool_propput_undo_t *propput;
2399         nvlist_t *bl = NULL;
2400         const pool_prop_t *prop;
2401 
2402         if ((bp = pool_knl_find_nvpair(pke->pke_properties, name)) != NULL) {
2403                 if (nvlist_alloc(&bl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2404                         pool_seterror(POE_SYSTEM);
2405                         return (PO_FAIL);
2406                 }
2407                 if (nvlist_add_nvpair(bl, bp) != 0) {
2408                         nvlist_free(bl);
2409                         pool_seterror(POE_SYSTEM);
2410                         return (PO_FAIL);
2411                 }
2412         }
2413         if (pool_knl_nvlist_add_value(pke->pke_properties, name, val) !=
2414             PO_SUCCESS)
2415                 return (PO_FAIL);
2416 
2417         if (prov->pkc_log->l_state != LS_DO) {
2418                 if (bl)
2419                         nvlist_free(bl);
2420                 return (PO_SUCCESS);
2421         }
2422         /*
2423          * The remaining logic is setting up the arguments for the
2424          * POOL_PROPPUT ioctl and appending the details into the log.
2425          */
2426         if ((propput = malloc(sizeof (pool_propput_undo_t))) == NULL) {
2427                 pool_seterror(POE_SYSTEM);
2428                 return (PO_FAIL);
2429         }
2430         (void) memset(propput, 0, sizeof (pool_propput_undo_t));
2431         propput->ppu_blist = bl;
2432 
2433         ap = pool_knl_find_nvpair(pke->pke_properties, name);
2434 
2435         if (nvlist_alloc(&propput->ppu_alist, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2436                 nvlist_free(propput->ppu_blist);
2437                 free(propput);
2438                 pool_seterror(POE_SYSTEM);
2439                 return (PO_FAIL);
2440         }
2441         if (nvlist_add_nvpair(propput->ppu_alist, ap) != 0) {
2442                 nvlist_free(propput->ppu_blist);
2443                 nvlist_free(propput->ppu_alist);
2444                 free(propput);
2445                 pool_seterror(POE_SYSTEM);
2446                 return (PO_FAIL);
2447         }
2448 
2449         if (nvlist_pack(propput->ppu_alist,
2450             (char **)&propput->ppu_ioctl.pp_o_buf,
2451             &propput->ppu_ioctl.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) {
2452                 pool_seterror(POE_SYSTEM);
2453                 return (PO_FAIL);
2454         }
2455         nvlist_free(propput->ppu_alist);
2456         propput->ppu_ioctl.pp_o_id_type = pool_elem_class(pe);
2457         if (pool_elem_class(pe) == PEC_RES_COMP ||
2458             pool_elem_class(pe) == PEC_RES_AGG)
2459                 propput->ppu_ioctl.pp_o_id_sub_type =
2460                     pool_resource_elem_class(pe);
2461         if (pool_elem_class(pe) == PEC_COMP)
2462                 propput->ppu_ioctl.pp_o_id_sub_type =
2463                     (pool_resource_elem_class_t)pool_component_elem_class(pe);
2464 
2465         propput->ppu_elem = pe;
2466         if ((prop = provider_get_prop(propput->ppu_elem, name)) != NULL) {
2467                 if (prop_is_readonly(prop) == PO_TRUE)
2468                         propput->ppu_doioctl |= KERNEL_PROP_RDONLY;
2469         }
2470 
2471         if (log_append(prov->pkc_log, POOL_PROPPUT, (void *)propput) !=
2472             PO_SUCCESS) {
2473                 nvlist_free(propput->ppu_blist);
2474                 free(propput);
2475                 return (PO_FAIL);
2476         }
2477         return (PO_SUCCESS);
2478 }
2479 
2480 /*
2481  * Remove the specified property value.
2482  *
2483  * PO_FAIL is returned if an error is detected and the error code is
2484  * updated to indicate the cause of the error.
2485  */
2486 int
2487 pool_knl_rm_property(pool_elem_t *pe, const char *name)
2488 {
2489         pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2490         pool_knl_connection_t *prov =
2491             (pool_knl_connection_t *)(TO_CONF(pe))->pc_prov;
2492         pool_proprm_undo_t *proprm;
2493 
2494         if (pool_knl_find_nvpair(pke->pke_properties, name) == NULL) {
2495                 pool_seterror(POE_BADPARAM);
2496                 return (PO_FAIL);
2497         }
2498 
2499         if ((proprm = malloc(sizeof (pool_proprm_undo_t))) == NULL) {
2500                 pool_seterror(POE_SYSTEM);
2501                 return (PO_FAIL);
2502         }
2503         (void) memset(proprm, 0, sizeof (pool_proprm_undo_t));
2504         proprm->pru_oldval.pv_class = POC_INVAL;
2505         (void) pool_get_property(TO_CONF(pe), pe, name, &proprm->pru_oldval);
2506 
2507         if (prov->pkc_log->l_state != LS_DO) {
2508                 free(proprm);
2509                 (void) nvlist_remove_all(pke->pke_properties, (char *)name);
2510                 return (PO_SUCCESS);
2511         }
2512         /*
2513          * The remaining logic is setting up the arguments for the
2514          * POOL_PROPRM ioctl and appending the details into the log.
2515          */
2516 
2517         proprm->pru_ioctl.pp_o_id_type = pool_elem_class(pe);
2518         if (pool_elem_class(pe) == PEC_RES_COMP ||
2519             pool_elem_class(pe) == PEC_RES_AGG)
2520                 proprm->pru_ioctl.pp_o_id_sub_type =
2521                     pool_resource_elem_class(pe);
2522 
2523         if (pool_elem_class(pe) == PEC_COMP)
2524                 proprm->pru_ioctl.pp_o_id_sub_type =
2525                     (pool_resource_elem_class_t)pool_component_elem_class(pe);
2526 
2527         proprm->pru_ioctl.pp_o_prop_name_size = strlen(name);
2528         proprm->pru_ioctl.pp_o_prop_name =
2529             (char *)pool_value_get_name(&proprm->pru_oldval);
2530         proprm->pru_elem = pe;
2531 
2532         if (log_append(prov->pkc_log, POOL_PROPRM, (void *)proprm) !=
2533             PO_SUCCESS) {
2534                 free(proprm);
2535                 return (PO_FAIL);
2536         }
2537 
2538         (void) nvlist_remove_all(pke->pke_properties, (char *)name);
2539         return (PO_SUCCESS);
2540 }
2541 
2542 /*
2543  * Return a NULL terminated array of pool_value_t which represents all
2544  * of the properties stored for an element
2545  *
2546  * Return NULL on failure. It is the caller's responsibility to free
2547  * the returned array of values.
2548  */
2549 pool_value_t **
2550 pool_knl_get_properties(const pool_elem_t *pe, uint_t *nprops)
2551 {
2552         nvpair_t *pair;
2553         pool_value_t **result;
2554         pool_knl_elem_t *pke = (pool_knl_elem_t *)pe;
2555         int i = 0;
2556 
2557         *nprops = 0;
2558 
2559         for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL;
2560             pair = nvlist_next_nvpair(pke->pke_properties, pair))
2561                 (*nprops)++;
2562         if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) {
2563                 pool_seterror(POE_SYSTEM);
2564                 return (NULL);
2565         }
2566         for (pair = nvlist_next_nvpair(pke->pke_properties, NULL); pair != NULL;
2567             pair = nvlist_next_nvpair(pke->pke_properties, pair), i++) {
2568                 result[i] = pool_value_alloc();
2569                 if (pool_value_from_nvpair(result[i], pair) == PO_FAIL) {
2570                         while (i-- >= 0)
2571                                 pool_value_free(result[i]);
2572                         free(result);
2573                         return (NULL);
2574                 }
2575         }
2576         return (result);
2577 }
2578 
2579 /*
2580  * Append an entry to a result set. Reallocate the array used to store
2581  * results if it's full.
2582  * Returns PO_SUCCESS/PO_FAIL
2583  */
2584 int
2585 pool_knl_result_set_append(pool_knl_result_set_t *rs, pool_knl_elem_t *pke)
2586 {
2587         if (rs->pkr_count == rs->pkr_size)
2588                 if (pool_knl_result_set_realloc(rs) != PO_SUCCESS)
2589                         return (PO_FAIL);
2590 
2591         rs->pkr_list[rs->pkr_count++] = pke;
2592 
2593         return (PO_SUCCESS);
2594 }
2595 
2596 /*
2597  * Resize the array used to store results. A simple doubling strategy
2598  * is used.
2599  * Returns PO_SUCCESS/PO_FAIL
2600  */
2601 int
2602 pool_knl_result_set_realloc(pool_knl_result_set_t *rs)
2603 {
2604         pool_knl_elem_t **old_list = rs->pkr_list;
2605         int new_size = rs->pkr_size * 2;
2606 
2607         if ((rs->pkr_list = realloc(rs->pkr_list,
2608             new_size * sizeof (pool_knl_elem_t *))) == NULL) {
2609                 rs->pkr_list = old_list;
2610                 pool_seterror(POE_SYSTEM);
2611                 return (PO_FAIL);
2612         }
2613         rs->pkr_size = new_size;
2614 
2615         return (PO_SUCCESS);
2616 }
2617 
2618 /*
2619  * Allocate a result set. The Result Set stores the result of a query.
2620  * Returns pool_knl_result_set_t pointer/NULL
2621  */
2622 pool_knl_result_set_t *
2623 pool_knl_result_set_alloc(const pool_conf_t *conf)
2624 {
2625         pool_knl_result_set_t *rs;
2626 
2627         if ((rs = malloc(sizeof (pool_knl_result_set_t))) == NULL) {
2628                 pool_seterror(POE_SYSTEM);
2629                 return (NULL);
2630         }
2631         (void) memset(rs, 0, sizeof (pool_knl_result_set_t));
2632         rs->pkr_size = KERNEL_RS_INITIAL_SZ;
2633         if (pool_knl_result_set_realloc(rs) == PO_FAIL) {
2634                 free(rs);
2635                 pool_seterror(POE_SYSTEM);
2636                 return (NULL);
2637         }
2638         rs->prs_conf = conf;
2639         rs->prs_index = -1;
2640         rs->prs_active = PO_TRUE;
2641         /* Fix up the result set accessor functions to the knl specfic ones */
2642         rs->prs_next = pool_knl_rs_next;
2643         rs->prs_prev = pool_knl_rs_prev;
2644         rs->prs_first = pool_knl_rs_first;
2645         rs->prs_last = pool_knl_rs_last;
2646         rs->prs_get_index = pool_knl_rs_get_index;
2647         rs->prs_set_index = pool_knl_rs_set_index;
2648         rs->prs_close = pool_knl_rs_close;
2649         rs->prs_count = pool_knl_rs_count;
2650         return (rs);
2651 }
2652 
2653 /*
2654  * Free a result set. Ensure that the resources are all released at
2655  * this point.
2656  */
2657 void
2658 pool_knl_result_set_free(pool_knl_result_set_t *rs)
2659 {
2660         free(rs->pkr_list);
2661         free(rs);
2662 }
2663 /*
2664  * Return the next element in a result set.
2665  * Returns pool_elem_t pointer/NULL
2666  */
2667 pool_elem_t *
2668 pool_knl_rs_next(pool_result_set_t *set)
2669 {
2670         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2671 
2672         if (kset->prs_index == kset->pkr_count - 1)
2673                 return (NULL);
2674         return ((pool_elem_t *)kset->pkr_list[++kset->prs_index]);
2675 }
2676 
2677 /*
2678  * Return the previous element in a result set.
2679  * Returns pool_elem_t pointer/NULL
2680  */
2681 pool_elem_t *
2682 pool_knl_rs_prev(pool_result_set_t *set)
2683 {
2684         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2685 
2686         if (kset->prs_index < 0)
2687                 return (NULL);
2688         return ((pool_elem_t *)kset->pkr_list[kset->prs_index--]);
2689 }
2690 
2691 /*
2692  * Sets the current index in a result set.
2693  * Returns PO_SUCCESS/PO_FAIL
2694  */
2695 int
2696 pool_knl_rs_set_index(pool_result_set_t *set, int index)
2697 {
2698         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2699 
2700         if (index < 0 || index >= kset->pkr_count) {
2701                 pool_seterror(POE_BADPARAM);
2702                 return (PO_FAIL);
2703         }
2704         kset->prs_index = index;
2705         return (PO_SUCCESS);
2706 }
2707 
2708 /*
2709  * Return the current index in a result set.
2710  * Returns current index
2711  */
2712 int
2713 pool_knl_rs_get_index(pool_result_set_t *set)
2714 {
2715         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2716 
2717         return (kset->prs_index);
2718 }
2719 
2720 /*
2721  * Return the first element in a result set.
2722  * Returns pool_elem_t pointer/NULL
2723  */
2724 pool_elem_t *
2725 pool_knl_rs_first(pool_result_set_t *set)
2726 {
2727         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2728 
2729         return ((pool_elem_t *)kset->pkr_list[0]);
2730 }
2731 
2732 /*
2733  * Return the last element in a result set.
2734  * Returns pool_elem_t pointer/NULL
2735  */
2736 pool_elem_t *
2737 pool_knl_rs_last(pool_result_set_t *set)
2738 {
2739         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2740 
2741         return ((pool_elem_t *)kset->pkr_list[kset->pkr_count - 1]);
2742 }
2743 
2744 /*
2745  * Return the number of results in a result set.
2746  * Returns result count
2747  */
2748 int
2749 pool_knl_rs_count(pool_result_set_t *set)
2750 {
2751         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2752 
2753         return (kset->pkr_count);
2754 }
2755 
2756 
2757 /*
2758  * Close a result set. Free the resources
2759  * Returns PO_SUCCESS/PO_FAIL
2760  */
2761 int
2762 pool_knl_rs_close(pool_result_set_t *set)
2763 {
2764         pool_knl_result_set_t *kset = (pool_knl_result_set_t *)set;
2765 
2766         pool_knl_result_set_free(kset);
2767         return (PO_SUCCESS);
2768 }
2769 
2770 /*
2771  * Commit an individual transaction log item(). This processing is
2772  * essential to the pool_conf_commit() logic. When pool_conf_commit()
2773  * is invoked, the pending transaction log for the configuration is
2774  * walked and all pending changes to the kernel are invoked. If a
2775  * change succeeds it is marked in the log as successful and
2776  * processing continues, if it fails then failure is returned and the
2777  * log will be "rolled back" to undo changes to the library snapshot
2778  * and the kernel.
2779  */
2780 int
2781 log_item_commit(log_item_t *li)
2782 {
2783         pool_knl_connection_t *prov =
2784             (pool_knl_connection_t *)li->li_log->l_conf->pc_prov;
2785         pool_create_undo_t *create;
2786         pool_destroy_undo_t *destroy;
2787         pool_assoc_undo_t *assoc;
2788         pool_dissoc_undo_t *dissoc;
2789         pool_propput_undo_t *propput;
2790         pool_proprm_undo_t *proprm;
2791         pool_xtransfer_undo_t *xtransfer;
2792         char_buf_t *cb;
2793         size_t size;
2794         pool_elem_t *pair;
2795         pool_value_t val = POOL_VALUE_INITIALIZER;
2796         int ret;
2797 
2798         switch (li->li_op) {
2799         case POOL_CREATE:
2800                 create = (pool_create_undo_t *)li->li_details;
2801                 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
2802                         return (PO_FAIL);
2803                 if (set_char_buf(cb, "%s.sys_id",
2804                     pool_elem_class_string(create->pcu_elem)) != PO_SUCCESS) {
2805                         free_char_buf(cb);
2806                         return (PO_FAIL);
2807                 }
2808 #ifdef DEBUG
2809                 dprintf("log_item_commit: POOL_CREATE, remove from dict\n");
2810                 pool_elem_dprintf(create->pcu_elem);
2811 #endif  /* DEBUG */
2812                 /*
2813                  * May not need to remove the element if it was
2814                  * already destroyed before commit. Just cast the
2815                  * return to void.
2816                  */
2817                 (void) dict_remove(prov->pkc_elements,
2818                     (pool_knl_elem_t *)create->pcu_elem);
2819 
2820                 if (ioctl(prov->pkc_fd, POOL_CREATE, &create->pcu_ioctl) < 0) {
2821                         pool_seterror(POE_SYSTEM);
2822                         return (PO_FAIL);
2823                 }
2824                 /*
2825                  * Now that we have created our element in the kernel,
2826                  * it has a valid allocated system id. Remove the
2827                  * element from the element dictionary, using the
2828                  * current key, and then re-insert under the new key.
2829                  */
2830 #ifdef DEBUG
2831                 pool_elem_dprintf(create->pcu_elem);
2832 #endif  /* DEBUG */
2833                 assert(nvlist_add_int64(
2834                     ((pool_knl_elem_t *)create->pcu_elem)->pke_properties,
2835                     cb->cb_buf, create->pcu_ioctl.pc_i_id) == 0);
2836                 free_char_buf(cb);
2837                 assert(dict_put(prov->pkc_elements, create->pcu_elem,
2838                     create->pcu_elem) == NULL);
2839                 /*
2840                  * If the element has a pair in the static
2841                  * configuration, update it with the sys_id
2842                  */
2843                 if ((pair = pool_get_pair(create->pcu_elem)) != NULL) {
2844                         pool_value_set_int64(&val, create->pcu_ioctl.pc_i_id);
2845                         assert(pool_put_any_ns_property(pair, c_sys_prop, &val)
2846                             == PO_SUCCESS);
2847                 }
2848                 li->li_state = LS_UNDO;
2849                 break;
2850         case POOL_DESTROY:
2851                 destroy = (pool_destroy_undo_t *)li->li_details;
2852 
2853                 destroy->pdu_ioctl.pd_o_id = elem_get_sysid(destroy->pdu_elem);
2854 
2855                 /*
2856                  * It may be that this element was created in the last
2857                  * transaction. In which case POOL_CREATE, above, will
2858                  * have re-inserted the element in the dictionary. Try
2859                  * to remove it just in case this has occurred.
2860                  */
2861                 (void) dict_remove(prov->pkc_elements,
2862                     (pool_knl_elem_t *)destroy->pdu_elem);
2863                 while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY,
2864                     &destroy->pdu_ioctl)) < 0 && errno == EAGAIN)
2865                         ;
2866                 if (ret < 0) {
2867                         pool_seterror(POE_SYSTEM);
2868                         return (PO_FAIL);
2869                 }
2870 #ifdef DEBUG
2871                 dprintf("log_item_commit: POOL_DESTROY\n");
2872                 pool_elem_dprintf(destroy->pdu_elem);
2873 #endif  /* DEBUG */
2874                 li->li_state = LS_UNDO;
2875                 break;
2876         case POOL_ASSOC:
2877                 assoc = (pool_assoc_undo_t *)li->li_details;
2878 
2879                 assoc->pau_ioctl.pa_o_pool_id =
2880                     elem_get_sysid(assoc->pau_assoc);
2881                 assoc->pau_ioctl.pa_o_res_id =
2882                     elem_get_sysid(assoc->pau_newres);
2883                 while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC,
2884                     &assoc->pau_ioctl)) < 0 && errno == EAGAIN)
2885                         ;
2886                 if (ret < 0) {
2887                         pool_seterror(POE_SYSTEM);
2888                         return (PO_FAIL);
2889                 }
2890                 li->li_state = LS_UNDO;
2891                 break;
2892         case POOL_DISSOC:
2893                 dissoc = (pool_dissoc_undo_t *)li->li_details;
2894 
2895                 dissoc->pdu_ioctl.pd_o_pool_id =
2896                     elem_get_sysid(dissoc->pdu_dissoc);
2897 
2898                 while ((ret = ioctl(prov->pkc_fd, POOL_DISSOC,
2899                     &dissoc->pdu_ioctl)) < 0 && errno == EAGAIN)
2900                         ;
2901                 if (ret < 0) {
2902                         pool_seterror(POE_SYSTEM);
2903                         return (PO_FAIL);
2904                 }
2905                 li->li_state = LS_UNDO;
2906                 break;
2907         case POOL_TRANSFER:
2908                 li->li_state = LS_UNDO;
2909                 pool_seterror(POE_BADPARAM);
2910                 return (PO_FAIL);
2911         case POOL_XTRANSFER:
2912                 xtransfer = (pool_xtransfer_undo_t *)li->li_details;
2913 
2914                 xtransfer->pxu_ioctl.px_o_src_id =
2915                     elem_get_sysid(xtransfer->pxu_src);
2916                 xtransfer->pxu_ioctl.px_o_tgt_id =
2917                     elem_get_sysid(xtransfer->pxu_tgt);
2918                 for (size = 0; xtransfer->pxu_rl[size] != NULL; size ++) {
2919                         xtransfer->pxu_ioctl.px_o_comp_list[size] =
2920                             elem_get_sysid(TO_ELEM(xtransfer->pxu_rl[size]));
2921 #ifdef DEBUG
2922                         dprintf("log_item_commit: POOL_XTRANSFER\n");
2923                         pool_elem_dprintf(TO_ELEM(xtransfer->pxu_rl[size]));
2924 #endif  /* DEBUG */
2925                 }
2926 
2927                 /*
2928                  * Don't actually transfer resources if the configuration
2929                  * is in POF_DESTROY state. This is to prevent problems
2930                  * relating to transferring off-line CPUs. Instead rely
2931                  * on the POOL_DESTROY ioctl to transfer the CPUS.
2932                  */
2933                 if (li->li_log->l_conf->pc_state != POF_DESTROY &&
2934                     ioctl(prov->pkc_fd, POOL_XTRANSFER,
2935                     &xtransfer->pxu_ioctl) < 0) {
2936 #ifdef DEBUG
2937                         dprintf("log_item_commit: POOL_XTRANSFER, ioctl "
2938                             "failed\n");
2939 #endif  /* DEBUG */
2940                         pool_seterror(POE_SYSTEM);
2941                         return (PO_FAIL);
2942                 }
2943                 li->li_state = LS_UNDO;
2944                 break;
2945         case POOL_PROPPUT:
2946                 propput = (pool_propput_undo_t *)li->li_details;
2947 
2948                 if (pool_elem_class(propput->ppu_elem) != PEC_SYSTEM) {
2949                         propput->ppu_ioctl.pp_o_id =
2950                             elem_get_sysid(propput->ppu_elem);
2951                 }
2952                 /*
2953                  * Some properties, e.g. pset.size, are read-only in the
2954                  * kernel and attempting to change them will fail and cause
2955                  * problems. Although this property is read-only through the
2956                  * public interface, the library needs to modify it's value.
2957                  */
2958                 if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) {
2959                         if (ioctl(prov->pkc_fd, POOL_PROPPUT,
2960                             &propput->ppu_ioctl) < 0) {
2961                                 pool_seterror(POE_SYSTEM);
2962                                 return (PO_FAIL);
2963                         }
2964                 }
2965                 li->li_state = LS_UNDO;
2966                 break;
2967         case POOL_PROPRM:
2968                 proprm = (pool_proprm_undo_t *)li->li_details;
2969 
2970                 if (pool_elem_class(proprm->pru_elem) != PEC_SYSTEM) {
2971                         proprm->pru_ioctl.pp_o_id =
2972                             elem_get_sysid(proprm->pru_elem);
2973                 }
2974                 if (ioctl(prov->pkc_fd, POOL_PROPRM, &proprm->pru_ioctl) < 0) {
2975                         pool_seterror(POE_SYSTEM);
2976                         return (PO_FAIL);
2977                 }
2978                 li->li_state = LS_UNDO;
2979                 break;
2980         default:
2981                 return (PO_FAIL);
2982         }
2983         return (PO_SUCCESS);
2984 }
2985 
2986 /*
2987  * Undo an individual transaction log item(). This processing is
2988  * essential to the pool_conf_commit() and pool_conf_rollback()
2989  * logic. Changes to the libpool snapshot and the kernel are carried
2990  * out separately. The library snapshot is updated synchronously,
2991  * however the kernel update is delayed until the user calls
2992  * pool_conf_commit().
2993  *
2994  * When undoing transactions, library changes will be undone unless
2995  * this invocation is as a result of a commit failure, in which case
2996  * the log state will be LS_RECOVER. Kernel changes will only be
2997  * undone if they are marked as having been done, in which case the
2998  * log item state will be LS_UNDO.
2999  */
3000 int
3001 log_item_undo(log_item_t *li)
3002 {
3003         pool_knl_connection_t *prov =
3004             (pool_knl_connection_t *)li->li_log->l_conf->pc_prov;
3005         pool_create_undo_t *create;
3006         pool_destroy_undo_t *destroy;
3007         pool_assoc_undo_t *assoc;
3008         pool_dissoc_undo_t *dissoc;
3009         pool_propput_undo_t *propput;
3010         pool_proprm_undo_t *proprm;
3011         pool_xtransfer_undo_t *xtransfer;
3012         char_buf_t *cb;
3013         size_t size;
3014         pool_destroy_t u_destroy;
3015         pool_create_t u_create;
3016         pool_assoc_t u_assoc;
3017         pool_xtransfer_t u_xtransfer;
3018         pool_propput_t u_propput;
3019         pool_proprm_t u_proprm;
3020         pool_conf_t *conf = li->li_log->l_conf;
3021         nvpair_t *pair;
3022         nvlist_t *tmplist;
3023         int ret;
3024 
3025         if (li->li_log->l_state != LS_RECOVER) {
3026         switch (li->li_op) {
3027         case POOL_CREATE:
3028                 create = (pool_create_undo_t *)li->li_details;
3029 
3030                 (void) dict_remove(prov->pkc_elements, create->pcu_elem);
3031 #ifdef DEBUG
3032                 dprintf("log_item_undo: POOL_CREATE\n");
3033                 assert(create->pcu_elem != NULL);
3034                 dprintf("log_item_undo: POOL_CREATE %p\n", create->pcu_elem);
3035                 pool_elem_dprintf(create->pcu_elem);
3036 #endif  /* DEBUG */
3037                 pool_knl_elem_free((pool_knl_elem_t *)create->pcu_elem,
3038                     PO_TRUE);
3039                 break;
3040         case POOL_DESTROY:
3041                 destroy = (pool_destroy_undo_t *)li->li_details;
3042 
3043                 assert(dict_put(prov->pkc_elements, destroy->pdu_elem,
3044                     destroy->pdu_elem) == NULL);
3045                 break;
3046         case POOL_ASSOC:
3047                 assoc = (pool_assoc_undo_t *)li->li_details;
3048 
3049                 if (assoc->pau_oldres != NULL)
3050                         ((pool_knl_pool_t *)assoc->pau_assoc)->pkp_assoc
3051                             [pool_resource_elem_class(assoc->pau_oldres)] =
3052                             (pool_knl_resource_t *)assoc->pau_oldres;
3053                 break;
3054         case POOL_DISSOC:
3055                 dissoc = (pool_dissoc_undo_t *)li->li_details;
3056 
3057                 if (dissoc->pdu_oldres != NULL)
3058                         ((pool_knl_pool_t *)dissoc->pdu_dissoc)->pkp_assoc
3059                             [pool_resource_elem_class(dissoc->pdu_oldres)] =
3060                             (pool_knl_resource_t *)dissoc->pdu_oldres;
3061                 break;
3062         case POOL_TRANSFER:
3063                 pool_seterror(POE_BADPARAM);
3064                 return (PO_FAIL);
3065         case POOL_XTRANSFER:
3066                 xtransfer = (pool_xtransfer_undo_t *)li->li_details;
3067 
3068                 for (size = 0; xtransfer->pxu_rl[size] != NULL; size++) {
3069                         pool_value_t val = POOL_VALUE_INITIALIZER;
3070                         uint64_t src_size;
3071                         uint64_t tgt_size;
3072 
3073                         if (pool_set_container(xtransfer->pxu_src,
3074                             TO_ELEM(xtransfer->pxu_rl[size])) == PO_FAIL) {
3075                                 return (PO_FAIL);
3076                         }
3077                         /*
3078                          * Maintain the library view of the size
3079                          */
3080                         if (resource_get_size(pool_elem_res(xtransfer->pxu_src),
3081                             &src_size) != PO_SUCCESS ||
3082                             resource_get_size(pool_elem_res(xtransfer->pxu_tgt),
3083                             &tgt_size) != PO_SUCCESS) {
3084                                 pool_seterror(POE_BADPARAM);
3085                                 return (PO_FAIL);
3086                         }
3087                         src_size++;
3088                         tgt_size--;
3089                         pool_value_set_uint64(&val, src_size);
3090                         (void) pool_put_any_ns_property(xtransfer->pxu_src,
3091                             c_size_prop, &val);
3092                         pool_value_set_uint64(&val, tgt_size);
3093                         (void) pool_put_any_ns_property(xtransfer->pxu_tgt,
3094                             c_size_prop, &val);
3095                 }
3096                 break;
3097         case POOL_PROPPUT:
3098                 propput = (pool_propput_undo_t *)li->li_details;
3099 
3100                 if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) {
3101                         if (propput->ppu_blist != NULL) {
3102                                 if (nvlist_merge(
3103                                     ((pool_knl_elem_t *)propput->ppu_elem)->
3104                                     pke_properties, propput->ppu_blist, 0)
3105                                     != 0) {
3106                                         pool_seterror(POE_SYSTEM);
3107                                         return (PO_FAIL);
3108                                 }
3109                         } else {
3110                                 if (nvlist_unpack(propput->ppu_ioctl.pp_o_buf,
3111                                     propput->ppu_ioctl.pp_o_bufsize,
3112                                     &propput->ppu_alist, 0) != 0) {
3113                                         pool_seterror(POE_SYSTEM);
3114                                         return (PO_FAIL);
3115                                 }
3116                                 pair = nvlist_next_nvpair(propput->ppu_alist,
3117                                     NULL);
3118                                 (void) nvlist_remove_all(((pool_knl_elem_t *)
3119                                     propput->ppu_elem)->pke_properties,
3120                                     nvpair_name(pair));
3121                                 nvlist_free(propput->ppu_alist);
3122                         }
3123                 }
3124                 break;
3125         case POOL_PROPRM:
3126                 proprm = (pool_proprm_undo_t *)li->li_details;
3127 
3128                 if (pool_value_get_type(&proprm->pru_oldval) != POC_INVAL) {
3129                         if (pool_put_property(conf, proprm->pru_elem,
3130                             proprm->pru_ioctl.pp_o_prop_name,
3131                             &proprm->pru_oldval) != PO_SUCCESS) {
3132                                 return (PO_FAIL);
3133                         }
3134                 }
3135                 break;
3136         default:
3137                 return (PO_FAIL);
3138         }
3139         }
3140         /*
3141          * Only try to undo the state of the kernel if we modified it.
3142          */
3143         if (li->li_state == LS_DO) {
3144                 return (PO_SUCCESS);
3145         }
3146 
3147         switch (li->li_op) {
3148         case POOL_CREATE:
3149                 create = (pool_create_undo_t *)li->li_details;
3150 
3151                 u_destroy.pd_o_type = create->pcu_ioctl.pc_o_type;
3152                 u_destroy.pd_o_sub_type = create->pcu_ioctl.pc_o_sub_type;
3153                 u_destroy.pd_o_id = create->pcu_ioctl.pc_i_id;
3154 
3155                 while ((ret = ioctl(prov->pkc_fd, POOL_DESTROY,
3156                     &u_destroy)) < 0 && errno == EAGAIN)
3157                         ;
3158                 if (ret < 0) {
3159                         pool_seterror(POE_SYSTEM);
3160                         return (PO_FAIL);
3161                 }
3162                 li->li_state = LS_DO;
3163                 break;
3164         case POOL_DESTROY:
3165                 destroy = (pool_destroy_undo_t *)li->li_details;
3166 
3167                 u_create.pc_o_type = destroy->pdu_ioctl.pd_o_type;
3168                 u_create.pc_o_sub_type = destroy->pdu_ioctl.pd_o_sub_type;
3169 
3170                 if (ioctl(prov->pkc_fd, POOL_CREATE, &u_create) < 0) {
3171                         pool_seterror(POE_SYSTEM);
3172                         return (PO_FAIL);
3173                 }
3174 
3175                 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
3176                         return (PO_FAIL);
3177                 }
3178                 if (set_char_buf(cb, "%s.sys_id",
3179                     pool_elem_class_string(destroy->pdu_elem)) != PO_SUCCESS) {
3180                         free_char_buf(cb);
3181                         return (PO_FAIL);
3182                 }
3183                 (void) nvlist_add_int64(
3184                     ((pool_knl_elem_t *)destroy->pdu_elem)->pke_properties,
3185                     cb->cb_buf, u_create.pc_i_id);
3186                 free_char_buf(cb);
3187                 if (dict_put(prov->pkc_elements, destroy->pdu_elem,
3188                     destroy->pdu_elem) != NULL) {
3189                         pool_seterror(POE_SYSTEM);
3190                         return (PO_FAIL);
3191                 }
3192                 /*
3193                  * Now we need to reset all the properties and
3194                  * associations in the kernel for this newly created
3195                  * replacement.
3196                  */
3197                 u_propput.pp_o_id_type = destroy->pdu_ioctl.pd_o_type;
3198                 u_propput.pp_o_id_sub_type = destroy->pdu_ioctl.pd_o_sub_type;
3199                 u_propput.pp_o_id = u_create.pc_i_id;
3200                 u_propput.pp_o_buf = NULL;
3201                 /*
3202                  * Remove the read-only properties before attempting
3203                  * to restore the state of the newly created property
3204                  */
3205                 (void) nvlist_dup(((pool_knl_elem_t *)destroy->pdu_elem)->
3206                     pke_properties, &tmplist, 0);
3207                 for (pair = nvlist_next_nvpair(tmplist, NULL); pair != NULL;
3208                     pair = nvlist_next_nvpair(tmplist, pair)) {
3209                         const pool_prop_t *prop;
3210                         char *name = nvpair_name(pair);
3211                         if ((prop = provider_get_prop(destroy->pdu_elem,
3212                             name)) != NULL)
3213                                 if (prop_is_readonly(prop) == PO_TRUE)
3214                                         (void) nvlist_remove_all(tmplist, name);
3215                 }
3216                 if (nvlist_pack(tmplist, (char **)&u_propput.pp_o_buf,
3217                     &u_propput.pp_o_bufsize, NV_ENCODE_NATIVE, 0) != 0) {
3218                         pool_seterror(POE_SYSTEM);
3219                         return (PO_FAIL);
3220                 }
3221                 nvlist_free(tmplist);
3222                 if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) {
3223                         free(u_propput.pp_o_buf);
3224                         pool_seterror(POE_SYSTEM);
3225                         return (PO_FAIL);
3226                 }
3227                 free(u_propput.pp_o_buf);
3228                 /*
3229                  * Now reset the associations for all the resource
3230                  * types if the thing which we are recreating is a
3231                  * pool
3232                  *
3233                  * TODO: This is resource specific and must be
3234                  * extended for additional resource types.
3235                  */
3236                 if (destroy->pdu_ioctl.pd_o_type == PEC_POOL) {
3237                         u_assoc.pa_o_pool_id = u_create.pc_i_id;
3238                         u_assoc.pa_o_res_id =
3239                             elem_get_sysid(
3240                             TO_ELEM(((pool_knl_pool_t *)destroy->pdu_elem)->
3241                             pkp_assoc[PREC_PSET]));
3242                         u_assoc.pa_o_id_type = PREC_PSET;
3243 
3244                         if (ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc) < 0) {
3245                                 pool_seterror(POE_SYSTEM);
3246                                 return (PO_FAIL);
3247                         }
3248                 }
3249                 li->li_state = LS_DO;
3250                 break;
3251         case POOL_ASSOC:
3252                 assoc = (pool_assoc_undo_t *)li->li_details;
3253 
3254                 u_assoc.pa_o_pool_id = elem_get_sysid(assoc->pau_assoc);
3255                 u_assoc.pa_o_res_id = elem_get_sysid(assoc->pau_oldres);
3256                 u_assoc.pa_o_id_type = assoc->pau_ioctl.pa_o_id_type;
3257 
3258                 while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 &&
3259                     errno == EAGAIN)
3260                         ;
3261                 if (ret < 0) {
3262                         pool_seterror(POE_SYSTEM);
3263                         return (PO_FAIL);
3264                 }
3265                 li->li_state = LS_DO;
3266                 break;
3267         case POOL_DISSOC:
3268                 dissoc = (pool_dissoc_undo_t *)li->li_details;
3269 
3270                 u_assoc.pa_o_pool_id = elem_get_sysid(dissoc->pdu_dissoc);
3271                 u_assoc.pa_o_res_id = elem_get_sysid(dissoc->pdu_oldres);
3272                 u_assoc.pa_o_id_type = dissoc->pdu_ioctl.pd_o_id_type;
3273 
3274                 while ((ret = ioctl(prov->pkc_fd, POOL_ASSOC, &u_assoc)) < 0 &&
3275                     errno == EAGAIN)
3276                         ;
3277                 if (ret < 0) {
3278                         pool_seterror(POE_SYSTEM);
3279                         return (PO_FAIL);
3280                 }
3281                 li->li_state = LS_DO;
3282                 break;
3283         case POOL_TRANSFER:
3284                 li->li_state = LS_DO;
3285                 pool_seterror(POE_BADPARAM);
3286                 return (PO_FAIL);
3287         case POOL_XTRANSFER:
3288                 xtransfer = (pool_xtransfer_undo_t *)li->li_details;
3289 
3290                 (void) memcpy(&u_xtransfer, &xtransfer->pxu_ioctl,
3291                     sizeof (pool_xtransfer_t));
3292                 u_xtransfer.px_o_src_id = elem_get_sysid(xtransfer->pxu_tgt);
3293                 u_xtransfer.px_o_tgt_id = elem_get_sysid(xtransfer->pxu_src);
3294 
3295                 if (ioctl(prov->pkc_fd, POOL_XTRANSFER, &u_xtransfer) < 0) {
3296                         pool_seterror(POE_SYSTEM);
3297                         return (PO_FAIL);
3298                 }
3299                 li->li_state = LS_DO;
3300                 break;
3301         case POOL_PROPPUT:
3302                 propput = (pool_propput_undo_t *)li->li_details;
3303 
3304                 if ((propput->ppu_doioctl & KERNEL_PROP_RDONLY) == 0) {
3305                         if (propput->ppu_blist) {
3306                                 (void) memcpy(&u_propput, &propput->ppu_ioctl,
3307                                     sizeof (pool_propput_t));
3308                                 u_propput.pp_o_id =
3309                                     elem_get_sysid(propput->ppu_elem);
3310                                 u_propput.pp_o_buf = NULL;
3311                                 if (nvlist_pack(propput->ppu_blist,
3312                                     (char **)&u_propput.pp_o_buf,
3313                                     &u_propput.pp_o_bufsize,
3314                                     NV_ENCODE_NATIVE, 0) != 0) {
3315                                         pool_seterror(POE_SYSTEM);
3316                                         return (PO_FAIL);
3317                                 }
3318                                 if (ioctl(prov->pkc_fd, POOL_PROPPUT,
3319                                     &u_propput) < 0) {
3320                                         free(u_propput.pp_o_buf);
3321                                         pool_seterror(POE_SYSTEM);
3322                                         return (PO_FAIL);
3323                                 }
3324                                 free(u_propput.pp_o_buf);
3325                         } else {
3326                                 if (nvlist_unpack(propput->
3327                                     ppu_ioctl.pp_o_buf,
3328                                     propput->ppu_ioctl.pp_o_bufsize,
3329                                     &propput->ppu_alist, 0) != 0) {
3330                                         pool_seterror(POE_SYSTEM);
3331                                         return (PO_FAIL);
3332                                 }
3333                                 u_proprm.pp_o_id_type =
3334                                     propput->ppu_ioctl.pp_o_id_type;
3335                                 u_proprm.pp_o_id_sub_type =
3336                                     propput->ppu_ioctl.pp_o_id_sub_type;
3337                                 u_proprm.pp_o_id =
3338                                     elem_get_sysid(propput->ppu_elem);
3339                                 pair = nvlist_next_nvpair(propput->ppu_alist,
3340                                     NULL);
3341                                 u_proprm.pp_o_prop_name = nvpair_name(pair);
3342                                 u_proprm.pp_o_prop_name_size =
3343                                     strlen(u_proprm.pp_o_prop_name);
3344 
3345                                 if (provider_get_prop(propput->ppu_elem,
3346                                     u_proprm.pp_o_prop_name) == NULL) {
3347                                         if (ioctl(prov->pkc_fd, POOL_PROPRM,
3348                                             &u_proprm) < 0) {
3349                                                 nvlist_free(propput->ppu_alist);
3350                                                 pool_seterror(POE_SYSTEM);
3351                                                 return (PO_FAIL);
3352                                         }
3353                                 }
3354                                 nvlist_free(propput->ppu_alist);
3355                         }
3356                 }
3357                 li->li_state = LS_DO;
3358                 break;
3359         case POOL_PROPRM:
3360                 proprm = (pool_proprm_undo_t *)li->li_details;
3361 
3362                 u_propput.pp_o_id_type = proprm->pru_ioctl.pp_o_id_type;
3363                 u_propput.pp_o_id_sub_type =
3364                     proprm->pru_ioctl.pp_o_id_sub_type;
3365                 u_propput.pp_o_id = elem_get_sysid(proprm->pru_elem);
3366                 u_propput.pp_o_buf = NULL;
3367                 /*
3368                  * Only try to remove the appropriate property
3369                  */
3370                 if (nvlist_alloc(&tmplist, NV_UNIQUE_NAME_TYPE, 0) !=
3371                     0) {
3372                         pool_seterror(POE_SYSTEM);
3373                         return (PO_FAIL);
3374                 }
3375                 if (pool_knl_nvlist_add_value(tmplist,
3376                     pool_value_get_name(&proprm->pru_oldval),
3377                     &proprm->pru_oldval) != PO_SUCCESS)
3378                         return (PO_FAIL);
3379 
3380                 if (nvlist_pack(tmplist,
3381                     (char **)&u_propput.pp_o_buf, &u_propput.pp_o_bufsize,
3382                     NV_ENCODE_NATIVE, 0) != 0) {
3383                         nvlist_free(tmplist);
3384                         pool_seterror(POE_SYSTEM);
3385                         return (PO_FAIL);
3386                 }
3387                 nvlist_free(tmplist);
3388                 if (ioctl(prov->pkc_fd, POOL_PROPPUT, &u_propput) < 0) {
3389                         free(u_propput.pp_o_buf);
3390                         pool_seterror(POE_SYSTEM);
3391                         return (PO_FAIL);
3392                 }
3393                 free(u_propput.pp_o_buf);
3394                 li->li_state = LS_DO;
3395                 break;
3396         default:
3397                 return (PO_FAIL);
3398         }
3399                 return (PO_SUCCESS);
3400 }
3401 
3402 /*
3403  * A log item stores state about the transaction it represents. This
3404  * function releases the resources associated with the transaction and
3405  * used to store the transaction state.
3406  */
3407 int
3408 log_item_release(log_item_t *li)
3409 {
3410         pool_create_undo_t *create;
3411         pool_destroy_undo_t *destroy;
3412         pool_assoc_undo_t *assoc;
3413         pool_dissoc_undo_t *dissoc;
3414         pool_propput_undo_t *propput;
3415         pool_proprm_undo_t *proprm;
3416         pool_xtransfer_undo_t *xtransfer;
3417 
3418         switch (li->li_op) {
3419         case POOL_CREATE:
3420                 create = (pool_create_undo_t *)li->li_details;
3421 
3422                 free(create);
3423                 break;
3424         case POOL_DESTROY:
3425                 destroy = (pool_destroy_undo_t *)li->li_details;
3426 
3427 #ifdef DEBUG
3428                 dprintf("log_item_release: POOL_DESTROY\n");
3429 #endif  /* DEBUG */
3430 
3431                 if (li->li_state == LS_UNDO) {
3432 #ifdef DEBUG
3433                         pool_elem_dprintf(destroy->pdu_elem);
3434 #endif  /* DEBUG */
3435                         pool_knl_elem_free((pool_knl_elem_t *)destroy->
3436                             pdu_elem, PO_TRUE);
3437                 }
3438                 free(destroy);
3439                 break;
3440         case POOL_ASSOC:
3441                 assoc = (pool_assoc_undo_t *)li->li_details;
3442 
3443                 free(assoc);
3444                 break;
3445         case POOL_DISSOC:
3446                 dissoc = (pool_dissoc_undo_t *)li->li_details;
3447 
3448                 free(dissoc);
3449                 break;
3450         case POOL_TRANSFER:
3451                 pool_seterror(POE_BADPARAM);
3452                 return (PO_FAIL);
3453         case POOL_XTRANSFER:
3454                 xtransfer = (pool_xtransfer_undo_t *)li->li_details;
3455 
3456                 free(xtransfer->pxu_rl);
3457                 free(xtransfer->pxu_ioctl.px_o_comp_list);
3458                 free(xtransfer);
3459                 break;
3460         case POOL_PROPPUT:
3461                 propput = (pool_propput_undo_t *)li->li_details;
3462 
3463                 if (propput->ppu_blist)
3464                         nvlist_free(propput->ppu_blist);
3465                 free(propput->ppu_ioctl.pp_o_buf);
3466                 free(propput);
3467                 break;
3468         case POOL_PROPRM:
3469                 proprm = (pool_proprm_undo_t *)li->li_details;
3470 
3471                 free(proprm);
3472                 break;
3473         default:
3474                 return (PO_FAIL);
3475         }
3476         return (PO_SUCCESS);
3477 }
3478 
3479 /*
3480  * pool_knl_nvlist_add_value() adds a pool_value_t to an nvlist.
3481  */
3482 int
3483 pool_knl_nvlist_add_value(nvlist_t *list, const char *name,
3484     const pool_value_t *pv)
3485 {
3486         uint64_t uval;
3487         int64_t ival;
3488         double dval;
3489         uchar_t dval_b[sizeof (double)];
3490         uchar_t bval;
3491         const char *sval;
3492         pool_value_class_t type;
3493         char *nv_name;
3494 
3495         if ((type = pool_value_get_type(pv)) == POC_INVAL) {
3496                 pool_seterror(POE_BADPARAM);
3497                 return (PO_FAIL);
3498         }
3499         nv_name = (char *)name;
3500 
3501         switch (type) {
3502         case POC_UINT:
3503                 if (pool_value_get_uint64(pv, &uval) == POC_INVAL) {
3504                         return (PO_FAIL);
3505                 }
3506                 if (nvlist_add_uint64(list, nv_name, uval) != 0) {
3507                         pool_seterror(POE_SYSTEM);
3508                         return (PO_FAIL);
3509                 }
3510                 break;
3511         case POC_INT:
3512                 if (pool_value_get_int64(pv, &ival) == POC_INVAL) {
3513                         return (PO_FAIL);
3514                 }
3515                 if (nvlist_add_int64(list, nv_name, ival) != 0) {
3516                         pool_seterror(POE_SYSTEM);
3517                         return (PO_FAIL);
3518                 }
3519                 break;
3520         case POC_DOUBLE:
3521                 if (pool_value_get_double(pv, &dval) == POC_INVAL) {
3522                         return (PO_FAIL);
3523                 }
3524                 /*
3525                  * Since there is no support for doubles in the
3526                  * kernel, store the double value in a byte array.
3527                  */
3528                 (void) memcpy(dval_b, &dval, sizeof (double));
3529                 if (nvlist_add_byte_array(list, nv_name, dval_b,
3530                     sizeof (double)) != 0) {
3531                         pool_seterror(POE_SYSTEM);
3532                         return (PO_FAIL);
3533                 }
3534                 break;
3535         case POC_BOOL:
3536                 if (pool_value_get_bool(pv, &bval) == POC_INVAL) {
3537                         return (PO_FAIL);
3538                 }
3539                 if (nvlist_add_byte(list, nv_name, bval) != 0) {
3540                         pool_seterror(POE_SYSTEM);
3541                         return (PO_FAIL);
3542                 }
3543                 break;
3544         case POC_STRING:
3545                 if (pool_value_get_string(pv, &sval) == POC_INVAL) {
3546                         return (PO_FAIL);
3547                 }
3548                 if (nvlist_add_string(list, nv_name, (char *)sval) != 0) {
3549                         pool_seterror(POE_SYSTEM);
3550                         return (PO_FAIL);
3551                 }
3552                 break;
3553         default:
3554                 pool_seterror(POE_BADPARAM);
3555                 return (PO_FAIL);
3556         }
3557         return (PO_SUCCESS);
3558 }
3559 
3560 /*
3561  * hash_id() hashes all elements in a pool configuration using the
3562  * "sys_id" property. Not all elements have a "sys_id" property,
3563  * however elem_get_sysid() caters for this by always returning a
3564  * constant value for those elements. This isn't anticipated to lead
3565  * to a performance degradation in the hash, since those elements
3566  * which are likely to be most prevalent in a configuration do have
3567  * "sys_id" as a property.
3568  */
3569 uint64_t
3570 hash_id(const pool_elem_t *pe)
3571 {
3572         id_t id;
3573 
3574         id = elem_get_sysid(pe);
3575         return (hash_buf(&id, sizeof (id)));
3576 }
3577 
3578 /*
3579  *  blocking_open() guarantees access to the pool device, if open()
3580  * is failing with EBUSY.
3581  */
3582 int
3583 blocking_open(const char *path, int oflag)
3584 {
3585         int fd;
3586 
3587         while ((fd = open(path, oflag)) == -1 && errno == EBUSY)
3588                 (void) poll(NULL, 0, 1 * MILLISEC);
3589 
3590         return (fd);
3591 }