Commit 5c0de3d7 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer

dm writecache: make writeback pause configurable

Commit 95b88f4d ("dm writecache: pause
writeback if cache full and origin being written directly") introduced a
code that pauses cache flushing if we are issuing writes directly to the
origin.

Improve that initial commit by making the timeout code configurable
(via the option "pause_writeback"). Also change the default from 1s to
3s because it performed better.
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 95b88f4d
...@@ -12,7 +12,6 @@ first sector should contain valid superblock from previous invocation. ...@@ -12,7 +12,6 @@ first sector should contain valid superblock from previous invocation.
Constructor parameters: Constructor parameters:
1. type of the cache device - "p" or "s" 1. type of the cache device - "p" or "s"
- p - persistent memory - p - persistent memory
- s - SSD - s - SSD
2. the underlying device that will be cached 2. the underlying device that will be cached
...@@ -21,7 +20,6 @@ Constructor parameters: ...@@ -21,7 +20,6 @@ Constructor parameters:
size) size)
5. the number of optional parameters (the parameters with an argument 5. the number of optional parameters (the parameters with an argument
count as two) count as two)
start_sector n (default: 0) start_sector n (default: 0)
offset from the start of cache device in 512-byte sectors offset from the start of cache device in 512-byte sectors
high_watermark n (default: 50) high_watermark n (default: 50)
...@@ -71,6 +69,9 @@ Constructor parameters: ...@@ -71,6 +69,9 @@ Constructor parameters:
metadata_only metadata_only
only metadata is promoted to the cache. This option only metadata is promoted to the cache. This option
improves performance for heavier REQ_META workloads. improves performance for heavier REQ_META workloads.
pause_writeback n (default: 3000)
pause writeback if there was some write I/O redirected to
the origin volume in the last n milliseconds
Status: Status:
1. error indicator - 0 if there was no error, otherwise error number 1. error indicator - 0 if there was no error, otherwise error number
......
...@@ -45,6 +45,18 @@ static inline bool dm_iot_idle_for(struct dm_io_tracker *iot, unsigned long j) ...@@ -45,6 +45,18 @@ static inline bool dm_iot_idle_for(struct dm_io_tracker *iot, unsigned long j)
return r; return r;
} }
static inline unsigned long dm_iot_idle_time(struct dm_io_tracker *iot)
{
unsigned long r = 0;
spin_lock_irq(&iot->lock);
if (!iot->in_flight)
r = jiffies - iot->idle_time;
spin_unlock_irq(&iot->lock);
return r;
}
static inline void dm_iot_io_begin(struct dm_io_tracker *iot, sector_t len) static inline void dm_iot_io_begin(struct dm_io_tracker *iot, sector_t len)
{ {
spin_lock_irq(&iot->lock); spin_lock_irq(&iot->lock);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define AUTOCOMMIT_MSEC 1000 #define AUTOCOMMIT_MSEC 1000
#define MAX_AGE_DIV 16 #define MAX_AGE_DIV 16
#define MAX_AGE_UNSPECIFIED -1UL #define MAX_AGE_UNSPECIFIED -1UL
#define PAUSE_WRITEBACK (HZ * 3)
#define BITMAP_GRANULARITY 65536 #define BITMAP_GRANULARITY 65536
#if BITMAP_GRANULARITY < PAGE_SIZE #if BITMAP_GRANULARITY < PAGE_SIZE
...@@ -125,6 +126,7 @@ struct dm_writecache { ...@@ -125,6 +126,7 @@ struct dm_writecache {
size_t freelist_high_watermark; size_t freelist_high_watermark;
size_t freelist_low_watermark; size_t freelist_low_watermark;
unsigned long max_age; unsigned long max_age;
unsigned long pause;
unsigned uncommitted_blocks; unsigned uncommitted_blocks;
unsigned autocommit_blocks; unsigned autocommit_blocks;
...@@ -174,11 +176,13 @@ struct dm_writecache { ...@@ -174,11 +176,13 @@ struct dm_writecache {
bool cleaner:1; bool cleaner:1;
bool cleaner_set:1; bool cleaner_set:1;
bool metadata_only:1; bool metadata_only:1;
bool pause_set:1;
unsigned high_wm_percent_value; unsigned high_wm_percent_value;
unsigned low_wm_percent_value; unsigned low_wm_percent_value;
unsigned autocommit_time_value; unsigned autocommit_time_value;
unsigned max_age_value; unsigned max_age_value;
unsigned pause_value;
unsigned writeback_all; unsigned writeback_all;
struct workqueue_struct *writeback_wq; struct workqueue_struct *writeback_wq;
...@@ -1470,9 +1474,11 @@ static int writecache_map(struct dm_target *ti, struct bio *bio) ...@@ -1470,9 +1474,11 @@ static int writecache_map(struct dm_target *ti, struct bio *bio)
} }
unlock_remap_origin: unlock_remap_origin:
if (bio_data_dir(bio) != READ) { if (likely(wc->pause != 0)) {
dm_iot_io_begin(&wc->iot, 1); if (bio_op(bio) == REQ_OP_WRITE) {
bio->bi_private = (void *)2; dm_iot_io_begin(&wc->iot, 1);
bio->bi_private = (void *)2;
}
} }
bio_set_dev(bio, wc->dev->bdev); bio_set_dev(bio, wc->dev->bdev);
wc_unlock(wc); wc_unlock(wc);
...@@ -1837,10 +1843,19 @@ static void writecache_writeback(struct work_struct *work) ...@@ -1837,10 +1843,19 @@ static void writecache_writeback(struct work_struct *work)
dm_kcopyd_client_flush(wc->dm_kcopyd); dm_kcopyd_client_flush(wc->dm_kcopyd);
} }
if (!wc->writeback_all && !dm_suspended(wc->ti)) { if (likely(wc->pause != 0)) {
while (!dm_iot_idle_for(&wc->iot, HZ)) { while (1) {
cond_resched(); unsigned long idle;
msleep(1000); if (unlikely(wc->cleaner) || unlikely(wc->writeback_all) ||
unlikely(dm_suspended(wc->ti)))
break;
idle = dm_iot_idle_time(&wc->iot);
if (idle >= wc->pause)
break;
idle = wc->pause - idle;
if (idle > HZ)
idle = HZ;
schedule_timeout_idle(idle);
} }
} }
...@@ -2113,7 +2128,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -2113,7 +2128,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct wc_memory_superblock s; struct wc_memory_superblock s;
static struct dm_arg _args[] = { static struct dm_arg _args[] = {
{0, 17, "Invalid number of feature args"}, {0, 18, "Invalid number of feature args"},
}; };
as.argc = argc; as.argc = argc;
...@@ -2206,6 +2221,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -2206,6 +2221,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad; goto bad;
} }
} else { } else {
wc->pause = PAUSE_WRITEBACK;
r = mempool_init_kmalloc_pool(&wc->copy_pool, 1, sizeof(struct copy_struct)); r = mempool_init_kmalloc_pool(&wc->copy_pool, 1, sizeof(struct copy_struct));
if (r) { if (r) {
ti->error = "Could not allocate mempool"; ti->error = "Could not allocate mempool";
...@@ -2344,6 +2360,18 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -2344,6 +2360,18 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
} else goto invalid_optional; } else goto invalid_optional;
} else if (!strcasecmp(string, "metadata_only")) { } else if (!strcasecmp(string, "metadata_only")) {
wc->metadata_only = true; wc->metadata_only = true;
} else if (!strcasecmp(string, "pause_writeback") && opt_params >= 1) {
unsigned pause_msecs;
if (WC_MODE_PMEM(wc))
goto invalid_optional;
string = dm_shift_arg(&as), opt_params--;
if (sscanf(string, "%u%c", &pause_msecs, &dummy) != 1)
goto invalid_optional;
if (pause_msecs > 60000)
goto invalid_optional;
wc->pause = msecs_to_jiffies(pause_msecs);
wc->pause_set = true;
wc->pause_value = pause_msecs;
} else { } else {
invalid_optional: invalid_optional:
r = -EINVAL; r = -EINVAL;
...@@ -2569,6 +2597,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type, ...@@ -2569,6 +2597,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
extra_args++; extra_args++;
if (wc->metadata_only) if (wc->metadata_only)
extra_args++; extra_args++;
if (wc->pause_set)
extra_args += 2;
DMEMIT("%u", extra_args); DMEMIT("%u", extra_args);
if (wc->start_sector_set) if (wc->start_sector_set)
...@@ -2591,6 +2621,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type, ...@@ -2591,6 +2621,8 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
DMEMIT(" %sfua", wc->writeback_fua ? "" : "no"); DMEMIT(" %sfua", wc->writeback_fua ? "" : "no");
if (wc->metadata_only) if (wc->metadata_only)
DMEMIT(" metadata_only"); DMEMIT(" metadata_only");
if (wc->pause_set)
DMEMIT(" pause_writeback %u", wc->pause_value);
break; break;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment