[DRBD-cvs] r1624 - in trunk: drbd drbd/linux user

svn at svn.drbd.org svn at svn.drbd.org
Wed Nov 3 16:57:33 CET 2004


Author: phil
Date: 2004-11-03 16:57:30 +0100 (Wed, 03 Nov 2004)
New Revision: 1624

Modified:
   trunk/drbd/Makefile
   trunk/drbd/drbd_actlog.c
   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_strings.c
   trunk/drbd/drbd_worker.c
   trunk/drbd/linux/drbd.h
   trunk/user/drbdsetup.c
Log:
* Introduced a new datatype to reflect the state of the
  whole cluster.
* Replaced set_cstate() by drbd_request_state() and
  drbd_force_state(). 
* Removed DISKLESS, PARTNER_DISKLESS and 
  PARTNER_CONSISTENT bits.
* Have a central function where the cluster state is
  checked.

It compiles. It completely untested. Will beginn testing
and debugging tomorrow (2004-11-04)




Modified: trunk/drbd/Makefile
===================================================================
--- trunk/drbd/Makefile	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/Makefile	2004-11-03 15:57:30 UTC (rev 1624)
@@ -74,7 +74,7 @@
   SRC_FILES := $(shell ls 2>/dev/null\
 	linux/drbd_config.h linux/drbd.h drbd_actlog.c drbd_bitmap.c drbd_fs.c \
 	drbd_main.c drbd_proc.c drbd_receiver.c drbd_req.c drbd_worker.c \
-	lru_cache.c drbd_compat_wrappers.h drbd_int.h \
+	drbd_strings.c lru_cache.c drbd_compat_wrappers.h drbd_int.h \
 	lru_cache.h )
 
   .PHONY: drbd.o default all greeting clean kbuild install dep

Modified: trunk/drbd/drbd_actlog.c
===================================================================
--- trunk/drbd/drbd_actlog.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_actlog.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -218,7 +218,7 @@
 
 		evicted = al_ext->lc_number;
 
-		if(mdev->cstate < Connected && evicted != LC_FREE ) {
+		if(mdev->state.s.conn < Connected && evicted != LC_FREE ) {
 			drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT );
 		}
 		drbd_al_write_transaction(mdev,al_ext,enr);
@@ -547,8 +547,8 @@
 	kfree(udw);
 
 	if(drbd_bm_total_weight(mdev) == 0 &&
-	   ( mdev->cstate == SyncSource || mdev->cstate == SyncTarget ||
-	     mdev->cstate == PausedSyncS || mdev->cstate == PausedSyncT ) ) {
+	   ( mdev->state.s.conn == SyncSource || mdev->state.s.conn == SyncTarget ||
+	     mdev->state.s.conn == PausedSyncS || mdev->state.s.conn == PausedSyncT ) ) {
 		D_ASSERT( mdev->resync_work.cb == w_resync_inactive );
 		drbd_bm_lock(mdev);
 		drbd_resync_finished(mdev);
@@ -588,7 +588,7 @@
 				     (unsigned long)sector,
 				     ext->lce.lc_number, ext->rs_left, cleared);
 				// FIXME brrrgs. should never happen!
-				_set_cstate(mdev,StandAlone);
+				drbd_force_state(mdev,NS(conn,StandAlone));
 				drbd_thread_stop_nowait(&mdev->receiver);
 				return;
 			}
@@ -651,16 +651,7 @@
 	unsigned long sbnr,ebnr,lbnr,bnr;
 	unsigned long count = 0;
 	sector_t esector, nr_sectors;
-	int strange_state;
 
-	strange_state = (mdev->cstate <= Connected) ||
-	                test_bit(DISKLESS,&mdev->flags) ||
-	                test_bit(PARTNER_DISKLESS,&mdev->flags);
-	if (strange_state) {
-		ERR("%s:%d: %s flags=0x%02lx\n", file , line ,
-				cstate_to_name(mdev->cstate), mdev->flags);
-	}
-
 	if (size <= 0 || (size & 0x1ff) != 0 || size > PAGE_SIZE) {
 		ERR("drbd_set_in_sync: sector=%lu size=%d nonsense!\n",
 				(unsigned long)sector,size);
@@ -727,17 +718,7 @@
 {
 	unsigned long sbnr,ebnr,lbnr,bnr;
 	sector_t esector, nr_sectors;
-	int strange_state;
 
-	strange_state = ( mdev->cstate  > Connected ) ||
-	                ( mdev->cstate == Connected &&
-	                 !(test_bit(DISKLESS,&mdev->flags) ||
-	                   test_bit(PARTNER_DISKLESS,&mdev->flags)) );
-	if (strange_state) {
-		ERR("%s:%d: %s flags=0x%02lx\n", file , line ,
-				cstate_to_name(mdev->cstate), mdev->flags);
-	}
-
 	if (size <= 0 || (size & 0x1ff) != 0 || size > PAGE_SIZE) {
 		ERR("sector: %lu, size: %d\n",(unsigned long)sector,size);
 		return;

Modified: trunk/drbd/drbd_fs.c
===================================================================
--- trunk/drbd/drbd_fs.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_fs.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -215,7 +215,7 @@
 int drbd_ioctl_set_disk(struct Drbd_Conf *mdev,
 			struct ioctl_disk_config * arg)
 {
-	int i, md_gc_valid, minor, mput=0;
+	int i, md_gc_valid, minor;
 	enum ret_codes retcode;
 	struct disk_config new_conf;
 	struct file *filp = 0;
@@ -227,7 +227,7 @@
 
 	/* if you want to reconfigure, please tear down first */
 	smp_rmb();
-	if (!test_bit(DISKLESS,&mdev->flags))
+	if (mdev->state.s.disk > Diskless)
 		return -EBUSY;
 
 	/* if this was "adding" a lo dev to a previously "diskless" node,
@@ -235,7 +235,7 @@
 	 * if it was mounted, we had an open_cnt > 1,
 	 * so it would be BUSY anyways...
 	 */
-	ERR_IF (mdev->state != Secondary)
+	ERR_IF (mdev->state.s.role != Secondary)
 		return -EBUSY;
 
 	if (mdev->open_cnt > 1)
@@ -257,20 +257,14 @@
 	 *
 	 */
 
-	if (mdev->cstate == Unconfigured) {
-		// ioctl already has a refcnt
-		__module_get(THIS_MODULE);
-		mput = 1;
-	} else {
-		/* FIXME allow reattach while connected,
-		 * and allow it in Primary/Diskless state...
-		 * currently there are strange races leading to a distributed
-		 * deadlock in that case...
-		 */
-		if ( mdev->cstate != StandAlone /* &&
-		    mdev->cstate != Connected */) {
-			return -EBUSY;
-		}
+
+	/* FIXME allow reattach while connected,
+	 * and allow it in Primary/Diskless state...
+	 * currently there are strange races leading to a distributed
+	 * deadlock in that case...
+	 */
+	if ( mdev->state.s.conn > StandAlone ) {
+		return -EBUSY;
 	}
 
 	if ( new_conf.meta_index < -1) {
@@ -387,7 +381,6 @@
 	D_ASSERT(q->hardsect_size <= PAGE_SIZE); // or we are really screwed ;-)
 #undef min_not_zero
 
-	clear_bit(SENT_DISK_FAILURE,&mdev->flags);
 	set_bit(MD_IO_ALLOWED,&mdev->flags);
 
 /* FIXME I think inc_local_md_only within drbd_md_read is misplaced.
@@ -441,24 +434,15 @@
 
 	drbd_set_blocksize(mdev,INITIAL_BLOCK_SIZE);
 
-	if(mdev->cstate == Unconfigured ) {
+	if (drbd_request_state(mdev,NS(disk,
+				       drbd_md_test_flag(mdev,MDF_Consistent) ?
+				       Consistent : Inconsistent ))) {
 		drbd_thread_start(&mdev->worker);
-		set_cstate(mdev,StandAlone);
 	}
 
-
-	clear_bit(DISKLESS,&mdev->flags);
-	smp_wmb();
 // FIXME EXPLAIN:
 	clear_bit(MD_IO_ALLOWED,&mdev->flags);
 
-	/* FIXME currently only StandAlone here...
-	 * Connected is not possible, since
-	 * above we return -EBUSY in that case  */
-	D_ASSERT(mdev->cstate <= Connected);
-	if(mdev->cstate == Connected ) {
-		drbd_send_param(mdev,1);
-	}
 	drbd_bm_unlock(mdev);
 
 	return 0;
@@ -468,7 +452,6 @@
  release_bdev_fail_ioctl:
 	bd_release(bdev);
  fail_ioctl:
-	if (mput) module_put(THIS_MODULE);
 	if (filp) fput(filp);
 	if (filp2) fput(filp2);
 	if (put_user(retcode, &arg->ret_code)) return -EFAULT;
@@ -491,10 +474,7 @@
 		cn.meta_device_minor  = MINOR(mdev->md_bdev->bd_dev);
 		bdevname(mdev->md_bdev,cn.meta_device_name);
 	}
-	cn.cstate=mdev->cstate;
 	cn.state=mdev->state;
-	cn.peer_state=mdev->o_state;
-	cn.disk_size_user=mdev->lo_usize;
 	cn.meta_index=mdev->md_index;
 	cn.on_io_error=mdev->on_io_error;
 	memcpy(&cn.nconf, &mdev->conf, sizeof(struct net_config));
@@ -510,7 +490,7 @@
 STATIC
 int drbd_ioctl_set_net(struct Drbd_Conf *mdev, struct ioctl_net_config * arg)
 {
-	int i,minor, mput=0;
+	int i,minor;
 	enum ret_codes retcode;
 	struct net_config new_conf;
 
@@ -520,24 +500,18 @@
 	if (copy_from_user(&new_conf, &arg->config,sizeof(struct net_config)))
 		return -EFAULT;
 
-	if (mdev->cstate == Unconfigured) {
-		// ioctl already has a refcnt
-		__module_get(THIS_MODULE);
-		mput = 1;
-	}
-
 #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.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].cstate!=Unconfigured &&
+		if( i!=minor && drbd_conf[i].state.s.conn==Unconfigured &&
 		    M_ADDR(new_conf) == M_ADDR(drbd_conf[i].conf) &&
 		    M_PORT(new_conf) == M_PORT(drbd_conf[i].conf) ) {
 			retcode=LAAlreadyInUse;
 			goto fail_ioctl;
 		}
-		if( i!=minor && drbd_conf[i].cstate!=Unconfigured &&
+		if( i!=minor && drbd_conf[i].state.s.conn!=Unconfigured &&
 		    O_ADDR(new_conf) == O_ADDR(drbd_conf[i].conf) &&
 		    O_PORT(new_conf) == O_PORT(drbd_conf[i].conf) ) {
 			retcode=OAAlreadyInUse;
@@ -590,35 +564,27 @@
 	mdev->recv_cnt = 0;
 
 	drbd_thread_start(&mdev->worker);
-	set_cstate(mdev,Unconnected);
+	drbd_request_state(mdev,NS(conn,Unconnected));
 	drbd_thread_start(&mdev->receiver);
 
 	return 0;
 
   fail_ioctl:
-	if (mput) module_put(THIS_MODULE);
 	if (put_user(retcode, &arg->ret_code)) return -EFAULT;
 	return -EINVAL;
 }
 
-int drbd_set_state(drbd_dev *mdev,Drbd_State newstate)
+int drbd_set_state(drbd_dev *mdev,drbd_role_t newstate)
 {
-	int forced = 0;
-	int dont_have_good_data;
+	int r;
 
 	D_ASSERT(semaphore_is_locked(&mdev->device_mutex));
 
-	if ( (newstate & 0x3) == mdev->state ) return 0; /* nothing to do */
+	if ( (newstate & 0x3) == mdev->state.s.role ) return 0; /* nothing to do */
 
 	// exactly one of sec or pri. not both.
 	if ( !((newstate ^ (newstate >> 1)) & 1) ) return -EINVAL;
 
-	if(mdev->cstate == Unconfigured)
-		return -ENXIO;
-
-	if ( (newstate & Primary) && (mdev->o_state == Primary) )
-		return -EACCES;
-
 	ERR_IF (mdev->this_bdev->bd_contains == 0) {
 		// FIXME this masks a bug somewhere else!
 		mdev->this_bdev->bd_contains = mdev->this_bdev;
@@ -632,47 +598,32 @@
 			return -EBUSY;
 	}
 
-	/* I dont have access to good data anywhere, if:
-	 *  ( I am diskless OR inconsistent )
-	 *  AND
-	 *  ( not connected, or partner has no consistent data either )
-	 */
-	dont_have_good_data =
-		(    test_bit(DISKLESS, &mdev->flags)
-		  || !drbd_md_test_flag(mdev,MDF_Consistent) )
-		&&
-		( mdev->cstate < Connected
-		  || test_bit(PARTNER_DISKLESS, &mdev->flags)
-		  || !test_bit(PARTNER_CONSISTENT, &mdev->flags) );
-
-	if (newstate & Primary) {
-		if ( test_bit(DISKLESS,&mdev->flags)
-		    && mdev->cstate < Connected ) {
-			/* not even brute force can find data without disk.
-			 * FIXME choose a usefull Error,
-			 * and update drbsetup accordingly */
+	r = drbd_request_state(mdev,NS(role,newstate & 0x3));
+	if ( r == 2 ) { return 0; }
+	if ( r == 0 ) {
+		/* request state does not like the new state. */
+		if (! (newstate & DontBlameDrbd)) {
 			return -EIO;
-		} else if (dont_have_good_data) {
-			/* ok, either we have a disk (which may be inconsistent)
-			 * or we have a connection */
-			if (newstate & DontBlameDrbd) {
-				forced = 1;
-				/* make sure the Human count is increased if
-				 * we got here only because it was forced.
-				 * maybe we want to force a FullSync? */
-				newstate |= Human;
-			} else {
-				return -EIO;
-			}
-		} else if (mdev->cstate >= Connected) {
-			/* do NOT increase the Human count if we are connected,
-			 * and there is no reason for it.  See
-			 * drbd_lk9.pdf middle of Page 7
-			 */
-			newstate &= ~(Human|DontBlameDrbd);
 		}
+
+		/* --do-what-I-say*/
+		if (mdev->state.s.disk < Consistent) {
+			WARN("Forcefully set consistent!");
+			r = drbd_request_state(mdev,NS2(role,newstate & 0x3,
+							disk,Consistent));
+			if(r==0) return -EIO;
+		}
 	}
 
+	if (mdev->state.s.conn >= Connected) {
+		/* do NOT increase the Human count if we are connected,
+		 * and there is no reason for it.  See
+		 * drbd_lk9.pdf middle of Page 7
+		 */
+		newstate &= ~(Human|DontBlameDrbd);
+	}
+
+
 	drbd_sync_me(mdev);
 
 	/* Wait until nothing is on the fly :) */
@@ -691,25 +642,8 @@
 	 * but that means someone is misusing DRBD...
 	 * */
 
-	if (forced) { /* this was --do-what-I-say ... */
-		int i;
-		// drbd_dump_md(mdev,0,0);
-		for (i=HumanCnt; i < GEN_CNT_SIZE ; i++) {
-			if (mdev->gen_cnt[i] != 1) {
-				WARN("Forcefully set consistent! "
-				     "If this screws your data, don't blame DRBD!\n");
-				break;
-			}
-		}
-		drbd_md_set_flag(mdev,MDF_Consistent);
-	}
 	set_bit(MD_DIRTY,&mdev->flags); // we are changing state!
-	INFO( "%s/%s --> %s/%s\n",
-	      nodestate_to_name(mdev->state),
-	      nodestate_to_name(mdev->o_state),
-	      nodestate_to_name(newstate & 0x03),
-	      nodestate_to_name(mdev->o_state)   );
-	mdev->state = (Drbd_State) newstate & 0x03;
+
 	if (newstate & Secondary) {
 		set_disk_ro(mdev->vdisk, TRUE );
 	} else {
@@ -734,22 +668,17 @@
 			drbd_md_inc(mdev,TimeoutCnt);
 		} else {
 			drbd_md_inc(mdev,
-			    mdev->cstate >= Connected ?
-			    ConnectedCnt : ArbitraryCnt);
+				    mdev->state.s.conn >= Connected ?
+				    ConnectedCnt : ArbitraryCnt);
 		}
 	}
 
-	if(!test_bit(DISKLESS,&mdev->flags) && (newstate & Secondary)) {
+	if(mdev->state.s.disk > Diskless && (newstate & Secondary)) {
 		drbd_al_to_on_disk_bm(mdev);
 	}
 	/* Primary indicator has changed in any case. */
 	drbd_md_write(mdev);
 
-	if (mdev->cstate >= WFReportParams) {
-		/* if this was forced, we should consider sync */
-		drbd_send_param(mdev,forced);
-	}
-
 	return 0;
 }
 
@@ -806,7 +735,7 @@
 	err = drbd_check_al_size(mdev);
 	if (err) return err;
 
-	if (mdev->cstate > WFConnection)
+	if (mdev->state.s.conn >= Connected)
 		drbd_send_sync_param(mdev,&sc);
 
 	drbd_alter_sg(mdev, sc.group);
@@ -814,51 +743,33 @@
 	return 0;
 }
 
+/* new */
 STATIC int drbd_detach_ioctl(drbd_dev *mdev)
 {
-	int would_discard_last_good_data;
-	int interrupted;
+	int interrupted,r;
+	drbd_state_t os,ns;
 
-	// not during resync. no.
-	if (mdev->cstate > Connected) return -EBUSY;
+	spin_lock_irq(&mdev->req_lock);
+	os = mdev->state;
+	r = _drbd_set_state(mdev,_NS(disk,Diskless),0);
+	ns = mdev->state;
+	spin_unlock_irq(&mdev->req_lock);
 
-	/* this was the last good data copy, if:
-	 *  (I am Primary, and not connected ),
-	 *  OR
-	 *  (we are connected, and Peer has no good data himself)
-	 */
-	would_discard_last_good_data =
-		( mdev->state == Primary && mdev->cstate < Connected )
-		||
-		( mdev->cstate >= Connected
-		  && (    test_bit(PARTNER_DISKLESS, &mdev->flags)
-		      || !test_bit(PARTNER_CONSISTENT, &mdev->flags) ) );
+	if( r == 2 ) { return 0; }
+	if( r == 0 ) { return -ENETRESET; }
 
-	if ( would_discard_last_good_data ) {
-		return -ENETRESET;
-	}
-	if (test_bit(DISKLESS,&mdev->flags) ||
-	    test_bit(PARTNER_DISKLESS,&mdev->flags) ) {
-		return -ENXIO;
-	}
-
 	drbd_sync_me(mdev);
 
-	set_bit(DISKLESS,&mdev->flags);
-	smp_wmb();
-
 	interrupted = wait_event_interruptible(mdev->cstate_wait,
 				      atomic_read(&mdev->local_cnt)==0);
 	if ( interrupted ) {
-		clear_bit(DISKLESS,&mdev->flags);
+		drbd_force_state(mdev,NS(disk,os.s.disk));
 		return -EINTR;
 	}
 
 	drbd_free_ll_dev(mdev);
+	after_state_ch(mdev, os, ns);
 
-/* FIXME race with sync start
-*/
-	if (mdev->cstate == Connected) drbd_send_param(mdev,0);
 /* FIXME
 * if you detach while connected, you are *at least* inconsistent now,
 * and should clear MDF_Consistent in metadata, and maybe even set the bitmap
@@ -866,19 +777,13 @@
 * since if you reattach, this might be a different lo dev, and then it needs
 * to receive a sync!
 */
-	if (mdev->cstate == StandAlone) {
-		// maybe  < Connected is better?
-		set_cstate(mdev,Unconfigured);
-		drbd_mdev_cleanup(mdev);
-		module_put(THIS_MODULE);
-	}
 	return 0;
 }
 
 int drbd_ioctl(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg)
 {
-	int minor,err=0;
+	int r,minor,err=0;
 	long time;
 	struct Drbd_Conf *mdev;
 	struct ioctl_wait* wp;
@@ -916,44 +821,6 @@
 		goto out_unlocked;
 	}
 
-	if (mdev->cstate == Unconfigured) {
-		switch (cmd) {
-		default:
-			/* oops, unknown IOCTL ?? */
-			err = -EINVAL;
-			goto out_unlocked;
-
-		case DRBD_IOCTL_GET_CONFIG:
-		case DRBD_IOCTL_GET_VERSION:
-			break;		/* always allowed */
-
-		case DRBD_IOCTL_SET_DISK_CONFIG:
-		case DRBD_IOCTL_SET_NET_CONFIG:
-			break;		/* no restriction here */
-
-		case DRBD_IOCTL_UNCONFIG_DISK:
-		case DRBD_IOCTL_UNCONFIG_NET:
-			/* no op, so "drbdadm down all" does not fail */
-			err = 0;
-			goto out_unlocked;
-
-		/* the rest of them don't make sense if Unconfigured.
-		 * still, set an Unconfigured device Secondary
-		 * is allowed, so "drbdadm down all" does not fail */
-		case DRBD_IOCTL_SET_STATE:
-		case DRBD_IOCTL_INVALIDATE:
-		case DRBD_IOCTL_INVALIDATE_REM:
-		case DRBD_IOCTL_SET_DISK_SIZE:
-		case DRBD_IOCTL_SET_STATE_FLAGS:
-		case DRBD_IOCTL_SET_SYNC_CONFIG:
-		case DRBD_IOCTL_WAIT_CONNECT:
-		case DRBD_IOCTL_WAIT_SYNC:
-			err = (cmd == DRBD_IOCTL_SET_STATE && arg == Secondary)
-				    ? 0 : -ENXIO;
-			goto out_unlocked;
-		}
-	}
-
 	if (unlikely(drbd_did_panic == DRBD_MAGIC))
 		return -EBUSY;
 
@@ -1000,7 +867,7 @@
 		break;
 
 	case DRBD_IOCTL_SET_DISK_SIZE:
-		if (mdev->cstate > Connected) {
+		if (mdev->state.s.conn > Connected) {
 			err = -EBUSY;
 			break;
 		}
@@ -1010,7 +877,7 @@
 		drbd_determin_dev_size(mdev);
 		drbd_md_write(mdev); // Write mdev->la_size to disk.
 		drbd_bm_unlock(mdev);
-		if (mdev->cstate == Connected) drbd_send_param(mdev,0);
+		if (mdev->state.s.conn == Connected) drbd_send_param(mdev,0);
 		break;
 
 	case DRBD_IOCTL_SET_NET_CONFIG:
@@ -1027,31 +894,31 @@
 		break;
 
 	case DRBD_IOCTL_UNCONFIG_NET:
-		if ( mdev->cstate == Unconfigured) break;
-		if (  (   mdev->state  == Primary
-		       && test_bit(DISKLESS,&mdev->flags) )
-		   || (   mdev->o_state == Primary
-		       && !test_bit(PARTNER_CONSISTENT,&mdev->flags) ) )
-		{
+		if ( mdev->state.s.conn == Unconfigured) break;
+
+		r = drbd_request_state(mdev,NS(conn,StandAlone));
+		if( r == 2 ) { break; }
+		if( r == 0 ) {
 			err=-ENODATA;
 			break;
-		}
-		/* FIXME what if fsync returns error */
-		drbd_sync_me(mdev);
+		} 
+		/* r == 1 which means that we changed the state... */
+
+		drbd_sync_me(mdev); /* FIXME what if fsync returns error */
+
 		set_bit(DO_NOT_INC_CONCNT,&mdev->flags);
-		set_cstate(mdev,Unconnected);
 		drbd_thread_stop(&mdev->receiver);
 
-		if (test_bit(DISKLESS,&mdev->flags)) {
-			set_cstate(mdev,Unconfigured);
-			drbd_mdev_cleanup(mdev);
+		if ( mdev->state.s.conn == StandAlone && 
+		     mdev->state.s.disk == Diskless ) {
+			drbd_mdev_cleanup(mdev);  // Move to after_state_ch() ?
 			module_put(THIS_MODULE);
-		} else set_cstate(mdev,StandAlone);
+		}
 
 		break;
 
 	case DRBD_IOCTL_UNCONFIG_DISK:
-		if (mdev->cstate == Unconfigured) break;
+		if (mdev->state.s.disk == Diskless) break;
 		err = drbd_detach_ioctl(mdev);
 		break;
 
@@ -1064,8 +931,8 @@
 
 		time = wait_event_interruptible_timeout(
 			mdev->cstate_wait,
-			mdev->cstate < Unconnected
-			|| mdev->cstate >= Connected,
+			mdev->state.s.conn < Unconnected
+			|| mdev->state.s.conn >= Connected,
 			time );
 		if (time < 0) {
 			err = time;
@@ -1077,7 +944,7 @@
 		}
 		err=0; // no error
 
-		if(put_user(mdev->cstate>=Connected,&wp->ret_code))err=-EFAULT;
+		if(put_user(mdev->state.s.conn>=Connected,&wp->ret_code))err=-EFAULT;
 		goto out_unlocked;
 
 	case DRBD_IOCTL_WAIT_SYNC:
@@ -1089,8 +956,8 @@
 		do {
 			time = wait_event_interruptible_timeout(
 				mdev->cstate_wait,
-				mdev->cstate == Connected
-				|| mdev->cstate < Unconnected,
+				mdev->state.s.conn == Connected
+				|| mdev->state.s.conn < Unconnected,
 				time );
 
 			if (time < 0 ) {
@@ -1098,7 +965,7 @@
 				goto out_unlocked;
 			}
 
-			if (mdev->cstate > Connected) {
+			if (mdev->state.s.conn > Connected) {
 				time=MAX_SCHEDULE_TIMEOUT;
 			}
 
@@ -1106,12 +973,12 @@
 				err = -ETIME;
 				goto out_unlocked;
 			}
-		} while ( mdev->cstate != Connected
-			  && mdev->cstate >= Unconnected );
+		} while ( mdev->state.s.conn != Connected
+			  && mdev->state.s.conn >= Unconnected );
 
 		err=0; // no error
 
-		if(put_user(mdev->cstate==Connected,&wp->ret_code))err=-EFAULT;
+		if(put_user(mdev->state.s.conn==Connected,&wp->ret_code))err=-EFAULT;
 		goto out_unlocked;
 
 	case DRBD_IOCTL_INVALIDATE:
@@ -1123,23 +990,22 @@
 		/* disallow "invalidation" of local replica
 		 * when currently in primary state (would be a Bad Idea),
 		 * or during a running sync (won't make any sense) */
-		if( mdev->state == Primary ||
-		    mdev->cstate < StandAlone ||
-		    mdev->cstate > Connected ||
-		    test_bit(DISKLESS,&mdev->flags) ||
-		    test_bit(PARTNER_DISKLESS,&mdev->flags) ) {
+
+		/* PRE TODO disallow invalidate if we are primary */
+		r = drbd_request_state(mdev,NS2(disk,Inconsistent,
+					        conn,WFBitMapT));
+
+		if( r == 2 ) { break; }
+		if( r == 0 ) {
 			err = -EINPROGRESS;
 			break;
-		}
+		} 
 
-		if (mdev->cstate == Connected) {
-			/* avoid races with set_in_sync
-			 * for successfull mirrored writes
-			 */
-			set_cstate(mdev,WFBitMapT);
-			wait_event(mdev->cstate_wait,
-				   atomic_read(&mdev->ap_bio_cnt)==0);
-		}
+		/* avoid races with set_in_sync
+		 * for successfull mirrored writes
+		 */
+		wait_event(mdev->cstate_wait,
+			   atomic_read(&mdev->ap_bio_cnt)==0);
 
 		drbd_bm_lock(mdev); // racy...
 
@@ -1153,8 +1019,7 @@
 		drbd_md_clear_flag(mdev,MDF_FullSync);
 		drbd_md_write(mdev);
 
-		if (mdev->cstate == Connected) {
-			drbd_send_short_cmd(mdev,BecomeSyncSource);
+		if (drbd_send_short_cmd(mdev,BecomeSyncSource)) {
 			drbd_start_resync(mdev,SyncTarget);
 		}
 
@@ -1163,18 +1028,17 @@
 		break;
 
 	case DRBD_IOCTL_INVALIDATE_REM:
-		if( mdev->o_state == Primary ||
-		    mdev->cstate != Connected ||
-		    test_bit(DISKLESS,&mdev->flags) ||
-		    test_bit(PARTNER_DISKLESS,&mdev->flags) ) {
+
+		/* PRE TODO disallow invalidate if we peer is primary */
+		/* remove EINVAL from error output... */
+		r = drbd_request_state(mdev,NS2(pedi,Inconsistent,
+					        conn,WFBitMapS));
+
+		if( r == 2 ) { break; }
+		if( r == 0 ) {
 			err = -EINPROGRESS;
 			break;
-		}
-		if ( !drbd_md_test_flag(mdev,MDF_Consistent) ) {
-			// FIXME use a more descriptive error number
-			err = -EINVAL;
-			break;
-		}
+		} 
 
 		drbd_md_set_flag(mdev,MDF_FullSync);
 		drbd_md_write(mdev);
@@ -1182,7 +1046,6 @@
 		/* avoid races with set_in_sync
 		 * for successfull mirrored writes
 		 */
-		set_cstate(mdev,WFBitMapS);
 		wait_event(mdev->cstate_wait,
 		     atomic_read(&mdev->ap_bio_cnt)==0);
 

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_int.h	2004-11-03 15:57:30 UTC (rev 1624)
@@ -613,9 +613,6 @@
 	ON_PRI_INC_TIMEOUTEX,   // When " - "  increase timeout-count
 	UNPLUG_QUEUED,		// only relevant with kernel 2.4
 	UNPLUG_REMOTE,		// whether sending a "UnplugRemote" makes sense
-	DISKLESS,		// no local disk
-	PARTNER_DISKLESS,	// partner has no storage
-	PARTNER_CONSISTENT,	// partner has consistent data
 	PROCESS_EE_RUNNING,	// eek!
 	MD_IO_ALLOWED,		// EXPLAIN
 	SENT_DISK_FAILURE,	// sending it once is enough
@@ -678,10 +675,8 @@
 	int md_index;
 	sector_t lo_usize;   /* user provided size */
 	sector_t p_size;     /* partner's disk size */
-	Drbd_State state;
-	volatile Drbd_CState cstate;
+	/* volatile */ drbd_state_t state;
 	wait_queue_head_t cstate_wait; // TODO Rename into "misc_wait". 
-	Drbd_State o_state;
 	sector_t la_size;     // last agreed disk size in sectors.
 	unsigned int send_cnt;
 	unsigned int recv_cnt;
@@ -748,7 +743,8 @@
  *************************/
 
 // drbd_main.c
-extern void _set_cstate(drbd_dev* mdev,Drbd_CState cs);
+extern int _drbd_set_state(drbd_dev* mdev, drbd_state_t ns, int hard);
+extern void after_state_ch(drbd_dev* mdev, drbd_state_t os, drbd_state_t ns);
 extern void drbd_thread_start(struct Drbd_thread *thi);
 extern void _drbd_thread_stop(struct Drbd_thread *thi, int restart, int wait);
 extern void drbd_free_resources(drbd_dev *mdev);
@@ -950,14 +946,14 @@
 // drbd_fs.c
 extern char* ppsize(char* buf, size_t size);
 extern int drbd_determin_dev_size(drbd_dev*);
-extern int drbd_set_state(drbd_dev *mdev,Drbd_State newstate);
+extern int drbd_set_state(drbd_dev *mdev,drbd_role_t newstate);
 extern int drbd_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg);
 
 // drbd_dsender.c
 extern int drbd_worker(struct Drbd_thread *thi);
 extern void drbd_alter_sg(drbd_dev *mdev, int ng);
-extern void drbd_start_resync(drbd_dev *mdev, Drbd_CState side);
+extern void drbd_start_resync(drbd_dev *mdev, drbd_conns_t side);
 extern int drbd_resync_finished(drbd_dev *mdev);
 // maybe rather drbd_main.c ?
 extern int drbd_md_sync_page_io(drbd_dev *mdev, sector_t sector, int rw);
@@ -984,8 +980,8 @@
 // drbd_proc.c
 extern struct proc_dir_entry *drbd_proc;
 extern int drbd_proc_get_info(char *, char **, off_t, int, int *, void *);
-extern const char* cstate_to_name(Drbd_CState s);
-extern const char* nodestate_to_name(Drbd_State s);
+extern const char* cstate_to_name(drbd_conns_t s);
+extern const char* nodestate_to_name(drbd_role_t s);
 
 // drbd_actlog.c
 extern void drbd_al_begin_io(struct Drbd_Conf *mdev, sector_t sector);
@@ -1010,14 +1006,57 @@
 
 #include "drbd_compat_wrappers.h"
 
-static inline void set_cstate(drbd_dev* mdev,Drbd_CState ns)
+#define peer_mask role_mask
+#define pedi_mask disk_mask
+
+#define NS(T,S) ({drbd_state_t mask; mask.i=0; mask.s.T = T##_mask; mask;}), \
+                ({drbd_state_t val; val.i=0; val.s.T = (S); val;})
+#define NS2(T1,S1,T2,S2) \
+                ({drbd_state_t mask; mask.i=0; mask.s.T1 = T1##_mask; \
+		  mask.s.T2 = T2##_mask; mask;}), \
+                ({drbd_state_t val; val.i=0; val.s.T1 = (S1); \
+                  val.s.T2 = (S2); val;})
+#define NS3(T1,S1,T2,S2,T3,S3) \
+                ({drbd_state_t mask; mask.i=0; mask.s.T1 = T1##_mask; \
+		  mask.s.T2 = T2##_mask; mask.s.T3 = T3##_mask; mask;}), \
+                ({drbd_state_t val; val.i=0; val.s.T1 = (S1); \
+                  val.s.T2 = (S2); val.s.T3 = (S3); val;})
+
+#define _NS(T,S) ({drbd_state_t ns; ns.i = mdev->state.i; ns.s.T = (S); ns;})
+
+static inline void drbd_force_state(drbd_dev* mdev, 
+				    drbd_state_t mask, drbd_state_t val)
 {
 	unsigned long flags;
+	drbd_state_t os,ns;
+
 	spin_lock_irqsave(&mdev->req_lock,flags);
-	_set_cstate(mdev,ns);
+	os = mdev->state;
+	ns.i = (os.i & ~mask.i) | val.i;
+	_drbd_set_state(mdev, ns, 1);
+	ns = mdev->state;
 	spin_unlock_irqrestore(&mdev->req_lock,flags);
+	after_state_ch(mdev,os,ns);
 }
 
+static inline int drbd_request_state(drbd_dev* mdev, 
+				     drbd_state_t mask, drbd_state_t val)
+{
+	unsigned long flags;
+	drbd_state_t os,ns;
+	int rv;
+
+	spin_lock_irqsave(&mdev->req_lock,flags);
+	os = mdev->state;
+	ns.i = (os.i & ~mask.i) | val.i;
+	rv = _drbd_set_state(mdev, ns, 0);
+	ns = mdev->state;
+	spin_unlock_irqrestore(&mdev->req_lock,flags);
+	after_state_ch(mdev,os,ns);
+
+	return rv;
+}
+
 /**
  * drbd_chk_io_error: Handles the on_io_error setting, should be called from
  * all io completion handlers. See also drbd_io_error().
@@ -1025,30 +1064,25 @@
 static inline void drbd_chk_io_error(drbd_dev* mdev, int error)
 {
 	if (error) {
+		unsigned long flags;
+		spin_lock_irqsave(&mdev->req_lock,flags);
+
 		switch(mdev->on_io_error) {
 		case PassOn:
 			ERR("Ignoring local IO error!\n");
 			break;
 		case Panic:
-			set_bit(DISKLESS,&mdev->flags);
-			smp_mb(); // but why is there smp_mb__after_clear_bit() ?
+			_drbd_set_state(mdev,_NS(disk,Failed),1);
 			drbd_panic("IO error on backing device!\n");
 			break;
 		case Detach:
-			/*lge:
-			 *  I still do not fully grasp when to set or clear
-			 *  this flag... but I want to be able to at least
-			 *  still _try_ and write the "I am inconsistent, and
-			 *  need full sync" information to the MD. */
 			set_bit(MD_IO_ALLOWED,&mdev->flags);
-			drbd_md_set_flag(mdev,MDF_FullSync);
-			drbd_md_clear_flag(mdev,MDF_Consistent);
-			if (!test_and_set_bit(DISKLESS,&mdev->flags)) {
-				smp_mb(); // Nack is sent in w_e handlers.
+			if (_drbd_set_state(mdev,_NS(disk,Failed),1) == 1) {
 				ERR("Local IO failed. Detaching...\n");
 			}
 			break;
 		}
+		spin_unlock_irqrestore(&mdev->req_lock,flags);
 	}
 }
 
@@ -1253,7 +1287,7 @@
 	int io_allowed;
 
 	atomic_inc(&mdev->local_cnt);
-	io_allowed = !test_bit(DISKLESS,&mdev->flags);
+	io_allowed = (mdev->state.s.disk >= Inconsistent);
 	if( !io_allowed ) {
 		atomic_dec(&mdev->local_cnt);
 	}
@@ -1265,7 +1299,7 @@
 	int io_allowed;
 
 	atomic_inc(&mdev->local_cnt);
-	io_allowed = !test_bit(DISKLESS,&mdev->flags) ||
+	io_allowed = (mdev->state.s.disk >= Inconsistent) ||
 		test_bit(MD_IO_ALLOWED,&mdev->flags);
 	if( !io_allowed ) {
 		atomic_dec(&mdev->local_cnt);
@@ -1276,7 +1310,7 @@
 static inline void dec_local(drbd_dev* mdev)
 {
 	if(atomic_dec_and_test(&mdev->local_cnt) && 
-	   test_bit(DISKLESS,&mdev->flags) &&
+	   mdev->state.s.disk == Diskless &&
 	   mdev->lo_file) {
 		wake_up(&mdev->cstate_wait);
 	}

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_main.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -331,12 +331,20 @@
  */
 int drbd_io_error(drbd_dev* mdev)
 {
-	int ok=1;
+	unsigned long flags;
+	int send,ok=1;
 
 	if(mdev->on_io_error != Panic && mdev->on_io_error != Detach) return 1;
-	if(test_and_set_bit(SENT_DISK_FAILURE,&mdev->flags)) return 1;
 
-	D_ASSERT(test_bit(DISKLESS,&mdev->flags));
+	spin_lock_irqsave(&mdev->req_lock,flags);
+	if( (send = (mdev->state.s.disk == Failed)) ) {
+		_drbd_set_state(mdev,_NS(disk,Diskless),1);
+	}
+	D_ASSERT(mdev->state.s.disk <= Failed);
+	spin_unlock_irqrestore(&mdev->req_lock,flags);
+
+	if(!send) return ok;
+
 	ok = drbd_send_param(mdev,0);
 	WARN("Notified peer that my disk is broken.\n");
 
@@ -347,11 +355,6 @@
 		drbd_md_write(mdev);
 	}
 
-	if(mdev->cstate > Connected ) {
-		WARN("Resync aborted.\n");
-		set_cstate(mdev,Connected);
-		mdev->rs_total = 0;
-	}
 	if ( wait_event_interruptible_timeout(mdev->cstate_wait,
 		     atomic_read(&mdev->local_cnt) == 0 , HZ ) <= 0) {
 		WARN("Not releasing backing storage device.\n");
@@ -371,36 +374,138 @@
 	return ok;
 }
 
-void _set_cstate(drbd_dev* mdev,Drbd_CState ns)
+#define drbd_peer_s_names drbd_role_s_names
+#define drbd_pedi_s_names drbd_disk_s_names
+
+#define PSC(A) \
+	({ if( ns.s.A != os.s.A ) { \
+		pbp += sprintf(pbp, #A "( %s -> %s ) ", \
+		              drbd_##A##_s_names[os.s.A], \
+		              drbd_##A##_s_names[ns.s.A]); \
+	} })
+
+
+/* PRE TODO: Should return ernno numbers from the pre-state-change checks. */
+int _drbd_set_state(drbd_dev* mdev, drbd_state_t ns, int hard)
 {
-	Drbd_CState os;
+	drbd_state_t os;
+	char pb[160], *pbp;
 
-	os = mdev->cstate;
+	os = mdev->state;
 
+	if( ns.i == os.i ) return 2;
+
+	if( !hard ) {
+		/*  pre-state-change checks ; only look at ns  */
+		if( !ns.s.mult && 
+		    ns.s.role == Primary && ns.s.peer == Primary ) {
+			WARN("Multiple primaries now allowed by config.");
+			return 0;
+		}
+
+		if( ns.s.role == Primary && ns.s.disk <= Inconsistent && 
+		    ns.s.conn < Connected ) {
+			WARN("Refusing to be Primary without consistent data");
+			return 0;
+		}
+
+		if( ns.s.peer == Primary && ns.s.pedi <= Inconsistent && 
+		    ns.s.conn < Connected ) {
+			WARN("Refusing to make peer Primary without data");
+			return 0;
+		}
+
+		if( ns.s.disk < Consistent && ns.s.pedi < Consistent ) {
+			WARN("Refusing to be inconsistent on both nodes.");
+			return 0;
+		}
+
+		if( ns.s.conn > Connected && 
+		    (ns.s.disk == Diskless || ns.s.pedi == Diskless ) ) {
+			WARN("Refusing to do resync without two disks.");
+			return 0;
+		}
+	}
+
+	/*  State sanitising  */
+	if( ns.s.conn < Connected ) ns.s.peer = Unknown;
+	if( ns.s.conn < Connected ) ns.s.pedi = DUnknown;
+
+	if( ns.s.disk <= Failed && ns.s.conn > Connected) {
+		WARN("Resync aborted.\n");
+		ns.s.conn = Connected;
+	}
+
 #if DUMP_MD >= 2
-	INFO("%s [%d]: cstate %s --> %s\n", current->comm, current->pid,
-	   cstate_to_name(os), cstate_to_name(ns) );
+	pbp = pb;
+	PSC(role);
+	PSC(peer);
+	PSC(conn);
+	PSC(disk);
+	PSC(pedi);
+	if( ns.s.mult != os.s.mult ) {
+		sprintf(pbp, "mult( %d -> %d)", os.s.mult,ns.s.mult);
+	}
+	INFO("%s\n", pb);
 #endif
 
-	mdev->cstate = ns;
-	smp_mb();
+	mdev->state.i = ns.i;
 	wake_up(&mdev->cstate_wait);
 
-	/* THINK.
-	 * was:
-	 * if ( ( os==SyncSource || os==SyncTarget ) && ns <= Connected ) {
-	 */
-	if ( ( os >= SyncSource ) && ns <= Connected ) {
+	/**   post-state-change actions   **/
+	if ( os.s.conn >= SyncSource   && ns.s.conn <= Connected ) {
 		set_bit(STOP_SYNC_TIMER,&mdev->flags);
 		mod_timer(&mdev->resync_timer,jiffies);
 	}
-	if(test_bit(MD_IO_ALLOWED,&mdev->flags) &&
-	   test_bit(DISKLESS,&mdev->flags) && ns < Connected) {
-// FIXME EXPLAIN
-		clear_bit(MD_IO_ALLOWED,&mdev->flags);
+
+	if ( os.s.peer == Secondary    && ns.s.peer == Primary ) {
+		drbd_md_inc(mdev,ConnectedCnt);
 	}
+
+	if ( os.s.disk == Diskless && os.s.peer == StandAlone &&
+	     (ns.s.disk >= Inconsistent || ns.s.peer > StandAlone) ) {
+		__module_get(THIS_MODULE);
+	}
+
+	if ( ns.s.role == Primary && ns.s.conn < Connected &&
+	     ns.s.disk < Consistent ) {
+		drbd_panic("No access to good data anymore.\n");
+	}
+
+	return 1;
 }
 
+void after_state_ch(drbd_dev* mdev, drbd_state_t os, drbd_state_t ns)
+{
+	/* Here we have the actions that are performed after a
+	   state change. This function might sleep */
+
+	/*  Added disk, tell peer.  */
+	if ( os.s.disk == Diskless && ns.s.disk >= Inconsistent &&
+	     ns.s.conn >= Connected ) {
+		drbd_send_param(mdev,1);
+	}
+
+	/*  Removed disk, tell peer.  */
+	if ( os.s.disk >= Inconsistent && ns.s.disk == Diskless &&
+	     ns.s.conn >= Connected ) {
+		drbd_send_param(mdev,0);
+	}
+
+	/*  Update MDF_Consistent in the meta-data  */
+	if ( os.s.disk != ns.s.disk && ns.s.disk > Failed ) {
+		if(ns.s.disk >= Outdated ) {
+			drbd_md_set_flag(mdev,MDF_Consistent);
+		} else {
+			drbd_md_clear_flag(mdev,MDF_Consistent);
+		}
+		/* TODO metadata, to support everything that 
+		   drbd_disk_t can express... */
+	}
+
+}
+
+
 STATIC int drbd_thread_setup(void* arg)
 {
 	struct Drbd_thread *thi = (struct Drbd_thread *) arg;
@@ -610,11 +715,12 @@
 
 	ok = drbd_send_cmd(mdev,mdev->data.socket,SyncParam,(Drbd_Header*)&p,sizeof(p));
 	if ( ok
-	    && (mdev->cstate == SkippedSyncS || mdev->cstate == SkippedSyncT)
-	    && !sc->skip )
+	     && (mdev->state.s.conn == SkippedSyncS || 
+		 mdev->state.s.conn == SkippedSyncT)
+	     && !sc->skip )
 	{
 		/* FIXME EXPLAIN. I think this cannot work properly! -lge */
-		set_cstate(mdev,WFReportParams);
+		drbd_request_state(mdev,NS(conn,WFReportParams));
 		ok = drbd_send_param(mdev,0);
 	}
 	return ok;
@@ -636,7 +742,7 @@
 	p.u_size = cpu_to_be64(mdev->lo_usize);
 	p.p_size = cpu_to_be64(m_size);
 
-	p.state    = cpu_to_be32(mdev->state);
+	p.state    = cpu_to_be32(mdev->state.i);
 	p.protocol = cpu_to_be32(mdev->conf.wire_protocol);
 	p.version  = cpu_to_be32(PRO_VERSION);
 
@@ -673,7 +779,7 @@
 	if (drbd_md_test_flag(mdev,MDF_FullSync)) {
 		drbd_bm_set_all(mdev);
 		drbd_bm_write(mdev);
-		if (unlikely(test_bit(DISKLESS,&mdev->flags))) {
+		if (unlikely(mdev->state.s.disk <= Failed )) {
 			/* write_bm did fail! panic.
 			 * FIXME can we do something better than panic?
 			 */
@@ -752,8 +858,8 @@
 	p.block_id = e->block_id;
 	p.blksize  = cpu_to_be32(drbd_ee_get_size(e));
 
-	if (!mdev->meta.socket || mdev->cstate < Connected) return FALSE;
-	ok = drbd_send_cmd(mdev,mdev->meta.socket,cmd,(Drbd_Header*)&p,sizeof(p));
+	if (!mdev->meta.socket || mdev->state.s.conn < Connected) return FALSE;
+	ok=drbd_send_cmd(mdev,mdev->meta.socket,cmd,(Drbd_Header*)&p,sizeof(p));
 	return ok;
 }
 
@@ -784,7 +890,7 @@
 	drop_it =   mdev->meta.socket == sock
 		|| !mdev->asender.task
 		|| get_t_state(&mdev->asender) != Running
-		|| (volatile int)mdev->cstate < Connected;
+		|| (volatile int)mdev->state.s.conn < Connected;
 
 	if (drop_it)
 		return TRUE;
@@ -1077,7 +1183,7 @@
 	int rv,sent=0;
 
 	if (!sock) return -1000;
-	if ((volatile int)mdev->cstate < WFReportParams) return -1001;
+	if ((volatile int)mdev->state.s.conn < WFReportParams) return -1001;
 
 	// THINK  if (signal_pending) return ... ?
 
@@ -1153,9 +1259,9 @@
 			ERR("%s_sendmsg returned %d\n",
 			    sock == mdev->meta.socket ? "msock" : "sock",
 			    rv);
-			set_cstate(mdev, BrokenPipe);
+			drbd_force_state(mdev, NS(conn,BrokenPipe));
 		} else
-			set_cstate(mdev, Timeout);
+			drbd_force_state(mdev, NS(conn,Timeout));
 		drbd_thread_restart_nowait(&mdev->receiver);
 	}
 
@@ -1170,7 +1276,7 @@
 	if(minor >= minor_count) return -ENODEV;
 
 	if (file->f_mode & FMODE_WRITE) {
-		if( drbd_conf[minor].state == Secondary) {
+		if( drbd_conf[minor].state.s.role == Secondary) {
 			return -EROFS;
 		}
 		set_bit(WRITER_PRESENT, &drbd_conf[minor].flags);
@@ -1212,31 +1318,34 @@
 	spin_unlock_irq(q->queue_lock);
 
 	/* only if connected */
-	if (mdev->cstate >= Connected && !test_bit(PARTNER_DISKLESS,&mdev->flags)) {
-		D_ASSERT(mdev->state == Primary);
+	spin_lock_irq(&mdev->req_lock);
+	if (mdev->state.s.pedi >= Inconsistent) /* implies cs >= Connected */ {
+		D_ASSERT(mdev->state.s.role == Primary);
 		if (test_and_clear_bit(UNPLUG_REMOTE,&mdev->flags)) {
-			spin_lock_irq(&mdev->req_lock);
 			/* add to the front of the data.work queue,
 			 * unless already queued.
 			 * XXX this might be a good addition to drbd_queue_work
 			 * anyways, to detect "double queuing" ... */
 			if (list_empty(&mdev->unplug_work.list))
 				_drbd_queue_work_front(&mdev->data.work,&mdev->unplug_work);
-			spin_unlock_irq(&mdev->req_lock);
 		}
 	}
+	spin_unlock_irq(&mdev->req_lock);
 
-	if(!test_bit(DISKLESS,&mdev->flags)) drbd_kick_lo(mdev);
+	if(mdev->state.s.disk >= Inconsistent) drbd_kick_lo(mdev);
 }
 
 void drbd_set_defaults(drbd_dev *mdev)
 {
-	mdev->flags = 1<<DISKLESS;
 	mdev->sync_conf.rate       = 250;
 	mdev->sync_conf.al_extents = 127; // 512 MB active set
-	mdev->state                = Secondary;
-	mdev->o_state              = Unknown;
-	mdev->cstate               = Unconfigured;
+	mdev->state = (drbd_state_t){ { Secondary,
+					Unknown,
+					StandAlone,
+					Diskless,
+					DUnknown,
+					0,
+					0 } };
 }
 
 void drbd_init_set_defaults(drbd_dev *mdev)
@@ -1841,8 +1950,8 @@
 	memset(buffer,0,512);
 
 	flags = mdev->gen_cnt[Flags] & ~(MDF_PrimaryInd|MDF_ConnectedInd);
-	if (mdev->state  == Primary)        flags |= MDF_PrimaryInd;
-	if (mdev->cstate >= WFReportParams) flags |= MDF_ConnectedInd;
+	if (mdev->state.s.role == Primary)        flags |= MDF_PrimaryInd;
+	if (mdev->state.s.conn >= WFReportParams) flags |= MDF_ConnectedInd;
 	mdev->gen_cnt[Flags] = flags;
 
 	for (i = Flags; i < GEN_CNT_SIZE; i++)
@@ -1870,7 +1979,7 @@
 	if (drbd_md_sync_page_io(mdev,sector,WRITE)) {
 		clear_bit(MD_DIRTY,&mdev->flags);
 	} else {
-		if (test_bit(DISKLESS,&mdev->flags)) {
+		if (mdev->state.s.disk <= Failed) {
 			/* this was a try anyways ... */
 			ERR("meta data update failed!\n");
 		} else {
@@ -1958,7 +2067,7 @@
 void drbd_dump_md(drbd_dev *mdev, Drbd_Parameter_Packet *peer, int verbose)
 {
 	INFO("I am(%c): %c:%08x:%08x:%08x:%08x:%c%c\n",
-		mdev->state == Primary ? 'P':'S',
+		mdev->state.s.role == Primary ? 'P':'S',
 		MeGC(Flags) & MDF_Consistent ? '1' : '0',
 		MeGC(HumanCnt),
 		MeGC(TimeoutCnt),
@@ -1968,7 +2077,7 @@
 		MeGC(Flags) & MDF_ConnectedInd ? '1' : '0');
 	if (peer) {
 		INFO("Peer(%c): %c:%08x:%08x:%08x:%08x:%c%c\n",
-			be32_to_cpu(peer->state) == Primary ? 'P':'S',
+			((drbd_state_t)be32_to_cpu(peer->state)).s.role == Primary ? 'P':'S',
 			PeGC(Flags) & MDF_Consistent ? '1' : '0',
 			PeGC(HumanCnt),
 			PeGC(TimeoutCnt),

Modified: trunk/drbd/drbd_proc.c
===================================================================
--- trunk/drbd/drbd_proc.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_proc.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -146,44 +146,24 @@
 	return sz;
 }
 
-const char* cstate_to_name(Drbd_CState s) {
-	static const char *cstate_names[] = {
-		[Unconfigured]   = "Unconfigured",
-		[StandAlone]     = "StandAlone",
-		[Unconnected]    = "Unconnected",
-		[Timeout]        = "Timeout",
-		[BrokenPipe]     = "BrokenPipe",
-		[NetworkFailure] = "NetworkFailure",
-		[WFConnection]   = "WFConnection",
-		[WFReportParams] = "WFReportParams",
-		[Connected]      = "Connected",
-		[SkippedSyncS]   = "SkippedSyncS",
-		[SkippedSyncT]   = "SkippedSyncT",
-		[WFBitMapS]      = "WFBitMapS",
-		[WFBitMapT]      = "WFBitMapT",
-		[SyncSource]     = "SyncSource",
-		[SyncTarget]     = "SyncTarget",
-		[PausedSyncS]    = "PausedSyncS",
-		[PausedSyncT]    = "PausedSyncT",
-	};
-
+const char* cstate_to_name(drbd_conns_t s) {
 	return s < Unconfigured ? "TO_SMALL" :
 	       s > PausedSyncT  ? "TO_LARGE"
-		                : cstate_names[s];
+		                : drbd_conn_s_names[s];
 }
 
-const char* nodestate_to_name(Drbd_State s) {
-	static const char *state_names[] = {
-		[Primary]   = "Primary",
-		[Secondary] = "Secondary",
-		[Unknown]   = "Unknown"
-	};
-
+const char* nodestate_to_name(drbd_role_t s) {
 	return s < Unknown    ? "TO_SMALL" :
 	       s > Secondary  ? "TO_LARGE"
-		              : state_names[s];
+		              : drbd_role_s_names[s];
 }
 
+const char* diskstate_to_name(drbd_disks_t s) {
+	return s < DUnknown    ? "TO_SMALL" :
+	       s > UpToDate    ? "TO_LARGE"
+		              : drbd_disk_s_names[s];
+}
+
 /* FIXME we should use snprintf, we only have guaranteed room for one page...
  * we should eventually use seq_file for this */
 int drbd_proc_get_info(char *buf, char **start, off_t offset,
@@ -209,27 +189,30 @@
 	*/
 
 	for (i = 0; i < minor_count; i++) {
-		sn = cstate_to_name(drbd_conf[i].cstate);
+		sn = cstate_to_name(drbd_conf[i].state.s.conn);
+		
+		/* PRE FIXME
 		if(drbd_conf[i].cstate == Connected) {
 			if(test_bit(DISKLESS,&drbd_conf[i].flags))
 				sn = "DiskLessClient";
 			if(test_bit(PARTNER_DISKLESS,&drbd_conf[i].flags))
 				sn = "ServerForDLess";
-		}
-		if ( drbd_conf[i].cstate == Unconfigured ) {
+				} */
+		
+		if ( drbd_conf[i].state.s.conn == StandAlone && 
+		     drbd_conf[i].state.s.disk == Diskless) {
 			rlen += sprintf( buf + rlen,
-			   "%2d: cs:Unconfigured\n", i);
+			   "%2d: Unconfigured\n", i);
 		} else {
 			rlen += sprintf( buf + rlen,
-			   "%2d: cs:%s st:%s/%s ld:%s\n"
+			   "%2d: cs:%s st:%s/%s ds:%s/%s\n"
 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
 			   "lo:%d pe:%d ua:%d ap:%d\n",
 			   i, sn,
-			   nodestate_to_name(drbd_conf[i].state),
-			   nodestate_to_name(drbd_conf[i].o_state),
-			   (drbd_conf[i].gen_cnt[Flags]
-			    & MDF_Consistent) ? "Consistent" : "Inconsistent",
-			// FIXME partner consistent?
+			   nodestate_to_name(drbd_conf[i].state.s.role),
+			   nodestate_to_name(drbd_conf[i].state.s.peer),
+			   diskstate_to_name(drbd_conf[i].state.s.disk),
+			   diskstate_to_name(drbd_conf[i].state.s.pedi),
 			   drbd_conf[i].send_cnt/2,
 			   drbd_conf[i].recv_cnt/2,
 			   drbd_conf[i].writ_cnt/2,
@@ -243,8 +226,8 @@
 			   atomic_read(&drbd_conf[i].ap_bio_cnt)
 			);
 
-			if ( drbd_conf[i].cstate == SyncSource ||
-			     drbd_conf[i].cstate == SyncTarget ) {
+			if ( drbd_conf[i].state.s.conn == SyncSource ||
+			     drbd_conf[i].state.s.conn == SyncTarget ) {
 				rlen += drbd_syncer_progress(drbd_conf+i,buf+rlen);
 			}
 

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_receiver.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -555,7 +555,7 @@
 	set_fs(oldfs);
 
 	if(rv != size) {
-		set_cstate(mdev,BrokenPipe);
+		drbd_force_state(mdev,NS(conn,BrokenPipe));
 		drbd_thread_restart_nowait(&mdev->receiver);
 	}
 
@@ -606,7 +606,7 @@
 	if (err) {
 		ERR("Unable to bind (%d)\n", err);
 		sock_release(sock2);
-		set_cstate(mdev,Unconnected);
+		drbd_force_state(mdev,NS(conn,Unconnected));
 		return 0;
 	}
 
@@ -622,10 +622,10 @@
 {
 	struct socket *sock,*msock;
 
-	D_ASSERT(mdev->cstate!=Unconfigured);
+	D_ASSERT(mdev->state.s.conn > Unconfigured);
 	D_ASSERT(!mdev->data.socket);
 
-	set_cstate(mdev,WFConnection);
+	if(!drbd_request_state(mdev,NS(conn,WFConnection))) return 0;
 
 	while(1) {
 		sock=drbd_try_connect(mdev);
@@ -649,7 +649,7 @@
 				sock_release(sock);
 			}
 		}
-		if(mdev->cstate==Unconnected) return 0;
+		if(mdev->state.s.conn == Unconnected) return 0;
 		if(signal_pending(current)) {
 			flush_signals(current);
 			smp_rmb();
@@ -691,7 +691,7 @@
 	mdev->meta.socket = msock;
 	mdev->last_received = jiffies;
 
-	set_cstate(mdev,WFReportParams);
+	if(!drbd_request_state(mdev,NS(conn,WFReportParams))) return 0;
 	D_ASSERT(mdev->asender.task == NULL);
 
 	if (!drbd_do_handshake(mdev)) {
@@ -740,7 +740,7 @@
 	int epoch_size;
 	Drbd_Barrier_Packet *p = (Drbd_Barrier_Packet*)h;
 
-	ERR_IF(mdev->state != Secondary) return FALSE;
+	ERR_IF(mdev->state.s.role != Secondary) return FALSE;
 	ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
 
 	rv = drbd_recv(mdev, h->payload, h->length);
@@ -842,8 +842,8 @@
 
 	drbd_rs_complete_io(mdev,sector); // before set_in_sync() !
 	if (likely( drbd_bio_uptodate(&e->private_bio) )) {
-		ok = !test_bit(DISKLESS,&mdev->flags) &&
-		     !test_bit(PARTNER_DISKLESS,&mdev->flags);
+		ok = mdev->state.s.disk >= Inconsistent &&
+			mdev->state.s.pedi >= Inconsistent;
 		if (likely( ok )) {
 			drbd_set_in_sync(mdev, sector, drbd_ee_get_size(e));
 			/* THINK maybe don't send ack either
@@ -1161,19 +1161,23 @@
 	mdev->sync_conf.skip      = be32_to_cpu(p->skip);
 	drbd_alter_sg(mdev, be32_to_cpu(p->group));
 
-	if (   (mdev->cstate == SkippedSyncS || mdev->cstate == SkippedSyncT)
-	    && !mdev->sync_conf.skip )
-	{
-		set_cstate(mdev,WFReportParams);
+	if ( (mdev->state.s.conn == SkippedSyncS || 
+	      mdev->state.s.conn == SkippedSyncT)
+	     && !mdev->sync_conf.skip ) {
+		drbd_request_state(mdev,NS(conn,WFReportParams));
 		ok = drbd_send_param(mdev,0);
 	}
 
 	return ok;
 }
 
-STATIC int drbd_sync_handshake(drbd_dev *mdev, Drbd_Parameter_Packet *p)
+/* drbd_sync_handshake() returns the new conn state on success, or 
+   conn_mask (-1) on failure.
+ */
+STATIC drbd_conns_t drbd_sync_handshake(drbd_dev *mdev, Drbd_Parameter_Packet *p)
 {
 	int have_good,sync;
+	drbd_conns_t rv = conn_mask;
 
 	have_good = drbd_md_compare(mdev,p);
 
@@ -1190,9 +1194,9 @@
 			 * for now: just go StandAlone.
 			 */
 			ALERT("Split-Brain detected, dropping connection!\n");
-			set_cstate(mdev,StandAlone);
+			drbd_force_state(mdev,NS(conn,StandAlone));
 			drbd_thread_stop_nowait(&mdev->receiver);
-			return FALSE;
+			return conn_mask;
 		}
 		sync=0;
 	} else {
@@ -1206,39 +1210,35 @@
 		/* doh. I cannot become SyncSource when I am inconsistent!
 		 */
 		ERR("I shall become SyncSource, but I am inconsistent!\n");
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
-		return FALSE;
+		return conn_mask;
 	}
 	if (have_good < 0 &&
 	    !(be32_to_cpu(p->gen_cnt[Flags]) & MDF_Consistent) ) {
 		/* doh. Peer cannot become SyncSource when inconsistent
 		 */
 		ERR("I shall become SyncTarget, but Peer is inconsistent!\n");
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
-		return FALSE;
+		return conn_mask;
 	}
 
 	if ( mdev->sync_conf.skip && sync ) {
-		if (have_good == 1)
-			set_cstate(mdev,SkippedSyncS);
-		else // have_good == -1
-			set_cstate(mdev,SkippedSyncT);
-		return TRUE;
+		return have_good == 1 ? SkippedSyncS : SkippedSyncT ;
 	}
 
 	if( sync ) {
 		if(have_good == 1) {
 			D_ASSERT(drbd_md_test_flag(mdev,MDF_Consistent));
-			set_cstate(mdev,WFBitMapS);
+			rv = WFBitMapS;
 			wait_event(mdev->cstate_wait,
 			     atomic_read(&mdev->ap_bio_cnt)==0);
 			drbd_bm_lock(mdev);   // {
 			drbd_send_bitmap(mdev);
 			drbd_bm_unlock(mdev); // }
 		} else { // have_good == -1
-			if ( (mdev->state == Primary) &&
+			if ( (mdev->state.s.role == Primary) &&
 			     drbd_md_test_flag(mdev,MDF_Consistent) ) {
 				/* FIXME
 				 * allow Primary become SyncTarget if it was
@@ -1248,15 +1248,15 @@
 				 */
 				ERR("Current Primary shall become sync TARGET!"
 				    " Aborting to prevent data corruption.\n");
-				set_cstate(mdev,StandAlone);
+				drbd_force_state(mdev,NS(conn,StandAlone));
 				drbd_thread_stop_nowait(&mdev->receiver);
-				return FALSE;
+				return conn_mask;
 			}
 			drbd_md_clear_flag(mdev,MDF_Consistent);
-			set_cstate(mdev,WFBitMapT);
+			rv = WFBitMapT;
 		}
 	} else {
-		set_cstate(mdev,Connected);
+		rv = Connected;
 		drbd_bm_lock(mdev);   // {
 		if(drbd_bm_total_weight(mdev)) {
 			if (drbd_md_test_flag(mdev,MDF_Consistent)) {
@@ -1283,19 +1283,21 @@
 			mdev->gen_cnt[i]=be32_to_cpu(p->gen_cnt[i]);
 		}
 	}
-	return TRUE;
+	return rv;
 }
 
 STATIC int receive_param(drbd_dev *mdev, Drbd_Header *h)
 {
 	Drbd_Parameter_Packet *p = (Drbd_Parameter_Packet*)h;
-	int consider_sync;
-	int oo_state;
+	drbd_conns_t nconn;
+	drbd_disks_t npedi;
+	drbd_state_t ns;
+	int consider_sync,rv;
 	sector_t p_size;
 
 	if (h->length != (sizeof(*p)-sizeof(*h))) {
 		ERR("Incompatible packet size of Parameter packet!\n");
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
 		return FALSE;
 	}
@@ -1306,7 +1308,7 @@
 	if (p->magic != BE_DRBD_MAGIC) {
 		ERR("invalid Parameter_Packet magic! Protocol version: me %d, peer %d\n",
 				PRO_VERSION, be32_to_cpu(p->version));
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
 		return FALSE;
 	}
@@ -1314,26 +1316,11 @@
 	if(be32_to_cpu(p->version)!=PRO_VERSION) {
 		ERR("incompatible releases! Protocol version: me %d, peer %d\n",
 				PRO_VERSION, be32_to_cpu(p->version));
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
 		return FALSE;
 	}
 
-	oo_state = be32_to_cpu(p->state);
-	if (oo_state != Primary && oo_state != Secondary) {
-		ERR("unexpected peer state: 0x%x\n", oo_state);
-		set_cstate(mdev,StandAlone);
-		drbd_thread_stop_nowait(&mdev->receiver);
-		return FALSE;
-	}
-
-	if(be32_to_cpu(p->state) == Primary && mdev->state == Primary ) {
-		ERR("incompatible states (both Primary!)\n");
-		set_cstate(mdev,StandAlone);
-		drbd_thread_stop_nowait(&mdev->receiver);
-		return FALSE;
-	}
-
 	if(be32_to_cpu(p->protocol)!=mdev->conf.wire_protocol) {
 		int peer_proto = be32_to_cpu(p->protocol);
 		if (DRBD_PROT_A <= peer_proto && peer_proto <= DRBD_PROT_C) {
@@ -1347,18 +1334,18 @@
 				'A'-1+mdev->conf.wire_protocol,
 				peer_proto);
 		}
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
 		return FALSE;
 	}
 
 	p_size=be64_to_cpu(p->p_size);
 
-	if(p_size == 0 && test_bit(DISKLESS,&mdev->flags)) {
+	if(p_size == 0 && mdev->state.s.disk == Diskless ) {
 		/* FIXME maybe allow connection,
 		 * but refuse to become primary? */
 		ERR("some backing storage is needed\n");
-		set_cstate(mdev,StandAlone);
+		drbd_force_state(mdev,NS(conn,StandAlone));
 		drbd_thread_stop_nowait(&mdev->receiver);
 		return FALSE;
 	}
@@ -1374,7 +1361,7 @@
  * right, and comment them!
  */
 
-	consider_sync = (mdev->cstate == WFReportParams);
+	consider_sync = ((nconn=mdev->state.s.conn) == WFReportParams);
 	if(drbd_determin_dev_size(mdev)) consider_sync=0;
 
 	drbd_bm_unlock(mdev); // }
@@ -1401,72 +1388,41 @@
 		     (unsigned long)mdev->lo_usize);
 	}
 
-	if(!p_size) {
-		/* no point in trying to sync a diskless peer: */
-		consider_sync = 0;
-		if (!test_and_set_bit(PARTNER_DISKLESS, &mdev->flags)) {
-			/* if we got here, we *do* have a disk.
-			 * but it may be inconsistent...
-			 * anyways, record that next time we need a full sync.
-			 */
-			clear_bit(PARTNER_CONSISTENT, &mdev->flags);
-			drbd_md_set_flag(mdev,MDF_FullSync);
-			drbd_md_write(mdev);
-			/* actually we'd need to bm_fill_bm(,-1); drbd_write_bm(mdev);
-			 * but this is not necessary _now_.
-			 * we have the MDF_FullSync bit on disk.
-			 * on the next _drbd_send_bitmap this will be done.
-			 */
-			WARN("PARTNER DISKLESS\n");
-			mdev->rs_total = 0;
+
+	if(p_size ) {
+		npedi = Inconsistent;
+ 		if (be32_to_cpu(p->gen_cnt[Flags]) & MDF_Consistent) {
+			npedi = Consistent;
 		}
-		if(mdev->cstate >= Connected ) {
-			if(mdev->state == Primary) tl_clear(mdev);
-			if(mdev->state == Primary ||
-			   be32_to_cpu(p->state) == Primary ) {
-				drbd_md_inc(mdev,ConnectedCnt);
-			}
-		}
-		if(mdev->cstate > Connected ) {
-			WARN("Resync aborted.\n");
-			set_cstate(mdev,Connected);
-		}
 	} else {
-		if (test_and_clear_bit(PARTNER_DISKLESS, &mdev->flags)) {
-			WARN("Partner no longer diskless\n");
-			D_ASSERT(consider_sync);
-		}
+		npedi = Diskless;
 	}
 
-	if (be32_to_cpu(p->gen_cnt[Flags]) & MDF_Consistent) {
-		set_bit(PARTNER_CONSISTENT, &mdev->flags);
-	} else {
-		clear_bit(PARTNER_CONSISTENT, &mdev->flags);
-	}
-
-	if (mdev->cstate == WFReportParams) {
+	if (mdev->state.s.conn == WFReportParams) {
 		INFO("Connection established.\n");
 	}
 
+	nconn=Connected;
 	if (consider_sync) {
-		if (!drbd_sync_handshake(mdev,p)) return FALSE;
+		if ((nconn=drbd_sync_handshake(mdev,p))==conn_mask) 
+			return FALSE;
 	}
 
-	if (mdev->cstate == WFReportParams) set_cstate(mdev,Connected);
+	spin_lock_irq(&mdev->req_lock);
+	ns.i = mdev->state.i;
+	ns.s.conn = nconn;
+	ns.s.peer = be32_to_cpu(p->state);
+	ns.s.pedi = npedi;
+	rv = _drbd_set_state(mdev,ns,0);
+	spin_unlock_irq(&mdev->req_lock);
 
-	oo_state = mdev->o_state;
-	mdev->o_state = be32_to_cpu(p->state);
-	if(oo_state == Secondary && mdev->o_state == Primary) {
-		drbd_md_inc(mdev,ConnectedCnt);
+	if(!rv) {
+		drbd_force_state(mdev,NS(conn,StandAlone));
+		drbd_thread_stop_nowait(&mdev->receiver);
+		return FALSE;
 	}
-	if (oo_state != mdev->o_state) {
-		INFO( "%s/%s --> %s/%s\n",
-		      nodestate_to_name(mdev->state),
-		      nodestate_to_name(oo_state),
-		      nodestate_to_name(mdev->state),
-		      nodestate_to_name(mdev->o_state) );
-		/* FIXME assertion for (gencounts do not diverge) */
-	}
+
+	/* FIXME assertion for (gencounts do not diverge) */
 	drbd_md_write(mdev); // update connected indicator, la_size, ...
 
 	return TRUE;
@@ -1508,15 +1464,15 @@
 		D_ASSERT(h->command == ReportBitMap);
 	}
 
-	if (mdev->cstate == WFBitMapS) {
+	if (mdev->state.s.conn == WFBitMapS) {
 		drbd_start_resync(mdev,SyncSource);
-	} else if (mdev->cstate == WFBitMapT) {
+	} else if (mdev->state.s.conn == WFBitMapT) {
 		ok = drbd_send_bitmap(mdev);
 		if (!ok) goto out;
 		drbd_start_resync(mdev,SyncTarget); // XXX cannot fail ???
 	} else {
 		ERR("unexpected cstate (%s) in receive_bitmap\n",
-		    cstate_to_name(mdev->cstate));
+		    cstate_to_name(mdev->state.s.conn));
 	}
 
 	// We just started resync. Now we can be sure that local disk IO is okay.
@@ -1528,8 +1484,8 @@
  *  FIXME this should only be D_ASSERT here.
  *        *doing* it here masks a logic bug elsewhere, I think.
  */
-	D_ASSERT(!test_bit(PARTNER_DISKLESS,&mdev->flags));
-	D_ASSERT(!test_bit(DISKLESS,&mdev->flags));
+	D_ASSERT(mdev->state.s.disk >= Inconsistent);
+	D_ASSERT(mdev->state.s.pedi >= Inconsistent);
 // EXPLAIN:
 	clear_bit(MD_IO_ALLOWED,&mdev->flags);
 
@@ -1593,13 +1549,6 @@
 {
 	ERR_IF(!mdev->bitmap) return FALSE;
 
-	/* THINK
-	 * otherwise this does not make much sense, no?
-	 * and some other assertion maybe about cstate...
-	 */
-	ERR_IF(mdev->state != Secondary || mdev->cstate != Connected)
-		return FALSE;
-
 	drbd_bm_lock(mdev);
 	drbd_bm_set_all(mdev);
 	drbd_bm_write(mdev);
@@ -1621,7 +1570,7 @@
 
 STATIC int receive_UnplugRemote(drbd_dev *mdev, Drbd_Header *h)
 {
-	if (!test_bit(DISKLESS,&mdev->flags)) drbd_kick_lo(mdev);
+	if (mdev->state.s.disk >= Inconsistent) drbd_kick_lo(mdev);
 	return TRUE; // cannot fail.
 }
 
@@ -1673,7 +1622,7 @@
 			    header->command, header->length);
 			break;
 		}
-		if (mdev->cstate == WFReportParams && header->command != ReportParams) {
+		if (mdev->state.s.conn == WFReportParams && header->command != ReportParams) {
 			ERR("received %s packet while WFReportParams!?\n",
 					cmdname(header->command));
 		}
@@ -1688,8 +1637,7 @@
 
 STATIC void drbd_disconnect(drbd_dev *mdev)
 {
-	D_ASSERT(mdev->cstate < Connected);
-	mdev->o_state = Unknown;
+	D_ASSERT(mdev->state.s.conn < Connected);
 
 	/* in case we have been syncing, and then we drop the connection,
 	 * we need to "w_resume_next_sg", which we try to achieve by
@@ -1751,10 +1699,6 @@
 	wait_event( mdev->cstate_wait, atomic_read(&mdev->ap_pending_cnt)==0 );
 	D_ASSERT(mdev->oldest_barrier->n_req == 0);
 
-	// both
-	clear_bit(PARTNER_CONSISTENT, &mdev->flags);
-	clear_bit(PARTNER_DISKLESS,&mdev->flags);
-
 	D_ASSERT(mdev->ee_in_use == 0);
 	D_ASSERT(list_empty(&mdev->read_ee)); // done by termination of worker
 	D_ASSERT(list_empty(&mdev->active_ee)); // done here
@@ -1788,27 +1732,15 @@
 
 	wake_up(&mdev->cstate_wait);
 
-	if ( mdev->state == Primary &&
-	    ( test_bit(DISKLESS,&mdev->flags)
-	    || !drbd_md_test_flag(mdev,MDF_Consistent) ) ) {
-		drbd_panic("Sorry, I have no access to good data anymore.\n");
-	}
-
 	if (get_t_state(&mdev->receiver) == Exiting) {
-		if (test_bit(DISKLESS,&mdev->flags)) {
-			// Secondary
-			set_cstate(mdev,Unconfigured);
-			drbd_mdev_cleanup(mdev);
-		} else {
-			set_cstate(mdev,StandAlone);
-			drbd_thread_start(&mdev->worker);
-		}
+		drbd_force_state(mdev,NS(conn,StandAlone));
+		drbd_thread_start(&mdev->worker);
 	} else {
-		set_cstate(mdev,Unconnected);
+		drbd_force_state(mdev,NS(conn,Unconnected));
 		drbd_thread_start(&mdev->worker);
 	}
 
-	if (mdev->state == Primary) {
+	if (mdev->state.s.role == Primary) {
 		if(!test_bit(DO_NOT_INC_CONCNT,&mdev->flags))
 			drbd_md_inc(mdev,ConnectedCnt);
 		drbd_md_write(mdev);
@@ -1926,7 +1858,7 @@
 			 * drbd_disconnect should set cstate properly...
 			 */
 			drbd_disconnect(mdev);
-			set_cstate(mdev,StandAlone);
+			drbd_force_state(mdev,NS(conn,StandAlone));
 			break;
 		}
 		if (get_t_state(thi) == Exiting) break;
@@ -1934,7 +1866,7 @@
 		drbd_disconnect(mdev);
 		if (get_t_state(thi) == Exiting) break;
 		if(mdev->conf.on_disconnect == DropNetConf) {
-			set_cstate(mdev,StandAlone);
+			drbd_force_state(mdev,NS(conn,StandAlone));
 			break;
 		}
 		else {
@@ -1977,7 +1909,7 @@
 	int blksize = be32_to_cpu(p->blksize);
 
 	smp_rmb();
-	if(likely(!test_bit(PARTNER_DISKLESS,&mdev->flags))) {
+	if(likely(mdev->state.s.pedi >= Inconsistent )) {
 		// test_bit(PARTNER_DISKLESS,&mdev->flags)
 		// This happens if one a few IO requests on the peer
 		// failed, and some subsequest completed sucessfull
@@ -2073,7 +2005,7 @@
 	Drbd_BarrierAck_Packet *p = (Drbd_BarrierAck_Packet*)h;
 
 	smp_rmb();
-	if(unlikely(test_bit(PARTNER_DISKLESS,&mdev->flags))) return TRUE;
+	if(unlikely(mdev->state.s.pedi <= Diskless)) return TRUE;
 
 	tl_release(mdev,p->barrier,be32_to_cpu(p->set_size));
 	dec_ap_pending(mdev);
@@ -2199,8 +2131,8 @@
 	if(0) {
 	err:
 		clear_bit(SIGNAL_ASENDER, &mdev->flags);
-		if (mdev->cstate >= Connected)
-			set_cstate(mdev,NetworkFailure);
+		if (mdev->state.s.conn >= Connected)
+			drbd_force_state(mdev,NS(conn,NetworkFailure));
 		drbd_thread_restart_nowait(&mdev->receiver);
 	}
 

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_req.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -178,7 +178,7 @@
 	 * not always true, e.g. someone trying to mount on Secondary
 	 * maybe error out immediately here?
 	 */
-	D_ASSERT(mdev->state == Primary);
+	D_ASSERT(mdev->state.s.role == Primary);
 
 	/*
 	 * Paranoia: we might have been primary, but sync target, or
@@ -189,13 +189,11 @@
 	 * to serialize state changes, this is racy, since we may lose
 	 * the connection *after* we test for the cstate.
 	 */
-	if ( (    test_bit(DISKLESS,&mdev->flags)
-	      || !drbd_md_test_flag(mdev,MDF_Consistent)
-	     ) && mdev->cstate < Connected )
-	{
+	if ( mdev->state.s.disk <= Inconsistent && 
+	     mdev->state.s.conn < Connected) {
 		ERR("Sorry, I have no access to good data anymore.\n");
 /*
-	FIXME suspend, loop waiting on cstate wait? panic?
+  FIXME suspend, loop waiting on cstate wait? panic?
 */
 		drbd_bio_IO_error(bio);
 		return 0;
@@ -226,8 +224,8 @@
 	// down_read(mdev->device_lock);
 
 	wait_event( mdev->cstate_wait,
-		    (volatile int)(mdev->cstate < WFBitMapS || 
-				   mdev->cstate > WFBitMapT) );
+		    (volatile int)(mdev->state.s.conn < WFBitMapS || 
+				   mdev->state.s.conn > WFBitMapT) );
 
 	local = inc_local(mdev);
 	if (rw == READ || rw == READA) {
@@ -257,7 +255,7 @@
 				dec_local(mdev);
 			}
 		}
-		remote = !local && test_bit(PARTNER_CONSISTENT, &mdev->flags);
+		remote = !local && mdev->state.s.pedi >= Consistent;
 	} else {
 		remote = 1;
 	}
@@ -270,7 +268,7 @@
 	 *        or make this configurable...
 	 *        if network is slow, READA won't do any good.
 	 */
-	if (rw == READA && !test_bit(DISKLESS,&mdev->flags) && !local) {
+	if (rw == READA && mdev->state.s.disk >= Inconsistent && !local) {
 		drbd_bio_IO_error(bio);
 		return 0;
 	}
@@ -278,8 +276,7 @@
 	if (rw == WRITE && local)
 		drbd_al_begin_io(mdev, sector);
 
-	remote = remote && (mdev->cstate >= Connected)
-			&& !test_bit(PARTNER_DISKLESS,&mdev->flags);
+	remote = remote && (mdev->state.s.pedi >= Inconsistent);
 
 	if (!(local || remote)) {
 		ERR("IO ERROR: neither local nor remote disk\n");
@@ -308,8 +305,8 @@
 		inc_ap_pending(mdev);
 		if (rw == WRITE) {
 			if (!drbd_send_dblock(mdev,req)) {
-				if (mdev->cstate >= Connected)
-					set_cstate(mdev,NetworkFailure);
+				if (mdev->state.s.conn >= Connected)
+					drbd_force_state(mdev,NS(conn,NetworkFailure));
 				dec_ap_pending(mdev);
 				drbd_thread_restart_nowait(&mdev->receiver);
 			} else if(mdev->conf.wire_protocol == DRBD_PROT_A) {
@@ -352,7 +349,7 @@
 {
 	unsigned int s_enr,e_enr;
 	struct Drbd_Conf* mdev = (drbd_dev*) q->queuedata;
-	if (mdev->cstate < StandAlone) {
+	if (mdev->state.s.disk < Inconsistent) {
 		drbd_bio_IO_error(bio);
 		return 0;
 	}

Modified: trunk/drbd/drbd_strings.c
===================================================================
--- trunk/drbd/drbd_strings.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_strings.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -1,4 +1,28 @@
-static const char *conn_s_names[] = {
+/*
+  drbd.h
+  Kernel module for 2.4.x/2.6.x Kernels
+
+  This file is part of drbd by Philipp Reisner.
+
+  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/drbd.h>
+
+const char *drbd_conn_s_names[] = {
 	[Unconfigured]   = "Unconfigured",
 	[StandAlone]     = "StandAlone",
 	[Unconnected]    = "Unconnected",
@@ -18,13 +42,14 @@
 	[PausedSyncT]    = "PausedSyncT",
 };
 
-static const char *role_s_names[] = {
+const char *drbd_role_s_names[] = {
 	[Primary]   = "Primary",
 	[Secondary] = "Secondary",
 	[Unknown]   = "Unknown"
 };
 
-static const char *disk_s_names[] = {
+const char *drbd_disk_s_names[] = {
+	[DUnknown]     = "DUnknown",
 	[Diskless]     = "Diskless",
 	[Failed]       = "Failed",
 	[Inconsistent] = "Inconsistent",

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/drbd_worker.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -228,8 +228,8 @@
 
 	smp_rmb();
 	if ( cancel ||
-	     mdev->cstate < Connected ||
-	     !test_bit(PARTNER_CONSISTENT,&mdev->flags) ) {
+	     mdev->state.s.conn < Connected ||
+	     mdev->state.s.pedi < Consistent ) {
 		drbd_panic("WE ARE LOST. Local IO failure, no peer.\n");
 
 		// does not make much sense, but anyways...
@@ -312,13 +312,13 @@
 	if(unlikely(cancel)) return 1;
 	/* FIXME THINK what about w_resume_next_sg ?? */
 
-	if(unlikely(mdev->cstate < Connected)) {
+	if(unlikely(mdev->state.s.conn < Connected)) {
 		ERR("Confused in w_make_resync_request()! cstate < Connected");
 		return 0;
 	}
 
-	if (mdev->cstate != SyncTarget) {
-		ERR("%s in w_make_resync_request\n", cstate_to_name(mdev->cstate));
+	if (mdev->state.s.conn != SyncTarget) {
+		ERR("%s in w_make_resync_request\n", cstate_to_name(mdev->state.s.conn));
 	}
 
         number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ);
@@ -394,25 +394,18 @@
 	INFO("Resync done (total %lu sec; paused %lu sec; %lu K/sec)\n",
 	     dt + mdev->rs_paused, mdev->rs_paused, dbdt);
 
-	if (mdev->cstate == SyncTarget || mdev->cstate == PausedSyncT) {
-		drbd_md_set_flag(mdev,MDF_Consistent);
-		ERR_IF(drbd_md_test_flag(mdev,MDF_FullSync))
-			drbd_md_clear_flag(mdev,MDF_FullSync);
-		drbd_md_write(mdev);
-	} else if (mdev->cstate == SyncSource || mdev->cstate == PausedSyncS) {
-		set_bit(PARTNER_CONSISTENT, &mdev->flags);
-	} else {
-		ERR("unexpected cstate (%s) in drbd_resync_finished\n",
-		    cstate_to_name(mdev->cstate));
-	}
-
 	// assert that all bit-map parts are cleared.
 	D_ASSERT(list_empty(&mdev->resync->lru));
 	D_ASSERT(drbd_bm_total_weight(mdev) == 0);
 	mdev->rs_total  = 0;
 	mdev->rs_paused = 0;
 
-	set_cstate(mdev,Connected);
+	drbd_request_state(mdev,NS3(conn,Connected,
+				    disk,Consistent,
+				    pedi,Consistent));
+
+	drbd_md_write(mdev);
+
 	/* FIXME
 	 * _queueing_ of w_resume_next_sg() gets _scheduled_ here.
 	 * maybe rather _do_ it right here instead? */
@@ -472,7 +465,7 @@
 	drbd_rs_complete_io(mdev,drbd_ee_get_sector(e));
 
 	if(likely(drbd_bio_uptodate(&e->private_bio))) {
-		if (likely( !test_bit(PARTNER_DISKLESS,&mdev->flags) )) {
+		if (likely( mdev->state.s.pedi >= Inconsistent )) {
 			inc_rs_pending(mdev);
 			ok=drbd_send_block(mdev, RSDataReply, e);
 		} else {
@@ -545,16 +538,16 @@
 
 STATIC void _drbd_rs_resume(drbd_dev *mdev)
 {
-	Drbd_CState ns;
+	drbd_conns_t ncs;
 
-	ns = mdev->cstate - (PausedSyncS - SyncSource);
-	D_ASSERT(ns == SyncSource || ns == SyncTarget);
+	ncs = mdev->state.s.conn - (PausedSyncS - SyncSource);
+	D_ASSERT(ncs == SyncSource || ncs == SyncTarget);
 
 	INFO("Syncer continues.\n");
 	mdev->rs_paused += (long)jiffies-(long)mdev->rs_mark_time;
-	_set_cstate(mdev,ns);
+	_drbd_set_state(mdev,_NS(conn,ncs),1);
 
-	if(mdev->cstate == SyncTarget) {
+	if(mdev->state.s.conn == SyncTarget) {
 		ERR_IF(test_bit(STOP_SYNC_TIMER,&mdev->flags)) {
 			unsigned long rs_left = drbd_bm_total_weight(mdev);
 			clear_bit(STOP_SYNC_TIMER,&mdev->flags);
@@ -573,16 +566,17 @@
 
 STATIC void _drbd_rs_pause(drbd_dev *mdev)
 {
-	Drbd_CState ns;
+	drbd_conns_t ncs;
 
-	D_ASSERT(mdev->cstate == SyncSource || mdev->cstate == SyncTarget);
-	ns = mdev->cstate + (PausedSyncS - SyncSource);
+	D_ASSERT(mdev->state.s.conn == SyncSource || mdev->state.s.conn == SyncTarget);
+	ncs = mdev->state.s.conn + (PausedSyncS - SyncSource);
 
-	if(mdev->cstate == SyncTarget) set_bit(STOP_SYNC_TIMER,&mdev->flags);
+	if(mdev->state.s.conn == SyncTarget) set_bit(STOP_SYNC_TIMER,&mdev->flags);
 
 	mdev->rs_mark_time = jiffies;
 	// mdev->rs_mark_left = drbd_bm_total_weight(mdev); // I don't care...
-	_set_cstate(mdev,ns);
+	_drbd_set_state(mdev,_NS(conn,ncs),1);
+
 	INFO("Syncer waits for sync group.\n");
 }
 
@@ -594,8 +588,8 @@
 	for (i=0; i < minor_count; i++) {
 		odev = drbd_conf + i;
 		if ( odev->sync_conf.group > mdev->sync_conf.group
-		     && ( odev->cstate == SyncSource || 
-			  odev->cstate == SyncTarget ) ) {
+		     && ( odev->state.s.conn == SyncSource || 
+			  odev->state.s.conn == SyncTarget ) ) {
 			_drbd_rs_pause(odev);
 			rv = 1;
 		}
@@ -612,8 +606,8 @@
 	for (i=0; i < minor_count; i++) {
 		odev = drbd_conf + i;
 		if ( odev->sync_conf.group < mdev->sync_conf.group
-		     && ( odev->cstate == SyncSource || 
-			  odev->cstate == SyncTarget ) ) {
+		     && ( odev->state.s.conn == SyncSource || 
+			  odev->state.s.conn == SyncTarget ) ) {
 			rv = 1;
 		}
 	}
@@ -629,8 +623,8 @@
 	for (i=0; i < minor_count; i++) {
 		odev = drbd_conf + i;
 		if ( odev->sync_conf.group < mdev->sync_conf.group
-		     && ( odev->cstate == PausedSyncS || 
-			  odev->cstate == PausedSyncT ) ) {
+		     && ( odev->state.s.conn == PausedSyncS || 
+			  odev->state.s.conn == PausedSyncT ) ) {
 			_drbd_rs_resume(odev);
 			rv = 1;
 		}
@@ -651,8 +645,8 @@
 	for (i=0; i < minor_count; i++) {
 		odev = drbd_conf + i;
 		if ( odev->sync_conf.group == mdev->sync_conf.group
-		     && ( odev->cstate == SyncSource || 
-			  odev->cstate == SyncTarget ) ) {
+		     && ( odev->state.s.conn == SyncSource || 
+			  odev->state.s.conn == SyncTarget ) ) {
 			goto out; // Sync on an other device in this group
 			          // still runs.
 		}
@@ -662,7 +656,7 @@
 		odev = drbd_conf + i;
 		if ( odev->sync_conf.group > mdev->sync_conf.group
 		     && odev->sync_conf.group < ng && 
-		     (odev->cstate==PausedSyncS || odev->cstate==PausedSyncT)){
+		     (odev->state.s.conn==PausedSyncS || odev->state.s.conn==PausedSyncT)){
 		  ng = odev->sync_conf.group;
 		}
 	}
@@ -670,7 +664,7 @@
 	for (i=0; i < minor_count; i++) { // resume all devices in next group
 		odev = drbd_conf + i;
 		if ( odev->sync_conf.group == ng &&
-		     (odev->cstate==PausedSyncS || odev->cstate==PausedSyncT)){
+		     (odev->state.s.conn==PausedSyncS || odev->state.s.conn==PausedSyncT)){
 			_drbd_rs_resume(odev);
 		}
 	}
@@ -690,15 +684,15 @@
 	drbd_global_lock();
 	mdev->sync_conf.group = ng;
 
-	if( ( mdev->cstate == PausedSyncS || 
-	      mdev->cstate == PausedSyncT ) && ( d < 0 ) ) {
+	if( ( mdev->state.s.conn == PausedSyncS || 
+	      mdev->state.s.conn == PausedSyncT ) && ( d < 0 ) ) {
 		if(_drbd_pause_higher_sg(mdev)) c=1;
 		else if(!_drbd_lower_sg_running(mdev)) c=1;
 		if(c) _drbd_rs_resume(mdev);
 	}
 
-	if( ( mdev->cstate == SyncSource || 
-	      mdev->cstate == SyncTarget ) && ( d > 0 ) ) {
+	if( ( mdev->state.s.conn == SyncSource || 
+	      mdev->state.s.conn == SyncTarget ) && ( d > 0 ) ) {
 		if(_drbd_resume_lower_sg(mdev)) p=1;
 		else if(_drbd_lower_sg_running(mdev)) p=1;
 		if(p) _drbd_rs_pause(mdev);
@@ -706,13 +700,17 @@
 	drbd_global_unlock();
 }
 
-void drbd_start_resync(drbd_dev *mdev, Drbd_CState side)
+void drbd_start_resync(drbd_dev *mdev, drbd_conns_t side)
 {
+	int r=0;
+
 	if(side == SyncTarget) {
-		drbd_md_clear_flag(mdev,MDF_Consistent);
 		drbd_bm_reset_find(mdev);
+		r = drbd_request_state(mdev,NS2(conn,SyncTarget,
+						disk,Inconsistent));
 	} else if (side == SyncSource) {
-		clear_bit(PARTNER_CONSISTENT, &mdev->flags);
+		r = drbd_request_state(mdev,NS2(conn,SyncSource,
+						pedi,Inconsistent));
 		/* If we are SyncSource we must be consistent.
 		 * FIXME this should be an assertion only,
 		 * otherwise it masks a logic bug somewhere else...
@@ -721,14 +719,16 @@
 			// FIXME this is actually a BUG()!
 			drbd_md_set_flag(mdev,MDF_Consistent);
 		}
-	} else {
-		ERR("Usage error in drbd_start_resync! (side == %s)\n",
-		     cstate_to_name(side));
+	}
+
+	if(r != 1) {
+		ERR("Error in drbd_start_resync! (side == %s)\n",
+		    cstate_to_name(side));
 		return;
 	}
+
 	drbd_md_write(mdev);
 
-	set_cstate(mdev,side);
 	mdev->rs_total     =
 	mdev->rs_mark_left = drbd_bm_total_weight(mdev);
 	mdev->rs_paused    = 0;
@@ -757,15 +757,14 @@
 		return;
 	}
 
-	/* FIXME THINK
-	 * use mdev->cstate (we may already be paused...) or side here ?? */
-	if (mdev->cstate == SyncTarget) {
+	if (side == SyncTarget) {
 		D_ASSERT(!test_bit(STOP_SYNC_TIMER,&mdev->flags));
 		mod_timer(&mdev->resync_timer,jiffies);
 	}
 
 	drbd_global_lock();
-	if (mdev->cstate == SyncTarget || mdev->cstate == SyncSource) {
+	if ( mdev->state.s.conn == SyncTarget || 
+	     mdev->state.s.conn == SyncSource ) {
 		_drbd_pause_higher_sg(mdev);
 		if(_drbd_lower_sg_running(mdev)) {
 			_drbd_rs_pause(mdev);
@@ -818,10 +817,10 @@
 		list_del_init(&w->list);
 		spin_unlock_irq(&mdev->req_lock);
 
-		if(!w->cb(mdev,w, mdev->cstate < Connected )) {
+		if(!w->cb(mdev,w, mdev->state.s.conn < Connected )) {
 			//WARN("worker: a callback failed! \n");
-			if (mdev->cstate >= Connected)
-				set_cstate(mdev,NetworkFailure);
+			if (mdev->state.s.conn >= Connected)
+				drbd_force_state(mdev,NS(conn,NetworkFailure));
 			drbd_thread_restart_nowait(&mdev->receiver);
 		}
 	}

Modified: trunk/drbd/linux/drbd.h
===================================================================
--- trunk/drbd/linux/drbd.h	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/drbd/linux/drbd.h	2004-11-03 15:57:30 UTC (rev 1624)
@@ -52,6 +52,11 @@
      divisible by 8.
 */
 
+/* defined in drbd_strings.c */
+extern const char *drbd_conn_s_names[];
+extern const char *drbd_role_s_names[];
+extern const char *drbd_disk_s_names[];
+
 #define MAX_SOCK_ADDR	128	/* 108 for Unix domain -
 				   16 for IP, 16 for IPX,
 				   24 for IPv6,
@@ -163,10 +168,11 @@
 	Unknown=0,
 	Primary=1,     // role
 	Secondary=2,   // role
+	role_mask=3,
 	Human=4,           // flag for set_state
 	TimeoutExpired=8,  // flag for set_state
 	DontBlameDrbd=16   // flag for set_state
-} Drbd_State;
+} drbd_role_t;
 
 /* The order of these constants is important.
  * The lower ones (<WFReportParams) indicate
@@ -195,8 +201,33 @@
 	SyncTarget,     // state must be the same for source and target. (+2)
 	PausedSyncS,    // see _drbd_rs_resume() and _drbd_rs_pause()
 	PausedSyncT,    // is sync target, but higher priority groups first
-} Drbd_CState;
+	conn_mask=31
+} drbd_conns_t;
 
+typedef enum {
+	DUnknown,
+	Diskless,
+	Failed,         /* Becomes Diskless as soon as we told it the peer */
+	Inconsistent,
+	Outdated,
+	Consistent,     /* Might be outdated, might be UpToDate ... */
+	UpToDate,
+	disk_mask=7
+} drbd_disks_t;
+
+typedef union {
+	struct {
+		unsigned role : 2 ;   // 3/3      primary/secondary/unknown
+		unsigned peer : 2 ;   // 3/3      primary/secondary/unknown
+		unsigned conn : 5 ;   // 17/32    cstates
+		unsigned disk : 3 ;   // 7/7      from DUnknown to UpToDate
+		unsigned pedi : 3 ;   // 7/7      from DUnknown to UpToDate
+		unsigned mult : 1 ;   // 2/2      multiple primaries allowed
+		unsigned _pad : 16;   // 0        unused
+	} s;
+	unsigned int i;
+} drbd_state_t;
+
 #ifndef BDEVNAME_SIZE
 # define BDEVNAME_SIZE 32
 #endif
@@ -213,9 +244,7 @@
 	OUT int               meta_device_major;
 	OUT int               meta_device_minor;
 	OUT int               meta_index;
-	OUT Drbd_CState       cstate;
-	OUT Drbd_State        state;
-	OUT Drbd_State        peer_state;
+	OUT drbd_state_t      state;
 	int                   _pad;
 };
 
@@ -227,7 +256,7 @@
  */
 #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, Drbd_State )
+#define DRBD_IOCTL_SET_STATE        _IOW( DRBD_IOCTL_LETTER, 0x02, drbd_role_t )
 #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 )
@@ -239,7 +268,7 @@
 #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_SET_STATE_FLAGS  _IOW( DRBD_IOCTL_LETTER, 0x14, Drbd_State )
+#define DRBD_IOCTL_SET_STATE_FLAGS  _IOW( DRBD_IOCTL_LETTER, 0x14, drbd_role_t )
 
 
 #endif

Modified: trunk/user/drbdsetup.c
===================================================================
--- trunk/user/drbdsetup.c	2004-11-02 22:12:08 UTC (rev 1623)
+++ trunk/user/drbdsetup.c	2004-11-03 15:57:30 UTC (rev 1624)
@@ -670,7 +670,7 @@
 
 
 
-int set_state(int drbd_fd,Drbd_State state)
+int set_state(int drbd_fd,drbd_role_t state)
 {
   int err;
   err=ioctl(drbd_fd,DRBD_IOCTL_SET_STATE,state);
@@ -703,7 +703,7 @@
 
 int cmd_primary(int drbd_fd,char** argv,int argc,struct option *options)
 {
-  Drbd_State newstate=Primary;
+  drbd_role_t newstate=Primary;
 
   if(argc > 0)
     {
@@ -756,7 +756,7 @@
 int cmd_on_primary(int drbd_fd,char** argv,int argc,struct option *options)
 {
   int err;
-  Drbd_State flags=0;
+  drbd_role_t flags=0;
 
   if(argc > 0)
     {
@@ -1168,72 +1168,78 @@
       return 20;
     }
 
-  if( cn.cstate < StandAlone )
+  if( cn.state.s.conn == StandAlone && cn.state.s.disk == Diskless)
     {
       printf("Not configured\n");
       return 0;
     }
 
-  printf("Lower device: %02d:%02d   (%s)\n",
-	 cn.lower_device_major,
-	 cn.lower_device_minor,
-        check_dev_name(cn.lower_device_name,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("Meta device: internal\n");
-  } else {
-    printf("Meta device: %02d:%02d   (%s)\n",
-	   cn.meta_device_major,
-	   cn.meta_device_minor,
-          check_dev_name(cn.meta_device_name,cn.meta_device_major,
-                         cn.meta_device_minor));
-    printf("Meta index: %d\n",cn.meta_index);
-  }
+  if( cn.state.s.disk > Diskless)
+    {
 
-  printf("Disk options:\n");
-  if( cn.disk_size_user ) printf(" size = %lu KB\n",
-				 (unsigned long)cn.disk_size_user);
-  if( cn.on_io_error != DEF_ON_IO_ERROR) {
-    printf(" on-io-error = %s\n",eh_names[cn.on_io_error]);
-  }
+      printf("Lower device: %02d:%02d   (%s)\n",
+	     cn.lower_device_major,
+	     cn.lower_device_minor,
+	     check_dev_name(cn.lower_device_name,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("Meta device: internal\n");
+      } else {
+	printf("Meta device: %02d:%02d   (%s)\n",
+	       cn.meta_device_major,
+	       cn.meta_device_minor,
+	       check_dev_name(cn.meta_device_name,cn.meta_device_major,
+			      cn.meta_device_minor));
+	printf("Meta index: %d\n",cn.meta_index);
+      }
 
-  if( cn.cstate < Unconnected ) return 0;
+      printf("Disk options:\n");
+      if( cn.disk_size_user ) printf(" size = %lu KB\n",
+				     (unsigned long)cn.disk_size_user);
+      if( cn.on_io_error != DEF_ON_IO_ERROR) {
+	printf(" on-io-error = %s\n",eh_names[cn.on_io_error]);
+      }
 
-  my_addr = (struct sockaddr_in *)cn.nconf.my_addr;
-  other_addr = (struct sockaddr_in *)cn.nconf.other_addr;
-  printf("Local address: %s:%d\n",
-	 inet_ntoa(my_addr->sin_addr),
-	 ntohs(my_addr->sin_port));
-  printf("Remote address: %s:%d\n",
-	 inet_ntoa(other_addr->sin_addr),
-	 ntohs(other_addr->sin_port));
-  printf("Wire protocol: %c\n",'A'-1+cn.nconf.wire_protocol);
-  printf("Net options:\n");
-  printf(" timeout = %d.%d sec %s\n",cn.nconf.timeout/10,cn.nconf.timeout%10,
-	 cn.nconf.timeout == DEF_NET_TIMEOUT ? "(default)" : "" );
+    }
 
+  if( cn.state.s.conn > StandAlone)
+    {
+      my_addr = (struct sockaddr_in *)cn.nconf.my_addr;
+      other_addr = (struct sockaddr_in *)cn.nconf.other_addr;
+      printf("Local address: %s:%d\n",
+	     inet_ntoa(my_addr->sin_addr),
+	     ntohs(my_addr->sin_port));
+      printf("Remote address: %s:%d\n",
+	     inet_ntoa(other_addr->sin_addr),
+	     ntohs(other_addr->sin_port));
+      printf("Wire protocol: %c\n",'A'-1+cn.nconf.wire_protocol);
+      printf("Net options:\n");
+      printf(" timeout = %d.%d sec %s\n",cn.nconf.timeout/10,cn.nconf.timeout%10,
+	     cn.nconf.timeout == DEF_NET_TIMEOUT ? "(default)" : "" );
+
 #define SHOW_I(T,U,M,D) printf(" " T " = %d " U " %s\n", M, M == D ? "(default)" : "")
 
-  SHOW_I("connect-int","sec", cn.nconf.try_connect_int, DEF_NET_TRY_CON_I);
-  SHOW_I("ping-int","sec", cn.nconf.ping_int, DEF_NET_PING_I);
-  SHOW_I("max-epoch-size","", cn.nconf.max_epoch_size, DEF_MAX_EPOCH_SIZE);
-  SHOW_I("max-buffers","", cn.nconf.max_buffers, DEF_MAX_BUFFERS);
-  SHOW_I("sndbuf-size","", cn.nconf.sndbuf_size, DEF_SNDBUF_SIZE);
-  SHOW_I("ko-count","", cn.nconf.ko_count, DEF_KO_COUNT);
-  if( cn.nconf.on_disconnect != DEF_ON_DISCONNECT) {
-    printf(" on-disconnect = %s\n",dh_names[cn.nconf.on_disconnect]);
-  }
+      SHOW_I("connect-int","sec", cn.nconf.try_connect_int, DEF_NET_TRY_CON_I);
+      SHOW_I("ping-int","sec", cn.nconf.ping_int, DEF_NET_PING_I);
+      SHOW_I("max-epoch-size","", cn.nconf.max_epoch_size, DEF_MAX_EPOCH_SIZE);
+      SHOW_I("max-buffers","", cn.nconf.max_buffers, DEF_MAX_BUFFERS);
+      SHOW_I("sndbuf-size","", cn.nconf.sndbuf_size, DEF_SNDBUF_SIZE);
+      SHOW_I("ko-count","", cn.nconf.ko_count, DEF_KO_COUNT);
+      if( cn.nconf.on_disconnect != DEF_ON_DISCONNECT) {
+	printf(" on-disconnect = %s\n",dh_names[cn.nconf.on_disconnect]);
+      }
 
 
-  printf("Syncer options:\n");
+      printf("Syncer options:\n");
 
-  SHOW_I("rate","KB/sec", cn.sconf.rate, DEF_SYNC_RATE);
-  SHOW_I("group","", cn.sconf.group, DEF_SYNC_GROUP);
-  SHOW_I("al-extents","", cn.sconf.al_extents, DEF_SYNC_AL_EXTENTS);
+      SHOW_I("rate","KB/sec", cn.sconf.rate, DEF_SYNC_RATE);
+      SHOW_I("group","", cn.sconf.group, DEF_SYNC_GROUP);
+      SHOW_I("al-extents","", cn.sconf.al_extents, DEF_SYNC_AL_EXTENTS);
 
-  if( cn.sconf.skip ) printf(" skip-sync\n");
-  if( cn.sconf.use_csums ) printf(" use-csums\n");
+      if( cn.sconf.skip ) printf(" skip-sync\n");
+      if( cn.sconf.use_csums ) printf(" use-csums\n");
+    }
 
   return 0;
 }
@@ -1256,13 +1262,13 @@
       return 20;
     }
 
-  if( cn.cstate < StandAlone )
+  if( cn.state.s.conn == StandAlone && cn.state.s.disk == Diskless)
     {
       printf("Not configured\n");
       return 0;
     }
 
-  printf("%s/%s\n",state_names[cn.state],state_names[cn.peer_state]);
+  printf("%s/%s\n",state_names[cn.state.s.role],state_names[cn.state.s.peer]);
 
   return 0;
 }
@@ -1299,13 +1305,13 @@
       return 20;
     }
 
-  if( cn.cstate < StandAlone )
+  if( cn.state.s.conn == StandAlone && cn.state.s.disk == Diskless)
     {
       printf("Not configured\n");
       return 0;
     }
 
-  printf("%s\n",cstate_names[cn.cstate]);
+  printf("%s\n",cstate_names[cn.state.s.conn]);
 
   return 0;
 }



More information about the drbd-cvs mailing list