Commit 054bee16 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer
Browse files

dm writecache: return the exact table values that were set



LVM doesn't like it when the target returns different values from what
was set in the constructor. Fix dm-writecache so that the returned
table values are exactly the same as requested values.

Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org # v4.18+
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 363880c4
Loading
Loading
Loading
Loading
+30 −24
Original line number Diff line number Diff line
@@ -159,14 +159,22 @@ struct dm_writecache {
	bool overwrote_committed:1;
	bool memory_vmapped:1;

	bool start_sector_set:1;
	bool high_wm_percent_set:1;
	bool low_wm_percent_set:1;
	bool max_writeback_jobs_set:1;
	bool autocommit_blocks_set:1;
	bool autocommit_time_set:1;
	bool max_age_set:1;
	bool writeback_fua_set:1;
	bool flush_on_suspend:1;
	bool cleaner:1;
	bool cleaner_set:1;

	unsigned high_wm_percent_value;
	unsigned low_wm_percent_value;
	unsigned autocommit_time_value;
	unsigned max_age_value;

	unsigned writeback_all;
	struct workqueue_struct *writeback_wq;
@@ -2203,6 +2211,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
			if (sscanf(string, "%llu%c", &start_sector, &dummy) != 1)
				goto invalid_optional;
			wc->start_sector = start_sector;
			wc->start_sector_set = true;
			if (wc->start_sector != start_sector ||
			    wc->start_sector >= wc->memory_map_size >> SECTOR_SHIFT)
				goto invalid_optional;
@@ -2212,6 +2221,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
				goto invalid_optional;
			if (high_wm_percent < 0 || high_wm_percent > 100)
				goto invalid_optional;
			wc->high_wm_percent_value = high_wm_percent;
			wc->high_wm_percent_set = true;
		} else if (!strcasecmp(string, "low_watermark") && opt_params >= 1) {
			string = dm_shift_arg(&as), opt_params--;
@@ -2219,6 +2229,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
				goto invalid_optional;
			if (low_wm_percent < 0 || low_wm_percent > 100)
				goto invalid_optional;
			wc->low_wm_percent_value = low_wm_percent;
			wc->low_wm_percent_set = true;
		} else if (!strcasecmp(string, "writeback_jobs") && opt_params >= 1) {
			string = dm_shift_arg(&as), opt_params--;
@@ -2238,6 +2249,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
			if (autocommit_msecs > 3600000)
				goto invalid_optional;
			wc->autocommit_jiffies = msecs_to_jiffies(autocommit_msecs);
			wc->autocommit_time_value = autocommit_msecs;
			wc->autocommit_time_set = true;
		} else if (!strcasecmp(string, "max_age") && opt_params >= 1) {
			unsigned max_age_msecs;
@@ -2247,7 +2259,10 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
			if (max_age_msecs > 86400000)
				goto invalid_optional;
			wc->max_age = msecs_to_jiffies(max_age_msecs);
			wc->max_age_set = true;
			wc->max_age_value = max_age_msecs;
		} else if (!strcasecmp(string, "cleaner")) {
			wc->cleaner_set = true;
			wc->cleaner = true;
		} else if (!strcasecmp(string, "fua")) {
			if (WC_MODE_PMEM(wc)) {
@@ -2453,7 +2468,6 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
	struct dm_writecache *wc = ti->private;
	unsigned extra_args;
	unsigned sz = 0;
	uint64_t x;

	switch (type) {
	case STATUSTYPE_INFO:
@@ -2465,11 +2479,11 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
		DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's',
				wc->dev->name, wc->ssd_dev->name, wc->block_size);
		extra_args = 0;
		if (wc->start_sector)
		if (wc->start_sector_set)
			extra_args += 2;
		if (wc->high_wm_percent_set && !wc->cleaner)
		if (wc->high_wm_percent_set)
			extra_args += 2;
		if (wc->low_wm_percent_set && !wc->cleaner)
		if (wc->low_wm_percent_set)
			extra_args += 2;
		if (wc->max_writeback_jobs_set)
			extra_args += 2;
@@ -2477,37 +2491,29 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
			extra_args += 2;
		if (wc->autocommit_time_set)
			extra_args += 2;
		if (wc->max_age != MAX_AGE_UNSPECIFIED)
		if (wc->max_age_set)
			extra_args += 2;
		if (wc->cleaner)
		if (wc->cleaner_set)
			extra_args++;
		if (wc->writeback_fua_set)
			extra_args++;

		DMEMIT("%u", extra_args);
		if (wc->start_sector)
		if (wc->start_sector_set)
			DMEMIT(" start_sector %llu", (unsigned long long)wc->start_sector);
		if (wc->high_wm_percent_set && !wc->cleaner) {
			x = (uint64_t)wc->freelist_high_watermark * 100;
			x += wc->n_blocks / 2;
			do_div(x, (size_t)wc->n_blocks);
			DMEMIT(" high_watermark %u", 100 - (unsigned)x);
		}
		if (wc->low_wm_percent_set && !wc->cleaner) {
			x = (uint64_t)wc->freelist_low_watermark * 100;
			x += wc->n_blocks / 2;
			do_div(x, (size_t)wc->n_blocks);
			DMEMIT(" low_watermark %u", 100 - (unsigned)x);
		}
		if (wc->high_wm_percent_set)
			DMEMIT(" high_watermark %u", wc->high_wm_percent_value);
		if (wc->low_wm_percent_set)
			DMEMIT(" low_watermark %u", wc->low_wm_percent_value);
		if (wc->max_writeback_jobs_set)
			DMEMIT(" writeback_jobs %u", wc->max_writeback_jobs);
		if (wc->autocommit_blocks_set)
			DMEMIT(" autocommit_blocks %u", wc->autocommit_blocks);
		if (wc->autocommit_time_set)
			DMEMIT(" autocommit_time %u", jiffies_to_msecs(wc->autocommit_jiffies));
		if (wc->max_age != MAX_AGE_UNSPECIFIED)
			DMEMIT(" max_age %u", jiffies_to_msecs(wc->max_age));
		if (wc->cleaner)
			DMEMIT(" autocommit_time %u", wc->autocommit_time_value);
		if (wc->max_age_set)
			DMEMIT(" max_age %u", wc->max_age_value);
		if (wc->cleaner_set)
			DMEMIT(" cleaner");
		if (wc->writeback_fua_set)
			DMEMIT(" %sfua", wc->writeback_fua ? "" : "no");
@@ -2517,7 +2523,7 @@ static void writecache_status(struct dm_target *ti, status_type_t type,

static struct target_type writecache_target = {
	.name			= "writecache",
	.version		= {1, 3, 0},
	.version		= {1, 4, 0},
	.module			= THIS_MODULE,
	.ctr			= writecache_ctr,
	.dtr			= writecache_dtr,