aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/admin-guide/device-mapper/writecache.rst16
-rw-r--r--drivers/md/dm-writecache.c56
2 files changed, 67 insertions, 5 deletions
diff --git a/Documentation/admin-guide/device-mapper/writecache.rst b/Documentation/admin-guide/device-mapper/writecache.rst
index 65427d8dfca6..10429779a91a 100644
--- a/Documentation/admin-guide/device-mapper/writecache.rst
+++ b/Documentation/admin-guide/device-mapper/writecache.rst
@@ -78,13 +78,23 @@ Status:
2. the number of blocks
3. the number of free blocks
4. the number of blocks under writeback
+5. the number of read requests
+6. the number of read requests that hit the cache
+7. the number of write requests
+8. the number of write requests that hit uncommitted block
+9. the number of write requests that hit committed block
+10. the number of write requests that bypass the cache
+11. the number of write requests that are allocated in the cache
+12. the number of write requests that are blocked on the freelist
+13. the number of flush requests
+14. the number of discard requests
Messages:
flush
- flush the cache device. The message returns successfully
+ Flush the cache device. The message returns successfully
if the cache device was flushed without an error
flush_on_suspend
- flush the cache device on next suspend. Use this message
+ Flush the cache device on next suspend. Use this message
when you are going to remove the cache device. The proper
sequence for removing the cache device is:
@@ -98,3 +108,5 @@ Messages:
6. the cache device is now inactive and it can be deleted
cleaner
See above "cleaner" constructor documentation.
+ clear_stats
+ Clear the statistics that are reported on the status line
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index e89868cf7d98..e1d7234eec3f 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -206,6 +206,19 @@ struct dm_writecache {
struct bio_set bio_set;
mempool_t copy_pool;
+
+ struct {
+ unsigned long long reads;
+ unsigned long long read_hits;
+ unsigned long long writes;
+ unsigned long long write_hits_uncommitted;
+ unsigned long long write_hits_committed;
+ unsigned long long writes_around;
+ unsigned long long writes_allocate;
+ unsigned long long writes_blocked_on_freelist;
+ unsigned long long flushes;
+ unsigned long long discards;
+ } stats;
};
#define WB_LIST_INLINE 16
@@ -1157,6 +1170,18 @@ static int process_cleaner_mesg(unsigned argc, char **argv, struct dm_writecache
return 0;
}
+static int process_clear_stats_mesg(unsigned argc, char **argv, struct dm_writecache *wc)
+{
+ if (argc != 1)
+ return -EINVAL;
+
+ wc_lock(wc);
+ memset(&wc->stats, 0, sizeof wc->stats);
+ wc_unlock(wc);
+
+ return 0;
+}
+
static int writecache_message(struct dm_target *ti, unsigned argc, char **argv,
char *result, unsigned maxlen)
{
@@ -1169,6 +1194,8 @@ static int writecache_message(struct dm_target *ti, unsigned argc, char **argv,
r = process_flush_on_suspend_mesg(argc, argv, wc);
else if (!strcasecmp(argv[0], "cleaner"))
r = process_cleaner_mesg(argc, argv, wc);
+ else if (!strcasecmp(argv[0], "clear_stats"))
+ r = process_clear_stats_mesg(argc, argv, wc);
else
DMERR("unrecognised message received: %s", argv[0]);
@@ -1320,8 +1347,10 @@ static enum wc_map_op writecache_map_read(struct dm_writecache *wc, struct bio *
struct wc_entry *e;
read_next_block:
+ wc->stats.reads++;
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
if (e && read_original_sector(wc, e) == bio->bi_iter.bi_sector) {
+ wc->stats.read_hits++;
if (WC_MODE_PMEM(wc)) {
bio_copy_block(wc, bio, memory_data(wc, e));
if (bio->bi_iter.bi_size)
@@ -1400,14 +1429,17 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
do {
bool found_entry = false;
bool search_used = false;
+ wc->stats.writes++;
if (writecache_has_error(wc))
return WC_MAP_ERROR;
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0);
if (e) {
if (!writecache_entry_is_committed(wc, e)) {
+ wc->stats.write_hits_uncommitted++;
search_used = true;
goto bio_copy;
}
+ wc->stats.write_hits_committed++;
if (!WC_MODE_PMEM(wc) && !e->write_in_progress) {
wc->overwrote_committed = true;
search_used = true;
@@ -1423,15 +1455,18 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
if (unlikely(!e)) {
if (!WC_MODE_PMEM(wc) && !found_entry) {
direct_write:
+ wc->stats.writes_around++;
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
return writecache_map_remap_origin(wc, bio, e);
}
+ wc->stats.writes_blocked_on_freelist++;
writecache_wait_on_freelist(wc);
continue;
}
write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count);
writecache_insert_entry(wc, e);
wc->uncommitted_blocks++;
+ wc->stats.writes_allocate++;
bio_copy:
if (WC_MODE_PMEM(wc))
bio_copy_block(wc, bio, memory_data(wc, e));
@@ -1453,6 +1488,7 @@ static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio
return WC_MAP_ERROR;
if (WC_MODE_PMEM(wc)) {
+ wc->stats.flushes++;
writecache_flush(wc);
if (writecache_has_error(wc))
return WC_MAP_ERROR;
@@ -1463,12 +1499,15 @@ static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio
/* SSD: */
if (dm_bio_get_target_bio_nr(bio))
return WC_MAP_REMAP_ORIGIN;
+ wc->stats.flushes++;
writecache_offload_bio(wc, bio);
return WC_MAP_RETURN;
}
static enum wc_map_op writecache_map_discard(struct dm_writecache *wc, struct bio *bio)
{
+ wc->stats.discards++;
+
if (writecache_has_error(wc))
return WC_MAP_ERROR;
@@ -2618,9 +2657,20 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
switch (type) {
case STATUSTYPE_INFO:
- DMEMIT("%ld %llu %llu %llu", writecache_has_error(wc),
+ DMEMIT("%ld %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
+ writecache_has_error(wc),
(unsigned long long)wc->n_blocks, (unsigned long long)wc->freelist_size,
- (unsigned long long)wc->writeback_size);
+ (unsigned long long)wc->writeback_size,
+ wc->stats.reads,
+ wc->stats.read_hits,
+ wc->stats.writes,
+ wc->stats.write_hits_uncommitted,
+ wc->stats.write_hits_committed,
+ wc->stats.writes_around,
+ wc->stats.writes_allocate,
+ wc->stats.writes_blocked_on_freelist,
+ wc->stats.flushes,
+ wc->stats.discards);
break;
case STATUSTYPE_TABLE:
DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's',
@@ -2678,7 +2728,7 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
static struct target_type writecache_target = {
.name = "writecache",
- .version = {1, 5, 0},
+ .version = {1, 6, 0},
.module = THIS_MODULE,
.ctr = writecache_ctr,
.dtr = writecache_dtr,