int vec_set_vector_length(struct task_struct *task, enum vec_type type,
                          unsigned long vl, unsigned long flags)
 {
+       bool free_sme = false;
+
        if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT |
                                     PR_SVE_SET_VL_ONEXEC))
                return -EINVAL;
                task->thread.fp_type = FP_STATE_FPSIMD;
        }
 
-       if (system_supports_sme() && type == ARM64_VEC_SME) {
-               task->thread.svcr &= ~(SVCR_SM_MASK |
-                                      SVCR_ZA_MASK);
-               clear_thread_flag(TIF_SME);
+       if (system_supports_sme()) {
+               if (type == ARM64_VEC_SME ||
+                   !(task->thread.svcr & (SVCR_SM_MASK | SVCR_ZA_MASK))) {
+                       /*
+                        * We are changing the SME VL or weren't using
+                        * SME anyway, discard the state and force a
+                        * reallocation.
+                        */
+                       task->thread.svcr &= ~(SVCR_SM_MASK |
+                                              SVCR_ZA_MASK);
+                       clear_thread_flag(TIF_SME);
+                       free_sme = true;
+               }
        }
 
        if (task == current)
                put_cpu_fpsimd_context();
 
        /*
-        * Force reallocation of task SVE and SME state to the correct
-        * size on next use:
+        * Free the changed states if they are not in use, SME will be
+        * reallocated to the correct size on next use and we just
+        * allocate SVE now in case it is needed for use in streaming
+        * mode.
         */
-       sve_free(task);
-       if (system_supports_sme() && type == ARM64_VEC_SME)
+       if (system_supports_sve()) {
+               sve_free(task);
+               sve_alloc(task, true);
+       }
+
+       if (free_sme)
                sme_free(task);
 
        task_set_vl(task, type, vl);