]> sourceware.org Git - lvm2.git/blobdiff - lib/activate/activate.c
activation: log target version present
[lvm2.git] / lib / activate / activate.c
index 2b44b19264d4d59599234e75b271a95d7159f5f4..512adcf8c4d53338ec43f6b04449cd587c78dfe8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -38,7 +38,7 @@
 
 int lvm1_present(struct cmd_context *cmd)
 {
-       char path[PATH_MAX];
+       static char path[PATH_MAX];
 
        if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
            < 0) {
@@ -147,17 +147,25 @@ int target_present(struct cmd_context *cmd, const char *target_name,
 {
        return 0;
 }
-int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned origin_only,
+int lvm_dm_prefix_check(int major, int minor, const char *prefix)
+{
+       return 0;
+}
+int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
            struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        return 0;
 }
-int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
-                   unsigned origin_only,
+int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
                    struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        return 0;
 }
+int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)),
+                       struct logical_volume *lv, struct lvinfo *info)
+{
+        return 0;
+}
 int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent)
 {
        return 0;
@@ -167,7 +175,26 @@ int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
 {
        return 0;
 }
-int lvs_in_vg_activated(struct volume_group *vg)
+int lv_raid_percent(const struct logical_volume *lv, percent_t *percent)
+{
+       return 0;
+}
+int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
+                        percent_t *percent)
+{
+       return 0;
+}
+int lv_thin_percent(const struct logical_volume *lv, int mapped,
+                   percent_t *percent)
+{
+       return 0;
+}
+int lv_thin_pool_transaction_id(const struct logical_volume *lv,
+                               uint64_t *transaction_id)
+{
+       return 0;
+}
+int lvs_in_vg_activated(const struct volume_group *vg)
 {
        return 0;
 }
@@ -181,7 +208,7 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
        return 1;
 }
 *******/
-int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only)
+int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive)
 {
        return 1;
 }
@@ -215,10 +242,6 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
 {
        return 1;
 }
-int lv_send_message(const struct logical_volume *lv, const char *message)
-{
-       return 0;
-}
 int pv_uses_vg(struct physical_volume *pv,
               struct volume_group *vg)
 {
@@ -231,23 +254,23 @@ void activation_exit(void)
 {
 }
 
-int lv_is_active(struct logical_volume *lv)
+int lv_is_active(const struct logical_volume *lv)
 {
        return 0;
 }
-int lv_is_active_but_not_locally(struct logical_volume *lv)
+int lv_is_active_but_not_locally(const struct logical_volume *lv)
 {
        return 0;
 }
-int lv_is_active_exclusive(struct logical_volume *lv)
+int lv_is_active_exclusive(const struct logical_volume *lv)
 {
        return 0;
 }
-int lv_is_active_exclusive_locally(struct logical_volume *lv)
+int lv_is_active_exclusive_locally(const struct logical_volume *lv)
 {
        return 0;
 }
-int lv_is_active_exclusive_remotely(struct logical_volume *lv)
+int lv_is_active_exclusive_remotely(const struct logical_volume *lv)
 {
        return 0;
 }
@@ -257,10 +280,31 @@ int lv_check_transient(struct logical_volume *lv)
        return 1;
 }
 int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
-                          struct lv_activate_opts *laopts, int monitor)
+                          const struct lv_activate_opts *laopts, int monitor)
 {
        return 1;
 }
+/* fs.c */
+void fs_unlock(void)
+{
+}
+/* dev_manager.c */
+#include "targets.h"
+int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
+                  struct dm_tree_node *node, uint32_t start_area,
+                  uint32_t areas)
+{
+        return 0;
+}
+int device_is_usable(struct device *dev)
+{
+        return 0;
+}
+int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
+                      const char *layer, const char *target_type)
+{
+        return 0;
+}
 #else                          /* DEVMAPPER_SUPPORT */
 
 static int _activation = 1;
@@ -284,49 +328,27 @@ int activation(void)
        return _activation;
 }
 
-static int _passes_activation_filter(struct cmd_context *cmd,
-                                    struct logical_volume *lv)
+static int _lv_passes_volumes_filter(struct cmd_context *cmd, struct logical_volume *lv,
+                                    const struct dm_config_node *cn, const char *config_path)
 {
-       const struct dm_config_node *cn;
        const struct dm_config_value *cv;
        const char *str;
-       char path[PATH_MAX];
-
-       if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) {
-               log_verbose("activation/volume_list configuration setting "
-                           "not defined, checking only host tags for %s/%s",
-                           lv->vg->name, lv->name);
-
-               /* If no host tags defined, activate */
-               if (dm_list_empty(&cmd->tags))
-                       return 1;
-
-               /* If any host tag matches any LV or VG tag, activate */
-               if (str_list_match_list(&cmd->tags, &lv->tags, NULL) ||
-                   str_list_match_list(&cmd->tags, &lv->vg->tags, NULL))
-                       return 1;
+       static char path[PATH_MAX];
 
-               log_verbose("No host tag matches %s/%s",
-                           lv->vg->name, lv->name);
-
-               /* Don't activate */
-               return 0;
-       }
-       else
-               log_verbose("activation/volume_list configuration setting "
-                           "defined, checking the list to match %s/%s",
-                           lv->vg->name, lv->name);
+       log_verbose("%s configuration setting defined: "
+                   "Checking the list to match %s/%s",
+                   config_path, lv->vg->name, lv->name);
 
        for (cv = cn->v; cv; cv = cv->next) {
                if (cv->type != DM_CFG_STRING) {
-                       log_error("Ignoring invalid string in config file "
-                                 "activation/volume_list");
+                       log_error("Ignoring invalid string in config file %s",
+                                 config_path);
                        continue;
                }
                str = cv->v.str;
                if (!*str) {
-                       log_error("Ignoring empty string in config file "
-                                 "activation/volume_list");
+                       log_error("Ignoring empty string in config file %s",
+                                 config_path);
                        continue;
                }
 
@@ -336,7 +358,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
                        str++;
                        if (!*str) {
                                log_error("Ignoring empty tag in config file "
-                                         "activation/volume_list");
+                                         "%s", config_path);
                                continue;
                        }
                        /* If any host tag matches any LV or VG tag, activate */
@@ -373,12 +395,66 @@ static int _passes_activation_filter(struct cmd_context *cmd,
                        return 1;
        }
 
-       log_verbose("No item supplied in activation/volume_list configuration "
-                   "setting matches %s/%s", lv->vg->name, lv->name);
+       log_verbose("No item supplied in %s configuration setting "
+                   "matches %s/%s", config_path, lv->vg->name, lv->name);
 
        return 0;
 }
 
+static int _passes_activation_filter(struct cmd_context *cmd,
+                                    struct logical_volume *lv)
+{
+       const struct dm_config_node *cn;
+
+       if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) {
+               log_verbose("activation/volume_list configuration setting "
+                           "not defined: Checking only host tags for %s/%s",
+                           lv->vg->name, lv->name);
+
+               /* If no host tags defined, activate */
+               if (dm_list_empty(&cmd->tags))
+                       return 1;
+
+               /* If any host tag matches any LV or VG tag, activate */
+               if (str_list_match_list(&cmd->tags, &lv->tags, NULL) ||
+                   str_list_match_list(&cmd->tags, &lv->vg->tags, NULL))
+                       return 1;
+
+               log_verbose("No host tag matches %s/%s",
+                           lv->vg->name, lv->name);
+
+               /* Don't activate */
+               return 0;
+       }
+
+       return _lv_passes_volumes_filter(cmd, lv, cn, "activation/volume_list");
+}
+
+static int _passes_readonly_filter(struct cmd_context *cmd,
+                                  struct logical_volume *lv)
+{
+       const struct dm_config_node *cn;
+
+       if (!(cn = find_config_tree_node(cmd, "activation/read_only_volume_list")))
+               return 0;
+
+       return _lv_passes_volumes_filter(cmd, lv, cn, "activation/read_only_volume_list");
+}
+
+
+int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_volume *lv)
+{
+       const struct dm_config_node *cn;
+
+       if (!(cn = find_config_tree_node(cmd, "activation/auto_activation_volume_list"))) {
+               log_verbose("activation/auto_activation_volume_list configuration setting "
+                           "not defined: All logical volumes will be auto-activated.");
+               return 1;
+       }
+
+       return _lv_passes_volumes_filter(cmd, lv, cn, "activation/auto_activation_volume_list");
+}
+
 int library_version(char *version, size_t size)
 {
        if (!activation())
@@ -414,7 +490,11 @@ int target_version(const char *target_name, uint32_t *maj,
        if (!dm_task_run(dmt)) {
                log_debug("Failed to get %s target version", target_name);
                /* Assume this was because LIST_VERSIONS isn't supported */
-               return 1;
+               *maj = 0;
+               *min = 0;
+               *patchlevel = 0;
+               r = 1;
+               goto out;
        }
 
        target = dm_task_get_versions(dmt);
@@ -434,11 +514,39 @@ int target_version(const char *target_name, uint32_t *maj,
        } while (last_target != target);
 
       out:
+       if (r)
+               log_very_verbose("Found %s target "
+                                "v%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".",
+                                target_name, *maj, *min, *patchlevel);
+
        dm_task_destroy(dmt);
 
        return r;
 }
 
+int lvm_dm_prefix_check(int major, int minor, const char *prefix)
+{
+       struct dm_task *dmt;
+       const char *uuid;
+       int r;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+               return_0;
+
+       if (!dm_task_set_minor(dmt, minor) ||
+           !dm_task_set_major(dmt, major) ||
+           !dm_task_run(dmt) ||
+           !(uuid = dm_task_get_uuid(dmt))) {
+               dm_task_destroy(dmt);
+               return 0;
+       }
+
+       r = strncasecmp(uuid, prefix, strlen(prefix));
+       dm_task_destroy(dmt);
+
+       return r ? 0 : 1;
+}
+
 int module_present(struct cmd_context *cmd, const char *target_name)
 {
        int ret = 0;
@@ -485,10 +593,11 @@ int target_present(struct cmd_context *cmd, const char *target_name,
 /*
  * Returns 1 if info structure populated, else 0 on failure.
  */
-int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned origin_only,
+int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
            struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        struct dm_info dminfo;
+       const char *layer;
 
        if (!activation())
                return 0;
@@ -505,7 +614,14 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned o
                        fs_unlock(); /* For non clustered - wait if there are non-delete ops */
        }
 
-       if (!dev_manager_info(lv->vg->cmd->mem, lv, origin_only ? "real" : NULL, with_open_count,
+       if (use_layer && lv_is_thin_pool(lv))
+               layer = "tpool";
+       else if (use_layer && lv_is_origin(lv))
+               layer = "real";
+       else
+               layer = NULL;
+
+       if (!dev_manager_info(lv->vg->cmd->mem, lv, layer, with_open_count,
                              with_read_ahead, &dminfo, &info->read_ahead))
                return_0;
 
@@ -521,8 +637,7 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned o
        return 1;
 }
 
-int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
-                   unsigned origin_only,
+int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
                    struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        int r;
@@ -531,10 +646,7 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
        if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
                return 0;
 
-       if (!lv_is_origin(lv))
-               origin_only = 0;
-
-       r = lv_info(cmd, lv, origin_only, info, with_open_count, with_read_ahead);
+       r = lv_info(cmd, lv, use_layer, info, with_open_count, with_read_ahead);
        release_vg(lv->vg);
 
        return r;
@@ -662,7 +774,89 @@ int lv_raid_percent(const struct logical_volume *lv, percent_t *percent)
        return lv_mirror_percent(lv->vg->cmd, lv, 0, percent, NULL);
 }
 
-static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
+/*
+ * Returns data or metadata percent usage, depends on metadata 0/1.
+ * Returns 1 if percent set, else 0 on failure.
+ */
+int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
+                        percent_t *percent)
+{
+       int r;
+       struct dev_manager *dm;
+
+       if (!activation())
+               return 0;
+
+       log_debug("Checking thin %sdata percent for LV %s/%s",
+                 (metadata) ? "meta" : "", lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
+               return_0;
+
+       if (!(r = dev_manager_thin_pool_percent(dm, lv, metadata, percent)))
+               stack;
+
+       dev_manager_destroy(dm);
+
+       return r;
+}
+
+/*
+ * Returns 1 if percent set, else 0 on failure.
+ */
+int lv_thin_percent(const struct logical_volume *lv,
+                   int mapped, percent_t *percent)
+{
+       int r;
+       struct dev_manager *dm;
+
+       if (!activation())
+               return 0;
+
+       log_debug("Checking thin percent for LV %s/%s",
+                 lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
+               return_0;
+
+       if (!(r = dev_manager_thin_percent(dm, lv, mapped, percent)))
+               stack;
+
+       dev_manager_destroy(dm);
+
+       return r;
+}
+
+/*
+ * Returns 1 if transaction_id set, else 0 on failure.
+ */
+int lv_thin_pool_transaction_id(const struct logical_volume *lv,
+                               uint64_t *transaction_id)
+{
+       int r;
+       struct dev_manager *dm;
+       struct dm_status_thin_pool *status;
+
+       if (!activation())
+               return 0;
+
+       log_debug("Checking thin percent for LV %s/%s",
+                 lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
+               return_0;
+
+       if (!(r = dev_manager_thin_pool_status(dm, lv, &status)))
+               stack;
+       else
+               *transaction_id = status->transaction_id;
+
+       dev_manager_destroy(dm);
+
+       return r;
+}
+
+static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
 {
        struct lvinfo info;
 
@@ -704,16 +898,22 @@ static int _lv_activate_lv(struct logical_volume *lv, struct lv_activate_opts *l
 static int _lv_preload(struct logical_volume *lv, struct lv_activate_opts *laopts,
                       int *flush_required)
 {
-       int r;
+       int r = 0;
        struct dev_manager *dm;
+       int old_readonly = laopts->read_only;
+
+       laopts->read_only = _passes_readonly_filter(lv->vg->cmd, lv);
 
        if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1)))
-               return_0;
+               goto_out;
 
        if (!(r = dev_manager_preload(dm, lv, laopts, flush_required)))
                stack;
 
        dev_manager_destroy(dm);
+
+       laopts->read_only = old_readonly;
+out:
        return r;
 }
 
@@ -738,6 +938,8 @@ static int _lv_suspend_lv(struct logical_volume *lv, struct lv_activate_opts *la
        int r;
        struct dev_manager *dm;
 
+       laopts->read_only = _passes_readonly_filter(lv->vg->cmd, lv);
+
        /*
         * When we are asked to manipulate (normally suspend/resume) the PVMOVE
         * device directly, we don't want to touch the devices that use it.
@@ -756,7 +958,7 @@ static int _lv_suspend_lv(struct logical_volume *lv, struct lv_activate_opts *la
  * These two functions return the number of visible LVs in the state,
  * or -1 on error.  FIXME Check this.
  */
-int lvs_in_vg_activated(struct volume_group *vg)
+int lvs_in_vg_activated(const struct volume_group *vg)
 {
        struct lv_list *lvl;
        int count = 0;
@@ -811,7 +1013,7 @@ int lvs_in_vg_opened(const struct volume_group *vg)
  *
  * Returns: 0 or 1
  */
-static int _lv_is_active(struct logical_volume *lv,
+static int _lv_is_active(const struct logical_volume *lv,
                         int *locally, int *exclusive)
 {
        int r, l, e; /* remote, local, and exclusive */
@@ -822,7 +1024,8 @@ static int _lv_is_active(struct logical_volume *lv,
                l = 1;
 
        if (!vg_is_clustered(lv->vg)) {
-               e = 1;  /* exclusive by definition */
+               if (l)
+                       e = 1;  /* exclusive by definition */
                goto out;
        }
 
@@ -842,21 +1045,15 @@ static int _lv_is_active(struct logical_volume *lv,
         * New users of this function who specifically ask for 'exclusive'
         * will be given an error message.
         */
-       if (l) {
-               if (exclusive)
-                       log_error("Unable to determine exclusivity of %s",
-                                 lv->name);
-               goto out;
-       }
+       log_error("Unable to determine exclusivity of %s", lv->name);
+
+       e = 0;
+
+       /*
+        * We used to attempt activate_lv_excl_local(lv->vg->cmd, lv) here,
+        * but it's unreliable.
+        */
 
-       /* FIXME: Is this fallback alright? */
-       if (activate_lv_excl(lv->vg->cmd, lv)) {
-               if (!deactivate_lv(lv->vg->cmd, lv))
-                       stack;
-               /* FIXME: locally & exclusive are undefined. */
-               return 0;
-       }
-       /* FIXME: Check exclusive value here. */
 out:
        if (locally)
                *locally = l;
@@ -872,32 +1069,32 @@ out:
        return r || l;
 }
 
-int lv_is_active(struct logical_volume *lv)
+int lv_is_active(const struct logical_volume *lv)
 {
        return _lv_is_active(lv, NULL, NULL);
 }
 
-int lv_is_active_but_not_locally(struct logical_volume *lv)
+int lv_is_active_but_not_locally(const struct logical_volume *lv)
 {
        int l;
        return _lv_is_active(lv, &l, NULL) && !l;
 }
 
-int lv_is_active_exclusive(struct logical_volume *lv)
+int lv_is_active_exclusive(const struct logical_volume *lv)
 {
        int e;
 
        return _lv_is_active(lv, NULL, &e) && e;
 }
 
-int lv_is_active_exclusive_locally(struct logical_volume *lv)
+int lv_is_active_exclusive_locally(const struct logical_volume *lv)
 {
        int l, e;
 
        return _lv_is_active(lv, &l, &e) && l && e;
 }
 
-int lv_is_active_exclusive_remotely(struct logical_volume *lv)
+int lv_is_active_exclusive_remotely(const struct logical_volume *lv)
 {
        int l, e;
 
@@ -946,20 +1143,32 @@ char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath)
        return path;
 }
 
+static char *_build_target_uuid(struct cmd_context *cmd, struct logical_volume *lv)
+{
+       const char *layer;
+
+       if (lv_is_thin_pool(lv))
+               layer = "tpool"; /* Monitor "tpool" for the "thin pool". */
+       else if (lv_is_origin(lv))
+               layer = "real"; /* Monitor "real" for "snapshot-origin". */
+       else
+               layer = NULL;
+
+       return build_dm_uuid(cmd->mem, lv->lvid.s, layer);
+}
+
 int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
                                    struct logical_volume *lv, int *pending)
 {
        char *uuid;
        enum dm_event_mask evmask = 0;
        struct dm_event_handler *dmevh;
-
        *pending = 0;
 
        if (!dso)
                return_0;
 
-       /* We always monitor the "real" device, never the "snapshot-origin" itself. */
-       if (!(uuid = build_dm_uuid(cmd->mem, lv->lvid.s, lv_is_origin(lv) ? "real" : NULL)))
+       if (!(uuid = _build_target_uuid(cmd, lv)))
                return_0;
 
        if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, 0, DM_EVENT_ALL_ERRORS)))
@@ -992,7 +1201,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, struct logi
                return_0;
 
        /* We always monitor the "real" device, never the "snapshot-origin" itself. */
-       if (!(uuid = build_dm_uuid(cmd->mem, lv->lvid.s, lv_is_origin(lv) ? "real" : NULL)))
+       if (!(uuid = _build_target_uuid(cmd, lv)))
                return_0;
 
        if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, timeout,
@@ -1029,6 +1238,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
        int (*monitor_fn) (struct lv_segment *s, int e);
        uint32_t s;
        static const struct lv_activate_opts zlaopts = { 0 };
+       static const struct lv_activate_opts thinopts = { .skip_in_use = 1 };
+       struct lvinfo info;
 
        if (!laopts)
                laopts = &zlaopts;
@@ -1043,6 +1254,19 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
        if (monitor && !dmeventd_monitor_mode())
                return 1;
 
+       /*
+        * Allow to unmonitor thin pool via explicit pool unmonitor
+        * or unmonitor before the last thin pool user deactivation
+        * Skip unmonitor, if invoked via unmonitor of thin volume
+        * and there is another thin pool user (open_count > 1)
+        */
+       if (laopts->skip_in_use && lv_info(lv->vg->cmd, lv, 1, &info, 1, 0) &&
+           (info.open_count != 1)) {
+               log_debug("Skipping unmonitor of opened %s (open:%d)",
+                         lv->name, info.open_count);
+               return 1;
+       }
+
        /*
         * In case of a snapshot device, we monitor lv->snapshot->lv,
         * not the actual LV itself.
@@ -1087,6 +1311,21 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
                        }
                }
 
+               /*
+                * If requested unmonitoring of thin volume, request test
+                * if there is no other thin pool user
+                *
+                * FIXME: code here looks like _lv_postorder()
+                */
+               if (seg->pool_lv &&
+                   !monitor_dev_for_events(cmd, seg->pool_lv,
+                                           (!monitor) ? &thinopts : NULL, monitor))
+                       r = 0;
+
+               if (seg->metadata_lv &&
+                   !monitor_dev_for_events(cmd, seg->metadata_lv, NULL, monitor))
+                       r = 0;
+
                if (!seg_monitored(seg) || (seg->status & PVMOVE))
                        continue;
 
@@ -1200,7 +1439,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
                goto_out;
 
        /* Ignore origin_only unless LV is origin in both old and new metadata */
-       if (!lv_is_origin(lv) || !lv_is_origin(lv_pre))
+       if (!lv_is_thin_volume(lv) && !(lv_is_origin(lv) && lv_is_origin(lv_pre)))
                laopts->origin_only = 0;
 
        if (test_mode()) {
@@ -1296,6 +1535,9 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
            (lv_is_origin(lv_pre) || lv_is_cow(lv_pre)))
                lockfs = 1;
 
+       if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
+               lockfs = 1;
+
        /*
         * Suspending an LV directly above a PVMOVE LV also
         * suspends other LVs using that same PVMOVE LV.
@@ -1334,10 +1576,18 @@ out:
        return r;
 }
 
-/* Returns success if the device is not active */
-int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only)
+/*
+ * In a cluster, set exclusive to indicate that only one node is using the
+ * device.  Any preloaded tables may then use non-clustered targets.
+ *
+ * Returns success if the device is not active
+ */
+int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive)
 {
-       struct lv_activate_opts laopts = { .origin_only = origin_only };
+       struct lv_activate_opts laopts = {
+               .origin_only = origin_only,
+               .exclusive = exclusive
+       };
 
        return _lv_suspend(cmd, lvid_s, &laopts, 0);
 }
@@ -1350,22 +1600,13 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
 }
 ***********/
 
- /*
-  * _lv_resume
-  * @cmd
-  * @lvid_s
-  * @origin_only
-  * @exclusive:  This parameter only has an affect in cluster-context.
-  *             It forces local target type to be used (instead of
-  *             cluster-aware type).
-  * @error_if_not_active
-  */
 static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
                      struct lv_activate_opts *laopts, int error_if_not_active)
 {
        struct logical_volume *lv;
        struct lvinfo info;
        int r = 0;
+       int messages_only = 0;
 
        if (!activation())
                return 1;
@@ -1373,7 +1614,10 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
        if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
                goto_out;
 
-       if (!lv_is_origin(lv))
+       if (lv_is_thin_pool(lv) && laopts->origin_only)
+               messages_only = 1;
+
+       if (!lv_is_origin(lv) && !lv_is_thin_volume(lv))
                laopts->origin_only = 0;
 
        if (test_mode()) {
@@ -1391,7 +1635,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
        if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
                goto_out;
 
-       if (!info.exists || !info.suspended) {
+       if (!info.exists || !(info.suspended || messages_only)) {
                if (error_if_not_active)
                        goto_out;
                r = 1;
@@ -1400,6 +1644,8 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
                goto out;
        }
 
+       laopts->read_only = _passes_readonly_filter(cmd, lv);
+
        if (!_lv_activate_lv(lv, laopts))
                goto_out;
 
@@ -1416,17 +1662,22 @@ out:
        return r;
 }
 
-/* Returns success if the device is not active */
+/*
+ * In a cluster, set exclusive to indicate that only one node is using the
+ * device.  Any tables loaded may then use non-clustered targets.
+ *
+ * @origin_only
+ * @exclusive   This parameter only has an affect in cluster-context.
+ *              It forces local target type to be used (instead of
+ *              cluster-aware type).
+ * Returns success if the device is not active
+ */
 int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
-                       unsigned origin_only, unsigned exclusive, unsigned revert)
+                       unsigned origin_only, unsigned exclusive,
+                       unsigned revert)
 {
        struct lv_activate_opts laopts = {
                .origin_only = origin_only,
-               /*
-                * When targets are activated exclusively in a cluster, the
-                * non-clustered target should be used.  This only happens
-                * if exclusive is set.
-                */
                .exclusive = exclusive,
                .revert = revert
        };
@@ -1589,13 +1840,21 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
                goto out;
        }
 
-       log_debug("Activating %s/%s%s.", lv->vg->name, lv->name,
-                 laopts->exclusive ? " exclusively" : "");
+       if (filter)
+               laopts->read_only = _passes_readonly_filter(cmd, lv);
+
+       log_debug("Activating %s/%s%s%s.", lv->vg->name, lv->name,
+                 laopts->exclusive ? " exclusively" : "",
+                 laopts->read_only ? " read-only" : "");
 
        if (!lv_info(cmd, lv, 0, &info, 0, 0))
                goto_out;
 
-       if (info.exists && !info.suspended && info.live_table) {
+       /*
+        * Nothing to do?
+        */
+       if (info.exists && !info.suspended && info.live_table &&
+           (info.read_only == read_only_lv(lv, laopts))) {
                r = 1;
                goto out;
        }
@@ -1671,7 +1930,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
 int pv_uses_vg(struct physical_volume *pv,
               struct volume_group *vg)
 {
-       if (!activation())
+       if (!activation() || !pv->dev)
                return 0;
 
        if (!dm_is_dm_major(MAJOR(pv->dev->dev)))
This page took 0.045818 seconds and 5 git commands to generate.