@@ -120,6 +120,17 @@ static void snd_rawmidi_input_event_work(struct work_struct *work)
120120 runtime -> event (runtime -> substream );
121121}
122122
123+ /* buffer refcount management: call with runtime->lock held */
124+ static inline void snd_rawmidi_buffer_ref (struct snd_rawmidi_runtime * runtime )
125+ {
126+ runtime -> buffer_ref ++ ;
127+ }
128+
129+ static inline void snd_rawmidi_buffer_unref (struct snd_rawmidi_runtime * runtime )
130+ {
131+ runtime -> buffer_ref -- ;
132+ }
133+
123134static int snd_rawmidi_runtime_create (struct snd_rawmidi_substream * substream )
124135{
125136 struct snd_rawmidi_runtime * runtime ;
@@ -669,6 +680,11 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
669680 if (!newbuf )
670681 return - ENOMEM ;
671682 spin_lock_irq (& runtime -> lock );
683+ if (runtime -> buffer_ref ) {
684+ spin_unlock_irq (& runtime -> lock );
685+ kvfree (newbuf );
686+ return - EBUSY ;
687+ }
672688 oldbuf = runtime -> buffer ;
673689 runtime -> buffer = newbuf ;
674690 runtime -> buffer_size = params -> buffer_size ;
@@ -1019,8 +1035,10 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
10191035 long result = 0 , count1 ;
10201036 struct snd_rawmidi_runtime * runtime = substream -> runtime ;
10211037 unsigned long appl_ptr ;
1038+ int err = 0 ;
10221039
10231040 spin_lock_irqsave (& runtime -> lock , flags );
1041+ snd_rawmidi_buffer_ref (runtime );
10241042 while (count > 0 && runtime -> avail ) {
10251043 count1 = runtime -> buffer_size - runtime -> appl_ptr ;
10261044 if (count1 > count )
@@ -1039,16 +1057,19 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
10391057 if (userbuf ) {
10401058 spin_unlock_irqrestore (& runtime -> lock , flags );
10411059 if (copy_to_user (userbuf + result ,
1042- runtime -> buffer + appl_ptr , count1 )) {
1043- return result > 0 ? result : - EFAULT ;
1044- }
1060+ runtime -> buffer + appl_ptr , count1 ))
1061+ err = - EFAULT ;
10451062 spin_lock_irqsave (& runtime -> lock , flags );
1063+ if (err )
1064+ goto out ;
10461065 }
10471066 result += count1 ;
10481067 count -= count1 ;
10491068 }
1069+ out :
1070+ snd_rawmidi_buffer_unref (runtime );
10501071 spin_unlock_irqrestore (& runtime -> lock , flags );
1051- return result ;
1072+ return result > 0 ? result : err ;
10521073}
10531074
10541075long snd_rawmidi_kernel_read (struct snd_rawmidi_substream * substream ,
@@ -1342,6 +1363,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
13421363 return - EAGAIN ;
13431364 }
13441365 }
1366+ snd_rawmidi_buffer_ref (runtime );
13451367 while (count > 0 && runtime -> avail > 0 ) {
13461368 count1 = runtime -> buffer_size - runtime -> appl_ptr ;
13471369 if (count1 > count )
@@ -1373,6 +1395,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
13731395 }
13741396 __end :
13751397 count1 = runtime -> avail < runtime -> buffer_size ;
1398+ snd_rawmidi_buffer_unref (runtime );
13761399 spin_unlock_irqrestore (& runtime -> lock , flags );
13771400 if (count1 )
13781401 snd_rawmidi_output_trigger (substream , 1 );
0 commit comments