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