1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Implement devices/global_filter.

The global filter is applied first, and is also applied in pvscan --cache (which
is called from udev rules to keep lvmetad updated). Cf. example.conf.
This commit is contained in:
Petr Rockai 2012-08-13 19:44:10 +02:00
parent ceb79c9a50
commit c7b17836ea
16 changed files with 279 additions and 112 deletions

View File

@ -41,6 +41,8 @@ typedef struct {
pthread_mutex_t vgid_to_metadata; pthread_mutex_t vgid_to_metadata;
pthread_mutex_t pvid_to_vgid; pthread_mutex_t pvid_to_vgid;
} lock; } lock;
char token[128];
pthread_mutex_t token_lock;
} lvmetad_state; } lvmetad_state;
static void lock_pvid_to_pvmeta(lvmetad_state *s) { static void lock_pvid_to_pvmeta(lvmetad_state *s) {
@ -58,6 +60,16 @@ static void lock_pvid_to_vgid(lvmetad_state *s) {
static void unlock_pvid_to_vgid(lvmetad_state *s) { static void unlock_pvid_to_vgid(lvmetad_state *s) {
pthread_mutex_unlock(&s->lock.pvid_to_vgid); } pthread_mutex_unlock(&s->lock.pvid_to_vgid); }
static response reply_fail(const char *reason)
{
return daemon_reply_simple("failed", "reason = %s", reason, NULL);
}
static response reply_unknown(const char *reason)
{
return daemon_reply_simple("unknown", "reason = %s", reason, NULL);
}
/* /*
* TODO: It may be beneficial to clean up the vg lock hash from time to time, * TODO: It may be beneficial to clean up the vg lock hash from time to time,
* since if we have many "rogue" requests for nonexistent things, we will keep * since if we have many "rogue" requests for nonexistent things, we will keep
@ -257,13 +269,13 @@ static response pv_lookup(lvmetad_state *s, request r)
struct dm_config_node *pv; struct dm_config_node *pv;
if (!pvid && !devt) if (!pvid && !devt)
return daemon_reply_simple("failed", "reason = %s", "need PVID or device", NULL); return reply_fail("need PVID or device");
if (!(res.cft = dm_config_create())) if (!(res.cft = dm_config_create()))
return daemon_reply_simple("failed", "reason = %s", "out of memory", NULL); return reply_fail("out of memory");
if (!(res.cft->root = make_text_node(res.cft, "response", "OK", NULL, NULL))) if (!(res.cft->root = make_text_node(res.cft, "response", "OK", NULL, NULL)))
return daemon_reply_simple("failed", "reason = %s", "out of memory", NULL); return reply_fail("out of memory");
lock_pvid_to_pvmeta(s); lock_pvid_to_pvmeta(s);
if (!pvid && devt) if (!pvid && devt)
@ -273,14 +285,14 @@ static response pv_lookup(lvmetad_state *s, request r)
WARN(s, "pv_lookup: could not find device %" PRIu64, devt); WARN(s, "pv_lookup: could not find device %" PRIu64, devt);
unlock_pvid_to_pvmeta(s); unlock_pvid_to_pvmeta(s);
dm_config_destroy(res.cft); dm_config_destroy(res.cft);
return daemon_reply_simple("unknown", "reason = %s", "device not found", NULL); return reply_unknown("device not found");
} }
pv = make_pv_node(s, pvid, res.cft, NULL, res.cft->root); pv = make_pv_node(s, pvid, res.cft, NULL, res.cft->root);
if (!pv) { if (!pv) {
unlock_pvid_to_pvmeta(s); unlock_pvid_to_pvmeta(s);
dm_config_destroy(res.cft); dm_config_destroy(res.cft);
return daemon_reply_simple("unknown", "reason = %s", "PV not found", NULL); return reply_unknown("PV not found");
} }
pv->key = "physical_volume"; pv->key = "physical_volume";
@ -381,12 +393,12 @@ static response vg_lookup(lvmetad_state *s, request r)
DEBUG(s, "vg_lookup: updated uuid = %s, name = %s", uuid, name); DEBUG(s, "vg_lookup: updated uuid = %s, name = %s", uuid, name);
if (!uuid) if (!uuid)
return daemon_reply_simple("unknown", "reason = %s", "VG not found", NULL); return reply_unknown("VG not found");
cft = lock_vg(s, uuid); cft = lock_vg(s, uuid);
if (!cft || !cft->root) { if (!cft || !cft->root) {
unlock_vg(s, uuid); unlock_vg(s, uuid);
return daemon_reply_simple("unknown", "reason = %s", "UUID not found", NULL); return reply_unknown("UUID not found");
} }
metadata = cft->root; metadata = cft->root;
@ -426,7 +438,7 @@ static response vg_lookup(lvmetad_state *s, request r)
return res; return res;
bad: bad:
unlock_vg(s, uuid); unlock_vg(s, uuid);
return daemon_reply_simple("failed", "reason = %s", "Out of memory", NULL); return reply_fail("out of memory");
} }
static int compare_value(struct dm_config_value *a, struct dm_config_value *b) static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
@ -694,7 +706,7 @@ static response pv_gone(lvmetad_state *s, request r)
pvid = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)); pvid = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
if (!pvid) { if (!pvid) {
unlock_pvid_to_pvmeta(s); unlock_pvid_to_pvmeta(s);
return daemon_reply_simple("unknown", "reason = %s", "device not in cache", NULL); return reply_unknown("device not in cache");
} }
DEBUG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device); DEBUG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
@ -709,7 +721,7 @@ static response pv_gone(lvmetad_state *s, request r)
dm_config_destroy(pvmeta); dm_config_destroy(pvmeta);
return daemon_reply_simple("OK", NULL); return daemon_reply_simple("OK", NULL);
} else } else
return daemon_reply_simple("unknown", "reason = %s", "PVID does not exist", NULL); return reply_unknown("PVID does not exist");
} }
static response pv_found(lvmetad_state *s, request r) static response pv_found(lvmetad_state *s, request r)
@ -726,12 +738,12 @@ static response pv_found(lvmetad_state *s, request r)
int complete = 0, orphan = 0; int complete = 0, orphan = 0;
if (!pvid) if (!pvid)
return daemon_reply_simple("failed", "reason = %s", "need PV UUID", NULL); return reply_fail("need PV UUID");
if (!pvmeta) if (!pvmeta)
return daemon_reply_simple("failed", "reason = %s", "need PV metadata", NULL); return reply_fail("need PV metadata");
if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device)) if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device))
return daemon_reply_simple("failed", "reason = %s", "need PV device number", NULL); return reply_fail("need PV device number");
DEBUG(s, "pv_found %s, vgid = %s, device = %" PRIu64, pvid, vgid, device); DEBUG(s, "pv_found %s, vgid = %s, device = %" PRIu64, pvid, vgid, device);
@ -745,14 +757,14 @@ static response pv_found(lvmetad_state *s, request r)
if (!(cft = dm_config_create()) || if (!(cft = dm_config_create()) ||
!(cft->root = dm_config_clone_node(cft, pvmeta, 0))) { !(cft->root = dm_config_clone_node(cft, pvmeta, 0))) {
unlock_pvid_to_pvmeta(s); unlock_pvid_to_pvmeta(s);
return daemon_reply_simple("failed", "reason = %s", "out of memory", NULL); return reply_fail("out of memory");
} }
pvid_dup = dm_config_find_str(cft->root, "pvmeta/id", NULL); pvid_dup = dm_config_find_str(cft->root, "pvmeta/id", NULL);
if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) || if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) ||
!dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) { !dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) {
unlock_pvid_to_pvmeta(s); unlock_pvid_to_pvmeta(s);
return daemon_reply_simple("failed", "reason = %s", "out of memory", NULL); return reply_fail("out of memory");
} }
if (pvmeta_old) if (pvmeta_old)
dm_config_destroy(pvmeta_old); dm_config_destroy(pvmeta_old);
@ -761,16 +773,15 @@ static response pv_found(lvmetad_state *s, request r)
if (metadata) { if (metadata) {
if (!vgid) if (!vgid)
return daemon_reply_simple("failed", "reason = %s", "need VG UUID", NULL); return reply_fail("need VG UUID");
DEBUG(s, "obtained vgid = %s, vgname = %s", vgid, vgname); DEBUG(s, "obtained vgid = %s, vgname = %s", vgid, vgname);
if (!vgname) if (!vgname)
return daemon_reply_simple("failed", "reason = %s", "need VG name", NULL); return reply_fail("need VG name");
if (daemon_request_int(r, "metadata/seqno", -1) < 0) if (daemon_request_int(r, "metadata/seqno", -1) < 0)
return daemon_reply_simple("failed", "reason = %s", "need VG seqno", NULL); return reply_fail("need VG seqno");
if (!update_metadata(s, vgname, vgid, metadata)) if (!update_metadata(s, vgname, vgid, metadata))
return daemon_reply_simple("failed", "reason = %s", return reply_fail("metadata update failed");
"metadata update failed", NULL);
} else { } else {
lock_pvid_to_vgid(s); lock_pvid_to_vgid(s);
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid); vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
@ -784,8 +795,7 @@ static response pv_found(lvmetad_state *s, request r)
orphan = 1; orphan = 1;
else { else {
unlock_vg(s, vgid); unlock_vg(s, vgid);
return daemon_reply_simple("failed", "reason = %s", return reply_fail("non-orphan VG without metadata encountered");
"non-orphan VG without metadata encountered", NULL);
} }
unlock_vg(s, vgid); unlock_vg(s, vgid);
} }
@ -804,17 +814,16 @@ static response vg_update(lvmetad_state *s, request r)
const char *vgname = daemon_request_str(r, "vgname", NULL); const char *vgname = daemon_request_str(r, "vgname", NULL);
if (metadata) { if (metadata) {
if (!vgid) if (!vgid)
return daemon_reply_simple("failed", "reason = %s", "need VG UUID", NULL); return reply_fail("need VG UUID");
if (!vgname) if (!vgname)
return daemon_reply_simple("failed", "reason = %s", "need VG name", NULL); return reply_fail("need VG name");
if (daemon_request_int(r, "metadata/seqno", -1) < 0) if (daemon_request_int(r, "metadata/seqno", -1) < 0)
return daemon_reply_simple("failed", "reason = %s", "need VG seqno", NULL); return reply_fail("need VG seqno");
/* TODO defer metadata update here; add a separate vg_commit /* TODO defer metadata update here; add a separate vg_commit
* call; if client does not commit, die */ * call; if client does not commit, die */
if (!update_metadata(s, vgname, vgid, metadata)) if (!update_metadata(s, vgname, vgid, metadata))
return daemon_reply_simple("failed", "reason = %s", return reply_fail("metadata update failed");
"metadata update failed", NULL);
} }
return daemon_reply_simple("OK", NULL); return daemon_reply_simple("OK", NULL);
} }
@ -824,7 +833,7 @@ static response vg_remove(lvmetad_state *s, request r)
const char *vgid = daemon_request_str(r, "uuid", NULL); const char *vgid = daemon_request_str(r, "uuid", NULL);
if (!vgid) if (!vgid)
return daemon_reply_simple("failed", "reason = %s", "need VG UUID", NULL); return reply_fail("need VG UUID");
DEBUG(s, "vg_remove: %s", vgid); DEBUG(s, "vg_remove: %s", vgid);
@ -839,6 +848,24 @@ static response handler(daemon_state s, client_handle h, request r)
{ {
lvmetad_state *state = s.private; lvmetad_state *state = s.private;
const char *rq = daemon_request_str(r, "request", "NONE"); const char *rq = daemon_request_str(r, "request", "NONE");
const char *token = daemon_request_str(r, "token", "NONE");
pthread_mutex_lock(&state->token_lock);
if (!strcmp(rq, "token_update")) {
strncpy(state->token, token, 128);
state->token[127] = 0;
pthread_mutex_unlock(&state->token_lock);
return daemon_reply_simple("OK", NULL);
}
if (strcmp(token, state->token)) {
pthread_mutex_unlock(&state->token_lock);
return daemon_reply_simple("token_mismatch",
"expected = %s", state->token,
"received = %s", token,
"reason = %s", "token mismatch", NULL);
}
pthread_mutex_unlock(&state->token_lock);
/* /*
* TODO Add a stats call, with transaction count/rate, time since last * TODO Add a stats call, with transaction count/rate, time since last
@ -869,7 +896,7 @@ static response handler(daemon_state s, client_handle h, request r)
if (!strcmp(rq, "vg_list")) if (!strcmp(rq, "vg_list"))
return vg_list(state, r); return vg_list(state, r);
return daemon_reply_simple("failed", "reason = %s", "no such request", NULL); return reply_fail("request not implemented");
} }
static int init(daemon_state *s) static int init(daemon_state *s)
@ -885,11 +912,13 @@ static int init(daemon_state *s)
ls->pvid_to_vgid = dm_hash_create(32); ls->pvid_to_vgid = dm_hash_create(32);
ls->vgname_to_vgid = dm_hash_create(32); ls->vgname_to_vgid = dm_hash_create(32);
ls->lock.vg = dm_hash_create(32); ls->lock.vg = dm_hash_create(32);
ls->token[0] = 0;
pthread_mutexattr_init(&rec); pthread_mutexattr_init(&rec);
pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&ls->lock.pvid_to_pvmeta, &rec); pthread_mutex_init(&ls->lock.pvid_to_pvmeta, &rec);
pthread_mutex_init(&ls->lock.vgid_to_metadata, &rec); pthread_mutex_init(&ls->lock.vgid_to_metadata, &rec);
pthread_mutex_init(&ls->lock.pvid_to_vgid, NULL); pthread_mutex_init(&ls->lock.pvid_to_vgid, NULL);
pthread_mutex_init(&ls->token_lock, NULL);
/* Set up stderr logging depending on the -d option. */ /* Set up stderr logging depending on the -d option. */
daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->debug_config, 1); daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->debug_config, 1);

View File

@ -79,6 +79,14 @@ devices {
# Use anchors if you want to be really specific # Use anchors if you want to be really specific
# filter = [ "a|^/dev/hda8$|", "r/.*/" ] # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
# Since "filter" is often overriden from command line, it is not suitable
# for system-wide device filtering (udev rules, lvmetad). To hide devices
# from LVM-specific udev processing and/or from lvmetad, you need to set
# global_filter. The syntax is the same as for normal "filter"
# above. Devices that fail the global_filter are not even opened by LVM.
# global_filter = []
# The results of the filtering are cached on disk to avoid # The results of the filtering are cached on disk to avoid
# rescanning dud devices (which can take a very long time). # rescanning dud devices (which can take a very long time).
# By default this cache is stored in the @DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@ directory # By default this cache is stored in the @DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@ directory

View File

@ -109,8 +109,6 @@ int lvmcache_init(void)
_vg_global_lock_held = 0; _vg_global_lock_held = 0;
} }
lvmetad_init();
return 1; return 1;
} }

167
lib/cache/lvmetad.c vendored
View File

@ -20,38 +20,120 @@
#include "lvmcache.h" #include "lvmcache.h"
#include "lvmetad-client.h" #include "lvmetad-client.h"
#include "format-text.h" // TODO for disk_locn, used as a DA representation #include "format-text.h" // TODO for disk_locn, used as a DA representation
#include "filter.h"
#include "assert.h"
#include "crc.h"
static int _using_lvmetad = 0;
static daemon_handle _lvmetad; static daemon_handle _lvmetad;
static const char *_lvmetad_token; static int _lvmetad_use = 0;
static int _lvmetad_connected = 0;
void lvmetad_init(void) static char *_lvmetad_token = NULL;
static const char *_lvmetad_socket = NULL;
static struct cmd_context *_lvmetad_cmd = NULL;
void lvmetad_disconnect(void)
{ {
const char *socket = getenv("LVM_LVMETAD_SOCKET"); daemon_close(_lvmetad);
if (_using_lvmetad) { /* configured by the toolcontext */ _lvmetad_connected = 0;
_lvmetad = lvmetad_open(socket ?: DEFAULT_RUN_DIR "/lvmetad.socket"); _lvmetad_cmd = NULL;
if (_lvmetad.socket_fd < 0 || _lvmetad.error) { }
void lvmetad_init(struct cmd_context *cmd)
{
if (_lvmetad_use && _lvmetad_socket && !_lvmetad_connected) {
assert(_lvmetad_socket);
_lvmetad = lvmetad_open(_lvmetad_socket);
if (_lvmetad.socket_fd >= 0 && !_lvmetad.error) {
_lvmetad_connected = 1;
_lvmetad_cmd = cmd;
} else
log_warn("WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning.", strerror(_lvmetad.error)); log_warn("WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning.", strerror(_lvmetad.error));
_using_lvmetad = 0;
}
} }
} }
int lvmetad_active(void)
{
return _lvmetad_use && _lvmetad_connected;
}
void lvmetad_set_active(int active)
{
_lvmetad_use = active;
}
void lvmetad_set_token(const struct dm_config_value *filter)
{
if (_lvmetad_token)
dm_free(_lvmetad_token);
int ft = 0;
while (filter && filter->type == DM_CFG_STRING) {
ft = calc_crc(ft, (const uint8_t *) filter->v.str, strlen(filter->v.str));
filter = filter->next;
}
if (!dm_asprintf(&_lvmetad_token, "filter:%u", ft))
log_warn("WARNING: Failed to set lvmetad token. Out of memory?");
}
void lvmetad_set_socket(const char *sock)
{
_lvmetad_socket = sock;
}
static daemon_reply _lvmetad_send(const char *id, ...);
static int _token_update()
{
daemon_reply repl = _lvmetad_send("token_update", NULL);
if (strcmp(daemon_reply_str(repl, "response", ""), "OK")) {
daemon_reply_destroy(repl);
return 0;
}
daemon_reply_destroy(repl);
return 1;
}
static daemon_reply _lvmetad_send(const char *id, ...) static daemon_reply _lvmetad_send(const char *id, ...)
{ {
va_list ap; va_list ap;
va_start(ap, id); daemon_reply repl, token_set;
daemon_reply repl; daemon_request req;
daemon_request req = daemon_request_make(id); int try = 0;
char *future_token;
// daemon_request_extend(req, "token", _lvmetad_token, NULL); retry:
req = daemon_request_make(id);
if (_lvmetad_token)
daemon_request_extend(req, "token = %s", _lvmetad_token, NULL);
va_start(ap, id);
daemon_request_extend_v(req, ap); daemon_request_extend_v(req, ap);
va_end(ap);
repl = daemon_send(_lvmetad, req); repl = daemon_send(_lvmetad, req);
daemon_request_destroy(req); daemon_request_destroy(req);
va_end(ap); if (!strcmp(daemon_reply_str(repl, "response", ""), "token_mismatch") && try < 2 && !test_mode()) {
future_token = _lvmetad_token;
_lvmetad_token = (char *) "update in progress";
if (!_token_update()) goto out;
if (pvscan_lvmetad_all_devs(_lvmetad_cmd, NULL)) {
_lvmetad_token = future_token;
if (!_token_update()) goto out;
}
_lvmetad_token = future_token;
++ try;
daemon_reply_destroy(repl);
goto retry;
}
out:
return repl; return repl;
} }
@ -203,7 +285,7 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
struct pv_list *pvl; struct pv_list *pvl;
struct lvmcache_info *info; struct lvmcache_info *info;
if (!_using_lvmetad) if (!lvmetad_active())
return NULL; return NULL;
if (vgid) { if (vgid) {
@ -317,7 +399,7 @@ int lvmetad_vg_update(struct volume_group *vg)
if (!vg) if (!vg)
return 0; return 0;
if (!_using_lvmetad || test_mode()) if (!lvmetad_active() || test_mode())
return 1; /* fake it */ return 1; /* fake it */
if (!(vgmeta = _export_vg_to_config_tree(vg))) if (!(vgmeta = _export_vg_to_config_tree(vg)))
@ -369,7 +451,7 @@ int lvmetad_vg_remove(struct volume_group *vg)
daemon_reply reply; daemon_reply reply;
int result; int result;
if (!_using_lvmetad || test_mode()) if (!lvmetad_active() || test_mode())
return 1; /* just fake it */ return 1; /* just fake it */
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
@ -390,7 +472,7 @@ int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found)
int result = 0; int result = 0;
struct dm_config_node *cn; struct dm_config_node *cn;
if (!_using_lvmetad) if (!lvmetad_active())
return_0; return_0;
if (!id_write_format(&pvid, uuid, sizeof(uuid))) if (!id_write_format(&pvid, uuid, sizeof(uuid)))
@ -423,7 +505,7 @@ int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *f
daemon_reply reply; daemon_reply reply;
struct dm_config_node *cn; struct dm_config_node *cn;
if (!_using_lvmetad) if (!lvmetad_active())
return_0; return_0;
reply = _lvmetad_send("pv_lookup", "device = %d", dev->dev, NULL); reply = _lvmetad_send("pv_lookup", "device = %d", dev->dev, NULL);
@ -450,7 +532,7 @@ int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
daemon_reply reply; daemon_reply reply;
struct dm_config_node *cn; struct dm_config_node *cn;
if (!_using_lvmetad) if (!lvmetad_active())
return 1; return 1;
reply = _lvmetad_send("pv_list", NULL); reply = _lvmetad_send("pv_list", NULL);
@ -476,7 +558,7 @@ int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
daemon_reply reply; daemon_reply reply;
struct dm_config_node *cn; struct dm_config_node *cn;
if (!_using_lvmetad) if (!lvmetad_active())
return 1; return 1;
reply = _lvmetad_send("vg_list", NULL); reply = _lvmetad_send("vg_list", NULL);
@ -576,7 +658,7 @@ int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_
const char *status; const char *status;
int result; int result;
if (!_using_lvmetad || test_mode()) if (!lvmetad_active() || test_mode())
return 1; return 1;
if (!id_write_format(&pvid, uuid, sizeof(uuid))) if (!id_write_format(&pvid, uuid, sizeof(uuid)))
@ -659,7 +741,7 @@ int lvmetad_pv_gone(dev_t device, const char *pv_name, activation_handler handle
int result; int result;
int found; int found;
if (!_using_lvmetad || test_mode()) if (!lvmetad_active() || test_mode())
return 1; return 1;
/* /*
@ -669,7 +751,7 @@ int lvmetad_pv_gone(dev_t device, const char *pv_name, activation_handler handle
* the whole stack from top to bottom (not yet upstream). * the whole stack from top to bottom (not yet upstream).
*/ */
reply = daemon_send_simple(_lvmetad, "pv_gone", "device = %d", device, NULL); reply = _lvmetad_send("pv_gone", "device = %d", device, NULL);
result = _lvmetad_handle_reply(reply, "drop PV", pv_name, &found); result = _lvmetad_handle_reply(reply, "drop PV", pv_name, &found);
/* We don't care whether or not the daemon had the PV cached. */ /* We don't care whether or not the daemon had the PV cached. */
@ -684,16 +766,6 @@ int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler)
return lvmetad_pv_gone(dev->dev, dev_name(dev), handler); return lvmetad_pv_gone(dev->dev, dev_name(dev), handler);
} }
int lvmetad_active(void)
{
return _using_lvmetad;
}
void lvmetad_set_active(int active)
{
_using_lvmetad = active;
}
/* /*
* The following code implements pvscan --cache. * The following code implements pvscan --cache.
*/ */
@ -771,3 +843,30 @@ bad:
"It is strongly recommended that you restart lvmetad immediately."); "It is strongly recommended that you restart lvmetad immediately.");
return 0; return 0;
} }
int pvscan_lvmetad_all_devs(struct cmd_context *cmd, activation_handler handler)
{
struct dev_iter *iter;
struct device *dev;
int r = 1;
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
log_error("dev_iter creation failed");
return 0;
}
while ((dev = dev_iter_get(iter))) {
if (!pvscan_lvmetad_single(cmd, dev, handler)) {
r = 0;
break;
}
if (sigint_caught())
break;
}
dev_iter_destroy(iter);
return r;
}

27
lib/cache/lvmetad.h vendored
View File

@ -30,19 +30,36 @@ typedef int (*activation_handler) (struct volume_group *vg, int partial,
* Initialise the communication with lvmetad. Normally called by * Initialise the communication with lvmetad. Normally called by
* lvmcache_init. Sets up a global handle for our process. * lvmcache_init. Sets up a global handle for our process.
*/ */
void lvmetad_init(void); void lvmetad_init(struct cmd_context *);
/* /*
* Override the use of lvmetad for retrieving scan results and metadata. * Override the use of lvmetad for retrieving scan results and metadata.
*/ */
void lvmetad_set_active(int); void lvmetad_set_active(int);
/*
* Configure the socket that lvmetad_init will use to connect to the daemon.
*/
void lvmetad_set_socket(const char *);
/* /*
* Check whether lvmetad is active (where active means both that it is running * Check whether lvmetad is active (where active means both that it is running
* and that we have a working connection with it). * and that we have a working connection with it).
*/ */
int lvmetad_active(void); int lvmetad_active(void);
/*
* Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish
* the connection (possibly at a different socket path).
*/
void lvmetad_disconnect(void);
/*
* Set the "lvmetad validity token" (currently only consists of the lvmetad
* filter. See lvm.conf.
*/
void lvmetad_set_token(const struct dm_config_value *filter);
/* /*
* Send a new version of VG metadata to lvmetad. This is normally called after * Send a new version of VG metadata to lvmetad. This is normally called after
* vg_write but before vg_commit. After vg_commit, lvmetad_vg_commit is called * vg_write but before vg_commit. After vg_commit, lvmetad_vg_commit is called
@ -111,11 +128,16 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
int pvscan_lvmetad_single(struct cmd_context *cmd, struct device *dev, int pvscan_lvmetad_single(struct cmd_context *cmd, struct device *dev,
activation_handler handler); activation_handler handler);
int pvscan_lvmetad_all_devs(struct cmd_context *cmd, activation_handler handler);
# else /* LVMETAD_SUPPORT */ # else /* LVMETAD_SUPPORT */
# define lvmetad_init() do { } while (0) # define lvmetad_init(cmd) do { } while (0)
# define lvmetad_disconnect() do { } while (0)
# define lvmetad_set_active(a) do { } while (0) # define lvmetad_set_active(a) do { } while (0)
# define lvmetad_set_socket(a) do { } while (0)
# define lvmetad_active() (0) # define lvmetad_active() (0)
# define lvmetad_set_token(a) do { } while (0)
# define lvmetad_vg_update(vg) (1) # define lvmetad_vg_update(vg) (1)
# define lvmetad_vg_remove(vg) (1) # define lvmetad_vg_remove(vg) (1)
# define lvmetad_pv_found(pvid, device, fmt, label_sector, vg, handler) (1) # define lvmetad_pv_found(pvid, device, fmt, label_sector, vg, handler) (1)
@ -127,6 +149,7 @@ int pvscan_lvmetad_single(struct cmd_context *cmd, struct device *dev,
# define lvmetad_vg_list_to_lvmcache(cmd) (1) # define lvmetad_vg_list_to_lvmcache(cmd) (1)
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL) # define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
# define pvscan_lvmetad_single(cmd, dev, handler) (0) # define pvscan_lvmetad_single(cmd, dev, handler) (0)
# define pvscan_lvmetad_all_devs(cmd, handler) (0)
# endif /* LVMETAD_SUPPORT */ # endif /* LVMETAD_SUPPORT */

View File

@ -399,7 +399,20 @@ static int _process_config(struct cmd_context *cmd)
(find_config_tree_int(cmd, "global/detect_internal_vg_cache_corruption", (find_config_tree_int(cmd, "global/detect_internal_vg_cache_corruption",
DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION)); DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION));
lvmetad_disconnect();
const char *lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
if (!lvmetad_socket)
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
/* TODO?
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
DEFAULT_RUN_DIR "/lvmetad.socket");
*/
lvmetad_set_socket(lvmetad_socket);
cn = find_config_tree_node(cmd, "devices/global_filter");
lvmetad_set_token(cn ? cn->v : NULL);
lvmetad_set_active(find_config_tree_int(cmd, "global/use_lvmetad", 0)); lvmetad_set_active(find_config_tree_int(cmd, "global/use_lvmetad", 0));
lvmetad_init(cmd);
return 1; return 1;
} }
@ -818,13 +831,14 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
{ {
static char cache_file[PATH_MAX]; static char cache_file[PATH_MAX];
const char *dev_cache = NULL, *cache_dir, *cache_file_prefix; const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
struct dev_filter *f3, *f4; struct dev_filter *f3 = NULL, *f4 = NULL, *toplevel_components[2] = { 0 };
struct stat st; struct stat st;
const struct dm_config_node *cn;
cmd->dump_filter = 0; cmd->dump_filter = 0;
if (!(f3 = _init_filter_components(cmd))) if (!(f3 = _init_filter_components(cmd)))
return_0; goto_bad;
init_ignore_suspended_devices(find_config_tree_int(cmd, init_ignore_suspended_devices(find_config_tree_int(cmd,
"devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES)); "devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
@ -843,8 +857,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
cache_dir ? : DEFAULT_CACHE_SUBDIR, cache_dir ? : DEFAULT_CACHE_SUBDIR,
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) { cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
log_error("Persistent cache filename too long."); log_error("Persistent cache filename too long.");
f3->destroy(f3); goto bad;
return 0;
} }
} else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) && } else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
(dm_snprintf(cache_file, sizeof(cache_file), (dm_snprintf(cache_file, sizeof(cache_file),
@ -852,8 +865,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
cmd->system_dir, DEFAULT_CACHE_SUBDIR, cmd->system_dir, DEFAULT_CACHE_SUBDIR,
DEFAULT_CACHE_FILE_PREFIX) < 0)) { DEFAULT_CACHE_FILE_PREFIX) < 0)) {
log_error("Persistent cache filename too long."); log_error("Persistent cache filename too long.");
f3->destroy(f3); goto bad;
return 0;
} }
if (!dev_cache) if (!dev_cache)
@ -883,9 +895,26 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
log_verbose("Failed to load existing device cache from %s", log_verbose("Failed to load existing device cache from %s",
dev_cache); dev_cache);
cmd->filter = f4; if (!(cn = find_config_tree_node(cmd, "devices/global_filter"))) {
cmd->filter = f4;
} else if (!(cmd->lvmetad_filter = regex_filter_create(cn->v)))
goto_bad;
else {
toplevel_components[0] = cmd->lvmetad_filter;
toplevel_components[1] = f4;
if (!(cmd->filter = composite_filter_create(2, toplevel_components)))
goto_bad;
}
return 1; return 1;
bad:
if (f3)
f3->destroy(f3);
if (f4)
f4->destroy(f4);
if (toplevel_components[0])
toplevel_components[0]->destroy(toplevel_components[0]);
return 0;
} }
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format) struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format)
@ -1495,6 +1524,8 @@ int refresh_filters(struct cmd_context *cmd)
cmd->filter = NULL; cmd->filter = NULL;
} }
cmd->lvmetad_filter = NULL;
if (!(r = _init_filters(cmd, 0))) if (!(r = _init_filters(cmd, 0)))
stack; stack;

View File

@ -91,6 +91,7 @@ struct cmd_context {
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */ unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
struct dev_filter *filter; struct dev_filter *filter;
struct dev_filter *lvmetad_filter;
int dump_filter; /* Dump filter when exiting? */ int dump_filter; /* Dump filter when exiting? */
struct dm_list config_files; struct dm_list config_files;

View File

@ -971,8 +971,8 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
if (dev_scan && !trust_cache()) { if (dev_scan && !trust_cache()) {
/* Flag gets reset between each command */ /* Flag gets reset between each command */
if (!full_scan_done() && f) if (!full_scan_done() && f && f->wipe)
persistent_filter_wipe(f); /* Calls _full_scan(1) */ f->wipe(f); /* Calls _full_scan(1) */
} else } else
_full_scan(0); _full_scan(0);

View File

@ -25,6 +25,7 @@
struct dev_filter { struct dev_filter {
int (*passes_filter) (struct dev_filter * f, struct device * dev); int (*passes_filter) (struct dev_filter * f, struct device * dev);
void (*destroy) (struct dev_filter * f); void (*destroy) (struct dev_filter * f);
void (*wipe) (struct dev_filter * f);
void *private; void *private;
unsigned use_count; unsigned use_count;
}; };

View File

@ -51,7 +51,7 @@ static int _init_hash(struct pfilter *pf)
return 1; return 1;
} }
int persistent_filter_wipe(struct dev_filter *f) static void _persistent_filter_wipe(struct dev_filter *f)
{ {
struct pfilter *pf = (struct pfilter *) f->private; struct pfilter *pf = (struct pfilter *) f->private;
@ -60,8 +60,6 @@ int persistent_filter_wipe(struct dev_filter *f)
/* Trigger complete device scan */ /* Trigger complete device scan */
dev_cache_scan(1); dev_cache_scan(1);
return 1;
} }
static int _read_array(struct pfilter *pf, struct dm_config_tree *cft, static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
@ -368,6 +366,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
f->destroy = _persistent_destroy; f->destroy = _persistent_destroy;
f->use_count = 0; f->use_count = 0;
f->private = pf; f->private = pf;
f->wipe = _persistent_filter_wipe;
return f; return f;

View File

@ -21,7 +21,6 @@
struct dev_filter *persistent_filter_create(struct dev_filter *f, struct dev_filter *persistent_filter_create(struct dev_filter *f,
const char *file); const char *file);
int persistent_filter_wipe(struct dev_filter *f);
int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out); int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out);
int persistent_filter_dump(struct dev_filter *f, int merge_existing); int persistent_filter_dump(struct dev_filter *f, int merge_existing);

View File

@ -221,8 +221,10 @@ static void chain_node(struct dm_config_node *cn,
if (parent && !parent->child) if (parent && !parent->child)
parent->child = cn; parent->child = cn;
if (pre_sib) if (pre_sib) {
cn->sib = pre_sib->sib;
pre_sib->sib = cn; pre_sib->sib = cn;
}
} }

View File

@ -527,5 +527,5 @@ target_at_least()
test -f DEVICES && devs=$(cat DEVICES) test -f DEVICES && devs=$(cat DEVICES)
unset LVM_VALGRIND #unset LVM_VALGRIND
"$@" "$@"

View File

@ -106,32 +106,6 @@ static int _auto_activation_handler(struct volume_group *vg, int partial,
return 1; return 1;
} }
static int _pvscan_lvmetad_all_devs(struct cmd_context *cmd, activation_handler handler)
{
struct dev_iter *iter;
struct device *dev;
int r = 1;
if (!(iter = dev_iter_create(cmd->filter, 1))) {
log_error("dev_iter creation failed");
return 0;
}
while ((dev = dev_iter_get(iter))) {
if (!pvscan_lvmetad_single(cmd, dev, handler)) {
r = 0;
break;
}
if (sigint_caught())
break;
}
dev_iter_destroy(iter);
return r;
}
static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv) static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
{ {
int ret = ECMD_PROCESSED; int ret = ECMD_PROCESSED;
@ -168,7 +142,7 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
/* Scan everything? */ /* Scan everything? */
if (!argc && !devno_args) { if (!argc && !devno_args) {
if (!_pvscan_lvmetad_all_devs(cmd, handler)) if (!pvscan_lvmetad_all_devs(cmd, handler))
ret = ECMD_FAILED; ret = ECMD_FAILED;
goto out; goto out;
} }
@ -283,7 +257,8 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED; return ECMD_FAILED;
} }
persistent_filter_wipe(cmd->filter); if (cmd->filter->wipe)
cmd->filter->wipe(cmd->filter);
lvmcache_destroy(cmd, 1); lvmcache_destroy(cmd, 1);
/* populate lvmcache */ /* populate lvmcache */

View File

@ -181,7 +181,8 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
vg_name_old, vg_name_new); vg_name_old, vg_name_new);
/* FIXME lvmcache corruption - vginfo duplicated instead of renamed */ /* FIXME lvmcache corruption - vginfo duplicated instead of renamed */
persistent_filter_wipe(cmd->filter); if (cmd->filter->wipe)
cmd->filter->wipe(cmd->filter);
lvmcache_destroy(cmd, 1); lvmcache_destroy(cmd, 1);
return 1; return 1;

View File

@ -50,7 +50,8 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED; return ECMD_FAILED;
} }
persistent_filter_wipe(cmd->filter); if (cmd->filter->wipe)
cmd->filter->wipe(cmd->filter);
lvmcache_destroy(cmd, 1); lvmcache_destroy(cmd, 1);
_lvmetad = lvmetad_active(); _lvmetad = lvmetad_active();