Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=3584e0c0d5e5992a3c93e…
Commit: 3584e0c0d5e5992a3c93e03de8b6042de0853ef2
Parent: dd8d0837950ae72939b13c3a1eb4cff902bbccdd
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Mar 4 12:13:09 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Mar 4 12:13:09 2019 -0600
io: warn when metadata size approaches io memory size
When a single copy of metadata gets within 1MB of the
current io_memory_size value, begin printing a warning
that the io_memory_size should be increased.
---
lib/cache/lvmcache.c | 15 +++++++++++++++
lib/cache/lvmcache.h | 3 +++
lib/format_text/format-text.c | 4 ++++
lib/label/label.c | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 0ffa604..8aed59b 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -2286,6 +2286,21 @@ int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const ch
return 1;
}
+static uint64_t _max_metadata_size;
+
+void lvmcache_save_metadata_size(uint64_t val)
+{
+ if (!_max_metadata_size)
+ _max_metadata_size = val;
+ else if (_max_metadata_size < val)
+ _max_metadata_size = val;
+}
+
+uint64_t lvmcache_max_metadata_size(void)
+{
+ return _max_metadata_size;
+}
+
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid)
{
struct lvmcache_info *info;
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 12f17df..26e0953 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -210,6 +210,9 @@ struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted);
struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid);
void lvmcache_drop_saved_vgid(const char *vgid);
+uint64_t lvmcache_max_metadata_size(void);
+void lvmcache_save_metadata_size(uint64_t val);
+
int dev_in_device_list(struct device *dev, struct dm_list *head);
#endif
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 414941f..d976177 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1548,6 +1548,10 @@ int read_metadata_location_summary(const struct format_type *fmt,
*/
vgsummary->mda_checksum = rlocn->checksum;
vgsummary->mda_size = rlocn->size;
+
+ /* Keep track of largest metadata size we find. */
+ lvmcache_save_metadata_size(rlocn->size);
+
lvmcache_lookup_mda(vgsummary);
if (!text_read_metadata_summary(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
diff --git a/lib/label/label.c b/lib/label/label.c
index a877b38..174139e 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -23,6 +23,7 @@
#include "lib/commands/toolcontext.h"
#include "lib/activate/activate.h"
#include "lib/label/hints.h"
+#include "lib/metadata/metadata.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -31,6 +32,8 @@
/* FIXME Allow for larger labels? Restricted to single sector currently */
+static uint64_t _current_bcache_size_bytes;
+
/*
* Internal labeller struct.
*/
@@ -809,6 +812,8 @@ static int _setup_bcache(int num_devs)
if (cache_blocks > MAX_BCACHE_BLOCKS)
cache_blocks = MAX_BCACHE_BLOCKS;
+ _current_bcache_size_bytes = cache_blocks * BCACHE_BLOCK_SIZE_IN_SECTORS * 512;
+
if (use_aio()) {
if (!(ioe = create_async_io_engine())) {
log_warn("Failed to set up async io, using sync io.");
@@ -854,6 +859,7 @@ int label_scan(struct cmd_context *cmd)
struct dev_iter *iter;
struct device_list *devl, *devl2;
struct device *dev;
+ uint64_t max_metadata_size_bytes;
int newhints = 0;
log_debug_devs("Finding devices to scan");
@@ -934,6 +940,41 @@ int label_scan(struct cmd_context *cmd)
*/
_scan_list(cmd, cmd->filter, &scan_devs, NULL);
+ /*
+ * Metadata could be larger than total size of bcache, and bcache
+ * cannot currently be resized during the command. If this is the
+ * case (or within reach), warn that io_memory_size needs to be
+ * set larger.
+ *
+ * Even if bcache out of space did not cause a failure during scan, it
+ * may cause a failure during the next vg_read phase or during vg_write.
+ *
+ * If there was an error during scan, we could recreate bcache here
+ * with a larger size and then restart label_scan. But, this does not
+ * address the problem of writing new metadata that excedes the bcache
+ * size and failing, which would often be hit first, i.e. we'll fail
+ * to write new metadata exceding the max size before we have a chance
+ * to read any metadata with that size, unless we find an existing vg
+ * that has been previously created with the larger size.
+ *
+ * If the largest metadata is within 1MB of the bcache size, then start
+ * warning.
+ */
+ max_metadata_size_bytes = lvmcache_max_metadata_size();
+
+ if (max_metadata_size_bytes + (1024 * 1024) > _current_bcache_size_bytes) {
+ /* we want bcache to be 1MB larger than the max metadata seen */
+ uint64_t want_size_kb = (max_metadata_size_bytes / 1024) + 1024;
+ uint64_t remainder;
+ if ((remainder = (want_size_kb % 1024)))
+ want_size_kb = want_size_kb + 1024 - remainder;
+
+ log_warn("WARNING: metadata may not be usable with current io_memory_size %d KiB",
+ io_memory_size());
+ log_warn("WARNING: increase lvm.conf io_memory_size to at least %llu KiB",
+ (unsigned long long)want_size_kb);
+ }
+
dm_list_init(&cmd->hints);
if (!dm_list_empty(&hints)) {
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=dd8d0837950ae72939b13…
Commit: dd8d0837950ae72939b13c3a1eb4cff902bbccdd
Parent: 3ed9256985bd9fadcbbb8f419b8d44bf22e93ef2
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Mar 1 13:55:59 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Mar 4 11:36:21 2019 -0600
config: add new setting io_memory_size
which defines the amount of memory that lvm will allocate
for bcache. Increasing this setting is required if it is
smaller than a single copy of VG metadata.
---
lib/commands/toolcontext.c | 2 ++
lib/config/config_settings.h | 8 ++++++++
lib/config/defaults.h | 2 ++
lib/label/label.c | 40 ++++++++++++++++++++--------------------
lib/misc/lvm-globals.c | 10 ++++++++++
lib/misc/lvm-globals.h | 2 ++
6 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 0b88dca..15e3499 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -715,6 +715,8 @@ static int _process_config(struct cmd_context *cmd)
if (!_init_system_id(cmd))
return_0;
+ init_io_memory_size(find_config_tree_int(cmd, global_io_memory_size_CFG, NULL));
+
return 1;
}
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index fc66117..a2df3ce 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -1224,6 +1224,14 @@ cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, 0, CFG_TYPE_BOOL,
"When enabled, an LVM command that changes PVs, changes VG metadata,\n"
"or changes the activation state of an LV will send a notification.\n")
+cfg(global_io_memory_size_CFG, "io_memory_size", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_IO_MEMORY_SIZE_KB, vsn(2, 3, 2), NULL, 0, NULL,
+ "The amount of memory in KiB that LVM allocates to perform disk io.\n"
+ "LVM performance may benefit from more io memory when there are many\n"
+ "disks or VG metadata is large. Increasing this size may be necessary\n"
+ "when a single copy of VG metadata is larger than the current setting.\n"
+ "This value should usually not be decreased from the default; setting\n"
+ "it too low can result in lvm failing to read VGs.\n")
+
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
"The --nodevsync option overrides this setting.\n"
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index affb4c9..ee6ca3a 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -314,4 +314,6 @@
#define DEFAULT_HINTS "all"
+#define DEFAULT_IO_MEMORY_SIZE_KB 4096
+
#endif /* _LVM_DEFAULTS_H */
diff --git a/lib/label/label.c b/lib/label/label.c
index 7d5073e..a877b38 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -775,33 +775,33 @@ out:
}
/*
- * How many blocks to set up in bcache? Is 1024 a good max?
+ * num_devs is the number of devices the caller is going to scan.
+ * When 0 the caller doesn't know, and we use the default cache size.
+ * When non-zero, allocate at least num_devs bcache blocks.
+ * num_devs doesn't really tell us how many bcache blocks we'll use
+ * because it includes lvm devs and non-lvm devs, and each lvm dev
+ * will often use a number of bcache blocks.
*
- * Currently, we tell bcache to set up N blocks where N
- * is the number of devices that are going to be scanned.
- * Reasons why this number may not be be a good choice:
- *
- * - there may be a lot of non-lvm devices, which
- * would make this number larger than necessary
- *
- * - each lvm device may use more than one cache
- * block if the metadata is large enough or it
- * uses more than one metadata area, which
- * would make this number smaller than it
- * should be for the best performance.
- *
- * This is even more tricky to estimate when lvmetad
- * is used, because it's hard to predict how many
- * devs might need to be scanned when using lvmetad.
- * This currently just sets up bcache with MIN blocks.
+ * We don't know ahead of time if we will find some VG metadata
+ * that is larger than the total size of the bcache, which would
+ * prevent us from reading/writing the VG since we do not dynamically
+ * increase the bcache size when we find it's too small. In these
+ * cases the user would need to set io_memory_size to be larger
+ * than the max VG metadata size (lvm does not impose any limit on
+ * the metadata size.)
*/
-#define MIN_BCACHE_BLOCKS 32
+#define MIN_BCACHE_BLOCKS 32 /* 4MB, currently matches DEFAULT_IO_MEMORY_SIZE_KB */
#define MAX_BCACHE_BLOCKS 1024
-static int _setup_bcache(int cache_blocks)
+static int _setup_bcache(int num_devs)
{
struct io_engine *ioe = NULL;
+ int iomem_kb = io_memory_size();
+ int block_size_kb = (BCACHE_BLOCK_SIZE_IN_SECTORS * 512) / 1024;
+ int cache_blocks;
+
+ cache_blocks = iomem_kb / block_size_kb;
if (cache_blocks < MIN_BCACHE_BLOCKS)
cache_blocks = MIN_BCACHE_BLOCKS;
diff --git a/lib/misc/lvm-globals.c b/lib/misc/lvm-globals.c
index 1ddd2fb..6d3bf02 100644
--- a/lib/misc/lvm-globals.c
+++ b/lib/misc/lvm-globals.c
@@ -53,6 +53,7 @@ static int _activation_checks = 0;
static char _sysfs_dir_path[PATH_MAX] = "";
static uint64_t _pv_min_size = (DEFAULT_PV_MIN_SIZE_KB * 1024L >> SECTOR_SHIFT);
static const char *_unknown_device_name = DEFAULT_UNKNOWN_DEVICE_NAME;
+static int _io_memory_size_kb = DEFAULT_IO_MEMORY_SIZE_KB;
void init_verbose(int level)
{
@@ -393,3 +394,12 @@ void init_unknown_device_name(const char *name)
_unknown_device_name = name;
}
+int io_memory_size(void)
+{
+ return _io_memory_size_kb;
+}
+
+void init_io_memory_size(int val)
+{
+ _io_memory_size_kb = val;
+}
diff --git a/lib/misc/lvm-globals.h b/lib/misc/lvm-globals.h
index c69b99a..944b822 100644
--- a/lib/misc/lvm-globals.h
+++ b/lib/misc/lvm-globals.h
@@ -51,6 +51,7 @@ void init_pv_min_size(uint64_t sectors);
void init_activation_checks(int checks);
void init_retry_deactivation(int retry);
void init_unknown_device_name(const char *name);
+void init_io_memory_size(int val);
void set_cmd_name(const char *cmd_name);
const char *get_cmd_name(void);
@@ -83,6 +84,7 @@ uint64_t pv_min_size(void);
int activation_checks(void);
int retry_deactivation(void);
const char *unknown_device_name(void);
+int io_memory_size(void);
#define DMEVENTD_MONITOR_IGNORE -1
int dmeventd_monitor_mode(void);
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=590a1ebcf78b8aae2a1e5…
Commit: 590a1ebcf78b8aae2a1e5ebaba1ac24a54435690
Parent: 863a2e693ee95b95463d60fa8b21f4c7c084292c
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Mar 4 11:18:34 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Mar 4 11:18:34 2019 -0600
io: increase the default io memory from 4 to 8 MiB
This is the default bcache size that is created at the
start of the command. It needs to be large enough to
hold a single copy of metadata for a given VG, or the
VG cannot be read or written (since the entire VG would
not fit into available memory.)
Increasing the default reduces the chances of anyone
needing to increase the default to use their VG.
The size can be set in lvm.conf global/io_memory_size;
the lower limit is 4 MiB and the upper limit is 128 MiB.
---
lib/config/defaults.h | 2 +-
lib/label/label.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 3b4438a..9e398d7 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -269,6 +269,6 @@
#define DEFAULT_SCAN_LVS 0
-#define DEFAULT_IO_MEMORY_SIZE_KB 4096
+#define DEFAULT_IO_MEMORY_SIZE_KB 8192
#endif /* _LVM_DEFAULTS_H */
diff --git a/lib/label/label.c b/lib/label/label.c
index e96a7fe..4f8e135 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -791,7 +791,7 @@ out:
* the metadata size.)
*/
-#define MIN_BCACHE_BLOCKS 32 /* 4MB, currently matches DEFAULT_IO_MEMORY_SIZE_KB */
+#define MIN_BCACHE_BLOCKS 32 /* 4MB */
#define MAX_BCACHE_BLOCKS 1024
static int _setup_bcache(int num_devs)
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=863a2e693ee95b95463d6…
Commit: 863a2e693ee95b95463d60fa8b21f4c7c084292c
Parent: 8dbfdb5b737cf916a8b95b8d19eec67a960a6392
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Mar 4 10:57:52 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Mar 4 10:57:52 2019 -0600
io: warn when metadata size approaches io memory size
When a single copy of metadata gets within 1MB of the
current io_memory_size value, begin printing a warning
that the io_memory_size should be increased.
---
lib/cache/lvmcache.c | 15 +++++++++++++++
lib/cache/lvmcache.h | 3 +++
lib/format_text/format-text.c | 4 ++++
lib/label/label.c | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index a2ee0cd..ad40d4c 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -3044,3 +3044,18 @@ int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const ch
return 1;
}
+static uint64_t _max_metadata_size;
+
+void lvmcache_save_metadata_size(uint64_t val)
+{
+ if (!_max_metadata_size)
+ _max_metadata_size = val;
+ else if (_max_metadata_size < val)
+ _max_metadata_size = val;
+}
+
+uint64_t lvmcache_max_metadata_size(void)
+{
+ return _max_metadata_size;
+}
+
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index bf976e9..f436785 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -225,4 +225,7 @@ struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted);
struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid);
void lvmcache_drop_saved_vgid(const char *vgid);
+uint64_t lvmcache_max_metadata_size(void);
+void lvmcache_save_metadata_size(uint64_t val);
+
#endif
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 4160ba8..b9d85a4 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1294,6 +1294,10 @@ int read_metadata_location_summary(const struct format_type *fmt,
*/
vgsummary->mda_checksum = rlocn->checksum;
vgsummary->mda_size = rlocn->size;
+
+ /* Keep track of largest metadata size we find. */
+ lvmcache_save_metadata_size(rlocn->size);
+
lvmcache_lookup_mda(vgsummary);
if (!text_read_metadata_summary(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
diff --git a/lib/label/label.c b/lib/label/label.c
index b94fd8d..e96a7fe 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -21,6 +21,7 @@
#include "bcache.h"
#include "toolcontext.h"
#include "activate.h"
+#include "metadata.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -29,6 +30,8 @@
int use_full_md_check;
+static uint64_t _current_bcache_size_bytes;
+
/* FIXME Allow for larger labels? Restricted to single sector currently */
/*
@@ -806,6 +809,8 @@ static int _setup_bcache(int num_devs)
if (cache_blocks > MAX_BCACHE_BLOCKS)
cache_blocks = MAX_BCACHE_BLOCKS;
+ _current_bcache_size_bytes = cache_blocks * BCACHE_BLOCK_SIZE_IN_SECTORS * 512;
+
if (use_aio()) {
if (!(ioe = create_async_io_engine())) {
log_warn("Failed to set up async io, using sync io.");
@@ -839,6 +844,7 @@ int label_scan(struct cmd_context *cmd)
struct dev_iter *iter;
struct device_list *devl, *devl2;
struct device *dev;
+ uint64_t max_metadata_size_bytes;
log_debug_devs("Finding devices to scan");
@@ -909,6 +915,41 @@ int label_scan(struct cmd_context *cmd)
_scan_list(cmd, cmd->full_filter, &all_devs, NULL);
+ /*
+ * Metadata could be larger than total size of bcache, and bcache
+ * cannot currently be resized during the command. If this is the
+ * case (or within reach), warn that io_memory_size needs to be
+ * set larger.
+ *
+ * Even if bcache out of space did not cause a failure during scan, it
+ * may cause a failure during the next vg_read phase or during vg_write.
+ *
+ * If there was an error during scan, we could recreate bcache here
+ * with a larger size and then restart label_scan. But, this does not
+ * address the problem of writing new metadata that excedes the bcache
+ * size and failing, which would often be hit first, i.e. we'll fail
+ * to write new metadata exceding the max size before we have a chance
+ * to read any metadata with that size, unless we find an existing vg
+ * that has been previously created with the larger size.
+ *
+ * If the largest metadata is within 1MB of the bcache size, then start
+ * warning.
+ */
+ max_metadata_size_bytes = lvmcache_max_metadata_size();
+
+ if (max_metadata_size_bytes + (1024 * 1024) > _current_bcache_size_bytes) {
+ /* we want bcache to be 1MB larger than the max metadata seen */
+ uint64_t want_size_kb = (max_metadata_size_bytes / 1024) + 1024;
+ uint64_t remainder;
+ if ((remainder = (want_size_kb % 1024)))
+ want_size_kb = want_size_kb + 1024 - remainder;
+
+ log_warn("WARNING: metadata may not be usable with current io_memory_size %d KiB",
+ io_memory_size());
+ log_warn("WARNING: increase lvm.conf io_memory_size to at least %llu KiB",
+ (unsigned long long)want_size_kb);
+ }
+
dm_list_iterate_items_safe(devl, devl2, &all_devs) {
dm_list_del(&devl->list);
dm_free(devl);
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8dbfdb5b737cf916a8b95…
Commit: 8dbfdb5b737cf916a8b95b8d19eec67a960a6392
Parent: 675b94a11b6e76b241bf84db2c4e318a9658c394
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Mar 1 13:55:59 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Mar 4 10:31:47 2019 -0600
config: add new setting io_memory_size
which defines the amount of memory that lvm will allocate
for bcache. Increasing this setting is required if it is
smaller than a single copy of VG metadata.
---
lib/commands/toolcontext.c | 2 ++
lib/config/config_settings.h | 8 ++++++++
lib/config/defaults.h | 2 ++
lib/label/label.c | 40 ++++++++++++++++++++--------------------
lib/misc/lvm-globals.c | 10 ++++++++++
lib/misc/lvm-globals.h | 3 +++
6 files changed, 45 insertions(+), 20 deletions(-)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 3289b38..25e8b87 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -685,6 +685,8 @@ static int _process_config(struct cmd_context *cmd)
if (!_init_system_id(cmd))
return_0;
+ init_io_memory_size(find_config_tree_int(cmd, global_io_memory_size_CFG, NULL));
+
return 1;
}
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index 8fe7ec9..75321da 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -1129,6 +1129,14 @@ cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, 0, CFG_TYPE_BOOL,
"When enabled, an LVM command that changes PVs, changes VG metadata,\n"
"or changes the activation state of an LV will send a notification.\n")
+cfg(global_io_memory_size_CFG, "io_memory_size", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_IO_MEMORY_SIZE_KB, vsn(2, 2, 184), NULL, 0, NULL,
+ "The amount of memory in KiB that LVM allocates to perform disk io.\n"
+ "LVM performance may benefit from more io memory when there are many\n"
+ "disks or VG metadata is large. Increasing this size may be necessary\n"
+ "when a single copy of VG metadata is larger than the current setting.\n"
+ "This value should usually not be decreased from the default; setting\n"
+ "it too low can result in lvm failing to read VGs.\n")
+
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
"The --nodevsync option overrides this setting.\n"
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 7a5d365..3b4438a 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -269,4 +269,6 @@
#define DEFAULT_SCAN_LVS 0
+#define DEFAULT_IO_MEMORY_SIZE_KB 4096
+
#endif /* _LVM_DEFAULTS_H */
diff --git a/lib/label/label.c b/lib/label/label.c
index e01608d..b94fd8d 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -772,33 +772,33 @@ out:
}
/*
- * How many blocks to set up in bcache? Is 1024 a good max?
+ * num_devs is the number of devices the caller is going to scan.
+ * When 0 the caller doesn't know, and we use the default cache size.
+ * When non-zero, allocate at least num_devs bcache blocks.
+ * num_devs doesn't really tell us how many bcache blocks we'll use
+ * because it includes lvm devs and non-lvm devs, and each lvm dev
+ * will often use a number of bcache blocks.
*
- * Currently, we tell bcache to set up N blocks where N
- * is the number of devices that are going to be scanned.
- * Reasons why this number may not be be a good choice:
- *
- * - there may be a lot of non-lvm devices, which
- * would make this number larger than necessary
- *
- * - each lvm device may use more than one cache
- * block if the metadata is large enough or it
- * uses more than one metadata area, which
- * would make this number smaller than it
- * should be for the best performance.
- *
- * This is even more tricky to estimate when lvmetad
- * is used, because it's hard to predict how many
- * devs might need to be scanned when using lvmetad.
- * This currently just sets up bcache with MIN blocks.
+ * We don't know ahead of time if we will find some VG metadata
+ * that is larger than the total size of the bcache, which would
+ * prevent us from reading/writing the VG since we do not dynamically
+ * increase the bcache size when we find it's too small. In these
+ * cases the user would need to set io_memory_size to be larger
+ * than the max VG metadata size (lvm does not impose any limit on
+ * the metadata size.)
*/
-#define MIN_BCACHE_BLOCKS 32
+#define MIN_BCACHE_BLOCKS 32 /* 4MB, currently matches DEFAULT_IO_MEMORY_SIZE_KB */
#define MAX_BCACHE_BLOCKS 1024
-static int _setup_bcache(int cache_blocks)
+static int _setup_bcache(int num_devs)
{
struct io_engine *ioe = NULL;
+ int iomem_kb = io_memory_size();
+ int block_size_kb = (BCACHE_BLOCK_SIZE_IN_SECTORS * 512) / 1024;
+ int cache_blocks;
+
+ cache_blocks = iomem_kb / block_size_kb;
if (cache_blocks < MIN_BCACHE_BLOCKS)
cache_blocks = MIN_BCACHE_BLOCKS;
diff --git a/lib/misc/lvm-globals.c b/lib/misc/lvm-globals.c
index 82c5706..3bd5cac 100644
--- a/lib/misc/lvm-globals.c
+++ b/lib/misc/lvm-globals.c
@@ -54,6 +54,7 @@ static char _sysfs_dir_path[PATH_MAX] = "";
static int _dev_disable_after_error_count = DEFAULT_DISABLE_AFTER_ERROR_COUNT;
static uint64_t _pv_min_size = (DEFAULT_PV_MIN_SIZE_KB * 1024L >> SECTOR_SHIFT);
static const char *_unknown_device_name = DEFAULT_UNKNOWN_DEVICE_NAME;
+static int _io_memory_size_kb = DEFAULT_IO_MEMORY_SIZE_KB;
void init_verbose(int level)
{
@@ -387,3 +388,12 @@ void init_unknown_device_name(const char *name)
_unknown_device_name = name;
}
+int io_memory_size(void)
+{
+ return _io_memory_size_kb;
+}
+
+void init_io_memory_size(int val)
+{
+ _io_memory_size_kb = val;
+}
diff --git a/lib/misc/lvm-globals.h b/lib/misc/lvm-globals.h
index f985cfa..3007cc5 100644
--- a/lib/misc/lvm-globals.h
+++ b/lib/misc/lvm-globals.h
@@ -53,6 +53,7 @@ void init_pv_min_size(uint64_t sectors);
void init_activation_checks(int checks);
void init_retry_deactivation(int retry);
void init_unknown_device_name(const char *name);
+void init_io_memory_size(int val);
void set_cmd_name(const char *cmd_name);
const char *get_cmd_name(void);
@@ -86,6 +87,7 @@ uint64_t pv_min_size(void);
int activation_checks(void);
int retry_deactivation(void);
const char *unknown_device_name(void);
+int io_memory_size(void);
#define DMEVENTD_MONITOR_IGNORE -1
int dmeventd_monitor_mode(void);
@@ -93,4 +95,5 @@ int dmeventd_monitor_mode(void);
#define NO_DEV_ERROR_COUNT_LIMIT 0
int dev_disable_after_error_count(void);
+
#endif