/[lkdp]/lkdp/mm/swapping.tex
ViewVC logotype

Diff of /lkdp/mm/swapping.tex

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.11 by rcastro, Wed Jul 10 19:48:03 2002 UTC revision 1.12 by rcastro, Fri Jul 12 21:02:11 2002 UTC
# Line 1671  return 1; Line 1671  return 1;
1671  \end{verbatim}  \end{verbatim}
1672    
1673  \section{Mechanism}  \section{Mechanism}
1674    
1675    \subsection{Function scan\_swap\_map()}
1676         \textit{File: }\url{mm/swapfile.c}\\
1677         \textit{Prototype: }
1678    \begin{verbatim}
1679    static inline int scan_swap_map(struct swap_info_struct *si)
1680    \end{verbatim}
1681    
1682    \begin{verbatim}
1683    unsigned long offset;
1684    /*
1685     * We try to cluster swap pages by allocating them
1686     * sequentially in swap.  Once we've allocated
1687     * SWAPFILE_CLUSTER pages this way, however, we resort to
1688     * first-free allocation, starting a new cluster.  This
1689     * prevents us from scattering swap pages all over the entire
1690     * swap partition, so that we reduce overall disk seek times
1691     * between swap pages.  -- sct */
1692    if (si->cluster_nr) {
1693            while (si->cluster_next <= si->highest_bit) {
1694                    offset = si->cluster_next++;
1695                    if (si->swap_map[offset])
1696                            continue;
1697                    si->cluster_nr--;
1698                    goto got_page;
1699            }
1700    }
1701    si->cluster_nr = SWAPFILE_CLUSTER;
1702    
1703    /* try to find an empty (even not aligned) cluster. */
1704    offset = si->lowest_bit;
1705    check_next_cluster:
1706    if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)
1707    {
1708            int nr;
1709            for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)
1710                    if (si->swap_map[nr])
1711                    {
1712                            offset = nr+1;
1713                            goto check_next_cluster;
1714                    }
1715            /* We found a completly empty cluster, so start
1716             * using it.
1717             */
1718            goto got_page;
1719    }
1720    /* No luck, so now go finegrined as usual. -Andrea */
1721    for (offset = si->lowest_bit; offset <= si->highest_bit ;
1722         offset++) {
1723            if (si->swap_map[offset])
1724                    continue;
1725            si->lowest_bit = offset+1;
1726    got_page:
1727            if (offset == si->lowest_bit)
1728                    si->lowest_bit++;
1729            if (offset == si->highest_bit)
1730                    si->highest_bit--;
1731            if (si->lowest_bit > si->highest_bit) {
1732                    si->lowest_bit = si->max;
1733                    si->highest_bit = 0;
1734            }
1735            si->swap_map[offset] = 1;
1736            nr_swap_pages--;
1737            si->cluster_next = offset+1;
1738            return offset;
1739    }
1740    si->lowest_bit = si->max;
1741    si->highest_bit = 0;
1742    return 0;
1743    \end{verbatim}
1744    
1745    \subsection{Function get\_swap\_page()}
1746         \textit{File: }\url{mm/swapfile.c}\\
1747         \textit{Prototype: }
1748    \begin{verbatim}
1749    swp_entry_t get_swap_page(void)
1750    \end{verbatim}
1751    
1752    \begin{verbatim}
1753    struct swap_info_struct * p;
1754    unsigned long offset;
1755    swp_entry_t entry;
1756    int type, wrapped = 0;
1757    
1758    entry.val = 0;  /* Out of memory */
1759    swap_list_lock();
1760    type = swap_list.next;
1761    if (type < 0)
1762            goto out;
1763    if (nr_swap_pages <= 0)
1764            goto out;
1765    
1766    while (1) {
1767            p = &swap_info[type];
1768            if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
1769                    swap_device_lock(p);
1770                    offset = scan_swap_map(p);
1771                    swap_device_unlock(p);
1772                    if (offset) {
1773                            entry = SWP_ENTRY(type,offset);
1774                            type = swap_info[type].next;
1775                            if (type < 0 ||
1776                                    p->prio != swap_info[type].prio) {
1777                                            swap_list.next = swap_list.head;
1778                            } else {
1779                                    swap_list.next = type;
1780                            }
1781                            goto out;
1782                    }
1783            }
1784            type = p->next;
1785            if (!wrapped) {
1786                    if (type < 0 || p->prio != swap_info[type].prio) {
1787                            type = swap_list.head;
1788                            wrapped = 1;
1789                    }
1790            } else
1791                    if (type < 0)
1792                            goto out;       /* out of swap space */
1793    }
1794    out:
1795    swap_list_unlock();
1796    return entry;
1797    \end{verbatim}
1798    
1799    \subsection{Function swap\_info\_get()}
1800         \textit{File: }\url{mm/swapfile.c}\\
1801         \textit{Prototype: }
1802    \begin{verbatim}
1803    static struct swap_info_struct * swap_info_get(swp_entry_t entry)
1804    \end{verbatim}
1805    
1806    \begin{verbatim}
1807    struct swap_info_struct * p;
1808    unsigned long offset, type;
1809    
1810    if (!entry.val)
1811            goto out;
1812    type = SWP_TYPE(entry);
1813    if (type >= nr_swapfiles)
1814            goto bad_nofile;
1815    p = & swap_info[type];
1816    if (!(p->flags & SWP_USED))
1817            goto bad_device;
1818    offset = SWP_OFFSET(entry);
1819    if (offset >= p->max)
1820            goto bad_offset;
1821    if (!p->swap_map[offset])
1822            goto bad_free;
1823    swap_list_lock();
1824    if (p->prio > swap_info[swap_list.next].prio)
1825            swap_list.next = type;
1826    swap_device_lock(p);
1827    return p;
1828    
1829    bad_free:
1830    printk(KERN_ERR "swap_free: %s%08lx\n", Unused_offset,
1831           entry.val);
1832    goto out;
1833    
1834    bad_offset:
1835    printk(KERN_ERR "swap_free: %s%08lx\n", Bad_offset,
1836           entry.val);
1837    goto out;
1838    
1839    bad_device:
1840    printk(KERN_ERR "swap_free: %s%08lx\n", Unused_file,
1841           entry.val);
1842    goto out;
1843    
1844    bad_nofile:
1845    printk(KERN_ERR "swap_free: %s%08lx\n", Bad_file,
1846           entry.val);
1847    out:
1848    return NULL;
1849    \end{verbatim}
1850    
1851    \subsection{Function swap\_info\_put()}
1852         \textit{File: }\url{mm/swapfile.c}\\
1853         \textit{Prototype: }
1854    \begin{verbatim}
1855    static void swap_info_put(struct swap_info_struct * p)
1856    \end{verbatim}
1857    
1858    \begin{verbatim}
1859    swap_device_unlock(p);
1860    swap_list_unlock();
1861    \end{verbatim}
1862    
1863    \subsection{Function swap\_entry\_free()}
1864         \textit{File: }\url{mm/swapfile.c}\\
1865         \textit{Prototype: }
1866    \begin{verbatim}
1867    static int swap_entry_free(struct swap_info_struct *p,
1868                               unsigned long offset)
1869    \end{verbatim}
1870    
1871    \begin{verbatim}
1872    int count = p->swap_map[offset];
1873    
1874    if (count < SWAP_MAP_MAX) {
1875             count--;
1876             p->swap_map[offset] = count;
1877             if (!count) {
1878                    if (offset < p->lowest_bit)
1879                            p->lowest_bit = offset;
1880                    if (offset > p->highest_bit)
1881                            p->highest_bit = offset;
1882                    nr_swap_pages++;
1883             }
1884    }
1885    return count;
1886    \end{verbatim}
1887    
1888    \subsection{Function swap\_free()}
1889         \textit{File: }\url{mm/swapfile.c}\\
1890         \textit{Prototype: }
1891    \begin{verbatim}
1892    void swap_free(swp_entry_t entry)
1893    \end{verbatim}
1894    
1895    \begin{verbatim}
1896    struct swap_info_struct * p;
1897    
1898    p = swap_info_get(entry);
1899    if (p) {
1900            swap_entry_free(p, SWP_OFFSET(entry));
1901            swap_info_put(p);
1902    }
1903    \end{verbatim}
1904    
1905    \subsection{Function exclusive\_swap\_page()}
1906         \textit{File: }\url{mm/swapfile.c}\\
1907         \textit{Prototype: }
1908    \begin{verbatim}
1909    static int exclusive_swap_page(struct page *page)
1910    \end{verbatim}
1911    
1912    \begin{verbatim}
1913    int retval = 0;
1914    struct swap_info_struct * p;
1915    swp_entry_t entry;
1916    
1917    entry.val = page->index;
1918    p = swap_info_get(entry);
1919    if (p) {
1920            /* Is the only swap cache user the cache itself? */
1921            if (p->swap_map[SWP_OFFSET(entry)] == 1) {
1922                    /* Recheck the page count with the
1923                       pagecache lock held.. */
1924                    spin_lock(&pagecache_lock);
1925                    if (page_count(page) - !!page->buffers == 2)
1926                            retval = 1;
1927                    spin_unlock(&pagecache_lock);
1928            }
1929            swap_info_put(p);
1930    }
1931    return retval;
1932    \end{verbatim}
1933    
1934    \subsection{Function can\_share\_swap\_page()}
1935         \textit{File: }\url{mm/swapfile.c}\\
1936         \textit{Prototype: }
1937    \begin{verbatim}
1938    int can_share_swap_page(struct page *page)
1939    \end{verbatim}
1940    
1941    \begin{verbatim}
1942    int retval = 0;
1943    
1944    if (!PageLocked(page))
1945            BUG();
1946    switch (page_count(page)) {
1947    case 3:
1948            if (!page->buffers)
1949                    break;
1950            /* Fallthrough */
1951    case 2:
1952            if (!PageSwapCache(page))
1953                    break;
1954            retval = exclusive_swap_page(page);
1955            break;
1956    case 1:
1957            if (PageReserved(page))
1958                    break;
1959            retval = 1;
1960    }
1961    return retval;
1962    \end{verbatim}
1963    
1964    \subsection{Function remove\_exclusive\_swap\_page()}
1965         \textit{File: }\url{mm/swapfile.c}\\
1966         \textit{Prototype: }
1967    \begin{verbatim}
1968    int remove_exclusive_swap_page(struct page *page)
1969    \end{verbatim}
1970    
1971    \begin{verbatim}
1972    int retval;
1973    struct swap_info_struct * p;
1974    swp_entry_t entry;
1975    
1976    if (!PageLocked(page))
1977            BUG();
1978    if (!PageSwapCache(page))
1979            return 0;
1980    /* 2: us + cache */
1981    if (page_count(page) - !!page->buffers != 2)
1982            return 0;
1983    
1984    entry.val = page->index;
1985    p = swap_info_get(entry);
1986    if (!p)
1987            return 0;
1988    
1989    /* Is the only swap cache user the cache itself? */
1990    retval = 0;
1991    if (p->swap_map[SWP_OFFSET(entry)] == 1) {
1992            /* Recheck the page count with the pagecache
1993               lock held.. */
1994            spin_lock(&pagecache_lock);
1995            if (page_count(page) - !!page->buffers == 2) {
1996                    __delete_from_swap_cache(page);
1997                    SetPageDirty(page);
1998                    retval = 1;
1999            }
2000            spin_unlock(&pagecache_lock);
2001    }
2002    swap_info_put(p);
2003    
2004    if (retval) {
2005            block_flushpage(page, 0);
2006            swap_free(entry);
2007            page_cache_release(page);
2008    }
2009    
2010    return retval;
2011    \end{verbatim}
2012    
2013    \subsection{Function free\_swap\_and\_cache()}
2014         \textit{File: }\url{mm/swapfile.c}\\
2015         \textit{Prototype: }
2016    \begin{verbatim}
2017    void free_swap_and_cache(swp_entry_t entry)
2018    \end{verbatim}
2019    
2020    \begin{verbatim}
2021    struct swap_info_struct * p;
2022    struct page *page = NULL;
2023    
2024    p = swap_info_get(entry);
2025    if (p) {
2026            if (swap_entry_free(p, SWP_OFFSET(entry)) == 1)
2027                    page = find_trylock_page(&swapper_space,
2028                           entry.val);
2029            swap_info_put(p);
2030    }
2031    if (page) {
2032            page_cache_get(page);
2033            /* Only cache user (+us), or swap space full? Free it! */
2034            if (page_count(page) - !!page->buffers == 2 ||
2035                vm_swap_full()) {
2036                    delete_from_swap_cache(page);
2037                    SetPageDirty(page);
2038            }
2039            UnlockPage(page);
2040            page_cache_release(page);
2041    }
2042    \end{verbatim}
2043    
2044    \subsection{Function unuse\_pte()}
2045         \textit{File: }\url{mm/swapfile.c}\\
2046         \textit{Prototype: }
2047    \begin{verbatim}
2048    static inline void unuse_pte(struct vm_area_struct * vma,
2049            unsigned long address, pte_t *dir,
2050            swp_entry_t entry, struct page* page)
2051    \end{verbatim}
2052    
2053    \begin{verbatim}
2054    pte_t pte = *dir;
2055    
2056    if (likely(pte_to_swp_entry(pte).val != entry.val))
2057            return;
2058    if (unlikely(pte_none(pte) || pte_present(pte)))
2059            return;
2060    get_page(page);
2061    set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
2062    swap_free(entry);
2063    ++vma->vm_mm->rss;
2064    \end{verbatim}
2065    
2066    \subsection{Function unuse\_pmd()}
2067         \textit{File: }\url{mm/swapfile.c}\\
2068         \textit{Prototype: }
2069    \begin{verbatim}
2070    static inline void unuse_pmd(struct vm_area_struct * vma,
2071            pmd_t *dir, unsigned long address,
2072            unsigned long size, unsigned long offset,
2073            swp_entry_t entry, struct page* page)
2074    \end{verbatim}
2075    
2076    \begin{verbatim}
2077    pte_t * pte;
2078    unsigned long end;
2079    
2080    if (pmd_none(*dir))
2081            return;
2082    if (pmd_bad(*dir)) {
2083            pmd_ERROR(*dir);
2084            pmd_clear(dir);
2085            return;
2086    }
2087    pte = pte_offset(dir, address);
2088    offset += address & PMD_MASK;
2089    address &= ~PMD_MASK;
2090    end = address + size;
2091    if (end > PMD_SIZE)
2092            end = PMD_SIZE;
2093    do {
2094            unuse_pte(vma, offset+address-vma->vm_start, pte, entry,
2095                      page);
2096            address += PAGE_SIZE;
2097            pte++;
2098    } while (address && (address < end));
2099    \end{verbatim}
2100    
2101    \subsection{Function unuse\_pgd()}
2102         \textit{File: }\url{mm/swapfile.c}\\
2103         \textit{Prototype: }
2104    \begin{verbatim}
2105    static inline void unuse_pgd(struct vm_area_struct * vma,
2106            pgd_t *dir, unsigned long address, unsigned long size,
2107            swp_entry_t entry, struct page* page)
2108    \end{verbatim}
2109    
2110    \begin{verbatim}
2111    pmd_t * pmd;
2112    unsigned long offset, end;
2113    
2114    if (pgd_none(*dir))
2115            return;
2116    if (pgd_bad(*dir)) {
2117            pgd_ERROR(*dir);
2118            pgd_clear(dir);
2119            return;
2120    }
2121    pmd = pmd_offset(dir, address);
2122    offset = address & PGDIR_MASK;
2123    address &= ~PGDIR_MASK;
2124    end = address + size;
2125    if (end > PGDIR_SIZE)
2126            end = PGDIR_SIZE;
2127    if (address >= end)
2128            BUG();
2129    do {
2130            unuse_pmd(vma, pmd, address, end - address, offset,
2131                      entry, page);
2132            address = (address + PMD_SIZE) & PMD_MASK;
2133            pmd++;
2134    } while (address && (address < end));
2135    \end{verbatim}
2136    
2137    \subsection{Function unuse\_vma()}
2138         \textit{File: }\url{mm/swapfile.c}\\
2139         \textit{Prototype: }
2140    \begin{verbatim}
2141    static void unuse_vma(struct vm_area_struct * vma,
2142                          pgd_t *pgdir, swp_entry_t entry,
2143                          struct page* page)
2144    \end{verbatim}
2145    
2146    \begin{verbatim}
2147    unsigned long start = vma->vm_start, end = vma->vm_end;
2148    
2149    if (start >= end)
2150            BUG();
2151    do {
2152            unuse_pgd(vma, pgdir, start, end - start, entry, page);
2153            start = (start + PGDIR_SIZE) & PGDIR_MASK;
2154            pgdir++;
2155    } while (start && (start < end));
2156    \end{verbatim}
2157    
2158    \subsection{Function unuse\_process()}
2159         \textit{File: }\url{mm/swapfile.c}\\
2160         \textit{Prototype: }
2161    \begin{verbatim}
2162    static void unuse_process(struct mm_struct * mm,
2163                            swp_entry_t entry, struct page* page)
2164    \end{verbatim}
2165    
2166    \begin{verbatim}
2167    struct vm_area_struct* vma;
2168    
2169    /*
2170     * Go through process' page directory.
2171     */
2172    spin_lock(&mm->page_table_lock);
2173    for (vma = mm->mmap; vma; vma = vma->vm_next) {
2174            pgd_t * pgd = pgd_offset(mm, vma->vm_start);
2175            unuse_vma(vma, pgd, entry, page);
2176    }
2177    spin_unlock(&mm->page_table_lock);
2178    return;
2179    \end{verbatim}
2180    
2181    \subsection{Function find\_next\_to\_unuse()}
2182         \textit{File: }\url{mm/swapfile.c}\\
2183         \textit{Prototype: }
2184    \begin{verbatim}
2185    static int find_next_to_unuse(struct swap_info_struct *si,
2186                                  int prev)
2187    \end{verbatim}
2188    
2189    \begin{verbatim}
2190    int max = si->max;
2191    int i = prev;
2192    int count;
2193    
2194    /*
2195     * No need for swap_device_lock(si) here: we're just looking
2196     * for whether an entry is in use, not modifying it; false
2197     * hits are okay, and sys_swapoff() has already prevented new
2198     * allocations from this area (while holding swap_list_lock()).
2199     */
2200    for (;;) {
2201            if (++i >= max) {
2202                    if (!prev) {
2203                            i = 0;
2204                            break;
2205                    }
2206                    /*
2207                     * No entries in use at top of swap_map,
2208                     * loop back to start and recheck there.
2209                     */
2210                    max = prev + 1;
2211                    prev = 0;
2212                    i = 1;
2213            }
2214            count = si->swap_map[i];
2215            if (count && count != SWAP_MAP_BAD)
2216                    break;
2217    }
2218    return i;
2219    \end{verbatim}
2220    
2221    \subsection{Function try\_to\_unuse()}
2222         \textit{File: }\url{mm/swapfile.c}\\
2223         \textit{Prototype: }
2224    \begin{verbatim}
2225    static int try_to_unuse(unsigned int type)
2226    \end{verbatim}
2227    
2228    \begin{verbatim}
2229    struct swap_info_struct * si = &swap_info[type];
2230    struct mm_struct *start_mm;
2231    unsigned short *swap_map;
2232    unsigned short swcount;
2233    struct page *page;
2234    swp_entry_t entry;
2235    int i = 0;
2236    int retval = 0;
2237    int reset_overflow = 0;
2238    
2239    /*
2240     * When searching mms for an entry, a good strategy is to
2241     * start at the first mm we freed the previous entry from
2242     * (though actually we don't notice whether we or coincidence
2243     * freed the entry).  Initialize this start_mm with a hold.
2244     *
2245     * A simpler strategy would be to start at the last mm we
2246     * freed the previous entry from; but that would take less
2247     * advantage of mmlist ordering (now preserved by swap_out()),
2248     * which clusters forked address spaces together, most recent
2249     * child immediately after parent.  If we race with dup_mmap(),
2250     * we very much want to resolve parent before child, otherwise
2251     * we may miss some entries: using last mm would invert that.
2252     */
2253    start_mm = &init_mm;
2254    atomic_inc(&init_mm.mm_users);
2255    
2256    /*
2257     * Keep on scanning until all entries have gone.  Usually,
2258     * one pass through swap_map is enough, but not necessarily:
2259     * mmput() removes mm from mmlist before exit_mmap() and its
2260     * zap_page_range().  That's not too bad, those entries are
2261     * on their way out, and handled faster there than here.
2262     * do_munmap() behaves similarly, taking the range out of mm's
2263     * vma list before zap_page_range().  But unfortunately, when
2264     * unmapping a part of a vma, it takes the whole out first,
2265     * then reinserts what's left after (might even reschedule if
2266     * open() method called) - so swap entries may be invisible
2267     * to swapoff for a while, then reappear - but that is rare.
2268     */
2269    while ((i = find_next_to_unuse(si, i))) {
2270            /*
2271             * Get a page for the entry, using the existing swap
2272             * cache page if there is one.  Otherwise, get a clean
2273             * page and read the swap into it.
2274             */
2275            swap_map = &si->swap_map[i];
2276            entry = SWP_ENTRY(type, i);
2277            page = read_swap_cache_async(entry);
2278            if (!page) {
2279                    /*
2280                     * Either swap_duplicate() failed because entry
2281                     * has been freed independently, and will not be
2282                     * reused since sys_swapoff() already disabled
2283                     * allocation from here, or alloc_page() failed.
2284                     */
2285                    if (!*swap_map)
2286                            continue;
2287                    retval = -ENOMEM;
2288                    break;
2289            }
2290    
2291            /*
2292             * Don't hold on to start_mm if it looks like exiting.
2293             */
2294            if (atomic_read(&start_mm->mm_users) == 1) {
2295                    mmput(start_mm);
2296                    start_mm = &init_mm;
2297                    atomic_inc(&init_mm.mm_users);
2298            }
2299    
2300            /*
2301             * Wait for and lock page.  When do_swap_page races with
2302             * try_to_unuse, do_swap_page can handle the fault much
2303             * faster than try_to_unuse can locate the entry.  This
2304             * apparently redundant "wait_on_page" lets try_to_unuse
2305             * defer to do_swap_page in such a case - in some tests,
2306             * do_swap_page and try_to_unuse repeatedly compete.
2307             */
2308            wait_on_page(page);
2309            lock_page(page);
2310    
2311            /*
2312             * Remove all references to entry, without blocking.
2313             * Whenever we reach init_mm, there's no address space
2314             * to search, but use it as a reminder to search shmem.
2315             */
2316            swcount = *swap_map;
2317            if (swcount > 1) {
2318                    flush_page_to_ram(page);
2319                    if (start_mm == &init_mm)
2320                            shmem_unuse(entry, page);
2321                    else
2322                            unuse_process(start_mm, entry, page);
2323            }
2324            if (*swap_map > 1) {
2325                    int set_start_mm = (*swap_map >= swcount);
2326                    struct list_head *p = &start_mm->mmlist;
2327                    struct mm_struct *new_start_mm = start_mm;
2328                    struct mm_struct *mm;
2329    
2330                    spin_lock(&mmlist_lock);
2331                    while (*swap_map > 1 &&
2332                                    (p = p->next) != &start_mm->mmlist) {
2333                            mm = list_entry(p, struct mm_struct, mmlist);
2334                            swcount = *swap_map;
2335                            if (mm == &init_mm) {
2336                                    set_start_mm = 1;
2337                                    shmem_unuse(entry, page);
2338                            } else
2339                                    unuse_process(mm, entry, page);
2340                            if (set_start_mm && *swap_map < swcount) {
2341                                    new_start_mm = mm;
2342                                    set_start_mm = 0;
2343                            }
2344                    }
2345                    atomic_inc(&new_start_mm->mm_users);
2346                    spin_unlock(&mmlist_lock);
2347                    mmput(start_mm);
2348                    start_mm = new_start_mm;
2349            }
2350    
2351            /*
2352             * How could swap count reach 0x7fff when the maximum
2353             * pid is 0x7fff, and there's no way to repeat a swap
2354             * page within an mm (except in shmem, where it's the
2355             * shared object which takes the reference count)?
2356             * We believe SWAP_MAP_MAX cannot occur in Linux 2.4.
2357             *
2358             * If that's wrong, then we should worry more about
2359             * exit_mmap() and do_munmap() cases described above:
2360             * we might be resetting SWAP_MAP_MAX too early here.
2361             * We know "Undead"s can happen, they're okay, so don't
2362             * report them; but do report if we reset SWAP_MAP_MAX.
2363             */
2364            if (*swap_map == SWAP_MAP_MAX) {
2365                    swap_list_lock();
2366                    swap_device_lock(si);
2367                    nr_swap_pages++;
2368                    *swap_map = 1;
2369                    swap_device_unlock(si);
2370                    swap_list_unlock();
2371                    reset_overflow = 1;
2372            }
2373    
2374            /*
2375             * If a reference remains (rare), we would like to leave
2376             * the page in the swap cache; but try_to_swap_out could
2377             * then re-duplicate the entry once we drop page lock,
2378             * so we might loop indefinitely; also, that page could
2379             * not be swapped out to other storage meanwhile.  So:
2380             * delete from cache even if there's another reference,
2381             * after ensuring that the data has been saved to disk -
2382             * since if the reference remains (rarer), it will be
2383             * read from disk into another page.  Splitting into two
2384             * pages would be incorrect if swap supported "shared
2385             * private" pages, but they are handled by tmpfs files.
2386             * Note shmem_unuse already deleted its from swap cache.
2387             */
2388            if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
2389                    rw_swap_page(WRITE, page);
2390                    lock_page(page);
2391            }
2392            if (PageSwapCache(page))
2393                    delete_from_swap_cache(page);
2394    
2395            /*
2396             * So we could skip searching mms once swap count went
2397             * to 1, we did not mark any present ptes as dirty: must
2398             * mark page dirty so try_to_swap_out will preserve it.
2399             */
2400            SetPageDirty(page);
2401            UnlockPage(page);
2402            page_cache_release(page);
2403    
2404            /*
2405             * Make sure that we aren't completely killing
2406             * interactive performance.  Interruptible check on
2407             * signal_pending() would be nice, but changes the spec?
2408             */
2409            if (current->need_resched)
2410                    schedule();
2411    }
2412    
2413    mmput(start_mm);
2414    if (reset_overflow) {
2415            printk(KERN_WARNING
2416                   "swapoff: cleared swap entry overflow\n");
2417            swap_overflow = 0;
2418    }
2419    return retval;
2420    \end{verbatim}
2421    
2422    \subsection{Function sys\_swapoff()}
2423         \textit{File: }\url{mm/swapfile.c}\\
2424         \textit{Prototype: }
2425    \begin{verbatim}
2426    asmlinkage long sys_swapoff(const char * specialfile)
2427    \end{verbatim}
2428    
2429    \begin{verbatim}
2430    struct swap_info_struct * p = NULL;
2431    unsigned short *swap_map;
2432    struct nameidata nd;
2433    int i, type, prev;
2434    int err;
2435    
2436    if (!capable(CAP_SYS_ADMIN))
2437            return -EPERM;
2438    
2439    err = user_path_walk(specialfile, &nd);
2440    if (err)
2441            goto out;
2442    
2443    lock_kernel();
2444    prev = -1;
2445    swap_list_lock();
2446    for (type = swap_list.head; type >= 0;
2447         type = swap_info[type].next) {
2448            p = swap_info + type;
2449            if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
2450                    if (p->swap_file == nd.dentry)
2451                            break;
2452            }
2453            prev = type;
2454    }
2455    err = -EINVAL;
2456    if (type < 0) {
2457            swap_list_unlock();
2458            goto out_dput;
2459    }
2460    
2461    if (prev < 0) {
2462            swap_list.head = p->next;
2463    } else {
2464            swap_info[prev].next = p->next;
2465    }
2466    if (type == swap_list.next) {
2467            /* just pick something that's safe... */
2468            swap_list.next = swap_list.head;
2469    }
2470    nr_swap_pages -= p->pages;
2471    total_swap_pages -= p->pages;
2472    p->flags = SWP_USED;
2473    swap_list_unlock();
2474    unlock_kernel();
2475    err = try_to_unuse(type);
2476    lock_kernel();
2477    if (err) {
2478            /* re-insert swap space back into swap_list */
2479            swap_list_lock();
2480            for (prev = -1, i = swap_list.head; i >= 0;
2481                 prev = i, i = swap_info[i].next)
2482                    if (p->prio >= swap_info[i].prio)
2483                            break;
2484            p->next = i;
2485            if (prev < 0)
2486                    swap_list.head = swap_list.next = p - swap_info;
2487            else
2488                    swap_info[prev].next = p - swap_info;
2489            nr_swap_pages += p->pages;
2490            total_swap_pages += p->pages;
2491            p->flags = SWP_WRITEOK;
2492            swap_list_unlock();
2493            goto out_dput;
2494    }
2495    if (p->swap_device)
2496            blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
2497    path_release(&nd);
2498    
2499    swap_list_lock();
2500    swap_device_lock(p);
2501    nd.mnt = p->swap_vfsmnt;
2502    nd.dentry = p->swap_file;
2503    p->swap_vfsmnt = NULL;
2504    p->swap_file = NULL;
2505    p->swap_device = 0;
2506    p->max = 0;
2507    swap_map = p->swap_map;
2508    p->swap_map = NULL;
2509    p->flags = 0;
2510    swap_device_unlock(p);
2511    swap_list_unlock();
2512    vfree(swap_map);
2513    err = 0;
2514    
2515    out_dput:
2516    unlock_kernel();
2517    path_release(&nd);
2518    out:
2519    return err;
2520    \end{verbatim}
2521    
2522    \subsection{Function get\_swaparea\_info()}
2523         \textit{File: }\url{mm/swapfile.c}\\
2524         \textit{Prototype: }
2525    \begin{verbatim}
2526    int get_swaparea_info(char *buf)
2527    \end{verbatim}
2528    
2529    \begin{verbatim}
2530    char * page = (char *) __get_free_page(GFP_KERNEL);
2531    struct swap_info_struct *ptr = swap_info;
2532    int i, j, len = 0, usedswap;
2533    
2534    if (!page)
2535            return -ENOMEM;
2536    
2537    len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
2538    for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
2539            if ((ptr->flags & SWP_USED) && ptr->swap_map) {
2540                    char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
2541                                            page, PAGE_SIZE);
2542    
2543                    len += sprintf(buf + len, "%-31s ", path);
2544    
2545                    if (!ptr->swap_device)
2546                            len += sprintf(buf + len, "file\t\t");
2547                    else
2548                            len += sprintf(buf + len, "partition\t");
2549    
2550                    usedswap = 0;
2551                    for (j = 0; j < ptr->max; ++j)
2552                            switch (ptr->swap_map[j]) {
2553                                    case SWAP_MAP_BAD:
2554                                    case 0:
2555                                            continue;
2556                                    default:
2557                                            usedswap++;
2558                            }
2559                    len += sprintf(buf + len, "%d\t%d\t%d\n", ptr->pages << (PAGE_SHIFT - 10),
2560                            usedswap << (PAGE_SHIFT - 10), ptr->prio);
2561            }
2562    }
2563    free_page((unsigned long) page);
2564    return len;
2565    \end{verbatim}
2566    
2567    \subsection{Function is\_swap\_partition()}
2568         \textit{File: }\url{mm/swapfile.c}\\
2569         \textit{Prototype: }
2570    \begin{verbatim}
2571    int is_swap_partition(kdev_t dev)
2572    \end{verbatim}
2573    
2574    \begin{verbatim}
2575    struct swap_info_struct *ptr = swap_info;
2576    int i;
2577    
2578    for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
2579            if (ptr->flags & SWP_USED)
2580                    if (ptr->swap_device == dev)
2581                            return 1;
2582    }
2583    return 0;
2584    \end{verbatim}
2585    
2586    \subsection{Function sys\_swapon()}
2587         \textit{File: }\url{mm/swapfile.c}\\
2588         \textit{Prototype: }
2589    \begin{verbatim}
2590    asmlinkage long sys_swapon(const char * specialfile,
2591                               int swap_flags)
2592    \end{verbatim}
2593    
2594    \begin{verbatim}
2595    struct swap_info_struct * p;
2596    struct nameidata nd;
2597    struct inode * swap_inode;
2598    unsigned int type;
2599    int i, j, prev;
2600    int error;
2601    static int least_priority = 0;
2602    union swap_header *swap_header = 0;
2603    int swap_header_version;
2604    int nr_good_pages = 0;
2605    unsigned long maxpages = 1;
2606    int swapfilesize;
2607    struct block_device *bdev = NULL;
2608    unsigned short *swap_map;
2609    
2610    if (!capable(CAP_SYS_ADMIN))
2611            return -EPERM;
2612    lock_kernel();
2613    swap_list_lock();
2614    p = swap_info;
2615    for (type = 0 ; type < nr_swapfiles ; type++,p++)
2616            if (!(p->flags & SWP_USED))
2617                    break;
2618    error = -EPERM;
2619    if (type >= MAX_SWAPFILES) {
2620            swap_list_unlock();
2621            goto out;
2622    }
2623    if (type >= nr_swapfiles)
2624            nr_swapfiles = type+1;
2625    p->flags = SWP_USED;
2626    p->swap_file = NULL;
2627    p->swap_vfsmnt = NULL;
2628    p->swap_device = 0;
2629    p->swap_map = NULL;
2630    p->lowest_bit = 0;
2631    p->highest_bit = 0;
2632    p->cluster_nr = 0;
2633    p->sdev_lock = SPIN_LOCK_UNLOCKED;
2634    p->next = -1;
2635    if (swap_flags & SWAP_FLAG_PREFER) {
2636            p->prio =
2637              (swap_flags & SWAP_FLAG_PRIO_MASK)>>
2638              SWAP_FLAG_PRIO_SHIFT;
2639    } else {
2640            p->prio = --least_priority;
2641    }
2642    swap_list_unlock();
2643    error = user_path_walk(specialfile, &nd);
2644    if (error)
2645            goto bad_swap_2;
2646    
2647    p->swap_file = nd.dentry;
2648    p->swap_vfsmnt = nd.mnt;
2649    swap_inode = nd.dentry->d_inode;
2650    error = -EINVAL;
2651    
2652    if (S_ISBLK(swap_inode->i_mode)) {
2653            kdev_t dev = swap_inode->i_rdev;
2654            struct block_device_operations *bdops;
2655            devfs_handle_t de;
2656    
2657            p->swap_device = dev;
2658            set_blocksize(dev, PAGE_SIZE);
2659            
2660            bd_acquire(swap_inode);
2661            bdev = swap_inode->i_bdev;
2662            de = devfs_get_handle_from_inode(swap_inode);
2663            /*  Increments module use count  */
2664            bdops = devfs_get_ops(de);  
2665            if (bdops) bdev->bd_op = bdops;
2666    
2667            error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0,
2668                               BDEV_SWAP);
2669            /*Decrement module use count now we're safe*/
2670            devfs_put_ops(de);
2671            if (error)
2672                    goto bad_swap_2;
2673            set_blocksize(dev, PAGE_SIZE);
2674            error = -ENODEV;
2675            if (!dev || (blk_size[MAJOR(dev)] &&
2676                 !blk_size[MAJOR(dev)][MINOR(dev)]))
2677                    goto bad_swap;
2678            swapfilesize = 0;
2679            if (blk_size[MAJOR(dev)])
2680                    swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
2681                            >> (PAGE_SHIFT - 10);
2682    } else if (S_ISREG(swap_inode->i_mode))
2683            swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
2684    else
2685            goto bad_swap;
2686    
2687    error = -EBUSY;
2688    for (i = 0 ; i < nr_swapfiles ; i++) {
2689            struct swap_info_struct *q = &swap_info[i];
2690            if (i == type || !q->swap_file)
2691                    continue;
2692            if (swap_inode->i_mapping ==
2693                q->swap_file->d_inode->i_mapping)
2694                    goto bad_swap;
2695    }
2696    
2697    swap_header = (void *) __get_free_page(GFP_USER);
2698    if (!swap_header) {
2699            printk("Unable to start swapping: out of memory :-)\n");
2700            error = -ENOMEM;
2701            goto bad_swap;
2702    }
2703    
2704    lock_page(virt_to_page(swap_header));
2705    rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header);
2706    
2707    if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
2708            swap_header_version = 1;
2709    else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))
2710            swap_header_version = 2;
2711    else {
2712            printk("Unable to find swap-space signature\n");
2713            error = -EINVAL;
2714            goto bad_swap;
2715    }
2716    
2717    switch (swap_header_version) {
2718    case 1:
2719            memset(((char *) swap_header)+PAGE_SIZE-10,0,10);
2720            j = 0;
2721            p->lowest_bit = 0;
2722            p->highest_bit = 0;
2723            for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
2724                    if (test_bit(i,(char *) swap_header)) {
2725                            if (!p->lowest_bit)
2726                                    p->lowest_bit = i;
2727                            p->highest_bit = i;
2728                            maxpages = i+1;
2729                            j++;
2730                    }
2731            }
2732            nr_good_pages = j;
2733            p->swap_map = vmalloc(maxpages * sizeof(short));
2734            if (!p->swap_map) {
2735                    error = -ENOMEM;                
2736                    goto bad_swap;
2737            }
2738            for (i = 1 ; i < maxpages ; i++) {
2739                    if (test_bit(i,(char *) swap_header))
2740                            p->swap_map[i] = 0;
2741                    else
2742                            p->swap_map[i] = SWAP_MAP_BAD;
2743            }
2744            break;
2745    
2746    case 2:
2747            /* Check the swap header's sub-version and the size of
2748               the swap file and bad block lists */
2749            if (swap_header->info.version != 1) {
2750                    printk(KERN_WARNING
2751                           "Unable to handle swap header
2752                            version %d\n",
2753                           swap_header->info.version);
2754                    error = -EINVAL;
2755                    goto bad_swap;
2756            }
2757    
2758            p->lowest_bit  = 1;
2759            maxpages = SWP_OFFSET(SWP_ENTRY(0,~0UL)) - 1;
2760            if (maxpages > swap_header->info.last_page)
2761                    maxpages = swap_header->info.last_page;
2762            p->highest_bit = maxpages - 1;
2763    
2764            error = -EINVAL;
2765            if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
2766                    goto bad_swap;
2767            
2768            /* OK, set up the swap map and apply the bad block list */
2769            if (!(p->swap_map = vmalloc(maxpages * sizeof(short)))) {
2770                    error = -ENOMEM;
2771                    goto bad_swap;
2772            }
2773    
2774            error = 0;
2775            memset(p->swap_map, 0, maxpages * sizeof(short));
2776            for (i=0; i<swap_header->info.nr_badpages; i++) {
2777                    int page = swap_header->info.badpages[i];
2778                    if (page <= 0 ||
2779                        page >= swap_header->info.last_page)
2780                            error = -EINVAL;
2781                    else
2782                            p->swap_map[page] = SWAP_MAP_BAD;
2783            }
2784            nr_good_pages = swap_header->info.last_page -
2785                            swap_header->info.nr_badpages -
2786                            1 /* header page */;
2787            if (error)
2788                    goto bad_swap;
2789    }
2790    
2791    if (swapfilesize && maxpages > swapfilesize) {
2792            printk(KERN_WARNING
2793                   "Swap area shorter than signature indicates\n");
2794            error = -EINVAL;
2795            goto bad_swap;
2796    }
2797    if (!nr_good_pages) {
2798            printk(KERN_WARNING "Empty swap-file\n");
2799            error = -EINVAL;
2800            goto bad_swap;
2801    }
2802    p->swap_map[0] = SWAP_MAP_BAD;
2803    swap_list_lock();
2804    swap_device_lock(p);
2805    p->max = maxpages;
2806    p->flags = SWP_WRITEOK;
2807    p->pages = nr_good_pages;
2808    nr_swap_pages += nr_good_pages;
2809    total_swap_pages += nr_good_pages;
2810    printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
2811           nr_good_pages\<\<(PAGE_SHIFT-10), p->prio);
2812    
2813    /* insert swap space into swap_list: */
2814    prev = -1;
2815    for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
2816            if (p->prio >= swap_info[i].prio) {
2817                    break;
2818            }
2819            prev = i;
2820    }
2821    p->next = i;
2822    if (prev < 0) {
2823            swap_list.head = swap_list.next = p - swap_info;
2824    } else {
2825            swap_info[prev].next = p - swap_info;
2826    }
2827    swap_device_unlock(p);
2828    swap_list_unlock();
2829    error = 0;
2830    goto out;
2831    bad_swap:
2832    if (bdev)
2833            blkdev_put(bdev, BDEV_SWAP);
2834    bad_swap_2:
2835    swap_list_lock();
2836    swap_map = p->swap_map;
2837    nd.mnt = p->swap_vfsmnt;
2838    nd.dentry = p->swap_file;
2839    p->swap_device = 0;
2840    p->swap_file = NULL;
2841    p->swap_vfsmnt = NULL;
2842    p->swap_map = NULL;
2843    p->flags = 0;
2844    if (!(swap_flags & SWAP_FLAG_PREFER))
2845            ++least_priority;
2846    swap_list_unlock();
2847    if (swap_map)
2848            vfree(swap_map);
2849    path_release(&nd);
2850    out:
2851    if (swap_header)
2852            free_page((long) swap_header);
2853    unlock_kernel();
2854    return error;
2855    \end{verbatim}
2856    
2857    \subsection{Function si\_swapinfo()}
2858         \textit{File: }\url{mm/swapfile.c}\\
2859         \textit{Prototype: }
2860    \begin{verbatim}
2861    void si_swapinfo(struct sysinfo *val)
2862    \end{verbatim}
2863    
2864    \begin{verbatim}
2865    unsigned int i;
2866    unsigned long nr_to_be_unused = 0;
2867    
2868    swap_list_lock();
2869    for (i = 0; i < nr_swapfiles; i++) {
2870            unsigned int j;
2871            if (swap_info[i].flags != SWP_USED)
2872                    continue;
2873            for (j = 0; j < swap_info[i].max; ++j) {
2874                    switch (swap_info[i].swap_map[j]) {
2875                            case 0:
2876                            case SWAP_MAP_BAD:
2877                                    continue;
2878                            default:
2879                                    nr_to_be_unused++;
2880                    }
2881            }
2882    }
2883    val->freeswap = nr_swap_pages + nr_to_be_unused;
2884    val->totalswap = total_swap_pages + nr_to_be_unused;
2885    swap_list_unlock();
2886    \end{verbatim}
2887    
2888    \subsection{Function swap\_duplicate()}
2889         \textit{File: }\url{mm/swapfile.c}\\
2890         \textit{Prototype: }
2891    \begin{verbatim}
2892    int swap_duplicate(swp_entry_t entry)
2893    \end{verbatim}
2894    
2895    \begin{verbatim}
2896    struct swap_info_struct * p;
2897    unsigned long offset, type;
2898    int result = 0;
2899    
2900    type = SWP_TYPE(entry);
2901    if (type >= nr_swapfiles)
2902            goto bad_file;
2903    p = type + swap_info;
2904    offset = SWP_OFFSET(entry);
2905    
2906    swap_device_lock(p);
2907    if (offset < p->max && p->swap_map[offset]) {
2908            if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {
2909                    p->swap_map[offset]++;
2910                    result = 1;
2911            } else if (p->swap_map[offset] <= SWAP_MAP_MAX) {
2912                    if (swap_overflow++ < 5)
2913                            printk(KERN_WARNING "swap_dup: swap
2914                                   entry overflow\n");
2915                    p->swap_map[offset] = SWAP_MAP_MAX;
2916                    result = 1;
2917            }
2918    }
2919    swap_device_unlock(p);
2920    out:
2921    return result;
2922    
2923    bad_file:
2924    printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
2925    goto out;
2926    \end{verbatim}
2927    
2928    \subsection{Function swap\_count()}
2929         \textit{File: }\url{mm/swapfile.c}\\
2930         \textit{Prototype: }
2931    \begin{verbatim}
2932    int swap_count(struct page *page)
2933    \end{verbatim}
2934    
2935    \begin{verbatim}
2936    struct swap_info_struct * p;
2937    unsigned long offset, type;
2938    swp_entry_t entry;
2939    int retval = 0;
2940    
2941    entry.val = page->index;
2942    if (!entry.val)
2943            goto bad_entry;
2944    type = SWP_TYPE(entry);
2945    if (type >= nr_swapfiles)
2946            goto bad_file;
2947    p = type + swap_info;
2948    offset = SWP_OFFSET(entry);
2949    if (offset >= p->max)
2950            goto bad_offset;
2951    if (!p->swap_map[offset])
2952            goto bad_unused;
2953    retval = p->swap_map[offset];
2954    out:
2955    return retval;
2956    
2957    bad_entry:
2958    printk(KERN_ERR "swap_count: null entry!\n");
2959    goto out;
2960    bad_file:
2961    printk(KERN_ERR "swap_count: %s%08lx\n", Bad_file, entry.val);
2962    goto out;
2963    bad_offset:
2964    printk(KERN_ERR "swap_count: %s%08lx\n", Bad_offset, entry.val);
2965    goto out;
2966    bad_unused:
2967    printk(KERN_ERR "swap_count: %s%08lx\n", Unused_offset, entry.val);
2968    goto out;
2969    \end{verbatim}
2970    
2971    \subsection{Function get\_swaphandle\_info()}
2972         \textit{File: }\url{mm/swapfile.c}\\
2973         \textit{Prototype: }
2974    \begin{verbatim}
2975    void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
2976                            kdev_t *dev, struct inode **swapf)
2977    \end{verbatim}
2978    
2979    \begin{verbatim}
2980    unsigned long type;
2981    struct swap_info_struct *p;
2982    
2983    type = SWP_TYPE(entry);
2984    if (type >= nr_swapfiles) {
2985            printk(KERN_ERR "rw_swap_page: %s%08lx\n",
2986                   Bad_file, entry.val);
2987            return;
2988    }
2989    
2990    p = &swap_info[type];
2991    *offset = SWP_OFFSET(entry);
2992    if (*offset >= p->max && *offset != 0) {
2993            printk(KERN_ERR "rw_swap_page: %s%08lx\n",
2994                   Bad_offset, entry.val);
2995            return;
2996    }
2997    if (p->swap_map && !p->swap_map[*offset]) {
2998            printk(KERN_ERR "rw_swap_page: %s%08lx\n",
2999                   Unused_offset, entry.val);
3000            return;
3001    }
3002    if (!(p->flags & SWP_USED)) {
3003            printk(KERN_ERR "rw_swap_page: %s%08lx\n",
3004                   Unused_file, entry.val);
3005            return;
3006    }
3007    
3008    if (p->swap_device) {
3009            *dev = p->swap_device;
3010    } else if (p->swap_file) {
3011            *swapf = p->swap_file->d_inode;
3012    } else {
3013            printk(KERN_ERR "rw_swap_page: no swap file or device\n");
3014    }
3015    return;
3016    \end{verbatim}
3017    
3018    \subsection{Function valid\_swaphandles()}
3019         \textit{File: }\url{mm/swapfile.c}\\
3020         \textit{Prototype: }
3021    \begin{verbatim}
3022    int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
3023    \end{verbatim}
3024    
3025    \begin{verbatim}
3026    int ret = 0, i = 1 \<\< page_cluster;
3027    unsigned long toff;
3028    struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
3029    
3030    if (!page_cluster)      /* no readahead */
3031            return 0;
3032    toff = (SWP_OFFSET(entry) >> page_cluster) \<\< page_cluster;
3033    if (!toff)              /* first page is swap header */
3034            toff++, i--;
3035    *offset = toff;
3036    
3037    swap_device_lock(swapdev);
3038    do {
3039            /* Don't read-ahead past the end of the swap area */
3040            if (toff >= swapdev->max)
3041                    break;
3042            /* Don't read in free or bad pages */
3043            if (!swapdev->swap_map[toff])
3044                    break;
3045            if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
3046                    break;
3047            toff++;
3048            ret++;
3049    } while (--i);
3050    swap_device_unlock(swapdev);
3051    return ret;
3052    \end{verbatim}
3053    
3054  swapfile.c  swapfile.c
3055  swap\_state.c  swap\_state.c

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26