[PATCH v 1/2] riscv: ptrace: Optimize the allocation of vector regset

Yong-Xuan Wang posted 2 patches 10 hours ago
[PATCH v 1/2] riscv: ptrace: Optimize the allocation of vector regset
Posted by Yong-Xuan Wang 10 hours ago
The vector regset uses the maximum possible vlen value to estimate the
.n field. But not all the hardwares support the maximum vlen. Linux
might wastes time to prepare a large memory buffer(about 2^6 pages) for
the vector regset.

The regset can only copy vector registers when the process are using
vector. Add .active callback and determine the n field of vector regset
in riscv_v_setup_ctx_cache() doesn't affect the ptrace syscall and
coredump. It can avoid oversized allocations and better matches real
hardware limits.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Greentime Hu <greentime.hu@sifive.com>
---
 arch/riscv/include/asm/vector.h |  1 +
 arch/riscv/kernel/ptrace.c      | 24 +++++++++++++++++++++---
 arch/riscv/kernel/vector.c      |  2 ++
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index b61786d43c20..e7aa449368ad 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -51,6 +51,7 @@ void put_cpu_vector_context(void);
 void riscv_v_thread_free(struct task_struct *tsk);
 void __init riscv_v_setup_ctx_cache(void);
 void riscv_v_thread_alloc(struct task_struct *tsk);
+void __init update_regset_vector_info(unsigned long size);
 
 static inline u32 riscv_v_flags(void)
 {
diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
index 8e86305831ea..e6272d74572f 100644
--- a/arch/riscv/kernel/ptrace.c
+++ b/arch/riscv/kernel/ptrace.c
@@ -153,6 +153,17 @@ static int riscv_vr_set(struct task_struct *target,
 				 0, riscv_v_vsize);
 	return ret;
 }
+
+static int riscv_vr_active(struct task_struct *target, const struct user_regset *regset)
+{
+	if (!(has_vector() || has_xtheadvector()))
+		return -ENODEV;
+
+	if (!riscv_v_vstate_query(task_pt_regs(target)))
+		return 0;
+
+	return regset->n;
+}
 #endif
 
 #ifdef CONFIG_RISCV_ISA_SUPM
@@ -184,7 +195,7 @@ static int tagged_addr_ctrl_set(struct task_struct *target,
 }
 #endif
 
-static const struct user_regset riscv_user_regset[] = {
+static struct user_regset riscv_user_regset[] __ro_after_init = {
 	[REGSET_X] = {
 		USER_REGSET_NOTE_TYPE(PRSTATUS),
 		.n = ELF_NGREG,
@@ -207,11 +218,10 @@ static const struct user_regset riscv_user_regset[] = {
 	[REGSET_V] = {
 		USER_REGSET_NOTE_TYPE(RISCV_VECTOR),
 		.align = 16,
-		.n = ((32 * RISCV_MAX_VLENB) +
-		      sizeof(struct __riscv_v_regset_state)) / sizeof(__u32),
 		.size = sizeof(__u32),
 		.regset_get = riscv_vr_get,
 		.set = riscv_vr_set,
+		.active = riscv_vr_active,
 	},
 #endif
 #ifdef CONFIG_RISCV_ISA_SUPM
@@ -233,6 +243,14 @@ static const struct user_regset_view riscv_user_native_view = {
 	.n = ARRAY_SIZE(riscv_user_regset),
 };
 
+#ifdef CONFIG_RISCV_ISA_V
+void __init update_regset_vector_info(unsigned long size)
+{
+	riscv_user_regset[REGSET_V].n = (size + sizeof(struct __riscv_v_regset_state)) /
+					sizeof(__u32);
+}
+#endif
+
 struct pt_regs_offset {
 	const char *name;
 	int offset;
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index 901e67adf576..3ed071dab9d8 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -66,6 +66,8 @@ void __init riscv_v_setup_ctx_cache(void)
 	if (!(has_vector() || has_xtheadvector()))
 		return;
 
+	update_regset_vector_info(riscv_v_vsize);
+
 	riscv_v_user_cachep = kmem_cache_create_usercopy("riscv_vector_ctx",
 							 riscv_v_vsize, 16, SLAB_PANIC,
 							 0, riscv_v_vsize, NULL);
-- 
2.43.0
Re: [PATCH v 1/2] riscv: ptrace: Optimize the allocation of vector regset
Posted by Andy Chiu 6 hours ago
Hi Yong-Xuan,

On Wed, Oct 1, 2025 at 6:15 AM Yong-Xuan Wang <yongxuan.wang@sifive.com> wrote:
>
> The vector regset uses the maximum possible vlen value to estimate the
> .n field. But not all the hardwares support the maximum vlen. Linux
> might wastes time to prepare a large memory buffer(about 2^6 pages) for
> the vector regset.
>
> The regset can only copy vector registers when the process are using
> vector. Add .active callback and determine the n field of vector regset
> in riscv_v_setup_ctx_cache() doesn't affect the ptrace syscall and
> coredump. It can avoid oversized allocations and better matches real
> hardware limits.
>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
> Reviewed-by: Greentime Hu <greentime.hu@sifive.com>

Reviewed-by: Andy Chiu <andybnac@gmail.com>

Thanks,
Andy

> ---
>  arch/riscv/include/asm/vector.h |  1 +
>  arch/riscv/kernel/ptrace.c      | 24 +++++++++++++++++++++---
>  arch/riscv/kernel/vector.c      |  2 ++
>  3 files changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
> index b61786d43c20..e7aa449368ad 100644
> --- a/arch/riscv/include/asm/vector.h
> +++ b/arch/riscv/include/asm/vector.h
> @@ -51,6 +51,7 @@ void put_cpu_vector_context(void);
>  void riscv_v_thread_free(struct task_struct *tsk);
>  void __init riscv_v_setup_ctx_cache(void);
>  void riscv_v_thread_alloc(struct task_struct *tsk);
> +void __init update_regset_vector_info(unsigned long size);
>
>  static inline u32 riscv_v_flags(void)
>  {
> diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
> index 8e86305831ea..e6272d74572f 100644
> --- a/arch/riscv/kernel/ptrace.c
> +++ b/arch/riscv/kernel/ptrace.c
> @@ -153,6 +153,17 @@ static int riscv_vr_set(struct task_struct *target,
>                                  0, riscv_v_vsize);
>         return ret;
>  }
> +
> +static int riscv_vr_active(struct task_struct *target, const struct user_regset *regset)
> +{
> +       if (!(has_vector() || has_xtheadvector()))
> +               return -ENODEV;
> +
> +       if (!riscv_v_vstate_query(task_pt_regs(target)))
> +               return 0;
> +
> +       return regset->n;
> +}
>  #endif
>
>  #ifdef CONFIG_RISCV_ISA_SUPM
> @@ -184,7 +195,7 @@ static int tagged_addr_ctrl_set(struct task_struct *target,
>  }
>  #endif
>
> -static const struct user_regset riscv_user_regset[] = {
> +static struct user_regset riscv_user_regset[] __ro_after_init = {
>         [REGSET_X] = {
>                 USER_REGSET_NOTE_TYPE(PRSTATUS),
>                 .n = ELF_NGREG,
> @@ -207,11 +218,10 @@ static const struct user_regset riscv_user_regset[] = {
>         [REGSET_V] = {
>                 USER_REGSET_NOTE_TYPE(RISCV_VECTOR),
>                 .align = 16,
> -               .n = ((32 * RISCV_MAX_VLENB) +
> -                     sizeof(struct __riscv_v_regset_state)) / sizeof(__u32),
>                 .size = sizeof(__u32),
>                 .regset_get = riscv_vr_get,
>                 .set = riscv_vr_set,
> +               .active = riscv_vr_active,
>         },
>  #endif
>  #ifdef CONFIG_RISCV_ISA_SUPM
> @@ -233,6 +243,14 @@ static const struct user_regset_view riscv_user_native_view = {
>         .n = ARRAY_SIZE(riscv_user_regset),
>  };
>
> +#ifdef CONFIG_RISCV_ISA_V
> +void __init update_regset_vector_info(unsigned long size)
> +{
> +       riscv_user_regset[REGSET_V].n = (size + sizeof(struct __riscv_v_regset_state)) /
> +                                       sizeof(__u32);
> +}
> +#endif
> +
>  struct pt_regs_offset {
>         const char *name;
>         int offset;
> diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
> index 901e67adf576..3ed071dab9d8 100644
> --- a/arch/riscv/kernel/vector.c
> +++ b/arch/riscv/kernel/vector.c
> @@ -66,6 +66,8 @@ void __init riscv_v_setup_ctx_cache(void)
>         if (!(has_vector() || has_xtheadvector()))
>                 return;
>
> +       update_regset_vector_info(riscv_v_vsize);
> +
>         riscv_v_user_cachep = kmem_cache_create_usercopy("riscv_vector_ctx",
>                                                          riscv_v_vsize, 16, SLAB_PANIC,
>                                                          0, riscv_v_vsize, NULL);
> --
> 2.43.0
>