Home | History | Annotate | Download | only in common
      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