--- zzzz-none-000/linux-4.4.60/sound/core/rawmidi.c 2017-04-08 07:53:53.000000000 +0000 +++ scorpion-7490-727/linux-4.4.60/sound/core/rawmidi.c 2021-02-04 17:41:59.000000000 +0000 @@ -115,6 +115,7 @@ return -ENOMEM; runtime->substream = substream; spin_lock_init(&runtime->lock); + mutex_init(&runtime->realloc_mutex); init_waitqueue_head(&runtime->sleep); INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; @@ -627,8 +628,10 @@ struct snd_rawmidi_params * params) { char *newbuf; + char *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; - + unsigned long flags; + if (substream->append && substream->use_count > 1) return -EBUSY; snd_rawmidi_drain_output(substream); @@ -639,13 +642,22 @@ return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, + mutex_lock(&runtime->realloc_mutex); + newbuf = __krealloc(runtime->buffer, params->buffer_size, GFP_KERNEL); - if (!newbuf) + if (!newbuf) { + mutex_unlock(&runtime->realloc_mutex); return -ENOMEM; + } + spin_lock_irqsave(&runtime->lock, flags); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; + spin_unlock_irqrestore(&runtime->lock, flags); + if (oldbuf != newbuf) + kfree(oldbuf); + mutex_unlock(&runtime->realloc_mutex); } runtime->avail_min = params->avail_min; substream->active_sensing = !params->no_active_sensing; @@ -657,7 +669,9 @@ struct snd_rawmidi_params * params) { char *newbuf; + char *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; snd_rawmidi_drain_input(substream); if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { @@ -667,12 +681,21 @@ return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, + mutex_lock(&runtime->realloc_mutex); + newbuf = __krealloc(runtime->buffer, params->buffer_size, GFP_KERNEL); - if (!newbuf) + if (!newbuf) { + mutex_unlock(&runtime->realloc_mutex); return -ENOMEM; + } + spin_lock_irqsave(&runtime->lock, flags); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; + spin_unlock_irqrestore(&runtime->lock, flags); + if (oldbuf != newbuf) + kfree(oldbuf); + mutex_unlock(&runtime->realloc_mutex); } runtime->avail_min = params->avail_min; return 0; @@ -944,6 +967,8 @@ struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long appl_ptr; + if (userbuf) + mutex_lock(&runtime->realloc_mutex); spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; @@ -964,6 +989,7 @@ spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + appl_ptr, count1)) { + mutex_unlock(&runtime->realloc_mutex); return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); @@ -972,6 +998,8 @@ count -= count1; } spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); return result; } @@ -1236,10 +1264,14 @@ return -EINVAL; result = 0; + if (userbuf) + mutex_lock(&runtime->realloc_mutex); spin_lock_irqsave(&runtime->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); return -EAGAIN; } } @@ -1275,6 +1307,8 @@ __end: count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); if (count1) snd_rawmidi_output_trigger(substream, 1); return result;