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