From: Chen Wandun chenwandun@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I645JI
-------------------------------
Commit 46d673d7fed7 ("mm/swapfile: fix broken kabi in swap_info_struct") uses KABI_EXTEND to fix kabi broken problem, but this is not the safest way, so use new way to fix this prolem.
Introduce new struct swap_extend_info that contains extend info of swap, meanwhile use KABI_USE to repalce memory space reserved by KABI_RESERVER.
Signed-off-by: Chen Wandun chenwandun@huawei.com Reviewed-by: zhangjialin zhangjialin11@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- include/linux/swap.h | 11 +++++++---- mm/swapfile.c | 33 +++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h index c55f6e410d05..7f49964f27d2 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -246,6 +246,11 @@ struct swap_cluster_list { struct swap_cluster_info tail; };
+struct swap_extend_info { + struct percpu_ref users; /* indicate and keep swap device valid. */ + struct completion comp; /* seldom referenced */ +}; + /* * The in-memory structure used to track swap areas. */ @@ -293,10 +298,8 @@ struct swap_info_struct { */ struct work_struct discard_work; /* discard worker */ struct swap_cluster_list discard_clusters; /* discard clusters list */ - KABI_RESERVE(1) + KABI_USE(1, struct swap_extend_info *sei) KABI_RESERVE(2) - KABI_EXTEND(struct percpu_ref users) /* indicate and keep swap device valid. */ - KABI_EXTEND(struct completion comp) /* seldom referenced */ struct plist_node avail_lists[]; /* * entries in swap_avail_heads, one * entry per node. @@ -537,7 +540,7 @@ sector_t swap_page_sector(struct page *page);
static inline void put_swap_device(struct swap_info_struct *si) { - percpu_ref_put(&si->users); + percpu_ref_put(&si->sei->users); }
#else /* CONFIG_SWAP */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 0c560204acf4..4594e808ebc0 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -515,10 +515,10 @@ static void swap_discard_work(struct work_struct *work)
static void swap_users_ref_free(struct percpu_ref *ref) { - struct swap_info_struct *si; + struct swap_extend_info *sei;
- si = container_of(ref, struct swap_info_struct, users); - complete(&si->comp); + sei = container_of(ref, struct swap_extend_info, users); + complete(&sei->comp); }
static void alloc_cluster(struct swap_info_struct *si, unsigned long idx) @@ -1316,7 +1316,7 @@ struct swap_info_struct *get_swap_device(swp_entry_t entry) si = swp_swap_info(entry); if (!si) goto bad_nofile; - if (!percpu_ref_tryget_live(&si->users)) + if (!percpu_ref_tryget_live(&si->sei->users)) goto out; /* * Guarantee the si->users are checked before accessing other @@ -1336,7 +1336,7 @@ struct swap_info_struct *get_swap_device(swp_entry_t entry) out: return NULL; put_out: - percpu_ref_put(&si->users); + percpu_ref_put(&si->sei->users); return NULL; }
@@ -2542,7 +2542,7 @@ static void enable_swap_info(struct swap_info_struct *p, int prio, /* * Finished initializing swap device, now it's safe to reference it. */ - percpu_ref_resurrect(&p->users); + percpu_ref_resurrect(&p->sei->users); spin_lock(&swap_lock); spin_lock(&p->lock); _enable_swap_info(p); @@ -2665,9 +2665,9 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) * We need synchronize_rcu() here to protect the accessing to * the swap cache data structure. */ - percpu_ref_kill(&p->users); + percpu_ref_kill(&p->sei->users); synchronize_rcu(); - wait_for_completion(&p->comp); + wait_for_completion(&p->sei->comp);
flush_work(&p->discard_work);
@@ -2899,8 +2899,15 @@ static struct swap_info_struct *alloc_swap_info(void) if (!p) return ERR_PTR(-ENOMEM);
- if (percpu_ref_init(&p->users, swap_users_ref_free, + p->sei = kvzalloc(sizeof(struct swap_extend_info), GFP_KERNEL); + if (!p->sei) { + kvfree(p); + return ERR_PTR(-ENOMEM); + } + + if (percpu_ref_init(&p->sei->users, swap_users_ref_free, PERCPU_REF_INIT_DEAD, GFP_KERNEL)) { + kvfree(p->sei); kvfree(p); return ERR_PTR(-ENOMEM); } @@ -2912,7 +2919,8 @@ static struct swap_info_struct *alloc_swap_info(void) } if (type >= MAX_SWAPFILES) { spin_unlock(&swap_lock); - percpu_ref_exit(&p->users); + percpu_ref_exit(&p->sei->users); + kvfree(p->sei); kvfree(p); return ERR_PTR(-EPERM); } @@ -2941,12 +2949,13 @@ static struct swap_info_struct *alloc_swap_info(void) p->flags = SWP_USED; spin_unlock(&swap_lock); if (defer) { - percpu_ref_exit(&defer->users); + percpu_ref_exit(&defer->sei->users); + kvfree(defer->sei); kvfree(defer); } spin_lock_init(&p->lock); spin_lock_init(&p->cont_lock); - init_completion(&p->comp); + init_completion(&p->sei->comp);
return p; }