diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c index a6905ef2f..5f7a4b167 100644 --- a/lib/format1/disk-rep.c +++ b/lib/format1/disk-rep.c @@ -344,7 +344,7 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem, int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter, struct pool *mem, struct list *head) { - struct dev_iter *iter = dev_iter_create(filter); + struct dev_iter *iter; struct device *dev; struct disk_list *data = NULL; @@ -364,12 +364,16 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter, list_size(head) == data->vgd.pv_cur)) return 1; - /* Something changed. */ + /* Something changed. Remove the hints. */ list_init(head); - /* FIXME Do at a lower level? */ vgcache_del(vg_name); } + if (!(iter = dev_iter_create(filter))) { + log_error("read_pvs_in_vg: dev_iter_create failed"); + return 0; + } + /* Otherwise do a complete scan */ for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { if ((data = read_disk(dev, mem, vg_name))) { @@ -498,6 +502,7 @@ static int __write_all_pvd(struct disk_list *data) return 0; } + vgcache_add(data->pvd.vg_name, data->dev); /* * Stop here for orphan pv's. */ diff --git a/lib/vgcache/vgcache.c b/lib/vgcache/vgcache.c index 68e71e6f5..2ad924e3e 100644 --- a/lib/vgcache/vgcache.c +++ b/lib/vgcache/vgcache.c @@ -12,19 +12,22 @@ #include "log.h" static struct hash_table *_vghash; +static struct hash_table *_pvhash; -/* NULL is a special case that returns all devices */ -const char *null_const = "\0"; +const char *all_devices = "\0"; int vgcache_init() { - if (!(_vghash = hash_create(128))) { + if (!(_vghash = hash_create(128))) + return 0; + + if (!(_pvhash = hash_create(128))) return 0; - } return 1; } +/* A vg_name of NULL returns all_devices */ struct list *vgcache_find(const char *vg_name) { struct vgname_entry *vgn; @@ -33,7 +36,7 @@ struct list *vgcache_find(const char *vg_name) return NULL; if (!vg_name) - vg_name = null_const; + vg_name = all_devices; if (!(vgn = hash_lookup(_vghash, vg_name))) return NULL; @@ -41,9 +44,20 @@ struct list *vgcache_find(const char *vg_name) return &vgn->pvdevs; } +void vgcache_del_orphan(struct device *dev) +{ + struct pvdev_list *pvdev; + + if (_pvhash && ((pvdev = hash_lookup(_pvhash, dev_name(dev))))) { + list_del(&pvdev->list); + hash_remove(_pvhash, dev_name(pvdev->dev)); + dbg_free(pvdev); + } +} + int vgcache_add_entry(const char *vg_name, struct device *dev) { - + const char *pv_name; struct vgname_entry *vgn; struct pvdev_list *pvdev; struct list *pvdh, *pvdevs; @@ -63,7 +77,7 @@ int vgcache_add_entry(const char *vg_name, struct device *dev) } if (!hash_insert(_vghash, vg_name, vgn)) { - log_error("vgcache_add: hash insertion failed"); + log_error("vgcache_add: VG hash insertion failed"); return 0; } } @@ -74,7 +88,16 @@ int vgcache_add_entry(const char *vg_name, struct device *dev) return 1; } - if (!(pvdev = dbg_malloc(sizeof(struct pvdev_list)))) { + /* Remove PV from any existing VG unless an all_devices request */ + pvdev = NULL; + pv_name = dev_name(dev); + if (*vg_name && _pvhash && ((pvdev = hash_lookup(_pvhash, pv_name)))) { + list_del(&pvdev->list); + hash_remove(_pvhash, dev_name(pvdev->dev)); + } + + /* Allocate new pvdev_list if there isn't an existing one to reuse */ + if (!pvdev && !(pvdev = dbg_malloc(sizeof(struct pvdev_list)))) { log_error("struct pvdev_list allocation failed"); return 0; } @@ -82,18 +105,31 @@ int vgcache_add_entry(const char *vg_name, struct device *dev) pvdev->dev = dev; list_add(pvdevs, &pvdev->list); + if (*vg_name && _pvhash && !hash_insert(_pvhash, pv_name, pvdev)) { + log_error("vgcache_add: PV hash insertion for %s " + "failed", pv_name); + return 0; + } + return 1; } +/* vg_name of "\0" is an orphan PV; NULL means only add to all_devices */ int vgcache_add(const char *vg_name, struct device *dev) { if (!_vghash && !vgcache_init()) return 0; - if (vg_name && !vgcache_add_entry(vg_name, dev)) + /* If orphan PV remove it */ + if (vg_name && !*vg_name) + vgcache_del_orphan(dev); + + /* Add PV if vg_name supplied */ + if (vg_name && *vg_name && !vgcache_add_entry(vg_name, dev)) return 0; - return vgcache_add_entry(null_const, dev); + /* Always add to all_devices */ + return vgcache_add_entry(all_devices, dev); } void vgcache_destroy_entry(struct vgname_entry *vgn) @@ -121,7 +157,7 @@ void vgcache_del(const char *vg_name) return; if (!vg_name) - vg_name = null_const; + vg_name = all_devices; if (!(vgn = hash_lookup(_vghash, vg_name))) return; @@ -135,5 +171,11 @@ void vgcache_destroy() if (_vghash) { hash_iterate(_vghash, (iterate_fn)vgcache_destroy_entry); hash_destroy(_vghash); + _vghash = NULL; + } + + if (_pvhash) { + hash_destroy(_pvhash); + _pvhash = NULL; } }