Commit 03e63b20 authored by Hugh Dickins's avatar Hugh Dickins Committed by james toy

Though swap_count() is useful, I'm finding that swap_has_cache() and

encode_swapmap() obscure what happens in the swap_map entry, just at
those points where I need to understand it.  Remove them, and pass
more usable "usage" values to scan_swap_map(), swap_entry_free() and
__swap_duplicate(), instead of the SWAP_MAP and SWAP_CACHE enum.
Signed-off-by: default avatarHugh Dickins <hugh.dickins@tiscali.co.uk>
Reviewed-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Rik van Riel <riel@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent f33c0c52
...@@ -154,7 +154,7 @@ enum { ...@@ -154,7 +154,7 @@ enum {
#define SWAP_MAP_MAX 0x7ffe #define SWAP_MAP_MAX 0x7ffe
#define SWAP_MAP_BAD 0x7fff #define SWAP_MAP_BAD 0x7fff
#define SWAP_HAS_CACHE 0x8000 /* There is a swap cache of entry. */ #define SWAP_HAS_CACHE 0x8000 /* There is a swap cache of entry. */
#define SWAP_COUNT_MASK (~SWAP_HAS_CACHE)
/* /*
* The in-memory structure used to track swap areas. * The in-memory structure used to track swap areas.
*/ */
......
...@@ -53,30 +53,9 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES]; ...@@ -53,30 +53,9 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES];
static DEFINE_MUTEX(swapon_mutex); static DEFINE_MUTEX(swapon_mutex);
/* For reference count accounting in swap_map */
/* enum for swap_map[] handling. internal use only */
enum {
SWAP_MAP = 0, /* ops for reference from swap users */
SWAP_CACHE, /* ops for reference from swap cache */
};
static inline int swap_count(unsigned short ent) static inline int swap_count(unsigned short ent)
{ {
return ent & SWAP_COUNT_MASK; return ent & ~SWAP_HAS_CACHE;
}
static inline bool swap_has_cache(unsigned short ent)
{
return !!(ent & SWAP_HAS_CACHE);
}
static inline unsigned short encode_swapmap(int count, bool has_cache)
{
unsigned short ret = count;
if (has_cache)
return SWAP_HAS_CACHE | ret;
return ret;
} }
/* returns 1 if swap entry is freed */ /* returns 1 if swap entry is freed */
...@@ -224,7 +203,7 @@ static int wait_for_discard(void *word) ...@@ -224,7 +203,7 @@ static int wait_for_discard(void *word)
#define LATENCY_LIMIT 256 #define LATENCY_LIMIT 256
static inline unsigned long scan_swap_map(struct swap_info_struct *si, static inline unsigned long scan_swap_map(struct swap_info_struct *si,
int cache) unsigned short usage)
{ {
unsigned long offset; unsigned long offset;
unsigned long scan_base; unsigned long scan_base;
...@@ -355,10 +334,7 @@ checks: ...@@ -355,10 +334,7 @@ checks:
si->lowest_bit = si->max; si->lowest_bit = si->max;
si->highest_bit = 0; si->highest_bit = 0;
} }
if (cache == SWAP_CACHE) /* at usual swap-out via vmscan.c */ si->swap_map[offset] = usage;
si->swap_map[offset] = encode_swapmap(0, true);
else /* at suspend */
si->swap_map[offset] = encode_swapmap(1, false);
si->cluster_next = offset + 1; si->cluster_next = offset + 1;
si->flags -= SWP_SCANNING; si->flags -= SWP_SCANNING;
...@@ -483,7 +459,7 @@ swp_entry_t get_swap_page(void) ...@@ -483,7 +459,7 @@ swp_entry_t get_swap_page(void)
swap_list.next = next; swap_list.next = next;
/* This is called for allocating swap entry for cache */ /* This is called for allocating swap entry for cache */
offset = scan_swap_map(si, SWAP_CACHE); offset = scan_swap_map(si, SWAP_HAS_CACHE);
if (offset) { if (offset) {
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
return swp_entry(type, offset); return swp_entry(type, offset);
...@@ -508,7 +484,7 @@ swp_entry_t get_swap_page_of_type(int type) ...@@ -508,7 +484,7 @@ swp_entry_t get_swap_page_of_type(int type)
if (si && (si->flags & SWP_WRITEOK)) { if (si && (si->flags & SWP_WRITEOK)) {
nr_swap_pages--; nr_swap_pages--;
/* This is called for allocating swap entry, not cache */ /* This is called for allocating swap entry, not cache */
offset = scan_swap_map(si, SWAP_MAP); offset = scan_swap_map(si, 1);
if (offset) { if (offset) {
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
return swp_entry(type, offset); return swp_entry(type, offset);
...@@ -555,29 +531,31 @@ out: ...@@ -555,29 +531,31 @@ out:
return NULL; return NULL;
} }
static int swap_entry_free(struct swap_info_struct *p, static unsigned short swap_entry_free(struct swap_info_struct *p,
swp_entry_t ent, int cache) swp_entry_t entry, unsigned short usage)
{ {
unsigned long offset = swp_offset(ent); unsigned long offset = swp_offset(entry);
int count = swap_count(p->swap_map[offset]); unsigned short count;
bool has_cache; unsigned short has_cache;
has_cache = swap_has_cache(p->swap_map[offset]); count = p->swap_map[offset];
has_cache = count & SWAP_HAS_CACHE;
count &= ~SWAP_HAS_CACHE;
if (cache == SWAP_MAP) { /* dropping usage count of swap */ if (usage == SWAP_HAS_CACHE) {
if (count < SWAP_MAP_MAX) {
count--;
p->swap_map[offset] = encode_swapmap(count, has_cache);
}
} else { /* dropping swap cache flag */
VM_BUG_ON(!has_cache); VM_BUG_ON(!has_cache);
p->swap_map[offset] = encode_swapmap(count, false); has_cache = 0;
} else if (count < SWAP_MAP_MAX)
count--;
if (!count)
mem_cgroup_uncharge_swap(entry);
usage = count | has_cache;
p->swap_map[offset] = usage;
}
/* return code. */
count = p->swap_map[offset];
/* free if no reference */ /* free if no reference */
if (!count) { if (!usage) {
if (offset < p->lowest_bit) if (offset < p->lowest_bit)
p->lowest_bit = offset; p->lowest_bit = offset;
if (offset > p->highest_bit) if (offset > p->highest_bit)
...@@ -588,9 +566,8 @@ static int swap_entry_free(struct swap_info_struct *p, ...@@ -588,9 +566,8 @@ static int swap_entry_free(struct swap_info_struct *p,
nr_swap_pages++; nr_swap_pages++;
p->inuse_pages--; p->inuse_pages--;
} }
if (!swap_count(count))
mem_cgroup_uncharge_swap(ent); return usage;
return count;
} }
/* /*
...@@ -603,7 +580,7 @@ void swap_free(swp_entry_t entry) ...@@ -603,7 +580,7 @@ void swap_free(swp_entry_t entry)
p = swap_info_get(entry); p = swap_info_get(entry);
if (p) { if (p) {
swap_entry_free(p, entry, SWAP_MAP); swap_entry_free(p, entry, 1);
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
} }
} }
...@@ -614,19 +591,13 @@ void swap_free(swp_entry_t entry) ...@@ -614,19 +591,13 @@ void swap_free(swp_entry_t entry)
void swapcache_free(swp_entry_t entry, struct page *page) void swapcache_free(swp_entry_t entry, struct page *page)
{ {
struct swap_info_struct *p; struct swap_info_struct *p;
int ret; unsigned short count;
p = swap_info_get(entry); p = swap_info_get(entry);
if (p) { if (p) {
ret = swap_entry_free(p, entry, SWAP_CACHE); count = swap_entry_free(p, entry, SWAP_HAS_CACHE);
if (page) { if (page)
bool swapout; mem_cgroup_uncharge_swapcache(page, entry, count != 0);
if (ret)
swapout = true; /* the end of swap out */
else
swapout = false; /* no more swap users! */
mem_cgroup_uncharge_swapcache(page, entry, swapout);
}
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
} }
} }
...@@ -705,7 +676,7 @@ int free_swap_and_cache(swp_entry_t entry) ...@@ -705,7 +676,7 @@ int free_swap_and_cache(swp_entry_t entry)
p = swap_info_get(entry); p = swap_info_get(entry);
if (p) { if (p) {
if (swap_entry_free(p, entry, SWAP_MAP) == SWAP_HAS_CACHE) { if (swap_entry_free(p, entry, 1) == SWAP_HAS_CACHE) {
page = find_get_page(&swapper_space, entry.val); page = find_get_page(&swapper_space, entry.val);
if (page && !trylock_page(page)) { if (page && !trylock_page(page)) {
page_cache_release(page); page_cache_release(page);
...@@ -1212,7 +1183,7 @@ static int try_to_unuse(unsigned int type) ...@@ -1212,7 +1183,7 @@ static int try_to_unuse(unsigned int type)
if (swap_count(*swap_map) == SWAP_MAP_MAX) { if (swap_count(*swap_map) == SWAP_MAP_MAX) {
spin_lock(&swap_lock); spin_lock(&swap_lock);
*swap_map = encode_swapmap(0, true); *swap_map = SWAP_HAS_CACHE;
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
reset_overflow = 1; reset_overflow = 1;
} }
...@@ -2111,16 +2082,16 @@ void si_swapinfo(struct sysinfo *val) ...@@ -2111,16 +2082,16 @@ void si_swapinfo(struct sysinfo *val)
* - swap-cache reference is requested but there is already one. -> EEXIST * - swap-cache reference is requested but there is already one. -> EEXIST
* - swap-cache reference is requested but the entry is not used. -> ENOENT * - swap-cache reference is requested but the entry is not used. -> ENOENT
*/ */
static int __swap_duplicate(swp_entry_t entry, bool cache) static int __swap_duplicate(swp_entry_t entry, unsigned short usage)
{ {
struct swap_info_struct *p; struct swap_info_struct *p;
unsigned long offset, type; unsigned long offset, type;
int result = -EINVAL; unsigned short count;
int count; unsigned short has_cache;
bool has_cache; int err = -EINVAL;
if (non_swap_entry(entry)) if (non_swap_entry(entry))
return -EINVAL; goto out;
type = swp_type(entry); type = swp_type(entry);
if (type >= nr_swapfiles) if (type >= nr_swapfiles)
...@@ -2129,54 +2100,56 @@ static int __swap_duplicate(swp_entry_t entry, bool cache) ...@@ -2129,54 +2100,56 @@ static int __swap_duplicate(swp_entry_t entry, bool cache)
offset = swp_offset(entry); offset = swp_offset(entry);
spin_lock(&swap_lock); spin_lock(&swap_lock);
if (unlikely(offset >= p->max)) if (unlikely(offset >= p->max))
goto unlock_out; goto unlock_out;
count = swap_count(p->swap_map[offset]); count = p->swap_map[offset];
has_cache = swap_has_cache(p->swap_map[offset]); has_cache = count & SWAP_HAS_CACHE;
count &= ~SWAP_HAS_CACHE;
err = 0;
if (cache == SWAP_CACHE) { /* called for swapcache/swapin-readahead */ if (usage == SWAP_HAS_CACHE) {
/* set SWAP_HAS_CACHE if there is no cache and entry is used */ /* set SWAP_HAS_CACHE if there is no cache and entry is used */
if (!has_cache && count) { if (!has_cache && count)
p->swap_map[offset] = encode_swapmap(count, true); has_cache = SWAP_HAS_CACHE;
result = 0; else if (has_cache) /* someone else added cache */
} else if (has_cache) /* someone added cache */ err = -EEXIST;
result = -EEXIST; else /* no users remaining */
else if (!count) /* no users */ err = -ENOENT;
result = -ENOENT;
} else if (count || has_cache) { } else if (count || has_cache) {
if (count < SWAP_MAP_MAX - 1) {
p->swap_map[offset] = encode_swapmap(count + 1, if (count < SWAP_MAP_MAX - 1)
has_cache); count++;
result = 0; else if (count <= SWAP_MAP_MAX) {
} else if (count <= SWAP_MAP_MAX) {
if (swap_overflow++ < 5) if (swap_overflow++ < 5)
printk(KERN_WARNING printk(KERN_WARNING
"swap_dup: swap entry overflow\n"); "swap_dup: swap entry overflow\n");
p->swap_map[offset] = encode_swapmap(SWAP_MAP_MAX, count = SWAP_MAP_MAX;
has_cache); } else
result = 0; err = -EINVAL;
}
} else } else
result = -ENOENT; /* unused swap entry */ err = -ENOENT; /* unused swap entry */
p->swap_map[offset] = count | has_cache;
unlock_out: unlock_out:
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
out: out:
return result; return err;
bad_file: bad_file:
printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val); printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
goto out; goto out;
} }
/* /*
* increase reference count of swap entry by 1. * increase reference count of swap entry by 1.
*/ */
void swap_duplicate(swp_entry_t entry) void swap_duplicate(swp_entry_t entry)
{ {
__swap_duplicate(entry, SWAP_MAP); __swap_duplicate(entry, 1);
} }
/* /*
...@@ -2189,7 +2162,7 @@ void swap_duplicate(swp_entry_t entry) ...@@ -2189,7 +2162,7 @@ void swap_duplicate(swp_entry_t entry)
*/ */
int swapcache_prepare(swp_entry_t entry) int swapcache_prepare(swp_entry_t entry)
{ {
return __swap_duplicate(entry, SWAP_CACHE); return __swap_duplicate(entry, SWAP_HAS_CACHE);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment