| .. | .. |
|---|
| 33 | 33 | #include <linux/vmalloc.h> |
|---|
| 34 | 34 | #include <linux/mutex.h> |
|---|
| 35 | 35 | #include <linux/mm.h> |
|---|
| 36 | +#include <trace/hooks/mm.h> |
|---|
| 36 | 37 | |
|---|
| 37 | 38 | static DEFINE_PER_CPU(struct swap_slots_cache, swp_slots); |
|---|
| 38 | 39 | static bool swap_slot_cache_active; |
|---|
| .. | .. |
|---|
| 46 | 47 | static void deactivate_swap_slots_cache(void); |
|---|
| 47 | 48 | static void reactivate_swap_slots_cache(void); |
|---|
| 48 | 49 | |
|---|
| 49 | | -#define use_swap_slot_cache (swap_slot_cache_active && \ |
|---|
| 50 | | - swap_slot_cache_enabled && swap_slot_cache_initialized) |
|---|
| 50 | +#define use_swap_slot_cache (swap_slot_cache_active && swap_slot_cache_enabled) |
|---|
| 51 | 51 | #define SLOTS_CACHE 0x1 |
|---|
| 52 | 52 | #define SLOTS_CACHE_RET 0x2 |
|---|
| 53 | 53 | |
|---|
| .. | .. |
|---|
| 55 | 55 | { |
|---|
| 56 | 56 | mutex_lock(&swap_slots_cache_mutex); |
|---|
| 57 | 57 | swap_slot_cache_active = false; |
|---|
| 58 | + trace_android_vh_swap_slot_cache_active(false); |
|---|
| 58 | 59 | __drain_swap_slots_cache(SLOTS_CACHE|SLOTS_CACHE_RET); |
|---|
| 59 | 60 | mutex_unlock(&swap_slots_cache_mutex); |
|---|
| 60 | 61 | } |
|---|
| .. | .. |
|---|
| 63 | 64 | { |
|---|
| 64 | 65 | mutex_lock(&swap_slots_cache_mutex); |
|---|
| 65 | 66 | swap_slot_cache_active = true; |
|---|
| 67 | + trace_android_vh_swap_slot_cache_active(true); |
|---|
| 66 | 68 | mutex_unlock(&swap_slots_cache_mutex); |
|---|
| 67 | 69 | } |
|---|
| 68 | 70 | |
|---|
| .. | .. |
|---|
| 90 | 92 | mutex_unlock(&swap_slots_cache_enable_mutex); |
|---|
| 91 | 93 | } |
|---|
| 92 | 94 | |
|---|
| 93 | | -static bool check_cache_active(void) |
|---|
| 95 | +bool is_swap_slot_cache_enabled(void) |
|---|
| 96 | +{ |
|---|
| 97 | + return swap_slot_cache_enabled; |
|---|
| 98 | +} |
|---|
| 99 | +EXPORT_SYMBOL_GPL(is_swap_slot_cache_enabled); |
|---|
| 100 | + |
|---|
| 101 | +bool check_cache_active(void) |
|---|
| 94 | 102 | { |
|---|
| 95 | 103 | long pages; |
|---|
| 96 | 104 | |
|---|
| 97 | | - if (!swap_slot_cache_enabled || !swap_slot_cache_initialized) |
|---|
| 105 | + if (!swap_slot_cache_enabled) |
|---|
| 98 | 106 | return false; |
|---|
| 99 | 107 | |
|---|
| 100 | 108 | pages = get_nr_swap_pages(); |
|---|
| .. | .. |
|---|
| 111 | 119 | out: |
|---|
| 112 | 120 | return swap_slot_cache_active; |
|---|
| 113 | 121 | } |
|---|
| 122 | +EXPORT_SYMBOL_GPL(check_cache_active); |
|---|
| 114 | 123 | |
|---|
| 115 | 124 | static int alloc_swap_slot_cache(unsigned int cpu) |
|---|
| 116 | 125 | { |
|---|
| 117 | 126 | struct swap_slots_cache *cache; |
|---|
| 118 | 127 | swp_entry_t *slots, *slots_ret; |
|---|
| 128 | + bool skip = false; |
|---|
| 129 | + int ret = 0; |
|---|
| 119 | 130 | |
|---|
| 120 | 131 | /* |
|---|
| 121 | 132 | * Do allocation outside swap_slots_cache_mutex |
|---|
| 122 | 133 | * as kvzalloc could trigger reclaim and get_swap_page, |
|---|
| 123 | 134 | * which can lock swap_slots_cache_mutex. |
|---|
| 124 | 135 | */ |
|---|
| 136 | + trace_android_rvh_alloc_swap_slot_cache(&per_cpu(swp_slots, cpu), |
|---|
| 137 | + &ret, &skip); |
|---|
| 138 | + trace_android_vh_alloc_swap_slot_cache(&per_cpu(swp_slots, cpu), |
|---|
| 139 | + &ret, &skip); |
|---|
| 140 | + if (skip) |
|---|
| 141 | + return ret; |
|---|
| 125 | 142 | slots = kvcalloc(SWAP_SLOTS_CACHE_SIZE, sizeof(swp_entry_t), |
|---|
| 126 | 143 | GFP_KERNEL); |
|---|
| 127 | 144 | if (!slots) |
|---|
| .. | .. |
|---|
| 136 | 153 | |
|---|
| 137 | 154 | mutex_lock(&swap_slots_cache_mutex); |
|---|
| 138 | 155 | cache = &per_cpu(swp_slots, cpu); |
|---|
| 139 | | - if (cache->slots || cache->slots_ret) |
|---|
| 156 | + if (cache->slots || cache->slots_ret) { |
|---|
| 140 | 157 | /* cache already allocated */ |
|---|
| 141 | | - goto out; |
|---|
| 158 | + mutex_unlock(&swap_slots_cache_mutex); |
|---|
| 159 | + |
|---|
| 160 | + kvfree(slots); |
|---|
| 161 | + kvfree(slots_ret); |
|---|
| 162 | + |
|---|
| 163 | + return 0; |
|---|
| 164 | + } |
|---|
| 165 | + |
|---|
| 142 | 166 | if (!cache->lock_initialized) { |
|---|
| 143 | 167 | mutex_init(&cache->alloc_lock); |
|---|
| 144 | 168 | spin_lock_init(&cache->free_lock); |
|---|
| .. | .. |
|---|
| 155 | 179 | */ |
|---|
| 156 | 180 | mb(); |
|---|
| 157 | 181 | cache->slots = slots; |
|---|
| 158 | | - slots = NULL; |
|---|
| 159 | 182 | cache->slots_ret = slots_ret; |
|---|
| 160 | | - slots_ret = NULL; |
|---|
| 161 | | -out: |
|---|
| 162 | 183 | mutex_unlock(&swap_slots_cache_mutex); |
|---|
| 163 | | - if (slots) |
|---|
| 164 | | - kvfree(slots); |
|---|
| 165 | | - if (slots_ret) |
|---|
| 166 | | - kvfree(slots_ret); |
|---|
| 167 | 184 | return 0; |
|---|
| 168 | 185 | } |
|---|
| 169 | 186 | |
|---|
| .. | .. |
|---|
| 172 | 189 | { |
|---|
| 173 | 190 | struct swap_slots_cache *cache; |
|---|
| 174 | 191 | swp_entry_t *slots = NULL; |
|---|
| 192 | + bool skip = false; |
|---|
| 175 | 193 | |
|---|
| 176 | 194 | cache = &per_cpu(swp_slots, cpu); |
|---|
| 195 | + trace_android_rvh_drain_slots_cache_cpu(cache, type, |
|---|
| 196 | + free_slots, &skip); |
|---|
| 197 | + trace_android_vh_drain_slots_cache_cpu(cache, type, |
|---|
| 198 | + free_slots, &skip); |
|---|
| 199 | + if (skip) |
|---|
| 200 | + return; |
|---|
| 177 | 201 | if ((type & SLOTS_CACHE) && cache->slots) { |
|---|
| 178 | 202 | mutex_lock(&cache->alloc_lock); |
|---|
| 179 | 203 | swapcache_free_entries(cache->slots + cache->cur, cache->nr); |
|---|
| .. | .. |
|---|
| 238 | 262 | return 0; |
|---|
| 239 | 263 | } |
|---|
| 240 | 264 | |
|---|
| 241 | | -int enable_swap_slots_cache(void) |
|---|
| 265 | +void enable_swap_slots_cache(void) |
|---|
| 242 | 266 | { |
|---|
| 243 | | - int ret = 0; |
|---|
| 244 | | - |
|---|
| 245 | 267 | mutex_lock(&swap_slots_cache_enable_mutex); |
|---|
| 246 | | - if (swap_slot_cache_initialized) { |
|---|
| 247 | | - __reenable_swap_slots_cache(); |
|---|
| 248 | | - goto out_unlock; |
|---|
| 268 | + if (!swap_slot_cache_initialized) { |
|---|
| 269 | + int ret; |
|---|
| 270 | + |
|---|
| 271 | + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "swap_slots_cache", |
|---|
| 272 | + alloc_swap_slot_cache, free_slot_cache); |
|---|
| 273 | + if (WARN_ONCE(ret < 0, "Cache allocation failed (%s), operating " |
|---|
| 274 | + "without swap slots cache.\n", __func__)) |
|---|
| 275 | + goto out_unlock; |
|---|
| 276 | + |
|---|
| 277 | + swap_slot_cache_initialized = true; |
|---|
| 249 | 278 | } |
|---|
| 250 | 279 | |
|---|
| 251 | | - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "swap_slots_cache", |
|---|
| 252 | | - alloc_swap_slot_cache, free_slot_cache); |
|---|
| 253 | | - if (WARN_ONCE(ret < 0, "Cache allocation failed (%s), operating " |
|---|
| 254 | | - "without swap slots cache.\n", __func__)) |
|---|
| 255 | | - goto out_unlock; |
|---|
| 256 | | - |
|---|
| 257 | | - swap_slot_cache_initialized = true; |
|---|
| 258 | 280 | __reenable_swap_slots_cache(); |
|---|
| 259 | 281 | out_unlock: |
|---|
| 260 | 282 | mutex_unlock(&swap_slots_cache_enable_mutex); |
|---|
| 261 | | - return 0; |
|---|
| 262 | 283 | } |
|---|
| 263 | 284 | |
|---|
| 264 | 285 | /* called with swap slot cache's alloc lock held */ |
|---|
| .. | .. |
|---|
| 278 | 299 | int free_swap_slot(swp_entry_t entry) |
|---|
| 279 | 300 | { |
|---|
| 280 | 301 | struct swap_slots_cache *cache; |
|---|
| 302 | + bool skip = false; |
|---|
| 281 | 303 | |
|---|
| 282 | 304 | cache = raw_cpu_ptr(&swp_slots); |
|---|
| 305 | + trace_android_rvh_free_swap_slot(entry, cache, &skip); |
|---|
| 306 | + trace_android_vh_free_swap_slot(entry, cache, &skip); |
|---|
| 307 | + if (skip) |
|---|
| 308 | + return 0; |
|---|
| 283 | 309 | if (likely(use_swap_slot_cache && cache->slots_ret)) { |
|---|
| 284 | 310 | spin_lock_irq(&cache->free_lock); |
|---|
| 285 | 311 | /* Swap slots cache may be deactivated before acquiring lock */ |
|---|
| .. | .. |
|---|
| 309 | 335 | |
|---|
| 310 | 336 | swp_entry_t get_swap_page(struct page *page) |
|---|
| 311 | 337 | { |
|---|
| 312 | | - swp_entry_t entry, *pentry; |
|---|
| 338 | + swp_entry_t entry; |
|---|
| 313 | 339 | struct swap_slots_cache *cache; |
|---|
| 314 | | - |
|---|
| 340 | + bool found = false; |
|---|
| 315 | 341 | entry.val = 0; |
|---|
| 342 | + |
|---|
| 343 | + trace_android_rvh_get_swap_page(page, &entry, raw_cpu_ptr(&swp_slots), &found); |
|---|
| 344 | + trace_android_vh_get_swap_page(page, &entry, raw_cpu_ptr(&swp_slots), &found); |
|---|
| 345 | + if (found) |
|---|
| 346 | + goto out; |
|---|
| 316 | 347 | |
|---|
| 317 | 348 | if (PageTransHuge(page)) { |
|---|
| 318 | 349 | if (IS_ENABLED(CONFIG_THP_SWAP)) |
|---|
| .. | .. |
|---|
| 336 | 367 | if (cache->slots) { |
|---|
| 337 | 368 | repeat: |
|---|
| 338 | 369 | if (cache->nr) { |
|---|
| 339 | | - pentry = &cache->slots[cache->cur++]; |
|---|
| 340 | | - entry = *pentry; |
|---|
| 341 | | - pentry->val = 0; |
|---|
| 370 | + entry = cache->slots[cache->cur]; |
|---|
| 371 | + cache->slots[cache->cur++].val = 0; |
|---|
| 342 | 372 | cache->nr--; |
|---|
| 343 | | - } else { |
|---|
| 344 | | - if (refill_swap_slots_cache(cache)) |
|---|
| 345 | | - goto repeat; |
|---|
| 373 | + } else if (refill_swap_slots_cache(cache)) { |
|---|
| 374 | + goto repeat; |
|---|
| 346 | 375 | } |
|---|
| 347 | 376 | } |
|---|
| 348 | 377 | mutex_unlock(&cache->alloc_lock); |
|---|