diff options
author | Hugh Dickins <hugh.dickins@tiscali.co.uk> | 2009-12-14 20:58:42 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-15 11:53:15 -0500 |
commit | 9625a5f289f7c3c100b59c317e2bcc3c7e2e51fb (patch) | |
tree | 88fecfbed0eaf627e8e08a9e196d1d2849737f0a /mm/swapfile.c | |
parent | efa90a981bbc891efad96db2a75b5487e00852ca (diff) |
swap_info: include first_swap_extent
Make better use of the space by folding first swap_extent into its
swap_info_struct, instead of just the list_head: swap partitions need
only that one, and for others it's used as a circular list anyway.
[jirislaby@gmail.com: fix crash on double swapon]
Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Rik van Riel <riel@redhat.com>
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/swapfile.c')
-rw-r--r-- | mm/swapfile.c | 70 |
1 files changed, 36 insertions, 34 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index dc88a7e4257e..16de84b56644 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -145,23 +145,28 @@ void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page) | |||
145 | static int discard_swap(struct swap_info_struct *si) | 145 | static int discard_swap(struct swap_info_struct *si) |
146 | { | 146 | { |
147 | struct swap_extent *se; | 147 | struct swap_extent *se; |
148 | sector_t start_block; | ||
149 | sector_t nr_blocks; | ||
148 | int err = 0; | 150 | int err = 0; |
149 | 151 | ||
150 | list_for_each_entry(se, &si->extent_list, list) { | 152 | /* Do not discard the swap header page! */ |
151 | sector_t start_block = se->start_block << (PAGE_SHIFT - 9); | 153 | se = &si->first_swap_extent; |
152 | sector_t nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9); | 154 | start_block = (se->start_block + 1) << (PAGE_SHIFT - 9); |
155 | nr_blocks = ((sector_t)se->nr_pages - 1) << (PAGE_SHIFT - 9); | ||
156 | if (nr_blocks) { | ||
157 | err = blkdev_issue_discard(si->bdev, start_block, | ||
158 | nr_blocks, GFP_KERNEL, DISCARD_FL_BARRIER); | ||
159 | if (err) | ||
160 | return err; | ||
161 | cond_resched(); | ||
162 | } | ||
153 | 163 | ||
154 | if (se->start_page == 0) { | 164 | list_for_each_entry(se, &si->first_swap_extent.list, list) { |
155 | /* Do not discard the swap header page! */ | 165 | start_block = se->start_block << (PAGE_SHIFT - 9); |
156 | start_block += 1 << (PAGE_SHIFT - 9); | 166 | nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9); |
157 | nr_blocks -= 1 << (PAGE_SHIFT - 9); | ||
158 | if (!nr_blocks) | ||
159 | continue; | ||
160 | } | ||
161 | 167 | ||
162 | err = blkdev_issue_discard(si->bdev, start_block, | 168 | err = blkdev_issue_discard(si->bdev, start_block, |
163 | nr_blocks, GFP_KERNEL, | 169 | nr_blocks, GFP_KERNEL, DISCARD_FL_BARRIER); |
164 | DISCARD_FL_BARRIER); | ||
165 | if (err) | 170 | if (err) |
166 | break; | 171 | break; |
167 | 172 | ||
@@ -200,14 +205,11 @@ static void discard_swap_cluster(struct swap_info_struct *si, | |||
200 | start_block <<= PAGE_SHIFT - 9; | 205 | start_block <<= PAGE_SHIFT - 9; |
201 | nr_blocks <<= PAGE_SHIFT - 9; | 206 | nr_blocks <<= PAGE_SHIFT - 9; |
202 | if (blkdev_issue_discard(si->bdev, start_block, | 207 | if (blkdev_issue_discard(si->bdev, start_block, |
203 | nr_blocks, GFP_NOIO, | 208 | nr_blocks, GFP_NOIO, DISCARD_FL_BARRIER)) |
204 | DISCARD_FL_BARRIER)) | ||
205 | break; | 209 | break; |
206 | } | 210 | } |
207 | 211 | ||
208 | lh = se->list.next; | 212 | lh = se->list.next; |
209 | if (lh == &si->extent_list) | ||
210 | lh = lh->next; | ||
211 | se = list_entry(lh, struct swap_extent, list); | 213 | se = list_entry(lh, struct swap_extent, list); |
212 | } | 214 | } |
213 | } | 215 | } |
@@ -761,10 +763,8 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p) | |||
761 | return type; | 763 | return type; |
762 | } | 764 | } |
763 | if (bdev == sis->bdev) { | 765 | if (bdev == sis->bdev) { |
764 | struct swap_extent *se; | 766 | struct swap_extent *se = &sis->first_swap_extent; |
765 | 767 | ||
766 | se = list_entry(sis->extent_list.next, | ||
767 | struct swap_extent, list); | ||
768 | if (se->start_block == offset) { | 768 | if (se->start_block == offset) { |
769 | if (bdev_p) | 769 | if (bdev_p) |
770 | *bdev_p = bdgrab(sis->bdev); | 770 | *bdev_p = bdgrab(sis->bdev); |
@@ -1310,8 +1310,6 @@ sector_t map_swap_page(swp_entry_t entry, struct block_device **bdev) | |||
1310 | return se->start_block + (offset - se->start_page); | 1310 | return se->start_block + (offset - se->start_page); |
1311 | } | 1311 | } |
1312 | lh = se->list.next; | 1312 | lh = se->list.next; |
1313 | if (lh == &sis->extent_list) | ||
1314 | lh = lh->next; | ||
1315 | se = list_entry(lh, struct swap_extent, list); | 1313 | se = list_entry(lh, struct swap_extent, list); |
1316 | sis->curr_swap_extent = se; | 1314 | sis->curr_swap_extent = se; |
1317 | BUG_ON(se == start_se); /* It *must* be present */ | 1315 | BUG_ON(se == start_se); /* It *must* be present */ |
@@ -1340,10 +1338,10 @@ sector_t swapdev_block(int type, pgoff_t offset) | |||
1340 | */ | 1338 | */ |
1341 | static void destroy_swap_extents(struct swap_info_struct *sis) | 1339 | static void destroy_swap_extents(struct swap_info_struct *sis) |
1342 | { | 1340 | { |
1343 | while (!list_empty(&sis->extent_list)) { | 1341 | while (!list_empty(&sis->first_swap_extent.list)) { |
1344 | struct swap_extent *se; | 1342 | struct swap_extent *se; |
1345 | 1343 | ||
1346 | se = list_entry(sis->extent_list.next, | 1344 | se = list_entry(sis->first_swap_extent.list.next, |
1347 | struct swap_extent, list); | 1345 | struct swap_extent, list); |
1348 | list_del(&se->list); | 1346 | list_del(&se->list); |
1349 | kfree(se); | 1347 | kfree(se); |
@@ -1364,8 +1362,15 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, | |||
1364 | struct swap_extent *new_se; | 1362 | struct swap_extent *new_se; |
1365 | struct list_head *lh; | 1363 | struct list_head *lh; |
1366 | 1364 | ||
1367 | lh = sis->extent_list.prev; /* The highest page extent */ | 1365 | if (start_page == 0) { |
1368 | if (lh != &sis->extent_list) { | 1366 | se = &sis->first_swap_extent; |
1367 | sis->curr_swap_extent = se; | ||
1368 | se->start_page = 0; | ||
1369 | se->nr_pages = nr_pages; | ||
1370 | se->start_block = start_block; | ||
1371 | return 1; | ||
1372 | } else { | ||
1373 | lh = sis->first_swap_extent.list.prev; /* Highest extent */ | ||
1369 | se = list_entry(lh, struct swap_extent, list); | 1374 | se = list_entry(lh, struct swap_extent, list); |
1370 | BUG_ON(se->start_page + se->nr_pages != start_page); | 1375 | BUG_ON(se->start_page + se->nr_pages != start_page); |
1371 | if (se->start_block + se->nr_pages == start_block) { | 1376 | if (se->start_block + se->nr_pages == start_block) { |
@@ -1385,7 +1390,7 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, | |||
1385 | new_se->nr_pages = nr_pages; | 1390 | new_se->nr_pages = nr_pages; |
1386 | new_se->start_block = start_block; | 1391 | new_se->start_block = start_block; |
1387 | 1392 | ||
1388 | list_add_tail(&new_se->list, &sis->extent_list); | 1393 | list_add_tail(&new_se->list, &sis->first_swap_extent.list); |
1389 | return 1; | 1394 | return 1; |
1390 | } | 1395 | } |
1391 | 1396 | ||
@@ -1437,7 +1442,7 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span) | |||
1437 | if (S_ISBLK(inode->i_mode)) { | 1442 | if (S_ISBLK(inode->i_mode)) { |
1438 | ret = add_swap_extent(sis, 0, sis->max, 0); | 1443 | ret = add_swap_extent(sis, 0, sis->max, 0); |
1439 | *span = sis->pages; | 1444 | *span = sis->pages; |
1440 | goto done; | 1445 | goto out; |
1441 | } | 1446 | } |
1442 | 1447 | ||
1443 | blkbits = inode->i_blkbits; | 1448 | blkbits = inode->i_blkbits; |
@@ -1508,15 +1513,12 @@ reprobe: | |||
1508 | sis->max = page_no; | 1513 | sis->max = page_no; |
1509 | sis->pages = page_no - 1; | 1514 | sis->pages = page_no - 1; |
1510 | sis->highest_bit = page_no - 1; | 1515 | sis->highest_bit = page_no - 1; |
1511 | done: | 1516 | out: |
1512 | sis->curr_swap_extent = list_entry(sis->extent_list.prev, | 1517 | return ret; |
1513 | struct swap_extent, list); | ||
1514 | goto out; | ||
1515 | bad_bmap: | 1518 | bad_bmap: |
1516 | printk(KERN_ERR "swapon: swapfile has holes\n"); | 1519 | printk(KERN_ERR "swapon: swapfile has holes\n"); |
1517 | ret = -EINVAL; | 1520 | ret = -EINVAL; |
1518 | out: | 1521 | goto out; |
1519 | return ret; | ||
1520 | } | 1522 | } |
1521 | 1523 | ||
1522 | SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) | 1524 | SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) |
@@ -1815,7 +1817,6 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
1815 | kfree(p); | 1817 | kfree(p); |
1816 | goto out; | 1818 | goto out; |
1817 | } | 1819 | } |
1818 | INIT_LIST_HEAD(&p->extent_list); | ||
1819 | if (type >= nr_swapfiles) { | 1820 | if (type >= nr_swapfiles) { |
1820 | p->type = type; | 1821 | p->type = type; |
1821 | swap_info[type] = p; | 1822 | swap_info[type] = p; |
@@ -1834,6 +1835,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
1834 | * would be relying on p->type to remain valid. | 1835 | * would be relying on p->type to remain valid. |
1835 | */ | 1836 | */ |
1836 | } | 1837 | } |
1838 | INIT_LIST_HEAD(&p->first_swap_extent.list); | ||
1837 | p->flags = SWP_USED; | 1839 | p->flags = SWP_USED; |
1838 | p->next = -1; | 1840 | p->next = -1; |
1839 | spin_unlock(&swap_lock); | 1841 | spin_unlock(&swap_lock); |