mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
thin: add discard support for thin pool
Add arg support for discard. Add discard ignore, nopassdown, passdown (=default) support. Flags could be set per pool. lvcreate [--discard {ignore|no_passdown|passdown}] vg/thinlv
This commit is contained in:
parent
260e8f2476
commit
ebbf7d8e68
@ -1,5 +1,6 @@
|
|||||||
Version 2.02.97 -
|
Version 2.02.97 -
|
||||||
===============================
|
===============================
|
||||||
|
Add support for controlling discard behavior of thin pool.
|
||||||
Detect features for new 1.1 thin pool target.
|
Detect features for new 1.1 thin pool target.
|
||||||
Count percentage of completeness upwards when merging a snapshot volume.
|
Count percentage of completeness upwards when merging a snapshot volume.
|
||||||
Skip activation when using vg/lvchange --sysinit -a ay and lvmetad is active.
|
Skip activation when using vg/lvchange --sysinit -a ay and lvmetad is active.
|
||||||
|
@ -166,6 +166,12 @@ typedef enum {
|
|||||||
DONT_PROMPT_OVERRIDE = 2 /* Skip prompt + override a second condition */
|
DONT_PROMPT_OVERRIDE = 2 /* Skip prompt + override a second condition */
|
||||||
} force_t;
|
} force_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
THIN_DISCARD_PASSDOWN,
|
||||||
|
THIN_DISCARD_NO_PASSDOWN,
|
||||||
|
THIN_DISCARD_IGNORE,
|
||||||
|
} thin_discard_t;
|
||||||
|
|
||||||
struct cmd_context;
|
struct cmd_context;
|
||||||
struct format_handler;
|
struct format_handler;
|
||||||
struct labeller;
|
struct labeller;
|
||||||
@ -347,6 +353,7 @@ struct lv_segment {
|
|||||||
uint64_t transaction_id; /* For thin_pool, thin */
|
uint64_t transaction_id; /* For thin_pool, thin */
|
||||||
uint64_t low_water_mark; /* For thin_pool */
|
uint64_t low_water_mark; /* For thin_pool */
|
||||||
unsigned zero_new_blocks; /* For thin_pool */
|
unsigned zero_new_blocks; /* For thin_pool */
|
||||||
|
thin_discard_t discard; /* For thin_pool */
|
||||||
struct dm_list thin_messages; /* For thin_pool */
|
struct dm_list thin_messages; /* For thin_pool */
|
||||||
struct logical_volume *pool_lv; /* For thin */
|
struct logical_volume *pool_lv; /* For thin */
|
||||||
uint32_t device_id; /* For thin, 24bit */
|
uint32_t device_id; /* For thin, 24bit */
|
||||||
@ -558,6 +565,8 @@ uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
|
|||||||
uint32_t extent_size);
|
uint32_t extent_size);
|
||||||
|
|
||||||
int update_pool_lv(struct logical_volume *lv, int activate);
|
int update_pool_lv(struct logical_volume *lv, int activate);
|
||||||
|
int get_pool_discard(const char *str, thin_discard_t *discard);
|
||||||
|
const char *get_pool_discard_name(thin_discard_t discard);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Activation options
|
* Activation options
|
||||||
|
@ -428,3 +428,38 @@ int update_pool_lv(struct logical_volume *lv, int activate)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_pool_discard(const char *str, thin_discard_t *discard)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(str, "passdown"))
|
||||||
|
*discard = THIN_DISCARD_PASSDOWN;
|
||||||
|
/* Allow some variation in thin parameter */
|
||||||
|
else if (!strcasecmp(str, "nopassdown") ||
|
||||||
|
!strcasecmp(str, "no-passdown") ||
|
||||||
|
!strcasecmp(str, "no_passdown"))
|
||||||
|
*discard = THIN_DISCARD_NO_PASSDOWN;
|
||||||
|
else if (!strcasecmp(str, "ignore"))
|
||||||
|
*discard = THIN_DISCARD_IGNORE;
|
||||||
|
else {
|
||||||
|
log_error("Thin pool discard type %s is unknown.", str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_pool_discard_name(thin_discard_t discard)
|
||||||
|
{
|
||||||
|
switch (discard) {
|
||||||
|
case THIN_DISCARD_PASSDOWN:
|
||||||
|
return "passdown";
|
||||||
|
case THIN_DISCARD_NO_PASSDOWN:
|
||||||
|
return "nopassdown";
|
||||||
|
case THIN_DISCARD_IGNORE:
|
||||||
|
return "ignore";
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error(INTERNAL_ERROR "Uknown discard type.");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -39,6 +39,10 @@
|
|||||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||||
|
|
||||||
|
static int _thin_target_present(struct cmd_context *cmd,
|
||||||
|
const struct lv_segment *seg,
|
||||||
|
unsigned *attributes);
|
||||||
|
|
||||||
static const char *_thin_pool_name(const struct lv_segment *seg)
|
static const char *_thin_pool_name(const struct lv_segment *seg)
|
||||||
{
|
{
|
||||||
return seg->segtype->name;
|
return seg->segtype->name;
|
||||||
@ -83,6 +87,7 @@ static int _thin_pool_text_import(struct lv_segment *seg,
|
|||||||
{
|
{
|
||||||
const char *lv_name;
|
const char *lv_name;
|
||||||
struct logical_volume *pool_data_lv, *pool_metadata_lv;
|
struct logical_volume *pool_data_lv, *pool_metadata_lv;
|
||||||
|
const char *discard = NULL;
|
||||||
|
|
||||||
if (!dm_config_get_str(sn, "metadata", &lv_name))
|
if (!dm_config_get_str(sn, "metadata", &lv_name))
|
||||||
return SEG_LOG_ERROR("Metadata must be a string in");
|
return SEG_LOG_ERROR("Metadata must be a string in");
|
||||||
@ -109,6 +114,15 @@ static int _thin_pool_text_import(struct lv_segment *seg,
|
|||||||
if (!dm_config_get_uint32(sn, "chunk_size", &seg->chunk_size))
|
if (!dm_config_get_uint32(sn, "chunk_size", &seg->chunk_size))
|
||||||
return SEG_LOG_ERROR("Could not read chunk_size");
|
return SEG_LOG_ERROR("Could not read chunk_size");
|
||||||
|
|
||||||
|
if (dm_config_has_node(sn, "discard") &&
|
||||||
|
!dm_config_get_str(sn, "discard", &discard))
|
||||||
|
return SEG_LOG_ERROR("Could not read discard for");
|
||||||
|
|
||||||
|
if (!discard)
|
||||||
|
seg->discard = THIN_DISCARD_PASSDOWN;
|
||||||
|
else if (!get_pool_discard(discard, &seg->discard))
|
||||||
|
return SEG_LOG_ERROR("Discard option unsupported for");
|
||||||
|
|
||||||
if (dm_config_has_node(sn, "low_water_mark") &&
|
if (dm_config_has_node(sn, "low_water_mark") &&
|
||||||
!dm_config_get_uint64(sn, "low_water_mark", &seg->low_water_mark))
|
!dm_config_get_uint64(sn, "low_water_mark", &seg->low_water_mark))
|
||||||
return SEG_LOG_ERROR("Could not read low_water_mark");
|
return SEG_LOG_ERROR("Could not read low_water_mark");
|
||||||
@ -149,6 +163,19 @@ static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter
|
|||||||
outsize(f, (uint64_t) seg->chunk_size,
|
outsize(f, (uint64_t) seg->chunk_size,
|
||||||
"chunk_size = %u", seg->chunk_size);
|
"chunk_size = %u", seg->chunk_size);
|
||||||
|
|
||||||
|
switch (seg->discard) {
|
||||||
|
case THIN_DISCARD_PASSDOWN:
|
||||||
|
/* nothing to do */
|
||||||
|
break;
|
||||||
|
case THIN_DISCARD_NO_PASSDOWN:
|
||||||
|
case THIN_DISCARD_IGNORE:
|
||||||
|
outf(f, "discard = \"%s\"", get_pool_discard_name(seg->discard));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error(INTERNAL_ERROR "Unexportable discard.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (seg->low_water_mark)
|
if (seg->low_water_mark)
|
||||||
outf(f, "low_water_mark = %" PRIu64, seg->low_water_mark);
|
outf(f, "low_water_mark = %" PRIu64, seg->low_water_mark);
|
||||||
|
|
||||||
@ -207,11 +234,16 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
|||||||
struct dm_tree_node *node, uint64_t len,
|
struct dm_tree_node *node, uint64_t len,
|
||||||
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
||||||
{
|
{
|
||||||
|
static int _no_discard = 0;
|
||||||
char *metadata_dlid, *pool_dlid;
|
char *metadata_dlid, *pool_dlid;
|
||||||
const struct lv_thin_message *lmsg;
|
const struct lv_thin_message *lmsg;
|
||||||
const struct logical_volume *origin;
|
const struct logical_volume *origin;
|
||||||
struct lvinfo info;
|
struct lvinfo info;
|
||||||
uint64_t transaction_id = 0;
|
uint64_t transaction_id = 0;
|
||||||
|
unsigned attr;
|
||||||
|
|
||||||
|
if (!_thin_target_present(cmd, seg, &attr))
|
||||||
|
return_0;
|
||||||
|
|
||||||
if (!laopts->real_pool) {
|
if (!laopts->real_pool) {
|
||||||
if (!(pool_dlid = build_dm_uuid(mem, seg->lv->lvid.s, "tpool"))) {
|
if (!(pool_dlid = build_dm_uuid(mem, seg->lv->lvid.s, "tpool"))) {
|
||||||
@ -246,6 +278,18 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
|||||||
seg->zero_new_blocks ? 0 : 1))
|
seg->zero_new_blocks ? 0 : 1))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
|
if (seg->discard != THIN_DISCARD_PASSDOWN) {
|
||||||
|
if (attr & THIN_FEATURE_DISCARD) {
|
||||||
|
/* FIXME: Check whether underlaying dev supports discard */
|
||||||
|
if (!dm_tree_node_set_thin_pool_discard(node,
|
||||||
|
seg->discard == THIN_DISCARD_IGNORE,
|
||||||
|
seg->discard == THIN_DISCARD_NO_PASSDOWN))
|
||||||
|
return_0;
|
||||||
|
} else
|
||||||
|
log_warn_suppress(_no_discard++, "WARNING: Thin pool target does "
|
||||||
|
"not support discard (needs kernel >= 3.4).");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add messages only for activation tree.
|
* Add messages only for activation tree.
|
||||||
* Otherwise avoid checking for existence of suspended origin.
|
* Otherwise avoid checking for existence of suspended origin.
|
||||||
|
@ -54,6 +54,8 @@ lvcreate \- create a logical volume in an existing volume group
|
|||||||
.RB [ \-T | \-\-thin
|
.RB [ \-T | \-\-thin
|
||||||
.RB [ \-c | \-\-chunksize
|
.RB [ \-c | \-\-chunksize
|
||||||
.IR ChunkSize ]
|
.IR ChunkSize ]
|
||||||
|
.RB [ \-\-discard
|
||||||
|
.RI { ignore | nopassdown | passdown }]
|
||||||
.RB [ \-\-poolmetadatasize
|
.RB [ \-\-poolmetadatasize
|
||||||
.IR MetadataSize [ bBsSkKmMgG ]]]
|
.IR MetadataSize [ bBsSkKmMgG ]]]
|
||||||
.RB [ \-\-thinpool
|
.RB [ \-\-thinpool
|
||||||
@ -138,6 +140,10 @@ Sets or resets the contiguous allocation policy for
|
|||||||
logical volumes. Default is no contiguous allocation based
|
logical volumes. Default is no contiguous allocation based
|
||||||
on a next free principle.
|
on a next free principle.
|
||||||
.TP
|
.TP
|
||||||
|
.BR \-\-discard " {" \fIignore | \fInopassdown | \fIpassdown }
|
||||||
|
Set discard behavior.
|
||||||
|
Default is \fIpassdown\fP.
|
||||||
|
.TP
|
||||||
.BR \-i ", " \-\-stripes " " \fIStripes
|
.BR \-i ", " \-\-stripes " " \fIStripes
|
||||||
Gives the number of stripes.
|
Gives the number of stripes.
|
||||||
This is equal to the number of physical volumes to scatter
|
This is equal to the number of physical volumes to scatter
|
||||||
|
@ -72,6 +72,7 @@ arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
|
|||||||
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
|
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
|
||||||
arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
|
arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
|
||||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)
|
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)
|
||||||
|
arg(discard_ARG, '\0', "discard", discard_arg, 0)
|
||||||
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0)
|
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0)
|
||||||
arg(sysinit_ARG, '\0', "sysinit", NULL, 0)
|
arg(sysinit_ARG, '\0', "sysinit", NULL, 0)
|
||||||
arg(thinpool_ARG, '\0', "thinpool", string_arg, 0)
|
arg(thinpool_ARG, '\0', "thinpool", string_arg, 0)
|
||||||
|
@ -177,6 +177,10 @@ xx(lvcreate,
|
|||||||
"\t[-p|--permission {r|rw}]\n"
|
"\t[-p|--permission {r|rw}]\n"
|
||||||
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
|
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
|
||||||
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
||||||
|
"\t[-T|--thin [-c|--chunksize ChunkSize]\n"
|
||||||
|
"\t [--discard {ignore|nopassdown|passdown}]\n"
|
||||||
|
"\t [--poolmetadatasize MetadataSize[bBsSkKmMgG]]]\n"
|
||||||
|
"\t[--thinpool ThinPoolLogicalVolume{Name|Path}]\n"
|
||||||
"\t[-t|--test]\n"
|
"\t[-t|--test]\n"
|
||||||
"\t[--type VolumeType]\n"
|
"\t[--type VolumeType]\n"
|
||||||
"\t[-v|--verbose]\n"
|
"\t[-v|--verbose]\n"
|
||||||
@ -215,7 +219,7 @@ xx(lvcreate,
|
|||||||
"\t[PhysicalVolumePath...]\n\n",
|
"\t[PhysicalVolumePath...]\n\n",
|
||||||
|
|
||||||
addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG,
|
addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG,
|
||||||
chunksize_ARG, contiguous_ARG, corelog_ARG, extents_ARG,
|
chunksize_ARG, contiguous_ARG, corelog_ARG, extents_ARG, discard_ARG,
|
||||||
ignoremonitoring_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
|
ignoremonitoring_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
|
||||||
monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG, permission_ARG,
|
monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG, permission_ARG,
|
||||||
persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
|
persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
|
||||||
|
@ -216,6 +216,19 @@ int activation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_v
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int discard_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
|
||||||
|
{
|
||||||
|
thin_discard_t discard;
|
||||||
|
|
||||||
|
if (!get_pool_discard(av->value, &discard))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
av->i_value = discard;
|
||||||
|
av->ui_value = discard;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av)
|
int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||||
{
|
{
|
||||||
return get_format_by_name(cmd, av->value) ? 1 : 0;
|
return get_format_by_name(cmd, av->value) ? 1 : 0;
|
||||||
|
@ -139,6 +139,7 @@ void usage(const char *name);
|
|||||||
/* the argument verify/normalise functions */
|
/* the argument verify/normalise functions */
|
||||||
int yes_no_arg(struct cmd_context *cmd, struct arg_values *av);
|
int yes_no_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||||
int activation_arg(struct cmd_context *cmd, struct arg_values *av);
|
int activation_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||||
|
int discard_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||||
int size_kb_arg(struct cmd_context *cmd, struct arg_values *av);
|
int size_kb_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||||
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av);
|
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||||
int int_arg(struct cmd_context *cmd, struct arg_values *av);
|
int int_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||||
|
Loading…
Reference in New Issue
Block a user