diff --git a/CLI/eio_cli b/CLI/eio_cli index fd8b71f..8c26619 100755 --- a/CLI/eio_cli +++ b/CLI/eio_cli @@ -227,10 +227,10 @@ def sanity(hdd, ssd): # Performs a very basic regression of operations modes = {3:"Write Through", 1:"Write Back", 2:"Read Only",0:"N/A"} - policies = {3:"rand", 1:"fifo", 2:"lru", 0:"N/A"} + policies = {4:"lifo",3:"rand", 1:"fifo", 2:"lru", 0:"N/A"} blksizes = {"4096":4096, "2048":2048, "8192":8192,"":0} for mode in ["wb","wt","ro"]: - for policy in ["rand","fifo","lru"]: + for policy in ["lifo","rand","fifo","lru"]: for blksize in ["4096","2048","8192"]: cache = Cache_rec(name = "test_cache", src_name = hdd,\ ssd_name = ssd, policy = policy, mode = mode,\ @@ -265,7 +265,7 @@ class Cache_rec(Structure): blksize="", assoc=""): modes = {"wt":3,"wb":1,"ro":2,"":0} - policies = {"rand":3,"fifo":1, "lru":2,"":0} + policies = {"lifo":4,"rand":3,"fifo":1, "lru":2,"":0} blksizes = {"4096":4096, "2048":2048, "8192":8192,"":0} associativity = {2048:128, 4096:256, 8192:512,0:0} @@ -288,7 +288,7 @@ class Cache_rec(Structure): # Display Cache info modes = {3:"Write Through", 1:"Write Back", 2:"Read Only",0:"N/A"} - policies = {3:"rand", 1:"fifo", 2:"lru", 0:"N/A"} + policies = {4:"lifo", 3:"rand", 1:"fifo", 2:"lru", 0:"N/A"} print "Cache Name : " + self.name print "Source Device : " + self.src_name @@ -404,7 +404,7 @@ class Cache_rec(Structure): cache_match_expr = make_udev_match_expr(self.ssd_name, self.name) print cache_match_expr modes = {3:"wt", 1:"wb", 2:"ro",0:"N/A"} - policies = {3:"rand", 1:"fifo", 2:"lru", 0:"N/A"} + policies = {4:"lifo", 3:"rand", 1:"fifo", 2:"lru", 0:"N/A"} try: udev_rule = udev_template.replace("",\ @@ -485,7 +485,7 @@ def create_parser(): parser_edit.add_argument("-m", action="store", dest="mode", \ choices=["wb","wt","ro"], help="cache mode",default="") parser_edit.add_argument("-p", action="store", dest="policy", \ - choices=["rand","fifo","lru"], help="cache \ + choices=["lifo","rand","fifo","lru"], help="cache \ replacement policy",default="") #info @@ -504,7 +504,7 @@ def create_parser(): parser_create.add_argument("-s", action="store", dest="ssd",\ required=True, help="name of the ssd device") parser_create.add_argument("-p", action="store", dest="policy",\ - choices=["rand","fifo","lru"],\ + choices=["lifo","rand","fifo","lru"],\ help="cache replacement policy",default="lru") parser_create.add_argument("-m", action="store", dest="mode",\ choices=["wb","wt","ro"],\ @@ -521,7 +521,7 @@ def create_parser(): parser_enable.add_argument("-s", action="store", dest="ssd",\ required=True, help="name of the ssd device") parser_enable.add_argument("-p", action="store", dest="policy", - choices=["rand","fifo","lru"],\ + choices=["lifo","rand","fifo","lru"],\ help="cache replacement policy",default="lru") parser_enable.add_argument("-m", action="store", dest="mode",\ choices=["wb","wt","ro"],\ @@ -563,6 +563,7 @@ def main(): run_cmd("/sbin/modprobe enhanceio_fifo") run_cmd("/sbin/modprobe enhanceio_lru") run_cmd("/sbin/modprobe enhanceio_rand") + run_cmd("/sbin/modprobe enhanceio_lifo") f = open("/run/eio.lock", "w") fcntl.flock(f, fcntl.LOCK_EX) diff --git a/Driver/enhanceio/Kconfig b/Driver/enhanceio/Kconfig index 15d44ff..aee311f 100644 --- a/Driver/enhanceio/Kconfig +++ b/Driver/enhanceio/Kconfig @@ -15,7 +15,7 @@ config ENHANCEIO The caching engine is a loadable kernel module ("enhanceio.ko") implemented as a device mapper target. The cache replacement policies are implemented as loadable kernel modules - ("enhanceio_fifo.ko", "enhanceio_lru.ko") that register with + ("enhanceio_fifo.ko", "enhanceio_lru.ko", "enhanceio_lifo.ko") that register with the caching engine module. If unsure, say N. diff --git a/Driver/enhanceio/Makefile b/Driver/enhanceio/Makefile index 5d3351b..a669c60 100644 --- a/Driver/enhanceio/Makefile +++ b/Driver/enhanceio/Makefile @@ -7,7 +7,7 @@ KERNEL_SOURCE_VERSION ?= $(shell uname -r) KERNEL_TREE ?= /lib/modules/$(KERNEL_SOURCE_VERSION)/build EXTRA_CFLAGS += -I$(KERNEL_TREE)/drivers/md -I./ -DCOMMIT_REV="\"$(COMMIT_REV)\"" EXTRA_CFLAGS += -I$(KERNEL_TREE)/include/ -I$(KERNEL_TREE)/include/linux -obj-m += enhanceio.o enhanceio_lru.o enhanceio_fifo.o enhanceio_rand.o +obj-m += enhanceio.o enhanceio_lru.o enhanceio_fifo.o enhanceio_rand.o enhanceio_lifo.o enhanceio-y += \ eio_conf.o \ eio_ioctl.o \ @@ -20,6 +20,7 @@ enhanceio-y += \ eio_ttc.o enhanceio_fifo-y += eio_fifo.o enhanceio_rand-y += eio_rand.o +enhanceio_lifo-y += eio_lifo.o enhanceio_lru-y += eio_lru.o .PHONY: all all: modules @@ -33,6 +34,7 @@ modules_install: modules install -o root -g root -m 0755 enhanceio_rand.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ install -o root -g root -m 0755 enhanceio_fifo.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ install -o root -g root -m 0755 enhanceio_lru.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ + install -o root -g root -m 0755 enhanceio_lifo.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ depmod -a .PHONY: install install: modules_install diff --git a/Driver/enhanceio/dkms.conf b/Driver/enhanceio/dkms.conf index d00398a..ebcd5fa 100644 --- a/Driver/enhanceio/dkms.conf +++ b/Driver/enhanceio/dkms.conf @@ -13,3 +13,7 @@ DEST_MODULE_LOCATION[1]="/updates" BUILT_MODULE_NAME[2]="enhanceio_lru" DEST_MODULE_LOCATION[2]="/updates" + + +BUILT_MODULE_NAME[3]="enhanceio_lifo" +DEST_MODULE_LOCATION[3]="/updates" diff --git a/Driver/enhanceio/eio.h b/Driver/enhanceio/eio.h index 49f0861..d0ee0e8 100644 --- a/Driver/enhanceio/eio.h +++ b/Driver/enhanceio/eio.h @@ -379,8 +379,9 @@ struct flash_cacheblock { #define CACHE_REPL_FIFO 1 #define CACHE_REPL_LRU 2 #define CACHE_REPL_RANDOM 3 +#define CACHE_REPL_LIFO 4 #define CACHE_REPL_FIRST CACHE_REPL_FIFO -#define CACHE_REPL_LAST CACHE_REPL_RANDOM +#define CACHE_REPL_LAST CACHE_REPL_LIFO #define CACHE_REPL_DEFAULT CACHE_REPL_FIFO struct eio_policy_and_name { @@ -393,6 +394,7 @@ static const struct eio_policy_and_name eio_policy_names[] = { { CACHE_REPL_FIFO, "fifo" }, { CACHE_REPL_LRU, "lru" }, { CACHE_REPL_RANDOM, "rand" }, + { CACHE_REPL_LIFO, "lifo" }, }; diff --git a/Driver/enhanceio/eio_fifo.c b/Driver/enhanceio/eio_fifo.c index 117fe06..bb1dc98 100644 --- a/Driver/enhanceio/eio_fifo.c +++ b/Driver/enhanceio/eio_fifo.c @@ -236,4 +236,4 @@ module_exit(fifo_unregister); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("FIFO policy for EnhanceIO"); -MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); +MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); \ No newline at end of file diff --git a/Driver/enhanceio/eio_lifo.c b/Driver/enhanceio/eio_lifo.c new file mode 100644 index 0000000..4187650 --- /dev/null +++ b/Driver/enhanceio/eio_lifo.c @@ -0,0 +1,237 @@ +/* + * eio_lifo.c + * + * Copyright (C) 2012 STEC, Inc. All rights not specifically granted + * under a license included herein are reserved + * Made EnhanceIO specific changes. + * Saied Kazemi + * Siddharth Choudhuri + * + * Copyright 2010 Facebook, Inc. + * Author: Mohan Srinivasan (mohan@facebook.com) + * + * Based on DM-Cache: + * Copyright (C) International Business Machines Corp., 2006 + * Author: Ming Zhao (mingzhao@ufl.edu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "eio.h" +/* Generic policy functions prototypes */ +int eio_lifo_init(struct cache_c *); +void eio_lifo_exit(void); +int eio_lifo_cache_sets_init(struct eio_policy *); +int eio_lifo_cache_blk_init(struct eio_policy *); +void eio_lifo_find_reclaim_dbn(struct eio_policy *, index_t, index_t *); +int eio_lifo_clean_set(struct eio_policy *, index_t, int); + +/* Per policy instance initialization */ +struct eio_policy *eio_lifo_instance_init(void); + +/* Per cache set data structure */ +struct eio_lifo_cache_set { + index_t set_lifo_next; + index_t set_clean_next; +}; + +/* + * Context that captures the LIFO replacement policy + */ +static struct eio_policy_header eio_lifo_ops = { + .sph_name = CACHE_REPL_LIFO, + .sph_instance_init = eio_lifo_instance_init, +}; + +/* + * Initialize LIFO policy. + */ +int eio_lifo_init(struct cache_c *dmc) +{ + return 0; +} + +/* + * Initialize LIFO data structure called from ctr. + */ +int eio_lifo_cache_sets_init(struct eio_policy *p_ops) +{ + int i; + sector_t order; + struct cache_c *dmc = p_ops->sp_dmc; + struct eio_lifo_cache_set *cache_sets; + + pr_info("Initializing lifo cache sets\n"); + order = (dmc->size >> dmc->consecutive_shift) * + sizeof(struct eio_lifo_cache_set); + + dmc->sp_cache_set = vmalloc((size_t)order); + if (dmc->sp_cache_set == NULL) + return -ENOMEM; + + cache_sets = (struct eio_lifo_cache_set *)dmc->sp_cache_set; + + for (i = 0; i < (int)(dmc->size >> dmc->consecutive_shift); i++) { + cache_sets[i].set_lifo_next = i * dmc->assoc; + cache_sets[i].set_clean_next = i * dmc->assoc; + } + + return 0; +} + +/* + * The actual function that returns a victim block in index. + */ +void eio_lifo_find_reclaim_dbn(struct eio_policy *p_ops, index_t start_index, + index_t *index) +{ + index_t end_index; + int slots_searched = 0; + index_t i; + index_t set; + struct eio_lifo_cache_set *cache_sets; + struct cache_c *dmc = p_ops->sp_dmc; + + set = start_index / dmc->assoc; + end_index = start_index + dmc->assoc; + cache_sets = (struct eio_lifo_cache_set *)dmc->sp_cache_set; + + i = cache_sets[set].set_lifo_next; + while (slots_searched < (int)dmc->assoc) { + EIO_ASSERT(i >= start_index); + EIO_ASSERT(i < end_index); + if (EIO_CACHE_STATE_GET(dmc, i) == VALID) { + *index = i; + break; + } + slots_searched++; + i--; + if (i == start_index - 1) + i = end_index - 1; + } + i--; + if (i == start_index - 1) + i = end_index - 1; + cache_sets[set].set_lifo_next = i; +} + +/* + * Go through the entire set and clean. + */ +int eio_lifo_clean_set(struct eio_policy *p_ops, index_t set, int to_clean) +{ + index_t i; + int scanned = 0, nr_writes = 0; + index_t start_index; + index_t end_index; + struct eio_lifo_cache_set *cache_sets; + struct cache_c *dmc; + + dmc = p_ops->sp_dmc; + cache_sets = (struct eio_lifo_cache_set *)dmc->sp_cache_set; + start_index = set * dmc->assoc; + end_index = start_index + dmc->assoc; + i = cache_sets[set].set_clean_next; + + while ((scanned < (int)dmc->assoc) && (nr_writes < to_clean)) { + if ((EIO_CACHE_STATE_GET(dmc, i) & (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { + EIO_CACHE_STATE_ON(dmc, i, DISKWRITEINPROG); + nr_writes++; + } + scanned++; + i++; + if (i == end_index) + i = start_index; + } + cache_sets[set].set_clean_next = i; + + return nr_writes; +} + +/* + * LIFO is per set, so do nothing on a per block init. + */ +int eio_lifo_cache_blk_init(struct eio_policy *p_ops) +{ + return 0; +} + +/* + * Allocate a new instance of eio_policy per dmc + */ +struct eio_policy *eio_lifo_instance_init(void) +{ + struct eio_policy *new_instance; + + new_instance = vmalloc(sizeof(struct eio_policy)); + if (new_instance == NULL) { + pr_err("ssdscache_lifo_instance_init: vmalloc failed"); + return NULL; + } + + /* Initialize the LIFO specific functions and variables */ + new_instance->sp_name = CACHE_REPL_LIFO; + new_instance->sp_policy.lru = NULL; + new_instance->sp_repl_init = eio_lifo_init; + new_instance->sp_repl_exit = eio_lifo_exit; + new_instance->sp_repl_sets_init = eio_lifo_cache_sets_init; + new_instance->sp_repl_blk_init = eio_lifo_cache_blk_init; + new_instance->sp_find_reclaim_dbn = eio_lifo_find_reclaim_dbn; + new_instance->sp_clean_set = eio_lifo_clean_set; + new_instance->sp_dmc = NULL; + + try_module_get(THIS_MODULE); + + pr_info("eio_lifo_instance_init: created new instance of LIFO"); + + return new_instance; +} + +/* + * Cleanup an instance of eio_policy (called from dtr). + */ +void eio_lifo_exit(void) +{ + module_put(THIS_MODULE); +} + +static +int __init lifo_register(void) +{ + int ret; + + ret = eio_register_policy(&eio_lifo_ops); + if (ret != 0) + pr_info("eio_lifo already registered"); + + return ret; +} + +static +void __exit lifo_unregister(void) +{ + int ret; + + ret = eio_unregister_policy(&eio_lifo_ops); + if (ret != 0) + pr_err("eio_lifo unregister failed"); +} + +module_init(lifo_register); +module_exit(lifo_unregister); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LIFO policy for EnhanceIO"); +MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); diff --git a/Install-EIO b/Install-EIO index 0bc4b83..678cae1 100755 --- a/Install-EIO +++ b/Install-EIO @@ -102,6 +102,8 @@ _LoadMods () ${SBPREFIX}modprobe enhanceio_rand && ${SBPREFIX}modprobe enhanceio_fifo && ${SBPREFIX}modprobe enhanceio_lru && + ${SBPREFIX}modprobe enhanceio_lifo && + return 0 return 1 } diff --git a/Install.txt b/Install.txt index dd83f59..c4ca106 100644 --- a/Install.txt +++ b/Install.txt @@ -113,6 +113,7 @@ Loading Modules: # modprode enhanceio_rand # modprode enhanceio_fifo # modprode enhanceio_lru + # modprode enhanceio_lifo Once the modules have been loaded you will be able to use eio_cli to create/modify caches.