[DRBD-cvs] svn commit by phil - r2386 - in trunk: . drbd drbd/linux user - The new netlink (connector) based userland <-> kernel i

drbd-cvs at lists.linbit.com drbd-cvs at lists.linbit.com
Fri Aug 25 10:50:51 CEST 2006


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 at linbit.com>.
+   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg at 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 at linbit.com>.
-   Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg at linbit.com>.
-   Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
-
-   Copyright (C) 2000, Fábio Olivé Leite <olive at 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 at 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 at 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>



More information about the drbd-cvs mailing list