swap_info: SWAP_HAS_CACHE cleanups
Hugh Dickins [Tue, 15 Dec 2009 01:58:44 +0000 (17:58 -0800)]
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: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

include/linux/swap.h
mm/swapfile.c

index 109dfe7..c9d8870 100644 (file)
@@ -154,7 +154,7 @@ enum {
 #define SWAP_MAP_MAX   0x7ffe
 #define SWAP_MAP_BAD   0x7fff
 #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.
  */
index fa5f10b..5249749 100644 (file)
@@ -53,30 +53,9 @@ static struct swap_info_struct *swap_info[MAX_SWAPFILES];
 
 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)
 {
-       return ent & SWAP_COUNT_MASK;
-}
-
-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;
+       return ent & ~SWAP_HAS_CACHE;
 }
 
 /* returns 1 if swap entry is freed */
@@ -224,7 +203,7 @@ static int wait_for_discard(void *word)
 #define LATENCY_LIMIT          256
 
 static inline unsigned long scan_swap_map(struct swap_info_struct *si,
-                                         int cache)
+                                         unsigned short usage)
 {
        unsigned long offset;
        unsigned long scan_base;
@@ -355,10 +334,7 @@ checks:
                si->lowest_bit = si->max;
                si->highest_bit = 0;
        }
-       if (cache == SWAP_CACHE) /* at usual swap-out via vmscan.c */
-               si->swap_map[offset] = encode_swapmap(0, true);
-       else /* at suspend */
-               si->swap_map[offset] = encode_swapmap(1, false);
+       si->swap_map[offset] = usage;
        si->cluster_next = offset + 1;
        si->flags -= SWP_SCANNING;
 
@@ -483,7 +459,7 @@ swp_entry_t get_swap_page(void)
 
                swap_list.next = next;
                /* 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) {
                        spin_unlock(&swap_lock);
                        return swp_entry(type, offset);
@@ -508,7 +484,7 @@ swp_entry_t get_swap_page_of_type(int type)
        if (si && (si->flags & SWP_WRITEOK)) {
                nr_swap_pages--;
                /* This is called for allocating swap entry, not cache */
-               offset = scan_swap_map(si, SWAP_MAP);
+               offset = scan_swap_map(si, 1);
                if (offset) {
                        spin_unlock(&swap_lock);
                        return swp_entry(type, offset);
@@ -555,29 +531,31 @@ out:
        return NULL;
 }
 
-static int swap_entry_free(struct swap_info_struct *p,
-                          swp_entry_t ent, int cache)
+static unsigned short swap_entry_free(struct swap_info_struct *p,
+                          swp_entry_t entry, unsigned short usage)
 {
-       unsigned long offset = swp_offset(ent);
-       int count = swap_count(p->swap_map[offset]);
-       bool has_cache;
+       unsigned long offset = swp_offset(entry);
+       unsigned short count;
+       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 (count < SWAP_MAP_MAX) {
-                       count--;
-                       p->swap_map[offset] = encode_swapmap(count, has_cache);
-               }
-       } else { /* dropping swap cache flag */
+       if (usage == SWAP_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 */
-       if (!count) {
+       if (!usage) {
                if (offset < p->lowest_bit)
                        p->lowest_bit = offset;
                if (offset > p->highest_bit)
@@ -588,9 +566,8 @@ static int swap_entry_free(struct swap_info_struct *p,
                nr_swap_pages++;
                p->inuse_pages--;
        }
-       if (!swap_count(count))
-               mem_cgroup_uncharge_swap(ent);
-       return count;
+
+       return usage;
 }
 
 /*
@@ -603,7 +580,7 @@ void swap_free(swp_entry_t entry)
 
        p = swap_info_get(entry);
        if (p) {
-               swap_entry_free(p, entry, SWAP_MAP);
+               swap_entry_free(p, entry, 1);
                spin_unlock(&swap_lock);
        }
 }
@@ -614,19 +591,13 @@ void swap_free(swp_entry_t entry)
 void swapcache_free(swp_entry_t entry, struct page *page)
 {
        struct swap_info_struct *p;
-       int ret;
+       unsigned short count;
 
        p = swap_info_get(entry);
        if (p) {
-               ret = swap_entry_free(p, entry, SWAP_CACHE);
-               if (page) {
-                       bool swapout;
-                       if (ret)
-                               swapout = true; /* the end of swap out */
-                       else
-                               swapout = false; /* no more swap users! */
-                       mem_cgroup_uncharge_swapcache(page, entry, swapout);
-               }
+               count = swap_entry_free(p, entry, SWAP_HAS_CACHE);
+               if (page)
+                       mem_cgroup_uncharge_swapcache(page, entry, count != 0);
                spin_unlock(&swap_lock);
        }
 }
@@ -705,7 +676,7 @@ int free_swap_and_cache(swp_entry_t entry)
 
        p = swap_info_get(entry);
        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);
                        if (page && !trylock_page(page)) {
                                page_cache_release(page);
@@ -1212,7 +1183,7 @@ static int try_to_unuse(unsigned int type)
 
                if (swap_count(*swap_map) == SWAP_MAP_MAX) {
                        spin_lock(&swap_lock);
-                       *swap_map = encode_swapmap(0, true);
+                       *swap_map = SWAP_HAS_CACHE;
                        spin_unlock(&swap_lock);
                        reset_overflow = 1;
                }
@@ -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 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;
        unsigned long offset, type;
-       int result = -EINVAL;
-       int count;
-       bool has_cache;
+       unsigned short count;
+       unsigned short has_cache;
+       int err = -EINVAL;
 
        if (non_swap_entry(entry))
-               return -EINVAL;
+               goto out;
 
        type = swp_type(entry);
        if (type >= nr_swapfiles)
@@ -2129,54 +2100,56 @@ static int __swap_duplicate(swp_entry_t entry, bool cache)
        offset = swp_offset(entry);
 
        spin_lock(&swap_lock);
-
        if (unlikely(offset >= p->max))
                goto unlock_out;
 
-       count = swap_count(p->swap_map[offset]);
-       has_cache = swap_has_cache(p->swap_map[offset]);
+       count = 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 */
-               if (!has_cache && count) {
-                       p->swap_map[offset] = encode_swapmap(count, true);
-                       result = 0;
-               } else if (has_cache) /* someone added cache */
-                       result = -EEXIST;
-               else if (!count) /* no users */
-                       result = -ENOENT;
+               if (!has_cache && count)
+                       has_cache = SWAP_HAS_CACHE;
+               else if (has_cache)             /* someone else added cache */
+                       err = -EEXIST;
+               else                            /* no users remaining */
+                       err = -ENOENT;
 
        } else if (count || has_cache) {
-               if (count < SWAP_MAP_MAX - 1) {
-                       p->swap_map[offset] = encode_swapmap(count + 1,
-                                                            has_cache);
-                       result = 0;
-               } else if (count <= SWAP_MAP_MAX) {
+
+               if (count < SWAP_MAP_MAX - 1)
+                       count++;
+               else if (count <= SWAP_MAP_MAX) {
                        if (swap_overflow++ < 5)
                                printk(KERN_WARNING
                                       "swap_dup: swap entry overflow\n");
-                       p->swap_map[offset] = encode_swapmap(SWAP_MAP_MAX,
-                                                             has_cache);
-                       result = 0;
-               }
+                       count = SWAP_MAP_MAX;
+               } else
+                       err = -EINVAL;
        } else
-               result = -ENOENT; /* unused swap entry */
+               err = -ENOENT;                  /* unused swap entry */
+
+       p->swap_map[offset] = count | has_cache;
+
 unlock_out:
        spin_unlock(&swap_lock);
 out:
-       return result;
+       return err;
 
 bad_file:
        printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
        goto out;
 }
+
 /*
  * increase reference count of swap entry by 1.
  */
 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)
  */
 int swapcache_prepare(swp_entry_t entry)
 {
-       return __swap_duplicate(entry, SWAP_CACHE);
+       return __swap_duplicate(entry, SWAP_HAS_CACHE);
 }
 
 /*