]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
krbd: fix rbd map hang due to udev return subsystem unordered 30176/head
authorZhi Zhang <willzzhang@tencent.com>
Thu, 11 Apr 2019 05:09:01 +0000 (13:09 +0800)
committerNathan Cutler <ncutler@suse.com>
Thu, 5 Sep 2019 13:04:52 +0000 (15:04 +0200)
The order of subsystem returned by udev_device_get_subsystem
might not be same order as adding subsystem by
udev_monitor_filter_add_match_subsystem_devtype. So if block
event is returned first and rbd event is returned next, then
further poll will get nothing back until timed-out.

Fixes: http://tracker.ceph.com/issues/39089
Signed-off-by: Zhi Zhang <zhangz.david@outlook.com>
(cherry picked from 42dd1eae630f31a628051049e4007175561f1939)

Conflicts:
        src/krbd.cc

src/krbd.cc

index 9192174f7aa44895e866f75f315a791c12379554..638595af1743ae391715b2ad6a1cd5b2cfb78303 100644 (file)
@@ -184,6 +184,8 @@ static int wait_for_udev_add(struct udev_monitor *mon, const char *pool,
                              string *pname)
 {
   struct udev_device *bus_dev = nullptr;
+  std::vector<struct udev_device*> block_dev_vec;
+  int r;
 
   /*
    * Catch /sys/devices/rbd/<id>/ and wait for the corresponding
@@ -193,16 +195,16 @@ static int wait_for_udev_add(struct udev_monitor *mon, const char *pool,
   for (;;) {
     struct pollfd fds[1];
     struct udev_device *dev;
-    int r;
 
     fds[0].fd = udev_monitor_get_fd(mon);
     fds[0].events = POLLIN;
     r = poll(fds, 1, POLL_TIMEOUT);
-    if (r < 0)
-      return -errno;
-
-    if (r == 0)
-      return -ETIMEDOUT;
+    if (r > 0) {
+      r = 0;
+    } else {
+      r = (r == 0) ? -ETIMEDOUT : -errno;
+      break;
+    }
 
     dev = udev_monitor_receive_device(mon);
     if (!dev)
@@ -211,8 +213,8 @@ static int wait_for_udev_add(struct udev_monitor *mon, const char *pool,
     if (strcmp(udev_device_get_action(dev), "add") != 0)
       goto next;
 
-    if (!bus_dev) {
-      if (strcmp(udev_device_get_subsystem(dev), "rbd") == 0) {
+    if (strcmp(udev_device_get_subsystem(dev), "rbd") == 0) {
+      if (!bus_dev) {
         const char *this_pool = udev_device_get_sysattr_value(dev, "pool");
         const char *this_image = udev_device_get_sysattr_value(dev, "name");
         const char *this_snap = udev_device_get_sysattr_value(dev,
@@ -222,37 +224,50 @@ static int wait_for_udev_add(struct udev_monitor *mon, const char *pool,
             this_image && strcmp(this_image, image) == 0 &&
             this_snap && strcmp(this_snap, snap) == 0) {
           bus_dev = dev;
-          continue;
+          goto check;
         }
       }
-    } else {
-      if (strcmp(udev_device_get_subsystem(dev), "block") == 0) {
-        const char *major = udev_device_get_sysattr_value(bus_dev, "major");
-        const char *minor = udev_device_get_sysattr_value(bus_dev, "minor");
-        const char *this_major = udev_device_get_property_value(dev, "MAJOR");
-        const char *this_minor = udev_device_get_property_value(dev, "MINOR");
+    } else if (strcmp(udev_device_get_subsystem(dev), "block") == 0) {
+      block_dev_vec.push_back(dev);
+      goto check;
+    }
+
+next:
+    udev_device_unref(dev);
+    continue;
+
+check:
+    if (bus_dev && !block_dev_vec.empty()) {
+      const char *major = udev_device_get_sysattr_value(bus_dev, "major");
+      const char *minor = udev_device_get_sysattr_value(bus_dev, "minor");
+      assert(!minor ^ have_minor_attr());
 
-        assert(!minor ^ have_minor_attr());
+      for (auto p : block_dev_vec) {
+        const char *this_major = udev_device_get_property_value(p, "MAJOR");
+        const char *this_minor = udev_device_get_property_value(p, "MINOR");
 
         if (strcmp(this_major, major) == 0 &&
             (!minor || strcmp(this_minor, minor) == 0)) {
           string name = get_kernel_rbd_name(udev_device_get_sysname(bus_dev));
 
-          assert(strcmp(udev_device_get_devnode(dev), name.c_str()) == 0);
+          assert(strcmp(udev_device_get_devnode(p), name.c_str()) == 0);
           *pname = name;
-
-          udev_device_unref(dev);
-          udev_device_unref(bus_dev);
-          break;
+          goto done;
         }
       }
     }
+  }
 
-  next:
-    udev_device_unref(dev);
+done:
+  if (bus_dev) {
+    udev_device_unref(bus_dev);
+  }
+  
+  for (auto p : block_dev_vec) {
+    udev_device_unref(p);
   }
 
-  return 0;
+  return r;
 }
 
 static int do_map(struct udev *udev, const char *pool, const char *image,