xref: /titanic_52/usr/src/lib/libdiskmgt/common/cache.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <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 	if ((status = events_start_event_watcher()) != 0) {
656 	    return (status);
657 	}
658 
659 	return (0);
660 }
661 
662 static int
663 make_descriptors(int type)
664 {
665 	int	error;
666 
667 	if ((error = initialize()) != 0) {
668 	    return (error);
669 	}
670 
671 	switch (type) {
672 	case DM_DRIVE:
673 	    error = drive_make_descriptors();
674 	    break;
675 	case DM_BUS:
676 	    error = bus_make_descriptors();
677 	    break;
678 	case DM_CONTROLLER:
679 	    error = controller_make_descriptors();
680 	    break;
681 	case DM_PATH:
682 	    error = path_make_descriptors();
683 	    break;
684 	case DM_ALIAS:
685 	    error = alias_make_descriptors();
686 	    break;
687 	case DM_MEDIA:
688 	    error = media_make_descriptors();
689 	    break;
690 	case DM_PARTITION:
691 	    error = partition_make_descriptors();
692 	    break;
693 	case DM_SLICE:
694 	    error = slice_make_descriptors();
695 	    break;
696 	}
697 
698 	return (error);
699 }
700 
701 static int
702 match_alias(alias_t *ap, alias_t *listp)
703 {
704 	if (ap->alias == NULL) {
705 	    return (0);
706 	}
707 
708 	while (listp != NULL) {
709 	    if (libdiskmgt_str_eq(ap->alias, listp->alias)) {
710 		return (1);
711 	    }
712 	    listp = listp->next;
713 	}
714 
715 	return (0);
716 }
717 
718 static int
719 match_aliases(disk_t *d1p, disk_t *d2p)
720 {
721 	alias_t *ap;
722 
723 	if (d1p->aliases == NULL || d2p->aliases == NULL) {
724 	    return (0);
725 	}
726 
727 	ap = d1p->aliases;
728 	while (ap != NULL) {
729 	    if (match_alias(ap, d2p->aliases)) {
730 		return (1);
731 	    }
732 	    ap = ap->next;
733 	}
734 
735 	return (0);
736 }
737 
738 static int
739 match_disk(disk_t *oldp, disk_t *newp)
740 {
741 	if (oldp->devid != NULL) {
742 	    if (newp->devid != NULL &&
743 		devid_compare(oldp->devid, newp->devid) == 0) {
744 		return (1);
745 	    }
746 
747 	} else {
748 	    /* oldp device id is null */
749 	    if (newp->devid == NULL) {
750 		/* both disks have no device id, check aliases */
751 		if (match_aliases(oldp, newp)) {
752 		    return (1);
753 		}
754 	    }
755 	}
756 
757 	return (0);
758 }
759 
760 static descriptor_t *
761 new_descriptor(dm_desc_type_t type, void *op, char *name, char *secondary_name)
762 {
763 	descriptor_t	*d;
764 
765 	if (name != NULL && name[0] == 0) {
766 	    name = NULL;
767 	}
768 
769 	if (secondary_name != NULL && secondary_name[0] == 0) {
770 	    secondary_name = NULL;
771 	}
772 
773 	d = (descriptor_t *)malloc(sizeof (descriptor_t));
774 	if (d == NULL) {
775 	    return (NULL);
776 	}
777 	d->type = type;
778 	switch (type) {
779 	case DM_CONTROLLER:
780 	    d->p.controller = op;
781 	    break;
782 	case DM_BUS:
783 	    d->p.bus = op;
784 	    break;
785 	default:
786 	    d->p.disk = op;
787 	    break;
788 	}
789 	if (name != NULL) {
790 	    d->name = strdup(name);
791 	    if (d->name == NULL) {
792 		free(d);
793 		return (NULL);
794 	    }
795 	} else {
796 	    d->name = NULL;
797 	}
798 
799 	if (type == DM_SLICE || type == DM_PARTITION) {
800 	    if (secondary_name != NULL) {
801 		d->secondary_name = strdup(secondary_name);
802 		if (d->secondary_name == NULL) {
803 		    free(d->name);
804 		    free(d);
805 		    return (NULL);
806 		}
807 	    } else {
808 		d->secondary_name = NULL;
809 	    }
810 	} else {
811 	    d->secondary_name = NULL;
812 	}
813 
814 	d->refcnt = 0;
815 
816 	/* add this descriptor to the head of the list */
817 	if (desc_listp != NULL) {
818 	    desc_listp->prev = d;
819 	}
820 	d->prev = NULL;
821 	d->next = desc_listp;
822 	desc_listp = d;
823 
824 	return (d);
825 }
826 
827 static void
828 rewalk_tree()
829 {
830 	struct search_args	args;
831 	disk_t			*free_disklistp;
832 	controller_t		*free_controllerlistp;
833 	bus_t			*free_buslistp;
834 
835 	findevs(&args);
836 
837 	if (args.dev_walk_status == 0) {
838 	    descriptor_t	*descp;
839 
840 	    /* walk the existing descriptors and update the ptrs */
841 	    descp = desc_listp;
842 	    while (descp != NULL) {
843 		update_desc(descp, args.disk_listp, args.controller_listp,
844 		    args.bus_listp);
845 		descp = descp->next;
846 	    }
847 
848 	    /* update the cached object ptrs */
849 	    free_disklistp = disk_listp;
850 	    free_controllerlistp = controller_listp;
851 	    free_buslistp = bus_listp;
852 	    disk_listp = args.disk_listp;
853 	    controller_listp = args.controller_listp;
854 	    bus_listp = args.bus_listp;
855 
856 	} else {
857 	    free_disklistp = args.disk_listp;
858 	    free_controllerlistp = args.controller_listp;
859 	    free_buslistp = args.bus_listp;
860 	}
861 
862 	/*
863 	 * Free the memory from either the old cached objects or the failed
864 	 * update objects.
865 	 */
866 	while (free_disklistp != NULL) {
867 	    disk_t *nextp;
868 
869 	    nextp = free_disklistp->next;
870 	    cache_free_disk(free_disklistp);
871 	    free_disklistp = nextp;
872 	}
873 	while (free_controllerlistp != NULL) {
874 	    controller_t *nextp;
875 
876 	    nextp = free_controllerlistp->next;
877 	    cache_free_controller(free_controllerlistp);
878 	    free_controllerlistp = nextp;
879 	}
880 	while (free_buslistp != NULL) {
881 	    bus_t *nextp;
882 
883 	    nextp = free_buslistp->next;
884 	    cache_free_bus(free_buslistp);
885 	    free_buslistp = nextp;
886 	}
887 }
888 
889 /*
890  * Walk the new set of cached objects and update the descriptor ptr to point
891  * to the correct new object.  If there is no object any more, set the desc
892  * ptr to null.
893  */
894 static void
895 update_desc(descriptor_t *descp, disk_t *newdisksp, controller_t *newctrlp,
896 	bus_t *newbusp)
897 {
898 	/* if the descriptor is already dead, we're done */
899 	if (descp->p.generic == NULL) {
900 	    return;
901 	}
902 
903 	/*
904 	 * All descriptors use a disk ptr except for controller descriptors
905 	 * and path descriptors.
906 	 */
907 
908 	switch (descp->type) {
909 	case DM_BUS:
910 	    update_desc_busp(descp, newbusp);
911 	    break;
912 	case DM_CONTROLLER:
913 	    update_desc_ctrlp(descp, newctrlp);
914 	    break;
915 	case DM_PATH:
916 	    update_desc_pathp(descp, newctrlp);
917 	    break;
918 	default:
919 	    update_desc_diskp(descp, newdisksp);
920 	    break;
921 	}
922 }
923 
924 static void
925 update_desc_busp(descriptor_t *descp, bus_t *busp)
926 {
927 	/* walk the new objects and find the correct bus */
928 	for (; busp; busp = busp->next) {
929 	    if (libdiskmgt_str_eq(descp->p.bus->name, busp->name)) {
930 		descp->p.bus = busp;
931 		return;
932 	    }
933 	}
934 
935 	/* we did not find the controller any more, clear the ptr in the desc */
936 	descp->p.bus = NULL;
937 }
938 
939 static void
940 update_desc_ctrlp(descriptor_t *descp, controller_t *newctrlp)
941 {
942 	/* walk the new objects and find the correct controller */
943 	for (; newctrlp; newctrlp = newctrlp->next) {
944 	    if (libdiskmgt_str_eq(descp->p.controller->name, newctrlp->name)) {
945 		descp->p.controller = newctrlp;
946 		return;
947 	    }
948 	}
949 
950 	/* we did not find the controller any more, clear the ptr in the desc */
951 	descp->p.controller = NULL;
952 }
953 
954 static void
955 update_desc_diskp(descriptor_t *descp, disk_t *newdisksp)
956 {
957 	/* walk the new objects and find the correct disk */
958 	for (; newdisksp; newdisksp = newdisksp->next) {
959 	    if (match_disk(descp->p.disk, newdisksp)) {
960 		descp->p.disk = newdisksp;
961 		return;
962 	    }
963 	}
964 
965 	/* we did not find the disk any more, clear the ptr in the descriptor */
966 	descp->p.disk = NULL;
967 }
968 
969 static void
970 update_desc_pathp(descriptor_t *descp, controller_t *newctrlp)
971 {
972 	/* walk the new objects and find the correct path */
973 	for (; newctrlp; newctrlp = newctrlp->next) {
974 	    path_t	**pp;
975 
976 	    pp = newctrlp->paths;
977 	    if (pp != NULL) {
978 		int i;
979 
980 		for (i = 0; pp[i]; i++) {
981 		    if (libdiskmgt_str_eq(descp->p.path->name, pp[i]->name)) {
982 			descp->p.path = pp[i];
983 			return;
984 		    }
985 		}
986 	    }
987 	}
988 
989 	/* we did not find the path any more, clear the ptr in the desc */
990 	descp->p.path = NULL;
991 }
992