···2121conform to certain policies as follows:22222323An "init" prepares the device to receive frontswap pages associated2424-with the specified swap device number (aka "type"). A "put_page" will2424+with the specified swap device number (aka "type"). A "store" will2525copy the page to transcendent memory and associate it with the type and2626-offset associated with the page. A "get_page" will copy the page, if found,2626+offset associated with the page. A "load" will copy the page, if found,2727from transcendent memory into kernel memory, but will NOT remove the page2828from from transcendent memory. An "invalidate_page" will remove the page2929from transcendent memory and an "invalidate_area" will remove ALL pages3030associated with the swap type (e.g., like swapoff) and notify the "device"3131-to refuse further puts with that swap type.3131+to refuse further stores with that swap type.32323333-Once a page is successfully put, a matching get on the page will normally3333+Once a page is successfully stored, a matching load on the page will normally3434succeed. So when the kernel finds itself in a situation where it needs3535-to swap out a page, it first attempts to use frontswap. If the put returns3535+to swap out a page, it first attempts to use frontswap. If the store returns3636success, the data has been successfully saved to transcendent memory and3737a disk write and, if the data is later read back, a disk read are avoided.3838-If a put returns failure, transcendent memory has rejected the data, and the3838+If a store returns failure, transcendent memory has rejected the data, and the3939page can be written to swap as usual.40404141If a backend chooses, frontswap can be configured as a "writethrough···4444in order to allow the backend to arbitrarily "reclaim" space used to4545store frontswap pages to more completely manage its memory usage.46464747-Note that if a page is put and the page already exists in transcendent memory4848-(a "duplicate" put), either the put succeeds and the data is overwritten,4949-or the put fails AND the page is invalidated. This ensures stale data may4747+Note that if a page is stored and the page already exists in transcendent memory4848+(a "duplicate" store), either the store succeeds and the data is overwritten,4949+or the store fails AND the page is invalidated. This ensures stale data may5050never be obtained from frontswap.51515252If properly configured, monitoring of frontswap is done via debugfs in5353the /sys/kernel/debug/frontswap directory. The effectiveness of5454frontswap can be measured (across all swap devices) with:55555656-failed_puts - how many put attempts have failed5757-gets - how many gets were attempted (all should succeed)5858-succ_puts - how many put attempts have succeeded5656+failed_stores - how many store attempts have failed5757+loads - how many loads were attempted (all should succeed)5858+succ_stores - how many store attempts have succeeded5959invalidates - how many invalidates were attempted60606161A backend implementation may provide additional metrics.···125125swap device. If CONFIG_FRONTSWAP is enabled but no frontswap "backend"126126registers, there is one extra global variable compared to zero for127127every swap page read or written. If CONFIG_FRONTSWAP is enabled128128-AND a frontswap backend registers AND the backend fails every "put"128128+AND a frontswap backend registers AND the backend fails every "store"129129request (i.e. provides no memory despite claiming it might),130130CPU overhead is still negligible -- and since every frontswap fail131131precedes a swap page write-to-disk, the system is highly likely···159159160160Whenever a swap-device is swapon'd frontswap_init() is called,161161passing the swap device number (aka "type") as a parameter.162162-This notifies frontswap to expect attempts to "put" swap pages162162+This notifies frontswap to expect attempts to "store" swap pages163163associated with that number.164164165165Whenever the swap subsystem is readying a page to write to a swap166166-device (c.f swap_writepage()), frontswap_put_page is called. Frontswap166166+device (c.f swap_writepage()), frontswap_store is called. Frontswap167167consults with the frontswap backend and if the backend says it does NOT168168-have room, frontswap_put_page returns -1 and the kernel swaps the page168168+have room, frontswap_store returns -1 and the kernel swaps the page169169to the swap device as normal. Note that the response from the frontswap170170backend is unpredictable to the kernel; it may choose to never accept a171171page, it could accept every ninth page, or it might accept every···177177otherwise have written the data.178178179179When the swap subsystem needs to swap-in a page (swap_readpage()),180180-it first calls frontswap_get_page() which checks the frontswap_map to180180+it first calls frontswap_load() which checks the frontswap_map to181181see if the page was earlier accepted by the frontswap backend. If182182it was, the page of data is filled from the frontswap backend and183183the swap-in is complete. If not, the normal swap-in code is···185185186186So every time the frontswap backend accepts a page, a swap device read187187and (potentially) a swap device write are replaced by a "frontswap backend188188-put" and (possibly) a "frontswap backend get", which are presumably much188188+store" and (possibly) a "frontswap backend loads", which are presumably much189189faster.1901901911914) Can't frontswap be configured as a "special" swap device that is···215215the write of some pages for a significant amount of time. Synchrony is216216required to ensure the dynamicity of the backend and to avoid thorny race217217conditions that would unnecessarily and greatly complicate frontswap218218-and/or the block I/O subsystem. That said, only the initial "put"219219-and "get" operations need be synchronous. A separate asynchronous thread218218+and/or the block I/O subsystem. That said, only the initial "store"219219+and "load" operations need be synchronous. A separate asynchronous thread220220is free to manipulate the pages stored by frontswap. For example,221221the "remotification" thread in RAMster uses standard asynchronous222222kernel sockets to move compressed frontswap pages to a remote machine.···229229then force guests to do their own swapping.230230231231There is a downside to the transcendent memory specifications for232232-frontswap: Since any "put" might fail, there must always be a real232232+frontswap: Since any "store" might fail, there must always be a real233233slot on a real swap device to swap the page. Thus frontswap must be234234implemented as a "shadow" to every swapon'd device with the potential235235capability of holding every page that the swap device might have held···240240can still use frontswap but a backend for such devices must configure241241some kind of "ghost" swap device and ensure that it is never used.242242243243-5) Why this weird definition about "duplicate puts"? If a page244244- has been previously successfully put, can't it always be243243+5) Why this weird definition about "duplicate stores"? If a page244244+ has been previously successfully stored, can't it always be245245 successfully overwritten?246246247247Nearly always it can, but no, sometimes it cannot. Consider an example248248where data is compressed and the original 4K page has been compressed249249to 1K. Now an attempt is made to overwrite the page with data that250250is non-compressible and so would take the entire 4K. But the backend251251-has no more space. In this case, the put must be rejected. Whenever252252-frontswap rejects a put that would overwrite, it also must invalidate251251+has no more space. In this case, the store must be rejected. Whenever252252+frontswap rejects a store that would overwrite, it also must invalidate253253the old data and ensure that it is no longer accessible. Since the254254swap subsystem then writes the new data to the read swap device,255255this is the correct course of action to ensure coherency.
+4-4
drivers/staging/ramster/zcache-main.c
···30023002 return oid;30033003}3004300430053005-static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,30053005+static int zcache_frontswap_store(unsigned type, pgoff_t offset,30063006 struct page *page)30073007{30083008 u64 ind64 = (u64)offset;···3025302530263026/* returns 0 if the page was successfully gotten from frontswap, -1 if30273027 * was not present (should never happen!) */30283028-static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,30283028+static int zcache_frontswap_load(unsigned type, pgoff_t offset,30293029 struct page *page)30303030{30313031 u64 ind64 = (u64)offset;···30803080}3081308130823082static struct frontswap_ops zcache_frontswap_ops = {30833083- .put_page = zcache_frontswap_put_page,30843084- .get_page = zcache_frontswap_get_page,30833083+ .store = zcache_frontswap_store,30843084+ .load = zcache_frontswap_load,30853085 .invalidate_page = zcache_frontswap_flush_page,30863086 .invalidate_area = zcache_frontswap_flush_area,30873087 .init = zcache_frontswap_init
+5-5
drivers/staging/zcache/zcache-main.c
···18351835 * Swizzling increases objects per swaptype, increasing tmem concurrency18361836 * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS18371837 * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from18381838- * frontswap_get_page(), but has side-effects. Hence using 8.18381838+ * frontswap_load(), but has side-effects. Hence using 8.18391839 */18401840#define SWIZ_BITS 818411841#define SWIZ_MASK ((1 << SWIZ_BITS) - 1)···18491849 return oid;18501850}1851185118521852-static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,18521852+static int zcache_frontswap_store(unsigned type, pgoff_t offset,18531853 struct page *page)18541854{18551855 u64 ind64 = (u64)offset;···1870187018711871/* returns 0 if the page was successfully gotten from frontswap, -1 if18721872 * was not present (should never happen!) */18731873-static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,18731873+static int zcache_frontswap_load(unsigned type, pgoff_t offset,18741874 struct page *page)18751875{18761876 u64 ind64 = (u64)offset;···19191919}1920192019211921static struct frontswap_ops zcache_frontswap_ops = {19221922- .put_page = zcache_frontswap_put_page,19231923- .get_page = zcache_frontswap_get_page,19221922+ .store = zcache_frontswap_store,19231923+ .load = zcache_frontswap_load,19241924 .invalidate_page = zcache_frontswap_flush_page,19251925 .invalidate_area = zcache_frontswap_flush_area,19261926 .init = zcache_frontswap_init
+4-4
drivers/xen/tmem.c
···269269}270270271271/* returns 0 if the page was successfully put into frontswap, -1 if not */272272-static int tmem_frontswap_put_page(unsigned type, pgoff_t offset,272272+static int tmem_frontswap_store(unsigned type, pgoff_t offset,273273 struct page *page)274274{275275 u64 ind64 = (u64)offset;···295295 * returns 0 if the page was successfully gotten from frontswap, -1 if296296 * was not present (should never happen!)297297 */298298-static int tmem_frontswap_get_page(unsigned type, pgoff_t offset,298298+static int tmem_frontswap_load(unsigned type, pgoff_t offset,299299 struct page *page)300300{301301 u64 ind64 = (u64)offset;···362362__setup("nofrontswap", no_frontswap);363363364364static struct frontswap_ops __initdata tmem_frontswap_ops = {365365- .put_page = tmem_frontswap_put_page,366366- .get_page = tmem_frontswap_get_page,365365+ .store = tmem_frontswap_store,366366+ .load = tmem_frontswap_load,367367 .invalidate_page = tmem_frontswap_flush_page,368368 .invalidate_area = tmem_frontswap_flush_area,369369 .init = tmem_frontswap_init
+8-8
include/linux/frontswap.h
···7788struct frontswap_ops {99 void (*init)(unsigned);1010- int (*put_page)(unsigned, pgoff_t, struct page *);1111- int (*get_page)(unsigned, pgoff_t, struct page *);1010+ int (*store)(unsigned, pgoff_t, struct page *);1111+ int (*load)(unsigned, pgoff_t, struct page *);1212 void (*invalidate_page)(unsigned, pgoff_t);1313 void (*invalidate_area)(unsigned);1414};···2121extern void frontswap_writethrough(bool);22222323extern void __frontswap_init(unsigned type);2424-extern int __frontswap_put_page(struct page *page);2525-extern int __frontswap_get_page(struct page *page);2424+extern int __frontswap_store(struct page *page);2525+extern int __frontswap_load(struct page *page);2626extern void __frontswap_invalidate_page(unsigned, pgoff_t);2727extern void __frontswap_invalidate_area(unsigned);2828···8888}8989#endif90909191-static inline int frontswap_put_page(struct page *page)9191+static inline int frontswap_store(struct page *page)9292{9393 int ret = -1;94949595 if (frontswap_enabled)9696- ret = __frontswap_put_page(page);9696+ ret = __frontswap_store(page);9797 return ret;9898}9999100100-static inline int frontswap_get_page(struct page *page)100100+static inline int frontswap_load(struct page *page)101101{102102 int ret = -1;103103104104 if (frontswap_enabled)105105- ret = __frontswap_get_page(page);105105+ ret = __frontswap_load(page);106106 return ret;107107}108108
+28-28
mm/frontswap.c
···3939EXPORT_SYMBOL(frontswap_enabled);40404141/*4242- * If enabled, frontswap_put will return failure even on success. As4242+ * If enabled, frontswap_store will return failure even on success. As4343 * a result, the swap subsystem will always write the page to swap, in4444 * effect converting frontswap into a writethrough cache. In this mode,4545 * there is no direct reduction in swap writes, but a frontswap backend···5454 * properly configured). These are for information only so are not protected5555 * against increment races.5656 */5757-static u64 frontswap_gets;5858-static u64 frontswap_succ_puts;5959-static u64 frontswap_failed_puts;5757+static u64 frontswap_loads;5858+static u64 frontswap_succ_stores;5959+static u64 frontswap_failed_stores;6060static u64 frontswap_invalidates;61616262-static inline void inc_frontswap_gets(void) {6363- frontswap_gets++;6262+static inline void inc_frontswap_loads(void) {6363+ frontswap_loads++;6464}6565-static inline void inc_frontswap_succ_puts(void) {6666- frontswap_succ_puts++;6565+static inline void inc_frontswap_succ_stores(void) {6666+ frontswap_succ_stores++;6767}6868-static inline void inc_frontswap_failed_puts(void) {6969- frontswap_failed_puts++;6868+static inline void inc_frontswap_failed_stores(void) {6969+ frontswap_failed_stores++;7070}7171static inline void inc_frontswap_invalidates(void) {7272 frontswap_invalidates++;7373}7474#else7575-static inline void inc_frontswap_gets(void) { }7676-static inline void inc_frontswap_succ_puts(void) { }7777-static inline void inc_frontswap_failed_puts(void) { }7575+static inline void inc_frontswap_loads(void) { }7676+static inline void inc_frontswap_succ_stores(void) { }7777+static inline void inc_frontswap_failed_stores(void) { }7878static inline void inc_frontswap_invalidates(void) { }7979#endif8080/*···116116EXPORT_SYMBOL(__frontswap_init);117117118118/*119119- * "Put" data from a page to frontswap and associate it with the page's119119+ * "Store" data from a page to frontswap and associate it with the page's120120 * swaptype and offset. Page must be locked and in the swap cache.121121 * If frontswap already contains a page with matching swaptype and122122 * offset, the frontswap implmentation may either overwrite the data and123123 * return success or invalidate the page from frontswap and return failure.124124 */125125-int __frontswap_put_page(struct page *page)125125+int __frontswap_store(struct page *page)126126{127127 int ret = -1, dup = 0;128128 swp_entry_t entry = { .val = page_private(page), };···134134 BUG_ON(sis == NULL);135135 if (frontswap_test(sis, offset))136136 dup = 1;137137- ret = (*frontswap_ops.put_page)(type, offset, page);137137+ ret = (*frontswap_ops.store)(type, offset, page);138138 if (ret == 0) {139139 frontswap_set(sis, offset);140140- inc_frontswap_succ_puts();140140+ inc_frontswap_succ_stores();141141 if (!dup)142142 atomic_inc(&sis->frontswap_pages);143143 } else if (dup) {···147147 */148148 frontswap_clear(sis, offset);149149 atomic_dec(&sis->frontswap_pages);150150- inc_frontswap_failed_puts();150150+ inc_frontswap_failed_stores();151151 } else152152- inc_frontswap_failed_puts();152152+ inc_frontswap_failed_stores();153153 if (frontswap_writethrough_enabled)154154 /* report failure so swap also writes to swap device */155155 ret = -1;156156 return ret;157157}158158-EXPORT_SYMBOL(__frontswap_put_page);158158+EXPORT_SYMBOL(__frontswap_store);159159160160/*161161 * "Get" data from frontswap associated with swaptype and offset that were162162 * specified when the data was put to frontswap and use it to fill the163163 * specified page with data. Page must be locked and in the swap cache.164164 */165165-int __frontswap_get_page(struct page *page)165165+int __frontswap_load(struct page *page)166166{167167 int ret = -1;168168 swp_entry_t entry = { .val = page_private(page), };···173173 BUG_ON(!PageLocked(page));174174 BUG_ON(sis == NULL);175175 if (frontswap_test(sis, offset))176176- ret = (*frontswap_ops.get_page)(type, offset, page);176176+ ret = (*frontswap_ops.load)(type, offset, page);177177 if (ret == 0)178178- inc_frontswap_gets();178178+ inc_frontswap_loads();179179 return ret;180180}181181-EXPORT_SYMBOL(__frontswap_get_page);181181+EXPORT_SYMBOL(__frontswap_load);182182183183/*184184 * Invalidate any data from frontswap associated with the specified swaptype···301301 struct dentry *root = debugfs_create_dir("frontswap", NULL);302302 if (root == NULL)303303 return -ENXIO;304304- debugfs_create_u64("gets", S_IRUGO, root, &frontswap_gets);305305- debugfs_create_u64("succ_puts", S_IRUGO, root, &frontswap_succ_puts);306306- debugfs_create_u64("failed_puts", S_IRUGO, root,307307- &frontswap_failed_puts);304304+ debugfs_create_u64("loads", S_IRUGO, root, &frontswap_loads);305305+ debugfs_create_u64("succ_stores", S_IRUGO, root, &frontswap_succ_stores);306306+ debugfs_create_u64("failed_stores", S_IRUGO, root,307307+ &frontswap_failed_stores);308308 debugfs_create_u64("invalidates", S_IRUGO,309309 root, &frontswap_invalidates);310310#endif
+2-2
mm/page_io.c
···9999 unlock_page(page);100100 goto out;101101 }102102- if (frontswap_put_page(page) == 0) {102102+ if (frontswap_store(page) == 0) {103103 set_page_writeback(page);104104 unlock_page(page);105105 end_page_writeback(page);···129129130130 VM_BUG_ON(!PageLocked(page));131131 VM_BUG_ON(PageUptodate(page));132132- if (frontswap_get_page(page) == 0) {132132+ if (frontswap_load(page) == 0) {133133 SetPageUptodate(page);134134 unlock_page(page);135135 goto out;