Offering: HULK hulk inclusion category: feature bugzilla: NA ---------------------------------------- support unregister remote range Signed-off-by: Yin Tirui <yintirui@huawei.com> --- include/linux/share_pool.h | 7 +++ mm/share_pool.c | 91 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/include/linux/share_pool.h b/include/linux/share_pool.h index b230f108e89d..4102d0dcf25b 100644 --- a/include/linux/share_pool.h +++ b/include/linux/share_pool.h @@ -166,6 +166,8 @@ extern int mg_sp_register_remote_range(int spg_id, unsigned long va, extern int mg_sp_register_remote_range_multi(int spg_id, unsigned long va, unsigned long *pa_array, unsigned long len, unsigned long page_size); +extern int mg_sp_unregister_remote_range(int spg_id, unsigned long addr); + extern int mg_sp_id_of_current(void); extern void __sp_mm_clean(struct mm_struct *mm); @@ -301,6 +303,11 @@ static inline int mg_sp_register_remote_range_multi(int spg_id, unsigned long va return -EPERM; } +static inline int mg_sp_unregister_remote_range(int spg_id, unsigned long addr) +{ + return -EPERM; +} + static inline bool sp_is_enabled(void) { return false; diff --git a/mm/share_pool.c b/mm/share_pool.c index bffd8f5731b8..0eb309ad38e4 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -1575,6 +1575,13 @@ static bool sp_group_delete_area(struct sp_group *spg, struct sp_area *spa) return atomic_dec_and_test(&spa->spg->spa_num); } +static bool sp_remote_group_delete_area(struct sp_remote_group *sprg, + struct sp_remote_area *spra) +{ + list_del(&spra->list); + return atomic_dec_and_test(&sprg->spra_num); +} + unsigned long sp_alloc_hugepage(unsigned long size, int nid, nodemask_t *nodemask) { struct folio *folio = alloc_hugetlb_folio_nodemask_size(size, nid, nodemask); @@ -1937,6 +1944,17 @@ static void sp_area_free(struct sp_area *spa) kfree(spa); } +static void sp_remote_area_free(struct sp_remote_area *spra) +{ + struct sp_area *spa = spra->spa; + + if (spa) + spa->spra = NULL; + if (spra->multi) + kvfree(spra->pa_array); + kfree(spra); +} + static void sp_area_put_locked(struct sp_area *spa) { if (atomic_dec_and_test(&spa->use_count)) { @@ -1947,6 +1965,16 @@ static void sp_area_put_locked(struct sp_area *spa) } } +static void sp_remote_area_put_locked(struct sp_remote_area *spra) +{ + if (atomic_dec_and_test(&spra->use_count)) { + if (sp_remote_group_delete_area(spra->sprg, spra)) + /* the caller must hold a refcount for spra->sprg under sprg->rw_lock */ + atomic_dec(&spra->sprg->use_count); + sp_remote_area_free(spra); + } +} + static void sp_area_drop_func(struct work_struct *work) { bool spa_zero; @@ -3661,6 +3689,11 @@ static int __register_remote(int spg_id, unsigned long va, if (!sp_is_enabled()) return -EOPNOTSUPP; + if (!(current->flags & PF_KTHREAD)) { + pr_err_ratelimited("register remote failed, task is non-kthread\n"); + return -EOPNOTSUPP; + } + if (unlikely(page_size != PMD_SIZE)) { pr_err_ratelimited("register remote failed, invalid page_size 0x%lx\n", page_size); return -EINVAL; @@ -3728,6 +3761,64 @@ int mg_sp_register_remote_range_multi(int spg_id, unsigned long va, } EXPORT_SYMBOL_GPL(mg_sp_register_remote_range_multi); +int mg_sp_unregister_remote_range(int spg_id, unsigned long addr) +{ + int ret = 0; + struct sp_area *spa; + struct sp_group *spg; + struct sp_remote_group *sprg; + struct sp_remote_area *spra, *tmp; + + if (!sp_is_enabled()) + return -EOPNOTSUPP; + + if (!(current->flags & PF_KTHREAD)) { + pr_err_ratelimited("unregister remote failed, task is non-kthread\n"); + return -EOPNOTSUPP; + } + + down_write(&sp_global_sem); + sprg = sp_remote_group_get_from_idr_locked(spg_id); + if (unlikely(!sprg)) { + pr_err_ratelimited("unregister remote failed, invalid spg id %d\n", spg_id); + ret = -EINVAL; + goto out_unlock; + } + + down_write(&sprg->rw_lock); + list_for_each_entry_safe(spra, tmp, &sprg->spra_list, list) { + if (spra->va_start == addr) + goto drop_spa; + } + pr_err_ratelimited("unregister remote failed, invalid addr 0x%lx for spg id %d\n", + addr, spg_id); + ret = -EINVAL; + goto drop_sprg; + +drop_spa: + spa = spra->spa; + if (spa) { + spg = spa->spg; + if (!atomic_inc_not_zero(&spg->use_count)) + goto drop_spra; + down_write(&spg->rw_lock); + __sp_free(spa, NULL); + sp_area_put_locked(spa); + up_write(&spg->rw_lock); + sp_group_put_locked(spg); + } +drop_spra: + sp_remote_area_put_locked(spra); +drop_sprg: + sp_remote_group_put_locked(sprg); + up_write(&sprg->rw_lock); +out_unlock: + up_write(&sp_global_sem); + + return ret; +} +EXPORT_SYMBOL_GPL(mg_sp_unregister_remote_range); + /*** Statistical and maintenance functions ***/ static void get_mm_rss_info(struct mm_struct *mm, unsigned long *anon, -- 2.43.0