1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

writecache: attach while active using fs block size

Use libblkid to detect sector/block size of the fs on the LV.
Use this to choose a compatible writecache block size.
Enable attaching writecache to an active LV.
This commit is contained in:
David Teigland 2020-03-30 16:25:15 -05:00
parent 1ee42f1391
commit d15c466f95

View File

@ -5433,7 +5433,166 @@ static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
return lv_wcorig;
}
#define DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS 8 /* 4K */
/*
* Currently only supports writecache block sizes 512 and 4096.
* This could be expanded later.
*/
static int _set_writecache_block_size(struct cmd_context *cmd,
struct logical_volume *lv,
uint32_t *block_size_sectors)
{
char pathname[PATH_MAX];
struct device *fs_dev;
struct dm_list pvs;
struct pv_list *pvl;
uint32_t fs_block_size = 0;
uint32_t block_size_setting = 0;
uint32_t block_size = 0;
int lbs_unknown = 0, lbs_4k = 0, lbs_512 = 0;
int pbs_unknown = 0, pbs_4k = 0, pbs_512 = 0;
int rv;
/* This is set if the user specified a writecache block size on the command line. */
if (*block_size_sectors)
block_size_setting = *block_size_sectors * 512;
dm_list_init(&pvs);
if (!get_pv_list_for_lv(cmd->mem, lv, &pvs)) {
log_error("Failed to build list of PVs for %s.", display_lvname(lv));
goto_bad;
}
dm_list_iterate_items(pvl, &pvs) {
unsigned int pbs = 0;
unsigned int lbs = 0;
if (!dev_get_direct_block_sizes(pvl->pv->dev, &pbs, &lbs)) {
lbs_unknown++;
pbs_unknown++;
continue;
}
if (lbs == 4096)
lbs_4k++;
else if (lbs == 512)
lbs_512++;
else
lbs_unknown++;
if (pbs == 4096)
pbs_4k++;
else if (pbs == 512)
pbs_512++;
else
pbs_unknown++;
}
if (lbs_4k && lbs_512) {
log_error("Writecache requires consistent logical block size for LV devices.");
goto_bad;
}
if (lbs_4k && block_size_setting && (block_size_setting < 4096)) {
log_error("Writecache block size %u not allowed with device logical block size 4096.",
block_size_setting);
goto_bad;
}
if (dm_snprintf(pathname, sizeof(pathname), "%s%s/%s", cmd->dev_dir,
lv->vg->name, lv->name) < 0) {
log_error("Path name too long to get LV block size %s", display_lvname(lv));
goto_bad;
}
if (!(fs_dev = dev_cache_get(cmd, pathname, NULL))) {
log_error("Device for LV not found to check block size %s", display_lvname(lv));
goto_bad;
}
/*
* get_fs_block_size() returns the libblkid BLOCK_SIZE value,
* where libblkid has fs-specific code to set BLOCK_SIZE to the
* value we need here.
*
* The term "block size" here may not equate directly to what the fs
* calls the block size, e.g. xfs calls this the sector size (and
* something different the block size); while ext4 does call this
* value the block size, but it's possible values are not the same
* as xfs's, and do not seem to relate directly to the device LBS.
*
* With 512 LBS and 4K PBS, mkfs.xfs will use xfs sector size 4K.
*/
rv = get_fs_block_size(fs_dev, &fs_block_size);
if (!rv || !fs_block_size) {
if (lbs_4k && pbs_4k && !pbs_512) {
block_size = 4096;
} else if (lbs_512 && pbs_512 && !pbs_4k) {
block_size = 512;
} else if (lbs_512 && pbs_4k) {
if (block_size_setting == 4096)
block_size = 4096;
else
block_size = 512;
} else {
block_size = 512;
}
if (block_size_setting && (block_size_setting != block_size)) {
log_error("Cannot use writecache block size %u with unknown file system block size, logical block size %u, physical block size %u.",
block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
goto bad;
}
if (block_size != 512) {
log_warn("WARNING: unable to detect a file system block size on %s", display_lvname(lv));
log_warn("WARNING: using a writecache block size larger than the file system block size may corrupt the file system.");
if (!arg_is_set(cmd, yes_ARG) &&
yes_no_prompt("Use writecache block size %u? [y/n]: ", block_size) == 'n') {
log_error("Conversion aborted.");
goto bad;
}
}
log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
goto out;
}
if (!block_size_setting) {
/* User did not specify a block size, so choose according to fs block size. */
if (fs_block_size == 4096)
block_size = 4096;
else if (fs_block_size == 512)
block_size = 512;
else if (fs_block_size > 4096)
block_size = 4096;
else if (fs_block_size < 4096)
block_size = 512;
else
goto_bad;
} else {
if (block_size_setting <= fs_block_size)
block_size = block_size_setting;
else {
log_error("Writecache block size %u cannot be larger than file system block size %u.",
block_size_setting, fs_block_size);
goto_bad;
}
}
out:
if (block_size == 512)
*block_size_sectors = 1;
else if (block_size == 4096)
*block_size_sectors = 8;
else
goto_bad;
return 1;
bad:
return 0;
}
static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
@ -5444,7 +5603,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv_fast;
struct writecache_settings settings;
const char *fast_name;
uint32_t block_size_sectors;
uint32_t block_size_sectors = 0;
char *lockd_fast_args = NULL;
char *lockd_fast_name = NULL;
struct id lockd_fast_id;
@ -5472,16 +5631,6 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
goto bad;
}
/*
* To permit this we need to check the block size of the fs using lv
* (recently in libblkid) so that we can use a matching writecache
* block size. We also want to do that if the lv is inactive.
*/
if (lv_is_active(lv)) {
log_error("LV %s must be inactive to attach writecache.", display_lvname(lv));
goto bad;
}
/* fast LV shouldn't generally be active by itself, but just in case. */
if (lv_info(cmd, lv_fast, 1, NULL, 0, 0)) {
log_error("LV %s must be inactive to attach.", display_lvname(lv_fast));
@ -5489,13 +5638,15 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
}
memset(&settings, 0, sizeof(settings));
block_size_sectors = DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS;
if (!get_writecache_settings(cmd, &settings, &block_size_sectors)) {
log_error("Invalid writecache settings.");
goto bad;
}
if (!_set_writecache_block_size(cmd, lv, &block_size_sectors))
goto_bad;
if (!arg_is_set(cmd, yes_ARG) &&
yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
log_error("Conversion aborted.");