commit 39380e53473963f93251ca337c39c9b2bd4490a6
Author: Philipp Reisner <philipp.reisner@linbit.com>
Date:   Fri Aug 25 13:00:57 2017 +0200

    drbdadm: Fix peer_device objects
    
    Commit e7a73044 was wrong. It introduced that there is one peer_device
    object per connection and d_volume. d_volume exists per host.
    
    Revert that.
    
    One peer_device object per volume is enough!

diff -Naur drbd-utils-9.0.0.orig/user/v9/drbdadm_adjust.c drbd-utils-9.0.0/user/v9/drbdadm_adjust.c
--- drbd-utils-9.0.0.orig/user/v9/drbdadm_adjust.c	2018-01-18 11:22:01.173513190 +0800
+++ drbd-utils-9.0.0/user/v9/drbdadm_adjust.c	2018-01-18 11:22:09.265471980 +0800
@@ -650,16 +650,16 @@
 }
 
 static void
-adjust_peer_devices(const struct cfg_ctx *ctx, struct connection *conn, struct connection *running_conn)
+adjust_peer_devices(const struct cfg_ctx *ctx, struct connection *running_conn)
 {
 	struct adm_cmd *cmd = &peer_device_options_defaults_cmd;
 	struct context_def *oc = &peer_device_options_ctx;
 	struct peer_device *peer_device, *running_pd;
 	struct cfg_ctx tmp_ctx = *ctx;
 
-	STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) {
+	STAILQ_FOREACH(peer_device, &ctx->conn->peer_devices, connection_link) {
 		running_pd = matching_peer_device(peer_device, &running_conn->peer_devices);
-		tmp_ctx.vol = peer_device->volume;
+		tmp_ctx.vol = volume_by_vnr(&ctx->conn->peer->volumes, peer_device->vnr);
 		if (!running_pd) {
 			schedule_deferred_cmd(cmd, &tmp_ctx, CFG_PEER_DEVICE);
 			continue;
@@ -682,23 +682,21 @@
 		struct d_host_info *me = ctx->res->me;
 		struct d_volume *vol;
 		for_each_volume(vol, &me->volumes) {
-			peer_device = find_peer_device(me, tmp_ctx.conn, vol->vnr);
+			peer_device = find_peer_device(tmp_ctx.conn, vol->vnr);
 			if (!peer_device || STAILQ_EMPTY(&peer_device->pd_options))
 				continue;
 
-			tmp_ctx.vol = peer_device->volume;
+			tmp_ctx.vol = vol;
 			schedule_deferred_cmd(cmd, &tmp_ctx, CFG_PEER_DEVICE | SCHEDULE_ONCE);
 		}
 	} else if (!tmp_ctx.conn) {
-		STAILQ_FOREACH(peer_device, &tmp_ctx.vol->peer_devices, volume_link) {
-
-			if (!peer_device->connection->paths.stqh_first->my_address ||
-					!peer_device->connection->paths.stqh_first->connect_to)
-				continue;
-			if (STAILQ_EMPTY(&peer_device->pd_options))
+		struct connection *conn;
+		for_each_connection(conn, &ctx->res->connections) {
+			peer_device = find_peer_device(conn, tmp_ctx.vol->vnr);
+			if (!peer_device || STAILQ_EMPTY(&peer_device->pd_options))
 				continue;
 
-			tmp_ctx.conn = peer_device->connection;
+			tmp_ctx.conn = conn;
 			schedule_deferred_cmd(cmd, &tmp_ctx, CFG_PEER_DEVICE | SCHEDULE_ONCE);
 		}
 	} else {
@@ -782,7 +780,7 @@
 			if (connect)
 				schedule_deferred_cmd(&connect_cmd, &tmp_ctx, CFG_NET_CONNECT);
 
-			adjust_peer_devices(&tmp_ctx, conn, running_conn);
+			adjust_peer_devices(&tmp_ctx, running_conn);
 		}
 
 		path = STAILQ_FIRST(&conn->paths); /* multiple paths via proxy, later! */
diff -Naur drbd-utils-9.0.0.orig/user/v9/drbdadm.h drbd-utils-9.0.0/user/v9/drbdadm.h
--- drbd-utils-9.0.0.orig/user/v9/drbdadm.h	2018-01-18 11:22:01.173513190 +0800
+++ drbd-utils-9.0.0/user/v9/drbdadm.h	2018-01-18 11:22:09.265471980 +0800
@@ -72,10 +72,12 @@
 	int config_line; /* parsed here */
 
 	struct connection *connection;
-	struct d_volume *volume; /* set in post_parese() */
+	/* No pointer to d_volume, because there are two!
+	   On each side of the connection!
+	   Iterate d_host_info and find the correct volume by matching vnr! */
 
 	STAILQ_ENTRY(peer_device) connection_link; /* added during parsing */
-	STAILQ_ENTRY(peer_device) volume_link; /* added in post_parse() */
+	/* no volume_link !! */
 
 	unsigned int implicit:1; /* Do not dump by default */
 };
@@ -437,7 +439,7 @@
 int do_proxy_conn_up(const struct cfg_ctx *ctx);
 int do_proxy_conn_down(const struct cfg_ctx *ctx);
 int do_proxy_conn_plugins(const struct cfg_ctx *ctx);
-struct peer_device *find_peer_device(struct d_host_info *host, struct connection *conn, int vnr);
+struct peer_device *find_peer_device(struct connection *conn, int vnr);
 bool peer_diskless(struct peer_device *peer_device);
 
 extern char *config_file;
diff -Naur drbd-utils-9.0.0.orig/user/v9/drbdadm_main.c drbd-utils-9.0.0/user/v9/drbdadm_main.c
--- drbd-utils-9.0.0.orig/user/v9/drbdadm_main.c	2018-01-18 11:22:01.173513190 +0800
+++ drbd-utils-9.0.0/user/v9/drbdadm_main.c	2018-01-18 11:22:09.265471980 +0800
@@ -1683,7 +1683,7 @@
 	char *argv[MAX_ARGS];
 	int argc = 0;
 
-	peer_device = find_peer_device(res->me, conn, vol->vnr);
+	peer_device = find_peer_device(conn, vol->vnr);
 	if (!peer_device) {
 		err("Could not find peer_device object!\n");
 		exit(E_THINKO);
@@ -2009,7 +2009,7 @@
 				continue;
 
 			tmp2_ctx = tmp_ctx;
-			tmp2_ctx.vol = peer_device->volume;
+			tmp2_ctx.vol = volume_by_vnr(&conn->peer->volumes, peer_device->vnr);
 			schedule_deferred_cmd(&peer_device_options_cmd, &tmp2_ctx, CFG_PEER_DEVICE);
 		}
 	}
diff -Naur drbd-utils-9.0.0.orig/user/v9/drbdadm_postparse.c drbd-utils-9.0.0/user/v9/drbdadm_postparse.c
--- drbd-utils-9.0.0.orig/user/v9/drbdadm_postparse.c	2018-01-18 11:22:01.173513190 +0800
+++ drbd-utils-9.0.0/user/v9/drbdadm_postparse.c	2018-01-18 11:22:09.265471980 +0800
@@ -464,7 +464,7 @@
 {
 	struct d_volume *vol;
 
-	vol = volume_by_vnr(&peer_device->connection->peer->volumes, peer_device->volume->vnr);
+	vol = volume_by_vnr(&peer_device->connection->peer->volumes, peer_device->vnr);
 	return vol->disk == NULL;
 }
 
@@ -1012,18 +1012,13 @@
 		_must_have_two_hosts(res, path);
 }
 
-struct peer_device *find_peer_device(struct d_host_info *host, struct connection *conn, int vnr)
+struct peer_device *find_peer_device(struct connection *conn, int vnr)
 {
 	struct peer_device *peer_device;
-	struct d_volume *vol;
 
 	STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) {
-		if (peer_device->vnr == vnr) {
-			for_each_volume(vol, &host->volumes) {
-				if (vol == peer_device->volume)
-					return peer_device;
-			}
-		}
+		if (peer_device->vnr == vnr)
+			return peer_device;
 	}
 
 	return NULL;
@@ -1044,46 +1039,30 @@
 		if (!some_path)
 			continue;
 
-		some_host = STAILQ_FIRST(&some_path->hname_address_pairs)->host_info;
-
 		STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) {
-
-			vol = volume_by_vnr(&some_host->volumes, peer_device->vnr);
-			if (!vol) {
-				err("%s:%d: Resource %s: There is a reference to a volume %d that"
-				    "is not known in this resource\n",
-				    res->config_file, peer_device->config_line, res->name,
-				    peer_device->vnr);
-				config_valid = 0;
+			STAILQ_FOREACH(ha, &some_path->hname_address_pairs, link) {
+				struct d_host_info *host = ha->host_info;
+				vol = volume_by_vnr(&host->volumes, peer_device->vnr);
+				if (!vol) {
+					err("%s:%d: Resource %s: There is a reference to a volume %d that"
+					    "is not known in this resource\n",
+					    res->config_file, peer_device->config_line, res->name,
+					    peer_device->vnr);
+					config_valid = 0;
+				}
 			}
-			peer_device->volume = vol;
-			STAILQ_INSERT_TAIL(&vol->peer_devices, peer_device, volume_link);
 		}
 
-		/* Take the first path, iterate over hname_address_pairs, take the host_info.
-		   this is the way to get hold of the two hosts of a connection. */
-		STAILQ_FOREACH(ha, &some_path->hname_address_pairs, link) {
-			struct d_host_info *host = ha->host_info;
-
-			if (!host) {
-				err("%s:%d: Resource %s: reference to unknown host '%s'\n",
-					res->config_file, ha->config_line, res->name, ha->name);
-				config_valid = 0;
+		some_host = STAILQ_FIRST(&some_path->hname_address_pairs)->host_info;
+		for_each_volume(vol, &some_host->volumes) {
+			peer_device = find_peer_device(conn, vol->vnr);
+			if (peer_device)
 				continue;
-			}
-
-			for_each_volume(vol, &host->volumes) {
-				peer_device = find_peer_device(host, conn, vol->vnr);
-				if (peer_device)
-					continue;
-				peer_device = alloc_peer_device();
-				peer_device->vnr = vol->vnr;
-				peer_device->implicit = 1;
-				peer_device->connection = conn;
-				peer_device->volume = vol;
-				STAILQ_INSERT_TAIL(&conn->peer_devices, peer_device, connection_link);
-				STAILQ_INSERT_TAIL(&vol->peer_devices, peer_device, volume_link);
-			}
+			peer_device = alloc_peer_device();
+			peer_device->vnr = vol->vnr;
+			peer_device->implicit = 1;
+			peer_device->connection = conn;
+			STAILQ_INSERT_TAIL(&conn->peer_devices, peer_device, connection_link);
 		}
 	}
 }
@@ -1275,9 +1254,23 @@
 		   tie the peer_device options from the volume to peer_devices */
 		for_each_connection(conn, &res->connections) {
 			struct peer_device *peer_device;
-			STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link) {
+			struct hname_address *ha;
+			struct path *some_path;
+
+			STAILQ_FOREACH(peer_device, &conn->peer_devices, connection_link)
 				expand_opts(&conn->pd_options, &peer_device->pd_options);
-				expand_opts(&peer_device->volume->pd_options, &peer_device->pd_options);
+
+			some_path = STAILQ_FIRST(&conn->paths);
+			if (!some_path)
+				continue;
+
+			STAILQ_FOREACH(ha, &some_path->hname_address_pairs, link) {
+				h = ha->host_info;
+				for_each_volume(vol, &h->volumes) {
+					peer_device = find_peer_device(conn, vol->vnr);
+
+					expand_opts(&vol->pd_options, &peer_device->pd_options);
+				}
 			}
 		}
 	}
diff -Naur drbd-utils-9.0.0.orig/user/v9/drbdadm_usage_cnt.c drbd-utils-9.0.0/user/v9/drbdadm_usage_cnt.c
--- drbd-utils-9.0.0.orig/user/v9/drbdadm_usage_cnt.c	2018-01-18 11:22:01.173513190 +0800
+++ drbd-utils-9.0.0/user/v9/drbdadm_usage_cnt.c	2018-01-18 11:22:09.269471957 +0800
@@ -544,6 +544,18 @@
 	return NULL;
 }
 
+static bool peer_completely_diskless(struct d_host_info *peer)
+{
+	struct d_volume *vol;
+
+	for_each_volume(vol, &peer->volumes) {
+		if (vol->disk)
+			return false;
+	}
+
+	return true;
+}
+
 int adm_create_md(const struct cfg_ctx *ctx)
 {
 	char answer[ANSWER_SIZE];
@@ -562,15 +574,17 @@
 	if (b_opt_max_peers) {
 		max_peers_str = ssprintf("%s", b_opt_max_peers->name + strlen(opt_max_peers));
 	} else {
-		struct peer_device *peer_device;
+		struct connection *conn;
 		int max_peers = 0;
 
 		set_peer_in_resource(ctx->res, true);
 
-		STAILQ_FOREACH(peer_device, &ctx->vol->peer_devices, volume_link) {
-			if (peer_device->connection->ignore || peer_diskless(peer_device))
+		for_each_connection(conn, &ctx->res->connections) {
+			if (conn->ignore)
 				continue;
-			max_peers++;
+
+			if (!peer_completely_diskless(conn->peer))
+				max_peers++;
 		}
 
 		if (max_peers == 0)

