netlib.narod.ru< Назад | Оглавление | Далее >

mm/swap_state.c

37479 /*
37480  *  linux/mm/swap_state.c
37481  *
37482  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
37483  *  Swap reorganised 29.12.95, Stephen Tweedie
37484  *
37485  *  Rewritten to use page cache, (C) 1998 Stephen Tweedie
37486  */
37487 
37488 #include <linux/mm.h>
37489 #include <linux/kernel_stat.h>
37490 #include <linux/swap.h>
37491 #include <linux/swapctl.h>
37492 #include <linux/init.h>
37493 #include <linux/pagemap.h>
37494 
37495 #include <asm/pgtable.h>
37496 
37497 /* Keep a reserved false inode which we will use to mark
37498  * pages in the page cache are acting as swap cache
37499  * instead of file cache.
37500  *
37501  * We only need a unique pointer to satisfy the page
37502  * cache, but we'll reserve an entire zeroed inode
37503  * structure for the purpose just to ensure that any
37504  * mistaken dereferences of this structure cause a kernel
37505  * oops.  */
37506 struct inode swapper_inode;
37507 
37508 #ifdef SWAP_CACHE_INFO
37509 unsigned long swap_cache_add_total = 0;
37510 unsigned long swap_cache_del_total = 0;
37511 unsigned long swap_cache_find_total = 0;
37512 unsigned long swap_cache_find_success = 0;
37513 
37514 void show_swap_cache_info(void)
37515 {
37516   printk("Swap cache: add %ld, delete %ld, "
37517          "find %ld/%ld\n",
37518          swap_cache_add_total,
37519          swap_cache_del_total,
37520          swap_cache_find_success, swap_cache_find_total);
37521 }
37522 #endif
37523 
37524 int add_to_swap_cache(struct page *page,
37525                       unsigned long entry)
37526 {
37527 #ifdef SWAP_CACHE_INFO
37528   swap_cache_add_total++;
37529 #endif
37530 #ifdef DEBUG_SWAP
37531   printk("DebugVM: add_to_swap_cache(%08lx count %d, "
37532          "entry %08lx)\n", page_address(page),
37533          atomic_read(&page->count), entry);
37534 #endif
37535   if (PageTestandSetSwapCache(page)) {
37536     printk(KERN_ERR
37537            "swap_cache: replacing non-empty entry %08lx "
37538            "on page %08lx\n",
37539            page->offset, page_address(page));
37540     return 0;
37541   }
37542   if (page->inode) {
37543     printk(KERN_ERR
37544            "swap_cache: replacing page-cached entry "
37545            "on page %08lx\n", page_address(page));
37546     return 0;
37547   }
37548   atomic_inc(&page->count);
37549   page->inode = &swapper_inode;
37550   page->offset = entry;
37551   add_page_to_hash_queue(page, &swapper_inode, entry);
37552   add_page_to_inode_queue(&swapper_inode, page);
37553   return 1;
37554 }
37555 
37556 /* Verify that a swap entry is valid and increment its
37557  * swap map count.
37558  *
37559  * Note: if swap_map[] reaches SWAP_MAP_MAX the entries
37560  * are treated as "permanent", but will be reclaimed by
37561  * the next swapoff.  */
37562 int swap_duplicate(unsigned long entry)
37563 {
37564   struct swap_info_struct * p;
37565   unsigned long offset, type;
37566   int result = 0;
37567 
37568   if (!entry)
37569     goto out;
37570   type = SWP_TYPE(entry);
37571   if (type & SHM_SWP_TYPE)
37572     goto out;
37573   if (type >= nr_swapfiles)
37574     goto bad_file;
37575   p = type + swap_info;
37576   offset = SWP_OFFSET(entry);
37577   if (offset >= p->max)
37578     goto bad_offset;
37579   if (!p->swap_map[offset])
37580     goto bad_unused;
37581   /* Entry is valid, so increment the map count. */
37582   if (p->swap_map[offset] < SWAP_MAP_MAX)
37583     p->swap_map[offset]++;
37584   else {
37585     static int overflow = 0;
37586     if (overflow++ < 5)
37587       printk(KERN_WARNING
37588         "swap_duplicate: entry %08lx map count=%d\n",
37589         entry, p->swap_map[offset]);
37590     p->swap_map[offset] = SWAP_MAP_MAX;
37591   }
37592   result = 1;
37593 #ifdef DEBUG_SWAP
37594   printk("DebugVM: swap_duplicate(entry %08lx, "
37595          "count now %d)\n", entry, p->swap_map[offset]);
37596 #endif
37597 out:
37598   return result;
37599 
37600 bad_file:
37601   printk(KERN_ERR "swap_duplicate: entry %08lx, "
37602          "nonexistent swap file\n", entry);
37603   goto out;
37604 bad_offset:
37605   printk(KERN_ERR "swap_duplicate: entry %08lx, "
37606          "offset exceeds max\n", entry);
37607   goto out;
37608 bad_unused:
37609   printk(KERN_ERR "swap_duplicate at %8p: "
37610          "entry %08lx, unused page\n",
37611          __builtin_return_address(0), entry);
37612   goto out;
37613 }
37614 
37615 int swap_count(unsigned long entry)
37616 {
37617   struct swap_info_struct * p;
37618   unsigned long offset, type;
37619   int retval = 0;
37620 
37621   if (!entry)
37622     goto bad_entry;
37623   type = SWP_TYPE(entry);
37624   if (type & SHM_SWP_TYPE)
37625     goto out;
37626   if (type >= nr_swapfiles)
37627     goto bad_file;
37628   p = type + swap_info;
37629   offset = SWP_OFFSET(entry);
37630   if (offset >= p->max)
37631     goto bad_offset;
37632   if (!p->swap_map[offset])
37633     goto bad_unused;
37634   retval = p->swap_map[offset];
37635 #ifdef DEBUG_SWAP
37636   printk("DebugVM: swap_count(entry %08lx, count %d)\n",
37637          entry, retval);
37638 #endif
37639 out:
37640   return retval;
37641 
37642 bad_entry:
37643   printk(KERN_ERR "swap_count: null entry!\n");
37644   goto out;
37645 bad_file:
37646   printk(KERN_ERR "swap_count: entry %08lx, "
37647          "nonexistent swap file!\n", entry);
37648   goto out;
37649 bad_offset:
37650   printk(KERN_ERR "swap_count: entry %08lx, offset "
37651          "exceeds max!\n", entry);
37652   goto out;
37653 bad_unused:
37654   printk(KERN_ERR "swap_count at %8p: entry %08lx, "
37655          "unused page!\n", __builtin_return_address(0),
37656          entry);
37657   goto out;
37658 }
37659 
37660 static inline void remove_from_swap_cache(
37661   struct page *page)
37662 {
37663   if (!page->inode) {
37664     printk("VM: Removing swap cache page with zero inode"
37665            " hash on page %08lx\n", page_address(page));
37666     return;
37667   }
37668   if (page->inode != &swapper_inode) {
37669     printk("VM: Removing swap cache page with wrong "
37670            "inode hash on page %08lx\n",
37671            page_address(page));
37672   }
37673 
37674 #ifdef DEBUG_SWAP
37675   printk("DebugVM: remove_from_swap_cache(%08lx "
37676          "count %d)\n",
37677          page_address(page), atomic_read(&page->count));
37678 #endif
37679   PageClearSwapCache (page);
37680   remove_inode_page(page);
37681 }
37682 
37683 
37684 /* This must be called only on pages that have been
37685  * verified to be in the swap cache.  */
37686 void delete_from_swap_cache(struct page *page)
37687 {
37688   long entry = page->offset;
37689 
37690 #ifdef SWAP_CACHE_INFO
37691   swap_cache_del_total++;
37692 #endif
37693 #ifdef DEBUG_SWAP
37694   printk("DebugVM: delete_from_swap_cache(%08lx "
37695          "count %d, entry %08lx)\n",
37696          page_address(page), atomic_read(&page->count),
37697          entry);
37698 #endif
37699   remove_from_swap_cache (page);
37700   swap_free (entry);
37701 }
37702 
37703 /* Perform a free_page(), also freeing any swap cache
37704  * associated with this page if it is the last user of
37705  * the page.  */
37706 
37707 void free_page_and_swap_cache(unsigned long addr)
37708 {
37709   struct page *page = mem_map + MAP_NR(addr);
37710 
37711   /* If we are the only user, then free up the swap
37712    * cache.  */
37713   if (PageSwapCache(page) && !is_page_shared(page)) {
37714     delete_from_swap_cache(page);
37715   }
37716 
37717   __free_page(page);
37718 }
37719 
37720 /* Lookup a swap entry in the swap cache.  We need to be
37721  * careful about locked pages.  A found page will be
37722  * returned with its refcount incremented.  */
37723 struct page * lookup_swap_cache(unsigned long entry)
37724 {
37725   struct page *found;
37726 
37727 #ifdef SWAP_CACHE_INFO
37728   swap_cache_find_total++;
37729 #endif
37730   while (1) {
37731     found = find_page(&swapper_inode, entry);
37732     if (!found)
37733       return 0;
37734     if (found->inode != &swapper_inode ||
37735         !PageSwapCache(found))
37736       goto out_bad;
37737     if (!PageLocked(found)) {
37738 #ifdef SWAP_CACHE_INFO
37739       swap_cache_find_success++;
37740 #endif
37741       return found;
37742     }
37743     __free_page(found);
37744     __wait_on_page(found);
37745   }
37746 
37747 out_bad:
37748   printk(KERN_ERR
37749          "VM: Found a non-swapper swap page!\n");
37750   __free_page(found);
37751   return 0;
37752 }
37753 
37754 /* Locate a page of swap in physical memory, reserving
37755  * swap cache space and reading the disk if it is not
37756  * already cached.  If wait==0, we are only doing
37757  * readahead, so don't worry if the page is already
37758  * locked.
37759  *
37760  * A failure return means that either the page allocation
37761  * failed or that the swap entry is no longer in use.  */
37762 struct page * read_swap_cache_async(unsigned long entry,
37763                                     int wait)
37764 {
37765   struct page *found_page = 0, *new_page;
37766   unsigned long new_page_addr;
37767 
37768 #ifdef DEBUG_SWAP
37769   printk("DebugVM: read_swap_cache_async entry %08lx%s\n"
37770          , entry, wait ? ", wait" : "");
37771 #endif
37772   /* Make sure the swap entry is still in use. */
37773   /* Account for the swap cache */
37774   if (!swap_duplicate(entry))
37775     goto out;
37776   /* Look for the page in the swap cache. */
37777   found_page = lookup_swap_cache(entry);
37778   if (found_page)
37779     goto out_free_swap;
37780 
37781   new_page_addr = __get_free_page(GFP_USER);
37782   if (!new_page_addr)
37783     goto out_free_swap;     /* Out of memory */
37784   new_page = mem_map + MAP_NR(new_page_addr);
37785 
37786   /* Check the swap cache again, in case we stalled
37787    * above. */
37788   found_page = lookup_swap_cache(entry);
37789   if (found_page)
37790     goto out_free_page;
37791   /* Add it to the swap cache and read its contents. */
37792   if (!add_to_swap_cache(new_page, entry))
37793     goto out_free_page;
37794 
37795   set_bit(PG_locked, &new_page->flags);
37796   rw_swap_page(READ, entry, (char *)new_page_addr, wait);
37797 #ifdef DEBUG_SWAP
37798   printk("DebugVM: read_swap_cache_async created "
37799          "entry %08lx at %p\n",
37800          entry, (char *) page_address(new_page));
37801 #endif
37802   return new_page;
37803 
37804 out_free_page:
37805   __free_page(new_page);
37806 out_free_swap:
37807   swap_free(entry);
37808 out:
37809   return found_page;
37810 }

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz