]> git.hungrycats.org Git - linux/commitdiff
[PATCH] rmap: swap_unplug page
authorAndrew Morton <akpm@osdl.org>
Sun, 18 Apr 2004 03:55:06 +0000 (20:55 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sun, 18 Apr 2004 03:55:06 +0000 (20:55 -0700)
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).

include/linux/swap.h
mm/filemap.c
mm/nommu.c
mm/swap_state.c
mm/swapfile.c

index f911d8afb8a57f6452df08d269d1539160555a47..5c5a797290417c5da851cb61f64404d8228d2dd0 100644 (file)
@@ -181,8 +181,6 @@ extern int vm_swappiness;
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
 #endif /* CONFIG_MMU */
 
-extern void swap_unplug_io_fn(struct backing_dev_info *);
-
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
 extern int swap_readpage(struct file *, struct page *);
@@ -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 int can_share_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 spinlock_t swaplock;
@@ -252,6 +250,7 @@ extern spinlock_t swaplock;
 #define move_from_swap_cache(p, i, m)          1
 #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)
 {
index 4149342710f1333e87c9b64d1d95fb3362deaa5c..a82e900593dae77dafc45217307c3258e94a394b 100644 (file)
@@ -127,7 +127,7 @@ static inline int sync_page(struct page *page)
                if (mapping->a_ops && mapping->a_ops->sync_page)
                        return mapping->a_ops->sync_page(page);
        } else if (PageSwapCache(page)) {
-               swap_unplug_io_fn(NULL);
+               swap_unplug_io_fn(page);
        }
        return 0;
 }
index 1432dbab85eba283f27ef0cc23eb6263d89d68bc..c940756b49e54504d5f45d34fee042e1cbcbeb3d 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
-#include <linux/backing-dev.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -572,7 +571,3 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr,
 void pte_chain_init(void)
 {
 }
-
-void swap_unplug_io_fn(struct backing_dev_info *)
-{
-}
index d76b2d1bcf79ddf7419f3fd1e380ec37551bee23..b6232384d4110bf4a7c0967281d0a565da1cc912 100644 (file)
@@ -25,13 +25,13 @@ static struct address_space_operations swap_aops = {
 };
 
 static struct backing_dev_info swap_backing_dev_info = {
-       .memory_backed  = 1,    /* Does not contribute to dirty memory */
-       .unplug_io_fn   = swap_unplug_io_fn,
+       .state          = 0,    /* uncongested */
 };
 
 struct address_space swapper_space = {
        .page_tree      = RADIX_TREE_INIT(GFP_ATOMIC),
        .tree_lock      = SPIN_LOCK_UNLOCKED,
+       .nrpages        = 0,    /* total_swapcache_pages */
        .a_ops          = &swap_aops,
        .backing_dev_info = &swap_backing_dev_info,
 };
index c3ece5503ddb19f8592c4edca5dabf3059e6a002..3103178c6e5208161ed9bca30ba947ca276666ce 100644 (file)
@@ -86,19 +86,26 @@ static void remove_swap_bdev(struct block_device *bdev)
        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);
-       for (i = 0; i < MAX_SWAPFILES; i++) {
-               struct block_device *bdev = swap_bdevs[i];
+       entry.val = page->private;
+       if (PageSwapCache(page)) {
+               struct block_device *bdev = swap_bdevs[swp_type(entry)];
                struct backing_dev_info *bdi;
 
-               if (bdev == NULL)
-                       break;
-               bdi = bdev->bd_inode->i_mapping->backing_dev_info;
-               (*bdi->unplug_io_fn)(bdi);
+               if (bdev) {
+                       bdi = bdev->bd_inode->i_mapping->backing_dev_info;
+                       (*bdi->unplug_io_fn)(bdi);
+               }
        }
        up(&swap_bdevs_sem);
 }