1
0
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:
Zdenek Kabelac 2012-06-28 14:47:34 +02:00
parent 260e8f2476
commit ebbf7d8e68
9 changed files with 115 additions and 1 deletions

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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);