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