mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a radix tree, they need to be distinguished as exceptional entries. Most of the handling of swap entries in radix tree will be contained in shmem.c, but a few functions in filemap.c's common code need to check for their appearance: find_get_page(), find_lock_page(), find_get_pages() and find_get_pages_contig(). So as not to slow their fast paths, tuck those checks inside the existing checks for unlikely radix_tree_deref_slot(); except for find_lock_page(), where it is an added test. And make it a BUG in find_get_pages_tag(), which is not applied to tmpfs files. A part of the reason for eliminating shmem_readpage() earlier, was to minimize the places where common code would need to allow for swap entries. The swp_entry_t known to swapfile.c must be massaged into a slightly different form when stored in the radix tree, just as it gets massaged into a pte_t when stored in page tables. In an i386 kernel this limits its information (type and page offset) to 30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum swapfile size of 128GB. Which is less than the 512GB we previously allowed with X86_PAE (where the swap entry can occupy the entire upper 32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and there's not a new limitation on 64-bit (where swap filesize is already limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is probably still enough swap for a 64GB 32-bit machine. Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and enforce filesize limit in read_swap_header(), just as for ptes. Signed-off-by: Hugh Dickins <hughd@google.com> Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:

committed by
Linus Torvalds

parent
6328650bb4
commit
a2c16d6cb0
@@ -1,3 +1,8 @@
|
||||
#ifndef _LINUX_SWAPOPS_H
|
||||
#define _LINUX_SWAPOPS_H
|
||||
|
||||
#include <linux/radix-tree.h>
|
||||
|
||||
/*
|
||||
* swapcache pages are stored in the swapper_space radix tree. We want to
|
||||
* get good packing density in that tree, so the index should be dense in
|
||||
@@ -76,6 +81,22 @@ static inline pte_t swp_entry_to_pte(swp_entry_t entry)
|
||||
return __swp_entry_to_pte(arch_entry);
|
||||
}
|
||||
|
||||
static inline swp_entry_t radix_to_swp_entry(void *arg)
|
||||
{
|
||||
swp_entry_t entry;
|
||||
|
||||
entry.val = (unsigned long)arg >> RADIX_TREE_EXCEPTIONAL_SHIFT;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static inline void *swp_to_radix_entry(swp_entry_t entry)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
value = entry.val << RADIX_TREE_EXCEPTIONAL_SHIFT;
|
||||
return (void *)(value | RADIX_TREE_EXCEPTIONAL_ENTRY);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIGRATION
|
||||
static inline swp_entry_t make_migration_entry(struct page *page, int write)
|
||||
{
|
||||
@@ -169,3 +190,5 @@ static inline int non_swap_entry(swp_entry_t entry)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_SWAPOPS_H */
|
||||
|
Reference in New Issue
Block a user