1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright 2024 Sebastian Wiedenroth
28 */
29
30 #include <fcntl.h>
31 #include <libdevinfo.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <libintl.h>
36 #include <synch.h>
37 #include <sys/sunddi.h>
38 #include <sys/types.h>
39 #include <libgen.h>
40 #include <syslog.h>
41
42 #include "libdiskmgt.h"
43 #include "disks_private.h"
44 #include "partition.h"
45
46 #define ALIASES 0
47 #define DEVPATHS 1
48
49 /*
50 * Set DM_LIBDISKMGT_DEBUG in the environment. Two levels of debugging:
51 * 1 - errors, warnings and minimal tracing information
52 * 2 - verbose information
53 * All output prints on stderr.
54 */
55 int dm_debug = 0;
56
57 /* Lock protecting the cached data */
58 static rwlock_t cache_lock = DEFAULTRWLOCK;
59 static disk_t *disk_listp = NULL;
60 static controller_t *controller_listp = NULL;
61 static bus_t *bus_listp = NULL;
62 static int cache_loaded = 0;
63
64 descriptor_t *desc_listp = NULL;
65
66 static void clear_descriptors(void *gp);
67 static void clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp);
68 static void clr_path_disk_ptr(path_t *pp, disk_t *dp);
69 static void del_drive(disk_t *dp);
70 static void del_drive_by_name(char *name);
71 static descriptor_t *have_desc(int type, void *gp, char *name, char *mname);
72 static int initialize();
73 static int make_descriptors(int type);
74 static int match_disk(disk_t *oldp, disk_t *newp);
75 static int match_aliases(disk_t *d1p, disk_t *d2p);
76 static int match_alias(alias_t *ap, alias_t *listp);
77 static descriptor_t *new_descriptor(dm_desc_type_t type, void *op,
78 char *name, char *mname);
79 static void rewalk_tree();
80 static void update_desc(descriptor_t *descp, disk_t *newdisksp,
81 controller_t *newctrlp, bus_t *newbusp);
82 static void update_desc_busp(descriptor_t *descp, bus_t *busp);
83 static void update_desc_ctrlp(descriptor_t *descp,
84 controller_t *newstrlp);
85 static void update_desc_diskp(descriptor_t *descp,
86 disk_t *newdisksp);
87 static void update_desc_pathp(descriptor_t *descp,
88 controller_t *newctrlp);
89
90 /*
91 * We only cache some of the data that we can obtain. For much of the data
92 * (e.g. slices & disks getting repartitioned) there are no events which would
93 * enable us to cache. As more events are added we can cache more information.
94 *
95 * Currently we cache the information we get from the dev tree walk. This is
96 * basically the information about the drives, aliases, devpaths, controllers
97 * and paths. We do not cache any information related to media, partitions
98 * or slices.
99 *
100 * A fundamental part of the API design is that the application can hold on
101 * to a set of descriptors for an indeterminate amount of time. Even if the
102 * application does not hold descriptors there is a window of time between the
103 * call that gets the descriptor and the use of the descriptor to get more
104 * information. Because of this, the cache design must work even if the object
105 * that the descriptor refers to no longer exists.
106 *
107 * Given this requirement, the code implements a two level cache. The
108 * descriptors that the application gets are really pointers into the first
109 * level of the cache. This first level contains the actual descriptors.
110 * These descriptors in turn refer to the objects we build from the dev tree
111 * walk which represent the drives and controllers. This is the second level
112 * in the cache.
113 *
114 * When we update the second level of the cache (the drives and controllers)
115 * we go through the first level (the descriptors) and update the pointers
116 * in those descriptors to refer to the new objects in the second level. If
117 * the object that the descriptor referred to is no longer in existence, we
118 * just null out the pointer in the descriptor. In this way the code that
119 * uses the descriptors knows that the object referred to by the descriptor
120 * no longer exists.
121 *
122 * We keep a reference count in the descriptors. This is incremented when
123 * we hand out a pointer to the descriptor and decremented when the application
124 * frees the descriptor it has. When the reference count goes to 0 we garbage
125 * collect the descriptors. In this way we only have to update active
126 * descriptors when we refresh the cache after an event.
127 *
128 * An example of the flow when we create descriptors:
129 * dm_get_descriptors libdiskmgt.c
130 * drive_get_descriptors drive.c
131 * cache_get_descriptors cache.c
132 * make_descriptors cache.c
133 * drive_make_descriptors drive.c
134 * cache_load_desc cache.c
135 * {update refcnts on descriptors & return them}
136 *
137 * The idea behind cache_get_descriptors and cache_load_desc is that we
138 * seperate the act of making the descriptor within the cache (which requires
139 * us to call back out to one of the object functions - drive_make_descriptors)
140 * from the act of handing out the descriptor (which requires us to increment
141 * the refcnt). In this way we keep all of the refcnt handling centralized
142 * in one function instead of forcing each object to ensure it replicates
143 * the refcnt handling correctly.
144 *
145 * Descriptors use two different kinds of indrection to refer to their
146 * corresponding object. For objects we cache (controllers, paths & drives)
147 * the descriptor keeps a pointer to that object. For objects that we
148 * dynamically build, the descriptor uses a combination of a pointer to the
149 * base object (usually the drive) along with a name (e.g. the media name or
150 * the alias). For objects that are based on media (e.g. a slice) we actually
151 * have to maintain a pointer (to the disk) and two names (e.g. the slice name
152 * and the media name which is the secondary name).
153 */
154
155 void
cache_free_alias(alias_t * aliasp)156 cache_free_alias(alias_t *aliasp)
157 {
158 slice_t *dp;
159
160 free(aliasp->alias);
161 free(aliasp->kstat_name);
162 free(aliasp->wwn);
163
164 /* free devpaths */
165 dp = aliasp->devpaths;
166 while (dp != NULL) {
167 slice_t *nextp;
168
169 nextp = dp->next;
170 free(dp->devpath);
171 free(dp);
172 dp = nextp;
173 }
174
175 /* free orig_paths */
176 dp = aliasp->orig_paths;
177 while (dp != NULL) {
178 slice_t *nextp;
179
180 nextp = dp->next;
181 free(dp->devpath);
182 free(dp);
183 dp = nextp;
184 }
185
186 free(aliasp);
187 }
188
189 void
cache_free_bus(bus_t * bp)190 cache_free_bus(bus_t *bp)
191 {
192 free(bp->name);
193 free(bp->btype);
194 free(bp->kstat_name);
195 free(bp->pname);
196 free(bp->controllers);
197 free(bp);
198 }
199
200 void
cache_free_controller(controller_t * cp)201 cache_free_controller(controller_t *cp)
202 {
203 free(cp->name);
204 free(cp->kstat_name);
205 free(cp->disks);
206 if (cp->paths != NULL) {
207 int i;
208
209 for (i = 0; cp->paths[i]; i++) {
210 /* free the path since it can't exist w/o the ctrlr */
211 cache_free_path(cp->paths[i]);
212 }
213 free(cp->paths);
214 }
215
216 free(cp);
217 }
218
219 void
cache_free_descriptor(descriptor_t * desc)220 cache_free_descriptor(descriptor_t *desc)
221 {
222 if (!cache_is_valid_desc(desc)) {
223 return;
224 }
225
226 desc->refcnt--;
227
228 if (desc->refcnt <= 0) {
229 free(desc->name);
230 free(desc->secondary_name);
231 if (desc->prev == NULL) {
232 /* this is the first descriptor, update head ptr */
233 desc_listp = desc->next;
234 } else {
235 desc->prev->next = desc->next;
236 }
237 if (desc->next != NULL) {
238 desc->next->prev = desc->prev;
239 }
240 free(desc);
241 }
242 }
243
244 void
cache_free_descriptors(descriptor_t ** desc_list)245 cache_free_descriptors(descriptor_t **desc_list)
246 {
247 int i;
248
249 for (i = 0; desc_list[i]; i++) {
250 cache_free_descriptor(desc_list[i]);
251 }
252
253 free(desc_list);
254 }
255
256 void
cache_free_disk(disk_t * dp)257 cache_free_disk(disk_t *dp)
258 {
259 alias_t *ap;
260
261 free(dp->device_id);
262 if (dp->devid != NULL) {
263 devid_free(dp->devid);
264 }
265 free(dp->kernel_name);
266 free(dp->product_id);
267 free(dp->vendor_id);
268 free(dp->controllers);
269 free(dp->serial);
270 /* the path objects are freed when we free the controller */
271 free(dp->paths);
272 ap = dp->aliases;
273 while (ap != NULL) {
274 alias_t *nextp;
275
276 nextp = ap->next;
277 cache_free_alias(ap);
278 ap = nextp;
279 }
280
281 free(dp);
282 }
283
284 void
cache_free_path(path_t * pp)285 cache_free_path(path_t *pp)
286 {
287 free(pp->name);
288 free(pp->disks);
289 free(pp->states);
290
291 if (pp->wwns) {
292 int i;
293
294 for (i = 0; pp->wwns[i]; i++) {
295 free(pp->wwns[i]);
296 }
297 free(pp->wwns);
298 }
299
300 free(pp);
301 }
302
303 bus_t *
cache_get_buslist()304 cache_get_buslist()
305 {
306 if (initialize() != 0) {
307 return (NULL);
308 }
309
310 return (bus_listp);
311 }
312
313 controller_t *
cache_get_controllerlist()314 cache_get_controllerlist()
315 {
316 if (initialize() != 0) {
317 return (NULL);
318 }
319
320 return (controller_listp);
321 }
322
323 /*
324 * This routine will either get the existing descriptor from the descriptor
325 * cache or make make a new descriptor and put it in the descriptor cache and
326 * return a pointer to that descriptor. We increment the refcnt when we hand
327 * out the descriptor.
328 */
329 descriptor_t *
cache_get_desc(int type,void * gp,char * name,char * secondary_name,int * errp)330 cache_get_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
331 {
332 descriptor_t *dp;
333
334 *errp = 0;
335 if ((dp = have_desc(type, gp, name, secondary_name)) == NULL) {
336 /* make a new desc */
337 if ((dp = new_descriptor(type, gp, name, secondary_name))
338 == NULL) {
339 *errp = ENOMEM;
340 }
341 }
342
343 if (dp != NULL) {
344 dp->refcnt++;
345 }
346
347 return (dp);
348 }
349
350 descriptor_t **
cache_get_descriptors(int type,int * errp)351 cache_get_descriptors(int type, int *errp)
352 {
353 descriptor_t **descs;
354 descriptor_t *descp;
355 int cnt = 0;
356 int pos;
357
358 if ((*errp = make_descriptors(type)) != 0) {
359 return (NULL);
360 }
361
362 /* count the number of active descriptors in the descriptor cache */
363 descp = desc_listp;
364 while (descp != NULL) {
365 if (descp->type == type && descp->p.generic != NULL) {
366 cnt++;
367 }
368 descp = descp->next;
369 }
370
371 descs = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
372 if (descs == NULL) {
373 *errp = ENOMEM;
374 return (NULL);
375 }
376
377 pos = 0;
378 descp = desc_listp;
379 while (descp != NULL) {
380 if (descp->type == type && descp->p.generic != NULL) {
381 /* update refcnts before handing out the descriptors */
382 descp->refcnt++;
383 descs[pos++] = descp;
384 }
385 descp = descp->next;
386 }
387 descs[pos] = NULL;
388
389 *errp = 0;
390 return (descs);
391 }
392
393 disk_t *
cache_get_disklist()394 cache_get_disklist()
395 {
396 if (initialize() != 0) {
397 return (NULL);
398 }
399
400 return (disk_listp);
401 }
402
403 int
cache_is_valid_desc(descriptor_t * d)404 cache_is_valid_desc(descriptor_t *d)
405 {
406 descriptor_t *descp;
407
408 for (descp = desc_listp; descp != NULL; descp = descp->next) {
409 if (descp == d) {
410 return (1);
411 }
412 }
413
414 return (0);
415 }
416
417 /*
418 * This function is called by the *_make_descriptors function
419 * (e.g. drive_make_descriptors) within each of the objects. This function
420 * makes sure that the descriptor is built in the descriptor cache but
421 * it does not hand out the descriptors, so the refcnt is never incremented.
422 */
423 void
cache_load_desc(int type,void * gp,char * name,char * secondary_name,int * errp)424 cache_load_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
425 {
426 *errp = 0;
427 if (have_desc(type, gp, name, secondary_name) == NULL) {
428 /* make a new desc */
429 if (new_descriptor(type, gp, name, secondary_name) == NULL) {
430 *errp = ENOMEM;
431 }
432 }
433 }
434
435 void
cache_rlock()436 cache_rlock()
437 {
438 (void) rw_rdlock(&cache_lock);
439 }
440
441 void
cache_unlock()442 cache_unlock()
443 {
444 (void) rw_unlock(&cache_lock);
445 }
446
447 /*
448 * This function is called when we get a devtree event. Type is either add
449 * or delete of a drive.
450 *
451 * For delete, we need to clean up the 2nd level structures and clean up
452 * the pointers between the them. We also clear the descriptor ptr.
453 */
454 void
cache_update(dm_event_type_t ev_type,char * devname)455 cache_update(dm_event_type_t ev_type, char *devname)
456 {
457 char *orig_name;
458
459 cache_wlock();
460
461 /* update the cache */
462 switch (ev_type) {
463 case DM_EV_DISK_ADD:
464 rewalk_tree();
465 events_new_event(devname, DM_DRIVE, DM_EV_TADD);
466 break;
467 case DM_EV_DISK_DELETE:
468 orig_name = devname;
469 devname = basename(devname);
470 del_drive_by_name(devname);
471 events_new_event(orig_name, DM_DRIVE, DM_EV_TREMOVE);
472 break;
473 }
474
475 cache_unlock();
476 }
477
478 void
cache_wlock()479 cache_wlock()
480 {
481 (void) rw_wrlock(&cache_lock);
482 }
483
484 /*
485 * Clear any descriptors that point at the specified cached object.
486 * We must go through the whole list since there can be multiple descriptors
487 * referencing the same object (i.e. drive/media/slice descriptors all point
488 * to the same drive object). The list is usually small (0 size) so this
489 * is not a big deal.
490 */
491 static void
clear_descriptors(void * gp)492 clear_descriptors(void *gp)
493 {
494 descriptor_t *descp;
495
496 for (descp = desc_listp; descp != NULL; descp = descp->next) {
497 if (descp->p.generic == gp) {
498 /* clear descriptor */
499 descp->p.generic = NULL;
500 }
501 }
502 }
503
504 /* remove the ptr from the controller to the specified disk */
505 static void
clr_ctrl_disk_ptr(controller_t * cp,disk_t * dp)506 clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp)
507 {
508 int i;
509
510 for (i = 0; cp->disks[i]; i++) {
511 if (dp == cp->disks[i]) {
512 int j;
513
514 for (j = i; cp->disks[j]; j++) {
515 cp->disks[j] = cp->disks[j + 1];
516 }
517 return;
518 }
519 }
520 }
521
522 /* remove the ptr from the path to the specified disk */
523 static void
clr_path_disk_ptr(path_t * pp,disk_t * dp)524 clr_path_disk_ptr(path_t *pp, disk_t *dp)
525 {
526 int i;
527
528 for (i = 0; pp->disks[i]; i++) {
529 if (dp == pp->disks[i]) {
530 int j;
531
532 for (j = i; pp->disks[j]; j++) {
533 pp->disks[j] = pp->disks[j + 1];
534 }
535 return;
536 }
537 }
538 }
539
540 static void
del_drive(disk_t * dp)541 del_drive(disk_t *dp)
542 {
543 int i;
544 disk_t *listp;
545 disk_t *prev = NULL;
546
547 clear_descriptors(dp);
548
549 /* clear any ptrs from controllers to this drive */
550 if (dp->controllers != NULL) {
551 for (i = 0; dp->controllers[i]; i++) {
552 clr_ctrl_disk_ptr(dp->controllers[i], dp);
553 }
554 }
555
556 /* clear any ptrs from paths to this drive */
557 if (dp->paths != NULL) {
558 for (i = 0; dp->paths[i]; i++) {
559 clr_path_disk_ptr(dp->paths[i], dp);
560 }
561 }
562
563 /* clear drive from disk list */
564 for (listp = disk_listp; listp != NULL; listp = listp->next) {
565 if (dp == listp) {
566 if (prev == NULL) {
567 disk_listp = dp->next;
568 } else {
569 prev->next = dp->next;
570 }
571
572 break;
573 }
574
575 if (prev == NULL) {
576 prev = disk_listp;
577 } else {
578 prev = prev->next;
579 }
580 }
581
582 cache_free_disk(dp);
583 }
584
585 /*
586 * Delete cached drive info when we get a devtree drive delete event.
587 */
588 static void
del_drive_by_name(char * name)589 del_drive_by_name(char *name)
590 {
591 disk_t *listp;
592
593 for (listp = disk_listp; listp != NULL; listp = listp->next) {
594 alias_t *ap;
595
596 for (ap = listp->aliases; ap; ap = ap->next) {
597 if (libdiskmgt_str_eq(name, ap->alias)) {
598 del_drive(listp);
599 return;
600 }
601 }
602 }
603 }
604
605 static descriptor_t *
have_desc(int type,void * gp,char * name,char * secondary_name)606 have_desc(int type, void *gp, char *name, char *secondary_name)
607 {
608 descriptor_t *descp;
609
610 if (name != NULL && name[0] == 0) {
611 name = NULL;
612 }
613
614 if (secondary_name != NULL && secondary_name[0] == 0) {
615 secondary_name = NULL;
616 }
617
618 descp = desc_listp;
619 while (descp != NULL) {
620 if (descp->type == type && descp->p.generic == gp &&
621 libdiskmgt_str_eq(descp->name, name)) {
622 if (type == DM_SLICE || type == DM_PARTITION ||
623 type == DM_PATH) {
624 if (libdiskmgt_str_eq(descp->secondary_name,
625 secondary_name)) {
626 return (descp);
627 }
628 } else {
629 return (descp);
630 }
631 }
632 descp = descp->next;
633 }
634
635 return (NULL);
636 }
637
638 static int
initialize()639 initialize()
640 {
641 struct search_args args;
642
643 if (cache_loaded) {
644 return (0);
645 }
646
647 libdiskmgt_init_debug();
648
649 findevs(&args);
650
651 if (args.dev_walk_status != 0) {
652 return (args.dev_walk_status);
653 }
654
655 disk_listp = args.disk_listp;
656 controller_listp = args.controller_listp;
657 bus_listp = args.bus_listp;
658
659 cache_loaded = 1;
660
661 /*
662 * Only start the event thread if we are not doing an install
663 */
664 if (getenv("_LIBDISKMGT_INSTALL") == NULL) {
665 if (events_start_event_watcher() != 0) {
666 /*
667 * Log a message about the failure to start
668 * sysevents and continue on.
669 */
670 syslog(LOG_WARNING, dgettext(TEXT_DOMAIN,
671 "libdiskmgt: sysevent thread for cache "
672 "events failed to start\n"));
673 }
674 }
675 return (0);
676 }
677
678 static int
make_descriptors(int type)679 make_descriptors(int type)
680 {
681 int error;
682
683 if ((error = initialize()) != 0) {
684 return (error);
685 }
686
687 switch (type) {
688 case DM_DRIVE:
689 error = drive_make_descriptors();
690 break;
691 case DM_BUS:
692 error = bus_make_descriptors();
693 break;
694 case DM_CONTROLLER:
695 error = controller_make_descriptors();
696 break;
697 case DM_PATH:
698 error = path_make_descriptors();
699 break;
700 case DM_ALIAS:
701 error = alias_make_descriptors();
702 break;
703 case DM_MEDIA:
704 error = media_make_descriptors();
705 break;
706 case DM_PARTITION:
707 error = partition_make_descriptors();
708 break;
709 case DM_SLICE:
710 error = slice_make_descriptors();
711 break;
712 }
713
714 return (error);
715 }
716
717 static int
match_alias(alias_t * ap,alias_t * listp)718 match_alias(alias_t *ap, alias_t *listp)
719 {
720 if (ap->alias == NULL) {
721 return (0);
722 }
723
724 while (listp != NULL) {
725 if (libdiskmgt_str_eq(ap->alias, listp->alias)) {
726 return (1);
727 }
728 listp = listp->next;
729 }
730
731 return (0);
732 }
733
734 static int
match_aliases(disk_t * d1p,disk_t * d2p)735 match_aliases(disk_t *d1p, disk_t *d2p)
736 {
737 alias_t *ap;
738
739 if (d1p->aliases == NULL || d2p->aliases == NULL) {
740 return (0);
741 }
742
743 ap = d1p->aliases;
744 while (ap != NULL) {
745 if (match_alias(ap, d2p->aliases)) {
746 return (1);
747 }
748 ap = ap->next;
749 }
750
751 return (0);
752 }
753
754 static int
match_disk(disk_t * oldp,disk_t * newp)755 match_disk(disk_t *oldp, disk_t *newp)
756 {
757 if (oldp->devid != NULL) {
758 if (newp->devid != NULL &&
759 devid_compare(oldp->devid, newp->devid) == 0) {
760 return (1);
761 }
762
763 } else {
764 /* oldp device id is null */
765 if (newp->devid == NULL) {
766 /* both disks have no device id, check aliases */
767 if (match_aliases(oldp, newp)) {
768 return (1);
769 }
770 }
771 }
772
773 return (0);
774 }
775
776 static descriptor_t *
new_descriptor(dm_desc_type_t type,void * op,char * name,char * secondary_name)777 new_descriptor(dm_desc_type_t type, void *op, char *name, char *secondary_name)
778 {
779 descriptor_t *d;
780
781 if (name != NULL && name[0] == 0) {
782 name = NULL;
783 }
784
785 if (secondary_name != NULL && secondary_name[0] == 0) {
786 secondary_name = NULL;
787 }
788
789 d = (descriptor_t *)malloc(sizeof (descriptor_t));
790 if (d == NULL) {
791 return (NULL);
792 }
793 d->type = type;
794 switch (type) {
795 case DM_CONTROLLER:
796 d->p.controller = op;
797 break;
798 case DM_BUS:
799 d->p.bus = op;
800 break;
801 default:
802 d->p.disk = op;
803 break;
804 }
805 if (name != NULL) {
806 d->name = strdup(name);
807 if (d->name == NULL) {
808 free(d);
809 return (NULL);
810 }
811 } else {
812 d->name = NULL;
813 }
814
815 if (type == DM_SLICE || type == DM_PARTITION) {
816 if (secondary_name != NULL) {
817 d->secondary_name = strdup(secondary_name);
818 if (d->secondary_name == NULL) {
819 free(d->name);
820 free(d);
821 return (NULL);
822 }
823 } else {
824 d->secondary_name = NULL;
825 }
826 } else {
827 d->secondary_name = NULL;
828 }
829
830 d->refcnt = 0;
831
832 /* add this descriptor to the head of the list */
833 if (desc_listp != NULL) {
834 desc_listp->prev = d;
835 }
836 d->prev = NULL;
837 d->next = desc_listp;
838 desc_listp = d;
839
840 return (d);
841 }
842
843 static void
rewalk_tree()844 rewalk_tree()
845 {
846 struct search_args args;
847 disk_t *free_disklistp;
848 controller_t *free_controllerlistp;
849 bus_t *free_buslistp;
850
851 findevs(&args);
852
853 if (args.dev_walk_status == 0) {
854 descriptor_t *descp;
855
856 /* walk the existing descriptors and update the ptrs */
857 descp = desc_listp;
858 while (descp != NULL) {
859 update_desc(descp, args.disk_listp,
860 args.controller_listp, args.bus_listp);
861 descp = descp->next;
862 }
863
864 /* update the cached object ptrs */
865 free_disklistp = disk_listp;
866 free_controllerlistp = controller_listp;
867 free_buslistp = bus_listp;
868 disk_listp = args.disk_listp;
869 controller_listp = args.controller_listp;
870 bus_listp = args.bus_listp;
871
872 } else {
873 free_disklistp = args.disk_listp;
874 free_controllerlistp = args.controller_listp;
875 free_buslistp = args.bus_listp;
876 }
877
878 /*
879 * Free the memory from either the old cached objects or the failed
880 * update objects.
881 */
882 while (free_disklistp != NULL) {
883 disk_t *nextp;
884
885 nextp = free_disklistp->next;
886 cache_free_disk(free_disklistp);
887 free_disklistp = nextp;
888 }
889 while (free_controllerlistp != NULL) {
890 controller_t *nextp;
891
892 nextp = free_controllerlistp->next;
893 cache_free_controller(free_controllerlistp);
894 free_controllerlistp = nextp;
895 }
896 while (free_buslistp != NULL) {
897 bus_t *nextp;
898
899 nextp = free_buslistp->next;
900 cache_free_bus(free_buslistp);
901 free_buslistp = nextp;
902 }
903 }
904
905 /*
906 * Walk the new set of cached objects and update the descriptor ptr to point
907 * to the correct new object. If there is no object any more, set the desc
908 * ptr to null.
909 */
910 static void
update_desc(descriptor_t * descp,disk_t * newdisksp,controller_t * newctrlp,bus_t * newbusp)911 update_desc(descriptor_t *descp, disk_t *newdisksp, controller_t *newctrlp,
912 bus_t *newbusp)
913 {
914 /* if the descriptor is already dead, we're done */
915 if (descp->p.generic == NULL) {
916 return;
917 }
918
919 /*
920 * All descriptors use a disk ptr except for controller descriptors
921 * and path descriptors.
922 */
923
924 switch (descp->type) {
925 case DM_BUS:
926 update_desc_busp(descp, newbusp);
927 break;
928 case DM_CONTROLLER:
929 update_desc_ctrlp(descp, newctrlp);
930 break;
931 case DM_PATH:
932 update_desc_pathp(descp, newctrlp);
933 break;
934 default:
935 update_desc_diskp(descp, newdisksp);
936 break;
937 }
938 }
939
940 static void
update_desc_busp(descriptor_t * descp,bus_t * busp)941 update_desc_busp(descriptor_t *descp, bus_t *busp)
942 {
943 /* walk the new objects and find the correct bus */
944 for (; busp; busp = busp->next) {
945 if (libdiskmgt_str_eq(descp->p.bus->name, busp->name)) {
946 descp->p.bus = busp;
947 return;
948 }
949 }
950
951 /* we did not find the controller any more, clear the ptr in the desc */
952 descp->p.bus = NULL;
953 }
954
955 static void
update_desc_ctrlp(descriptor_t * descp,controller_t * newctrlp)956 update_desc_ctrlp(descriptor_t *descp, controller_t *newctrlp)
957 {
958 /* walk the new objects and find the correct controller */
959 for (; newctrlp; newctrlp = newctrlp->next) {
960 if (libdiskmgt_str_eq(descp->p.controller->name,
961 newctrlp->name)) {
962 descp->p.controller = newctrlp;
963 return;
964 }
965 }
966
967 /* we did not find the controller any more, clear the ptr in the desc */
968 descp->p.controller = NULL;
969 }
970
971 static void
update_desc_diskp(descriptor_t * descp,disk_t * newdisksp)972 update_desc_diskp(descriptor_t *descp, disk_t *newdisksp)
973 {
974 /* walk the new objects and find the correct disk */
975 for (; newdisksp; newdisksp = newdisksp->next) {
976 if (match_disk(descp->p.disk, newdisksp)) {
977 descp->p.disk = newdisksp;
978 return;
979 }
980 }
981
982 /* we did not find the disk any more, clear the ptr in the descriptor */
983 descp->p.disk = NULL;
984 }
985
986 static void
update_desc_pathp(descriptor_t * descp,controller_t * newctrlp)987 update_desc_pathp(descriptor_t *descp, controller_t *newctrlp)
988 {
989 /* walk the new objects and find the correct path */
990 for (; newctrlp; newctrlp = newctrlp->next) {
991 path_t **pp;
992
993 pp = newctrlp->paths;
994 if (pp != NULL) {
995 int i;
996
997 for (i = 0; pp[i]; i++) {
998 if (libdiskmgt_str_eq(descp->p.path->name,
999 pp[i]->name)) {
1000 descp->p.path = pp[i];
1001 return;
1002 }
1003 }
1004 }
1005 }
1006
1007 /* we did not find the path any more, clear the ptr in the desc */
1008 descp->p.path = NULL;
1009 }
1010