[DRBD-cvs] r1418 - in trunk/drbd: . linux

drbd-user@lists.linbit.com drbd-user@lists.linbit.com
Tue, 13 Jul 2004 12:05:25 +0200 (CEST)


Author: phil
Date: 2004-07-13 12:05:24 +0200 (Tue, 13 Jul 2004)
New Revision: 1418

Modified:
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/linux/drbd_config.h
Log:
[patch by LGE] 
 Implemented the handshake packet. -> In order to allow rolling
 updates with further protocol changes...


Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2004-07-13 09:50:11 UTC (rev 1417)
+++ trunk/drbd/drbd_int.h	2004-07-13 10:05:24 UTC (rev 1418)
@@ -358,10 +358,15 @@
 	MAX_CMD,
 	MayIgnore = 0x100, // Flag only to test if (cmd > MayIgnore) ...
 	MAX_OPT_CMD,
+
+	HandShake = 0xfffe // FIXED for the next century!
 } Drbd_Packet_Cmd;
 
 static inline const char* cmdname(Drbd_Packet_Cmd cmd)
 {
+	/* THINK may need to become several global tables
+	 * when we want to support more than
+	 * one PRO_VERSION */
 	static const char *cmdnames[] = {
 		[Data]             = "Data",
 		[DataReply]        = "DataReply",
@@ -385,7 +390,8 @@
 		[BarrierAck]       = "BarrierAck"
 	};
 
-	if(cmd < 0 || cmd > MAX_CMD) return "Unknown";
+	if (cmd == HandShake) return "HandShake";
+	if (Data > cmd || cmd >= MAX_CMD) return "Unknown";
 	return cmdnames[cmd];
 }
 
@@ -406,6 +412,7 @@
 	u16       length;	// bytes of data after this header
 	char      payload[0];
 } Drbd_Header __attribute((packed));
+// 8 bytes. packet FIXED for the next century!
 
 /*
  * short commands, packets without payload, plain Drbd_Header:
@@ -450,12 +457,27 @@
 
 /*
  * commands with their own struct for additional fields:
+ *   HandShake
  *   Barrier
  *   BarrierAck
  *   SyncParam
  *   ReportParams
  */
+
 typedef struct {
+	Drbd_Header head;		// 8 bytes
+	u32         protocol_version;
+	u32         feature_flags;
+
+	/* should be more than enough for future enhancements
+	 * for now, feature_flags and the reserverd array shall be zero.
+	 */
+
+	u64         reserverd[8];
+} Drbd_HandShake_Packet __attribute((packed));
+// 80 bytes, FIXED for the next century
+
+typedef struct {
 	Drbd_Header head;
 	u32         barrier;   // may be 0 or a barrier number
 	u32         pad;	//make sure packet is a multiple of 8 Byte
@@ -505,6 +527,7 @@
 
 typedef union {
 	Drbd_Header              head;
+	Drbd_HandShake_Packet    HandShake;
 	Drbd_Data_Packet         Data;
 	Drbd_BlockAck_Packet     BlockAck;
 	Drbd_Barrier_Packet      Barrier;
@@ -782,6 +805,9 @@
 extern int drbd_send(drbd_dev *mdev, struct socket *sock,
 		     void* buf, size_t size, unsigned msg_flags);
 extern int drbd_send_param(drbd_dev *mdev, int flags);
+extern int _drbd_send_cmd(drbd_dev *mdev, struct socket *sock,
+			  Drbd_Packet_Cmd cmd, Drbd_Header *h,
+			  size_t size, unsigned msg_flags);
 extern int drbd_send_cmd(drbd_dev *mdev, struct socket *sock,
 			  Drbd_Packet_Cmd cmd, Drbd_Header *h, size_t size);
 extern int drbd_send_sync_param(drbd_dev *mdev, struct syncer_config *sc);
@@ -1348,6 +1374,10 @@
 	char *sockname = sock == mdev->meta.socket ? "meta" : "data";
 	int cmd = (recv == 2) ? p->head.command : be16_to_cpu(p->head.command);
 	switch (cmd) {
+	case HandShake:
+		INFOP("%s (%u)\n", be32_to_cpu(p->HandShake.protocol_version));
+		break;
+
 	case Ping:
 	case PingAck:
 	case BecomeSyncTarget:

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2004-07-13 09:50:11 UTC (rev 1417)
+++ trunk/drbd/drbd_main.c	2004-07-13 10:05:24 UTC (rev 1418)
@@ -600,7 +600,7 @@
 	UNLOCK_SIGMASK(current,flags);
 }
 
-STATIC int _drbd_send_cmd(drbd_dev *mdev, struct socket *sock,
+int _drbd_send_cmd(drbd_dev *mdev, struct socket *sock,
 			  Drbd_Packet_Cmd cmd, Drbd_Header *h,
 			  size_t size, unsigned msg_flags)
 {
@@ -1617,6 +1617,7 @@
 	SZO(wait_queue_head_t);
 	SZO(spinlock_t);
 	SZO(Drbd_Header);
+	SZO(Drbd_HandShake_Packet);
 	SZO(Drbd_Barrier_Packet);
 	SZO(Drbd_BarrierAck_Packet);
 	SZO(Drbd_SyncParam_Packet);
@@ -1628,6 +1629,12 @@
 	return -EBUSY;
 #endif
 
+	if (sizeof(Drbd_HandShake_Packet) != 80) {
+		printk(KERN_ERR DEVICE_NAME
+		       ": never change the size or layout of the HandShake packet.\n");
+		return -EINVAL;
+	}
+
 	if (1 > minor_count||minor_count > 255) {
 		printk(KERN_ERR DEVICE_NAME
 			": invalid minor_count (%d)\n",minor_count);

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2004-07-13 09:50:11 UTC (rev 1417)
+++ trunk/drbd/drbd_receiver.c	2004-07-13 10:05:24 UTC (rev 1418)
@@ -600,7 +600,6 @@
 	return rv;
 }
 
-
 STATIC struct socket *drbd_try_connect(drbd_dev *mdev)
 {
 	int err;
@@ -656,6 +655,8 @@
 	return sock;
 }
 
+STATIC int drbd_do_handshake(drbd_dev *mdev);
+
 int drbd_connect(drbd_dev *mdev)
 {
 	struct socket *sock,*msock;
@@ -712,8 +713,12 @@
 	// FIXME fold to limits. should be done in drbd_ioctl
 	sock->sk->SK_(sndbuf) = mdev->conf.sndbuf_size;
 	sock->sk->SK_(rcvbuf) = mdev->conf.sndbuf_size;
-	sock->sk->SK_(sndtimeo) = mdev->conf.timeout*HZ/20;
-	sock->sk->SK_(rcvtimeo) = MAX_SCHEDULE_TIMEOUT;
+	/* NOT YET ...
+	 * sock->sk->SK_(sndtimeo) = mdev->conf.timeout*HZ/20;
+	 * sock->sk->SK_(rcvtimeo) = MAX_SCHEDULE_TIMEOUT;
+	 * THINK HandShake timeout, hardcoded for now: */
+	sock->sk->SK_(sndtimeo) =
+	sock->sk->SK_(rcvtimeo) = 2*HZ;
 	sock->sk->SK_(userlocks) |= SOCK_SNDBUF_LOCK | SOCK_RCVBUF_LOCK;
 
 	msock->sk->SK_(priority)=TC_PRIO_INTERACTIVE;
@@ -728,9 +733,15 @@
 	mdev->last_received = jiffies;
 
 	set_cstate(mdev,WFReportParams);
-
 	D_ASSERT(mdev->asender.task == NULL);
 
+	if (!drbd_do_handshake(mdev)) {
+		return 0;
+	}
+
+	sock->sk->SK_(sndtimeo) = mdev->conf.timeout*HZ/20;
+	sock->sk->SK_(rcvtimeo) = MAX_SCHEDULE_TIMEOUT;
+
 	drbd_thread_start(&mdev->asender);
 
 	drbd_send_param(mdev,0);
@@ -1811,6 +1822,85 @@
 	INFO("Connection lost.\n");
 }
 
+/*
+ * we hereby assure that we always support the drbd dialects
+ * PRO_VERSION and (PRO_VERSION -1), allowing for rolling upgrades
+ *
+ * feature flags and the reserved array should be enough room for future
+ * enhancements of the handshake protocol, and possible plugins...
+ *
+ * for now, they are expected to be zero, but ignored.
+ */
+int drbd_send_handshake(drbd_dev *mdev)
+{
+	// ASSERT current == mdev->receiver ...
+	Drbd_HandShake_Packet *p = &mdev->data.sbuf.HandShake;
+	int ok;
+
+	down(&mdev->data.mutex);
+	memset(p,0,sizeof(*p));
+	p->protocol_version = cpu_to_be32(PRO_VERSION);
+	ok = _drbd_send_cmd( mdev, mdev->data.socket, HandShake,
+	                     (Drbd_Header *)p, sizeof(*p), 0 );
+	up(&mdev->data.mutex);
+	return ok;
+}
+
+STATIC int drbd_do_handshake(drbd_dev *mdev)
+{
+	// ASSERT current == mdev->receiver ...
+	Drbd_HandShake_Packet *p = &mdev->data.rbuf.HandShake;
+	const int expect = sizeof(Drbd_HandShake_Packet)-sizeof(Drbd_Header);
+	int rv;
+
+	rv = drbd_send_handshake(mdev);
+	if (!rv) return 0;
+
+	rv = drbd_recv_header(mdev,&p->head);
+	if (!rv) return 0;
+
+	if (p->head.command == ReportParams) {
+		ERR("expected HandShake packet, received ReportParams...\n");
+		ERR("peer probaly runs some incompatible 0.7 -preX version\n");
+		return 0;
+	} else if (p->head.command != HandShake) {
+		ERR( "expected HandShake packet, received: %s (0x%04x)\n",
+		     cmdname(p->head.command), p->head.command );
+		return 0;
+	}
+
+	if (p->head.length != expect) {
+		ERR( "expected HandShake length: %u, received: %u\n",
+		     expect, p->head.length );
+		return 0;
+	}
+
+	rv = drbd_recv(mdev, &p->head.payload, expect);
+
+	if (rv != expect) {
+		ERR("short read receiving handshake packet: l=%u\n", rv);
+		return 0;
+	}
+
+	dump_packet(mdev,mdev->data.socket,2,&mdev->data.rbuf, __FILE__, __LINE__);
+
+	p->protocol_version = be32_to_cpu(p->protocol_version);
+
+	if ( p->protocol_version == PRO_VERSION ) {
+		INFO( "Handshake successful: DRBD Protocol version %u\n",
+				p->protocol_version );
+	} /* else if ( p->protocol_version == (PRO_VERSION-1) ) {
+		// not yet; but next time :)
+	} */ else {
+		ERR( "incompatible DRBD dialects: "
+		     "I support %u, peer wants %u\n",
+		     PRO_VERSION, p->protocol_version );
+		return 0;
+	}
+
+	return 1;
+}
+
 int drbdd_init(struct Drbd_thread *thi)
 {
 	drbd_dev *mdev = thi->mdev;
@@ -1823,6 +1913,12 @@
 	while (TRUE) {
 		if (!drbd_connect(mdev)) {
 			WARN("Discarding network configuration.\n");
+			/* FIXME DISKLESS StandAlone
+			 * does not make much sense...
+			 * drbd_disconnect should set cstate properly...
+			 */
+			drbd_disconnect(mdev);
+			set_cstate(mdev,StandAlone);
 			break;
 		}
 		if (get_t_state(thi) == Exiting) break;

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2004-07-13 09:50:11 UTC (rev 1417)
+++ trunk/drbd/linux/drbd_config.h	2004-07-13 10:05:24 UTC (rev 1418)
@@ -22,9 +22,7 @@
 
 #define REL_VERSION "0.7-pre10 cvs $Date: 2004/07/09 18:29:24 $"
 #define API_VERSION 74
-#define PRO_VERSION 73 /* actually already 74, but I expect some more
-			* protocol changes, maybe even an additional packet
-			* soonish... */
+#define PRO_VERSION 74
 
 //#define DBG_ALL_SYMBOLS // no static functs, improves quality of OOPS traces