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

SHM_LOCKED pages are unevictable

Shmem segments locked into memory via shmctl(SHM_LOCKED) should not be
kept on the normal LRU, since scanning them is a waste of time and might
throw off kswapd's balancing algorithms. Place them on the unevictable
LRU list instead.

Use the AS_UNEVICTABLE flag to mark address_space of SHM_LOCKed shared
memory regions as unevictable. Then these pages will be culled off the
normal LRU lists during vmscan.

Add new wrapper function to clear the mapping's unevictable state when/if
shared memory segment is munlocked.

Add 'scan_mapping_unevictable_page()' to mm/vmscan.c to scan all pages in
the shmem segment's mapping [struct address_space] for evictability now
that they're no longer locked. If so, move them to the appropriate zone
lru list.

Changes depend on [CONFIG_]UNEVICTABLE_LRU.

[kosaki.motohiro@jp.fujitsu.com: revert shm change]
Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>
Signed-off-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Kosaki Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Lee Schermerhorn and committed by
Linus Torvalds
89e004ea ba9ddf49

+112 -5
+2 -2
include/linux/mm.h
··· 700 700 extern void show_free_areas(void); 701 701 702 702 #ifdef CONFIG_SHMEM 703 - int shmem_lock(struct file *file, int lock, struct user_struct *user); 703 + extern int shmem_lock(struct file *file, int lock, struct user_struct *user); 704 704 #else 705 705 static inline int shmem_lock(struct file *file, int lock, 706 - struct user_struct *user) 706 + struct user_struct *user) 707 707 { 708 708 return 0; 709 709 }
+9 -3
include/linux/pagemap.h
··· 40 40 set_bit(AS_UNEVICTABLE, &mapping->flags); 41 41 } 42 42 43 + static inline void mapping_clear_unevictable(struct address_space *mapping) 44 + { 45 + clear_bit(AS_UNEVICTABLE, &mapping->flags); 46 + } 47 + 43 48 static inline int mapping_unevictable(struct address_space *mapping) 44 49 { 45 - if (mapping && (mapping->flags & AS_UNEVICTABLE)) 46 - return 1; 47 - return 0; 50 + if (likely(mapping)) 51 + return test_bit(AS_UNEVICTABLE, &mapping->flags); 52 + return !!mapping; 48 53 } 49 54 #else 50 55 static inline void mapping_set_unevictable(struct address_space *mapping) { } 56 + static inline void mapping_clear_unevictable(struct address_space *mapping) { } 51 57 static inline int mapping_unevictable(struct address_space *mapping) 52 58 { 53 59 return 0;
+4
include/linux/swap.h
··· 232 232 233 233 #ifdef CONFIG_UNEVICTABLE_LRU 234 234 extern int page_evictable(struct page *page, struct vm_area_struct *vma); 235 + extern void scan_mapping_unevictable_pages(struct address_space *); 235 236 #else 236 237 static inline int page_evictable(struct page *page, 237 238 struct vm_area_struct *vma) 238 239 { 239 240 return 1; 241 + } 242 + static inline void scan_mapping_unevictable_pages(struct address_space *mapping) 243 + { 240 244 } 241 245 #endif 242 246
+4
ipc/shm.c
··· 737 737 case SHM_LOCK: 738 738 case SHM_UNLOCK: 739 739 { 740 + struct file *uninitialized_var(shm_file); 741 + 742 + lru_add_drain_all(); /* drain pagevecs to lru lists */ 743 + 740 744 shp = shm_lock_check(ns, shmid); 741 745 if (IS_ERR(shp)) { 742 746 err = PTR_ERR(shp);
+4
mm/shmem.c
··· 1477 1477 if (!user_shm_lock(inode->i_size, user)) 1478 1478 goto out_nomem; 1479 1479 info->flags |= VM_LOCKED; 1480 + mapping_set_unevictable(file->f_mapping); 1480 1481 } 1481 1482 if (!lock && (info->flags & VM_LOCKED) && user) { 1482 1483 user_shm_unlock(inode->i_size, user); 1483 1484 info->flags &= ~VM_LOCKED; 1485 + mapping_clear_unevictable(file->f_mapping); 1486 + scan_mapping_unevictable_pages(file->f_mapping); 1484 1487 } 1485 1488 retval = 0; 1489 + 1486 1490 out_nomem: 1487 1491 spin_unlock(&info->lock); 1488 1492 return retval;
+89
mm/vmscan.c
··· 2346 2346 2347 2347 return 1; 2348 2348 } 2349 + 2350 + /** 2351 + * check_move_unevictable_page - check page for evictability and move to appropriate zone lru list 2352 + * @page: page to check evictability and move to appropriate lru list 2353 + * @zone: zone page is in 2354 + * 2355 + * Checks a page for evictability and moves the page to the appropriate 2356 + * zone lru list. 2357 + * 2358 + * Restrictions: zone->lru_lock must be held, page must be on LRU and must 2359 + * have PageUnevictable set. 2360 + */ 2361 + static void check_move_unevictable_page(struct page *page, struct zone *zone) 2362 + { 2363 + VM_BUG_ON(PageActive(page)); 2364 + 2365 + retry: 2366 + ClearPageUnevictable(page); 2367 + if (page_evictable(page, NULL)) { 2368 + enum lru_list l = LRU_INACTIVE_ANON + page_is_file_cache(page); 2369 + __dec_zone_state(zone, NR_UNEVICTABLE); 2370 + list_move(&page->lru, &zone->lru[l].list); 2371 + __inc_zone_state(zone, NR_INACTIVE_ANON + l); 2372 + __count_vm_event(UNEVICTABLE_PGRESCUED); 2373 + } else { 2374 + /* 2375 + * rotate unevictable list 2376 + */ 2377 + SetPageUnevictable(page); 2378 + list_move(&page->lru, &zone->lru[LRU_UNEVICTABLE].list); 2379 + if (page_evictable(page, NULL)) 2380 + goto retry; 2381 + } 2382 + } 2383 + 2384 + /** 2385 + * scan_mapping_unevictable_pages - scan an address space for evictable pages 2386 + * @mapping: struct address_space to scan for evictable pages 2387 + * 2388 + * Scan all pages in mapping. Check unevictable pages for 2389 + * evictability and move them to the appropriate zone lru list. 2390 + */ 2391 + void scan_mapping_unevictable_pages(struct address_space *mapping) 2392 + { 2393 + pgoff_t next = 0; 2394 + pgoff_t end = (i_size_read(mapping->host) + PAGE_CACHE_SIZE - 1) >> 2395 + PAGE_CACHE_SHIFT; 2396 + struct zone *zone; 2397 + struct pagevec pvec; 2398 + 2399 + if (mapping->nrpages == 0) 2400 + return; 2401 + 2402 + pagevec_init(&pvec, 0); 2403 + while (next < end && 2404 + pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { 2405 + int i; 2406 + int pg_scanned = 0; 2407 + 2408 + zone = NULL; 2409 + 2410 + for (i = 0; i < pagevec_count(&pvec); i++) { 2411 + struct page *page = pvec.pages[i]; 2412 + pgoff_t page_index = page->index; 2413 + struct zone *pagezone = page_zone(page); 2414 + 2415 + pg_scanned++; 2416 + if (page_index > next) 2417 + next = page_index; 2418 + next++; 2419 + 2420 + if (pagezone != zone) { 2421 + if (zone) 2422 + spin_unlock_irq(&zone->lru_lock); 2423 + zone = pagezone; 2424 + spin_lock_irq(&zone->lru_lock); 2425 + } 2426 + 2427 + if (PageLRU(page) && PageUnevictable(page)) 2428 + check_move_unevictable_page(page, zone); 2429 + } 2430 + if (zone) 2431 + spin_unlock_irq(&zone->lru_lock); 2432 + pagevec_release(&pvec); 2433 + 2434 + count_vm_events(UNEVICTABLE_PGSCANNED, pg_scanned); 2435 + } 2436 + 2437 + } 2349 2438 #endif