1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <assert.h>
30 #include <libintl.h>
31
32 #include <string.h>
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <errno.h>
36 #include <search.h>
37
38 #include "volume_dlist.h"
39 #include "volume_error.h"
40 #include "volume_output.h"
41
42 #include "layout_device_cache.h"
43 #include "layout_dlist_util.h"
44 #include "layout_request.h"
45
46 /*
47 * Implementation note:
48 * The current caches are implemented as linked lists of data
49 * structures described below. Cached object lookup uses hsearch()
50 * where possible to minimize the inefficiency of linear search.
51 */
52
53 /*
54 * The name and attribute maps use hesarch() for faster lookup
55 */
56 static const uint32_t MAX_CACHED_OBJECTS = 50000;
57
58 /*
59 * The attribute cache is maintained as a list of these
60 * structs which map a device name to attributes. The
61 * device name is the unique device name returned from
62 * the device library, typically a devfs path. It should
63 * not be confused with the "display" name of the device
64 * which is typically a CTD or DID name.
65 */
66 typedef struct {
67 char *name;
68 nvlist_t *attrs;
69 } attr_cache_t;
70
71 static dlist_t *_attr_cache = NULL;
72
73 /*
74 * The name cache is maintained via a list of these structs
75 * which map a descriptor to its name.
76 * The descriptor is saved as a string for hsearch()
77 */
78 typedef struct {
79 char *desc;
80 char *name;
81 } name_cache_t;
82 static dlist_t *_name_cache = NULL;
83
84 /*
85 * The desc cache is maintained as a list of these
86 * structs which map a device display name (CTD or DID)
87 * or alias to a descriptor.
88 */
89 typedef struct {
90 char *name;
91 dm_descriptor_t desc;
92 } desc_cache_t;
93
94 static dlist_t *_desc_cache = NULL;
95
96 /*
97 * Since each of the lookup caches shares the same hsearch()
98 * hash table, the names used as lookup keys for the desc_cache_t
99 * and attr_cache_t may cause collisions.
100 *
101 * The desc_cache_t map alters the device name by prepending
102 * this string to avoid collisions.
103 */
104 static const char *DESC_CACHE_KEY_PREFIX = "desc_cache";
105
106 /*
107 * The set of descriptors to be returned to libdiskmgt is
108 * maintained via a list of dm_descriptor_t handles.
109 * descriptors are added by new_descriptor() and
110 * cache_descriptor_to_free().
111 */
112 typedef struct {
113 dm_descriptor_t desc;
114 boolean_t virtual;
115 } desc_free_t;
116 static dlist_t *_desc_to_free = NULL;
117
118 static char *find_cached_name(dm_descriptor_t desc);
119 static nvlist_t *find_cached_attrs(char *name);
120
121 static int add_descriptor_to_free(dm_descriptor_t desc);
122
123 static void release_name_cache();
124 static void release_desc_to_free_cache();
125 static void release_attribute_cache();
126 static void release_descriptor_cache();
127
128 static uint32_t interal_name_count = 0;
129
130 /*
131 * FUNCTION: create_device_caches()
132 *
133 * PURPOSE: Helper which initializes the module's private data
134 * structures.
135 */
136 int
create_device_caches()137 create_device_caches()
138 {
139 if (hcreate(MAX_CACHED_OBJECTS) == 0) {
140 return (ENOMEM);
141 }
142
143 return (0);
144 }
145
146 /*
147 * FUNCTION: release_device_caches()
148 *
149 * PURPOSE: Helper which cleans up memory allocated to the module's
150 * private data structures.
151 */
152 int
release_device_caches()153 release_device_caches()
154 {
155 release_name_cache();
156 release_desc_to_free_cache();
157 release_attribute_cache();
158 release_descriptor_cache();
159
160 return (0);
161 }
162
163 /*
164 * FUNCTION: free_desc_cache_object(void *obj)
165 *
166 * INPUT: obj - opaque pointer
167 *
168 * PURPOSE: Frees memory associated with an entry in the
169 * desc cache.
170 *
171 * Assumes that the input object is a pointer
172 * to a desc_cache_t struct.
173 */
174 static void
free_desc_cache_object(void * obj)175 free_desc_cache_object(
176 void *obj)
177 {
178 if (obj == NULL) {
179 return;
180 }
181
182 free(((desc_cache_t *)obj)->name);
183 free(obj);
184 }
185 /*
186 * FUNCTION: release_descriptor_cache()
187 *
188 * RETURNS: int - 0 on success
189 * !0 otherwise
190 *
191 * PURPOSE: Frees all entries in the name cache.
192 */
193 static void
release_descriptor_cache()194 release_descriptor_cache()
195 {
196 oprintf(OUTPUT_DEBUG,
197 gettext(" destroying descriptor cache (%d items)\n"),
198 dlist_length(_desc_cache));
199
200 dlist_free_items(_desc_cache, free_desc_cache_object);
201 _desc_cache = NULL;
202 }
203
204 /*
205 * FUNCTION: add_cached_descriptor(char *name, dm_descriptor_t desc)
206 *
207 * INPUT: name - a device name
208 * desc - a dm_descriptor_t handle
209 *
210 * RETURNS: int - 0 on success
211 * !0 otherwise
212 *
213 * PURPOSE: Adds an entry to the descriptor cache using the input
214 * descriptor and name.
215 *
216 * Note that all of the lookup caches shares the same hsearch()
217 * hash table and that the names used as lookup keys for the
218 * desc_cache_t and attr_cache_t cause collisions.
219 *
220 * The desc_cache_t map alters the device name to avoid collisions.
221 */
222 int
add_cached_descriptor(char * name,dm_descriptor_t desc)223 add_cached_descriptor(
224 char *name,
225 dm_descriptor_t desc)
226 {
227 desc_cache_t *dcp;
228 char buf[MAXNAMELEN+1];
229 dlist_t *item;
230 ENTRY entry;
231
232 if ((dcp = (desc_cache_t *)
233 calloc(1, sizeof (desc_cache_t))) == NULL) {
234 return (ENOMEM);
235 }
236
237 dcp->desc = desc;
238
239 (void) snprintf(buf, MAXNAMELEN, "%s-%s", DESC_CACHE_KEY_PREFIX, name);
240 dcp->name = strdup(buf);
241 if (dcp->name == NULL) {
242 free(dcp);
243 return (ENOMEM);
244 }
245
246 /*
247 * insert into the hashtable... ignore the return from hsearch(),
248 * there is no existing entry corresponding to desc since the
249 * map was already searched just before this function is called,
250 * see get_name() below
251 */
252 entry.key = dcp->name;
253 entry.data = (void *)dcp;
254 (void) hsearch(entry, ENTER);
255
256 /* insert into the list cache... */
257 if ((item = dlist_new_item((void *)dcp)) == NULL) {
258 free(dcp);
259 return (ENOMEM);
260 }
261
262 _desc_cache = dlist_append(item, _desc_cache, AT_HEAD);
263
264 return (0);
265 }
266
267 /*
268 * FUNCTION: dm_descriptor_t find_cached_descriptor(char *name)
269 *
270 * INPUT: char * - pointer to a name or alias.
271 *
272 * RETURNS: dm_descriptor_t - dm_descriptor_t handle cached under the
273 * input name if a match is found. A null descriptor
274 * is returned if no match is found.
275 *
276 * PURPOSE: Searches for the desc that has been cached for
277 * the input device name.
278 *
279 * Note that all of the lookup caches shares the same hsearch()
280 * hash table and that the names used as lookup keys for the
281 * desc_cache_t and attr_cache_t cause collisions.
282 *
283 * The desc_cache_t map alters the device name to avoid collisions.
284 */
285 dm_descriptor_t
find_cached_descriptor(char * name)286 find_cached_descriptor(
287 char *name)
288 {
289 ENTRY item;
290 ENTRY *cached_item = NULL;
291 char buf[MAXNAMELEN+1];
292 dm_descriptor_t desc = (dm_descriptor_t)0;
293
294 (void) snprintf(buf, MAXNAMELEN, "%s-%s", DESC_CACHE_KEY_PREFIX, name);
295 item.key = buf;
296
297 /* get descriptor associated with this name */
298 if ((cached_item = hsearch(item, FIND)) != NULL) {
299 /* LINTED */
300 desc = ((desc_cache_t *)cached_item->data)->desc;
301 }
302
303 return (desc);
304 }
305
306 /*
307 * FUNCTION: free_name_cache_object(void *obj)
308 *
309 * INPUT: obj - opaque pointer
310 *
311 * PURPOSE: Frees memory associated with an entry in the
312 * name cache.
313 *
314 * Assumes that the input object is a pointer
315 * to a name_cache_t struct.
316 */
317 static void
free_name_cache_object(void * obj)318 free_name_cache_object(
319 void *obj)
320 {
321 if (obj == NULL) {
322 return;
323 }
324
325 free(((name_cache_t *)obj)->desc);
326 free(((name_cache_t *)obj)->name);
327 free(obj);
328 }
329
330 /*
331 * FUNCTION: release_name_cache()
332 *
333 * RETURNS: int - 0 on success
334 * !0 otherwise
335 *
336 * PURPOSE: Frees all entries in the name cache.
337 */
338 static void
release_name_cache()339 release_name_cache()
340 {
341 oprintf(OUTPUT_DEBUG,
342 gettext(" destroying name cache (%d items)\n"),
343 dlist_length(_name_cache));
344
345 dlist_free_items(_name_cache, free_name_cache_object);
346 _name_cache = NULL;
347 }
348
349 /*
350 * FUNCTION: add_cached_name(dm_descriptor_t desc, char *name)
351 *
352 * INPUT: desc - a dm_descriptor_t handle
353 * name - a device name
354 *
355 * RETURNS: int - 0 on success
356 * !0 otherwise
357 *
358 * PURPOSE: Adds an entry to the name cache using the input
359 * descriptor and name.
360 */
361 int
add_cached_name(dm_descriptor_t desc,char * name)362 add_cached_name(
363 dm_descriptor_t desc,
364 char *name)
365 {
366 name_cache_t *ncp;
367 char buf[MAXNAMELEN+1];
368 dlist_t *item;
369 ENTRY entry;
370
371 if ((ncp = (name_cache_t *)
372 calloc(1, sizeof (name_cache_t))) == NULL) {
373 return (ENOMEM);
374 }
375
376 (void) snprintf(buf, MAXNAMELEN, "%llu", desc);
377 ncp->desc = strdup(buf);
378 if (ncp->desc == NULL) {
379 free(ncp);
380 return (ENOMEM);
381 }
382
383 ncp->name = strdup(name);
384 if (ncp->name == NULL) {
385 free(ncp->desc);
386 free(ncp);
387 return (ENOMEM);
388 }
389
390 /*
391 * insert into the hashtable... ignore the return from hsearch(),
392 * there is no existing entry corresponding to desc since the
393 * map was already searched just before this function is called,
394 * see get_name() below
395 */
396 entry.key = ncp->desc;
397 entry.data = (void *)ncp;
398 (void) hsearch(entry, ENTER);
399
400 /* insert into the list cache... */
401 if ((item = dlist_new_item((void *)ncp)) == NULL) {
402 free(ncp->desc);
403 free(ncp->name);
404 free(ncp);
405 return (ENOMEM);
406 }
407
408 _name_cache = dlist_append(item, _name_cache, AT_HEAD);
409
410 return (0);
411 }
412
413 /*
414 * FUNCTION: char *find_cached_name(dm_descriptor_t desc)
415 *
416 * INPUT: desc - a dm_descriptor_t handle
417 *
418 * RETURNS: char * - pointer to the name cached for the descriptor.
419 * Null otherwise.
420 *
421 * PURPOSE: Searches for the name that has been cached for
422 * the input dm_descriptor_t.
423 *
424 * Search linked list.
425 */
426 static char *
find_cached_name(dm_descriptor_t desc)427 find_cached_name(
428 dm_descriptor_t desc)
429 {
430 char buf[MAXNAMELEN+1];
431 ENTRY item;
432 ENTRY *cached_item = NULL;
433 char *name = NULL;
434
435 (void) snprintf(buf, MAXNAMELEN, "%llu", desc);
436 item.key = buf;
437
438 /* get name associated with this descriptor */
439 if ((cached_item = hsearch(item, FIND)) != NULL) {
440 /* LINTED */
441 name = ((name_cache_t *)cached_item->data)->name;
442 }
443
444 return (name);
445 }
446
447 /*
448 * FUNCTION: get_name(dm_descriptor_t desc,
449 * char_t **name)
450 *
451 * INPUT: desc - a dm_descriptor_t handle
452 *
453 * OUTPUT: name - pointer to char * to hold the name
454 *
455 * RETURNS: int - 0 on success
456 * !0 otherwise
457 *
458 * PURPOSE: Searches for the name that has been cached for the
459 * input dm_descriptor_t.
460 *
461 * Names are cached using the dm_descriptor.
462 * If no name has yet been cached, it is retrieved from
463 * libdiskmgt and added to the cache.
464 *
465 * Names are cached so that all name strings obtained from
466 * libdiskmgt will get properly released when layout completes.
467 */
468 int
get_name(dm_descriptor_t desc,char ** name)469 get_name(
470 dm_descriptor_t desc,
471 char **name)
472 {
473
474 int dm_free = 1;
475 int error = 0;
476
477 if ((desc != (dm_descriptor_t)0) &&
478 (*name = find_cached_name(desc)) == NULL) {
479
480 /* not in descriptor->name cache/map, add it */
481
482 if (is_virtual_slice(desc) != B_TRUE) {
483
484 dm_desc_type_t type;
485
486 *name = dm_get_name(desc, &error);
487 if (error != 0) {
488 volume_set_error(
489 gettext("failed to get name for descriptor: %d\n"),
490 error);
491 return (-1);
492 }
493
494 /*
495 * some devices can be unnamed...
496 * assign a unique internal name if necessary
497 */
498 if (*name == NULL) {
499 char buf[MAXNAMELEN];
500
501 dm_free = 0;
502 (void) snprintf(buf, MAXNAMELEN-1, "temp-name-%lu",
503 interal_name_count++);
504 *name = strdup(buf);
505 if (*name == NULL) {
506 volume_set_error(
507 gettext("failed to get name for descriptor: %d\n"),
508 errno);
509 return (-1);
510 }
511 oprintf(OUTPUT_DEBUG,
512 gettext("unnamed descriptor %llu assigned %s\n"),
513 desc, *name);
514 }
515
516 /*
517 * media can have the same name as the associated drive
518 * which hoses the attribute caching scheme, so unique-ify
519 */
520 if ((type = dm_get_type(desc)) == DM_MEDIA) {
521 char buf[MAXNAMELEN];
522 (void) snprintf(buf, MAXNAMELEN-1, "%s-%d", *name, type);
523 error = add_cached_name(desc, buf);
524 } else {
525 error = add_cached_name(desc, *name);
526 }
527 if (dm_free)
528 dm_free_name(*name);
529 else
530 free(*name);
531
532 if (error == 0) {
533 /* return copied name */
534 *name = find_cached_name(desc);
535 } else {
536 *name = NULL;
537 }
538 }
539 }
540
541 return (error);
542 }
543
544 /*
545 * FUNCTION: free_attr_cache_object(void *obj)
546 *
547 * INPUT: obj - opaque pointer
548 *
549 * PURPOSE: Frees memory associated with an entry in the
550 * attribute cache.
551 *
552 * Assumes that the input object is a pointer
553 * to a attr_cache_t struct.
554 */
555 static void
free_attr_cache_object(void * obj)556 free_attr_cache_object(
557 void *obj)
558 {
559 if (obj == NULL) {
560 return;
561 }
562
563 nvlist_free(((attr_cache_t *)obj)->attrs);
564 free(obj);
565 }
566
567 /*
568 * FUNCTION: release_attribute_cache()
569 *
570 * RETURNS: int - 0 on success
571 * !0 otherwise
572 *
573 * PURPOSE: Frees all entries in the attribute cache.
574 */
575 void
release_attribute_cache()576 release_attribute_cache()
577 {
578 oprintf(OUTPUT_DEBUG,
579 gettext(" destroying attribute cache (%d items)\n"),
580 dlist_length(_attr_cache));
581
582 dlist_free_items(_attr_cache, free_attr_cache_object);
583 _attr_cache = NULL;
584
585 /* cleanup attribute cache lookup hashtable */
586 hdestroy();
587 }
588
589 /*
590 * FUNCTION: add_cached_attributes(char *name, nvlist_t *attrs)
591 *
592 * INPUT: name - a device name
593 * attrs - pointer to an nvlist_t attribute structure
594 *
595 * RETURNS: int - 0 on success
596 * !0 otherwise
597 *
598 * PURPOSE: Adds an entry to the attribute cache using the input
599 * name and attributes.
600 *
601 * Uses a linked list to cache attributes.
602 * Keeps a parallel hash table for faster lookup.
603 */
604 int
add_cached_attributes(char * name,nvlist_t * attrs)605 add_cached_attributes(
606 char *name,
607 nvlist_t *attrs)
608 {
609 attr_cache_t *acp = NULL;
610 dlist_t *item = NULL;
611 ENTRY *exist = NULL;
612 ENTRY entry;
613
614 /* insert into the hashtable... */
615 entry.key = name;
616 entry.data = (void *)attrs;
617
618 if ((exist = hsearch(entry, ENTER)) != NULL) {
619 /* replace the existing attrs entry */
620 exist->data = (void *)attrs;
621 }
622
623 if ((acp = (attr_cache_t *)calloc(1, sizeof (attr_cache_t))) == NULL) {
624 return (ENOMEM);
625 }
626
627 acp->name = name;
628 acp->attrs = attrs;
629
630 /* and cache of attr structs to be freed */
631 if ((item = dlist_new_item((void *)acp)) == NULL) {
632 free(acp);
633 return (ENOMEM);
634 }
635
636 _attr_cache = dlist_append(item, _attr_cache, AT_HEAD);
637
638 return (0);
639 }
640
641 /*
642 * FUNCTION: nvlist_t *find_cached_attrs(char *name)
643 *
644 * INPUT: name - a device name
645 *
646 * RETURNS: nvlist_t * - pointer to an nvlist_t attribute structure
647 * cached under 'name'. Null otherwise.
648 *
649 * PURPOSE: Searches for the nvlist attributes that have been
650 * cached for the input name.
651 */
652 static nvlist_t *
find_cached_attrs(char * name)653 find_cached_attrs(
654 char *name)
655 {
656 ENTRY item;
657 ENTRY *cached_item = NULL;
658 nvlist_t *attrs = NULL;
659
660 item.key = name;
661
662 /* get attributes cached under this name */
663 if ((cached_item = hsearch(item, FIND)) != NULL) {
664 /* LINTED */
665 attrs = (nvlist_t *)cached_item->data;
666 }
667
668 return (attrs);
669 }
670
671 /*
672 * FUNCTION: get_cached_attributes(dm_descriptor_t desc,
673 * nvlist_t **attrs)
674 *
675 * INPUT: desc - a dm_descriptor_t handle
676 *
677 * OUTPUT: attrs - pointer to an nvlist_t attribute structure
678 *
679 * RETURNS: int - 0 on success
680 * !0 otherwise
681 *
682 * PURPOSE: Searches for the nvlist attributes that have been
683 * cached for the input dm_descriptor_t.
684 *
685 * Attributes are cached using the name associated with
686 * the descriptor. If no attributes have yet been cached
687 * they are retrieved from libdiskmgt and added to the
688 * cache.
689 *
690 * Attributes are cached so that layout may store transient
691 * data relevant to the layout process.
692 */
693 int
get_cached_attributes(dm_descriptor_t desc,nvlist_t ** attrs)694 get_cached_attributes(
695 dm_descriptor_t desc,
696 nvlist_t **attrs)
697 {
698 int error = 0;
699 char *name = NULL;
700
701 if ((desc != (dm_descriptor_t)0) &&
702 (error = get_name(desc, &name)) == 0) {
703
704 if ((*attrs = find_cached_attrs(name)) == NULL) {
705 /* get attrs and cache them */
706 *attrs = dm_get_attributes(desc, &error);
707 if (error == 0) {
708 error = add_cached_attributes(name, *attrs);
709 }
710 }
711 }
712
713 return (error);
714 }
715
716 /*
717 * FUNCTION: new_descriptor(dm_descriptor_t *desc)
718 *
719 * INPUT: desc - a pointer to a dm_descriptor_t to hold
720 * the result.
721 *
722 * RETURNS: int - 0 on success
723 * !0 otherwise
724 *
725 * PURPOSE: Allocates a new dm_descriptor_t handle.
726 *
727 * This is necessary because the process may have to
728 * create "virtual" objects to represent devices that
729 * do not yet exist on the system and hence are unknown
730 * to libdiskmgt and diskmgtd.
731 *
732 * A unique handle is created for such objects and may
733 * be used by layout to access the virtual devices as
734 * if they were obtained from libdiskmgt.
735 */
736 int
new_descriptor(dm_descriptor_t * desc)737 new_descriptor(
738 dm_descriptor_t *desc)
739 {
740 desc_free_t *dfp;
741 dlist_t *item;
742
743 *desc = NULL;
744
745 if ((dfp = (desc_free_t *)
746 calloc(1, sizeof (desc_free_t))) == NULL) {
747 return (ENOMEM);
748 }
749
750 dfp->desc = (uintptr_t)dfp;
751 dfp->virtual = B_TRUE;
752
753 if ((item = dlist_new_item((void *)dfp)) == NULL) {
754 free(dfp);
755 return (ENOMEM);
756 }
757
758 _desc_to_free = dlist_append(item, _desc_to_free, AT_HEAD);
759
760 *desc = (uintptr_t)dfp;
761
762 return (0);
763 }
764
765 /*
766 * FUNCTION: add_descriptors_to_free(dm_descriptor_t *desc)
767 *
768 * INPUT: desc - an array of dm_descriptor_t handles from
769 * libdiskmgt
770 *
771 * RETURNS: int - 0 on success
772 * !0 otherwise
773 *
774 * PURPOSE: Function which accepts an array of dm_descriptor_t handles
775 * that need to be returned to libdiskmgt.
776 *
777 * The array is iterated and each handle is passed to
778 * add_descriptor_to_free.
779 */
780 int
add_descriptors_to_free(dm_descriptor_t * desc_list)781 add_descriptors_to_free(
782 dm_descriptor_t *desc_list)
783 {
784 int i = 0;
785
786 if (desc_list != NULL) {
787 for (i = 0; desc_list[i] != NULL; i++) {
788 (void) add_descriptor_to_free(desc_list[i]);
789 }
790 }
791
792 return (0);
793 }
794
795 /*
796 * FUNCTION: add_descriptor_to_free(dm_descriptor_t desc)
797 *
798 * INPUT: desc - dm_descriptor_t handle from libdiskmgt
799 *
800 * RETURNS: int - 0 on success
801 * !0 otherwise
802 *
803 * PURPOSE: Remembers a dm_descriptor_t handle which needs to be
804 * returned to libdiskmgt. These handles represent memory
805 * allocated by the the diskmgtd and must be returned in
806 * order for that memory to be released.
807 *
808 * The handles are cached for the duration of layout
809 * processing so that layout is guaranteed to have
810 * unique handles for all objects received from
811 * libdiskmgt.
812 *
813 * The caching is accomplished by adding the handle to
814 * a list of desc_free_t structs.
815 */
816 static int
add_descriptor_to_free(dm_descriptor_t desc)817 add_descriptor_to_free(
818 dm_descriptor_t desc)
819 {
820 desc_free_t *dfp = NULL;
821 dlist_t *item = NULL;
822
823 if (desc == (dm_descriptor_t)0) {
824 return (0);
825 }
826
827 if (is_virtual_slice(desc) == B_TRUE) {
828 /* don't return virtual slice descriptors to libdiskmgt */
829 return (0);
830 }
831
832 if ((dfp = calloc(1, sizeof (desc_free_t))) == NULL) {
833 return (ENOMEM);
834 }
835
836 dfp->desc = desc;
837 dfp->virtual = B_FALSE;
838
839 if ((item = dlist_new_item((void *)dfp)) == NULL) {
840 free(dfp);
841 return (ENOMEM);
842 }
843
844 _desc_to_free = dlist_append(item, _desc_to_free, AT_HEAD);
845
846 return (0);
847 }
848
849 /*
850 * FUNCTION: release_desc_to_free_cache()
851 *
852 * PURPOSE: Frees all entries in the desc_to_free cache.
853 *
854 * Iterates the _desc_to_free list and builds an
855 * array with all dm_descriptor_t handles that were
856 * obtained from libdiskmgt. Passing this array to
857 * dm_free_descriptors() is faster than calling
858 * dm_free_descriptor() to free individual handles.
859 */
860 void
release_desc_to_free_cache()861 release_desc_to_free_cache()
862 {
863 dlist_t *iter;
864 dm_descriptor_t *array;
865 int i = 0;
866
867 oprintf(OUTPUT_DEBUG,
868 gettext(" destroying desc_to_free cache (%d items)\n"),
869 dlist_length(_desc_to_free));
870
871 array = (dm_descriptor_t *)calloc(
872 dlist_length(_desc_to_free) + 1, sizeof (dm_descriptor_t));
873
874 if (array != NULL) {
875 for (iter = _desc_to_free; iter != NULL; iter = iter->next) {
876 desc_free_t *dfp = (desc_free_t *)iter->obj;
877 if (dfp->virtual == B_FALSE) {
878 array[i++] = dfp->desc;
879 }
880 }
881 array[i] = (dm_descriptor_t)0;
882 dm_free_descriptors(array);
883 }
884
885 /*
886 * If the calloc failed, the descriptors aren't explicitly freed,
887 * but the libdiskmgt daemon will eventually reclaim them after
888 * a period of inactivity.
889 */
890 dlist_free_items(_desc_to_free, free);
891
892 _desc_to_free = NULL;
893 }
894