[PATCH] Use refcounting for sysfs devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



As we're caching sysfs devices we need to introduce some sort
of refcounting here. Otherwise the device might be removed from
other threads while we're still accessing it.

References: bnc#642846

Signed-off-by: Hannes Reinecke <hare@xxxxxxx>

diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
index fc64881..ff63a1b 100644
--- a/libmultipath/sysfs.c
+++ b/libmultipath/sysfs.c
@@ -44,6 +44,7 @@ static LIST_HEAD(sysfs_dev_list);
 struct sysfs_dev {
 	struct list_head node;
 	struct sysfs_device dev;
+	int refcount;
 };
 
 int sysfs_init(char *path, size_t len)
@@ -152,6 +153,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 			if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
 				dbg("found vanished dev in cache '%s'",
 				    sysdev_loop->dev.devpath);
+				sysdev_loop->refcount++;
 				return &sysdev_loop->dev;
 			}
 		}
@@ -167,6 +169,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 		if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
 			dbg("found dev in cache '%s'", sysdev_loop->dev.devpath);
 			dev = &sysdev_loop->dev;
+			sysdev_loop->refcount++;
 		}
 	}
 
@@ -177,6 +180,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 		if (sysdev == NULL)
 			return NULL;
 		memset(sysdev, 0x00, sizeof(struct sysfs_dev));
+		sysdev->refcount = 1;
 		list_add(&sysdev->node, &sysfs_dev_list);
 		dev = &sysdev->dev;
 	}
@@ -243,6 +247,8 @@ struct sysfs_device *sysfs_device_verify(struct sysfs_device *dev)
 	char path[PATH_SIZE];
 	struct stat statbuf;
 
+	if (!dev->devpath)
+		return NULL;
 	strlcpy(path, sysfs_path, sizeof(path));
 	strlcat(path, dev->devpath, sizeof(path));
 	if (stat(dev->devpath, &statbuf) == 0 &&
@@ -258,15 +264,21 @@ void sysfs_device_put(struct sysfs_device *dev)
 
 	list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
 		if (&sysdev_loop->dev == dev) {
-			dbg("removed dev '%s' from cache",
-			    sysdev_loop->dev.devpath);
-			list_del(&sysdev_loop->node);
-			free(sysdev_loop);
+			sysdev_loop->refcount--;
+			if (!sysdev_loop->refcount) {
+				dbg("removed dev '%s' from cache",
+				    sysdev_loop->dev.devpath);
+				list_del(&sysdev_loop->node);
+				free(sysdev_loop);
+			} else {
+				dbg("dev '%s' still in cache, refcount %d",
+				    sysdev_loop->dev.devpath,
+				    sysdev_loop->refcount);
+			}
 			return;
 		}
 	}
-	dbg("dev '%s' not found in cache",
-	    sysdev_loop->dev.devpath);
+	dbg("dev '%s' not found in cache", dev->devpath);
 
 	return;
 }

--
dm-devel mailing list
dm-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/dm-devel


[Index of Archives]     [DM Crypt]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite Discussion]     [KDE Users]     [Fedora Docs]

  Powered by Linux