From drbd-cvs at lists.linbit.com  Tue Aug  1 09:52:46 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 09:52:47 2006
Subject: [DRBD-cvs] svn commit by lars - r2318 - trunk/user - fixed bad side
	effects of too much paranoia... 
Message-ID: <20060801075246.39E3E2CE6E2F@mail.linbit.com>

Author: lars
Date: 2006-08-01 09:52:45 +0200 (Tue, 01 Aug 2006)
New Revision: 2318

Modified:
   trunk/user/drbdadm_adjust.c
   trunk/user/drbdadm_parser.c
Log:
fixed bad side effects of too much paranoia...


Modified: trunk/user/drbdadm_adjust.c
===================================================================
--- trunk/user/drbdadm_adjust.c	2006-07-31 14:29:02 UTC (rev 2317)
+++ trunk/user/drbdadm_adjust.c	2006-08-01 07:52:45 UTC (rev 2318)
@@ -187,6 +187,7 @@
 
 	yyin = m_popen(&pid,argv);
 	line = 1;
+	config_file = "drbdsetup/show";
 	running = parse_resource("drbdsetup/show");
 	fclose(yyin);
 	waitpid(pid,0,0);

Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-07-31 14:29:02 UTC (rev 2317)
+++ trunk/user/drbdadm_parser.c	2006-08-01 07:52:45 UTC (rev 2318)
@@ -368,7 +368,8 @@
 			EXP(TK_INTEGER);
 			host->port = yylval.txt;
 			range_check(R_PORT, "port", yylval.txt);
-			check_uniq("IP", "%s:%s", host->address, host->port);
+			if (!require_all) /* if not drbdsetup_dump */
+				check_uniq("IP", "%s:%s", host->address, host->port);
 			EXP(';');
 			break;
 		case TK_META_DISK:
@@ -505,8 +506,10 @@
 
 	if(local) {
 		res->me = host;
+		host->name = strdup("_this_host");
 	} else {
 		res->peer = host;
+		host->name = strdup("_remote_host");
 	}
 
 	parse_host_body(host,res,0);

From drbd-cvs at lists.linbit.com  Tue Aug  1 12:06:04 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 12:06:05 2006
Subject: [DRBD-cvs] svn commit by phil - r2319 - trunk/drbd - Fixed the
	ASSERTS. The w_try_send_barrier() was simply 
Message-ID: <20060801100604.DEB032DC7051@mail.linbit.com>

Author: phil
Date: 2006-08-01 12:06:03 +0200 (Tue, 01 Aug 2006)
New Revision: 2319

Modified:
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_req.c
   trunk/drbd/drbd_worker.c
Log:
Fixed the ASSERTS. The w_try_send_barrier() was simply wrong.


Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-01 07:52:45 UTC (rev 2318)
+++ trunk/drbd/drbd_int.h	2006-08-01 10:06:03 UTC (rev 2319)
@@ -749,7 +749,6 @@
 	volatile unsigned long last_received; // in jiffies, either socket
 	volatile unsigned int ko_count;
 	struct drbd_work  resync_work,
-			  barrier_work,
 			  unplug_work,
 	                  md_sync_work;
 	struct timer_list resync_timer;

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-01 07:52:45 UTC (rev 2318)
+++ trunk/drbd/drbd_main.c	2006-08-01 10:06:03 UTC (rev 2319)
@@ -231,35 +231,9 @@
 }
 
 /**
- * tl_add_barrier: Creates a new barrier object and links it into the
- * transfer log. It returns the the newest (but not the just created 
- * barrier to the caller.
+ * _tl_add_barrier: Adds a barrier to the TL. It returns the the newest 
+ * (but not the just created barrier) to the caller.
  */
-struct drbd_barrier *tl_add_barrier(drbd_dev *mdev)
-{
-	struct drbd_barrier *new, *newest_before;
-
-	new=kmalloc(sizeof(struct drbd_barrier),GFP_NOIO);
-	if(!new) {
-		ERR("could not kmalloc() barrier\n");
-		return 0;
-	}
-	INIT_LIST_HEAD(&new->requests);
-	new->next=0;
-	new->n_req=0;
-
-	spin_lock_irq(&mdev->tl_lock);
-	/* mdev->newest_barrier == NULL "cannot happen". but anyways... */
-	newest_before = mdev->newest_barrier;
-	/* never send a barrier number == 0 */
-	new->br_number = (newest_before->br_number+1) ?: 1;
-	mdev->newest_barrier->next = new;
-	mdev->newest_barrier = new;
-	spin_unlock_irq(&mdev->tl_lock);
-
-	return newest_before;
-}
-
 struct drbd_barrier *_tl_add_barrier(drbd_dev *mdev,struct drbd_barrier *new)
 {
 	struct drbd_barrier *newest_before;
@@ -2016,12 +1990,10 @@
 	INIT_LIST_HEAD(&mdev->data.work.q);
 	INIT_LIST_HEAD(&mdev->meta.work.q);
 	INIT_LIST_HEAD(&mdev->resync_work.list);
-	INIT_LIST_HEAD(&mdev->barrier_work.list);
 	INIT_LIST_HEAD(&mdev->unplug_work.list);
 	INIT_LIST_HEAD(&mdev->md_sync_work.list);
 	INIT_LIST_HEAD(&mdev->discard);
 	mdev->resync_work.cb  = w_resync_inactive;
-	mdev->barrier_work.cb = w_try_send_barrier;
 	mdev->unplug_work.cb  = w_send_write_hint;
 	mdev->md_sync_work.cb = w_md_sync;
 	init_timer(&mdev->resync_timer);
@@ -2132,7 +2104,6 @@
 	D_ASSERT(list_empty(&mdev->data.work.q));
 	D_ASSERT(list_empty(&mdev->meta.work.q));
 	D_ASSERT(list_empty(&mdev->resync_work.list));
-	D_ASSERT(list_empty(&mdev->barrier_work.list));
 	D_ASSERT(list_empty(&mdev->unplug_work.list));
 
 	drbd_set_defaults(mdev);

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-01 07:52:45 UTC (rev 2318)
+++ trunk/drbd/drbd_req.c	2006-08-01 10:06:03 UTC (rev 2319)
@@ -57,6 +57,7 @@
 	   Try to get the locking right :) */
 
 	struct Drbd_Conf* mdev = drbd_req_get_mdev(req);
+	struct drbd_barrier *b;
 	unsigned long flags=0;
 	int uptodate;
 
@@ -124,12 +125,17 @@
 	drbd_req_free(req);
 
  out:
-	if (test_bit(ISSUE_BARRIER,&mdev->flags)) {
-		spin_lock_irqsave(&mdev->data.work.q_lock,flags);
-		if(list_empty(&mdev->barrier_work.list)) {
-			_drbd_queue_work(&mdev->data.work,&mdev->barrier_work);
+	b = kmalloc(sizeof(struct drbd_barrier),GFP_NOIO);
+	if(b) {
+		spin_lock_irq(&mdev->tl_lock);
+		if(test_and_clear_bit(ISSUE_BARRIER,&mdev->flags)) {
+			b = _tl_add_barrier(mdev,b);
+			b->w.cb =  w_send_barrier;
+			drbd_queue_work(&mdev->data.work, &b->w);
+		} else {
+			kfree(b);
 		}
-		spin_unlock_irqrestore(&mdev->data.work.q_lock,flags);
+		spin_unlock_irq(&mdev->tl_lock);
 	}
 }
 
@@ -379,6 +385,7 @@
 					local=0;
 
 					drbd_end_req(req, RQ_DRBD_DONE, 1, sector);
+					if(b) kfree(b);
 					return 0;
 				}
 			} else {

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-01 07:52:45 UTC (rev 2318)
+++ trunk/drbd/drbd_worker.c	2006-08-01 10:06:03 UTC (rev 2319)
@@ -518,21 +518,6 @@
 	return ok;
 }
 
-int w_try_send_barrier(drbd_dev *mdev, struct drbd_work *w, int cancel)
-{
-	int ok=1;
-
-	if(unlikely(cancel)) return ok;
-
-	down(&mdev->data.mutex);
-	if(test_and_clear_bit(ISSUE_BARRIER,&mdev->flags)) {
-		ok = _drbd_send_barrier(mdev,tl_add_barrier(mdev));
-	}
-	up(&mdev->data.mutex);
-
-	return ok;
-}
-
 int w_send_barrier(drbd_dev *mdev, struct drbd_work *w, int cancel)
 {
 	struct drbd_barrier *b = (struct drbd_barrier *)w;

From drbd-cvs at lists.linbit.com  Tue Aug  1 12:35:27 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 12:35:29 2006
Subject: [DRBD-cvs] svn commit by phil - r2320 - trunk/user - * Allow to
	specify the protocol in the common section.
Message-ID: <20060801103527.D74D22DF6275@mail.linbit.com>

Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Author: phil
Date: 2006-08-01 12:35:23 +0200 (Tue, 01 Aug 2006)
New Revision: 2320

Modified:
   trunk/user/drbdadm_main.c
   trunk/user/drbdadm_parser.c
Log:
* Allow to specify the protocol in the common section.
* It is spelled 'flexible-meta-disk'.



Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-08-01 10:06:03 UTC (rev 2319)
+++ trunk/user/drbdadm_main.c	2006-08-01 10:35:23 UTC (rev 2320)
@@ -319,7 +319,7 @@
 static int adm_dump(struct d_resource* res,const char* unused __attribute((unused)))
 {
   printI("resource %s {\n",esc(res->name)); ++indent;
-  printA("protocol",res->protocol);
+  if(res->protocol) printA("protocol",res->protocol);
   dump_host_info(res->me);
   dump_host_info(res->peer);
   dump_options("net",res->net_options);
@@ -482,6 +482,9 @@
     expand_opts(common->sync_options,    &res->sync_options);
     expand_opts(common->startup_options, &res->startup_options);
     expand_opts(common->handlers,        &res->handlers);
+    if(common->protocol && ! res->protocol) {
+      res->protocol = strdup(common->protocol);
+    }
   }
 }
 

Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-01 10:06:03 UTC (rev 2319)
+++ trunk/user/drbdadm_parser.c	2006-08-01 10:35:23 UTC (rev 2320)
@@ -413,7 +413,7 @@
 			goto break_loop;
 		default:
 			pe_expected("disk | device | address | meta-disk "
-				    "| flex-meta-disk");
+				    "| flexible-meta-disk");
 		}
 	}
       break_loop:

From drbd-cvs at lists.linbit.com  Tue Aug  1 14:30:00 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 14:30:01 2006
Subject: [DRBD-cvs] svn commit by phil - r2321 - trunk/drbd - Fixes an
	endless loop (with irq-lock spinlock...) in th
Message-ID: <20060801123000.A29872DF6275@mail.linbit.com>

Author: phil
Date: 2006-08-01 14:29:59 +0200 (Tue, 01 Aug 2006)
New Revision: 2321

Modified:
   trunk/drbd/drbd_worker.c
Log:
Fixes an endless loop (with irq-lock spinlock...) in the resync
dependency pause/resume code.


Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-01 10:35:23 UTC (rev 2320)
+++ trunk/drbd/drbd_worker.c	2006-08-01 12:29:59 UTC (rev 2321)
@@ -847,8 +847,7 @@
 		if ( odev->state.conn == SyncSource ||
 		     odev->state.conn == SyncTarget ) {
 			if (! _drbd_may_sync_now(odev)) {
-				_drbd_rs_pause(odev,AfterDependency);
-				rv = 1;
+				rv |= _drbd_rs_pause(odev,AfterDependency);
 			}
 		}
 	}
@@ -872,8 +871,7 @@
 		if ( odev->state.conn == PausedSyncS ||
 		     odev->state.conn == PausedSyncT ) {
 			if (_drbd_may_sync_now(odev)) {
-				_drbd_rs_resume(odev,AfterDependency);
-				rv = 1;
+				rv |= _drbd_rs_resume(odev,AfterDependency);
 			}
 		}
 	}

From drbd-cvs at lists.linbit.com  Tue Aug  1 14:45:10 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 14:45:14 2006
Subject: [DRBD-cvs] svn commit by lars - r2322 - trunk/user - disable
	check_uniq once the config file is sucessfully 
Message-ID: <20060801124513.5F47D2DF6275@mail.linbit.com>

Author: lars
Date: 2006-08-01 14:45:09 +0200 (Tue, 01 Aug 2006)
New Revision: 2322

Modified:
   trunk/user/drbdadm_adjust.c
   trunk/user/drbdadm_main.c
   trunk/user/drbdadm_parser.c
Log:
disable check_uniq once the config file is sucessfully validated,
so it won't interfere with parsing the output of drbdsetup show.


Modified: trunk/user/drbdadm_adjust.c
===================================================================
--- trunk/user/drbdadm_adjust.c	2006-08-01 12:29:59 UTC (rev 2321)
+++ trunk/user/drbdadm_adjust.c	2006-08-01 12:45:09 UTC (rev 2322)
@@ -179,6 +179,7 @@
 	int do_attach=0;
 	int do_connect=0;
 	int do_syncer=0;
+	char config_file_dummy[250];
 
 	argv[argc++]=drbdsetup;
 	argv[argc++]=res->me->device;
@@ -187,8 +188,9 @@
 
 	yyin = m_popen(&pid,argv);
 	line = 1;
-	config_file = "drbdsetup/show";
-	running = parse_resource("drbdsetup/show");
+	sprintf(config_file_dummy,"drbdsetup %s show", res->me->device);
+	config_file = config_file_dummy;
+	running = parse_resource(config_file_dummy);
 	fclose(yyin);
 	waitpid(pid,0,0);
 

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-08-01 12:29:59 UTC (rev 2321)
+++ trunk/user/drbdadm_main.c	2006-08-01 12:45:09 UTC (rev 2322)
@@ -1291,6 +1291,11 @@
   ENTRY e, *ep;
   e.key = e.data = ep = NULL;
 
+  /* if we are done parsing the config file,
+   * switch off this paranoia */
+  if (config_valid >= 2)
+	  return 1;
+
   va_start(ap, fmt);
   rv=vasprintf(&e.key,fmt,ap);
   va_end(ap);
@@ -1562,6 +1567,10 @@
 
   if(!config_valid) exit(E_config_invalid);
 
+  /* disable check_uniq, so it won't interfere
+   * with parsing of drbdsetup show output */
+  config_valid = 2;
+
   if (config == NULL) {
     fprintf(stderr, "no resources defined!\n");
     exit(0); /* THINK exit here? what code? */

Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-01 12:29:59 UTC (rev 2321)
+++ trunk/user/drbdadm_parser.c	2006-08-01 12:45:09 UTC (rev 2322)
@@ -368,8 +368,7 @@
 			EXP(TK_INTEGER);
 			host->port = yylval.txt;
 			range_check(R_PORT, "port", yylval.txt);
-			if (!require_all) /* if not drbdsetup_dump */
-				check_uniq("IP", "%s:%s", host->address, host->port);
+			check_uniq("IP", "%s:%s", host->address, host->port);
 			EXP(';');
 			break;
 		case TK_META_DISK:

From drbd-cvs at lists.linbit.com  Tue Aug  1 15:34:57 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 15:34:58 2006
Subject: [DRBD-cvs] svn commit by phil - r2323 - trunk/user - Various fixes
	to make "drbdadm adjust" work 
Message-ID: <20060801133457.C67352DF6275@mail.linbit.com>

Author: phil
Date: 2006-08-01 15:34:56 +0200 (Tue, 01 Aug 2006)
New Revision: 2323

Modified:
   trunk/user/drbdadm_parser.c
   trunk/user/drbdsetup.c
Log:
Various fixes to make "drbdadm adjust" work


Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-01 12:45:09 UTC (rev 2322)
+++ trunk/user/drbdadm_parser.c	2006-08-01 13:34:56 UTC (rev 2323)
@@ -406,7 +406,17 @@
 			host->meta_disk = yylval.txt;
 			host->meta_index = strdup("flexible");
 			check_meta_disk(host);
-			EXP(';');
+			switch (yylex()) {
+			case TK__MAJOR:
+				EXP(TK_INTEGER);
+				host->meta_major = atoi(yylval.txt);
+				EXP(TK__MINOR);
+				EXP(TK_INTEGER);
+				host->meta_minor = atoi(yylval.txt);
+				EXP(';');
+			case ';':
+				break;
+			}
 			break;
 		case '}':
 			goto break_loop;

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-01 12:45:09 UTC (rev 2322)
+++ trunk/user/drbdsetup.c	2006-08-01 13:34:56 UTC (rev 2323)
@@ -946,6 +946,7 @@
   struct ioctl_get_config current_cn;
   int err;
 
+  /*
   err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&current_cn);
   if(err)
     {
@@ -958,7 +959,14 @@
   cn.config.al_extents = current_cn.sconf.al_extents;
   cn.config.use_csums = 0; //current_cn.sconf.use_csums;
   cn.config.skip = 0; //current_cn.sconf.skip;
+  */
+  cn.config.rate = DEF_SYNC_RATE;
+  cn.config.after = DEF_SYNC_AFTER;
+  cn.config.al_extents = DEF_SYNC_AL_EXTENTS;
+  cn.config.use_csums = 0; //current_cn.sconf.use_csums;
+  cn.config.skip = 0; //current_cn.sconf.skip;
 
+
   if(argc > 0)
     {
       while(1)
@@ -1340,9 +1348,9 @@
 printf(";  \t# " U "\n")
 
 #define SHOW_IU(T,U1,U2,M,D) \
-printf("\t" T "\t%d",M); \
+printf("\t" T "\t%d"U1,M); \
 if(M==D) printf(" _is_default"); \
-printf(U1";  \t# " U2 "\n")
+printf(";  \t# " U2 "\n")
 
 #define SHOW_H(T,M,D,H) \
 printf("\t" T "\t%s",H[M]); \
@@ -1392,7 +1400,7 @@
       printf("}\n");
     }
 
-  if( cn.state.conn > StandAlone)
+  if( cn.state.disk > Diskless || cn.state.conn > StandAlone)
     {
       printf("syncer {\n");
       SHOW_IU("rate\t","K","(K)Byte/second", cn.sconf.rate, DEF_SYNC_RATE);
@@ -1401,10 +1409,7 @@
       if( cn.sconf.skip ) printf("\tskip-sync;\n");
       if( cn.sconf.use_csums ) printf("\tuse-csums;\n");
       printf("}\n");
-    }
 
-  if( cn.state.disk > Diskless || cn.state.conn > StandAlone)
-    {
       err=fstat(drbd_fd,&sb);
       if(err)
 	{
@@ -1423,12 +1428,20 @@
 	  cn.lower_device_minor == cn.meta_device_minor ) {
 	printf("\tmeta-disk\tinternal;\n");
       } else {
-	printf("\tmeta-disk\t\"%s\" [%d] _major %d _minor %d;\n",
-	       check_dev_name(cn.meta_device_name,cn.meta_device_major,
-			      cn.meta_device_minor),
-	       cn.meta_index,
-	       cn.meta_device_major,
-	       cn.meta_device_minor);
+	if( cn.meta_index == DRBD_MD_INDEX_FLEX_EXT ) {
+  	  printf("\tflexible-meta-disk\t\"%s\" _major %d _minor %d;\n",
+		 check_dev_name(cn.meta_device_name,cn.meta_device_major,
+				cn.meta_device_minor),
+		 cn.meta_device_major,
+		 cn.meta_device_minor);
+	} else {
+  	  printf("\tmeta-disk\t\"%s\" [%d] _major %d _minor %d;\n",
+		 check_dev_name(cn.meta_device_name,cn.meta_device_major,
+				cn.meta_device_minor),
+		 cn.meta_index,
+		 cn.meta_device_major,
+		 cn.meta_device_minor);
+	}
       }
 
       if( cn.state.conn > StandAlone) {

From drbd-cvs at lists.linbit.com  Tue Aug  1 15:44:12 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 15:44:14 2006
Subject: [DRBD-cvs] svn commit by phil - r2324 - trunk/drbd - And fixed a
	bug where the "sync after" code did not got
Message-ID: <20060801134412.A88722DF6275@mail.linbit.com>

Author: phil
Date: 2006-08-01 15:44:11 +0200 (Tue, 01 Aug 2006)
New Revision: 2324

Modified:
   trunk/drbd/drbd_worker.c
Log:
And fixed a bug where the "sync after" code did not got the pauses 
with sync-after dependencies right.


Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-01 13:34:56 UTC (rev 2323)
+++ trunk/drbd/drbd_worker.c	2006-08-01 13:44:11 UTC (rev 2324)
@@ -844,11 +844,8 @@
 
 	for (i=0; i < minor_count; i++) {
 		odev = drbd_conf + i;
-		if ( odev->state.conn == SyncSource ||
-		     odev->state.conn == SyncTarget ) {
-			if (! _drbd_may_sync_now(odev)) {
-				rv |= _drbd_rs_pause(odev,AfterDependency);
-			}
+		if (! _drbd_may_sync_now(odev)) {
+			rv |= _drbd_rs_pause(odev,AfterDependency);
 		}
 	}
 

From drbd-cvs at lists.linbit.com  Tue Aug  1 16:39:41 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  1 16:39:42 2006
Subject: [DRBD-cvs] svn commit by phil - r2325 - in branches/drbd-0.7: .
	debian drbd/linux - Preparing the 0.7.21 release 
Message-ID: <20060801143941.AB6702DC7051@mail.linbit.com>

Author: phil
Date: 2006-08-01 16:39:39 +0200 (Tue, 01 Aug 2006)
New Revision: 2325

Modified:
   branches/drbd-0.7/ChangeLog
   branches/drbd-0.7/debian/changelog
   branches/drbd-0.7/drbd.spec.in
   branches/drbd-0.7/drbd/linux/drbd_config.h
Log:
Preparing the 0.7.21 release


Modified: branches/drbd-0.7/ChangeLog
===================================================================
--- branches/drbd-0.7/ChangeLog	2006-08-01 13:44:11 UTC (rev 2324)
+++ branches/drbd-0.7/ChangeLog	2006-08-01 14:39:39 UTC (rev 2325)
@@ -6,6 +6,14 @@
  Cumulative changes since last tarball.
  For even more detail, use "svn log" and "svn diff".
 
+0.7.21 (api:79/proto:74)
+-----
+ * Fixed the "syncer stalled" after reconnect symptom.
+ * Fixed the "stalled in WFParams" after reconnect symptom. The cause
+   of this bug was actually a misuse of the data socket.
+ * Allow to set the uplug_watermark to 1, only usefull for very strange
+   cases.
+
 0.7.20 (api:79/proto:74)
 -----
  * The GC comparison code failed to start a resync in case the two

Modified: branches/drbd-0.7/debian/changelog
===================================================================
--- branches/drbd-0.7/debian/changelog	2006-08-01 13:44:11 UTC (rev 2324)
+++ branches/drbd-0.7/debian/changelog	2006-08-01 14:39:39 UTC (rev 2325)
@@ -1,3 +1,9 @@
+drbd (0.7.21-0) unstable; urgency=low
+
+  * New upstream release
+
+ -- Philipp Reisner <phil@linbit.com>  Tue, 01 Aug 2006 16:34:22 +0200
+
 drbd (0.7.20-0) unstable; urgency=low
 
   * New upstream release

Modified: branches/drbd-0.7/drbd/linux/drbd_config.h
===================================================================
--- branches/drbd-0.7/drbd/linux/drbd_config.h	2006-08-01 13:44:11 UTC (rev 2324)
+++ branches/drbd-0.7/drbd/linux/drbd_config.h	2006-08-01 14:39:39 UTC (rev 2325)
@@ -22,7 +22,7 @@
 
 extern const char * drbd_buildtag(void);
 
-#define REL_VERSION "0.7.20"
+#define REL_VERSION "0.7.21"
 #define API_VERSION 79
 #define PRO_VERSION 74
 

Modified: branches/drbd-0.7/drbd.spec.in
===================================================================
--- branches/drbd-0.7/drbd.spec.in	2006-08-01 13:44:11 UTC (rev 2324)
+++ branches/drbd-0.7/drbd.spec.in	2006-08-01 14:39:39 UTC (rev 2325)
@@ -190,6 +190,14 @@
 /sbin/depmod -a -F /boot/System.map-%{kernelversion} %{kernelversion} >/dev/null 2>&1 || true
 
 %changelog
+* Tue Aug  1 2006 16:34:22 +0200 Philipp Reisner <phil@linbit.com>
+- drbd (0.7.21-1)
+ * Fixed the "syncer stalled" after reconnect symptom.
+ * Fixed the "stalled in WFParams" after reconnect symptom. The cause
+   of this bug was actually a misuse of the data socket.
+ * Allow to set the uplug_watermark to 1, only usefull for very strange
+   cases.
+
 * Tue Jul  4 2006 15:13:15 +0200 Philipp Reisner <phil@linbit.com>
 - drbd (0.7.20-1)
  * The GC comparison code failed to start a resync in case the two

From drbd-cvs at lists.linbit.com  Wed Aug  2 10:53:59 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Aug  2 10:54:01 2006
Subject: [DRBD-cvs] svn commit by phil - r2326 - branches/drbd-0.7/drbd -
	OOps, there is no lru_cache.used member in drbd-0.7 
Message-ID: <20060802085400.0569D2CE6E4E@mail.linbit.com>

Author: phil
Date: 2006-08-02 10:53:59 +0200 (Wed, 02 Aug 2006)
New Revision: 2326

Modified:
   branches/drbd-0.7/drbd/drbd_actlog.c
Log:
OOps, there is no lru_cache.used member in drbd-0.7


Modified: branches/drbd-0.7/drbd/drbd_actlog.c
===================================================================
--- branches/drbd-0.7/drbd/drbd_actlog.c	2006-08-01 14:39:39 UTC (rev 2325)
+++ branches/drbd-0.7/drbd/drbd_actlog.c	2006-08-02 08:53:59 UTC (rev 2326)
@@ -985,7 +985,6 @@
 		clear_bit(BME_NO_WRITES,&bm_ext->flags);
 		lc_del(mdev->resync,&bm_ext->lce);
 	}
-	mdev->resync->used=0;
 	atomic_set(&mdev->resync_locked,0);   
 	spin_unlock_irq(&mdev->al_lock);
 	wake_up(&mdev->al_wait);

From drbd-cvs at lists.linbit.com  Wed Aug  2 11:32:19 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Aug  2 11:32:22 2006
Subject: [DRBD-cvs] svn commit by phil - r2327 - tags - And the release of
	drbd-0.7.21 ... 
Message-ID: <20060802093219.D3CF72CE6E4E@mail.linbit.com>

Author: phil
Date: 2006-08-02 11:32:18 +0200 (Wed, 02 Aug 2006)
New Revision: 2327

Added:
   tags/drbd-0.7.21/
Log:
And the release of drbd-0.7.21 ...


Copied: tags/drbd-0.7.21 (from rev 2326, branches/drbd-0.7)

From drbd-cvs at lists.linbit.com  Thu Aug  3 18:18:55 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Aug  3 18:18:57 2006
Subject: [DRBD-cvs] svn commit by lars - r2333 - trunk/user - * fix some
	bogus "error" messages for dump when protoco
Message-ID: <20060803161855.97A392DF6278@mail.linbit.com>

Author: lars
Date: 2006-08-03 18:18:52 +0200 (Thu, 03 Aug 2006)
New Revision: 2333

Modified:
   trunk/user/drbdadm.h
   trunk/user/drbdadm_main.c
   trunk/user/drbdadm_usage_cnt.c
   trunk/user/drbdsetup.c
Log:
 * fix some bogus "error" messages for dump
   when protocol is defined in common section only
 * make "drbdadm -d dump" expand the common section
 * fix usage count dialog to do nothing when called
   from init, or stdin/stdout is not a tty, and
   make additional output go to stderr in any case,
   to not confuse "X=`drbdadm sh-resources`" and the like.


Modified: trunk/user/drbdadm.h
===================================================================
--- trunk/user/drbdadm.h	2006-08-03 10:17:00 UTC (rev 2332)
+++ trunk/user/drbdadm.h	2006-08-03 16:18:52 UTC (rev 2333)
@@ -127,6 +127,7 @@
 extern struct d_globals global_options;
 extern int line, fline, c_resource_start;
 
+extern int no_tty;
 extern int dry_run;
 extern char* drbdsetup;
 extern char ss_buffer[255];

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-08-03 10:17:00 UTC (rev 2332)
+++ trunk/user/drbdadm_main.c	2006-08-03 16:18:52 UTC (rev 2333)
@@ -120,6 +120,7 @@
 int nr_resources;
 int highest_minor;
 int config_valid=1;
+int no_tty;
 int dry_run;
 int do_verify_ips;
 char* drbdsetup;
@@ -320,6 +321,7 @@
 {
   printI("resource %s {\n",esc(res->name)); ++indent;
   if(res->protocol) printA("protocol",res->protocol);
+  // else if (common && common->protocol) printA("# common protocol", common->protocol);
   dump_host_info(res->me);
   dump_host_info(res->peer);
   dump_options("net",res->net_options);
@@ -1016,7 +1018,7 @@
 
   saved_stdin = -1;
   saved_stdout = -1;
-  if( isatty(fileno(stdin)) == 0 || isatty(fileno(stdout)) == 0 ) {
+  if (no_tty) {
     fprintf(stderr,"WARN: stdin/stdout is not a TTY; using /dev/console");
     fprintf(stdout,"WARN: stdin/stdout is not a TTY; using /dev/console");
     saved_stdin  = dup(fileno(stdin));
@@ -1337,10 +1339,13 @@
   struct d_option* opt;
 
   if (!res->protocol) {
-    fprintf(stderr,
-	    "%s:%d: in resource %s:\n\tprotocol definition missing.\n",
-	    config_file, c_resource_start, res->name);
-    config_valid = 0;
+    if (!common || !common->protocol) {
+      fprintf(stderr,
+	      "%s:%d: in resource %s:\n\tprotocol definition missing.\n",
+	      config_file, c_resource_start, res->name);
+      config_valid = 0;
+    } /* else:
+       * may not have been expanded yet for "dump" subcommand */
   } else {
     res->protocol[0] = toupper(res->protocol[0]);
   }
@@ -1408,6 +1413,7 @@
   dry_run=0;
   yyin=NULL;
   uname(&nodeinfo); /* FIXME maybe fold to lower case ? */
+  no_tty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
 
   env_drbd_nodename = getenv("__DRBD_NODE__");
   if (env_drbd_nodename && *env_drbd_nodename) {
@@ -1612,9 +1618,9 @@
       if (optind + 1 > argc && !is_dump)
         print_usage_and_exit("missing arguments"); // arguments missing.
 
-      if(!is_dump) {
-	expand_common();
-	global_validate();
+      if (!is_dump || dry_run) expand_common();
+      global_validate();
+      if (!is_dump) {
 	if(!config_valid) exit(E_config_invalid);
 
         for_each_resource(res,tmp,config) {

Modified: trunk/user/drbdadm_usage_cnt.c
===================================================================
--- trunk/user/drbdadm_usage_cnt.c	2006-08-03 10:17:00 UTC (rev 2332)
+++ trunk/user/drbdadm_usage_cnt.c	2006-08-03 16:18:52 UTC (rev 2333)
@@ -268,7 +268,7 @@
 			if (buffer[0] == '\r' || buffer[0] == '\n')
 				writeit = 1;
 		} else {
-			printf("%s", buffer);
+			fprintf(stderr,"%s", buffer);
 		}
 	}
 	fclose(sockfd);
@@ -316,6 +316,14 @@
 	if( type == UC_NO ) return;
 	if( getuid() != 0 ) return;
 
+	/* not when running directly from init,
+	 * or if stdout is no tty.
+	 * you do not want to have the "user information message"
+	 * as output from `drbdadm sh-resources all`
+	 */
+	if (getenv("INIT_VERSION")) return;
+	if (no_tty) return;
+
 	current = current_svn_revision();
 
 	if( ! read_node_id(&ni) ) {
@@ -335,7 +343,7 @@
 
 	n_comment[0]=0;
 	if (type == UC_ASK ) {
-		printf(
+		fprintf(stderr,
 "\n"
 "\t\t--== This is %s of DRBD ==--\n"
 "Please take part in the global DRBD usage count at http://"HTTP_HOST".\n\n"
@@ -370,12 +378,12 @@
 	if (send) {
 		write_node_id(&ni);
 
-		printf(
+		fprintf(stderr,
 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
 "  --==  Thank you for participating in the global usage survey  ==--\n"
 "The server's response is:\n\n");
 		make_get_request(req_buf);
-		printf(
+		fprintf(stderr,
 "\n"
 "In the future drbdadm will only contact "HTTP_HOST" when you update\n"
 "DRBD or when you use 'drbdadm create-md'. Of course it will continue\n"
@@ -458,7 +466,7 @@
 
 		if( global_options.usage_count == UC_YES ) send = 1;
 		if( global_options.usage_count == UC_ASK ) {
-			printf(
+			fprintf(stderr,
 "\n"
 "\t\t--== Creating metadata ==--\n"
 "As with nodes we count the total number of devices mirrored by DRBD at\n"

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-03 10:17:00 UTC (rev 2332)
+++ trunk/user/drbdsetup.c	2006-08-03 16:18:52 UTC (rev 2333)
@@ -943,10 +943,10 @@
 int cmd_syncer(int drbd_fd,char** argv,int argc,struct option *options)
 {
   struct ioctl_syncer_config cn;
-  struct ioctl_get_config current_cn;
   int err;
 
   /*
+  struct ioctl_get_config current_cn;
   err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&current_cn);
   if(err)
     {

From drbd-cvs at lists.linbit.com  Sun Aug  6 15:11:44 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sun Aug  6 15:11:45 2006
Subject: [DRBD-cvs] svn commit by phil - r2335 - trunk/testing - Proove of
	conect of the tag-based binary interface. 
Message-ID: <20060806131144.99A7F2CE7342@mail.linbit.com>

Author: phil
Date: 2006-08-06 15:11:43 +0200 (Sun, 06 Aug 2006)
New Revision: 2335

Added:
   trunk/testing/tag-magic.h
   trunk/testing/tag-test.h
   trunk/testing/tag-test1.c
Log:
Proove of conect of the tag-based binary interface.


Added: trunk/testing/tag-magic.h
===================================================================
--- trunk/testing/tag-magic.h	2006-08-04 10:13:54 UTC (rev 2334)
+++ trunk/testing/tag-magic.h	2006-08-06 13:11:43 UTC (rev 2335)
@@ -0,0 +1,96 @@
+#ifndef TAG_MAGIC_H
+#define TAG_MAGIC_H
+
+#define TT_END     0
+
+// create packet_type enums
+enum packet_types {
+#define PACKET(name, fields) P_ ## name,
+#define INTEGER(pn,member)
+#define STRING(pn,member,len)
+#include "tag-test.h"
+};
+
+// declate structs
+#define PACKET(name, fields) struct name { fields };
+#define INTEGER(pn,member) int member;
+#define STRING(pn,member,len) unsigned char member[len];
+#include "tag-test.h"
+
+// declate tag-list-sizes
+#define PACKET(name, fields) const name ## _tag_size = 1 fields ;
+#define INTEGER(pn,member) +6 
+#define STRING(pn, member,len) +2+len
+#include "tag-test.h"
+
+// convert to tag list fuctions
+#define PACKET(name, fields) \
+name ## _to_tags ( struct name * arg, unsigned char* tl) \
+{ \
+	int i=0; \
+	\
+	fields \
+	tl[i] = TT_END; \
+}
+#define INTEGER(pn,member) \
+	tl[i++] = pn; \
+	tl[i++] = sizeof(int); \
+	*(int*)(tl+i) = arg->member; \
+	i+=sizeof(int);
+#define STRING(pn,member,len) \
+	tl[i++] = pn; \
+	tl[i++] = len; \
+	strcpy(tl+i,arg->member); i+=len;
+#include "tag-test.h"
+
+// convert from tag list functions
+#define PACKET(name, fields) \
+name ## _from_tags ( unsigned char* tl, struct name * arg) \
+{ \
+	int i=0; \
+	\
+	while( tl[i] != TT_END ) { \
+		switch( tl[i++] ) { \
+		fields \
+		default: i += tl[i++]; /* ignoring unknown */ \
+		} \
+	} \
+}
+#define INTEGER(pn,member) \
+	case pn: i++; \
+		 arg->member = *(int*)(tl+i); \
+		 i+=sizeof(int); \
+		 break;
+#define STRING(pn,member,len) \
+	case pn: i++; \
+		 strcpy(tl+i,arg->member); \
+		 tl+=len; \
+		 break; 
+#include "tag-test.h"
+
+
+// dump packet functions
+#define PACKET(name, fields) \
+dump_ ## name ( const char* n, struct name * arg) \
+{ \
+	fields \
+}
+#define INTEGER(pn,member) printf( "%s.%s = %d\n",n,#member,arg->member);
+#define STRING(pn,member,len) printf( "%s.%s = %s\n",n,#member,arg->member);
+#include "tag-test.h"
+
+
+void dump_tag_list( const char* n, unsigned char* tl)
+{
+	int len;
+
+	printf("Tag list %s:\n",n);
+
+	while(*tl != TT_END) {
+		printf("tag: %u\n",(int)*tl++);
+		len = *tl++;
+		printf("len: %u\n",len);
+		tl+=len;
+	}
+}
+#endif

Added: trunk/testing/tag-test.h
===================================================================
--- trunk/testing/tag-test.h	2006-08-04 10:13:54 UTC (rev 2334)
+++ trunk/testing/tag-test.h	2006-08-06 13:11:43 UTC (rev 2335)
@@ -0,0 +1,23 @@
+/* 
+   PAKET( name,
+          TYPE ( pn, member )
+          ...
+   )
+
+   You may never reissue one of the pn arguments
+*/
+
+PACKET(syncer_conf,
+       INTEGER(1,rate)
+       INTEGER(2,after)
+       INTEGER(3,al_extents)
+)
+
+PACKET(net_conf,
+       STRING(4,my_addr,128)
+       INTEGER(5,timeout)
+)
+
+#undef PACKET
+#undef STRING
+#undef INTEGER

Added: trunk/testing/tag-test1.c
===================================================================
--- trunk/testing/tag-test1.c	2006-08-04 10:13:54 UTC (rev 2334)
+++ trunk/testing/tag-test1.c	2006-08-06 13:11:43 UTC (rev 2335)
@@ -0,0 +1,31 @@
+#include "tag-magic.h"
+
+int main(int argc, char** argv)
+{
+	struct syncer_conf sc = (struct syncer_conf) { 250, -1, 247 };
+	struct syncer_conf sc2;
+
+	struct net_conf nc = (struct net_conf) { "hallo welt",60 };
+	struct net_conf nc2;
+
+	char sct[syncer_conf_tag_size];
+	char nct[net_conf_tag_size];
+
+	dump_syncer_conf("sc",&sc);
+	dump_net_conf("nc",&nc);
+
+	printf("Converting to tag list\n");
+	syncer_conf_to_tags(&sc,sct);
+	net_conf_to_tags(&nc,nct);
+
+	dump_tag_list("sct",sct);
+	dump_tag_list("nct",nct);
+
+	printf("Converting from tag list\n");
+	syncer_conf_from_tags(sct,&sc2);
+	net_conf_from_tags(nct,&nc2);
+
+	dump_syncer_conf("sc2",&sc2);
+	dump_net_conf("nc2",&nc2);
+
+}

From drbd-cvs at lists.linbit.com  Tue Aug  8 13:57:51 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  8 13:57:53 2006
Subject: [DRBD-cvs] svn commit by lars - r2340 - branches/drbd-0.7/scripts -
	on drbddisk stop, 'fail' silently with exit code 0 if d
Message-ID: <20060808115751.E7E192D99B59@mail.linbit.com>

Author: lars
Date: 2006-08-08 13:57:50 +0200 (Tue, 08 Aug 2006)
New Revision: 2340

Modified:
   branches/drbd-0.7/scripts/drbddisk
Log:
on drbddisk stop, 'fail' silently with exit code 0 if drbd is not present

Modified: branches/drbd-0.7/scripts/drbddisk
===================================================================
--- branches/drbd-0.7/scripts/drbddisk	2006-08-08 11:06:42 UTC (rev 2339)
+++ branches/drbd-0.7/scripts/drbddisk	2006-08-08 11:57:50 UTC (rev 2340)
@@ -34,7 +34,7 @@
 	;;
     stop)
 	# exec, so the exit code of drbdadm propagates
-	exec $DRBDADM secondary $RES
+	! test -e /proc/drbd || exec $DRBDADM secondary $RES
 	;;
     status)
 	if [ "$RES" = "all" ]; then

From drbd-cvs at lists.linbit.com  Tue Aug  8 13:58:49 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  8 13:58:50 2006
Subject: [DRBD-cvs] svn commit by lars - r2341 - branches/drbd-0.7/user -
	some more commands that need not check for the presence
Message-ID: <20060808115849.C8FC72D99B59@mail.linbit.com>

Author: lars
Date: 2006-08-08 13:58:49 +0200 (Tue, 08 Aug 2006)
New Revision: 2341

Modified:
   branches/drbd-0.7/user/drbdadm_main.c
Log:
some more commands that need not check for the presence of the ip

Modified: branches/drbd-0.7/user/drbdadm_main.c
===================================================================
--- branches/drbd-0.7/user/drbdadm_main.c	2006-08-08 11:57:50 UTC (rev 2340)
+++ branches/drbd-0.7/user/drbdadm_main.c	2006-08-08 11:58:49 UTC (rev 2341)
@@ -171,15 +171,15 @@
 
 struct adm_cmd cmds[] = {
 /*   name, function, arg,                     show, needs res, verify_ips */
-  { "attach",            adm_attach,  0                  ,1,1,1 },
-  { "detach",            adm_generic_s,"detach"          ,1,1,1 },
+  { "attach",            adm_attach,  0                  ,1,1,0 },
+  { "detach",            adm_generic_s,"detach"          ,1,1,0 },
   { "connect",           adm_connect, 0                  ,1,1,1 },
   { "disconnect",        adm_generic_s,"disconnect"      ,1,1,0 },
   { "up",                adm_up,      0                  ,1,1,1 },
   { "down",              adm_generic_s,"down"            ,1,1,0 },
-  { "primary",           adm_primary, 0                  ,1,1,1 },
-  { "secondary",         adm_generic_s,"secondary"       ,1,1,1 },
-  { "invalidate",        adm_generic_l,"invalidate"      ,1,1,1 },
+  { "primary",           adm_primary, 0                  ,1,1,0 },
+  { "secondary",         adm_generic_s,"secondary"       ,1,1,0 },
+  { "invalidate",        adm_generic_l,"invalidate"      ,1,1,0 },
   { "invalidate_remote", adm_generic_l,"invalidate_remote",1,1,1 },
   { "resize",            adm_resize,  0                  ,1,1,1 },
   { "syncer",            adm_syncer,  0                  ,1,1,1 },

From drbd-cvs at lists.linbit.com  Tue Aug  8 15:28:35 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  8 15:28:37 2006
Subject: [DRBD-cvs] svn commit by phil - r2342 - trunk/drbd - Fixes for
	issues pointed out by Simon Graham.
Message-ID: <20060808132835.AC9B02D99B58@mail.linbit.com>

Author: phil
Date: 2006-08-08 15:28:34 +0200 (Tue, 08 Aug 2006)
New Revision: 2342

Modified:
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_req.c
Log:
Fixes for issues pointed out by Simon Graham.
http://lists.linbit.com/pipermail/drbd-dev/2006-August/000378.html


Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-08 11:58:49 UTC (rev 2341)
+++ trunk/drbd/drbd_receiver.c	2006-08-08 13:28:34 UTC (rev 2342)
@@ -1442,7 +1442,8 @@
 	if(!inc_local(mdev) || mdev->state.disk < UpToDate ) {
 		if (DRBD_ratelimit(5*HZ,5))
 			ERR("Can not satisfy peer's read request, no local data.\n");
-		drbd_send_ack(mdev,NegDReply,e);
+		drbd_send_ack(mdev,h->command == DataRequest ? NegDReply :
+			      NegRSDReply ,e);
 		drbd_free_ee(mdev,e);
 		return TRUE;
 	}

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-08 11:58:49 UTC (rev 2341)
+++ trunk/drbd/drbd_req.c	2006-08-08 13:28:34 UTC (rev 2342)
@@ -161,8 +161,7 @@
 
 int drbd_pr_verify(drbd_dev *mdev, drbd_request_t * req, sector_t sector)
 {
-	struct hlist_head *slot = mdev->app_reads_hash +
-		ar_hash_fn(mdev, drbd_req_get_sector(req) );
+	struct hlist_head *slot = mdev->app_reads_hash+ar_hash_fn(mdev,sector);
 	struct hlist_node *n;
 	drbd_request_t * i;
 	int rv=0;

From drbd-cvs at lists.linbit.com  Tue Aug  8 17:00:55 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  8 17:00:56 2006
Subject: [DRBD-cvs] svn commit by phil - r2343 - trunk/drbd - Another
	execellent bug report by Simon...
Message-ID: <20060808150055.BB68B2D99B58@mail.linbit.com>

Author: phil
Date: 2006-08-08 17:00:53 +0200 (Tue, 08 Aug 2006)
New Revision: 2343

Modified:
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
Log:
Another execellent bug report by Simon...
http://lists.linbit.com/pipermail/drbd-dev/2006-August/000380.html


Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-08 13:28:34 UTC (rev 2342)
+++ trunk/drbd/drbd_int.h	2006-08-08 15:00:53 UTC (rev 2343)
@@ -880,6 +880,10 @@
 			   u32 set_size);
 extern int drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd,
 			 struct Tl_epoch_entry *e);
+extern int drbd_send_ack_rp(drbd_dev *mdev, Drbd_Packet_Cmd cmd, 
+			    Drbd_BlockRequest_Packet *rp);
+extern int drbd_send_ack_dp(drbd_dev *mdev, Drbd_Packet_Cmd cmd, 
+			    Drbd_Data_Packet *dp);
 extern int _drbd_send_page(drbd_dev *mdev, struct page *page,
 			   int offset, size_t size);
 extern int drbd_send_block(drbd_dev *mdev, Drbd_Packet_Cmd cmd,

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-08 13:28:34 UTC (rev 2342)
+++ trunk/drbd/drbd_main.c	2006-08-08 15:00:53 UTC (rev 2343)
@@ -1497,31 +1497,52 @@
 	return ok;
 }
 
-
-int drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd, struct Tl_epoch_entry *e)
+/** 
+ * _drbd_send_ack:
+ * This helper function expects the sector and block_id parameter already
+ * in big endian!
+ */ 
+static int _drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd, 
+			  sector_t sector,
+			  unsigned int blksize,
+			  u64 block_id)
 {
 	int ok;
 	Drbd_BlockAck_Packet p;
 
-	p.sector   = cpu_to_be64(drbd_ee_get_sector(e));
-	p.block_id = e->block_id;
-	p.blksize  = cpu_to_be32(drbd_ee_get_size(e));
-/*
- * FIXME kernel source <= 2.6.8 don't have atomic_add_return!
- */
-#if 0
-#warning "YES I KNOW. JUST SO IT COMPILES NOW."
-	atomic_inc(&mdev->packet_seq);
-	p.seq_num = atomic_read(&mdev->packet_seq);
-#else
+	p.sector   = sector;
+	p.block_id = block_id;
+	p.blksize  = blksize;
 	p.seq_num  = cpu_to_be32(atomic_add_return(1,&mdev->packet_seq));
-#endif
 
 	if (!mdev->meta.socket || mdev->state.conn < Connected) return FALSE;
 	ok=drbd_send_cmd(mdev,USE_META_SOCKET,cmd,(Drbd_Header*)&p,sizeof(p));
 	return ok;
 }
 
+int drbd_send_ack_dp(drbd_dev *mdev, Drbd_Packet_Cmd cmd, 
+		     Drbd_Data_Packet *dp)
+{
+	const int header_size = sizeof(Drbd_Data_Packet) - sizeof(Drbd_Header);
+	int data_size  = ((Drbd_Header*)dp)->length - header_size;
+
+	return _drbd_send_ack(mdev,cmd,dp->sector,data_size,dp->block_id);
+}
+
+int drbd_send_ack_rp(drbd_dev *mdev, Drbd_Packet_Cmd cmd, 
+		     Drbd_BlockRequest_Packet *rp)
+{
+	return _drbd_send_ack(mdev,cmd,rp->sector,rp->blksize,rp->block_id);
+}
+
+int drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd, struct Tl_epoch_entry *e)
+{
+	return _drbd_send_ack(mdev,cmd,
+			      cpu_to_be64(drbd_ee_get_sector(e)),
+			      cpu_to_be32(drbd_ee_get_size(e)),
+			      e->block_id);
+}
+
 int drbd_send_drequest(drbd_dev *mdev, int cmd,
 		       sector_t sector,int size, u64 block_id)
 {

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-08 13:28:34 UTC (rev 2342)
+++ trunk/drbd/drbd_receiver.c	2006-08-08 15:00:53 UTC (rev 2343)
@@ -988,18 +988,14 @@
 	struct Tl_epoch_entry *e;
 
 	e = read_in_block(mdev,sector,data_size);
-	if(!e) return FALSE;
+	if(!e) {
+		dec_local(mdev);
+		return FALSE;
+	}
 
 	dec_rs_pending(mdev);
 
 	e->block_id = ID_SYNCER;
-	if(!inc_local(mdev)) {
-		if (DRBD_ratelimit(5*HZ,5))
-			ERR("Can not write resync data to local disk.\n");
-		drbd_send_ack(mdev,NegAck,e);
-		drbd_free_ee(mdev,e);
-		return TRUE;
-	}
 
 	drbd_ee_prepare_write(mdev,e);
 	e->w.cb     = e_end_resync_block;
@@ -1079,6 +1075,13 @@
 	sector = be64_to_cpu(p->sector);
 	D_ASSERT(p->block_id == ID_SYNCER);
 
+	if(!inc_local(mdev)) {
+		if (DRBD_ratelimit(5*HZ,5))
+			ERR("Can not write resync data to local disk.\n");
+		drbd_send_ack_dp(mdev,NegAck,p);
+		return TRUE;
+	}
+
 	ok = recv_resync_read(mdev,sector,data_size);
 
 	return ok;
@@ -1221,18 +1224,20 @@
 	if (drbd_recv(mdev, h->payload, header_size) != header_size)
 		return FALSE;
 
-	sector = be64_to_cpu(p->sector);
-	e = read_in_block(mdev,sector,data_size);
-	if (!e) return FALSE;
-
 	if(!inc_local(mdev)) {
 		if (DRBD_ratelimit(5*HZ,5))
 			ERR("Can not write mirrored data block to local disk.\n");
-		drbd_send_ack(mdev,NegAck,e);
-		rv = TRUE;
-		goto out1;
+		drbd_send_ack_dp(mdev,NegAck,p);
+		return TRUE;
 	}
 
+	sector = be64_to_cpu(p->sector);
+	e = read_in_block(mdev,sector,data_size);
+	if (!e) {
+		dec_local(mdev);
+		return FALSE;
+	}
+
 	e->block_id = p->block_id; // no meaning on this side, e* on partner
 	drbd_ee_prepare_write(mdev, e);
 	e->w.cb     = e_end_block;
@@ -1399,7 +1404,6 @@
 	 * but we drop the connection anyways, so we don't have a chance to
 	 * receive a barrier... atomic_inc(&mdev->epoch_size); */
 	dec_local(mdev);
- out1:
 	drbd_free_ee(mdev,e);
 	return rv;
 }
@@ -1431,23 +1435,25 @@
 		return FALSE;
 	}
 
+	if(!inc_local(mdev) || mdev->state.disk < UpToDate ) {
+		if (DRBD_ratelimit(5*HZ,5))
+			ERR("Can not satisfy peer's read request, no local data.\n");
+		drbd_send_ack_rp(mdev,h->command == DataRequest ? NegDReply :
+				 NegRSDReply ,p);
+		return TRUE;
+	}
+
 	e = drbd_alloc_ee(mdev,sector,size,GFP_KERNEL);
-	if (!e) return FALSE;
+	if (!e) {
+		dec_local(mdev);
+		return FALSE;
+	}
 
 	e->block_id = p->block_id; // no meaning on this side, pr* on partner
 	spin_lock_irq(&mdev->ee_lock);
 	list_add(&e->w.list,&mdev->read_ee);
 	spin_unlock_irq(&mdev->ee_lock);
 
-	if(!inc_local(mdev) || mdev->state.disk < UpToDate ) {
-		if (DRBD_ratelimit(5*HZ,5))
-			ERR("Can not satisfy peer's read request, no local data.\n");
-		drbd_send_ack(mdev,h->command == DataRequest ? NegDReply :
-			      NegRSDReply ,e);
-		drbd_free_ee(mdev,e);
-		return TRUE;
-	}
-
 	drbd_ee_prepare_read(mdev,e);
 
 	switch (h->command) {

From drbd-cvs at lists.linbit.com  Tue Aug  8 17:46:15 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug  8 17:46:17 2006
Subject: [DRBD-cvs] svn commit by phil - r2344 - trunk/drbd - Handle IO
	errors while reading the activity log right.
Message-ID: <20060808154615.4F9842D99B58@mail.linbit.com>

Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Author: phil
Date: 2006-08-08 17:46:14 +0200 (Tue, 08 Aug 2006)
New Revision: 2344

Modified:
   trunk/drbd/drbd_actlog.c
Log:
Handle IO errors while reading the activity log right.
The right thing is, to simply fail the attach request.
The issue was repoerted by Simon Graham
http://lists.linbit.com/pipermail/drbd-dev/2006-August/000386.html


Modified: trunk/drbd/drbd_actlog.c
===================================================================
--- trunk/drbd/drbd_actlog.c	2006-08-08 15:00:53 UTC (rev 2343)
+++ trunk/drbd/drbd_actlog.c	2006-08-08 15:46:14 UTC (rev 2344)
@@ -357,8 +357,6 @@
 	sector = bdev->md.md_offset + bdev->md.al_offset + index;
 
 	if(!drbd_md_sync_page_io(mdev,bdev,sector,READ)) {
-		drbd_chk_io_error(mdev, 1);
-		drbd_io_error(mdev);
 		return -1;
 	}
 

From drbd-cvs at lists.linbit.com  Wed Aug  9 16:26:14 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Aug  9 16:26:16 2006
Subject: [DRBD-cvs] svn commit by phil - r2345 - trunk/drbd - The fix to the
	issues:
Message-ID: <20060809142614.A58DD2DD05B2@mail.linbit.com>

Author: phil
Date: 2006-08-09 16:26:13 +0200 (Wed, 09 Aug 2006)
New Revision: 2345

Modified:
   trunk/drbd/drbd_receiver.c
Log:
The fix to the issues:
http://lists.linbit.com/pipermail/drbd-dev/2006-August/000381.html

and item 3 of this mail:
http://lists.linbit.com/pipermail/drbd-dev/2006-August/000382.html



Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-08 15:46:14 UTC (rev 2344)
+++ trunk/drbd/drbd_receiver.c	2006-08-09 14:26:13 UTC (rev 2345)
@@ -2124,9 +2124,11 @@
 	ns.pdsk = peer_state.disk;
 	ns.peer_isp = ( peer_state.aftr_isp | peer_state.user_isp );
 	if(nconn == Connected && ns.disk == Attaching) ns.disk = UpToDate;
-	rv = _drbd_set_state(mdev,ns,ChgStateVerbose);
+	rv = _drbd_set_state(mdev,ns,ChgStateVerbose | ChgStateHard);
 	spin_unlock_irq(&mdev->req_lock);
-	after_state_ch(mdev,os,ns,ChgStateVerbose);
+	if (rv==SS_Success) {
+		after_state_ch(mdev,os,ns,ChgStateVerbose | ChgStateHard);
+	}
 
 	if(rv < SS_Success) {
 		drbd_force_state(mdev,NS(conn,StandAlone));

From drbd-cvs at lists.linbit.com  Thu Aug 10 11:37:29 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Aug 10 11:37:32 2006
Subject: [DRBD-cvs] svn commit by phil - r2350 - in trunk/drbd: . linux -
	Applied Simon's dump-packet patch. 
Message-ID: <20060810093729.D542C2CE77A0@mail.linbit.com>

Author: phil
Date: 2006-08-10 11:37:28 +0200 (Thu, 10 Aug 2006)
New Revision: 2350

Modified:
   trunk/drbd/drbd_actlog.c
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/linux/drbd_config.h
Log:
Applied Simon's dump-packet patch.


Modified: trunk/drbd/drbd_actlog.c
===================================================================
--- trunk/drbd/drbd_actlog.c	2006-08-10 08:14:48 UTC (rev 2349)
+++ trunk/drbd/drbd_actlog.c	2006-08-10 09:37:28 UTC (rev 2350)
@@ -732,8 +732,10 @@
 	sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1);
 
 #ifdef DUMP_EACH_PACKET
-	INFO("drbd_set_in_sync: sector=%lu size=%d sbnr=%lu ebnr=%lu\n",
-			(unsigned long)sector, size, sbnr, ebnr);
+	if (dump_packets >= DUMP_MAX) {
+	    INFO("drbd_set_in_sync: sector=%llx size=%x sbnr=%lx ebnr=%lx\n",
+		 (long long)sector, size, sbnr, ebnr);
+	}
 #endif
 
 	if (sbnr > ebnr) return;
@@ -794,6 +796,13 @@
 	sbnr = BM_SECT_TO_BIT(sector);
 	ebnr = BM_SECT_TO_BIT(esector);
 
+#ifdef DUMP_EACH_PACKET
+	if (dump_packets >= DUMP_MAX) {
+	    INFO("drbd_set_out_of_sync: sector=%llx size=%x sbnr=%lx ebnr=%lx\n",
+		 (long long)sector, size, sbnr, ebnr);
+	}
+#endif
+
 	/*
 	 * ok, (capacity & 7) != 0 sometimes, but who cares...
 	 * we count rs_{total,left} in bits, not sectors.

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-10 08:14:48 UTC (rev 2349)
+++ trunk/drbd/drbd_int.h	2006-08-10 09:37:28 UTC (rev 2350)
@@ -361,8 +361,22 @@
 		[StateChgReply]    = "StateChgReply"
 	};
 
-	if (cmd == HandShake) return "HandShake";
-	if (Data > cmd || cmd >= MAX_CMD) return "Unknown";
+	if (Data > cmd || cmd >= MAX_CMD) {
+	    switch (cmd) {
+	    case HandShakeM:
+		return "HandShakeM";
+		break;
+	    case HandShakeS:
+		return "HandShakeS";
+		break;
+	    case HandShake:
+		return "HandShake";
+		break;
+	    default:
+		return "Unknown";
+		break;
+	    }
+	}
 	return cmdnames[cmd];
 }
 
@@ -543,7 +557,10 @@
 	Drbd_Sizes_Packet        Sizes;
 	Drbd_GenCnt_Packet       GenCnt;
 	Drbd_State_Packet        State;
+	Drbd_Req_State_Packet	 ReqState;
+	Drbd_RqS_Reply_Packet	 RqSReply;
 	Drbd_BlockRequest_Packet BlockRequest;
+	Drbd_Discard_Packet	 Discard;
 } __attribute((packed)) Drbd_Polymorph_Packet;
 
 /**********************************************************************/
@@ -1602,63 +1619,29 @@
 }
 
 #ifdef DUMP_EACH_PACKET
+
 /*
+ * variable that controls dumping
+ */
+extern int dump_packets;
+
+#define DUMP_NONE 0
+#define DUMP_SUMMARY 1
+#define DUMP_ALL 2
+#define DUMP_MAX 3
+
+/*
  * enable to dump information about every packet exchange.
  */
-#define INFOP(fmt, args...) \
-	INFO("%s:%d: %s [%d] %s %s " fmt , \
-	     file, line, current->comm, current->pid, \
-	     sockname, recv?"<<<":">>>" \
-	     , ## args )
+extern void _dump_packet(drbd_dev *mdev, struct socket *sock,
+			 int recv, Drbd_Polymorph_Packet *p, char* file, int line);
+
 static inline void
 dump_packet(drbd_dev *mdev, struct socket *sock,
 	    int recv, Drbd_Polymorph_Packet *p, char* file, int line)
 {
-	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:
-	case BecomeSyncSource:
-	case UnplugRemote:
-
-	case SyncParam:
-	case ReportParams:
-		INFOP("%s\n", cmdname(cmd));
-		break;
-
-	case ReportBitMap: /* don't report this */
-		break;
-
-	case Data:
-	case DataReply:
-	case RSDataReply:
-
-	case RecvAck:   /* yes I know. but it is the same layout */
-	case WriteAck:
-	case NegAck:
-
-	case DataRequest:
-	case RSDataRequest:
-		INFOP("%s (%lu,%llx)\n", cmdname(cmd),
-		     (long)be64_to_cpu(p->Data.sector), (long long)p->Data.block_id
-		);
-		break;
-
-	case Barrier:
-	case BarrierAck:
-		INFOP("%s (%u)\n", cmdname(cmd), p->Barrier.barrier);
-		break;
-
-	default:
-		INFOP("%s (%u)\n",cmdname(cmd), cmd);
-		break;
-	}
+	if (dump_packets > DUMP_NONE)
+		_dump_packet(mdev,sock,recv,p,file,line);
 }
 #else
 #define dump_packet(ignored...) ((void)0)

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-10 08:14:48 UTC (rev 2349)
+++ trunk/drbd/drbd_main.c	2006-08-10 09:37:28 UTC (rev 2350)
@@ -126,6 +126,14 @@
 #endif
 int disable_bd_claim = 0;
 
+#ifdef DUMP_EACH_PACKET
+int dump_packets = 0;	// Module parameter that controls packet tracing
+			// 0 = none
+			// 1 = summary (trace 'interesting' packets in summary fmt)
+			// 2 = verbose (trace all packets in full format)
+module_param(dump_packets,int,0644);
+#endif
+
 // devfs name
 char* drbd_devfs_name = "drbd";
 
@@ -859,6 +867,7 @@
 	}
 
 #if DUMP_MD >= 2
+	{
 	char *pbp,pb[300];
 	pbp = pb;
 	*pbp=0;
@@ -872,6 +881,7 @@
 	PSC(peer_isp);
 	PSC(user_isp);
 	INFO("%s\n", pb);
+	}
 #endif
 
 	mdev->state.i = ns.i;
@@ -2870,5 +2880,145 @@
 	return 1;
 }
 
+#ifdef DUMP_EACH_PACKET
+#define PSM(A) \
+do { \
+	if( mask.A ) { \
+		int i = snprintf(p, len, " " #A "( %s )", \
+				A##s_to_name(val.A)); \
+		if (i >= len) return op; \
+		p += i; \
+		len -= i; \
+	} \
+} while (0)
+
+STATIC char *dump_st(char *p, int len, drbd_state_t mask, drbd_state_t val)
+{
+	char *op=p;
+	*p = '\0';
+	PSM(role);
+	PSM(peer);
+	PSM(conn);
+	PSM(disk);
+	PSM(pdsk);
+
+	return op;
+}
+
+#define INFOP(fmt, args...) \
+do { \
+	if (dump_packets > DUMP_SUMMARY) { \
+		INFO("%s:%d: %s [%d] %s %s " fmt , \
+		     file, line, current->comm, current->pid, \
+		     sockname, recv?"<<<":">>>" \
+		     , ## args ); \
+	} \
+	else { \
+		INFO("%s " fmt, recv?"<<<":">>>", ## args ); \
+	} \
+} while (0)
+
+void
+_dump_packet(drbd_dev *mdev, struct socket *sock,
+	    int recv, Drbd_Polymorph_Packet *p, char* file, int line)
+{
+	char *sockname = sock == mdev->meta.socket ? "meta" : "data";
+	int cmd = (recv == 2) ? p->head.command : be16_to_cpu(p->head.command);
+	char tmp[300];
+	drbd_state_t m,v;
+
+	switch (cmd) {
+	case HandShake:
+		INFOP("%s (protocol %u)\n", cmdname(cmd), be32_to_cpu(p->HandShake.protocol_version));
+		break;
+
+	case ReportBitMap: /* don't report this */
+		break;
+
+	case Data:
+	case DataReply:
+	case RSDataReply:
+		INFOP("%s (sector %llx, id %llx, seq %x, f %x)\n", cmdname(cmd),
+		     (long long)be64_to_cpu(p->Data.sector), 
+		     (long long)be64_to_cpu(p->Data.block_id),
+		     be32_to_cpu(p->Data.seq_num),
+		     be32_to_cpu(p->Data.dp_flags)
+		);
+		break;
+
+	case RecvAck:
+	case WriteAck:
+	case NegAck:
+		INFOP("%s (sector %llx, size %x, id %llx, seq %x)\n", cmdname(cmd),
+		     (long long)be64_to_cpu(p->BlockAck.sector), 
+		     be32_to_cpu(p->BlockAck.blksize),
+		     (long long)be64_to_cpu(p->BlockAck.block_id),
+		     be32_to_cpu(p->BlockAck.seq_num)
+		);
+		break;
+
+	case DataRequest:
+	case RSDataRequest:
+		INFOP("%s (sector %llx, size %x, id %llx)\n", cmdname(cmd),
+		     (long long)be64_to_cpu(p->BlockRequest.sector), 
+		     be32_to_cpu(p->BlockRequest.blksize),
+		     (long long)be64_to_cpu(p->BlockRequest.block_id)
+		);
+		break;
+
+	case Barrier:
+	case BarrierAck:
+		INFOP("%s (barrier %u)\n", cmdname(cmd), p->Barrier.barrier);
+		break;
+
+	case ReportSizes:
+		INFOP("%s (d %lluMiB, u %lluMiB, c %lldMiB, max bio %x, q order %x)\n", cmdname(cmd), 
+		     (long long)(be64_to_cpu(p->Sizes.d_size)>>(20-9)),
+		     (long long)(be64_to_cpu(p->Sizes.u_size)>>(20-9)),
+		     (long long)(be64_to_cpu(p->Sizes.c_size)>>(20-9)),
+		     be32_to_cpu(p->Sizes.max_segment_size),
+		     be32_to_cpu(p->Sizes.queue_order_type));
+		break;
+
+	case ReportState:
+		v.i = be32_to_cpu(p->State.state);
+		m.i = 0xffffffff;
+		dump_st(tmp,sizeof(tmp),m,v);
+		INFOP("%s (s %x {%s})\n", cmdname(cmd), v.i, tmp);
+		break;
+
+	case StateChgRequest:
+		m.i = be32_to_cpu(p->ReqState.mask);
+		v.i = be32_to_cpu(p->ReqState.val);
+		dump_st(tmp,sizeof(tmp),m,v);
+		INFOP("%s (m %x v %x {%s})\n", cmdname(cmd), m.i, v.i, tmp);
+		break;
+
+	case StateChgReply:
+		INFOP("%s (ret %x)\n", cmdname(cmd), 
+		     be32_to_cpu(p->RqSReply.retcode));
+		break;
+
+	case DiscardNote:
+		INFOP("%s (id %llx, seq %x)\n", cmdname(cmd),
+		     (long long)be64_to_cpu(p->Discard.block_id),
+		     be32_to_cpu(p->Discard.seq_num));
+		break;
+
+	case Ping:
+	case PingAck:
+		/*
+		 * Dont trace pings at summary level
+		 */
+		if (dump_packets <= DUMP_SUMMARY)
+			break;
+		/* fall through... */
+	default:
+		INFOP("%s (%u)\n",cmdname(cmd), cmd);
+		break;
+	}
+}
+#endif
+
 module_init(drbd_init)
 module_exit(drbd_cleanup)

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-10 08:14:48 UTC (rev 2349)
+++ trunk/drbd/drbd_receiver.c	2006-08-10 09:37:28 UTC (rev 2350)
@@ -2375,6 +2375,8 @@
 		else
 			handler = NULL;
 
+		dump_packet(mdev,mdev->data.socket,2,&mdev->data.rbuf, __FILE__, __LINE__);
+
 		if (unlikely(!handler)) {
 			ERR("unknown packet type %d, l: %d!\n",
 			    header->command, header->length);
@@ -2385,7 +2387,6 @@
 			    cmdname(header->command), header->length);
 			break;
 		}
-		dump_packet(mdev,mdev->data.socket,2,&mdev->data.rbuf, __FILE__, __LINE__);
 	}
 }
 

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-08-10 08:14:48 UTC (rev 2349)
+++ trunk/drbd/linux/drbd_config.h	2006-08-10 09:37:28 UTC (rev 2350)
@@ -36,7 +36,8 @@
 #define DUMP_MD 2       // Dump even all cstate changes (I like it!)
 //#define PARANOIA // some extra checks
 
-// don't enable this, unless you can cope with gigabyte syslogs :)
+// Define this to enable printing of packets under control of dump_packets
+// module parameter (/sys/module/drbd/parameters/dump_packets)
 //#define DUMP_EACH_PACKET
 
 // Dump every hour the usage / not usage of zero copy IO

From drbd-cvs at lists.linbit.com  Thu Aug 10 11:47:22 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Aug 10 11:47:23 2006
Subject: [DRBD-cvs] svn commit by phil - r2351 - trunk/drbd - Another small
	fix... 
Message-ID: <20060810094722.CECBF2D99950@mail.linbit.com>

Author: phil
Date: 2006-08-10 11:46:33 +0200 (Thu, 10 Aug 2006)
New Revision: 2351

Modified:
   trunk/drbd/drbd_receiver.c
Log:
Another small fix...


Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-10 09:37:28 UTC (rev 2350)
+++ trunk/drbd/drbd_receiver.c	2006-08-10 09:46:33 UTC (rev 2351)
@@ -2281,9 +2281,9 @@
 	}
 	ns = mdev->state;
 	spin_unlock_irq(&mdev->req_lock);
-	after_state_ch(mdev,os,ns,ChgStateVerbose);
+	if( r == SS_Success) after_state_ch(mdev,os,ns,ChgStateVerbose);
 
-	if( r >= 0 ) {
+	if( r >= SS_Success) {
 		drbd_md_sync(mdev);
 		drbd_send_short_cmd(mdev, OutdatedReply);
 		return TRUE;

From drbd-cvs at lists.linbit.com  Thu Aug 10 13:32:08 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Aug 10 13:32:09 2006
Subject: [DRBD-cvs] svn commit by phil - r2356 - in trunk: documentation
	drbd drbd/linux user - Removed the long unused skip-sync
	option, and the not h
Message-ID: <20060810113208.9D35F2CE77B0@mail.linbit.com>

Author: phil
Date: 2006-08-10 13:31:57 +0200 (Thu, 10 Aug 2006)
New Revision: 2356

Modified:
   trunk/documentation/drbdsetup.sgml
   trunk/drbd/drbd_fs.c
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_sizeof_sanity_check.c
   trunk/drbd/drbd_strings.c
   trunk/drbd/linux/drbd.h
   trunk/drbd/linux/drbd_config.h
   trunk/user/drbdsetup.c
Log:
Removed the long unused skip-sync option, and the not here
implemented use-csyms option.


Modified: trunk/documentation/drbdsetup.sgml
===================================================================
--- trunk/documentation/drbdsetup.sgml	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/documentation/drbdsetup.sgml	2006-08-10 11:31:57 UTC (rev 2356)
@@ -55,7 +55,6 @@
       <command>drbdsetup</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
       <arg choice="req">syncer</arg>
-      <arg>-k</arg>
       <arg>-a<arg choice="req"><replaceable>dev_minor</replaceable></arg></arg>
       <arg>-r<arg choice="req"><replaceable>rate</replaceable></arg></arg>
       <arg>-e<arg choice="req"><replaceable>extents</replaceable></arg></arg>
@@ -587,15 +586,6 @@
 	  </listitem>
 	</varlistentry>
 	<varlistentry>
-	  <term><option>-k</option>,
-	  <option>--skip-sync </option></term>
-	  <listitem><para>
-	  This option suppresses the automatic start of the resynchronization
-	  process, which
-	  is triggered as soon as two DRBD devices are connected.
-	  </para></listitem>
-	</varlistentry>
-	<varlistentry>
 	  <term><option>-a</option>,
 	  <option>--after <replaceable>minor</replaceable></option></term>
 	  <listitem>

Modified: trunk/drbd/drbd_fs.c
===================================================================
--- trunk/drbd/drbd_fs.c	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/drbd_fs.c	2006-08-10 11:31:57 UTC (rev 2356)
@@ -1034,9 +1034,7 @@
 		}
 	}
 
-	sc.use_csums = 0; // TODO, NYI
 	ERR_IF (sc.rate < 1) sc.rate = 1;
-	ERR_IF (sc.skip & ~1) sc.skip = !!sc.skip;
 	ERR_IF (sc.al_extents < 7) sc.al_extents = 127; // arbitrary minimum
 #define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT)
 	if(sc.al_extents > AL_MAX) {
@@ -1046,8 +1044,6 @@
 #undef AL_MAX
 
 	mdev->sync_conf.rate       = sc.rate;
-	mdev->sync_conf.use_csums  = sc.use_csums;
-	mdev->sync_conf.skip       = sc.skip;
 	mdev->sync_conf.al_extents = sc.al_extents;
 
 	err = drbd_check_al_size(mdev);

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/drbd_int.h	2006-08-10 11:31:57 UTC (rev 2356)
@@ -483,8 +483,6 @@
 typedef struct {
 	Drbd_Header head;
 	u32         rate;
-	u32         use_csums;
-	u32         skip;
 	u32         after;
 } __attribute((packed)) Drbd_SyncParam_Packet;
 

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/drbd_main.c	2006-08-10 11:31:57 UTC (rev 2356)
@@ -724,7 +724,6 @@
 		rv=SS_SyncingDiskless;
 
 	else if( (ns.conn == Connected ||
-		  ns.conn == SkippedSyncS ||
 		  ns.conn == WFBitMapS ||
 		  ns.conn == SyncSource ||
 		  ns.conn == PausedSyncS) &&
@@ -782,13 +781,11 @@
 	if( ns.conn >= Connected &&
 	    ( ns.disk == Consistent || ns.disk == Outdated ) ) {
 		switch(ns.conn) {
-		case SkippedSyncT:
 		case WFBitMapT:
 		case PausedSyncT:
 			ns.disk = Outdated;
 			break;
 		case Connected:
-		case SkippedSyncS:
 		case WFBitMapS:
 		case SyncSource:
 		case PausedSyncS:
@@ -808,13 +805,11 @@
 	    ( ns.pdsk == Consistent || ns.pdsk == Outdated ) ) {
 		switch(ns.conn) {
 		case Connected:
-		case SkippedSyncT:
 		case WFBitMapT:
 		case PausedSyncT:
 		case SyncTarget:
 			ns.pdsk = UpToDate;
 			break;
-		case SkippedSyncS:
 		case WFBitMapS:
 		case PausedSyncS:
 			ns.pdsk = Outdated;
@@ -1313,8 +1308,6 @@
 	Drbd_SyncParam_Packet p;
 
 	p.rate      = cpu_to_be32(sc->rate);
-	p.use_csums = cpu_to_be32(sc->use_csums);
-	p.skip      = cpu_to_be32(sc->skip);
 	p.after     = cpu_to_be32(sc->after);
 
 	return drbd_send_cmd(mdev,USE_DATA_SOCKET,SyncParam,(Drbd_Header*)&p,sizeof(p));

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/drbd_receiver.c	2006-08-10 11:31:57 UTC (rev 2356)
@@ -1846,8 +1846,6 @@
 
 	// XXX harmless race with ioctl ...
 	mdev->sync_conf.rate      = be32_to_cpu(p->rate);
-	mdev->sync_conf.use_csums = be32_to_cpu(p->use_csums);
-	mdev->sync_conf.skip      = be32_to_cpu(p->skip);
 	drbd_alter_sa(mdev, be32_to_cpu(p->after));
 
 	return ok;

Modified: trunk/drbd/drbd_sizeof_sanity_check.c
===================================================================
--- trunk/drbd/drbd_sizeof_sanity_check.c	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/drbd_sizeof_sanity_check.c	2006-08-10 11:31:57 UTC (rev 2356)
@@ -9,11 +9,11 @@
 
 SZO(disk_config,	 32)
 SZO(net_config,		456)
-SZO(syncer_config,	 24)
+SZO(syncer_config,	 16)
 SZO(ioctl_disk_config,	 40)
 SZO(ioctl_net_config,	464)
-SZO(ioctl_syncer_config, 32)
+SZO(ioctl_syncer_config, 24)
 SZO(ioctl_wait,		 16)
-SZO(ioctl_get_config,	584)
+SZO(ioctl_get_config,	576)
 SZO(ioctl_get_uuids,     48)
 

Modified: trunk/drbd/drbd_strings.c
===================================================================
--- trunk/drbd/drbd_strings.c	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/drbd_strings.c	2006-08-10 11:31:57 UTC (rev 2356)
@@ -32,8 +32,6 @@
 	[WFReportParams] = "WFReportParams",
 	[TearDown]       = "TearDown",
 	[Connected]      = "Connected",
-	[SkippedSyncS]   = "SkippedSyncS",
-	[SkippedSyncT]   = "SkippedSyncT",
 	[StartingSyncS]  = "StartingSyncS",
 	[StartingSyncT]  = "StartingSyncT",
 	[WFBitMapS]      = "WFBitMapS",

Modified: trunk/drbd/linux/drbd.h
===================================================================
--- trunk/drbd/linux/drbd.h	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/linux/drbd.h	2006-08-10 11:31:57 UTC (rev 2356)
@@ -128,8 +128,6 @@
 
 struct syncer_config {
 	int      rate; /* KB/sec */
-	int      use_csums;   /* use checksum based syncing*/
-	int      skip;
 	int      after;
 	int      al_extents;
 	const int _pad;
@@ -221,8 +219,6 @@
 	WFReportParams, // we have a socket
 	TearDown,
 	Connected,      // we have introduced each other
-	SkippedSyncS,   // we should have synced, but user said no
-	SkippedSyncT,
 	StartingSyncS,  // starting full sync by IOCTL.
 	StartingSyncT,  // stariing full sync by IOCTL.
 	WFBitMapS,

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/drbd/linux/drbd_config.h	2006-08-10 11:31:57 UTC (rev 2356)
@@ -23,7 +23,7 @@
 extern const char * drbd_buildtag(void);
 
 #define REL_VERSION "8.0pre4"
-#define API_VERSION 83
+#define API_VERSION 84
 #define PRO_VERSION 82
 
 // undef if you need the workaround in drbd_receiver

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-10 11:13:53 UTC (rev 2355)
+++ trunk/user/drbdsetup.c	2006-08-10 11:31:57 UTC (rev 2356)
@@ -957,14 +957,10 @@
   cn.config.rate = current_cn.sconf.rate;
   cn.config.after = current_cn.sconf.after;
   cn.config.al_extents = current_cn.sconf.al_extents;
-  cn.config.use_csums = 0; //current_cn.sconf.use_csums;
-  cn.config.skip = 0; //current_cn.sconf.skip;
   */
   cn.config.rate = DEF_SYNC_RATE;
   cn.config.after = DEF_SYNC_AFTER;
   cn.config.al_extents = DEF_SYNC_AL_EXTENTS;
-  cn.config.use_csums = 0; //current_cn.sconf.use_csums;
-  cn.config.skip = 0; //current_cn.sconf.skip;
 
 
   if(argc > 0)
@@ -978,12 +974,6 @@
 	  if(c == -1) break;
 	  switch(c)
 	    {
-	    case 'c':
-	      cn.config.use_csums=1;
-	      break;
-	    case 'k':
-	      cn.config.skip=1;
-	      break;
 	    case 'r':
 	      cn.config.rate=m_strtoll_range(optarg,'K', "rate",
 			      DRBD_RATE_MIN, DRBD_RATE_MAX);
@@ -1406,8 +1396,6 @@
       SHOW_IU("rate\t","K","(K)Byte/second", cn.sconf.rate, DEF_SYNC_RATE);
       SHOW_I("after\t","minor", cn.sconf.after, DEF_SYNC_AFTER);
       SHOW_I("al-extents","4MByte", cn.sconf.al_extents, DEF_SYNC_AL_EXTENTS);
-      if( cn.sconf.skip ) printf("\tskip-sync;\n");
-      if( cn.sconf.use_csums ) printf("\tuse-csums;\n");
       printf("}\n");
 
       err=fstat(drbd_fd,&sb);

From drbd-cvs at lists.linbit.com  Fri Aug 11 09:09:40 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 11 09:09:42 2006
Subject: [DRBD-cvs] svn commit by phil - r2360 - trunk/user - Removed old
	code 
Message-ID: <20060811070940.AEAFB2DD05B2@mail.linbit.com>

Author: phil
Date: 2006-08-11 09:09:39 +0200 (Fri, 11 Aug 2006)
New Revision: 2360

Modified:
   trunk/user/drbdadm_scanner.fl
   trunk/user/drbdsetup.c
Log:
Removed old code


Modified: trunk/user/drbdadm_scanner.fl
===================================================================
--- trunk/user/drbdadm_scanner.fl	2006-08-10 13:25:03 UTC (rev 2359)
+++ trunk/user/drbdadm_scanner.fl	2006-08-11 07:09:39 UTC (rev 2360)
@@ -84,8 +84,6 @@
 allow-two-primaries	{ DP; CP; return TK_NET_SWITCH;		}
 rate			{ DP; CP; RC(RATE); return TK_SYNCER_OPTION;	}
 after			{ DP; CP; return TK_SYNCER_OPTION;	}
-use-csums		{ DP; CP; return TK_SYNCER_SWITCH;	}
-skip-sync		{ DP; CP; return TK_SYNCER_SWITCH;	}
 al-extents		{ DP; CP; RC(AL_EXTENTS); return TK_SYNCER_OPTION;}
 wfc-timeout		{ DP; CP; RC(WFC_TIMEOUT); return TK_STARTUP_OPTION;}
 degr-wfc-timeout	{ DP; CP; RC(DEGR_WFC_TIMEOUT); return TK_STARTUP_OPTION;}

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-10 13:25:03 UTC (rev 2359)
+++ trunk/user/drbdsetup.c	2006-08-11 07:09:39 UTC (rev 2360)
@@ -150,8 +150,6 @@
   {"invalidate_remote", cmd_invalidate_rem,0, 0, },
   {"syncer", cmd_syncer,                0,
    (struct option[]) {
-     { "use-csums",  no_argument,       0, 'c' },
-     { "skip-sync",  no_argument,       0, 'k' },
      { "after",      required_argument, 0, 'a' },
      { "rate",       required_argument, 0, 'r' },
      { "al-extents", required_argument, 0, 'e' },

From drbd-cvs at lists.linbit.com  Fri Aug 11 09:55:26 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 11 09:55:28 2006
Subject: [DRBD-cvs] svn commit by lars - r2362 - trunk/user - commands
	'secondary' and 'invalidate' don't really need
Message-ID: <20060811075526.F41C32DF6275@mail.linbit.com>

Author: lars
Date: 2006-08-11 09:55:23 +0200 (Fri, 11 Aug 2006)
New Revision: 2362

Modified:
   trunk/user/drbdadm_main.c
Log:
commands 'secondary' and 'invalidate' don't really need to verify the ip-address

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-08-11 07:51:24 UTC (rev 2361)
+++ trunk/user/drbdadm_main.c	2006-08-11 07:55:23 UTC (rev 2362)
@@ -193,8 +193,8 @@
   { "up",                adm_up,        1,1,1 },
   { "down",              adm_generic_s, 1,1,0 },
   { "primary",           adm_generic_s, 1,1,0 },
-  { "secondary",         adm_generic_s, 1,1,1 },
-  { "invalidate",        adm_generic_l, 1,1,1 },
+  { "secondary",         adm_generic_s, 1,1,0 },
+  { "invalidate",        adm_generic_l, 1,1,0 },
   { "invalidate_remote", adm_generic_l, 1,1,1 },
   { "outdate",           adm_generic_b, 1,1,0 },
   { "resize",            adm_resize,    1,1,1 },

From drbd-cvs at lists.linbit.com  Fri Aug 11 09:56:59 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 11 09:57:01 2006
Subject: [DRBD-cvs] svn commit by lars - r2363 - trunk/user - cosmetics: I
	don't like >>>expected ''{''<<<, I'd rathe
Message-ID: <20060811075700.04A8E2DD05B2@mail.linbit.com>

Author: lars
Date: 2006-08-11 09:56:59 +0200 (Fri, 11 Aug 2006)
New Revision: 2363

Modified:
   trunk/user/drbdadm_parser.c
Log:
cosmetics: I don't like >>>expected ''{''<<<, I'd rather see >>>expected '{'<<<

Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-11 07:55:23 UTC (rev 2362)
+++ trunk/user/drbdadm_parser.c	2006-08-11 07:56:59 UTC (rev 2363)
@@ -228,6 +228,8 @@
 		tmp[0] = exp[1];
 	}
 	fprintf(stderr, "%s:%u: Parse error: '%s' expected,\n\t"
+		"but got '%s' (TK %d)\n",
+		config_file, line,
 		"but got '%s' (TK %d)\n", config_file, line, exp, yytext, got);
 	exit(E_config_invalid);
 }

From drbd-cvs at lists.linbit.com  Fri Aug 11 10:34:23 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 11 10:34:24 2006
Subject: [DRBD-cvs] svn commit by phil - r2365 - trunk/drbd - Applied
	Simon's update to the packet tracing (with a fe
Message-ID: <20060811083423.7B5CA2DF624A@mail.linbit.com>

Author: phil
Date: 2006-08-11 10:34:22 +0200 (Fri, 11 Aug 2006)
New Revision: 2365

Modified:
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
Log:
Applied Simon's update to the packet tracing (with a few cosmetic
changes)


Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-11 08:24:29 UTC (rev 2364)
+++ trunk/drbd/drbd_int.h	2006-08-11 08:34:22 UTC (rev 2365)
@@ -1619,9 +1619,10 @@
 #ifdef DUMP_EACH_PACKET
 
 /*
- * variable that controls dumping
+ * variables that controls dumping
  */
 extern int dump_packets;
+extern int dump_packet_devs; 
 
 #define DUMP_NONE 0
 #define DUMP_SUMMARY 1
@@ -1638,7 +1639,8 @@
 dump_packet(drbd_dev *mdev, struct socket *sock,
 	    int recv, Drbd_Polymorph_Packet *p, char* file, int line)
 {
-	if (dump_packets > DUMP_NONE)
+	if (dump_packets > DUMP_NONE &&
+	    ( ( 1 << (int)(mdev-drbd_conf)) & dump_packet_devs) )
 		_dump_packet(mdev,sock,recv,p,file,line);
 }
 #else

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-11 08:24:29 UTC (rev 2364)
+++ trunk/drbd/drbd_main.c	2006-08-11 08:34:22 UTC (rev 2365)
@@ -131,7 +131,12 @@
 			// 0 = none
 			// 1 = summary (trace 'interesting' packets in summary fmt)
 			// 2 = verbose (trace all packets in full format)
+int dump_packet_devs = 0;// bitmap of drbd devices to have tracing
+			// enabled
+
 module_param(dump_packets,int,0644);
+module_param(dump_packet_devs,int,0644);
+
 #endif
 
 // devfs name
@@ -305,14 +310,23 @@
 
 	hlist_for_each_entry(i, n, slot, colision) {
 		if (i==req) {
-			D_ASSERT(drbd_req_get_sector(i) == sector);
-			rv=1;
-			break;
+		  if (drbd_req_get_sector(i) != sector) {
+			  ERR("tl_verify: found req %p but it has wrong sector (%llx versus %llx)\n",
+			      req, (long long)drbd_req_get_sector(i), (long long)sector);
+		  }
+		  rv=1;
+		  break;
 		}
 	}
 
 	spin_unlock_irq(&mdev->tl_lock);
 
+	// Really better find it!
+	if (!rv) {
+		ERR("tl_verify: failed to find req %p, sector %llx in list\n", 
+		    req, (long long)sector);
+	}
+
 	return rv;
 }
 
@@ -1295,6 +1309,8 @@
 
 	down(&mdev->data.mutex);
 
+	dump_packet(mdev,mdev->data.socket,0,(void*)&h, __FILE__, __LINE__);
+
 	ok = ( sizeof(h) == drbd_send(mdev,mdev->data.socket,&h,sizeof(h),0) );
 	ok = ok && ( size == drbd_send(mdev,mdev->data.socket,data,size,0) );
 
@@ -2903,11 +2919,13 @@
 	if (dump_packets > DUMP_SUMMARY) { \
 		INFO("%s:%d: %s [%d] %s %s " fmt , \
 		     file, line, current->comm, current->pid, \
-		     sockname, recv?"<<<":">>>" \
-		     , ## args ); \
+		     sockname, recv?"<<<":">>>", \
+		     ## args ); \
 	} \
 	else { \
-		INFO("%s " fmt, recv?"<<<":">>>", ## args ); \
+		INFO("%s %s " fmt, sockname, \
+		     recv?"<<<":">>>", \
+		     ## args ); \
 	} \
 } while (0)
 
@@ -2929,8 +2947,6 @@
 		break;
 
 	case Data:
-	case DataReply:
-	case RSDataReply:
 		INFOP("%s (sector %llx, id %llx, seq %x, f %x)\n", cmdname(cmd),
 		     (long long)be64_to_cpu(p->Data.sector), 
 		     (long long)be64_to_cpu(p->Data.block_id),
@@ -2939,6 +2955,14 @@
 		);
 		break;
 
+	case DataReply:
+	case RSDataReply:
+		INFOP("%s (sector %llx, id %llx)\n", cmdname(cmd),
+		     (long long)be64_to_cpu(p->Data.sector), 
+		     (long long)be64_to_cpu(p->Data.block_id)
+		);
+		break;
+
 	case RecvAck:
 	case WriteAck:
 	case NegAck:

From drbd-cvs at lists.linbit.com  Fri Aug 11 13:52:21 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 11 13:52:23 2006
Subject: [DRBD-cvs] svn commit by phil - r2366 - trunk/user - Fixed some of
	the anoing bugs in the userlans stuff. 
Message-ID: <20060811115222.069692CE72EE@mail.linbit.com>

Author: phil
Date: 2006-08-11 13:52:20 +0200 (Fri, 11 Aug 2006)
New Revision: 2366

Modified:
   trunk/user/drbdadm_parser.c
   trunk/user/drbdadm_usage_cnt.c
   trunk/user/drbdmeta.c
Log:
Fixed some of the anoing bugs in the userlans stuff.


Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-11 08:34:22 UTC (rev 2365)
+++ trunk/user/drbdadm_parser.c	2006-08-11 11:52:20 UTC (rev 2366)
@@ -229,8 +229,8 @@
 	}
 	fprintf(stderr, "%s:%u: Parse error: '%s' expected,\n\t"
 		"but got '%s' (TK %d)\n",
-		config_file, line,
-		"but got '%s' (TK %d)\n", config_file, line, exp, yytext, got);
+		config_file, line, 
+		tmp[0] ? tmp : exp, yytext, got);
 	exit(E_config_invalid);
 }
 

Modified: trunk/user/drbdadm_usage_cnt.c
===================================================================
--- trunk/user/drbdadm_usage_cnt.c	2006-08-11 08:34:22 UTC (rev 2365)
+++ trunk/user/drbdadm_usage_cnt.c	2006-08-11 11:52:20 UTC (rev 2366)
@@ -455,6 +455,8 @@
 
 	rv = _admm_generic(res, cmd, SLEEPS_VERY_LONG); // cmd is "create-md".
 
+	if(rv || dry_run) return rv;
+
 	fd = open(res->me->disk,O_RDONLY);
 	if( fd != -1) {
 		device_size = bdev_size(fd);

Modified: trunk/user/drbdmeta.c
===================================================================
--- trunk/user/drbdmeta.c	2006-08-11 08:34:22 UTC (rev 2365)
+++ trunk/user/drbdmeta.c	2006-08-11 11:52:20 UTC (rev 2366)
@@ -2120,7 +2120,7 @@
 	if (!virgin) {
 		if (!confirmed("Valid meta-data already in place, recreate new?")) {
 			printf("Operation cancelled.\n");
-			exit(0);
+			exit(1); // 1 to avoid online resource counting
 		}
 	} else {
 		printf("About to create a new drbd meta data block\non %s.\n",
@@ -2130,7 +2130,7 @@
 		if (!confirmed(" ==> This might destroy existing data! <==\n\n"
 				"Do you want to proceed?")) {
 			printf("Operation cancelled.\n");
-			exit(0);
+			exit(1); // 1 to avoid online resource counting
 		}
 	}
 

From drbd-cvs at lists.linbit.com  Sat Aug 12 01:08:00 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sat Aug 12 01:08:01 2006
Subject: [DRBD-cvs] svn commit by lars - r2367 - trunk/user - drbdadm: *
	make sure progname gets set before it might 
Message-ID: <20060811230800.C82F02D99950@mail.linbit.com>

Author: lars
Date: 2006-08-12 01:07:59 +0200 (Sat, 12 Aug 2006)
New Revision: 2367

Modified:
   trunk/user/drbdadm_main.c
   trunk/user/drbdmeta.c
Log:

drbdadm:
 * make sure progname gets set before it might be used
 * initialize drbdmeta command name pointer the same way
   as that of drbdsetup: let execvp sort it out...
 * fix compiler warning

drbdmeta:
 allow drbdmeta dump-md to be forced even when the corresponding device is
 configured and used. It may return stale data, but that might still be useful
 sometimes, especially for debugging the syncer related issues now.



Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-08-11 11:52:20 UTC (rev 2366)
+++ trunk/user/drbdadm_main.c	2006-08-11 23:07:59 UTC (rev 2367)
@@ -1424,26 +1424,37 @@
             "   PRETENDING that I am >>%s<<\n\n",nodeinfo.nodename);
   }
 
-  if(argc == 1) print_usage_and_exit("missing arguments"); // arguments missing.
-
   /* in case drbdadm is called with an absolut or relative pathname
    * look for the drbdsetup binary in the same location,
    * otherwise, just let execvp sort it out... */
   if( (progname=strrchr(argv[0],'/')) == 0 ) {
     progname=argv[0];
     drbdsetup = strdup("drbdsetup");
+    drbdmeta = strdup("drbdmeta");
   } else {
     size_t len = strlen(argv[0]) + 1;
     ++progname;
+
     len += strlen("drbdsetup") - strlen(progname);
     drbdsetup = malloc(len);
     if (drbdsetup) {
       strncpy(drbdsetup, argv[0], (progname - argv[0]));
       strcpy(drbdsetup + (progname - argv[0]), "drbdsetup");
     }
+
+    len += strlen("drbdmeta") - strlen(progname);
+    drbdmeta = malloc(len);
+    if (drbdmeta) {
+      strncpy(drbdmeta, argv[0], (progname - argv[0]));
+      strcpy(drbdmeta + (progname - argv[0]), "drbdmeta");
+    }
+
     argv[0] = progname;
   }
-  if (drbdsetup == NULL) {
+
+  if(argc == 1) print_usage_and_exit("missing arguments"); // arguments missing.
+
+  if (drbdsetup == NULL || drbdmeta == NULL) {
     fprintf(stderr,"could not strdup argv[0].\n");
     exit(E_exec_error);
   }
@@ -1602,14 +1613,6 @@
     }
   }
 
-  if(drbdsetup == NULL) {
-    find_drbdcmd(&drbdsetup,(char *[]){"./drbdsetup", "/sbin/drbdsetup", 0 });
-  }
-
-  if(drbdmeta == NULL) {
-    find_drbdcmd(&drbdmeta,(char *[]){"./drbdmeta", "/sbin/drbdmeta", 0 });
-  }
-
   uc_node(global_options.usage_count);
 
   if(cmd->res_name_required)

Modified: trunk/user/drbdmeta.c
===================================================================
--- trunk/user/drbdmeta.c	2006-08-11 11:52:20 UTC (rev 2366)
+++ trunk/user/drbdmeta.c	2006-08-11 23:07:59 UTC (rev 2367)
@@ -1350,7 +1350,7 @@
 		size_t i;
 		unsigned int percent_done = 0;
 		unsigned int percent_last_report = 0;
-		fprintf(stderr,"initialising bitmap (%u KB)\n", (bm_bytes>>10));
+		fprintf(stderr,"initialising bitmap (%u KB)\n", (unsigned int)(bm_bytes>>10));
 		/* give some progress */
 		for (i = 0; i < bm_bytes; i += chunk) {
 			MEMSET((char*)cfg->on_disk.bm+i, 0xff, chunk);
@@ -1360,11 +1360,11 @@
 				percent_last_report = percent_done;
 			}
 		}
+		fprintf(stderr,"\r100%%\n");
 #else
 		printf("initialising bitmap (%u KB)\n", (bm_bytes>>10));
 		MEMSET((void*)cfg->on_disk.bm, 0xff, bm_bytes);
 #endif
-		//fprintf(stderr,"\r100%%\n");
 	}
 #endif
 	return 0;
@@ -2460,16 +2460,6 @@
 		exit(20);
 	}
 
-	cfg->drbd_fd = dt_lock_open_drbd(cfg->drbd_dev_name, &cfg->lock_fd, 1);
-	if (cfg->drbd_fd > -1) {
-		if (is_attached(dt_minor_of_dev(cfg->drbd_dev_name))) {
-			fprintf(stderr, "Device '%s' is configured!\n",
-				cfg->drbd_dev_name);
-			exit(20);
-		}
-	}
-
-
 	for (i = 0; i < ARRY_SIZE(cmds); i++) {
 		if (!strcmp(cmds[i].name, argv[ai])) {
 			command = cmds + i;
@@ -2482,6 +2472,17 @@
 	}
 	ai++;
 
+	cfg->drbd_fd = dt_lock_open_drbd(cfg->drbd_dev_name, &cfg->lock_fd, 1);
+	if (cfg->drbd_fd > -1) {
+		if (is_attached(dt_minor_of_dev(cfg->drbd_dev_name))) {
+			if (!(force && (command->function == meta_dump_md))) {
+				fprintf(stderr, "Device '%s' is configured!\n",
+					cfg->drbd_dev_name);
+				exit(20);
+			}
+		}
+	}
+
 	return command->function(cfg, argv + ai, argc - ai);
 	/* and if we want an explicit free,
 	 * this would be the place for it.

From drbd-cvs at lists.linbit.com  Sat Aug 12 01:11:32 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sat Aug 12 01:11:34 2006
Subject: [DRBD-cvs] svn commit by lars - r2368 - in trunk/drbd: . linux -
	use the right prototype for _drbd_send_ack
Message-ID: <20060811231132.A97E62D99950@mail.linbit.com>

to avoid tru
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Author: lars
Date: 2006-08-12 01:11:31 +0200 (Sat, 12 Aug 2006)
New Revision: 2368

Modified:
   trunk/drbd/drbd_main.c
   trunk/drbd/linux/drbd_config.h
Log:
use the right prototype for _drbd_send_ack
to avoid truncating sector number to 0 ALWAYS
in case CONFIG_LBD is NOT set.

default to compile in the tracing stuff,
now we can toggle it at runtime.



Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-11 23:07:59 UTC (rev 2367)
+++ trunk/drbd/drbd_main.c	2006-08-11 23:11:31 UTC (rev 2368)
@@ -1521,9 +1521,9 @@
  * This helper function expects the sector and block_id parameter already
  * in big endian!
  */ 
-static int _drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd, 
-			  sector_t sector,
-			  unsigned int blksize,
+static int _drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd,
+			  u64 sector,
+			  u32 blksize,
 			  u64 block_id)
 {
 	int ok;

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-08-11 23:07:59 UTC (rev 2367)
+++ trunk/drbd/linux/drbd_config.h	2006-08-11 23:11:31 UTC (rev 2368)
@@ -38,7 +38,7 @@
 
 // Define this to enable printing of packets under control of dump_packets
 // module parameter (/sys/module/drbd/parameters/dump_packets)
-//#define DUMP_EACH_PACKET
+#define DUMP_EACH_PACKET
 
 // Dump every hour the usage / not usage of zero copy IO
 //#define SHOW_SENDPAGE_USAGE

From drbd-cvs at lists.linbit.com  Mon Aug 14 17:18:27 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Aug 14 17:18:29 2006
Subject: [DRBD-cvs] svn commit by phil - r2371 - trunk/user - The begin of
	the new netlink based drbdstup... 
Message-ID: <20060814151827.CBE292CE7575@mail.linbit.com>

Author: phil
Date: 2006-08-14 17:18:26 +0200 (Mon, 14 Aug 2006)
New Revision: 2371

Added:
   trunk/user/drbd_nl.h
   trunk/user/drbd_tag_magic.h
   trunk/user/drbdsetup_nl.c
Log:
The begin of the new netlink based drbdstup...


Added: trunk/user/drbd_nl.h
===================================================================
--- trunk/user/drbd_nl.h	2006-08-14 07:03:59 UTC (rev 2370)
+++ trunk/user/drbd_nl.h	2006-08-14 15:18:26 UTC (rev 2371)
@@ -0,0 +1,59 @@
+/* 
+   PAKET( name,
+          TYPE ( pn, pr, member )
+          ...
+   )
+
+   You may never reissue one of the pn arguments
+*/
+
+#if !defined(PACKET) || !defined(STRING) || !defined(INTEGER) || !defined(BIT) || !defined(INT64)
+#error "The macros PACKET, STRING, INTEGER, INT64 and BIT needs to be defined"
+#endif
+
+PACKET(primary,
+       BIT(		1,	T_MAY_IGNORE,	overwrite_peer)
+)
+
+PACKET(secondary, )
+
+PACKET(disk_conf,
+	INT64(  	2,	T_MAY_IGNORE,	disk_size)
+	INTEGER(	3,	T_MANDATORY,	backing_dev)
+	INTEGER(	4,	T_MANDATORY,	meta_dev)
+	INTEGER(	5,	T_MANDATORY,	meta_dev_idx)
+	INTEGER(	6,	T_MAY_IGNORE,	on_io_error)
+	INTEGER(	7,	T_MAY_IGNORE,	fencing)
+)
+
+PACKET(detach, )
+
+PACKET(net_conf,
+	STRING(		8,	T_MANDATORY,	my_addr,	128)
+	STRING(		9,	T_MANDATORY,	peer_addr,	128)
+	STRING(		10,	T_MAY_IGNORE,	shared_secret,	128)
+	STRING(		11,	T_MAY_IGNORE,	cram_hmac_alg,	128)
+	INTEGER(	12,	T_MANDATORY,	my_addr_len)
+	INTEGER(	13,	T_MANDATORY,	peer_addr_len)
+	INTEGER(	14,	T_MAY_IGNORE,	timeout)
+	INTEGER(	15,	T_MANDATORY,	wire_protocol)
+	INTEGER(	16,	T_MAY_IGNORE,	try_connect_int)
+	INTEGER(	17,	T_MAY_IGNORE,	ping_int)
+	INTEGER(	18,	T_MAY_IGNORE,	max_epoch_size)
+	INTEGER(	19,	T_MAY_IGNORE,	max_buffers)
+	INTEGER(	20,	T_MAY_IGNORE,	unplug_watermark)
+	INTEGER(	21,	T_MAY_IGNORE,	sndbuf_size)
+	INTEGER(	22,	T_MAY_IGNORE,	ko_count)
+	INTEGER(	24,	T_MAY_IGNORE,	after_sb_0p)
+	INTEGER(	25,	T_MAY_IGNORE,	after_sb_1p)
+	INTEGER(	26,	T_MAY_IGNORE,	after_sb_2p)
+	BIT(		27,	T_MAY_IGNORE,	want_lose)
+	BIT(		28,	T_MAY_IGNORE,	two_primaries)
+)
+
+#undef PACKET
+#undef INTEGER
+#undef INT64
+#undef BIT
+#undef STRING
+

Added: trunk/user/drbd_tag_magic.h
===================================================================
--- trunk/user/drbd_tag_magic.h	2006-08-14 07:03:59 UTC (rev 2370)
+++ trunk/user/drbd_tag_magic.h	2006-08-14 15:18:26 UTC (rev 2371)
@@ -0,0 +1,72 @@
+#ifndef DRBD_TAG_MAGIC_H
+#define DRBD_TAG_MAGIC_H
+
+#define TT_END     0
+
+// declare packet_type enums
+enum packet_types {
+#define PACKET(name, fields) P_ ## name,
+#define INTEGER(pn,pr,member)
+#define INT64(pn,pr,member)
+#define BIT(pn,pr,member)
+#define STRING(pn,pr,member,len)
+#include "drbd_nl.h"
+};
+
+// declate structs
+#define PACKET(name, fields) struct name { fields };
+#define INTEGER(pn,pr,member) int member;
+#define INT64(pn,pr,member) __u64 member;
+#define BIT(pn,pr,member)   unsigned member : 1;
+#define STRING(pn,pr,member,len) unsigned char member[len];
+#include "drbd_nl.h"
+
+// declate tag-list-sizes
+#define PACKET(name,fields) const int name ## _tag_size = 2 fields ;
+#define INTEGER(pn,pr,member)     +4+4 
+#define INT64(pn,pr,member)       +4+8
+#define BIT(pn,pr,member)         +4+1
+#define STRING(pn,pr,member,len)  +4+len
+#include "drbd_nl.h"
+
+/* The two highest bits are used for the tag type */
+#define TT_MASK      0xC000
+#define TT_INTEGER   0x0000
+#define TT_INT64     0x4000
+#define TT_BIT       0x8000
+#define TT_STRING    0xC000
+/* The next bit indicates if processing of the tag is mandatory */
+#define T_MANDATORY  0x2000
+#define T_MAY_IGNORE 0x0000
+#define TN_MASK      0x1fff
+/* The remaining 13 bits are used to enumerate the tags */
+
+#define tag_type(T)   ((T) & TT_MASK)
+#define tag_number(T) ((T) & TN_MASK)
+
+// declare tag enums
+#define PACKET(name, fields) fields
+enum drbd_tags {
+#define INTEGER(pn,pr,member)    T_ ## member = pn | TT_INTEGER | pr ,
+#define INT64(pn,pr,member)      T_ ## member = pn | TT_INT64   | pr ,
+#define BIT(pn,pr,member)        T_ ## member = pn | TT_BIT     | pr ,
+#define STRING(pn,pr,member,len) T_ ## member = pn | TT_STRING  | pr ,
+#include "drbd_nl.h"
+};
+
+struct tag {
+	const char* name;
+	int type_n_flags;
+};
+
+// declare tag names
+#define PACKET(name, fields) fields
+const struct tag tag_descriptions[] = {
+#define INTEGER(pn,pr,member)    [ pn ] = { #member, TT_INTEGER | pr },
+#define INT64(pn,pr,member)      [ pn ] = { #member, TT_INT64   | pr },
+#define BIT(pn,pr,member)        [ pn ] = { #member, TT_BIT     | pr },
+#define STRING(pn,pr,member,len) [ pn ] = { #member, TT_STRING  | pr },
+#include "drbd_nl.h"
+};
+
+#endif

Added: trunk/user/drbdsetup_nl.c
===================================================================
--- trunk/user/drbdsetup_nl.c	2006-08-14 07:03:59 UTC (rev 2370)
+++ trunk/user/drbdsetup_nl.c	2006-08-14 15:18:26 UTC (rev 2371)
@@ -0,0 +1,643 @@
+/*
+   drbdsetup.c
+
+   This file is part of drbd by Philipp Reisner.
+
+   Copyright (C) 1999-2006, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg@linbit.com>.
+   Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
+
+   Copyright (C) 2000, Fábio Olivé Leite <olive@conectiva.com.br>.
+        Added sanity checks before using the device.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/drbd.h>
+#include <linux/drbd_config.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <mntent.h>
+#include "drbdtool_common.h"
+#include "drbd_limits.h"
+#include "drbd_tag_magic.h"
+
+struct drbd_tag_list {
+	unsigned short *tag_list_start;
+	unsigned short *tag_list_cpos;
+	int    tag_size;
+};
+
+struct drbd_argument {
+	const char* name;
+	const enum drbd_tags tag;
+	int (*convert_function)(struct drbd_argument *,
+				struct drbd_tag_list *, 
+				char *);
+};
+
+struct drbd_option {
+	const char* name;
+	const char short_name;
+	const enum drbd_tags tag;
+	int (*convert_function)(struct drbd_option *,
+				struct drbd_tag_list *,
+				char *);
+	union {
+		struct {
+			const unsigned long long min;
+			const unsigned long long max;
+			const unsigned long long def;
+			const unsigned char default_unit;
+		} numeric_param;
+		struct {
+			const char** handler_names;
+			const int number_of_handlers;
+		} handler_param;
+	};
+};
+
+struct drbd_cmd {
+	const char* cmd;
+	const int packet_id;
+	int (*function)(struct drbd_cmd *, int, char **);
+	struct drbd_argument *args;
+	struct drbd_option *options;
+};
+
+
+const char *on_error[] = {
+	[PassOn] = "pass_on",
+	[Panic]  = "panic",
+	[Detach] = "detach",
+};
+
+const char *fencing_n[] = {
+	[DontCare] = "dont-care",
+	[Resource] = "resource-only",
+	[Stonith]  = "resource-and-stonith",
+};
+
+const char *asb0p_n[] = {
+        [Disconnect]        = "disconnect",
+	[DiscardYoungerPri] = "discard-younger-primary",
+	[DiscardOlderPri]   = "discard-older-primary",
+	[DiscardLeastChg]   = "discard-least-changes",
+	[DiscardLocal]      = "discard-local",
+	[DiscardRemote]     = "discard-remote"
+};
+
+const char *asb1p_n[] = {
+	[Disconnect]        = "disconnect",
+	[Consensus]         = "consensus",
+	[DiscardSecondary]  = "discard-secondary",
+	[PanicPrimary]      = "panic-primary"
+};
+
+const char *asb2p_n[] = {
+	[Disconnect]        = "disconnect",
+	[PanicPrimary]      = "panic"
+};
+
+// other functions
+void print_command_usage(int i, const char *addinfo);
+// command functions
+int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv);
+// convert functions for arguments
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+// convert functions for options
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+
+#define EN(N) \
+	conv_numeric, { .numeric_param = { N ## _min, N ## _max, N ## _default } }
+#define EN0 	conv_numeric, { .numeric_param = { 0, -1, 0, 0 } }
+#define EH(N) \
+	conv_handler, { .handler_param = { N, ARRY_SIZE(N) } }
+#define EB      conv_bit, { } 
+
+
+
+
+struct drbd_cmd commands[] = {
+	{"primary", P_primary, generic_config_cmd, NULL,
+	 (struct drbd_option[]) {
+		 { "overwrite-data-of-peer",'o',T_disk_size, EB	     },
+		 { NULL,0,0,NULL, { } }, }, },
+
+	{"secondary", P_secondary, generic_config_cmd, NULL, NULL },
+
+	{"disk", P_disk_conf, generic_config_cmd,
+	 (struct drbd_argument[]) {
+		 { "lower_dev",		T_backing_dev,	conv_block_dev },
+		 { "meta_data_dev",	T_meta_dev,	conv_block_dev },
+		 { "meta_data_index",	T_meta_dev_idx,	conv_md_idx },
+		 { NULL,                0,           	NULL}, },
+	 (struct drbd_option[]) {
+		 { "size",'d',		T_disk_size,	EN0 },
+		 { "on-io-error",'e',	T_on_io_error,	EH(on_error) },
+		 { "fencing",'f',	T_fencing,	EH(fencing_n) },
+		 { NULL,0,0,NULL, { } }, }, },
+
+	{"detach", P_detach, generic_config_cmd, NULL, NULL },
+
+	{"net", P_net_conf, generic_config_cmd,
+	 (struct drbd_argument[]) {
+		 { "local_addr",	T_my_addr,	conv_address },
+		 { "remote_addr",	T_peer_addr,	conv_address },
+		 { "protocol",		T_wire_protocol,conv_protocol },
+ 		 { NULL,                0,           	NULL}, },
+	 (struct drbd_option[]) {
+		 { "timeout",'t',	T_timeout,	EN0 },
+		 { "max-epoch-size",'e',T_max_epoch_size,EN0 },
+		 { "max-buffers",'b',	T_max_buffers,	EN0 },
+		 { "unplug-watermark",'u',T_unplug_watermark, EN0 },
+		 { "connect-int",'c',	T_try_connect_int, EN0 },
+		 { "ping-int",'i',	T_ping_int,	   EN0 },
+		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN0 },
+		 { "ko-count",'k',	T_ko_count,	   EN0 },
+		 { "allow-two-primaries",'m',T_two_primaries, EN0 },
+		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   EN0 },
+		 { "shared-secret",'x',	T_shared_secret,   EN0 },
+		 { "after-sb-0pri",'A',	T_after_sb_0p,     EH(asb0p_n) },
+		 { "after-sb-1pri",'B',	T_after_sb_1p,     EH(asb1p_n) },
+		 { "after-sb-2pri",'C',	T_after_sb_2p,     EH(asb2p_n) },
+		 { "discard-my-data",'D', T_want_lose,     EB },
+		 { NULL,0,0,NULL, { } }, }, },
+};
+
+char* cmdname = 0;
+
+void dump_tag_list(struct drbd_tag_list *tl)
+{
+	unsigned short *tlc = tl->tag_list_start;
+	enum drbd_tags tag;
+	int len;
+	int integer;
+	char bit;
+	__u64 int64;
+	char* string;
+
+	while(*tlc != TT_END) {
+		tag = tag_number(*tlc++);
+		printf("(%d) %s = ",tag,tag_descriptions[tag].name);
+		len = *tlc++;
+		switch(tag_type(tag)) {
+		case TT_INTEGER: 
+			integer = *(int*)tlc;
+			printf("%d",integer);
+			break;
+		case TT_INT64:
+			int64 = *(__u64*)tlc;
+			printf("%lld",(long long)int64);
+			break;
+		case TT_BIT:
+			bit = *(char*)tlc;
+			printf( bit ? "on" : "off");
+			break;
+		case TT_STRING:
+			string = (char*)tlc;
+			printf("%s",string);
+			break;
+		}
+		printf(" (len: %u)\n",len);
+		tlc = (unsigned short*)((char*)tlc + len);
+	}
+}
+
+struct drbd_tag_list *create_tag_list(int size)
+{
+	struct drbd_tag_list *tl;
+
+	tl = malloc(sizeof(struct drbd_tag_list));
+	tl->tag_list_start = malloc(size);
+	tl->tag_list_cpos = tl->tag_list_start;
+	tl->tag_size = size;
+
+	return tl;
+}
+
+void add_tag(struct drbd_tag_list *tl, int tag, void *data, int data_len)
+{
+	if( (tl->tag_list_cpos - tl->tag_list_start) + data_len 
+	    > tl->tag_size ) {
+		fprintf(stderr, "Tag list size exceeded!\n");
+		exit(20);
+	}
+	*tl->tag_list_cpos++ = tag;
+	*tl->tag_list_cpos++ = data_len;
+	memcpy(tl->tag_list_cpos,data,data_len);
+	tl->tag_list_cpos = (unsigned short*)((char*)tl->tag_list_cpos + data_len);
+}
+
+void free_tag_list(struct drbd_tag_list *tl)
+{
+	free(tl->tag_list_start);
+	free(tl);
+}
+
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	struct stat sb;
+	int device_fd;
+	int err;
+
+	if ((device_fd = open(arg,O_RDWR))==-1) {
+		PERROR("Can not open device '%s'", arg);
+		return 20;
+	}
+
+	if ( (err=fstat(device_fd, &sb)) ) {
+		PERROR("fstat(%s) failed", arg);
+		return 20;
+	}
+
+	if(!S_ISBLK(sb.st_mode)) {
+		fprintf(stderr, "%s is not a block device!\n", arg);
+		return 20;
+	}
+
+	add_tag(tl,ad->tag,&device_fd,sizeof(device_fd));
+
+	return 0;
+}
+
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	int idx;
+
+	if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT;
+	else if(!strcmp(arg,"flex")) idx = DRBD_MD_INDEX_FLEX_EXT;
+	else idx = m_strtoll(arg,1);
+
+	add_tag(tl,ad->tag,&idx,sizeof(idx));
+
+	return 0;
+}
+
+const char* addr_part(const char* s)
+{
+	static char buffer[200];
+	char *b;
+
+	b=strchr(s,':');
+	if(b) {
+		strncpy(buffer,s,b-s);
+		buffer[b-s]=0;
+		return buffer;
+	}
+	return s;
+}
+
+int port_part(const char* s)
+{
+	char *b;
+
+	b=strchr(s,':');
+
+	// m_strtoll_range(b+1,1, "port", DRBD_PORT_MIN, DRBD_PORT_MAX);
+	if(b) return m_strtoll(b+1,1);
+	return 7788;
+}
+
+unsigned long resolv(const char* name)
+{
+	unsigned long retval;
+
+	if((retval = inet_addr(name)) == INADDR_NONE ) {
+		struct hostent *he;
+		he = gethostbyname(name);
+		if (!he) {
+			PERROR("can not resolv the hostname");
+			exit(20);
+		}
+		retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr;
+	}
+	return retval;
+}
+
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	struct sockaddr_in addr;
+	int addr_len = sizeof(struct sockaddr_in);
+
+	addr.sin_port = htons(port_part(arg));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = resolv(addr_part(arg));
+
+	switch(ad->tag) {
+	case T_my_addr:
+		add_tag(tl,T_my_addr,&addr,addr_len);
+		add_tag(tl,T_my_addr_len,&addr_len,sizeof(addr_len));
+		break;
+	case T_peer_addr:
+		add_tag(tl,T_peer_addr,&addr,addr_len);
+		add_tag(tl,T_peer_addr_len,&addr_len,sizeof(addr_len));
+		break;
+	default:
+		fprintf(stderr, "internal error in conv_address()\n");
+	}
+
+	return 0;
+}
+
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	int prot;
+
+	if(!strcmp(arg,"A") || !strcmp(arg,"a")) {
+		prot=DRBD_PROT_A;
+	} else if (!strcmp(arg,"B") || !strcmp(arg,"b")) {
+		prot=DRBD_PROT_B;
+	} else if (!strcmp(arg,"C") || !strcmp(arg,"c")) {
+		prot=DRBD_PROT_C;
+	} else {
+		fprintf(stderr, "'%s' is no valid protocol.\n", arg);
+		return 20;
+	}
+
+	add_tag(tl,ad->tag,&prot,sizeof(prot));
+
+	return 0;
+}
+
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	char bit=1;
+
+	add_tag(tl,od->tag,&bit,sizeof(bit));
+
+	return 0;
+}
+
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	const unsigned long long min = od->numeric_param.min;
+	const unsigned long long max = od->numeric_param.max;
+	const unsigned char default_unit = od->numeric_param.default_unit;
+	unsigned long long l;
+	int i;
+	char unit[] = {0,0};
+
+
+	l = m_strtoll(arg, default_unit);
+
+	if (min > l || l > max) {
+		unit[0] = default_unit > 1 ? default_unit : 0;
+		fprintf(stderr,"%s %s => %llu%s out of range [%llu..%llu]%s\n",
+			od->name, arg, l, unit, min, max, unit);
+		return(20);
+	}
+
+	switch(tag_type(od->tag)) {
+	case TT_INT64:
+		add_tag(tl,od->tag,&l,sizeof(l));
+		break;
+	case TT_INTEGER:
+		i=l;
+		add_tag(tl,od->tag,&i,sizeof(i));
+		break;
+	default:
+		fprintf(stderr, "internal error in conv_numeric()\n");
+	}
+	return 0;
+
+}
+
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	const char** handler_names = od->handler_param.handler_names;
+	const int number_of_handlers = od->handler_param.number_of_handlers;
+	int i,nr;
+
+	for(i=0;i<number_of_handlers;i++) {
+		if(strcmp(arg,handler_names[i])==0) {
+			nr = i;
+			break;
+		}
+	}
+
+	add_tag(tl,od->tag,&nr,sizeof(nr));
+
+	return 0;
+}
+
+struct option *	make_longoptions(struct drbd_option* od)
+{
+	static struct option buffer[20];
+	int i=0;
+
+	while(od->name) {
+		buffer[i].name = od->name;
+		buffer[i].has_arg = tag_type(od->tag) == TT_BIT ? 
+			no_argument : required_argument ;
+		buffer[i].flag = NULL;
+		buffer[i].val = od->short_name;
+		if(i++ == 20) {
+			fprintf(stderr,"buffer in make_longoptions to small.\n");
+		}
+		od++;
+	}
+	buffer[i].name = NULL;
+	buffer[i].has_arg = 0;
+	buffer[i].flag = NULL;
+	buffer[i].val = 0;
+
+	return buffer;
+}
+
+struct drbd_option *find_opt_by_short_name(struct drbd_option *od, int c)
+{
+	while(od->name) {
+		if(od->short_name == c) return od;
+		od++;
+	}
+
+	return NULL;
+}
+
+int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv)
+{
+	struct drbd_argument *ad = cm->args;
+	struct drbd_option *od;
+	static struct option *lo;
+	struct drbd_tag_list *tl;
+	int c,i=0,rv=0;
+
+	tl = create_tag_list(4096);
+
+	while(ad->name) {
+		if(argc < i+1) {
+			fprintf(stderr,"Missing argument '%s'\n", ad->name);
+			print_command_usage(cm-commands, "");
+			rv=20;
+			break;
+		}
+		rv |= ad->convert_function(ad,tl,argv[i++]);
+		if(rv) break;
+		ad++;
+	}
+
+	lo = make_longoptions(cm->options);
+	while( (c=getopt_long(argc,argv,make_optstring(lo,0),lo,0)) != -1 ) {
+		od = find_opt_by_short_name(cm->options,c);
+		if(od) rv |= od->convert_function(od,tl,optarg);
+		else {
+			fprintf(stderr,"opt for short '%c' (%d) not found\n",
+				c,c);
+			rv=20;			
+		}
+		if(rv) break;
+	}
+
+	if(rv == 0) dump_tag_list(tl);
+	free_tag_list(tl);
+
+	return rv;
+}
+
+
+void print_command_usage(int i, const char *addinfo)
+    // CAUTION no range check for i
+{
+	struct drbd_argument *args;
+	struct drbd_option *options;
+#define  maxcol 70 // plus initial tab ...
+	static char line[maxcol+1];
+	int col,prevcol;
+
+	prevcol=col=0;
+
+	col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
+	if ((args = commands[i].args)) {
+		while (args->name) {
+			col += snprintf(line+col, maxcol-col, " %s", args->name);
+			args++;
+		}
+					
+	}
+	if (col > maxcol) {
+		printf("%s\n\t",line);
+		col=0;
+	}
+	prevcol=col;
+	if ((options = commands[i].options)) {
+		while (options->name) {
+			if (tag_type(options->tag) == TT_BIT) {
+				col += snprintf(line+col, maxcol-col, 
+						" [{--%s|-%c}]",
+						options->name, options->short_name);
+			} else {
+				col += snprintf(line+col, maxcol-col, 
+						" [{--%s|-%c} val]",
+						options->name, options->short_name);
+			}
+			if (col >= maxcol) {
+				line[prevcol]=0;
+				printf("%s\n\t",line);
+				prevcol=col=0;
+			} else {
+				prevcol=col;
+				options++;
+			}
+		}
+	}
+	line[col]=0;
+	printf("%s\n",line);
+	if (addinfo) {
+		printf("%s\n",addinfo);
+		exit(20);
+	}
+}
+
+
+void print_usage(const char* addinfo)
+{
+	size_t i;
+
+	printf("\nUSAGE: %s device command arguments options\n\n"
+	       "Device is usually /dev/drbdX or /dev/drbd/X.\n"
+	       "Commands, arguments and options are:\n",cmdname);
+
+
+	for (i = 0; i < ARRY_SIZE(commands); i++)
+		print_command_usage(i, 0);
+
+	printf("\nAvailable on-io-error handlers:");
+	for(i=0;i<ARRY_SIZE(on_error);i++) {
+		printf(" %s",on_error[i]);
+		if(i < ARRY_SIZE(on_error)-1) printf(",");
+	}
+
+	printf("\nAvailable fencing policies:");
+	for(i=0;i<ARRY_SIZE(fencing_n);i++) {
+		printf(" %s",fencing_n[i]);
+		if(i < ARRY_SIZE(fencing_n)-1) printf(",");
+	}
+	/*
+	printf("\n\nVersion: "REL_VERSION" (api:%d)\n%s\n",
+	       API_VERSION, drbd_buildtag());
+	*/
+	if (addinfo)
+		printf("\n%s\n",addinfo);
+
+	exit(20);
+}
+
+int main(int argc, char** argv)
+{
+	int help = 0;
+	unsigned int i;
+
+	if ( (cmdname = strrchr(argv[0],'/')) )
+		argv[0] = ++cmdname;
+	else
+		cmdname = argv[0];
+
+	/* == '-' catches -h, --help, and similar */
+	if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-'))
+		help = 1;
+	if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
+
+	chdir("/");
+
+	for(i=0;i<ARRY_SIZE(commands);i++) {
+		if(strcmp(argv[2],commands[i].cmd)==0) {
+			commands[i].function(commands+i,argc-3,argv+3);
+		}
+	}
+
+	return 0;
+}

From drbd-cvs at lists.linbit.com  Mon Aug 14 19:05:59 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Aug 14 19:06:01 2006
Subject: [DRBD-cvs] svn commit by phil - r2372 - trunk/user - A bit more
	work on the new drbdsetup ... 
Message-ID: <20060814170600.020EB2D99B7B@mail.linbit.com>

Author: phil
Date: 2006-08-14 19:05:58 +0200 (Mon, 14 Aug 2006)
New Revision: 2372

Modified:
   trunk/user/Makefile
   trunk/user/drbd_nl.h
   trunk/user/drbdsetup_nl.c
Log:
A bit more work on the new drbdsetup ...


Modified: trunk/user/Makefile
===================================================================
--- trunk/user/Makefile	2006-08-14 15:18:26 UTC (rev 2371)
+++ trunk/user/Makefile	2006-08-14 17:05:58 UTC (rev 2372)
@@ -29,7 +29,7 @@
 
 drbdmeta-obj = drbdmeta.o drbdmeta_scanner.o drbdtool_common.o ../drbd/drbd_buildtag.o
 
-all: drbdsetup drbdadm drbdmeta
+all: drbdsetup drbdadm drbdmeta drbdsetup_nl
 
 drbdadm: $(drbdadm-obj)
 	$(CC) -o $@ $^ 
@@ -42,6 +42,9 @@
 
 # for debug:	flex -d -s -odrbdadm_scanner.c drbdadm_scanner.fl
 
+drbdsetup_nl: drbdsetup_nl.o drbdtool_common.o
+	$(CC) -o $@ $^ 
+
 drbdsetup: $(drbdsetup-obj)
 	$(CC) -o $@ $^ 
 
@@ -72,6 +75,7 @@
 	rm -f $(PREFIX)/sbin/drbdadm
 
 ###dependencies
+drbdsetup.o:       drbdtool_common.h           drbd_limits.h
 drbdtool_common.o: drbdtool_common.h          
 drbdadm_main.o:    drbdtool_common.h drbdadm.h
 drbdadm_adjust.o:  drbdtool_common.h drbdadm.h

Modified: trunk/user/drbd_nl.h
===================================================================
--- trunk/user/drbd_nl.h	2006-08-14 15:18:26 UTC (rev 2371)
+++ trunk/user/drbd_nl.h	2006-08-14 17:05:58 UTC (rev 2372)
@@ -51,6 +51,26 @@
 	BIT(		28,	T_MAY_IGNORE,	two_primaries)
 )
 
+PACKET(disconnect, )
+
+PACKET(resize,
+	INT64(  	29,	T_MAY_IGNORE,	resize_size)
+)
+
+PACKET(syncer_conf,
+	INTEGER(	30,	T_MAY_IGNORE,	sync_rate)
+	INTEGER(  	31,	T_MAY_IGNORE,	sync_after)
+	INTEGER(  	32,	T_MAY_IGNORE,	al_extents)
+)
+
+PACKET(invalidate, )
+PACKET(invalidate_peer, )
+PACKET(pause_sync, )
+PACKET(resume_sync, )
+PACKET(suspend_io, )
+PACKET(resume_io, )
+PACKET(outdate, )
+
 #undef PACKET
 #undef INTEGER
 #undef INT64

Modified: trunk/user/drbdsetup_nl.c
===================================================================
--- trunk/user/drbdsetup_nl.c	2006-08-14 15:18:26 UTC (rev 2371)
+++ trunk/user/drbdsetup_nl.c	2006-08-14 17:05:58 UTC (rev 2372)
@@ -188,7 +188,7 @@
 		 { "ping-int",'i',	T_ping_int,	   EN0 },
 		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN0 },
 		 { "ko-count",'k',	T_ko_count,	   EN0 },
-		 { "allow-two-primaries",'m',T_two_primaries, EN0 },
+		 { "allow-two-primaries",'m',T_two_primaries, EB },
 		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   EN0 },
 		 { "shared-secret",'x',	T_shared_secret,   EN0 },
 		 { "after-sb-0pri",'A',	T_after_sb_0p,     EH(asb0p_n) },
@@ -196,6 +196,39 @@
 		 { "after-sb-2pri",'C',	T_after_sb_2p,     EH(asb2p_n) },
 		 { "discard-my-data",'D', T_want_lose,     EB },
 		 { NULL,0,0,NULL, { } }, }, },
+
+	{"disconnect", P_disconnect, generic_config_cmd, NULL, NULL },
+
+	{"resize", P_resize, generic_config_cmd, NULL,
+	 (struct drbd_option[]) {
+		 { "size",'s',T_resize_size,		EN0 },
+		 { NULL,0,0,NULL, { } }, }, },
+
+	{"syncer", P_syncer_conf, generic_config_cmd, NULL,
+	 (struct drbd_option[]) {
+		 { "rate",'r',T_sync_rate,		EN0 },
+		 { "after",'a',T_sync_after,		EN0 },
+		 { "al-extents",'e',T_al_extents,	EN0 },
+		 { NULL,0,0,NULL, { } }, }, },
+
+	{"invalidate", P_invalidate, generic_config_cmd, NULL, NULL },
+	{"invalidate-remote", P_invalidate_peer, generic_config_cmd, NULL, NULL },
+	{"pause-sync", P_pause_sync, generic_config_cmd, NULL, NULL },
+	{"resume-sync", P_resume_sync, generic_config_cmd, NULL, NULL },
+	{"suspend-io", P_suspend_io, generic_config_cmd, NULL, NULL },
+	{"resume-io", P_resume_io, generic_config_cmd, NULL, NULL },
+	{"outdate", P_outdate, generic_config_cmd, NULL, NULL },
+
+	// {"down", 0 , down_cmd, NULL, NULL },
+
+	/*
+	{"state", cmd_state,               0, 0, },
+	{"cstate", cmd_cstate,             0, 0, },
+	{"dstate", cmd_dstate,             0, 0, },
+	{"show-gi", cmd_show_gi,           0, 0, },
+	{"get-gi", cmd_get_gi,             0, 0, },
+	{"show", cmd_show,                 0, 0, },
+	*/
 };
 
 char* cmdname = 0;
@@ -211,28 +244,29 @@
 	char* string;
 
 	while(*tlc != TT_END) {
-		tag = tag_number(*tlc++);
-		printf("(%d) %s = ",tag,tag_descriptions[tag].name);
+		tag = *tlc++;
+		printf("(%2d) %16s = ",tag_number(tag),
+		       tag_descriptions[tag_number(tag)].name);
 		len = *tlc++;
 		switch(tag_type(tag)) {
 		case TT_INTEGER: 
 			integer = *(int*)tlc;
-			printf("%d",integer);
+			printf("(integer) %d",integer);
 			break;
 		case TT_INT64:
 			int64 = *(__u64*)tlc;
-			printf("%lld",(long long)int64);
+			printf("(int64) %lld",(long long)int64);
 			break;
 		case TT_BIT:
 			bit = *(char*)tlc;
-			printf( bit ? "on" : "off");
+			printf("(bit) %s", bit ? "on" : "off");
 			break;
 		case TT_STRING:
 			string = (char*)tlc;
-			printf("%s",string);
+			printf("(string)'%s'",string);
 			break;
 		}
-		printf(" (len: %u)\n",len);
+		printf(" \t[len: %u]\n",len);
 		tlc = (unsigned short*)((char*)tlc + len);
 	}
 }
@@ -528,13 +562,12 @@
 	return rv;
 }
 
-
 void print_command_usage(int i, const char *addinfo)
     // CAUTION no range check for i
 {
 	struct drbd_argument *args;
 	struct drbd_option *options;
-#define  maxcol 70 // plus initial tab ...
+#define  maxcol 100 // plus initial tab ...
 	static char line[maxcol+1];
 	int col,prevcol;
 
@@ -556,11 +589,11 @@
 	if ((options = commands[i].options)) {
 		while (options->name) {
 			if (tag_type(options->tag) == TT_BIT) {
-				col += snprintf(line+col, maxcol-col, 
+				col += snprintf(line+col, maxcol-col,
 						" [{--%s|-%c}]",
 						options->name, options->short_name);
 			} else {
-				col += snprintf(line+col, maxcol-col, 
+				col += snprintf(line+col, maxcol-col,
 						" [{--%s|-%c} val]",
 						options->name, options->short_name);
 			}
@@ -582,7 +615,20 @@
 	}
 }
 
+void print_handler(const char* info, const char** handlers, unsigned int size)
+{
+	unsigned int i;
 
+	printf(info);
+
+	for(i=0;i<size;i++) {
+		if(handlers[i]) {
+			printf(" %s",handlers[i]);
+			if(i < size-1) printf(",");
+		}
+	}
+}
+
 void print_usage(const char* addinfo)
 {
 	size_t i;
@@ -595,17 +641,13 @@
 	for (i = 0; i < ARRY_SIZE(commands); i++)
 		print_command_usage(i, 0);
 
-	printf("\nAvailable on-io-error handlers:");
-	for(i=0;i<ARRY_SIZE(on_error);i++) {
-		printf(" %s",on_error[i]);
-		if(i < ARRY_SIZE(on_error)-1) printf(",");
-	}
+	print_handler("\non-io-error handlers:",on_error,ARRY_SIZE(on_error));
+	print_handler("\nfencing policies:",fencing_n,ARRY_SIZE(fencing_n));
+	print_handler("\nafter-sb-0pri handler:",asb0p_n,ARRY_SIZE(asb0p_n));
+	print_handler("\nafter-sb-1pri handler:",asb1p_n,ARRY_SIZE(asb1p_n));
+	print_handler("\nafter-sb-2pri handler:",asb2p_n,ARRY_SIZE(asb2p_n));
 
-	printf("\nAvailable fencing policies:");
-	for(i=0;i<ARRY_SIZE(fencing_n);i++) {
-		printf(" %s",fencing_n[i]);
-		if(i < ARRY_SIZE(fencing_n)-1) printf(",");
-	}
+	printf("\n\n");
 	/*
 	printf("\n\nVersion: "REL_VERSION" (api:%d)\n%s\n",
 	       API_VERSION, drbd_buildtag());

From drbd-cvs at lists.linbit.com  Tue Aug 15 14:24:34 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug 15 14:24:35 2006
Subject: [DRBD-cvs] svn commit by lars - r2373 - branches/drbd-0.7/drbd - no
	more devfs. thanks to lmb and the kernel.org 2.6.18
Message-ID: <20060815122434.D97982D99AE7@mail.linbit.com>

Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Author: lars
Date: 2006-08-15 14:24:33 +0200 (Tue, 15 Aug 2006)
New Revision: 2373

Modified:
   branches/drbd-0.7/drbd/drbd_int.h
   branches/drbd-0.7/drbd/drbd_main.c
Log:
no more devfs. thanks to lmb and the kernel.org 2.6.18

Modified: branches/drbd-0.7/drbd/drbd_int.h
===================================================================
--- branches/drbd-0.7/drbd/drbd_int.h	2006-08-14 17:05:58 UTC (rev 2372)
+++ branches/drbd-0.7/drbd/drbd_int.h	2006-08-15 12:24:33 UTC (rev 2373)
@@ -73,8 +73,10 @@
 extern int major_nr;
 extern int use_nbd_major;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 // use_nbd_major ? "nbd" : "drbd";
 extern char* drbd_devfs_name;
+#endif
 
 #include <linux/major.h>
 #ifdef DRBD_MAJOR

Modified: branches/drbd-0.7/drbd/drbd_main.c
===================================================================
--- branches/drbd-0.7/drbd/drbd_main.c	2006-08-14 17:05:58 UTC (rev 2372)
+++ branches/drbd-0.7/drbd/drbd_main.c	2006-08-15 12:24:33 UTC (rev 2373)
@@ -49,7 +49,9 @@
 #include <linux/mm_inline.h>
 #endif
 #include <linux/slab.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 #include <linux/devfs_fs_kernel.h>
+#endif
 
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -144,10 +146,11 @@
 #endif
 int disable_bd_claim = 0;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 // devfs name
 char* drbd_devfs_name = "drbd";
+#endif
 
-
 // global panic flag
 volatile int drbd_did_panic = 0;
 
@@ -1695,8 +1698,10 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	devfs_unregister(devfs_handle);
 #else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 	devfs_remove(drbd_devfs_name);
 #endif
+#endif
 
 	if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0)
 		printk(KERN_ERR DEVICE_NAME": unregister of device failed\n");
@@ -1769,7 +1774,9 @@
 		return err;
 	}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 	drbd_devfs_name = (major_nr == NBD_MAJOR) ? "nbd" : "drbd";
+#endif
 
 	/*
 	 * allocate all necessary structs
@@ -1791,7 +1798,9 @@
 	if (unlikely(!drbd_blocksizes)) goto Enomem;
 #else
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 	devfs_mk_dir(drbd_devfs_name);
+#endif
 
 	for (i = 0; i < minor_count; i++) {
 		drbd_dev    *mdev = drbd_conf + i;
@@ -1814,7 +1823,9 @@
 		disk->first_minor = i;
 		disk->fops = &drbd_ops;
 		sprintf(disk->disk_name, DEVICE_NAME "%d", i);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 		sprintf(disk->devfs_name, "%s/%d", drbd_devfs_name, i);
+#endif
 		disk->private_data = mdev;
 		add_disk(disk);
 

From drbd-cvs at lists.linbit.com  Wed Aug 16 16:03:41 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Aug 16 16:03:42 2006
Subject: [DRBD-cvs] svn commit by phil - r2374 - trunk/drbd - The fix for
	another issue found by Simon Graham. It see
Message-ID: <20060816140341.9BE452CE79D3@mail.linbit.com>

Author: phil
Date: 2006-08-16 16:03:40 +0200 (Wed, 16 Aug 2006)
New Revision: 2374

Modified:
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_req.c
   trunk/drbd/drbd_worker.c
Log:
The fix for another issue found by Simon Graham.

It seems that under some conditions it is possible that the
ACK for a packet comes in even before the drbd_send_dblock()
functions returns. This leads to a crash, probably when 
__bio_for_each_segment() wants to exit its loop the bio
it works on is already free()d.

This patch fixes this.


Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-15 12:24:33 UTC (rev 2373)
+++ trunk/drbd/drbd_int.h	2006-08-16 14:03:40 UTC (rev 2374)
@@ -233,9 +233,9 @@
 #define RQ_DRBD_NOTHING	  0x0001
 #define RQ_DRBD_SENT      0x0010   // We got an ack
 #define RQ_DRBD_LOCAL     0x0020   // We wrote it to the local disk
-#define RQ_DRBD_DONE      0x0030   // We are done ;)
 #define RQ_DRBD_IN_TL     0x0040   // Set when it is in the TL
 #define RQ_DRBD_ON_WIRE   0x0080   // Set as soon as it is on the socket...
+#define RQ_DRBD_DONE      ( RQ_DRBD_SENT + RQ_DRBD_LOCAL + RQ_DRBD_ON_WIRE )
 
 /* drbd_meta-data.c (still in drbd_main.c) */
 #define DRBD_MD_MAGIC (DRBD_MAGIC+4) // 4th incarnation of the disk layout.

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-15 12:24:33 UTC (rev 2373)
+++ trunk/drbd/drbd_req.c	2006-08-16 14:03:40 UTC (rev 2374)
@@ -341,7 +341,7 @@
 	if (!local)
 		req->rq_status |= RQ_DRBD_LOCAL;
 	if (!remote)
-		req->rq_status |= RQ_DRBD_SENT;
+		req->rq_status |= RQ_DRBD_SENT | RQ_DRBD_ON_WIRE;
 
 	/* we need to plug ALWAYS since we possibly need to kick lo_dev */
 	drbd_plug_device(mdev);

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-15 12:24:33 UTC (rev 2373)
+++ trunk/drbd/drbd_worker.c	2006-08-16 14:03:40 UTC (rev 2374)
@@ -564,12 +564,10 @@
 
 	ok = drbd_send_dblock(mdev,req);
 	if (ok) {
-		spin_lock_irq(&mdev->req_lock);
-		req->rq_status |= RQ_DRBD_ON_WIRE;
-		spin_unlock_irq(&mdev->req_lock);
-
 		inc_ap_pending(mdev);
 
+		drbd_end_req(req,RQ_DRBD_ON_WIRE,1,drbd_req_get_sector(req));
+
 		if(mdev->net_conf->wire_protocol == DRBD_PROT_A) {
 			dec_ap_pending(mdev);
 			drbd_end_req(req, RQ_DRBD_SENT, 1, 

From drbd-cvs at lists.linbit.com  Wed Aug 16 16:16:15 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Aug 16 16:16:17 2006
Subject: [DRBD-cvs] svn commit by phil - r2375 - trunk/drbd - Currently it
	seems that Simon drives drbd-8 development
Message-ID: <20060816141615.DBA132D99B58@mail.linbit.com>

Author: phil
Date: 2006-08-16 16:16:06 +0200 (Wed, 16 Aug 2006)
New Revision: 2375

Modified:
   trunk/drbd/drbd_req.c
Log:
Currently it seems that Simon drives drbd-8 development.


Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-16 14:03:40 UTC (rev 2374)
+++ trunk/drbd/drbd_req.c	2006-08-16 14:16:06 UTC (rev 2375)
@@ -380,7 +380,6 @@
 					WARN("Concurrent write! [DISCARD L] sec=%lu\n",
 					     (unsigned long)sector);
 					dec_local(mdev);
-					dec_ap_pending(mdev);
 					local=0;
 
 					drbd_end_req(req, RQ_DRBD_DONE, 1, sector);

From drbd-cvs at lists.linbit.com  Fri Aug 18 16:09:06 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 18 16:09:08 2006
Subject: [DRBD-cvs] svn commit by lars - r2376 - trunk/drbd - we have issues
	stacking the device limits properly.
Message-ID: <20060818140906.E88E92CDC422@mail.linbit.com>

I'd
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Author: lars
Date: 2006-08-18 16:09:04 +0200 (Fri, 18 Aug 2006)
New Revision: 2376

Modified:
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_req.c
Log:

we have issues stacking the device limits properly.
I'd like to know/be able to print the "id" in case
the bio_add_page in drbd_alloc_ee fails.

we have no more free_ee list,
thats been converted to mempool long ago.

Think:
we may either remove the asserts refering to ID_VACANT, too,
or we reinitialize before mempool_freeing.
the later might be good practise, anyways.

also, devfs has been removed from the kernel 2.6.18 (and deprecated for ages)
so get rid of it here, too.



Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/drbd_int.h	2006-08-18 14:09:04 UTC (rev 2376)
@@ -39,9 +39,6 @@
 extern int major_nr;
 extern int use_nbd_major;
 
-// use_nbd_major ? "nbd" : "drbd";
-extern char* drbd_devfs_name;
-
 #include <linux/major.h>
 #ifdef DRBD_MAJOR
 # warning "FIXME. DRBD_MAJOR is now officially defined in major.h"
@@ -628,7 +625,6 @@
 typedef struct drbd_request drbd_request_t;
 
 /* These Tl_epoch_entries may be in one of 6 lists:
-   free_ee   .. free entries
    active_ee .. data packet being written
    sync_ee   .. syncer block being written
    done_ee   .. block written, need to send WriteAck
@@ -1166,6 +1162,7 @@
 // drbd_receiver.c
 extern int drbd_release_ee(drbd_dev* mdev,struct list_head* list);
 extern struct Tl_epoch_entry* drbd_alloc_ee(drbd_dev *mdev,
+					    u64 id,
 					    sector_t sector,
 					    unsigned int data_size,
 					    unsigned int gfp_mask);

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/drbd_main.c	2006-08-18 14:09:04 UTC (rev 2376)
@@ -47,7 +47,6 @@
 #include <linux/drbd_config.h>
 #include <linux/mm_inline.h>
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/random.h>
 #include <linux/reboot.h>
 #include <linux/notifier.h>
@@ -139,10 +138,6 @@
 
 #endif
 
-// devfs name
-char* drbd_devfs_name = "drbd";
-
-
 // global panic flag
 volatile int drbd_did_panic = 0;
 
@@ -2131,9 +2126,6 @@
 	/*
 	 * currently we drbd_init_ee only on module load, so
 	 * we may do drbd_release_ee only on module unload!
-	 * drbd_release_ee(&mdev->free_ee);
-	 * D_ASSERT(list_emptry(&mdev->free_ee));
-	 *
 	 */
 	D_ASSERT(list_empty(&mdev->active_ee));
 	D_ASSERT(list_empty(&mdev->sync_ee));
@@ -2367,8 +2359,6 @@
 #endif
 	kfree(drbd_conf);
 
-	devfs_remove(drbd_devfs_name);
-
 	if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0)
 		printk(KERN_ERR DEVICE_NAME": unregister of device failed\n");
 
@@ -2441,8 +2431,6 @@
 	}
 	register_reboot_notifier(&drbd_notifier);
 
-	drbd_devfs_name = (major_nr == NBD_MAJOR) ? "nbd" : "drbd";
-
 	/*
 	 * allocate all necessary structs
 	 */
@@ -2456,8 +2444,6 @@
 		memset(drbd_conf,0,sizeof(drbd_dev)*minor_count);
 	else goto Enomem;
 
-	devfs_mk_dir(drbd_devfs_name);
-
 	for (i = 0; i < minor_count; i++) {
 		drbd_dev    *mdev = drbd_conf + i;
 		struct gendisk         *disk;
@@ -2480,7 +2466,6 @@
 		disk->first_minor = i;
 		disk->fops = &drbd_ops;
 		sprintf(disk->disk_name, DEVICE_NAME "%d", i);
-		sprintf(disk->devfs_name, "%s/%d", drbd_devfs_name, i);
 		disk->private_data = mdev;
 		add_disk(disk);
 

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/drbd_receiver.c	2006-08-18 14:09:04 UTC (rev 2376)
@@ -230,6 +230,7 @@
 */
 
 struct Tl_epoch_entry* drbd_alloc_ee(drbd_dev *mdev,
+				     u64 id,
 				     sector_t sector,
 				     unsigned int data_size,
 				     unsigned int gfp_mask)
@@ -239,7 +240,7 @@
 	struct page *page;
 	struct bio *bio;
 	unsigned int ds;
-	int bio_add,i;
+	int i;
 
 	e = mempool_alloc(drbd_ee_mempool, gfp_mask);
 	if (!e) return NULL;
@@ -254,8 +255,24 @@
 	while(ds) {
 		page = drbd_pp_alloc(mdev, gfp_mask);
 		if (!page) goto fail2;
-		bio_add=bio_add_page(bio, page, min_t(int, ds, PAGE_SIZE), 0);
-		D_ASSERT(bio_add);
+		if (!bio_add_page(bio, page, min_t(int, ds, PAGE_SIZE), 0)) {
+			/* if this happens, it indicates we are not doing correct
+			 * stacking of device limits.
+			 * or that the syncer (which may choose to ignore the
+			 * device limits) happend to request something which
+			 * does not work on this side...
+			 *
+			 * if this happens for the _first_ page, however, my
+			 * understanding is it would indicate a bug in the
+			 * lower levels, since adding _one_ page is
+			 * "guaranteed" to work.
+			 */
+			ERR("bio_add_page failed: "
+			    "id/sector/data_size/rest 0x%llx %llu %u %u\n",
+			    (unsigned long long)id,
+			    (unsigned long long)sector, data_size, ds);
+			break;
+		}
 		ds -= min_t(int, ds, PAGE_SIZE);
 	}
 
@@ -265,7 +282,7 @@
 	e->ee_size = bio->bi_size;
 	D_ASSERT( data_size == bio->bi_size);
 	e->private_bio = bio;
-	e->block_id = ID_VACANT;
+	e->block_id = id;
 	INIT_HLIST_NODE(&e->colision);
 	e->barrier_nr = 0;
 	e->barrier_nr2 = 0;
@@ -880,7 +897,7 @@
 }
 
 STATIC struct Tl_epoch_entry *
-read_in_block(drbd_dev *mdev, sector_t sector, int data_size)
+read_in_block(drbd_dev *mdev, u64 id, sector_t sector, int data_size)
 {
 	struct Tl_epoch_entry *e;
 	struct bio_vec *bvec;
@@ -888,7 +905,7 @@
 	struct bio *bio;
 	int ds,i,rr;
 
-	e = drbd_alloc_ee(mdev,sector,data_size,GFP_KERNEL);
+	e = drbd_alloc_ee(mdev,id,sector,data_size,GFP_KERNEL);
 	if(!e) return 0;
 	bio = e->private_bio;
 	ds = data_size;
@@ -987,7 +1004,7 @@
 {
 	struct Tl_epoch_entry *e;
 
-	e = read_in_block(mdev,sector,data_size);
+	e = read_in_block(mdev,ID_SYNCER,sector,data_size);
 	if(!e) {
 		dec_local(mdev);
 		return FALSE;
@@ -995,8 +1012,6 @@
 
 	dec_rs_pending(mdev);
 
-	e->block_id = ID_SYNCER;
-
 	drbd_ee_prepare_write(mdev,e);
 	e->w.cb     = e_end_resync_block;
 
@@ -1232,13 +1247,12 @@
 	}
 
 	sector = be64_to_cpu(p->sector);
-	e = read_in_block(mdev,sector,data_size);
+	e = read_in_block(mdev,p->block_id,sector,data_size);
 	if (!e) {
 		dec_local(mdev);
 		return FALSE;
 	}
 
-	e->block_id = p->block_id; // no meaning on this side, e* on partner
 	drbd_ee_prepare_write(mdev, e);
 	e->w.cb     = e_end_block;
 
@@ -1443,13 +1457,12 @@
 		return TRUE;
 	}
 
-	e = drbd_alloc_ee(mdev,sector,size,GFP_KERNEL);
+	e = drbd_alloc_ee(mdev,p->block_id,sector,size,GFP_KERNEL);
 	if (!e) {
 		dec_local(mdev);
 		return FALSE;
 	}
 
-	e->block_id = p->block_id; // no meaning on this side, pr* on partner
 	spin_lock_irq(&mdev->ee_lock);
 	list_add(&e->w.list,&mdev->read_ee);
 	spin_unlock_irq(&mdev->ee_lock);

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/drbd_req.c	2006-08-18 14:09:04 UTC (rev 2376)
@@ -271,7 +271,13 @@
 		    (volatile int)((mdev->state.conn < WFBitMapS ||
 				    mdev->state.conn > WFBitMapT) &&
 				   !mdev->state.susp ) );
-
+	/* FIXME RACE
+	 * the wait condition may already be wrong again...
+	 * ok, thats "academic" atm, but probably not good in the long term.
+	 *
+	 * we should have a function that does wait for the condition,
+	 * and do the inc_local within what ever lock is necessary...
+	 */
 	local = inc_local(mdev);
 	if (rw == READ || rw == READA) {
 		if (local) {

From drbd-cvs at lists.linbit.com  Fri Aug 18 18:13:51 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 18 18:13:52 2006
Subject: [DRBD-cvs] svn commit by lars - r2377 - trunk/drbd - work on the
	syncer may or may not ignore the agreed-upo
Message-ID: <20060818161351.9671D2D99849@mail.linbit.com>

Author: lars
Date: 2006-08-18 18:13:50 +0200 (Fri, 18 Aug 2006)
New Revision: 2377

Modified:
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_worker.c
Log:

work on the syncer may or may not ignore the agreed-upon max_segment-size
apart from "it still compiles" no test done.  I'll have to make up my mind
whether it is worth the hassle.  probably not...



Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-18 14:09:04 UTC (rev 2376)
+++ trunk/drbd/drbd_receiver.c	2006-08-18 16:13:50 UTC (rev 2377)
@@ -256,31 +256,81 @@
 		page = drbd_pp_alloc(mdev, gfp_mask);
 		if (!page) goto fail2;
 		if (!bio_add_page(bio, page, min_t(int, ds, PAGE_SIZE), 0)) {
-			/* if this happens, it indicates we are not doing correct
-			 * stacking of device limits.
-			 * or that the syncer (which may choose to ignore the
-			 * device limits) happend to request something which
-			 * does not work on this side...
-			 *
-			 * if this happens for the _first_ page, however, my
-			 * understanding is it would indicate a bug in the
-			 * lower levels, since adding _one_ page is
-			 * "guaranteed" to work.
+			/*
+			 * actually:
+			drbd_pp_free(page);
+			goto fail2;
+			 * But see below.
 			 */
+			break;
+		}
+		ds -= min_t(int, ds, PAGE_SIZE);
+	}
+
+	/* D_ASSERT( data_size == bio->bi_size); */
+	if (ds) {
+		/*
+		 * bio_add_page failed.
+		 *
+		 * if this happens, it indicates we are not doing correct
+		 * stacking of device limits.
+		 *
+		 * ---
+		 * this may also happen on the SyncSource for syncer requests:
+		 * for performance, the syncer may choose to ignore the
+		 * agreed-upon device limits (max_segment_size may be
+		 * arbitrarily set to PAGE_SIZE because the lower level device
+		 * happens to have a merge_bvec_fn).
+		 *
+		 * we would then just "split" the request here,
+		 * and then send multiple RSDataReply packets to the peer.
+		 *
+		 * FIXME to implement that, we'd need ot be able to
+		 * "return several Tl_epoch_entry" here,
+		 * so we'd need to either recurse, or add more state to the
+		 * return valud of this function.
+		 * or let the caller check e->ee_size against what he requested,
+		 * and reiterate there.
+		 *
+		 * It is probably just not worth the hassle,
+		 * but I'll check it in unfinished now anyways.
+		 *
+		 * TODO
+		 * either complete support on this side, or rip it out
+		 * and do the one-liner patch in w_make_resync_request
+		 * exchanging DRBD_MAX_SEGMENT_SIZE with q->max_segment_size
+		 * ---
+		 *
+		 * if this happens for the _first_ page, however, my
+		 * understanding is it would indicate a bug in the lower levels,
+		 * since adding _one_ page is "guaranteed" to work.
+		 */
+		if (ds < data_size && id == ID_SYNCER) {
+			/* this currently only serves the first part of that
+			 * request. you have to restart the syncer...
+			 * this is currently still very buggy and get our
+			 * housekeeping about in-sync areas completely wrong.
+			 */
+			ERR("should have split resync request: "
+			    "sector/data_size/rest %llu %u %u\n",
+			    (unsigned long long)sector, data_size, ds);
+		} else {
+			/* this should not happen,
+			 * if we correctly stacked limits. */
 			ERR("bio_add_page failed: "
 			    "id/sector/data_size/rest 0x%llx %llu %u %u\n",
 			    (unsigned long long)id,
 			    (unsigned long long)sector, data_size, ds);
-			break;
+			drbd_pp_free(mdev,page);
+			goto fail2;
 		}
-		ds -= min_t(int, ds, PAGE_SIZE);
 	}
 
 	bio->bi_private = e;
 	e->mdev = mdev;
 	e->ee_sector = sector;
 	e->ee_size = bio->bi_size;
-	D_ASSERT( data_size == bio->bi_size);
+
 	e->private_bio = bio;
 	e->block_id = id;
 	INIT_HLIST_NODE(&e->colision);

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-18 14:09:04 UTC (rev 2376)
+++ trunk/drbd/drbd_worker.c	2006-08-18 16:13:50 UTC (rev 2377)
@@ -322,6 +322,7 @@
 
 	next_sector:
 		size = BM_BLOCK_SIZE;
+		/* as of now, we are the only user of drbd_bm_find_next */
 		bit  = drbd_bm_find_next(mdev);
 
 		if (bit == -1UL) {
@@ -347,19 +348,38 @@
 		}
 
 #if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE
-		// try to find some adjacent bits...
-		while ( drbd_bm_test_bit(mdev,bit+1) == 1 ) {
-			// stop if we have the already the maximum req size
-			if(size == DRBD_MAX_SEGMENT_SIZE) break;
-			// do not leafe the current BM_EXTEND
-			if(( (bit+1) & BM_BLOCKS_PER_BM_EXT_MASK ) == 0) break;
+		/* try to find some adjacent bits.
+		 * we stop if we have already the maximum req size
+		 * or if it the request would cross a 32k boundary
+		 * (play more nicely with most raid devices).
+		 *
+		 * we don't care about the agreed-uppon q->max_segment_size
+		 * here, because we don't keep a reference on this side.
+		 * the sync source will split the requests approrpiately as
+		 * needed, and may send multiple RSDataReply packets.
+		 */
+		for (;;) {
+			if (size < DRBD_MAX_SEGMENT_SIZE)
+				break;
+			if ((sector & ~63ULL) + BM_BIT_TO_SECT(2) <= 64ULL)
+				break;
+			// do not cross extent boundaries
+			if (( (bit+1) & BM_BLOCKS_PER_BM_EXT_MASK ) == 0)
+				break;
+			// now, is it actually dirty, after all?
+			if ( drbd_bm_test_bit(mdev,bit+1) == 0 )
+				break;
 			bit++;
 			size += BM_BLOCK_SIZE;
 			i++;
 		}
-		drbd_bm_set_find(mdev,bit+1);
+		/* if we merged some,
+		 * reset the offset to start the next drbd_bm_find_next from */
+		if (size > BM_BLOCK_SIZE)
+			drbd_bm_set_find(mdev,bit+1);
 #endif
 
+		/* adjust very last sectors, in case we are oddly sized */
 		if (sector + (size>>9) > capacity) size = (capacity-sector)<<9;
 		inc_rs_pending(mdev);
 		if(!drbd_send_drequest(mdev,RSDataRequest,

From drbd-cvs at lists.linbit.com  Sat Aug 19 18:49:59 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sat Aug 19 18:50:01 2006
Subject: [DRBD-cvs] svn commit by lars - r2378 - trunk/drbd - CAUTION:
Message-ID: <20060819165000.212972CE93AC@mail.linbit.com>

checkin of broken code. well, I'ts not newly b
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Author: lars
Date: 2006-08-19 18:49:58 +0200 (Sat, 19 Aug 2006)
New Revision: 2378

Modified:
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_req.c
   trunk/drbd/drbd_worker.c
Log:

CAUTION:
checkin of broken code.  well, I'ts not newly broken,
I just point out where it is broken.

I don't think adding several band aids in various places is the way to go, so
I'm going to work on a new implementation of the req "state machine" next.



Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-18 16:13:50 UTC (rev 2377)
+++ trunk/drbd/drbd_receiver.c	2006-08-19 16:49:58 UTC (rev 2378)
@@ -1100,7 +1100,7 @@
 
 	sector = be64_to_cpu(p->sector);
 
-	req = (drbd_request_t *)(long)p->block_id;
+	req = (drbd_request_t *)(unsigned long)p->block_id;
 	if(unlikely(!drbd_pr_verify(mdev,req,sector))) {
 		ERR("Got a corrupt block_id/sector pair(1).\n");
 		return FALSE;

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-18 16:13:50 UTC (rev 2377)
+++ trunk/drbd/drbd_req.c	2006-08-19 16:49:58 UTC (rev 2378)
@@ -94,6 +94,11 @@
 			if(tl_dependence(mdev,req))
 				set_bit(ISSUE_BARRIER,&mdev->flags);
 		} else {
+			/* FIXME not longer true!
+			 * we don't have the tl_lock here anymore...
+			 * sorry sir.
+			 **/
+			MUST_HOLD(&mdev->tl_lock);
 			list_del(&req->tl_requests); // we have the tl_lock...
 			hlist_del(&req->colision);
 			// req->barrier->n_req--; // Barrier migh be free'ed !

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-18 16:13:50 UTC (rev 2377)
+++ trunk/drbd/drbd_worker.c	2006-08-19 16:49:58 UTC (rev 2378)
@@ -576,18 +576,16 @@
 		sector = drbd_req_get_sector(req);
 		size   = drbd_req_get_size(req);
 
-		drbd_end_req(req,RQ_DRBD_SENT,1, sector);
+		drbd_end_req(req,RQ_DRBD_SENT|RQ_DRBD_ON_WIRE,1, sector);
 		drbd_set_out_of_sync(mdev, sector, size);
 
 		return 1;
 	}
 
+	inc_ap_pending(mdev);
 	ok = drbd_send_dblock(mdev,req);
+	drbd_end_req(req,RQ_DRBD_ON_WIRE,1,drbd_req_get_sector(req));
 	if (ok) {
-		inc_ap_pending(mdev);
-
-		drbd_end_req(req,RQ_DRBD_ON_WIRE,1,drbd_req_get_sector(req));
-
 		if(mdev->net_conf->wire_protocol == DRBD_PROT_A) {
 			dec_ap_pending(mdev);
 			drbd_end_req(req, RQ_DRBD_SENT, 1, 

From drbd-cvs at lists.linbit.com  Wed Aug 23 12:10:10 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Aug 23 12:10:11 2006
Subject: [DRBD-cvs] svn commit by phil - r2381 - in branches/drbd-0.7: drbd
	drbd/linux scripts - More stuff to gracefully fade out the
	DEVFS support 
Message-ID: <20060823101010.7EDB32CF09E8@mail.linbit.com>

Author: phil
Date: 2006-08-23 12:10:08 +0200 (Wed, 23 Aug 2006)
New Revision: 2381

Modified:
   branches/drbd-0.7/drbd/drbd_int.h
   branches/drbd-0.7/drbd/drbd_main.c
   branches/drbd-0.7/drbd/linux/drbd_config.h
   branches/drbd-0.7/scripts/adjust_drbd_config_h.sh
Log:
More stuff to gracefully fade out the DEVFS support


Modified: branches/drbd-0.7/drbd/drbd_int.h
===================================================================
--- branches/drbd-0.7/drbd/drbd_int.h	2006-08-23 09:56:05 UTC (rev 2380)
+++ branches/drbd-0.7/drbd/drbd_int.h	2006-08-23 10:10:08 UTC (rev 2381)
@@ -73,7 +73,7 @@
 extern int major_nr;
 extern int use_nbd_major;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 // use_nbd_major ? "nbd" : "drbd";
 extern char* drbd_devfs_name;
 #endif

Modified: branches/drbd-0.7/drbd/drbd_main.c
===================================================================
--- branches/drbd-0.7/drbd/drbd_main.c	2006-08-23 09:56:05 UTC (rev 2380)
+++ branches/drbd-0.7/drbd/drbd_main.c	2006-08-23 10:10:08 UTC (rev 2381)
@@ -49,7 +49,7 @@
 #include <linux/mm_inline.h>
 #endif
 #include <linux/slab.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 #include <linux/devfs_fs_kernel.h>
 #endif
 
@@ -146,7 +146,7 @@
 #endif
 int disable_bd_claim = 0;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 // devfs name
 char* drbd_devfs_name = "drbd";
 #endif
@@ -1698,7 +1698,7 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	devfs_unregister(devfs_handle);
 #else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 	devfs_remove(drbd_devfs_name);
 #endif
 #endif
@@ -1774,7 +1774,7 @@
 		return err;
 	}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 	drbd_devfs_name = (major_nr == NBD_MAJOR) ? "nbd" : "drbd";
 #endif
 
@@ -1798,7 +1798,7 @@
 	if (unlikely(!drbd_blocksizes)) goto Enomem;
 #else
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 	devfs_mk_dir(drbd_devfs_name);
 #endif
 
@@ -1823,7 +1823,7 @@
 		disk->first_minor = i;
 		disk->fops = &drbd_ops;
 		sprintf(disk->disk_name, DEVICE_NAME "%d", i);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#ifndef NO_MORE_DEV_FS
 		sprintf(disk->devfs_name, "%s/%d", drbd_devfs_name, i);
 #endif
 		disk->private_data = mdev;

Modified: branches/drbd-0.7/drbd/linux/drbd_config.h
===================================================================
--- branches/drbd-0.7/drbd/linux/drbd_config.h	2006-08-23 09:56:05 UTC (rev 2380)
+++ branches/drbd-0.7/drbd/linux/drbd_config.h	2006-08-23 10:10:08 UTC (rev 2381)
@@ -69,4 +69,6 @@
 // but more recent kernels define it in arch/um/include/mem.h
 #define HAVE_UML_TO_VIRT
 
+#define NO_MORE_DEV_FS
+
 #endif

Modified: branches/drbd-0.7/scripts/adjust_drbd_config_h.sh
===================================================================
--- branches/drbd-0.7/scripts/adjust_drbd_config_h.sh	2006-08-23 09:56:05 UTC (rev 2380)
+++ branches/drbd-0.7/scripts/adjust_drbd_config_h.sh	2006-08-23 10:10:08 UTC (rev 2381)
@@ -80,6 +80,7 @@
   else
     have_mm_inline_h=0
   fi
+    no_more_dev_fs=0
 else
     # 2.6. kernel. just leave it alone...
     need_sighand_hack=0
@@ -87,6 +88,7 @@
     need_RH_2_4_18_hack=0
     have_find_next_bit=0
     have_mm_inline_h=0
+    no_more_dev_fs=1
 fi
 
 test -e ./linux/drbd_config.h.orig || cp ./linux/drbd_config.h{,.orig}
@@ -101,7 +103,9 @@
  s{.*(#define HAVE_FIND_NEXT_BIT.*)}
   { ( $have_find_next_bit ? '' : '//' ) . \$1}e;
  s{.*(#define HAVE_MM_INLINE_H.*)}
-  { ( $have_mm_inline_h ? '' : '//' ) . \$1}e;" \
+  { ( $have_mm_inline_h ? '' : '//' ) . \$1}e;
+ s{.*(#define NO_MORE_DEV_FS.*)}
+  { ( $no_more_dev_fs ? '' : '//' ) . \$1}e;" \
 	  < ./linux/drbd_config.h \
 	  > ./linux/drbd_config.h.new
 

From drbd-cvs at lists.linbit.com  Fri Aug 25 10:50:51 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 25 10:50:55 2006
Subject: [DRBD-cvs] svn commit by phil - r2386 - in trunk: . drbd drbd/linux
	user - The new netlink (connector) based userland <-> kernel i
Message-ID: <20060825085051.961C42DF624A@mail.linbit.com>

Author: phil
Date: 2006-08-25 10:50:47 +0200 (Fri, 25 Aug 2006)
New Revision: 2386

Added:
   trunk/drbd/drbd_nl.c
   trunk/drbd/linux/drbd_limits.h
   trunk/drbd/linux/drbd_nl.h
   trunk/drbd/linux/drbd_tag_magic.h
Removed:
   trunk/drbd/drbd_sizeof_sanity_check.c
   trunk/user/drbd_limits.h
   trunk/user/drbd_nl.h
   trunk/user/drbd_tag_magic.h
   trunk/user/drbdsetup.c
Modified:
   trunk/ROADMAP
   trunk/drbd/Makefile-2.6
   trunk/drbd/drbd_compat_wrappers.h
   trunk/drbd/drbd_fs.c
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_proc.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_req.c
   trunk/drbd/drbd_worker.c
   trunk/drbd/linux/drbd.h
   trunk/drbd/linux/drbd_config.h
   trunk/user/Makefile
   trunk/user/drbdadm_parser.c
   trunk/user/drbdsetup_nl.c
   trunk/user/drbdtool_common.c
Log:
The new netlink (connector) based userland <-> kernel interface.
It probably breaks a lot of things, but it the way to go. It will
take a few days before everything works again, and the bugs are
shaked out...


Modified: trunk/ROADMAP
===================================================================
--- trunk/ROADMAP	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/ROADMAP	2006-08-25 08:50:47 UTC (rev 2386)
@@ -417,8 +417,41 @@
   at the beginning, including the expected API version.
   Consider using DRBD ioctls with some char device similar to
   /dev/mapper/control
-  0% DONE
 
+  The new interface is now based on netlink (actually connector).
+  It is based on the concept of tag lists. The idea is that on the
+  interface we pass lists (actually arrays) of tags. Where each
+  tag identifies the following sniplet of data. 
+  Each tag also states if it is mandatory.
+
+  In case we have to add a new value to the interface, the
+  existing userland tools continue to work with newer kernel
+  modules and vice versa. (Only the older part of the two will
+  inform the user with a warning, that there was a unknown
+  tag on the interface, and that the unknown tag got ignored) 
+  But the basic functionality stays intact!
+
+  While implementing this, we also implemented dynamic device allocation.
+
+  drbdsetup is basically call compatible to its ioctl based
+  ancestor, but has two now options:
+
+    --create-device ___ create the device in case int does not exist yet.
+    --set-defaults ____ set all not mentioned options to it's default values.
+
+  Things to do:
+  
+  * Fix drbdadm (nees to use --create-device and --set-defaults; adjust
+      needs to be changes since the kernel can not return the device
+      names of backing and meta device.)
+  * Remove the memset( .., 0, ...) from drbd_nl.c. Use the defaults instead.
+  * Use only one connector callback.
+  * use try_module_get() and put_module() when control enters a/the connector
+    callback.
+  * Locking in userspace, to prevent multiple instances of drbdsetup
+
+  50% DONE
+
 15 Accept BIOs bigger than one page, probabely up to 32k (8 pages) 
   currently.
   * Normal Requsts. -> DONE
@@ -785,7 +818,7 @@
 34 Improve the initial hand-shake, to identify the sockets (and TCP-
    links) by an initial message, and not only by the connection timming.
 
-   99% DONE   
+   99% DONE
 
 35 Bigger AL-extents (e.g. 16MB)
 
@@ -828,17 +861,14 @@
 
 2 Implement online verification
 
-3 dynamic device allocation 
-  (requires configuration throu a new mechanism (netlink socket/misc dev)
-
-4 Change the bitmap code to work with unmapped highmem pages, instead
+3 Change the bitmap code to work with unmapped highmem pages, instead
   of using vmalloc()ed memory. This allows users of 32bit platforms
   to use drbd on big devices (in the ~3TB range)
 
-5 3 node support. Do and test a 3 node setup (2nd DRBD stacked over
+4 3 node support. Do and test a 3 node setup (2nd DRBD stacked over
   a DRBD pair). Enhance the user level tools to support the 3 node
   setup.
 
-6 Have protocol version 74 available in drbd-0.8, to allow rolling 
+5 Have protocol version 74 available in drbd-0.8, to allow rolling 
   upgrades
 

Modified: trunk/drbd/Makefile-2.6
===================================================================
--- trunk/drbd/Makefile-2.6	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/Makefile-2.6	2006-08-25 08:50:47 UTC (rev 2386)
@@ -1,7 +1,6 @@
 #CFLAGS_drbd_sizeof_sanity_check.o = -Wpadded # -Werror
 
-drbd-objs  :=	drbd_sizeof_sanity_check.o \
-		drbd_buildtag.o drbd_bitmap.o drbd_fs.o drbd_proc.o \
+drbd-objs  :=	drbd_buildtag.o drbd_bitmap.o drbd_proc.o \
 		drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o \
-		lru_cache.o drbd_main.o drbd_strings.o
+		lru_cache.o drbd_main.o drbd_strings.o drbd_nl.o
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd.o

Modified: trunk/drbd/drbd_compat_wrappers.h
===================================================================
--- trunk/drbd/drbd_compat_wrappers.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_compat_wrappers.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -174,14 +174,11 @@
  */
 static inline void drbd_generic_make_request(int rw, struct bio *bio)
 {
-	drbd_dev *mdev = drbd_conf -1; // for DRBD_ratelimit
 	bio->bi_rw = rw; // on the receiver side, e->..rw was not yet defined.
 
 	if (!bio->bi_bdev) {
-		if (DRBD_ratelimit(5*HZ,5)) {
-			printk(KERN_ERR "drbd_generic_make_request: bio->bi_bdev == NULL\n");
-			dump_stack();
-		}
+		printk(KERN_ERR "drbd_generic_make_request: bio->bi_bdev == NULL\n");
+		dump_stack();
 		drbd_bio_IO_error(bio);
 		return;
 	}

Modified: trunk/drbd/drbd_fs.c
===================================================================
--- trunk/drbd/drbd_fs.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_fs.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -54,7 +54,7 @@
 				       struct drbd_backing_dev *bdev)
 {
 	sector_t md_size_sect = 0;
-	switch(bdev->md_index) {
+	switch(bdev->dc.meta_dev_idx) {
 	default:
 	case DRBD_MD_INDEX_FLEX_EXT:
 		/* just occupy the full device; unit: sectors */
@@ -180,7 +180,7 @@
 	sector_t p_size = mdev->p_size;   // partner's disk size.
 	sector_t la_size = bdev->md.la_size_sect; // last agreed size.
 	sector_t m_size; // my size
-	sector_t u_size = bdev->u_size; // size requested by user.
+	sector_t u_size = bdev->dc.disk_size; // size requested by user.
 	sector_t size=0;
 
 	m_size = drbd_get_max_capacity(bdev);
@@ -316,7 +316,7 @@
 	drbd_state_t ns,os;
 	int rv;
 
-	minor=(int)(mdev-drbd_conf);
+	minor=mdev_to_minor(mdev);
 
 	/* if you want to reconfigure, please tear down first */
 	if (mdev->state.disk > Diskless)
@@ -439,10 +439,10 @@
 		goto release_bdev2_fail_ioctl;
 	}
 
-	nbc->md_index = new_conf.meta_index;
-	nbc->u_size = new_conf.disk_size;
-	nbc->on_io_error = new_conf.on_io_error;
-	nbc->fencing = new_conf.fencing;
+	nbc->dc.meta_dev_idx = new_conf.meta_index;
+	nbc->dc.disk_size = new_conf.disk_size;
+	nbc->dc.on_io_error = new_conf.on_io_error;
+	nbc->dc.fencing = new_conf.fencing;
 	drbd_md_set_sector_offsets(mdev,nbc);
 
 	retcode = drbd_md_read(mdev,nbc);
@@ -562,7 +562,7 @@
 		}
 
 		if( ns.disk == Consistent && 
-		    ( ns.pdsk == Outdated || nbc->fencing == DontCare ) ) {
+		    ( ns.pdsk == Outdated || nbc->dc.fencing == DontCare ) ) {
 			ns.disk = UpToDate;
 		}
 		
@@ -616,17 +616,17 @@
 		cn.meta_device_major  = MAJOR(mdev->bc->md_bdev->bd_dev);
 		cn.meta_device_minor  = MINOR(mdev->bc->md_bdev->bd_dev);
 		bdevname(mdev->bc->md_bdev,cn.meta_device_name);
-		cn.meta_index=mdev->bc->md_index;
-		cn.on_io_error=mdev->bc->on_io_error;
-		cn.fencing=mdev->bc->fencing;
+		cn.meta_index=mdev->bc->dc.meta_dev_idx;
+		cn.on_io_error=mdev->bc->dc.on_io_error;
+		cn.fencing=mdev->bc->dc.fencing;
 		dec_local(mdev);
 	}
 	cn.state=mdev->state;
 	if(inc_net(mdev)) {
-		memcpy(&cn.nconf, mdev->net_conf, sizeof(struct net_config));
+		memcpy(&cn.nconf, mdev->net_conf, sizeof(struct net_conf));
 		dec_net(mdev);
 	}
-	memcpy(&cn.sconf, &mdev->sync_conf, sizeof(struct syncer_config));
+	memcpy(&cn.sconf, &mdev->sync_conf, sizeof(struct syncer_conf));
 
 	if (copy_to_user(arg,&cn,sizeof(struct ioctl_get_config)))
 		return -EFAULT;
@@ -636,24 +636,23 @@
 
 
 STATIC
-int drbd_ioctl_set_net(struct Drbd_Conf *mdev, struct ioctl_net_config * arg)
+int drbd_ioctl_set_net(struct Drbd_Conf *mdev, struct ioctl_net_conf * arg)
 {
-	int i,minor,ns;
+	int i,ns;
 	enum ret_codes retcode;
-	struct net_config *new_conf = NULL;
+	struct net_conf *new_conf = NULL;
 	struct crypto_tfm* tfm = NULL;
 	struct hlist_head *new_tl_hash = NULL;
 	struct hlist_head *new_ee_hash = NULL;
+	struct Drbd_Conf *odev;
 
-	minor=(int)(mdev-drbd_conf);
-
-	new_conf = kmalloc(sizeof(struct net_config),GFP_KERNEL);
+	new_conf = kmalloc(sizeof(struct net_conf),GFP_KERNEL);
 	if(!new_conf) {			
 		retcode=KMallocFailed;
 		goto fail_ioctl;
 	}
 
-	if (copy_from_user(new_conf, &arg->config,sizeof(struct net_config)))
+	if (copy_from_user(new_conf, &arg->config,sizeof(struct net_conf)))
 		return -EFAULT;
 
 	if( mdev->state.role == Primary && new_conf->want_lose ) {
@@ -665,16 +664,17 @@
 #define M_PORT(A) (((struct sockaddr_in *)&A->my_addr)->sin_port)
 #define O_ADDR(A) (((struct sockaddr_in *)&A->other_addr)->sin_addr.s_addr)
 #define O_PORT(A) (((struct sockaddr_in *)&A->other_addr)->sin_port)
-	for(i=0;i<minor_count;i++) {
-		if( i!=minor && drbd_conf[i].state.conn > StandAlone &&
-		    M_ADDR(new_conf) == M_ADDR(drbd_conf[i].net_conf) &&
-		    M_PORT(new_conf) == M_PORT(drbd_conf[i].net_conf) ) {
+	for(i=0;i<next_minor;i++) {
+		odev = minor_to_mdev(i);
+		if( mdev != odev && odev->state.conn > StandAlone &&
+		    M_ADDR(new_conf) == M_ADDR(odev->net_conf) &&
+		    M_PORT(new_conf) == M_PORT(odev->net_conf) ) {
 			retcode=LAAlreadyInUse;
 			goto fail_ioctl;
 		}
-		if( i!=minor && drbd_conf[i].state.conn > StandAlone &&
-		    O_ADDR(new_conf) == O_ADDR(drbd_conf[i].net_conf) &&
-		    O_PORT(new_conf) == O_PORT(drbd_conf[i].net_conf) ) {
+		if( mdev != odev && odev->state.conn > StandAlone &&
+		    O_ADDR(new_conf) == O_ADDR(odev->net_conf) &&
+		    O_PORT(new_conf) == O_PORT(odev->net_conf) ) {
 			retcode=OAAlreadyInUse;
 			goto fail_ioctl;
 		}
@@ -808,7 +808,7 @@
 				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
 				NULL };
 
-	snprintf(mb,12,"minor-%d",(int)(mdev-drbd_conf));
+	snprintf(mb,12,"minor-%d",mdev_to_minor(mdev));
 	return call_usermodehelper("/sbin/drbdadm",argv,envp,1);
 }
 
@@ -822,7 +822,7 @@
 
 	fp = DontCare;
 	if(inc_local(mdev)) {
-		fp = mdev->bc->fencing;
+		fp = mdev->bc->dc.fencing;
 		dec_local(mdev);
 	}
 
@@ -1015,9 +1015,9 @@
 }
 
 STATIC int drbd_ioctl_set_syncer(struct Drbd_Conf *mdev,
-				 struct ioctl_syncer_config* arg)
+				 struct ioctl_syncer_conf* arg)
 {
-	struct syncer_config sc;
+	struct syncer_conf sc;
 	drbd_dev *odev;
 
 	int err;
@@ -1025,12 +1025,12 @@
 	if(copy_from_user(&sc,&arg->config,sizeof(sc))) return -EFAULT;
 
 	if( sc.after != -1) {
-		if( sc.after < -1 || sc.after > minor_count ) return -ERANGE;
-		odev = drbd_conf + sc.after; // check against loops in
+		if( sc.after < -1 || sc.after > next_minor ) return -ERANGE;
+		odev = minor_to_mdev(sc.after); // check against loops in
 		while(1) {
 			if( odev == mdev ) return -EBADMSG; // cycle found.
 			if( odev->sync_conf.after == -1 ) break; // no cycles.
-			odev = drbd_conf + odev->sync_conf.after;
+			odev = minor_to_mdev(odev->sync_conf.after);
 		}
 	}
 
@@ -1181,8 +1181,8 @@
 	struct gendisk *disk = bdev->bd_disk;
 
 	minor = MINOR(inode->i_rdev);
-	if (minor >= minor_count) return -ENODEV;
-	mdev = drbd_conf + minor;
+	if (minor >= next_minor) return -ENODEV;
+	mdev = minor_to_mdev(minor);
 
 	D_ASSERT(MAJOR(inode->i_rdev) == MAJOR_NR);
 
@@ -1259,7 +1259,7 @@
 			break;
 		}
 		err=0;
-		mdev->bc->u_size = (sector_t)(u64)arg;
+		mdev->bc->dc.disk_size = (sector_t)(u64)arg;
 		drbd_bm_lock(mdev);
 		drbd_determin_dev_size(mdev);
 		drbd_md_sync(mdev);
@@ -1271,12 +1271,12 @@
 		break;
 
 	case DRBD_IOCTL_SET_NET_CONFIG:
-		err = drbd_ioctl_set_net(mdev,(struct ioctl_net_config*) arg);
+		err = drbd_ioctl_set_net(mdev,(struct ioctl_net_conf*) arg);
 		break;
 
 	case DRBD_IOCTL_SET_SYNC_CONFIG:
 		err = drbd_ioctl_set_syncer(mdev,
-					    (struct ioctl_syncer_config*) arg);
+					    (struct ioctl_syncer_conf*) arg);
 		break;
 
 	case DRBD_IOCTL_GET_CONFIG:

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_int.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -129,7 +129,7 @@
 //       Otherwise this is not portable from gcc-2.95 to gcc-3.3
 #define PRINTK(level,fmt,args...) \
 	printk(level DEVICE_NAME "%d: " fmt, \
-		(int)(mdev-drbd_conf) , ##args)
+		mdev->minor , ##args)
 
 #define ALERT(fmt,args...) PRINTK(KERN_ALERT, fmt , ##args)
 #define ERR(fmt,args...)  PRINTK(KERN_ERR, fmt , ##args)
@@ -246,24 +246,25 @@
  */
 
 extern volatile int drbd_did_panic;
+extern struct Drbd_Conf **minor_table;
 
 #if    DRBD_PANIC == 0
 #define drbd_panic(fmt, args...) \
-	panic(DEVICE_NAME "%d: " fmt, (int)(mdev-drbd_conf) , ##args)
+	panic(DEVICE_NAME "%d: " fmt, mdev_to_minor(mdev) , ##args)
 #elif  DRBD_PANIC == 1
 #error "sorry , this does not work, please contribute"
 #elif  DRBD_PANIC == 2
 #define drbd_panic(fmt, args...) do {					\
 	printk(KERN_EMERG DEVICE_NAME "%d: " fmt,			\
-			(int)(mdev-drbd_conf) , ##args);		\
+			mdev_to_minor(mdev) , ##args);		\
 	drbd_did_panic = DRBD_MAGIC;					\
 	smp_mb();							\
-	panic(DEVICE_NAME "%d: " fmt, (int)(mdev-drbd_conf) , ##args);	\
+	panic(DEVICE_NAME "%d: " fmt, mdev_to_minor(mdev) , ##args);	\
 } while (0)
 #else
 #define drbd_panic(fmt, args...) do {					\
 	printk(KERN_EMERG DEVICE_NAME "%d: " fmt,			\
-			(int)(mdev-drbd_conf) , ##args);		\
+			mdev_to_minor(mdev) , ##args);		\
 } while (0)
 #endif
 #undef DRBD_PANIC
@@ -723,16 +724,21 @@
 	 */
 };
 
+// for sync_conf and other types...
+#define PACKET(name, fields) struct name { fields };
+#define INTEGER(pn,pr,member) int member;
+#define INT64(pn,pr,member) __u64 member;
+#define BIT(pn,pr,member)   unsigned member : 1;
+#define STRING(pn,pr,member,len) unsigned char member[len]; int member ## _len;
+#include "linux/drbd_nl.h"
+
 struct drbd_backing_dev {
 	struct block_device *backing_bdev;
 	struct block_device *md_bdev;
 	struct file *lo_file;
 	struct file *md_file;
-	int md_index;
-	enum io_error_handler on_io_error;
-	enum fencing_policy fencing;
-	sector_t u_size;   /* user provided size */
 	struct drbd_md md;
+	struct disk_conf dc; /* The user provided config... */
 };
 
 struct Drbd_Conf {
@@ -746,8 +752,8 @@
 	struct semaphore device_mutex;
 
 	/* configured by drbdsetup */
-	struct net_config *net_conf; // protected by inc_net() and dec_net()
-	struct syncer_config sync_conf;
+	struct net_conf *net_conf; // protected by inc_net() and dec_net()
+	struct syncer_conf sync_conf;
 	struct drbd_backing_dev *bc; // protected by inc_local() dec_local()
 
 	sector_t p_size;     /* partner's disk size */
@@ -831,9 +837,24 @@
 	int peer_seq;
 	spinlock_t peer_seq_lock;
 	struct list_head discard;
+	int minor;
 };
 
+static inline drbd_dev *minor_to_mdev(int minor)
+{
+	drbd_dev *mdev;
 
+	mdev = minor < minor_count ? minor_table[minor] : NULL;
+
+	return mdev;
+}
+
+static inline int mdev_to_minor(drbd_dev *mdev)
+{
+	return mdev->minor;
+}
+
+
 /*
  * function declarations
  *************************/
@@ -886,7 +907,7 @@
 			  Drbd_Packet_Cmd cmd, Drbd_Header *h, size_t size);
 extern int drbd_send_cmd2(drbd_dev *mdev, Drbd_Packet_Cmd cmd,
 			  char* data, size_t size);
-extern int drbd_send_sync_param(drbd_dev *mdev, struct syncer_config *sc);
+extern int drbd_send_sync_param(drbd_dev *mdev, struct syncer_conf *sc);
 extern int drbd_send_b_ack(drbd_dev *mdev, u32 barrier_nr,
 			   u32 set_size);
 extern int drbd_send_ack(drbd_dev *mdev, Drbd_Packet_Cmd cmd,
@@ -1092,7 +1113,6 @@
 
 
 // drbd_main.c
-extern drbd_dev *drbd_conf;
 extern int minor_count;
 extern kmem_cache_t *drbd_request_cache;
 extern kmem_cache_t *drbd_ee_cache;
@@ -1104,6 +1124,8 @@
 extern int          drbd_pp_vacant;
 extern wait_queue_head_t drbd_pp_wait;
 
+extern drbd_dev *drbd_new_device(int minor);
+
 // drbd_req
 #define ERF_NOTLD    2   /* do not call tl_dependence */
 extern void drbd_end_req(drbd_request_t *, int, int, sector_t);
@@ -1118,7 +1140,7 @@
 extern sector_t drbd_new_dev_size(struct Drbd_Conf*, struct drbd_backing_dev*);
 extern int drbd_determin_dev_size(drbd_dev*);
 extern void drbd_setup_queue_param(drbd_dev *mdev, unsigned int);
-extern int drbd_set_role(drbd_dev *mdev, int *arg);
+extern int drbd_set_role(drbd_dev *mdev, drbd_role_t new_role, int force);
 extern int drbd_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg);
 drbd_disks_t drbd_try_outdate_peer(drbd_dev *mdev);
@@ -1195,6 +1217,12 @@
 extern void drbd_al_to_on_disk_bm(struct Drbd_Conf *mdev);
 extern void drbd_al_shrink(struct Drbd_Conf *mdev);
 
+
+// drbd_nl.c
+
+void drbd_nl_cleanup(void);
+int __init drbd_nl_init(void);
+
 /*
  * inline helper functions
  *************************/
@@ -1260,7 +1288,7 @@
 		unsigned long flags;
 		spin_lock_irqsave(&mdev->req_lock,flags);
 
-		switch(mdev->bc->on_io_error) {
+		switch(mdev->bc->dc.on_io_error) {
 		case PassOn:
 			ERR("Ignoring local IO error!\n");
 			break;
@@ -1294,7 +1322,7 @@
  */
 static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev)
 {
-	switch (bdev->md_index) {
+	switch (bdev->dc.meta_dev_idx) {
 	case DRBD_MD_INDEX_INTERNAL:
 	case DRBD_MD_INDEX_FLEX_INT:
 		return bdev->md.md_offset + bdev->md.bm_offset;
@@ -1308,7 +1336,7 @@
  * to be able to catch out of band md access */
 static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
 {
-	switch (bdev->md_index) {
+	switch (bdev->dc.meta_dev_idx) {
 	case DRBD_MD_INDEX_INTERNAL:
 	case DRBD_MD_INDEX_FLEX_INT:
 		return bdev->md.md_offset + MD_AL_OFFSET -1;
@@ -1321,7 +1349,7 @@
 /* returns the capacity we announce to out peer */
 static inline sector_t drbd_get_max_capacity(struct drbd_backing_dev *bdev)
 {
-	switch (bdev->md_index) {
+	switch (bdev->dc.meta_dev_idx) {
 	case DRBD_MD_INDEX_INTERNAL:
 	case DRBD_MD_INDEX_FLEX_INT:
 		return drbd_get_capacity(bdev->backing_bdev)
@@ -1337,9 +1365,9 @@
 static inline sector_t drbd_md_ss__(drbd_dev *mdev,
 				    struct drbd_backing_dev *bdev)
 {
-	switch (bdev->md_index) {
+	switch (bdev->dc.meta_dev_idx) {
 	default: /* external, some index */
-		return MD_RESERVED_SECT * bdev->md_index;
+		return MD_RESERVED_SECT * bdev->dc.meta_dev_idx;
 	case DRBD_MD_INDEX_INTERNAL:
 		/* with drbd08, internal meta data is always "flexible" */
 	case DRBD_MD_INDEX_FLEX_INT:
@@ -1637,7 +1665,7 @@
 	    int recv, Drbd_Polymorph_Packet *p, char* file, int line)
 {
 	if (dump_packets > DUMP_NONE &&
-	    ( ( 1 << (int)(mdev-drbd_conf)) & dump_packet_devs) )
+	    ( ( 1 << mdev_to_minor(mdev)) & dump_packet_devs) )
 		_dump_packet(mdev,sock,recv,p,file,line);
 }
 #else

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_main.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -56,24 +56,13 @@
 #include <linux/vmalloc.h>
 
 #include <linux/drbd.h>
+#include <linux/drbd_limits.h>
 #include "drbd_int.h"
 
 /* YES. We got an official device major from lanana
  */
 #define LANANA_DRBD_MAJOR 147
 
-#ifdef CONFIG_COMPAT
-# if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
-    /* FIXME on which thing could we test instead of the KERNEL_VERSION
-     * again?  register_ioctl32_conversion was deprecated in 2.6.10, got
-     * "officially" deprecated somewhen in 2.6.12, and removed in 2.6.14.
-     * so lets assume all vendor kernels did the transition.  */
-#   define HAVE_COMPAT_IOCTL_MEMBER
-# else
-#  include <linux/ioctl32.h>
-# endif
-#endif
-
 struct after_state_chg_work {
 	struct drbd_work w;
 	drbd_state_t os;
@@ -118,11 +107,8 @@
 
 // module parameter, defined
 int major_nr = LANANA_DRBD_MAJOR;
-#ifdef MODULE
-int minor_count = 2;
-#else
-int minor_count = 8;
-#endif
+int minor_count = 32;
+
 int disable_bd_claim = 0;
 
 #ifdef DUMP_EACH_PACKET
@@ -144,7 +130,8 @@
 /* in 2.6.x, our device mapping and config info contains our virtual gendisks
  * as member "struct gendisk *vdisk;"
  */
-struct Drbd_Conf *drbd_conf;
+struct Drbd_Conf **minor_table = NULL;
+
 kmem_cache_t *drbd_request_cache;
 kmem_cache_t *drbd_ee_cache;
 mempool_t *drbd_request_mempool;
@@ -161,15 +148,10 @@
 int          drbd_pp_vacant;
 wait_queue_head_t drbd_pp_wait;
 
-
 STATIC struct block_device_operations drbd_ops = {
 	.owner =   THIS_MODULE,
 	.open =    drbd_open,
 	.release = drbd_close,
-	.ioctl =   drbd_ioctl,
-#ifdef HAVE_COMPAT_IOCTL_MEMBER
-	.compat_ioctl = drbd_compat_ioctl,
-#endif
 };
 
 #define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0]))
@@ -505,7 +487,7 @@
 	unsigned long flags;
 	int send,ok=1;
 
-	if(mdev->bc->on_io_error != Panic && mdev->bc->on_io_error != Detach) return 1;
+	if(mdev->bc->dc.on_io_error != Panic && mdev->bc->dc.on_io_error != Detach) return 1;
 
 	spin_lock_irqsave(&mdev->req_lock,flags);
 	if( (send = (mdev->state.disk == Failed)) ) {
@@ -702,7 +684,7 @@
 
 	fp = DontCare;
 	if(inc_local(mdev)) {
-		fp = mdev->bc->fencing;
+		fp = mdev->bc->dc.fencing;
 		dec_local(mdev);
 	}
 
@@ -768,7 +750,7 @@
 
 	fp = DontCare;
 	if(inc_local(mdev)) {
-		fp = mdev->bc->fencing;
+		fp = mdev->bc->dc.fencing;
 		dec_local(mdev);
 	}
 
@@ -900,7 +882,9 @@
 
 	if ( os.disk == Diskless && os.conn == StandAlone &&
 	     (ns.disk > Diskless || ns.conn > StandAlone) ) {
-		__module_get(THIS_MODULE);
+		int i;
+		i = try_module_get(THIS_MODULE);
+		D_ASSERT(i);
 	}
 
 	if ( ns.role == Primary && ns.conn < Connected &&
@@ -950,7 +934,7 @@
 
 	fp = DontCare;
 	if(inc_local(mdev)) {
-		fp = mdev->bc->fencing;
+		fp = mdev->bc->dc.fencing;
 		dec_local(mdev);
 	}
 
@@ -1314,7 +1298,7 @@
 	return ok;
 }
 
-int drbd_send_sync_param(drbd_dev *mdev, struct syncer_config *sc)
+int drbd_send_sync_param(drbd_dev *mdev, struct syncer_conf *sc)
 {
 	Drbd_SyncParam_Packet p;
 
@@ -1369,7 +1353,7 @@
 	if(inc_md_only(mdev,Attaching)) {
 		D_ASSERT(mdev->bc->backing_bdev);
 		d_size = drbd_get_max_capacity(mdev->bc);
-		p.u_size = cpu_to_be64(mdev->bc->u_size);
+		p.u_size = cpu_to_be64(mdev->bc->dc.disk_size);
 		dec_local(mdev);
 	} else d_size = 0;
 
@@ -1901,19 +1885,19 @@
 
 STATIC int drbd_open(struct inode *inode, struct file *file)
 {
-	int minor;
+	drbd_dev *mdev;
 
-	minor = MINOR(inode->i_rdev);
-	if(minor >= minor_count) return -ENODEV;
+	mdev = minor_to_mdev(MINOR(inode->i_rdev));
+	if(!mdev) return -ENODEV;
 
 	if (file->f_mode & FMODE_WRITE) {
-		if( drbd_conf[minor].state.role == Secondary) {
+		if( mdev->state.role == Secondary) {
 			return -EROFS;
 		}
-		set_bit(WRITER_PRESENT, &drbd_conf[minor].flags);
+		set_bit(WRITER_PRESENT, &mdev->flags);
 	}
 
-	drbd_conf[minor].open_cnt++;
+	mdev->open_cnt++;
 
 	return 0;
 }
@@ -1921,10 +1905,10 @@
 STATIC int drbd_close(struct inode *inode, struct file *file)
 {
 	/* do not use *file (May be NULL, in case of a unmount :-) */
-	int minor;
+	drbd_dev *mdev;
 
-	minor = MINOR(inode->i_rdev);
-	if(minor >= minor_count) return -ENODEV;
+	mdev = minor_to_mdev(MINOR(inode->i_rdev));
+	if(!mdev) return -ENODEV;
 
 	/*
 	printk(KERN_ERR DEVICE_NAME ": close(inode=%p,file=%p)"
@@ -1932,8 +1916,8 @@
 	       inode->i_writecount);
 	*/
 
-	if (--drbd_conf[minor].open_cnt == 0) {
-		clear_bit(WRITER_PRESENT, &drbd_conf[minor].flags);
+	if (--mdev->open_cnt == 0) {
+		clear_bit(WRITER_PRESENT, &mdev->flags);
 	}
 
 	return 0;
@@ -1968,9 +1952,9 @@
 
 void drbd_set_defaults(drbd_dev *mdev)
 {
-	mdev->sync_conf.after      = -1;
-	mdev->sync_conf.rate       = 250;
-	mdev->sync_conf.al_extents = 127; // 512 MB active set
+	mdev->sync_conf.after      = DRBD_AFTER_DEF;
+	mdev->sync_conf.rate       = DRBD_RATE_DEF;
+	mdev->sync_conf.al_extents = DRBD_AL_EXTENTS_DEF; // 512 MB active set
 	mdev->state = (drbd_state_t){ { Secondary,
 					Unknown,
 					StandAlone,
@@ -2138,7 +2122,6 @@
 	D_ASSERT(list_empty(&mdev->resync_work.list));
 	D_ASSERT(list_empty(&mdev->unplug_work.list));
 
-	drbd_set_defaults(mdev);
 }
 
 
@@ -2250,28 +2233,29 @@
 
 	unregister_reboot_notifier(&drbd_notifier);
 
-	if (drbd_conf) {
+	drbd_nl_cleanup();
+
+	if (minor_table) {
 		for (i = 0; i < minor_count; i++) {
-			drbd_dev    *mdev = drbd_conf + i;
+			drbd_dev    *mdev = minor_to_mdev(i);
+			if(!mdev) continue;
 
-			if (mdev) {
-				down(&mdev->device_mutex);
-				rr = Secondary;
-				drbd_set_role(mdev,&rr);
-				up(&mdev->device_mutex);
-				drbd_sync_me(mdev);
-				drbd_thread_stop(&mdev->receiver);
-			}
+			down(&mdev->device_mutex);
+			drbd_set_role(mdev,Secondary,0);
+			up(&mdev->device_mutex);
+			drbd_sync_me(mdev);
+			drbd_thread_stop(&mdev->receiver);
 		}
 
 		if (drbd_proc)
 			remove_proc_entry("drbd",&proc_root);
 		i=minor_count;
 		while (i--) {
-			drbd_dev        *mdev  = drbd_conf+i;
+			drbd_dev        *mdev  = minor_to_mdev(i);
 			struct gendisk  **disk = &mdev->vdisk;
 			request_queue_t **q    = &mdev->rq_queue;
 
+			if(!mdev) continue;
 			drbd_free_resources(mdev);
 
 			if (*disk) {
@@ -2338,26 +2322,7 @@
 		drbd_destroy_mempools();
 	}
 
-#ifndef HAVE_COMPAT_IOCTL_MEMBER
-#if defined(CONFIG_PPC64) || defined(CONFIG_SPARC64) || defined(CONFIG_X86_64)
-	lock_kernel();
-	unregister_ioctl32_conversion(DRBD_IOCTL_GET_VERSION);
-	unregister_ioctl32_conversion(DRBD_IOCTL_SET_STATE);
-	unregister_ioctl32_conversion(DRBD_IOCTL_SET_DISK_CONFIG);
-	unregister_ioctl32_conversion(DRBD_IOCTL_SET_NET_CONFIG);
-	unregister_ioctl32_conversion(DRBD_IOCTL_UNCONFIG_NET);
-	unregister_ioctl32_conversion(DRBD_IOCTL_GET_CONFIG);
-	unregister_ioctl32_conversion(DRBD_IOCTL_INVALIDATE);
-	unregister_ioctl32_conversion(DRBD_IOCTL_INVALIDATE_REM);
-	unregister_ioctl32_conversion(DRBD_IOCTL_SET_SYNC_CONFIG);
-	unregister_ioctl32_conversion(DRBD_IOCTL_SET_DISK_SIZE);
-	unregister_ioctl32_conversion(DRBD_IOCTL_WAIT_CONNECT);
-	unregister_ioctl32_conversion(DRBD_IOCTL_WAIT_SYNC);
-	unregister_ioctl32_conversion(DRBD_IOCTL_UNCONFIG_DISK);
-	unlock_kernel();
-#endif
-#endif
-	kfree(drbd_conf);
+	kfree(minor_table);
 
 	if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0)
 		printk(KERN_ERR DEVICE_NAME": unregister of device failed\n");
@@ -2365,9 +2330,83 @@
 	printk(KERN_INFO DEVICE_NAME": module cleanup done.\n");
 }
 
+drbd_dev *drbd_new_device(int minor)
+{
+	drbd_dev *mdev = NULL;
+	struct gendisk *disk;
+	request_queue_t *q;
+
+	mdev = kmalloc(sizeof(drbd_dev),GFP_KERNEL);
+	if(!mdev) goto Enomem;
+	memset(mdev,0,sizeof(drbd_dev ));
+
+	mdev->minor = minor;
+
+	drbd_init_set_defaults(mdev);
+
+	q = blk_alloc_queue(GFP_KERNEL);
+	if (!q) goto Enomem;
+	mdev->rq_queue = q;
+	q->queuedata   = mdev;
+	q->max_segment_size = DRBD_MAX_SEGMENT_SIZE;
+
+	disk = alloc_disk(1);
+	if (!disk) goto Enomem;
+	mdev->vdisk = disk;
+
+	set_disk_ro( disk, TRUE );
+
+	disk->queue = q;
+	disk->major = MAJOR_NR;
+	disk->first_minor = minor;
+	disk->fops = &drbd_ops;
+	sprintf(disk->disk_name, DEVICE_NAME "%d", minor);
+	sprintf(disk->devfs_name, "%s/%d", drbd_devfs_name, minor);
+	disk->private_data = mdev;
+	add_disk(disk);
+		
+	mdev->this_bdev = bdget(MKDEV(MAJOR_NR,minor));
+	// we have no partitions. we contain only ourselves.
+	mdev->this_bdev->bd_contains = mdev->this_bdev;
+	if (bd_claim(mdev->this_bdev,drbd_sec_holder)) {
+		// Initial we are Secondary -> should claim myself.
+		WARN("Could not bd_claim() myself.");
+	} else if (disable_bd_claim) {
+		bd_release(mdev->this_bdev);
+	}
+
+	blk_queue_make_request(q, drbd_make_request_26);
+	blk_queue_merge_bvec(q, drbd_merge_bvec);
+	q->queue_lock = &mdev->req_lock; // needed since we use
+		// plugging on a queue, that actually has no requests!
+	q->unplug_fn = drbd_unplug_fn;
+
+	mdev->md_io_page = alloc_page(GFP_KERNEL);
+	if(!mdev->md_io_page) goto Enomem;
+
+	if (drbd_bm_init(mdev)) goto Enomem;
+	// no need to lock access, we are still initializing the module.
+	init_MUTEX(&mdev->device_mutex);
+	if (!tl_init(mdev)) goto Enomem;
+
+	mdev->app_reads_hash=kmalloc(APP_R_HSIZE*sizeof(void*),GFP_KERNEL);
+	if (!mdev->app_reads_hash) goto Enomem;
+	memset(mdev->app_reads_hash,0,APP_R_HSIZE*sizeof(void*));
+
+	return mdev;
+
+ Enomem:
+	if(mdev) {
+		if(mdev->app_reads_hash) kfree(mdev->app_reads_hash);
+		if(mdev->md_io_page) __free_page(mdev->md_io_page);
+		kfree(mdev);
+	}
+	return NULL;
+}
+
 int __init drbd_init(void)
 {
-	int i,err;
+	int err;
 
 #if 0
 #warning "DEBUGGING"
@@ -2422,6 +2461,10 @@
 #endif
 	}
 
+	if( (err = drbd_nl_init()) ) {
+		return err;
+	}
+
 	err = register_blkdev(MAJOR_NR, DEVICE_NAME);
 	if (err) {
 		printk(KERN_ERR DEVICE_NAME
@@ -2429,6 +2472,7 @@
 		       MAJOR_NR);
 		return err;
 	}
+
 	register_reboot_notifier(&drbd_notifier);
 
 	/*
@@ -2439,76 +2483,13 @@
 	init_waitqueue_head(&drbd_pp_wait);
 
 	drbd_proc = NULL; // play safe for drbd_cleanup
-	drbd_conf = kmalloc(sizeof(drbd_dev)*minor_count,GFP_KERNEL);
-	if (likely(drbd_conf!=NULL))
-		memset(drbd_conf,0,sizeof(drbd_dev)*minor_count);
-	else goto Enomem;
+	minor_table = kmalloc(sizeof(drbd_dev *)*minor_count,GFP_KERNEL);
+	if(!minor_table) goto Enomem;
+	memset(minor_table,0,sizeof(drbd_dev *)*minor_count);
 
-	for (i = 0; i < minor_count; i++) {
-		drbd_dev    *mdev = drbd_conf + i;
-		struct gendisk         *disk;
-		request_queue_t        *q;
-
-		q = blk_alloc_queue(GFP_KERNEL);
-		if (!q) goto Enomem;
-		mdev->rq_queue = q;
-		q->queuedata   = mdev;
-		q->max_segment_size = DRBD_MAX_SEGMENT_SIZE;
-
-		disk = alloc_disk(1);
-		if (!disk) goto Enomem;
-		mdev->vdisk = disk;
-
-		set_disk_ro( disk, TRUE );
-
-		disk->queue = q;
-		disk->major = MAJOR_NR;
-		disk->first_minor = i;
-		disk->fops = &drbd_ops;
-		sprintf(disk->disk_name, DEVICE_NAME "%d", i);
-		disk->private_data = mdev;
-		add_disk(disk);
-
-		mdev->this_bdev = bdget(MKDEV(MAJOR_NR,i));
-		// we have no partitions. we contain only ourselves.
-		mdev->this_bdev->bd_contains = mdev->this_bdev;
-		if (bd_claim(mdev->this_bdev,drbd_sec_holder)) {
-			// Initial we are Secondary -> should claim myself.
-			WARN("Could not bd_claim() myself.");
-		} else if (disable_bd_claim) {
-			bd_release(mdev->this_bdev);
-		}
-
-		blk_queue_make_request(q, drbd_make_request_26);
-		blk_queue_merge_bvec(q, drbd_merge_bvec);
-		q->queue_lock = &mdev->req_lock; // needed since we use
-		// plugging on a queue, that actually has no requests!
-		q->unplug_fn = drbd_unplug_fn;
-	}
-
 	if ((err = drbd_create_mempools()))
 		goto Enomem;
 
-	for (i = 0; i < minor_count; i++) {
-		drbd_dev    *mdev = &drbd_conf[i];
-		struct page *page = alloc_page(GFP_KERNEL);
-
-		drbd_init_set_defaults(mdev);
-
-		if(!page) goto Enomem;
-		mdev->md_io_page = page;
-
-		if (drbd_bm_init(mdev)) goto Enomem;
-		// no need to lock access, we are still initializing the module.
-		init_MUTEX(&mdev->device_mutex);
-		if (!tl_init(mdev)) goto Enomem;
-
-		mdev->app_reads_hash=kmalloc(APP_R_HSIZE*sizeof(void*),
-					     GFP_KERNEL);
-		if (!mdev->app_reads_hash) goto Enomem;
-		memset(mdev->app_reads_hash,0,APP_R_HSIZE*sizeof(void*));
-	}
-
 #if CONFIG_PROC_FS
 	/*
 	 * register with procfs
@@ -2526,27 +2507,6 @@
 # error "Currently drbd depends on the proc file system (CONFIG_PROC_FS)"
 #endif
 
-#ifndef HAVE_COMPAT_IOCTL_MEMBER
-#if defined(CONFIG_PPC64) || defined(CONFIG_SPARC64) || defined(CONFIG_X86_64)
-	// tell the kernel that we think our ioctls are 64bit clean
-	lock_kernel();
-	register_ioctl32_conversion(DRBD_IOCTL_GET_VERSION,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_SET_STATE,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_SET_DISK_CONFIG,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_SET_NET_CONFIG,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_UNCONFIG_NET,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_GET_CONFIG,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_INVALIDATE,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_INVALIDATE_REM,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_SET_SYNC_CONFIG,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_SET_DISK_SIZE,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_WAIT_CONNECT,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_WAIT_SYNC,NULL);
-	register_ioctl32_conversion(DRBD_IOCTL_UNCONFIG_DISK,NULL);
-	unlock_kernel();
-#endif
-#endif
-
 	printk(KERN_INFO DEVICE_NAME ": initialised. "
 	       "Version: " REL_VERSION " (api:%d/proto:%d)\n",
 	       API_VERSION,PRO_VERSION);

Added: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_nl.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -0,0 +1,1608 @@
+/*
+-*- linux-c -*-
+   drbd_nl.c
+   Kernel module for 2.4.x/2.6.x Kernels
+
+   This file is part of drbd by Philipp Reisner.
+
+   Copyright (C) 1999-2006, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg@linbit.com>.
+   Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/connector.h>
+#include <linux/drbd.h>
+#include <linux/blkpg.h>
+
+#include <drbd_int.h>
+#include <linux/drbd_tag_magic.h>
+#include <linux/drbd_limits.h>
+
+/* see get_sb_bdev and bd_claim */
+char *drbd_sec_holder = "Secondary DRBD cannot be bd_claimed ;)";
+char *drbd_m_holder = "Hands off! this is DRBD's meta data device.";
+
+
+// Generate the tag_list to struct functions
+#define PACKET(name, fields) \
+int name ## _from_tags (drbd_dev *mdev, unsigned short* tags, struct name * arg) \
+{ \
+	int tag; \
+	int dlen; \
+	\
+	memset(arg,0,sizeof(struct name)); \
+	while( (tag = *tags++) != TT_END ) { \
+		dlen = *tags++; \
+		switch( tag_number(tag) ) { \
+		fields \
+		default: \
+			if( tag & T_MANDATORY ) { \
+				ERR("Unknown tag: %d\n",tag_number(tag)); \
+				return 0; \
+			} \
+		} \
+		tags = (unsigned short*)((char*)tags + dlen); \
+	} \
+	return 1; \
+}
+#define INTEGER(pn,pr,member) \
+	case pn: /* D_ASSERT( tag_type(tag) == TT_INTEGER ); */ \
+		 arg->member = *(int*)(tags); \
+		 break;
+#define INT64(pn,pr,member) \
+	case pn: /* D_ASSERT( tag_type(tag) == TT_INT64 ); */ \
+		 arg->member = *(u64*)(tags); \
+		 break;
+#define BIT(pn,pr,member) \
+	case pn: /* D_ASSERT( tag_type(tag) == TT_BIT ); */ \
+		 arg->member = *(char*)(tags) ? 1 : 0; \
+		 break;
+#define STRING(pn,pr,member,len) \
+	case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \
+		 arg->member ## _len = dlen; \
+		 memcpy(arg->member,tags,dlen); \
+		 break; 
+#include "linux/drbd_nl.h"
+
+// Generate the struct to tag_list functions
+#define PACKET(name, fields) \
+unsigned short* \
+name ## _to_tags (drbd_dev *mdev, struct name * arg, unsigned short* tags) \
+{ \
+	fields \
+	return tags; \
+}
+
+#define INTEGER(pn,pr,member) \
+	*tags++ = pn | pr | TT_INTEGER; \
+	*tags++ = sizeof(int); \
+	*(int*)tags = arg->member; \
+	tags = (unsigned short*)((char*)tags+sizeof(int)); 
+#define INT64(pn,pr,member) \
+	*tags++ = pn | pr | TT_INT64; \
+	*tags++ = sizeof(u64); \
+	*(u64*)tags = arg->member; \
+	tags = (unsigned short*)((char*)tags+sizeof(u64));
+#define BIT(pn,pr,member) \
+	*tags++ = pn | pr | TT_BIT; \
+	*tags++ = sizeof(char); \
+	*(char*)tags = arg->member; \
+	tags = (unsigned short*)((char*)tags+sizeof(char));
+#define STRING(pn,pr,member,len) \
+	*tags++ = pn | pr | TT_STRING; \
+	*tags++ = arg->member ## _len; \
+	memcpy(tags,arg->member, arg->member ## _len); \
+	tags = (unsigned short*)((char*)tags + arg->member ## _len);
+#include "linux/drbd_nl.h"
+
+
+extern void drbd_init_set_defaults(drbd_dev *mdev);
+void drbd_nl_send_reply(struct cn_msg *, int);
+
+
+STATIC void drbd_nl_create (void *data)
+{ 
+	static int next_minor=0;
+	int minor,ok;
+	drbd_dev *mdev = NULL;
+
+	minor = next_minor;
+
+	mdev = drbd_new_device(minor);
+	if(!mdev) goto out;
+
+	spin_lock_irq(&drbd_pp_lock); // just to protect this from itself
+	if ( (ok = next_minor < minor_count && minor == next_minor) ) {
+		minor_table[minor] = mdev;
+		wmb();
+		next_minor++;
+	}
+	spin_unlock_irq(&drbd_pp_lock);
+
+	if(!ok) {
+	out:
+		if(mdev) {
+			if(mdev->app_reads_hash) kfree(mdev->app_reads_hash);
+			if(mdev->md_io_page) __free_page(mdev->md_io_page);
+			kfree(mdev);
+		}
+	}
+}
+
+int drbd_khelper(drbd_dev *mdev, char* cmd)
+{
+	char mb[12];
+	char *argv[] = {"/sbin/drbdadm", cmd, mb, NULL };
+	static char *envp[] = { "HOME=/",
+				"TERM=linux",
+				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+				NULL };
+
+	snprintf(mb,12,"minor-%d",mdev_to_minor(mdev));
+	return call_usermodehelper("/sbin/drbdadm",argv,envp,1);
+}
+
+drbd_disks_t drbd_try_outdate_peer(drbd_dev *mdev)
+{
+	int r;
+	drbd_disks_t nps;
+	enum fencing_policy fp;
+
+	D_ASSERT(mdev->state.pdsk == DUnknown);
+
+	fp = DontCare;
+	if(inc_local(mdev)) {
+		fp = mdev->bc->dc.fencing;
+		dec_local(mdev);
+	}
+
+	D_ASSERT( fp > DontCare );
+
+	if( fp == Stonith ) drbd_request_state(mdev,NS(susp,1));
+
+	r=drbd_khelper(mdev,"outdate-peer");
+
+	switch( (r>>8) & 0xff ) {
+	case 3: /* peer is inconsistent */
+		nps = Inconsistent;
+		break;
+	case 4: /* peer is outdated */
+		nps = Outdated;
+		break;
+	case 5: /* peer was down, we will(have) create(d) a new UUID anyways... */
+		/* If we would be more strict, we would return DUnknown here. */
+		nps = Outdated;
+		break;
+	case 6: /* Peer is primary, voluntarily outdate myself */
+		WARN("Peer is primary, outdating myself.\n");
+		nps = DUnknown;
+		drbd_request_state(mdev,NS(disk,Outdated));
+		break;
+	case 7:
+		if( fp != Stonith ) {
+			ERR("outdate-peer() = 7 && fencing != Stonith !!!\n");
+		}
+		nps = Outdated;
+		break;
+	default:
+		/* The script is broken ... */
+		nps = DUnknown;
+		drbd_request_state(mdev,NS(disk,Outdated));
+		ERR("outdate-peer helper broken, returned %d \n",(r>>8)&0xff);
+		return nps;
+	}
+
+	INFO("outdate-peer helper returned %d \n",(r>>8)&0xff);
+	return nps;
+}
+
+
+int drbd_set_role(drbd_dev *mdev, drbd_role_t new_role, int force)
+{
+	int r=0,forced = 0, try=0;
+	drbd_state_t mask, val;
+	drbd_disks_t nps;
+
+	ERR_IF (mdev->this_bdev->bd_contains == 0) {
+		// FIXME this masks a bug somewhere else!
+		mdev->this_bdev->bd_contains = mdev->this_bdev;
+	}
+
+	if ( new_role & Secondary ) {
+		/* If I got here, I am Primary. I claim me for myself. If that
+		 * does not succeed, someone other has claimed me, so I cannot
+		 * become Secondary. */
+		if (bd_claim(mdev->this_bdev,drbd_sec_holder))
+			return FailedToClaimMyself;
+		if (disable_bd_claim)
+			bd_release(mdev->this_bdev);
+	}
+
+	mask.i = 0; mask.role = role_mask;
+	val.i  = 0; val.role  = new_role & role_mask;
+
+	while (try++ < 3) {
+		r = _drbd_request_state(mdev,mask,val,0);
+		if( r == SS_NoUpToDateDisk && force && 
+		    ( mdev->state.disk == Inconsistent || 
+		      mdev->state.disk == Outdated ) ) {
+			mask.disk = disk_mask;
+			val.disk  = UpToDate;
+			forced = 1;
+			continue;
+		}
+		if ( r == SS_NothingToDo ) goto fail;
+		if ( r == SS_PrimaryNOP ) {
+			nps = drbd_try_outdate_peer(mdev);
+
+			if ( force && nps > Outdated ) {
+				WARN("Forced into split brain situation!\n");
+				nps = Outdated;
+			}
+
+			mask.pdsk = disk_mask;
+			val.pdsk  = nps;
+
+			continue;
+		}
+
+		if ( r < SS_Success ) {
+			r = drbd_request_state(mdev,mask,val); // Be verbose.
+			if( r < SS_Success ) goto fail;
+		}
+		break;
+	}
+
+	if(forced) WARN("Forced to conisder local data as UpToDate!\n");
+
+	drbd_sync_me(mdev);
+
+	/* Wait until nothing is on the fly :) */
+	if ( wait_event_interruptible( mdev->cstate_wait,
+			         atomic_read(&mdev->ap_pending_cnt) == 0 ) ) {
+		r = GotSignal;
+		goto fail;
+	}
+
+	/* FIXME RACE here: if our direct user is not using bd_claim (i.e.
+	 *  not a filesystem) since cstate might still be >= Connected, new
+	 * ap requests may come in and increase ap_pending_cnt again!
+	 * but that means someone is misusing DRBD...
+	 * */
+
+	if (new_role & Secondary) {
+		set_disk_ro(mdev->vdisk, TRUE );
+	} else {
+		if(inc_net(mdev)) {
+			mdev->net_conf->want_lose = 0;
+			dec_net(mdev);
+		}
+		set_disk_ro(mdev->vdisk, FALSE );
+		D_ASSERT(mdev->this_bdev->bd_holder == drbd_sec_holder);
+		bd_release(mdev->this_bdev);
+		mdev->this_bdev->bd_disk = mdev->vdisk;
+
+		if ( ( ( mdev->state.conn < Connected ||
+			 mdev->state.pdsk <= Attaching ) &&
+		       mdev->bc->md.uuid[Bitmap] == 0) || forced ) {
+			drbd_uuid_new_current(mdev);
+		}
+	}
+
+	if(mdev->state.disk > Diskless && (new_role & Secondary)) {
+		drbd_al_to_on_disk_bm(mdev);
+	}
+
+	if (mdev->state.conn >= WFReportParams) {
+		/* if this was forced, we should consider sync */
+		if(forced) drbd_send_uuids(mdev);
+		drbd_send_state(mdev);
+	}
+
+	drbd_md_sync(mdev);
+
+	return r;
+
+ fail:
+	if ( new_role & Secondary ) {
+		D_ASSERT(mdev->this_bdev->bd_holder == drbd_sec_holder);
+		bd_release(mdev->this_bdev);
+	}
+
+	return r;
+}
+
+STATIC drbd_dev *ensure_mdev(struct drbd_nl_cfg_req *nlp)
+{
+	drbd_dev *mdev;
+
+	mdev = minor_to_mdev(nlp->drbd_minor);
+
+	if(!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) {
+		mdev = drbd_new_device(nlp->drbd_minor);
+		
+		spin_lock_irq(&drbd_pp_lock);
+		if( minor_table[nlp->drbd_minor] == NULL) {
+			minor_table[nlp->drbd_minor] = mdev;
+			mdev = NULL;
+		}
+		spin_unlock_irq(&drbd_pp_lock);
+		
+		if(mdev) {
+			if(mdev->app_reads_hash) kfree(mdev->app_reads_hash);
+			if(mdev->md_io_page) __free_page(mdev->md_io_page);
+			kfree(mdev);
+			mdev = NULL;
+		}
+
+		mdev = minor_to_mdev(nlp->drbd_minor);
+	}
+
+	return mdev;
+}
+
+
+STATIC void drbd_nl_primary (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	struct primary primary_args;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	if(!primary_from_tags(mdev,nlp->tag_list,&primary_args)) {
+		retcode=UnknownMandatoryTag;
+		goto fail;
+	}
+
+	retcode = drbd_set_role(mdev, Primary, primary_args.overwrite_peer);
+
+ fail:
+	drbd_nl_send_reply(req, retcode );
+}
+
+STATIC void drbd_nl_secondary (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	retcode = drbd_set_role(mdev, Secondary, 0);
+
+ fail:
+	drbd_nl_send_reply(req, retcode );
+}
+
+/* initializes the md.*_offset members, so we are able to find
+ * the on disk meta data */
+STATIC void drbd_md_set_sector_offsets(drbd_dev *mdev,
+				       struct drbd_backing_dev *bdev)
+{
+	sector_t md_size_sect = 0;
+	switch(bdev->dc.meta_dev_idx) {
+	default:
+	case DRBD_MD_INDEX_FLEX_EXT:
+		/* just occupy the full device; unit: sectors */
+		bdev->md.md_size_sect = drbd_get_capacity(bdev->md_bdev);
+		bdev->md.md_offset = 0;
+		bdev->md.al_offset = MD_AL_OFFSET;
+		bdev->md.bm_offset = MD_BM_OFFSET;
+		break;
+	case DRBD_MD_INDEX_INTERNAL:
+	case DRBD_MD_INDEX_FLEX_INT:
+		bdev->md.md_offset = drbd_md_ss__(mdev,bdev);
+		/* al size is still fixed */
+		bdev->md.al_offset = -MD_AL_MAX_SIZE;
+                //LGE FIXME max size check missing.
+		/* we need (slightly less than) ~ this much bitmap sectors: */
+		md_size_sect = drbd_get_capacity(bdev->backing_bdev);
+		md_size_sect = ALIGN(md_size_sect,BM_SECT_PER_EXT);
+		md_size_sect = BM_SECT_TO_EXT(md_size_sect);
+		md_size_sect = ALIGN(md_size_sect,8);
+
+		/* plus the "drbd meta data super block",
+		 * and the activity log; */
+		md_size_sect += MD_BM_OFFSET;
+
+		bdev->md.md_size_sect = md_size_sect;
+		/* bitmap offset is adjusted by 'super' block size */
+		bdev->md.bm_offset   = -md_size_sect + MD_AL_OFFSET;
+		break;
+	}
+}
+
+char* ppsize(char* buf, size_t size)
+{
+	// Needs 9 bytes at max.
+	static char units[] = { 'K','M','G','T','P','E' };
+	int base = 0;
+	while (size >= 10000 ) {
+		size = size >> 10;
+		base++;
+	}
+	sprintf(buf,"%ld %cB",(long)size,units[base]);
+
+	return buf;
+}
+
+/* You should call drbd_md_sync() after calling this.
+ */
+int drbd_determin_dev_size(struct Drbd_Conf* mdev)
+{
+	sector_t prev_first_sect, prev_size; // previous meta location
+	sector_t la_size;
+	sector_t size;
+	char ppb[10];
+
+	int md_moved, la_size_changed;
+	int rv=0;
+
+	wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+	prev_first_sect = drbd_md_first_sector(mdev->bc);
+	prev_size = mdev->bc->md.md_size_sect;
+	la_size = mdev->bc->md.la_size_sect;
+
+	// TODO: should only be some assert here, not (re)init...
+	drbd_md_set_sector_offsets(mdev,mdev->bc);
+
+	size = drbd_new_dev_size(mdev,mdev->bc);
+
+	if( drbd_get_capacity(mdev->this_bdev) != size ) {
+		int err;
+		err = drbd_bm_resize(mdev,size);
+		if (unlikely(err)) {
+			/* currently there is only one error: ENOMEM! */
+			size = drbd_bm_capacity(mdev)>>1;
+			if (size == 0) {
+				ERR("OUT OF MEMORY! Could not allocate bitmap! Set device size => 0\n");
+			} else {
+				/* FIXME this is problematic,
+				 * if we in fact are smaller now! */
+				ERR("BM resizing failed. "
+				    "Leaving size unchanged at size = %lu KB\n",
+				    (unsigned long)size);
+			}
+			rv = err;
+		}
+		// racy, see comments above.
+		drbd_set_my_capacity(mdev,size);
+		mdev->bc->md.la_size_sect = size;
+		INFO("size = %s (%lu KB)\n",ppsize(ppb,size>>1),
+		     (unsigned long)size>>1);
+	}
+	if (rv < 0) goto out;
+
+	la_size_changed = (la_size != mdev->bc->md.la_size_sect);
+
+	//LGE: flexible device size!! is this the right thing to test?
+	md_moved = prev_first_sect != drbd_md_first_sector(mdev->bc)
+		|| prev_size       != mdev->bc->md.md_size_sect;
+
+	if ( md_moved ) {
+		WARN("Moving meta-data.\n");
+		/* assert: (flexible) internal meta data */
+	}
+
+	if ( la_size_changed || md_moved ) {
+		if( inc_md_only(mdev,Attaching) ) {
+			drbd_al_shrink(mdev); // All extents inactive.
+			drbd_bm_write(mdev);  // write bitmap
+			// Write mdev->la_size to on disk.
+			drbd_md_mark_dirty(mdev);
+			dec_local(mdev);
+		}
+	}
+  out:
+	lc_unlock(mdev->act_log);
+
+	return rv;
+}
+
+sector_t 
+drbd_new_dev_size(struct Drbd_Conf* mdev, struct drbd_backing_dev *bdev)
+{
+	sector_t p_size = mdev->p_size;   // partner's disk size.
+	sector_t la_size = bdev->md.la_size_sect; // last agreed size.
+	sector_t m_size; // my size
+	sector_t u_size = bdev->dc.disk_size; // size requested by user.
+	sector_t size=0;
+
+	m_size = drbd_get_max_capacity(bdev);
+
+	if(p_size && m_size) {
+		size=min_t(sector_t,p_size,m_size);
+	} else {
+		if(la_size) {
+			size=la_size;
+			if(m_size && m_size < size) size=m_size;
+			if(p_size && p_size < size) size=p_size;
+		} else {
+			if(m_size) size=m_size;
+			if(p_size) size=p_size;
+		}
+	}
+
+	if(size == 0) {
+		ERR("Both nodes diskless!\n");
+	}
+
+	if(u_size) {
+		if(u_size<<1 > size) {
+			ERR("Requested disk size is too big (%lu > %lu)\n",
+			    (unsigned long)u_size, (unsigned long)size>>1);
+		} else {
+			size = u_size<<1;
+		}
+	}
+
+	return size;
+}
+
+/** 
+ * drbd_check_al_size:
+ * checks that the al lru is of requested size, and if neccessary tries to
+ * allocate a new one. returns -EBUSY if current al lru is still used,
+ * -ENOMEM when allocation failed, and 0 on success. You should call
+ * drbd_md_sync() after you called this function.
+ */
+STATIC int drbd_check_al_size(drbd_dev *mdev)
+{
+	struct lru_cache *n,*t;
+	struct lc_element *e;
+	unsigned int in_use;
+	int i;
+
+	ERR_IF(mdev->sync_conf.al_extents < 7)
+		mdev->sync_conf.al_extents = 127;
+
+	if ( mdev->act_log &&
+	     mdev->act_log->nr_elements == mdev->sync_conf.al_extents )
+		return 0;
+
+	in_use = 0;
+	t = mdev->act_log;
+	n = lc_alloc("act_log", mdev->sync_conf.al_extents,
+		     sizeof(struct lc_element), mdev);
+
+	if (n==NULL) {
+		ERR("Cannot allocate act_log lru!\n");
+		return -ENOMEM;
+	}
+	spin_lock_irq(&mdev->al_lock);
+	if (t) {
+		for (i=0; i < t->nr_elements; i++) {
+			e = lc_entry(t,i);
+			if (e->refcnt)
+				ERR("refcnt(%d)==%d\n",
+				    e->lc_number, e->refcnt);
+			in_use += e->refcnt;
+		}
+	}
+	if (!in_use) {
+		mdev->act_log = n;
+	}
+	spin_unlock_irq(&mdev->al_lock);
+	if (in_use) {
+		ERR("Activity log still in use!\n");
+		lc_free(n);
+		return -EBUSY;
+	} else {
+		if (t) lc_free(t);
+	}
+	drbd_md_mark_dirty(mdev);	//we changed mdev->act_log->nr_elemens
+	return 0;
+}
+
+void drbd_setup_queue_param(drbd_dev *mdev, unsigned int max_seg_s)
+{
+	request_queue_t * const q = mdev->rq_queue;
+	request_queue_t * const b = mdev->bc->backing_bdev->bd_disk->queue;
+
+	unsigned int old_max_seg_s = q->max_segment_size;
+
+	if(b->merge_bvec_fn) {
+		max_seg_s = PAGE_SIZE;
+	}
+
+	q->max_sectors       = max_seg_s >> 9;
+	q->max_phys_segments = max_seg_s >> PAGE_SHIFT;
+	q->max_hw_segments   = max_seg_s >> PAGE_SHIFT;
+	q->max_segment_size  = max_seg_s;
+	q->hardsect_size     = 512;
+	q->seg_boundary_mask = PAGE_SIZE-1;
+	blk_queue_stack_limits(q, b);
+
+	if( old_max_seg_s != q->max_segment_size ) {
+		if(b->merge_bvec_fn) {
+			WARN("Backing device has merge_bvec_fn()!\n");
+		}
+		INFO("max_segment_size ( = BIO size ) = %u\n",
+		     q->max_segment_size);
+	}
+
+	if( q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+		INFO("Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+		     q->backing_dev_info.ra_pages,
+		     b->backing_dev_info.ra_pages);
+		q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+	}
+}
+
+STATIC void drbd_nl_disk_conf (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	enum ret_codes retcode;
+	struct drbd_backing_dev* nbc=NULL; // new_backing_conf
+	struct inode *inode, *inode2;
+	struct lru_cache* resync_lru = NULL;
+	drbd_state_t ns,os;
+	drbd_dev *mdev;
+	int rv;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	/* if you want to reconfigure, please tear down first */
+	if (mdev->state.disk > Diskless) {
+		retcode=HaveDiskConfig;
+		goto fail;
+	}
+
+	nbc = kmalloc(sizeof(struct drbd_backing_dev),GFP_KERNEL);
+	if(!nbc) {
+		retcode=KMallocFailed;
+		goto fail;
+	}
+
+	if(inc_local(mdev)) {
+		memcpy(&nbc->dc,&mdev->bc->dc,sizeof(struct disk_conf));
+		dec_local(mdev);
+	} else memset(&nbc->dc,0,sizeof(struct disk_conf));
+
+	if(nlp->flags & DRBD_NL_SET_DEFAULTS) {
+		nbc->dc.disk_size   = DRBD_DISK_SIZE_SECT_DEF;
+		nbc->dc.on_io_error = DRBD_ON_IO_ERROR_DEF;
+		nbc->dc.fencing     = DRBD_FENCING_DEF;
+	}
+
+	if(!disk_conf_from_tags(mdev,nlp->tag_list,&nbc->dc)) {
+		retcode=UnknownMandatoryTag;
+		goto fail;
+	}
+
+	nbc->lo_file = NULL;
+	nbc->md_file = NULL;
+
+	if ( nbc->dc.meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) {
+		retcode=LDMDInvalid;
+		goto fail;
+	}
+
+	nbc->lo_file = filp_open(nbc->dc.backing_dev,O_RDWR,0);
+	if (!nbc->lo_file) {
+		retcode=LDNameInvalid;
+		goto fail;
+	}
+
+	inode = nbc->lo_file->f_dentry->d_inode;
+
+	if (!S_ISBLK(inode->i_mode)) {
+		retcode=LDNoBlockDev;
+		goto fail;
+	}
+
+	nbc->md_file = filp_open(nbc->dc.meta_dev,O_RDWR,0);
+
+	if (!nbc->md_file) {
+		retcode=MDNameInvalid;
+		goto fail;
+	}
+
+	inode2 = nbc->md_file->f_dentry->d_inode;
+
+	if (!S_ISBLK(inode2->i_mode)) {
+		retcode=MDNoBlockDev;
+		goto fail;
+	}
+
+	nbc->backing_bdev = inode->i_bdev;
+	if (bd_claim(nbc->backing_bdev, mdev)) {
+		retcode=LDMounted;
+		goto fail;
+	}
+
+	resync_lru = lc_alloc("resync",7, sizeof(struct bm_extent),mdev);
+	if(!resync_lru) {
+		retcode=KMallocFailed;
+		goto fail;
+	}
+
+	nbc->md_bdev = inode2->i_bdev;
+	if (bd_claim(nbc->md_bdev,
+		     (nbc->dc.meta_dev_idx==DRBD_MD_INDEX_INTERNAL ||
+		      nbc->dc.meta_dev_idx==DRBD_MD_INDEX_FLEX_INT) ?
+		     (void *)mdev : (void*) drbd_m_holder )) {
+		retcode=MDMounted;
+		goto release_bdev_fail;
+	}
+
+	if ( (nbc->backing_bdev==nbc->md_bdev) != 
+	     (nbc->dc.meta_dev_idx==DRBD_MD_INDEX_INTERNAL ||
+	      nbc->dc.meta_dev_idx==DRBD_MD_INDEX_FLEX_INT) ) {
+		retcode=LDMDInvalid;
+		goto release_bdev2_fail;
+	}
+
+	if ((drbd_get_capacity(nbc->backing_bdev)>>1) < nbc->dc.disk_size) {
+		retcode = LDDeviceTooSmall;
+		goto release_bdev2_fail;
+	}
+
+#warning checks below no longer valid
+// --- rewrite
+#if 0
+	if (drbd_get_capacity(nbc->backing_bdev) >= (sector_t)DRBD_MAX_SECTORS) {
+		retcode = LDDeviceTooLarge;
+		goto release_bdev2_fail;
+	}
+
+	if ( nbc->dc.meta_dev_idx == -1 ) i = 1;
+	else i = nbc->dc.meta_dev_idx+1;
+
+	/* for internal, we need to check agains <= (then we have a drbd with
+	 * zero size, but meta data...) to be on the safe side, I require 32MB
+	 * minimal data storage area for drbd with internal meta data (thats
+	 * 160 total).  if someone wants to use that small devices, she can use
+	 * drbd 0.6 anyways...
+	 *
+	 * FIXME this is arbitrary and needs to be reconsidered as soon as we
+	 * move to flexible size meta data.
+	 */
+	if( drbd_get_capacity(nbc->md_bdev) < 2*MD_RESERVED_SIZE*i
+				+ (nbc->dc.meta_dev_idx == -1) ? (1<<16) : 0 )
+	{
+		retcode = MDDeviceTooSmall;
+		goto release_bdev2_fail;
+	}
+#endif
+// -- up to here
+
+	// Make sure the new disk is big enough
+	if (drbd_get_capacity(nbc->backing_bdev) < 
+	    drbd_get_capacity(mdev->this_bdev) ) {
+		retcode = LDDeviceTooSmall;
+		goto release_bdev2_fail;
+	}
+
+	if((retcode = drbd_request_state(mdev,NS(disk,Attaching))) < SS_Success ) {
+		goto release_bdev2_fail;
+	}
+
+	drbd_md_set_sector_offsets(mdev,nbc);
+
+	retcode = drbd_md_read(mdev,nbc);
+	if ( retcode != NoError ) {
+		goto release_bdev3_fail;
+	}
+
+	// Since ware are diskless, fix the AL first...
+	if (drbd_check_al_size(mdev)) {
+		retcode = KMallocFailed;
+		goto release_bdev3_fail;
+	}
+
+	// Prevent shrinking of consistent devices !
+	if(drbd_md_test_flag(nbc,MDF_Consistent) &&
+	   drbd_new_dev_size(mdev,nbc) < nbc->md.la_size_sect) {
+		retcode = LDDeviceTooSmall;
+		goto release_bdev3_fail;
+	}
+
+	if(!drbd_al_read_log(mdev,nbc)) {
+		retcode = MDIOError;
+		goto release_bdev3_fail;		
+	}
+
+	// Point of no return reached.
+
+	if(drbd_md_test_flag(nbc,MDF_PrimaryInd)) {
+		set_bit(CRASHED_PRIMARY, &mdev->flags);
+	} else {		
+		clear_bit(CRASHED_PRIMARY, &mdev->flags);
+	}
+
+	D_ASSERT(mdev->bc == NULL);
+	mdev->bc = nbc;
+	mdev->resync = resync_lru;
+
+	mdev->send_cnt = 0;
+	mdev->recv_cnt = 0;
+	mdev->read_cnt = 0;
+	mdev->writ_cnt = 0;
+
+	drbd_setup_queue_param(mdev, DRBD_MAX_SEGMENT_SIZE);
+	/*
+	 * FIXME currently broken.
+	 * drbd_set_recv_tcq(mdev,drbd_queue_order_type(mdev)==QUEUE_ORDERED_TAG);
+	 */
+
+	/* If I am currently not Primary,
+	 * but meta data primary indicator is set,
+	 * I just now recover from a hard crash,
+	 * and have been Primary before that crash.
+	 *
+	 * Now, if I had no connection before that crash
+	 * (have been degraded Primary), chances are that
+	 * I won't find my peer now either.
+	 *
+	 * In that case, and _only_ in that case,
+	 * we use the degr-wfc-timeout instead of the default,
+	 * so we can automatically recover from a crash of a
+	 * degraded but active "cluster" after a certain timeout.
+	 */
+	clear_bit(USE_DEGR_WFC_T,&mdev->flags);
+	if ( mdev->state.role != Primary &&
+	     drbd_md_test_flag(mdev->bc,MDF_PrimaryInd) &&
+	    !drbd_md_test_flag(mdev->bc,MDF_ConnectedInd) ) {
+		set_bit(USE_DEGR_WFC_T,&mdev->flags);
+	}
+
+	drbd_bm_lock(mdev); // racy...
+	drbd_determin_dev_size(mdev);
+
+	if (drbd_md_test_flag(mdev->bc,MDF_FullSync)) {
+		INFO("Assuming that all blocks are out of sync (aka FullSync)\n");
+		drbd_bm_set_all(mdev);
+		drbd_bm_write(mdev);
+		drbd_md_clear_flag(mdev,MDF_FullSync);
+	} else {
+		/* FIXME this still does not propagate io errors! */
+		drbd_bm_read(mdev);
+	}
+
+	if(test_bit(CRASHED_PRIMARY, &mdev->flags)) {
+		drbd_al_apply_to_bm(mdev);
+		drbd_al_to_on_disk_bm(mdev);
+	}
+	/* else {
+	     FIXME wipe out on disk al!
+	} */
+
+
+	if(mdev->state.conn == Connected) {
+		drbd_send_sizes(mdev);  // to start sync...
+		drbd_send_uuids(mdev);
+		drbd_send_state(mdev);
+	} else {
+		spin_lock_irq(&mdev->req_lock);
+		os = mdev->state;
+		ns.i = os.i;
+		/* If MDF_Consistent is not set go into inconsistent state, 
+		   otherwise investige MDF_WasUpToDate...
+		   If MDF_WasUpToDate is not set go into Outdated disk state, 
+		   otherwise into Consistent state.
+		*/
+		if(drbd_md_test_flag(mdev->bc,MDF_Consistent)) {
+			if(drbd_md_test_flag(mdev->bc,MDF_WasUpToDate)) {
+				ns.disk = Consistent;
+			} else {
+				ns.disk = Outdated;
+			}
+		} else {
+			ns.disk = Inconsistent;
+		}
+
+		if(drbd_md_test_flag(mdev->bc,MDF_PeerOutDated)) {
+			ns.pdsk = Outdated;
+		}
+
+		if( ns.disk == Consistent && 
+		    ( ns.pdsk == Outdated || nbc->dc.fencing == DontCare ) ) {
+			ns.disk = UpToDate;
+		}
+		
+		/* All tests on MDF_PrimaryInd, MDF_ConnectedInd, 
+		   MDF_Consistent and MDF_WasUpToDate must happen before 
+		   this point, because drbd_request_state() modifies these
+		   flags. */
+
+		rv = _drbd_set_state(mdev, ns, ChgStateVerbose);
+		ns = mdev->state;
+		spin_unlock_irq(&mdev->req_lock);
+		after_state_ch(mdev,os,ns,ChgStateVerbose);
+
+		if(rv < SS_Success ) {
+			drbd_bm_unlock(mdev);
+			goto  release_bdev3_fail;
+		}
+	}
+
+	drbd_bm_unlock(mdev);
+	drbd_md_sync(mdev);
+
+	drbd_nl_send_reply(req, NoError);
+	return;
+
+ release_bdev3_fail:
+	drbd_force_state(mdev,NS(disk,Diskless));
+	drbd_md_sync(mdev);
+ release_bdev2_fail:
+	bd_release(nbc->md_bdev);
+ release_bdev_fail:
+	bd_release(nbc->backing_bdev);
+ fail:
+	if (nbc) {
+		if (nbc->lo_file) fput(nbc->lo_file);
+		if (nbc->md_file) fput(nbc->md_file);
+		kfree(nbc);
+	}
+	if (resync_lru) lc_free(resync_lru);
+
+	drbd_nl_send_reply(req, retcode );
+}
+
+STATIC void drbd_nl_detach (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	retcode = drbd_request_state(mdev,NS(disk,Diskless));
+
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_net_conf (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	int i,ns;
+	enum ret_codes retcode;
+	struct net_conf *new_conf = NULL;
+	struct crypto_tfm* tfm = NULL;
+	struct hlist_head *new_tl_hash = NULL;
+	struct hlist_head *new_ee_hash = NULL;
+	struct Drbd_Conf *odev;
+	drbd_dev *mdev;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	new_conf = kmalloc(sizeof(struct net_conf),GFP_KERNEL);
+	if(!new_conf) {			
+		retcode=KMallocFailed;
+		goto fail;
+	}
+
+	if(inc_net(mdev)) {
+		memcpy(new_conf,mdev->net_conf,sizeof(struct net_conf));
+		dec_local(mdev);
+	} else memset(new_conf,0,sizeof(struct net_conf));
+
+	if(nlp->flags & DRBD_NL_SET_DEFAULTS) {
+		new_conf->timeout         = DRBD_TIMEOUT_DEF;
+		new_conf->try_connect_int = DRBD_CONNECT_INT_DEF;
+		new_conf->ping_int        = DRBD_PING_INT_DEF;
+		new_conf->max_epoch_size  = DRBD_MAX_EPOCH_SIZE_DEF;
+		new_conf->max_buffers     = DRBD_MAX_BUFFERS_DEF;
+		new_conf->unplug_watermark= DRBD_UNPLUG_WATERMARK_DEF;
+		new_conf->sndbuf_size     = DRBD_SNDBUF_SIZE_DEF;
+		new_conf->ko_count        = DRBD_KO_COUNT_DEF;
+		new_conf->after_sb_0p     = DRBD_AFTER_SB_0P_DEF;
+		new_conf->after_sb_1p     = DRBD_AFTER_SB_1P_DEF;
+		new_conf->after_sb_2p     = DRBD_AFTER_SB_2P_DEF;
+		new_conf->want_lose       = 0;
+		new_conf->two_primaries   = 0;
+	}
+
+	if (!net_conf_from_tags(mdev,nlp->tag_list,new_conf)) {
+		retcode=UnknownMandatoryTag;
+		goto fail;
+	}
+
+	if( mdev->state.role == Primary && new_conf->want_lose ) {
+		retcode=DiscardNotAllowed;
+		goto fail;
+	}
+
+#define M_ADDR(A) (((struct sockaddr_in *)&A->my_addr)->sin_addr.s_addr)
+#define M_PORT(A) (((struct sockaddr_in *)&A->my_addr)->sin_port)
+#define O_ADDR(A) (((struct sockaddr_in *)&A->peer_addr)->sin_addr.s_addr)
+#define O_PORT(A) (((struct sockaddr_in *)&A->peer_addr)->sin_port)
+	for(i=0;i<minor_count;i++) {
+		odev = minor_to_mdev(i);
+		if(!odev) continue;
+		if( mdev != odev && odev->state.conn > StandAlone &&
+		    M_ADDR(new_conf) == M_ADDR(odev->net_conf) &&
+		    M_PORT(new_conf) == M_PORT(odev->net_conf) ) {
+			retcode=LAAlreadyInUse;
+			goto fail;
+		}
+		if( mdev != odev && odev->state.conn > StandAlone &&
+		    O_ADDR(new_conf) == O_ADDR(odev->net_conf) &&
+		    O_PORT(new_conf) == O_PORT(odev->net_conf) ) {
+			retcode=OAAlreadyInUse;
+			goto fail;
+		}
+	}
+#undef M_ADDR
+#undef M_PORT
+#undef O_ADDR
+#undef O_PORT
+
+	if( new_conf->cram_hmac_alg[0] != 0) {
+		tfm = crypto_alloc_tfm(new_conf->cram_hmac_alg, 0);
+		if (tfm == NULL) {
+			retcode=CRAMAlgNotAvail;
+			goto fail;
+		}
+
+		if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST) {
+			retcode=CRAMAlgNotDigest;
+			goto fail;
+		}
+	}
+
+
+	ns = new_conf->max_epoch_size/8;
+	if (mdev->tl_hash_s != ns) {
+		new_tl_hash=kmalloc(ns*sizeof(void*), GFP_KERNEL);
+		if(!new_tl_hash) {
+			retcode=KMallocFailed;
+			goto fail;
+		}
+		memset(new_tl_hash, 0, ns*sizeof(void*));
+	}
+
+	ns = new_conf->max_buffers/8;
+	if (new_conf->two_primaries && ( mdev->ee_hash_s != ns ) ) {
+		new_ee_hash=kmalloc(ns*sizeof(void*), GFP_KERNEL);
+		if(!new_ee_hash) {
+			retcode=KMallocFailed;
+			goto fail;
+		}
+		memset(new_ee_hash, 0, ns*sizeof(void*));
+	}
+
+	/* IMPROVE:
+	   We should warn the user if the LL_DEV is
+	   used already. E.g. some FS mounted on it.
+	*/
+
+	((char*)new_conf->shared_secret)[SHARED_SECRET_MAX-1]=0;
+
+#if 0
+FIXME LGE
+	/* for the connection loss logic in drbd_recv
+	 * I _need_ the resulting timeo in jiffies to be
+	 * non-zero and different
+	 *
+	 * XXX maybe rather store the value scaled to jiffies?
+	 * Note: MAX_SCHEDULE_TIMEOUT/HZ*HZ != MAX_SCHEDULE_TIMEOUT
+	 *       and HZ > 10; which is unlikely to change...
+	 *       Thus, if interrupted by a signal,
+	 *       sock_{send,recv}msg returns -EINTR,
+	 *       if the timeout expires, -EAGAIN.
+	 */
+	// unlikely: someone disabled the timeouts ...
+	// just put some huge values in there.
+	if (!new_conf->ping_int)
+		new_conf->ping_int = MAX_SCHEDULE_TIMEOUT/HZ;
+	if (!new_conf->timeout)
+		new_conf->timeout = MAX_SCHEDULE_TIMEOUT/HZ*10;
+	if (new_conf->ping_int*10 < new_conf->timeout)
+		new_conf->timeout = new_conf->ping_int*10/6;
+	if (new_conf->ping_int*10 == new_conf->timeout)
+		new_conf->ping_int = new_conf->ping_int+1;
+#endif
+
+	drbd_sync_me(mdev);
+	drbd_thread_stop(&mdev->receiver); // conn = StadAlone afterwards
+	drbd_free_sock(mdev);
+
+	/* As soon as mdev->state.conn < Unconnected nobody can increase
+	   the net_cnt. Wait until the net_cnt is 0. */
+	if ( wait_event_interruptible( mdev->cstate_wait,
+				       atomic_read(&mdev->net_cnt) == 0 ) ) {
+		retcode=GotSignal;
+		goto fail;
+	}
+
+	/* Now we may touch net_conf */
+	if (mdev->net_conf) kfree(mdev->net_conf);
+	mdev->net_conf = new_conf;
+
+	mdev->send_cnt = 0;
+	mdev->recv_cnt = 0;
+
+	if(new_tl_hash) {
+		if (mdev->tl_hash) kfree(mdev->tl_hash);
+		mdev->tl_hash_s = mdev->net_conf->max_epoch_size/8;
+		mdev->tl_hash = new_tl_hash;
+	}
+
+	if(new_ee_hash) {
+		if (mdev->ee_hash) kfree(mdev->ee_hash);
+		mdev->ee_hash_s = mdev->net_conf->max_buffers/8;
+		mdev->ee_hash = new_ee_hash;
+	}
+
+	if ( mdev->cram_hmac_tfm ) {
+		crypto_free_tfm(mdev->cram_hmac_tfm);
+	}
+	mdev->cram_hmac_tfm = tfm;
+
+	retcode = drbd_request_state(mdev,NS(conn,Unconnected));
+
+	drbd_nl_send_reply(req, retcode);
+	return ;
+
+  fail:
+	if (tfm) crypto_free_tfm(tfm);
+	if (new_tl_hash) kfree(new_tl_hash);
+	if (new_ee_hash) kfree(new_ee_hash);
+	if (new_conf) kfree(new_conf);
+
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_disconnect (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+
+	retcode = _drbd_request_state(mdev,NS(conn,StandAlone),0);	// silently.
+
+	if ( retcode == SS_NothingToDo ) goto done;
+	if ( retcode == SS_PrimaryNOP ) {
+		drbd_send_short_cmd(mdev, OutdateRequest);
+		wait_event(mdev->cstate_wait,
+			   mdev->state.pdsk <= Outdated ||
+			   mdev->state.conn < TearDown );
+		if( mdev->state.conn < TearDown ) goto done;
+
+		retcode = drbd_request_state(mdev,NS(conn,StandAlone));
+	}
+
+	if( retcode < SS_Success ) goto fail;
+
+	if ( mdev->cram_hmac_tfm ) {
+		crypto_free_tfm(mdev->cram_hmac_tfm);
+		mdev->cram_hmac_tfm = NULL;
+	}
+
+ done:
+	retcode = NoError;
+ fail:
+	drbd_md_sync(mdev);
+	drbd_nl_send_reply(req, retcode);
+	return ;
+}
+
+STATIC void drbd_nl_resize (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	struct resize rs;
+	drbd_dev *mdev;
+	int retcode=NoError;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	if (!resize_from_tags(mdev,nlp->tag_list,&rs)) {
+		retcode=UnknownMandatoryTag;
+		goto fail;
+	}
+
+	if (mdev->state.conn > Connected) {
+		retcode = NoResizeDuringResync;
+		goto fail;
+	}
+
+	if ( mdev->state.role == Secondary &&
+	     mdev->state.peer == Secondary) {
+		retcode = APrimaryNodeNeeded;
+		goto fail;
+	}
+	mdev->bc->dc.disk_size = (sector_t)rs.resize_size;
+	drbd_bm_lock(mdev);
+	drbd_determin_dev_size(mdev);
+	drbd_md_sync(mdev);
+	drbd_bm_unlock(mdev);
+	if (mdev->state.conn == Connected) {
+		drbd_send_uuids(mdev); // to start sync...
+		drbd_send_sizes(mdev);
+	}
+
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_syncer_conf (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError;
+	struct syncer_conf sc;
+	drbd_dev *odev;
+	int err;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	memcpy(&sc,&mdev->sync_conf,sizeof(struct syncer_conf));
+
+	if(nlp->flags & DRBD_NL_SET_DEFAULTS) {
+		sc.rate       = DRBD_RATE_DEF;
+		sc.after      = DRBD_AFTER_DEF;
+		sc.al_extents = DRBD_AL_EXTENTS_DEF;
+	}
+
+	if (!syncer_conf_from_tags(mdev,nlp->tag_list,&sc)) {
+		retcode=UnknownMandatoryTag;
+		goto fail;
+	}
+
+	if( sc.after != -1) {
+		if( sc.after < -1 || minor_to_mdev(sc.after) == NULL ) {
+			retcode=SyncAfterInvalid;
+			goto fail;
+		}
+		odev = minor_to_mdev(sc.after); // check against loops in
+		while(1) {
+			if( odev == mdev ) {
+				retcode=SyncAfterCycle;
+				goto fail;
+			}
+			if( odev->sync_conf.after == -1 ) break; // no cycles.
+			odev = minor_to_mdev(odev->sync_conf.after);
+		}
+	}
+
+	ERR_IF (sc.rate < 1) sc.rate = 1;
+	ERR_IF (sc.al_extents < 7) sc.al_extents = 127; // arbitrary minimum
+#define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT)
+	if(sc.al_extents > AL_MAX) {
+		ERR("sc.al_extents > %d\n",AL_MAX);
+		sc.al_extents = AL_MAX;
+	}
+#undef AL_MAX
+
+	mdev->sync_conf.rate       = sc.rate;
+	mdev->sync_conf.al_extents = sc.al_extents;
+
+	err = drbd_check_al_size(mdev);
+	drbd_md_sync(mdev);
+	if (err) {
+		retcode = KMallocFailed;
+		goto fail;
+	}
+
+	if (mdev->state.conn >= Connected)
+		drbd_send_sync_param(mdev,&sc);
+
+	drbd_alter_sa(mdev, sc.after);
+
+ fail:
+	drbd_nl_send_reply(req, retcode);
+	return;
+}
+
+STATIC void drbd_nl_invalidate (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	retcode = drbd_request_state(mdev,NS2(conn,StartingSyncT,
+					disk,Inconsistent));
+ fail:
+	drbd_nl_send_reply(req, retcode);
+	return;
+}
+
+STATIC void drbd_nl_invalidate_peer (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	retcode = drbd_request_state(mdev,NS2(conn,StartingSyncS,
+					      pdsk,Inconsistent));
+ fail:
+	drbd_nl_send_reply(req, retcode);
+	return;
+}
+
+STATIC void drbd_nl_pause_sync (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	if(!drbd_resync_pause(mdev, UserImposed)) retcode = PauseFlagAlreadySet;
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_resume_sync (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	if(!drbd_resync_resume(mdev, UserImposed)) retcode = PauseFlagAlreadyClear;
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_suspend_io (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	retcode = drbd_request_state(mdev,NS(susp,1));
+
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_resume_io (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	retcode = drbd_request_state(mdev,NS(susp,0));
+
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_outdate (void *data) 
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode;
+	drbd_state_t os,ns;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	spin_lock_irq(&mdev->req_lock);
+	os = mdev->state;
+	if( mdev->state.disk < Outdated ) {
+		retcode = -999;
+	} else {
+		retcode = _drbd_set_state(mdev,_NS(disk,Outdated),ChgStateVerbose);
+	}
+	ns = mdev->state;
+	spin_unlock_irq(&mdev->req_lock);
+	if (retcode==SS_Success) after_state_ch(mdev,os,ns, ChgStateVerbose);
+
+	if( retcode == -999 ) {
+		retcode = DiskLowerThanOutdated;
+		goto fail;
+	}
+
+	drbd_md_sync(mdev);
+
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+
+STATIC void drbd_nl_get_config (void *data)
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError,rr;
+	struct drbd_nl_cfg_reply* reply;
+	struct cn_msg *cn_reply;
+	unsigned short *tl;
+	int size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) +
+		disk_conf_tag_size + net_conf_tag_size + syncer_conf_tag_size + 2;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	if( !(cn_reply = kmalloc(size,GFP_KERNEL)) ) {
+		retcode=KMallocFailed;
+		goto fail;
+	}
+	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
+	tl = reply->tag_list;
+
+	if(inc_local(mdev)) {
+		tl = disk_conf_to_tags(mdev,&mdev->bc->dc,tl);
+		dec_local(mdev);
+	}
+
+	if(inc_net(mdev)) {
+		tl = net_conf_to_tags(mdev,mdev->net_conf,tl);
+		dec_net(mdev);
+	}
+	tl = syncer_conf_to_tags(mdev,&mdev->sync_conf,tl);
+
+	*tl++ = TT_END; /* Close the tag list */
+
+	cn_reply->id = req->id;
+	cn_reply->seq = req->seq;
+	cn_reply->ack = req->ack  + 1;
+	cn_reply->len = (char*)tl - (char *)reply;
+	cn_reply->flags = 0;
+
+	reply->minor = nlp->drbd_minor;
+	reply->ret_code = retcode;
+
+	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
+	return;
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+// Generate the packet_number to callback table...
+typedef void (*cn_handler)(void*);
+
+static cn_handler cnd_table[] = {
+#define PACKET(name, fields) [ P_ ## name ] = & drbd_nl_ ## name,
+#define INTEGER(pn,pr,member)
+#define INT64(pn,pr,member)
+#define BIT(pn,pr,member)
+#define STRING(pn,pr,member,len)
+#include "linux/drbd_nl.h"
+};
+
+int __init drbd_nl_init()
+{
+	static struct cb_id cn_id_drbd = { CN_IDX_DRBD, 0 };
+	int i,err;
+
+	for(i=0;i<P_nl_after_last_packet;i++) {
+		cn_id_drbd.val = i;
+		err = cn_add_callback(&cn_id_drbd,"cn_drbd",cnd_table[i]);
+		if(err) {
+			printk(KERN_ERR DEVICE_NAME "cn_drbd failed to register\n");
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+void drbd_nl_cleanup()
+{
+	static struct cb_id cn_id_drbd = { CN_IDX_DRBD, 0 };
+	int i;
+
+	for(i=0;i<P_nl_after_last_packet;i++) {
+		cn_id_drbd.val = i;
+		cn_del_callback(&cn_id_drbd);
+	}
+}
+
+void drbd_nl_send_reply( struct cn_msg *req, 
+			 int ret_code)
+{
+	char buffer[sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply)];
+	struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+	struct drbd_nl_cfg_reply* reply = (struct drbd_nl_cfg_reply*)cn_reply->data;
+	int rr;
+
+	cn_reply->id = req->id;
+
+	cn_reply->seq = req->seq;
+	cn_reply->ack = req->ack  + 1;
+	cn_reply->len = sizeof(struct drbd_nl_cfg_reply);
+	cn_reply->flags = 0;
+
+	reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor;
+	reply->ret_code = ret_code;
+
+	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
+}
+

Modified: trunk/drbd/drbd_proc.c
===================================================================
--- trunk/drbd/drbd_proc.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_proc.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -172,8 +172,9 @@
 
 STATIC int drbd_seq_show(struct seq_file *seq, void *v)
 {
-	int i;
+	int i,hole=0;
 	const char *sn;
+	drbd_dev *mdev;
 
 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d)\n%s\n",
 		    API_VERSION,PRO_VERSION, drbd_buildtag());
@@ -192,10 +193,20 @@
 	*/
 
 	for (i = 0; i < minor_count; i++) {
-		sn = conns_to_name(drbd_conf[i].state.conn);
+		mdev = minor_to_mdev(i);
+		if(!mdev) {
+			hole=1;
+			continue;
+		}
+		if( hole ) {
+			hole=0;
+			seq_printf( seq, "\n");
+		}
 
-		if ( drbd_conf[i].state.conn == StandAlone &&
-		     drbd_conf[i].state.disk == Diskless) {
+		sn = conns_to_name(mdev->state.conn);
+
+		if ( mdev->state.conn == StandAlone &&
+		     mdev->state.disk == Diskless) {
 			seq_printf( seq, "%2d: cs:Unconfigured\n", i);
 		} else {
 			seq_printf( seq,
@@ -203,40 +214,40 @@
 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
 			   "lo:%d pe:%d ua:%d ap:%d\n",
 			   i, sn,
-			   roles_to_name(drbd_conf[i].state.role),
-			   roles_to_name(drbd_conf[i].state.peer),
-			   disks_to_name(drbd_conf[i].state.disk),
-			   disks_to_name(drbd_conf[i].state.pdsk),
-			   drbd_conf[i].state.susp ? 's' : 'r',
-			   drbd_conf[i].state.aftr_isp ? 'a' : '-',
-			   drbd_conf[i].state.peer_isp ? 'p' : '-',
-			   drbd_conf[i].state.user_isp ? 'u' : '-',
-			   drbd_conf[i].send_cnt/2,
-			   drbd_conf[i].recv_cnt/2,
-			   drbd_conf[i].writ_cnt/2,
-			   drbd_conf[i].read_cnt/2,
-			   drbd_conf[i].al_writ_cnt,
-			   drbd_conf[i].bm_writ_cnt,
-			   atomic_read(&drbd_conf[i].local_cnt),
-			   atomic_read(&drbd_conf[i].ap_pending_cnt) +
-			   atomic_read(&drbd_conf[i].rs_pending_cnt),
-			   atomic_read(&drbd_conf[i].unacked_cnt),
-			   atomic_read(&drbd_conf[i].ap_bio_cnt)
+			   roles_to_name(mdev->state.role),
+			   roles_to_name(mdev->state.peer),
+			   disks_to_name(mdev->state.disk),
+			   disks_to_name(mdev->state.pdsk),
+			   mdev->state.susp ? 's' : 'r',
+			   mdev->state.aftr_isp ? 'a' : '-',
+			   mdev->state.peer_isp ? 'p' : '-',
+			   mdev->state.user_isp ? 'u' : '-',
+			   mdev->send_cnt/2,
+			   mdev->recv_cnt/2,
+			   mdev->writ_cnt/2,
+			   mdev->read_cnt/2,
+			   mdev->al_writ_cnt,
+			   mdev->bm_writ_cnt,
+			   atomic_read(&mdev->local_cnt),
+			   atomic_read(&mdev->ap_pending_cnt) +
+			   atomic_read(&mdev->rs_pending_cnt),
+			   atomic_read(&mdev->unacked_cnt),
+			   atomic_read(&mdev->ap_bio_cnt)
 			);
 		}
-		if ( drbd_conf[i].state.conn == SyncSource ||
-		     drbd_conf[i].state.conn == SyncTarget ) {
-			drbd_syncer_progress(drbd_conf+i,seq);
+		if ( mdev->state.conn == SyncSource ||
+		     mdev->state.conn == SyncTarget ) {
+			drbd_syncer_progress(mdev,seq);
 		}
-		if(drbd_conf[i].resync) {
-			lc_printf_stats(seq,drbd_conf[i].resync);
+		if(mdev->resync) {
+			lc_printf_stats(seq,mdev->resync);
 		}
-		if(drbd_conf[i].act_log) {
-			lc_printf_stats(seq,drbd_conf[i].act_log);
+		if(mdev->act_log) {
+			lc_printf_stats(seq,mdev->act_log);
 		}
 #if 0
-		if(drbd_conf[i].resync) {
-			lc_dump(drbd_conf[i].resync,seq,"rs_left",
+		if(mdev->resync) {
+			lc_dump(mdev->resync,seq,"rs_left",
 				resync_dump_detail);
 		}
 #endif

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_receiver.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -80,13 +80,13 @@
 		if( le->prev != la ) {
 			printk(KERN_ERR DEVICE_NAME
 			       "%d: %s list fucked.\n",
-			       (int)(mdev-drbd_conf),t);
+			       mdev_to_minor(mdev),t);
 			break;
 		}
 		if( forward++ > CHECK_LIST_LIMIT ) {
 			printk(KERN_ERR DEVICE_NAME
 			       "%d: %s forward > 1000\n",
-			       (int)(mdev-drbd_conf),t);
+			       mdev_to_minor(mdev),t);
 			break;
 		}
 	} while(le != list);
@@ -98,20 +98,20 @@
 		if( le->next != la ) {
 			printk(KERN_ERR DEVICE_NAME
 			       "%d: %s list fucked.\n",
-			       (int)(mdev-drbd_conf),t);
+			       mdev_to_minor(mdev),t);
 			break;
 		}
 		if( backward++ > CHECK_LIST_LIMIT ) {
 			printk(KERN_ERR DEVICE_NAME
 			       "%d: %s backward > 1000\n",
-			       (int)(mdev-drbd_conf),t);
+			       mdev_to_minor(mdev),t);
 			break;
 		}
 	} while(le != list);
 
 	if(forward != backward) {
 		printk(KERN_ERR DEVICE_NAME "%d: forward=%d, backward=%d\n",
-		       (int)(mdev-drbd_conf),forward,backward);
+		       mdev_to_minor(mdev),forward,backward);
 	}
 }
 #endif
@@ -646,8 +646,8 @@
 	}
 
 	err = sock->ops->connect(sock,
-				 (struct sockaddr *)mdev->net_conf->other_addr,
-				 mdev->net_conf->other_addr_len, 0);
+				 (struct sockaddr *)mdev->net_conf->peer_addr,
+				 mdev->net_conf->peer_addr_len, 0);
 
 	if (err) {
 		sock_release(sock);
@@ -1590,7 +1590,7 @@
 				(((struct sockaddr_in *)mdev->net_conf->my_addr)
 				 ->sin_addr.s_addr);
 			ch_peer = (unsigned long)
-				(((struct sockaddr_in *)mdev->net_conf->other_addr)
+				(((struct sockaddr_in *)mdev->net_conf->peer_addr)
 				 ->sin_addr.s_addr);
 			if      ( ch_self < ch_peer ) rv = -1;
 			else if ( ch_self > ch_peer ) rv =  1;
@@ -1634,10 +1634,9 @@
 	case PanicPrimary:
 		hg = drbd_asb_recover_0p(mdev);
 		if( hg == -1 && mdev->state.role==Primary) {
-			int sec = Secondary;
 			int got_mutex=!down_interruptible(&mdev->device_mutex);
-			if (got_mutex) self = drbd_set_role(mdev,&sec);
-			if (self || !got_mutex) {
+			if (got_mutex) self = drbd_set_role(mdev,Secondary,0);
+			if (self != SS_Success || !got_mutex) {
 				drbd_khelper(mdev,"pri-lost-after-sb");
 				drbd_panic("Panic by after-sb-1pri handler\n");
 			} else {
@@ -1672,10 +1671,9 @@
 	case PanicPrimary:
 		hg = drbd_asb_recover_0p(mdev);
 		if( hg == -1 ) {
-			int sec = Secondary;
 			int got_mutex=!down_interruptible(&mdev->device_mutex);
-			if (got_mutex) self = drbd_set_role(mdev,&sec);
-			if (self || !got_mutex) {
+			if (got_mutex) self = drbd_set_role(mdev,Secondary,0);
+			if (self != SS_Success || !got_mutex) {
 				drbd_khelper(mdev,"pri-lost-after-sb");
 				drbd_panic("Panic by after-sb-2pri handler\n");
 			} else {
@@ -1986,20 +1984,20 @@
 		warn_if_differ_considerably(mdev, "lower level device sizes",
 			   p_size, drbd_get_capacity(mdev->bc->backing_bdev));
 		warn_if_differ_considerably(mdev, "user requested size",
-					    p_usize, mdev->bc->u_size);
+					    p_usize, mdev->bc->dc.disk_size);
 
 		if (mdev->state.conn == WFReportParams) {
 			/* this is first connect, or an otherwise expected 
 			   param exchange.  choose the minimum */
-			p_usize = min_not_zero(mdev->bc->u_size, p_usize);
+			p_usize = min_not_zero(mdev->bc->dc.disk_size, p_usize);
 		}
 
-		my_usize = mdev->bc->u_size;
+		my_usize = mdev->bc->dc.disk_size;
 
-		if( mdev->bc->u_size != p_usize ) {
-			mdev->bc->u_size = p_usize;
+		if( mdev->bc->dc.disk_size != p_usize ) {
+			mdev->bc->dc.disk_size = p_usize;
 			INFO("Peer sets u_size to %lu KB\n",
-			     (unsigned long)mdev->bc->u_size);
+			     (unsigned long)mdev->bc->dc.disk_size);
 		}
 
 		// Never shrink a device with usable data.
@@ -2010,7 +2008,7 @@
 			ERR("The peer's disk size is too small!\n");
 			drbd_force_state(mdev,NS(conn,StandAlone));
 			drbd_thread_stop_nowait(&mdev->receiver);
-			mdev->bc->u_size = my_usize;
+			mdev->bc->dc.disk_size = my_usize;
 			return FALSE;
 		}
 		dec_local(mdev);
@@ -2463,7 +2461,7 @@
 
 	fp = DontCare;
 	if(inc_local(mdev)) {
-		fp = mdev->bc->fencing;
+		fp = mdev->bc->dc.fencing;
 		dec_local(mdev);
 	}
 
@@ -2748,7 +2746,7 @@
 int drbdd_init(struct Drbd_thread *thi)
 {
 	drbd_dev *mdev = thi->mdev;
-	int minor = (int)(mdev-drbd_conf);
+	int minor = mdev_to_minor(mdev);
 	int h;
 
 	sprintf(current->comm, "drbd%d_receiver", minor);
@@ -2991,7 +2989,7 @@
 		[StateChgReply]={sizeof(Drbd_RqS_Reply_Packet),got_RqSReply },
 	};
 
-	sprintf(current->comm, "drbd%d_asender", (int)(mdev-drbd_conf));
+	sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
 
 	current->policy = SCHED_RR;  /* Make this a realtime task! */
 	current->rt_priority = 2;    /* more important than all other tasks */

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_req.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -106,7 +106,7 @@
 	}
 
 	uptodate = req->rq_status & 0x0001;
-	if( !uptodate && mdev->bc->on_io_error == Detach) {
+	if( !uptodate && mdev->bc->dc.on_io_error == Detach) {
 		drbd_set_out_of_sync(mdev,rsector, drbd_req_get_size(req));
 		// It should also be as out of sync on
 		// the other side!  See w_io_error()

Deleted: trunk/drbd/drbd_sizeof_sanity_check.c
===================================================================
--- trunk/drbd/drbd_sizeof_sanity_check.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_sizeof_sanity_check.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -1,19 +0,0 @@
-#include <linux/drbd.h>
-#include <linux/kernel.h>
-
-#define COMPILETIME_ASSERT(x) \
-	switch(0) { case 0:; case (x):; }
-#define SZO(type,size) \
-void __assert_sizeof_ ##type ## _eq_ ##size(void) { COMPILETIME_ASSERT(sizeof(struct type) == (size)); } \
-void __assert_sizeof_ ##type ## _modulo_8_eq_0(void) { COMPILETIME_ASSERT(sizeof(struct type) % 8 == 0); }
-
-SZO(disk_config,	 32)
-SZO(net_config,		456)
-SZO(syncer_config,	 16)
-SZO(ioctl_disk_config,	 40)
-SZO(ioctl_net_config,	464)
-SZO(ioctl_syncer_config, 24)
-SZO(ioctl_wait,		 16)
-SZO(ioctl_get_config,	576)
-SZO(ioctl_get_uuids,     48)
-

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/drbd_worker.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -175,7 +175,7 @@
 	if (bio_rw(bio) == READA) goto pass_on;
 	if (error) {
 		drbd_chk_io_error(mdev,error); // handle panic and detach.
-		if(mdev->bc->on_io_error == PassOn) goto pass_on;
+		if(mdev->bc->dc.on_io_error == PassOn) goto pass_on;
 		// ok, if we survived this, retry:
 		// FIXME sector ...
 		if (DRBD_ratelimit(5*HZ,5))
@@ -206,7 +206,7 @@
 	 * a "we are diskless" param packet anyways, and the peer
 	 * will then set the FullSync bit in the meta data ...
 	 */
-	D_ASSERT(mdev->bc->on_io_error != PassOn);
+	D_ASSERT(mdev->bc->dc.on_io_error != PassOn);
 
 	drbd_req_free(req);
 
@@ -734,20 +734,24 @@
 
 STATIC void drbd_global_lock(void)
 {
+	drbd_dev *mdev;
 	int i;
 
 	local_irq_disable();
 	for (i=0; i < minor_count; i++) {
-		spin_lock(&drbd_conf[i].req_lock);
+		if(!(mdev = minor_to_mdev(i))) continue;
+		spin_lock(&mdev->req_lock);
 	}
 }
 
 STATIC void drbd_global_unlock(void)
 {
+	drbd_dev *mdev;
 	int i;
 
 	for (i=0; i < minor_count; i++) {
-		spin_unlock(&drbd_conf[i].req_lock);
+		if(!(mdev = minor_to_mdev(i))) continue;
+		spin_unlock(&mdev->req_lock);
 	}
 	local_irq_enable();
 }
@@ -841,7 +845,7 @@
 
 	while(1) {
 		if( odev->sync_conf.after == -1 ) return 1;
-		odev = drbd_conf + odev->sync_conf.after;
+		odev = minor_to_mdev(odev->sync_conf.after);
 		if( odev->state.conn >= SyncSource &&
 		    odev->state.conn <= PausedSyncT ) return 0;
 	}
@@ -859,7 +863,7 @@
 	int i, rv = 0;
 
 	for (i=0; i < minor_count; i++) {
-		odev = drbd_conf + i;
+		if( !(odev = minor_to_mdev(i)) ) continue;
 		if (! _drbd_may_sync_now(odev)) {
 			rv |= _drbd_rs_pause(odev,AfterDependency);
 		}
@@ -880,7 +884,7 @@
 	int i, rv = 0;
 
 	for (i=0; i < minor_count; i++) {
-		odev = drbd_conf + i;
+		if( !(odev = minor_to_mdev(i)) ) continue;
 		if ( odev->state.conn == PausedSyncS ||
 		     odev->state.conn == PausedSyncT ) {
 			if (_drbd_may_sync_now(odev)) {
@@ -1020,7 +1024,7 @@
 	LIST_HEAD(work_list);
 	int intr,i;
 
-	sprintf(current->comm, "drbd%d_worker", (int)(mdev-drbd_conf));
+	sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev));
 
 	for (;;) {
 		intr = down_interruptible(&mdev->data.work.s);

Modified: trunk/drbd/linux/drbd.h
===================================================================
--- trunk/drbd/linux/drbd.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/linux/drbd.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -27,42 +27,12 @@
 
 #ifdef __KERNEL__
 #include <linux/types.h>
-#include <linux/ioctl.h>
 #else
 #include <sys/types.h>
-#include <sys/ioctl.h>
 #include <sys/wait.h>
 #include <limits.h>
 #endif
 
-#ifdef __KERNEL__
-#define IN const
-#define OUT
-#define INOUT
-#else
-#define IN
-#define OUT const
-#define INOUT
-#endif
-
-/* 
-   - Never forget to place bigger members before the smaller ones, 
-     to avoid unaligned placement of members on 64 bit architectures. 
-   - Never forget to add explicit _pad members to make sizeof(struct)
-     divisible by 8.
-*/
-
-#define MAX_SOCK_ADDR	128	/* 108 for Unix domain -
-				   16 for IP, 16 for IPX,
-				   24 for IPv6,
-				   about 80 for AX.25
-				   must be at least one bigger than
-				   the AF_UNIX size (see net/unix/af_unix.c
-				   :unix_mkname()).
-				 */
-#define CRYPTO_MAX_ALG_NAME 64
-#define SHARED_SECRET_MAX   64
-
 enum io_error_handler {
 	PassOn,
 	Panic,
@@ -75,16 +45,6 @@
 	Stonith
 };
 
-struct disk_config {
-	IN __u64    disk_size;
-	IN int      lower_device;
-	IN enum io_error_handler on_io_error;
-	IN int      meta_device;
-	IN int      meta_index;
-	IN enum fencing_policy fencing;
-	const int   _pad;
-};
-
 enum disconnect_handler {
 	Reconnect,
 	DropNetConf,
@@ -103,44 +63,15 @@
 	PanicPrimary
 };
 
-struct net_config {
-	IN char     my_addr[MAX_SOCK_ADDR];
-	IN char     other_addr[MAX_SOCK_ADDR];
-	IN char     shared_secret[SHARED_SECRET_MAX];
-	IN char     cram_hmac_alg[CRYPTO_MAX_ALG_NAME];
-	IN int      my_addr_len;
-	IN int      other_addr_len;
-	IN int      timeout;          // deci seconds
-	IN int      wire_protocol;
-	IN int      try_connect_int;  /* seconds */
-	IN int      ping_int;         /* seconds */
-	IN int      max_epoch_size;
-	IN int      max_buffers;
-	IN int      unplug_watermark;
-	IN int      sndbuf_size;  /* socket send buffer size */
-	IN int      two_primaries;
-	IN unsigned int ko_count;
-	   int      want_lose;
-	IN enum disconnect_handler on_disconnect;
-	IN enum after_sb_handler after_sb_0p, after_sb_1p, after_sb_2p;
-	const int _pad;  
-};
-
-struct syncer_config {
-	int      rate; /* KB/sec */
-	int      after;
-	int      al_extents;
-	const int _pad;
-};
-
 /* KEEP the order, do not delete or insert!
  * Or change the API_VERSION, too. */
 enum ret_codes {
-	NoError=0,
+	RetCodeBase=100,
+	NoError,         // 101 ...
 	LAAlreadyInUse,
 	OAAlreadyInUse,
-	LDFDInvalid,
-	MDFDInvalid,
+	LDNameInvalid,
+	MDNameInvalid,
 	LDAlreadyInUse,
 	LDNoBlockDev,
 	MDNoBlockDev,
@@ -159,35 +90,22 @@
 	CRAMAlgNotDigest,
 	KMallocFailed,
 	DiscardNotAllowed,
+	HaveDiskConfig,
+	UnknownMandatoryTag,
+	MinorNotKnown,
 	StateNotAllowed,
 	GotSignal, // EINTR
+	NoResizeDuringResync,
+	APrimaryNodeNeeded,
+	SyncAfterInvalid,
+	SyncAfterCycle,
+	PauseFlagAlreadySet,
+	PauseFlagAlreadyClear,
+	DiskLowerThanOutdated,
+	FailedToClaimMyself,
+	AfterLastRetCode,
 };
 
-struct ioctl_disk_config {
-	struct disk_config    config;
-	OUT enum ret_codes    ret_code;
-	const int             _pad;
-};
-
-struct ioctl_net_config {
-	struct net_config     config;
-	OUT enum ret_codes    ret_code;
-	const int             _pad;
-};
-
-struct ioctl_syncer_config {
-	struct syncer_config  config;
-	OUT enum ret_codes    ret_code;
-	const int             _pad;
-};
-
-struct ioctl_wait {
-	IN int wfc_timeout;
-	IN int degr_wfc_timeout;
-	OUT int ret_code;
-	int      _pad;
-};
-
 #define DRBD_PROT_A   1
 #define DRBD_PROT_B   2
 #define DRBD_PROT_C   3
@@ -284,21 +202,7 @@
 # define BDEVNAME_SIZE 32
 #endif
 
-struct ioctl_get_config {
-	OUT __u64             disk_size_user;
-	OUT char              lower_device_name[BDEVNAME_SIZE];
-	OUT char              meta_device_name[BDEVNAME_SIZE];
-	struct net_config     nconf;
-	struct syncer_config  sconf;
-	OUT int               lower_device_major;
-	OUT int               lower_device_minor;
-	OUT enum io_error_handler on_io_error;
-	OUT enum fencing_policy fencing;
-	OUT int               meta_device_major;
-	OUT int               meta_device_minor;
-	OUT int               meta_index;
-	OUT drbd_state_t      state;
-};
+#define SHARED_SECRET_MAX 64
 
 enum MetaDataFlags {
 	__MDF_Consistent,
@@ -327,13 +231,6 @@
 
 #define UUID_JUST_CREATED ((__u64)4)
 
-struct ioctl_get_uuids {
-	OUT __u64        uuid[UUID_SIZE];
-	OUT __u64        current_size;
-	OUT unsigned int flags;
-	OUT unsigned int bits_set;
-};
-
 #define DRBD_MAGIC 0x83740267
 #define BE_DRBD_MAGIC __constant_cpu_to_be32(DRBD_MAGIC)
 
@@ -342,29 +239,25 @@
 #define DRBD_MD_INDEX_FLEX_EXT -2
 #define DRBD_MD_INDEX_FLEX_INT -3
 
-/* 'D' already taken by s390 dasd driver.
- *  maybe we want to change to something else, and register it officially?
- */
-#define DRBD_IOCTL_LETTER 'D'
-#define DRBD_IOCTL_GET_VERSION      _IOR( DRBD_IOCTL_LETTER, 0x00, int )
-#define DRBD_IOCTL_SET_STATE        _IOW( DRBD_IOCTL_LETTER, 0x02, int )
-#define DRBD_IOCTL_SET_DISK_CONFIG  _IOW( DRBD_IOCTL_LETTER, 0x06, struct ioctl_disk_config )
-#define DRBD_IOCTL_SET_NET_CONFIG   _IOW( DRBD_IOCTL_LETTER, 0x07, struct ioctl_net_config )
-#define DRBD_IOCTL_UNCONFIG_NET     _IO ( DRBD_IOCTL_LETTER, 0x08 )
-#define DRBD_IOCTL_GET_CONFIG       _IOW( DRBD_IOCTL_LETTER, 0x0A, struct ioctl_get_config )
-#define DRBD_IOCTL_INVALIDATE       _IO ( DRBD_IOCTL_LETTER, 0x0D )
-#define DRBD_IOCTL_INVALIDATE_REM   _IO ( DRBD_IOCTL_LETTER, 0x0E )
-#define DRBD_IOCTL_SET_SYNC_CONFIG  _IOW( DRBD_IOCTL_LETTER, 0x0F, struct ioctl_syncer_config )
-#define DRBD_IOCTL_SET_DISK_SIZE    _IOW( DRBD_IOCTL_LETTER, 0x10, __u64 )
-#define DRBD_IOCTL_WAIT_CONNECT     _IOR( DRBD_IOCTL_LETTER, 0x11, struct ioctl_wait )
-#define DRBD_IOCTL_WAIT_SYNC        _IOR( DRBD_IOCTL_LETTER, 0x12, struct ioctl_wait )
-#define DRBD_IOCTL_UNCONFIG_DISK    _IO ( DRBD_IOCTL_LETTER, 0x13 )
-#define DRBD_IOCTL_OUTDATE_DISK     _IOW( DRBD_IOCTL_LETTER, 0x15, int )
-#define DRBD_IOCTL_GET_UUIDS        _IOR( DRBD_IOCTL_LETTER, 0x16, struct ioctl_get_uuids )
-#define DRBD_IOCTL_PAUSE_SYNC       _IO ( DRBD_IOCTL_LETTER, 0x17)
-#define DRBD_IOCTL_RESUME_SYNC      _IO ( DRBD_IOCTL_LETTER, 0x18)
-#define DRBD_IOCTL_SUSPEND_IO       _IOW( DRBD_IOCTL_LETTER, 0x19, int )
-#define DRBD_IOCTL_RESUME_IO        _IOW( DRBD_IOCTL_LETTER, 0x1A, int )
+// Start of the new netlink/connector stuff
 
-#endif
+#define DRBD_NL_CREATE_DEVICE 0x01
+#define DRBD_NL_SET_DEFAULTS  0x02
 
+// The following line should be moved over to linux/connector.h
+// when the time comes
+#define CN_IDX_DRBD			0x4
+
+struct drbd_nl_cfg_req {
+	int drbd_minor;
+	int flags;
+	unsigned short tag_list[];
+};
+
+struct drbd_nl_cfg_reply {
+	int minor;
+	int ret_code; // enum ret_code or set_st_err_t
+	unsigned short tag_list[]; // only used with get_config()...
+};
+
+#endif

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/drbd/linux/drbd_config.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -29,7 +29,7 @@
 // undef if you need the workaround in drbd_receiver
 #define HAVE_UML_TO_VIRT 1
 
-//#define DBG_ALL_SYMBOLS // no static functs, improves quality of OOPS traces
+#define DBG_ALL_SYMBOLS // no static functs, improves quality of OOPS traces
 
 //#define DBG_SPINLOCKS   // enables MUST_HOLD macro (assertions for spinlocks)
 //#define DBG_ASSERTS     // drbd_assert_breakpoint() function

Copied: trunk/drbd/linux/drbd_limits.h (from rev 2375, trunk/user/drbd_limits.h)
===================================================================
--- trunk/user/drbd_limits.h	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/linux/drbd_limits.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -0,0 +1,118 @@
+/*
+  drbd_limits.h
+  This file is part of drbd by Philipp Reisner / Lars Ellenberg.
+*/
+
+/*
+ * Our current limitations.
+ * Some of them are hard limits,
+ * some of them are arbitrary range limits, that make it easier to provide
+ * feedback about nonsense settings for certain configurable values.
+ */
+
+#ifndef DRBD_LIMITS_H
+#define DRBD_LIMITS_H 1
+
+#define DEBUG_RANGE_CHECK 0
+
+#define DRBD_MINOR_COUNT_MIN 1
+#define DRBD_MINOR_COUNT_MAX 255
+
+#define DRBD_DIALOG_REFRESH_MIN 0
+#define DRBD_DIALOG_REFRESH_MAX 600
+
+/* valid port number */
+#define DRBD_PORT_MIN 1
+#define DRBD_PORT_MAX 0xffff
+
+/* startup { */
+  /* if you want more than 3.4 days, disable */
+#define DRBD_WFC_TIMEOUT_MIN 0
+#define DRBD_WFC_TIMEOUT_MAX 300000
+#define DRBD_WFC_TIMEOUT_DEF 0
+
+#define DRBD_DEGR_WFC_TIMEOUT_MIN 0
+#define DRBD_DEGR_WFC_TIMEOUT_MAX 300000
+#define DRBD_DEGR_WFC_TIMEOUT_DEF 60
+
+/* }*/
+
+/* net { */
+  /* timeout, unit centi seconds
+   * more than one minute timeout is not usefull */
+#define DRBD_TIMEOUT_MIN 1
+#define DRBD_TIMEOUT_MAX 600
+#define DRBD_TIMEOUT_DEF 60       // 6 seconds
+
+  /* active connection retries when WFConnection */
+#define DRBD_CONNECT_INT_MIN 1
+#define DRBD_CONNECT_INT_MAX 120
+#define DRBD_CONNECT_INT_DEF 10   //seconds
+
+  /* keep-alive probes when idle */
+#define DRBD_PING_INT_MIN 1
+#define DRBD_PING_INT_MAX 120
+#define DRBD_PING_INT_DEF 10
+
+  /* max number of write requests between write barriers */
+#define DRBD_MAX_EPOCH_SIZE_MIN 1
+#define DRBD_MAX_EPOCH_SIZE_MAX 20000
+#define DRBD_MAX_EPOCH_SIZE_DEF 2048
+
+  /* I don't think that a tcp send buffer of more than 10M is usefull */
+#define DRBD_SNDBUF_SIZE_MIN  1
+#define DRBD_SNDBUF_SIZE_MAX  10000000
+#define DRBD_SNDBUF_SIZE_DEF  (2*65535)
+
+  /* @4k PageSize -> 128kB - 512MB */
+#define DRBD_MAX_BUFFERS_MIN  32
+#define DRBD_MAX_BUFFERS_MAX  131072
+#define DRBD_MAX_BUFFERS_DEF  2048
+
+  /* @4k PageSize -> 4kB - 512MB */
+#define DRBD_UNPLUG_WATERMARK_MIN  1
+#define DRBD_UNPLUG_WATERMARK_MAX  131072
+#define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16)
+
+  /* 0 is disabled.
+   * 200 should be more than enough even for very short timeouts */
+#define DRBD_KO_COUNT_MIN  0
+#define DRBD_KO_COUNT_MAX  200
+#define DRBD_KO_COUNT_DEF  0
+/* } */
+
+/* syncer { */
+  /* FIXME allow rate to be zero? */
+#define DRBD_RATE_MIN 1
+#define DRBD_RATE_MAX 700000
+#define DRBD_RATE_DEF 250  // kb/second
+
+  /* less than 7 would hit performance unneccessarily.
+   * 3833 is the largest prime that still does fit
+   * into 64 sectors of activity log */
+#define DRBD_AL_EXTENTS_MIN  7
+#define DRBD_AL_EXTENTS_MAX  3833
+#define DRBD_AL_EXTENTS_DEF  127
+
+#define DRBD_AFTER_MIN  -1
+#define DRBD_AFTER_MAX  255
+#define DRBD_AFTER_DEF  -1
+
+/* } */
+
+/* drbdsetup XY resize -d Z
+ * you are free to reduce the device size to nothing, if you want to.
+ * but more than 3998G are currently not possible */
+/* DRBD_MAX_SECTORS */
+#define DRBD_DISK_SIZE_SECT_MIN  0
+#define DRBD_DISK_SIZE_SECT_MAX  (128LLU*1024*2 - 72)*512LLU*8*8 
+#define DRBD_DISK_SIZE_SECT_DEF  0 // = disabled = no user size...
+
+#define DRBD_ON_IO_ERROR_DEF PassOn
+#define DRBD_FENCING_DEF DontCare
+#define DRBD_AFTER_SB_0P_DEF Disconnect
+#define DRBD_AFTER_SB_1P_DEF Disconnect
+#define DRBD_AFTER_SB_2P_DEF Disconnect
+
+#undef RANGE
+#endif

Copied: trunk/drbd/linux/drbd_nl.h (from rev 2375, trunk/user/drbd_nl.h)
===================================================================
--- trunk/user/drbd_nl.h	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/linux/drbd_nl.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -0,0 +1,78 @@
+/* 
+   PAKET( name,
+          TYPE ( pn, pr, member )
+          ...
+   )
+
+   You may never reissue one of the pn arguments
+*/
+
+#if !defined(PACKET) || !defined(STRING) || !defined(INTEGER) || !defined(BIT) || !defined(INT64)
+#error "The macros PACKET, STRING, INTEGER, INT64 and BIT needs to be defined"
+#endif
+
+PACKET(primary,
+       BIT(		1,	T_MAY_IGNORE,	overwrite_peer)
+)
+
+PACKET(secondary, )
+
+PACKET(disk_conf,
+	INT64(  	2,	T_MAY_IGNORE,	disk_size)
+	STRING(		3,	T_MANDATORY,	backing_dev,	32)
+	STRING(		4,	T_MANDATORY,	meta_dev,	32)
+	INTEGER(	5,	T_MANDATORY,	meta_dev_idx)
+	INTEGER(	6,	T_MAY_IGNORE,	on_io_error)
+	INTEGER(	7,	T_MAY_IGNORE,	fencing)
+)
+
+PACKET(detach, )
+
+PACKET(net_conf,
+	STRING(		8,	T_MANDATORY,	my_addr,	128)
+	STRING(		9,	T_MANDATORY,	peer_addr,	128)
+	STRING(		10,	T_MAY_IGNORE,	shared_secret,	SHARED_SECRET_MAX)
+	STRING(		11,	T_MAY_IGNORE,	cram_hmac_alg,	SHARED_SECRET_MAX)
+	INTEGER(	14,	T_MAY_IGNORE,	timeout)
+	INTEGER(	15,	T_MANDATORY,	wire_protocol)
+	INTEGER(	16,	T_MAY_IGNORE,	try_connect_int)
+	INTEGER(	17,	T_MAY_IGNORE,	ping_int)
+	INTEGER(	18,	T_MAY_IGNORE,	max_epoch_size)
+	INTEGER(	19,	T_MAY_IGNORE,	max_buffers)
+	INTEGER(	20,	T_MAY_IGNORE,	unplug_watermark)
+	INTEGER(	21,	T_MAY_IGNORE,	sndbuf_size)
+	INTEGER(	22,	T_MAY_IGNORE,	ko_count)
+	INTEGER(	24,	T_MAY_IGNORE,	after_sb_0p)
+	INTEGER(	25,	T_MAY_IGNORE,	after_sb_1p)
+	INTEGER(	26,	T_MAY_IGNORE,	after_sb_2p)
+	BIT(		27,	T_MAY_IGNORE,	want_lose)
+	BIT(		28,	T_MAY_IGNORE,	two_primaries)
+)
+
+PACKET(disconnect, )
+
+PACKET(resize,
+	INT64(  	29,	T_MAY_IGNORE,	resize_size)
+)
+
+PACKET(syncer_conf,
+	INTEGER(	30,	T_MAY_IGNORE,	rate)
+	INTEGER(  	31,	T_MAY_IGNORE,	after)
+	INTEGER(  	32,	T_MAY_IGNORE,	al_extents)
+)
+
+PACKET(invalidate, )
+PACKET(invalidate_peer, )
+PACKET(pause_sync, )
+PACKET(resume_sync, )
+PACKET(suspend_io, )
+PACKET(resume_io, )
+PACKET(outdate, )
+PACKET(get_config, )
+
+#undef PACKET
+#undef INTEGER
+#undef INT64
+#undef BIT
+#undef STRING
+

Copied: trunk/drbd/linux/drbd_tag_magic.h (from rev 2375, trunk/user/drbd_tag_magic.h)
===================================================================
--- trunk/user/drbd_tag_magic.h	2006-08-16 14:16:06 UTC (rev 2375)
+++ trunk/drbd/linux/drbd_tag_magic.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -0,0 +1,66 @@
+#ifndef DRBD_TAG_MAGIC_H
+#define DRBD_TAG_MAGIC_H
+
+#define TT_END     0
+#define TT_REMOVED 0xE000
+
+// declare packet_type enums
+enum packet_types {
+#define PACKET(name, fields) P_ ## name,
+#define INTEGER(pn,pr,member)
+#define INT64(pn,pr,member)
+#define BIT(pn,pr,member)
+#define STRING(pn,pr,member,len)
+#include "drbd_nl.h"
+	P_nl_after_last_packet,
+};
+
+// declate tag-list-sizes
+#define PACKET(name,fields) const int name ## _tag_size = 2 fields ;
+#define INTEGER(pn,pr,member)     +4+4 
+#define INT64(pn,pr,member)       +4+8
+#define BIT(pn,pr,member)         +4+1
+#define STRING(pn,pr,member,len)  +4+len
+#include "drbd_nl.h"
+
+/* The two highest bits are used for the tag type */
+#define TT_MASK      0xC000
+#define TT_INTEGER   0x0000
+#define TT_INT64     0x4000
+#define TT_BIT       0x8000
+#define TT_STRING    0xC000
+/* The next bit indicates if processing of the tag is mandatory */
+#define T_MANDATORY  0x2000
+#define T_MAY_IGNORE 0x0000
+#define TN_MASK      0x1fff
+/* The remaining 13 bits are used to enumerate the tags */
+
+#define tag_type(T)   ((T) & TT_MASK)
+#define tag_number(T) ((T) & TN_MASK)
+
+// declare tag enums
+#define PACKET(name, fields) fields
+enum drbd_tags {
+#define INTEGER(pn,pr,member)    T_ ## member = pn | TT_INTEGER | pr ,
+#define INT64(pn,pr,member)      T_ ## member = pn | TT_INT64   | pr ,
+#define BIT(pn,pr,member)        T_ ## member = pn | TT_BIT     | pr ,
+#define STRING(pn,pr,member,len) T_ ## member = pn | TT_STRING  | pr ,
+#include "drbd_nl.h"
+};
+
+struct tag {
+	const char* name;
+	int type_n_flags;
+};
+
+// declare tag names
+#define PACKET(name, fields) fields
+const struct tag tag_descriptions[] = {
+#define INTEGER(pn,pr,member)    [ pn ] = { #member, TT_INTEGER | pr },
+#define INT64(pn,pr,member)      [ pn ] = { #member, TT_INT64   | pr },
+#define BIT(pn,pr,member)        [ pn ] = { #member, TT_BIT     | pr },
+#define STRING(pn,pr,member,len) [ pn ] = { #member, TT_STRING  | pr },
+#include "drbd_nl.h"
+};
+
+#endif

Modified: trunk/user/Makefile
===================================================================
--- trunk/user/Makefile	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/Makefile	2006-08-25 08:50:47 UTC (rev 2386)
@@ -17,7 +17,7 @@
 # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
-CFLAGS = -g -O2 -c -W -Wall -I../drbd
+CFLAGS = -g -O2 -c -W -Wall -I../drbd -I$(KDIR)/include
 CC = gcc
 
 drbdadm-obj = drbdadm_scanner.o drbdadm_parser.o drbdadm_main.o \
@@ -29,7 +29,7 @@
 
 drbdmeta-obj = drbdmeta.o drbdmeta_scanner.o drbdtool_common.o ../drbd/drbd_buildtag.o
 
-all: drbdsetup drbdadm drbdmeta drbdsetup_nl
+all: drbdadm drbdmeta drbdsetup_nl
 
 drbdadm: $(drbdadm-obj)
 	$(CC) -o $@ $^ 
@@ -42,11 +42,11 @@
 
 # for debug:	flex -d -s -odrbdadm_scanner.c drbdadm_scanner.fl
 
-drbdsetup_nl: drbdsetup_nl.o drbdtool_common.o
+drbdsetup_nl: drbdsetup_nl.o drbdtool_common.o ../drbd/drbd_strings.o
 	$(CC) -o $@ $^ 
 
-drbdsetup: $(drbdsetup-obj)
-	$(CC) -o $@ $^ 
+#drbdsetup: $(drbdsetup-obj)
+#	$(CC) -o $@ $^ 
 
 drbdmeta: $(drbdmeta-obj)
 	$(CC) -o $@ $^ 
@@ -75,13 +75,13 @@
 	rm -f $(PREFIX)/sbin/drbdadm
 
 ###dependencies
-drbdsetup.o:       drbdtool_common.h           drbd_limits.h
+drbdsetup.o:       drbdtool_common.h           ../drbd/linux/drbd_limits.h
 drbdtool_common.o: drbdtool_common.h          
 drbdadm_main.o:    drbdtool_common.h drbdadm.h
 drbdadm_adjust.o:  drbdtool_common.h drbdadm.h
-drbdadm_parser.o:  drbdtool_common.h drbdadm.h drbd_limits.h
+drbdadm_parser.o:  drbdtool_common.h drbdadm.h ../drbd/linux/drbd_limits.h
 drbdadm_scanner.o:                   drbdadm.h               drbdadm_parser.h 
-drbdsetup.o:       drbdtool_common.h           drbd_limits.h
+drbdsetup.o:       drbdtool_common.h           ../drbd/linux/drbd_limits.h
 drbdsetup.o: ../drbd/linux/drbd.h ../drbd/linux/drbd_config.h
 drbdmeta.o:        drbdtool_common.h drbd_endian.h 
 drbdadm_usage_cnt.o: drbdadm.h drbd_endian.h

Deleted: trunk/user/drbd_limits.h
===================================================================
--- trunk/user/drbd_limits.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbd_limits.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -1,80 +0,0 @@
-/*
-  drbd_limits.h
-  This file is part of drbd by Philipp Reisner / Lars Ellenberg.
-*/
-
-/*
- * Our current limitations.
- * Some of them are hard limits,
- * some of them are arbitrary range limits, that make it easier to provide
- * feedback about nonsense settings for certain configurable values.
- */
-
-#ifndef DRBD_LIMITS_H
-#define DRBD_LIMITS_H 1
-
-#define DEBUG_RANGE_CHECK 0
-
-#define RANGE(what,min,max) \
-const unsigned long long DRBD_ ## what ## _MIN = (min); \
-const unsigned long long DRBD_ ## what ## _MAX = (max)
-
-RANGE(MINOR_COUNT,1,255);
-RANGE(DIALOG_REFRESH,0,600);
-
-/* valid port number */
-RANGE(PORT,1,0xffff);
-
-
-/* startup { */
-  /* if you want more than 3.4 days, disable */
-  RANGE(WFC_TIMEOUT,0,300000);
-  RANGE(DEGR_WFC_TIMEOUT,0,300000);
-/* }*/
-
-/* net { */
-  /* timeout, unit centi seconds
-   * more than one minute timeout is not usefull */
-  RANGE(TIMEOUT,1,600);
-
-  /* active connection retries when WFConnection */
-  RANGE(CONNECT_INT,1,120);
-
-  /* keep-alive probes when idle */
-  RANGE(PING_INT,1,120);
-
-  /* max number of write requests between write barriers */
-  RANGE(MAX_EPOCH_SIZE,1,20000);
-
-  /* I don't think that a tcp send buffer of more than 10M is usefull */
-  RANGE(SNDBUF_SIZE, 1, 10000000);
-
-  /* @4k PageSize -> 128kB - 512MB */
-  RANGE(MAX_BUFFERS, 32, 131072);
-
-  /* @4k PageSize -> 4kB - 512MB */
-  RANGE(UNPLUG_WATERMARK, 1, 131072);
-
-  /* 0 is disabled.
-   * 200 should be more than enough even for very short timeouts */
-  RANGE(KO_COUNT,0, 200);
-/* } */
-
-/* syncer { */
-  /* FIXME allow rate to be zero? */
-  RANGE(RATE,1,700000);
-
-  /* less than 7 would hit performance unneccessarily.
-   * 3833 is the largest prime that still does fit
-   * into 64 sectors of activity log */
-  RANGE(AL_EXTENTS, 7, 3833);
-/* } */
-
-/* drbdsetup XY resize -d Z
- * you are free to reduce the device size to nothing, if you want to.
- * but more than 3998G are currently not possible */
-/* DRBD_MAX_SECTORS */
-RANGE(DISK_SIZE_SECT, 0, (128LLU*1024*2 - 72)*512LLU*8*8 );
-
-#undef RANGE
-#endif

Deleted: trunk/user/drbd_nl.h
===================================================================
--- trunk/user/drbd_nl.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbd_nl.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -1,79 +0,0 @@
-/* 
-   PAKET( name,
-          TYPE ( pn, pr, member )
-          ...
-   )
-
-   You may never reissue one of the pn arguments
-*/
-
-#if !defined(PACKET) || !defined(STRING) || !defined(INTEGER) || !defined(BIT) || !defined(INT64)
-#error "The macros PACKET, STRING, INTEGER, INT64 and BIT needs to be defined"
-#endif
-
-PACKET(primary,
-       BIT(		1,	T_MAY_IGNORE,	overwrite_peer)
-)
-
-PACKET(secondary, )
-
-PACKET(disk_conf,
-	INT64(  	2,	T_MAY_IGNORE,	disk_size)
-	INTEGER(	3,	T_MANDATORY,	backing_dev)
-	INTEGER(	4,	T_MANDATORY,	meta_dev)
-	INTEGER(	5,	T_MANDATORY,	meta_dev_idx)
-	INTEGER(	6,	T_MAY_IGNORE,	on_io_error)
-	INTEGER(	7,	T_MAY_IGNORE,	fencing)
-)
-
-PACKET(detach, )
-
-PACKET(net_conf,
-	STRING(		8,	T_MANDATORY,	my_addr,	128)
-	STRING(		9,	T_MANDATORY,	peer_addr,	128)
-	STRING(		10,	T_MAY_IGNORE,	shared_secret,	128)
-	STRING(		11,	T_MAY_IGNORE,	cram_hmac_alg,	128)
-	INTEGER(	12,	T_MANDATORY,	my_addr_len)
-	INTEGER(	13,	T_MANDATORY,	peer_addr_len)
-	INTEGER(	14,	T_MAY_IGNORE,	timeout)
-	INTEGER(	15,	T_MANDATORY,	wire_protocol)
-	INTEGER(	16,	T_MAY_IGNORE,	try_connect_int)
-	INTEGER(	17,	T_MAY_IGNORE,	ping_int)
-	INTEGER(	18,	T_MAY_IGNORE,	max_epoch_size)
-	INTEGER(	19,	T_MAY_IGNORE,	max_buffers)
-	INTEGER(	20,	T_MAY_IGNORE,	unplug_watermark)
-	INTEGER(	21,	T_MAY_IGNORE,	sndbuf_size)
-	INTEGER(	22,	T_MAY_IGNORE,	ko_count)
-	INTEGER(	24,	T_MAY_IGNORE,	after_sb_0p)
-	INTEGER(	25,	T_MAY_IGNORE,	after_sb_1p)
-	INTEGER(	26,	T_MAY_IGNORE,	after_sb_2p)
-	BIT(		27,	T_MAY_IGNORE,	want_lose)
-	BIT(		28,	T_MAY_IGNORE,	two_primaries)
-)
-
-PACKET(disconnect, )
-
-PACKET(resize,
-	INT64(  	29,	T_MAY_IGNORE,	resize_size)
-)
-
-PACKET(syncer_conf,
-	INTEGER(	30,	T_MAY_IGNORE,	sync_rate)
-	INTEGER(  	31,	T_MAY_IGNORE,	sync_after)
-	INTEGER(  	32,	T_MAY_IGNORE,	al_extents)
-)
-
-PACKET(invalidate, )
-PACKET(invalidate_peer, )
-PACKET(pause_sync, )
-PACKET(resume_sync, )
-PACKET(suspend_io, )
-PACKET(resume_io, )
-PACKET(outdate, )
-
-#undef PACKET
-#undef INTEGER
-#undef INT64
-#undef BIT
-#undef STRING
-

Deleted: trunk/user/drbd_tag_magic.h
===================================================================
--- trunk/user/drbd_tag_magic.h	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbd_tag_magic.h	2006-08-25 08:50:47 UTC (rev 2386)
@@ -1,72 +0,0 @@
-#ifndef DRBD_TAG_MAGIC_H
-#define DRBD_TAG_MAGIC_H
-
-#define TT_END     0
-
-// declare packet_type enums
-enum packet_types {
-#define PACKET(name, fields) P_ ## name,
-#define INTEGER(pn,pr,member)
-#define INT64(pn,pr,member)
-#define BIT(pn,pr,member)
-#define STRING(pn,pr,member,len)
-#include "drbd_nl.h"
-};
-
-// declate structs
-#define PACKET(name, fields) struct name { fields };
-#define INTEGER(pn,pr,member) int member;
-#define INT64(pn,pr,member) __u64 member;
-#define BIT(pn,pr,member)   unsigned member : 1;
-#define STRING(pn,pr,member,len) unsigned char member[len];
-#include "drbd_nl.h"
-
-// declate tag-list-sizes
-#define PACKET(name,fields) const int name ## _tag_size = 2 fields ;
-#define INTEGER(pn,pr,member)     +4+4 
-#define INT64(pn,pr,member)       +4+8
-#define BIT(pn,pr,member)         +4+1
-#define STRING(pn,pr,member,len)  +4+len
-#include "drbd_nl.h"
-
-/* The two highest bits are used for the tag type */
-#define TT_MASK      0xC000
-#define TT_INTEGER   0x0000
-#define TT_INT64     0x4000
-#define TT_BIT       0x8000
-#define TT_STRING    0xC000
-/* The next bit indicates if processing of the tag is mandatory */
-#define T_MANDATORY  0x2000
-#define T_MAY_IGNORE 0x0000
-#define TN_MASK      0x1fff
-/* The remaining 13 bits are used to enumerate the tags */
-
-#define tag_type(T)   ((T) & TT_MASK)
-#define tag_number(T) ((T) & TN_MASK)
-
-// declare tag enums
-#define PACKET(name, fields) fields
-enum drbd_tags {
-#define INTEGER(pn,pr,member)    T_ ## member = pn | TT_INTEGER | pr ,
-#define INT64(pn,pr,member)      T_ ## member = pn | TT_INT64   | pr ,
-#define BIT(pn,pr,member)        T_ ## member = pn | TT_BIT     | pr ,
-#define STRING(pn,pr,member,len) T_ ## member = pn | TT_STRING  | pr ,
-#include "drbd_nl.h"
-};
-
-struct tag {
-	const char* name;
-	int type_n_flags;
-};
-
-// declare tag names
-#define PACKET(name, fields) fields
-const struct tag tag_descriptions[] = {
-#define INTEGER(pn,pr,member)    [ pn ] = { #member, TT_INTEGER | pr },
-#define INT64(pn,pr,member)      [ pn ] = { #member, TT_INT64   | pr },
-#define BIT(pn,pr,member)        [ pn ] = { #member, TT_BIT     | pr },
-#define STRING(pn,pr,member,len) [ pn ] = { #member, TT_STRING  | pr },
-#include "drbd_nl.h"
-};
-
-#endif

Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbdadm_parser.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -30,7 +30,7 @@
 #include <string.h>
 
 #include "drbdadm.h"
-#include "drbd_limits.h"
+#include "linux/drbd_limits.h"
 #include "drbdtool_common.h"
 #include "drbdadm_parser.h"
 

Deleted: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbdsetup.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -1,1669 +0,0 @@
-/*
-   drbdsetup.c
-
-   This file is part of drbd by Philipp Reisner.
-
-   Copyright (C) 1999-2006, Philipp Reisner <philipp.reisner@linbit.com>.
-   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg@linbit.com>.
-   Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
-
-   Copyright (C) 2000, Fábio Olivé Leite <olive@conectiva.com.br>.
-        Added sanity checks before using the device.
-
-   drbd is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   drbd is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with drbd; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <linux/drbd.h>
-#include <linux/drbd_config.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <mntent.h>
-#include "drbdtool_common.h"
-#include "drbd_limits.h"
-
-/* Default values */
-#define DEF_NET_TIMEOUT             60      //  6 seconds
-#define DEF_NET_TRY_CON_I           10      // 10 seconds
-#define DEF_NET_PING_I              10      // 10 seconds
-#define DEF_SYNC_RATE              250
-#define DEF_SYNC_AFTER              -1
-#define DEF_WFC_TIMEOUT              0      // forever
-#define DEF_DEGR_WFC_TIMEOUT        60      // 60 Seconds
-#define DEF_SYNC_WFC_TIMEOUT         8      // 8 seconds
-#define DEF_SYNC_DEGR_WFC_TIMEOUT    4      // 4 seconds
-#define DEF_SYNC_AL_EXTENTS        127
-#define DEF_MAX_EPOCH_SIZE        2048      // entries
-#define DEF_MAX_BUFFERS           2048      // entries
-#define DEF_SNDBUF_SIZE           (2*65535) // ~128KB
-#define DEF_DISK_SIZE                0
-#define DEF_ON_IO_ERROR         PassOn
-#define DEF_KO_COUNT                 0
-#define DEF_ON_DISCONNECT       Reconnect
-#define DEF_FENCING             DontCare
-#define DEF_TWO_PRIMARIES            0
-#define DEF_AFTER_SB_0P       Disconnect
-#define DEF_AFTER_SB_1P       Disconnect
-#define DEF_AFTER_SB_2P       Disconnect
-#define DEF_UNPLUG_WATERMARK       (DEF_MAX_BUFFERS/16)
-
-#if 0
-# define ioctl(X...) (fprintf(stderr,"ioctl(%s)\n",#X),0);
-# define PRINT_ARGV do { \
-	int i; \
-		fprintf(stderr,"# argv (optind=%i argc=%i) in %s:%i:\n#",\
-			optind, argc, __FUNCTION__, __LINE__); \
-		for (i=optind; i < argc; i++) \
-			fprintf(stderr," %s",argv[i]); \
-				fprintf(stderr,"\n"); \
-} while(0)
-#else
-# define PRINT_ARGV
-#endif
-
-/* avoid warnings with -W for unused function arguments;
- * alternative use __attribute((unused))
-#define UNUSED(x)	(void)(x == x)
- */
-
-// some globals
-char* cmdname = 0;
-
-struct drbd_cmd {
-  const char* cmd;
-  int (* function)(int, char**, int, struct option*);
-  char **args;
-  struct option *options;
-};
-
-int cmd_primary(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_secondary(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_wait_sync(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_wait_connect(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_invalidate(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_invalidate_rem(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_down(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_net_conf(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_disk_conf(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_disk_size(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_outdate(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_disconnect(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_show(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_syncer(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_pause_sync(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_resume_sync(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_detach(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_state(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_cstate(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_dstate(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_show_gi(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_get_gi(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_suspend_io(int drbd_fd,char** argv,int argc,struct option *options);
-int cmd_resume_io(int drbd_fd,char** argv,int argc,struct option *options);
-
-
-struct drbd_cmd commands[] = {
-  {"primary", cmd_primary,           0,
-   (struct option[]) {
-     { "do-what-I-say",no_argument,     0, 'd' },
-     { "overwrite-data-of-peer",no_argument, 0, 'o' },
-     { 0,            0,                 0, 0   } } },
-  {"secondary", cmd_secondary,       0, 0, },
-  {"wait_sync", cmd_wait_sync,       0,
-   (struct option[]) {
-     { "wfc-timeout",required_argument, 0, 't' },
-     { "degr-wfc-timeout",required_argument,0,'d'},
-     { 0,            0,                 0, 0   } } },
-  {"wait_connect", cmd_wait_connect, 0,
-   (struct option[]) {
-     { "wfc-timeout",required_argument, 0, 't' },
-     { "degr-wfc-timeout",required_argument,0,'d'},
-     { 0,            0,                 0, 0   } } },
-  {"invalidate", cmd_invalidate,     0, 0, },
-  {"invalidate_remote", cmd_invalidate_rem,0, 0, },
-  {"syncer", cmd_syncer,                0,
-   (struct option[]) {
-     { "after",      required_argument, 0, 'a' },
-     { "rate",       required_argument, 0, 'r' },
-     { "al-extents", required_argument, 0, 'e' },
-     { 0,            0,                 0, 0 } } },
-  {"pause-sync",  cmd_pause_sync,       0, 0, },
-  {"resume-sync", cmd_resume_sync,      0, 0, },
-  {"down", cmd_down,                 0, 0, },
-  {"detach", cmd_detach,             0, 0, },
-  {"net", cmd_net_conf, (char *[]){"local_addr","remote_addr","protocol",0},
-   (struct option[]) {
-     { "timeout",    required_argument, 0, 't' },
-     { "max-epoch-size", required_argument, 0, 'e' },
-     { "max-buffers",required_argument, 0, 'b' },
-     { "unplug-watermark",required_argument, 0, 'u' },
-     { "connect-int",required_argument, 0, 'c' },
-     { "ping-int",   required_argument, 0, 'i' },
-     { "sndbuf-size",required_argument, 0, 'S' },
-     { "ko-count",   required_argument, 0, 'k' },
-     { "on-disconnect",required_argument, 0, 'd' },
-     { "allow-two-primaries",no_argument, 0, 'm' },
-     { "cram-hmac-alg",required_argument, 0, 'a' },
-     { "shared-secret",required_argument, 0, 'x' },
-     { "after-sb-0pri",required_argument, 0, 'A' },
-     { "after-sb-1pri",required_argument, 0, 'B' },
-     { "after-sb-2pri",required_argument, 0, 'C' },
-     { "discard-my-data",    no_argument, 0, 'D' },
-     { 0,            0,                 0, 0 } } },
-  {"disk", cmd_disk_conf,(char *[]){"lower_dev","meta_data_dev",
-				    "meta_data_index",0},
-   (struct option[]) {
-     { "size",       required_argument, 0, 'd' },
-     { "on-io-error",required_argument, 0, 'e' },
-     { "fencing",    required_argument, 0, 'f' },
-     { 0,            0,                 0, 0 } } },
-  {"resize", cmd_disk_size,             0,
-   (struct option[]) {
-     { "size",  required_argument,      0, 'd' },
-     { 0,            0,                 0, 0 } } },
-  {"outdate", cmd_outdate,           0, 0, },
-  {"disconnect", cmd_disconnect,     0, 0, },
-  {"state", cmd_state,               0, 0, },
-  {"cstate", cmd_cstate,             0, 0, },
-  {"dstate", cmd_dstate,             0, 0, },
-  {"show-gi", cmd_show_gi,           0, 0, },
-  {"get-gi", cmd_get_gi,             0, 0, },
-  {"show", cmd_show,                 0, 0, },
-  {"suspend-io", cmd_suspend_io,     0, 0, },
-  {"resume-io", cmd_resume_io,       0, 0, },
-};
-
-const char *eh_names[] = {
-  [PassOn] = "pass_on",
-  [Panic]  = "panic",
-  [Detach] = "detach" 
-};
-
-const char *dh_names[] = {
-  [Reconnect]   = "reconnect",
-  [DropNetConf] = "stand_alone",
-  // [FreezeIO]    = "freeze_io" // TODO on the kernel side...
-};
-
-const char *fencing_names[] = {
-  [DontCare] = "dont-care",
-  [Resource] = "resource-only",
-  [Stonith]  = "resource-and-stonith" 
-};
-
-const char *asb0p_names[] = {
-  [Disconnect]        = "disconnect",
-  [DiscardYoungerPri] = "discard-younger-primary",
-  [DiscardOlderPri]   = "discard-older-primary",
-  [DiscardLeastChg]   = "discard-least-changes",
-  [DiscardLocal]      = "discard-local",
-  [DiscardRemote]     = "discard-remote"
-};
-
-const char *asb1p_names[] = {
-  [Disconnect]        = "disconnect",
-  [Consensus]         = "consensus",
-  [DiscardSecondary]  = "discard-secondary",
-  [PanicPrimary]      = "panic-primary"
-};
-
-const char *asb2p_names[] = {
-  [Disconnect]        = "disconnect",
-  [PanicPrimary]      = "panic"
-};
-
-int _lookup_handler(const char* text, const char** handlers, int size)
-{
-  int i;
-
-  for(i=0;i<size;i++) {
-    if (handlers[i]==0) continue;
-    if (strcmp(text,handlers[i])==0) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-#define lookup_handler(A,B) _lookup_handler(A,B,ARRY_SIZE(B))
-
-unsigned long resolv(const char* name)
-{
-  unsigned long retval;
-
-  if((retval = inet_addr(name)) == INADDR_NONE )
-    {
-      struct hostent *he;
-      he = gethostbyname(name);
-      if (!he)
-	{
-	  PERROR("can not resolv the hostname");
-	  exit(20);
-	}
-      retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr;
-    }
-  return retval;
-}
-
-/* NOTE all values are _unsigned_ */
-unsigned long long
-m_strtoll_range(const char *s, const char def_unit, const char *name,
-		const unsigned long long min, const unsigned long long max)
-{
-  unsigned long long r = m_strtoll(s, def_unit);
-  char unit[] = { def_unit > '1' ? def_unit : 0, 0 };
-  if (min > r || r > max)
-    {
-      fprintf(stderr, "%s %s => %llu%s out of range [%llu..%llu]%s\n",
-	      name, s, r, unit, min, max, unit);
-      exit(20);
-    }
-  if (DEBUG_RANGE_CHECK)
-    {
-      fprintf(stderr,
-	      "OK: %s %s => %llu%s in range [%llu..%llu]%s.\n",
-	      name, s, r, unit, min, max, unit);
-    }
-  return r;
-}
-
-const char* addr_part(const char* s)
-{
-  static char buffer[200];
-  char *b;
-
-  b=strchr(s,':');
-  if(b)
-    {
-      strncpy(buffer,s,b-s);
-      buffer[b-s]=0;
-      return buffer;
-    }
-  return s;
-}
-
-int port_part(const char* s)
-{
-  char *b;
-
-  b=strchr(s,':');
-  if(b)
-      return m_strtoll_range(b+1,1, "port", DRBD_PORT_MIN, DRBD_PORT_MAX);
-
-  return 7788;
-}
-
-int already_in_use_tab(const char* dev_name,const char* tab_name)
-{
-  FILE* tab;
-  struct mntent* entry;
-
-
-  if( ! (tab=setmntent(tab_name,"r")) )
-    return 0;
-
-  while( (entry=getmntent(tab)) )
-    {
-      if( !strcmp(entry->mnt_fsname, dev_name) )
-	{
-	  endmntent(tab);
-	  return 1;
-	}
-    }
-
-  endmntent(tab);
-
-  return 0;
-}
-
-int already_in_use(const char* dev_name)
-{
-  return already_in_use_tab(dev_name,"/etc/mtab") ||
-    already_in_use_tab(dev_name,"/proc/mounts");
-}
-
-void print_command_usage(int i, const char *addinfo)
-    // CAUTION no range check for i
-{
-  char **args;
-  struct option *options;
-#define  maxcol 70 // plus initial tab ...
-  static char line[maxcol+1];
-  int col,prevcol;
-
-  prevcol=col=0;
-
-  col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
-  if ((args = commands[i].args)) {
-    while (*args)
-      col += snprintf(line+col, maxcol-col, " %s", *args++);
-  }
-  if (col > maxcol) {
-    printf("%s\n\t",line);
-    col=0;
-  }
-  prevcol=col;
-  if ((options = commands[i].options)) {
-    while (options->name) {
-      if (options->has_arg == required_argument) {
-	col += snprintf(line+col, maxcol-col, " [{--%s|-%c} val]",
-			options->name, options->val);
-      } else {
-	col += snprintf(line+col, maxcol-col, " [{--%s|-%c}]",
-			options->name, options->val);
-      }
-      if (col >= maxcol) {
-	line[prevcol]=0;
-	printf("%s\n\t",line);
-	prevcol=col=0;
-      } else {
-	prevcol=col;
-	options++;
-      }
-    }
-  }
-  line[col]=0;
-  printf("%s\n",line);
-  if (addinfo) {
-      printf("%s\n",addinfo);
-      exit(20);
-  }
-}
-
-void print_usage(const char* addinfo)
-{
-  size_t i;
-
-  printf("\nUSAGE: %s device command arguments options\n\n"
-	 "Device is usually /dev/drbdX or /dev/drbd/X.\n"
-         "Commands, arguments and options are:\n",cmdname);
-
-
-  for (i = 0; i < ARRY_SIZE(commands); i++)
-    print_command_usage(i, 0);
-
-  printf("\nAvailable on-io-error handlers:");
-  for(i=0;i<ARRY_SIZE(eh_names);i++) {
-    printf(" %s",eh_names[i]);
-    if(i < ARRY_SIZE(eh_names)-1) printf(",");
-  }
-
-  printf("\nAvailable on-disconnect handlers:");
-  for(i=0;i<ARRY_SIZE(dh_names);i++) {
-    printf(" %s",dh_names[i]);
-    if(i < ARRY_SIZE(dh_names)-1) printf(",");
-  }
-
-  printf("\nAvailable fencing policies:");
-  for(i=0;i<ARRY_SIZE(fencing_names);i++) {
-    printf(" %s",fencing_names[i]);
-    if(i < ARRY_SIZE(fencing_names)-1) printf(",");
-  }
-
-  printf("\n\nVersion: "REL_VERSION" (api:%d)\n%s\n",
-		  API_VERSION, drbd_buildtag());
-  if (addinfo)
-      printf("\n%s\n",addinfo);
-
-  exit(20);
-}
-
-int open_drbd_device(const char* device)
-{
-  int err,drbd_fd,version = 0;
-
-  drbd_fd = dt_lock_open_drbd(device,NULL,0);
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_VERSION,&version);
-  if(err)
-    {
-      PERROR("ioctl(,GET_VERSION,) failed");
-      exit(20);
-    }
-
-  if (version != API_VERSION)
-    {
-      fprintf(stderr,"\tVersion tags of drbdsetup and drbd kernel module are not matching!\n"
-		     "\tAPI_VERSION: drbdsetup:%d -- drbd module:%d\n"
-		     "\tPlease check your installation!\n", API_VERSION, version);
-      exit(20);
-    }
-
-  return drbd_fd;
-}
-
-int scan_disk_options(char **argv,
-		      int argc,
-		      struct ioctl_disk_config* cn,
-		      struct option *options)
-{
-  cn->config.disk_size = 0; /* default not known */
-  cn->config.on_io_error = DEF_ON_IO_ERROR;
-  cn->config.fencing = DEF_FENCING;
-
-  if(argc==0) return 0;
-
-  while(1)
-    {
-      int c;
-
-      PRINT_ARGV;
-      c = getopt_long(argc,argv,make_optstring(options,'-'),options,0);
-      if(c == -1) break;
-      switch(c)
-	{
-	case 'd':
-	  cn->config.disk_size = m_strtoll_range(optarg,'K', "size",
-			      DRBD_DISK_SIZE_SECT_MIN>>1,
-			      DRBD_DISK_SIZE_SECT_MAX>>1 ) << 1;
-	  break;
-	case 'e':
-	  cn->config.on_io_error=lookup_handler(optarg,eh_names);
-	  if( cn->config.on_io_error == -1U ) {
-	    fprintf(stderr,"%s: '%s' is an invalid on-io-error handler.\n",
-		    cmdname,optarg);
-	    return 20;
-	  }
-	  break;
-	case 'f':
-	  cn->config.fencing = lookup_handler(optarg,fencing_names);
-	  if( cn->config.fencing == -1U ) {
-	    fprintf(stderr,"%s: '%s' is an invalid fency policy.\n",
-		    cmdname,optarg);
-	    return 20;
-	  }
-	  break;
-	case 1:	// non option argument. see getopt_long(3)
-	  fprintf(stderr,"%s: Unexpected nonoption argument '%s'\n",cmdname,optarg);
-	case '?':
-	  return 20;
-	}
-    }
-  return 0;
-}
-
-int scan_net_options(char **argv,
-		     int argc,
-		     struct ioctl_net_config* cn,
-		     struct option *options)
-{
-  cn->config.timeout = DEF_NET_TIMEOUT;
-  cn->config.try_connect_int = DEF_NET_TRY_CON_I;
-  cn->config.ping_int = DEF_NET_PING_I;
-  cn->config.max_epoch_size = DEF_MAX_EPOCH_SIZE;
-  cn->config.max_buffers = DEF_MAX_BUFFERS;
-  cn->config.sndbuf_size = DEF_SNDBUF_SIZE ;
-  cn->config.on_disconnect = DEF_ON_DISCONNECT;
-  cn->config.two_primaries = DEF_TWO_PRIMARIES;
-  cn->config.cram_hmac_alg[0] = 0;
-  cn->config.shared_secret[0] = 0;
-  cn->config.after_sb_0p = DEF_AFTER_SB_0P;
-  cn->config.after_sb_1p = DEF_AFTER_SB_1P;
-  cn->config.after_sb_2p = DEF_AFTER_SB_2P;
-  cn->config.want_lose = 0;
-  cn->config.ko_count = DEF_KO_COUNT;
-  cn->config.unplug_watermark = DEF_UNPLUG_WATERMARK;
-
-  if(argc==0) return 0;
-
-  while(1)
-    {
-      int c;
-
-      PRINT_ARGV;
-      c = getopt_long(argc,argv,make_optstring(options,'-'),options,0);
-      if(c == -1) break;
-      switch(c)
-	{
-	case 't':
-	  cn->config.timeout = m_strtoll_range(optarg,1, "timeout",
-			  DRBD_TIMEOUT_MIN, DRBD_TIMEOUT_MAX);
-	  break;
-	case 'e':
-	  cn->config.max_epoch_size = m_strtoll_range(optarg,1,
-			  "max-epoch-size",
-			  DRBD_MAX_EPOCH_SIZE_MIN, DRBD_MAX_EPOCH_SIZE_MAX);
-	  break;
-	case 'b':
-	  cn->config.max_buffers = m_strtoll_range(optarg,1, "max-buffers",
-			  DRBD_MAX_BUFFERS_MIN, DRBD_MAX_BUFFERS_MAX);
-	  break;
-	case 'u':
-	  cn->config.unplug_watermark = m_strtoll_range(optarg,1, "unplug-watermark",
-			  DRBD_UNPLUG_WATERMARK_MIN, DRBD_UNPLUG_WATERMARK_MAX);
-	  break;
-	case 'c':
-	  cn->config.try_connect_int = m_strtoll_range(optarg,1, "connect-int",
-			  DRBD_CONNECT_INT_MIN, DRBD_CONNECT_INT_MAX);
-	  break;
-	case 'i':
-	  cn->config.ping_int = m_strtoll_range(optarg,1, "ping-int",
-			  DRBD_PING_INT_MIN, DRBD_PING_INT_MAX);
-	  break;
-	case 'S':
-	  cn->config.sndbuf_size = m_strtoll_range(optarg,1, "sndbuf-size",
-			  DRBD_SNDBUF_SIZE_MIN, DRBD_SNDBUF_SIZE_MAX);
-	  break;
-       case 'k':
-          cn->config.ko_count = m_strtoll_range(optarg,1, "ko-count",
-			  DRBD_KO_COUNT_MIN, DRBD_KO_COUNT_MAX);
-          break;
-       case 'm':
-	  cn->config.two_primaries = 1;
-          break;
-	case 'd':
-	  cn->config.on_disconnect = lookup_handler(optarg,dh_names);
-	  if( cn->config.on_disconnect == -1U ) {
-	    fprintf(stderr,"%s: '%s' is an invalid on-disconnect handler.\n",
-		    cmdname,optarg);
-	    return 20;
-	  }
-	  break;
-	case 'a':
-	  strncpy(cn->config.cram_hmac_alg,optarg,CRYPTO_MAX_ALG_NAME);
-	  break;
-	case 'x':
-	  strncpy(cn->config.shared_secret,optarg,SHARED_SECRET_MAX);
-	  break;
-	case 'A':
-	  cn->config.after_sb_0p = lookup_handler(optarg,asb0p_names);
-	  if( cn->config.after_sb_0p == -1U ) {
-	    fprintf(stderr,"%s: '%s' is an invalid after-sb-0pri handler.\n",
-		    cmdname,optarg);
-	    return 20;
-	  }
-	  break;
-	case 'B':
-	  cn->config.after_sb_1p = lookup_handler(optarg,asb1p_names);
-	  if( cn->config.after_sb_0p == -1U ) {
-	    fprintf(stderr,"%s: '%s' is an invalid after-sb-1pri handler.\n",
-		    cmdname,optarg);
-	    return 20;
-	  }
-	  break;
-	case 'C':
-	  cn->config.after_sb_2p = lookup_handler(optarg,asb2p_names);
-	  if( cn->config.after_sb_0p == -1U ) {
-	    fprintf(stderr,"%s: '%s' is an invalid after-sb-2pri handler.\n",
-		    cmdname,optarg);
-	    return 20;
-	  }
-	  break;
-       case 'D':
-	  cn->config.want_lose = 1;
-          break;
-
-
-	case 1:	// non option argument. see getopt_long(3)
-	  fprintf(stderr,"%s: Unexpected nonoption argument '%s'\n",cmdname,optarg);
-	case '?':
-	  return 20;
-	}
-    }
-
-  /* sanity checks of the timeouts */
-
-  if(cn->config.timeout >= cn->config.try_connect_int * 10 ||
-     cn->config.timeout >= cn->config.ping_int * 10)
-    {
-      fprintf(stderr,"The timeout has to be smaller than "
-	      "connect-int and ping-int.\n");
-      return 20;
-    }
-  return 0;
-}
-
-void print_config_ioctl_err(int err_no)
-{
-  const char *etext[] = {
-    [NoError]="No further Information available.",
-    [LAAlreadyInUse]="Local address(port) already in use.",
-    [OAAlreadyInUse]="Remote address(port) already in use.",
-    [LDFDInvalid]="Filedescriptor for lower device is invalid.",
-    [MDFDInvalid]="Filedescriptor for meta device is invalid.",
-    [LDAlreadyInUse]="Lower device already in use.",
-    [LDNoBlockDev]="Lower device is not a block device.",
-    [MDNoBlockDev]="Meta device is not a block device.",
-    [LDOpenFailed]="Open of lower device failed.",
-    [MDOpenFailed]="Open of meta device failed.",
-    [LDDeviceTooSmall]="Low.dev. smaller than requested DRBD-dev. size.",
-    [MDDeviceTooSmall]="Meta device too small.",
-    [LDNoConfig]="You have to use the disk command first.",
-    [LDMounted]="Lower device is already mounted.",
-    [MDMounted]="Meta device is already mounted.",
-    [LDMDInvalid]="Lower device / meta device / index combination invalid.",
-    [LDDeviceTooLarge]="Currently we only support devices up to 3.998TB.\n"
-                       "(up to 2TB in case you do not have CONFIG_LBD set)",
-                       "Contact office@linbit.com, if you need more.",
-    [MDIOError]="IO error(s) orruced during initial access to meta-data.\n",
-    [MDInvalid]="No valid meta-data signature found.\n"
-                "Use 'drbdadm create-md res' to initialize meta-data area.\n",
-    [CRAMAlgNotAvail]="The 'cram-hmac-alg' you specified is not known in "
-                      "the kernel.\n",
-    [CRAMAlgNotDigest]="The 'cram-hmac-alg' you specified is not a digest.",
-    [KMallocFailed]="kmalloc() failed. Out of memory?",
-    [DiscardNotAllowed]="--discard-my-data not allowed when primary."
-  };
-
-  if (err_no<0 || (size_t)err_no>ARRY_SIZE(etext)) err_no=0;
-  fprintf(stderr,"%s\n",etext[err_no]);
-}
-
-int check_if_blk_dev(int fd,const char* dev_name)
-{
-  struct stat lower_stat;
-  int err;
-
-  err=fstat(fd, &lower_stat);
-  if(err)
-    {
-      PERROR("fstat(%s) failed", dev_name);
-      return 20;
-    }
-  if(!S_ISBLK(lower_stat.st_mode))
-    {
-      fprintf(stderr, "%s is not a block device!\n", dev_name);
-      return 20;
-    }
-
-  return 0;
-}
-
-int do_disk_conf(int drbd_fd,
-		 const char* lower_dev_name,
-		 const char* meta_dev_name,
-		 struct ioctl_disk_config* cn)
-{
-  int lower_device,meta_device,err;
-
-  if(already_in_use(lower_dev_name))
-    {
-      fprintf(stderr,"Lower device (%s) is already mounted\n",lower_dev_name);
-      return 20;
-    }
-
-  if((lower_device = open(lower_dev_name,O_RDWR))==-1)
-    {
-      PERROR("Can not open lower device '%s'", lower_dev_name);
-      return 20;
-    }
-
-  err = check_if_blk_dev(lower_device,lower_dev_name);
-  if(err) return err;
-
-  if(!strcmp(meta_dev_name,"internal")) {
-    meta_dev_name = lower_dev_name;
-  }
-
-  if((meta_device = open(meta_dev_name,O_RDWR))==-1)
-    {
-      PERROR("Can not open meta data device '%s'", meta_dev_name);
-      return 20;
-    }
-
-  err = check_if_blk_dev(meta_device,meta_dev_name);
-  if(err) return err;
-
-  cn->config.lower_device=lower_device;
-  cn->config.meta_device=meta_device;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_SET_DISK_CONFIG,cn);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,SET_DISK_CONFIG,) failed");
-      if(err == EINVAL) print_config_ioctl_err(cn->ret_code);
-      return 20;
-    }
-  return 0;
-}
-
-
-int do_net_conf(int drbd_fd,
-		const char* proto,
-		const char* local_addr,
-		const char* remote_addr,
-		struct ioctl_net_config* cn)
-{
-  struct sockaddr_in *other_addr;
-  struct sockaddr_in *my_addr;
-  int err;
-
-  if(proto[1] != 0)
-    {
-      fprintf(stderr,"Invalid protocol specifier '%s'.\n",proto);
-      return 20;
-    }
-  switch(proto[0])
-    {
-    case 'a':
-    case 'A':
-      cn->config.wire_protocol = DRBD_PROT_A;
-      break;
-    case 'b':
-    case 'B':
-      cn->config.wire_protocol = DRBD_PROT_B;
-      break;
-    case 'c':
-    case 'C':
-      cn->config.wire_protocol = DRBD_PROT_C;
-      break;
-    default:
-      fprintf(stderr,"Invalid protocol specifier '%s'.\n",proto);
-      return 20;
-    }
-
-  cn->config.my_addr_len = sizeof(struct sockaddr_in);
-  my_addr = (struct sockaddr_in *)cn->config.my_addr;
-  my_addr->sin_port = htons(port_part(local_addr));
-  my_addr->sin_family = AF_INET;
-  my_addr->sin_addr.s_addr = resolv(addr_part(local_addr));
-
-  cn->config.other_addr_len = sizeof(struct sockaddr_in);
-  other_addr = (struct sockaddr_in *)cn->config.other_addr;
-  other_addr->sin_port = htons(port_part(remote_addr));
-  other_addr->sin_family = AF_INET;
-  other_addr->sin_addr.s_addr = resolv(addr_part(remote_addr));
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_SET_NET_CONFIG,cn);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,SET_NET_CONFIG,) failed");
-      if(err == EINVAL) print_config_ioctl_err(cn->ret_code);
-      return 20;
-    }
-  return 0;
-}
-
-
-
-int set_state(int drbd_fd,drbd_role_t state)
-{
-  int err, arg = state;
-  err=ioctl(drbd_fd,DRBD_IOCTL_SET_STATE,&arg);
-  if(err) {
-    err=errno;
-    PERROR("ioctl(,SET_STATE,) failed");
-    switch(err)
-      {
-      case EBUSY:
-	fprintf(stderr,"Someone has opened the device for RW access!\n");
-	break;
-      case EIO:
-	fprintf(stderr,"%s\n", set_st_err_name(arg));
-        break;
-      }
-    return 20;
-  }
-  return 0;
-}
-
-
-int cmd_primary(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  drbd_role_t newstate=Primary;
-
-  if(argc > 0)
-    {
-      while(1)
-	{
-	  int c;
-
-	  PRINT_ARGV;
-	  /* --do-what-I-say have to be spelled out */
-	  c = getopt_long_only(argc,argv,make_optstring(options,'-'),options,0);
-	  if(c == -1) break;
-	  switch(c)
-	    {
-	    case 'o':
-	      if (strcmp("--overwrite-data-of-peer",argv[optind-1])) {
-		      fprintf(stderr,"%s\nYou have to spell out --overwrite-data-of-peer, if you mean it\n",
-				      argv[optind-1]);
-		      return 20;
-	      }
-	      newstate |= DontBlameDrbd;
-	      break;
-	    case 'd':
-	      fprintf(stderr,
-"--do-what-I-say was renamed to --overwrite-data-of-peer, since that is\n"
-"less ambiguous.\n"
-"Only do it if you really know what you are doing. DRBD is going to save\n"
-"this fact to its metadata, and it will really overwrite the peer's copy\n"
-"of data with the local copy.\n");
-	      return 20;
-	    case 1:	// non option argument. see getopt_long(3)
-	      fprintf(stderr,"%s: Unexpected nonoption argument '%s'\n",cmdname,optarg);
-	    case '?':
-	      return 20;
-	    }
-	}
-    }
-
-  return set_state(drbd_fd,newstate);
-}
-
-int cmd_secondary(int drbd_fd,char **argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  return set_state(drbd_fd,Secondary);
-}
-
-int wait_on(int drbd_fd,char** argv,int argc,int wfct,int dwfct, int req,
-	    struct option *options)
-{
-  int err;
-  struct ioctl_wait p;
-
-  p.wfc_timeout=wfct;
-  p.degr_wfc_timeout=dwfct;
-
-  if(argc > 0)
-    {
-      while(1)
-	{
-	  int c;
-
-	  PRINT_ARGV;
-	  c = getopt_long(argc,argv,make_optstring(options,'-'),options,0);
-	  if(c == -1) break;
-	  switch(c)
-	    {
-	    case 't':
-	      p.wfc_timeout = m_strtoll_range(optarg,1, "wfc-timeout",
-			      DRBD_WFC_TIMEOUT_MIN, DRBD_WFC_TIMEOUT_MAX);
-	      break;
-	    case 'd':
-	      p.degr_wfc_timeout = m_strtoll_range(optarg,1,
-			      "degr-wfc-timeout",
-			      DRBD_DEGR_WFC_TIMEOUT_MIN,
-			      DRBD_DEGR_WFC_TIMEOUT_MAX);
-	      break;
-	    case 1:	// non option argument. see getopt_long(3)
-	      fprintf(stderr,"%s: Unexpected nonoption argument '%s'\n",cmdname,optarg);
-	    case '?':
-	      return 20;
-	    }
-	}
-    }
-  err=ioctl(drbd_fd,req,&p);
-  if(errno == ETIME) exit(5);
-  if(err)
-    {
-      PERROR("ioctl(,WAIT_*,) failed");
-      exit(20);
-    }
-  return !p.ret_code;
-}
-
-int cmd_wait_connect(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  return wait_on(drbd_fd,argv,argc,
-		 DEF_WFC_TIMEOUT,
-		 DEF_DEGR_WFC_TIMEOUT,
-		 DRBD_IOCTL_WAIT_CONNECT,options);
-}
-
-int cmd_wait_sync(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  return wait_on(drbd_fd,argv,argc,
-		 DEF_SYNC_WFC_TIMEOUT,
-		 DEF_SYNC_DEGR_WFC_TIMEOUT,
-		 DRBD_IOCTL_WAIT_SYNC,options);
-}
-
-int cmd_syncer(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  struct ioctl_syncer_config cn;
-  int err;
-
-  /*
-  struct ioctl_get_config current_cn;
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&current_cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_CONFIG,) failed");
-      return 20;
-    }
-
-  cn.config.rate = current_cn.sconf.rate;
-  cn.config.after = current_cn.sconf.after;
-  cn.config.al_extents = current_cn.sconf.al_extents;
-  */
-  cn.config.rate = DEF_SYNC_RATE;
-  cn.config.after = DEF_SYNC_AFTER;
-  cn.config.al_extents = DEF_SYNC_AL_EXTENTS;
-
-
-  if(argc > 0)
-    {
-      while(1)
-	{
-	  int c;
-
-	  PRINT_ARGV;
-	  c = getopt_long(argc,argv,make_optstring(options,'-'),options,0);
-	  if(c == -1) break;
-	  switch(c)
-	    {
-	    case 'r':
-	      cn.config.rate=m_strtoll_range(optarg,'K', "rate",
-			      DRBD_RATE_MIN, DRBD_RATE_MAX);
-	      break;
-	    case 'a':
-	      cn.config.after=m_strtoll(optarg,1);
-	      break;
-	    case 'e':
-	      cn.config.al_extents=m_strtoll_range(optarg,1, "al-extents",
-			      DRBD_AL_EXTENTS_MIN, DRBD_AL_EXTENTS_MAX);
-	      break;
-	    case 1:	// non option argument. see getopt_long(3)
-	      fprintf(stderr,"%s: Unexpected nonoption argument '%s'\n",cmdname,optarg);
-	    case '?':
-	      return 20;
-	    }
-	}
-    }
-
-
-  if (cn.config.al_extents < 7)
-	cn.config.al_extents = 127;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_SET_SYNC_CONFIG,&cn);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,SET_SYNC_CONFIG,) failed");
-      if(err == EBADMSG) fprintf(stderr,"Sync-after cycle found!\n");
-      if(err == ERANGE) fprintf(stderr,"Sync-after to small or big.\n");
-      return 20;
-    }
-
-  return 0;
-}
-
-int cmd_pause_sync(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_PAUSE_SYNC);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,PAUSE_SYNC,) failed");
-      if(err == EINPROGRESS) fprintf(stderr,"Pause flag is already set!\n");
-      return 20;
-    }
-  return 0;
-}
-
-int cmd_resume_sync(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_RESUME_SYNC);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,RESUME_SYNC,) failed");
-      if(err == EINPROGRESS) fprintf(stderr,"Pause flag is not set!\n");
-      return 20;
-    }
-  return 0;
-}
-
-int cmd_invalidate(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_INVALIDATE);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,INVALIDATE,) failed");
-      if(err==EINPROGRESS)
-	fprintf(stderr,"Only in 'Connected' cstate possible.\n");
-      return 20;
-    }
-  return 0;
-}
-
-int cmd_invalidate_rem(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_INVALIDATE_REM);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,INVALIDATE_REM,) failed");
-      if(err==EINPROGRESS)
-	fprintf(stderr,"Only in 'Connected' cstate possible.\n");
-      return 20;
-    }
-  return 0;
-}
-
-int cmd_outdate(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-  int reason;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_OUTDATE_DISK,&reason);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,OUTDATE_DISK,) failed");
-      if(err==EIO) 
-	{
-	  fprintf(stderr,"%s\n",set_st_err_name(reason));
-	  if(reason == SS_NoUpToDateDisk) return 17;
-	}
-      return 20;
-    }
-  return 0;
-}
-
-int cmd_down(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  int err;
-  err = cmd_secondary(drbd_fd,argv,argc,options);
-  if (!err) err = cmd_disconnect(drbd_fd,argv,argc,options);
-  if (!err) err = cmd_detach(drbd_fd,argv,argc,options);
-  return err;
-}
-
-int cmd_detach(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_UNCONFIG_DISK);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,UNCONFIG_DISK,) failed");
-      if(err==EBUSY)
-	fprintf(stderr,"Not possible during resynchronisation.\n");
-      if(err==ENETRESET)
-	fprintf(stderr,"Not possible, since the device is in primary state\n"
-		"and not connected.\n");
-      if(err==ENODATA)
-	fprintf(stderr,"Not possible, since the device is in primary state\n"
-		"and has no local disk.\n");
-      if(err==ENXIO)
-	fprintf(stderr," - Do not shoot yourself in the foot. -\n"
-		"A system without backing storage is not possible.\n");
-      return 20;
-    }
-  return 0;
-}
-
-int cmd_disconnect(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_UNCONFIG_NET);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,UNCONFIG_NET,) failed");
-      if(err==ENXIO)
-	fprintf(stderr,"Device is not configured!\n");
-      return 20;
-    }
-  return 0;
-
-}
-
-int cmd_net_conf(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  struct ioctl_net_config cn;
-  int retval;
-
-  retval=scan_net_options(argv,argc,&cn,options);
-  if(retval) return retval;
-
-  return do_net_conf(drbd_fd,argv[5],argv[3],argv[4],&cn);
-}
-
-int cmd_disk_conf(int drbd_fd, char **argv, int argc, struct option *options)
-{
-  struct ioctl_disk_config cn;
-  int retval, mi = 0;
-
-  retval = scan_disk_options(argv, argc, &cn, options);
-  if (retval)
-    return retval;
-
-  if (argc == 5) {
-    /* short variant, index and other options omitted */
-    if (!strcmp("internal", argv[4])) {
-      mi = DRBD_MD_INDEX_FLEX_INT;
-    } else {
-      fprintf(stderr, "meta_index missing.\n");
-    }
-  } else {
-    /* index or any options given. check the index */
-    if (!strcmp("internal", argv[4])) {
-      /* in drbd8, internal is always flexible */
-      if (!strncmp("flex", argv[5], 4) ||
-	  !strcmp("-1", argv[5]) ||
-	  !strcmp("internal", argv[5]))
-      {
-	  mi = DRBD_MD_INDEX_FLEX_INT;
-      } else {
-	  fprintf(stderr, "invalid meta_index for 'internal'.\n");
-	  return 20;
-      }
-    } else {
-      if (!strncmp("flex", argv[5], 4)) {
-	  mi = DRBD_MD_INDEX_FLEX_EXT;
-      } else {
-	mi = m_strtoll(argv[5], 1);
-	if (mi < 0) {
-	  fprintf(stderr, "meta_index may not be negative.\n");
-	  return 20;
-	}
-      }
-    }
-  }
-  //FIXME check that mi*128M is not bigger than meta device!
-  cn.config.meta_index = mi;
-  return do_disk_conf(drbd_fd, argv[3], argv[4], &cn);
-}
-
-int cmd_disk_size(int drbd_fd,char** argv,int argc,struct option *options)
-{
-  __u64 u_size=0; // unit: sectors.
-  int err;
-
-  if(argc > 0)
-    {
-      while(1)
-	{
-	  int c;
-
-	  PRINT_ARGV;
-	  c = getopt_long(argc,argv,make_optstring(options,'-'),options,0);
-	  if(c == -1) break;
-	  switch(c)
-	    {
-	    case 'd':
-	      u_size=m_strtoll_range(optarg,'K', "size",
-			      DRBD_DISK_SIZE_SECT_MIN>>1,
-			      DRBD_DISK_SIZE_SECT_MAX>>1 ) << 1;
-	      break;
-	    case 1:	// non option argument. see getopt_long(3)
-	      fprintf(stderr,"%s: Unexpected nonoption argument '%s'\n",cmdname,optarg);
-	    case '?':
-	      return 20;
-	    }
-	}
-    }
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_SET_DISK_SIZE,u_size);
-  if(err)
-    {
-      PERROR("ioctl(,SET_DISK_SIZE,) failed");
-      if(err==EBUSY) {
-	fprintf(stderr,"Online resizing is not allowed during resync.");
-      }
-      if(err==EINPROGRESS) {
-	fprintf(stderr,"One node must be primary to do online resizing.");
-      }
-      return 20;
-    }
-
-  return 0;
-}
-
-const char* guess_dev_name(const char* dir,unsigned int g_major,unsigned int g_minor)
-{
-  DIR* device_dir;
-  struct dirent* dde;
-  struct stat sb;
-  static char dev_name[50];
-
-  device_dir=opendir(dir);
-
-  if(!device_dir) goto err_out;
-
-  while((dde=readdir(device_dir)))
-    {
-      snprintf(dev_name,50,"%s/%s",dir,dde->d_name);
-      if(stat(dev_name,&sb)) continue;
-
-      if(S_ISBLK(sb.st_mode))
-	{
-	  if (g_major == major(sb.st_rdev) &&
-	      g_minor == minor(sb.st_rdev) )
-	    {
-	      closedir(device_dir);
-	      return dev_name;
-	    }
-	}
-    }
-
-  rewinddir(device_dir);
-
-  while((dde=readdir(device_dir)))
-    {
-      snprintf(dev_name,50,"%s/%s",dir,dde->d_name);
-      if(stat(dev_name,&sb)) continue;
-
-      if(!strcmp(dde->d_name,".")) continue;
-      if(!strcmp(dde->d_name,"..")) continue;
-      if(!strcmp(dde->d_name,"fd")) continue;
-      if(!strcmp(dde->d_name,"shm")) continue;
-      if(S_ISLNK(sb.st_mode)) continue;
-
-      if(S_ISDIR(sb.st_mode))
-	{
-	  char subdir[50];
-
-	  if(snprintf(subdir,50,"%s/%s",dir,dde->d_name)==49)
-	    { /* recursion is too deep */
-	      strcpy(dev_name,"can not guess name");
-	      return dev_name;
-	    }
-
-	  if(guess_dev_name(subdir,g_major,g_minor)) return dev_name;
-	}
-    }
-
-  closedir(device_dir);
- err_out:
-  return NULL;
-}
-
-const char* check_dev_name(const char* dev_name , int major, int minor)
-{
-  // this is because the SmartArray (Compaq, HP, whatever...) driver
-  // returns a closing bracket in the device name...
-
-  if(!dev_name || !dev_name[0] || index(dev_name,')') )
-    {
-      dev_name = guess_dev_name("/dev",major,minor);
-    }
-  if(dev_name) return dev_name;
-  else return "n.a.";
-}
-
-int cmd_show(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  struct ioctl_get_config cn;
-  struct sockaddr_in *other_addr;
-  struct sockaddr_in *my_addr;
-  struct stat sb;
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_CONFIG,) failed");
-      return 20;
-    }
-
-#define SHOW_I(T,U,M,D) \
-printf("\t" T "\t%d",M); \
-if(M==D) printf(" _is_default"); \
-printf(";  \t# " U "\n")
-
-#define SHOW_IU(T,U1,U2,M,D) \
-printf("\t" T "\t%d"U1,M); \
-if(M==D) printf(" _is_default"); \
-printf(";  \t# " U2 "\n")
-
-#define SHOW_H(T,M,D,H) \
-printf("\t" T "\t%s",H[M]); \
-if(M==D) printf(" _is_default"); \
-printf(";\n")
-
-#define SHOW_S(T,M,D) \
-printf("\t" T "\t\"%s\"",M); \
-if(!strcmp(M,D)) printf(" _is_default"); \
-printf(";\n")
-
-  if( cn.state.disk == Diskless && cn.state.conn == StandAlone)
-    {
-      printf("# not configured.\n");
-    }
-
-  if( cn.state.disk > Diskless)
-    {
-      printf("disk {\n");
-      SHOW_H("on-io-error",cn.on_io_error,DEF_ON_IO_ERROR,eh_names);
-      SHOW_H("fencing\t",cn.fencing,DEF_FENCING,fencing_names);
-      if( cn.disk_size_user ) printf("\tsize\t%luK;\n",
-				     (unsigned long)cn.disk_size_user);
-      printf("}\n");
-    }
-
-  if( cn.state.conn > StandAlone)
-    {
-      printf("protocol %c;\n",'A'-1+cn.nconf.wire_protocol);
-      printf("net {\n");
-      SHOW_I("timeout\t","1/10 seconds",cn.nconf.timeout,DEF_NET_TIMEOUT);
-      SHOW_I("connect-int","seconds", cn.nconf.try_connect_int, DEF_NET_TRY_CON_I);
-      SHOW_I("ping-int","seconds", cn.nconf.ping_int, DEF_NET_PING_I);
-      SHOW_I("max-epoch-size","write requests", cn.nconf.max_epoch_size, DEF_MAX_EPOCH_SIZE);
-      SHOW_I("max-buffers","pages", cn.nconf.max_buffers, DEF_MAX_BUFFERS);
-      SHOW_I("unplug-watermark","write requests", cn.nconf.unplug_watermark, DEF_UNPLUG_WATERMARK);
-      SHOW_I("sndbuf-size","byte", cn.nconf.sndbuf_size, DEF_SNDBUF_SIZE);
-      SHOW_I("ko-count","1", cn.nconf.ko_count, DEF_KO_COUNT);
-      // SHOW_H("on-disconnect",cn.nconf.on_disconnect,DEF_ON_DISCONNECT,dh_names);
-      SHOW_H("after-sb-0pri",cn.nconf.after_sb_0p,DEF_AFTER_SB_0P,asb0p_names);
-      SHOW_H("after-sb-1pri",cn.nconf.after_sb_1p,DEF_AFTER_SB_0P,asb1p_names);
-      SHOW_H("after-sb-2pri",cn.nconf.after_sb_2p,DEF_AFTER_SB_0P,asb2p_names);
-      SHOW_S("cram-hmac-alg",cn.nconf.cram_hmac_alg,"");
-      SHOW_S("shared-secret",cn.nconf.shared_secret,"");
-      if( cn.nconf.two_primaries ) printf("\tallow-two-primaries;\n");
-      if( cn.nconf.want_lose ) printf("\tdiscard-my-data;\n");
-      printf("}\n");
-    }
-
-  if( cn.state.disk > Diskless || cn.state.conn > StandAlone)
-    {
-      printf("syncer {\n");
-      SHOW_IU("rate\t","K","(K)Byte/second", cn.sconf.rate, DEF_SYNC_RATE);
-      SHOW_I("after\t","minor", cn.sconf.after, DEF_SYNC_AFTER);
-      SHOW_I("al-extents","4MByte", cn.sconf.al_extents, DEF_SYNC_AL_EXTENTS);
-      printf("}\n");
-
-      err=fstat(drbd_fd,&sb);
-      if(err)
-	{
-	  PERROR("fstat() failed");
-	  return 20;
-	}
-      printf("_this_host {\n");
-      printf("\tdevice\t\t\"/dev/drbd%d\";\n",minor(sb.st_rdev));
-      printf("\tdisk\t\t\"/dev/%s\" _major %d _minor %d;\n",
-	     check_dev_name(cn.lower_device_name,cn.lower_device_major,
-			    cn.lower_device_minor),
-	     cn.lower_device_major,
-	     cn.lower_device_minor);
-
-      if( cn.lower_device_major == cn.meta_device_major && 
-	  cn.lower_device_minor == cn.meta_device_minor ) {
-	printf("\tmeta-disk\tinternal;\n");
-      } else {
-	if( cn.meta_index == DRBD_MD_INDEX_FLEX_EXT ) {
-  	  printf("\tflexible-meta-disk\t\"%s\" _major %d _minor %d;\n",
-		 check_dev_name(cn.meta_device_name,cn.meta_device_major,
-				cn.meta_device_minor),
-		 cn.meta_device_major,
-		 cn.meta_device_minor);
-	} else {
-  	  printf("\tmeta-disk\t\"%s\" [%d] _major %d _minor %d;\n",
-		 check_dev_name(cn.meta_device_name,cn.meta_device_major,
-				cn.meta_device_minor),
-		 cn.meta_index,
-		 cn.meta_device_major,
-		 cn.meta_device_minor);
-	}
-      }
-
-      if( cn.state.conn > StandAlone) {
-	my_addr = (struct sockaddr_in *)cn.nconf.my_addr;
-	printf("\taddress\t\t%s:%d;\n",
-	       inet_ntoa(my_addr->sin_addr),
-	       ntohs(my_addr->sin_port));
-      }
-      printf("}\n");
-    }
-
-  if( cn.state.conn > StandAlone)
-    {
-      other_addr = (struct sockaddr_in *)cn.nconf.other_addr;
-      printf("_remote_host {\n");
-      printf("\taddress\t%s:%d;\n",
-	     inet_ntoa(other_addr->sin_addr),
-	     ntohs(other_addr->sin_port));
-      printf("}\n");
-    }
-
-  return 0;
-}
-
-int cmd_state(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  struct ioctl_get_config cn;
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_CONFIG,) failed");
-      return 20;
-    }
-
-  if( cn.state.conn == StandAlone && cn.state.disk == Diskless)
-    {
-      fprintf(stderr,"Not configured\n");
-      return 10;
-    }
-
-  printf("%s/%s\n",roles_to_name(cn.state.role),
-	 roles_to_name(cn.state.peer));
-
-  return 0;
-}
-
-int cmd_cstate(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  struct ioctl_get_config cn;
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_CONFIG,) failed");
-      return 20;
-    }
-
-  if( cn.state.conn == StandAlone && cn.state.disk == Diskless)
-    {
-      fprintf(stderr,"Not configured\n");
-      return 10;
-    }
-
-  printf("%s\n",conns_to_name(cn.state.conn));
-
-  return 0;
-}
-
-int cmd_dstate(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  struct ioctl_get_config cn;
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_CONFIG,&cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_CONFIG,) failed");
-      return 20;
-    }
-
-  if( cn.state.conn == StandAlone && cn.state.disk == Diskless)
-    {
-      fprintf(stderr,"Not configured\n");
-      return 10;
-    }
-
-  printf("%s/%s\n",disks_to_name(cn.state.disk),disks_to_name(cn.state.pdsk));
-
-  return 0;
-}
-
-int cmd_get_gi(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  struct ioctl_get_uuids cn;
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_UUIDS,&cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_GEN_UUIDS,) failed");
-      return 20;
-    }
-  
-  dt_print_uuids(cn.uuid, cn.flags);
-
-  return 0;
-}
-
-int cmd_show_gi(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  struct ioctl_get_uuids cn;
-  char ppb[10];
-  int err;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_GET_UUIDS,&cn);
-  if(err)
-    {
-      PERROR("ioctl(,GET_GEN_UUIDS,) failed");
-      return 20;
-    }
-  
-  dt_pretty_print_uuids(cn.uuid, cn.flags);
-
-  printf("current agreed size: %s\n", ppsize(ppb, cn.current_size >> 1));
-  printf("%u bits set in the bitmap [ %s out of sync ]\n",
-	 cn.bits_set, ppsize(ppb, cn.bits_set * 4));
-
-  return 0;
-}
-
-int cmd_suspend_io(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-  int reason;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_SUSPEND_IO, &reason);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,DRBD_IOCTL_SUSPEND_IO) failed");
-      if(err==EIO) 
-	{
-	  fprintf(stderr,"%s\n",set_st_err_name(reason));
-	}
-      return 20;
-    }
-  
-  return 0;
-}
-
-int cmd_resume_io(int drbd_fd,char** argv __attribute((unused)),int argc __attribute((unused)),struct option *options __attribute((unused)))
-{
-  int err;
-  int reason;
-
-  err=ioctl(drbd_fd,DRBD_IOCTL_RESUME_IO, &reason);
-  if(err)
-    {
-      err=errno;
-      PERROR("ioctl(,DRBD_IOCTL_RESUME_IO) failed");
-      if(err==EIO) 
-	{
-	  fprintf(stderr,"%s\n",set_st_err_name(reason));
-	}
-      return 20;
-    }
-  
-  return 0;
-}
-
-int main(int argc, char** argv)
-{
-  int drbd_fd;
-  int num_of_args;
-  int help = 0;
-  int err;
-  size_t i;
-  char **args;
-
-  if ( (cmdname = strrchr(argv[0],'/')) )
-      argv[0] = ++cmdname;
-  else
-      cmdname = argv[0];
-
-  /* == '-' catches -h, --help, and similar */
-  if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-'))
-	  help = 1;
-  if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
-
-  chdir("/");
-
-  for(i=0;i<ARRY_SIZE(commands);i++)
-    {
-      if(strcmp(argv[2],commands[i].cmd)==0)
-	{
-	  num_of_args=0;
-	  if((args=commands[i].args))
-	    {
-	      while(*args++) num_of_args++;
-	    }
-	  if (0 == strcmp(argv[2],"disk") && (argc == 5) &&
-	      0 == strcmp(argv[4],"internal") ) {
-	      --num_of_args;
-	      /* don't require that stupid "-1" */
-	  }
-	  if (help || argc-3 < num_of_args)
-	      print_command_usage(i,help?"":"Not enough arguments.");
-	  if (argc-3-num_of_args>0 && commands[i].options==0)
-	    {
-	      fprintf(stderr,"Too many arguments or options.\n");
-	      return 20;
-	    }
-
-	  if (strncmp ("/dev/drbd", argv[1], 9))
-	    {
-	      fprintf (stderr,
-		       "  | NOTE: we now have officially asigned"
-		       " device name and major number.\n"
-		       "  | Please use /dev/drbd*; if neccessary"
-		       " create the device nodes first.\n"
-		       "  | To do so: for i in `seq 0 15` ;"
-		       " do mknod -m 0660 /dev/drbd$i b 147 $i; done\n");
-	    }
-	  drbd_fd=open_drbd_device(argv[1]);
-
-	  opterr = 1; /* let getopt() print error messages */
-	  optind = 3+num_of_args;
-	  err =  commands[i].function(drbd_fd,argv,argc,
-				      commands[i].options);
-	  close(drbd_fd); // explicit close on drbd device!
-	  return err;
-	}
-    }
-  fprintf(stderr,"%s is not a command\n",argv[2]);
-  return 20;
-}

Modified: trunk/user/drbdsetup_nl.c
===================================================================
--- trunk/user/drbdsetup_nl.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbdsetup_nl.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -28,29 +28,40 @@
 
 #define _GNU_SOURCE
 
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <mntent.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/poll.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+
+#include <linux/netlink.h>
+#include <linux/connector.h>
+
 #include <linux/drbd.h>
 #include <linux/drbd_config.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <mntent.h>
+#include <linux/drbd_tag_magic.h>
+#include <linux/drbd_limits.h>
+
 #include "drbdtool_common.h"
-#include "drbd_limits.h"
-#include "drbd_tag_magic.h"
 
+
+
 struct drbd_tag_list {
+	struct nlmsghdr *nl_header;
+	struct cn_msg   *cn_header;
+	struct drbd_nl_cfg_req* drbd_p_header;
 	unsigned short *tag_list_start;
 	unsigned short *tag_list_cpos;
 	int    tag_size;
@@ -71,6 +82,7 @@
 	int (*convert_function)(struct drbd_option *,
 				struct drbd_tag_list *,
 				char *);
+	void (*show_function)(struct drbd_option *,unsigned short*);
 	union {
 		struct {
 			const unsigned long long min;
@@ -81,6 +93,7 @@
 		struct {
 			const char** handler_names;
 			const int number_of_handlers;
+			const int def;
 		} handler_param;
 	};
 };
@@ -88,12 +101,41 @@
 struct drbd_cmd {
 	const char* cmd;
 	const int packet_id;
-	int (*function)(struct drbd_cmd *, int, char **);
+	int (*function)(struct drbd_cmd *, int, int, char **);
 	struct drbd_argument *args;
 	struct drbd_option *options;
 };
 
 
+// Connector functions
+int open_cn();
+int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size);
+int send_tag_list_cn(int, struct drbd_tag_list *, const int, int, int);
+int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size);
+void close_cn(int sk_nl);
+
+// other functions
+void print_command_usage(int i, const char *addinfo);
+// command functions
+int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+// convert functions for arguments
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+// convert functions for options
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+// show functions for options
+void show_numeric(struct drbd_option *od, unsigned short* tp);
+void show_handler(struct drbd_option *od, unsigned short* tp);
+void show_bit(struct drbd_option *od, unsigned short* tp);
+void show_string(struct drbd_option *od, unsigned short* tp);
+
+
 const char *on_error[] = {
 	[PassOn] = "pass_on",
 	[Panic]  = "panic",
@@ -127,35 +169,21 @@
 	[PanicPrimary]      = "panic"
 };
 
-// other functions
-void print_command_usage(int i, const char *addinfo);
-// command functions
-int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv);
-// convert functions for arguments
-int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-// convert functions for options
-int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-
 #define EN(N) \
-	conv_numeric, { .numeric_param = { N ## _min, N ## _max, N ## _default } }
-#define EN0 	conv_numeric, { .numeric_param = { 0, -1, 0, 0 } }
-#define EH(N) \
-	conv_handler, { .handler_param = { N, ARRY_SIZE(N) } }
-#define EB      conv_bit, { } 
+	conv_numeric, show_numeric, \
+	{ .numeric_param = { DRBD_ ## N ## _MIN, DRBD_ ## N ## _MAX, \
+		DRBD_ ## N ## _DEF ,0  } }
+#define EH(N,D) \
+	conv_handler, show_handler, { .handler_param = { N, ARRY_SIZE(N), \
+	DRBD_ ## D ## _DEF } }
+#define EB      conv_bit, show_bit, { } 
+#define ES      conv_string, show_string, { } 
 
-
-
-
 struct drbd_cmd commands[] = {
 	{"primary", P_primary, generic_config_cmd, NULL,
 	 (struct drbd_option[]) {
-		 { "overwrite-data-of-peer",'o',T_disk_size, EB	     },
-		 { NULL,0,0,NULL, { } }, }, },
+		 { "overwrite-data-of-peer",'o',T_overwrite_peer, EB   },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"secondary", P_secondary, generic_config_cmd, NULL, NULL },
 
@@ -166,10 +194,10 @@
 		 { "meta_data_index",	T_meta_dev_idx,	conv_md_idx },
 		 { NULL,                0,           	NULL}, },
 	 (struct drbd_option[]) {
-		 { "size",'d',		T_disk_size,	EN0 },
-		 { "on-io-error",'e',	T_on_io_error,	EH(on_error) },
-		 { "fencing",'f',	T_fencing,	EH(fencing_n) },
-		 { NULL,0,0,NULL, { } }, }, },
+		 { "size",'d',		T_disk_size,	EN(DISK_SIZE_SECT) },
+		 { "on-io-error",'e',	T_on_io_error,	EH(on_error,ON_IO_ERROR) },
+		 { "fencing",'f',	T_fencing,      EH(fencing_n,FENCING) },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"detach", P_detach, generic_config_cmd, NULL, NULL },
 
@@ -180,36 +208,36 @@
 		 { "protocol",		T_wire_protocol,conv_protocol },
  		 { NULL,                0,           	NULL}, },
 	 (struct drbd_option[]) {
-		 { "timeout",'t',	T_timeout,	EN0 },
-		 { "max-epoch-size",'e',T_max_epoch_size,EN0 },
-		 { "max-buffers",'b',	T_max_buffers,	EN0 },
-		 { "unplug-watermark",'u',T_unplug_watermark, EN0 },
-		 { "connect-int",'c',	T_try_connect_int, EN0 },
-		 { "ping-int",'i',	T_ping_int,	   EN0 },
-		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN0 },
-		 { "ko-count",'k',	T_ko_count,	   EN0 },
+		 { "timeout",'t',	T_timeout,	EN(TIMEOUT) },
+		 { "max-epoch-size",'e',T_max_epoch_size,EN(MAX_EPOCH_SIZE) },
+		 { "max-buffers",'b',	T_max_buffers,	EN(MAX_BUFFERS) },
+		 { "unplug-watermark",'u',T_unplug_watermark, EN(UNPLUG_WATERMARK) },
+		 { "connect-int",'c',	T_try_connect_int, EN(CONNECT_INT) },
+		 { "ping-int",'i',	T_ping_int,	   EN(PING_INT) },
+		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN(SNDBUF_SIZE) },
+		 { "ko-count",'k',	T_ko_count,	   EN(KO_COUNT) },
 		 { "allow-two-primaries",'m',T_two_primaries, EB },
-		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   EN0 },
-		 { "shared-secret",'x',	T_shared_secret,   EN0 },
-		 { "after-sb-0pri",'A',	T_after_sb_0p,     EH(asb0p_n) },
-		 { "after-sb-1pri",'B',	T_after_sb_1p,     EH(asb1p_n) },
-		 { "after-sb-2pri",'C',	T_after_sb_2p,     EH(asb2p_n) },
+		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   ES },
+		 { "shared-secret",'x',	T_shared_secret,   ES },
+		 { "after-sb-0pri",'A',	T_after_sb_0p,EH(asb0p_n,AFTER_SB_0P) },
+		 { "after-sb-1pri",'B',	T_after_sb_1p,EH(asb1p_n,AFTER_SB_1P) },
+		 { "after-sb-2pri",'C',	T_after_sb_2p,EH(asb2p_n,AFTER_SB_2P) },
 		 { "discard-my-data",'D', T_want_lose,     EB },
-		 { NULL,0,0,NULL, { } }, }, },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"disconnect", P_disconnect, generic_config_cmd, NULL, NULL },
 
 	{"resize", P_resize, generic_config_cmd, NULL,
 	 (struct drbd_option[]) {
-		 { "size",'s',T_resize_size,		EN0 },
-		 { NULL,0,0,NULL, { } }, }, },
+		 { "size",'s',T_resize_size,		EN(DISK_SIZE_SECT) },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"syncer", P_syncer_conf, generic_config_cmd, NULL,
 	 (struct drbd_option[]) {
-		 { "rate",'r',T_sync_rate,		EN0 },
-		 { "after",'a',T_sync_after,		EN0 },
-		 { "al-extents",'e',T_al_extents,	EN0 },
-		 { NULL,0,0,NULL, { } }, }, },
+		 { "rate",'r',T_rate,			EN(RATE) },
+		 { "after",'a',T_after,			EN(AFTER) },
+		 { "al-extents",'e',T_al_extents,	EN(AL_EXTENTS) },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"invalidate", P_invalidate, generic_config_cmd, NULL, NULL },
 	{"invalidate-remote", P_invalidate_peer, generic_config_cmd, NULL, NULL },
@@ -226,28 +254,80 @@
 	{"cstate", cmd_cstate,             0, 0, },
 	{"dstate", cmd_dstate,             0, 0, },
 	{"show-gi", cmd_show_gi,           0, 0, },
-	{"get-gi", cmd_get_gi,             0, 0, },
-	{"show", cmd_show,                 0, 0, },
-	*/
+	{"get-gi", cmd_get_gi,             0, 0, }, */
+	{"show", P_get_config, show_cmd, NULL, NULL },
 };
 
+#define EM(C) [ C - RetCodeBase ]
+
+static const char *error_messages[] = {
+	EM(NoError) = "No further Information available.",
+	EM(LAAlreadyInUse) = "Local address(port) already in use.",
+	EM(OAAlreadyInUse) = "Remote address(port) already in use.",
+	EM(LDNameInvalid) = "Can not open backing device.",
+	EM(MDNameInvalid) = "Can not open meta device.",
+	EM(LDAlreadyInUse) = "Lower device already in use.",
+	EM(LDNoBlockDev) = "Lower device is not a block device.",
+	EM(MDNoBlockDev) = "Meta device is not a block device.",
+	EM(LDOpenFailed) = "Open of lower device failed.",
+	EM(MDOpenFailed) = "Open of meta device failed.",
+	EM(LDDeviceTooSmall) = "Low.dev. smaller than requested DRBD-dev. size.",
+	EM(MDDeviceTooSmall) = "Meta device too small.",
+	EM(LDNoConfig) = "You have to use the disk command first.",
+	EM(LDMounted) = "Lower device is already mounted.",
+	EM(MDMounted) = "Meta device is already mounted.",
+	EM(LDMDInvalid) = "Lower device / meta device / index combination invalid.",
+	EM(LDDeviceTooLarge) = "Currently we only support devices up to 3.998TB.\n"
+	"(up to 2TB in case you do not have CONFIG_LBD set)"
+	"Contact office@linbit.com, if you need more.",
+	EM(MDIOError) = "IO error(s) orruced during initial access to meta-data.\n",
+	EM(MDInvalid) = "No valid meta-data signature found.\n)"
+	"Use 'drbdadm create-md res' to initialize meta-data area.\n",
+	EM(CRAMAlgNotAvail) = "The 'cram-hmac-alg' you specified is not known in )"
+	"the kernel.\n",
+	EM(CRAMAlgNotDigest) = "The 'cram-hmac-alg' you specified is not a digest.",
+	EM(KMallocFailed) = "kmalloc() failed. Out of memory?",
+	EM(DiscardNotAllowed) = "--discard-my-data not allowed when primary.",
+	EM(HaveDiskConfig) = "HaveDiskConfig",
+	EM(UnknownMandatoryTag) = "UnknownMandatoryTag",
+	EM(MinorNotKnown) = "MinorNotKnown",
+	EM(StateNotAllowed) = "StateNotAllowed",
+	EM(GotSignal) = "GotSignal",
+	EM(NoResizeDuringResync) = "Resize not allowed during resync.",
+	EM(APrimaryNodeNeeded) = "Need the a primary node to resize.",
+	EM(SyncAfterInvalid) = "The sync after minor number is invalid",
+	EM(SyncAfterCycle-) = "This would cause a sync-after dependency cycle",
+	EM(PauseFlagAlreadySet) = "PauseFlagAlreadySet",
+	EM(PauseFlagAlreadyClear) = "PauseFlagAlreadyClear",
+	EM(DiskLowerThanOutdated) = "DiskLowerThanOutdated",
+	EM(FailedToClaimMyself) = "FailedToClaimMyself",
+};
+
 char* cmdname = 0;
 
-void dump_tag_list(struct drbd_tag_list *tl)
+int dump_tag_list(unsigned short *tlc)
 {
-	unsigned short *tlc = tl->tag_list_start;
 	enum drbd_tags tag;
+	unsigned int tag_nr;
 	int len;
 	int integer;
 	char bit;
 	__u64 int64;
 	char* string;
+	int found_unknown=0;
 
-	while(*tlc != TT_END) {
-		tag = *tlc++;
-		printf("(%2d) %16s = ",tag_number(tag),
-		       tag_descriptions[tag_number(tag)].name);
+	while( (tag = *tlc++ ) != TT_END) {
 		len = *tlc++;
+		if(tag == TT_REMOVED) goto skip;
+
+		tag_nr = tag_number(tag);
+		if(tag_nr<ARRY_SIZE(tag_descriptions)) {
+			string = tag_descriptions[tag_nr].name;
+		} else {
+			string = "unknown tag";
+			found_unknown=1;
+		}
+		printf("# (%2d) %16s = ",tag_nr,string);
 		switch(tag_type(tag)) {
 		case TT_INTEGER: 
 			integer = *(int*)tlc;
@@ -267,16 +347,24 @@
 			break;
 		}
 		printf(" \t[len: %u]\n",len);
+	skip:
 		tlc = (unsigned short*)((char*)tlc + len);
 	}
+
+	return found_unknown;
 }
 
 struct drbd_tag_list *create_tag_list(int size)
 {
 	struct drbd_tag_list *tl;
-
+	
 	tl = malloc(sizeof(struct drbd_tag_list));
-	tl->tag_list_start = malloc(size);
+	tl->nl_header  = malloc(NLMSG_SPACE( sizeof(struct cn_msg) +
+					     sizeof(struct drbd_nl_cfg_req) + 
+					     size) );
+	tl->cn_header = NLMSG_DATA(tl->nl_header);
+	tl->drbd_p_header = (struct drbd_nl_cfg_req*) tl->cn_header->data;
+	tl->tag_list_start = tl->drbd_p_header->tag_list;
 	tl->tag_list_cpos = tl->tag_list_start;
 	tl->tag_size = size;
 
@@ -298,7 +386,7 @@
 
 void free_tag_list(struct drbd_tag_list *tl)
 {
-	free(tl->tag_list_start);
+	free(tl->nl_header);
 	free(tl);
 }
 
@@ -322,8 +410,10 @@
 		fprintf(stderr, "%s is not a block device!\n", arg);
 		return 20;
 	}
+	
+	close(device_fd);
 
-	add_tag(tl,ad->tag,&device_fd,sizeof(device_fd));
+	add_tag(tl,ad->tag,arg,strlen(arg)+1); // include the null byte. 
 
 	return 0;
 }
@@ -391,18 +481,7 @@
 	addr.sin_family = AF_INET;
 	addr.sin_addr.s_addr = resolv(addr_part(arg));
 
-	switch(ad->tag) {
-	case T_my_addr:
-		add_tag(tl,T_my_addr,&addr,addr_len);
-		add_tag(tl,T_my_addr_len,&addr_len,sizeof(addr_len));
-		break;
-	case T_peer_addr:
-		add_tag(tl,T_peer_addr,&addr,addr_len);
-		add_tag(tl,T_peer_addr_len,&addr_len,sizeof(addr_len));
-		break;
-	default:
-		fprintf(stderr, "internal error in conv_address()\n");
-	}
+	add_tag(tl,ad->tag,&addr,addr_len);
 
 	return 0;
 }
@@ -445,7 +524,6 @@
 	int i;
 	char unit[] = {0,0};
 
-
 	l = m_strtoll(arg, default_unit);
 
 	if (min > l || l > max) {
@@ -488,12 +566,19 @@
 	return 0;
 }
 
+int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	add_tag(tl,od->tag,arg,strlen(arg)+1);
+
+	return 0;
+}
+
 struct option *	make_longoptions(struct drbd_option* od)
 {
 	static struct option buffer[20];
 	int i=0;
 
-	while(od->name) {
+	while(od && od->name) {
 		buffer[i].name = od->name;
 		buffer[i].has_arg = tag_type(od->tag) == TT_BIT ? 
 			no_argument : required_argument ;
@@ -504,6 +589,20 @@
 		}
 		od++;
 	}
+	
+	// The two omnipresent options:
+	buffer[i].name = "set-defaults";
+	buffer[i].has_arg = 0;
+	buffer[i].flag = NULL;
+	buffer[i].val = '(';
+	i++;
+
+	buffer[i].name = "create-device";
+	buffer[i].has_arg = 0;
+	buffer[i].flag = NULL;
+	buffer[i].val = ')';
+	i++;
+
 	buffer[i].name = NULL;
 	buffer[i].has_arg = 0;
 	buffer[i].flag = NULL;
@@ -522,17 +621,44 @@
 	return NULL;
 }
 
-int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv)
+void print_config_error( struct drbd_nl_cfg_reply *reply)
 {
+	int err_no = reply->ret_code;
+
+	if (err_no == NoError) return;
+	if (err_no == SS_Success) return;
+
+	if ( ( err_no >= AfterLastRetCode || err_no <= RetCodeBase ) &&
+	     ( err_no > SS_TowPrimaries || err_no < SS_CW_FailedByPeer) ) {
+		fprintf(stderr,"Error code %d unknown.\n"
+			"You should updated the drbd userland tools.\n",err_no);
+	} else {
+		if(err_no > RetCodeBase ) {
+			fprintf(stderr,"Failure: (%d) %s\n",err_no,
+				error_messages[err_no-RetCodeBase]);
+		} else {
+			fprintf(stderr,"State change failed: (%d) %s\n",
+				err_no, set_st_err_name(err_no));
+		}
+	}
+}
+
+#define RCV_SIZE NLMSG_SPACE(sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply))
+
+int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
+{
+	char buffer[ RCV_SIZE ];
+	struct drbd_nl_cfg_reply *reply;
 	struct drbd_argument *ad = cm->args;
 	struct drbd_option *od;
 	static struct option *lo;
 	struct drbd_tag_list *tl;
-	int c,i=0,rv=0;
+	int c,i=0,rv=0,sk_nl;
+	int flags=0;
 
 	tl = create_tag_list(4096);
 
-	while(ad->name) {
+	while(ad && ad->name) {
 		if(argc < i+1) {
 			fprintf(stderr,"Missing argument '%s'\n", ad->name);
 			print_command_usage(cm-commands, "");
@@ -545,23 +671,245 @@
 	}
 
 	lo = make_longoptions(cm->options);
+	opterr=0;
 	while( (c=getopt_long(argc,argv,make_optstring(lo,0),lo,0)) != -1 ) {
 		od = find_opt_by_short_name(cm->options,c);
 		if(od) rv |= od->convert_function(od,tl,optarg);
 		else {
-			fprintf(stderr,"opt for short '%c' (%d) not found\n",
-				c,c);
-			rv=20;			
+			if(c=='(') flags |= DRBD_NL_SET_DEFAULTS;
+			else if(c==')') flags |= DRBD_NL_CREATE_DEVICE;
+			else {
+				fprintf(stderr,
+					"%s: unrecognized option '%s'\n",
+					cmdname, argv[optind-1]);
+				rv=20;
+			}
 		}
 		if(rv) break;
 	}
 
-	if(rv == 0) dump_tag_list(tl);
+	add_tag(tl,TT_END,NULL,0); // close the tag list
+
+	if(rv == 0) {
+		// dump_tag_list(tl->tag_list_start);
+		sk_nl = open_cn();
+		if(sk_nl < 0) return 20;
+
+		send_tag_list_cn(sk_nl,tl,cm->packet_id,minor,flags);
+
+		receive_cn(sk_nl, (struct nlmsghdr*)buffer, RCV_SIZE );
+		close_cn(sk_nl);
+		reply = (struct drbd_nl_cfg_reply *)
+			((struct cn_msg *)NLMSG_DATA(buffer))->data;
+		print_config_error(reply);
+	}
 	free_tag_list(tl);
 
 	return rv;
 }
 
+#define ASSERT(exp) if (!(exp)) \
+		fprintf(stderr,"ASSERT( " #exp " ) in %s:%d\n", __FILE__,__LINE__);
+
+void show_numeric(struct drbd_option *od, unsigned short* tp)
+{
+	long long val;
+
+	switch(tag_type(*tp++)) {
+	case TT_INTEGER: 
+		ASSERT( *tp++ == sizeof(int) );
+		val = *(int*)tp;
+		break;
+	case TT_INT64:
+		ASSERT( *tp++ == sizeof(__u64) );
+		val = *(__u64*)tp;
+		break;
+	default: 
+		ASSERT(0);
+		val=0;
+	}
+
+	printf("\t%s\t\t%lld",od->name,val);
+	if(val == (long long) od->numeric_param.def) printf(" _is_default");
+	printf(";\n");
+}
+
+void show_handler(struct drbd_option *od, unsigned short* tp)
+{
+	const char** handler_names = od->handler_param.handler_names;
+	int i;
+
+	ASSERT( tag_type(*tp++) == TT_INTEGER );
+	ASSERT( *tp++ == sizeof(int) );
+	i = *(int*)tp;
+	printf("\t%s\t\t%s",od->name,handler_names[i]);
+	if( i == (long long)od->numeric_param.def) printf(" _is_default");
+	printf(";\n");
+}
+
+void show_bit(struct drbd_option *od, unsigned short* tp)
+{
+	ASSERT( tag_type(*tp++) == TT_BIT );
+	ASSERT( *tp++ == sizeof(char) );
+	if(*(char*)tp) printf("\t%s;\n",od->name);
+}
+
+void show_string(struct drbd_option *od, unsigned short* tp)
+{
+	ASSERT( tag_type(*tp++) == TT_STRING );
+	if( *tp++ > 0) printf("\t%s\t\t\"%s\";\n",od->name,(char*)tp);
+}
+
+unsigned short *look_for_tag(unsigned short *tlc, unsigned short tag)
+{
+	enum drbd_tags t;
+	int len;
+
+	while( (t = *tlc) != TT_END ) {
+		if(t == tag) return tlc;
+		tlc++;
+		len = *tlc++;
+		tlc = (unsigned short*)((char*)tlc + len);
+	}
+	return NULL;
+}
+
+void print_options(struct drbd_option *od, unsigned short *tlc, const char* sect_name)
+{
+	unsigned short *tp;
+	int opened = 0;
+
+	while(od->name) {
+		tp = look_for_tag(tlc,od->tag);
+		if(tp) {
+			if(!opened) {
+				opened=1;
+				printf("%s {\n",sect_name);
+			}
+			od->show_function(od,tp);
+			*tp = TT_REMOVED;
+		}
+		od++;
+	}
+	if(opened) {
+		printf("}\n");
+	}
+}
+
+char* consume_tag_string(enum drbd_tags tag, unsigned short *tlc)
+{
+	unsigned short *tp;
+	tp = look_for_tag(tlc,tag);
+	if(tp) {
+		*tp++ = TT_REMOVED;
+		if( *tp++ > 0) return (char*)tp;
+	}
+	return "";
+}
+
+int consume_tag_int(enum drbd_tags tag, unsigned short *tlc)
+{
+	unsigned short *tp;
+	tp = look_for_tag(tlc,tag);
+	if(tp) {
+		*tp++ = TT_REMOVED;
+		tp++;
+		return *(int *)tp;
+	}
+	return 0;
+}
+
+int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
+{
+	char buffer[ 4096 ];
+	struct drbd_tag_list *tl;
+	struct drbd_nl_cfg_reply *reply;
+	struct sockaddr_in *addr;
+	int sk_nl;
+	unsigned short *rtl;
+
+	int idx;
+	char* str;
+
+	ASSERT(cm->packet_id == P_get_config);
+
+	if(argc > 1) {
+		fprintf(stderr,"Ignoring excess arguments\n");
+	
+	}
+
+	tl = create_tag_list(2);
+	add_tag(tl,TT_END,NULL,0); // close the tag list
+
+	sk_nl = open_cn();
+	if(sk_nl < 0) return 20;
+
+	send_tag_list_cn(sk_nl,tl,cm->packet_id,minor,0);
+
+	receive_cn(sk_nl, (struct nlmsghdr*)buffer, 4096 );
+	close_cn(sk_nl);
+	reply = (struct drbd_nl_cfg_reply *)
+		((struct cn_msg *)NLMSG_DATA(buffer))->data;
+
+	rtl = reply->tag_list;
+
+	// find all commands that have options and print those...
+	for ( cm = commands ; cm < commands + ARRY_SIZE(commands) ; cm++ ) {
+		if(cm->options)
+			print_options(cm->options, rtl, cm->cmd);
+	}
+
+	// start of spagethi code...
+	idx = consume_tag_int(T_wire_protocol,rtl);
+	if(idx) printf("protocol %c;\n",'A'+idx-1);
+	str = consume_tag_string(T_backing_dev,rtl);
+	if(str) {
+		printf("_this_host {\n");
+		printf("\tdevice\t\t\"/dev/drbd%d\";\n",minor);
+		printf("\tdisk\t\t\"%s\";\n",str);
+		idx=consume_tag_int(T_meta_dev_idx,rtl);
+		switch(idx) {
+		case DRBD_MD_INDEX_INTERNAL:
+		case DRBD_MD_INDEX_FLEX_INT:
+			printf("\tmeta-disk\tinternal;\n");
+			consume_tag_string(T_meta_dev,rtl);
+			break;
+		case DRBD_MD_INDEX_FLEX_EXT:
+			printf("\tflexible-meta-disk\t\"%s\";\n",
+			       consume_tag_string(T_meta_dev,rtl));
+			break;
+		default:
+			printf("\tmeta-disk\t\"%s\" [ %d ];\n",
+			       consume_tag_string(T_meta_dev,rtl),idx);
+		}
+		str = consume_tag_string(T_my_addr,rtl);
+		if(str) {
+			addr = (struct sockaddr_in *)str;
+			printf("\taddress\t\t%s:%d;\n",
+			       inet_ntoa(addr->sin_addr),
+			       ntohs(addr->sin_port));
+		}
+		printf("}\n");
+	}
+
+	str = consume_tag_string(T_peer_addr,rtl);
+	if(str) {
+		printf("_remote_host {\n");
+		addr = (struct sockaddr_in *)str;
+		printf("\taddress\t\t%s:%d;\n",
+		       inet_ntoa(addr->sin_addr),
+		       ntohs(addr->sin_port));
+		printf("}\n");
+	}
+
+	if(dump_tag_list(reply->tag_list)) {
+		printf("# Found unknown tags, you should update your\n"
+		       "# userland tools\n");
+	}
+
+	return 0;
+}
+
 void print_command_usage(int i, const char *addinfo)
     // CAUTION no range check for i
 {
@@ -641,6 +989,8 @@
 	for (i = 0; i < ARRY_SIZE(commands); i++)
 		print_command_usage(i, 0);
 
+	printf("\nGeneral options: --create-device, --set-defaults\n");
+
 	print_handler("\non-io-error handlers:",on_error,ARRY_SIZE(on_error));
 	print_handler("\nfencing policies:",fencing_n,ARRY_SIZE(fencing_n));
 	print_handler("\nafter-sb-0pri handler:",asb0p_n,ARRY_SIZE(asb0p_n));
@@ -658,11 +1008,100 @@
 	exit(20);
 }
 
+int open_cn()
+{
+	int sk_nl;
+	int err;
+	struct sockaddr_nl my_nla;
+
+	sk_nl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+	if (sk_nl == -1) {
+		perror("socket() failed");
+		return -1;
+	}
+
+	my_nla.nl_family = AF_NETLINK;
+	my_nla.nl_groups = -1; //CN_IDX_DRBD; 
+	my_nla.nl_pid = getpid();
+
+	err = bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla));
+	if (err == -1) {
+		err = errno;
+		perror("bind() failed");
+		if(err == ENOENT) {
+			fprintf(stderr,"DRBD driver not present in the kernel?\n");
+		}
+		return -1;
+	}
+
+	return sk_nl;
+}
+
+
+int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size)
+{
+	struct cn_msg *cn_hdr;
+	cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
+	int rr;
+
+	/* fill the netlink header */
+	nl_hdr->nlmsg_len = NLMSG_LENGTH(size - sizeof(struct nlmsghdr));
+	nl_hdr->nlmsg_type = NLMSG_DONE;
+	nl_hdr->nlmsg_flags = 0;
+	nl_hdr->nlmsg_seq = 0;
+	nl_hdr->nlmsg_pid = getpid();
+	/* fill the connector header */
+	cn_hdr->id.idx = CN_IDX_DRBD;
+	cn_hdr->seq = 0;
+	cn_hdr->ack = 0;
+	cn_hdr->len = size - sizeof(struct nlmsghdr) - sizeof(struct cn_msg);
+
+	rr = send(sk_nl,nl_hdr,nl_hdr->nlmsg_len,0);
+	if( rr != (ssize_t)nl_hdr->nlmsg_len) {
+		perror("send() failed");
+		return -1;
+	}
+	return rr;
+}
+
+int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size)
+{
+	int rr;
+
+	rr = recv(sk_nl,nl_hdr,size,0);
+
+	if( rr < 0 ) {
+		perror("recv() failed");
+		return -1;
+	}
+	return rr;
+}
+
+int send_tag_list_cn(int sk_nl, struct drbd_tag_list *tl, const int packet_id, int minor, int flags)
+{
+	tl->cn_header->id.val = packet_id;
+	tl->drbd_p_header->drbd_minor = minor;
+	tl->drbd_p_header->flags = flags;
+
+	return send_cn(sk_nl, tl->nl_header, (char*)tl->tag_list_cpos - 
+		       (char*)tl->nl_header);
+}
+
+void close_cn(int sk_nl)
+{
+	close(sk_nl);
+}
+
 int main(int argc, char** argv)
 {
 	int help = 0;
 	unsigned int i;
+	int minor;
+	int drbd_fd,lock_fd;
+	struct drbd_cmd *cmd;
 
+	chdir("/");
+
 	if ( (cmdname = strrchr(argv[0],'/')) )
 		argv[0] = ++cmdname;
 	else
@@ -671,15 +1110,25 @@
 	/* == '-' catches -h, --help, and similar */
 	if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-'))
 		help = 1;
+
 	if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
 
-	chdir("/");
-
+	cmd=NULL;
 	for(i=0;i<ARRY_SIZE(commands);i++) {
 		if(strcmp(argv[2],commands[i].cmd)==0) {
-			commands[i].function(commands+i,argc-3,argv+3);
+			cmd = commands+i;
+			break;
 		}
 	}
 
+	if(cmd) {
+		drbd_fd = dt_lock_open_drbd(argv[1], &lock_fd, 1 );
+		minor=dt_minor_of_dev(argv[1]);
+		commands[i].function(commands+i,minor,argc-3,argv+3);
+		dt_close_drbd_unlock(drbd_fd,lock_fd);
+	} else {
+		print_usage("invalid command");
+	}
+
 	return 0;
 }

Modified: trunk/user/drbdtool_common.c
===================================================================
--- trunk/user/drbdtool_common.c	2006-08-23 10:19:26 UTC (rev 2385)
+++ trunk/user/drbdtool_common.c	2006-08-25 08:50:47 UTC (rev 2386)
@@ -4,6 +4,7 @@
 #include <asm/types.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
+#include <sys/ioctl.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>

From drbd-cvs at lists.linbit.com  Fri Aug 25 11:01:55 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Aug 25 11:01:57 2006
Subject: [DRBD-cvs] svn commit by phil - r2387 - trunk/user - Moved
	drbdsetup to its final name 
Message-ID: <20060825090155.99FEC2DF624A@mail.linbit.com>

Author: phil
Date: 2006-08-25 11:01:54 +0200 (Fri, 25 Aug 2006)
New Revision: 2387

Added:
   trunk/user/drbdsetup.c
Removed:
   trunk/user/drbdsetup_nl.c
Modified:
   trunk/user/Makefile
Log:
Moved drbdsetup to its final name


Modified: trunk/user/Makefile
===================================================================
--- trunk/user/Makefile	2006-08-25 08:50:47 UTC (rev 2386)
+++ trunk/user/Makefile	2006-08-25 09:01:54 UTC (rev 2387)
@@ -29,7 +29,7 @@
 
 drbdmeta-obj = drbdmeta.o drbdmeta_scanner.o drbdtool_common.o ../drbd/drbd_buildtag.o
 
-all: drbdadm drbdmeta drbdsetup_nl
+all: drbdadm drbdmeta drbdsetup
 
 drbdadm: $(drbdadm-obj)
 	$(CC) -o $@ $^ 
@@ -42,12 +42,9 @@
 
 # for debug:	flex -d -s -odrbdadm_scanner.c drbdadm_scanner.fl
 
-drbdsetup_nl: drbdsetup_nl.o drbdtool_common.o ../drbd/drbd_strings.o
+drbdsetup: $(drbdsetup-obj)
 	$(CC) -o $@ $^ 
 
-#drbdsetup: $(drbdsetup-obj)
-#	$(CC) -o $@ $^ 
-
 drbdmeta: $(drbdmeta-obj)
 	$(CC) -o $@ $^ 
 

Copied: trunk/user/drbdsetup.c (from rev 2386, trunk/user/drbdsetup_nl.c)
===================================================================
--- trunk/user/drbdsetup_nl.c	2006-08-25 08:50:47 UTC (rev 2386)
+++ trunk/user/drbdsetup.c	2006-08-25 09:01:54 UTC (rev 2387)
@@ -0,0 +1,1136 @@
+/*
+   drbdsetup.c
+
+   This file is part of drbd by Philipp Reisner.
+
+   Copyright (C) 1999-2006, Philipp Reisner <philipp.reisner@linbit.com>.
+   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg@linbit.com>.
+   Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
+
+   Copyright (C) 2000, Fábio Olivé Leite <olive@conectiva.com.br>.
+        Added sanity checks before using the device.
+
+   drbd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   drbd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with drbd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <mntent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+
+#include <linux/netlink.h>
+#include <linux/connector.h>
+
+#include <linux/drbd.h>
+#include <linux/drbd_config.h>
+#include <linux/drbd_tag_magic.h>
+#include <linux/drbd_limits.h>
+
+#include "drbdtool_common.h"
+
+#ifndef __CONNECTOR_H
+#error "You need to set KDIR while building drbdsetup."
+#endif
+
+struct drbd_tag_list {
+	struct nlmsghdr *nl_header;
+	struct cn_msg   *cn_header;
+	struct drbd_nl_cfg_req* drbd_p_header;
+	unsigned short *tag_list_start;
+	unsigned short *tag_list_cpos;
+	int    tag_size;
+};
+
+struct drbd_argument {
+	const char* name;
+	const enum drbd_tags tag;
+	int (*convert_function)(struct drbd_argument *,
+				struct drbd_tag_list *, 
+				char *);
+};
+
+struct drbd_option {
+	const char* name;
+	const char short_name;
+	const enum drbd_tags tag;
+	int (*convert_function)(struct drbd_option *,
+				struct drbd_tag_list *,
+				char *);
+	void (*show_function)(struct drbd_option *,unsigned short*);
+	union {
+		struct {
+			const unsigned long long min;
+			const unsigned long long max;
+			const unsigned long long def;
+			const unsigned char default_unit;
+		} numeric_param;
+		struct {
+			const char** handler_names;
+			const int number_of_handlers;
+			const int def;
+		} handler_param;
+	};
+};
+
+struct drbd_cmd {
+	const char* cmd;
+	const int packet_id;
+	int (*function)(struct drbd_cmd *, int, int, char **);
+	struct drbd_argument *args;
+	struct drbd_option *options;
+};
+
+
+// Connector functions
+int open_cn();
+int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size);
+int send_tag_list_cn(int, struct drbd_tag_list *, const int, int, int);
+int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size);
+void close_cn(int sk_nl);
+
+// other functions
+void print_command_usage(int i, const char *addinfo);
+// command functions
+int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+// convert functions for arguments
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+// convert functions for options
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+// show functions for options
+void show_numeric(struct drbd_option *od, unsigned short* tp);
+void show_handler(struct drbd_option *od, unsigned short* tp);
+void show_bit(struct drbd_option *od, unsigned short* tp);
+void show_string(struct drbd_option *od, unsigned short* tp);
+
+
+const char *on_error[] = {
+	[PassOn] = "pass_on",
+	[Panic]  = "panic",
+	[Detach] = "detach",
+};
+
+const char *fencing_n[] = {
+	[DontCare] = "dont-care",
+	[Resource] = "resource-only",
+	[Stonith]  = "resource-and-stonith",
+};
+
+const char *asb0p_n[] = {
+        [Disconnect]        = "disconnect",
+	[DiscardYoungerPri] = "discard-younger-primary",
+	[DiscardOlderPri]   = "discard-older-primary",
+	[DiscardLeastChg]   = "discard-least-changes",
+	[DiscardLocal]      = "discard-local",
+	[DiscardRemote]     = "discard-remote"
+};
+
+const char *asb1p_n[] = {
+	[Disconnect]        = "disconnect",
+	[Consensus]         = "consensus",
+	[DiscardSecondary]  = "discard-secondary",
+	[PanicPrimary]      = "panic-primary"
+};
+
+const char *asb2p_n[] = {
+	[Disconnect]        = "disconnect",
+	[PanicPrimary]      = "panic"
+};
+
+#define EN(N) \
+	conv_numeric, show_numeric, \
+	{ .numeric_param = { DRBD_ ## N ## _MIN, DRBD_ ## N ## _MAX, \
+		DRBD_ ## N ## _DEF ,0  } }
+#define EH(N,D) \
+	conv_handler, show_handler, { .handler_param = { N, ARRY_SIZE(N), \
+	DRBD_ ## D ## _DEF } }
+#define EB      conv_bit, show_bit, { } 
+#define ES      conv_string, show_string, { } 
+
+struct drbd_cmd commands[] = {
+	{"primary", P_primary, generic_config_cmd, NULL,
+	 (struct drbd_option[]) {
+		 { "overwrite-data-of-peer",'o',T_overwrite_peer, EB   },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
+
+	{"secondary", P_secondary, generic_config_cmd, NULL, NULL },
+
+	{"disk", P_disk_conf, generic_config_cmd,
+	 (struct drbd_argument[]) {
+		 { "lower_dev",		T_backing_dev,	conv_block_dev },
+		 { "meta_data_dev",	T_meta_dev,	conv_block_dev },
+		 { "meta_data_index",	T_meta_dev_idx,	conv_md_idx },
+		 { NULL,                0,           	NULL}, },
+	 (struct drbd_option[]) {
+		 { "size",'d',		T_disk_size,	EN(DISK_SIZE_SECT) },
+		 { "on-io-error",'e',	T_on_io_error,	EH(on_error,ON_IO_ERROR) },
+		 { "fencing",'f',	T_fencing,      EH(fencing_n,FENCING) },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
+
+	{"detach", P_detach, generic_config_cmd, NULL, NULL },
+
+	{"net", P_net_conf, generic_config_cmd,
+	 (struct drbd_argument[]) {
+		 { "local_addr",	T_my_addr,	conv_address },
+		 { "remote_addr",	T_peer_addr,	conv_address },
+		 { "protocol",		T_wire_protocol,conv_protocol },
+ 		 { NULL,                0,           	NULL}, },
+	 (struct drbd_option[]) {
+		 { "timeout",'t',	T_timeout,	EN(TIMEOUT) },
+		 { "max-epoch-size",'e',T_max_epoch_size,EN(MAX_EPOCH_SIZE) },
+		 { "max-buffers",'b',	T_max_buffers,	EN(MAX_BUFFERS) },
+		 { "unplug-watermark",'u',T_unplug_watermark, EN(UNPLUG_WATERMARK) },
+		 { "connect-int",'c',	T_try_connect_int, EN(CONNECT_INT) },
+		 { "ping-int",'i',	T_ping_int,	   EN(PING_INT) },
+		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN(SNDBUF_SIZE) },
+		 { "ko-count",'k',	T_ko_count,	   EN(KO_COUNT) },
+		 { "allow-two-primaries",'m',T_two_primaries, EB },
+		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   ES },
+		 { "shared-secret",'x',	T_shared_secret,   ES },
+		 { "after-sb-0pri",'A',	T_after_sb_0p,EH(asb0p_n,AFTER_SB_0P) },
+		 { "after-sb-1pri",'B',	T_after_sb_1p,EH(asb1p_n,AFTER_SB_1P) },
+		 { "after-sb-2pri",'C',	T_after_sb_2p,EH(asb2p_n,AFTER_SB_2P) },
+		 { "discard-my-data",'D', T_want_lose,     EB },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
+
+	{"disconnect", P_disconnect, generic_config_cmd, NULL, NULL },
+
+	{"resize", P_resize, generic_config_cmd, NULL,
+	 (struct drbd_option[]) {
+		 { "size",'s',T_resize_size,		EN(DISK_SIZE_SECT) },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
+
+	{"syncer", P_syncer_conf, generic_config_cmd, NULL,
+	 (struct drbd_option[]) {
+		 { "rate",'r',T_rate,			EN(RATE) },
+		 { "after",'a',T_after,			EN(AFTER) },
+		 { "al-extents",'e',T_al_extents,	EN(AL_EXTENTS) },
+		 { NULL,0,0,NULL,NULL, { } }, }, },
+
+	{"invalidate", P_invalidate, generic_config_cmd, NULL, NULL },
+	{"invalidate-remote", P_invalidate_peer, generic_config_cmd, NULL, NULL },
+	{"pause-sync", P_pause_sync, generic_config_cmd, NULL, NULL },
+	{"resume-sync", P_resume_sync, generic_config_cmd, NULL, NULL },
+	{"suspend-io", P_suspend_io, generic_config_cmd, NULL, NULL },
+	{"resume-io", P_resume_io, generic_config_cmd, NULL, NULL },
+	{"outdate", P_outdate, generic_config_cmd, NULL, NULL },
+
+	// {"down", 0 , down_cmd, NULL, NULL },
+
+	/*
+	{"state", cmd_state,               0, 0, },
+	{"cstate", cmd_cstate,             0, 0, },
+	{"dstate", cmd_dstate,             0, 0, },
+	{"show-gi", cmd_show_gi,           0, 0, },
+	{"get-gi", cmd_get_gi,             0, 0, }, */
+	{"show", P_get_config, show_cmd, NULL, NULL },
+};
+
+#define EM(C) [ C - RetCodeBase ]
+
+static const char *error_messages[] = {
+	EM(NoError) = "No further Information available.",
+	EM(LAAlreadyInUse) = "Local address(port) already in use.",
+	EM(OAAlreadyInUse) = "Remote address(port) already in use.",
+	EM(LDNameInvalid) = "Can not open backing device.",
+	EM(MDNameInvalid) = "Can not open meta device.",
+	EM(LDAlreadyInUse) = "Lower device already in use.",
+	EM(LDNoBlockDev) = "Lower device is not a block device.",
+	EM(MDNoBlockDev) = "Meta device is not a block device.",
+	EM(LDOpenFailed) = "Open of lower device failed.",
+	EM(MDOpenFailed) = "Open of meta device failed.",
+	EM(LDDeviceTooSmall) = "Low.dev. smaller than requested DRBD-dev. size.",
+	EM(MDDeviceTooSmall) = "Meta device too small.",
+	EM(LDNoConfig) = "You have to use the disk command first.",
+	EM(LDMounted) = "Lower device is already mounted.",
+	EM(MDMounted) = "Meta device is already mounted.",
+	EM(LDMDInvalid) = "Lower device / meta device / index combination invalid.",
+	EM(LDDeviceTooLarge) = "Currently we only support devices up to 3.998TB.\n"
+	"(up to 2TB in case you do not have CONFIG_LBD set)"
+	"Contact office@linbit.com, if you need more.",
+	EM(MDIOError) = "IO error(s) orruced during initial access to meta-data.\n",
+	EM(MDInvalid) = "No valid meta-data signature found.\n)"
+	"Use 'drbdadm create-md res' to initialize meta-data area.\n",
+	EM(CRAMAlgNotAvail) = "The 'cram-hmac-alg' you specified is not known in )"
+	"the kernel.\n",
+	EM(CRAMAlgNotDigest) = "The 'cram-hmac-alg' you specified is not a digest.",
+	EM(KMallocFailed) = "kmalloc() failed. Out of memory?",
+	EM(DiscardNotAllowed) = "--discard-my-data not allowed when primary.",
+	EM(HaveDiskConfig) = "HaveDiskConfig",
+	EM(UnknownMandatoryTag) = "UnknownMandatoryTag",
+	EM(MinorNotKnown) = "MinorNotKnown",
+	EM(StateNotAllowed) = "StateNotAllowed",
+	EM(GotSignal) = "GotSignal",
+	EM(NoResizeDuringResync) = "Resize not allowed during resync.",
+	EM(APrimaryNodeNeeded) = "Need the a primary node to resize.",
+	EM(SyncAfterInvalid) = "The sync after minor number is invalid",
+	EM(SyncAfterCycle-) = "This would cause a sync-after dependency cycle",
+	EM(PauseFlagAlreadySet) = "PauseFlagAlreadySet",
+	EM(PauseFlagAlreadyClear) = "PauseFlagAlreadyClear",
+	EM(DiskLowerThanOutdated) = "DiskLowerThanOutdated",
+	EM(FailedToClaimMyself) = "FailedToClaimMyself",
+};
+
+char* cmdname = 0;
+
+int dump_tag_list(unsigned short *tlc)
+{
+	enum drbd_tags tag;
+	unsigned int tag_nr;
+	int len;
+	int integer;
+	char bit;
+	__u64 int64;
+	char* string;
+	int found_unknown=0;
+
+	while( (tag = *tlc++ ) != TT_END) {
+		len = *tlc++;
+		if(tag == TT_REMOVED) goto skip;
+
+		tag_nr = tag_number(tag);
+		if(tag_nr<ARRY_SIZE(tag_descriptions)) {
+			string = tag_descriptions[tag_nr].name;
+		} else {
+			string = "unknown tag";
+			found_unknown=1;
+		}
+		printf("# (%2d) %16s = ",tag_nr,string);
+		switch(tag_type(tag)) {
+		case TT_INTEGER: 
+			integer = *(int*)tlc;
+			printf("(integer) %d",integer);
+			break;
+		case TT_INT64:
+			int64 = *(__u64*)tlc;
+			printf("(int64) %lld",(long long)int64);
+			break;
+		case TT_BIT:
+			bit = *(char*)tlc;
+			printf("(bit) %s", bit ? "on" : "off");
+			break;
+		case TT_STRING:
+			string = (char*)tlc;
+			printf("(string)'%s'",string);
+			break;
+		}
+		printf(" \t[len: %u]\n",len);
+	skip:
+		tlc = (unsigned short*)((char*)tlc + len);
+	}
+
+	return found_unknown;
+}
+
+struct drbd_tag_list *create_tag_list(int size)
+{
+	struct drbd_tag_list *tl;
+	
+	tl = malloc(sizeof(struct drbd_tag_list));
+	tl->nl_header  = malloc(NLMSG_SPACE( sizeof(struct cn_msg) +
+					     sizeof(struct drbd_nl_cfg_req) + 
+					     size) );
+	tl->cn_header = NLMSG_DATA(tl->nl_header);
+	tl->drbd_p_header = (struct drbd_nl_cfg_req*) tl->cn_header->data;
+	tl->tag_list_start = tl->drbd_p_header->tag_list;
+	tl->tag_list_cpos = tl->tag_list_start;
+	tl->tag_size = size;
+
+	return tl;
+}
+
+void add_tag(struct drbd_tag_list *tl, int tag, void *data, int data_len)
+{
+	if( (tl->tag_list_cpos - tl->tag_list_start) + data_len 
+	    > tl->tag_size ) {
+		fprintf(stderr, "Tag list size exceeded!\n");
+		exit(20);
+	}
+	*tl->tag_list_cpos++ = tag;
+	*tl->tag_list_cpos++ = data_len;
+	memcpy(tl->tag_list_cpos,data,data_len);
+	tl->tag_list_cpos = (unsigned short*)((char*)tl->tag_list_cpos + data_len);
+}
+
+void free_tag_list(struct drbd_tag_list *tl)
+{
+	free(tl->nl_header);
+	free(tl);
+}
+
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	struct stat sb;
+	int device_fd;
+	int err;
+
+	if ((device_fd = open(arg,O_RDWR))==-1) {
+		PERROR("Can not open device '%s'", arg);
+		return 20;
+	}
+
+	if ( (err=fstat(device_fd, &sb)) ) {
+		PERROR("fstat(%s) failed", arg);
+		return 20;
+	}
+
+	if(!S_ISBLK(sb.st_mode)) {
+		fprintf(stderr, "%s is not a block device!\n", arg);
+		return 20;
+	}
+	
+	close(device_fd);
+
+	add_tag(tl,ad->tag,arg,strlen(arg)+1); // include the null byte. 
+
+	return 0;
+}
+
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	int idx;
+
+	if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT;
+	else if(!strcmp(arg,"flex")) idx = DRBD_MD_INDEX_FLEX_EXT;
+	else idx = m_strtoll(arg,1);
+
+	add_tag(tl,ad->tag,&idx,sizeof(idx));
+
+	return 0;
+}
+
+const char* addr_part(const char* s)
+{
+	static char buffer[200];
+	char *b;
+
+	b=strchr(s,':');
+	if(b) {
+		strncpy(buffer,s,b-s);
+		buffer[b-s]=0;
+		return buffer;
+	}
+	return s;
+}
+
+int port_part(const char* s)
+{
+	char *b;
+
+	b=strchr(s,':');
+
+	// m_strtoll_range(b+1,1, "port", DRBD_PORT_MIN, DRBD_PORT_MAX);
+	if(b) return m_strtoll(b+1,1);
+	return 7788;
+}
+
+unsigned long resolv(const char* name)
+{
+	unsigned long retval;
+
+	if((retval = inet_addr(name)) == INADDR_NONE ) {
+		struct hostent *he;
+		he = gethostbyname(name);
+		if (!he) {
+			PERROR("can not resolv the hostname");
+			exit(20);
+		}
+		retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr;
+	}
+	return retval;
+}
+
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	struct sockaddr_in addr;
+	int addr_len = sizeof(struct sockaddr_in);
+
+	addr.sin_port = htons(port_part(arg));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = resolv(addr_part(arg));
+
+	add_tag(tl,ad->tag,&addr,addr_len);
+
+	return 0;
+}
+
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+	int prot;
+
+	if(!strcmp(arg,"A") || !strcmp(arg,"a")) {
+		prot=DRBD_PROT_A;
+	} else if (!strcmp(arg,"B") || !strcmp(arg,"b")) {
+		prot=DRBD_PROT_B;
+	} else if (!strcmp(arg,"C") || !strcmp(arg,"c")) {
+		prot=DRBD_PROT_C;
+	} else {
+		fprintf(stderr, "'%s' is no valid protocol.\n", arg);
+		return 20;
+	}
+
+	add_tag(tl,ad->tag,&prot,sizeof(prot));
+
+	return 0;
+}
+
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	char bit=1;
+
+	add_tag(tl,od->tag,&bit,sizeof(bit));
+
+	return 0;
+}
+
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	const unsigned long long min = od->numeric_param.min;
+	const unsigned long long max = od->numeric_param.max;
+	const unsigned char default_unit = od->numeric_param.default_unit;
+	unsigned long long l;
+	int i;
+	char unit[] = {0,0};
+
+	l = m_strtoll(arg, default_unit);
+
+	if (min > l || l > max) {
+		unit[0] = default_unit > 1 ? default_unit : 0;
+		fprintf(stderr,"%s %s => %llu%s out of range [%llu..%llu]%s\n",
+			od->name, arg, l, unit, min, max, unit);
+		return(20);
+	}
+
+	switch(tag_type(od->tag)) {
+	case TT_INT64:
+		add_tag(tl,od->tag,&l,sizeof(l));
+		break;
+	case TT_INTEGER:
+		i=l;
+		add_tag(tl,od->tag,&i,sizeof(i));
+		break;
+	default:
+		fprintf(stderr, "internal error in conv_numeric()\n");
+	}
+	return 0;
+
+}
+
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	const char** handler_names = od->handler_param.handler_names;
+	const int number_of_handlers = od->handler_param.number_of_handlers;
+	int i,nr;
+
+	for(i=0;i<number_of_handlers;i++) {
+		if(strcmp(arg,handler_names[i])==0) {
+			nr = i;
+			break;
+		}
+	}
+
+	add_tag(tl,od->tag,&nr,sizeof(nr));
+
+	return 0;
+}
+
+int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+	add_tag(tl,od->tag,arg,strlen(arg)+1);
+
+	return 0;
+}
+
+struct option *	make_longoptions(struct drbd_option* od)
+{
+	static struct option buffer[20];
+	int i=0;
+
+	while(od && od->name) {
+		buffer[i].name = od->name;
+		buffer[i].has_arg = tag_type(od->tag) == TT_BIT ? 
+			no_argument : required_argument ;
+		buffer[i].flag = NULL;
+		buffer[i].val = od->short_name;
+		if(i++ == 20) {
+			fprintf(stderr,"buffer in make_longoptions to small.\n");
+		}
+		od++;
+	}
+	
+	// The two omnipresent options:
+	buffer[i].name = "set-defaults";
+	buffer[i].has_arg = 0;
+	buffer[i].flag = NULL;
+	buffer[i].val = '(';
+	i++;
+
+	buffer[i].name = "create-device";
+	buffer[i].has_arg = 0;
+	buffer[i].flag = NULL;
+	buffer[i].val = ')';
+	i++;
+
+	buffer[i].name = NULL;
+	buffer[i].has_arg = 0;
+	buffer[i].flag = NULL;
+	buffer[i].val = 0;
+
+	return buffer;
+}
+
+struct drbd_option *find_opt_by_short_name(struct drbd_option *od, int c)
+{
+	while(od->name) {
+		if(od->short_name == c) return od;
+		od++;
+	}
+
+	return NULL;
+}
+
+void print_config_error( struct drbd_nl_cfg_reply *reply)
+{
+	int err_no = reply->ret_code;
+
+	if (err_no == NoError) return;
+	if (err_no == SS_Success) return;
+
+	if ( ( err_no >= AfterLastRetCode || err_no <= RetCodeBase ) &&
+	     ( err_no > SS_TowPrimaries || err_no < SS_CW_FailedByPeer) ) {
+		fprintf(stderr,"Error code %d unknown.\n"
+			"You should updated the drbd userland tools.\n",err_no);
+	} else {
+		if(err_no > RetCodeBase ) {
+			fprintf(stderr,"Failure: (%d) %s\n",err_no,
+				error_messages[err_no-RetCodeBase]);
+		} else {
+			fprintf(stderr,"State change failed: (%d) %s\n",
+				err_no, set_st_err_name(err_no));
+		}
+	}
+}
+
+#define RCV_SIZE NLMSG_SPACE(sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply))
+
+int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
+{
+	char buffer[ RCV_SIZE ];
+	struct drbd_nl_cfg_reply *reply;
+	struct drbd_argument *ad = cm->args;
+	struct drbd_option *od;
+	static struct option *lo;
+	struct drbd_tag_list *tl;
+	int c,i=0,rv=0,sk_nl;
+	int flags=0;
+
+	tl = create_tag_list(4096);
+
+	while(ad && ad->name) {
+		if(argc < i+1) {
+			fprintf(stderr,"Missing argument '%s'\n", ad->name);
+			print_command_usage(cm-commands, "");
+			rv=20;
+			break;
+		}
+		rv |= ad->convert_function(ad,tl,argv[i++]);
+		if(rv) break;
+		ad++;
+	}
+
+	lo = make_longoptions(cm->options);
+	opterr=0;
+	while( (c=getopt_long(argc,argv,make_optstring(lo,0),lo,0)) != -1 ) {
+		od = find_opt_by_short_name(cm->options,c);
+		if(od) rv |= od->convert_function(od,tl,optarg);
+		else {
+			if(c=='(') flags |= DRBD_NL_SET_DEFAULTS;
+			else if(c==')') flags |= DRBD_NL_CREATE_DEVICE;
+			else {
+				fprintf(stderr,
+					"%s: unrecognized option '%s'\n",
+					cmdname, argv[optind-1]);
+				rv=20;
+			}
+		}
+		if(rv) break;
+	}
+
+	add_tag(tl,TT_END,NULL,0); // close the tag list
+
+	if(rv == 0) {
+		// dump_tag_list(tl->tag_list_start);
+		sk_nl = open_cn();
+		if(sk_nl < 0) return 20;
+
+		send_tag_list_cn(sk_nl,tl,cm->packet_id,minor,flags);
+
+		receive_cn(sk_nl, (struct nlmsghdr*)buffer, RCV_SIZE );
+		close_cn(sk_nl);
+		reply = (struct drbd_nl_cfg_reply *)
+			((struct cn_msg *)NLMSG_DATA(buffer))->data;
+		print_config_error(reply);
+	}
+	free_tag_list(tl);
+
+	return rv;
+}
+
+#define ASSERT(exp) if (!(exp)) \
+		fprintf(stderr,"ASSERT( " #exp " ) in %s:%d\n", __FILE__,__LINE__);
+
+void show_numeric(struct drbd_option *od, unsigned short* tp)
+{
+	long long val;
+
+	switch(tag_type(*tp++)) {
+	case TT_INTEGER: 
+		ASSERT( *tp++ == sizeof(int) );
+		val = *(int*)tp;
+		break;
+	case TT_INT64:
+		ASSERT( *tp++ == sizeof(__u64) );
+		val = *(__u64*)tp;
+		break;
+	default: 
+		ASSERT(0);
+		val=0;
+	}
+
+	printf("\t%s\t\t%lld",od->name,val);
+	if(val == (long long) od->numeric_param.def) printf(" _is_default");
+	printf(";\n");
+}
+
+void show_handler(struct drbd_option *od, unsigned short* tp)
+{
+	const char** handler_names = od->handler_param.handler_names;
+	int i;
+
+	ASSERT( tag_type(*tp++) == TT_INTEGER );
+	ASSERT( *tp++ == sizeof(int) );
+	i = *(int*)tp;
+	printf("\t%s\t\t%s",od->name,handler_names[i]);
+	if( i == (long long)od->numeric_param.def) printf(" _is_default");
+	printf(";\n");
+}
+
+void show_bit(struct drbd_option *od, unsigned short* tp)
+{
+	ASSERT( tag_type(*tp++) == TT_BIT );
+	ASSERT( *tp++ == sizeof(char) );
+	if(*(char*)tp) printf("\t%s;\n",od->name);
+}
+
+void show_string(struct drbd_option *od, unsigned short* tp)
+{
+	ASSERT( tag_type(*tp++) == TT_STRING );
+	if( *tp++ > 0) printf("\t%s\t\t\"%s\";\n",od->name,(char*)tp);
+}
+
+unsigned short *look_for_tag(unsigned short *tlc, unsigned short tag)
+{
+	enum drbd_tags t;
+	int len;
+
+	while( (t = *tlc) != TT_END ) {
+		if(t == tag) return tlc;
+		tlc++;
+		len = *tlc++;
+		tlc = (unsigned short*)((char*)tlc + len);
+	}
+	return NULL;
+}
+
+void print_options(struct drbd_option *od, unsigned short *tlc, const char* sect_name)
+{
+	unsigned short *tp;
+	int opened = 0;
+
+	while(od->name) {
+		tp = look_for_tag(tlc,od->tag);
+		if(tp) {
+			if(!opened) {
+				opened=1;
+				printf("%s {\n",sect_name);
+			}
+			od->show_function(od,tp);
+			*tp = TT_REMOVED;
+		}
+		od++;
+	}
+	if(opened) {
+		printf("}\n");
+	}
+}
+
+char* consume_tag_string(enum drbd_tags tag, unsigned short *tlc)
+{
+	unsigned short *tp;
+	tp = look_for_tag(tlc,tag);
+	if(tp) {
+		*tp++ = TT_REMOVED;
+		if( *tp++ > 0) return (char*)tp;
+	}
+	return "";
+}
+
+int consume_tag_int(enum drbd_tags tag, unsigned short *tlc)
+{
+	unsigned short *tp;
+	tp = look_for_tag(tlc,tag);
+	if(tp) {
+		*tp++ = TT_REMOVED;
+		tp++;
+		return *(int *)tp;
+	}
+	return 0;
+}
+
+int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
+{
+	char buffer[ 4096 ];
+	struct drbd_tag_list *tl;
+	struct drbd_nl_cfg_reply *reply;
+	struct sockaddr_in *addr;
+	int sk_nl;
+	unsigned short *rtl;
+
+	int idx;
+	char* str;
+
+	ASSERT(cm->packet_id == P_get_config);
+
+	if(argc > 1) {
+		fprintf(stderr,"Ignoring excess arguments\n");
+	
+	}
+
+	tl = create_tag_list(2);
+	add_tag(tl,TT_END,NULL,0); // close the tag list
+
+	sk_nl = open_cn();
+	if(sk_nl < 0) return 20;
+
+	send_tag_list_cn(sk_nl,tl,cm->packet_id,minor,0);
+
+	receive_cn(sk_nl, (struct nlmsghdr*)buffer, 4096 );
+	close_cn(sk_nl);
+	reply = (struct drbd_nl_cfg_reply *)
+		((struct cn_msg *)NLMSG_DATA(buffer))->data;
+
+	rtl = reply->tag_list;
+
+	// find all commands that have options and print those...
+	for ( cm = commands ; cm < commands + ARRY_SIZE(commands) ; cm++ ) {
+		if(cm->options)
+			print_options(cm->options, rtl, cm->cmd);
+	}
+
+	// start of spagethi code...
+	idx = consume_tag_int(T_wire_protocol,rtl);
+	if(idx) printf("protocol %c;\n",'A'+idx-1);
+	str = consume_tag_string(T_backing_dev,rtl);
+	if(str) {
+		printf("_this_host {\n");
+		printf("\tdevice\t\t\"/dev/drbd%d\";\n",minor);
+		printf("\tdisk\t\t\"%s\";\n",str);
+		idx=consume_tag_int(T_meta_dev_idx,rtl);
+		switch(idx) {
+		case DRBD_MD_INDEX_INTERNAL:
+		case DRBD_MD_INDEX_FLEX_INT:
+			printf("\tmeta-disk\tinternal;\n");
+			consume_tag_string(T_meta_dev,rtl);
+			break;
+		case DRBD_MD_INDEX_FLEX_EXT:
+			printf("\tflexible-meta-disk\t\"%s\";\n",
+			       consume_tag_string(T_meta_dev,rtl));
+			break;
+		default:
+			printf("\tmeta-disk\t\"%s\" [ %d ];\n",
+			       consume_tag_string(T_meta_dev,rtl),idx);
+		}
+		str = consume_tag_string(T_my_addr,rtl);
+		if(str) {
+			addr = (struct sockaddr_in *)str;
+			printf("\taddress\t\t%s:%d;\n",
+			       inet_ntoa(addr->sin_addr),
+			       ntohs(addr->sin_port));
+		}
+		printf("}\n");
+	}
+
+	str = consume_tag_string(T_peer_addr,rtl);
+	if(str) {
+		printf("_remote_host {\n");
+		addr = (struct sockaddr_in *)str;
+		printf("\taddress\t\t%s:%d;\n",
+		       inet_ntoa(addr->sin_addr),
+		       ntohs(addr->sin_port));
+		printf("}\n");
+	}
+
+	if(dump_tag_list(reply->tag_list)) {
+		printf("# Found unknown tags, you should update your\n"
+		       "# userland tools\n");
+	}
+
+	return 0;
+}
+
+void print_command_usage(int i, const char *addinfo)
+    // CAUTION no range check for i
+{
+	struct drbd_argument *args;
+	struct drbd_option *options;
+#define  maxcol 100 // plus initial tab ...
+	static char line[maxcol+1];
+	int col,prevcol;
+
+	prevcol=col=0;
+
+	col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
+	if ((args = commands[i].args)) {
+		while (args->name) {
+			col += snprintf(line+col, maxcol-col, " %s", args->name);
+			args++;
+		}
+					
+	}
+	if (col > maxcol) {
+		printf("%s\n\t",line);
+		col=0;
+	}
+	prevcol=col;
+	if ((options = commands[i].options)) {
+		while (options->name) {
+			if (tag_type(options->tag) == TT_BIT) {
+				col += snprintf(line+col, maxcol-col,
+						" [{--%s|-%c}]",
+						options->name, options->short_name);
+			} else {
+				col += snprintf(line+col, maxcol-col,
+						" [{--%s|-%c} val]",
+						options->name, options->short_name);
+			}
+			if (col >= maxcol) {
+				line[prevcol]=0;
+				printf("%s\n\t",line);
+				prevcol=col=0;
+			} else {
+				prevcol=col;
+				options++;
+			}
+		}
+	}
+	line[col]=0;
+	printf("%s\n",line);
+	if (addinfo) {
+		printf("%s\n",addinfo);
+		exit(20);
+	}
+}
+
+void print_handler(const char* info, const char** handlers, unsigned int size)
+{
+	unsigned int i;
+
+	printf(info);
+
+	for(i=0;i<size;i++) {
+		if(handlers[i]) {
+			printf(" %s",handlers[i]);
+			if(i < size-1) printf(",");
+		}
+	}
+}
+
+void print_usage(const char* addinfo)
+{
+	size_t i;
+
+	printf("\nUSAGE: %s device command arguments options\n\n"
+	       "Device is usually /dev/drbdX or /dev/drbd/X.\n"
+	       "Commands, arguments and options are:\n",cmdname);
+
+
+	for (i = 0; i < ARRY_SIZE(commands); i++)
+		print_command_usage(i, 0);
+
+	printf("\nGeneral options: --create-device, --set-defaults\n");
+
+	print_handler("\non-io-error handlers:",on_error,ARRY_SIZE(on_error));
+	print_handler("\nfencing policies:",fencing_n,ARRY_SIZE(fencing_n));
+	print_handler("\nafter-sb-0pri handler:",asb0p_n,ARRY_SIZE(asb0p_n));
+	print_handler("\nafter-sb-1pri handler:",asb1p_n,ARRY_SIZE(asb1p_n));
+	print_handler("\nafter-sb-2pri handler:",asb2p_n,ARRY_SIZE(asb2p_n));
+
+	printf("\n\n");
+	/*
+	printf("\n\nVersion: "REL_VERSION" (api:%d)\n%s\n",
+	       API_VERSION, drbd_buildtag());
+	*/
+	if (addinfo)
+		printf("\n%s\n",addinfo);
+
+	exit(20);
+}
+
+int open_cn()
+{
+	int sk_nl;
+	int err;
+	struct sockaddr_nl my_nla;
+
+	sk_nl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+	if (sk_nl == -1) {
+		perror("socket() failed");
+		return -1;
+	}
+
+	my_nla.nl_family = AF_NETLINK;
+	my_nla.nl_groups = -1; //CN_IDX_DRBD; 
+	my_nla.nl_pid = getpid();
+
+	err = bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla));
+	if (err == -1) {
+		err = errno;
+		perror("bind() failed");
+		if(err == ENOENT) {
+			fprintf(stderr,"DRBD driver not present in the kernel?\n");
+		}
+		return -1;
+	}
+
+	return sk_nl;
+}
+
+
+int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size)
+{
+	struct cn_msg *cn_hdr;
+	cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
+	int rr;
+
+	/* fill the netlink header */
+	nl_hdr->nlmsg_len = NLMSG_LENGTH(size - sizeof(struct nlmsghdr));
+	nl_hdr->nlmsg_type = NLMSG_DONE;
+	nl_hdr->nlmsg_flags = 0;
+	nl_hdr->nlmsg_seq = 0;
+	nl_hdr->nlmsg_pid = getpid();
+	/* fill the connector header */
+	cn_hdr->id.idx = CN_IDX_DRBD;
+	cn_hdr->seq = 0;
+	cn_hdr->ack = 0;
+	cn_hdr->len = size - sizeof(struct nlmsghdr) - sizeof(struct cn_msg);
+
+	rr = send(sk_nl,nl_hdr,nl_hdr->nlmsg_len,0);
+	if( rr != (ssize_t)nl_hdr->nlmsg_len) {
+		perror("send() failed");
+		return -1;
+	}
+	return rr;
+}
+
+int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size)
+{
+	int rr;
+
+	rr = recv(sk_nl,nl_hdr,size,0);
+
+	if( rr < 0 ) {
+		perror("recv() failed");
+		return -1;
+	}
+	return rr;
+}
+
+int send_tag_list_cn(int sk_nl, struct drbd_tag_list *tl, const int packet_id, int minor, int flags)
+{
+	tl->cn_header->id.val = packet_id;
+	tl->drbd_p_header->drbd_minor = minor;
+	tl->drbd_p_header->flags = flags;
+
+	return send_cn(sk_nl, tl->nl_header, (char*)tl->tag_list_cpos - 
+		       (char*)tl->nl_header);
+}
+
+void close_cn(int sk_nl)
+{
+	close(sk_nl);
+}
+
+int main(int argc, char** argv)
+{
+	int help = 0;
+	unsigned int i;
+	int minor;
+	int drbd_fd,lock_fd;
+	struct drbd_cmd *cmd;
+
+	chdir("/");
+
+	if ( (cmdname = strrchr(argv[0],'/')) )
+		argv[0] = ++cmdname;
+	else
+		cmdname = argv[0];
+
+	/* == '-' catches -h, --help, and similar */
+	if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-'))
+		help = 1;
+
+	if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
+
+	cmd=NULL;
+	for(i=0;i<ARRY_SIZE(commands);i++) {
+		if(strcmp(argv[2],commands[i].cmd)==0) {
+			cmd = commands+i;
+			break;
+		}
+	}
+
+	if(cmd) {
+		drbd_fd = dt_lock_open_drbd(argv[1], &lock_fd, 1 );
+		minor=dt_minor_of_dev(argv[1]);
+		commands[i].function(commands+i,minor,argc-3,argv+3);
+		dt_close_drbd_unlock(drbd_fd,lock_fd);
+	} else {
+		print_usage("invalid command");
+	}
+
+	return 0;
+}

Deleted: trunk/user/drbdsetup_nl.c
===================================================================
--- trunk/user/drbdsetup_nl.c	2006-08-25 08:50:47 UTC (rev 2386)
+++ trunk/user/drbdsetup_nl.c	2006-08-25 09:01:54 UTC (rev 2387)
@@ -1,1134 +0,0 @@
-/*
-   drbdsetup.c
-
-   This file is part of drbd by Philipp Reisner.
-
-   Copyright (C) 1999-2006, Philipp Reisner <philipp.reisner@linbit.com>.
-   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg@linbit.com>.
-   Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
-
-   Copyright (C) 2000, Fábio Olivé Leite <olive@conectiva.com.br>.
-        Added sanity checks before using the device.
-
-   drbd is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   drbd is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with drbd; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
-#define _GNU_SOURCE
-
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <mntent.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <stdlib.h>
-
-#include <linux/netlink.h>
-#include <linux/connector.h>
-
-#include <linux/drbd.h>
-#include <linux/drbd_config.h>
-#include <linux/drbd_tag_magic.h>
-#include <linux/drbd_limits.h>
-
-#include "drbdtool_common.h"
-
-
-
-struct drbd_tag_list {
-	struct nlmsghdr *nl_header;
-	struct cn_msg   *cn_header;
-	struct drbd_nl_cfg_req* drbd_p_header;
-	unsigned short *tag_list_start;
-	unsigned short *tag_list_cpos;
-	int    tag_size;
-};
-
-struct drbd_argument {
-	const char* name;
-	const enum drbd_tags tag;
-	int (*convert_function)(struct drbd_argument *,
-				struct drbd_tag_list *, 
-				char *);
-};
-
-struct drbd_option {
-	const char* name;
-	const char short_name;
-	const enum drbd_tags tag;
-	int (*convert_function)(struct drbd_option *,
-				struct drbd_tag_list *,
-				char *);
-	void (*show_function)(struct drbd_option *,unsigned short*);
-	union {
-		struct {
-			const unsigned long long min;
-			const unsigned long long max;
-			const unsigned long long def;
-			const unsigned char default_unit;
-		} numeric_param;
-		struct {
-			const char** handler_names;
-			const int number_of_handlers;
-			const int def;
-		} handler_param;
-	};
-};
-
-struct drbd_cmd {
-	const char* cmd;
-	const int packet_id;
-	int (*function)(struct drbd_cmd *, int, int, char **);
-	struct drbd_argument *args;
-	struct drbd_option *options;
-};
-
-
-// Connector functions
-int open_cn();
-int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size);
-int send_tag_list_cn(int, struct drbd_tag_list *, const int, int, int);
-int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size);
-void close_cn(int sk_nl);
-
-// other functions
-void print_command_usage(int i, const char *addinfo);
-// command functions
-int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
-int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
-// convert functions for arguments
-int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
-// convert functions for options
-int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
-// show functions for options
-void show_numeric(struct drbd_option *od, unsigned short* tp);
-void show_handler(struct drbd_option *od, unsigned short* tp);
-void show_bit(struct drbd_option *od, unsigned short* tp);
-void show_string(struct drbd_option *od, unsigned short* tp);
-
-
-const char *on_error[] = {
-	[PassOn] = "pass_on",
-	[Panic]  = "panic",
-	[Detach] = "detach",
-};
-
-const char *fencing_n[] = {
-	[DontCare] = "dont-care",
-	[Resource] = "resource-only",
-	[Stonith]  = "resource-and-stonith",
-};
-
-const char *asb0p_n[] = {
-        [Disconnect]        = "disconnect",
-	[DiscardYoungerPri] = "discard-younger-primary",
-	[DiscardOlderPri]   = "discard-older-primary",
-	[DiscardLeastChg]   = "discard-least-changes",
-	[DiscardLocal]      = "discard-local",
-	[DiscardRemote]     = "discard-remote"
-};
-
-const char *asb1p_n[] = {
-	[Disconnect]        = "disconnect",
-	[Consensus]         = "consensus",
-	[DiscardSecondary]  = "discard-secondary",
-	[PanicPrimary]      = "panic-primary"
-};
-
-const char *asb2p_n[] = {
-	[Disconnect]        = "disconnect",
-	[PanicPrimary]      = "panic"
-};
-
-#define EN(N) \
-	conv_numeric, show_numeric, \
-	{ .numeric_param = { DRBD_ ## N ## _MIN, DRBD_ ## N ## _MAX, \
-		DRBD_ ## N ## _DEF ,0  } }
-#define EH(N,D) \
-	conv_handler, show_handler, { .handler_param = { N, ARRY_SIZE(N), \
-	DRBD_ ## D ## _DEF } }
-#define EB      conv_bit, show_bit, { } 
-#define ES      conv_string, show_string, { } 
-
-struct drbd_cmd commands[] = {
-	{"primary", P_primary, generic_config_cmd, NULL,
-	 (struct drbd_option[]) {
-		 { "overwrite-data-of-peer",'o',T_overwrite_peer, EB   },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
-
-	{"secondary", P_secondary, generic_config_cmd, NULL, NULL },
-
-	{"disk", P_disk_conf, generic_config_cmd,
-	 (struct drbd_argument[]) {
-		 { "lower_dev",		T_backing_dev,	conv_block_dev },
-		 { "meta_data_dev",	T_meta_dev,	conv_block_dev },
-		 { "meta_data_index",	T_meta_dev_idx,	conv_md_idx },
-		 { NULL,                0,           	NULL}, },
-	 (struct drbd_option[]) {
-		 { "size",'d',		T_disk_size,	EN(DISK_SIZE_SECT) },
-		 { "on-io-error",'e',	T_on_io_error,	EH(on_error,ON_IO_ERROR) },
-		 { "fencing",'f',	T_fencing,      EH(fencing_n,FENCING) },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
-
-	{"detach", P_detach, generic_config_cmd, NULL, NULL },
-
-	{"net", P_net_conf, generic_config_cmd,
-	 (struct drbd_argument[]) {
-		 { "local_addr",	T_my_addr,	conv_address },
-		 { "remote_addr",	T_peer_addr,	conv_address },
-		 { "protocol",		T_wire_protocol,conv_protocol },
- 		 { NULL,                0,           	NULL}, },
-	 (struct drbd_option[]) {
-		 { "timeout",'t',	T_timeout,	EN(TIMEOUT) },
-		 { "max-epoch-size",'e',T_max_epoch_size,EN(MAX_EPOCH_SIZE) },
-		 { "max-buffers",'b',	T_max_buffers,	EN(MAX_BUFFERS) },
-		 { "unplug-watermark",'u',T_unplug_watermark, EN(UNPLUG_WATERMARK) },
-		 { "connect-int",'c',	T_try_connect_int, EN(CONNECT_INT) },
-		 { "ping-int",'i',	T_ping_int,	   EN(PING_INT) },
-		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN(SNDBUF_SIZE) },
-		 { "ko-count",'k',	T_ko_count,	   EN(KO_COUNT) },
-		 { "allow-two-primaries",'m',T_two_primaries, EB },
-		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   ES },
-		 { "shared-secret",'x',	T_shared_secret,   ES },
-		 { "after-sb-0pri",'A',	T_after_sb_0p,EH(asb0p_n,AFTER_SB_0P) },
-		 { "after-sb-1pri",'B',	T_after_sb_1p,EH(asb1p_n,AFTER_SB_1P) },
-		 { "after-sb-2pri",'C',	T_after_sb_2p,EH(asb2p_n,AFTER_SB_2P) },
-		 { "discard-my-data",'D', T_want_lose,     EB },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
-
-	{"disconnect", P_disconnect, generic_config_cmd, NULL, NULL },
-
-	{"resize", P_resize, generic_config_cmd, NULL,
-	 (struct drbd_option[]) {
-		 { "size",'s',T_resize_size,		EN(DISK_SIZE_SECT) },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
-
-	{"syncer", P_syncer_conf, generic_config_cmd, NULL,
-	 (struct drbd_option[]) {
-		 { "rate",'r',T_rate,			EN(RATE) },
-		 { "after",'a',T_after,			EN(AFTER) },
-		 { "al-extents",'e',T_al_extents,	EN(AL_EXTENTS) },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
-
-	{"invalidate", P_invalidate, generic_config_cmd, NULL, NULL },
-	{"invalidate-remote", P_invalidate_peer, generic_config_cmd, NULL, NULL },
-	{"pause-sync", P_pause_sync, generic_config_cmd, NULL, NULL },
-	{"resume-sync", P_resume_sync, generic_config_cmd, NULL, NULL },
-	{"suspend-io", P_suspend_io, generic_config_cmd, NULL, NULL },
-	{"resume-io", P_resume_io, generic_config_cmd, NULL, NULL },
-	{"outdate", P_outdate, generic_config_cmd, NULL, NULL },
-
-	// {"down", 0 , down_cmd, NULL, NULL },
-
-	/*
-	{"state", cmd_state,               0, 0, },
-	{"cstate", cmd_cstate,             0, 0, },
-	{"dstate", cmd_dstate,             0, 0, },
-	{"show-gi", cmd_show_gi,           0, 0, },
-	{"get-gi", cmd_get_gi,             0, 0, }, */
-	{"show", P_get_config, show_cmd, NULL, NULL },
-};
-
-#define EM(C) [ C - RetCodeBase ]
-
-static const char *error_messages[] = {
-	EM(NoError) = "No further Information available.",
-	EM(LAAlreadyInUse) = "Local address(port) already in use.",
-	EM(OAAlreadyInUse) = "Remote address(port) already in use.",
-	EM(LDNameInvalid) = "Can not open backing device.",
-	EM(MDNameInvalid) = "Can not open meta device.",
-	EM(LDAlreadyInUse) = "Lower device already in use.",
-	EM(LDNoBlockDev) = "Lower device is not a block device.",
-	EM(MDNoBlockDev) = "Meta device is not a block device.",
-	EM(LDOpenFailed) = "Open of lower device failed.",
-	EM(MDOpenFailed) = "Open of meta device failed.",
-	EM(LDDeviceTooSmall) = "Low.dev. smaller than requested DRBD-dev. size.",
-	EM(MDDeviceTooSmall) = "Meta device too small.",
-	EM(LDNoConfig) = "You have to use the disk command first.",
-	EM(LDMounted) = "Lower device is already mounted.",
-	EM(MDMounted) = "Meta device is already mounted.",
-	EM(LDMDInvalid) = "Lower device / meta device / index combination invalid.",
-	EM(LDDeviceTooLarge) = "Currently we only support devices up to 3.998TB.\n"
-	"(up to 2TB in case you do not have CONFIG_LBD set)"
-	"Contact office@linbit.com, if you need more.",
-	EM(MDIOError) = "IO error(s) orruced during initial access to meta-data.\n",
-	EM(MDInvalid) = "No valid meta-data signature found.\n)"
-	"Use 'drbdadm create-md res' to initialize meta-data area.\n",
-	EM(CRAMAlgNotAvail) = "The 'cram-hmac-alg' you specified is not known in )"
-	"the kernel.\n",
-	EM(CRAMAlgNotDigest) = "The 'cram-hmac-alg' you specified is not a digest.",
-	EM(KMallocFailed) = "kmalloc() failed. Out of memory?",
-	EM(DiscardNotAllowed) = "--discard-my-data not allowed when primary.",
-	EM(HaveDiskConfig) = "HaveDiskConfig",
-	EM(UnknownMandatoryTag) = "UnknownMandatoryTag",
-	EM(MinorNotKnown) = "MinorNotKnown",
-	EM(StateNotAllowed) = "StateNotAllowed",
-	EM(GotSignal) = "GotSignal",
-	EM(NoResizeDuringResync) = "Resize not allowed during resync.",
-	EM(APrimaryNodeNeeded) = "Need the a primary node to resize.",
-	EM(SyncAfterInvalid) = "The sync after minor number is invalid",
-	EM(SyncAfterCycle-) = "This would cause a sync-after dependency cycle",
-	EM(PauseFlagAlreadySet) = "PauseFlagAlreadySet",
-	EM(PauseFlagAlreadyClear) = "PauseFlagAlreadyClear",
-	EM(DiskLowerThanOutdated) = "DiskLowerThanOutdated",
-	EM(FailedToClaimMyself) = "FailedToClaimMyself",
-};
-
-char* cmdname = 0;
-
-int dump_tag_list(unsigned short *tlc)
-{
-	enum drbd_tags tag;
-	unsigned int tag_nr;
-	int len;
-	int integer;
-	char bit;
-	__u64 int64;
-	char* string;
-	int found_unknown=0;
-
-	while( (tag = *tlc++ ) != TT_END) {
-		len = *tlc++;
-		if(tag == TT_REMOVED) goto skip;
-
-		tag_nr = tag_number(tag);
-		if(tag_nr<ARRY_SIZE(tag_descriptions)) {
-			string = tag_descriptions[tag_nr].name;
-		} else {
-			string = "unknown tag";
-			found_unknown=1;
-		}
-		printf("# (%2d) %16s = ",tag_nr,string);
-		switch(tag_type(tag)) {
-		case TT_INTEGER: 
-			integer = *(int*)tlc;
-			printf("(integer) %d",integer);
-			break;
-		case TT_INT64:
-			int64 = *(__u64*)tlc;
-			printf("(int64) %lld",(long long)int64);
-			break;
-		case TT_BIT:
-			bit = *(char*)tlc;
-			printf("(bit) %s", bit ? "on" : "off");
-			break;
-		case TT_STRING:
-			string = (char*)tlc;
-			printf("(string)'%s'",string);
-			break;
-		}
-		printf(" \t[len: %u]\n",len);
-	skip:
-		tlc = (unsigned short*)((char*)tlc + len);
-	}
-
-	return found_unknown;
-}
-
-struct drbd_tag_list *create_tag_list(int size)
-{
-	struct drbd_tag_list *tl;
-	
-	tl = malloc(sizeof(struct drbd_tag_list));
-	tl->nl_header  = malloc(NLMSG_SPACE( sizeof(struct cn_msg) +
-					     sizeof(struct drbd_nl_cfg_req) + 
-					     size) );
-	tl->cn_header = NLMSG_DATA(tl->nl_header);
-	tl->drbd_p_header = (struct drbd_nl_cfg_req*) tl->cn_header->data;
-	tl->tag_list_start = tl->drbd_p_header->tag_list;
-	tl->tag_list_cpos = tl->tag_list_start;
-	tl->tag_size = size;
-
-	return tl;
-}
-
-void add_tag(struct drbd_tag_list *tl, int tag, void *data, int data_len)
-{
-	if( (tl->tag_list_cpos - tl->tag_list_start) + data_len 
-	    > tl->tag_size ) {
-		fprintf(stderr, "Tag list size exceeded!\n");
-		exit(20);
-	}
-	*tl->tag_list_cpos++ = tag;
-	*tl->tag_list_cpos++ = data_len;
-	memcpy(tl->tag_list_cpos,data,data_len);
-	tl->tag_list_cpos = (unsigned short*)((char*)tl->tag_list_cpos + data_len);
-}
-
-void free_tag_list(struct drbd_tag_list *tl)
-{
-	free(tl->nl_header);
-	free(tl);
-}
-
-int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
-{
-	struct stat sb;
-	int device_fd;
-	int err;
-
-	if ((device_fd = open(arg,O_RDWR))==-1) {
-		PERROR("Can not open device '%s'", arg);
-		return 20;
-	}
-
-	if ( (err=fstat(device_fd, &sb)) ) {
-		PERROR("fstat(%s) failed", arg);
-		return 20;
-	}
-
-	if(!S_ISBLK(sb.st_mode)) {
-		fprintf(stderr, "%s is not a block device!\n", arg);
-		return 20;
-	}
-	
-	close(device_fd);
-
-	add_tag(tl,ad->tag,arg,strlen(arg)+1); // include the null byte. 
-
-	return 0;
-}
-
-int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
-{
-	int idx;
-
-	if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT;
-	else if(!strcmp(arg,"flex")) idx = DRBD_MD_INDEX_FLEX_EXT;
-	else idx = m_strtoll(arg,1);
-
-	add_tag(tl,ad->tag,&idx,sizeof(idx));
-
-	return 0;
-}
-
-const char* addr_part(const char* s)
-{
-	static char buffer[200];
-	char *b;
-
-	b=strchr(s,':');
-	if(b) {
-		strncpy(buffer,s,b-s);
-		buffer[b-s]=0;
-		return buffer;
-	}
-	return s;
-}
-
-int port_part(const char* s)
-{
-	char *b;
-
-	b=strchr(s,':');
-
-	// m_strtoll_range(b+1,1, "port", DRBD_PORT_MIN, DRBD_PORT_MAX);
-	if(b) return m_strtoll(b+1,1);
-	return 7788;
-}
-
-unsigned long resolv(const char* name)
-{
-	unsigned long retval;
-
-	if((retval = inet_addr(name)) == INADDR_NONE ) {
-		struct hostent *he;
-		he = gethostbyname(name);
-		if (!he) {
-			PERROR("can not resolv the hostname");
-			exit(20);
-		}
-		retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr;
-	}
-	return retval;
-}
-
-int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
-{
-	struct sockaddr_in addr;
-	int addr_len = sizeof(struct sockaddr_in);
-
-	addr.sin_port = htons(port_part(arg));
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = resolv(addr_part(arg));
-
-	add_tag(tl,ad->tag,&addr,addr_len);
-
-	return 0;
-}
-
-int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
-{
-	int prot;
-
-	if(!strcmp(arg,"A") || !strcmp(arg,"a")) {
-		prot=DRBD_PROT_A;
-	} else if (!strcmp(arg,"B") || !strcmp(arg,"b")) {
-		prot=DRBD_PROT_B;
-	} else if (!strcmp(arg,"C") || !strcmp(arg,"c")) {
-		prot=DRBD_PROT_C;
-	} else {
-		fprintf(stderr, "'%s' is no valid protocol.\n", arg);
-		return 20;
-	}
-
-	add_tag(tl,ad->tag,&prot,sizeof(prot));
-
-	return 0;
-}
-
-int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
-{
-	char bit=1;
-
-	add_tag(tl,od->tag,&bit,sizeof(bit));
-
-	return 0;
-}
-
-int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
-{
-	const unsigned long long min = od->numeric_param.min;
-	const unsigned long long max = od->numeric_param.max;
-	const unsigned char default_unit = od->numeric_param.default_unit;
-	unsigned long long l;
-	int i;
-	char unit[] = {0,0};
-
-	l = m_strtoll(arg, default_unit);
-
-	if (min > l || l > max) {
-		unit[0] = default_unit > 1 ? default_unit : 0;
-		fprintf(stderr,"%s %s => %llu%s out of range [%llu..%llu]%s\n",
-			od->name, arg, l, unit, min, max, unit);
-		return(20);
-	}
-
-	switch(tag_type(od->tag)) {
-	case TT_INT64:
-		add_tag(tl,od->tag,&l,sizeof(l));
-		break;
-	case TT_INTEGER:
-		i=l;
-		add_tag(tl,od->tag,&i,sizeof(i));
-		break;
-	default:
-		fprintf(stderr, "internal error in conv_numeric()\n");
-	}
-	return 0;
-
-}
-
-int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
-{
-	const char** handler_names = od->handler_param.handler_names;
-	const int number_of_handlers = od->handler_param.number_of_handlers;
-	int i,nr;
-
-	for(i=0;i<number_of_handlers;i++) {
-		if(strcmp(arg,handler_names[i])==0) {
-			nr = i;
-			break;
-		}
-	}
-
-	add_tag(tl,od->tag,&nr,sizeof(nr));
-
-	return 0;
-}
-
-int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
-{
-	add_tag(tl,od->tag,arg,strlen(arg)+1);
-
-	return 0;
-}
-
-struct option *	make_longoptions(struct drbd_option* od)
-{
-	static struct option buffer[20];
-	int i=0;
-
-	while(od && od->name) {
-		buffer[i].name = od->name;
-		buffer[i].has_arg = tag_type(od->tag) == TT_BIT ? 
-			no_argument : required_argument ;
-		buffer[i].flag = NULL;
-		buffer[i].val = od->short_name;
-		if(i++ == 20) {
-			fprintf(stderr,"buffer in make_longoptions to small.\n");
-		}
-		od++;
-	}
-	
-	// The two omnipresent options:
-	buffer[i].name = "set-defaults";
-	buffer[i].has_arg = 0;
-	buffer[i].flag = NULL;
-	buffer[i].val = '(';
-	i++;
-
-	buffer[i].name = "create-device";
-	buffer[i].has_arg = 0;
-	buffer[i].flag = NULL;
-	buffer[i].val = ')';
-	i++;
-
-	buffer[i].name = NULL;
-	buffer[i].has_arg = 0;
-	buffer[i].flag = NULL;
-	buffer[i].val = 0;
-
-	return buffer;
-}
-
-struct drbd_option *find_opt_by_short_name(struct drbd_option *od, int c)
-{
-	while(od->name) {
-		if(od->short_name == c) return od;
-		od++;
-	}
-
-	return NULL;
-}
-
-void print_config_error( struct drbd_nl_cfg_reply *reply)
-{
-	int err_no = reply->ret_code;
-
-	if (err_no == NoError) return;
-	if (err_no == SS_Success) return;
-
-	if ( ( err_no >= AfterLastRetCode || err_no <= RetCodeBase ) &&
-	     ( err_no > SS_TowPrimaries || err_no < SS_CW_FailedByPeer) ) {
-		fprintf(stderr,"Error code %d unknown.\n"
-			"You should updated the drbd userland tools.\n",err_no);
-	} else {
-		if(err_no > RetCodeBase ) {
-			fprintf(stderr,"Failure: (%d) %s\n",err_no,
-				error_messages[err_no-RetCodeBase]);
-		} else {
-			fprintf(stderr,"State change failed: (%d) %s\n",
-				err_no, set_st_err_name(err_no));
-		}
-	}
-}
-
-#define RCV_SIZE NLMSG_SPACE(sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply))
-
-int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
-{
-	char buffer[ RCV_SIZE ];
-	struct drbd_nl_cfg_reply *reply;
-	struct drbd_argument *ad = cm->args;
-	struct drbd_option *od;
-	static struct option *lo;
-	struct drbd_tag_list *tl;
-	int c,i=0,rv=0,sk_nl;
-	int flags=0;
-
-	tl = create_tag_list(4096);
-
-	while(ad && ad->name) {
-		if(argc < i+1) {
-			fprintf(stderr,"Missing argument '%s'\n", ad->name);
-			print_command_usage(cm-commands, "");
-			rv=20;
-			break;
-		}
-		rv |= ad->convert_function(ad,tl,argv[i++]);
-		if(rv) break;
-		ad++;
-	}
-
-	lo = make_longoptions(cm->options);
-	opterr=0;
-	while( (c=getopt_long(argc,argv,make_optstring(lo,0),lo,0)) != -1 ) {
-		od = find_opt_by_short_name(cm->options,c);
-		if(od) rv |= od->convert_function(od,tl,optarg);
-		else {
-			if(c=='(') flags |= DRBD_NL_SET_DEFAULTS;
-			else if(c==')') flags |= DRBD_NL_CREATE_DEVICE;
-			else {
-				fprintf(stderr,
-					"%s: unrecognized option '%s'\n",
-					cmdname, argv[optind-1]);
-				rv=20;
-			}
-		}
-		if(rv) break;
-	}
-
-	add_tag(tl,TT_END,NULL,0); // close the tag list
-
-	if(rv == 0) {
-		// dump_tag_list(tl->tag_list_start);
-		sk_nl = open_cn();
-		if(sk_nl < 0) return 20;
-
-		send_tag_list_cn(sk_nl,tl,cm->packet_id,minor,flags);
-
-		receive_cn(sk_nl, (struct nlmsghdr*)buffer, RCV_SIZE );
-		close_cn(sk_nl);
-		reply = (struct drbd_nl_cfg_reply *)
-			((struct cn_msg *)NLMSG_DATA(buffer))->data;
-		print_config_error(reply);
-	}
-	free_tag_list(tl);
-
-	return rv;
-}
-
-#define ASSERT(exp) if (!(exp)) \
-		fprintf(stderr,"ASSERT( " #exp " ) in %s:%d\n", __FILE__,__LINE__);
-
-void show_numeric(struct drbd_option *od, unsigned short* tp)
-{
-	long long val;
-
-	switch(tag_type(*tp++)) {
-	case TT_INTEGER: 
-		ASSERT( *tp++ == sizeof(int) );
-		val = *(int*)tp;
-		break;
-	case TT_INT64:
-		ASSERT( *tp++ == sizeof(__u64) );
-		val = *(__u64*)tp;
-		break;
-	default: 
-		ASSERT(0);
-		val=0;
-	}
-
-	printf("\t%s\t\t%lld",od->name,val);
-	if(val == (long long) od->numeric_param.def) printf(" _is_default");
-	printf(";\n");
-}
-
-void show_handler(struct drbd_option *od, unsigned short* tp)
-{
-	const char** handler_names = od->handler_param.handler_names;
-	int i;
-
-	ASSERT( tag_type(*tp++) == TT_INTEGER );
-	ASSERT( *tp++ == sizeof(int) );
-	i = *(int*)tp;
-	printf("\t%s\t\t%s",od->name,handler_names[i]);
-	if( i == (long long)od->numeric_param.def) printf(" _is_default");
-	printf(";\n");
-}
-
-void show_bit(struct drbd_option *od, unsigned short* tp)
-{
-	ASSERT( tag_type(*tp++) == TT_BIT );
-	ASSERT( *tp++ == sizeof(char) );
-	if(*(char*)tp) printf("\t%s;\n",od->name);
-}
-
-void show_string(struct drbd_option *od, unsigned short* tp)
-{
-	ASSERT( tag_type(*tp++) == TT_STRING );
-	if( *tp++ > 0) printf("\t%s\t\t\"%s\";\n",od->name,(char*)tp);
-}
-
-unsigned short *look_for_tag(unsigned short *tlc, unsigned short tag)
-{
-	enum drbd_tags t;
-	int len;
-
-	while( (t = *tlc) != TT_END ) {
-		if(t == tag) return tlc;
-		tlc++;
-		len = *tlc++;
-		tlc = (unsigned short*)((char*)tlc + len);
-	}
-	return NULL;
-}
-
-void print_options(struct drbd_option *od, unsigned short *tlc, const char* sect_name)
-{
-	unsigned short *tp;
-	int opened = 0;
-
-	while(od->name) {
-		tp = look_for_tag(tlc,od->tag);
-		if(tp) {
-			if(!opened) {
-				opened=1;
-				printf("%s {\n",sect_name);
-			}
-			od->show_function(od,tp);
-			*tp = TT_REMOVED;
-		}
-		od++;
-	}
-	if(opened) {
-		printf("}\n");
-	}
-}
-
-char* consume_tag_string(enum drbd_tags tag, unsigned short *tlc)
-{
-	unsigned short *tp;
-	tp = look_for_tag(tlc,tag);
-	if(tp) {
-		*tp++ = TT_REMOVED;
-		if( *tp++ > 0) return (char*)tp;
-	}
-	return "";
-}
-
-int consume_tag_int(enum drbd_tags tag, unsigned short *tlc)
-{
-	unsigned short *tp;
-	tp = look_for_tag(tlc,tag);
-	if(tp) {
-		*tp++ = TT_REMOVED;
-		tp++;
-		return *(int *)tp;
-	}
-	return 0;
-}
-
-int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
-{
-	char buffer[ 4096 ];
-	struct drbd_tag_list *tl;
-	struct drbd_nl_cfg_reply *reply;
-	struct sockaddr_in *addr;
-	int sk_nl;
-	unsigned short *rtl;
-
-	int idx;
-	char* str;
-
-	ASSERT(cm->packet_id == P_get_config);
-
-	if(argc > 1) {
-		fprintf(stderr,"Ignoring excess arguments\n");
-	
-	}
-
-	tl = create_tag_list(2);
-	add_tag(tl,TT_END,NULL,0); // close the tag list
-
-	sk_nl = open_cn();
-	if(sk_nl < 0) return 20;
-
-	send_tag_list_cn(sk_nl,tl,cm->packet_id,minor,0);
-
-	receive_cn(sk_nl, (struct nlmsghdr*)buffer, 4096 );
-	close_cn(sk_nl);
-	reply = (struct drbd_nl_cfg_reply *)
-		((struct cn_msg *)NLMSG_DATA(buffer))->data;
-
-	rtl = reply->tag_list;
-
-	// find all commands that have options and print those...
-	for ( cm = commands ; cm < commands + ARRY_SIZE(commands) ; cm++ ) {
-		if(cm->options)
-			print_options(cm->options, rtl, cm->cmd);
-	}
-
-	// start of spagethi code...
-	idx = consume_tag_int(T_wire_protocol,rtl);
-	if(idx) printf("protocol %c;\n",'A'+idx-1);
-	str = consume_tag_string(T_backing_dev,rtl);
-	if(str) {
-		printf("_this_host {\n");
-		printf("\tdevice\t\t\"/dev/drbd%d\";\n",minor);
-		printf("\tdisk\t\t\"%s\";\n",str);
-		idx=consume_tag_int(T_meta_dev_idx,rtl);
-		switch(idx) {
-		case DRBD_MD_INDEX_INTERNAL:
-		case DRBD_MD_INDEX_FLEX_INT:
-			printf("\tmeta-disk\tinternal;\n");
-			consume_tag_string(T_meta_dev,rtl);
-			break;
-		case DRBD_MD_INDEX_FLEX_EXT:
-			printf("\tflexible-meta-disk\t\"%s\";\n",
-			       consume_tag_string(T_meta_dev,rtl));
-			break;
-		default:
-			printf("\tmeta-disk\t\"%s\" [ %d ];\n",
-			       consume_tag_string(T_meta_dev,rtl),idx);
-		}
-		str = consume_tag_string(T_my_addr,rtl);
-		if(str) {
-			addr = (struct sockaddr_in *)str;
-			printf("\taddress\t\t%s:%d;\n",
-			       inet_ntoa(addr->sin_addr),
-			       ntohs(addr->sin_port));
-		}
-		printf("}\n");
-	}
-
-	str = consume_tag_string(T_peer_addr,rtl);
-	if(str) {
-		printf("_remote_host {\n");
-		addr = (struct sockaddr_in *)str;
-		printf("\taddress\t\t%s:%d;\n",
-		       inet_ntoa(addr->sin_addr),
-		       ntohs(addr->sin_port));
-		printf("}\n");
-	}
-
-	if(dump_tag_list(reply->tag_list)) {
-		printf("# Found unknown tags, you should update your\n"
-		       "# userland tools\n");
-	}
-
-	return 0;
-}
-
-void print_command_usage(int i, const char *addinfo)
-    // CAUTION no range check for i
-{
-	struct drbd_argument *args;
-	struct drbd_option *options;
-#define  maxcol 100 // plus initial tab ...
-	static char line[maxcol+1];
-	int col,prevcol;
-
-	prevcol=col=0;
-
-	col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
-	if ((args = commands[i].args)) {
-		while (args->name) {
-			col += snprintf(line+col, maxcol-col, " %s", args->name);
-			args++;
-		}
-					
-	}
-	if (col > maxcol) {
-		printf("%s\n\t",line);
-		col=0;
-	}
-	prevcol=col;
-	if ((options = commands[i].options)) {
-		while (options->name) {
-			if (tag_type(options->tag) == TT_BIT) {
-				col += snprintf(line+col, maxcol-col,
-						" [{--%s|-%c}]",
-						options->name, options->short_name);
-			} else {
-				col += snprintf(line+col, maxcol-col,
-						" [{--%s|-%c} val]",
-						options->name, options->short_name);
-			}
-			if (col >= maxcol) {
-				line[prevcol]=0;
-				printf("%s\n\t",line);
-				prevcol=col=0;
-			} else {
-				prevcol=col;
-				options++;
-			}
-		}
-	}
-	line[col]=0;
-	printf("%s\n",line);
-	if (addinfo) {
-		printf("%s\n",addinfo);
-		exit(20);
-	}
-}
-
-void print_handler(const char* info, const char** handlers, unsigned int size)
-{
-	unsigned int i;
-
-	printf(info);
-
-	for(i=0;i<size;i++) {
-		if(handlers[i]) {
-			printf(" %s",handlers[i]);
-			if(i < size-1) printf(",");
-		}
-	}
-}
-
-void print_usage(const char* addinfo)
-{
-	size_t i;
-
-	printf("\nUSAGE: %s device command arguments options\n\n"
-	       "Device is usually /dev/drbdX or /dev/drbd/X.\n"
-	       "Commands, arguments and options are:\n",cmdname);
-
-
-	for (i = 0; i < ARRY_SIZE(commands); i++)
-		print_command_usage(i, 0);
-
-	printf("\nGeneral options: --create-device, --set-defaults\n");
-
-	print_handler("\non-io-error handlers:",on_error,ARRY_SIZE(on_error));
-	print_handler("\nfencing policies:",fencing_n,ARRY_SIZE(fencing_n));
-	print_handler("\nafter-sb-0pri handler:",asb0p_n,ARRY_SIZE(asb0p_n));
-	print_handler("\nafter-sb-1pri handler:",asb1p_n,ARRY_SIZE(asb1p_n));
-	print_handler("\nafter-sb-2pri handler:",asb2p_n,ARRY_SIZE(asb2p_n));
-
-	printf("\n\n");
-	/*
-	printf("\n\nVersion: "REL_VERSION" (api:%d)\n%s\n",
-	       API_VERSION, drbd_buildtag());
-	*/
-	if (addinfo)
-		printf("\n%s\n",addinfo);
-
-	exit(20);
-}
-
-int open_cn()
-{
-	int sk_nl;
-	int err;
-	struct sockaddr_nl my_nla;
-
-	sk_nl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-	if (sk_nl == -1) {
-		perror("socket() failed");
-		return -1;
-	}
-
-	my_nla.nl_family = AF_NETLINK;
-	my_nla.nl_groups = -1; //CN_IDX_DRBD; 
-	my_nla.nl_pid = getpid();
-
-	err = bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla));
-	if (err == -1) {
-		err = errno;
-		perror("bind() failed");
-		if(err == ENOENT) {
-			fprintf(stderr,"DRBD driver not present in the kernel?\n");
-		}
-		return -1;
-	}
-
-	return sk_nl;
-}
-
-
-int send_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size)
-{
-	struct cn_msg *cn_hdr;
-	cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
-	int rr;
-
-	/* fill the netlink header */
-	nl_hdr->nlmsg_len = NLMSG_LENGTH(size - sizeof(struct nlmsghdr));
-	nl_hdr->nlmsg_type = NLMSG_DONE;
-	nl_hdr->nlmsg_flags = 0;
-	nl_hdr->nlmsg_seq = 0;
-	nl_hdr->nlmsg_pid = getpid();
-	/* fill the connector header */
-	cn_hdr->id.idx = CN_IDX_DRBD;
-	cn_hdr->seq = 0;
-	cn_hdr->ack = 0;
-	cn_hdr->len = size - sizeof(struct nlmsghdr) - sizeof(struct cn_msg);
-
-	rr = send(sk_nl,nl_hdr,nl_hdr->nlmsg_len,0);
-	if( rr != (ssize_t)nl_hdr->nlmsg_len) {
-		perror("send() failed");
-		return -1;
-	}
-	return rr;
-}
-
-int receive_cn(int sk_nl, struct nlmsghdr* nl_hdr, int size)
-{
-	int rr;
-
-	rr = recv(sk_nl,nl_hdr,size,0);
-
-	if( rr < 0 ) {
-		perror("recv() failed");
-		return -1;
-	}
-	return rr;
-}
-
-int send_tag_list_cn(int sk_nl, struct drbd_tag_list *tl, const int packet_id, int minor, int flags)
-{
-	tl->cn_header->id.val = packet_id;
-	tl->drbd_p_header->drbd_minor = minor;
-	tl->drbd_p_header->flags = flags;
-
-	return send_cn(sk_nl, tl->nl_header, (char*)tl->tag_list_cpos - 
-		       (char*)tl->nl_header);
-}
-
-void close_cn(int sk_nl)
-{
-	close(sk_nl);
-}
-
-int main(int argc, char** argv)
-{
-	int help = 0;
-	unsigned int i;
-	int minor;
-	int drbd_fd,lock_fd;
-	struct drbd_cmd *cmd;
-
-	chdir("/");
-
-	if ( (cmdname = strrchr(argv[0],'/')) )
-		argv[0] = ++cmdname;
-	else
-		cmdname = argv[0];
-
-	/* == '-' catches -h, --help, and similar */
-	if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-'))
-		help = 1;
-
-	if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
-
-	cmd=NULL;
-	for(i=0;i<ARRY_SIZE(commands);i++) {
-		if(strcmp(argv[2],commands[i].cmd)==0) {
-			cmd = commands+i;
-			break;
-		}
-	}
-
-	if(cmd) {
-		drbd_fd = dt_lock_open_drbd(argv[1], &lock_fd, 1 );
-		minor=dt_minor_of_dev(argv[1]);
-		commands[i].function(commands+i,minor,argc-3,argv+3);
-		dt_close_drbd_unlock(drbd_fd,lock_fd);
-	} else {
-		print_usage("invalid command");
-	}
-
-	return 0;
-}

From drbd-cvs at lists.linbit.com  Mon Aug 28 13:48:33 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Aug 28 13:48:34 2006
Subject: [DRBD-cvs] svn commit by phil - r2388 - in trunk: . drbd user -
	Slowly shaking out the bugs of the new netlink/connecto
Message-ID: <20060828114833.8BE0D2DF6550@mail.linbit.com>

Author: phil
Date: 2006-08-28 13:48:29 +0200 (Mon, 28 Aug 2006)
New Revision: 2388

Modified:
   trunk/Makefile
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_nl.c
   trunk/user/Makefile
   trunk/user/drbdadm.h
   trunk/user/drbdadm_adjust.c
   trunk/user/drbdadm_main.c
   trunk/user/drbdadm_parser.c
   trunk/user/drbdadm_scanner.fl
   trunk/user/drbdsetup.c
   trunk/user/drbdtool_common.c
Log:
Slowly shaking out the bugs of the new netlink/connector
based drbdsetup <-> kernel interface .


Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/Makefile	2006-08-28 11:48:29 UTC (rev 2388)
@@ -13,7 +13,7 @@
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with drbd; see the file COPYING.  If not, write to
+# along with drbd
 # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/drbd/drbd_main.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -2084,11 +2084,6 @@
 	/* no need to lock it, I'm the only thread alive */
 	if ( mdev->epoch_size !=  0)
 		ERR("epoch_size:%d\n",mdev->epoch_size);
-#define ZAP(x) memset(&x,0,sizeof(x))
-	ZAP(mdev->sync_conf);
-	// ZAP(mdev->data); Not yet!
-	// ZAP(mdev->meta); Not yet!
-#undef ZAP
 	mdev->al_writ_cnt  =
 	mdev->bm_writ_cnt  =
 	mdev->read_cnt     =
@@ -2361,7 +2356,6 @@
 	disk->first_minor = minor;
 	disk->fops = &drbd_ops;
 	sprintf(disk->disk_name, DEVICE_NAME "%d", minor);
-	sprintf(disk->devfs_name, "%s/%d", drbd_devfs_name, minor);
 	disk->private_data = mdev;
 	add_disk(disk);
 		

Modified: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/drbd/drbd_nl.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -690,12 +690,11 @@
 		goto fail;
 	}
 
-	if(inc_local(mdev)) {
+	if( !(nlp->flags & DRBD_NL_SET_DEFAULTS) && inc_local(mdev) ) {
 		memcpy(&nbc->dc,&mdev->bc->dc,sizeof(struct disk_conf));
 		dec_local(mdev);
-	} else memset(&nbc->dc,0,sizeof(struct disk_conf));
-
-	if(nlp->flags & DRBD_NL_SET_DEFAULTS) {
+	} else {
+		memset(&nbc->dc,0,sizeof(struct disk_conf));
 		nbc->dc.disk_size   = DRBD_DISK_SIZE_SECT_DEF;
 		nbc->dc.on_io_error = DRBD_ON_IO_ERROR_DEF;
 		nbc->dc.fencing     = DRBD_FENCING_DEF;
@@ -1019,12 +1018,11 @@
 		goto fail;
 	}
 
-	if(inc_net(mdev)) {
+	if( !(nlp->flags & DRBD_NL_SET_DEFAULTS) && inc_net(mdev)) {
 		memcpy(new_conf,mdev->net_conf,sizeof(struct net_conf));
 		dec_local(mdev);
-	} else memset(new_conf,0,sizeof(struct net_conf));
-
-	if(nlp->flags & DRBD_NL_SET_DEFAULTS) {
+	} else {
+		memset(new_conf,0,sizeof(struct net_conf));
 		new_conf->timeout         = DRBD_TIMEOUT_DEF;
 		new_conf->try_connect_int = DRBD_CONNECT_INT_DEF;
 		new_conf->ping_int        = DRBD_PING_INT_DEF;

Modified: trunk/user/Makefile
===================================================================
--- trunk/user/Makefile	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/Makefile	2006-08-28 11:48:29 UTC (rev 2388)
@@ -17,20 +17,28 @@
 # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
+KDIR := /lib/modules/$(shell uname -r)/build
+
 CFLAGS = -g -O2 -c -W -Wall -I../drbd -I$(KDIR)/include
 CC = gcc
 
 drbdadm-obj = drbdadm_scanner.o drbdadm_parser.o drbdadm_main.o \
 	      drbdadm_adjust.o drbdtool_common.o drbdadm_usage_cnt.o \
-	      ../drbd/drbd_buildtag.o
+	      drbd_buildtag.o
 
-drbdsetup-obj = drbdsetup.o drbdtool_common.o ../drbd/drbd_buildtag.o \
-	        ../drbd/drbd_strings.o
+drbdsetup-obj = drbdsetup.o drbdtool_common.o drbd_buildtag.o \
+	        drbd_strings.o
 
-drbdmeta-obj = drbdmeta.o drbdmeta_scanner.o drbdtool_common.o ../drbd/drbd_buildtag.o
+drbdmeta-obj = drbdmeta.o drbdmeta_scanner.o drbdtool_common.o drbd_buildtag.o
 
 all: drbdadm drbdmeta drbdsetup
 
+drbd_buildtag.c: ../drbd/drbd_buildtag.c
+	cp $^ $@ 
+
+drbd_strings.c: ../drbd/drbd_strings.c
+	cp $^ $@ 
+
 drbdadm: $(drbdadm-obj)
 	$(CC) -o $@ $^ 
 
@@ -51,6 +59,7 @@
 clean:
 	rm -f drbdadm_scanner.c drbdmeta_scanner.c
 	rm -f drbdsetup drbdadm drbdmeta *.o
+	rm -f drbd_buildtag.c drbd_strings.c
 	rm -f *~
 
 distclean: clean
@@ -72,13 +81,14 @@
 	rm -f $(PREFIX)/sbin/drbdadm
 
 ###dependencies
-drbdsetup.o:       drbdtool_common.h           ../drbd/linux/drbd_limits.h
-drbdtool_common.o: drbdtool_common.h          
+drbdsetup.o:       drbdtool_common.h ../drbd/linux/drbd_limits.h
+drbdsetup.o:       ../drbd/linux/drbd_tag_magic.h ../drbd/linux/drbd.h
+drbdsetup.o:       ../drbd/linux/drbd_config.h ../drbd/linux/drbd_nl.h
+drbdtool_common.o: drbdtool_common.h    
 drbdadm_main.o:    drbdtool_common.h drbdadm.h
 drbdadm_adjust.o:  drbdtool_common.h drbdadm.h
 drbdadm_parser.o:  drbdtool_common.h drbdadm.h ../drbd/linux/drbd_limits.h
 drbdadm_scanner.o:                   drbdadm.h               drbdadm_parser.h 
 drbdsetup.o:       drbdtool_common.h           ../drbd/linux/drbd_limits.h
-drbdsetup.o: ../drbd/linux/drbd.h ../drbd/linux/drbd_config.h
 drbdmeta.o:        drbdtool_common.h drbd_endian.h 
 drbdadm_usage_cnt.o: drbdadm.h drbd_endian.h

Modified: trunk/user/drbdadm.h
===================================================================
--- trunk/user/drbdadm.h	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdadm.h	2006-08-28 11:48:29 UTC (rev 2388)
@@ -68,8 +68,6 @@
   char* name;
   char* device;
   char* disk;
-  int disk_major;
-  int disk_minor;
   char* address;
   char* port;
   char* meta_disk;

Modified: trunk/user/drbdadm_adjust.c
===================================================================
--- trunk/user/drbdadm_adjust.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdadm_adjust.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -139,15 +139,6 @@
 	return !strcmp(conf->protocol, running->protocol);
 }
 
-static int dev_eq(char* device_name, unsigned int g_major, unsigned int g_minor)
-{
-	struct stat sb;
-	
-	if(stat(device_name,&sb)) return 0;
-
-	return major(sb.st_rdev) == g_major && minor(sb.st_rdev) == g_minor;
-}
-
 /* Are both internal, or are both not internal. */
 static int int_eq(char* m_conf, char* m_running)
 {
@@ -158,10 +149,10 @@
 {
 	int eq = 1;
 
-	eq &= dev_eq(conf->disk,running->disk_major,running->disk_minor);
+	eq &= !strcmp(conf->disk,running->disk);
 	eq &= int_eq(conf->meta_disk,running->meta_disk);
 	if(!strcmp(conf->meta_disk,"internal")) return eq;
-	eq &= dev_eq(conf->meta_disk,running->meta_major,running->meta_minor);
+	eq &= !strcmp(conf->meta_disk,running->meta_disk);
 
 	return eq;
 }

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdadm_main.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -623,8 +623,14 @@
   argv[argc++]=res->me->device;
   argv[argc++]="disk";
   argv[argc++]=res->me->disk;
-  argv[argc++]=res->me->meta_disk;
+  if(!strcmp(res->me->meta_disk,"internal")) {
+    argv[argc++]=res->me->disk;
+  } else {
+    argv[argc++]=res->me->meta_disk;
+  }
   argv[argc++]=res->me->meta_index;
+  argv[argc++]="--set-defaults";
+  argv[argc++]="--create-device";
   opt=res->disk_options;
   make_options(opt);
   argv[argc++]=0;
@@ -790,6 +796,8 @@
   ssprintf(argv[argc++],"%s:%s",res->peer->address,res->peer->port);
   argv[argc++]=res->protocol;
 
+  argv[argc++]="--set-defaults";
+  argv[argc++]="--create-device";
   opt=res->net_options;
   make_options(opt);
 
@@ -829,6 +837,8 @@
   argv[argc++]=res->me->device;
   argv[argc++]="syncer";
 
+  argv[argc++]="--set-defaults";
+  argv[argc++]="--create-device";
   opt=res->sync_options;
   make_options(opt);
   argv[argc++]=0;

Modified: trunk/user/drbdadm_parser.c
===================================================================
--- trunk/user/drbdadm_parser.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdadm_parser.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -338,19 +338,7 @@
 			host->disk = yylval.txt;
 			check_uniq("disk", "%s:%s:%s", "disk",
 				   host->name, yylval.txt);
-			switch (yylex()) {
-			case TK__MAJOR:
-				EXP(TK_INTEGER);
-				host->disk_major = atoi(yylval.txt);
-				EXP(TK__MINOR);
-				EXP(TK_INTEGER);
-				host->disk_minor = atoi(yylval.txt);
-				EXP(';');
-			case ';':
-				break;
-			default:
-				pe_expected("_major | ;");
-			}
+			EXP(';');
 			break;
 		case TK_DEVICE:
 			check_uniq("device statement", "%s:%s:device",
@@ -383,19 +371,7 @@
 				EXP(TK_INTEGER);
 				host->meta_index = yylval.txt;
 				EXP(']');
-				switch (yylex()) {
-				case TK__MAJOR:
-					EXP(TK_INTEGER);
-					host->meta_major = atoi(yylval.txt);
-					EXP(TK__MINOR);
-					EXP(TK_INTEGER);
-					host->meta_minor = atoi(yylval.txt);
-					EXP(';');
-				case ';':
-					break;
-				default:
-					pe_expected("_major | ;");
-				}
+				EXP(';');
 			} else {
 				EXP(';');
 			}

Modified: trunk/user/drbdadm_scanner.fl
===================================================================
--- trunk/user/drbdadm_scanner.fl	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdadm_scanner.fl	2006-08-28 11:48:29 UTC (rev 2388)
@@ -63,8 +63,6 @@
 flexible-meta-disk	{ DP; return TK_FLEX_META_DISK;		}
 usage-count 		{ DP; return TK_USAGE_COUNT;		}
 _is_default 		{ DP; return TK__IS_DEFAULT;		}
-_major	 		{ DP; return TK__MAJOR;			}
-_minor	 		{ DP; return TK__MINOR;			}
 _this_host 		{ DP; return TK__THIS_HOST;		}
 _remote_host 		{ DP; return TK__REMOTE_HOST;		}
 size			{ DP; CP; RC(DISK_SIZE); return TK_DISK_OPTION;	}

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdsetup.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -87,9 +87,9 @@
 	void (*show_function)(struct drbd_option *,unsigned short*);
 	union {
 		struct {
-			const unsigned long long min;
-			const unsigned long long max;
-			const unsigned long long def;
+			const long long min;
+			const long long max;
+			const long long def;
 			const unsigned char default_unit;
 		} numeric_param;
 		struct {
@@ -118,9 +118,11 @@
 
 // other functions
 void print_command_usage(int i, const char *addinfo);
+
 // command functions
 int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
 int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+int down_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
 // convert functions for arguments
 int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
 int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
@@ -171,10 +173,10 @@
 	[PanicPrimary]      = "panic"
 };
 
-#define EN(N) \
+#define EN(N,U) \
 	conv_numeric, show_numeric, \
 	{ .numeric_param = { DRBD_ ## N ## _MIN, DRBD_ ## N ## _MAX, \
-		DRBD_ ## N ## _DEF ,0  } }
+		DRBD_ ## N ## _DEF ,U  } }
 #define EH(N,D) \
 	conv_handler, show_handler, { .handler_param = { N, ARRY_SIZE(N), \
 	DRBD_ ## D ## _DEF } }
@@ -196,7 +198,7 @@
 		 { "meta_data_index",	T_meta_dev_idx,	conv_md_idx },
 		 { NULL,                0,           	NULL}, },
 	 (struct drbd_option[]) {
-		 { "size",'d',		T_disk_size,	EN(DISK_SIZE_SECT) },
+		 { "size",'d',		T_disk_size,	EN(DISK_SIZE_SECT,'s') },
 		 { "on-io-error",'e',	T_on_io_error,	EH(on_error,ON_IO_ERROR) },
 		 { "fencing",'f',	T_fencing,      EH(fencing_n,FENCING) },
 		 { NULL,0,0,NULL,NULL, { } }, }, },
@@ -210,14 +212,14 @@
 		 { "protocol",		T_wire_protocol,conv_protocol },
  		 { NULL,                0,           	NULL}, },
 	 (struct drbd_option[]) {
-		 { "timeout",'t',	T_timeout,	EN(TIMEOUT) },
-		 { "max-epoch-size",'e',T_max_epoch_size,EN(MAX_EPOCH_SIZE) },
-		 { "max-buffers",'b',	T_max_buffers,	EN(MAX_BUFFERS) },
-		 { "unplug-watermark",'u',T_unplug_watermark, EN(UNPLUG_WATERMARK) },
-		 { "connect-int",'c',	T_try_connect_int, EN(CONNECT_INT) },
-		 { "ping-int",'i',	T_ping_int,	   EN(PING_INT) },
-		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN(SNDBUF_SIZE) },
-		 { "ko-count",'k',	T_ko_count,	   EN(KO_COUNT) },
+		 { "timeout",'t',	T_timeout,	EN(TIMEOUT,1) },
+		 { "max-epoch-size",'e',T_max_epoch_size,EN(MAX_EPOCH_SIZE,1) },
+		 { "max-buffers",'b',	T_max_buffers,	EN(MAX_BUFFERS,1) },
+		 { "unplug-watermark",'u',T_unplug_watermark, EN(UNPLUG_WATERMARK,1) },
+		 { "connect-int",'c',	T_try_connect_int, EN(CONNECT_INT,1) },
+		 { "ping-int",'i',	T_ping_int,	   EN(PING_INT,1) },
+		 { "sndbuf-size",'S',	T_sndbuf_size,	   EN(SNDBUF_SIZE,1) },
+		 { "ko-count",'k',	T_ko_count,	   EN(KO_COUNT,1) },
 		 { "allow-two-primaries",'m',T_two_primaries, EB },
 		 { "cram-hmac-alg",'a',	T_cram_hmac_alg,   ES },
 		 { "shared-secret",'x',	T_shared_secret,   ES },
@@ -231,14 +233,14 @@
 
 	{"resize", P_resize, generic_config_cmd, NULL,
 	 (struct drbd_option[]) {
-		 { "size",'s',T_resize_size,		EN(DISK_SIZE_SECT) },
+		 { "size",'s',T_resize_size,		EN(DISK_SIZE_SECT,'s') },
 		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"syncer", P_syncer_conf, generic_config_cmd, NULL,
 	 (struct drbd_option[]) {
-		 { "rate",'r',T_rate,			EN(RATE) },
-		 { "after",'a',T_after,			EN(AFTER) },
-		 { "al-extents",'e',T_al_extents,	EN(AL_EXTENTS) },
+		 { "rate",'r',T_rate,			EN(RATE,'k') },
+		 { "after",'a',T_after,			EN(AFTER,1) },
+		 { "al-extents",'e',T_al_extents,	EN(AL_EXTENTS,1) },
 		 { NULL,0,0,NULL,NULL, { } }, }, },
 
 	{"invalidate", P_invalidate, generic_config_cmd, NULL, NULL },
@@ -248,9 +250,8 @@
 	{"suspend-io", P_suspend_io, generic_config_cmd, NULL, NULL },
 	{"resume-io", P_resume_io, generic_config_cmd, NULL, NULL },
 	{"outdate", P_outdate, generic_config_cmd, NULL, NULL },
+	{"down", 0, down_cmd, NULL, NULL },
 
-	// {"down", 0 , down_cmd, NULL, NULL },
-
 	/*
 	{"state", cmd_state,               0, 0, },
 	{"cstate", cmd_cstate,             0, 0, },
@@ -298,13 +299,14 @@
 	EM(NoResizeDuringResync) = "Resize not allowed during resync.",
 	EM(APrimaryNodeNeeded) = "Need the a primary node to resize.",
 	EM(SyncAfterInvalid) = "The sync after minor number is invalid",
-	EM(SyncAfterCycle-) = "This would cause a sync-after dependency cycle",
+	EM(SyncAfterCycle) = "This would cause a sync-after dependency cycle",
 	EM(PauseFlagAlreadySet) = "PauseFlagAlreadySet",
 	EM(PauseFlagAlreadyClear) = "PauseFlagAlreadyClear",
 	EM(DiskLowerThanOutdated) = "DiskLowerThanOutdated",
 	EM(FailedToClaimMyself) = "FailedToClaimMyself",
 };
 
+const char empty_string[] = "";
 char* cmdname = 0;
 
 int dump_tag_list(unsigned short *tlc)
@@ -315,7 +317,7 @@
 	int integer;
 	char bit;
 	__u64 int64;
-	char* string;
+	const char* string;
 	int found_unknown=0;
 
 	while( (tag = *tlc++ ) != TT_END) {
@@ -425,7 +427,7 @@
 	int idx;
 
 	if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT;
-	else if(!strcmp(arg,"flex")) idx = DRBD_MD_INDEX_FLEX_EXT;
+	else if(!strcmp(arg,"flexible")) idx = DRBD_MD_INDEX_FLEX_EXT;
 	else idx = m_strtoll(arg,1);
 
 	add_tag(tl,ad->tag,&idx,sizeof(idx));
@@ -508,7 +510,7 @@
 	return 0;
 }
 
-int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg __attribute((unused)))
 {
 	char bit=1;
 
@@ -519,10 +521,10 @@
 
 int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
 {
-	const unsigned long long min = od->numeric_param.min;
-	const unsigned long long max = od->numeric_param.max;
+	const long long min = od->numeric_param.min;
+	const long long max = od->numeric_param.max;
 	const unsigned char default_unit = od->numeric_param.default_unit;
-	unsigned long long l;
+	long long l;
 	int i;
 	char unit[] = {0,0};
 
@@ -731,7 +733,7 @@
 		val=0;
 	}
 
-	printf("\t%s\t\t%lld",od->name,val);
+	printf("\t%-16s\t%lld",od->name,val);
 	if(val == (long long) od->numeric_param.def) printf(" _is_default");
 	printf(";\n");
 }
@@ -744,7 +746,7 @@
 	ASSERT( tag_type(*tp++) == TT_INTEGER );
 	ASSERT( *tp++ == sizeof(int) );
 	i = *(int*)tp;
-	printf("\t%s\t\t%s",od->name,handler_names[i]);
+	printf("\t%-16s\t%s",od->name,handler_names[i]);
 	if( i == (long long)od->numeric_param.def) printf(" _is_default");
 	printf(";\n");
 }
@@ -753,13 +755,13 @@
 {
 	ASSERT( tag_type(*tp++) == TT_BIT );
 	ASSERT( *tp++ == sizeof(char) );
-	if(*(char*)tp) printf("\t%s;\n",od->name);
+	if(*(char*)tp) printf("\t%-16s;\n",od->name);
 }
 
 void show_string(struct drbd_option *od, unsigned short* tp)
 {
 	ASSERT( tag_type(*tp++) == TT_STRING );
-	if( *tp++ > 0) printf("\t%s\t\t\"%s\";\n",od->name,(char*)tp);
+	if( *tp++ > 0) printf("\t%-16s\t\"%s\";\n",od->name,(char*)tp);
 }
 
 unsigned short *look_for_tag(unsigned short *tlc, unsigned short tag)
@@ -798,7 +800,7 @@
 	}
 }
 
-char* consume_tag_string(enum drbd_tags tag, unsigned short *tlc)
+const char* consume_tag_string(enum drbd_tags tag, unsigned short *tlc)
 {
 	unsigned short *tp;
 	tp = look_for_tag(tlc,tag);
@@ -806,7 +808,7 @@
 		*tp++ = TT_REMOVED;
 		if( *tp++ > 0) return (char*)tp;
 	}
-	return "";
+	return empty_string;
 }
 
 int consume_tag_int(enum drbd_tags tag, unsigned short *tlc)
@@ -821,7 +823,7 @@
 	return 0;
 }
 
-int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
+int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv __attribute((unused)))
 {
 	char buffer[ 4096 ];
 	struct drbd_tag_list *tl;
@@ -831,13 +833,12 @@
 	unsigned short *rtl;
 
 	int idx;
-	char* str;
+	const char* str;
 
 	ASSERT(cm->packet_id == P_get_config);
 
 	if(argc > 1) {
 		fprintf(stderr,"Ignoring excess arguments\n");
-	
 	}
 
 	tl = create_tag_list(2);
@@ -865,15 +866,15 @@
 	idx = consume_tag_int(T_wire_protocol,rtl);
 	if(idx) printf("protocol %c;\n",'A'+idx-1);
 	str = consume_tag_string(T_backing_dev,rtl);
-	if(str) {
+	if(str != empty_string) {
 		printf("_this_host {\n");
-		printf("\tdevice\t\t\"/dev/drbd%d\";\n",minor);
-		printf("\tdisk\t\t\"%s\";\n",str);
+		printf("\tdevice\t\t\t\"/dev/drbd%d\";\n",minor);
+		printf("\tdisk\t\t\t\"%s\";\n",str);
 		idx=consume_tag_int(T_meta_dev_idx,rtl);
 		switch(idx) {
 		case DRBD_MD_INDEX_INTERNAL:
 		case DRBD_MD_INDEX_FLEX_INT:
-			printf("\tmeta-disk\tinternal;\n");
+			printf("\tmeta-disk\t\tinternal;\n");
 			consume_tag_string(T_meta_dev,rtl);
 			break;
 		case DRBD_MD_INDEX_FLEX_EXT:
@@ -881,13 +882,13 @@
 			       consume_tag_string(T_meta_dev,rtl));
 			break;
 		default:
-			printf("\tmeta-disk\t\"%s\" [ %d ];\n",
+			printf("\tmeta-disk\t\t\"%s\" [ %d ];\n",
 			       consume_tag_string(T_meta_dev,rtl),idx);
 		}
 		str = consume_tag_string(T_my_addr,rtl);
-		if(str) {
+		if(str != empty_string ) {
 			addr = (struct sockaddr_in *)str;
-			printf("\taddress\t\t%s:%d;\n",
+			printf("\taddress\t\t\t%s:%d;\n",
 			       inet_ntoa(addr->sin_addr),
 			       ntohs(addr->sin_port));
 		}
@@ -895,10 +896,10 @@
 	}
 
 	str = consume_tag_string(T_peer_addr,rtl);
-	if(str) {
+	if(str != empty_string) {
 		printf("_remote_host {\n");
 		addr = (struct sockaddr_in *)str;
-		printf("\taddress\t\t%s:%d;\n",
+		printf("\taddress\t\t\t%s:%d;\n",
 		       inet_ntoa(addr->sin_addr),
 		       ntohs(addr->sin_port));
 		printf("}\n");
@@ -912,6 +913,35 @@
 	return 0;
 }
 
+static struct drbd_cmd *find_cmd_by_name(const char* name)
+{
+	unsigned int i;
+
+	for(i=0;i<ARRY_SIZE(commands);i++) {
+		if(!strcmp(name,commands[i].cmd)) {
+			return commands+i;
+		}
+	}
+	return NULL;
+}
+
+int down_cmd(struct drbd_cmd *cm __attribute((unused)), int minor, int argc, char **argv)
+{
+	struct drbd_cmd *cmd;
+	int rv = 0;
+
+	if(argc > 1) {
+		fprintf(stderr,"Ignoring excess arguments\n");	
+	}
+
+	cmd = find_cmd_by_name("disconnect");
+	rv |= cmd->function(cmd,minor,argc,argv);
+	cmd = find_cmd_by_name("detach");
+	rv |= cmd->function(cmd,minor,argc,argv);
+
+	return rv;
+}
+
 void print_command_usage(int i, const char *addinfo)
     // CAUTION no range check for i
 {
@@ -1096,11 +1126,9 @@
 
 int main(int argc, char** argv)
 {
-	int help = 0;
-	unsigned int i;
-	int minor;
-	int drbd_fd,lock_fd;
+	int minor,drbd_fd,lock_fd;
 	struct drbd_cmd *cmd;
+	int help = 0, rv=0;
 
 	chdir("/");
 
@@ -1115,22 +1143,16 @@
 
 	if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
 
-	cmd=NULL;
-	for(i=0;i<ARRY_SIZE(commands);i++) {
-		if(strcmp(argv[2],commands[i].cmd)==0) {
-			cmd = commands+i;
-			break;
-		}
-	}
+	cmd=find_cmd_by_name(argv[2]);
 
 	if(cmd) {
 		drbd_fd = dt_lock_open_drbd(argv[1], &lock_fd, 1 );
 		minor=dt_minor_of_dev(argv[1]);
-		commands[i].function(commands+i,minor,argc-3,argv+3);
+		rv = cmd->function(cmd,minor,argc-3,argv+3);
 		dt_close_drbd_unlock(drbd_fd,lock_fd);
 	} else {
 		print_usage("invalid command");
 	}
 
-	return 0;
+	return rv;
 }

Modified: trunk/user/drbdtool_common.c
===================================================================
--- trunk/user/drbdtool_common.c	2006-08-25 09:01:54 UTC (rev 2387)
+++ trunk/user/drbdtool_common.c	2006-08-28 11:48:29 UTC (rev 2388)
@@ -80,6 +80,10 @@
       shift = -10;
       break;
 
+    case 's':
+      shift = -9;   // sectors 
+      break;
+
       /*
          case 'M':
          case 'm':

From drbd-cvs at lists.linbit.com  Mon Aug 28 14:16:55 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Aug 28 14:16:56 2006
Subject: [DRBD-cvs] svn commit by phil - r2389 - in trunk: drbd user - Now
	drbdadm adjust seems to work again... 
Message-ID: <20060828121655.27E202D99D8B@mail.linbit.com>

Author: phil
Date: 2006-08-28 14:16:33 +0200 (Mon, 28 Aug 2006)
New Revision: 2389

Modified:
   trunk/drbd/drbd_nl.c
   trunk/user/drbdadm_adjust.c
   trunk/user/drbdadm_scanner.fl
   trunk/user/drbdsetup.c
   trunk/user/drbdtool_common.c
Log:
Now drbdadm adjust seems to work again...


Modified: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2006-08-28 11:48:29 UTC (rev 2388)
+++ trunk/drbd/drbd_nl.c	2006-08-28 12:16:33 UTC (rev 2389)
@@ -51,7 +51,6 @@
 	int tag; \
 	int dlen; \
 	\
-	memset(arg,0,sizeof(struct name)); \
 	while( (tag = *tags++) != TT_END ) { \
 		dlen = *tags++; \
 		switch( tag_number(tag) ) { \
@@ -376,6 +375,7 @@
 		goto fail;
 	}
 	
+	memset(&primary_args, 0, sizeof(struct primary));
 	if(!primary_from_tags(mdev,nlp->tag_list,&primary_args)) {
 		retcode=UnknownMandatoryTag;
 		goto fail;
@@ -1243,6 +1243,7 @@
 		goto fail;
 	}
 
+	memset(&rs, 0, sizeof(struct resize));
 	if (!resize_from_tags(mdev,nlp->tag_list,&rs)) {
 		retcode=UnknownMandatoryTag;
 		goto fail;

Modified: trunk/user/drbdadm_adjust.c
===================================================================
--- trunk/user/drbdadm_adjust.c	2006-08-28 11:48:29 UTC (rev 2388)
+++ trunk/user/drbdadm_adjust.c	2006-08-28 12:16:33 UTC (rev 2389)
@@ -94,8 +94,8 @@
 	while(running) {
 		if((opt=find_opt(conf,running->name))) {
 			if(!ov_eq(running->value,opt->value)) {
-				/*printf("Value of '%s' differs: r=%s c=%s\n",
-				  opt->name,running->value,opt->value);*/
+			/* printf("Value of '%s' differs: r=%s c=%s\n",
+			   opt->name,running->value,opt->value); */
 				return 0;
 			}
 			opt->mentioned=1;

Modified: trunk/user/drbdadm_scanner.fl
===================================================================
--- trunk/user/drbdadm_scanner.fl	2006-08-28 11:48:29 UTC (rev 2388)
+++ trunk/user/drbdadm_scanner.fl	2006-08-28 12:16:33 UTC (rev 2389)
@@ -24,7 +24,7 @@
 
 %option noyywrap
 
-NUM		[0-9]{1,8}[MKG]?
+NUM		[0-9]{1,8}[MKGs]?
 SNUMB		[0-9]{1,3}
 IPV4ADDR	({SNUMB}"."){3}{SNUMB}
 WS		[ \t]

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-28 11:48:29 UTC (rev 2388)
+++ trunk/user/drbdsetup.c	2006-08-28 12:16:33 UTC (rev 2389)
@@ -718,6 +718,7 @@
 void show_numeric(struct drbd_option *od, unsigned short* tp)
 {
 	long long val;
+	const unsigned char def_unit = od->numeric_param.default_unit;
 
 	switch(tag_type(*tp++)) {
 	case TT_INTEGER: 
@@ -733,7 +734,8 @@
 		val=0;
 	}
 
-	printf("\t%-16s\t%lld",od->name,val);
+	if(def_unit == 1) printf("\t%-16s\t%lld",od->name,val);
+	else printf("\t%-16s\t%lld%c",od->name,val,def_unit);
 	if(val == (long long) od->numeric_param.def) printf(" _is_default");
 	printf(";\n");
 }

Modified: trunk/user/drbdtool_common.c
===================================================================
--- trunk/user/drbdtool_common.c	2006-08-28 11:48:29 UTC (rev 2388)
+++ trunk/user/drbdtool_common.c	2006-08-28 12:16:33 UTC (rev 2389)
@@ -122,6 +122,9 @@
     case 'g':
       shift += 30;
       break;
+    case 's':
+      shift += 9;
+      break;
     default:
       fprintf(stderr, "%s is not a valid number\n", s);
       exit(20);

From drbd-cvs at lists.linbit.com  Mon Aug 28 17:18:29 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Aug 28 17:18:30 2006
Subject: [DRBD-cvs] svn commit by phil - r2390 - in trunk: drbd drbd/linux
	user - Implemented the state, cstate, dstate as well the get-u
Message-ID: <20060828151829.CED922D99D4F@mail.linbit.com>

Author: phil
Date: 2006-08-28 17:18:27 +0200 (Mon, 28 Aug 2006)
New Revision: 2390

Modified:
   trunk/drbd/drbd_nl.c
   trunk/drbd/linux/drbd.h
   trunk/drbd/linux/drbd_nl.h
   trunk/user/drbdsetup.c
Log:
Implemented the state, cstate, dstate as well the get-uuid and
show-uuid commands


Modified: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2006-08-28 12:16:33 UTC (rev 2389)
+++ trunk/drbd/drbd_nl.c	2006-08-28 15:18:27 UTC (rev 2390)
@@ -1538,11 +1538,107 @@
 
 	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
 	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
+	kfree(cn_reply);
 	return;
  fail:
 	drbd_nl_send_reply(req, retcode);
 }
 
+STATIC void drbd_nl_get_state (void *data)
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError,rr;
+	struct drbd_nl_cfg_reply* reply;
+	struct cn_msg *cn_reply;
+	unsigned short *tl;
+	int size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) +
+		get_state_tag_size;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	if( !(cn_reply = kmalloc(size,GFP_KERNEL)) ) {
+		retcode=KMallocFailed;
+		goto fail;
+	}
+	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
+	tl = reply->tag_list;
+
+	tl = get_state_to_tags(mdev,(struct get_state*)&mdev->state,tl);
+	*tl++ = TT_END; /* Close the tag list */
+
+	cn_reply->id = req->id;
+	cn_reply->seq = req->seq;
+	cn_reply->ack = req->ack  + 1;
+	cn_reply->len = (char*)tl - (char *)reply;
+	cn_reply->flags = 0;
+
+	reply->minor = nlp->drbd_minor;
+	reply->ret_code = retcode;
+
+	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
+	kfree(cn_reply);
+	return;
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
+STATIC void drbd_nl_get_uuids (void *data)
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	drbd_dev *mdev;
+	int retcode=NoError,rr;
+	struct drbd_nl_cfg_reply* reply;
+	struct cn_msg *cn_reply;
+	unsigned short *tl;
+	int size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) +
+		get_uuids_tag_size;
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+	
+	if( !(cn_reply = kmalloc(size,GFP_KERNEL)) ) {
+		retcode=KMallocFailed;
+		goto fail;
+	}
+	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
+	tl = reply->tag_list;
+
+	if(inc_local(mdev)) {
+		// This is a hand crafted add tag ;)
+		*tl++ = T_uuids;
+		*tl++ = UUID_SIZE*sizeof(u64);
+		memcpy(tl,mdev->bc->md.uuid,UUID_SIZE*sizeof(u64));
+		tl= (unsigned short*)((char*)tl + UUID_SIZE*sizeof(u64));
+		dec_local(mdev);
+	}
+	*tl++ = TT_END; /* Close the tag list */
+
+	cn_reply->id = req->id;
+	cn_reply->seq = req->seq;
+	cn_reply->ack = req->ack  + 1;
+	cn_reply->len = (char*)tl - (char *)reply;
+	cn_reply->flags = 0;
+
+	reply->minor = nlp->drbd_minor;
+	reply->ret_code = retcode;
+
+	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
+	kfree(cn_reply);
+	return;
+ fail:
+	drbd_nl_send_reply(req, retcode);
+}
+
 // Generate the packet_number to callback table...
 typedef void (*cn_handler)(void*);
 

Modified: trunk/drbd/linux/drbd.h
===================================================================
--- trunk/drbd/linux/drbd.h	2006-08-28 12:16:33 UTC (rev 2389)
+++ trunk/drbd/linux/drbd.h	2006-08-28 15:18:27 UTC (rev 2390)
@@ -257,7 +257,7 @@
 struct drbd_nl_cfg_reply {
 	int minor;
 	int ret_code; // enum ret_code or set_st_err_t
-	unsigned short tag_list[]; // only used with get_config()...
+	unsigned short tag_list[]; // only used with get_* calls
 };
 
 #endif

Modified: trunk/drbd/linux/drbd_nl.h
===================================================================
--- trunk/drbd/linux/drbd_nl.h	2006-08-28 12:16:33 UTC (rev 2389)
+++ trunk/drbd/linux/drbd_nl.h	2006-08-28 15:18:27 UTC (rev 2390)
@@ -69,7 +69,15 @@
 PACKET(resume_io, )
 PACKET(outdate, )
 PACKET(get_config, )
+PACKET(get_state,
+	INTEGER(	33,	T_MAY_IGNORE,	state_i)
+)
 
+PACKET(get_uuids,
+	STRING(		34,	T_MAY_IGNORE,	uuids,	(UUID_SIZE*sizeof(__u64)))
+	INTEGER(  	35,	T_MAY_IGNORE,	uuids_flags)
+)
+
 #undef PACKET
 #undef INTEGER
 #undef INT64

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-28 12:16:33 UTC (rev 2389)
+++ trunk/user/drbdsetup.c	2006-08-28 15:18:27 UTC (rev 2390)
@@ -104,8 +104,16 @@
 	const char* cmd;
 	const int packet_id;
 	int (*function)(struct drbd_cmd *, int, int, char **);
-	struct drbd_argument *args;
-	struct drbd_option *options;
+	union {
+		struct {
+			struct drbd_argument *args;
+			struct drbd_option *options;
+		} cp;
+		struct {
+			int (*show_function)(struct drbd_cmd *, int, 
+					     unsigned short* );
+		} gp;
+	};
 };
 
 
@@ -121,18 +129,28 @@
 
 // command functions
 int generic_config_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
-int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
 int down_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+int generic_get_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv);
+
+// sub commands for generic_get_cmd
+int show_scmd(struct drbd_cmd *cm, int minor, unsigned short *rtl);
+int state_scmd(struct drbd_cmd *cm, int minor, unsigned short *rtl);
+int cstate_scmd(struct drbd_cmd *cm, int minor, unsigned short *rtl);
+int dstate_scmd(struct drbd_cmd *cm, int minor, unsigned short *rtl);
+int uuids_scmd(struct drbd_cmd *cm, int minor, unsigned short *rtl);
+
 // convert functions for arguments
 int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
 int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
 int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
 int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+
 // convert functions for options
 int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
 int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
 int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
 int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+
 // show functions for options
 void show_numeric(struct drbd_option *od, unsigned short* tp);
 void show_handler(struct drbd_option *od, unsigned short* tp);
@@ -184,14 +202,14 @@
 #define ES      conv_string, show_string, { } 
 
 struct drbd_cmd commands[] = {
-	{"primary", P_primary, generic_config_cmd, NULL,
+	{"primary", P_primary, generic_config_cmd, {{ NULL,
 	 (struct drbd_option[]) {
 		 { "overwrite-data-of-peer",'o',T_overwrite_peer, EB   },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
+		 { NULL,0,0,NULL,NULL, { } }, }} }, },
 
-	{"secondary", P_secondary, generic_config_cmd, NULL, NULL },
+	{"secondary", P_secondary, generic_config_cmd, {{NULL, NULL}} },
 
-	{"disk", P_disk_conf, generic_config_cmd,
+	{"disk", P_disk_conf, generic_config_cmd, {{
 	 (struct drbd_argument[]) {
 		 { "lower_dev",		T_backing_dev,	conv_block_dev },
 		 { "meta_data_dev",	T_meta_dev,	conv_block_dev },
@@ -201,11 +219,11 @@
 		 { "size",'d',		T_disk_size,	EN(DISK_SIZE_SECT,'s') },
 		 { "on-io-error",'e',	T_on_io_error,	EH(on_error,ON_IO_ERROR) },
 		 { "fencing",'f',	T_fencing,      EH(fencing_n,FENCING) },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
+		 { NULL,0,0,NULL,NULL, { } }, }, }} },
 
-	{"detach", P_detach, generic_config_cmd, NULL, NULL },
+	{"detach", P_detach, generic_config_cmd, {{NULL, NULL}} },
 
-	{"net", P_net_conf, generic_config_cmd,
+	{"net", P_net_conf, generic_config_cmd, {{
 	 (struct drbd_argument[]) {
 		 { "local_addr",	T_my_addr,	conv_address },
 		 { "remote_addr",	T_peer_addr,	conv_address },
@@ -227,38 +245,36 @@
 		 { "after-sb-1pri",'B',	T_after_sb_1p,EH(asb1p_n,AFTER_SB_1P) },
 		 { "after-sb-2pri",'C',	T_after_sb_2p,EH(asb2p_n,AFTER_SB_2P) },
 		 { "discard-my-data",'D', T_want_lose,     EB },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
+		 { NULL,0,0,NULL,NULL, { } }, }, }} },
 
-	{"disconnect", P_disconnect, generic_config_cmd, NULL, NULL },
+	{"disconnect", P_disconnect, generic_config_cmd, {{NULL, NULL}} },
 
-	{"resize", P_resize, generic_config_cmd, NULL,
+	{"resize", P_resize, generic_config_cmd, {{ NULL,
 	 (struct drbd_option[]) {
 		 { "size",'s',T_resize_size,		EN(DISK_SIZE_SECT,'s') },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
+		 { NULL,0,0,NULL,NULL, { } }, }, }} },
 
-	{"syncer", P_syncer_conf, generic_config_cmd, NULL,
+	{"syncer", P_syncer_conf, generic_config_cmd, {{ NULL,
 	 (struct drbd_option[]) {
 		 { "rate",'r',T_rate,			EN(RATE,'k') },
 		 { "after",'a',T_after,			EN(AFTER,1) },
 		 { "al-extents",'e',T_al_extents,	EN(AL_EXTENTS,1) },
-		 { NULL,0,0,NULL,NULL, { } }, }, },
+		 { NULL,0,0,NULL,NULL, { } }, }, }} },
 
-	{"invalidate", P_invalidate, generic_config_cmd, NULL, NULL },
-	{"invalidate-remote", P_invalidate_peer, generic_config_cmd, NULL, NULL },
-	{"pause-sync", P_pause_sync, generic_config_cmd, NULL, NULL },
-	{"resume-sync", P_resume_sync, generic_config_cmd, NULL, NULL },
-	{"suspend-io", P_suspend_io, generic_config_cmd, NULL, NULL },
-	{"resume-io", P_resume_io, generic_config_cmd, NULL, NULL },
-	{"outdate", P_outdate, generic_config_cmd, NULL, NULL },
-	{"down", 0, down_cmd, NULL, NULL },
-
-	/*
-	{"state", cmd_state,               0, 0, },
-	{"cstate", cmd_cstate,             0, 0, },
-	{"dstate", cmd_dstate,             0, 0, },
-	{"show-gi", cmd_show_gi,           0, 0, },
-	{"get-gi", cmd_get_gi,             0, 0, }, */
-	{"show", P_get_config, show_cmd, NULL, NULL },
+	{"invalidate", P_invalidate, generic_config_cmd, {{ NULL, NULL }} },
+	{"invalidate-remote", P_invalidate_peer, generic_config_cmd, {{NULL, NULL}} },
+	{"pause-sync", P_pause_sync, generic_config_cmd, {{ NULL, NULL }} },
+	{"resume-sync", P_resume_sync, generic_config_cmd, {{ NULL, NULL }} },
+	{"suspend-io", P_suspend_io, generic_config_cmd, {{ NULL, NULL }} },
+	{"resume-io", P_resume_io, generic_config_cmd, {{ NULL, NULL }} },
+	{"outdate", P_outdate, generic_config_cmd, {{ NULL, NULL }} },
+	{"down",            0, down_cmd,  { {NULL, NULL }} },
+	{"state", P_get_state, generic_get_cmd, { .gp={ state_scmd} } },
+	{"cstate", P_get_state, generic_get_cmd, {.gp={ cstate_scmd} } },
+	{"dstate", P_get_state, generic_get_cmd, {.gp={ dstate_scmd} } },
+	{"show-gi", P_get_uuids, generic_get_cmd, {.gp={ uuids_scmd} }},
+	{"get-gi", P_get_uuids, generic_get_cmd, {.gp={ uuids_scmd} } },
+	{"show", P_get_config, generic_get_cmd, {.gp={ show_scmd} } },
 };
 
 #define EM(C) [ C - RetCodeBase ]
@@ -653,7 +669,7 @@
 {
 	char buffer[ RCV_SIZE ];
 	struct drbd_nl_cfg_reply *reply;
-	struct drbd_argument *ad = cm->args;
+	struct drbd_argument *ad = cm->cp.args;
 	struct drbd_option *od;
 	static struct option *lo;
 	struct drbd_tag_list *tl;
@@ -674,10 +690,10 @@
 		ad++;
 	}
 
-	lo = make_longoptions(cm->options);
+	lo = make_longoptions(cm->cp.options);
 	opterr=0;
 	while( (c=getopt_long(argc,argv,make_optstring(lo,0),lo,0)) != -1 ) {
-		od = find_opt_by_short_name(cm->options,c);
+		od = find_opt_by_short_name(cm->cp.options,c);
 		if(od) rv |= od->convert_function(od,tl,optarg);
 		else {
 			if(c=='(') flags |= DRBD_NL_SET_DEFAULTS;
@@ -802,6 +818,20 @@
 	}
 }
 
+
+const char* consume_tag_blob(enum drbd_tags tag, unsigned short *tlc, 
+			     unsigned int* len)
+{
+	unsigned short *tp;
+	tp = look_for_tag(tlc,tag);
+	if(tp) {
+		*tp++ = TT_REMOVED;
+		*len = *tp++;
+		return (char*)tp;
+	}
+	return NULL;
+}
+
 const char* consume_tag_string(enum drbd_tags tag, unsigned short *tlc)
 {
 	unsigned short *tp;
@@ -825,20 +855,14 @@
 	return 0;
 }
 
-int show_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv __attribute((unused)))
+int generic_get_cmd(struct drbd_cmd *cm, int minor, int argc, 
+		    char **argv __attribute((unused)))
 {
 	char buffer[ 4096 ];
 	struct drbd_tag_list *tl;
 	struct drbd_nl_cfg_reply *reply;
-	struct sockaddr_in *addr;
-	int sk_nl;
-	unsigned short *rtl;
+	int sk_nl,rv;
 
-	int idx;
-	const char* str;
-
-	ASSERT(cm->packet_id == P_get_config);
-
 	if(argc > 1) {
 		fprintf(stderr,"Ignoring excess arguments\n");
 	}
@@ -856,12 +880,26 @@
 	reply = (struct drbd_nl_cfg_reply *)
 		((struct cn_msg *)NLMSG_DATA(buffer))->data;
 
-	rtl = reply->tag_list;
+	rv = cm->gp.show_function(cm,minor,reply->tag_list);
 
+	if(dump_tag_list(reply->tag_list)) {
+		printf("# Found unknown tags, you should update your\n"
+		       "# userland tools\n");
+	}
+
+	return rv;
+}
+
+int show_scmd(struct drbd_cmd *cm, int minor, unsigned short *rtl)
+{
+	int idx;
+	const char* str;
+	struct sockaddr_in *addr;
+
 	// find all commands that have options and print those...
 	for ( cm = commands ; cm < commands + ARRY_SIZE(commands) ; cm++ ) {
-		if(cm->options)
-			print_options(cm->options, rtl, cm->cmd);
+		if(cm->cp.options)
+			print_options(cm->cp.options, rtl, cm->cmd);
 	}
 
 	// start of spagethi code...
@@ -907,14 +945,64 @@
 		printf("}\n");
 	}
 
-	if(dump_tag_list(reply->tag_list)) {
-		printf("# Found unknown tags, you should update your\n"
-		       "# userland tools\n");
-	}
+	return 0;
+}
 
+int state_scmd(struct drbd_cmd *cm __attribute((unused)), 
+	       int minor __attribute((unused)), 
+	       unsigned short *rtl)
+{
+	drbd_state_t state;
+	state = (drbd_state_t)(unsigned int)consume_tag_int(T_state_i,rtl);
+	printf("%s\n",roles_to_name(state.role));
 	return 0;
 }
 
+int cstate_scmd(struct drbd_cmd *cm __attribute((unused)), 
+		int minor __attribute((unused)), 
+		unsigned short *rtl)
+{
+	drbd_state_t state;
+	state = (drbd_state_t)(unsigned int)consume_tag_int(T_state_i,rtl);
+	printf("%s\n",conns_to_name(state.conn));
+	return 0;
+}
+
+int dstate_scmd(struct drbd_cmd *cm __attribute((unused)), 
+		int minor __attribute((unused)), 
+		unsigned short *rtl)
+{
+	drbd_state_t state;
+	state = (drbd_state_t)(unsigned int)consume_tag_int(T_state_i,rtl);
+	printf("%s\n",disks_to_name(state.disk));
+	return 0;
+}
+
+int uuids_scmd(struct drbd_cmd *cm, 
+	       int minor __attribute((unused)), 
+	       unsigned short *rtl)
+{
+	__u64 *uuids;
+	int flags;
+	unsigned int len ;
+
+	uuids = (__u64 *)consume_tag_blob(T_uuids,rtl,&len);
+	flags = consume_tag_int(T_uuids_flags,rtl);
+	if( len == UUID_SIZE * sizeof(__u64)) {
+		if(!strcmp(cm->cmd,"show-gi")) {
+			dt_pretty_print_uuids(uuids,flags);
+		} else if(!strcmp(cm->cmd,"get-gi")) {
+			dt_print_uuids(uuids,flags);
+		} else {
+			ASSERT( 0 );
+		}
+	} else {
+		printf("Unexpected length of T_uuids tag. You should upgrade your\n"
+		       "userland tools\n");
+	}
+	return 0;
+}
+
 static struct drbd_cmd *find_cmd_by_name(const char* name)
 {
 	unsigned int i;
@@ -927,19 +1015,18 @@
 	return NULL;
 }
 
-int down_cmd(struct drbd_cmd *cm __attribute((unused)), int minor, int argc, char **argv)
+int down_cmd(struct drbd_cmd *cm, int minor, int argc, char **argv)
 {
-	struct drbd_cmd *cmd;
 	int rv = 0;
 
 	if(argc > 1) {
 		fprintf(stderr,"Ignoring excess arguments\n");	
 	}
 
-	cmd = find_cmd_by_name("disconnect");
-	rv |= cmd->function(cmd,minor,argc,argv);
-	cmd = find_cmd_by_name("detach");
-	rv |= cmd->function(cmd,minor,argc,argv);
+	cm = find_cmd_by_name("disconnect");
+	rv |= cm->function(cm,minor,argc,argv);
+	cm = find_cmd_by_name("detach");
+	rv |= cm->function(cm,minor,argc,argv);
 
 	return rv;
 }
@@ -956,7 +1043,7 @@
 	prevcol=col=0;
 
 	col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
-	if ((args = commands[i].args)) {
+	if ((args = commands[i].cp.args)) {
 		while (args->name) {
 			col += snprintf(line+col, maxcol-col, " %s", args->name);
 			args++;
@@ -968,7 +1055,7 @@
 		col=0;
 	}
 	prevcol=col;
-	if ((options = commands[i].options)) {
+	if ((options = commands[i].cp.options)) {
 		while (options->name) {
 			if (tag_type(options->tag) == TT_BIT) {
 				col += snprintf(line+col, maxcol-col,

From drbd-cvs at lists.linbit.com  Tue Aug 29 15:50:40 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Aug 29 15:50:42 2006
Subject: [DRBD-cvs] svn commit by phil - r2391 - in trunk: drbd user - Fixed
	the bugs of get-gi and show-gi 
Message-ID: <20060829135040.A30682DF654C@mail.linbit.com>

Author: phil
Date: 2006-08-29 15:50:39 +0200 (Tue, 29 Aug 2006)
New Revision: 2391

Modified:
   trunk/drbd/drbd_nl.c
   trunk/user/drbdsetup.c
Log:
Fixed the bugs of get-gi and show-gi


Modified: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2006-08-28 15:18:27 UTC (rev 2390)
+++ trunk/drbd/drbd_nl.c	2006-08-29 13:50:39 UTC (rev 2391)
@@ -1617,8 +1617,12 @@
 		*tl++ = T_uuids;
 		*tl++ = UUID_SIZE*sizeof(u64);
 		memcpy(tl,mdev->bc->md.uuid,UUID_SIZE*sizeof(u64));
-		tl= (unsigned short*)((char*)tl + UUID_SIZE*sizeof(u64));
+		tl=(unsigned short*)((char*)tl + UUID_SIZE*sizeof(u64));
 		dec_local(mdev);
+		*tl++ = T_uuids_flags;
+		*tl++ = sizeof(int);
+		memcpy(tl,&mdev->bc->md.flags,sizeof(int));
+		tl=(unsigned short*)((char*)tl + sizeof(int));
 	}
 	*tl++ = TT_END; /* Close the tag list */
 

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-28 15:18:27 UTC (rev 2390)
+++ trunk/user/drbdsetup.c	2006-08-29 13:50:39 UTC (rev 2391)
@@ -151,7 +151,7 @@
 int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
 int conv_string(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
 
-// show functions for options
+// show functions for options (used by show_scmd)
 void show_numeric(struct drbd_option *od, unsigned short* tp);
 void show_handler(struct drbd_option *od, unsigned short* tp);
 void show_bit(struct drbd_option *od, unsigned short* tp);
@@ -649,13 +649,18 @@
 	if (err_no == SS_Success) return;
 
 	if ( ( err_no >= AfterLastRetCode || err_no <= RetCodeBase ) &&
-	     ( err_no > SS_TowPrimaries || err_no < SS_CW_FailedByPeer) ) {
+	     ( err_no > SS_CW_NoNeed || err_no < SS_CW_FailedByPeer) ) {
 		fprintf(stderr,"Error code %d unknown.\n"
 			"You should updated the drbd userland tools.\n",err_no);
 	} else {
 		if(err_no > RetCodeBase ) {
 			fprintf(stderr,"Failure: (%d) %s\n",err_no,
 				error_messages[err_no-RetCodeBase]);
+		} else if (err_no == SS_UnknownError) {
+			fprintf(stderr,"State change failed: (%d)"
+				"unknown error.\n", err_no);
+		} else if (err_no > SS_TowPrimaries) {
+			// Ignore SS_Success, SS_NothingToDo, SS_CW_Success... 
 		} else {
 			fprintf(stderr,"State change failed: (%d) %s\n",
 				err_no, set_st_err_name(err_no));
@@ -984,9 +989,14 @@
 {
 	__u64 *uuids;
 	int flags;
-	unsigned int len ;
+	unsigned int len = 4711;
 
 	uuids = (__u64 *)consume_tag_blob(T_uuids,rtl,&len);
+	if(len == 4711) {
+		fprintf(stderr,"Reply payload did not carry an uuid-tag,\n"
+			"Probabely the device has no disk!\n");
+		return 1;
+	}
 	flags = consume_tag_int(T_uuids_flags,rtl);
 	if( len == UUID_SIZE * sizeof(__u64)) {
 		if(!strcmp(cm->cmd,"show-gi")) {
@@ -997,8 +1007,8 @@
 			ASSERT( 0 );
 		}
 	} else {
-		printf("Unexpected length of T_uuids tag. You should upgrade your\n"
-		       "userland tools\n");
+		fprintf(stderr, "Unexpected length of T_uuids tag. "
+			"You should upgrade your userland tools\n");
 	}
 	return 0;
 }

From drbd-cvs at lists.linbit.com  Thu Aug 31 21:06:58 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Aug 31 21:06:59 2006
Subject: [DRBD-cvs] svn commit by phil - r2392 - in trunk: . drbd drbd/linux
	user - Cleanup of the kernel side of drbd_nl.c 
Message-ID: <20060831190658.C091D2DF6550@mail.linbit.com>

Author: phil
Date: 2006-08-31 21:06:56 +0200 (Thu, 31 Aug 2006)
New Revision: 2392

Modified:
   trunk/ROADMAP
   trunk/drbd/drbd_nl.c
   trunk/drbd/linux/drbd.h
   trunk/drbd/linux/drbd_tag_magic.h
   trunk/user/drbdsetup.c
Log:
Cleanup of the kernel side of drbd_nl.c 


Modified: trunk/ROADMAP
===================================================================
--- trunk/ROADMAP	2006-08-29 13:50:39 UTC (rev 2391)
+++ trunk/ROADMAP	2006-08-31 19:06:56 UTC (rev 2392)
@@ -441,13 +441,6 @@
 
   Things to do:
   
-  * Fix drbdadm (nees to use --create-device and --set-defaults; adjust
-      needs to be changes since the kernel can not return the device
-      names of backing and meta device.)
-  * Remove the memset( .., 0, ...) from drbd_nl.c. Use the defaults instead.
-  * Use only one connector callback.
-  * use try_module_get() and put_module() when control enters a/the connector
-    callback.
   * Locking in userspace, to prevent multiple instances of drbdsetup
 
   50% DONE

Modified: trunk/drbd/drbd_nl.c
===================================================================
--- trunk/drbd/drbd_nl.c	2006-08-29 13:50:39 UTC (rev 2391)
+++ trunk/drbd/drbd_nl.c	2006-08-31 19:06:56 UTC (rev 2392)
@@ -120,35 +120,6 @@
 void drbd_nl_send_reply(struct cn_msg *, int);
 
 
-STATIC void drbd_nl_create (void *data)
-{ 
-	static int next_minor=0;
-	int minor,ok;
-	drbd_dev *mdev = NULL;
-
-	minor = next_minor;
-
-	mdev = drbd_new_device(minor);
-	if(!mdev) goto out;
-
-	spin_lock_irq(&drbd_pp_lock); // just to protect this from itself
-	if ( (ok = next_minor < minor_count && minor == next_minor) ) {
-		minor_table[minor] = mdev;
-		wmb();
-		next_minor++;
-	}
-	spin_unlock_irq(&drbd_pp_lock);
-
-	if(!ok) {
-	out:
-		if(mdev) {
-			if(mdev->app_reads_hash) kfree(mdev->app_reads_hash);
-			if(mdev->md_io_page) __free_page(mdev->md_io_page);
-			kfree(mdev);
-		}
-	}
-}
-
 int drbd_khelper(drbd_dev *mdev, char* cmd)
 {
 	char mb[12];
@@ -332,77 +303,29 @@
 	return r;
 }
 
-STATIC drbd_dev *ensure_mdev(struct drbd_nl_cfg_req *nlp)
-{
-	drbd_dev *mdev;
 
-	mdev = minor_to_mdev(nlp->drbd_minor);
-
-	if(!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) {
-		mdev = drbd_new_device(nlp->drbd_minor);
-		
-		spin_lock_irq(&drbd_pp_lock);
-		if( minor_table[nlp->drbd_minor] == NULL) {
-			minor_table[nlp->drbd_minor] = mdev;
-			mdev = NULL;
-		}
-		spin_unlock_irq(&drbd_pp_lock);
-		
-		if(mdev) {
-			if(mdev->app_reads_hash) kfree(mdev->app_reads_hash);
-			if(mdev->md_io_page) __free_page(mdev->md_io_page);
-			kfree(mdev);
-			mdev = NULL;
-		}
-
-		mdev = minor_to_mdev(nlp->drbd_minor);
-	}
-
-	return mdev;
-}
-
-
-STATIC void drbd_nl_primary (void *data) 
+STATIC int drbd_nl_primary(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			   struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
 	struct primary primary_args;
-	int retcode;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-	
 	memset(&primary_args, 0, sizeof(struct primary));
 	if(!primary_from_tags(mdev,nlp->tag_list,&primary_args)) {
-		retcode=UnknownMandatoryTag;
-		goto fail;
+		reply->ret_code=UnknownMandatoryTag;
+		return 0;
 	}
 
-	retcode = drbd_set_role(mdev, Primary, primary_args.overwrite_peer);
+	reply->ret_code = drbd_set_role(mdev, Primary, primary_args.overwrite_peer);
 
- fail:
-	drbd_nl_send_reply(req, retcode );
+	return 0;
 }
 
-STATIC void drbd_nl_secondary (void *data) 
+STATIC int drbd_nl_secondary(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			     struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode;
+	reply->ret_code = drbd_set_role(mdev, Secondary, 0);
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-	
-	retcode = drbd_set_role(mdev, Secondary, 0);
-
- fail:
-	drbd_nl_send_reply(req, retcode );
+	return 0;
 }
 
 /* initializes the md.*_offset members, so we are able to find
@@ -661,23 +584,16 @@
 	}
 }
 
-STATIC void drbd_nl_disk_conf (void *data) 
+STATIC int drbd_nl_disk_conf(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			     struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
 	enum ret_codes retcode;
 	struct drbd_backing_dev* nbc=NULL; // new_backing_conf
 	struct inode *inode, *inode2;
 	struct lru_cache* resync_lru = NULL;
 	drbd_state_t ns,os;
-	drbd_dev *mdev;
 	int rv;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-	
 	/* if you want to reconfigure, please tear down first */
 	if (mdev->state.disk > Diskless) {
 		retcode=HaveDiskConfig;
@@ -955,8 +871,8 @@
 	drbd_bm_unlock(mdev);
 	drbd_md_sync(mdev);
 
-	drbd_nl_send_reply(req, NoError);
-	return;
+	reply->ret_code = retcode;
+	return 0;
 
  release_bdev3_fail:
 	drbd_force_state(mdev,NS(disk,Diskless));
@@ -973,31 +889,21 @@
 	}
 	if (resync_lru) lc_free(resync_lru);
 
-	drbd_nl_send_reply(req, retcode );
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_detach (void *data) 
+STATIC int drbd_nl_detach(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			  struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode;
+	reply->ret_code = drbd_request_state(mdev,NS(disk,Diskless));
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
-	retcode = drbd_request_state(mdev,NS(disk,Diskless));
-
- fail:
-	drbd_nl_send_reply(req, retcode);
+	return 0;
 }
 
-STATIC void drbd_nl_net_conf (void *data) 
+STATIC int drbd_nl_net_conf(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			    struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
 	int i,ns;
 	enum ret_codes retcode;
 	struct net_conf *new_conf = NULL;
@@ -1005,13 +911,7 @@
 	struct hlist_head *new_tl_hash = NULL;
 	struct hlist_head *new_ee_hash = NULL;
 	struct Drbd_Conf *odev;
-	drbd_dev *mdev;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
 	new_conf = kmalloc(sizeof(struct net_conf),GFP_KERNEL);
 	if(!new_conf) {			
 		retcode=KMallocFailed;
@@ -1177,8 +1077,8 @@
 
 	retcode = drbd_request_state(mdev,NS(conn,Unconnected));
 
-	drbd_nl_send_reply(req, retcode);
-	return ;
+	reply->ret_code = retcode;
+	return 0;
 
   fail:
 	if (tfm) crypto_free_tfm(tfm);
@@ -1186,22 +1086,15 @@
 	if (new_ee_hash) kfree(new_ee_hash);
 	if (new_conf) kfree(new_conf);
 
-	drbd_nl_send_reply(req, retcode);
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_disconnect (void *data) 
+STATIC int drbd_nl_disconnect(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			      struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
 	int retcode;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
-
 	retcode = _drbd_request_state(mdev,NS(conn,StandAlone),0);	// silently.
 
 	if ( retcode == SS_NothingToDo ) goto done;
@@ -1226,23 +1119,16 @@
 	retcode = NoError;
  fail:
 	drbd_md_sync(mdev);
-	drbd_nl_send_reply(req, retcode);
-	return ;
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_resize (void *data) 
+STATIC int drbd_nl_resize(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			  struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
 	struct resize rs;
-	drbd_dev *mdev;
 	int retcode=NoError;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
 	memset(&rs, 0, sizeof(struct resize));
 	if (!resize_from_tags(mdev,nlp->tag_list,&rs)) {
 		retcode=UnknownMandatoryTag;
@@ -1270,24 +1156,18 @@
 	}
 
  fail:
-	drbd_nl_send_reply(req, retcode);
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_syncer_conf (void *data) 
+STATIC int drbd_nl_syncer_conf(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			       struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
 	int retcode=NoError;
 	struct syncer_conf sc;
 	drbd_dev *odev;
 	int err;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
 	memcpy(&sc,&mdev->sync_conf,sizeof(struct syncer_conf));
 
 	if(nlp->flags & DRBD_NL_SET_DEFAULTS) {
@@ -1342,131 +1222,69 @@
 	drbd_alter_sa(mdev, sc.after);
 
  fail:
-	drbd_nl_send_reply(req, retcode);
-	return;
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_invalidate (void *data) 
+STATIC int drbd_nl_invalidate(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			      struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode;
-
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
-	retcode = drbd_request_state(mdev,NS2(conn,StartingSyncT,
-					disk,Inconsistent));
- fail:
-	drbd_nl_send_reply(req, retcode);
-	return;
+	reply->ret_code = drbd_request_state(mdev,NS2(conn,StartingSyncT,
+						      disk,Inconsistent));
+	return 0;
 }
 
-STATIC void drbd_nl_invalidate_peer (void *data) 
+STATIC int drbd_nl_invalidate_peer(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+				   struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
+	reply->ret_code = drbd_request_state(mdev,NS2(conn,StartingSyncS,
+						      pdsk,Inconsistent));
 
-	retcode = drbd_request_state(mdev,NS2(conn,StartingSyncS,
-					      pdsk,Inconsistent));
- fail:
-	drbd_nl_send_reply(req, retcode);
-	return;
+	return 0;
 }
 
-STATIC void drbd_nl_pause_sync (void *data) 
+STATIC int drbd_nl_pause_sync(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			      struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
 	int retcode=NoError;
-
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
 	
 	if(!drbd_resync_pause(mdev, UserImposed)) retcode = PauseFlagAlreadySet;
- fail:
-	drbd_nl_send_reply(req, retcode);
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_resume_sync (void *data) 
+STATIC int drbd_nl_resume_sync(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			       struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
 	int retcode=NoError;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-	
 	if(!drbd_resync_resume(mdev, UserImposed)) retcode = PauseFlagAlreadyClear;
- fail:
-	drbd_nl_send_reply(req, retcode);
+	reply->ret_code = retcode;
+	return 0;
 }
 
-STATIC void drbd_nl_suspend_io (void *data) 
+STATIC int drbd_nl_suspend_io(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			      struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode;
+	reply->ret_code = drbd_request_state(mdev,NS(susp,1));
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
-	retcode = drbd_request_state(mdev,NS(susp,1));
-
- fail:
-	drbd_nl_send_reply(req, retcode);
+	return 0;
 }
 
-STATIC void drbd_nl_resume_io (void *data) 
+STATIC int drbd_nl_resume_io(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			     struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode=NoError;
-
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
-	retcode = drbd_request_state(mdev,NS(susp,0));
-
- fail:
-	drbd_nl_send_reply(req, retcode);
+	reply->ret_code = drbd_request_state(mdev,NS(susp,0));
+	return 0;
 }
 
-STATIC void drbd_nl_outdate (void *data) 
+STATIC int drbd_nl_outdate(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			   struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
 	int retcode;
 	drbd_state_t os,ns;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-
 	spin_lock_irq(&mdev->req_lock);
 	os = mdev->state;
 	if( mdev->state.disk < Outdated ) {
@@ -1486,32 +1304,15 @@
 	drbd_md_sync(mdev);
 
  fail:
-	drbd_nl_send_reply(req, retcode);
+	reply->ret_code = retcode;
+	return 0;
 }
 
-
-STATIC void drbd_nl_get_config (void *data)
+STATIC int drbd_nl_get_config(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			   struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode=NoError,rr;
-	struct drbd_nl_cfg_reply* reply;
-	struct cn_msg *cn_reply;
 	unsigned short *tl;
-	int size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) +
-		disk_conf_tag_size + net_conf_tag_size + syncer_conf_tag_size + 2;
-
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
 	
-	if( !(cn_reply = kmalloc(size,GFP_KERNEL)) ) {
-		retcode=KMallocFailed;
-		goto fail;
-	}
-	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
 	tl = reply->tag_list;
 
 	if(inc_local(mdev)) {
@@ -1527,89 +1328,27 @@
 
 	*tl++ = TT_END; /* Close the tag list */
 
-	cn_reply->id = req->id;
-	cn_reply->seq = req->seq;
-	cn_reply->ack = req->ack  + 1;
-	cn_reply->len = (char*)tl - (char *)reply;
-	cn_reply->flags = 0;
-
-	reply->minor = nlp->drbd_minor;
-	reply->ret_code = retcode;
-
-	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
-	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
-	kfree(cn_reply);
-	return;
- fail:
-	drbd_nl_send_reply(req, retcode);
+	return (int)((char*)tl - (char*)reply->tag_list);
 }
 
-STATIC void drbd_nl_get_state (void *data)
+STATIC int drbd_nl_get_state(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			     struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode=NoError,rr;
-	struct drbd_nl_cfg_reply* reply;
-	struct cn_msg *cn_reply;
 	unsigned short *tl;
-	int size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) +
-		get_state_tag_size;
 
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
-	
-	if( !(cn_reply = kmalloc(size,GFP_KERNEL)) ) {
-		retcode=KMallocFailed;
-		goto fail;
-	}
-	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
 	tl = reply->tag_list;
 
 	tl = get_state_to_tags(mdev,(struct get_state*)&mdev->state,tl);
 	*tl++ = TT_END; /* Close the tag list */
 
-	cn_reply->id = req->id;
-	cn_reply->seq = req->seq;
-	cn_reply->ack = req->ack  + 1;
-	cn_reply->len = (char*)tl - (char *)reply;
-	cn_reply->flags = 0;
-
-	reply->minor = nlp->drbd_minor;
-	reply->ret_code = retcode;
-
-	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
-	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
-	kfree(cn_reply);
-	return;
- fail:
-	drbd_nl_send_reply(req, retcode);
+	return (int)((char*)tl - (char*)reply->tag_list);
 }
 
-STATIC void drbd_nl_get_uuids (void *data)
+STATIC int drbd_nl_get_uuids(drbd_dev *mdev, struct drbd_nl_cfg_req *nlp,
+			     struct drbd_nl_cfg_reply *reply)
 {
-	struct cn_msg *req = data;
-	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
-	drbd_dev *mdev;
-	int retcode=NoError,rr;
-	struct drbd_nl_cfg_reply* reply;
-	struct cn_msg *cn_reply;
 	unsigned short *tl;
-	int size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply) +
-		get_uuids_tag_size;
-
-	if( !(mdev = ensure_mdev(nlp)) ) {
-		retcode=MinorNotKnown;
-		goto fail;
-	}
 	
-	if( !(cn_reply = kmalloc(size,GFP_KERNEL)) ) {
-		retcode=KMallocFailed;
-		goto fail;
-	}
-	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
 	tl = reply->tag_list;
 
 	if(inc_local(mdev)) {
@@ -1626,47 +1365,137 @@
 	}
 	*tl++ = TT_END; /* Close the tag list */
 
+	return (int)((char*)tl - (char*)reply->tag_list);
+}
+
+STATIC drbd_dev *ensure_mdev(struct drbd_nl_cfg_req *nlp)
+{
+	drbd_dev *mdev;
+
+	mdev = minor_to_mdev(nlp->drbd_minor);
+
+	if(!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) {
+		mdev = drbd_new_device(nlp->drbd_minor);
+		
+		spin_lock_irq(&drbd_pp_lock);
+		if( minor_table[nlp->drbd_minor] == NULL) {
+			minor_table[nlp->drbd_minor] = mdev;
+			mdev = NULL;
+		}
+		spin_unlock_irq(&drbd_pp_lock);
+		
+		if(mdev) {
+			if(mdev->app_reads_hash) kfree(mdev->app_reads_hash);
+			if(mdev->md_io_page) __free_page(mdev->md_io_page);
+			kfree(mdev);
+			mdev = NULL;
+		}
+
+		mdev = minor_to_mdev(nlp->drbd_minor);
+	}
+
+	return mdev;
+}
+
+struct cn_handler_struct {
+	int (*function)(drbd_dev *,
+			 struct drbd_nl_cfg_req *, 
+			 struct drbd_nl_cfg_reply* );
+	int reply_body_size;
+};
+
+static struct cn_handler_struct cnd_table[] = {
+	[ P_primary ]		= { &drbd_nl_primary,		0 },
+	[ P_secondary ]		= { &drbd_nl_secondary,		0 },
+	[ P_disk_conf ]		= { &drbd_nl_disk_conf,		0 },
+	[ P_detach ]		= { &drbd_nl_detach,		0 },
+	[ P_net_conf ]		= { &drbd_nl_net_conf,		0 },
+	[ P_disconnect ]	= { &drbd_nl_disconnect,	0 },
+	[ P_resize ]		= { &drbd_nl_resize,		0 },
+	[ P_syncer_conf ]	= { &drbd_nl_syncer_conf,	0 },
+	[ P_invalidate ]	= { &drbd_nl_invalidate,	0 },
+	[ P_invalidate_peer ]	= { &drbd_nl_invalidate_peer,	0 },
+	[ P_pause_sync ]	= { &drbd_nl_pause_sync,	0 },
+	[ P_resume_sync ]	= { &drbd_nl_resume_sync,	0 },
+	[ P_suspend_io ]	= { &drbd_nl_suspend_io,	0 },
+	[ P_resume_io ]		= { &drbd_nl_resume_io,		0 },
+	[ P_outdate ]		= { &drbd_nl_outdate,		0 },
+	[ P_get_config ]	= { &drbd_nl_get_config,
+				    sizeof(struct syncer_conf_tag_len_struct) +
+				    sizeof(struct disk_conf_tag_len_struct) +
+				    sizeof(struct net_conf_tag_len_struct) },
+	[ P_get_state ]		= { &drbd_nl_get_state,
+				    sizeof(struct get_state_tag_len_struct) },
+	[ P_get_uuids ]		= { &drbd_nl_get_uuids,
+				    sizeof(struct get_uuids_tag_len_struct) },
+};
+
+void drbd_connector_callback(void *data)
+{
+	struct cn_msg *req = data;
+	struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req*)req->data;
+	struct cn_handler_struct *cm;
+	struct cn_msg *cn_reply;
+	struct drbd_nl_cfg_reply* reply;
+	drbd_dev *mdev;
+	int retcode,rr;
+	int reply_size = sizeof(struct cn_msg) + sizeof(struct drbd_nl_cfg_reply);
+	
+	if(!try_module_get(THIS_MODULE)) {
+		printk(KERN_ERR DEVICE_NAME "try_module_get() failed!\n");
+		return;
+	}
+
+	if( !(mdev = ensure_mdev(nlp)) ) {
+		retcode=MinorNotKnown;
+		goto fail;
+	}
+
+	if( nlp->packet_type >= P_nl_after_last_packet ) {
+		retcode=UnknownNetLinkPacket;
+		goto fail;
+	}
+
+	cm = cnd_table + nlp->packet_type;
+	reply_size += cm->reply_body_size;
+
+	if( !(cn_reply = kmalloc(reply_size,GFP_KERNEL)) ) {
+		retcode=KMallocFailed;
+		goto fail;
+	}
+	reply = (struct drbd_nl_cfg_reply*) cn_reply->data;
+
+	reply->minor = nlp->drbd_minor;
+	reply->ret_code = NoError; // Might by modified by cm->function.
+	// reply->tag_list; might be modified by cm->fucntion.
+
+	rr = cm->function(mdev,nlp,reply);
+	
 	cn_reply->id = req->id;
 	cn_reply->seq = req->seq;
 	cn_reply->ack = req->ack  + 1;
-	cn_reply->len = (char*)tl - (char *)reply;
+	cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + rr;
 	cn_reply->flags = 0;
 
-	reply->minor = nlp->drbd_minor;
-	reply->ret_code = retcode;
-
 	rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
 	if(rr) printk(KERN_INFO DEVICE_NAME " cn_netlink_send()=%d\n",rr);
 	kfree(cn_reply);
+	module_put(THIS_MODULE);
 	return;
  fail:
 	drbd_nl_send_reply(req, retcode);
+	module_put(THIS_MODULE);
 }
 
-// Generate the packet_number to callback table...
-typedef void (*cn_handler)(void*);
-
-static cn_handler cnd_table[] = {
-#define PACKET(name, fields) [ P_ ## name ] = & drbd_nl_ ## name,
-#define INTEGER(pn,pr,member)
-#define INT64(pn,pr,member)
-#define BIT(pn,pr,member)
-#define STRING(pn,pr,member,len)
-#include "linux/drbd_nl.h"
-};
-
 int __init drbd_nl_init()
 {
-	static struct cb_id cn_id_drbd = { CN_IDX_DRBD, 0 };
-	int i,err;
+	static struct cb_id cn_id_drbd = { CN_IDX_DRBD, CN_VAL_DRBD };
+	int err;
 
-	for(i=0;i<P_nl_after_last_packet;i++) {
-		cn_id_drbd.val = i;
-		err = cn_add_callback(&cn_id_drbd,"cn_drbd",cnd_table[i]);
-		if(err) {
-			printk(KERN_ERR DEVICE_NAME "cn_drbd failed to register\n");
-			return err;
-		}
+	err = cn_add_callback(&cn_id_drbd,"cn_drbd",&drbd_connector_callback);
+	if(err) {
+		printk(KERN_ERR DEVICE_NAME "cn_drbd failed to register\n");
+		return err;
 	}
 
 	return 0;

Modified: trunk/drbd/linux/drbd.h
===================================================================
--- trunk/drbd/linux/drbd.h	2006-08-29 13:50:39 UTC (rev 2391)
+++ trunk/drbd/linux/drbd.h	2006-08-31 19:06:56 UTC (rev 2392)
@@ -103,6 +103,7 @@
 	PauseFlagAlreadyClear,
 	DiskLowerThanOutdated,
 	FailedToClaimMyself,
+	UnknownNetLinkPacket,
 	AfterLastRetCode,
 };
 
@@ -247,8 +248,10 @@
 // The following line should be moved over to linux/connector.h
 // when the time comes
 #define CN_IDX_DRBD			0x4
+#define CN_VAL_DRBD			0x1
 
 struct drbd_nl_cfg_req {
+	int packet_type;
 	int drbd_minor;
 	int flags;
 	unsigned short tag_list[];

Modified: trunk/drbd/linux/drbd_tag_magic.h
===================================================================
--- trunk/drbd/linux/drbd_tag_magic.h	2006-08-29 13:50:39 UTC (rev 2391)
+++ trunk/drbd/linux/drbd_tag_magic.h	2006-08-31 19:06:56 UTC (rev 2392)
@@ -15,13 +15,24 @@
 	P_nl_after_last_packet,
 };
 
+// These struct are used to deduce the size of the tag lists:
+#define PACKET(name, fields) struct name ## _tag_len_struct { fields };
+#define INTEGER(pn,pr,member) int member; int tag_and_len ## member;
+#define INT64(pn,pr,member) __u64 member; int tag_and_len ## member;
+#define BIT(pn,pr,member)   unsigned char member : 1; int tag_and_len ## member;
+#define STRING(pn,pr,member,len) unsigned char member[len]; int member ## _len; \
+				 int tag_and_len ## member;
+#include "linux/drbd_nl.h"
+
 // declate tag-list-sizes
-#define PACKET(name,fields) const int name ## _tag_size = 2 fields ;
+const int tag_list_sizes[] = {
+#define PACKET(name,fields) 2 fields ,
 #define INTEGER(pn,pr,member)     +4+4 
 #define INT64(pn,pr,member)       +4+8
 #define BIT(pn,pr,member)         +4+1
 #define STRING(pn,pr,member,len)  +4+len
 #include "drbd_nl.h"
+};
 
 /* The two highest bits are used for the tag type */
 #define TT_MASK      0xC000

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2006-08-29 13:50:39 UTC (rev 2391)
+++ trunk/user/drbdsetup.c	2006-08-31 19:06:56 UTC (rev 2392)
@@ -1053,6 +1053,10 @@
 	prevcol=col=0;
 
 	col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
+
+	// Only those config commands have arguments and options...
+	if(commands[i].function != generic_config_cmd) goto out;
+
 	if ((args = commands[i].cp.args)) {
 		while (args->name) {
 			col += snprintf(line+col, maxcol-col, " %s", args->name);
@@ -1087,6 +1091,8 @@
 		}
 	}
 	line[col]=0;
+
+ out:
 	printf("%s\n",line);
 	if (addinfo) {
 		printf("%s\n",addinfo);
@@ -1210,7 +1216,8 @@
 
 int send_tag_list_cn(int sk_nl, struct drbd_tag_list *tl, const int packet_id, int minor, int flags)
 {
-	tl->cn_header->id.val = packet_id;
+	tl->cn_header->id.val = CN_VAL_DRBD;
+	tl->drbd_p_header->packet_type = packet_id;
 	tl->drbd_p_header->drbd_minor = minor;
 	tl->drbd_p_header->flags = flags;
 

