Skip to content

Commit e3a35d0

Browse files
Mikulas Patockasnitm
authored andcommitted
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 <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent df699cc commit e3a35d0

File tree

2 files changed

+67
-5
lines changed

2 files changed

+67
-5
lines changed

Documentation/admin-guide/device-mapper/writecache.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,23 @@ Status:
7878
2. the number of blocks
7979
3. the number of free blocks
8080
4. the number of blocks under writeback
81+
5. the number of read requests
82+
6. the number of read requests that hit the cache
83+
7. the number of write requests
84+
8. the number of write requests that hit uncommitted block
85+
9. the number of write requests that hit committed block
86+
10. the number of write requests that bypass the cache
87+
11. the number of write requests that are allocated in the cache
88+
12. the number of write requests that are blocked on the freelist
89+
13. the number of flush requests
90+
14. the number of discard requests
8191

8292
Messages:
8393
flush
84-
flush the cache device. The message returns successfully
94+
Flush the cache device. The message returns successfully
8595
if the cache device was flushed without an error
8696
flush_on_suspend
87-
flush the cache device on next suspend. Use this message
97+
Flush the cache device on next suspend. Use this message
8898
when you are going to remove the cache device. The proper
8999
sequence for removing the cache device is:
90100

@@ -98,3 +108,5 @@ Messages:
98108
6. the cache device is now inactive and it can be deleted
99109
cleaner
100110
See above "cleaner" constructor documentation.
111+
clear_stats
112+
Clear the statistics that are reported on the status line

drivers/md/dm-writecache.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,19 @@ struct dm_writecache {
206206

207207
struct bio_set bio_set;
208208
mempool_t copy_pool;
209+
210+
struct {
211+
unsigned long long reads;
212+
unsigned long long read_hits;
213+
unsigned long long writes;
214+
unsigned long long write_hits_uncommitted;
215+
unsigned long long write_hits_committed;
216+
unsigned long long writes_around;
217+
unsigned long long writes_allocate;
218+
unsigned long long writes_blocked_on_freelist;
219+
unsigned long long flushes;
220+
unsigned long long discards;
221+
} stats;
209222
};
210223

211224
#define WB_LIST_INLINE 16
@@ -1157,6 +1170,18 @@ static int process_cleaner_mesg(unsigned argc, char **argv, struct dm_writecache
11571170
return 0;
11581171
}
11591172

1173+
static int process_clear_stats_mesg(unsigned argc, char **argv, struct dm_writecache *wc)
1174+
{
1175+
if (argc != 1)
1176+
return -EINVAL;
1177+
1178+
wc_lock(wc);
1179+
memset(&wc->stats, 0, sizeof wc->stats);
1180+
wc_unlock(wc);
1181+
1182+
return 0;
1183+
}
1184+
11601185
static int writecache_message(struct dm_target *ti, unsigned argc, char **argv,
11611186
char *result, unsigned maxlen)
11621187
{
@@ -1169,6 +1194,8 @@ static int writecache_message(struct dm_target *ti, unsigned argc, char **argv,
11691194
r = process_flush_on_suspend_mesg(argc, argv, wc);
11701195
else if (!strcasecmp(argv[0], "cleaner"))
11711196
r = process_cleaner_mesg(argc, argv, wc);
1197+
else if (!strcasecmp(argv[0], "clear_stats"))
1198+
r = process_clear_stats_mesg(argc, argv, wc);
11721199
else
11731200
DMERR("unrecognised message received: %s", argv[0]);
11741201

@@ -1320,8 +1347,10 @@ static enum wc_map_op writecache_map_read(struct dm_writecache *wc, struct bio *
13201347
struct wc_entry *e;
13211348

13221349
read_next_block:
1350+
wc->stats.reads++;
13231351
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
13241352
if (e && read_original_sector(wc, e) == bio->bi_iter.bi_sector) {
1353+
wc->stats.read_hits++;
13251354
if (WC_MODE_PMEM(wc)) {
13261355
bio_copy_block(wc, bio, memory_data(wc, e));
13271356
if (bio->bi_iter.bi_size)
@@ -1400,14 +1429,17 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
14001429
do {
14011430
bool found_entry = false;
14021431
bool search_used = false;
1432+
wc->stats.writes++;
14031433
if (writecache_has_error(wc))
14041434
return WC_MAP_ERROR;
14051435
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0);
14061436
if (e) {
14071437
if (!writecache_entry_is_committed(wc, e)) {
1438+
wc->stats.write_hits_uncommitted++;
14081439
search_used = true;
14091440
goto bio_copy;
14101441
}
1442+
wc->stats.write_hits_committed++;
14111443
if (!WC_MODE_PMEM(wc) && !e->write_in_progress) {
14121444
wc->overwrote_committed = true;
14131445
search_used = true;
@@ -1423,15 +1455,18 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
14231455
if (unlikely(!e)) {
14241456
if (!WC_MODE_PMEM(wc) && !found_entry) {
14251457
direct_write:
1458+
wc->stats.writes_around++;
14261459
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
14271460
return writecache_map_remap_origin(wc, bio, e);
14281461
}
1462+
wc->stats.writes_blocked_on_freelist++;
14291463
writecache_wait_on_freelist(wc);
14301464
continue;
14311465
}
14321466
write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count);
14331467
writecache_insert_entry(wc, e);
14341468
wc->uncommitted_blocks++;
1469+
wc->stats.writes_allocate++;
14351470
bio_copy:
14361471
if (WC_MODE_PMEM(wc))
14371472
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
14531488
return WC_MAP_ERROR;
14541489

14551490
if (WC_MODE_PMEM(wc)) {
1491+
wc->stats.flushes++;
14561492
writecache_flush(wc);
14571493
if (writecache_has_error(wc))
14581494
return WC_MAP_ERROR;
@@ -1463,12 +1499,15 @@ static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio
14631499
/* SSD: */
14641500
if (dm_bio_get_target_bio_nr(bio))
14651501
return WC_MAP_REMAP_ORIGIN;
1502+
wc->stats.flushes++;
14661503
writecache_offload_bio(wc, bio);
14671504
return WC_MAP_RETURN;
14681505
}
14691506

14701507
static enum wc_map_op writecache_map_discard(struct dm_writecache *wc, struct bio *bio)
14711508
{
1509+
wc->stats.discards++;
1510+
14721511
if (writecache_has_error(wc))
14731512
return WC_MAP_ERROR;
14741513

@@ -2618,9 +2657,20 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
26182657

26192658
switch (type) {
26202659
case STATUSTYPE_INFO:
2621-
DMEMIT("%ld %llu %llu %llu", writecache_has_error(wc),
2660+
DMEMIT("%ld %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
2661+
writecache_has_error(wc),
26222662
(unsigned long long)wc->n_blocks, (unsigned long long)wc->freelist_size,
2623-
(unsigned long long)wc->writeback_size);
2663+
(unsigned long long)wc->writeback_size,
2664+
wc->stats.reads,
2665+
wc->stats.read_hits,
2666+
wc->stats.writes,
2667+
wc->stats.write_hits_uncommitted,
2668+
wc->stats.write_hits_committed,
2669+
wc->stats.writes_around,
2670+
wc->stats.writes_allocate,
2671+
wc->stats.writes_blocked_on_freelist,
2672+
wc->stats.flushes,
2673+
wc->stats.discards);
26242674
break;
26252675
case STATUSTYPE_TABLE:
26262676
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,
26782728

26792729
static struct target_type writecache_target = {
26802730
.name = "writecache",
2681-
.version = {1, 5, 0},
2731+
.version = {1, 6, 0},
26822732
.module = THIS_MODULE,
26832733
.ctr = writecache_ctr,
26842734
.dtr = writecache_dtr,

0 commit comments

Comments
 (0)