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

lvresize: restructure code

Rewrite top level resize function to prepare for adding
new fs resizing.
This commit is contained in:
David Teigland 2022-09-09 16:07:07 -05:00
parent 55e9494e5f
commit 18722dfdf4
15 changed files with 920 additions and 588 deletions

19
lib/commands/cmd_enum.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _CMD_ENUM_H
#define _CMD_ENUM_H
/*
* tools/cmds.h is generated by the Makefile. For each command definition
* in command-lines.in, cmds.h contains:
* cmd(foo_CMD, foo)
*
* This header adds each of the foo_CMD's into an enum, so there's
* a unique integer identifier for each command definition.
*/
enum {
#define cmd(a, b) a ,
#include "../tools/cmds.h"
#undef cmd
};
#endif

View File

@ -18,6 +18,7 @@
#include "lib/device/dev-cache.h" #include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h" #include "lib/device/dev-type.h"
#include "lib/commands/cmd_enum.h"
#include <limits.h> #include <limits.h>
@ -94,6 +95,7 @@ struct cmd_context {
const char *name; /* needed before cmd->command is set */ const char *name; /* needed before cmd->command is set */
struct command_name *cname; struct command_name *cname;
struct command *command; struct command *command;
int command_enum; /* duplicate from command->command_enum for lib code */
char **argv; char **argv;
struct arg_values *opt_arg_values; struct arg_values *opt_arg_values;
struct dm_list arg_value_groups; struct dm_list arg_value_groups;

View File

@ -577,8 +577,9 @@ static int _extend_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg,
(uint32_t)(new_size_sectors * SECTOR_SIZE)); (uint32_t)(new_size_sectors * SECTOR_SIZE));
lp.size = new_size_sectors; lp.size = new_size_sectors;
lp.pvh = &vg->pvs;
if (!lv_resize(lv, &lp, &vg->pvs)) { if (!lv_resize(cmd, lv, &lp)) {
log_error("Extend sanlock LV %s to size %s failed.", log_error("Extend sanlock LV %s to size %s failed.",
display_lvname(lv), display_size(cmd, lp.size)); display_lvname(lv), display_size(cmd, lp.size));
return 0; return 0;
@ -2733,6 +2734,9 @@ int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
if (!_lvmlockd_connected) if (!_lvmlockd_connected)
return 0; return 0;
if (lv_is_lockd_sanlock_lv(lv))
return 1;
/* /*
* A special case for gfs2 where we want to allow lvextend * A special case for gfs2 where we want to allow lvextend
* of an LV that has an existing shared lock, which is normally * of an LV that has an existing shared lock, which is normally

File diff suppressed because it is too large Load Diff

View File

@ -297,6 +297,9 @@
int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv, int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
struct dm_list **layout, struct dm_list **role); struct dm_list **layout, struct dm_list **role);
int lv_is_linear(struct logical_volume *lv);
int lv_is_striped(struct logical_volume *lv);
/* Ordered list - see lv_manip.c */ /* Ordered list - see lv_manip.c */
typedef enum { typedef enum {
AREA_UNASSIGNED, AREA_UNASSIGNED,
@ -661,42 +664,33 @@ struct pvcreate_params {
}; };
struct lvresize_params { struct lvresize_params {
int argc;
char **argv;
const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
const char *lv_name;
const struct segment_type *segtype;
uint64_t poolmetadata_size;
sign_t poolmetadata_sign;
/* Per LV applied parameters */
enum { enum {
LV_ANY = 0, LV_ANY = 0,
LV_REDUCE = 1, LV_REDUCE = 1,
LV_EXTEND = 2 LV_EXTEND = 2
} resize; } resize;
int use_policies;
alloc_policy_t alloc; alloc_policy_t alloc;
int yes; int yes;
int force; int force;
int nosync; int nosync;
int nofsck; int nofsck;
int resizefs; int resizefs;
int use_policies;
const struct segment_type *segtype;
unsigned mirrors; unsigned mirrors;
uint32_t stripes; uint32_t stripes;
uint64_t stripe_size; uint64_t stripe_size;
uint32_t extents;
uint64_t size; uint64_t size;
uint32_t extents;
sign_t sign; sign_t sign;
percent_type_t percent; percent_type_t percent; /* the type of percentage, not a value */
uint32_t percent_value; /* 0 - 100 */
uint64_t poolmetadata_size;
sign_t poolmetadata_sign;
uint32_t policy_percent_main;
uint32_t policy_percent_meta;
int approx_alloc; int approx_alloc;
int extents_are_pes; /* Is 'extents' counting PEs or LEs? */ int extents_are_pes; /* Is 'extents' counting PEs or LEs? */
@ -705,6 +699,8 @@ struct lvresize_params {
const char *lockopt; const char *lockopt;
char *lockd_lv_refresh_path; /* set during resize to use for refresh at the end */ char *lockd_lv_refresh_path; /* set during resize to use for refresh at the end */
char *lockd_lv_refresh_uuid; /* set during resize to use for refresh at the end */ char *lockd_lv_refresh_uuid; /* set during resize to use for refresh at the end */
struct dm_list *pvh; /* list of pvs to use */
}; };
void pvcreate_params_set_defaults(struct pvcreate_params *pp); void pvcreate_params_set_defaults(struct pvcreate_params *pp);
@ -745,9 +741,10 @@ int vgs_are_compatible(struct cmd_context *cmd,
struct volume_group *vg_to); struct volume_group *vg_to);
uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname); uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname);
int lv_resize(struct logical_volume *lv, int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
struct lvresize_params *lp, struct lvresize_params *lp);
struct dm_list *pvh); int lv_extend_policy_calculate_percent(struct logical_volume *lv,
uint32_t *amount, uint32_t *meta_amount);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const char *vgid, struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const char *vgid,
uint32_t read_flags, uint32_t lockd_state, uint32_t read_flags, uint32_t lockd_state,

View File

@ -5302,3 +5302,15 @@ int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, s
return 1; return 1;
} }
int lv_is_linear(struct logical_volume *lv)
{
struct lv_segment *seg = first_seg(lv);
return segtype_is_linear(seg->segtype);
}
int lv_is_striped(struct logical_volume *lv)
{
struct lv_segment *seg = first_seg(lv);
return segtype_is_striped(seg->segtype);
}

View File

@ -737,6 +737,7 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents,
extents = MAX_SIZE; extents = MAX_SIZE;
if (!lv) { if (!lv) {
log_debug("Adding new pool metadata spare %u extents.", extents);
if (!_alloc_pool_metadata_spare(vg, extents, pvh)) if (!_alloc_pool_metadata_spare(vg, extents, pvh))
return_0; return_0;
@ -746,6 +747,8 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents,
seg = last_seg(lv); seg = last_seg(lv);
seg_mirrors = lv_mirror_count(lv); seg_mirrors = lv_mirror_count(lv);
log_debug("Extending pool metadata spare from %u to %u extents.",
lv->le_count, extents);
/* Check spare LV is big enough and preserve segtype */ /* Check spare LV is big enough and preserve segtype */
if ((lv->le_count < extents) && seg && if ((lv->le_count < extents) && seg &&
!lv_extend(lv, seg->segtype, !lv_extend(lv, seg->segtype,

View File

@ -41,16 +41,15 @@ lvcreate -L2M -n $lv1 $vg
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1" "$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1 lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
# active thin pool is needed to use policy
not lvextend --use-policies $vg/pool 2>&1 | tee err
lvchange -ay $vg
# Cannot resize if set to 0% # Cannot resize if set to 0%
not lvextend --use-policies --config 'activation{thin_pool_autoextend_percent = 0}' $vg/pool 2>&1 | tee err not lvextend --use-policies --config 'activation{thin_pool_autoextend_percent = 0}' $vg/pool 2>&1 | tee err
grep "0%" err grep "0%" err
# Locally active LV is needed
not lvextend --use-policies $vg/pool 2>&1 | tee err
grep "locally" err
lvchange -ay $vg
# Creation of new LV is not allowed when thinpool is over threshold # Creation of new LV is not allowed when thinpool is over threshold
not lvcreate -V10 $vg/pool not lvcreate -V10 $vg/pool

View File

@ -37,15 +37,19 @@ lvs -a $vg
"$MKFS" "$lvdev" "$MKFS" "$lvdev"
# this should resolve to resize to same actual size # this should resolve to resize to same actual size
lvreduce -r -f -l-100%FREE $vg/$lv1 not lvreduce -l-100%FREE $vg/$lv1
not lvreduce -r -f -l-100%FREE $vg/$lv1
"$FSCK" -n "$lvdev" "$FSCK" -n "$lvdev"
# size should remain the same # size should remain the same
lvextend -r -f -l+100%FREE $vg/$lv1 # lvresize fails with same result with or without -r
not lvextend -l+100%FREE $vg/$lv1
not lvextend -r -f -l+100%FREE $vg/$lv1
"$FSCK" -n "$lvdev" "$FSCK" -n "$lvdev"
#lvchange -an $vg/$lv1 #lvchange -an $vg/$lv1
lvresize -r -f -l+100%FREE $vg/$lv1 not lvresize -l+100%FREE $vg/$lv1
not lvresize -r -f -l+100%FREE $vg/$lv1
"$FSCK" -n "$lvdev" "$FSCK" -n "$lvdev"
# Check there is really file system resize happening # Check there is really file system resize happening
@ -55,7 +59,8 @@ lvresize -r -f -l+100%FREE $vg/$lv1
grep "20000 blocks" out grep "20000 blocks" out
SIZE=$(get lv_field $vg/$lv1 size) SIZE=$(get lv_field $vg/$lv1 size)
lvresize -r -f -l-100%FREE $vg/$lv1 not lvresize -l-100%FREE $vg/$lv1
not lvresize -r -f -l-100%FREE $vg/$lv1
test "$SIZE" = "$(get lv_field $vg/$lv1 size)" test "$SIZE" = "$(get lv_field $vg/$lv1 size)"
"$FSCK" -n "$lvdev" | tee out "$FSCK" -n "$lvdev" | tee out

View File

@ -1382,7 +1382,7 @@ OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--stripes Number, --stripesize SizeKB, --poolmetadatasize PSizeMB, --stripes Number, --stripesize SizeKB, --poolmetadatasize PSizeMB,
--type SegType --type SegType
OP: PV ... OP: PV ...
ID: lvextend_by_size ID: lvextend_size
DESC: Extend an LV by a specified size. DESC: Extend an LV by a specified size.
lvextend LV PV ... lvextend LV PV ...
@ -1390,25 +1390,25 @@ OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--nofsck, --nosync, --noudevsync, --nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB, --reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB,
--type SegType --type SegType
ID: lvextend_by_pv ID: lvextend_pv
DESC: Extend an LV by specified PV extents. DESC: Extend an LV by specified PV extents.
lvextend --poolmetadatasize PSizeMB LV_thinpool lvextend --poolmetadatasize PSizeMB LV_thinpool_linear
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number, OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--nofsck, --nosync, --noudevsync, --nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --stripes Number, --stripesize SizeKB, --reportformat ReportFmt, --stripes Number, --stripesize SizeKB,
--type SegType --type SegType
OP: PV ... OP: PV ...
ID: lvextend_pool_metadata_by_size ID: lvextend_pool_metadata
DESC: Extend a pool metadata SubLV by a specified size. DESC: Extend a pool metadata SubLV by a specified size.
lvextend --usepolicies LV_thinpool_snapshot lvextend --usepolicies LV_snapshot_thinpool_vdopool
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number, OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--nofsck, --nosync, --noudevsync, --nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs, --reportformat ReportFmt, --resizefs,
--type SegType --type SegType
OP: PV ... OP: PV ...
ID: lvextend_by_policy ID: lvextend_policy
DESC: Extend an LV according to a predefined policy. DESC: Extend an LV according to a predefined policy.
--- ---
@ -1456,7 +1456,7 @@ DESC: Remove the devices file entry for the given PVID.
lvreduce --size NSizeMB LV lvreduce --size NSizeMB LV
OO: --autobackup Bool, --force, --nofsck, --noudevsync, OO: --autobackup Bool, --force, --nofsck, --noudevsync,
--reportformat ReportFmt, --resizefs --reportformat ReportFmt, --resizefs
ID: lvreduce_general ID: lvreduce_size
--- ---
@ -1487,7 +1487,7 @@ OO: --alloc Alloc, --autobackup Bool, --force,
--stripes Number, --stripesize SizeKB, --poolmetadatasize PSizeMB, --stripes Number, --stripesize SizeKB, --poolmetadatasize PSizeMB,
--type SegType --type SegType
OP: PV ... OP: PV ...
ID: lvresize_by_size ID: lvresize_size
DESC: Resize an LV by a specified size. DESC: Resize an LV by a specified size.
lvresize LV PV ... lvresize LV PV ...
@ -1495,7 +1495,7 @@ OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB, --reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB,
--type SegType --type SegType
ID: lvresize_by_pv ID: lvresize_pv
DESC: Resize an LV by specified PV extents. DESC: Resize an LV by specified PV extents.
lvresize --poolmetadatasize PSizeMB LV_thinpool lvresize --poolmetadatasize PSizeMB LV_thinpool
@ -1504,7 +1504,7 @@ OO: --alloc Alloc, --autobackup Bool, --force,
--reportformat ReportFmt, --stripes Number, --stripesize SizeKB, --reportformat ReportFmt, --stripes Number, --stripesize SizeKB,
--type SegType --type SegType
OP: PV ... OP: PV ...
ID: lvresize_pool_metadata_by_size ID: lvresize_pool_metadata
DESC: Resize a pool metadata SubLV by a specified size. DESC: Resize a pool metadata SubLV by a specified size.
--- ---

View File

@ -17,5 +17,5 @@
int lvextend(struct cmd_context *cmd, int argc, char **argv) int lvextend(struct cmd_context *cmd, int argc, char **argv)
{ {
return lvresize(cmd, argc, argv); return lvresize_cmd(cmd, argc, argv);
} }

View File

@ -165,6 +165,16 @@ static const struct command_function _command_functions[CMD_COUNT] = {
{ pvscan_display_CMD, pvscan_display_cmd }, { pvscan_display_CMD, pvscan_display_cmd },
{ pvscan_cache_CMD, pvscan_cache_cmd }, { pvscan_cache_CMD, pvscan_cache_cmd },
/* lvextend/lvreduce/lvresize */
{ lvextend_policy_CMD, lvextend_policy_cmd },
{ lvextend_pool_metadata_CMD, lvresize_cmd },
{ lvresize_pool_metadata_CMD, lvresize_cmd },
{ lvextend_pv_CMD, lvresize_cmd },
{ lvresize_pv_CMD, lvresize_cmd },
{ lvextend_size_CMD, lvresize_cmd },
{ lvreduce_size_CMD, lvresize_cmd },
{ lvresize_size_CMD, lvresize_cmd },
}; };
@ -3153,6 +3163,9 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv))) if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
return EINVALID_CMD_LINE; return EINVALID_CMD_LINE;
/* avoid this by letting lib code use cmd->command */
cmd->command_enum = cmd->command->command_enum;
/* /*
* If option --foo is set which is listed in IO (ignore option) in * If option --foo is set which is listed in IO (ignore option) in
* command-lines.in, then unset foo. Commands won't usually use an * command-lines.in, then unset foo. Commands won't usually use an

View File

@ -17,5 +17,5 @@
int lvreduce(struct cmd_context *cmd, int argc, char **argv) int lvreduce(struct cmd_context *cmd, int argc, char **argv)
{ {
return lvresize(cmd, argc, argv); return lvresize_cmd(cmd, argc, argv);
} }

View File

@ -15,12 +15,101 @@
#include "tools.h" #include "tools.h"
static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv, static int _lvresize_params(struct cmd_context *cmd, struct lvresize_params *lp)
struct lvresize_params *lp)
{ {
const char *cmd_name = command_name(cmd);
const char *type_str = arg_str_value(cmd, type_ARG, NULL); const char *type_str = arg_str_value(cmd, type_ARG, NULL);
int only_linear = 0; int only_linear = 0;
int set_extents_and_size = 0;
memset(lp, 0, sizeof(struct lvresize_params));
switch (cmd->command->command_enum) {
case lvextend_policy_CMD:
lp->resize = LV_EXTEND;
lp->size = 0;
lp->extents = 0;
lp->percent = PERCENT_LV;
lp->sign = SIGN_PLUS;
lp->poolmetadata_size = 0;
lp->use_policies = 1;
break;
case lvextend_pool_metadata_CMD:
case lvresize_pool_metadata_CMD:
lp->resize = LV_EXTEND;
lp->size = 0;
lp->extents = 0;
lp->percent = PERCENT_NONE;
lp->sign = SIGN_NONE;
lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0);
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
break;
case lvextend_pv_CMD:
case lvresize_pv_CMD:
lp->resize = LV_EXTEND;
lp->size = 0;
lp->extents = 0;
lp->percent_value = 100;
lp->percent = PERCENT_PVS;
lp->sign = SIGN_PLUS;
lp->poolmetadata_size = 0;
lp->resizefs = arg_is_set(cmd, resizefs_ARG);
lp->nofsck = arg_is_set(cmd, nofsck_ARG);
break;
case lvextend_size_CMD:
lp->resize = LV_EXTEND;
lp->resizefs = arg_is_set(cmd, resizefs_ARG);
lp->nofsck = arg_is_set(cmd, nofsck_ARG);
if ((lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0)))
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
set_extents_and_size = 1;
break;
case lvreduce_size_CMD:
lp->resize = LV_REDUCE;
lp->poolmetadata_size = 0;
lp->resizefs = arg_is_set(cmd, resizefs_ARG);
lp->nofsck = arg_is_set(cmd, nofsck_ARG);
set_extents_and_size = 1;
break;
case lvresize_size_CMD:
lp->resize = LV_ANY;
lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0);
lp->resizefs = arg_is_set(cmd, resizefs_ARG);
lp->nofsck = arg_is_set(cmd, nofsck_ARG);
if ((lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0)))
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
set_extents_and_size = 1;
break;
default:
log_error(INTERNAL_ERROR "unknown lvresize type");
return 0;
};
if (set_extents_and_size) {
if ((lp->extents = arg_uint_value(cmd, extents_ARG, 0))) {
lp->sign = arg_sign_value(cmd, extents_ARG, 0);
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
}
if ((lp->size = arg_uint64_value(cmd, size_ARG, 0))) {
lp->sign = arg_sign_value(cmd, size_ARG, 0);
lp->percent = PERCENT_NONE;
}
if (lp->size && lp->extents) {
log_error("Please specify either size or extents but not both.");
return 0;
}
}
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, 0);
lp->yes = arg_is_set(cmd, yes_ARG);
lp->force = arg_is_set(cmd, force_ARG),
lp->nosync = arg_is_set(cmd, nosync_ARG);
lp->lockopt = arg_str_value(cmd, lockopt_ARG, NULL);
if (type_str) { if (type_str) {
if (!strcmp(type_str, "linear")) { if (!strcmp(type_str, "linear")) {
@ -32,104 +121,6 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
return_0; return_0;
} }
if (!strcmp(cmd_name, "lvreduce"))
lp->resize = LV_REDUCE;
else if (!strcmp(cmd_name, "lvextend"))
lp->resize = LV_EXTEND;
else
lp->resize = LV_ANY;
lp->sign = lp->poolmetadata_sign = SIGN_NONE;
if ((lp->use_policies = arg_is_set(cmd, usepolicies_ARG))) {
/* do nothing; lv_resize will handle --use-policies itself */
if (arg_from_list_is_set(cmd, NULL,
chunksize_ARG, extents_ARG,
poolmetadatasize_ARG,
regionsize_ARG,
size_ARG,
stripes_ARG, stripesize_ARG,
-1))
log_print_unless_silent("Ignoring size parameters with --use-policies.");
} else {
/*
* Allow omission of extents and size if the user has given us
* one or more PVs. Most likely, the intent was "resize this
* LV the best you can with these PVs"
* If only --poolmetadatasize is specified with list of PVs,
* then metadata will be extended there.
*/
if ((lp->extents = arg_uint_value(cmd, extents_ARG, 0))) {
lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
}
if (arg_from_list_is_zero(cmd, "may not be zero",
chunksize_ARG, extents_ARG,
poolmetadatasize_ARG,
regionsize_ARG,
size_ARG,
stripes_ARG, stripesize_ARG,
virtualsize_ARG,
-1))
return_0;
if ((lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0))) {
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
if (lp->poolmetadata_sign == SIGN_MINUS) {
log_error("Can't reduce pool metadata size.");
return 0;
}
}
if ((lp->size = arg_uint64_value(cmd, size_ARG, 0))) {
lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
lp->percent = PERCENT_NONE;
}
if (lp->size && lp->extents) {
log_error("Please specify either size or extents but not both.");
return 0;
}
if (!lp->extents &&
!lp->size &&
!lp->poolmetadata_size &&
(argc >= 2)) {
lp->extents = 100;
lp->percent = PERCENT_PVS;
lp->sign = SIGN_PLUS;
}
}
if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
log_error("Negative argument not permitted - use lvreduce.");
return 0;
}
if (lp->resize == LV_REDUCE &&
((lp->sign == SIGN_PLUS) ||
(lp->poolmetadata_sign == SIGN_PLUS))) {
log_error("Positive sign not permitted - use lvextend.");
return 0;
}
if (!argc) {
log_error("Please provide the logical volume name.");
return 0;
}
lp->lv_name = argv[0];
if (!validate_lvname_param(cmd, &lp->vg_name, &lp->lv_name))
return_0;
/* Check for $LVM_VG_NAME */
if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) {
log_error("Please specify a logical volume path.");
return 0;
}
if (arg_is_set(cmd, mirrors_ARG)) { if (arg_is_set(cmd, mirrors_ARG)) {
if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) != SIGN_NONE) { if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) != SIGN_NONE) {
log_error("Mirrors argument may not be signed."); log_error("Mirrors argument may not be signed.");
@ -156,66 +147,150 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
return 0; return 0;
} }
lp->argc = --argc;
lp->argv = ++argv;
return 1; return 1;
} }
static int _lvresize_single(struct cmd_context *cmd, const char *vg_name, /*
struct volume_group *vg, struct processing_handle *handle) * lvextend --use-policies is usually called by dmeventd, as a method of
* "auto extending" an LV as it's used. It checks how full a snapshot cow or
* thin pool is, and extends it if it's too full, based on threshold settings
* in lvm.conf for when to auto extend it.
*
* The extension of a thin pool LV can involve extending either the data sub
* LV, the metadata sub LV, or both, so there may be two LVs extended here.
*/
static int _lv_extend_policy(struct cmd_context *cmd, struct logical_volume *lv,
struct lvresize_params *lp, int *skipped)
{ {
struct lvresize_params *lp = (struct lvresize_params *) handle->custom_handle; struct lvresize_params lp_meta;
struct dm_list *pvh; uint32_t percent_main = 0;
struct logical_volume *lv; uint32_t percent_meta = 0;
int ret = ECMD_FAILED; int is_active;
/* Does LV exist? */ memset(&lp_meta, 0, sizeof(lp_meta));
if (!(lv = find_lv(vg, lp->lv_name))) {
log_error("Logical volume %s not found in volume group %s.", if (!lv_is_cow(lv) && !lv_is_thin_pool(lv) && !lv_is_vdo_pool(lv)) {
lp->lv_name, vg->name); log_error("lvextend policy is supported only for snapshot, thin pool and vdo pool volumes.");
goto out; *skipped = 1;
return 0;
} }
if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc, lp->argv, 1) : &vg->pvs)) is_active = lv_is_active(lv);
goto_out;
if (!lv_resize(lv, lp, pvh)) if (vg_is_shared(lv->vg) && !is_active) {
goto_out; log_debug("lvextend policy requires LV to be active in a shared VG.");
*skipped = 1;
return 1;
}
ret = ECMD_PROCESSED; if (lv_is_thin_pool(lv) && !is_active) {
out: log_error("lvextend using policy requires the thin pool to be active.");
return ret; return 0;
}
/*
* Calculate the percent of extents to extend the LV based on current
* usage info from the kernel and policy settings from lvm.conf, e.g.
* autoextend_threshold, autoextend_percent. For thin pools, both the
* thin pool data LV and thin pool metadata LV may need to be extended.
* In this case, percent_main is the amount to extend the data LV, and
* percent_meta is the amount to extend the metadata LV.
*/
if (!lv_extend_policy_calculate_percent(lv, &percent_main, &percent_meta))
return_0;
if (!percent_main && !percent_meta) {
log_debug("lvextend policy not needed.");
*skipped = 1;
return 1;
}
*skipped = 0;
lp->policy_percent_main = percent_main;
lp->policy_percent_meta = percent_meta;
return lv_resize(cmd, lv, lp);
} }
int lvresize(struct cmd_context *cmd, int argc, char **argv) static int _lvextend_policy_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle)
{
struct lvresize_params *lp = (struct lvresize_params *) handle->custom_handle;
int skipped = 0;
if (cmd->position_argc > 1) {
/* First pos arg is required LV, remaining are optional PVs. */
if (!(lp->pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
return_ECMD_FAILED;
} else
lp->pvh = &lv->vg->pvs;
if (!_lv_extend_policy(cmd, lv, lp, &skipped))
return ECMD_FAILED;
if (!skipped)
log_print_unless_silent("Logical volume %s successfully resized.", display_lvname(lv));
return ECMD_PROCESSED;
}
static int _lvresize_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle)
{
struct lvresize_params *lp = (struct lvresize_params *) handle->custom_handle;
if (cmd->position_argc > 1) {
/* First pos arg is required LV, remaining are optional PVs. */
if (!(lp->pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
return_ECMD_FAILED;
} else
lp->pvh = &lv->vg->pvs;
if (!lv_resize(cmd, lv, lp))
return ECMD_FAILED;
log_print_unless_silent("Logical volume %s successfully resized.",
display_lvname(lv));
return ECMD_PROCESSED;
}
int lvextend_policy_cmd(struct cmd_context *cmd, int argc, char **argv)
{ {
struct processing_handle *handle; struct processing_handle *handle;
struct lvresize_params lp = { struct lvresize_params lp;
.alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, 0),
.yes = arg_is_set(cmd, yes_ARG),
.force = arg_is_set(cmd, force_ARG),
.nofsck = arg_is_set(cmd, nofsck_ARG),
.nosync = arg_is_set(cmd, nosync_ARG),
.resizefs = arg_is_set(cmd, resizefs_ARG),
.lockopt = arg_str_value(cmd, lockopt_ARG, NULL),
};
int ret; int ret;
if (!_lvresize_params(cmd, argc, argv, &lp)) { if (!_lvresize_params(cmd, &lp))
stack;
return EINVALID_CMD_LINE; return EINVALID_CMD_LINE;
}
if (!(handle = init_processing_handle(cmd, NULL))) { if (!(handle = init_processing_handle(cmd, NULL)))
log_error("Failed to initialize processing handle.");
return ECMD_FAILED; return ECMD_FAILED;
}
handle->custom_handle = &lp; handle->custom_handle = &lp;
ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle, ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
&_lvresize_single); handle, NULL, &_lvextend_policy_single);
destroy_processing_handle(cmd, handle);
return ret;
}
int lvresize_cmd(struct cmd_context *cmd, int argc, char **argv)
{
struct processing_handle *handle;
struct lvresize_params lp;
int ret;
if (!_lvresize_params(cmd, &lp))
return EINVALID_CMD_LINE;
if (!(handle = init_processing_handle(cmd, NULL)))
return ECMD_FAILED;
handle->custom_handle = &lp;
ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
handle, NULL, &_lvresize_single);
destroy_processing_handle(cmd, handle); destroy_processing_handle(cmd, handle);
@ -224,3 +299,16 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
return ret; return ret;
} }
/*
* All lvresize command defs have their own function,
* so the generic function name is unused.
*/
int lvresize(struct cmd_context *cmd, int argc, char **argv)
{
log_error(INTERNAL_ERROR "Missing function for command definition %d:%s.",
cmd->command->command_index, cmd->command->command_id);
return ECMD_FAILED;
}

View File

@ -45,19 +45,18 @@
#include "lib/notify/lvmnotify.h" #include "lib/notify/lvmnotify.h"
#include "lib/label/hints.h" #include "lib/label/hints.h"
/*
* cmd_enum.h uses the generated cmds.h to create the enum with an ID
* for each command definition in command-lines.in.
*/
#include "lib/commands/cmd_enum.h"
#include <ctype.h> #include <ctype.h>
#include <sys/types.h> #include <sys/types.h>
#define CMD_LEN 256 #define CMD_LEN 256
#define MAX_ARGS 64 #define MAX_ARGS 64
/* define the enums for each unique ID in command defs in command-lines.in */
enum {
#define cmd(a, b) a ,
#include "cmds.h"
#undef cmd
};
/* define the enums for the values accepted by command line --options, foo_VAL */ /* define the enums for the values accepted by command line --options, foo_VAL */
enum { enum {
#define val(a, b, c, d) a , #define val(a, b, c, d) a ,
@ -296,4 +295,7 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
struct logical_volume *lv, struct logical_volume *lv,
struct processing_handle *handle); struct processing_handle *handle);
int lvresize_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvextend_policy_cmd(struct cmd_context *cmd, int argc, char **argv);
#endif #endif