LTP GCOV extension - code coverage report
Current view: directory - mm - swap_state.c
Test: 2.6.14_rebootonly_gcov.info
Date: 2006-05-22 Instrumented lines: 139
Code covered: 3.6 % Executed lines: 5

       1                 : /*
       2                 :  *  linux/mm/swap_state.c
       3                 :  *
       4                 :  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
       5                 :  *  Swap reorganised 29.12.95, Stephen Tweedie
       6                 :  *
       7                 :  *  Rewritten to use page cache, (C) 1998 Stephen Tweedie
       8                 :  */
       9                 : #include <linux/module.h>
      10                 : #include <linux/mm.h>
      11                 : #include <linux/kernel_stat.h>
      12                 : #include <linux/swap.h>
      13                 : #include <linux/init.h>
      14                 : #include <linux/pagemap.h>
      15                 : #include <linux/buffer_head.h>
      16                 : #include <linux/backing-dev.h>
      17                 : 
      18                 : #include <asm/pgtable.h>
      19                 : 
      20                 : /*
      21                 :  * swapper_space is a fiction, retained to simplify the path through
      22                 :  * vmscan's shrink_list, to make sync_page look nicer, and to allow
      23                 :  * future use of radix_tree tags in the swap cache.
      24                 :  */
      25                 : static struct address_space_operations swap_aops = {
      26                 :         .writepage      = swap_writepage,
      27                 :         .sync_page      = block_sync_page,
      28                 :         .set_page_dirty = __set_page_dirty_nobuffers,
      29                 : };
      30                 : 
      31                 : static struct backing_dev_info swap_backing_dev_info = {
      32                 :         .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
      33                 :         .unplug_io_fn   = swap_unplug_io_fn,
      34                 : };
      35                 : 
      36                 : struct address_space swapper_space = {
      37                 :         .page_tree      = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN),
      38                 :         .tree_lock      = RW_LOCK_UNLOCKED,
      39                 :         .a_ops          = &swap_aops,
      40                 :         .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear),
      41                 :         .backing_dev_info = &swap_backing_dev_info,
      42                 : };
      43                 : EXPORT_SYMBOL(swapper_space);
      44                 : 
      45                 : #define INC_CACHE_INFO(x)       do { swap_cache_info.x++; } while (0)
      46                 : 
      47                 : static struct {
      48                 :         unsigned long add_total;
      49                 :         unsigned long del_total;
      50                 :         unsigned long find_success;
      51                 :         unsigned long find_total;
      52                 :         unsigned long noent_race;
      53                 :         unsigned long exist_race;
      54                 : } swap_cache_info;
      55                 : 
      56                 : void show_swap_cache_info(void)
      57               0 : {
      58               0 :         printk("Swap cache: add %lu, delete %lu, find %lu/%lu, race %lu+%lu\n",
      59                 :                 swap_cache_info.add_total, swap_cache_info.del_total,
      60                 :                 swap_cache_info.find_success, swap_cache_info.find_total,
      61                 :                 swap_cache_info.noent_race, swap_cache_info.exist_race);
      62               0 :         printk("Free swap  = %lukB\n", nr_swap_pages << (PAGE_SHIFT - 10));
      63               0 :         printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10));
      64                 : }
      65                 : 
      66                 : /*
      67                 :  * __add_to_swap_cache resembles add_to_page_cache on swapper_space,
      68                 :  * but sets SwapCache flag and private instead of mapping and index.
      69                 :  */
      70                 : static int __add_to_swap_cache(struct page *page, swp_entry_t entry,
      71                 :                                gfp_t gfp_mask)
      72               0 : {
      73               0 :         int error;
      74                 : 
      75               0 :         BUG_ON(PageSwapCache(page));
      76               0 :         BUG_ON(PagePrivate(page));
      77               0 :         error = radix_tree_preload(gfp_mask);
      78               0 :         if (!error) {
      79               0 :                 write_lock_irq(&swapper_space.tree_lock);
      80               0 :                 error = radix_tree_insert(&swapper_space.page_tree,
      81                 :                                                 entry.val, page);
      82               0 :                 if (!error) {
      83               0 :                         page_cache_get(page);
      84               0 :                         SetPageLocked(page);
      85               0 :                         SetPageSwapCache(page);
      86               0 :                         page->private = entry.val;
      87               0 :                         total_swapcache_pages++;
      88               0 :                         pagecache_acct(1);
      89                 :                 }
      90               0 :                 write_unlock_irq(&swapper_space.tree_lock);
      91               0 :                 radix_tree_preload_end();
      92                 :         }
      93               0 :         return error;
      94                 : }
      95                 : 
      96                 : static int add_to_swap_cache(struct page *page, swp_entry_t entry)
      97               0 : {
      98               0 :         int error;
      99                 : 
     100               0 :         if (!swap_duplicate(entry)) {
     101               0 :                 INC_CACHE_INFO(noent_race);
     102               0 :                 return -ENOENT;
     103                 :         }
     104               0 :         error = __add_to_swap_cache(page, entry, GFP_KERNEL);
     105                 :         /*
     106                 :          * Anon pages are already on the LRU, we don't run lru_cache_add here.
     107                 :          */
     108               0 :         if (error) {
     109               0 :                 swap_free(entry);
     110               0 :                 if (error == -EEXIST)
     111               0 :                         INC_CACHE_INFO(exist_race);
     112               0 :                 return error;
     113                 :         }
     114               0 :         INC_CACHE_INFO(add_total);
     115               0 :         return 0;
     116                 : }
     117                 : 
     118                 : /*
     119                 :  * This must be called only on pages that have
     120                 :  * been verified to be in the swap cache.
     121                 :  */
     122                 : void __delete_from_swap_cache(struct page *page)
     123               0 : {
     124               0 :         BUG_ON(!PageLocked(page));
     125               0 :         BUG_ON(!PageSwapCache(page));
     126               0 :         BUG_ON(PageWriteback(page));
     127               0 :         BUG_ON(PagePrivate(page));
     128                 : 
     129               0 :         radix_tree_delete(&swapper_space.page_tree, page->private);
     130               0 :         page->private = 0;
     131               0 :         ClearPageSwapCache(page);
     132               0 :         total_swapcache_pages--;
     133               0 :         pagecache_acct(-1);
     134               0 :         INC_CACHE_INFO(del_total);
     135                 : }
     136                 : 
     137                 : /**
     138                 :  * add_to_swap - allocate swap space for a page
     139                 :  * @page: page we want to move to swap
     140                 :  *
     141                 :  * Allocate swap space for the page and add the page to the
     142                 :  * swap cache.  Caller needs to hold the page lock. 
     143                 :  */
     144                 : int add_to_swap(struct page * page)
     145               0 : {
     146               0 :         swp_entry_t entry;
     147               0 :         int err;
     148                 : 
     149               0 :         if (!PageLocked(page))
     150               0 :                 BUG();
     151                 : 
     152               0 :         for (;;) {
     153               0 :                 entry = get_swap_page();
     154               0 :                 if (!entry.val)
     155               0 :                         return 0;
     156                 : 
     157                 :                 /*
     158                 :                  * Radix-tree node allocations from PF_MEMALLOC contexts could
     159                 :                  * completely exhaust the page allocator. __GFP_NOMEMALLOC
     160                 :                  * stops emergency reserves from being allocated.
     161                 :                  *
     162                 :                  * TODO: this could cause a theoretical memory reclaim
     163                 :                  * deadlock in the swap out path.
     164                 :                  */
     165                 :                 /*
     166                 :                  * Add it to the swap cache and mark it dirty
     167                 :                  */
     168               0 :                 err = __add_to_swap_cache(page, entry,
     169                 :                                 GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN);
     170                 : 
     171               0 :                 switch (err) {
     172                 :                 case 0:                         /* Success */
     173               0 :                         SetPageUptodate(page);
     174               0 :                         SetPageDirty(page);
     175               0 :                         INC_CACHE_INFO(add_total);
     176               0 :                         return 1;
     177                 :                 case -EEXIST:
     178                 :                         /* Raced with "speculative" read_swap_cache_async */
     179               0 :                         INC_CACHE_INFO(exist_race);
     180               0 :                         swap_free(entry);
     181               0 :                         continue;
     182                 :                 default:
     183                 :                         /* -ENOMEM radix-tree allocation failure */
     184               0 :                         swap_free(entry);
     185               0 :                         return 0;
     186                 :                 }
     187                 :         }
     188                 : }
     189                 : 
     190                 : /*
     191                 :  * This must be called only on pages that have
     192                 :  * been verified to be in the swap cache and locked.
     193                 :  * It will never put the page into the free list,
     194                 :  * the caller has a reference on the page.
     195                 :  */
     196                 : void delete_from_swap_cache(struct page *page)
     197               0 : {
     198               0 :         swp_entry_t entry;
     199                 : 
     200               0 :         entry.val = page->private;
     201                 : 
     202               0 :         write_lock_irq(&swapper_space.tree_lock);
     203               0 :         __delete_from_swap_cache(page);
     204               0 :         write_unlock_irq(&swapper_space.tree_lock);
     205                 : 
     206               0 :         swap_free(entry);
     207               0 :         page_cache_release(page);
     208                 : }
     209                 : 
     210                 : /*
     211                 :  * Strange swizzling function only for use by shmem_writepage
     212                 :  */
     213                 : int move_to_swap_cache(struct page *page, swp_entry_t entry)
     214               0 : {
     215               0 :         int err = __add_to_swap_cache(page, entry, GFP_ATOMIC);
     216               0 :         if (!err) {
     217               0 :                 remove_from_page_cache(page);
     218               0 :                 page_cache_release(page);       /* pagecache ref */
     219               0 :                 if (!swap_duplicate(entry))
     220               0 :                         BUG();
     221               0 :                 SetPageDirty(page);
     222               0 :                 INC_CACHE_INFO(add_total);
     223               0 :         } else if (err == -EEXIST)
     224               0 :                 INC_CACHE_INFO(exist_race);
     225               0 :         return err;
     226                 : }
     227                 : 
     228                 : /*
     229                 :  * Strange swizzling function for shmem_getpage (and shmem_unuse)
     230                 :  */
     231                 : int move_from_swap_cache(struct page *page, unsigned long index,
     232                 :                 struct address_space *mapping)
     233               0 : {
     234               0 :         int err = add_to_page_cache(page, mapping, index, GFP_ATOMIC);
     235               0 :         if (!err) {
     236               0 :                 delete_from_swap_cache(page);
     237                 :                 /* shift page from clean_pages to dirty_pages list */
     238               0 :                 ClearPageDirty(page);
     239               0 :                 set_page_dirty(page);
     240                 :         }
     241               0 :         return err;
     242                 : }
     243                 : 
     244                 : /* 
     245                 :  * If we are the only user, then try to free up the swap cache. 
     246                 :  * 
     247                 :  * Its ok to check for PageSwapCache without the page lock
     248                 :  * here because we are going to recheck again inside 
     249                 :  * exclusive_swap_page() _with_ the lock. 
     250                 :  *                                      - Marcelo
     251                 :  */
     252                 : static inline void free_swap_cache(struct page *page)
     253           14592 : {
     254           14592 :         if (PageSwapCache(page) && !TestSetPageLocked(page)) {
     255               0 :                 remove_exclusive_swap_page(page);
     256               0 :                 unlock_page(page);
     257                 :         }
     258                 : }
     259                 : 
     260                 : /* 
     261                 :  * Perform a free_page(), also freeing any swap cache associated with
     262                 :  * this page if it is the last user of the page. Can not do a lock_page,
     263                 :  * as we are holding the page_table_lock spinlock.
     264                 :  */
     265                 : void free_page_and_swap_cache(struct page *page)
     266           14592 : {
     267           14592 :         free_swap_cache(page);
     268           14592 :         page_cache_release(page);
     269                 : }
     270                 : 
     271                 : /*
     272                 :  * Passed an array of pages, drop them all from swapcache and then release
     273                 :  * them.  They are removed from the LRU and freed if this is their last use.
     274                 :  */
     275                 : void free_pages_and_swap_cache(struct page **pages, int nr)
     276               0 : {
     277               0 :         int chunk = 16;
     278               0 :         struct page **pagep = pages;
     279                 : 
     280               0 :         lru_add_drain();
     281               0 :         while (nr) {
     282               0 :                 int todo = min(chunk, nr);
     283               0 :                 int i;
     284                 : 
     285               0 :                 for (i = 0; i < todo; i++)
     286               0 :                         free_swap_cache(pagep[i]);
     287               0 :                 release_pages(pagep, todo, 0);
     288               0 :                 pagep += todo;
     289               0 :                 nr -= todo;
     290                 :         }
     291                 : }
     292                 : 
     293                 : /*
     294                 :  * Lookup a swap entry in the swap cache. A found page will be returned
     295                 :  * unlocked and with its refcount incremented - we rely on the kernel
     296                 :  * lock getting page table operations atomic even if we drop the page
     297                 :  * lock before returning.
     298                 :  */
     299                 : struct page * lookup_swap_cache(swp_entry_t entry)
     300               0 : {
     301               0 :         struct page *page;
     302                 : 
     303               0 :         page = find_get_page(&swapper_space, entry.val);
     304                 : 
     305               0 :         if (page)
     306               0 :                 INC_CACHE_INFO(find_success);
     307                 : 
     308               0 :         INC_CACHE_INFO(find_total);
     309               0 :         return page;
     310                 : }
     311                 : 
     312                 : /* 
     313                 :  * Locate a page of swap in physical memory, reserving swap cache space
     314                 :  * and reading the disk if it is not already cached.
     315                 :  * A failure return means that either the page allocation failed or that
     316                 :  * the swap entry is no longer in use.
     317                 :  */
     318                 : struct page *read_swap_cache_async(swp_entry_t entry,
     319                 :                         struct vm_area_struct *vma, unsigned long addr)
     320               0 : {
     321               0 :         struct page *found_page, *new_page = NULL;
     322               0 :         int err;
     323                 : 
     324               0 :         do {
     325                 :                 /*
     326                 :                  * First check the swap cache.  Since this is normally
     327                 :                  * called after lookup_swap_cache() failed, re-calling
     328                 :                  * that would confuse statistics.
     329                 :                  */
     330               0 :                 found_page = find_get_page(&swapper_space, entry.val);
     331               0 :                 if (found_page)
     332               0 :                         break;
     333                 : 
     334                 :                 /*
     335                 :                  * Get a new page to read into from swap.
     336                 :                  */
     337               0 :                 if (!new_page) {
     338               0 :                         new_page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
     339               0 :                         if (!new_page)
     340               0 :                                 break;          /* Out of memory */
     341                 :                 }
     342                 : 
     343                 :                 /*
     344                 :                  * Associate the page with swap entry in the swap cache.
     345                 :                  * May fail (-ENOENT) if swap entry has been freed since
     346                 :                  * our caller observed it.  May fail (-EEXIST) if there
     347                 :                  * is already a page associated with this entry in the
     348                 :                  * swap cache: added by a racing read_swap_cache_async,
     349                 :                  * or by try_to_swap_out (or shmem_writepage) re-using
     350                 :                  * the just freed swap entry for an existing page.
     351                 :                  * May fail (-ENOMEM) if radix-tree node allocation failed.
     352                 :                  */
     353               0 :                 err = add_to_swap_cache(new_page, entry);
     354               0 :                 if (!err) {
     355                 :                         /*
     356                 :                          * Initiate read into locked page and return.
     357                 :                          */
     358               0 :                         lru_cache_add_active(new_page);
     359               0 :                         swap_readpage(NULL, new_page);
     360               0 :                         return new_page;
     361                 :                 }
     362               0 :         } while (err != -ENOENT && err != -ENOMEM);
     363                 : 
     364               0 :         if (new_page)
     365               0 :                 page_cache_release(new_page);
     366               0 :         return found_page;
     367                 : }

Generated by: LTP GCOV extension version 1.4