]> sourceware.org Git - lvm2.git/blobdiff - lib/cache/lvmetad.c
Scan all devices for lvmetad if 'pvscan --cache' used without device list.
[lvm2.git] / lib / cache / lvmetad.c
index f82576513ede0bd51d11c0cc935dbc5503a82d17..47b71feed307179057835fc14973ff2f815eadeb 100644 (file)
@@ -1,3 +1,17 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
 #include "lib.h"
 #include "toolcontext.h"
 #include "metadata.h"
@@ -16,8 +30,8 @@ void lvmetad_init(void)
        const char *socket = getenv("LVM_LVMETAD_SOCKET");
        if (_using_lvmetad) { /* configured by the toolcontext */
                _lvmetad = lvmetad_open(socket ?: DEFAULT_RUN_DIR "/lvmetad.socket");
-               if (_lvmetad.socket_fd < 0) {
-                       log_warn("Failed to connect to lvmetad. Falling back to scanning.");
+               if (_lvmetad.socket_fd < 0 || _lvmetad.error) {
+                       log_warn("WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning.", strerror(_lvmetad.error));
                        _using_lvmetad = 0;
                }
        }
@@ -25,20 +39,41 @@ void lvmetad_init(void)
 
 /*
  * Helper; evaluate the reply from lvmetad, check for errors, print diagnostics
- * and return a summary success/failure exit code. Frees up the reply resources
- * as well.
+ * and return a summary success/failure exit code.
+ *
+ * If found is set, *found indicates whether or not device exists,
+ * and missing device is not treated as an error.
  */
-static int _lvmetad_handle_reply(daemon_reply reply, const char *action, const char *object) {
-       if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
-               log_error("Request to %s %s in lvmetad has failed. Reason: %s",
-                         action, object, reply.error ? strerror(reply.error) :
-                         daemon_reply_str(reply, "reason", "Unknown."));
-               daemon_reply_destroy(reply);
+static int _lvmetad_handle_reply(daemon_reply reply, const char *action, const char *object,
+                                int *found)
+{
+       if (reply.error) {
+               log_error("Request to %s %s%sin lvmetad gave response %s.",
+                         action, object, *object ? " " : "", strerror(reply.error));
                return 0;
        }
 
-       daemon_reply_destroy(reply);
-       return 1;
+       /* All OK? */
+       if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+               if (found)
+                       *found = 1;
+               return 1;
+       }
+
+       /* Unknown device permitted? */
+       if (found && !strcmp(daemon_reply_str(reply, "response", ""), "unknown")) {
+               log_very_verbose("Request to %s %s%sin lvmetad did not find object.",
+                                action, object, *object ? " " : "");
+               *found = 0;
+               return 1;
+       }
+
+       log_error("Request to %s %s%sin lvmetad gave response %s. Reason: %s",
+                 action, object, *object ? " " : "", 
+                 daemon_reply_str(reply, "response", "<missing>"),
+                 daemon_reply_str(reply, "reason", "<missing>"));
+
+       return 0;
 }
 
 static int _read_mda(struct lvmcache_info *info,
@@ -71,13 +106,13 @@ static struct lvmcache_info *_pv_populate_lvmcache(
                   *vgname = dm_config_find_str(cn->child, "vgname", NULL),
                   *fmt_name = dm_config_find_str(cn->child, "format", NULL);
        dev_t devt = dm_config_find_int(cn->child, "device", 0);
-       uint64_t devsize = dm_config_find_int(cn->child, "dev_size", 0),
-                label_sector = dm_config_find_int(cn->child, "label_sector", 0);
+       uint64_t devsize = dm_config_find_int64(cn->child, "dev_size", 0),
+                label_sector = dm_config_find_int64(cn->child, "label_sector", 0);
 
        struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL;
 
        if (!fmt) {
-               log_warn("No format for PV %s. It is probably missing.", pvid_txt);
+               log_error("PV %s not recognised. Is the device missing?", pvid_txt);
                return NULL;
        }
 
@@ -86,12 +121,12 @@ static struct lvmcache_info *_pv_populate_lvmcache(
                device = dev_cache_get_by_devt(fallback, cmd->filter);
 
        if (!device) {
-               log_warn("No device for PV %s.", pvid_txt);
+               log_error("No device found for PV %s.", pvid_txt);
                return NULL;
        }
 
        if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) {
-               log_warn("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
+               log_error("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
                return NULL;
        }
 
@@ -153,7 +188,8 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
                return NULL;
 
        if (vgid) {
-               id_write_format((const struct id*)vgid, uuid, 64);
+               if (!id_write_format((const struct id*)vgid, uuid, sizeof(uuid)))
+                       return_0;
                reply = daemon_send_simple(_lvmetad, "vg_lookup", "uuid = %s", uuid, NULL);
        } else {
                if (!vgname)
@@ -172,7 +208,7 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
                        log_error(INTERNAL_ERROR
                                  "We do not know the format (%s) reported by lvmetad.",
                                  fmt_name);
-                       return NULL;
+                       goto out;
                }
 
                fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
@@ -180,29 +216,33 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
                fic.context.vg_ref.vg_id = vgid;
 
                if (!(fid = fmt->ops->create_instance(fmt, &fic)))
-                       return_NULL;
+                       goto_out;
 
-               pvcn = dm_config_find_node(top, "metadata/physical_volumes")->child;
-               while (pvcn) {
-                       _pv_populate_lvmcache(cmd, pvcn, 0);
-                       pvcn = pvcn->sib;
-               }
+               if ((pvcn = dm_config_find_node(top, "metadata/physical_volumes")))
+                       for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
+                               _pv_populate_lvmcache(cmd, pvcn, 0);
 
                top->key = name;
-               vg = import_vg_from_config_tree(reply.cft, fid);
+               if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
+                       goto_out;
 
                dm_list_iterate_items(pvl, &vg->pvs) {
                        if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
                                pvl->pv->label_sector = lvmcache_get_label(info)->sector;
                                pvl->pv->dev = lvmcache_device(info);
-                               lvmcache_fid_add_mdas_pv(info, fid);
+                               if (!lvmcache_fid_add_mdas_pv(info, fid)) {
+                                       vg = NULL;
+                                       goto_out;       /* FIXME error path */
+                               }
                        } /* else probably missing */
                }
 
                lvmcache_update_vg(vg, 0);
        }
 
+out:
        daemon_reply_destroy(reply);
+
        return vg;
 }
 
@@ -245,15 +285,19 @@ int lvmetad_vg_update(struct volume_group *vg)
         * request.  */
        if (!export_vg_to_buffer(vg, &buf)) {
                log_error("Could not format VG metadata.");
-               return_0;
+               return 0;
        }
 
        reply = daemon_send_simple(_lvmetad, "vg_update", "vgname = %s", vg->name,
-                                            "metadata = %b", strchr(buf, '{'),
-                                  NULL);
+                                  "metadata = %b", strchr(buf, '{'), NULL);
+       dm_free(buf);
 
-       if (!_lvmetad_handle_reply(reply, "update VG", vg->name))
+       if (!_lvmetad_handle_reply(reply, "update VG", vg->name, NULL)) {
+               daemon_reply_destroy(reply);
                return 0;
+       }
+
+       daemon_reply_destroy(reply);
 
        n = (vg->fid && vg->fid->metadata_areas_index) ?
                dm_hash_get_first(vg->fid->metadata_areas_index) : NULL;
@@ -288,63 +332,83 @@ int lvmetad_vg_remove(struct volume_group *vg)
 {
        char uuid[64];
        daemon_reply reply;
+       int result;
 
        if (!_using_lvmetad)
                return 1; /* just fake it */
 
-       id_write_format(&vg->id, uuid, 64);
+       if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
+               return_0;
+
        reply = daemon_send_simple(_lvmetad, "vg_remove", "uuid = %s", uuid, NULL);
 
-       return _lvmetad_handle_reply(reply, "remove VG", vg->name);
+       result = _lvmetad_handle_reply(reply, "remove VG", vg->name, NULL);
+
+       daemon_reply_destroy(reply);
+
+       return result;
 }
 
-int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid)
+int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found)
 {
        char uuid[64];
        daemon_reply reply;
-       int result = 1;
+       int result = 0;
        struct dm_config_node *cn;
 
        if (!_using_lvmetad)
                return_0;
 
-       id_write_format(&pvid, uuid, 64);
+       if (!id_write_format(&pvid, uuid, sizeof(uuid)))
+               return_0;
 
        reply = daemon_send_simple(_lvmetad, "pv_lookup", "uuid = %s", uuid, NULL);
 
-       if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
-               _lvmetad_handle_reply(reply, "lookup PVs", "");
-               return_0;
-       }
+       if (!_lvmetad_handle_reply(reply, "lookup PV", "", found))
+               goto_out;
 
-       cn = dm_config_find_node(reply.cft->root, "physical_volume");
-       if (!_pv_populate_lvmcache(cmd, cn, 0))
-               result = 0;
+       if (found && !*found)
+               goto out_success;
+
+       if (!(cn = dm_config_find_node(reply.cft->root, "physical_volume")))
+               goto_out;
+        else if (!_pv_populate_lvmcache(cmd, cn, 0))
+               goto_out;
+
+out_success:
+       result = 1;
 
+out:
        daemon_reply_destroy(reply);
+
        return result;
 }
 
-int lvmetad_pv_lookup_by_devt(struct cmd_context *cmd, dev_t device)
+int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found)
 {
-       int result = 1;
+       int result = 0;
        daemon_reply reply;
        struct dm_config_node *cn;
 
        if (!_using_lvmetad)
                return_0;
 
-       reply = daemon_send_simple(_lvmetad, "pv_lookup", "device = %d", device, NULL);
+       reply = daemon_send_simple(_lvmetad, "pv_lookup", "device = %d", dev->dev, NULL);
 
-       if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
-               _lvmetad_handle_reply(reply, "lookup PVs", "");
-               return_0;
-       }
+       if (!_lvmetad_handle_reply(reply, "lookup PV", dev_name(dev), found))
+               goto_out;
+
+       if (found && !*found)
+               goto out_success;
 
        cn = dm_config_find_node(reply.cft->root, "physical_volume");
-       if (!_pv_populate_lvmcache(cmd, cn, device))
-               result = 0;
+       if (!cn || !_pv_populate_lvmcache(cmd, cn, dev->dev))
+               goto_out;
+
+out_success:
+       result = 1;
 
+out:
        daemon_reply_destroy(reply);
        return result;
 }
@@ -355,22 +419,21 @@ int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
        struct dm_config_node *cn;
 
        if (!_using_lvmetad)
-               return_0;
+               return 1;
 
        reply = daemon_send_simple(_lvmetad, "pv_list", NULL);
 
-       if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
-               _lvmetad_handle_reply(reply, "list PVs", "");
+       if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) {
+               daemon_reply_destroy(reply);
                return_0;
        }
 
-       cn = dm_config_find_node(reply.cft->root, "physical_volumes")->child;
-       while (cn) {
-               _pv_populate_lvmcache(cmd, cn, 0);
-               cn = cn->sib;
-       }
+       if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes")))
+               for (cn = cn->child; cn; cn = cn->sib)
+                       _pv_populate_lvmcache(cmd, cn, 0);
 
        daemon_reply_destroy(reply);
+
        return 1;
 }
 
@@ -383,24 +446,27 @@ int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
        struct dm_config_node *cn;
 
        if (!_using_lvmetad)
-               return_0;
+               return 1;
 
        reply = daemon_send_simple(_lvmetad, "vg_list", NULL);
-       if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
-               _lvmetad_handle_reply(reply, "list VGs", "");
+
+       if (!_lvmetad_handle_reply(reply, "list VGs", "", NULL)) {
+               daemon_reply_destroy(reply);
                return_0;
        }
 
-       cn = dm_config_find_node(reply.cft->root, "volume_groups")->child;
-       while (cn) {
-               vgid_txt = cn->key;
-               id_read_format(&vgid, vgid_txt);
-               cn = cn->sib;
+       if ((cn = dm_config_find_node(reply.cft->root, "volume_groups")))
+               for (cn = cn->child; cn; cn = cn->sib) {
+                       vgid_txt = cn->key;
+                       if (!id_read_format(&vgid, vgid_txt)) {
+                               stack;
+                               continue;
+                       }
 
-               /* the call to lvmetad_vg_lookup will poke the VG into lvmcache */
-               tmp = lvmetad_vg_lookup(cmd, NULL, (const char*)&vgid);
-               release_vg(tmp);
-       }
+                       /* the call to lvmetad_vg_lookup will poke the VG into lvmcache */
+                       tmp = lvmetad_vg_lookup(cmd, NULL, (const char*)&vgid);
+                       release_vg(tmp);
+               }
 
        daemon_reply_destroy(reply);
        return 1;
@@ -477,11 +543,13 @@ int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_
        const char *mdas = NULL;
        char *pvmeta;
        char *buf = NULL;
+       int result;
 
        if (!_using_lvmetad)
                return 1;
 
-       id_write_format(&pvid, uuid, 64);
+       if (!id_write_format(&pvid, uuid, sizeof(uuid)))
+                return_0;
 
        /* FIXME A more direct route would be much preferable. */
        if ((info = lvmcache_info_from_pvid((const char *)&pvid, 0)))
@@ -496,8 +564,12 @@ int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_
                         "  %s"
                         "}", device->dev,
                         info ? lvmcache_device_size(info) : 0,
-                        fmt->name, label_sector, uuid, mdas ?: ""))
+                        fmt->name, label_sector, uuid, mdas ?: "")) {
+               dm_free((char *)mdas);
                return_0;
+       }
+
+       dm_free((char *)mdas);
 
        if (vg) {
                /*
@@ -508,7 +580,11 @@ int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_
                 * formatted and has no conflicting keys with the rest of the
                 * request.
                 */
-               export_vg_to_buffer(vg, &buf);
+               if (!export_vg_to_buffer(vg, &buf)) {
+                       dm_free(pvmeta);
+                       return_0;
+               }
+
                reply = daemon_send_simple(_lvmetad,
                                           "pv_found",
                                           "pvmeta = %b", pvmeta,
@@ -524,15 +600,34 @@ int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_
        }
 
        dm_free(pvmeta);
-       return _lvmetad_handle_reply(reply, "update PV", uuid);
+
+       result = _lvmetad_handle_reply(reply, "update PV", uuid, NULL);
+       daemon_reply_destroy(reply);
+
+       return result;
 }
 
-int lvmetad_pv_gone(dev_t device)
+int lvmetad_pv_gone(dev_t device, const char *pv_name)
 {
-       daemon_reply reply =
-               daemon_send_simple(_lvmetad, "pv_gone", "device = %d", device, NULL);
+       int result;
+       int found;
+
+       if (!_using_lvmetad)
+               return 1;
+
+       daemon_reply reply = daemon_send_simple(_lvmetad, "pv_gone", "device = %d", device, NULL);
 
-       return _lvmetad_handle_reply(reply, "drop PV", "");
+       result = _lvmetad_handle_reply(reply, "drop PV", pv_name, &found);
+       /* We don't care whether or not the daemon had the PV cached. */
+
+       daemon_reply_destroy(reply);
+
+       return result;
+}
+
+int lvmetad_pv_gone_by_dev(struct device *dev)
+{
+       return lvmetad_pv_gone(dev->dev, dev_name(dev));
 }
 
 int lvmetad_active(void)
@@ -546,7 +641,7 @@ void lvmetad_set_active(int active)
 }
 
 /*
- * The following code implements pvscan --lvmetad.
+ * The following code implements pvscan --cache.
  */
 
 struct _pvscan_lvmetad_baton {
@@ -557,39 +652,19 @@ struct _pvscan_lvmetad_baton {
 static int _pvscan_lvmetad_single(struct metadata_area *mda, void *baton)
 {
        struct _pvscan_lvmetad_baton *b = baton;
-       struct volume_group *this = mda->ops->vg_read(b->fid, "", mda);
-       if ((this && !b->vg) || this->seqno > b->vg->seqno)
-               b->vg = this;
-       else release_vg(this);
-       return 1;
-}
-
-static dev_t _parse_devt(const char *str) { /* Oh. */
-       char *where = (char *) str;
-       int major = strtol(str, &where, 10);
-       int minor;
-
-       if (where == str)
-               return -1;
+       struct volume_group *this = mda->ops->vg_read(b->fid, "", mda, 1);
 
-       if (*where != ':')
-               return -1;
-
-       str = ++where;
-       minor = strtol(str, &where, 10);
-
-       if (where == str)
-               return -1;
-
-       if (*where)
-               return -1;
+       /* FIXME Also ensure contents match etc. */
+       if (!b->vg || this->seqno > b->vg->seqno)
+               b->vg = this;
+       else if (b->vg)
+               release_vg(this);
 
-       return MKDEV(major, minor);
+       return 1;
 }
 
-int pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+int pvscan_lvmetad_single(struct cmd_context *cmd, struct device *dev)
 {
-       struct device *dev;
        struct label *label;
        struct lvmcache_info *info;
        struct physical_volume pv;
@@ -597,37 +672,15 @@ int pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
        /* Create a dummy instance. */
        struct format_instance_ctx fic = { .type = 0 };
 
-       if (argc != 1) {
-               log_error("Exactly one device parameter required.");
-               return 0;
-       }
-
        if (!lvmetad_active()) {
                log_error("Cannot proceed since lvmetad is not active.");
                return 0;
        }
 
-       dev = dev_cache_get(argv[0], NULL);
-       if (!dev && _parse_devt(argv[0]) != -1)
-               dev = dev_cache_get_by_devt(_parse_devt(argv[0]), NULL);
-
-       if (!dev) {
-               if (_parse_devt(argv[0]) == -1) {
-                       log_error("For devices that do not exist, we need a MAJOR:MINOR pair.");
-                       return 0;
-               }
-
-               if (!lvmetad_pv_gone(_parse_devt(argv[0])))
-                       goto fatal;
-
-               log_info("Device %s not found and was wiped from lvmetad.", argv[0]);
-               return 1;
-       }
-
        if (!label_read(dev, &label, 0)) {
-               log_warn("No PV label found on %s.", dev_name(dev));
-               if (!lvmetad_pv_gone(dev->dev))
-                       goto fatal;
+               log_print("No PV label found on %s.", dev_name(dev));
+               if (!lvmetad_pv_gone_by_dev(dev))
+                       goto_bad;
                return 1;
        }
 
@@ -639,6 +692,8 @@ int pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
                                                             &fic);
 
        lvmcache_foreach_mda(info, _pvscan_lvmetad_single, &baton);
+       if (!baton.vg)
+               lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
 
        /*
         * NB. If this command failed and we are relying on lvmetad to have an
@@ -646,16 +701,17 @@ int pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
         * sync needs to be killed.
         */
        if (!lvmetad_pv_found(*(struct id *)dev->pvid, dev, lvmcache_fmt(info),
-                             label->sector, baton.vg))
-               goto fatal;
+                             label->sector, baton.vg)) {
+               release_vg(baton.vg);
+               goto_bad;
+       }
 
        release_vg(baton.vg);
        return 1;
-fatal:
-       release_vg(baton.vg);
+
+bad:
        /* FIXME kill lvmetad automatically if we can */
        log_error("Update of lvmetad failed. This is a serious problem.\n  "
                  "It is strongly recommended that you restart lvmetad immediately.");
        return 0;
 }
-
This page took 1.10471 seconds and 5 git commands to generate.