From: Tang Yizhou tangyizhou@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
Provide a free area cache for the share pool VA allocator, based on the algorithm used by linux mainline commit 89699605fe7c.
This reduces the number of rbtree operations and linear traversals over the share pool extents in order to find a free area, by starting off at the last point that a free area was found.
The free area cache is reset if areas are freed behind it, or if we are searching for an another area (such as DVPP 16G area) than last time. So allocation patterns are not changed.
After this patch, the search will start from where it left off, giving closer to an amortized O(1).
Test environment: Huawei 1951 DC (8 CPU cores) with 21G memory, no load.
Test method: A single thread process first call sp_alloc() to allocate a specified number of 2M hugepages, then we calculate the allocation time when sp_alloc() another 2M hugepage. The results are in microsecond.
test 1, first sp_alloc() 256 2M-hugepage, total 512M test 2, first sp_alloc() 512 2M-hugepage, total 1G test 3, first sp_alloc() 1024 2M-hugepage, total 2G test 4, first sp_alloc() 1536 2M-hugepage, total 3G test 5, first sp_alloc() 2048 2M-hugepage, total 4G test 6, first sp_alloc() 4096 2M-hugepage, total 8G test 7, first sp_alloc() 6072 2M-hugepage, total 12G test 8, first sp_alloc() 8192 2M-hugepage, total 16G
test1 test2 test3 test4 231 238 240 252 279 253 315 268 242 238 247 253 282 255 326 265 233 234 250 243 272 251 314 258 239 224 245 246 273 261 324 262 234 233 252 257 277 262 326 265 225 231 243 243 279 249 325 264 236 261 246 248 265 262 323 266 233 238 247 246 281 259 331 265 239 222 243 241 270 248 325 263 241 231 239 241 335 246 321 268 avg: 235.3 235 245.2 247 281.3 254.6 323 264.4 res: - - 9.49% 18.14%
test5 test6 test7 test8 371 280 720 458 1001 629 1547 909 369 283 691 465 1005 718 1533 903 374 279 954 470 1003 680 1371 908 363 279 697 457 1004 923 1375 930 369 286 711 464 1016 683 1395 1083 382 280 967 491 1029 695 1413 1096 378 284 688 823 1008 689 1419 905 376 360 921 469 1285 696 1554 1085 374 287 896 485 1030 682 1381 902 380 276 706 545 1286 717 1606 1097 avg: 373.6 289.4 791.5 512.7 1066.7 717.5 1459.4 981.8 res: 22.54% 35.52% 32.74% 32.73%
Suggested-by: Zefan Li lizefan@huawei.com Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 104 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 29 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index 24c5dd680451..b9d30d36b7c2 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -730,6 +730,11 @@ static void __insert_sp_area(struct sp_area *spa) rb_insert_color(&spa->rb_node, &sp_area_root); }
+/* The sp_area cache globals are protected by sp_area_lock */ +static struct rb_node *free_sp_area_cache; +static unsigned long cached_hole_size; +static unsigned long cached_vstart; /* affected by SP_DVPP and sp_config_dvpp_range() */ + /* * Allocate a region of VA from the share pool. * @size - the size of VA to allocate @@ -741,7 +746,7 @@ static void __insert_sp_area(struct sp_area *spa) static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, struct sp_group *spg, enum spa_type type) { - struct sp_area *spa, *err; + struct sp_area *spa, *first, *err; struct rb_node *n; unsigned long vstart = MMAP_SHARE_POOL_START; unsigned long vend = MMAP_SHARE_POOL_16G_START; @@ -763,8 +768,6 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, } }
- addr = vstart; - spa = kmalloc(sizeof(struct sp_area), GFP_KERNEL); if (unlikely(!spa)) { if (printk_ratelimit()) @@ -774,45 +777,75 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags,
spin_lock(&sp_area_lock);
- n = sp_area_root.rb_node; - if (n) { - struct sp_area *first = NULL; + /* + * Invalidate cache if we have more permissive parameters. + * cached_hole_size notes the largest hole noticed _below_ + * the sp_area cached in free_sp_area_cache: if size fits + * into that hole, we want to scan from vstart to reuse + * the hole instead of allocating above free_sp_area_cache. + * Note that sp_free_area may update free_sp_area_cache + * without updating cached_hole_size. + */ + if (!free_sp_area_cache || size_align < cached_hole_size || + vstart != cached_vstart) { + cached_hole_size = 0; + free_sp_area_cache = NULL; + } + + /* record if we encounter less permissive parameters */ + cached_vstart = vstart; + + /* find starting point for our search */ + if (free_sp_area_cache) { + first = rb_entry(free_sp_area_cache, struct sp_area, rb_node); + addr = first->va_end; + if (addr + size_align < addr) { + err = ERR_PTR(-EOVERFLOW); + goto error; + } + } else { + addr = vstart; + if (addr + size_align < addr) { + err = ERR_PTR(-EOVERFLOW); + goto error; + } + + n = sp_area_root.rb_node; + first = NULL;
- do { + while (n) { struct sp_area *tmp; tmp = rb_entry(n, struct sp_area, rb_node); if (tmp->va_end >= addr) { - if (!first && tmp->va_start < addr + size_align) - first = tmp; - n = n->rb_left; - } else { first = tmp; + if (tmp->va_start <= addr) + break; + n = n->rb_left; + } else n = n->rb_right; - } - } while (n); + }
if (!first) goto found; + }
- if (first->va_end < addr) { - n = rb_next(&first->rb_node); - if (n) - first = rb_entry(n, struct sp_area, rb_node); - else - goto found; + /* from the starting point, traverse areas until a suitable hole is found */ + while (addr + size_align > first->va_start && addr + size_align <= vend) { + if (addr + cached_hole_size < first->va_start) + cached_hole_size = first->va_start - addr; + addr = first->va_end; + if (addr + size_align < addr) { + err = ERR_PTR(-EOVERFLOW); + goto error; }
- while (addr + size_align >= first->va_start && - addr + size_align <= vend) { - addr = first->va_end; - - n = rb_next(&first->rb_node); - if (n) - first = rb_entry(n, struct sp_area, rb_node); - else - goto found; - } + n = rb_next(&first->rb_node); + if (n) + first = rb_entry(n, struct sp_area, rb_node); + else + goto found; } + found: if (addr + size_align > vend) { err = ERR_PTR(-EOVERFLOW); @@ -833,6 +866,7 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, }
__insert_sp_area(spa); + free_sp_area_cache = &spa->rb_node; if (spa->spg) { atomic_inc(&spg->spa_num); atomic64_add(size, &spg->size); @@ -889,6 +923,18 @@ static void sp_free_area(struct sp_area *spa) { lockdep_assert_held(&sp_area_lock);
+ if (free_sp_area_cache) { + struct sp_area *cache; + cache = rb_entry(free_sp_area_cache, struct sp_area, rb_node); + if (spa->va_start <= cache->va_start) { + free_sp_area_cache = rb_prev(&spa->rb_node); + /* + * We don't try to update cached_hole_size, + * but it won't go very wrong. + */ + } + } + spa_dec_usage(spa->type, spa->real_size); /* won't fail */ if (spa->spg) { atomic_dec(&spa->spg->spa_num);
From: Tang Yizhou tangyizhou@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
DVPP process channel destroy procedure: do_exit() -> exit_mm() (mm no longer in spg) -> exit_task_work() -> task_work_run() -> __fput() -> ... -> vdec_close() -> sp_unshare(uva, ..., SPG_ID_DEFAULT).
So when it calls sp_unshare(), current->mm is NULL, just like buff_module_guard_work kthread.
To solve this problem, we skip corresponding sanity checks.
Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 94 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 33 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index b9d30d36b7c2..32c3250795e9 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -530,7 +530,8 @@ int sp_group_add_task(int pid, int spg_id) } }
- mm = get_task_mm(tsk); + /* current thread may be exiting in a multithread process */ + mm = get_task_mm(tsk->group_leader); if (!mm) { ret = -ESRCH; goto out_drop_group; @@ -583,6 +584,8 @@ int sp_group_add_task(int pid, int spg_id) pr_warn("share pool: task add group failed when mm populate " "failed (potential no enough memory): %d\n", ret); sp_munmap_task_areas(mm, spa->link.next); + spin_lock(&sp_area_lock); + break; } }
@@ -859,6 +862,7 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, spa->spg = spg; atomic_set(&spa->use_count, 1); spa->type = type; + spa->mm = NULL;
if (spa_inc_usage(type, size)) { err = ERR_PTR(-EINVAL); @@ -1292,7 +1296,6 @@ void *sp_alloc(unsigned long size, unsigned long sp_flags, int spg_id) pr_warn("share pool: allocation failed due to mm populate failed" "(potential no enough memory when -12): %d\n", ret); p = ERR_PTR(ret); - __sp_area_drop(spa);
mode = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE; offset = sp_addr - MMAP_SHARE_POOL_START; @@ -1840,11 +1843,29 @@ void *sp_make_share_u2k(unsigned long uva, unsigned long size, int pid) } EXPORT_SYMBOL_GPL(sp_make_share_u2k);
+/* + * Input parameters uva and spg_id are now useless. spg_id will be useful when + * supporting a process in multiple sp groups. + * Always use process pid. Using thread pid is hard to check sanity. + * + * Procedure of unshare uva must be compatible with: + * + * 1. DVPP channel destroy procedure: + * do_exit() -> exit_mm() (mm no longer in spg and current->mm == NULL) -> + * exit_task_work() -> task_work_run() -> __fput() -> ... -> vdec_close() -> + * sp_unshare(uva, SPG_ID_DEFAULT) + * + * 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 pid, int spg_id) { int ret = 0; struct task_struct *tsk; - struct sp_group *spg; + struct mm_struct *mm; struct sp_area *spa; unsigned long uva_aligned; unsigned long size_aligned; @@ -1861,7 +1882,8 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp if (!spa) { ret = -EINVAL; if (printk_ratelimit()) - pr_err("share pool: invalid input uva %pK in unshare uva\n", (void *)uva); + pr_err("share pool: invalid input uva %pK in unshare uva\n", + (void *)uva); goto out_unlock; } } @@ -1904,7 +1926,6 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp if (printk_ratelimit()) pr_info("share pool: no need to unshare uva(to task), " "target process not found or do_exit\n"); - ret = -EINVAL; rcu_read_unlock(); sp_dump_stack(); goto out_drop_area; @@ -1912,35 +1933,51 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp get_task_struct(tsk); rcu_read_unlock();
- if (!spa->mm || - (current->mm && (current->mm != tsk->mm || tsk->mm != spa->mm))) { + if (!spa->mm) { if (printk_ratelimit()) pr_err("share pool: unshare uva(to task) failed, " - "wrong pid or invalid spa\n"); + "none spa owner\n"); ret = -EINVAL; + put_task_struct(tsk); goto out_drop_area; }
- if (spa->mm != tsk->mm) { + /* current thread may be exiting in a multithread process */ + mm = get_task_mm(tsk->group_leader); + if (!mm) { + if (printk_ratelimit()) + pr_info("share pool: no need to unshare uva(to task), " + "target process mm is exiting\n"); + put_task_struct(tsk); + goto out_drop_area; + } + + if (spa->mm != mm) { if (printk_ratelimit()) pr_err("share pool: unshare uva(to task) failed, " "spa not belong to the task\n"); ret = -EINVAL; + mmput(mm); + put_task_struct(tsk); goto out_drop_area; }
- if (!mmget_not_zero(tsk->mm)) { - put_task_struct(tsk); + /* alway allow kthread and dvpp channel destroy procedure */ + if (current->mm && current->mm != mm) { if (printk_ratelimit()) - pr_info("share pool: no need to unshare uva(to task), " - "target process mm is not existing\n"); - sp_dump_stack(); + pr_err("share pool: unshare uva(to task failed, caller " + "process %d not match target process %d\n)", + current->pid, pid); + ret = -EINVAL; + mmput(mm); + put_task_struct(tsk); goto out_drop_area; } - down_write(&tsk->mm->mmap_sem); + + down_write(&mm->mmap_sem); ret = do_munmap(tsk->mm, uva_aligned, size_aligned, NULL); - up_write(&tsk->mm->mmap_sem); - mmput(tsk->mm); + up_write(&mm->mmap_sem); + mmput(mm); if (ret) { /* we are not supposed to fail */ pr_err("share pool: failed to unmap VA %pK when munmap in unshare uva\n", @@ -1948,7 +1985,7 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp } put_task_struct(tsk); } else if (spa->type == SPA_TYPE_K2SPG) { - if (!spa->spg || spg_id == SPG_ID_NONE) { + if (spg_id < 0) { if (printk_ratelimit()) pr_err("share pool: unshare uva(to group) failed, " "invalid spg id %d\n", spg_id); @@ -1956,24 +1993,15 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp goto out_drop_area; }
- spg = __sp_find_spg(pid, SPG_ID_DEFAULT); - if (!spg_valid(spg)) { + if (!spg_valid(spa->spg)) { if (printk_ratelimit()) - pr_err("share pool: unshare uva(to group) invalid pid, " - "process not in sp group or group is dead\n"); - ret = -EINVAL; - goto out_drop_area; - } - - if (spa->spg != spg) { - if (printk_ratelimit()) - pr_err("share pool: unshare uva(to group) failed, " - "spa not belong to the group\n"); - ret = -EINVAL; + pr_info("share pool: no need to unshare uva(to group), " + "spa doesn't belong to a sp group or group is dead\n"); goto out_drop_area; }
- if (current->mm && current->mm->sp_group != spg) { + /* alway allow kthread and dvpp channel destroy procedure */ + if (current->mm && current->mm->sp_group != spa->spg) { if (printk_ratelimit()) pr_err("share pool: unshare uva(to group) failed, " "caller process doesn't belong to target group\n"); @@ -1981,7 +2009,7 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp goto out_drop_area; }
- __sp_free(spg, uva_aligned, size_aligned, NULL); + __sp_free(spa->spg, uva_aligned, size_aligned, NULL); }
if (!ret) {
From: Zhou Guanghui zhouguanghui1@huawei.com
of some abnormal branches
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
1. sp_group_add_task: when spg invalid, low 32bits of pointer spg will be returned. This will be considered a correct spg id.
2.sp_alloc: The error branch goto out, then sp_mutex will be unlocked incorrectly(since not be locked).
Signed-off-by: Zhou Guanghui zhouguanghui1@huawei.com Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index 32c3250795e9..2d0e4b6fe4b7 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -516,10 +516,15 @@ int sp_group_add_task(int pid, int spg_id) goto out_unlock;
spg = find_or_alloc_sp_group(spg_id); - if (IS_ERR(spg) || !spg_valid(spg)) { + if (IS_ERR(spg)) { ret = PTR_ERR(spg); goto out_put_task; } + + if (!spg_valid(spg)) { + ret = -ENODEV; + goto out_put_task; + } atomic_inc(&spg->use_count);
/* access control permission check */ @@ -1191,8 +1196,7 @@ void *sp_alloc(unsigned long size, unsigned long sp_flags, int spg_id) if (ret < 0 && (ret != -EEXIST)) { pr_err("share pool: allocation failed due to add group error %d in DVPP pass through scenario", ret); - p = ERR_PTR(ret); - goto out; + return ERR_PTR(ret); } mutex_lock(&sp_mutex); spg = current->mm->sp_group;
From: Tang Yizhou tangyizhou@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
In fact, input parameters *size*, *pid* and *spg_id* of sp_unshare_uva() now can be treated as useless. They will be reserved to support multiple sp group in the future.
Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 47 +++++++++++------------------------------------ 1 file changed, 11 insertions(+), 36 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index 2d0e4b6fe4b7..1ff071a97edb 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -1848,9 +1848,8 @@ void *sp_make_share_u2k(unsigned long uva, unsigned long size, int pid) EXPORT_SYMBOL_GPL(sp_make_share_u2k);
/* - * Input parameters uva and spg_id are now useless. spg_id will be useful when - * supporting a process in multiple sp groups. - * Always use process pid. Using thread pid is hard to check sanity. + * Input parameters uva, pid and spg_id are now useless. spg_id will be useful + * when supporting a process in multiple sp groups. * * Procedure of unshare uva must be compatible with: * @@ -1868,7 +1867,6 @@ EXPORT_SYMBOL_GPL(sp_make_share_u2k); static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int spg_id) { int ret = 0; - struct task_struct *tsk; struct mm_struct *mm; struct sp_area *spa; unsigned long uva_aligned; @@ -1924,35 +1922,26 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp goto out_drop_area; }
- rcu_read_lock(); - tsk = find_task_by_vpid(pid); - if (!tsk || !tsk->mm || (tsk->flags & PF_EXITING)) { - if (printk_ratelimit()) - pr_info("share pool: no need to unshare uva(to task), " - "target process not found or do_exit\n"); - rcu_read_unlock(); - sp_dump_stack(); - goto out_drop_area; - } - get_task_struct(tsk); - rcu_read_unlock(); - if (!spa->mm) { if (printk_ratelimit()) pr_err("share pool: unshare uva(to task) failed, " "none spa owner\n"); ret = -EINVAL; - put_task_struct(tsk); goto out_drop_area; }
- /* current thread may be exiting in a multithread process */ - mm = get_task_mm(tsk->group_leader); + /* + * 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) { if (printk_ratelimit()) pr_info("share pool: no need to unshare uva(to task), " "target process mm is exiting\n"); - put_task_struct(tsk); goto out_drop_area; }
@@ -1962,24 +1951,11 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp "spa not belong to the task\n"); ret = -EINVAL; mmput(mm); - put_task_struct(tsk); - goto out_drop_area; - } - - /* alway allow kthread and dvpp channel destroy procedure */ - if (current->mm && current->mm != mm) { - if (printk_ratelimit()) - pr_err("share pool: unshare uva(to task failed, caller " - "process %d not match target process %d\n)", - current->pid, pid); - ret = -EINVAL; - mmput(mm); - put_task_struct(tsk); goto out_drop_area; }
down_write(&mm->mmap_sem); - ret = do_munmap(tsk->mm, uva_aligned, size_aligned, NULL); + ret = do_munmap(mm, uva_aligned, size_aligned, NULL); up_write(&mm->mmap_sem); mmput(mm); if (ret) { @@ -1987,7 +1963,6 @@ static int sp_unshare_uva(unsigned long uva, unsigned long size, int pid, int sp pr_err("share pool: failed to unmap VA %pK when munmap in unshare uva\n", (void *)uva_aligned); } - put_task_struct(tsk); } else if (spa->type == SPA_TYPE_K2SPG) { if (spg_id < 0) { if (printk_ratelimit())
From: Tang Yizhou tangyizhou@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
------------------------------------------------- We have two independent memory regions: normal 8T region and 16G DVPP region. When an spa is freed, new cache node found by rb_prev() may be located in the other region.
When this happens, cached_vstart should be changed, otherwise the next new allocated spa may be in the wrong region.
Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/mm/share_pool.c b/mm/share_pool.c index 1ff071a97edb..d96f76b45b2a 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -164,6 +164,7 @@ struct sp_area { unsigned long va_start; unsigned long va_end; /* va_end always align to hugepage */ unsigned long real_size; /* real size with alignment */ + unsigned long region_vstart; /* belong to normal region or DVPP region */ bool is_hugepage; atomic_t use_count; /* How many vmas use this VA region */ struct rb_node rb_node; /* address sorted rbtree */ @@ -863,6 +864,7 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, spa->va_start = addr; spa->va_end = addr + size_align; spa->real_size = size; + spa->region_vstart = vstart; spa->is_hugepage = (flags & SP_HUGEPAGE); spa->spg = spg; atomic_set(&spa->use_count, 1); @@ -937,6 +939,15 @@ static void sp_free_area(struct sp_area *spa) cache = rb_entry(free_sp_area_cache, struct sp_area, rb_node); if (spa->va_start <= cache->va_start) { free_sp_area_cache = rb_prev(&spa->rb_node); + /* + * the new cache node may be changed to another region, + * i.e. from DVPP region to normal region + */ + if (free_sp_area_cache) { + cache = rb_entry(free_sp_area_cache, + struct sp_area, rb_node); + cached_vstart = cache->region_vstart; + } /* * We don't try to update cached_hole_size, * but it won't go very wrong.
From: Tang Yizhou tangyizhou@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
------------------------------------------------- Now spa overview in /proc/sharepool/spa_stat supports two new data. Spa dvpp size: physical memory usage in DVPP region. Spa dvpp va size: virtual memory usage in DVPP region.
Signed-off-by: Tang Yizhou tangyizhou@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- mm/share_pool.c | 52 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 15 deletions(-)
diff --git a/mm/share_pool.c b/mm/share_pool.c index d96f76b45b2a..23195a76c2c6 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -50,6 +50,7 @@ #define ESPGMMEXIT 4000
#define byte2kb(size) ((size) / 1024) +#define byte2mb(size) ((size) / 1024 / 1024)
/* mdc scene hack */ int enable_mdc_default_group; @@ -135,6 +136,8 @@ struct sp_spa_stat { unsigned long alloc_size; unsigned long k2u_task_size; unsigned long k2u_spg_size; + unsigned long dvpp_size; + unsigned long dvpp_va_size; };
static struct sp_spa_stat spa_stat = {0}; @@ -165,6 +168,7 @@ struct sp_area { unsigned long va_end; /* va_end always align to hugepage */ unsigned long real_size; /* real size with alignment */ unsigned long region_vstart; /* belong to normal region or DVPP region */ + unsigned long flags; bool is_hugepage; atomic_t use_count; /* How many vmas use this VA region */ struct rb_node rb_node; /* address sorted rbtree */ @@ -193,14 +197,8 @@ static struct file *spa_file(struct sp_area *spa) }
/* the caller should hold sp_area_lock */ -static int spa_inc_usage(enum spa_type type, unsigned long size) +static int spa_inc_usage(enum spa_type type, unsigned long size, bool is_dvpp) { - /* - * all the calculations won't overflow due to system limitation and - * parameter checking in sp_alloc_area() - */ - spa_stat.total_num += 1; - spa_stat.total_size += size; switch (type) { case SPA_TYPE_ALLOC: spa_stat.alloc_num += 1; @@ -218,11 +216,23 @@ static int spa_inc_usage(enum spa_type type, unsigned long size) /* usually impossible, perhaps a developer's mistake */ return -EINVAL; } + + if (is_dvpp) { + spa_stat.dvpp_size += size; + spa_stat.dvpp_va_size += PMD_ALIGN(size); + } + + /* + * all the calculations won't overflow due to system limitation and + * parameter checking in sp_alloc_area() + */ + spa_stat.total_num += 1; + spa_stat.total_size += size; return 0; }
/* the caller should hold sp_area_lock */ -static int spa_dec_usage(enum spa_type type, unsigned long size) +static int spa_dec_usage(enum spa_type type, unsigned long size, bool is_dvpp) { switch (type) { case SPA_TYPE_ALLOC: @@ -239,9 +249,14 @@ static int spa_dec_usage(enum spa_type type, unsigned long size) break; default: /* usually impossible, perhaps a developer's mistake */ - spin_unlock(&sp_area_lock); return -EINVAL; } + + if (is_dvpp) { + spa_stat.dvpp_size -= size; + spa_stat.dvpp_va_size -= PMD_ALIGN(size); + } + spa_stat.total_num -= 1; spa_stat.total_size -= size; return 0; @@ -760,7 +775,7 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, unsigned long vstart = MMAP_SHARE_POOL_START; unsigned long vend = MMAP_SHARE_POOL_16G_START; unsigned long addr; - unsigned long size_align = ALIGN(size, 1 << 21); /* align to 2M */ + unsigned long size_align = PMD_ALIGN(size); /* va aligned to 2M */
if ((flags & SP_DVPP)) { if (host_svm_sp_enable == false) { @@ -865,13 +880,14 @@ static struct sp_area *sp_alloc_area(unsigned long size, unsigned long flags, spa->va_end = addr + size_align; spa->real_size = size; spa->region_vstart = vstart; + spa->flags = flags; spa->is_hugepage = (flags & SP_HUGEPAGE); spa->spg = spg; atomic_set(&spa->use_count, 1); spa->type = type; spa->mm = NULL;
- if (spa_inc_usage(type, size)) { + if (spa_inc_usage(type, size, (flags & SP_DVPP))) { err = ERR_PTR(-EINVAL); goto error; } @@ -955,7 +971,7 @@ static void sp_free_area(struct sp_area *spa) } }
- spa_dec_usage(spa->type, spa->real_size); /* won't fail */ + spa_dec_usage(spa->type, spa->real_size, (spa->flags & SP_DVPP)); /* won't fail */ if (spa->spg) { atomic_dec(&spa->spg->spa_num); atomic64_sub(spa->real_size, &spa->spg->size); @@ -2321,6 +2337,7 @@ static void spa_overview_show(struct seq_file *seq) { unsigned int total_num, alloc_num, k2u_task_num, k2u_spg_num; unsigned long total_size, alloc_size, k2u_task_size, k2u_spg_size; + unsigned long dvpp_size, dvpp_va_size;
spin_lock(&sp_area_lock); total_num = spa_stat.total_num; @@ -2331,6 +2348,8 @@ static void spa_overview_show(struct seq_file *seq) alloc_size = spa_stat.alloc_size; k2u_task_size = spa_stat.k2u_task_size; k2u_spg_size = spa_stat.k2u_spg_size; + dvpp_size = spa_stat.dvpp_size; + dvpp_va_size = spa_stat.dvpp_va_size; spin_unlock(&sp_area_lock);
seq_printf(seq, "Spa total num %u.\n", total_num); @@ -2340,6 +2359,8 @@ static void spa_overview_show(struct seq_file *seq) seq_printf(seq, "Spa alloc size: %13lu KB\n", byte2kb(alloc_size)); seq_printf(seq, "Spa k2u(task) size: %13lu KB\n", byte2kb(k2u_task_size)); seq_printf(seq, "Spa k2u(spg) size: %13lu KB\n", byte2kb(k2u_spg_size)); + seq_printf(seq, "Spa dvpp size: %13lu KB\n", byte2kb(dvpp_size)); + seq_printf(seq, "Spa dvpp va size: %13lu MB\n", byte2mb(dvpp_va_size)); seq_printf(seq, "\n"); }
@@ -2358,12 +2379,13 @@ static int idr_spg_stat_cb(int id, void *p, void *data)
static void spg_overview_show(struct seq_file *seq) { + seq_printf(seq, "Share pool total size: %13ld KB, spa total num: %d.\n", + byte2kb(atomic64_read(&spg_stat.spa_total_size)), + atomic_read(&spg_stat.spa_total_num)); mutex_lock(&sp_mutex); idr_for_each(&sp_group_idr, idr_spg_stat_cb, seq); mutex_unlock(&sp_mutex); - seq_printf(seq, "Share pool total size: %13ld KB, spa total num: %d.\n\n", - byte2kb(atomic64_read(&spg_stat.spa_total_size)), - atomic_read(&spg_stat.spa_total_num)); + seq_printf(seq, "\n"); }
static int spa_stat_show(struct seq_file *seq, void *offset)