1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-02 01:18:26 +03:00

A new cache.

This commit is contained in:
Alasdair Kergon 2002-11-18 13:53:58 +00:00
parent 34917a5373
commit 74b27447c1
4 changed files with 564 additions and 341 deletions

491
lib/cache/cache.c vendored Normal file
View File

@ -0,0 +1,491 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "lib.h"
#include "cache.h"
#include "hash.h"
#include "toolcontext.h"
#include "dev-cache.h"
#include "metadata.h"
static struct hash_table *_pvid_hash = NULL;
static struct hash_table *_vgid_hash = NULL;
static struct hash_table *_vgname_hash = NULL;
static struct list _vginfos;
int _has_scanned = 0;
int cache_init()
{
list_init(&_vginfos);
if (!(_vgname_hash = hash_create(128)))
return 0;
if (!(_vgid_hash = hash_create(128)))
return 0;
if (!(_pvid_hash = hash_create(128)))
return 0;
return 1;
}
struct cache_vginfo *vginfo_from_vgname(const char *vgname)
{
struct cache_vginfo *vginfo;
if (!_vgname_hash)
return NULL;
if (!(vginfo = hash_lookup(_vgname_hash, vgname)))
return NULL;
return vginfo;
}
struct format_type *fmt_from_vgname(const char *vgname)
{
struct cache_vginfo *vginfo;
if (!(vginfo = vginfo_from_vgname(vgname)))
return NULL;
return vginfo->fmt;
}
struct cache_vginfo *vginfo_from_vgid(const char *vgid)
{
struct cache_vginfo *vginfo;
if (!_vgid_hash || !vgid)
return NULL;
if (!(vginfo = hash_lookup_fixed(_vgid_hash, vgid, ID_LEN)))
return NULL;
return vginfo;
}
struct cache_info *info_from_pvid(const char *pvid)
{
struct cache_info *info;
if (!_pvid_hash || !pvid)
return NULL;
if (!(info = hash_lookup_fixed(_pvid_hash, pvid, ID_LEN)))
return NULL;
return info;
}
static void _rescan_entry(struct cache_info *info)
{
struct label *label;
if (info->status & CACHE_INVALID)
label_read(info->dev, &label);
}
static int _scan_invalid(struct cmd_context *cmd)
{
hash_iter(_pvid_hash, (iterate_fn) _rescan_entry);
return 1;
}
int cache_label_scan(struct cmd_context *cmd, int full_scan)
{
struct label *label;
struct dev_iter *iter;
struct device *dev;
struct list *fmth;
struct format_type *fmt;
static int _scanning_in_progress = 0;
int r = 0;
/* Avoid recursion when a PVID can't be found! */
if (_scanning_in_progress)
return 0;
_scanning_in_progress = 1;
if (!_vgname_hash && !cache_init()) {
log_error("Internal cache initialisation failed");
goto out;
}
if (_has_scanned && !full_scan) {
r = _scan_invalid(cmd);
goto out;
}
if (!(iter = dev_iter_create(cmd->filter))) {
log_error("dev_iter creation failed");
goto out;
}
while ((dev = dev_iter_get(iter)))
label_read(dev, &label);
dev_iter_destroy(iter);
_has_scanned = 1;
/* Perform any format-specific scanning e.g. text files */
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
if (fmt->ops->scan && !fmt->ops->scan(fmt))
goto out;
}
r = 1;
out:
_scanning_in_progress = 0;
return r;
}
struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan)
{
struct list *vgih, *vgnames;
struct str_list *sl;
cache_label_scan(cmd, full_scan);
if (!(vgnames = pool_alloc(cmd->mem, sizeof(struct list)))) {
log_error("vgnames list allocation failed");
return NULL;
}
list_init(vgnames);
list_iterate(vgih, &_vginfos) {
if (!(sl = pool_alloc(cmd->mem, sizeof(*sl)))) {
log_error("strlist allocation failed");
return NULL;
}
if (!(sl->str = pool_strdup(cmd->mem,
list_item(vgih,
struct cache_vginfo)->
vgname))) {
log_error("vgname allocation failed");
return NULL;
}
list_add(vgnames, &sl->list);
}
return vgnames;
}
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
{
struct label *label;
struct cache_info *info;
/* Already cached ? */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct cache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
cache_label_scan(cmd, 0);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct cache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
cache_label_scan(cmd, 1);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct cache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
return NULL;
}
void _drop_vginfo(struct cache_info *info)
{
if (!list_empty(&info->list)) {
list_del(&info->list);
list_init(&info->list);
}
if (info->vginfo && list_empty(&info->vginfo->infos)) {
hash_remove(_vgname_hash, info->vginfo->vgname);
if (info->vginfo->vgname)
dbg_free(info->vginfo->vgname);
if (*info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
list_del(&info->vginfo->list);
dbg_free(info->vginfo);
}
info->vginfo = NULL;
}
/* Unused
void cache_del(struct cache_info *info)
{
if (info->dev->pvid[0] && _pvid_hash)
hash_remove(_pvid_hash, info->dev->pvid);
_drop_vginfo(info);
info->label->labeller->ops->destroy_label(info->label->labeller,
info->label);
dbg_free(info);
return;
} */
static int _cache_update_pvid(struct cache_info *info, const char *pvid)
{
if (!strcmp(info->dev->pvid, pvid))
return 1;
if (*info->dev->pvid) {
hash_remove(_pvid_hash, info->dev->pvid);
}
strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
if (!hash_insert(_pvid_hash, pvid, info)) {
log_error("_cache_update: pvid insertion failed: %s", pvid);
return 0;
}
return 1;
}
static int _cache_update_vgid(struct cache_info *info, const char *vgid)
{
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
sizeof(info->vginfo->vgid)))
return 1;
if (info->vginfo && *info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
if (!vgid)
return 1;
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
if (!hash_insert(_vgid_hash, vgid, info->vginfo)) {
log_error("_cache_update: vgid hash insertion failed: %s",
vgid);
return 0;
}
return 1;
}
int cache_update_vgname(struct cache_info *info, const char *vgname)
{
struct cache_vginfo *vginfo;
/* If vgname is NULL and we don't already have a vgname,
* assume ORPHAN - we want every entry to have a vginfo
* attached for scanning reasons.
*/
if (!vgname && !info->vginfo)
vgname = ORPHAN;
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
return 1;
/* Remove existing vginfo entry */
_drop_vginfo(info);
/* Get existing vginfo or create new one */
if (!(vginfo = vginfo_from_vgname(vgname))) {
if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
log_error("cache_update_vgname: list alloc failed");
return 0;
}
memset(vginfo, 0, sizeof(*vginfo));
if (!(vginfo->vgname = dbg_strdup(vgname))) {
dbg_free(vginfo);
log_error("cache vgname alloc failed for %s", vgname);
return 0;
}
list_init(&vginfo->infos);
if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
log_error("cache_update: vg hash insertion failed: %s",
vginfo->vgname);
dbg_free(vginfo->vgname);
dbg_free(vginfo);
return 0;
}
/* Ensure orphans appear last on list_iterate */
if (!*vgname)
list_add(&_vginfos, &vginfo->list);
else
list_add_h(&_vginfos, &vginfo->list);
}
info->vginfo = vginfo;
list_add(&vginfo->infos, &info->list);
/* FIXME Check consistency of list! */
vginfo->fmt = info->fmt;
return 1;
}
int cache_update_vg(struct volume_group *vg)
{
struct list *pvh;
struct physical_volume *pv;
struct cache_info *info;
char pvid_s[ID_LEN + 1];
int vgid_updated = 0;
pvid_s[sizeof(pvid_s) - 1] = '\0';
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
/* FIXME Could pv->dev->pvid ever be different? */
if ((info = info_from_pvid(pvid_s))) {
cache_update_vgname(info, vg->name);
if (!vgid_updated) {
_cache_update_vgid(info, (char *) &vg->id);
vgid_updated = 1;
}
}
}
return 1;
}
struct cache_info *cache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid)
{
struct label *label;
struct cache_info *existing, *info;
char pvid_s[ID_LEN + 1];
if (!_vgname_hash && !cache_init()) {
log_error("Internal cache initialisation failed");
return NULL;
}
strncpy(pvid_s, pvid, sizeof(pvid_s));
pvid_s[sizeof(pvid_s) - 1] = '\0';
if (!(existing = info_from_pvid(pvid_s)) &&
!(existing = info_from_pvid(dev->pvid))) {
if (!(label = label_create(labeller))) {
stack;
return NULL;
}
if (!(info = dbg_malloc(sizeof(*info)))) {
log_error("cache_info allocation failed");
label_destroy(label);
return NULL;
}
memset(info, 0, sizeof(*info));
label->info = info;
info->label = label;
list_init(&info->list);
info->dev = dev;
} else {
info = existing;
/* Has labeller changed? */
if (info->label->labeller != labeller) {
label_destroy(info->label);
if (!(info->label = label_create(labeller))) {
/* FIXME leaves info without label! */
stack;
return NULL;
}
info->label->info = info;
}
label = info->label;
}
info->fmt = (struct format_type *) labeller->private;
info->status |= CACHE_INVALID;
if (!_cache_update_pvid(info, pvid_s)) {
if (!existing) {
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!cache_update_vgname(info, vgname)) {
if (!existing) {
hash_remove(_pvid_hash, pvid_s);
strcpy(info->dev->pvid, "");
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!_cache_update_vgid(info, vgid))
/* Non-critical */
stack;
return info;
}
static void _cache_destroy_entry(struct cache_info *info)
{
if (!list_empty(&info->list))
list_del(&info->list);
strcpy(info->dev->pvid, "");
label_destroy(info->label);
dbg_free(info);
}
static void _cache_destroy_vgnamelist(struct cache_vginfo *vginfo)
{
if (vginfo->vgname)
dbg_free(vginfo->vgname);
dbg_free(vginfo);
}
void cache_destroy()
{
_has_scanned = 0;
if (_vgid_hash) {
hash_destroy(_vgid_hash);
_vgid_hash = NULL;
}
if (_pvid_hash) {
hash_iter(_pvid_hash, (iterate_fn) _cache_destroy_entry);
hash_destroy(_pvid_hash);
_pvid_hash = NULL;
}
if (_vgname_hash) {
hash_iter(_vgname_hash, (iterate_fn) _cache_destroy_vgnamelist);
hash_destroy(_vgname_hash);
_vgname_hash = NULL;
}
list_init(&_vginfos);
}

73
lib/cache/cache.h vendored Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#ifndef _LVM_CACHE_H
#define _LVM_CACHE_H
#include "dev-cache.h"
#include "list.h"
#include "uuid.h"
#include "label.h"
#include "metadata.h"
#include <sys/types.h>
#define ORPHAN ""
#define CACHE_INVALID 0x00000001
/* LVM specific per-volume info */
/* Eventual replacement for struct physical_volume perhaps? */
struct cache_vginfo {
struct list list; /* Join these vginfos together */
struct list infos; /* List head for cache_infos */
char *vgname; /* "" == orphan */
char vgid[ID_LEN + 1];
struct format_type *fmt;
};
struct cache_info {
struct list list; /* Join VG members together */
struct list mdas; /* list head for metadata areas */
struct list das; /* list head for data areas */
struct cache_vginfo *vginfo; /* NULL == unknown */
struct label *label;
struct format_type *fmt;
struct device *dev;
uint64_t device_size; /* Bytes */
uint32_t status;
};
int cache_init();
void cache_destroy();
/* Set full_scan to 1 to reread every filtered device label */
int cache_label_scan(struct cmd_context *cmd, int full_scan);
/* Add/delete a device */
struct cache_info *cache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid);
void cache_del(struct cache_info *info);
/* Update things */
int cache_update_vgname(struct cache_info *info, const char *vgname);
int cache_update_vg(struct volume_group *vg);
/* Queries */
struct format_type *fmt_from_vgname(const char *vgname);
struct cache_vginfo *vginfo_from_vgname(const char *vgname);
struct cache_vginfo *vginfo_from_vgid(const char *vgid);
struct cache_info *info_from_pvid(const char *pvid);
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
/* Returns list of struct str_lists containing pool-allocated copy of vgnames */
/* Set full_scan to 1 to reread every filtered device label */
struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan);
#endif

View File

@ -1,295 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include <stdlib.h>
#include "vgcache.h"
#include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "uuid.h"
#include "toolcontext.h"
static struct hash_table *_vghash;
static struct hash_table *_vgidhash;
static struct hash_table *_pvhash;
const char *all_devices = "\0";
int vgcache_init()
{
if (!(_vghash = hash_create(128)))
return 0;
if (!(_vgidhash = 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;
if (!_vghash)
return NULL;
if (!vg_name)
vg_name = all_devices;
if (!(vgn = hash_lookup(_vghash, vg_name)))
return NULL;
return &vgn->pvdevs;
}
struct format_type *vgcache_find_format(const char *vg_name)
{
struct vgname_entry *vgn;
if (!_vghash)
return NULL;
if (!vg_name)
vg_name = all_devices;
if (!(vgn = hash_lookup(_vghash, vg_name)))
return NULL;
return vgn->fmt;
}
struct list *vgcache_find_by_vgid(const char *vgid)
{
struct vgname_entry *vgn;
char vgid_s[ID_LEN + 1];
if (!_vgidhash || !vgid)
return NULL;
memcpy(vgid_s, vgid, ID_LEN);
vgid_s[ID_LEN] = '\0';
if (!(vgn = hash_lookup(_vgidhash, vgid_s)))
return NULL;
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, const char *vgid, struct device *dev,
struct format_type *fmt)
{
const char *pv_name;
struct vgname_entry *vgn;
struct pvdev_list *pvdev;
struct list *pvdh, *pvdevs;
if (!(pvdevs = vgcache_find(vg_name))) {
if (!(vgn = dbg_malloc(sizeof(struct vgname_entry)))) {
log_error("struct vgname_entry allocation failed");
return 0;
}
memset(vgn, 0, sizeof(struct vgname_entry));
vgn->fmt = fmt;
pvdevs = &vgn->pvdevs;
list_init(pvdevs);
if (!(vgn->vgname = dbg_strdup(vg_name))) {
log_error("vgcache_add: strdup vg_name failed");
return 0;
}
if (!hash_insert(_vghash, vg_name, vgn)) {
log_error("vgcache_add: VG hash insertion failed");
return 0;
}
} else if (!(vgn = hash_lookup(_vghash, vg_name))) {
log_error("vgcache_add: VG name entry %s not found", vg_name);
return 0;
}
if (vgid && strncmp(vgid, vgn->vgid, ID_LEN)) {
hash_remove(_vgidhash, vgn->vgid);
memcpy(vgn->vgid, vgid, ID_LEN);
vgn->vgid[ID_LEN] = '\0';
if (!hash_insert(_vgidhash, vgn->vgid, vgn)) {
log_error("vgcache_add: vgid hash insertion " "failed");
return 0;
}
}
if (!dev)
return 1;
list_iterate(pvdh, pvdevs) {
pvdev = list_item(pvdh, struct pvdev_list);
if (dev == pvdev->dev)
return 1;
}
/* 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;
}
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, const char *vgid, struct device *dev,
struct format_type *fmt)
{
if (!_vghash && !vgcache_init())
return 0;
/* If orphan PV remove it */
if (dev && vg_name && !*vg_name)
vgcache_del_orphan(dev);
/* Add PV if vg_name supplied */
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, vgid, dev, fmt))
return 0;
/* Add to all_devices */
if (dev)
return vgcache_add_entry(all_devices, NULL, dev, fmt);
return 1;
}
void vgcache_destroy_entry(struct vgname_entry *vgn)
{
struct list *pvdh;
struct pvdev_list *pvdev;
if (vgn) {
pvdh = vgn->pvdevs.n;
while (pvdh != &vgn->pvdevs) {
pvdev = list_item(pvdh, struct pvdev_list);
pvdh = pvdh->n;
if (_pvhash)
hash_remove(_pvhash, dev_name(pvdev->dev));
dbg_free(pvdev);
}
dbg_free(vgn->vgname);
if (_vgidhash && vgn->vgid[0])
hash_remove(_vgidhash, vgn->vgid);
}
dbg_free(vgn);
}
void vgcache_del(const char *vg_name)
{
struct vgname_entry *vgn;
if (!_vghash)
return;
if (!vg_name)
vg_name = all_devices;
if (!(vgn = hash_lookup(_vghash, vg_name)))
return;
hash_remove(_vghash, vg_name);
if (vgn->vgid[0])
hash_remove(_vgidhash, vgn->vgid);
vgcache_destroy_entry(vgn);
}
void vgcache_del_by_vgid(const char *vgid)
{
struct vgname_entry *vgn;
char vgid_s[ID_LEN + 1];
if (!_vgidhash || !vgid)
return;
memcpy(vgid_s, vgid, ID_LEN);
vgid_s[ID_LEN] = '\0';
if (!(vgn = hash_lookup(_vghash, vgid_s)))
return;
hash_remove(_vgidhash, vgn->vgid);
if (vgn->vgname[0])
hash_remove(_vghash, vgn->vgname);
vgcache_destroy_entry(vgn);
}
void vgcache_destroy()
{
if (_vghash) {
hash_iter(_vghash, (iterate_fn) vgcache_destroy_entry);
hash_destroy(_vghash);
_vghash = NULL;
}
if (_vgidhash) {
hash_destroy(_vgidhash);
_vgidhash = NULL;
}
if (_pvhash) {
hash_destroy(_pvhash);
_pvhash = NULL;
}
}
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid)
{
struct vgname_entry *vgn;
char vgid_s[ID_LEN + 1];
if (!_vgidhash || !vgid)
return NULL;
memcpy(vgid_s, vgid->uuid, ID_LEN);
vgid_s[ID_LEN] = '\0';
if (!(vgn = hash_lookup(_vgidhash, vgid_s)))
return NULL;
return pool_strdup(cmd->mem, vgn->vgname);
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#ifndef _LVM_VGCACHE_H
#define _LVM_VGCACHE_H
#include <sys/types.h>
#include <asm/page.h>
#include "dev-cache.h"
#include "list.h"
#include "uuid.h"
#include "toolcontext.h"
struct vgname_entry {
struct list pvdevs;
char *vgname;
char vgid[ID_LEN + 1];
struct format_type *fmt;
};
struct pvdev_list {
struct list list;
struct device *dev;
};
int vgcache_init();
void vgcache_destroy();
/* Return list of PVs in named VG */
struct list *vgcache_find(const char *vg_name);
struct format_type *vgcache_find_format(const char *vg_name);
struct list *vgcache_find_by_vgid(const char *vgid);
/* FIXME Temporary function */
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid);
/* Add/delete a device */
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt);
void vgcache_del(const char *vg_name);
#endif