mm: fix various kernel-doc comments
[safe/jmp/linux-2.6] / mm / swapfile.c
index 9678182..2da149c 100644 (file)
@@ -5,7 +5,6 @@
  *  Swap reorganised 29.12.95, Stephen Tweedie
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/mman.h>
@@ -28,6 +27,7 @@
 #include <linux/mutex.h>
 #include <linux/capability.h>
 #include <linux/syscalls.h>
+#include <linux/memcontrol.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -45,7 +45,7 @@ static const char Unused_offset[] = "Unused swap offset entry ";
 
 struct swap_list_t swap_list = {-1, -1};
 
-struct swap_info_struct swap_info[MAX_SWAPFILES];
+static struct swap_info_struct swap_info[MAX_SWAPFILES];
 
 static DEFINE_MUTEX(swapon_mutex);
 
@@ -116,7 +116,7 @@ static inline unsigned long scan_swap_map(struct swap_info_struct *si)
                                last_in_cluster = offset + SWAPFILE_CLUSTER;
                        else if (offset == last_in_cluster) {
                                spin_lock(&swap_lock);
-                               si->cluster_next = offset-SWAPFILE_CLUSTER-1;
+                               si->cluster_next = offset-SWAPFILE_CLUSTER+1;
                                goto cluster;
                        }
                        if (unlikely(--latency_ration < 0)) {
@@ -395,20 +395,29 @@ void free_swap_and_cache(swp_entry_t entry)
        struct swap_info_struct * p;
        struct page *page = NULL;
 
+       if (is_migration_entry(entry))
+               return;
+
        p = swap_info_get(entry);
        if (p) {
-               if (swap_entry_free(p, swp_offset(entry)) == 1)
-                       page = find_trylock_page(&swapper_space, entry.val);
+               if (swap_entry_free(p, swp_offset(entry)) == 1) {
+                       page = find_get_page(&swapper_space, entry.val);
+                       if (page && unlikely(TestSetPageLocked(page))) {
+                               page_cache_release(page);
+                               page = NULL;
+                       }
+               }
                spin_unlock(&swap_lock);
        }
        if (page) {
                int one_user;
 
                BUG_ON(PagePrivate(page));
-               page_cache_get(page);
                one_user = (page_count(page) == 2);
                /* Only cache user (+us), or swap space full? Free it! */
-               if (!PageWriteback(page) && (one_user || vm_swap_full())) {
+               /* Also recheck PageSwapCache after page is locked (above) */
+               if (PageSwapCache(page) && !PageWriteback(page) &&
+                                       (one_user || vm_swap_full())) {
                        delete_from_swap_cache(page);
                        SetPageDirty(page);
                }
@@ -417,14 +426,105 @@ void free_swap_and_cache(swp_entry_t entry)
        }
 }
 
+#ifdef CONFIG_HIBERNATION
+/*
+ * Find the swap type that corresponds to given device (if any).
+ *
+ * @offset - number of the PAGE_SIZE-sized block of the device, starting
+ * from 0, in which the swap header is expected to be located.
+ *
+ * This is needed for the suspend to disk (aka swsusp).
+ */
+int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
+{
+       struct block_device *bdev = NULL;
+       int i;
+
+       if (device)
+               bdev = bdget(device);
+
+       spin_lock(&swap_lock);
+       for (i = 0; i < nr_swapfiles; i++) {
+               struct swap_info_struct *sis = swap_info + i;
+
+               if (!(sis->flags & SWP_WRITEOK))
+                       continue;
+
+               if (!bdev) {
+                       if (bdev_p)
+                               *bdev_p = sis->bdev;
+
+                       spin_unlock(&swap_lock);
+                       return i;
+               }
+               if (bdev == sis->bdev) {
+                       struct swap_extent *se;
+
+                       se = list_entry(sis->extent_list.next,
+                                       struct swap_extent, list);
+                       if (se->start_block == offset) {
+                               if (bdev_p)
+                                       *bdev_p = sis->bdev;
+
+                               spin_unlock(&swap_lock);
+                               bdput(bdev);
+                               return i;
+                       }
+               }
+       }
+       spin_unlock(&swap_lock);
+       if (bdev)
+               bdput(bdev);
+
+       return -ENODEV;
+}
+
+/*
+ * Return either the total number of swap pages of given type, or the number
+ * of free pages of that type (depending on @free)
+ *
+ * This is needed for software suspend
+ */
+unsigned int count_swap_pages(int type, int free)
+{
+       unsigned int n = 0;
+
+       if (type < nr_swapfiles) {
+               spin_lock(&swap_lock);
+               if (swap_info[type].flags & SWP_WRITEOK) {
+                       n = swap_info[type].pages;
+                       if (free)
+                               n -= swap_info[type].inuse_pages;
+               }
+               spin_unlock(&swap_lock);
+       }
+       return n;
+}
+#endif
+
 /*
  * No need to decide whether this PTE shares the swap entry with others,
  * just let do_wp_page work it out if a write is requested later - to
  * force COW, vm_page_prot omits write permission from any private vma.
  */
-static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
+static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, swp_entry_t entry, struct page *page)
 {
+       spinlock_t *ptl;
+       pte_t *pte;
+       int ret = 1;
+
+       if (mem_cgroup_charge(page, vma->vm_mm, GFP_KERNEL))
+               ret = -ENOMEM;
+
+       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
+               if (ret > 0)
+                       mem_cgroup_uncharge_page(page);
+               ret = 0;
+               goto out;
+       }
+
        inc_mm_counter(vma->vm_mm, anon_rss);
        get_page(page);
        set_pte_at(vma->vm_mm, addr, pte,
@@ -436,6 +536,9 @@ static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
         * immediately swapped out again after swapon.
         */
        activate_page(page);
+out:
+       pte_unmap_unlock(pte, ptl);
+       return ret;
 }
 
 static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
@@ -444,23 +547,34 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 {
        pte_t swp_pte = swp_entry_to_pte(entry);
        pte_t *pte;
-       spinlock_t *ptl;
-       int found = 0;
+       int ret = 0;
 
-       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       /*
+        * We don't actually need pte lock while scanning for swp_pte: since
+        * we hold page lock and mmap_sem, swp_pte cannot be inserted into the
+        * page table while we're scanning; though it could get zapped, and on
+        * some architectures (e.g. x86_32 with PAE) we might catch a glimpse
+        * of unmatched parts which look like swp_pte, so unuse_pte must
+        * recheck under pte lock.  Scanning without pte lock lets it be
+        * preemptible whenever CONFIG_PREEMPT but not CONFIG_HIGHPTE.
+        */
+       pte = pte_offset_map(pmd, addr);
        do {
                /*
                 * swapoff spends a _lot_ of time in this loop!
                 * Test inline before going to call unuse_pte.
                 */
                if (unlikely(pte_same(*pte, swp_pte))) {
-                       unuse_pte(vma, pte++, addr, entry, page);
-                       found = 1;
-                       break;
+                       pte_unmap(pte);
+                       ret = unuse_pte(vma, pmd, addr, entry, page);
+                       if (ret)
+                               goto out;
+                       pte = pte_offset_map(pmd, addr);
                }
        } while (pte++, addr += PAGE_SIZE, addr != end);
-       pte_unmap_unlock(pte - 1, ptl);
-       return found;
+       pte_unmap(pte - 1);
+out:
+       return ret;
 }
 
 static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,
@@ -469,14 +583,16 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,
 {
        pmd_t *pmd;
        unsigned long next;
+       int ret;
 
        pmd = pmd_offset(pud, addr);
        do {
                next = pmd_addr_end(addr, end);
                if (pmd_none_or_clear_bad(pmd))
                        continue;
-               if (unuse_pte_range(vma, pmd, addr, next, entry, page))
-                       return 1;
+               ret = unuse_pte_range(vma, pmd, addr, next, entry, page);
+               if (ret)
+                       return ret;
        } while (pmd++, addr = next, addr != end);
        return 0;
 }
@@ -487,14 +603,16 @@ static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
 {
        pud_t *pud;
        unsigned long next;
+       int ret;
 
        pud = pud_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
                if (pud_none_or_clear_bad(pud))
                        continue;
-               if (unuse_pmd_range(vma, pud, addr, next, entry, page))
-                       return 1;
+               ret = unuse_pmd_range(vma, pud, addr, next, entry, page);
+               if (ret)
+                       return ret;
        } while (pud++, addr = next, addr != end);
        return 0;
 }
@@ -504,6 +622,7 @@ static int unuse_vma(struct vm_area_struct *vma,
 {
        pgd_t *pgd;
        unsigned long addr, end, next;
+       int ret;
 
        if (page->mapping) {
                addr = page_address_in_vma(page, vma);
@@ -521,8 +640,9 @@ static int unuse_vma(struct vm_area_struct *vma,
                next = pgd_addr_end(addr, end);
                if (pgd_none_or_clear_bad(pgd))
                        continue;
-               if (unuse_pud_range(vma, pgd, addr, next, entry, page))
-                       return 1;
+               ret = unuse_pud_range(vma, pgd, addr, next, entry, page);
+               if (ret)
+                       return ret;
        } while (pgd++, addr = next, addr != end);
        return 0;
 }
@@ -531,6 +651,7 @@ static int unuse_mm(struct mm_struct *mm,
                                swp_entry_t entry, struct page *page)
 {
        struct vm_area_struct *vma;
+       int ret = 0;
 
        if (!down_read_trylock(&mm->mmap_sem)) {
                /*
@@ -543,15 +664,11 @@ static int unuse_mm(struct mm_struct *mm,
                lock_page(page);
        }
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if (vma->anon_vma && unuse_vma(vma, entry, page))
+               if (vma->anon_vma && (ret = unuse_vma(vma, entry, page)))
                        break;
        }
        up_read(&mm->mmap_sem);
-       /*
-        * Currently unuse_mm cannot fail, but leave error handling
-        * at call sites for now, since we change it from time to time.
-        */
-       return 0;
+       return (ret < 0)? ret: 0;
 }
 
 /*
@@ -646,8 +763,8 @@ static int try_to_unuse(unsigned int type)
                 */
                swap_map = &si->swap_map[i];
                entry = swp_entry(type, i);
-again:
-               page = read_swap_cache_async(entry, NULL, 0);
+               page = read_swap_cache_async(entry,
+                                       GFP_HIGHUSER_MOVABLE, NULL, 0);
                if (!page) {
                        /*
                         * Either swap_duplicate() failed because entry
@@ -681,12 +798,6 @@ again:
                wait_on_page_locked(page);
                wait_on_page_writeback(page);
                lock_page(page);
-               if (!PageSwapCache(page)) {
-                       /* Page migration has occured */
-                       unlock_page(page);
-                       page_cache_release(page);
-                       goto again;
-               }
                wait_on_page_writeback(page);
 
                /*
@@ -712,13 +823,11 @@ again:
                        atomic_inc(&new_start_mm->mm_users);
                        atomic_inc(&prev_mm->mm_users);
                        spin_lock(&mmlist_lock);
-                       while (*swap_map > 1 && !retval &&
+                       while (*swap_map > 1 && !retval && !shmem &&
                                        (p = p->next) != &start_mm->mmlist) {
                                mm = list_entry(p, struct mm_struct, mmlist);
-                               if (atomic_inc_return(&mm->mm_users) == 1) {
-                                       atomic_dec(&mm->mm_users);
+                               if (!atomic_inc_not_zero(&mm->mm_users))
                                        continue;
-                               }
                                spin_unlock(&mmlist_lock);
                                mmput(prev_mm);
                                prev_mm = mm;
@@ -746,6 +855,13 @@ again:
                        mmput(start_mm);
                        start_mm = new_start_mm;
                }
+               if (shmem) {
+                       /* page has already been unlocked and released */
+                       if (shmem > 0)
+                               continue;
+                       retval = shmem;
+                       break;
+               }
                if (retval) {
                        unlock_page(page);
                        page_cache_release(page);
@@ -784,12 +900,6 @@ again:
                 * read from disk into another page.  Splitting into two
                 * pages would be incorrect if swap supported "shared
                 * private" pages, but they are handled by tmpfs files.
-                *
-                * Note shmem_unuse already deleted a swappage from
-                * the swap cache, unless the move to filepage failed:
-                * in which case it left swappage in cache, lowered its
-                * swap count to pass quickly through the loops above,
-                * and now we must reincrement count to try again later.
                 */
                if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
                        struct writeback_control wbc = {
@@ -800,17 +910,13 @@ again:
                        lock_page(page);
                        wait_on_page_writeback(page);
                }
-               if (PageSwapCache(page)) {
-                       if (shmem)
-                               swap_duplicate(entry);
-                       else
-                               delete_from_swap_cache(page);
-               }
+               if (PageSwapCache(page))
+                       delete_from_swap_cache(page);
 
                /*
                 * So we could skip searching mms once swap count went
                 * to 1, we did not mark any present ptes as dirty: must
-                * mark page dirty so shrink_list will preserve it.
+                * mark page dirty so shrink_page_list will preserve it.
                 */
                SetPageDirty(page);
                unlock_page(page);
@@ -876,6 +982,23 @@ sector_t map_swap_page(struct swap_info_struct *sis, pgoff_t offset)
        }
 }
 
+#ifdef CONFIG_HIBERNATION
+/*
+ * Get the (PAGE_SIZE) block corresponding to given offset on the swapdev
+ * corresponding to given index in swap_info (swap type).
+ */
+sector_t swapdev_block(int swap_type, pgoff_t offset)
+{
+       struct swap_info_struct *sis;
+
+       if (swap_type >= nr_swapfiles)
+               return 0;
+
+       sis = swap_info + swap_type;
+       return (sis->flags & SWP_WRITEOK) ? map_swap_page(sis, offset) : 0;
+}
+#endif /* CONFIG_HIBERNATION */
+
 /*
  * Free all of a swapdev's extent information
  */
@@ -1219,10 +1342,13 @@ static void *swap_start(struct seq_file *swap, loff_t *pos)
 
        mutex_lock(&swapon_mutex);
 
+       if (!l)
+               return SEQ_START_TOKEN;
+
        for (i = 0; i < nr_swapfiles; i++, ptr++) {
                if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
                        continue;
-               if (!l--)
+               if (!--l)
                        return ptr;
        }
 
@@ -1231,10 +1357,17 @@ static void *swap_start(struct seq_file *swap, loff_t *pos)
 
 static void *swap_next(struct seq_file *swap, void *v, loff_t *pos)
 {
-       struct swap_info_struct *ptr = v;
+       struct swap_info_struct *ptr;
        struct swap_info_struct *endptr = swap_info + nr_swapfiles;
 
-       for (++ptr; ptr < endptr; ptr++) {
+       if (v == SEQ_START_TOKEN)
+               ptr = swap_info;
+       else {
+               ptr = v;
+               ptr++;
+       }
+
+       for (; ptr < endptr; ptr++) {
                if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
                        continue;
                ++*pos;
@@ -1255,14 +1388,16 @@ static int swap_show(struct seq_file *swap, void *v)
        struct file *file;
        int len;
 
-       if (v == swap_info)
-               seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
+       if (ptr == SEQ_START_TOKEN) {
+               seq_puts(swap,"Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
+               return 0;
+       }
 
        file = ptr->swap_file;
-       len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+       len = seq_path(swap, &file->f_path, " \t\n\\");
        seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",
                       len < 40 ? 40 - len : 1, " ",
-                      S_ISBLK(file->f_dentry->d_inode->i_mode) ?
+                      S_ISBLK(file->f_path.dentry->d_inode->i_mode) ?
                                "partition" : "file\t",
                       ptr->pages << (PAGE_SHIFT - 10),
                       ptr->inuse_pages << (PAGE_SHIFT - 10),
@@ -1270,7 +1405,7 @@ static int swap_show(struct seq_file *swap, void *v)
        return 0;
 }
 
-static struct seq_operations swaps_op = {
+static const struct seq_operations swaps_op = {
        .start =        swap_start,
        .next =         swap_next,
        .stop =         swap_stop,
@@ -1282,7 +1417,7 @@ static int swaps_open(struct inode *inode, struct file *file)
        return seq_open(file, &swaps_op);
 }
 
-static struct file_operations proc_swaps_operations = {
+static const struct file_operations proc_swaps_operations = {
        .open           = swaps_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -1337,19 +1472,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                if (!(p->flags & SWP_USED))
                        break;
        error = -EPERM;
-       /*
-        * Test if adding another swap device is possible. There are
-        * two limiting factors: 1) the number of bits for the swap
-        * type swp_entry_t definition and 2) the number of bits for
-        * the swap type in the swap ptes as defined by the different
-        * architectures. To honor both limitations a swap entry
-        * with swap offset 0 and swap type ~0UL is created, encoded
-        * to a swap pte, decoded to a swp_entry_t again and finally
-        * the swap type part is extracted. This will mask all bits
-        * from the initial ~0UL that can't be encoded in either the
-        * swp_entry_t or the architecture definition of a swap pte.
-        */
-       if (type > swp_type(pte_to_swp_entry(swp_entry_to_pte(swp_entry(~0UL,0))))) {
+       if (type >= MAX_SWAPFILES) {
                spin_unlock(&swap_lock);
                goto out;
        }
@@ -1434,15 +1557,11 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                error = -EINVAL;
                goto bad_swap;
        }
-       page = read_cache_page(mapping, 0,
-                       (filler_t *)mapping->a_ops->readpage, swap_file);
+       page = read_mapping_page(mapping, 0, swap_file);
        if (IS_ERR(page)) {
                error = PTR_ERR(page);
                goto bad_swap;
        }
-       wait_on_page_locked(page);
-       if (!PageUptodate(page))
-               goto bad_swap;
        kmap(page);
        swap_header = page_address(page);
 
@@ -1498,6 +1617,11 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                error = -EINVAL;
                if (!maxpages)
                        goto bad_swap;
+               if (swapfilesize && maxpages > swapfilesize) {
+                       printk(KERN_WARNING
+                              "Swap area shorter than signature indicates\n");
+                       goto bad_swap;
+               }
                if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode))
                        goto bad_swap;
                if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
@@ -1525,12 +1649,6 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                        goto bad_swap;
        }
 
-       if (swapfilesize && maxpages > swapfilesize) {
-               printk(KERN_WARNING
-                      "Swap area shorter than signature indicates\n");
-               error = -EINVAL;
-               goto bad_swap;
-       }
        if (nr_good_pages) {
                p->swap_map[0] = SWAP_MAP_BAD;
                p->max = maxpages;
@@ -1639,6 +1757,9 @@ int swap_duplicate(swp_entry_t entry)
        unsigned long offset, type;
        int result = 0;
 
+       if (is_migration_entry(entry))
+               return 1;
+
        type = swp_type(entry);
        if (type >= nr_swapfiles)
                goto bad_file;
@@ -1678,30 +1799,48 @@ get_swap_info_struct(unsigned type)
  */
 int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
 {
-       int ret = 0, i = 1 << page_cluster;
-       unsigned long toff;
-       struct swap_info_struct *swapdev = swp_type(entry) + swap_info;
+       struct swap_info_struct *si;
+       int our_page_cluster = page_cluster;
+       pgoff_t target, toff;
+       pgoff_t base, end;
+       int nr_pages = 0;
 
-       if (!page_cluster)      /* no readahead */
+       if (!our_page_cluster)  /* no readahead */
                return 0;
-       toff = (swp_offset(entry) >> page_cluster) << page_cluster;
-       if (!toff)              /* first page is swap header */
-               toff++, i--;
-       *offset = toff;
+
+       si = &swap_info[swp_type(entry)];
+       target = swp_offset(entry);
+       base = (target >> our_page_cluster) << our_page_cluster;
+       end = base + (1 << our_page_cluster);
+       if (!base)              /* first page is swap header */
+               base++;
 
        spin_lock(&swap_lock);
-       do {
-               /* Don't read-ahead past the end of the swap area */
-               if (toff >= swapdev->max)
+       if (end > si->max)      /* don't go beyond end of map */
+               end = si->max;
+
+       /* Count contiguous allocated slots above our target */
+       for (toff = target; ++toff < end; nr_pages++) {
+               /* Don't read in free or bad pages */
+               if (!si->swap_map[toff])
                        break;
+               if (si->swap_map[toff] == SWAP_MAP_BAD)
+                       break;
+       }
+       /* Count contiguous allocated slots below our target */
+       for (toff = target; --toff >= base; nr_pages++) {
                /* Don't read in free or bad pages */
-               if (!swapdev->swap_map[toff])
+               if (!si->swap_map[toff])
                        break;
-               if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
+               if (si->swap_map[toff] == SWAP_MAP_BAD)
                        break;
-               toff++;
-               ret++;
-       } while (--i);
+       }
        spin_unlock(&swap_lock);
-       return ret;
+
+       /*
+        * Indicate starting offset, and return number of pages to get:
+        * if only 1, say 0, since there's then no readahead to be done.
+        */
+       *offset = ++toff;
+       return nr_pages? ++nr_pages: 0;
 }