From: Michal Privoznik Date: Mon, 20 Apr 2020 14:12:03 +0000 (+0200) Subject: udevHandleOneDevice: Remove old instance of device on "move" X-Git-Tag: v6.3.0-rc1~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a13704818e4a018723e0ec5b9e97b176f1c8584;p=thirdparty%2Flibvirt.git udevHandleOneDevice: Remove old instance of device on "move" When a device is "move"-d (this basically means it was renamed), we add the new device onto our list but keep the old there too. Fortunately, udev sets this DEVPATH_OLD property which points to the old device path. We can use it to remove the old instance. To test this try renaming an interface, for instance: # ip link set tunl0 name tunl1 # ip link set tunl1 name tunl0 One problem with udev is that it sends old ifname in INTERFACE property, which creates a problem for us, the property is where we get the ifname from and use it then to query all kind of info about the interface. Well, if it is non-existent then we can't query anything. This happens if ifname rename is suppressed (net.ifnames=0 on kernel cmd line for instance). Fortunately, we can use "kernel" source for udev events which has always the fresh info. Signed-off-by: Michal Privoznik Reviewed-by: Martin Kletzander --- diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index e9a76a7b01..386f23ef3a 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1507,7 +1507,14 @@ udevHandleOneDevice(struct udev_device *device) return udevRemoveOneDevice(device); if (STREQ(action, "move")) { - /* TODO: implement a way of finding and removing the old device */ + const char *devpath_old = udevGetDeviceProperty(device, "DEVPATH_OLD"); + + if (devpath_old) { + g_autofree char *devpath_old_fixed = g_strdup_printf("/sys%s", devpath_old); + + udevRemoveOneDeviceSysPath(devpath_old_fixed); + } + return udevAddOneDevice(device); } @@ -1872,7 +1879,7 @@ nodeStateInitialize(bool privileged, virObjectLock(priv); - priv->udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + priv->udev_monitor = udev_monitor_new_from_netlink(udev, "kernel"); if (!priv->udev_monitor) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("udev_monitor_new_from_netlink returned NULL"));