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