Permalink
Browse files

Adds a second block cleaning heuristic. Clean dirty blocks based on

some amount of "inactivity". The default policy is to clean dirty
blocks that were inactive for the last 60 seconds. But this can be
changed with fallow_delay (seconds). Setting fallow_delay to 0 completely
turns off the "clean based on inactivity" policy.
  • Loading branch information...
1 parent be44cb5 commit a9cf0f7b4549cac62b76ba2ddf579a053a5d1389 Mohan Srinivasan committed Feb 22, 2011
Showing with 223 additions and 77 deletions.
  1. +5 −0 doc/flashcache-doc.txt
  2. +6 −2 doc/flashcache-sa-guide.txt
  3. +20 −7 src/flashcache.h
  4. +25 −11 src/flashcache_conf.c
  5. +159 −52 src/flashcache_main.c
  6. +8 −5 src/flashcache_subr.c
@@ -99,6 +99,11 @@ strives to keep the percentage of dirty blocks in each set below the
dirty threshold. When the dirty blocks in a set exceeds the dirty
threshold, the set is eligible for cleaning.
+Dirty blocks are also cleaned based on "idleness" By defalt a
+dirty block not read or written for 60 seconds
+(dev.flashcache.fallow_delay) will be cleaned. To disable idle
+cleaning set that value to 0.
+
DIRTY blocks are selected for cleaning based on the replacement policy
(FIFO vs LRU). Once we have a target set of blocks to clean, we sort
these blocks, search for other contigous dirty blocks in the set
@@ -162,10 +162,14 @@ dev.flashcache.dirty_thresh_pct:
dev.flashcache.do_sync:
Schedule cleaning of all dirty blocks in the cache.
dev.flashcache.stop_sync:
- Stop the sync in progress.
-dev.flashcache.cache_all:
+ Stop the sync in progress.dev.flashcache.cache_all:
Global caching mode to cache everything or cache nothing.
See section on Caching Controls. Defaults to "cache everything".
+dev.flashcache.fallow_delay:
+ In seconds. Clean dirty blocks that have been "idle" (not
+ read or written) for fallow_delay seconds. Default is 60
+ seconds.
+ Setting this to 0 disables idle cleaning completely.
There is little reason to change these :
View
@@ -125,9 +125,11 @@ struct cacheblock {
struct cache_set {
u_int32_t set_fifo_next;
u_int32_t set_clean_next;
- u_int32_t clean_inprog;
- u_int32_t nr_dirty;
+ u_int16_t clean_inprog;
+ u_int16_t nr_dirty;
u_int16_t lru_head, lru_tail;
+ u_int16_t dirty_fallow;
+ unsigned long fallow_tstamp;
};
/*
@@ -199,6 +201,7 @@ struct cache_c {
#endif
unsigned long enqueues; /* enqueues on pending queue */
unsigned long cleanings;
+ unsigned long fallow_cleanings;
unsigned long noroom; /* No room in set */
unsigned long md_write_dirty; /* Metadata sector writes dirtying block */
unsigned long md_write_clean; /* Metadata sector writes cleaning block */
@@ -214,12 +217,7 @@ struct cache_c {
unsigned long ssd_reads, ssd_writes;
unsigned long uncached_io_requeue;
- unsigned long clean_set_calls;
- unsigned long clean_set_less_dirty;
- unsigned long clean_set_fails;
unsigned long clean_set_ios;
- unsigned long set_limit_reached;
- unsigned long total_limit_reached;
unsigned long pending_jobs_count;
/* Errors */
@@ -295,7 +293,18 @@ struct pending_job {
#define CACHEREADINPROG 0x0010 /* Read from cache in progress */
#define CACHEWRITEINPROG 0x0020 /* Write to cache in progress */
#define DIRTY 0x0040 /* Dirty, needs writeback to disk */
+/*
+ * Old and Dirty blocks are cleaned with a Clock like algorithm. The leading hand
+ * marks DIRTY_FALLOW_1. 60 seconds (default) later, the trailing hand comes along and
+ * marks DIRTY_FALLOW_2 if DIRTY_FALLOW_1 is already set. If the block was used in the
+ * interim, (DIRTY_FALLOW_1|DIRTY_FALLOW_2) is cleared. Any block that has both
+ * DIRTY_FALLOW_1 and DIRTY_FALLOW_2 marked is considered old and is eligible
+ * for cleaning.
+ */
+#define DIRTY_FALLOW_1 0x0080
+#define DIRTY_FALLOW_2 0x0100
+#define FALLOW_DOCLEAN (DIRTY_FALLOW_1 | DIRTY_FALLOW_2)
#define BLOCK_IO_INPROG (DISKREADINPROG | DISKWRITEINPROG | CACHEREADINPROG | CACHEWRITEINPROG)
/* Cache metadata is read by Flashcache utilities */
@@ -440,6 +449,7 @@ void flashcache_dtr(struct dm_target *ti);
int flashcache_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen);
+
struct kcached_job *flashcache_alloc_cache_job(void);
void flashcache_free_cache_job(struct kcached_job *job);
struct pending_job *flashcache_alloc_pending_job(struct cache_c *dmc);
@@ -505,6 +515,9 @@ int dm_io_async_bvec(unsigned int num_regions,
void *context);
#endif
+void flashcache_detect_fallow(struct cache_c *dmc, int index);
+void flashcache_clear_fallow(struct cache_c *dmc, int index);
+
#endif /* __KERNEL__ */
#endif
View
@@ -78,6 +78,7 @@ int sysctl_pid_expiry_check = 60;
int sysctl_pid_do_expiry = 0;
int sysctl_flashcache_fast_remove = 0;
int sysctl_cache_all = 1;
+int sysctl_fallow_delay = 60;
struct cache_c *cache_list_head = NULL;
struct work_struct _kcached_wq;
@@ -463,6 +464,16 @@ static ctl_table flashcache_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+ {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+ .ctl_name = CTL_UNNUMBERED,
+#endif
+ .procname = "fallow_delay",
+ .data = &sysctl_fallow_delay,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
.ctl_name = 0
@@ -1458,6 +1469,8 @@ flashcache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
dmc->cache_sets[i].set_clean_next = i * dmc->assoc;
dmc->cache_sets[i].nr_dirty = 0;
dmc->cache_sets[i].clean_inprog = 0;
+ dmc->cache_sets[i].dirty_fallow = 0;
+ dmc->cache_sets[i].fallow_tstamp = jiffies;
dmc->cache_sets[i].lru_tail = FLASHCACHE_LRU_NULL;
dmc->cache_sets[i].lru_head = FLASHCACHE_LRU_NULL;
}
@@ -1563,6 +1576,7 @@ flashcache_zero_stats(struct cache_c *dmc)
dmc->rd_invalidates = 0;
dmc->pending_inval = 0;
dmc->enqueues = 0;
+ dmc->fallow_cleanings = 0;
dmc->cleanings = 0;
dmc->noroom = 0;
dmc->md_write_dirty = 0;
@@ -1574,9 +1588,7 @@ flashcache_zero_stats(struct cache_c *dmc)
dmc->checksum_valid = 0;
dmc->checksum_invalid = 0;
#endif
- dmc->clean_set_calls = dmc->clean_set_less_dirty = 0;
- dmc->clean_set_fails = dmc->clean_set_ios = 0;
- dmc->set_limit_reached = dmc->total_limit_reached = 0;
+ dmc->clean_set_ios = 0;
dmc->front_merge = dmc->back_merge = 0;
dmc->pid_drops = dmc->pid_adds = dmc->pid_dels = dmc->expiry = 0;
dmc->uncached_reads = dmc->uncached_writes = 0;
@@ -1619,25 +1631,27 @@ flashcache_dtr(struct dm_target *ti)
DMINFO("stats: reads(%lu), writes(%lu), read hits(%lu), write hits(%lu), " \
"read hit percent(%ld), replacement(%lu), write invalidates(%lu), " \
"read invalidates(%lu), write replacement(%lu), pending enqueues(%lu), " \
- "pending inval(%lu) cleanings(%lu), " \
+ "pending inval(%lu) cleanings(%lu), fallow cleanings(%lu) " \
"checksum invalid(%ld), checksum store(%ld), checksum valid(%ld)" \
"front merge(%ld) back merge(%ld)",
dmc->reads, dmc->writes, dmc->read_hits, dmc->write_hits,
dmc->read_hits*100/dmc->reads,
dmc->replace, dmc->wr_invalidates, dmc->rd_invalidates,
- dmc->wr_replace, dmc->enqueues, dmc->pending_inval, dmc->cleanings,
+ dmc->wr_replace, dmc->enqueues,
+ dmc->pending_inval, dmc->cleanings, dmc->fallow_cleanings,
dmc->checksum_store, dmc->checksum_valid, dmc->checksum_invalid,
dmc->front_merge, dmc->back_merge);
#else
DMINFO("stats: reads(%lu), writes(%lu), read hits(%lu), write hits(%lu), " \
"read hit percent(%ld), replacement(%lu), write invalidates(%lu), " \
"read invalidates(%lu), write replacement(%lu), pending enqueues(%lu), " \
- "pending inval(%lu) cleanings(%lu)" \
+ "pending inval(%lu) cleanings(%lu) fallow cleanings(%lu)" \
"front merge(%ld) back merge(%ld)",
dmc->reads, dmc->writes, dmc->read_hits, dmc->write_hits,
dmc->read_hits*100/dmc->reads,
dmc->replace, dmc->wr_invalidates, dmc->rd_invalidates,
- dmc->wr_replace, dmc->enqueues, dmc->pending_inval, dmc->cleanings,
+ dmc->wr_replace, dmc->enqueues,
+ dmc->pending_inval, dmc->cleanings, dmc->fallow_cleanings,
dmc->front_merge, dmc->back_merge);
#endif
@@ -1709,7 +1723,7 @@ flashcache_status_info(struct cache_c *dmc, status_type_t type,
"\tpending enqueues(%lu), pending inval(%lu)\n" \
"\tmetadata dirties(%lu), metadata cleans(%lu)\n" \
"\tmetadata batch(%lu) metadata ssd writes(%lu)\n" \
- "\tcleanings(%lu), no room(%lu) front merge(%lu) back merge(%lu)\n" \
+ "\tcleanings(%lu) fallow cleanings(%lu) no room(%lu) front merge(%lu) back merge(%lu)\n" \
"\tdisk reads(%lu), disk writes(%lu) ssd reads(%lu) ssd writes(%lu)\n" \
"\tuncached reads(%lu), uncached writes(%lu), uncached IO requeue(%lu)\n" \
"\tpid_adds(%lu), pid_dels(%lu), pid_drops(%lu) pid_expiry(%lu)",
@@ -1721,7 +1735,7 @@ flashcache_status_info(struct cache_c *dmc, status_type_t type,
dmc->enqueues, dmc->pending_inval,
dmc->md_write_dirty, dmc->md_write_clean,
dmc->md_write_batch, dmc->md_ssd_writes,
- dmc->cleanings, dmc->noroom, dmc->front_merge, dmc->back_merge,
+ dmc->cleanings, dmc->fallow_cleanings, dmc->noroom, dmc->front_merge, dmc->back_merge,
dmc->disk_reads, dmc->disk_writes, dmc->ssd_reads, dmc->ssd_writes,
dmc->uncached_reads, dmc->uncached_writes, dmc->uncached_io_requeue,
dmc->pid_adds, dmc->pid_dels, dmc->pid_drops, dmc->expiry);
@@ -1734,7 +1748,7 @@ flashcache_status_info(struct cache_c *dmc, status_type_t type,
"\tpending enqueues(%lu) pending inval(%lu)\n" \
"\tmetadata dirties(%lu) metadata cleans(%lu)\n" \
"\tmetadata batch(%lu) metadata ssd writes(%lu)\n" \
- "\tcleanings(%lu) no room(%lu) front merge(%lu) back merge(%lu)\n" \
+ "\tcleanings(%lu) fallow cleanings(%lu) no room(%lu) front merge(%lu) back merge(%lu)\n" \
"\tdisk reads(%lu) disk writes(%lu) ssd reads(%lu) ssd writes(%lu)\n" \
"\tuncached reads(%lu) uncached writes(%lu), uncached IO requeue(%lu)\n" \
"\tpid_adds(%lu) pid_dels(%lu) pid_drops(%lu) pid_expiry(%lu)",
@@ -1745,7 +1759,7 @@ flashcache_status_info(struct cache_c *dmc, status_type_t type,
dmc->enqueues, dmc->pending_inval,
dmc->md_write_dirty, dmc->md_write_clean,
dmc->md_write_batch, dmc->md_ssd_writes,
- dmc->cleanings, dmc->noroom, dmc->front_merge, dmc->back_merge,
+ dmc->cleanings, dmc->fallow_cleanings, dmc->noroom, dmc->front_merge, dmc->back_merge,
dmc->disk_reads, dmc->disk_writes, dmc->ssd_reads, dmc->ssd_writes,
dmc->uncached_reads, dmc->uncached_writes, dmc->uncached_io_requeue,
dmc->pid_adds, dmc->pid_dels, dmc->pid_drops, dmc->expiry);
Oops, something went wrong. Retry.

0 comments on commit a9cf0f7

Please sign in to comment.