@@ -521,6 +521,38 @@ def __init__(self):
521521 "/etc/qubes-rpc/qubes.USB"
522522 )
523523 self .devices_cache = collections .defaultdict (dict )
524+ self .autoattach_locks = collections .defaultdict (asyncio .Lock )
525+
526+ async def _auto_attach_devices (self , vm ):
527+ # pylint: disable=unused-argument
528+ async with self .autoattach_locks [vm .uuid ]:
529+ to_attach = {}
530+ assignments = get_assigned_devices (vm .devices ["usb" ])
531+ # the most specific assignments first
532+ for assignment in reversed (sorted (assignments )):
533+ for device in assignment .devices :
534+ if isinstance (device , qubes .device_protocol .UnknownDevice ):
535+ continue
536+ if device .attachment :
537+ continue
538+ if not assignment .matches (device ):
539+ print (
540+ "Unrecognized identity, skipping attachment of device "
541+ f"from the port { assignment } " ,
542+ file = sys .stderr ,
543+ )
544+ continue
545+ # chose first assignment (the most specific) and ignore rest
546+ if device not in to_attach :
547+ # make it unique
548+ to_attach [device ] = assignment .clone (device = device )
549+ in_progress = set ()
550+ for assignment in to_attach .values ():
551+ in_progress .add (
552+ asyncio .ensure_future (self .attach_and_notify (vm , assignment ))
553+ )
554+ if in_progress :
555+ await asyncio .wait (in_progress )
524556
525557 @qubes .ext .handler ("domain-init" , "domain-load" )
526558 def on_domain_init_load (self , vm , event ):
@@ -743,42 +775,21 @@ async def on_device_assign_usb(self, vm, event, device, options):
743775
744776 @qubes .ext .handler ("domain-start" )
745777 async def on_domain_start (self , vm , _event , ** _kwargs ):
746- # pylint: disable=unused-argument
747- to_attach = {}
748- assignments = get_assigned_devices (vm .devices ["usb" ])
749- # the most specific assignments first
750- for assignment in reversed (sorted (assignments )):
751- for device in assignment .devices :
752- if isinstance (device , qubes .device_protocol .UnknownDevice ):
753- continue
754- if device .attachment :
755- continue
756- if not assignment .matches (device ):
757- print (
758- "Unrecognized identity, skipping attachment of device "
759- f"from the port { assignment } " ,
760- file = sys .stderr ,
761- )
762- continue
763- # chose first assignment (the most specific) and ignore rest
764- if device not in to_attach :
765- # make it unique
766- to_attach [device ] = assignment .clone (device = device )
767- in_progress = set ()
768- for assignment in to_attach .values ():
769- in_progress .add (
770- asyncio .ensure_future (self .attach_and_notify (vm , assignment ))
771- )
772- if in_progress :
773- await asyncio .wait (in_progress )
778+ await self ._auto_attach_devices (vm )
774779
775780 @qubes .ext .handler ("domain-shutdown" )
776781 async def on_domain_shutdown (self , vm , _event , ** _kwargs ):
777782 # pylint: disable=unused-argument
778783 vm .fire_event ("device-list-change:usb" )
779784 utils .device_list_change (self , {}, vm , None , USBDevice )
785+ del self .autoattach_locks [vm .uuid ]
786+
787+ @qubes .ext .handler ("domain-resumed" )
788+ async def on_domain_resumed (self , vm , _event , ** _kwargs ):
789+ await self ._auto_attach_devices (vm )
780790
781791 @qubes .ext .handler ("qubes-close" , system = True )
782792 def on_qubes_close (self , app , event ):
783793 # pylint: disable=unused-argument
784794 self .devices_cache .clear ()
795+ self .autoattach_locks .clear ()
0 commit comments