X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=inline;f=mm%2Fswapfile.c;h=0cefbba421e6b374a53edd579aba10860d1ee84e;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=c25ffae06315a050ca8a015878effe8f3ddca8d8;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/mm/swapfile.c b/mm/swapfile.c index c25ffae06..0cefbba42 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -5,6 +5,7 @@ * Swap reorganised 29.12.95, Stephen Tweedie */ +#include #include #include #include @@ -396,9 +397,6 @@ 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) { @@ -620,6 +618,15 @@ static int unuse_mm(struct mm_struct *mm, return 0; } +#ifdef CONFIG_MIGRATION +int remove_vma_swap(struct vm_area_struct *vma, struct page *page) +{ + swp_entry_t entry = { .val = page_private(page) }; + + return unuse_vma(vma, entry, page); +} +#endif + /* * Scan swap_map from current position to next entry still in use. * Recycle to start on reaching the end, returning 0 when empty. @@ -712,6 +719,7 @@ 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); if (!page) { /* @@ -746,6 +754,12 @@ static int try_to_unuse(unsigned int type) 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); /* @@ -774,8 +788,10 @@ static int try_to_unuse(unsigned int type) while (*swap_map > 1 && !retval && (p = p->next) != &start_mm->mmlist) { mm = list_entry(p, struct mm_struct, mmlist); - if (!atomic_inc_not_zero(&mm->mm_users)) + if (atomic_inc_return(&mm->mm_users) == 1) { + atomic_dec(&mm->mm_users); continue; + } spin_unlock(&mmlist_lock); mmput(prev_mm); prev_mm = mm; @@ -1394,7 +1410,19 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) if (!(p->flags & SWP_USED)) break; error = -EPERM; - if (type >= MAX_SWAPFILES) { + /* + * 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))))) { spin_unlock(&swap_lock); goto out; } @@ -1479,7 +1507,8 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) error = -EINVAL; goto bad_swap; } - page = read_mapping_page(mapping, 0, swap_file); + page = read_cache_page(mapping, 0, + (filler_t *)mapping->a_ops->readpage, swap_file); if (IS_ERR(page)) { error = PTR_ERR(page); goto bad_swap; @@ -1685,9 +1714,6 @@ 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;