提交 10e8409f 编写于 作者: W Wang Wensheng 提交者: Zhong Jinghua

mm/sharepool: Simplify sp_unshare_uva()

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I650K6

--------------------------------

The unshare process for k2task can be normalized with k2spg
since there exist a local sp group for k2task.
Signed-off-by: NWang Wensheng <wangwensheng4@huawei.com>
上级 7325bc5b
...@@ -3264,54 +3264,42 @@ void *mg_sp_make_share_u2k(unsigned long uva, unsigned long size, int tgid) ...@@ -3264,54 +3264,42 @@ void *mg_sp_make_share_u2k(unsigned long uva, unsigned long size, int tgid)
EXPORT_SYMBOL_GPL(mg_sp_make_share_u2k); EXPORT_SYMBOL_GPL(mg_sp_make_share_u2k);
/* /*
* Input parameters uva, tgid and spg_id are now useless. spg_id will be useful * sp_unshare_uva - unshare a uva from sp_make_share_k2u
* when supporting a process in multiple sp groups. * @uva: the uva to be unshared
* @size: not used actually and we just check it
* @group_id: specify the spg of the uva; for local group, it can be SPG_ID_DEFAULT
* unless current process is exiting.
* *
* Procedure of unshare uva must be compatible with: * Procedure of unshare uva must be compatible with:
* *
* 1. DVPP channel destroy procedure: * 1. DVPP channel destroy procedure:
* do_exit() -> exit_mm() (mm no longer in spg and current->mm == NULL) -> * do_exit() -> exit_mm() (mm no longer in spg and current->mm == NULL) ->
* exit_task_work() -> task_work_run() -> __fput() -> ... -> vdec_close() -> * exit_task_work() -> task_work_run() -> __fput() -> ... -> vdec_close() ->
* sp_unshare(uva, SPG_ID_DEFAULT) * sp_unshare(uva, local_spg_id)
*
* 2. Process A once was the target of k2u(to group), then it exits.
* Guard worker kthread tries to free this uva and it must succeed, otherwise
* spa of this uva leaks.
*
* This also means we must trust DVPP channel destroy and guard worker code.
*/ */
static int sp_unshare_uva(unsigned long uva, unsigned long size, int group_id) static int sp_unshare_uva(unsigned long uva, unsigned long size, int group_id)
{ {
int ret = 0; int ret = 0;
struct mm_struct *mm;
struct sp_area *spa; struct sp_area *spa;
unsigned long uva_aligned;
unsigned long size_aligned;
unsigned int page_size; unsigned int page_size;
struct sp_group *spg; struct sp_group *spg;
spg = sp_group_get(current->tgid, group_id); spg = sp_group_get(current->tgid, group_id);
if (!spg) { if (!spg) {
pr_debug("sp unshare find group failed %d\n", group_id); pr_err("sp unshare find group failed %d\n", group_id);
return -EINVAL; return -EINVAL;
} }
/* /* All the spa are aligned to 2M. */
* at first we guess it's a hugepage addr
* we can tolerate at most PMD_SIZE or PAGE_SIZE which is matched in k2u
*/
spa = get_sp_area(spg, ALIGN_DOWN(uva, PMD_SIZE)); spa = get_sp_area(spg, ALIGN_DOWN(uva, PMD_SIZE));
if (!spa) {
spa = get_sp_area(spg, ALIGN_DOWN(uva, PAGE_SIZE));
if (!spa) { if (!spa) {
ret = -EINVAL; ret = -EINVAL;
pr_debug("invalid input uva %lx in unshare uva\n", (unsigned long)uva); pr_err("invalid input uva %lx in unshare uva\n", (unsigned long)uva);
goto out; goto out;
} }
}
if (spa->type != SPA_TYPE_K2TASK && spa->type != SPA_TYPE_K2SPG) { if (spa->type != SPA_TYPE_K2TASK && spa->type != SPA_TYPE_K2SPG) {
pr_err_ratelimited("unshare wrong type spa\n"); pr_err("unshare wrong type spa\n");
ret = -EINVAL; ret = -EINVAL;
goto out_drop_area; goto out_drop_area;
} }
...@@ -3322,75 +3310,33 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int group_id) ...@@ -3322,75 +3310,33 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int group_id)
* Thus input parameter size is not necessarily needed. * Thus input parameter size is not necessarily needed.
*/ */
page_size = (spa->is_hugepage ? PMD_SIZE : PAGE_SIZE); page_size = (spa->is_hugepage ? PMD_SIZE : PAGE_SIZE);
uva_aligned = spa->va_start;
size_aligned = spa->real_size;
if (size_aligned < ALIGN(size, page_size)) { if (spa->real_size < ALIGN(size, page_size)) {
ret = -EINVAL; ret = -EINVAL;
pr_err_ratelimited("unshare uva failed, invalid parameter size %lu\n", size); pr_err("unshare uva failed, invalid parameter size %lu\n", size);
goto out_drop_area;
}
if (spa->type == SPA_TYPE_K2TASK) {
if (spa->applier != current->tgid) {
pr_err_ratelimited("unshare uva(to task) no permission\n");
ret = -EPERM;
goto out_drop_area;
}
/*
* current thread may be exiting in a multithread process
*
* 1. never need a kthread to make unshare when process has exited
* 2. in dvpp channel destroy procedure, exit_mm() has been called
* and don't need to make unshare
*/
mm = get_task_mm(current->group_leader);
if (!mm) {
pr_info_ratelimited("no need to unshare uva(to task), target process mm is exiting\n");
goto out_clr_flag;
}
down_write(&mm->mmap_lock);
if (unlikely(mm->core_state)) {
ret = 0;
up_write(&mm->mmap_lock);
mmput(mm);
goto out_drop_area; goto out_drop_area;
} }
ret = do_munmap(mm, uva_aligned, size_aligned, NULL);
up_write(&mm->mmap_lock);
mmput(mm);
/* we are not supposed to fail */
if (ret)
pr_err("failed to unmap VA %pK when munmap in unshare uva\n",
(void *)uva_aligned);
sp_update_process_stat(current, false, spa);
} else if (spa->type == SPA_TYPE_K2SPG) {
down_read(&spa->spg->rw_lock); down_read(&spa->spg->rw_lock);
/* always allow kthread and dvpp channel destroy procedure */ /* always allow dvpp channel destroy procedure */
if (current->mm) { if (current->mm && !is_process_in_group(spa->spg, current->mm)) {
if (!is_process_in_group(spa->spg, current->mm)) {
up_read(&spa->spg->rw_lock); up_read(&spa->spg->rw_lock);
pr_err_ratelimited("unshare uva(to group) failed, caller process doesn't belong to target group\n"); pr_err("unshare uva failed, caller process doesn't belong to target group\n");
ret = -EPERM; ret = -EPERM;
goto out_drop_area; goto out_drop_area;
} }
}
up_read(&spa->spg->rw_lock); up_read(&spa->spg->rw_lock);
down_write(&spa->spg->rw_lock); down_write(&spa->spg->rw_lock);
if (!spg_valid(spa->spg)) { if (!spg_valid(spa->spg)) {
up_write(&spa->spg->rw_lock); up_write(&spa->spg->rw_lock);
pr_info_ratelimited("share pool: no need to unshare uva(to group), sp group of spa is dead\n"); pr_info("no need to unshare uva, sp group of spa is dead\n");
goto out_clr_flag; goto out_clr_flag;
} }
/* the life cycle of spa has a direct relation with sp group */ /* the life cycle of spa has a direct relation with sp group */
if (unlikely(spa->is_dead)) { if (unlikely(spa->is_dead)) {
up_write(&spa->spg->rw_lock); up_write(&spa->spg->rw_lock);
pr_err_ratelimited("unexpected double sp unshare\n"); pr_err("unexpected double sp unshare\n");
dump_stack(); dump_stack();
ret = -EINVAL; ret = -EINVAL;
goto out_drop_area; goto out_drop_area;
...@@ -3399,20 +3345,17 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int group_id) ...@@ -3399,20 +3345,17 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int group_id)
up_write(&spa->spg->rw_lock); up_write(&spa->spg->rw_lock);
down_read(&spa->spg->rw_lock); down_read(&spa->spg->rw_lock);
__sp_free(spa->spg, uva_aligned, size_aligned, NULL); __sp_free(spa->spg, spa->va_start, spa->real_size, NULL);
up_read(&spa->spg->rw_lock); up_read(&spa->spg->rw_lock);
if (current->mm == NULL) if (current->mm == NULL)
atomic64_sub(spa->real_size, &kthread_stat.k2u_size); atomic64_sub(spa->real_size, &kthread_stat.k2u_size);
else else
sp_update_process_stat(current, false, spa); sp_update_process_stat(current, false, spa);
} else {
WARN(1, "unshare uva invalid spa type");
}
out_clr_flag: out_clr_flag:
if (!vmalloc_area_clr_flag(spa->kva, VM_SHAREPOOL)) if (!vmalloc_area_clr_flag(spa->kva, VM_SHAREPOOL))
pr_debug("clear spa->kva %ld is not valid\n", spa->kva); pr_info("clear spa->kva %ld is not valid\n", spa->kva);
spa->kva = 0; spa->kva = 0;
out_drop_area: out_drop_area:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册