xref: /illumos-gate/usr/src/lib/libdiskmgt/common/cache.c (revision 9164a50bf932130cbb5097a16f6986873ce0e6e5)
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
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
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
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
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
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
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
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 *
304 cache_get_buslist()
305 {
306 	if (initialize() != 0) {
307 		return (NULL);
308 	}
309 
310 	return (bus_listp);
311 }
312 
313 controller_t *
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 *
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 **
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 *
394 cache_get_disklist()
395 {
396 	if (initialize() != 0) {
397 		return (NULL);
398 	}
399 
400 	return (disk_listp);
401 }
402 
403 int
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
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
436 cache_rlock()
437 {
438 	(void) rw_rdlock(&cache_lock);
439 }
440 
441 void
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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 *
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
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
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
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
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
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
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