diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h index 488752c8f..655d9f297 100644 --- a/lib/commands/toolcontext.h +++ b/lib/commands/toolcontext.h @@ -153,6 +153,7 @@ struct cmd_context { unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */ unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */ unsigned vg_read_print_access_error:1; /* print access errors from vg_read */ + unsigned allow_mixed_block_sizes:1; unsigned force_access_clustered:1; unsigned lockd_gl_disable:1; unsigned lockd_vg_disable:1; diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h index 527d5bd07..edfe4a31a 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h @@ -502,6 +502,11 @@ cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_ "Enabling this setting allows the VG to be used as usual even with\n" "uncertain devices.\n") +cfg(devices_allow_mixed_block_sizes_CFG, "allow_mixed_block_sizes", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 3, 6), NULL, 0, NULL, + "Allow PVs in the same VG with different logical block sizes.\n" + "When allowed, the user is responsible to ensure that an LV is\n" + "using PVs with matching block sizes when necessary.\n") + cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 77), NULL, 0, NULL, "Advise LVM which PVs to use when searching for new space.\n" "When searching for free space to extend an LV, the 'cling' allocation\n" diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index f18587a73..e1767b78d 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -623,6 +623,7 @@ struct pvcreate_params { unsigned is_remove : 1; /* is removing PVs, not creating */ unsigned preserve_existing : 1; unsigned check_failed : 1; + unsigned check_consistent_block_size : 1; }; struct lvresize_params { diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index f19df3d1d..e55adc212 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -751,12 +751,40 @@ int vg_extend_each_pv(struct volume_group *vg, struct pvcreate_params *pp) { struct pv_list *pvl; unsigned int max_phys_block_size = 0; + unsigned int physical_block_size, logical_block_size; + unsigned int prev_lbs = 0; + int inconsistent_existing_lbs = 0; log_debug_metadata("Adding PVs to VG %s.", vg->name); if (vg_bad_status_bits(vg, RESIZEABLE_VG)) return_0; + /* + * Check if existing PVs have inconsistent block sizes. + * If so, do not enforce new devices to be consistent. + */ + dm_list_iterate_items(pvl, &vg->pvs) { + logical_block_size = 0; + physical_block_size = 0; + + if (!dev_get_direct_block_sizes(pvl->pv->dev, &physical_block_size, &logical_block_size)) + continue; + + if (!logical_block_size) + continue; + + if (!prev_lbs) { + prev_lbs = logical_block_size; + continue; + } + + if (prev_lbs != logical_block_size) { + inconsistent_existing_lbs = 1; + break; + } + } + dm_list_iterate_items(pvl, &pp->pvs) { log_debug_metadata("Adding PV %s to VG %s.", pv_dev_name(pvl->pv), vg->name); @@ -767,6 +795,22 @@ int vg_extend_each_pv(struct volume_group *vg, struct pvcreate_params *pp) return 0; } + logical_block_size = 0; + physical_block_size = 0; + + if (!dev_get_direct_block_sizes(pvl->pv->dev, &physical_block_size, &logical_block_size)) + log_warn("WARNING: PV %s has unknown block size.", pv_dev_name(pvl->pv)); + + else if (prev_lbs && logical_block_size && (logical_block_size != prev_lbs)) { + if (vg->cmd->allow_mixed_block_sizes || inconsistent_existing_lbs) + log_debug("Devices have inconsistent block sizes (%u and %u)", prev_lbs, logical_block_size); + else { + log_error("Devices have inconsistent logical block sizes (%u and %u).", + prev_lbs, logical_block_size); + return 0; + } + } + if (!add_pv_to_vg(vg, pv_dev_name(pvl->pv), pvl->pv, 0)) { log_error("PV %s cannot be added to VG %s.", pv_dev_name(pvl->pv), vg->name); diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 30f9d8133..7d29b6fab 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -2319,6 +2319,8 @@ static int _get_current_settings(struct cmd_context *cmd) cmd->scan_lvs = find_config_tree_bool(cmd, devices_scan_lvs_CFG, NULL); + cmd->allow_mixed_block_sizes = find_config_tree_bool(cmd, devices_allow_mixed_block_sizes_CFG, NULL); + /* * enable_hints is set to 1 if any commands are using hints. * use_hints is set to 1 if this command doesn't use the hints. diff --git a/tools/toollib.c b/tools/toollib.c index b2313f8ff..155528c4e 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -5355,6 +5355,8 @@ int pvcreate_each_device(struct cmd_context *cmd, struct pv_list *vgpvl; struct device_list *devl; const char *pv_name; + unsigned int physical_block_size, logical_block_size; + unsigned int prev_pbs = 0, prev_lbs = 0; int must_use_all = (cmd->cname->flags & MUST_USE_ALL_ARGS); int found; unsigned i; @@ -5394,6 +5396,51 @@ int pvcreate_each_device(struct cmd_context *cmd, dm_list_iterate_items(pd, &pp->arg_devices) pd->dev = dev_cache_get(cmd, pd->name, cmd->filter); + /* + * Check for consistent block sizes. + */ + if (pp->check_consistent_block_size) { + dm_list_iterate_items(pd, &pp->arg_devices) { + if (!pd->dev) + continue; + + logical_block_size = 0; + physical_block_size = 0; + + if (!dev_get_direct_block_sizes(pd->dev, &physical_block_size, &logical_block_size)) { + log_warn("WARNING: Unknown block size for device %s.", dev_name(pd->dev)); + continue; + } + + if (!logical_block_size) { + log_warn("WARNING: Unknown logical_block_size for device %s.", dev_name(pd->dev)); + continue; + } + + if (!prev_lbs) { + prev_lbs = logical_block_size; + prev_pbs = physical_block_size; + continue; + } + + if (prev_lbs == logical_block_size) { + /* Require lbs to match, just warn about unmatching pbs. */ + if (!cmd->allow_mixed_block_sizes && prev_pbs && physical_block_size && + (prev_pbs != physical_block_size)) + log_warn("WARNING: Devices have inconsistent physical block sizes (%u and %u).", + prev_pbs, physical_block_size); + continue; + } + + if (!cmd->allow_mixed_block_sizes) { + log_error("Devices have inconsistent logical block sizes (%u and %u).", + prev_lbs, logical_block_size); + log_print("See lvm.conf allow_mixed_block_sizes."); + return 0; + } + } + } + /* * Use process_each_pv to search all existing PVs and devices. * diff --git a/tools/vgcreate.c b/tools/vgcreate.c index d594ec110..09b6a6c95 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -47,6 +47,8 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) /* Don't create a new PV on top of an existing PV like pvcreate does. */ pp.preserve_existing = 1; + pp.check_consistent_block_size = 1; + if (!vgcreate_params_set_defaults(cmd, &vp_def, NULL)) return EINVALID_CMD_LINE; vp_def.vg_name = vg_name;