I don't know this code at all so probably this is dumb... I don't undestand how vec_set_vector_length() ensures that sme_state_size() stays in sync with the actual size allocated in sme_alloc()
arch/arm64/kernel/fpsimd.c 847 int vec_set_vector_length(struct task_struct *task, enum vec_type type, 848 unsigned long vl, unsigned long flags) ^^^ "vl" comes from the user and is 0-u16max.
849 { 850 if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT | 851 PR_SVE_SET_VL_ONEXEC)) 852 return -EINVAL; 853 854 if (!sve_vl_valid(vl))
valid values are '16-8192'
855 return -EINVAL; 856 857 /* 858 * Clamp to the maximum vector length that VL-agnostic code 859 * can work with. A flag may be assigned in the future to 860 * allow setting of larger vector lengths without confusing 861 * older software. 862 */ 863 if (vl > VL_ARCH_MAX) 864 vl = VL_ARCH_MAX;
Now 16-256'
865 866 vl = find_supported_vector_length(type, vl);
type is ARM64_VEC_SVE. I've looked at this function for a while and I don't see anything which ensures that "vl" is less than the current value.
867 868 if (flags & (PR_SVE_VL_INHERIT | 869 PR_SVE_SET_VL_ONEXEC)) 870 task_set_vl_onexec(task, type, vl); 871 else 872 /* Reset VL to system default on next exec: */ 873 task_set_vl_onexec(task, type, 0); 874 875 /* Only actually set the VL if not deferred: */ 876 if (flags & PR_SVE_SET_VL_ONEXEC)
Assume the PR_SVE_SET_VL_ONEXEC flag is not set.
877 goto out; 878 879 if (vl == task_get_vl(task, type))
This checks if the flag is == and if so we are done.
880 goto out; 881 882 /* 883 * To ensure the FPSIMD bits of the SVE vector registers are preserved, 884 * write any live register state back to task_struct, and convert to a 885 * regular FPSIMD thread. 886 */ 887 if (task == current) { 888 get_cpu_fpsimd_context(); 889 890 fpsimd_save(); 891 } 892 893 fpsimd_flush_task_state(task); 894 if (test_and_clear_tsk_thread_flag(task, TIF_SVE) || 895 thread_sm_enabled(&task->thread)) { 896 sve_to_fpsimd(task); 897 task->thread.fp_type = FP_STATE_FPSIMD; 898 } 899 900 if (system_supports_sme() && type == ARM64_VEC_SME) { 901 task->thread.svcr &= ~(SVCR_SM_MASK | 902 SVCR_ZA_MASK); 903 clear_thread_flag(TIF_SME); 904 } 905 906 if (task == current) 907 put_cpu_fpsimd_context(); 908 909 /* 910 * Force reallocation of task SVE and SME state to the correct 911 * size on next use: 912 */ 913 sve_free(task); 914 if (system_supports_sme() && type == ARM64_VEC_SME) 915 sme_free(task); 916 917 task_set_vl(task, type, vl);
"vl" is set here. This is fine if we are setting it to a smaller value, but if we are setting it to a larger value then I think we need to realloc the ->sme_state buffer.
When we call sme_alloc() it will say the buffer is already allocated and just zero out what we need for "vl", but the existing buffer is too small.
918 919 out: 920 update_tsk_thread_flag(task, vec_vl_inherit_flag(type), 922 923 return 0; 924 }
regards, dan carpenter