From: Minchan Kim <minchan@xxxxxxxxxx> Frontswap initialization routine depends on swap_lock, which want to be atomic about frontswap's first appearance. IOW, frontswap is not present and will fail all calls OR frontswap is fully functional but if new swap_info_struct isn't registered by enable_swap_info, swap subsystem doesn't start I/O so there is no race between init procedure and page I/O working on frontswap. So let's remove unncessary swap_lock dependency. Cc: Dan Magenheimer <dan.magenheimer@xxxxxxxxxx> Signed-off-by: Minchan Kim <minchan@xxxxxxxxxx> [v1: Rebased on my branch, reworked to work with backends loading late] [v2: Added a check for !map] Signed-off-by: Konrad Rzeszutek Wilk <konrad@xxxxxxxxxx> squash --- include/linux/frontswap.h | 6 +++--- mm/frontswap.c | 12 +++++++++--- mm/swapfile.c | 7 ++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/linux/frontswap.h b/include/linux/frontswap.h index 612c176..3d72f14 100644 --- a/include/linux/frontswap.h +++ b/include/linux/frontswap.h @@ -20,7 +20,7 @@ extern void frontswap_writethrough(bool); #define FRONTSWAP_HAS_EXCLUSIVE_GETS extern void frontswap_tmem_exclusive_gets(bool); -extern void __frontswap_init(unsigned type); +extern void __frontswap_init(unsigned type, unsigned long *map); extern int __frontswap_store(struct page *page); extern int __frontswap_load(struct page *page); extern void __frontswap_invalidate_page(unsigned, pgoff_t); @@ -122,9 +122,9 @@ static inline void frontswap_invalidate_area(unsigned type) __frontswap_invalidate_area(type); } -static inline void frontswap_init(unsigned type) +static inline void frontswap_init(unsigned type, unsigned long *map) { - __frontswap_init(type); + __frontswap_init(type, map); } #endif /* _LINUX_FRONTSWAP_H */ diff --git a/mm/frontswap.c b/mm/frontswap.c index ebf4c18..8254a6a 100644 --- a/mm/frontswap.c +++ b/mm/frontswap.c @@ -127,8 +127,13 @@ struct frontswap_ops *frontswap_register_ops(struct frontswap_ops *ops) int i; for (i = 0; i < MAX_SWAPFILES; i++) { - if (test_and_clear_bit(i, need_init)) + if (test_and_clear_bit(i, need_init)) { + struct swap_info_struct *sis = swap_info[i]; + /* enable_swap_info _should_ have set it! */ + if (!sis->frontswap_map) + return ERR_PTR(-EINVAL); ops->init(i); + } } /* * We MUST have frontswap_ops set _after_ the frontswap_init's @@ -166,14 +171,15 @@ EXPORT_SYMBOL(frontswap_tmem_exclusive_gets); * * Can be called without any backend driver is registered. */ -void __frontswap_init(unsigned type) +void __frontswap_init(unsigned type, unsigned long *map) { struct swap_info_struct *sis = swap_info[type]; if (static_key_false(&frontswap_key)) { BUG_ON(sis == NULL); - if (sis->frontswap_map == NULL) + if (!map) return; + frontswap_map_set(sis, map); frontswap_ops->init(type); } else { diff --git a/mm/swapfile.c b/mm/swapfile.c index e97a0e5..c1c3a62 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1454,6 +1454,10 @@ static void _enable_swap_info(struct swap_info_struct *p, int prio, else p->prio = --least_priority; p->swap_map = swap_map; + /* + * This is required for frontswap to handle backends loading + * after the swap has been activated. + */ frontswap_map_set(p, frontswap_map); p->flags |= SWP_WRITEOK; nr_swap_pages += p->pages; @@ -1477,9 +1481,9 @@ static void enable_swap_info(struct swap_info_struct *p, int prio, unsigned char *swap_map, unsigned long *frontswap_map) { + frontswap_init(p->type, frontswap_map); spin_lock(&swap_lock); _enable_swap_info(p, prio, swap_map, frontswap_map); - frontswap_init(p->type); spin_unlock(&swap_lock); } @@ -1589,6 +1593,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) p->swap_map = NULL; p->flags = 0; frontswap_invalidate_area(type); + frontswap_map_set(p, NULL); spin_unlock(&swap_lock); mutex_unlock(&swapon_mutex); vfree(swap_map); -- 1.7.11.7 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>