Commit 3df9aaf3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] rmap: swap_unplug page

From: Hugh Dickins <hugh@veritas.com>

Good example of "swapper_space considered harmful": swap_unplug_io_fn was
originally designed for calling via swapper_space.backing_dev_info; but
that way it loses track of which device is to be unplugged, so had to
unplug all swap devices.  But now sync_page tests SwapCache anyway, can
call swap_unplug_io_fn with page, which leads direct to the device.

Reverted -mc4's CONFIG_SWAP=n fix, just add another NOTHING for it.
Reverted -mc3's editorial adjustments to swap_backing_dev_info and
swapper_space initializations: they document the few fields which are
actually used now, as comment above them says (sound of slapped wrist).
parent c4d92e6b
...@@ -181,8 +181,6 @@ extern int vm_swappiness; ...@@ -181,8 +181,6 @@ extern int vm_swappiness;
extern int shmem_unuse(swp_entry_t entry, struct page *page); extern int shmem_unuse(swp_entry_t entry, struct page *page);
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
extern void swap_unplug_io_fn(struct backing_dev_info *);
#ifdef CONFIG_SWAP #ifdef CONFIG_SWAP
/* linux/mm/page_io.c */ /* linux/mm/page_io.c */
extern int swap_readpage(struct file *, struct page *); extern int swap_readpage(struct file *, struct page *);
...@@ -218,7 +216,7 @@ extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); ...@@ -218,7 +216,7 @@ extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t);
extern struct swap_info_struct *get_swap_info_struct(unsigned); extern struct swap_info_struct *get_swap_info_struct(unsigned);
extern int can_share_swap_page(struct page *); extern int can_share_swap_page(struct page *);
extern int remove_exclusive_swap_page(struct page *); extern int remove_exclusive_swap_page(struct page *);
struct backing_dev_info; extern void swap_unplug_io_fn(struct page *);
extern struct swap_list_t swap_list; extern struct swap_list_t swap_list;
extern spinlock_t swaplock; extern spinlock_t swaplock;
...@@ -252,6 +250,7 @@ extern spinlock_t swaplock; ...@@ -252,6 +250,7 @@ extern spinlock_t swaplock;
#define move_from_swap_cache(p, i, m) 1 #define move_from_swap_cache(p, i, m) 1
#define __delete_from_swap_cache(p) /*NOTHING*/ #define __delete_from_swap_cache(p) /*NOTHING*/
#define delete_from_swap_cache(p) /*NOTHING*/ #define delete_from_swap_cache(p) /*NOTHING*/
#define swap_unplug_io_fn(p) /*NOTHING*/
static inline int remove_exclusive_swap_page(struct page *p) static inline int remove_exclusive_swap_page(struct page *p)
{ {
......
...@@ -127,7 +127,7 @@ static inline int sync_page(struct page *page) ...@@ -127,7 +127,7 @@ static inline int sync_page(struct page *page)
if (mapping->a_ops && mapping->a_ops->sync_page) if (mapping->a_ops && mapping->a_ops->sync_page)
return mapping->a_ops->sync_page(page); return mapping->a_ops->sync_page(page);
} else if (PageSwapCache(page)) { } else if (PageSwapCache(page)) {
swap_unplug_io_fn(NULL); swap_unplug_io_fn(page);
} }
return 0; return 0;
} }
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -572,7 +571,3 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr, ...@@ -572,7 +571,3 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr,
void pte_chain_init(void) void pte_chain_init(void)
{ {
} }
void swap_unplug_io_fn(struct backing_dev_info *)
{
}
...@@ -25,13 +25,13 @@ static struct address_space_operations swap_aops = { ...@@ -25,13 +25,13 @@ static struct address_space_operations swap_aops = {
}; };
static struct backing_dev_info swap_backing_dev_info = { static struct backing_dev_info swap_backing_dev_info = {
.memory_backed = 1, /* Does not contribute to dirty memory */ .state = 0, /* uncongested */
.unplug_io_fn = swap_unplug_io_fn,
}; };
struct address_space swapper_space = { struct address_space swapper_space = {
.page_tree = RADIX_TREE_INIT(GFP_ATOMIC), .page_tree = RADIX_TREE_INIT(GFP_ATOMIC),
.tree_lock = SPIN_LOCK_UNLOCKED, .tree_lock = SPIN_LOCK_UNLOCKED,
.nrpages = 0, /* total_swapcache_pages */
.a_ops = &swap_aops, .a_ops = &swap_aops,
.backing_dev_info = &swap_backing_dev_info, .backing_dev_info = &swap_backing_dev_info,
}; };
......
...@@ -86,19 +86,26 @@ static void remove_swap_bdev(struct block_device *bdev) ...@@ -86,19 +86,26 @@ static void remove_swap_bdev(struct block_device *bdev)
BUG(); BUG();
} }
void swap_unplug_io_fn(struct backing_dev_info *unused_bdi) /*
* Unlike a standard unplug_io_fn, swap_unplug_io_fn is never called
* through swap's backing_dev_info (which is only used by shrink_list),
* but directly from sync_page when PageSwapCache: and takes the page
* as argument, so that it can find the right device from swp_entry_t.
*/
void swap_unplug_io_fn(struct page *page)
{ {
int i; swp_entry_t entry;
down(&swap_bdevs_sem); down(&swap_bdevs_sem);
for (i = 0; i < MAX_SWAPFILES; i++) { entry.val = page->private;
struct block_device *bdev = swap_bdevs[i]; if (PageSwapCache(page)) {
struct block_device *bdev = swap_bdevs[swp_type(entry)];
struct backing_dev_info *bdi; struct backing_dev_info *bdi;
if (bdev == NULL) if (bdev) {
break; bdi = bdev->bd_inode->i_mapping->backing_dev_info;
bdi = bdev->bd_inode->i_mapping->backing_dev_info; (*bdi->unplug_io_fn)(bdi);
(*bdi->unplug_io_fn)(bdi); }
} }
up(&swap_bdevs_sem); up(&swap_bdevs_sem);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment