diff options
Diffstat (limited to 'mm/swapfile.c')
| -rw-r--r-- | mm/swapfile.c | 65 |
1 files changed, 33 insertions, 32 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index bd1bb5920306..1e330f2998fa 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
| @@ -33,17 +33,18 @@ | |||
| 33 | #include <asm/tlbflush.h> | 33 | #include <asm/tlbflush.h> |
| 34 | #include <linux/swapops.h> | 34 | #include <linux/swapops.h> |
| 35 | 35 | ||
| 36 | DEFINE_SPINLOCK(swap_lock); | 36 | static DEFINE_SPINLOCK(swap_lock); |
| 37 | unsigned int nr_swapfiles; | 37 | static unsigned int nr_swapfiles; |
| 38 | long total_swap_pages; | 38 | long total_swap_pages; |
| 39 | static int swap_overflow; | 39 | static int swap_overflow; |
| 40 | static int least_priority; | ||
| 40 | 41 | ||
| 41 | static const char Bad_file[] = "Bad swap file entry "; | 42 | static const char Bad_file[] = "Bad swap file entry "; |
| 42 | static const char Unused_file[] = "Unused swap file entry "; | 43 | static const char Unused_file[] = "Unused swap file entry "; |
| 43 | static const char Bad_offset[] = "Bad swap offset entry "; | 44 | static const char Bad_offset[] = "Bad swap offset entry "; |
| 44 | static const char Unused_offset[] = "Unused swap offset entry "; | 45 | static const char Unused_offset[] = "Unused swap offset entry "; |
| 45 | 46 | ||
| 46 | struct swap_list_t swap_list = {-1, -1}; | 47 | static struct swap_list_t swap_list = {-1, -1}; |
| 47 | 48 | ||
| 48 | static struct swap_info_struct swap_info[MAX_SWAPFILES]; | 49 | static struct swap_info_struct swap_info[MAX_SWAPFILES]; |
| 49 | 50 | ||
| @@ -368,13 +369,13 @@ int remove_exclusive_swap_page(struct page *page) | |||
| 368 | retval = 0; | 369 | retval = 0; |
| 369 | if (p->swap_map[swp_offset(entry)] == 1) { | 370 | if (p->swap_map[swp_offset(entry)] == 1) { |
| 370 | /* Recheck the page count with the swapcache lock held.. */ | 371 | /* Recheck the page count with the swapcache lock held.. */ |
| 371 | write_lock_irq(&swapper_space.tree_lock); | 372 | spin_lock_irq(&swapper_space.tree_lock); |
| 372 | if ((page_count(page) == 2) && !PageWriteback(page)) { | 373 | if ((page_count(page) == 2) && !PageWriteback(page)) { |
| 373 | __delete_from_swap_cache(page); | 374 | __delete_from_swap_cache(page); |
| 374 | SetPageDirty(page); | 375 | SetPageDirty(page); |
| 375 | retval = 1; | 376 | retval = 1; |
| 376 | } | 377 | } |
| 377 | write_unlock_irq(&swapper_space.tree_lock); | 378 | spin_unlock_irq(&swapper_space.tree_lock); |
| 378 | } | 379 | } |
| 379 | spin_unlock(&swap_lock); | 380 | spin_unlock(&swap_lock); |
| 380 | 381 | ||
| @@ -402,7 +403,7 @@ void free_swap_and_cache(swp_entry_t entry) | |||
| 402 | if (p) { | 403 | if (p) { |
| 403 | if (swap_entry_free(p, swp_offset(entry)) == 1) { | 404 | if (swap_entry_free(p, swp_offset(entry)) == 1) { |
| 404 | page = find_get_page(&swapper_space, entry.val); | 405 | page = find_get_page(&swapper_space, entry.val); |
| 405 | if (page && unlikely(TestSetPageLocked(page))) { | 406 | if (page && unlikely(!trylock_page(page))) { |
| 406 | page_cache_release(page); | 407 | page_cache_release(page); |
| 407 | page = NULL; | 408 | page = NULL; |
| 408 | } | 409 | } |
| @@ -655,8 +656,8 @@ static int unuse_mm(struct mm_struct *mm, | |||
| 655 | 656 | ||
| 656 | if (!down_read_trylock(&mm->mmap_sem)) { | 657 | if (!down_read_trylock(&mm->mmap_sem)) { |
| 657 | /* | 658 | /* |
| 658 | * Activate page so shrink_cache is unlikely to unmap its | 659 | * Activate page so shrink_inactive_list is unlikely to unmap |
| 659 | * ptes while lock is dropped, so swapoff can make progress. | 660 | * its ptes while lock is dropped, so swapoff can make progress. |
| 660 | */ | 661 | */ |
| 661 | activate_page(page); | 662 | activate_page(page); |
| 662 | unlock_page(page); | 663 | unlock_page(page); |
| @@ -1260,6 +1261,11 @@ asmlinkage long sys_swapoff(const char __user * specialfile) | |||
| 1260 | /* just pick something that's safe... */ | 1261 | /* just pick something that's safe... */ |
| 1261 | swap_list.next = swap_list.head; | 1262 | swap_list.next = swap_list.head; |
| 1262 | } | 1263 | } |
| 1264 | if (p->prio < 0) { | ||
| 1265 | for (i = p->next; i >= 0; i = swap_info[i].next) | ||
| 1266 | swap_info[i].prio = p->prio--; | ||
| 1267 | least_priority++; | ||
| 1268 | } | ||
| 1263 | nr_swap_pages -= p->pages; | 1269 | nr_swap_pages -= p->pages; |
| 1264 | total_swap_pages -= p->pages; | 1270 | total_swap_pages -= p->pages; |
| 1265 | p->flags &= ~SWP_WRITEOK; | 1271 | p->flags &= ~SWP_WRITEOK; |
| @@ -1272,9 +1278,14 @@ asmlinkage long sys_swapoff(const char __user * specialfile) | |||
| 1272 | if (err) { | 1278 | if (err) { |
| 1273 | /* re-insert swap space back into swap_list */ | 1279 | /* re-insert swap space back into swap_list */ |
| 1274 | spin_lock(&swap_lock); | 1280 | spin_lock(&swap_lock); |
| 1275 | for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next) | 1281 | if (p->prio < 0) |
| 1282 | p->prio = --least_priority; | ||
| 1283 | prev = -1; | ||
| 1284 | for (i = swap_list.head; i >= 0; i = swap_info[i].next) { | ||
| 1276 | if (p->prio >= swap_info[i].prio) | 1285 | if (p->prio >= swap_info[i].prio) |
| 1277 | break; | 1286 | break; |
| 1287 | prev = i; | ||
| 1288 | } | ||
| 1278 | p->next = i; | 1289 | p->next = i; |
| 1279 | if (prev < 0) | 1290 | if (prev < 0) |
| 1280 | swap_list.head = swap_list.next = p - swap_info; | 1291 | swap_list.head = swap_list.next = p - swap_info; |
| @@ -1447,7 +1458,6 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
| 1447 | unsigned int type; | 1458 | unsigned int type; |
| 1448 | int i, prev; | 1459 | int i, prev; |
| 1449 | int error; | 1460 | int error; |
| 1450 | static int least_priority; | ||
| 1451 | union swap_header *swap_header = NULL; | 1461 | union swap_header *swap_header = NULL; |
| 1452 | int swap_header_version; | 1462 | int swap_header_version; |
| 1453 | unsigned int nr_good_pages = 0; | 1463 | unsigned int nr_good_pages = 0; |
| @@ -1455,7 +1465,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
| 1455 | sector_t span; | 1465 | sector_t span; |
| 1456 | unsigned long maxpages = 1; | 1466 | unsigned long maxpages = 1; |
| 1457 | int swapfilesize; | 1467 | int swapfilesize; |
| 1458 | unsigned short *swap_map; | 1468 | unsigned short *swap_map = NULL; |
| 1459 | struct page *page = NULL; | 1469 | struct page *page = NULL; |
| 1460 | struct inode *inode = NULL; | 1470 | struct inode *inode = NULL; |
| 1461 | int did_down = 0; | 1471 | int did_down = 0; |
| @@ -1474,22 +1484,10 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
| 1474 | } | 1484 | } |
| 1475 | if (type >= nr_swapfiles) | 1485 | if (type >= nr_swapfiles) |
| 1476 | nr_swapfiles = type+1; | 1486 | nr_swapfiles = type+1; |
| 1487 | memset(p, 0, sizeof(*p)); | ||
| 1477 | INIT_LIST_HEAD(&p->extent_list); | 1488 | INIT_LIST_HEAD(&p->extent_list); |
| 1478 | p->flags = SWP_USED; | 1489 | p->flags = SWP_USED; |
| 1479 | p->swap_file = NULL; | ||
| 1480 | p->old_block_size = 0; | ||
| 1481 | p->swap_map = NULL; | ||
| 1482 | p->lowest_bit = 0; | ||
| 1483 | p->highest_bit = 0; | ||
| 1484 | p->cluster_nr = 0; | ||
| 1485 | p->inuse_pages = 0; | ||
| 1486 | p->next = -1; | 1490 | p->next = -1; |
| 1487 | if (swap_flags & SWAP_FLAG_PREFER) { | ||
| 1488 | p->prio = | ||
| 1489 | (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT; | ||
| 1490 | } else { | ||
| 1491 | p->prio = --least_priority; | ||
| 1492 | } | ||
| 1493 | spin_unlock(&swap_lock); | 1491 | spin_unlock(&swap_lock); |
| 1494 | name = getname(specialfile); | 1492 | name = getname(specialfile); |
| 1495 | error = PTR_ERR(name); | 1493 | error = PTR_ERR(name); |
| @@ -1632,19 +1630,20 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
| 1632 | goto bad_swap; | 1630 | goto bad_swap; |
| 1633 | 1631 | ||
| 1634 | /* OK, set up the swap map and apply the bad block list */ | 1632 | /* OK, set up the swap map and apply the bad block list */ |
| 1635 | if (!(p->swap_map = vmalloc(maxpages * sizeof(short)))) { | 1633 | swap_map = vmalloc(maxpages * sizeof(short)); |
| 1634 | if (!swap_map) { | ||
| 1636 | error = -ENOMEM; | 1635 | error = -ENOMEM; |
| 1637 | goto bad_swap; | 1636 | goto bad_swap; |
| 1638 | } | 1637 | } |
| 1639 | 1638 | ||
| 1640 | error = 0; | 1639 | error = 0; |
| 1641 | memset(p->swap_map, 0, maxpages * sizeof(short)); | 1640 | memset(swap_map, 0, maxpages * sizeof(short)); |
| 1642 | for (i = 0; i < swap_header->info.nr_badpages; i++) { | 1641 | for (i = 0; i < swap_header->info.nr_badpages; i++) { |
| 1643 | int page_nr = swap_header->info.badpages[i]; | 1642 | int page_nr = swap_header->info.badpages[i]; |
| 1644 | if (page_nr <= 0 || page_nr >= swap_header->info.last_page) | 1643 | if (page_nr <= 0 || page_nr >= swap_header->info.last_page) |
| 1645 | error = -EINVAL; | 1644 | error = -EINVAL; |
| 1646 | else | 1645 | else |
| 1647 | p->swap_map[page_nr] = SWAP_MAP_BAD; | 1646 | swap_map[page_nr] = SWAP_MAP_BAD; |
| 1648 | } | 1647 | } |
| 1649 | nr_good_pages = swap_header->info.last_page - | 1648 | nr_good_pages = swap_header->info.last_page - |
| 1650 | swap_header->info.nr_badpages - | 1649 | swap_header->info.nr_badpages - |
| @@ -1654,7 +1653,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
| 1654 | } | 1653 | } |
| 1655 | 1654 | ||
| 1656 | if (nr_good_pages) { | 1655 | if (nr_good_pages) { |
| 1657 | p->swap_map[0] = SWAP_MAP_BAD; | 1656 | swap_map[0] = SWAP_MAP_BAD; |
| 1658 | p->max = maxpages; | 1657 | p->max = maxpages; |
| 1659 | p->pages = nr_good_pages; | 1658 | p->pages = nr_good_pages; |
| 1660 | nr_extents = setup_swap_extents(p, &span); | 1659 | nr_extents = setup_swap_extents(p, &span); |
| @@ -1672,6 +1671,12 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
| 1672 | 1671 | ||
| 1673 | mutex_lock(&swapon_mutex); | 1672 | mutex_lock(&swapon_mutex); |
| 1674 | spin_lock(&swap_lock); | 1673 | spin_lock(&swap_lock); |
| 1674 | if (swap_flags & SWAP_FLAG_PREFER) | ||
| 1675 | p->prio = | ||
| 1676 | (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; | ||
| 1677 | else | ||
| 1678 | p->prio = --least_priority; | ||
| 1679 | p->swap_map = swap_map; | ||
| 1675 | p->flags = SWP_ACTIVE; | 1680 | p->flags = SWP_ACTIVE; |
| 1676 | nr_swap_pages += nr_good_pages; | 1681 | nr_swap_pages += nr_good_pages; |
| 1677 | total_swap_pages += nr_good_pages; | 1682 | total_swap_pages += nr_good_pages; |
| @@ -1707,12 +1712,8 @@ bad_swap: | |||
| 1707 | destroy_swap_extents(p); | 1712 | destroy_swap_extents(p); |
| 1708 | bad_swap_2: | 1713 | bad_swap_2: |
| 1709 | spin_lock(&swap_lock); | 1714 | spin_lock(&swap_lock); |
| 1710 | swap_map = p->swap_map; | ||
| 1711 | p->swap_file = NULL; | 1715 | p->swap_file = NULL; |
| 1712 | p->swap_map = NULL; | ||
| 1713 | p->flags = 0; | 1716 | p->flags = 0; |
| 1714 | if (!(swap_flags & SWAP_FLAG_PREFER)) | ||
| 1715 | ++least_priority; | ||
| 1716 | spin_unlock(&swap_lock); | 1717 | spin_unlock(&swap_lock); |
| 1717 | vfree(swap_map); | 1718 | vfree(swap_map); |
| 1718 | if (swap_file) | 1719 | if (swap_file) |
