master - toollib: search for duplicate PVs only when needed
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b64da4d8b52160...
Commit: b64da4d8b52160be3ab5635b44d7bb06ef619f43
Parent: 3a7c47af0e8840f4f5b5c39294e9f378de386a50
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jan 14 14:38:05 2015 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jan 14 14:47:08 2015 -0600
toollib: search for duplicate PVs only when needed
A full search for duplicate PVs in the case of pvs -a
is only necessary when duplicates have previously been
detected in lvmcache. Use a global variable from lvmcache
to indicate that duplicate PVs exist, so we can skip the
search for duplicates when none exist.
---
lib/cache/lvmcache.c | 15 ++++++++++++++-
lib/cache/lvmcache.h | 2 ++
tools/toollib.c | 4 +---
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 6cdf766..6a9a05f 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -76,6 +76,7 @@ static int _scanning_in_progress = 0;
static int _has_scanned = 0;
static int _vgs_locked = 0;
static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */
+static int _found_duplicate_pvs = 0; /* If we never see a duplicate PV we can skip checking for them later. */
int lvmcache_init(void)
{
@@ -402,6 +403,16 @@ int lvmcache_vgs_locked(void)
return _vgs_locked;
}
+/*
+ * When lvmcache sees a duplicate PV, this is set.
+ * process_each_pv() can avoid searching for duplicates
+ * by checking this and seeing that no duplicate PVs exist.
+ */
+int lvmcache_found_duplicate_pvs(void)
+{
+ return _found_duplicate_pvs;
+}
+
static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
struct lvmcache_info *info)
{
@@ -1560,10 +1571,12 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
//dm_is_dm_major(MAJOR(dev->dev)))
//
- else if (!strcmp(pvid_s, existing->dev->pvid))
+ else if (!strcmp(pvid_s, existing->dev->pvid)) {
log_error("Found duplicate PV %s: using %s not "
"%s", pvid, dev_name(dev),
dev_name(existing->dev));
+ _found_duplicate_pvs = 1;
+ }
}
if (strcmp(pvid_s, existing->dev->pvid))
log_debug_cache("Updating pvid cache to %s (%s) from %s (%s)",
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 7a04917..0a7d898 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -160,4 +160,6 @@ uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
struct device *dev);
+int lvmcache_found_duplicate_pvs(void);
+
#endif
diff --git a/tools/toollib.c b/tools/toollib.c
index 41e1581..17a9c71 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -2329,11 +2329,9 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
* duplicate devices are being displayed by pvs -a, and
* we want each of them to be displayed in the context
* of this VG, so that this VG name appears next to it.
- * FIXME: the repeated search through all devices is a
- * high cost to pay for a very rare benefit.
*/
- if (process_all_devices) {
+ if (process_all_devices && lvmcache_found_duplicate_pvs()) {
while ((dil = _device_list_find_pvid(all_devices, pv))) {
_device_list_remove(all_devices, dil->dev);
9 years, 3 months
master - toollib: pvs -a should display VG name for each duplicate PV
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3a7c47af0e8840...
Commit: 3a7c47af0e8840f4f5b5c39294e9f378de386a50
Parent: 57d74a45a05ef14655fbb575586738b6a4cfd4da
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jan 14 14:16:03 2015 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jan 14 14:16:03 2015 -0600
toollib: pvs -a should display VG name for each duplicate PV
Previously, 'pvs -a' displayed the VG name for only the device
associated with the cached PV (pv->dev), and other duplicate
devices would have a blank VG name. This commit displays the
VG name for each of the duplicate devices. The cost of doing
this is not small: for each PV processed, the list of all
devices must be searched for duplicates.
---
tools/toollib.c | 45 ++++++++++++++++++++++++++++++++++++++-------
1 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/tools/toollib.c b/tools/toollib.c
index 472e362..41e1581 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -2126,6 +2126,7 @@ static int _get_all_devices(struct cmd_context *cmd, struct dm_list *all_devices
goto out;
}
+ strncpy(dil->pvid, dev->pvid, ID_LEN);
dil->dev = dev;
dm_list_add(all_devices, &dil->list);
}
@@ -2213,7 +2214,8 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
struct dm_list *all_devices,
struct dm_list *arg_devices,
struct dm_list *arg_tags,
- int process_all,
+ int process_all_pvs,
+ int process_all_devices,
int skip,
void *handle,
process_single_pv_fn_t process_single_pv)
@@ -2235,7 +2237,7 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
pv = pvl->pv;
pv_name = pv_dev_name(pv);
- process_pv = process_all;
+ process_pv = process_all_pvs;
/* Remove each arg_devices entry as it is processed. */
@@ -2321,12 +2323,38 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
lvmcache_replace_dev(cmd, pv, dev_orig);
}
}
+
+ /*
+ * This is another rare and obscure case where multiple
+ * duplicate devices are being displayed by pvs -a, and
+ * we want each of them to be displayed in the context
+ * of this VG, so that this VG name appears next to it.
+ * FIXME: the repeated search through all devices is a
+ * high cost to pay for a very rare benefit.
+ */
+
+ if (process_all_devices) {
+ while ((dil = _device_list_find_pvid(all_devices, pv))) {
+ _device_list_remove(all_devices, dil->dev);
+
+ dev_orig = pv->dev;
+ lvmcache_replace_dev(cmd, pv, dil->dev);
+
+ ret = process_single_pv(cmd, vg, pv, handle);
+ if (ret != ECMD_PROCESSED)
+ stack;
+ if (ret > ret_max)
+ ret_max = ret;
+
+ lvmcache_replace_dev(cmd, pv, dev_orig);
+ }
+ }
}
/*
* When processing only specific PVs, we can quit once they've all been found.
*/
- if (!process_all && dm_list_empty(arg_tags) && dm_list_empty(arg_devices))
+ if (!process_all_pvs && dm_list_empty(arg_tags) && dm_list_empty(arg_devices))
break;
}
@@ -2349,7 +2377,8 @@ static int _process_pvs_in_vgs(struct cmd_context *cmd, uint32_t flags,
struct dm_list *all_devices,
struct dm_list *arg_devices,
struct dm_list *arg_tags,
- int process_all,
+ int process_all_pvs,
+ int process_all_devices,
void *handle,
process_single_pv_fn_t process_single_pv)
{
@@ -2383,7 +2412,8 @@ static int _process_pvs_in_vgs(struct cmd_context *cmd, uint32_t flags,
*/
ret = _process_pvs_in_vg(cmd, vg, all_devices, arg_devices, arg_tags,
- process_all, skip, handle, process_single_pv);
+ process_all_pvs, process_all_devices, skip,
+ handle, process_single_pv);
if (ret != ECMD_PROCESSED)
stack;
if (ret > ret_max)
@@ -2395,7 +2425,7 @@ static int _process_pvs_in_vgs(struct cmd_context *cmd, uint32_t flags,
unlock_and_release_vg(cmd, vg, vg->name);
/* Quit early when possible. */
- if (!process_all && dm_list_empty(arg_tags) && dm_list_empty(arg_devices))
+ if (!process_all_pvs && dm_list_empty(arg_tags) && dm_list_empty(arg_devices))
return ret_max;
}
@@ -2470,7 +2500,8 @@ int process_each_pv(struct cmd_context *cmd,
}
ret = _process_pvs_in_vgs(cmd, flags, &all_vgnameids, &all_devices,
- &arg_devices, &arg_tags, process_all_pvs,
+ &arg_devices, &arg_tags,
+ process_all_pvs, process_all_devices,
handle, process_single_pv);
if (ret != ECMD_PROCESSED)
stack;
9 years, 3 months
master - toollib: override the PV device with duplicates
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=57d74a45a05ef1...
Commit: 57d74a45a05ef14655fbb575586738b6a4cfd4da
Parent: c1f246fedfc349c25749da501e68a7f70bd122b0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jan 13 16:16:22 2015 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jan 14 11:57:29 2015 -0600
toollib: override the PV device with duplicates
When multiple duplicate devices are specified on the
command line, the PV is processed once for each of them,
but pv->dev is the device used each time.
This overrides the PV device to reflect the duplicate
device that was specified on the command line. This is
done by hacking the lvmcache to replace pv->dev with the
device of the duplicate being processed. (It would be
preferable to override pv->dev without munging the content
of the cache, and without sprinkling special cases throughout
the code.)
This override only applies when multiple duplicate devices are
specified on the command line. When only a single duplicate
device of pv->dev is specified, the priority is to display the
cached pv->dev, so pv->dev is not overridden by the named
duplicate device.
In the examples below, loop3 is the cached device referenced
by pv->dev, and is given priority for processing. Only after
loop3 is processed/displayed, will other duplicate devices
loop0/loop1 appear (when requested on the command line.)
With two duplicate devices, loop0 and loop3:
# pvs
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m
# pvs -o+dev_size /dev/loop0 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop0
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
With three duplicate devices, loop0, loop1, loop3:
# pvs -o+dev_size
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop3 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
# pvs -o+dev_size /dev/loop0 /dev/loop1 /dev/loop3
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop1 not /dev/loop0
Found duplicate PV XhLbpVo0hmuwrMQLjfxuAvPFUFZqD4vr: using /dev/loop3 not /dev/loop1
PV VG Fmt Attr PSize PFree DevSize
/dev/loop0 loopa lvm2 a-- 12.00m 12.00m 16.00m
/dev/loop1 loopa lvm2 a-- 12.00m 12.00m 32.00m
/dev/loop3 loopa lvm2 a-- 12.00m 12.00m 32.00m
---
lib/cache/lvmcache.c | 21 +++++++++++++++++++++
lib/cache/lvmcache.h | 3 +++
tools/toollib.c | 15 +++++++++++----
3 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 932b1ca..6cdf766 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1467,6 +1467,27 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
return 1;
}
+/*
+ * Replace pv->dev with dev so that dev will appear for reporting.
+ */
+
+void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
+ struct device *dev)
+{
+ struct lvmcache_info *info;
+ char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
+
+ strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
+ pvid_s[sizeof(pvid_s) - 1] = '\0';
+
+ if (!(info = lvmcache_info_from_pvid(pvid_s, 0)))
+ return;
+
+ info->dev = dev;
+ info->label->dev = dev;
+ pv->dev = dev;
+}
+
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid,
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index d43866d..7a04917 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -157,4 +157,7 @@ unsigned lvmcache_mda_count(struct lvmcache_info *info);
int lvmcache_vgid_is_cached(const char *vgid);
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
+void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
+ struct device *dev);
+
#endif
diff --git a/tools/toollib.c b/tools/toollib.c
index c534e89..472e362 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -2221,6 +2221,7 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
struct physical_volume *pv;
struct pv_list *pvl;
struct device_id_list *dil;
+ struct device *dev_orig;
const char *pv_name;
int process_pv;
int dev_found;
@@ -2298,11 +2299,14 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
_device_list_remove(arg_devices, dil->dev);
/*
- * This will simply display the same PV
- * multiple times. Further changes would
- * be needed to make this display the details
- * of dil->dev instead of pv->dev.
+ * Replace pv->dev with this dil->dev
+ * in lvmcache so the duplicate dev
+ * info will be reported. FIXME: it
+ * would be nicer to override pv->dev
+ * without munging lvmcache content.
*/
+ dev_orig = pv->dev;
+ lvmcache_replace_dev(cmd, pv, dil->dev);
log_very_verbose("Processing PV %s device %s in VG %s.",
pv_name, dev_name(dil->dev), vg->name);
@@ -2312,6 +2316,9 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
stack;
if (ret > ret_max)
ret_max = ret;
+
+ /* Put the cache state back as it was. */
+ lvmcache_replace_dev(cmd, pv, dev_orig);
}
}
}
9 years, 3 months
master - toollib: handle duplicate pvs in process_in_pv
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=c1f246fedfc349...
Commit: c1f246fedfc349c25749da501e68a7f70bd122b0
Parent: eac4e1e939c6fe7eba0d2c3865e25b8ed43fe6d9
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 9 14:55:16 2015 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jan 14 11:57:29 2015 -0600
toollib: handle duplicate pvs in process_in_pv
Processes a PV once for each time a device with its PV ID
exists on the command line.
This fixes a regression in the case where:
. devices /dev/sdA and /dev/sdB where clones (same PV ID)
. the cached VG references /dev/sdA
. before the regression, the command: pvs /dev/sdB
would display the cached device clone /dev/sdA
. after the regression, pvs /dev/sdB would display nothing,
causing vgimportclone /dev/sdB to fail.
. with this fix, pvs /dev/sdB displays /dev/sdA
Also, pvs /dev/sdA /dev/sdB will report two lines, one for each
device on the command line, but /dev/sdA is displayed for each.
This only works without lvmetad.
---
lib/cache/lvmcache.c | 2 +-
tools/toollib.c | 139 ++++++++++++++++++++++++++++++++++++--------------
2 files changed, 101 insertions(+), 40 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 416907e..932b1ca 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1539,7 +1539,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
//dm_is_dm_major(MAJOR(dev->dev)))
//
- else if (!strcmp(pvid_s, existing->dev->pvid))
+ else if (!strcmp(pvid_s, existing->dev->pvid))
log_error("Found duplicate PV %s: using %s not "
"%s", pvid, dev_name(dev),
dev_name(existing->dev));
diff --git a/tools/toollib.c b/tools/toollib.c
index 1b3883e..c534e89 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -18,6 +18,12 @@
#include <signal.h>
#include <sys/wait.h>
+struct device_id_list {
+ struct dm_list list;
+ struct device *dev;
+ char pvid[ID_LEN + 1];
+};
+
const char *command_name(struct cmd_context *cmd)
{
return cmd->command->name;
@@ -2079,20 +2085,21 @@ static int _get_arg_devices(struct cmd_context *cmd,
struct dm_list *arg_devices)
{
struct dm_str_list *sl;
- struct device_list *devl;
+ struct device_id_list *dil;
int ret_max = ECMD_PROCESSED;
dm_list_iterate_items(sl, arg_pvnames) {
- if (!(devl = dm_pool_alloc(cmd->mem, sizeof(*devl)))) {
- log_error("device_list alloc failed.");
+ if (!(dil = dm_pool_alloc(cmd->mem, sizeof(*dil)))) {
+ log_error("device_id_list alloc failed.");
return ECMD_FAILED;
}
- if (!(devl->dev = dev_cache_get(sl->str, cmd->filter))) {
- log_error("Failed to find physical volume \"%s\".", sl->str);
+ if (!(dil->dev = dev_cache_get(sl->str, cmd->filter))) {
+ log_error("Failed to find device for physical volume \"%s\".", sl->str);
ret_max = ECMD_FAILED;
} else {
- dm_list_add(arg_devices, &devl->list);
+ strncpy(dil->pvid, dil->dev->pvid, ID_LEN);
+ dm_list_add(arg_devices, &dil->list);
}
}
@@ -2103,7 +2110,7 @@ static int _get_all_devices(struct cmd_context *cmd, struct dm_list *all_devices
{
struct dev_iter *iter;
struct device *dev;
- struct device_list *devl;
+ struct device_id_list *dil;
int r = ECMD_FAILED;
lvmcache_seed_infos_from_lvmetad(cmd);
@@ -2114,13 +2121,13 @@ static int _get_all_devices(struct cmd_context *cmd, struct dm_list *all_devices
}
while ((dev = dev_iter_get(iter))) {
- if (!(devl = dm_pool_alloc(cmd->mem, sizeof(*devl)))) {
- log_error("device_list alloc failed.");
+ if (!(dil = dm_pool_alloc(cmd->mem, sizeof(*dil)))) {
+ log_error("device_id_list alloc failed.");
goto out;
}
- devl->dev = dev;
- dm_list_add(all_devices, &devl->list);
+ dil->dev = dev;
+ dm_list_add(all_devices, &dil->list);
}
r = ECMD_PROCESSED;
@@ -2129,13 +2136,13 @@ out:
return r;
}
-static int _device_list_remove(struct dm_list *all_devices, struct device *dev)
+static int _device_list_remove(struct dm_list *devices, struct device *dev)
{
- struct device_list *devl;
+ struct device_id_list *dil;
- dm_list_iterate_items(devl, all_devices) {
- if (devl->dev == dev) {
- dm_list_del(&devl->list);
+ dm_list_iterate_items(dil, devices) {
+ if (dil->dev == dev) {
+ dm_list_del(&dil->list);
return 1;
}
}
@@ -2143,16 +2150,28 @@ static int _device_list_remove(struct dm_list *all_devices, struct device *dev)
return 0;
}
-static int _device_list_match(struct dm_list *devices, struct device *dev)
+static struct device_id_list *_device_list_find_dev(struct dm_list *devices, struct device *dev)
{
- struct device_list *devl;
+ struct device_id_list *dil;
- dm_list_iterate_items(devl, devices) {
- if (devl->dev == dev)
- return 1;
+ dm_list_iterate_items(dil, devices) {
+ if (dil->dev == dev)
+ return dil;
}
- return 0;
+ return NULL;
+}
+
+static struct device_id_list *_device_list_find_pvid(struct dm_list *devices, struct physical_volume *pv)
+{
+ struct device_id_list *dil;
+
+ dm_list_iterate_items(dil, devices) {
+ if (id_equal((struct id *) dil->pvid, &pv->id))
+ return dil;
+ }
+
+ return NULL;
}
static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_devices,
@@ -2160,7 +2179,7 @@ static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_dev
{
struct physical_volume pv_dummy;
struct physical_volume *pv;
- struct device_list *devl;
+ struct device_id_list *dil;
int ret_max = ECMD_PROCESSED;
int ret = 0;
@@ -2168,17 +2187,17 @@ static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_dev
* Pretend that each device is a PV with dummy values.
* FIXME Formalise this extension or find an alternative.
*/
- dm_list_iterate_items(devl, all_devices) {
+ dm_list_iterate_items(dil, all_devices) {
if (sigint_caught())
return_ECMD_FAILED;
memset(&pv_dummy, 0, sizeof(pv_dummy));
dm_list_init(&pv_dummy.tags);
dm_list_init(&pv_dummy.segments);
- pv_dummy.dev = devl->dev;
+ pv_dummy.dev = dil->dev;
pv = &pv_dummy;
- log_very_verbose("Processing device %s.", dev_name(devl->dev));
+ log_very_verbose("Processing device %s.", dev_name(dil->dev));
ret = process_single_pv(cmd, NULL, pv, handle);
@@ -2201,6 +2220,7 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
{
struct physical_volume *pv;
struct pv_list *pvl;
+ struct device_id_list *dil;
const char *pv_name;
int process_pv;
int dev_found;
@@ -2219,9 +2239,17 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
/* Remove each arg_devices entry as it is processed. */
if (!process_pv && !dm_list_empty(arg_devices) &&
- _device_list_match(arg_devices, pv->dev)) {
+ (dil = _device_list_find_dev(arg_devices, pv->dev))) {
process_pv = 1;
- _device_list_remove(arg_devices, pv->dev);
+ _device_list_remove(arg_devices, dil->dev);
+ }
+
+ /* Select the PV if the device arg has the same pvid. */
+
+ if (!process_pv && !dm_list_empty(arg_devices) &&
+ (dil = _device_list_find_pvid(arg_devices, pv))) {
+ process_pv = 1;
+ _device_list_remove(arg_devices, dil->dev);
}
if (!process_pv && !dm_list_empty(arg_tags) &&
@@ -2257,6 +2285,35 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
if (ret > ret_max)
ret_max = ret;
}
+
+ /*
+ * This is a very rare and obscure case where multiple
+ * duplicate devices are specified on the command line
+ * referring to this PV. In this case we want to
+ * process this PV once for each specified device.
+ */
+
+ if (!skip && !dm_list_empty(arg_devices)) {
+ while ((dil = _device_list_find_pvid(arg_devices, pv))) {
+ _device_list_remove(arg_devices, dil->dev);
+
+ /*
+ * This will simply display the same PV
+ * multiple times. Further changes would
+ * be needed to make this display the details
+ * of dil->dev instead of pv->dev.
+ */
+
+ log_very_verbose("Processing PV %s device %s in VG %s.",
+ pv_name, dev_name(dil->dev), vg->name);
+
+ ret = process_single_pv(cmd, vg, pv, handle);
+ if (ret != ECMD_PROCESSED)
+ stack;
+ if (ret > ret_max)
+ ret_max = ret;
+ }
+ }
}
/*
@@ -2278,7 +2335,7 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
* Each PV is removed from arg_devices and all_devices when it is
* processed. Any names remaining in arg_devices were not found, and
* should produce an error. Any devices remaining in all_devices were
- * not found and should be processed by process_all_devices().
+ * not found and should be processed by process_device_list().
*/
static int _process_pvs_in_vgs(struct cmd_context *cmd, uint32_t flags,
struct dm_list *all_vgnameids,
@@ -2347,10 +2404,10 @@ int process_each_pv(struct cmd_context *cmd,
{
struct dm_list arg_tags; /* str_list */
struct dm_list arg_pvnames; /* str_list */
- struct dm_list arg_devices; /* device_list */
+ struct dm_list arg_devices; /* device_id_list */
struct dm_list all_vgnameids; /* vgnameid_list */
- struct dm_list all_devices; /* device_list */
- struct device_list *devl;
+ struct dm_list all_devices; /* device_id_list */
+ struct device_id_list *dil;
int process_all_pvs;
int process_all_devices;
int ret_max = ECMD_PROCESSED;
@@ -2363,6 +2420,15 @@ int process_each_pv(struct cmd_context *cmd,
dm_list_init(&all_devices);
/*
+ * Read all the vgs first because this has the effect of initializing
+ * other device/lvmcache info that is needed when creating device lists.
+ */
+ if ((ret = _get_vgnameids_on_system(cmd, &all_vgnameids, only_this_vgname, 1) != ECMD_PROCESSED)) {
+ stack;
+ return ret;
+ }
+
+ /*
* Create two lists from argv:
* arg_pvnames: pvs explicitly named in argv
* arg_tags: tags explicitly named in argv
@@ -2396,11 +2462,6 @@ int process_each_pv(struct cmd_context *cmd,
return ret;
}
- if ((ret = _get_vgnameids_on_system(cmd, &all_vgnameids, only_this_vgname, 1) != ECMD_PROCESSED)) {
- stack;
- return ret;
- }
-
ret = _process_pvs_in_vgs(cmd, flags, &all_vgnameids, &all_devices,
&arg_devices, &arg_tags, process_all_pvs,
handle, process_single_pv);
@@ -2409,8 +2470,8 @@ int process_each_pv(struct cmd_context *cmd,
if (ret > ret_max)
ret_max = ret;
- dm_list_iterate_items(devl, &arg_devices) {
- log_error("Failed to find physical volume \"%s\".", dev_name(devl->dev));
+ dm_list_iterate_items(dil, &arg_devices) {
+ log_error("Failed to find physical volume \"%s\".", dev_name(dil->dev));
ret_max = ECMD_FAILED;
}
9 years, 3 months
master - dmeventd: Call lvscan --cache also for mirrors (in addition to RAID).
by Petr Rockai
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=eac4e1e939c6fe...
Commit: eac4e1e939c6fe7eba0d2c3865e25b8ed43fe6d9
Parent: 4a55175bacbad1261917f170254040fb2846f994
Author: Petr Rockai <prockai(a)redhat.com>
AuthorDate: Wed Jan 14 18:04:46 2015 +0100
Committer: Petr Rockai <prockai(a)redhat.com>
CommitterDate: Wed Jan 14 18:05:44 2015 +0100
dmeventd: Call lvscan --cache also for mirrors (in addition to RAID).
---
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c b/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
index 2328089..084be28 100644
--- a/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
+++ b/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
@@ -136,10 +136,20 @@ static int _remove_failed_devices(const char *device)
char cmd_str[CMD_SIZE];
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
+ "lvscan --cache", device))
+ return -1;
+
+ r = dmeventd_lvm2_run(cmd_str);
+
+ if (!r)
+ syslog(LOG_INFO, "Re-scan of mirror device %s failed.", device);
+
+ if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
"lvconvert --config devices{ignore_suspended_devices=1} "
"--repair --use-policies", device))
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
+ /* if repair goes OK, report success even if lvscan has failed */
r = dmeventd_lvm2_run(cmd_str);
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
9 years, 3 months
master - WHATS_NEW
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4a55175bacbad1...
Commit: 4a55175bacbad1261917f170254040fb2846f994
Parent: 2908ab3eed4d7feb041c99a4e2fca98a5bcf6922
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 14 15:15:29 2015 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 14 15:15:29 2015 +0100
WHATS_NEW
More news
---
WHATS_NEW | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 3881d5d..344aeb7 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,7 @@
Version 2.02.115 -
=====================================
+ Report lv_health_status and health attribute also for thin pool.
+ Add lv_error_when_full reporting field.
Add support for lvcreate --errorwhenfull y|n for thin pools.
Fix lvconvert --repair to honour resilience requirement for segmented RAID LV.
Filter out partitioned device-mapper devices as unsuitable for use as PVs.
9 years, 3 months
master - thin: errrorwhenfull support
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2908ab3eed4d7f...
Commit: 2908ab3eed4d7feb041c99a4e2fca98a5bcf6922
Parent: 1e050a77ff333fd1849eb8068b6d22cb9411fc06
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jan 13 15:23:03 2015 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 14 14:52:05 2015 +0100
thin: errrorwhenfull support
Support error_if_no_space feature for thin pools.
Report more info about thinpool status:
(out_of_data (D), metadata_read_only (M), failed (F) also as health
attribute.)
---
WHATS_NEW | 1 +
WHATS_NEW_DM | 2 ++
conf/example.conf.in | 5 +++++
lib/config/config_settings.h | 1 +
lib/config/defaults.h | 1 +
lib/format_text/flags.c | 1 +
lib/metadata/lv.c | 16 ++++++++++++++++
lib/metadata/lv.h | 1 +
lib/metadata/lv_manip.c | 2 ++
lib/metadata/merge.c | 7 +++++++
lib/metadata/metadata-exported.h | 4 +++-
lib/metadata/segtype.h | 3 +++
lib/report/columns.h | 1 +
lib/report/properties.c | 2 ++
lib/report/report.c | 21 +++++++++++++++++++++
lib/report/values.h | 1 +
lib/thin/thin.c | 11 ++++++++++-
libdm/libdevmapper.h | 12 ++++++++++--
libdm/libdm-deptree.c | 34 +++++++++++++++++++++++++++++-----
tools/args.h | 1 +
tools/commands.h | 3 ++-
tools/lvcreate.c | 15 +++++++++++++++
22 files changed, 135 insertions(+), 10 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index bbb45c4..3881d5d 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.115 -
=====================================
+ Add support for lvcreate --errorwhenfull y|n for thin pools.
Fix lvconvert --repair to honour resilience requirement for segmented RAID LV.
Filter out partitioned device-mapper devices as unsuitable for use as PVs.
Also notify lvmetad about filtered device if using pvscan --cache DevicePath.
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 02b8045..98f98b6 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,7 @@
Version 1.02.93 -
====================================
+ Report more info from thin pool status (out of data, metadata-ro, fail).
+ Support error_if_no_space for thin pool target.
Fix segfault while using selection with regex and unbuffered reporting.
Add dm_report_compact_fields to remove empty fields from report output.
Remove unimplemented dm_report_set_output_selection from libdevmapper.h.
diff --git a/conf/example.conf.in b/conf/example.conf.in
index 70d3e6b..21b963b 100644
--- a/conf/example.conf.in
+++ b/conf/example.conf.in
@@ -777,6 +777,7 @@ global {
# external_origin
# metadata_resize
# external_origin_extend
+ # error_if_no_space
#
# thin_disabled_features = [ "discards", "block_size" ]
@@ -937,6 +938,10 @@ activation {
# enables or disables this automatic setting of the flag while LVs are created.
# auto_set_activation_skip = 1
+ # Control error behavior when provisioned device becomes full.
+ # Set to 1 to instant error when there is missing free space in device.
+ # error_when_full = 0
+
# For RAID or 'mirror' segment types, 'raid_region_size' is the
# size (in KiB) of each:
# - synchronization operation when initializing
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index 6de948e..8978b5b 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -205,6 +205,7 @@ cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_li
cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 89), NULL)
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL)
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL)
+cfg(activation_error_when_full_CFG, "error_when_full", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ERROR_WHEN_FULL, vsn(2, 2, 115), NULL)
cfg(activation_readahead_CFG, "readahead", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_READ_AHEAD, vsn(1, 0, 23), NULL)
cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_RAID_FAULT_POLICY, vsn(2, 2, 89), NULL)
cfg(activation_mirror_device_fault_policy_CFG, "mirror_device_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_DEVICE_FAULT_POLICY, vsn(1, 2, 10), NULL)
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index e15926c..1431de2 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -44,6 +44,7 @@
#define DEFAULT_PV_MIN_SIZE_KB 2048
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
+#define DEFAULT_ERROR_WHEN_FULL 0
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
#define DEFAULT_WAIT_FOR_LOCKS 1
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index e3a00a6..cf01271 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -61,6 +61,7 @@ static const struct flag _lv_flags[] = {
{LV_REBUILD, "REBUILD", STATUS_FLAG},
{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
+ {LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG},
{LV_NOSCAN, NULL, 0},
{LV_TEMPORARY, NULL, 0},
{POOL_METADATA_SPARE, NULL, 0},
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index fb1cd78..8682535 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -210,6 +210,11 @@ uint64_t lvseg_size(const struct lv_segment *seg)
return (uint64_t) seg->len * seg->lv->vg->extent_size;
}
+uint32_t lv_error_when_full(const struct logical_volume *lv)
+{
+ return (lv_is_thin_pool(lv) && (lv->status & LV_ERROR_WHEN_FULL)) ? 1 : 0;
+}
+
uint32_t lv_kernel_read_ahead(const struct logical_volume *lv)
{
struct lvinfo info;
@@ -644,6 +649,7 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
dm_percent_t snap_percent;
struct lvinfo info;
struct lv_segment *seg;
+ struct lv_seg_status seg_status;
char *repstr;
if (!(repstr = dm_pool_zalloc(mem, 11))) {
@@ -797,6 +803,16 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
repstr[8] = 'm'; /* RAID has 'm'ismatches */
} else if (lv->status & LV_WRITEMOSTLY)
repstr[8] = 'w'; /* sub-LV has 'w'ritemostly */
+ } else if (lv_is_thin_pool(lv)) {
+ seg_status.mem = lv->vg->cmd->mem;
+ if (!lv_status(lv->vg->cmd, first_seg(lv), &seg_status))
+ repstr[8] = 'X'; /* Unknown */
+ else if (((struct dm_status_thin_pool *)seg_status.status)->fail)
+ repstr[8] = 'F';
+ else if (((struct dm_status_thin_pool *)seg_status.status)->out_of_data_space)
+ repstr[8] = 'D';
+ else if (((struct dm_status_thin_pool *)seg_status.status)->read_only)
+ repstr[8] = 'M';
}
if (lv->status & LV_ACTIVATION_SKIP)
diff --git a/lib/metadata/lv.h b/lib/metadata/lv.h
index 8064ba2..6c6df73 100644
--- a/lib/metadata/lv.h
+++ b/lib/metadata/lv.h
@@ -88,6 +88,7 @@ char *lvseg_monitor_dup(struct dm_pool *mem, const struct lv_segment *seg);
char *lvseg_tags_dup(const struct lv_segment *seg);
char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg);
char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg);
+uint32_t lv_error_when_full(const struct logical_volume *lv);
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv);
char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv);
int lv_set_creation(struct logical_volume *lv,
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 457cf9e..8a3b779 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -7010,6 +7010,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
stack;
goto revert_new_lv;
}
+ if (lp->error_when_full)
+ lv->status |= LV_ERROR_WHEN_FULL;
} else if (pool_lv && seg_is_thin_volume(lp)) {
seg = first_seg(lv);
pool_seg = first_seg(pool_lv);
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index 5e09123..6d661f8 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -147,6 +147,13 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
inc_error_count;
}
+ if ((lv->status & LV_ERROR_WHEN_FULL) &&
+ !seg_can_error_when_full(seg)) {
+ log_error("LV %s: segment %u (%s) does not support flag "
+ "ERROR_WHEN_FULL.", lv->name, seg_count, seg->segtype->name);
+ inc_error_count;
+ }
+
if (complete_vg && seg->log_lv &&
!seg_is_mirrored(seg) && !(seg->status & RAID_IMAGE)) {
log_error("LV %s: segment %u log LV %s is not a "
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 14a5ef5..a48aef2 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -118,8 +118,9 @@
#define CACHE UINT64_C(0x0001000000000000) /* LV - Internal use only */
#define LV_PENDING_DELETE UINT64_C(0x0004000000000000) /* LV - Internal use only */
+#define LV_ERROR_WHEN_FULL UINT64_C(0x0008000000000000) /* LV - error when full */
-/* Next unused flag: UINT64_C(0x0008000000000000) */
+/* Next unused flag: UINT64_C(0x0010000000000000) */
/* Format features flags */
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
@@ -871,6 +872,7 @@ struct lvcreate_params {
struct dm_list *pvh; /* all */
uint64_t permission; /* all */
+ unsigned error_when_full; /* when segment supports it */
uint32_t read_ahead; /* all */
int approx_alloc; /* all */
alloc_policy_t alloc; /* all */
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index ecb598d..4b2df78 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -45,6 +45,7 @@ struct dev_manager;
#define SEG_CACHE_POOL 0x00004000U
#define SEG_MIRROR 0x00008000U
#define SEG_ONLY_EXCLUSIVE 0x00010000U /* In cluster only exlusive activation */
+#define SEG_CAN_ERROR_WHEN_FULL 0x00020000U
#define SEG_UNKNOWN 0x80000000U
#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0)
@@ -80,6 +81,7 @@ struct dev_manager;
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
#define seg_only_exclusive(seg) ((seg)->segtype->flags & SEG_ONLY_EXCLUSIVE ? 1 : 0)
+#define seg_can_error_when_full(seg) ((seg)->segtype->flags & SEG_CAN_ERROR_WHEN_FULL ? 1 : 0)
struct segment_type {
struct dm_list list; /* Internal */
@@ -179,6 +181,7 @@ int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seg
#define THIN_FEATURE_DISCARDS_NON_POWER_2 (1U << 4)
#define THIN_FEATURE_METADATA_RESIZE (1U << 5)
#define THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND (1U << 6)
+#define THIN_FEATURE_ERROR_IF_NO_SPACE (1U << 7)
#ifdef THIN_INTERNAL
int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 1dd2ae0..9f64ac8 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -52,6 +52,7 @@ FIELD(LVS, lv, BIN, "MergeFailed", lvid, 15, lvmergefailed, lv_merge_failed, "Se
FIELD(LVS, lv, BIN, "SnapInvalid", lvid, 15, lvsnapshotinvalid, lv_snapshot_invalid, "Set if snapshot LV is invalid.", 0)
FIELD(LVS, lv, STR, "Health", lvid, 15, lvhealthstatus, lv_health_status, "LV health status.", 0)
FIELD(LVS, lv, BIN, "SkipAct", lvid, 15, lvskipactivation, lv_skip_activation, "Set if LV is skipped on activation.", 0)
+FIELD(LVS, lv, BIN, "WhenFull", lvid, 15, lverrorwhenfull, lv_error_when_full, "For thin pools, behavior when full.", 0)
FIELD(LVS, lv, STR, "Active", lvid, 6, lvactive, lv_active, "Active state of the LV.", 0)
FIELD(LVS, lv, BIN, "ActLocal", lvid, 10, lvactivelocally, lv_active_locally, "Set if the LV is active locally.", 0)
FIELD(LVS, lv, BIN, "ActRemote", lvid, 10, lvactiveremotely, lv_active_remotely, "Set if the LV is active remotely.", 0)
diff --git a/lib/report/properties.c b/lib/report/properties.c
index 4796000..cece62c 100644
--- a/lib/report/properties.c
+++ b/lib/report/properties.c
@@ -281,6 +281,8 @@ GET_LV_STR_PROPERTY_FN(lv_attr, lv_attr_dup(lv->vg->vgmem, lv))
GET_LV_NUM_PROPERTY_FN(lv_major, lv->major)
#define _lv_major_set prop_not_implemented_set
GET_LV_NUM_PROPERTY_FN(lv_minor, lv->minor)
+#define _lv_error_when_full_set prop_not_implemented_set
+GET_LV_NUM_PROPERTY_FN(lv_error_when_full, lv_error_when_full(lv))
#define _lv_minor_set prop_not_implemented_set
GET_LV_NUM_PROPERTY_FN(lv_read_ahead, lv->read_ahead * SECTOR_SIZE)
#define _lv_read_ahead_set prop_not_implemented_set
diff --git a/lib/report/report.c b/lib/report/report.c
index be80e77..1b1ccca 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -726,6 +726,16 @@ static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((
return dm_report_field_int32(rh, field, data);
}
+static int _lverrorwhenfull_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data, void *private __attribute__((unused)))
+{
+ const struct logical_volume *lv = (const struct logical_volume *) data;
+
+ return _binary_disp(rh, mem, field, lv_error_when_full(lv),
+ GET_FIRST_RESERVED_NAME(lv_error_when_full_y), private);
+}
+
static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
@@ -1761,6 +1771,7 @@ static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
+ struct lv_seg_status seg_status;
const char *health = "";
uint64_t n;
@@ -1776,6 +1787,16 @@ static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem,
health = "mismatches exist";
} else if (lv->status & LV_WRITEMOSTLY)
health = "writemostly";
+ } else if (lv_is_thin_pool(lv)) {
+ seg_status.mem = lv->vg->cmd->mem;
+ if (!lv_status(lv->vg->cmd, first_seg(lv), &seg_status))
+ health = "unknown";
+ else if (((struct dm_status_thin_pool *)seg_status.status)->fail)
+ health = "failed";
+ else if (((struct dm_status_thin_pool *)seg_status.status)->out_of_data_space)
+ health = "out_of_data";
+ else if (((struct dm_status_thin_pool *)seg_status.status)->read_only)
+ health = "metadata_read_only";
}
return _string_disp(rh, mem, field, &health, private);
diff --git a/lib/report/values.h b/lib/report/values.h
index 4ea92bd..4323c17 100644
--- a/lib/report/values.h
+++ b/lib/report/values.h
@@ -68,6 +68,7 @@ FIELD_RESERVED_BINARY_VALUE(lv_image_synced, lv_image_synced, "", "image synced"
FIELD_RESERVED_BINARY_VALUE(lv_merging, lv_merging, "", "merging")
FIELD_RESERVED_BINARY_VALUE(lv_converting, lv_converting, "", "converting")
FIELD_RESERVED_BINARY_VALUE(lv_allocation_locked, lv_allocation_locked, "", "allocation locked", "locked")
+FIELD_RESERVED_BINARY_VALUE(lv_error_when_full, lv_error_when_full, "", "error when full", "error if no space", "error")
FIELD_RESERVED_BINARY_VALUE(lv_fixed_minor, lv_fixed_minor, "", "fixed minor", "fixed")
FIELD_RESERVED_BINARY_VALUE(lv_active_locally, lv_active_locally, "", "active locally", "active", "locally")
FIELD_RESERVED_BINARY_VALUE(lv_active_remotely, lv_active_remotely, "", "active remotely", "active", "remotely")
diff --git a/lib/thin/thin.c b/lib/thin/thin.c
index f27f240..377d6ad 100644
--- a/lib/thin/thin.c
+++ b/lib/thin/thin.c
@@ -259,6 +259,7 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
uint32_t *pvmove_mirror_count __attribute__((unused)))
{
static int _no_discards = 0;
+ static int _no_error_if_no_space = 0;
char *metadata_dlid, *pool_dlid;
const struct lv_thin_message *lmsg;
const struct logical_volume *origin;
@@ -314,6 +315,12 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
log_warn_suppress(_no_discards++, "WARNING: Thin pool target does "
"not support discards (needs kernel >= 3.4).");
+ if (attr & THIN_FEATURE_ERROR_IF_NO_SPACE)
+ dm_tree_node_set_thin_pool_error_if_no_space(node, (seg->lv->status & LV_ERROR_WHEN_FULL) ? 1 : 0);
+ else if (seg->lv->status & LV_ERROR_WHEN_FULL)
+ log_warn_suppress(_no_error_if_no_space++, "WARNING: Thin pool target does "
+ "not support error if no space (needs version >= 1.10).");
+
/*
* Add messages only for activation tree.
* Otherwise avoid checking for existence of suspended origin.
@@ -639,6 +646,7 @@ static int _thin_target_present(struct cmd_context *cmd,
{ 1, 5, THIN_FEATURE_DISCARDS_NON_POWER_2, "discards_non_power_2" },
{ 1, 10, THIN_FEATURE_METADATA_RESIZE, "metadata_resize" },
{ 9, 11, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND, "external_origin_extend" },
+ { 1, 10, THIN_FEATURE_ERROR_IF_NO_SPACE, "error_if_no_space" },
};
static const char _lvmconf[] = "global/thin_disabled_features";
@@ -753,7 +761,8 @@ int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *segl
const char name[16];
uint32_t flags;
} reg_segtypes[] = {
- { &_thin_pool_ops, "thin-pool", SEG_THIN_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE },
+ { &_thin_pool_ops, "thin-pool", SEG_THIN_POOL | SEG_CANNOT_BE_ZEROED |
+ SEG_ONLY_EXCLUSIVE | SEG_CAN_ERROR_WHEN_FULL },
/* FIXME Maybe use SEG_THIN_VOLUME instead of SEG_VIRTUAL */
{ &_thin_ops, "thin", SEG_THIN_VOLUME | SEG_VIRTUAL | SEG_ONLY_EXCLUSIVE }
};
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 48adf22..b164b51 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -366,8 +366,12 @@ struct dm_status_thin_pool {
uint64_t used_data_blocks;
uint64_t total_data_blocks;
uint64_t held_metadata_root;
- uint32_t read_only;
+ uint32_t read_only; /* metadata may not be changed */
dm_thin_discards_t discards;
+ uint32_t fail : 1; /* all I/O fails */
+ uint32_t error_if_no_space : 1; /* otherwise queue_if_no_space */
+ uint32_t out_of_data_space : 1; /* metadata may be changed, but data may not be allocated */
+ uint32_t reserved : 29;
};
int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
@@ -886,7 +890,11 @@ int dm_tree_node_add_thin_pool_message(struct dm_tree_node *node,
int dm_tree_node_set_thin_pool_discard(struct dm_tree_node *node,
unsigned ignore,
unsigned no_passdown);
-
+/*
+ * Set error if no space, instead of queueing for thin pool.
+ */
+int dm_tree_node_set_thin_pool_error_if_no_space(struct dm_tree_node *node,
+ unsigned error_if_no_space);
/*
* FIXME: Defines bellow are based on kernel's dm-thin.c defines
* MAX_DEV_ID ((1 << 24) - 1)
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index c3a5df6..cd63061 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -204,6 +204,7 @@ struct load_segment {
unsigned skip_block_zeroing; /* Thin_pool */
unsigned ignore_discard; /* Thin_pool target vsn 1.1 */
unsigned no_discard_passdown; /* Thin_pool target vsn 1.1 */
+ unsigned error_if_no_space; /* Thin pool target vsn 1.10 */
uint32_t device_id; /* Thin */
};
@@ -2417,9 +2418,10 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
{
int pos = 0;
char pool[DM_FORMAT_DEV_BUFSIZE], metadata[DM_FORMAT_DEV_BUFSIZE];
- int features = (seg->skip_block_zeroing ? 1 : 0) +
- (seg->ignore_discard ? 1 : 0) +
- (seg->no_discard_passdown ? 1 : 0);
+ int features = (seg->error_if_no_space ? 1 : 0) +
+ (seg->ignore_discard ? 1 : 0) +
+ (seg->no_discard_passdown ? 1 : 0) +
+ (seg->skip_block_zeroing ? 1 : 0);
if (!_build_dev_string(metadata, sizeof(metadata), seg->metadata))
return_0;
@@ -2427,8 +2429,9 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
if (!_build_dev_string(pool, sizeof(pool), seg->pool))
return_0;
- EMIT_PARAMS(pos, "%s %s %d %" PRIu64 " %d%s%s%s", metadata, pool,
+ EMIT_PARAMS(pos, "%s %s %d %" PRIu64 " %d%s%s%s%s", metadata, pool,
seg->data_block_size, seg->low_water_mark, features,
+ seg->error_if_no_space ? " error_if_no_space" : "",
seg->skip_block_zeroing ? " skip_block_zeroing" : "",
seg->ignore_discard ? " ignore_discard" : "",
seg->no_discard_passdown ? " no_discard_passdown" : ""
@@ -3848,6 +3851,19 @@ int dm_tree_node_set_thin_pool_discard(struct dm_tree_node *node,
return 1;
}
+int dm_tree_node_set_thin_pool_error_if_no_space(struct dm_tree_node *node,
+ unsigned error_if_no_space)
+{
+ struct load_segment *seg;
+
+ if (!(seg = _get_single_load_segment(node, SEG_THIN_POOL)))
+ return_0;
+
+ seg->error_if_no_space = error_if_no_space;
+
+ return 1;
+}
+
int dm_tree_node_add_thin_target(struct dm_tree_node *node,
uint64_t size,
const char *pool_uuid,
@@ -3936,7 +3952,15 @@ int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
else /* default discard_passdown */
s->discards = DM_THIN_DISCARDS_PASSDOWN;
- s->read_only = (strstr(params + pos, "ro ")) ? 1 : 0;
+ if (strstr(params + pos, "ro "))
+ s->read_only = 1;
+ else if (strstr(params + pos, "fail"))
+ s->fail = 1;
+ else if (strstr(params + pos, "out_of_data_space"))
+ s->out_of_data_space = 1;
+
+ if (strstr(params + pos, "error_if_no_space"))
+ s->error_if_no_space = 1;
*status = s;
diff --git a/tools/args.h b/tools/args.h
index 1abe0eb..80e9155 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -39,6 +39,7 @@ arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE)
arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0)
arg(discards_ARG, '\0', "discards", discards_arg, 0)
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0)
+arg(errorwhenfull_ARG, '\0', "errorwhenfull", yes_no_arg, 0)
arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE)
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", NULL, 0)
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0)
diff --git a/tools/commands.h b/tools/commands.h
index 8b6b607..6eb8cc5 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -267,6 +267,7 @@ xx(lvcreate,
"\t[--commandprofile ProfileName]\n"
"\t[-d|--debug]\n"
"\t[-h|-?|--help]\n"
+ "\t[--errorwhenfull {y|n}]\n"
"\t[--ignoremonitoring]\n"
"\t[--monitor {y|n}]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
@@ -339,7 +340,7 @@ xx(lvcreate,
addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG,
cache_ARG, cachemode_ARG, cachepool_ARG, cachepolicy_ARG, cachesettings_ARG,
- chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG,
+ chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, errorwhenfull_ARG,
extents_ARG, ignoreactivationskip_ARG, ignoremonitoring_ARG, major_ARG,
metadataprofile_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG, monitor_ARG,
minrecoveryrate_ARG, maxrecoveryrate_ARG, name_ARG, nosync_ARG,
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 7236ffc..fd5ac39 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -582,6 +582,14 @@ static int _read_activation_params(struct cmd_context *cmd,
lp->activate = (activation_change_t)
arg_uint_value(cmd, activate_ARG, CHANGE_AY);
+ /* Error when full */
+ if (arg_is_set(cmd, errorwhenfull_ARG)) {
+ lp->error_when_full = arg_uint_value(cmd, errorwhenfull_ARG, 0);
+ } else
+ lp->error_when_full =
+ seg_can_error_when_full(lp) &&
+ find_config_tree_bool(cmd, activation_error_when_full_CFG, NULL);
+
/* Read ahead */
lp->read_ahead = arg_uint_value(cmd, readahead_ARG,
cmd->default_settings.read_ahead);
@@ -856,6 +864,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
SIZE_ARGS,
THIN_POOL_ARGS,
chunksize_ARG,
+ errorwhenfull_ARG,
snapshot_ARG,
thin_ARG,
virtualsize_ARG,
@@ -875,6 +884,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
SIZE_ARGS,
chunksize_ARG,
discards_ARG,
+ errorwhenfull_ARG,
zero_ARG,
-1))
return_0;
@@ -941,6 +951,11 @@ static int _lvcreate_params(struct cmd_context *cmd,
-1))
return_0;
+ if (!seg_can_error_when_full(lp) && arg_is_set(cmd, errorwhenfull_ARG)) {
+ log_error("Segment type %s does not support --errorwhenfull.", lp->segtype->name);
+ return 0;
+ }
+
/* Basic segment type validation finished here */
if (activation() && lp->segtype->ops->target_present) {
9 years, 3 months
master - cleanup: missed for build without devmapper
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=1e050a77ff333f...
Commit: 1e050a77ff333fd1849eb8068b6d22cb9411fc06
Parent: 0869631d7d197fec3ea909c243a5e1f2901bea5c
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 14 13:03:52 2015 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 14 14:50:08 2015 +0100
cleanup: missed for build without devmapper
configure --disable-devmapper build fixes.
---
lib/activate/activate.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 94ad9e2..ed41058 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -238,6 +238,22 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
{
return 0;
}
+int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
+ const struct lv_segment *lv_seg, int use_layer,
+ struct lv_with_info_and_seg_status *status,
+ int with_open_count, int with_read_ahead)
+{
+ return 0;
+}
+int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
+ struct lv_seg_status *lv_seg_status)
+{
+ return 0;
+}
+int lv_cache_status(const struct logical_volume *cache_lv,
+ struct lv_status_cache **status)
+{
+}
int lv_check_not_in_use(const struct logical_volume *lv)
{
return 0;
9 years, 3 months
master - lv_status: enable lv_status for thinpool
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0869631d7d197f...
Commit: 0869631d7d197fec3ea909c243a5e1f2901bea5c
Parent: 0b7ccf835bf90b6cb75cdeb6615163835a988107
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 14 12:51:03 2015 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 14 14:50:08 2015 +0100
lv_status: enable lv_status for thinpool
Support also status for thin pools.
---
lib/activate/dev_manager.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index c134e1b..f310a67 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -128,7 +128,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
* linear/striped, old snapshots and raids have proper
* segment selected for status!
*/
- if (strcmp(target_name, "cache"))
+ if (strcmp(target_name, "cache") && strcmp(target_name, "thin-pool"))
return 1;
if (!(segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, target_name)))
9 years, 3 months
master - lv_status: track layered device
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0b7ccf835bf90b...
Commit: 0b7ccf835bf90b6cb75cdeb6615163835a988107
Parent: d0f26440eed53fd34faf2773a9a7faf6deaf7d66
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 14 12:52:40 2015 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jan 14 14:50:08 2015 +0100
lv_status: track layered device
For info of i.e. thin-pool we need layered device.
Needs some more thinking about proper interface here.
For now it's usable for cache and thin-pool.
---
lib/activate/activate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index d1d1104..94ad9e2 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -705,7 +705,7 @@ int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
if (!activation())
return 0;
- return _lv_info(cmd, lv_seg->lv, 0, NULL, lv_seg, lv_seg_status, 0, 0);
+ return _lv_info(cmd, lv_seg->lv, 1, NULL, lv_seg, lv_seg_status, 0, 0);
}
/*
9 years, 3 months