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 */
53int dm_debug = 0;
54
55/* Lock protecting the cached data */
56static rwlock_t		cache_lock = DEFAULTRWLOCK;
57static disk_t		*disk_listp = NULL;
58static controller_t	*controller_listp = NULL;
59static bus_t		*bus_listp = NULL;
60static int		cache_loaded = 0;
61
62descriptor_t		*desc_listp = NULL;
63
64static void		clear_descriptors(void *gp);
65static void		clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp);
66static void		clr_path_disk_ptr(path_t *pp, disk_t *dp);
67static void		del_drive(disk_t *dp);
68static void		del_drive_by_name(char *name);
69static descriptor_t	*have_desc(int type, void *gp, char *name, char *mname);
70static int		initialize();
71static int		make_descriptors(int type);
72static int		match_disk(disk_t *oldp, disk_t *newp);
73static int		match_aliases(disk_t *d1p, disk_t *d2p);
74static int		match_alias(alias_t *ap, alias_t *listp);
75static descriptor_t	*new_descriptor(dm_desc_type_t type, void *op,
76			    char *name, char *mname);
77static void		rewalk_tree();
78static void		update_desc(descriptor_t *descp, disk_t *newdisksp,
79			    controller_t *newctrlp, bus_t *newbusp);
80static void		update_desc_busp(descriptor_t *descp, bus_t *busp);
81static void		update_desc_ctrlp(descriptor_t *descp,
82			    controller_t *newstrlp);
83static void		update_desc_diskp(descriptor_t *descp,
84			    disk_t *newdisksp);
85static 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
153void
154cache_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
187void
188cache_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
198void
199cache_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
217void
218cache_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
242void
243cache_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
254void
255cache_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
281void
282cache_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
300bus_t *
301cache_get_buslist()
302{
303	if (initialize() != 0) {
304		return (NULL);
305	}
306
307	return (bus_listp);
308}
309
310controller_t *
311cache_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 */
326descriptor_t *
327cache_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
347descriptor_t **
348cache_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
390disk_t *
391cache_get_disklist()
392{
393	if (initialize() != 0) {
394		return (NULL);
395	}
396
397	return (disk_listp);
398}
399
400int
401cache_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 */
420void
421cache_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
432void
433cache_rlock()
434{
435	(void) rw_rdlock(&cache_lock);
436}
437
438void
439cache_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 */
451void
452cache_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
475void
476cache_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 */
488static void
489clear_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 */
502static void
503clr_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 */
520static void
521clr_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
537static void
538del_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 */
585static void
586del_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
602static descriptor_t *
603have_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
635static int
636initialize()
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
675static int
676make_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
714static int
715match_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
731static int
732match_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
751static int
752match_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
773static descriptor_t *
774new_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
840static void
841rewalk_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 */
907static void
908update_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
937static void
938update_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
952static void
953update_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
968static void
969update_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
983static void
984update_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