mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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…
	
		Reference in a new issue