USB device detection by scdaemon
Open, LowPublic

Assigned To
Authored By
• gniibe
Aug 23 2022, 7:06 AM

Description

It seems that after new device is inserted, running gpg-card l or (gpg --card-status), detecting new device is unstable.
IIUC, it may be the bug of libusb.

Event Timeline

• gniibe created this task.

In libusb (1.0.26), I found this:

diff --git a/libusb/os/linux_udev.c b/libusb/os/linux_udev.c
index 9ec9eb17..66e27244 100644
--- a/libusb/os/linux_udev.c
+++ b/libusb/os/linux_udev.c
@@ -194,9 +194,11 @@ static void *linux_udev_event_thread_main(void *arg)
 		}
 		if (fds[1].revents) {
 			usbi_mutex_static_lock(&linux_hotplug_lock);
-			udev_dev = udev_monitor_receive_device(udev_monitor);
-			if (udev_dev)
-				udev_hotplug_event(udev_dev);
+			do {
+				udev_dev = udev_monitor_receive_device(udev_monitor);
+				if (udev_dev)
+					udev_hotplug_event(udev_dev);
+			} while (udev_dev);
 			usbi_mutex_static_unlock(&linux_hotplug_lock);
 		}
 	}

Perhaps, this can improve the situation.

What I learned today:

  • libusb backend for Linux does:
    • scanning devices, it uses hotplug feature
    • hotplug feature uses udev_monitor_new_from_netlink and udev_monitor_receive_device, which are available in libudev (it communicates udev through AF_NETLINK socket)
    • libudev differs in Devuan
    • At initialization, hotplug feature spawns linux_udev_event_thread_main (its name is {libusb_event})
      • It is this thread, which receives information of device insertion/removal

The interesting thing is that I did not changed my box but it "suddenly" started to misbehave. Thus I conclude this is a matter of our own changes. The log I sent you by PM was done with my suggested improvement (npth_unlock/lock around libusb_get-device_list) and it might actually helped a bit - I am not sure. I will test again w/o that change. Or maybe I should bisect.

Okay, the mentioned patch does not help. I now tried the actual use
case of mine, which is to ssh without the token plugged in. I clicked
two times OK, then inserted the token and then I had to click
around dozen times onto OK before the inserted card was detected.

Here is the last check resulting in "no such device" commencing at
15:23:49 - the device was inserted 41 seconds earlier.

DBG: chan_7 <- SERIALNO --all
DBG: libusb{4}: [43.658888] [00001c84] libusb: debug [libusb_get_device_list]
DBG: libusb{4}: [43.658931] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [43.659005] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [43.659058] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [43.659118] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [43.659175] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: chan_7 -> ERR 100696144 No such device <SCD>

Then udev kicked this:

DBG: libusb{4}: [44.593546] [00001c86] libusb: debug [linux_get_device_address] getting address for device: 2-1.1 detached: 0
DBG: libusb{4}: [44.593581] [00001c86] libusb: debug [linux_get_device_address] scan 2-1.1
DBG: libusb{4}: [44.593647] [00001c86] libusb: debug [linux_get_device_address] bus=2 dev=37
DBG: libusb{4}: [44.593661] [00001c86] libusb: debug [udev_hotplug_event] udev hotplug event. action: add.
DBG: libusb{4}: [44.593672] [00001c86] libusb: debug [linux_enumerate_device] busnum 2 devaddr 37 session_id 549
DBG: libusb{4}: [44.593684] [00001c86] libusb: debug [linux_enumerate_device] allocating new device for 2/37 (session 549)
DBG: libusb{4}: [44.593734] [00001c86] libusb: debug [linux_get_parent_info] dev 0x7fef04002340 (2-1.1) has parent 0x7fef0c00b870 (2-1) port 1

Here I hit the OK button again:

DBG: chan_7 <- SERIALNO --all
DBG: libusb{4}: [44.820358] [00001c84] libusb: debug [libusb_get_device_list]
DBG: libusb{4}: [44.820384] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [44.820446] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [44.820496] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [44.820540] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [44.820571] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [44.820597] [00001c84] libusb: debug [libusb_get_device_descriptor]
DBG: libusb{4}: [44.820630] [00001c84] libusb: debug [libusb_open] open 2.37
DBG: libusb{4}: [44.820664] [00001c84] libusb: debug [usbi_add_event_source] add fd 13 events 4
[...]

Things worked from here on. The question is why we have this delay.

I went back to 2.3.3 and it seems it never worked as I expected. But we should understand the reason for the long delay.

I wrote a simple testusb.c if monitoring USB devices works:

#include <stdlib.h>
#include <libusb.h>
#include <poll.h>
#include <stdio.h>

static void
log_usb (libusb_context *ctx, enum libusb_log_level level, const char *str)
{
  fputs (str, stderr);
}

int
main (int argc, const char *argv[])
{
  int r;

  libusb_set_option (NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
  libusb_set_log_cb (NULL, log_usb, LIBUSB_LOG_CB_GLOBAL);

  r = libusb_init (NULL);
  if (r)
    exit (1);

  poll (NULL, 0, -1);

  return 0;
}

/* Local Variables: */
/* compile-command: "cc -o testusb testusb.c -I /usr/include/libusb-1.0 -lusb-1.0" */
/* End:             */

Running ./testusb, we can see what's going on in an application with libusb.
In my environment, it detects removal soon. It takes a bit of time (like a second or so) for detecting new device, but it works.

I think that testing with testusb, we may see if it's libusb issue or not.

Inserting as well as removal is detected on my machine always only after 25 seconds

• werner lowered the priority of this task from High to Low.Aug 24 2022, 10:52 AM

The delays are due to /usr/sbin/laptop_mode from the laptop-mode-tools package.