dm writecache: add event counters
Add 10 counters for various events (hit, miss, etc) and export them in the status line (accessed from userspace with "dmsetup status"). Also add a message "clear_stats" that resets these counters. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
parent
df699cc16e
commit
e3a35d0340
2 changed files with 67 additions and 5 deletions
|
@ -78,13 +78,23 @@ Status:
|
||||||
2. the number of blocks
|
2. the number of blocks
|
||||||
3. the number of free blocks
|
3. the number of free blocks
|
||||||
4. the number of blocks under writeback
|
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:
|
Messages:
|
||||||
flush
|
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
|
if the cache device was flushed without an error
|
||||||
flush_on_suspend
|
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
|
when you are going to remove the cache device. The proper
|
||||||
sequence for removing the cache device is:
|
sequence for removing the cache device is:
|
||||||
|
|
||||||
|
@ -98,3 +108,5 @@ Messages:
|
||||||
6. the cache device is now inactive and it can be deleted
|
6. the cache device is now inactive and it can be deleted
|
||||||
cleaner
|
cleaner
|
||||||
See above "cleaner" constructor documentation.
|
See above "cleaner" constructor documentation.
|
||||||
|
clear_stats
|
||||||
|
Clear the statistics that are reported on the status line
|
||||||
|
|
|
@ -206,6 +206,19 @@ struct dm_writecache {
|
||||||
|
|
||||||
struct bio_set bio_set;
|
struct bio_set bio_set;
|
||||||
mempool_t copy_pool;
|
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
|
#define WB_LIST_INLINE 16
|
||||||
|
@ -1157,6 +1170,18 @@ static int process_cleaner_mesg(unsigned argc, char **argv, struct dm_writecache
|
||||||
return 0;
|
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,
|
static int writecache_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||||
char *result, unsigned maxlen)
|
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);
|
r = process_flush_on_suspend_mesg(argc, argv, wc);
|
||||||
else if (!strcasecmp(argv[0], "cleaner"))
|
else if (!strcasecmp(argv[0], "cleaner"))
|
||||||
r = process_cleaner_mesg(argc, argv, wc);
|
r = process_cleaner_mesg(argc, argv, wc);
|
||||||
|
else if (!strcasecmp(argv[0], "clear_stats"))
|
||||||
|
r = process_clear_stats_mesg(argc, argv, wc);
|
||||||
else
|
else
|
||||||
DMERR("unrecognised message received: %s", argv[0]);
|
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;
|
struct wc_entry *e;
|
||||||
|
|
||||||
read_next_block:
|
read_next_block:
|
||||||
|
wc->stats.reads++;
|
||||||
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
|
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) {
|
if (e && read_original_sector(wc, e) == bio->bi_iter.bi_sector) {
|
||||||
|
wc->stats.read_hits++;
|
||||||
if (WC_MODE_PMEM(wc)) {
|
if (WC_MODE_PMEM(wc)) {
|
||||||
bio_copy_block(wc, bio, memory_data(wc, e));
|
bio_copy_block(wc, bio, memory_data(wc, e));
|
||||||
if (bio->bi_iter.bi_size)
|
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 {
|
do {
|
||||||
bool found_entry = false;
|
bool found_entry = false;
|
||||||
bool search_used = false;
|
bool search_used = false;
|
||||||
|
wc->stats.writes++;
|
||||||
if (writecache_has_error(wc))
|
if (writecache_has_error(wc))
|
||||||
return WC_MAP_ERROR;
|
return WC_MAP_ERROR;
|
||||||
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0);
|
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0);
|
||||||
if (e) {
|
if (e) {
|
||||||
if (!writecache_entry_is_committed(wc, e)) {
|
if (!writecache_entry_is_committed(wc, e)) {
|
||||||
|
wc->stats.write_hits_uncommitted++;
|
||||||
search_used = true;
|
search_used = true;
|
||||||
goto bio_copy;
|
goto bio_copy;
|
||||||
}
|
}
|
||||||
|
wc->stats.write_hits_committed++;
|
||||||
if (!WC_MODE_PMEM(wc) && !e->write_in_progress) {
|
if (!WC_MODE_PMEM(wc) && !e->write_in_progress) {
|
||||||
wc->overwrote_committed = true;
|
wc->overwrote_committed = true;
|
||||||
search_used = 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 (unlikely(!e)) {
|
||||||
if (!WC_MODE_PMEM(wc) && !found_entry) {
|
if (!WC_MODE_PMEM(wc) && !found_entry) {
|
||||||
direct_write:
|
direct_write:
|
||||||
|
wc->stats.writes_around++;
|
||||||
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
|
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
|
||||||
return writecache_map_remap_origin(wc, bio, e);
|
return writecache_map_remap_origin(wc, bio, e);
|
||||||
}
|
}
|
||||||
|
wc->stats.writes_blocked_on_freelist++;
|
||||||
writecache_wait_on_freelist(wc);
|
writecache_wait_on_freelist(wc);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count);
|
write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count);
|
||||||
writecache_insert_entry(wc, e);
|
writecache_insert_entry(wc, e);
|
||||||
wc->uncommitted_blocks++;
|
wc->uncommitted_blocks++;
|
||||||
|
wc->stats.writes_allocate++;
|
||||||
bio_copy:
|
bio_copy:
|
||||||
if (WC_MODE_PMEM(wc))
|
if (WC_MODE_PMEM(wc))
|
||||||
bio_copy_block(wc, bio, memory_data(wc, e));
|
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;
|
return WC_MAP_ERROR;
|
||||||
|
|
||||||
if (WC_MODE_PMEM(wc)) {
|
if (WC_MODE_PMEM(wc)) {
|
||||||
|
wc->stats.flushes++;
|
||||||
writecache_flush(wc);
|
writecache_flush(wc);
|
||||||
if (writecache_has_error(wc))
|
if (writecache_has_error(wc))
|
||||||
return WC_MAP_ERROR;
|
return WC_MAP_ERROR;
|
||||||
|
@ -1463,12 +1499,15 @@ static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio
|
||||||
/* SSD: */
|
/* SSD: */
|
||||||
if (dm_bio_get_target_bio_nr(bio))
|
if (dm_bio_get_target_bio_nr(bio))
|
||||||
return WC_MAP_REMAP_ORIGIN;
|
return WC_MAP_REMAP_ORIGIN;
|
||||||
|
wc->stats.flushes++;
|
||||||
writecache_offload_bio(wc, bio);
|
writecache_offload_bio(wc, bio);
|
||||||
return WC_MAP_RETURN;
|
return WC_MAP_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum wc_map_op writecache_map_discard(struct dm_writecache *wc, struct bio *bio)
|
static enum wc_map_op writecache_map_discard(struct dm_writecache *wc, struct bio *bio)
|
||||||
{
|
{
|
||||||
|
wc->stats.discards++;
|
||||||
|
|
||||||
if (writecache_has_error(wc))
|
if (writecache_has_error(wc))
|
||||||
return WC_MAP_ERROR;
|
return WC_MAP_ERROR;
|
||||||
|
|
||||||
|
@ -2618,9 +2657,20 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case STATUSTYPE_INFO:
|
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->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;
|
break;
|
||||||
case STATUSTYPE_TABLE:
|
case STATUSTYPE_TABLE:
|
||||||
DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's',
|
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 = {
|
static struct target_type writecache_target = {
|
||||||
.name = "writecache",
|
.name = "writecache",
|
||||||
.version = {1, 5, 0},
|
.version = {1, 6, 0},
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.ctr = writecache_ctr,
|
.ctr = writecache_ctr,
|
||||||
.dtr = writecache_dtr,
|
.dtr = writecache_dtr,
|
||||||
|
|
Loading…
Add table
Reference in a new issue