summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdiskmgt/common/cache.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libdiskmgt/common/cache.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libdiskmgt/common/cache.c')
-rw-r--r--usr/src/lib/libdiskmgt/common/cache.c991
1 files changed, 991 insertions, 0 deletions
diff --git a/usr/src/lib/libdiskmgt/common/cache.c b/usr/src/lib/libdiskmgt/common/cache.c
new file mode 100644
index 0000000000..411d6c41b7
--- /dev/null
+++ b/usr/src/lib/libdiskmgt/common/cache.c
@@ -0,0 +1,991 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <fcntl.h>
+#include <libdevinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <synch.h>
+#include <sys/sunddi.h>
+#include <sys/types.h>
+#include <libgen.h>
+
+#include "libdiskmgt.h"
+#include "disks_private.h"
+#include "partition.h"
+
+#define ALIASES 0
+#define DEVPATHS 1
+
+/*
+ * Set DM_LIBDISKMGT_DEBUG in the environment. Two levels of debugging:
+ * 1 - errors, warnings and minimal tracing information
+ * 2 - verbose information
+ * All output prints on stderr.
+ */
+int dm_debug = 0;
+
+/* Lock protecting the cached data */
+static rwlock_t cache_lock = DEFAULTRWLOCK;
+static disk_t *disk_listp = NULL;
+static controller_t *controller_listp = NULL;
+static bus_t *bus_listp = NULL;
+static int cache_loaded = 0;
+
+descriptor_t *desc_listp = NULL;
+
+static void clear_descriptors(void *gp);
+static void clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp);
+static void clr_path_disk_ptr(path_t *pp, disk_t *dp);
+static void del_drive(disk_t *dp);
+static void del_drive_by_name(char *name);
+static descriptor_t *have_desc(int type, void *gp, char *name, char *mname);
+static int initialize();
+static int make_descriptors(int type);
+static int match_disk(disk_t *oldp, disk_t *newp);
+static int match_aliases(disk_t *d1p, disk_t *d2p);
+static int match_alias(alias_t *ap, alias_t *listp);
+static descriptor_t *new_descriptor(dm_desc_type_t type, void *op,
+ char *name, char *mname);
+static void rewalk_tree();
+static void update_desc(descriptor_t *descp, disk_t *newdisksp,
+ controller_t *newctrlp, bus_t *newbusp);
+static void update_desc_busp(descriptor_t *descp, bus_t *busp);
+static void update_desc_ctrlp(descriptor_t *descp,
+ controller_t *newstrlp);
+static void update_desc_diskp(descriptor_t *descp,
+ disk_t *newdisksp);
+static void update_desc_pathp(descriptor_t *descp,
+ controller_t *newctrlp);
+
+/*
+ * We only cache some of the data that we can obtain. For much of the data
+ * (e.g. slices & disks getting repartitioned) there are no events which would
+ * enable us to cache. As more events are added we can cache more information.
+ *
+ * Currently we cache the information we get from the dev tree walk. This is
+ * basically the information about the drives, aliases, devpaths, controllers
+ * and paths. We do not cache any information related to media, partitions
+ * or slices.
+ *
+ * A fundamental part of the API design is that the application can hold on
+ * to a set of descriptors for an indeterminate amount of time. Even if the
+ * application does not hold descriptors there is a window of time between the
+ * call that gets the descriptor and the use of the descriptor to get more
+ * information. Because of this, the cache design must work even if the object
+ * that the descriptor refers to no longer exists.
+ *
+ * Given this requirement, the code implements a two level cache. The
+ * descriptors that the application gets are really pointers into the first
+ * level of the cache. This first level contains the actual descriptors.
+ * These descriptors in turn refer to the objects we build from the dev tree
+ * walk which represent the drives and controllers. This is the second level
+ * in the cache.
+ *
+ * When we update the second level of the cache (the drives and controllers)
+ * we go through the first level (the descriptors) and update the pointers
+ * in those descriptors to refer to the new objects in the second level. If
+ * the object that the descriptor referred to is no longer in existence, we
+ * just null out the pointer in the descriptor. In this way the code that
+ * uses the descriptors knows that the object referred to by the descriptor
+ * no longer exists.
+ *
+ * We keep a reference count in the descriptors. This is incremented when
+ * we hand out a pointer to the descriptor and decremented when the application
+ * frees the descriptor it has. When the reference count goes to 0 we garbage
+ * collect the descriptors. In this way we only have to update active
+ * descriptors when we refresh the cache after an event.
+ *
+ * An example of the flow when we create descriptors:
+ * dm_get_descriptors libdiskmgt.c
+ * drive_get_descriptors drive.c
+ * cache_get_descriptors cache.c
+ * make_descriptors cache.c
+ * drive_make_descriptors drive.c
+ * cache_load_desc cache.c
+ * {update refcnts on descriptors & return them}
+ *
+ * The idea behind cache_get_descriptors and cache_load_desc is that we
+ * seperate the act of making the descriptor within the cache (which requires
+ * us to call back out to one of the object functions - drive_make_descriptors)
+ * from the act of handing out the descriptor (which requires us to increment
+ * the refcnt). In this way we keep all of the refcnt handling centralized
+ * in one function instead of forcing each object to ensure it replicates
+ * the refcnt handling correctly.
+ *
+ * Descriptors use two different kinds of indrection to refer to their
+ * corresponding object. For objects we cache (controllers, paths & drives)
+ * the descriptor keeps a pointer to that object. For objects that we
+ * dynamically build, the descriptor uses a combination of a pointer to the
+ * base object (usually the drive) along with a name (e.g. the media name or
+ * the alias). For objects that are based on media (e.g. a slice) we actually
+ * have to maintain a pointer (to the disk) and two names (e.g. the slice name
+ * and the media name which is the secondary name).
+ */
+
+void
+cache_free_alias(alias_t *aliasp)
+{
+ slice_t *dp;
+
+ free(aliasp->alias);
+ free(aliasp->kstat_name);
+ free(aliasp->wwn);
+
+ /* free devpaths */
+ dp = aliasp->devpaths;
+ while (dp != NULL) {
+ slice_t *nextp;
+
+ nextp = dp->next;
+ free(dp->devpath);
+ free(dp);
+ dp = nextp;
+ }
+
+ /* free orig_paths */
+ dp = aliasp->orig_paths;
+ while (dp != NULL) {
+ slice_t *nextp;
+
+ nextp = dp->next;
+ free(dp->devpath);
+ free(dp);
+ dp = nextp;
+ }
+
+ free(aliasp);
+}
+
+void
+cache_free_bus(bus_t *bp)
+{
+ free(bp->name);
+ free(bp->btype);
+ free(bp->kstat_name);
+ free(bp->pname);
+ free(bp->controllers);
+ free(bp);
+}
+
+void
+cache_free_controller(controller_t *cp)
+{
+ free(cp->name);
+ free(cp->kstat_name);
+ free(cp->disks);
+ if (cp->paths != NULL) {
+ int i;
+
+ for (i = 0; cp->paths[i]; i++) {
+ /* free the path since it can't exist w/o the controller */
+ cache_free_path(cp->paths[i]);
+ }
+ free(cp->paths);
+ }
+
+ free(cp);
+}
+
+void
+cache_free_descriptor(descriptor_t *desc)
+{
+ if (!cache_is_valid_desc(desc)) {
+ return;
+ }
+
+ desc->refcnt--;
+
+ if (desc->refcnt <= 0) {
+ free(desc->name);
+ free(desc->secondary_name);
+ if (desc->prev == NULL) {
+ /* this is the first descriptor, update head ptr */
+ desc_listp = desc->next;
+ } else {
+ desc->prev->next = desc->next;
+ }
+ if (desc->next != NULL) {
+ desc->next->prev = desc->prev;
+ }
+ free(desc);
+ }
+}
+
+void
+cache_free_descriptors(descriptor_t **desc_list)
+{
+ int i;
+
+ for (i = 0; desc_list[i]; i++) {
+ cache_free_descriptor(desc_list[i]);
+ }
+
+ free(desc_list);
+}
+
+void
+cache_free_disk(disk_t *dp)
+{
+ alias_t *ap;
+
+ free(dp->device_id);
+ if (dp->devid != NULL) {
+ devid_free(dp->devid);
+ }
+ free(dp->kernel_name);
+ free(dp->product_id);
+ free(dp->vendor_id);
+ free(dp->controllers);
+ /* the path objects are freed when we free the controller */
+ free(dp->paths);
+ ap = dp->aliases;
+ while (ap != NULL) {
+ alias_t *nextp;
+
+ nextp = ap->next;
+ cache_free_alias(ap);
+ ap = nextp;
+ }
+
+ free(dp);
+}
+
+void
+cache_free_path(path_t *pp)
+{
+ int i;
+
+ free(pp->name);
+ free(pp->disks);
+ free(pp->states);
+
+ for (i = 0; pp->wwns[i]; i++) {
+ free(pp->wwns[i]);
+ }
+ free(pp->wwns);
+
+ free(pp);
+}
+
+bus_t *
+cache_get_buslist()
+{
+ if (initialize() != 0) {
+ return (NULL);
+ }
+
+ return (bus_listp);
+}
+
+controller_t *
+cache_get_controllerlist()
+{
+ if (initialize() != 0) {
+ return (NULL);
+ }
+
+ return (controller_listp);
+}
+
+/*
+ * This routine will either get the existing descriptor from the descriptor
+ * cache or make make a new descriptor and put it in the descriptor cache and
+ * return a pointer to that descriptor. We increment the refcnt when we hand
+ * out the descriptor.
+ */
+descriptor_t *
+cache_get_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
+{
+ descriptor_t *dp;
+
+ *errp = 0;
+ if ((dp = have_desc(type, gp, name, secondary_name)) == NULL) {
+ /* make a new desc */
+ if ((dp = new_descriptor(type, gp, name, secondary_name)) == NULL) {
+ *errp = ENOMEM;
+ }
+ }
+
+ if (dp != NULL) {
+ dp->refcnt++;
+ }
+
+ return (dp);
+}
+
+descriptor_t **
+cache_get_descriptors(int type, int *errp)
+{
+ descriptor_t **descs;
+ descriptor_t *descp;
+ int cnt = 0;
+ int pos;
+
+ if ((*errp = make_descriptors(type)) != 0) {
+ return (NULL);
+ }
+
+ /* count the number of active descriptors in the descriptor cache */
+ descp = desc_listp;
+ while (descp != NULL) {
+ if (descp->type == type && descp->p.generic != NULL) {
+ cnt++;
+ }
+ descp = descp->next;
+ }
+
+ descs = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
+ if (descs == NULL) {
+ *errp = ENOMEM;
+ return (NULL);
+ }
+
+ pos = 0;
+ descp = desc_listp;
+ while (descp != NULL) {
+ if (descp->type == type && descp->p.generic != NULL) {
+ /* update refcnts before handing out the descriptors */
+ descp->refcnt++;
+ descs[pos++] = descp;
+ }
+ descp = descp->next;
+ }
+ descs[pos] = NULL;
+
+ *errp = 0;
+ return (descs);
+}
+
+disk_t *
+cache_get_disklist()
+{
+ if (initialize() != 0) {
+ return (NULL);
+ }
+
+ return (disk_listp);
+}
+
+int
+cache_is_valid_desc(descriptor_t *d)
+{
+ descriptor_t *descp;
+
+ for (descp = desc_listp; descp != NULL; descp = descp->next) {
+ if (descp == d) {
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * This function is called by the *_make_descriptors function
+ * (e.g. drive_make_descriptors) within each of the objects. This function
+ * makes sure that the descriptor is built in the descriptor cache but
+ * it does not hand out the descriptors, so the refcnt is never incremented.
+ */
+void
+cache_load_desc(int type, void *gp, char *name, char *secondary_name, int *errp)
+{
+ *errp = 0;
+ if (have_desc(type, gp, name, secondary_name) == NULL) {
+ /* make a new desc */
+ if (new_descriptor(type, gp, name, secondary_name) == NULL) {
+ *errp = ENOMEM;
+ }
+ }
+}
+
+void
+cache_rlock()
+{
+ (void) rw_rdlock(&cache_lock);
+}
+
+void
+cache_unlock()
+{
+ (void) rw_unlock(&cache_lock);
+}
+
+/*
+ * This function is called when we get a devtree event. Type is either add
+ * or delete of a drive.
+ *
+ * For delete, we need to clean up the 2nd level structures and clean up
+ * the pointers between the them. We also clear the descriptor ptr.
+ */
+void
+cache_update(dm_event_type_t ev_type, char *devname)
+{
+ char *orig_name;
+
+ cache_wlock();
+
+ /* update the cache */
+ switch (ev_type) {
+ case DM_EV_DISK_ADD:
+ rewalk_tree();
+ events_new_event(devname, DM_DRIVE, DM_EV_TADD);
+ break;
+ case DM_EV_DISK_DELETE:
+ orig_name = devname;
+ devname = basename(devname);
+ del_drive_by_name(devname);
+ events_new_event(orig_name, DM_DRIVE, DM_EV_TREMOVE);
+ break;
+ }
+
+ cache_unlock();
+}
+
+void
+cache_wlock()
+{
+ (void) rw_wrlock(&cache_lock);
+}
+
+/*
+ * Clear any descriptors that point at the specified cached object.
+ * We must go through the whole list since there can be multiple descriptors
+ * referencing the same object (i.e. drive/media/slice descriptors all point
+ * to the same drive object). The list is usually small (0 size) so this
+ * is not a big deal.
+ */
+static void
+clear_descriptors(void *gp)
+{
+ descriptor_t *descp;
+
+ for (descp = desc_listp; descp != NULL; descp = descp->next) {
+ if (descp->p.generic == gp) {
+ /* clear descriptor */
+ descp->p.generic = NULL;
+ }
+ }
+}
+
+/* remove the ptr from the controller to the specified disk */
+static void
+clr_ctrl_disk_ptr(controller_t *cp, disk_t *dp)
+{
+ int i;
+
+ for (i = 0; cp->disks[i]; i++) {
+ if (dp == cp->disks[i]) {
+ int j;
+
+ for (j = i; cp->disks[j]; j++) {
+ cp->disks[j] = cp->disks[j + 1];
+ }
+ return;
+ }
+ }
+}
+
+/* remove the ptr from the path to the specified disk */
+static void
+clr_path_disk_ptr(path_t *pp, disk_t *dp)
+{
+ int i;
+
+ for (i = 0; pp->disks[i]; i++) {
+ if (dp == pp->disks[i]) {
+ int j;
+
+ for (j = i; pp->disks[j]; j++) {
+ pp->disks[j] = pp->disks[j + 1];
+ }
+ return;
+ }
+ }
+}
+
+static void
+del_drive(disk_t *dp)
+{
+ int i;
+ disk_t *listp;
+ disk_t *prev = NULL;
+
+ clear_descriptors(dp);
+
+ /* clear any ptrs from controllers to this drive */
+ if (dp->controllers != NULL) {
+ for (i = 0; dp->controllers[i]; i++) {
+ clr_ctrl_disk_ptr(dp->controllers[i], dp);
+ }
+ }
+
+ /* clear any ptrs from paths to this drive */
+ if (dp->paths != NULL) {
+ for (i = 0; dp->paths[i]; i++) {
+ clr_path_disk_ptr(dp->paths[i], dp);
+ }
+ }
+
+ /* clear drive from disk list */
+ for (listp = disk_listp; listp != NULL; listp = listp->next) {
+ if (dp == listp) {
+ if (prev == NULL) {
+ disk_listp = dp->next;
+ } else {
+ prev->next = dp->next;
+ }
+
+ break;
+ }
+
+ if (prev == NULL) {
+ prev = disk_listp;
+ } else {
+ prev = prev->next;
+ }
+ }
+
+ cache_free_disk(dp);
+}
+
+/*
+ * Delete cached drive info when we get a devtree drive delete event.
+ */
+static void
+del_drive_by_name(char *name)
+{
+ disk_t *listp;
+
+ for (listp = disk_listp; listp != NULL; listp = listp->next) {
+ alias_t *ap;
+
+ for (ap = listp->aliases; ap; ap = ap->next) {
+ if (libdiskmgt_str_eq(name, ap->alias)) {
+ del_drive(listp);
+ return;
+ }
+ }
+ }
+}
+
+static descriptor_t *
+have_desc(int type, void *gp, char *name, char *secondary_name)
+{
+ descriptor_t *descp;
+
+ if (name != NULL && name[0] == 0) {
+ name = NULL;
+ }
+
+ if (secondary_name != NULL && secondary_name[0] == 0) {
+ secondary_name = NULL;
+ }
+
+ descp = desc_listp;
+ while (descp != NULL) {
+ if (descp->type == type && descp->p.generic == gp &&
+ libdiskmgt_str_eq(descp->name, name)) {
+ if (type == DM_SLICE || type == DM_PARTITION ||
+ type == DM_PATH) {
+ if (libdiskmgt_str_eq(descp->secondary_name,
+ secondary_name)) {
+ return (descp);
+ }
+ } else {
+ return (descp);
+ }
+ }
+ descp = descp->next;
+ }
+
+ return (NULL);
+}
+
+static int
+initialize()
+{
+ struct search_args args;
+ int status;
+
+ if (cache_loaded) {
+ return (0);
+ }
+
+ libdiskmgt_init_debug();
+
+ findevs(&args);
+
+ if (args.dev_walk_status != 0) {
+ return (args.dev_walk_status);
+ }
+
+ disk_listp = args.disk_listp;
+ controller_listp = args.controller_listp;
+ bus_listp = args.bus_listp;
+
+ cache_loaded = 1;
+
+ if ((status = events_start_event_watcher()) != 0) {
+ return (status);
+ }
+
+ return (0);
+}
+
+static int
+make_descriptors(int type)
+{
+ int error;
+
+ if ((error = initialize()) != 0) {
+ return (error);
+ }
+
+ switch (type) {
+ case DM_DRIVE:
+ error = drive_make_descriptors();
+ break;
+ case DM_BUS:
+ error = bus_make_descriptors();
+ break;
+ case DM_CONTROLLER:
+ error = controller_make_descriptors();
+ break;
+ case DM_PATH:
+ error = path_make_descriptors();
+ break;
+ case DM_ALIAS:
+ error = alias_make_descriptors();
+ break;
+ case DM_MEDIA:
+ error = media_make_descriptors();
+ break;
+ case DM_PARTITION:
+ error = partition_make_descriptors();
+ break;
+ case DM_SLICE:
+ error = slice_make_descriptors();
+ break;
+ }
+
+ return (error);
+}
+
+static int
+match_alias(alias_t *ap, alias_t *listp)
+{
+ if (ap->alias == NULL) {
+ return (0);
+ }
+
+ while (listp != NULL) {
+ if (libdiskmgt_str_eq(ap->alias, listp->alias)) {
+ return (1);
+ }
+ listp = listp->next;
+ }
+
+ return (0);
+}
+
+static int
+match_aliases(disk_t *d1p, disk_t *d2p)
+{
+ alias_t *ap;
+
+ if (d1p->aliases == NULL || d2p->aliases == NULL) {
+ return (0);
+ }
+
+ ap = d1p->aliases;
+ while (ap != NULL) {
+ if (match_alias(ap, d2p->aliases)) {
+ return (1);
+ }
+ ap = ap->next;
+ }
+
+ return (0);
+}
+
+static int
+match_disk(disk_t *oldp, disk_t *newp)
+{
+ if (oldp->devid != NULL) {
+ if (newp->devid != NULL &&
+ devid_compare(oldp->devid, newp->devid) == 0) {
+ return (1);
+ }
+
+ } else {
+ /* oldp device id is null */
+ if (newp->devid == NULL) {
+ /* both disks have no device id, check aliases */
+ if (match_aliases(oldp, newp)) {
+ return (1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+static descriptor_t *
+new_descriptor(dm_desc_type_t type, void *op, char *name, char *secondary_name)
+{
+ descriptor_t *d;
+
+ if (name != NULL && name[0] == 0) {
+ name = NULL;
+ }
+
+ if (secondary_name != NULL && secondary_name[0] == 0) {
+ secondary_name = NULL;
+ }
+
+ d = (descriptor_t *)malloc(sizeof (descriptor_t));
+ if (d == NULL) {
+ return (NULL);
+ }
+ d->type = type;
+ switch (type) {
+ case DM_CONTROLLER:
+ d->p.controller = op;
+ break;
+ case DM_BUS:
+ d->p.bus = op;
+ break;
+ default:
+ d->p.disk = op;
+ break;
+ }
+ if (name != NULL) {
+ d->name = strdup(name);
+ if (d->name == NULL) {
+ free(d);
+ return (NULL);
+ }
+ } else {
+ d->name = NULL;
+ }
+
+ if (type == DM_SLICE || type == DM_PARTITION) {
+ if (secondary_name != NULL) {
+ d->secondary_name = strdup(secondary_name);
+ if (d->secondary_name == NULL) {
+ free(d->name);
+ free(d);
+ return (NULL);
+ }
+ } else {
+ d->secondary_name = NULL;
+ }
+ } else {
+ d->secondary_name = NULL;
+ }
+
+ d->refcnt = 0;
+
+ /* add this descriptor to the head of the list */
+ if (desc_listp != NULL) {
+ desc_listp->prev = d;
+ }
+ d->prev = NULL;
+ d->next = desc_listp;
+ desc_listp = d;
+
+ return (d);
+}
+
+static void
+rewalk_tree()
+{
+ struct search_args args;
+ disk_t *free_disklistp;
+ controller_t *free_controllerlistp;
+ bus_t *free_buslistp;
+
+ findevs(&args);
+
+ if (args.dev_walk_status == 0) {
+ descriptor_t *descp;
+
+ /* walk the existing descriptors and update the ptrs */
+ descp = desc_listp;
+ while (descp != NULL) {
+ update_desc(descp, args.disk_listp, args.controller_listp,
+ args.bus_listp);
+ descp = descp->next;
+ }
+
+ /* update the cached object ptrs */
+ free_disklistp = disk_listp;
+ free_controllerlistp = controller_listp;
+ free_buslistp = bus_listp;
+ disk_listp = args.disk_listp;
+ controller_listp = args.controller_listp;
+ bus_listp = args.bus_listp;
+
+ } else {
+ free_disklistp = args.disk_listp;
+ free_controllerlistp = args.controller_listp;
+ free_buslistp = args.bus_listp;
+ }
+
+ /*
+ * Free the memory from either the old cached objects or the failed
+ * update objects.
+ */
+ while (free_disklistp != NULL) {
+ disk_t *nextp;
+
+ nextp = free_disklistp->next;
+ cache_free_disk(free_disklistp);
+ free_disklistp = nextp;
+ }
+ while (free_controllerlistp != NULL) {
+ controller_t *nextp;
+
+ nextp = free_controllerlistp->next;
+ cache_free_controller(free_controllerlistp);
+ free_controllerlistp = nextp;
+ }
+ while (free_buslistp != NULL) {
+ bus_t *nextp;
+
+ nextp = free_buslistp->next;
+ cache_free_bus(free_buslistp);
+ free_buslistp = nextp;
+ }
+}
+
+/*
+ * Walk the new set of cached objects and update the descriptor ptr to point
+ * to the correct new object. If there is no object any more, set the desc
+ * ptr to null.
+ */
+static void
+update_desc(descriptor_t *descp, disk_t *newdisksp, controller_t *newctrlp,
+ bus_t *newbusp)
+{
+ /* if the descriptor is already dead, we're done */
+ if (descp->p.generic == NULL) {
+ return;
+ }
+
+ /*
+ * All descriptors use a disk ptr except for controller descriptors
+ * and path descriptors.
+ */
+
+ switch (descp->type) {
+ case DM_BUS:
+ update_desc_busp(descp, newbusp);
+ break;
+ case DM_CONTROLLER:
+ update_desc_ctrlp(descp, newctrlp);
+ break;
+ case DM_PATH:
+ update_desc_pathp(descp, newctrlp);
+ break;
+ default:
+ update_desc_diskp(descp, newdisksp);
+ break;
+ }
+}
+
+static void
+update_desc_busp(descriptor_t *descp, bus_t *busp)
+{
+ /* walk the new objects and find the correct bus */
+ for (; busp; busp = busp->next) {
+ if (libdiskmgt_str_eq(descp->p.bus->name, busp->name)) {
+ descp->p.bus = busp;
+ return;
+ }
+ }
+
+ /* we did not find the controller any more, clear the ptr in the desc */
+ descp->p.bus = NULL;
+}
+
+static void
+update_desc_ctrlp(descriptor_t *descp, controller_t *newctrlp)
+{
+ /* walk the new objects and find the correct controller */
+ for (; newctrlp; newctrlp = newctrlp->next) {
+ if (libdiskmgt_str_eq(descp->p.controller->name, newctrlp->name)) {
+ descp->p.controller = newctrlp;
+ return;
+ }
+ }
+
+ /* we did not find the controller any more, clear the ptr in the desc */
+ descp->p.controller = NULL;
+}
+
+static void
+update_desc_diskp(descriptor_t *descp, disk_t *newdisksp)
+{
+ /* walk the new objects and find the correct disk */
+ for (; newdisksp; newdisksp = newdisksp->next) {
+ if (match_disk(descp->p.disk, newdisksp)) {
+ descp->p.disk = newdisksp;
+ return;
+ }
+ }
+
+ /* we did not find the disk any more, clear the ptr in the descriptor */
+ descp->p.disk = NULL;
+}
+
+static void
+update_desc_pathp(descriptor_t *descp, controller_t *newctrlp)
+{
+ /* walk the new objects and find the correct path */
+ for (; newctrlp; newctrlp = newctrlp->next) {
+ path_t **pp;
+
+ pp = newctrlp->paths;
+ if (pp != NULL) {
+ int i;
+
+ for (i = 0; pp[i]; i++) {
+ if (libdiskmgt_str_eq(descp->p.path->name, pp[i]->name)) {
+ descp->p.path = pp[i];
+ return;
+ }
+ }
+ }
+ }
+
+ /* we did not find the path any more, clear the ptr in the desc */
+ descp->p.path = NULL;
+}