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;
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);
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;
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) {
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;
unsigned long appl_ptr;
spin_lock_irqsave(&runtime->lock, flags);
+ if (userbuf)
+ mutex_lock(&runtime->realloc_mutex);
while (count > 0 && runtime->avail) {
count1 = runtime->buffer_size - runtime->appl_ptr;
if (count1 > count)
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);
count -= count1;
}
spin_unlock_irqrestore(&runtime->lock, flags);
+ if (userbuf)
+ mutex_unlock(&runtime->realloc_mutex);
return result;
}
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;
}
}
__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;