Merge "ANDROID: sound: rawmidi: Hold lock around realloc"
This commit is contained in:
commit
6fa93fc89f
2 changed files with 40 additions and 5 deletions
|
@ -78,6 +78,7 @@ struct snd_rawmidi_runtime {
|
||||||
size_t xruns; /* over/underruns counter */
|
size_t xruns; /* over/underruns counter */
|
||||||
/* misc */
|
/* misc */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
struct mutex realloc_mutex;
|
||||||
wait_queue_head_t sleep;
|
wait_queue_head_t sleep;
|
||||||
/* event handler (new bytes, input only) */
|
/* event handler (new bytes, input only) */
|
||||||
void (*event)(struct snd_rawmidi_substream *substream);
|
void (*event)(struct snd_rawmidi_substream *substream);
|
||||||
|
|
|
@ -115,6 +115,7 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
runtime->substream = substream;
|
runtime->substream = substream;
|
||||||
spin_lock_init(&runtime->lock);
|
spin_lock_init(&runtime->lock);
|
||||||
|
mutex_init(&runtime->realloc_mutex);
|
||||||
init_waitqueue_head(&runtime->sleep);
|
init_waitqueue_head(&runtime->sleep);
|
||||||
INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
|
INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
|
||||||
runtime->event = NULL;
|
runtime->event = NULL;
|
||||||
|
@ -636,7 +637,9 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
|
||||||
struct snd_rawmidi_params * params)
|
struct snd_rawmidi_params * params)
|
||||||
{
|
{
|
||||||
char *newbuf;
|
char *newbuf;
|
||||||
|
char *oldbuf;
|
||||||
struct snd_rawmidi_runtime *runtime = substream->runtime;
|
struct snd_rawmidi_runtime *runtime = substream->runtime;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (substream->append && substream->use_count > 1)
|
if (substream->append && substream->use_count > 1)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -648,13 +651,22 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (params->buffer_size != runtime->buffer_size) {
|
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);
|
GFP_KERNEL);
|
||||||
if (!newbuf)
|
if (!newbuf) {
|
||||||
|
mutex_unlock(&runtime->realloc_mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
spin_lock_irqsave(&runtime->lock, flags);
|
||||||
|
oldbuf = runtime->buffer;
|
||||||
runtime->buffer = newbuf;
|
runtime->buffer = newbuf;
|
||||||
runtime->buffer_size = params->buffer_size;
|
runtime->buffer_size = params->buffer_size;
|
||||||
runtime->avail = runtime->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;
|
runtime->avail_min = params->avail_min;
|
||||||
substream->active_sensing = !params->no_active_sensing;
|
substream->active_sensing = !params->no_active_sensing;
|
||||||
|
@ -666,7 +678,9 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
|
||||||
struct snd_rawmidi_params * params)
|
struct snd_rawmidi_params * params)
|
||||||
{
|
{
|
||||||
char *newbuf;
|
char *newbuf;
|
||||||
|
char *oldbuf;
|
||||||
struct snd_rawmidi_runtime *runtime = substream->runtime;
|
struct snd_rawmidi_runtime *runtime = substream->runtime;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
snd_rawmidi_drain_input(substream);
|
snd_rawmidi_drain_input(substream);
|
||||||
if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
|
if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
|
||||||
|
@ -676,12 +690,21 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (params->buffer_size != runtime->buffer_size) {
|
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);
|
GFP_KERNEL);
|
||||||
if (!newbuf)
|
if (!newbuf) {
|
||||||
|
mutex_unlock(&runtime->realloc_mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
spin_lock_irqsave(&runtime->lock, flags);
|
||||||
|
oldbuf = runtime->buffer;
|
||||||
runtime->buffer = newbuf;
|
runtime->buffer = newbuf;
|
||||||
runtime->buffer_size = params->buffer_size;
|
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;
|
runtime->avail_min = params->avail_min;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -954,6 +977,8 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
|
||||||
unsigned long appl_ptr;
|
unsigned long appl_ptr;
|
||||||
|
|
||||||
spin_lock_irqsave(&runtime->lock, flags);
|
spin_lock_irqsave(&runtime->lock, flags);
|
||||||
|
if (userbuf)
|
||||||
|
mutex_lock(&runtime->realloc_mutex);
|
||||||
while (count > 0 && runtime->avail) {
|
while (count > 0 && runtime->avail) {
|
||||||
count1 = runtime->buffer_size - runtime->appl_ptr;
|
count1 = runtime->buffer_size - runtime->appl_ptr;
|
||||||
if (count1 > count)
|
if (count1 > count)
|
||||||
|
@ -973,6 +998,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
|
||||||
spin_unlock_irqrestore(&runtime->lock, flags);
|
spin_unlock_irqrestore(&runtime->lock, flags);
|
||||||
if (copy_to_user(userbuf + result,
|
if (copy_to_user(userbuf + result,
|
||||||
runtime->buffer + appl_ptr, count1)) {
|
runtime->buffer + appl_ptr, count1)) {
|
||||||
|
mutex_unlock(&runtime->realloc_mutex);
|
||||||
return result > 0 ? result : -EFAULT;
|
return result > 0 ? result : -EFAULT;
|
||||||
}
|
}
|
||||||
spin_lock_irqsave(&runtime->lock, flags);
|
spin_lock_irqsave(&runtime->lock, flags);
|
||||||
|
@ -981,6 +1007,8 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
|
||||||
count -= count1;
|
count -= count1;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&runtime->lock, flags);
|
spin_unlock_irqrestore(&runtime->lock, flags);
|
||||||
|
if (userbuf)
|
||||||
|
mutex_unlock(&runtime->realloc_mutex);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1245,10 +1273,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
|
if (userbuf)
|
||||||
|
mutex_lock(&runtime->realloc_mutex);
|
||||||
spin_lock_irqsave(&runtime->lock, flags);
|
spin_lock_irqsave(&runtime->lock, flags);
|
||||||
if (substream->append) {
|
if (substream->append) {
|
||||||
if ((long)runtime->avail < count) {
|
if ((long)runtime->avail < count) {
|
||||||
spin_unlock_irqrestore(&runtime->lock, flags);
|
spin_unlock_irqrestore(&runtime->lock, flags);
|
||||||
|
if (userbuf)
|
||||||
|
mutex_unlock(&runtime->realloc_mutex);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1284,6 +1316,8 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
|
||||||
__end:
|
__end:
|
||||||
count1 = runtime->avail < runtime->buffer_size;
|
count1 = runtime->avail < runtime->buffer_size;
|
||||||
spin_unlock_irqrestore(&runtime->lock, flags);
|
spin_unlock_irqrestore(&runtime->lock, flags);
|
||||||
|
if (userbuf)
|
||||||
|
mutex_unlock(&runtime->realloc_mutex);
|
||||||
if (count1)
|
if (count1)
|
||||||
snd_rawmidi_output_trigger(substream, 1);
|
snd_rawmidi_output_trigger(substream, 1);
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Add table
Reference in a new issue