@@ -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+
11601185static 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
13221349read_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 ) {
14251457direct_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 ++ ;
14351470bio_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
14701507static 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
26792729static 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