@@ -52,7 +52,7 @@ struct irq_entry {
5252 bool sigio_workaround ;
5353};
5454
55- static DEFINE_SPINLOCK (irq_lock );
55+ static DEFINE_RAW_SPINLOCK (irq_lock );
5656static LIST_HEAD (active_fds );
5757static DECLARE_BITMAP (irqs_allocated , UM_LAST_SIGNAL_IRQ ) ;
5858static bool irqs_suspended ;
@@ -257,15 +257,14 @@ static struct irq_entry *get_irq_entry_by_fd(int fd)
257257 return NULL ;
258258}
259259
260- static void free_irq_entry (struct irq_entry * to_free , bool remove )
260+ static void remove_irq_entry (struct irq_entry * to_free , bool remove )
261261{
262262 if (!to_free )
263263 return ;
264264
265265 if (remove )
266266 os_del_epoll_fd (to_free -> fd );
267267 list_del (& to_free -> list );
268- kfree (to_free );
269268}
270269
271270static bool update_irq_entry (struct irq_entry * entry )
@@ -286,27 +285,30 @@ static bool update_irq_entry(struct irq_entry *entry)
286285 return false;
287286}
288287
289- static void update_or_free_irq_entry (struct irq_entry * entry )
288+ static struct irq_entry * update_or_remove_irq_entry (struct irq_entry * entry )
290289{
291- if (!update_irq_entry (entry ))
292- free_irq_entry (entry , false);
290+ if (update_irq_entry (entry ))
291+ return NULL ;
292+ remove_irq_entry (entry , false);
293+ return entry ;
293294}
294295
295296static int activate_fd (int irq , int fd , enum um_irq_type type , void * dev_id ,
296297 void (* timetravel_handler )(int , int , void * ,
297298 struct time_travel_event * ))
298299{
299- struct irq_entry * irq_entry ;
300+ struct irq_entry * irq_entry , * to_free = NULL ;
300301 int err , events = os_event_mask (type );
301302 unsigned long flags ;
302303
303304 err = os_set_fd_async (fd );
304305 if (err < 0 )
305306 goto out ;
306307
307- spin_lock_irqsave (& irq_lock , flags );
308+ raw_spin_lock_irqsave (& irq_lock , flags );
308309 irq_entry = get_irq_entry_by_fd (fd );
309310 if (irq_entry ) {
311+ already :
310312 /* cannot register the same FD twice with the same type */
311313 if (WARN_ON (irq_entry -> reg [type ].events )) {
312314 err = - EALREADY ;
@@ -316,11 +318,22 @@ static int activate_fd(int irq, int fd, enum um_irq_type type, void *dev_id,
316318 /* temporarily disable to avoid IRQ-side locking */
317319 os_del_epoll_fd (fd );
318320 } else {
319- irq_entry = kzalloc (sizeof (* irq_entry ), GFP_ATOMIC );
320- if (!irq_entry ) {
321- err = - ENOMEM ;
322- goto out_unlock ;
321+ struct irq_entry * new ;
322+
323+ /* don't restore interrupts */
324+ raw_spin_unlock (& irq_lock );
325+ new = kzalloc (sizeof (* irq_entry ), GFP_ATOMIC );
326+ if (!new ) {
327+ local_irq_restore (flags );
328+ return - ENOMEM ;
323329 }
330+ raw_spin_lock (& irq_lock );
331+ irq_entry = get_irq_entry_by_fd (fd );
332+ if (irq_entry ) {
333+ to_free = new ;
334+ goto already ;
335+ }
336+ irq_entry = new ;
324337 irq_entry -> fd = fd ;
325338 list_add_tail (& irq_entry -> list , & active_fds );
326339 maybe_sigio_broken (fd );
@@ -339,12 +352,11 @@ static int activate_fd(int irq, int fd, enum um_irq_type type, void *dev_id,
339352#endif
340353
341354 WARN_ON (!update_irq_entry (irq_entry ));
342- spin_unlock_irqrestore (& irq_lock , flags );
343-
344- return 0 ;
355+ err = 0 ;
345356out_unlock :
346- spin_unlock_irqrestore (& irq_lock , flags );
357+ raw_spin_unlock_irqrestore (& irq_lock , flags );
347358out :
359+ kfree (to_free );
348360 return err ;
349361}
350362
@@ -358,19 +370,20 @@ void free_irq_by_fd(int fd)
358370 struct irq_entry * to_free ;
359371 unsigned long flags ;
360372
361- spin_lock_irqsave (& irq_lock , flags );
373+ raw_spin_lock_irqsave (& irq_lock , flags );
362374 to_free = get_irq_entry_by_fd (fd );
363- free_irq_entry (to_free , true);
364- spin_unlock_irqrestore (& irq_lock , flags );
375+ remove_irq_entry (to_free , true);
376+ raw_spin_unlock_irqrestore (& irq_lock , flags );
377+ kfree (to_free );
365378}
366379EXPORT_SYMBOL (free_irq_by_fd );
367380
368381static void free_irq_by_irq_and_dev (unsigned int irq , void * dev )
369382{
370- struct irq_entry * entry ;
383+ struct irq_entry * entry , * to_free = NULL ;
371384 unsigned long flags ;
372385
373- spin_lock_irqsave (& irq_lock , flags );
386+ raw_spin_lock_irqsave (& irq_lock , flags );
374387 list_for_each_entry (entry , & active_fds , list ) {
375388 enum um_irq_type i ;
376389
@@ -386,12 +399,13 @@ static void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
386399
387400 os_del_epoll_fd (entry -> fd );
388401 reg -> events = 0 ;
389- update_or_free_irq_entry (entry );
402+ to_free = update_or_remove_irq_entry (entry );
390403 goto out ;
391404 }
392405 }
393406out :
394- spin_unlock_irqrestore (& irq_lock , flags );
407+ raw_spin_unlock_irqrestore (& irq_lock , flags );
408+ kfree (to_free );
395409}
396410
397411void deactivate_fd (int fd , int irqnum )
@@ -402,7 +416,7 @@ void deactivate_fd(int fd, int irqnum)
402416
403417 os_del_epoll_fd (fd );
404418
405- spin_lock_irqsave (& irq_lock , flags );
419+ raw_spin_lock_irqsave (& irq_lock , flags );
406420 entry = get_irq_entry_by_fd (fd );
407421 if (!entry )
408422 goto out ;
@@ -414,9 +428,10 @@ void deactivate_fd(int fd, int irqnum)
414428 entry -> reg [i ].events = 0 ;
415429 }
416430
417- update_or_free_irq_entry (entry );
431+ entry = update_or_remove_irq_entry (entry );
418432out :
419- spin_unlock_irqrestore (& irq_lock , flags );
433+ raw_spin_unlock_irqrestore (& irq_lock , flags );
434+ kfree (entry );
420435
421436 ignore_sigio_fd (fd );
422437}
@@ -546,7 +561,7 @@ void um_irqs_suspend(void)
546561
547562 irqs_suspended = true;
548563
549- spin_lock_irqsave (& irq_lock , flags );
564+ raw_spin_lock_irqsave (& irq_lock , flags );
550565 list_for_each_entry (entry , & active_fds , list ) {
551566 enum um_irq_type t ;
552567 bool clear = true;
@@ -579,7 +594,7 @@ void um_irqs_suspend(void)
579594 !__ignore_sigio_fd (entry -> fd );
580595 }
581596 }
582- spin_unlock_irqrestore (& irq_lock , flags );
597+ raw_spin_unlock_irqrestore (& irq_lock , flags );
583598}
584599
585600void um_irqs_resume (void )
@@ -588,7 +603,7 @@ void um_irqs_resume(void)
588603 unsigned long flags ;
589604
590605
591- spin_lock_irqsave (& irq_lock , flags );
606+ raw_spin_lock_irqsave (& irq_lock , flags );
592607 list_for_each_entry (entry , & active_fds , list ) {
593608 if (entry -> suspended ) {
594609 int err = os_set_fd_async (entry -> fd );
@@ -602,7 +617,7 @@ void um_irqs_resume(void)
602617 }
603618 }
604619 }
605- spin_unlock_irqrestore (& irq_lock , flags );
620+ raw_spin_unlock_irqrestore (& irq_lock , flags );
606621
607622 irqs_suspended = false;
608623 send_sigio_to_self ();
@@ -613,7 +628,7 @@ static int normal_irq_set_wake(struct irq_data *d, unsigned int on)
613628 struct irq_entry * entry ;
614629 unsigned long flags ;
615630
616- spin_lock_irqsave (& irq_lock , flags );
631+ raw_spin_lock_irqsave (& irq_lock , flags );
617632 list_for_each_entry (entry , & active_fds , list ) {
618633 enum um_irq_type t ;
619634
@@ -628,7 +643,7 @@ static int normal_irq_set_wake(struct irq_data *d, unsigned int on)
628643 }
629644 }
630645unlock :
631- spin_unlock_irqrestore (& irq_lock , flags );
646+ raw_spin_unlock_irqrestore (& irq_lock , flags );
632647 return 0 ;
633648}
634649#else
0 commit comments