From 42dd1eae630f31a628051049e4007175561f1939 Mon Sep 17 00:00:00 2001 From: Zhi Zhang Date: Thu, 11 Apr 2019 13:09:01 +0800 Subject: [PATCH] krbd: fix rbd map hang due to udev return subsystem unordered 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 --- src/krbd.cc | 63 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/src/krbd.cc b/src/krbd.cc index a7ae25bafed..f766a4e8c90 100644 --- a/src/krbd.cc +++ b/src/krbd.cc @@ -232,6 +232,8 @@ static int wait_for_udev_add(struct udev_monitor *mon, const krbd_spec& spec, string *pname) { struct udev_device *bus_dev = nullptr; + std::vector block_dev_vec; + int r; /* * Catch /sys/devices/rbd// and wait for the corresponding @@ -241,16 +243,16 @@ static int wait_for_udev_add(struct udev_monitor *mon, const krbd_spec& spec, 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) @@ -259,42 +261,55 @@ static int wait_for_udev_add(struct udev_monitor *mon, const krbd_spec& spec, 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) { auto cur_spec = spec_from_dev(dev); if (cur_spec && *cur_spec == spec) { 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"); + ceph_assert(!minor ^ have_minor_attr()); - ceph_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)); - ceph_assert(strcmp(udev_device_get_devnode(dev), name.c_str()) == 0); + ceph_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 krbd_spec& spec, const string& buf, -- 2.47.3