--- 25-akpm/include/linux/swap.h | 2 + 25-akpm/mm/swap_state.c | 1 25-akpm/mm/swapfile.c | 63 +++++++++++++++++++++++++++++++++++++++++++ include/linux/backing-dev.h | 0 4 files changed, 66 insertions(+) diff -puN mm/swapfile.c~swapper_space-unplug_fn mm/swapfile.c --- 25/mm/swapfile.c~swapper_space-unplug_fn 2004-03-14 13:58:22.461298432 -0800 +++ 25-akpm/mm/swapfile.c 2004-03-14 14:13:41.598568328 -0800 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -44,8 +45,64 @@ struct swap_list_t swap_list = {-1, -1}; struct swap_info_struct swap_info[MAX_SWAPFILES]; +/* + * Array of backing blockdevs, for swap_unplug_fn. We need this because the + * bdev->unplug_fn can sleep and we cannot hold swap_list_lock while calling + * the unplug_fn. And swap_list_lock cannot be turned into a semaphore. + */ +static DECLARE_MUTEX(swap_bdevs_sem); +static struct block_device *swap_bdevs[MAX_SWAPFILES]; + #define SWAPFILE_CLUSTER 256 +/* + * Caller holds swap_bdevs_sem + */ +static void install_swap_bdev(struct block_device *bdev) +{ + int i; + + for (i = 0; i < MAX_SWAPFILES; i++) { + if (swap_bdevs[i] == NULL) { + swap_bdevs[i] = bdev; + return; + } + } + BUG(); +} + +static void remove_swap_bdev(struct block_device *bdev) +{ + int i; + + for (i = 0; i < MAX_SWAPFILES; i++) { + if (swap_bdevs[i] == bdev) { + memcpy(&swap_bdevs[i], &swap_bdevs[i + 1], + (MAX_SWAPFILES - i - 1) * sizeof(*swap_bdevs)); + swap_bdevs[MAX_SWAPFILES - 1] = NULL; + return; + } + } + BUG(); +} + +void swap_unplug_io_fn(struct backing_dev_info *unused_bdi) +{ + int i; + + down(&swap_bdevs_sem); + for (i = 0; i < MAX_SWAPFILES; i++) { + struct block_device *bdev = swap_bdevs[i]; + struct backing_dev_info *bdi; + + if (bdev == NULL) + break; + bdi = bdev->bd_inode->i_mapping->backing_dev_info; + (*bdi->unplug_io_fn)(bdi); + } + up(&swap_bdevs_sem); +} + static inline int scan_swap_map(struct swap_info_struct *si) { unsigned long offset; @@ -1088,6 +1145,7 @@ asmlinkage long sys_swapoff(const char _ swap_list_unlock(); goto out_dput; } + down(&swap_bdevs_sem); swap_list_lock(); swap_device_lock(p); swap_file = p->swap_file; @@ -1099,6 +1157,8 @@ asmlinkage long sys_swapoff(const char _ destroy_swap_extents(p); swap_device_unlock(p); swap_list_unlock(); + remove_swap_bdev(p->bdev); + up(&swap_bdevs_sem); vfree(swap_map); if (S_ISBLK(mapping->host->i_mode)) { struct block_device *bdev = I_BDEV(mapping->host); @@ -1412,6 +1472,7 @@ asmlinkage long sys_swapon(const char __ if (error) goto bad_swap; + down(&swap_bdevs_sem); swap_list_lock(); swap_device_lock(p); p->flags = SWP_ACTIVE; @@ -1437,6 +1498,8 @@ asmlinkage long sys_swapon(const char __ } swap_device_unlock(p); swap_list_unlock(); + install_swap_bdev(p->bdev); + up(&swap_bdevs_sem); error = 0; goto out; bad_swap: diff -puN include/linux/swap.h~swapper_space-unplug_fn include/linux/swap.h --- 25/include/linux/swap.h~swapper_space-unplug_fn 2004-03-14 13:58:22.462298280 -0800 +++ 25-akpm/include/linux/swap.h 2004-03-14 13:58:22.469297216 -0800 @@ -232,6 +232,8 @@ extern sector_t map_swap_page(struct swa 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 backing_dev_info *); extern struct swap_list_t swap_list; extern spinlock_t swaplock; diff -puN mm/swap_state.c~swapper_space-unplug_fn mm/swap_state.c --- 25/mm/swap_state.c~swapper_space-unplug_fn 2004-03-14 13:58:22.463298128 -0800 +++ 25-akpm/mm/swap_state.c 2004-03-14 13:58:22.469297216 -0800 @@ -19,6 +19,7 @@ static struct backing_dev_info swap_backing_dev_info = { .ra_pages = 0, /* No readahead */ .memory_backed = 1, /* Does not contribute to dirty memory */ + .unplug_io_fn = swap_unplug_io_fn, }; extern struct address_space_operations swap_aops; diff -puN include/linux/backing-dev.h~swapper_space-unplug_fn include/linux/backing-dev.h _