Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.2-rc4 277 lines 8.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Frontswap frontend 4 * 5 * This code provides the generic "frontend" layer to call a matching 6 * "backend" driver implementation of frontswap. See 7 * Documentation/mm/frontswap.rst for more information. 8 * 9 * Copyright (C) 2009-2012 Oracle Corp. All rights reserved. 10 * Author: Dan Magenheimer 11 */ 12 13#include <linux/mman.h> 14#include <linux/swap.h> 15#include <linux/swapops.h> 16#include <linux/security.h> 17#include <linux/module.h> 18#include <linux/debugfs.h> 19#include <linux/frontswap.h> 20#include <linux/swapfile.h> 21 22DEFINE_STATIC_KEY_FALSE(frontswap_enabled_key); 23 24/* 25 * frontswap_ops are added by frontswap_register_ops, and provide the 26 * frontswap "backend" implementation functions. Multiple implementations 27 * may be registered, but implementations can never deregister. This 28 * is a simple singly-linked list of all registered implementations. 29 */ 30static const struct frontswap_ops *frontswap_ops __read_mostly; 31 32#ifdef CONFIG_DEBUG_FS 33/* 34 * Counters available via /sys/kernel/debug/frontswap (if debugfs is 35 * properly configured). These are for information only so are not protected 36 * against increment races. 37 */ 38static u64 frontswap_loads; 39static u64 frontswap_succ_stores; 40static u64 frontswap_failed_stores; 41static u64 frontswap_invalidates; 42 43static inline void inc_frontswap_loads(void) 44{ 45 data_race(frontswap_loads++); 46} 47static inline void inc_frontswap_succ_stores(void) 48{ 49 data_race(frontswap_succ_stores++); 50} 51static inline void inc_frontswap_failed_stores(void) 52{ 53 data_race(frontswap_failed_stores++); 54} 55static inline void inc_frontswap_invalidates(void) 56{ 57 data_race(frontswap_invalidates++); 58} 59#else 60static inline void inc_frontswap_loads(void) { } 61static inline void inc_frontswap_succ_stores(void) { } 62static inline void inc_frontswap_failed_stores(void) { } 63static inline void inc_frontswap_invalidates(void) { } 64#endif 65 66/* 67 * Due to the asynchronous nature of the backends loading potentially 68 * _after_ the swap system has been activated, we have chokepoints 69 * on all frontswap functions to not call the backend until the backend 70 * has registered. 71 * 72 * This would not guards us against the user deciding to call swapoff right as 73 * we are calling the backend to initialize (so swapon is in action). 74 * Fortunately for us, the swapon_mutex has been taken by the callee so we are 75 * OK. The other scenario where calls to frontswap_store (called via 76 * swap_writepage) is racing with frontswap_invalidate_area (called via 77 * swapoff) is again guarded by the swap subsystem. 78 * 79 * While no backend is registered all calls to frontswap_[store|load| 80 * invalidate_area|invalidate_page] are ignored or fail. 81 * 82 * The time between the backend being registered and the swap file system 83 * calling the backend (via the frontswap_* functions) is indeterminate as 84 * frontswap_ops is not atomic_t (or a value guarded by a spinlock). 85 * That is OK as we are comfortable missing some of these calls to the newly 86 * registered backend. 87 * 88 * Obviously the opposite (unloading the backend) must be done after all 89 * the frontswap_[store|load|invalidate_area|invalidate_page] start 90 * ignoring or failing the requests. However, there is currently no way 91 * to unload a backend once it is registered. 92 */ 93 94/* 95 * Register operations for frontswap 96 */ 97int frontswap_register_ops(const struct frontswap_ops *ops) 98{ 99 if (frontswap_ops) 100 return -EINVAL; 101 102 frontswap_ops = ops; 103 static_branch_inc(&frontswap_enabled_key); 104 return 0; 105} 106 107/* 108 * Called when a swap device is swapon'd. 109 */ 110void frontswap_init(unsigned type, unsigned long *map) 111{ 112 struct swap_info_struct *sis = swap_info[type]; 113 114 VM_BUG_ON(sis == NULL); 115 116 /* 117 * p->frontswap is a bitmap that we MUST have to figure out which page 118 * has gone in frontswap. Without it there is no point of continuing. 119 */ 120 if (WARN_ON(!map)) 121 return; 122 /* 123 * Irregardless of whether the frontswap backend has been loaded 124 * before this function or it will be later, we _MUST_ have the 125 * p->frontswap set to something valid to work properly. 126 */ 127 frontswap_map_set(sis, map); 128 129 if (!frontswap_enabled()) 130 return; 131 frontswap_ops->init(type); 132} 133 134static bool __frontswap_test(struct swap_info_struct *sis, 135 pgoff_t offset) 136{ 137 if (sis->frontswap_map) 138 return test_bit(offset, sis->frontswap_map); 139 return false; 140} 141 142static inline void __frontswap_set(struct swap_info_struct *sis, 143 pgoff_t offset) 144{ 145 set_bit(offset, sis->frontswap_map); 146 atomic_inc(&sis->frontswap_pages); 147} 148 149static inline void __frontswap_clear(struct swap_info_struct *sis, 150 pgoff_t offset) 151{ 152 clear_bit(offset, sis->frontswap_map); 153 atomic_dec(&sis->frontswap_pages); 154} 155 156/* 157 * "Store" data from a page to frontswap and associate it with the page's 158 * swaptype and offset. Page must be locked and in the swap cache. 159 * If frontswap already contains a page with matching swaptype and 160 * offset, the frontswap implementation may either overwrite the data and 161 * return success or invalidate the page from frontswap and return failure. 162 */ 163int __frontswap_store(struct page *page) 164{ 165 int ret = -1; 166 swp_entry_t entry = { .val = page_private(page), }; 167 int type = swp_type(entry); 168 struct swap_info_struct *sis = swap_info[type]; 169 pgoff_t offset = swp_offset(entry); 170 171 VM_BUG_ON(!frontswap_ops); 172 VM_BUG_ON(!PageLocked(page)); 173 VM_BUG_ON(sis == NULL); 174 175 /* 176 * If a dup, we must remove the old page first; we can't leave the 177 * old page no matter if the store of the new page succeeds or fails, 178 * and we can't rely on the new page replacing the old page as we may 179 * not store to the same implementation that contains the old page. 180 */ 181 if (__frontswap_test(sis, offset)) { 182 __frontswap_clear(sis, offset); 183 frontswap_ops->invalidate_page(type, offset); 184 } 185 186 ret = frontswap_ops->store(type, offset, page); 187 if (ret == 0) { 188 __frontswap_set(sis, offset); 189 inc_frontswap_succ_stores(); 190 } else { 191 inc_frontswap_failed_stores(); 192 } 193 194 return ret; 195} 196 197/* 198 * "Get" data from frontswap associated with swaptype and offset that were 199 * specified when the data was put to frontswap and use it to fill the 200 * specified page with data. Page must be locked and in the swap cache. 201 */ 202int __frontswap_load(struct page *page) 203{ 204 int ret = -1; 205 swp_entry_t entry = { .val = page_private(page), }; 206 int type = swp_type(entry); 207 struct swap_info_struct *sis = swap_info[type]; 208 pgoff_t offset = swp_offset(entry); 209 210 VM_BUG_ON(!frontswap_ops); 211 VM_BUG_ON(!PageLocked(page)); 212 VM_BUG_ON(sis == NULL); 213 214 if (!__frontswap_test(sis, offset)) 215 return -1; 216 217 /* Try loading from each implementation, until one succeeds. */ 218 ret = frontswap_ops->load(type, offset, page); 219 if (ret == 0) 220 inc_frontswap_loads(); 221 return ret; 222} 223 224/* 225 * Invalidate any data from frontswap associated with the specified swaptype 226 * and offset so that a subsequent "get" will fail. 227 */ 228void __frontswap_invalidate_page(unsigned type, pgoff_t offset) 229{ 230 struct swap_info_struct *sis = swap_info[type]; 231 232 VM_BUG_ON(!frontswap_ops); 233 VM_BUG_ON(sis == NULL); 234 235 if (!__frontswap_test(sis, offset)) 236 return; 237 238 frontswap_ops->invalidate_page(type, offset); 239 __frontswap_clear(sis, offset); 240 inc_frontswap_invalidates(); 241} 242 243/* 244 * Invalidate all data from frontswap associated with all offsets for the 245 * specified swaptype. 246 */ 247void __frontswap_invalidate_area(unsigned type) 248{ 249 struct swap_info_struct *sis = swap_info[type]; 250 251 VM_BUG_ON(!frontswap_ops); 252 VM_BUG_ON(sis == NULL); 253 254 if (sis->frontswap_map == NULL) 255 return; 256 257 frontswap_ops->invalidate_area(type); 258 atomic_set(&sis->frontswap_pages, 0); 259 bitmap_zero(sis->frontswap_map, sis->max); 260} 261 262static int __init init_frontswap(void) 263{ 264#ifdef CONFIG_DEBUG_FS 265 struct dentry *root = debugfs_create_dir("frontswap", NULL); 266 if (root == NULL) 267 return -ENXIO; 268 debugfs_create_u64("loads", 0444, root, &frontswap_loads); 269 debugfs_create_u64("succ_stores", 0444, root, &frontswap_succ_stores); 270 debugfs_create_u64("failed_stores", 0444, root, 271 &frontswap_failed_stores); 272 debugfs_create_u64("invalidates", 0444, root, &frontswap_invalidates); 273#endif 274 return 0; 275} 276 277module_init(init_frontswap);