[dm-devel] patch to fix locking bug in libmultipath/alias.c

Edward Goggin egoggin at emc.com
Tue Jul 18 03:05:20 UTC 2006


Christophe,

The posix file byte range locks used to provide atomicity for accessing
the entries in the multipath bindings file get released from whenever
__any__ descriptor or FILE structure for that file is closed.  This
patch delays the fclose() for the FILE structures used within
lookup_binding() and rlookup_binding() until there is no more need for
the atomicity.

Without this patch I could fairly easily get two multipath mpath0
entries in /var/lib/multipath/bindings by running 8 concurrent instances
of multipath(8) while with the patch I cannot get this problem to occur.

diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index 6d103d7..86cae9b 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -166,28 +166,14 @@ fail:
 
 
 static int
-lookup_binding(int fd, char *map_wwid, char **map_alias)
+lookup_binding(FILE *f, char *map_wwid, char **map_alias)
 {
 	char buf[LINE_MAX];
-	FILE *f;
 	unsigned int line_nr = 0;
-	int scan_fd;
 	int id = 0;
 
 	*map_alias = NULL;
-	scan_fd = dup(fd);
-	if (scan_fd < 0) {
-		condlog(0, "Cannot dup bindings file descriptor : %s",
-			strerror(errno));
-		return -1;
-	}
-	f = fdopen(scan_fd, "r");
-	if (!f) {
-		condlog(0, "cannot fdopen on bindings file descriptor :
%s",
-			strerror(errno));
-		close(scan_fd);
-		return -1;
-	}
+
 	while (fgets(buf, LINE_MAX, f)) {
 		char *c, *alias, *wwid;
 		int curr_id;
@@ -215,38 +201,22 @@ lookup_binding(int fd, char *map_wwid, c
 			if (*map_alias == NULL)
 				condlog(0, "Cannot copy alias from
bindings "
 					"file : %s", strerror(errno));
-			fclose(f);
 			return id;
 		}
 	}
 	condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
-	fclose(f);
 	return id;
 }	
 
 static int
-rlookup_binding(int fd, char **map_wwid, char *map_alias)
+rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
 {
 	char buf[LINE_MAX];
-	FILE *f;
 	unsigned int line_nr = 0;
-	int scan_fd;
 	int id = 0;
 
 	*map_wwid = NULL;
-	scan_fd = dup(fd);
-	if (scan_fd < 0) {
-		condlog(0, "Cannot dup bindings file descriptor : %s",
-			strerror(errno));
-		return -1;
-	}
-	f = fdopen(scan_fd, "r");
-	if (!f) {
-		condlog(0, "cannot fdopen on bindings file descriptor :
%s",
-			strerror(errno));
-		close(scan_fd);
-		return -1;
-	}
+
 	while (fgets(buf, LINE_MAX, f)) {
 		char *c, *alias, *wwid;
 		int curr_id;
@@ -274,12 +244,10 @@ rlookup_binding(int fd, char **map_wwid,
 			if (*map_wwid == NULL)
 				condlog(0, "Cannot copy alias from
bindings "
 					"file : %s", strerror(errno));
-			fclose(f);
 			return id;
 		}
 	}
 	condlog(3, "No matching alias [%s] in bindings file.",
map_alias);
-	fclose(f);
 	return id;
 }	
 
@@ -327,7 +295,8 @@ char *
 get_user_friendly_alias(char *wwid, char *file)
 {
 	char *alias;
-	int fd, id;
+	int fd, scan_fd, id;
+	FILE *f;
 
 	if (!wwid || *wwid == '\0') {
 		condlog(3, "Cannot find binding for empty WWID");
@@ -337,14 +306,37 @@ get_user_friendly_alias(char *wwid, char
 	fd = open_bindings_file(file);
 	if (fd < 0)
 		return NULL;
-	id = lookup_binding(fd, wwid, &alias);
+
+	scan_fd = dup(fd);
+	if (scan_fd < 0) {
+		condlog(0, "Cannot dup bindings file descriptor : %s",
+			strerror(errno));
+		close(fd);
+		return NULL;
+	}
+
+	f = fdopen(scan_fd, "r");
+	if (!f) {
+		condlog(0, "cannot fdopen on bindings file descriptor :
%s",
+			strerror(errno));
+		close(scan_fd);
+		close(fd);
+		return NULL;
+	}
+
+	id = lookup_binding(f, wwid, &alias);
 	if (id < 0) {
+		fclose(f);
+		close(scan_fd);
 		close(fd);
 		return NULL;
 	}
+
 	if (!alias)
 		alias = allocate_binding(fd, wwid, id);
 
+	fclose(f);
+	close(scan_fd);
 	close(fd);
 	return alias;
 }
@@ -353,7 +345,8 @@ char *
 get_user_friendly_wwid(char *alias, char *file)
 {
 	char *wwid;
-	int fd, id;
+	int fd, scan_fd, id;
+	FILE *f;
 
 	if (!alias || *alias == '\0') {
 		condlog(3, "Cannot find binding for empty alias");
@@ -363,12 +356,34 @@ get_user_friendly_wwid(char *alias, char
 	fd = open_bindings_file(file);
 	if (fd < 0)
 		return NULL;
-	id = rlookup_binding(fd, &wwid, alias);
+
+	scan_fd = dup(fd);
+	if (scan_fd < 0) {
+		condlog(0, "Cannot dup bindings file descriptor : %s",
+			strerror(errno));
+		close(fd);
+		return NULL;
+	}
+
+	f = fdopen(scan_fd, "r");
+	if (!f) {
+		condlog(0, "cannot fdopen on bindings file descriptor :
%s",
+			strerror(errno));
+		close(scan_fd);
+		close(fd);
+		return NULL;
+	}
+
+	id = rlookup_binding(f, &wwid, alias);
 	if (id < 0) {
+		fclose(f);
+		close(scan_fd);
 		close(fd);
 		return NULL;
 	}
 
+	fclose(f);
+	close(scan_fd);
 	close(fd);
 	return wwid;
 }




More information about the dm-devel mailing list