From drbd-cvs at lists.linbit.com  Wed Mar  1 17:36:25 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Mar  1 17:36:27 2006
Subject: [DRBD-cvs] svn commit by phil - r2087 - in trunk: . drbd user -
	Hopefully last changes to meta-data layout before we be
Message-ID: <20060301163625.4DA9C1689F@mail.linbit.com>

Author: phil
Date: 2006-03-01 17:36:23 +0100 (Wed, 01 Mar 2006)
New Revision: 2087

Modified:
   trunk/ROADMAP
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/user/drbdadm_usage_cnt.c
   trunk/user/drbdmeta.c
   trunk/user/drbdmeta_parser.h
   trunk/user/drbdmeta_scanner.fl
Log:
Hopefully last changes to meta-data layout before we begin with
stabilising for drbd-v08

implemented item 25 of the ROADMAP (reserved fields, bytes per bit)


Modified: trunk/ROADMAP
===================================================================
--- trunk/ROADMAP	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/ROADMAP	2006-03-01 16:36:23 UTC (rev 2087)
@@ -652,6 +652,8 @@
 25 Add reserved fields to DRBD-meta-data, add a bytes per bit field to
    metadata.
 
+   99% DONE
+
 26 Implement a kind of "dstate" command to make integration with 
    Heartbeat-2.0's master/slave-support possible.
 

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/drbd/drbd_int.h	2006-03-01 16:36:23 UTC (rev 2087)
@@ -681,6 +681,7 @@
 
 	u64 la_size_sect;	/* last agreed size, unit sectors */
 	u64 uuid[UUID_SIZE];
+	u64 device_uuid;
 	u32 flags;
 	u32 md_size_sect;
 

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/drbd/drbd_main.c	2006-03-01 16:36:23 UTC (rev 2087)
@@ -2402,6 +2402,7 @@
 	u64 la_size;           // last agreed size.
 	u64 uuid[UUID_SIZE];   // UUIDs.
 	u64 device_uuid;
+	u64 reserved_u64_1;
 	u32 flags;             // MDF
 	u32 magic;
 	u32 md_size_sect;
@@ -2409,6 +2410,9 @@
 	u32 al_nr_extents;     // important for restoring the AL
 	      // `-- act_log->nr_elements <-- sync_conf.al_extents
 	u32 bm_offset;         // offset to the bitmap, from here
+	u32 bm_bytes_per_bit;  // BM_BLOCK_SIZE
+	u32 reserved_u32[4];
+
 } __attribute((packed));
 
 /** 
@@ -2439,6 +2443,8 @@
 	buffer->md_size_sect  = cpu_to_be32(mdev->bc->md.md_size_sect);
 	buffer->al_offset     = cpu_to_be32(mdev->bc->md.al_offset);
 	buffer->al_nr_extents = cpu_to_be32(mdev->act_log->nr_elements);
+	buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE);
+	buffer->device_uuid = cpu_to_be64(mdev->bc->md.device_uuid);
 
 	buffer->bm_offset = cpu_to_be32(mdev->bc->md.bm_offset);
 
@@ -2523,11 +2529,19 @@
 		goto err;
 	}
 
+	if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
+		ERR("unexpected bm_bytes_per_bit: %u (expected %u)\n",
+		    be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
+		rv = MDInvalid;
+		goto err;
+	}
+
 	bdev->md.la_size_sect = be64_to_cpu(buffer->la_size);
 	for (i = Current; i < UUID_SIZE; i++)
 		bdev->md.uuid[i]=be64_to_cpu(buffer->uuid[i]);
 	bdev->md.flags = be32_to_cpu(buffer->flags);
 	mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents);
+	bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
 
 	if (mdev->sync_conf.al_extents < 7)
 		mdev->sync_conf.al_extents = 127;

Modified: trunk/user/drbdadm_usage_cnt.c
===================================================================
--- trunk/user/drbdadm_usage_cnt.c	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/user/drbdadm_usage_cnt.c	2006-03-01 16:36:23 UTC (rev 2087)
@@ -356,7 +356,7 @@
 			update ? "an update" : "a new installation",
 			REL_VERSION,ni.node_uuid, ni.version_code);
 		fgets(answer,ANSWER_SIZE,stdin);
-		if(!strcmp(answer,"no")) send = 0;
+		if(!strcmp(answer,"no\n")) send = 0;
 	}
 
 
@@ -448,17 +448,15 @@
 
 	rv = _admm_generic(res, cmd, SLEEPS_VERY_LONG); // cmd is "create-md".
 
-	if(!device_uuid) {
-		get_random_bytes(&device_uuid, sizeof(u64));
-	}
-
 	fd = open(res->me->disk,O_RDONLY);
 	if( fd != -1) {
 		device_size = bdev_size(fd);
 		close(fd);
 	}
 
-	if( read_node_id(&ni) && device_size ) {
+	if( read_node_id(&ni) && device_size && !device_uuid) {
+		get_random_bytes(&device_uuid, sizeof(u64));
+
 		if( global_options.usage_count == UC_YES ) send = 1;
 		if( global_options.usage_count == UC_ASK ) {
 			printf(
@@ -473,10 +471,14 @@
 				ni.node_uuid,device_uuid,device_size
 				);
 		fgets(answer,ANSWER_SIZE,stdin);
-		if(strcmp(answer,"no")) send = 1;
+		if(strcmp(answer,"no\n")) send = 1;
 		}
 	}
 
+	if(!device_uuid) {
+		get_random_bytes(&device_uuid, sizeof(u64));
+	}
+
 	if (send) {
 		ssprintf(req_buf,"GET http://"HTTP_HOST"/cgi-bin/insert_usage.pl?"
 			 "nu="U64"&ru="U64"&rs="U64" HTTP/1.0\n\n",

Modified: trunk/user/drbdmeta.c
===================================================================
--- trunk/user/drbdmeta.c	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/user/drbdmeta.c	2006-03-01 16:36:23 UTC (rev 2087)
@@ -124,6 +124,8 @@
 #define MD_BM_MAX_BYTE_07      ( (u64)(MD_RESERVED_SECT_07 - MD_BM_OFFSET_07)*512 )
 #define MD_BM_MAX_BYTE_FLEX    ( (u64)(1ULL << (32-3)) )
 
+#define DEFAULT_BM_BLOCK_SIZE  (1<<12)
+
 #define DRBD_MD_MAGIC_06   (DRBD_MAGIC+2)
 #define DRBD_MD_MAGIC_07   (DRBD_MAGIC+3)
 #define DRBD_MD_MAGIC_08   (DRBD_MAGIC+4)
@@ -234,6 +236,7 @@
 	u64 uuid[UUID_SIZE];
 	u32 flags;
 	u64 device_uuid;
+	u32 bm_bytes_per_bit;
 };
 
 /*
@@ -524,14 +527,17 @@
 	be_u64 la_sect;		/* last agreed size. */
 	be_u64 uuid[UUID_SIZE];   // UUIDs.
 	be_u64 device_uuid;
+	be_u64 reserved_u64_1;
 	be_u32 flags;
 	be_u32 magic;
 	be_u32 md_size_sect;
 	be_s32 al_offset;	/* signed sector offset to this block */
 	be_u32 al_nr_extents;	/* important for restoring the AL */
 	be_s32 bm_offset;	/* signed sector offset to the bitmap, from here */
+	be_u32 bm_bytes_per_bit;
+	be_u32 reserved_u32[4];
 	
-	char reserved[8 * 512 - (8*(UUID_SIZE+2)+4*6)];
+	char reserved[8 * 512 - (8*(UUID_SIZE+3)+4*11)];
 };
 
 void md_disk_08_to_cpu(struct md_cpu *cpu, const struct md_on_disk_08 *disk)
@@ -549,6 +555,7 @@
 	cpu->al_offset = be32_to_cpu(disk->al_offset.be);
 	cpu->al_nr_extents = be32_to_cpu(disk->al_nr_extents.be);
 	cpu->bm_offset = be32_to_cpu(disk->bm_offset.be);
+	cpu->bm_bytes_per_bit = be32_to_cpu(disk->bm_bytes_per_bit.be);
 }
 
 void md_cpu_to_disk_08(struct md_on_disk_08 *disk, const struct md_cpu *cpu)
@@ -565,6 +572,7 @@
 	disk->al_offset.be = cpu_to_be32(cpu->al_offset);
 	disk->al_nr_extents.be = cpu_to_be32(cpu->al_nr_extents);
 	disk->bm_offset.be = cpu_to_be32(cpu->bm_offset);
+	disk->bm_bytes_per_bit.be = cpu_to_be32(cpu->bm_bytes_per_bit);
 	MEMSET(disk->reserved, 0, sizeof(disk->reserved));
 }
 
@@ -1235,6 +1243,7 @@
 		break;
 	}
 	cfg->md.al_nr_extents = 257;	/* arbitrary. */
+	cfg->md.bm_bytes_per_bit = DEFAULT_BM_BLOCK_SIZE;
 	cfg->bm_mmaped_length = ((u64)cfg->md.md_size_sect - MD_BM_OFFSET_07)*512;
 
 	cfg->al_offset = cfg->md_offset + cfg->md.al_offset * 512;
@@ -1627,6 +1636,8 @@
 
 	if (format_version(cfg) >= Drbd_07) {
 		printf("la-size-sect "U64";\n", cfg->md.la_sect);
+		printf("bm-byte-per-bit "U32";\n",cfg->md.bm_bytes_per_bit);
+		printf("device-uuid 0x"X64(016)";\n",cfg->md.device_uuid);
 		printf("# bm-bytes %u;\n", cfg->bm_bytes);
 		printf("# bits-set %u;\n", cfg->bits_set);
 		if (cfg->on_disk.bm)
@@ -1692,6 +1703,10 @@
 	}
 	EXP(TK_LA_SIZE); EXP(TK_NUM); EXP(';');
 	cfg->md.la_sect = yylval.u64;
+	EXP(TK_BM_BYTE_PER_BIT); EXP(TK_NUM); EXP(';');
+	cfg->md.bm_bytes_per_bit = yylval.u64;
+	EXP(TK_DEVICE_UUID); EXP(TK_U64); EXP(';');
+	cfg->md.device_uuid = yylval.u64;
 	EXP(TK_BM); EXP('{');
 	bm = (le_u64 *)cfg->on_disk.bm;
 	i = 0;

Modified: trunk/user/drbdmeta_parser.h
===================================================================
--- trunk/user/drbdmeta_parser.h	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/user/drbdmeta_parser.h	2006-03-01 16:36:23 UTC (rev 2087)
@@ -18,6 +18,8 @@
 	TK_UUID,
 	TK_VERSION,
 	TK_LA_SIZE,
+	TK_BM_BYTE_PER_BIT,
+	TK_DEVICE_UUID,
 	TK_TIMES
 };
 

Modified: trunk/user/drbdmeta_scanner.fl
===================================================================
--- trunk/user/drbdmeta_scanner.fl	2006-02-28 18:14:50 UTC (rev 2086)
+++ trunk/user/drbdmeta_scanner.fl	2006-03-01 16:36:23 UTC (rev 2087)
@@ -34,6 +34,8 @@
 uuid		DP; return TK_UUID;
 version		DP; return TK_VERSION;
 la-size-sect	DP; return TK_LA_SIZE;
+bm-byte-per-bit DP; return TK_BM_BYTE_PER_BIT;
+device-uuid	DP; return TK_DEVICE_UUID;
 times		DP; return TK_TIMES;
 
 %%

From drbd-cvs at lists.linbit.com  Wed Mar  1 19:02:04 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Mar  1 19:02:06 2006
Subject: [DRBD-cvs] svn commit by phil - r2088 - trunk/drbd - The first fix
	from tests on hans-wurst. Now the "detach
Message-ID: <20060301180204.E4EA21689D@mail.linbit.com>

Author: phil
Date: 2006-03-01 19:02:03 +0100 (Wed, 01 Mar 2006)
New Revision: 2088

Modified:
   trunk/drbd/drbd_main.c
Log:
The first fix from tests on hans-wurst. Now the "detach"
command works also an SMP-preempt machines.


Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-01 16:36:23 UTC (rev 2087)
+++ trunk/drbd/drbd_main.c	2006-03-01 18:02:03 UTC (rev 2088)
@@ -729,13 +729,6 @@
 		}
 	}
 
-	/* it feels better to have the module_put last ... */
-	if ( (os.disk > Diskless || os.conn > StandAlone) &&
-	     ns.disk == Diskless && ns.conn == StandAlone ) {
-		drbd_mdev_cleanup(mdev);
-		module_put(THIS_MODULE);
-	}
-
 	return rv;
 }
 
@@ -820,6 +813,13 @@
 	        ns.aftr_isp == 0 && ns.user_isp == 0   ) {
 		drbd_send_short_cmd(mdev,ResumeResync);
 	}
+
+	/* it feels better to have the module_put last ... */
+	if ( (os.disk > Diskless || os.conn > StandAlone) &&
+	     ns.disk == Diskless && ns.conn == StandAlone ) {
+		drbd_mdev_cleanup(mdev);
+		module_put(THIS_MODULE);
+	}
 }
 
 

From drbd-cvs at lists.linbit.com  Fri Mar  3 16:38:36 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Mar  3 16:38:38 2006
Subject: [DRBD-cvs] svn commit by phil - r2089 - trunk/drbd - * Late
	allocation of resync_lru and act_log
Message-ID: <20060303153836.935CF168DC@mail.linbit.com>

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

Author: phil
Date: 2006-03-03 16:38:34 +0100 (Fri, 03 Mar 2006)
New Revision: 2089

Modified:
   trunk/drbd/drbd_bitmap.c
   trunk/drbd/drbd_fs.c
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_proc.c
   trunk/drbd/drbd_worker.c
Log:
* Late allocation of resync_lru and act_log
* The code that finds adjacent bits during resync needed some fixes


Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-01 18:02:03 UTC (rev 2088)
+++ trunk/drbd/drbd_bitmap.c	2006-03-03 15:38:34 UTC (rev 2089)
@@ -786,7 +786,11 @@
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
 
-	b->bm_fo = i;
+	if (i < b->bm_bits) {
+		b->bm_fo = i;
+	} else {
+		b->bm_fo = 0;
+	}
 
 	spin_unlock_irq(&b->bm_lock);
 }
@@ -871,6 +875,9 @@
 /* returns bit state
  * wants bitnr, NOT sector.
  * inherently racy... area needs to be locked by means of {al,rs}_lru
+ *  1 ... bit set
+ *  0 ... bit not set
+ * -1 ... first out of bounds access, stop testing for bits!
  */
 int drbd_bm_test_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
@@ -881,12 +888,15 @@
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
-	ERR_IF (bitnr >= b->bm_bits) {
-		ERR("bitnr=%lu bm_bits=%lu\n",bitnr, b->bm_bits);
-		i = 0;
-	} else {
+	if (bitnr < b->bm_bits) {
 		i = test_bit(bitnr, b->bm);
+	} else if (bitnr == b->bm_bits) {
+		i = -1;
+	} else /* (bitnr > b->bm_bits) */ {
+		ERR("bitnr=%lu > bm_bits=%lu\n",bitnr, b->bm_bits);
+		i = 0;		
 	}
+
 	spin_unlock_irq(&b->bm_lock);
 	return i;
 }

Modified: trunk/drbd/drbd_fs.c
===================================================================
--- trunk/drbd/drbd_fs.c	2006-03-01 18:02:03 UTC (rev 2088)
+++ trunk/drbd/drbd_fs.c	2006-03-03 15:38:34 UTC (rev 2089)
@@ -307,6 +307,7 @@
 	struct disk_config new_conf;  // local copy of ioctl() args.
 	struct drbd_backing_dev* nbc; // new_backing_conf
 	struct inode *inode, *inode2;
+	struct lru_cache* resync_lru = NULL;
 	drbd_disks_t nds;
 
 	minor=(int)(mdev-drbd_conf);
@@ -364,6 +365,12 @@
 		goto fail_ioctl;
 	}
 
+	resync_lru = lc_alloc("resync",7, sizeof(struct bm_extent),mdev);
+	if(!resync_lru) {
+		retcode=KMallocFailed;
+		goto fail_ioctl;
+	}
+
 	nbc->md_bdev = inode2->i_bdev;
 	if (bd_claim(nbc->md_bdev,
 		     (new_conf.meta_index==DRBD_MD_INDEX_INTERNAL ||
@@ -453,6 +460,7 @@
 
 	D_ASSERT(mdev->bc == NULL);
 	mdev->bc = nbc;
+	mdev->resync = resync_lru;
 
 	if (new_conf.split_brain_fix) set_bit(SPLIT_BRAIN_FIX,&mdev->flags);
 	else clear_bit(SPLIT_BRAIN_FIX,&mdev->flags);
@@ -557,6 +565,7 @@
 	if (nbc->lo_file) fput(nbc->lo_file);
 	if (nbc->md_file) fput(nbc->md_file);
 	if (nbc) kfree(nbc);
+	if (resync_lru) lc_free(resync_lru);
 	if (put_user(retcode, &arg->ret_code)) return -EFAULT;
 	return -EINVAL;
 }
@@ -1031,8 +1040,9 @@
 		return -EINTR;
 	}
 
-	drbd_free_bc(mdev->bc);
-	mdev->bc=0;
+	drbd_free_bc(mdev->bc);	mdev->bc = NULL;
+	lc_free(mdev->resync);  mdev->resync = NULL;
+	lc_free(mdev->act_log); mdev->act_log = NULL;
 
 	after_state_ch(mdev, os, ns);
 

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-01 18:02:03 UTC (rev 2088)
+++ trunk/drbd/drbd_main.c	2006-03-03 15:38:34 UTC (rev 2089)
@@ -521,8 +521,7 @@
 		 * and no real references on the device. */
 		WARN("Releasing backing storage device.\n");
 		drbd_free_bc(mdev->bc);
-		mdev->bc=0;
-		mdev->bc->md.la_size_sect=0;
+		mdev->bc=NULL;
 	}
 
 	return ok;
@@ -2290,12 +2289,6 @@
 
 		if (drbd_bm_init(mdev)) goto Enomem;
 		// no need to lock access, we are still initializing the module.
-		mdev->resync = lc_alloc("resync",17, sizeof(struct bm_extent),mdev);
-		if (!mdev->resync) goto Enomem;
-		mdev->act_log = lc_alloc("act_log",mdev->sync_conf.al_extents,
-					 sizeof(struct lc_element), mdev);
-		if (!mdev->act_log) goto Enomem;
-
 		init_MUTEX(&mdev->device_mutex);
 		if (!tl_init(mdev)) goto Enomem;
 

Modified: trunk/drbd/drbd_proc.c
===================================================================
--- trunk/drbd/drbd_proc.c	2006-03-01 18:02:03 UTC (rev 2088)
+++ trunk/drbd/drbd_proc.c	2006-03-03 15:38:34 UTC (rev 2089)
@@ -215,8 +215,12 @@
 		     drbd_conf[i].state.conn == SyncTarget ) {
 			drbd_syncer_progress(drbd_conf+i,seq);
 		}
-		lc_printf_stats(seq,drbd_conf[i].resync);
-		lc_printf_stats(seq,drbd_conf[i].act_log);
+		if(drbd_conf[i].resync) {
+			lc_printf_stats(seq,drbd_conf[i].resync);
+		}
+		if(drbd_conf[i].act_log) {
+			lc_printf_stats(seq,drbd_conf[i].act_log);
+		}
 	}
 
 	return 0;

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-03-01 18:02:03 UTC (rev 2088)
+++ trunk/drbd/drbd_worker.c	2006-03-03 15:38:34 UTC (rev 2089)
@@ -355,7 +355,7 @@
 
 #if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE
 		// try to find some adjacent bits...
-		while ( drbd_bm_test_bit(mdev,bit+1) ) {
+		while ( drbd_bm_test_bit(mdev,bit+1) == 1 ) {
 			// stop if we have the already the maximum req size
 			if(size == DRBD_MAX_SEGMENT_SIZE) break;
 			// do not leafe the current BM_EXTEND

From drbd-cvs at lists.linbit.com  Fri Mar  3 16:47:53 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Mar  3 16:47:55 2006
Subject: [DRBD-cvs] svn commit by lars - r2090 - in trunk/drbd: . linux - *
	page->private is page->u.private since 2.6.15
Message-ID: <20060303154753.C3EBB168DC@mail.linbit.com>

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

Author: lars
Date: 2006-03-03 16:47:52 +0100 (Fri, 03 Mar 2006)
New Revision: 2090

Modified:
   trunk/drbd/drbd_bitmap.c
   trunk/drbd/drbd_compat_wrappers.h
   trunk/drbd/drbd_int.h
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/linux/drbd_config.h
Log:
* page->private is page->u.private since 2.6.15
* drbd07-plus async bitmap io code ==> drbd 8
  untested!




Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-03 15:38:34 UTC (rev 2089)
+++ trunk/drbd/drbd_bitmap.c	2006-03-03 15:47:52 UTC (rev 2090)
@@ -29,6 +29,7 @@
 #include <linux/bitops.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h> // for memset
+#include <linux/swap.h>   // for total_swapcache_pages
 
 #include <linux/drbd.h>
 #include "drbd_int.h"
@@ -57,12 +58,13 @@
 
 /*
  * NOTE
- *  Access to the *bm is protected by bm_lock.
+ *  Access to the *bm_pages is protected by bm_lock.
  *  It is safe to read the other members within the lock.
  *
  *  drbd_bm_set_bit is called from bio_endio callbacks,
  *  so there we need a spin_lock_irqsave.
  *  Everywhere else we need a spin_lock_irq.
+ *  And we need the kmap_atomic :-(
  *
  * FIXME
  *  Actually you need to serialize all resize operations.
@@ -78,17 +80,28 @@
  *  than have two resize operations interfere somewhen.
  */
 struct drbd_bitmap {
-	unsigned long *bm;
+	struct page **bm_pages;
 	spinlock_t bm_lock;
+	/* WARNING unsigned long bm_fo and friends:
+	 * 32bit number of bit offset is just enough for 512 MB bitmap.
+	 * it will blow up if we make the bitmap bigger...
+	 * not that it makes much sense to have a bitmap that large,
+	 * rather change the granularity to 16k or 64k or something.
+	 */
 	unsigned long bm_fo;        // next offset for drbd_bm_find_next
 	unsigned long bm_set;       // nr of set bits; THINK maybe atomic_t ?
 	unsigned long bm_bits;
 	size_t   bm_words;
+	size_t   bm_number_of_pages;
 	sector_t bm_dev_capacity;
 	struct semaphore bm_change; // serializes resize operations
 
+	atomic_t bm_async_io;
+	wait_queue_head_t bm_io_wait;
+
+	unsigned long  bm_flags;
+
 	// { REMOVE
-	unsigned long  bm_flags;     // currently debugging aid only
 	unsigned long  bm_line;
 	char          *bm_file;
 	// }
@@ -96,7 +109,9 @@
 
 // { REMOVE once we serialize all state changes properly
 #define D_BUG_ON(x)	ERR_IF(x) { dump_stack(); }
-#define BM_LOCKED 0
+#define BM_LOCKED      0
+#define BM_MD_IO_ERROR (BITS_PER_LONG-1) // 31? 63?
+
 #if 0 // simply disabled for now...
 #define MUST_NOT_BE_LOCKED() do {					\
 	if (test_bit(BM_LOCKED,&b->bm_flags)) {				\
@@ -158,7 +173,6 @@
 // has been very helpful to indicate that rs_total and rs_left have been
 // used in a non-smp safe way...
 #define BM_PARANOIA_CHECK() do {						\
-	D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC);				\
 	D_ASSERT(b->bm_dev_capacity == drbd_get_capacity(mdev->this_bdev));	\
 	if ( (b->bm_set != mdev->rs_total) &&					\
 	     (b->bm_set != mdev->rs_left) ) {					\
@@ -171,7 +185,6 @@
 } while (0)
 #else
 #define BM_PARANOIA_CHECK() do {					\
-	D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC);			\
 	if (b->bm_dev_capacity != drbd_get_capacity(mdev->this_bdev)) {	\
 		ERR("%s:%d: bm_dev_capacity:%llu drbd_get_capacity:%llu\n", \
 		__FILE__, __LINE__,					\
@@ -184,6 +197,7 @@
 
 #if DUMP_MD >= 3
 /* debugging aid */
+#error "FIXME"
 STATIC void bm_end_info(drbd_dev *mdev, const char* where)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
@@ -202,9 +216,52 @@
 #define bm_end_info(ignored...)	((void)(0))
 #endif
 
+#if 0
+#define catch_oob_access_start() do {	\
+	do {				\
+		if ((bm-p_addr) >= PAGE_SIZE/sizeof(long)) { \
+			printk(KERN_ALERT "drbd_bitmap.c:%u %s: p_addr:%p bm:%p %d\n", \
+					__LINE__ , __func__ , p_addr, bm, (bm-p_addr)); \
+			break;		\
+		}
+#define catch_oob_access_end()	\
+	} while(0); } while (0)
+#else
+#define catch_oob_access_start() ((void)0)
+#define catch_oob_access_end() ((void)0)
+#endif
+
+/* word offset to long pointer */
+STATIC unsigned long * bm_map_paddr(struct drbd_bitmap* b, unsigned long offset)
+{
+	struct page * page;
+	unsigned long page_nr;
+
+	// page_nr = (word*sizeof(long)) >> PAGE_SHIFT;
+	page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3);
+	BUG_ON(page_nr >= b->bm_number_of_pages);
+	page = b->bm_pages[page_nr];
+
+	return (unsigned long*) kmap_atomic(page,KM_USER0);
+}
+
+STATIC void bm_unmap(unsigned long *p_addr) {
+	kunmap_atomic(p_addr, KM_USER0);
+};
+
 /* long word offset of _bitmap_ sector */
 #define S2W(s)	((s)<<(BM_EXT_SIZE_B-BM_BLOCK_SIZE_B-LN2_BPL))
+/* word offset from start of bitmap to word number _in_page_
+ * modulo longs per page
+#define MLPP(X) ((X) % (PAGE_SIZE/sizeof(long))
+ hm, well, Philipp thinks gcc might not optimze the % into & (... - 1)
+ so do it explicitly:
+ */
+#define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
 
+/* Long words per page */
+#define LWPP (PAGE_SIZE/sizeof(long))
+
 /*
  * actually most functions herein should take a struct drbd_bitmap*, not a
  * drbd_dev*, but for the debug macros I like to have the mdev around
@@ -217,7 +274,113 @@
  * But it is NOT strictly ok.
  */
 
+STATIC void bm_free_pages(struct page ** pages, unsigned long number)
+{
+	unsigned long i;
+	if (!pages)
+		return;
+
+	for(i=0;i<number;i++) {
+		if (!pages[i]) {
+			printk(KERN_ALERT "drbd: bm_free_pages tried to free "
+					  "a NULL pointer; i=%lu n=%lu\n",
+					  i, number);
+			continue;
+		}
+		__free_page(pages[i]);
+		pages[i] = NULL;
+	}
+}
+
 /*
+ * "have" and "want" are NUMBER OF PAGES.
+ */
+STATIC struct page ** bm_realloc_pages(struct page ** old_pages,
+				       unsigned long have,
+				       unsigned long want)
+{
+	struct page** new_pages, *page;
+	unsigned int i, bytes;
+
+	BUG_ON(have == 0 && old_pages != NULL);
+	BUG_ON(have != 0 && old_pages == NULL);
+
+	if (have == want)
+		return old_pages;
+
+	/* don't even try if it is likely to be too much */
+	if (want > have) {
+		unsigned long nfree, nleft;
+		nfree = nr_free_pages();
+		nleft = nfree + get_page_cache_size()-total_swapcache_pages;
+
+		if (nleft <= (want-have)) {
+			printk(KERN_ALERT "drbd: bm_realloc_pages: OOM!\n");
+			return NULL;
+		}
+
+		nleft -= (want-have);
+
+		/* protect me agains the infamous oom killer.
+		 * FIXME sorry, now it does no longer work on embeded boxes with less than 16MB main ram :-)
+		 */
+		if ( nleft < (10 << (20 - PAGE_SHIFT)) ) {
+			printk(KERN_ALERT "drbd: bm_realloc_pages would have left less than 10MB ram free; OOM!\n");
+			printk(KERN_ALERT "drbd: free:%lu buf+cache:%lu want:%lu have:%lu left:%lu\n"
+			,	nfree
+			,	get_page_cache_size()-total_swapcache_pages
+			,	want, have, nleft
+			);
+			return NULL;
+		}
+	}
+
+	/* To use kmalloc here is ok, as long as we support 4TB at max...
+	 * otherwise this might become bigger than 128KB, which is
+	 * the maximum for kmalloc.
+	 *
+	 * no, it is not: on 64bit boxes, sizeof(void*) == 8,
+	 * 128MB bitmap @ 4K pages -> 256K of page pointers.
+	 * ==> use vmalloc for now again.
+	 * then again, we could do something like
+	 *   if (nr_pages > watermark) vmalloc else kmalloc :*> ...
+	 * or do cascading page arrays:
+	 *   one page for the page array of the page array,
+	 *   those pages for the real bitmap pages.
+	 *   there we could even add some optimization members,
+	 *   so we won't need to kmap_atomic in bm_find_next_bit just to see
+	 *   that the page has no bits set ...
+	 */
+	bytes = sizeof(struct page*)*want;
+	new_pages = vmalloc(bytes);
+	if(!new_pages) return NULL;
+
+	memset(new_pages,0,bytes);
+	if( want >= have ) {
+		for(i=0;i<have;i++) {
+			new_pages[i] = old_pages[i];
+		}
+		for(;i<want;i++) {
+			if ( !(page = alloc_page(GFP_HIGHUSER)) ) {
+				bm_free_pages(new_pages + have, i - have);
+				vfree(new_pages);
+				return NULL;
+			}
+			new_pages[i] = page;
+		}
+	} else {
+		for(i=0;i<want;i++) {
+			new_pages[i] = old_pages[i];
+		}
+		/* NOT HERE, we are outside the spinlock!
+		bm_free_pages(old_pages + want, have - want);
+		*/
+	}
+
+	return new_pages;
+}
+
+/*
  * called on driver init only. TODO call when a device is created.
  * allocates the drbd_bitmap, and stores it in mdev->bitmap.
  */
@@ -231,6 +394,7 @@
 	memset(b,0,sizeof(*b));
 	spin_lock_init(&b->bm_lock);
 	init_MUTEX(&b->bm_change);
+	init_waitqueue_head(&b->bm_io_wait);
 	mdev->bitmap = b;
 	return 0;
 }
@@ -251,7 +415,8 @@
 	 *
 	D_BUG_ON(mdev->bitmap->bm);
 	 */
-	vfree(mdev->bitmap->bm);
+	bm_free_pages(mdev->bitmap->bm_pages,mdev->bitmap->bm_number_of_pages);
+	vfree(mdev->bitmap->bm_pages);
 	kfree(mdev->bitmap);
 	mdev->bitmap = NULL;
 }
@@ -266,17 +431,25 @@
 	const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1;
 	size_t w = b->bm_bits >> LN2_BPL;
 	int cleared=0;
+	unsigned long *p_addr, *bm;
 
+	p_addr = bm_map_paddr(b,w);
+	bm = p_addr + MLPP(w);
 	if ( w < b->bm_words ) {
-		cleared = hweight_long(b->bm[w] & ~mask);
-		b->bm[w++] &= mask;
+		catch_oob_access_start();
+		cleared = hweight_long(*bm & ~mask);
+		*bm &= mask;
+		catch_oob_access_end();
+		w++; bm++;
 	}
 
 	if ( w < b->bm_words ) {
-		cleared += hweight_long(b->bm[w]);
-		b->bm[w++]=0;
+		catch_oob_access_start();
+		cleared += hweight_long(*bm);
+		*bm=0;
+		catch_oob_access_end();
 	}
-
+	bm_unmap(p_addr);
 	return cleared;
 }
 
@@ -284,31 +457,80 @@
 {
 	const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1;
 	size_t w = b->bm_bits >> LN2_BPL;
+	unsigned long *p_addr, *bm;
 
+	p_addr = bm_map_paddr(b,w);
+	bm = p_addr + MLPP(w);
 	if ( w < b->bm_words ) {
-		b->bm[w++] |= ~mask;
+		catch_oob_access_start();
+		*bm |= ~mask;
+		bm++; w++;
+		catch_oob_access_end();
 	}
 
 	if ( w < b->bm_words ) {
-		b->bm[w++] = ~(0UL);
+		catch_oob_access_start();
+		*bm = ~(0UL);
+		catch_oob_access_end();
 	}
+	bm_unmap(p_addr);
 }
 
-STATIC unsigned long bm_count_bits(struct drbd_bitmap * b)
+STATIC unsigned long bm_count_bits(struct drbd_bitmap * b, int just_read)
 {
-	unsigned long *bm = b->bm;
-	unsigned long *ep = b->bm + b->bm_words;
+	unsigned long *p_addr, *bm, offset = 0;
 	unsigned long bits = 0;
+	unsigned long i,do_now;
 
-	while ( bm < ep ) {
-		bits += hweight_long(*bm++);
+	while ( offset < b->bm_words ) {
+		i = do_now = min_t( size_t, b->bm_words-offset, LWPP );
+		p_addr = bm_map_paddr(b,offset);
+		bm = p_addr + MLPP(offset);
+		while(i--) {
+			catch_oob_access_start();
+			/* on little endian, this is *bm = *bm;
+			 * and should be optimized away by the compiler */
+			if (just_read) *bm = lel_to_cpu(*bm);
+			bits += hweight_long(*bm++);
+			catch_oob_access_end();
+		}
+		bm_unmap(p_addr);
+		offset += do_now;
 	}
 
 	return bits;
 }
 
-#define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512)
+/* offset and len in long words.*/
+STATIC void bm_memset(struct drbd_bitmap * b, size_t offset, int c, size_t len)
+{
+	unsigned long *p_addr, *bm;
+	size_t do_now, end;
 
+	end = offset+len;
+
+	if( end > b->bm_words ) {
+		printk(KERN_ALERT "drbd: bm_memset end > bm_words\n");
+		return;
+	}
+
+	while (offset < end) {
+		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
+		p_addr = bm_map_paddr(b,offset);
+		bm = p_addr + MLPP(offset);
+		catch_oob_access_start();
+		if ( bm+do_now > p_addr + LWPP ) {
+			printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n",
+					p_addr, bm, do_now);
+			break;
+		}
+		memset(bm,c,do_now*sizeof(long));
+		catch_oob_access_end();
+		bm_unmap(p_addr);
+		offset += do_now;
+	}
+}
+
 /*
  * make sure the bitmap has enough room for the attached storage,
  * if neccessary, resize.
@@ -320,7 +542,9 @@
 int drbd_bm_resize(drbd_dev *mdev, sector_t capacity)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long bits, bytes, words, *nbm, *obm = 0;
+	unsigned long bits, words, owords, obits, *p_addr, *bm;
+	unsigned long want, have, onpages; // number of pages
+	struct page **npages, **opages = NULL;
 	int err = 0, growing;
 
 	ERR_IF(!b) return -ENOMEM;
@@ -337,79 +561,89 @@
 
 	if (capacity == 0) {
 		spin_lock_irq(&b->bm_lock);
-		obm = b->bm;
-		b->bm = NULL;
+		opages = b->bm_pages;
+		onpages = b->bm_number_of_pages;
+		owords = b->bm_words;
+		b->bm_pages = NULL;
+		b->bm_number_of_pages =
 		b->bm_fo    =
 		b->bm_set   =
 		b->bm_bits  =
 		b->bm_words =
 		b->bm_dev_capacity = 0;
 		spin_unlock_irq(&b->bm_lock);
-		goto free_obm;
+		bm_free_pages(opages, onpages);
+		vfree(opages);
+		goto out;
+	}
+	bits  = BM_SECT_TO_BIT(ALIGN(capacity,BM_SECT_PER_BIT));
+
+	/* if we would use
+	   words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL;
+	   a 32bit host could present the wrong number of words
+	   to a 64bit host.
+	*/
+	words = ALIGN(bits,64) >> LN2_BPL;
+
+	D_ASSERT((u64)bits <= (((u64)mdev->bc->md.md_size_sect-MD_BM_OFFSET) << 12));
+
+	/* one extra long to catch off by one errors */
+	want = ALIGN( (words+1)*sizeof(long) ,PAGE_SIZE) >> PAGE_SHIFT;
+	have = b->bm_number_of_pages;
+	if (want == have) {
+		D_ASSERT(b->bm_pages != NULL);
+		npages = b->bm_pages;
 	} else {
-		bits = BM_SECT_TO_BIT(ALIGN(capacity,BM_SECTORS_PER_BIT));
-		DUMPI(bits);
+		npages = bm_realloc_pages(b->bm_pages,have,want);
+	}
 
-		/* if we would use
-		   words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL;
-		   a 32bit host could present the wrong number of words
-		   to a 64bit host.
-		*/
-		words = ALIGN(bits,64) >> LN2_BPL;
+	if (!npages) {
+		err = -ENOMEM;
+		goto out;
+	}
 
-		D_ASSERT((u64)bits <= (((u64)mdev->bc->md.md_size_sect-MD_BM_OFFSET) << 12));
+	spin_lock_irq(&b->bm_lock);
+	opages = b->bm_pages;
+	owords = b->bm_words;
+	obits  = b->bm_bits;
 
-		if ( words == b->bm_words ) {
-			/* optimize: capacity has changed,
-			 * but only within one long word worth of bits.
-			 * just update the bm_dev_capacity and bm_bits members.
-			 */
-			spin_lock_irq(&b->bm_lock);
-			b->bm_bits    = bits;
-			b->bm_dev_capacity = capacity;
-			b->bm_set -= bm_clear_surplus(b);
-			bm_end_info(mdev, __FUNCTION__ );
-			spin_unlock_irq(&b->bm_lock);
-			goto out;
-		} else {
-		        /* one extra long to catch off by one errors */
-			bytes = (words+1)*sizeof(long);
-			nbm = vmalloc(bytes);
-			if (!nbm) {
-				ERR("bitmap: failed to vmalloc %lu bytes\n",bytes);
-				err = -ENOMEM;
-				goto out;
-			}
-		}
-		spin_lock_irq(&b->bm_lock);
-		obm = b->bm;
-		// brgs. move several MB within spinlock...
-		// FIXME this should go into userspace!
-		if (obm) {
-			bm_set_surplus(b);
-			D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC);
-			memcpy(nbm,obm,min_t(size_t,b->bm_words,words)*sizeof(long));
-		}
-		growing = words > b->bm_words;
-		if (growing) { // set all newly allocated bits
-			// start at -1, just to be sure.
-			memset( nbm + (b->bm_words?:1)-1 , 0xff,
-				(words - ((b->bm_words?:1)-1)) * sizeof(long) );
-			b->bm_set  += bits - b->bm_bits;
-		}
-		nbm[words] = DRBD_MAGIC;
-		b->bm = nbm;
-		b->bm_bits  = bits;
-		b->bm_words = words;
-		b->bm_dev_capacity = capacity;
-		bm_clear_surplus(b);
-		if( !growing ) b->bm_set = bm_count_bits(b);
-		bm_end_info(mdev, __FUNCTION__ );
-		spin_unlock_irq(&b->bm_lock);
-		INFO("resync bitmap: bits=%lu words=%lu\n",bits,words);
+	growing = bits > obits;
+	if (opages) {
+		bm_set_surplus(b);
 	}
- free_obm:
-	vfree(obm); // vfree(NULL) is noop
+
+	b->bm_pages = npages;
+	b->bm_number_of_pages = want;
+	b->bm_bits  = bits;
+	b->bm_words = words;
+	b->bm_dev_capacity = capacity;
+
+	if( growing ) {
+		bm_memset(b,owords,0xff,words-owords);
+		b->bm_set += bits - obits;
+	}
+
+	if ( want < have ) {
+		/* implicit: (opages != NULL) && (opages != npages) */
+		bm_free_pages(opages + want, have - want);
+	}
+
+	p_addr = bm_map_paddr(b,words);
+	bm = p_addr + MLPP(words);
+	catch_oob_access_start();
+	*bm = DRBD_MAGIC;
+	catch_oob_access_end();
+	bm_unmap(p_addr);
+
+	(void)bm_clear_surplus(b);
+	if( !growing )
+		b->bm_set = bm_count_bits(b, 0 /* not just read */ );
+
+	bm_end_info(mdev, __FUNCTION__ );
+	spin_unlock_irq(&b->bm_lock);
+	if (opages != npages) vfree(opages);
+	INFO("resync bitmap: bits=%lu words=%lu\n",bits,words);
+
  out:
 	up(&b->bm_change);
 	return err;
@@ -430,6 +664,7 @@
 	unsigned long flags;
 
 	ERR_IF(!b) return 0;
+	ERR_IF(!b->bm_pages) return 0;
 	// MUST_BE_LOCKED(); well. yes. but ...
 
 	spin_lock_irqsave(&b->bm_lock,flags);
@@ -443,6 +678,7 @@
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	ERR_IF(!b) return 0;
+	ERR_IF(!b->bm_pages) return 0;
 
 	/* FIXME
 	 * actually yes. really. otherwise it could just change its size ...
@@ -460,34 +696,42 @@
 			unsigned long* buffer )
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *bm;
+	unsigned long *p_addr, *bm;
 	unsigned long word, bits;
-	size_t n = number;
+	size_t end, do_now;
 
-	if (number == 0) return;
+	end = offset + number;
+
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm) return;
-	D_BUG_ON(offset        >= b->bm_words);
-	D_BUG_ON(offset+number >  b->bm_words);
-	D_BUG_ON(number > PAGE_SIZE/sizeof(long));
+	ERR_IF(!b->bm_pages) return;
+	D_BUG_ON(offset >= b->bm_words);
+	D_BUG_ON(end    >  b->bm_words);
 
 	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
 	// BM_PARANOIA_CHECK(); no.
-	bm = b->bm + offset;
-	while(n--) {
-		bits = hweight_long(*bm);
-		word = *bm | lel_to_cpu(*buffer++);
-		*bm++ = word;
-		b->bm_set += hweight_long(word) - bits;
+	while(offset < end) {
+		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
+		p_addr = bm_map_paddr(b,offset);
+		bm = p_addr + MLPP(offset);
+		offset += do_now;
+		while(do_now--) {
+			catch_oob_access_start();
+			bits = hweight_long(*bm);
+			word = *bm | lel_to_cpu(*buffer++);
+			*bm++ = word;
+			b->bm_set += hweight_long(word) - bits;
+			catch_oob_access_end();
+		}
+		bm_unmap(p_addr);
 	}
 	/* with 32bit <-> 64bit cross-platform connect
 	 * this is only correct for current usage,
 	 * where we _know_ that we are 64 bit aligned,
 	 * and know that this function is used in this way, too...
 	 */
-	if (offset+number == b->bm_words) {
+	if (end == b->bm_words) {
 		b->bm_set -= bm_clear_surplus(b);
 		bm_end_info(mdev, __FUNCTION__ );
 	}
@@ -501,34 +745,42 @@
 		      unsigned long* buffer )
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *bm;
+	unsigned long *p_addr, *bm;
 	unsigned long word, bits;
-	size_t n = number;
+	size_t end, do_now;
 
-	if (number == 0) return;
+	end = offset + number;
+
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm) return;
-	D_BUG_ON(offset        >= b->bm_words);
-	D_BUG_ON(offset+number >  b->bm_words);
-	D_BUG_ON(number > PAGE_SIZE/sizeof(long));
+	ERR_IF(!b->bm_pages) return;
+	D_BUG_ON(offset >= b->bm_words);
+	D_BUG_ON(end    >  b->bm_words);
 
 	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
 	// BM_PARANOIA_CHECK(); no.
-	bm = b->bm + offset;
-	while(n--) {
-		bits = hweight_long(*bm);
-		word = lel_to_cpu(*buffer++);
-		*bm++ = word;
-		b->bm_set += hweight_long(word) - bits;
+	while(offset < end) {
+		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
+		p_addr = bm_map_paddr(b,offset);
+		bm = p_addr + MLPP(offset);
+		offset += do_now;
+		while(do_now--) {
+			catch_oob_access_start();
+			bits = hweight_long(*bm);
+			word = lel_to_cpu(*buffer++);
+			*bm++ = word;
+			b->bm_set += hweight_long(word) - bits;
+			catch_oob_access_end();
+		}
+		bm_unmap(p_addr);
 	}
 	/* with 32bit <-> 64bit cross-platform connect
 	 * this is only correct for current usage,
 	 * where we _know_ that we are 64 bit aligned,
 	 * and know that this function is used in this way, too...
 	 */
-	if (offset+number == b->bm_words) {
+	if (end == b->bm_words) {
 		b->bm_set -= bm_clear_surplus(b);
 		bm_end_info(mdev, __FUNCTION__ );
 	}
@@ -542,14 +794,16 @@
 		      unsigned long* buffer )
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *bm;
+	unsigned long *p_addr, *bm;
+	size_t end, do_now;
 
-	if (number == 0) return;
+	end = offset + number;
+
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm) return;
-	if ( (offset        >= b->bm_words) ||
-	     (offset+number >  b->bm_words) ||
-	     (number > PAGE_SIZE/sizeof(long)) ||
+	ERR_IF(!b->bm_pages) return;
+
+	if ( (offset >= b->bm_words) ||
+	     (end    >  b->bm_words) ||
 	     (number <= 0) ) {
 		// yes, there is "%z", but that gives compiler warnings...
 		ERR("offset=%lu number=%lu bm_words=%lu\n",
@@ -563,8 +817,18 @@
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
-	bm = b->bm + offset;
-	while(number--) *buffer++ = cpu_to_lel(*bm++);
+	while(offset < end) {
+		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
+		p_addr = bm_map_paddr(b,offset);
+		bm = p_addr + MLPP(offset);
+		offset += do_now;
+		while(do_now--) {
+			catch_oob_access_start();
+			*buffer++ = cpu_to_lel(*bm++);
+			catch_oob_access_end();
+		}
+		bm_unmap(p_addr);
+	}
 	spin_unlock_irq(&b->bm_lock);
 }
 
@@ -573,22 +837,62 @@
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm) return;
+	ERR_IF(!b->bm_pages) return;
 
-	D_BUG_ON(!b);
-	if (b->bm_bits == 0) return;
-	D_BUG_ON(!b->bm);
-
 	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
-	BM_PARANOIA_CHECK();
-	memset(b->bm,0xff,b->bm_words*sizeof(long));
-	bm_clear_surplus(b);
+	bm_memset(b,0,0xff,b->bm_words);
+	(void)bm_clear_surplus(b);
 	b->bm_set = b->bm_bits;
 	spin_unlock_irq(&b->bm_lock);
 }
 
+int drbd_bm_async_io_complete(struct bio *bio, unsigned int bytes_done, int error)
+{
+	struct drbd_bitmap *b = bio->bi_private;
+
+	if (bio->bi_size)
+		return 1;
+
+	if (error) {
+		/* doh. what now?
+		 * for now, set all bits, and flag MD_IO_ERROR
+		 */
+		/* FIXME kmap_atomic memset etc. pp. */
+		__set_bit(BM_MD_IO_ERROR,&b->bm_flags);
+	}
+	if (atomic_dec_and_test(&b->bm_async_io))
+		wake_up(&b->bm_io_wait);
+
+	bio_put(bio);
+
+	return 0;
+}
+
+STATIC void drbd_bm_page_io_async(drbd_dev *mdev, struct drbd_bitmap *b, int page_nr, int rw)
+{
+	/* we are process context. we always get a bio */
+	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	unsigned int len;
+	sector_t on_disk_sector = mdev->bc->md.md_offset + mdev->bc->md.bm_offset;
+	on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
+
+	/* this might happen with very small flexible external meta data device */
+	len = min_t(unsigned int, PAGE_SIZE,
+		(drbd_md_last_sector(mdev->bc) - on_disk_sector + 1)<<9);
+
+	D_DUMPLU(on_disk_sector);
+	D_DUMPI(len);
+
+	bio->bi_bdev = mdev->bc->md_bdev;
+	bio->bi_sector = on_disk_sector;
+	bio_add_page(bio, b->bm_pages[page_nr], len, 0);
+	bio->bi_private = b;
+	bio->bi_end_io = drbd_bm_async_io_complete;
+	submit_bio(rw, bio);
+}
+
 /* read one sector of the on disk bitmap into memory.
  * on disk bitmap is little endian.
  * @enr is _sector_ offset from start of on disk bitmap (aka bm-extent nr).
@@ -596,11 +900,13 @@
  */
 int drbd_bm_read_sect(drbd_dev *mdev,unsigned long enr)
 {
+	/* addition of sector_t/u64/s32... works anyways */
 	sector_t on_disk_sector = mdev->bc->md.md_offset + mdev->bc->md.bm_offset + enr;
 	int bm_words, num_words, offset, err  = 0;
 
 	// MUST_BE_LOCKED(); not neccessarily global ...
 
+	D_DUMPLU(on_disk_sector);
 	down(&mdev->md_io_mutex);
 	if(drbd_md_sync_page_io(mdev,mdev->bc,on_disk_sector,READ)) {
 		bm_words  = drbd_bm_words(mdev);
@@ -629,12 +935,50 @@
 
 /**
  * drbd_bm_read: Read the whole bitmap from its on disk location.
+ *
+ * currently only called from "drbd_ioctl_set_disk"
+ * FIXME need to be able to return an error!!
+ *
  */
-void drbd_bm_read(struct Drbd_Conf *mdev)
+# if defined(__LITTLE_ENDIAN)
+	/* nothing to do, on disk == in memory */
+# define bm_cpu_to_lel(x) ((void)0)
+# else
+void bm_cpu_to_lel(struct drbd_bitmap *b)
 {
+	/* need to cpu_to_lel all the pages ...
+	 * this may be optimized by using
+	 * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0;
+	 * the following is still not optimal, but better than nothing */
+	if (b->bm_set == 0) {
+		/* no page at all; avoid swap if all is 0 */
+		i = b->bm_number_of_pages;
+	} else if (b->bm_set == b->bm_bits) {
+		/* only the last page */
+		i = b->bm_number_of_pages -1;
+	} else {
+		/* all pages */
+		i = 0;
+	}
+	for (; i < b->bm_number_of_pages; i++) {
+		unsigned long *bm;
+		p_addr = kmap_atomic(b->bm_pages[i],KM_USER0)
+		for (bm = p_addr; bm < p_addr+PAGE_SIZE/sizeof(long); bm++) {
+			*bm = cpu_to_lel(*bm);
+		}
+		kunmap_atomic(p_addr);
+	}
+}
+# endif
+/* lel_to_cpu == cpu_to_lel */
+# define bm_lel_to_cpu(x) bm_cpu_to_lel(x)
+
+STATIC void drbd_bm_rw(struct Drbd_Conf *mdev, int rw)
+{
 	struct drbd_bitmap *b = mdev->bitmap;
-	sector_t sector;
-	int bm_words, num_sectors;
+	/* sector_t sector; */
+	int bm_words, num_sectors, i;
+	unsigned long now;
 	char ppb[10];
 
 	MUST_BE_LOCKED();
@@ -642,15 +986,62 @@
 	bm_words    = drbd_bm_words(mdev);
 	num_sectors = (bm_words*sizeof(long) + 511) >> 9;
 
-	for (sector = 0; sector < num_sectors; sector++) {
-		// FIXME do something on io error here?
-		drbd_bm_read_sect(mdev,sector);
+	/* OK, I manipulate the bitmap low level,
+	 * and I expect to be the exclusive user.
+	 * If not, I am really in a bad mood...
+	 * to catch such bugs early, make all people who want to access the
+	 * bitmap while I read it dereference a NULL pointer :->
+	 */
+	mdev->bitmap = NULL;
+
+	if(rw == WRITE)	bm_cpu_to_lel(b);
+
+	now = jiffies;
+	atomic_set(&b->bm_async_io, b->bm_number_of_pages);
+	for (i = 0; i < b->bm_number_of_pages; i++) {
+		/* let the layers below us try to merge these bios... */
+		drbd_bm_page_io_async(mdev,b,i,rw);
 	}
 
+	blk_run_queue(bdev_get_queue(mdev->bc->md_bdev));
+	wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0);
+	INFO("%s of bitmap took %lu jiffies\n",
+	     rw == READ ? "reading" : "writing", jiffies - now);
+
+	if (test_bit(BM_MD_IO_ERROR,&b->bm_flags)) {
+		/* FIXME correct handling of this.
+		 * detach?
+		 */
+		ALERT("we had at least one MD IO ERROR during bitmap IO\n");
+		drbd_chk_io_error(mdev, 1);
+		drbd_io_error(mdev);
+	}
+
+	now = jiffies;
+	/* just read, if neccessary adjust endianness */
+	if(rw == WRITE) {
+		bm_lel_to_cpu(b);
+	} else /* rw == READ */ {
+		b->bm_set = bm_count_bits(b, 1);
+		INFO("recounting of set bits took additional %lu jiffies\n", 
+		     jiffies - now);
+	}
+
+	/* ok, done,
+	 * now it is visible again
+	 */
+
+	mdev->bitmap = b;
+
 	INFO("%s marked out-of-sync by on disk bit-map.\n",
 	     ppsize(ppb,drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B-10)) );
 }
 
+void drbd_bm_read(struct Drbd_Conf *mdev)
+{
+	drbd_bm_rw(mdev, READ);
+}
+
 /**
  * drbd_bm_write_sect: Writes a 512 byte piece of the bitmap to its
  * on disk location. On disk bitmap is little endian.
@@ -678,6 +1069,7 @@
 	}
 	drbd_bm_get_lel( mdev, offset, num_words,
 			 page_address(mdev->md_io_page) );
+	D_DUMPLU(on_disk_sector);
 	if (!drbd_md_sync_page_io(mdev,mdev->bc,on_disk_sector,WRITE)) {
 		int i;
 		err = -EIO;
@@ -696,25 +1088,27 @@
 
 /**
  * drbd_bm_write: Write the whole bitmap to its on disk location.
+ *
+ * called at various occasions:
+ *
+int drbd_determin_dev_size(struct Drbd_Conf* mdev)
+int drbd_ioctl_set_disk(struct Drbd_Conf *mdev,
+			struct ioctl_disk_config * arg)
+	case DRBD_IOCTL_INVALIDATE:
+	case DRBD_IOCTL_INVALIDATE_REM:
+	case DRBD_IOCTL_SET_DISK_SIZE:
+int _drbd_send_bitmap(drbd_dev *mdev)
+STATIC int drbd_sync_handshake(drbd_dev *mdev, Drbd_Parameter_Packet *p)
+STATIC int receive_BecomeSyncTarget(drbd_dev *mdev, Drbd_Header *h)
+STATIC int receive_BecomeSyncSource(drbd_dev *mdev, Drbd_Header *h)
+STATIC int receive_param(drbd_dev *mdev, Drbd_Header *h)
+ *
+ * FIXME need to be able to return an error!!
  */
+
 void drbd_bm_write(struct Drbd_Conf *mdev)
 {
-	struct drbd_bitmap *b = mdev->bitmap;
-	sector_t sector;
-	int bm_words, num_sectors;
-
-	MUST_BE_LOCKED();
-
-	bm_words    = drbd_bm_words(mdev);
-	num_sectors = (bm_words*sizeof(long) + 511) >> 9;
-
-	for (sector = 0; sector < num_sectors; sector++) {
-		// FIXME do something on io error here?
-		drbd_bm_write_sect(mdev,sector);
-	}
-
-	INFO("%lu KB now marked out-of-sync by on disk bit-map.\n",
-	      drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B-10) );
+	drbd_bm_rw(mdev, WRITE);
 }
 
 /* clear all bits in the bitmap */
@@ -723,13 +1117,12 @@
 	struct drbd_bitmap *b = mdev->bitmap;
 
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm) return;
+	ERR_IF(!b->bm_pages) return;
 
-	MUST_BE_LOCKED();						\
+	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
-	BM_PARANOIA_CHECK();
-	memset(b->bm,0,b->bm_words*sizeof(long));
+	bm_memset(b,0,0x00,b->bm_words);
 	b->bm_set = 0;
 	spin_unlock_irq(&b->bm_lock);
 }
@@ -752,29 +1145,44 @@
 /* NOTE
  * find_first_bit returns int, we return unsigned long.
  * should not make much difference anyways, but ...
+ *
  * this returns a bit number, NOT a sector!
  */
+#define BPP_MASK ((1UL << (PAGE_SHIFT+3) ) - 1)
 unsigned long drbd_bm_find_next(drbd_dev *mdev)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	unsigned long i = -1UL;
+	unsigned long *p_addr;
+	unsigned long bit_offset; //bit offset of the mapped page.
 
 	ERR_IF(!b) return i;
-	ERR_IF(!b->bm) return i;
+	ERR_IF(!b->bm_pages) return i;
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
-	if (b->bm_fo < b->bm_bits) {
-		i = find_next_bit(b->bm,b->bm_bits,b->bm_fo);
-	} else if (b->bm_fo > b->bm_bits) {
+	if (b->bm_fo > b->bm_bits) {
 		ERR("bm_fo=%lu bm_bits=%lu\n",b->bm_fo, b->bm_bits);
-	}
-	if (i >= b->bm_bits) {
+	} else {
+		while (b->bm_fo < b->bm_bits) {
+			unsigned long offset;
+			bit_offset = b->bm_fo & ~BPP_MASK; // bit offset of the page
+			offset = bit_offset >> LN2_BPL;    // word offset of the page
+			p_addr = bm_map_paddr(b,offset);
+			i = find_next_bit(p_addr,PAGE_SIZE*8,b->bm_fo&BPP_MASK);
+			bm_unmap(p_addr);
+			if (i < PAGE_SIZE*8) {
+				i = bit_offset + i;
+				if( i >= b->bm_bits ) break;
+				b->bm_fo = i+1;
+				goto found;
+			}
+			b->bm_fo = bit_offset + PAGE_SIZE*8;
+		}
 		i = -1UL;
 		b->bm_fo = 0;
-	} else {
-		b->bm_fo = i+1;
 	}
+ found:
 	spin_unlock_irq(&b->bm_lock);
 	return i;
 }
@@ -795,7 +1203,6 @@
 	spin_unlock_irq(&b->bm_lock);
 }
 
-
 int drbd_bm_rs_done(drbd_dev *mdev)
 {
 	return mdev->bitmap->bm_fo == 0;
@@ -809,9 +1216,11 @@
 int drbd_bm_set_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
+	unsigned long *p_addr;
 	int i;
+
 	ERR_IF(!b) return 1;
-	ERR_IF(!b->bm) return 1;
+	ERR_IF(!b->bm_pages) return 1;
 
 /*
  * only called from drbd_set_out_of_sync.
@@ -831,7 +1240,10 @@
 		ERR("bitnr=%lu bm_bits=%lu\n",bitnr, b->bm_bits);
 		i = 0;
 	} else {
-		i = (0 != __test_and_set_bit(bitnr, b->bm));
+		unsigned long offset = bitnr>>LN2_BPL;
+		p_addr = bm_map_paddr(b,offset);
+		i = (0 != __test_and_set_bit(bitnr & BPP_MASK, p_addr));
+		bm_unmap(p_addr);
 		b->bm_set += !i;
 	}
 	spin_unlock_irq(&b->bm_lock);
@@ -844,10 +1256,12 @@
 int drbd_bm_clear_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
+	unsigned long *p_addr;
 	unsigned long flags;
 	int i;
+
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm) return 0;
+	ERR_IF(!b->bm_pages) return 0;
 
 	spin_lock_irqsave(&b->bm_lock,flags);
 	BM_PARANOIA_CHECK();
@@ -856,7 +1270,10 @@
 		ERR("bitnr=%lu bm_bits=%lu\n",bitnr, b->bm_bits);
 		i = 0;
 	} else {
-		i = (0 != __test_and_clear_bit(bitnr, b->bm));
+		unsigned long offset = bitnr>>LN2_BPL;
+		p_addr = bm_map_paddr(b,offset);
+		i = (0 != __test_and_clear_bit(bitnr & BPP_MASK, p_addr));
+		bm_unmap(p_addr);
 		b->bm_set -= i;
 	}
 	spin_unlock_irqrestore(&b->bm_lock,flags);
@@ -882,14 +1299,19 @@
 int drbd_bm_test_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
+	unsigned long *p_addr;
 	int i;
+
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm) return 0;
+	ERR_IF(!b->bm_pages) return 0;
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
 	if (bitnr < b->bm_bits) {
-		i = test_bit(bitnr, b->bm);
+		unsigned long offset = bitnr>>LN2_BPL;
+		p_addr = bm_map_paddr(b,offset);
+		i = test_bit(bitnr & BPP_MASK, p_addr);
+		bm_unmap(p_addr);
 	} else if (bitnr == b->bm_bits) {
 		i = -1;
 	} else /* (bitnr > b->bm_bits) */ {
@@ -920,9 +1342,11 @@
 	struct drbd_bitmap *b = mdev->bitmap;
 	int count, s, e;
 	unsigned long flags;
+	unsigned long *p_addr, *bm;
 
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm) return 0;
+	ERR_IF(!b->bm_pages) return 0;
+
 	spin_lock_irqsave(&b->bm_lock,flags);
 	BM_PARANOIA_CHECK();
 
@@ -930,9 +1354,15 @@
 	e = min((size_t)S2W(enr+1),b->bm_words);
 	count = 0;
 	if (s < b->bm_words) {
-		const unsigned long* w = b->bm+s;
 		int n = e-s;
-		while (n--) count += hweight_long(*w++);
+		p_addr = bm_map_paddr(b,s);
+		bm = p_addr + MLPP(s);
+		while (n--) {
+			catch_oob_access_start();
+			count += hweight_long(*bm++);
+			catch_oob_access_end();
+		}
+		bm_unmap(p_addr);
 	} else {
 		ERR("start offset (%d) too large in drbd_bm_e_weight\n", s);
 	}
@@ -947,10 +1377,11 @@
 unsigned long drbd_bm_ALe_set_all(drbd_dev *mdev, unsigned long al_enr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
+	unsigned long *p_addr, *bm;
 	unsigned long weight;
-	int count, s, e;
+	int count, s, e, i, do_now;
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm) return 0;
+	ERR_IF(!b->bm_pages) return 0;
 
 	MUST_BE_LOCKED();
 
@@ -960,14 +1391,23 @@
 
 	s = al_enr * BM_WORDS_PER_AL_EXT;
 	e = min_t(size_t, s + BM_WORDS_PER_AL_EXT, b->bm_words);
+	/* assert that s and e are on the same page */
+	D_ASSERT(  (e-1) >> (PAGE_SHIFT - LN2_BPL + 3)
+		==  s    >> (PAGE_SHIFT - LN2_BPL + 3) );
 	count = 0;
 	if (s < b->bm_words) {
-		const unsigned long* w = b->bm+s;
-		int n = e-s;
-		while (n--) count += hweight_long(*w++);
-		n = e-s;
-		memset(b->bm+s,-1,n*sizeof(long));
-		b->bm_set += n*BITS_PER_LONG - count;
+		i = do_now = e-s;
+		p_addr = bm_map_paddr(b,s);
+		bm = p_addr + MLPP(s);
+		while (i--) {
+			catch_oob_access_start();
+			count += hweight_long(*bm);
+			*bm = -1UL;
+			catch_oob_access_end();
+			bm++;
+		}
+		bm_unmap(p_addr);
+		b->bm_set += do_now*BITS_PER_LONG - count;
 		if (e == b->bm_words) {
 			b->bm_set -= bm_clear_surplus(b);
 		}

Modified: trunk/drbd/drbd_compat_wrappers.h
===================================================================
--- trunk/drbd/drbd_compat_wrappers.h	2006-03-03 15:38:34 UTC (rev 2089)
+++ trunk/drbd/drbd_compat_wrappers.h	2006-03-03 15:47:52 UTC (rev 2090)
@@ -7,6 +7,14 @@
 # error "use a 2.6 kernel, please"
 #endif
 
+
+/* struct page has a union since 2.6.15 ... */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#define U_PRIVATE private
+#else
+#define U_PRIVATE u.private
+#endif
+
 #include <linux/buffer_head.h> // for fsync_bdev
 
 /* see get_sb_bdev and bd_claim */

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-03-03 15:38:34 UTC (rev 2089)
+++ trunk/drbd/drbd_int.h	2006-03-03 15:47:52 UTC (rev 2090)
@@ -116,6 +116,19 @@
 
 #define DUMPST(A) DUMPLLU((unsigned long long)(A))
 
+#if 0
+#define D_DUMPP(A)   DUMPP(A)
+#define D_DUMPLU(A)  DUMPLU(A)
+#define D_DUMPLLU(A) DUMPLLU(A)
+#define D_DUMPLX(A)  DUMPLX(A)
+#define D_DUMPI(A)   DUMPI(A)
+#else
+#define D_DUMPP(A)
+#define D_DUMPLU(A)
+#define D_DUMPLLU(A)
+#define D_DUMPLX(A)
+#define D_DUMPI(A)
+#endif
 
 // Info: do not remove the spaces around the "," before ##
 //       Otherwise this is not portable from gcc-2.95 to gcc-3.3

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-03 15:38:34 UTC (rev 2089)
+++ trunk/drbd/drbd_main.c	2006-03-03 15:47:52 UTC (rev 2090)
@@ -1929,7 +1929,7 @@
 
 	while(drbd_pp_pool) {
 		page = drbd_pp_pool;
-		drbd_pp_pool = (struct page*)page->private;
+		drbd_pp_pool = (struct page*)page->U_PRIVATE;
 		__free_page(page);
 		drbd_pp_vacant--;
 	}
@@ -1998,7 +1998,7 @@
 	for (i=0;i< number;i++) {
 		page = alloc_page(GFP_HIGHUSER);
 		if(!page) goto Enomem;
-		page->private = (unsigned long)drbd_pp_pool;
+		page->U_PRIVATE = (unsigned long)drbd_pp_pool;
 		drbd_pp_pool = page;
 	}
 	drbd_pp_vacant = number;

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-03 15:38:34 UTC (rev 2089)
+++ trunk/drbd/drbd_receiver.c	2006-03-03 15:47:52 UTC (rev 2090)
@@ -52,7 +52,7 @@
 #include <linux/drbd.h>
 #include "drbd_int.h"
 
-#ifdef __arch_um__
+#if defined(__arch_um__) && !defined(HAVE_UML_TO_VIRT)
 void *to_virt(unsigned long phys)
 {
 	return((void *) uml_physmem + phys);
@@ -136,7 +136,7 @@
 	/* first, use our pool. */
 	spin_lock(&drbd_pp_lock);
 	if ( (page = drbd_pp_pool) ) {
-		drbd_pp_pool = (struct page*)page->private;
+		drbd_pp_pool = (struct page*)page->U_PRIVATE;
 		drbd_pp_vacant--;
 	}
 	spin_unlock(&drbd_pp_lock);
@@ -150,7 +150,7 @@
 		/* try the pool again, maybe the drbd_kick_log set some free */
 		spin_lock(&drbd_pp_lock);
 		if ( (page = drbd_pp_pool) ) {
-			drbd_pp_pool = (struct page*)page->private;
+			drbd_pp_pool = (struct page*)page->U_PRIVATE;
 			drbd_pp_vacant--;
 		}
 		spin_unlock(&drbd_pp_lock);
@@ -192,7 +192,7 @@
 	if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
 		__free_page(page);
 	} else {
-		page->private = (unsigned long)drbd_pp_pool;
+		page->U_PRIVATE = (unsigned long)drbd_pp_pool;
 		drbd_pp_pool = page;
 		drbd_pp_vacant++;
 	}

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-03-03 15:38:34 UTC (rev 2089)
+++ trunk/drbd/linux/drbd_config.h	2006-03-03 15:47:52 UTC (rev 2090)
@@ -26,6 +26,9 @@
 #define API_VERSION 80
 #define PRO_VERSION 80
 
+// 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_SPINLOCKS   // enables MUST_HOLD macro (assertions for spinlocks)

From drbd-cvs at lists.linbit.com  Fri Mar  3 23:39:30 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Mar  3 23:39:31 2006
Subject: [DRBD-cvs] svn commit by lars - r2091 - trunk/drbd - named union ->
	anonymous union in 2.6.16... lalala
Message-ID: <20060303223930.32D3E168DC@mail.linbit.com>

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

Author: lars
Date: 2006-03-03 23:39:29 +0100 (Fri, 03 Mar 2006)
New Revision: 2091

Modified:
   trunk/drbd/drbd_compat_wrappers.h
Log:
named union -> anonymous union in 2.6.16... lalala

Modified: trunk/drbd/drbd_compat_wrappers.h
===================================================================
--- trunk/drbd/drbd_compat_wrappers.h	2006-03-03 15:47:52 UTC (rev 2090)
+++ trunk/drbd/drbd_compat_wrappers.h	2006-03-03 22:39:29 UTC (rev 2091)
@@ -8,8 +8,9 @@
 #endif
 
 
-/* struct page has a union since 2.6.15 ... */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+/* struct page has a union in 2.6.15 ...
+ * an anonymous union and struct since 2.6.16 */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
 #define U_PRIVATE private
 #else
 #define U_PRIVATE u.private

From drbd-cvs at lists.linbit.com  Mon Mar  6 15:00:42 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Mar  6 15:00:43 2006
Subject: [DRBD-cvs] svn commit by phil - r2093 - in branches/drbd-0.7: .
	debian drbd/linux - Preparing the 0.7.17 release 
Message-ID: <20060306140042.73CAD1687C@mail.linbit.com>

Author: phil
Date: 2006-03-06 15:00:35 +0100 (Mon, 06 Mar 2006)
New Revision: 2093

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


Modified: branches/drbd-0.7/ChangeLog
===================================================================
--- branches/drbd-0.7/ChangeLog	2006-03-06 10:46:13 UTC (rev 2092)
+++ branches/drbd-0.7/ChangeLog	2006-03-06 14:00:35 UTC (rev 2093)
@@ -1,9 +1,18 @@
 Latest:
 ------
- ChangeLog last updated: r2014 2005-12-19
+ ChangeLog last updated: r2085 2006-03-06
  Cumulative changes since last tarball.
  For even more detail, use "svn log" and "svn diff".
 
+0.7.17 (api:77/proto:74)
+-----
+ * There was a bug that could cause the activity log to be not applied 
+   after a primary crash, when an other size than 127 elements was configured.
+ * There was a bug in the activity log code, that could cause that the
+   latest update to the AL is omitted at recovery time.
+ * The "Marked additional XXKB as out-of-synced based on AL." message
+   showed one one eighth of the real amount, fixed.
+
 0.7.16 (api:77/proto:74)
 -----
  * DRBD no longer shrinks an consistent device if it gets connected to

Modified: branches/drbd-0.7/debian/changelog
===================================================================
--- branches/drbd-0.7/debian/changelog	2006-03-06 10:46:13 UTC (rev 2092)
+++ branches/drbd-0.7/debian/changelog	2006-03-06 14:00:35 UTC (rev 2093)
@@ -1,3 +1,9 @@
+drbd (0.7.17-0) unstable; urgency=low
+
+  * New upstream release
+
+ -- Philipp Reisner <phil@linbit.com>  Mon, 6 Mar 2006 14:43:00 +0200
+
 drbd (0.7.16-0) unstable; urgency=low
 
   * New upstream release

Modified: branches/drbd-0.7/drbd/linux/drbd_config.h
===================================================================
--- branches/drbd-0.7/drbd/linux/drbd_config.h	2006-03-06 10:46:13 UTC (rev 2092)
+++ branches/drbd-0.7/drbd/linux/drbd_config.h	2006-03-06 14:00:35 UTC (rev 2093)
@@ -22,7 +22,7 @@
 
 extern const char * drbd_buildtag(void);
 
-#define REL_VERSION "0.7.16"
+#define REL_VERSION "0.7.17"
 #define API_VERSION 77
 #define PRO_VERSION 74
 

Modified: branches/drbd-0.7/drbd.spec.in
===================================================================
--- branches/drbd-0.7/drbd.spec.in	2006-03-06 10:46:13 UTC (rev 2092)
+++ branches/drbd-0.7/drbd.spec.in	2006-03-06 14:00:35 UTC (rev 2093)
@@ -190,6 +190,15 @@
 /sbin/depmod -a -F /boot/System.map-%{kernelversion} %{kernelversion} >/dev/null 2>&1 || true
 
 %changelog
+* Mon Mar  6 2006 14:43:41 +0200 Philipp Reisner <phil@linbit.com>
+- drbd (0.7.17-1)
+ * There was a bug that could cause the activity log to be not applied 
+   after a primary crash, when an other size than 127 elements was configured.
+ * There was a bug in the activity log code, that could cause that the
+   latest update to the AL is omitted at recovery time.
+ * The "Marked additional XXKB as out-of-synced based on AL." message
+   showed one one eighth of the real amount, fixed.
+
 * Mon Feb 13 2006 15:52:00 +0200 Philipp Reisner <phil@linbit.com>
 - drbd (0.7.16-1)
  * DRBD no longer shrinks an consistent device if it gets connected to

From drbd-cvs at lists.linbit.com  Mon Mar  6 15:01:52 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Mar  6 15:01:53 2006
Subject: [DRBD-cvs] svn commit by phil - r2094 - tags - First try to tag
	0.7.17 
Message-ID: <20060306140153.0E0181687C@mail.linbit.com>

Author: phil
Date: 2006-03-06 15:01:52 +0100 (Mon, 06 Mar 2006)
New Revision: 2094

Added:
   tags/drbd-0.7.17/
Log:
First try to tag 0.7.17


Copied: tags/drbd-0.7.17 (from rev 2093, branches/drbd-0.7)

From drbd-cvs at lists.linbit.com  Tue Mar  7 11:24:33 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Mar  7 11:24:35 2006
Subject: [DRBD-cvs] svn commit by phil - r2098 - in trunk: . drbd - drbd8
	now has all bugfixes from the stable branch up to
Message-ID: <20060307102433.805A21687C@mail.linbit.com>

Author: phil
Date: 2006-03-07 11:24:32 +0100 (Tue, 07 Mar 2006)
New Revision: 2098

Modified:
   trunk/
   trunk/drbd/drbd_int.h
Log:
drbd8 now has all bugfixes from the stable branch up to drbd-0.7.17



Property changes on: trunk
___________________________________________________________________
Name: propagate:at
   - 2083
   + 2097

Modified: trunk/drbd/drbd_int.h
===================================================================
--- trunk/drbd/drbd_int.h	2006-03-07 10:17:25 UTC (rev 2097)
+++ trunk/drbd/drbd_int.h	2006-03-07 10:24:32 UTC (rev 2098)
@@ -906,7 +906,7 @@
 #define MD_HARDSECT      (1<<MD_HARDSECT_B)
 
 // activity log
-#define AL_EXTENTS_PT    (MD_HARDSECT-12)/8-1 // 61 ; Extents per 512B sector
+#define AL_EXTENTS_PT    ((MD_HARDSECT-12)/8-1) // 61 ; Extents per 512B sector
 #define AL_EXTENT_SIZE_B 22      // One extent represents 4M Storage
 #define AL_EXTENT_SIZE (1<<AL_EXTENT_SIZE_B)
 

From drbd-cvs at lists.linbit.com  Wed Mar  8 11:40:25 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Mar  8 11:40:26 2006
Subject: [DRBD-cvs] svn commit by phil - r2105 - trunk/drbd - * Fixed an
	SMP/preemption lockup. We need to take the d
Message-ID: <20060308104025.BFA2615EA7@mail.linbit.com>

Author: phil
Date: 2006-03-08 11:40:24 +0100 (Wed, 08 Mar 2006)
New Revision: 2105

Modified:
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_worker.c
Log:
* Fixed an SMP/preemption lockup. We need to take the drbd_pp_lock IRQ
  save in drbd_pp_alloc(), becuase we call drbd_pp_free() from IRQ 
  context later on.
    
* Fixed the counting of the epoch_size on the receiver, grumbl. Lars!



Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-07 13:26:14 UTC (rev 2104)
+++ trunk/drbd/drbd_receiver.c	2006-03-08 10:40:24 UTC (rev 2105)
@@ -125,6 +125,7 @@
  */
 STATIC struct page * drbd_pp_alloc(drbd_dev *mdev, unsigned int gfp_mask)
 {
+	unsigned long flags=0;
 	struct page *page;
 	DEFINE_WAIT(wait);
 
@@ -133,13 +134,14 @@
 	 * not make sense.
 	 */
 
-	/* first, use our pool. */
-	spin_lock(&drbd_pp_lock);
+	spin_lock_irqsave(&drbd_pp_lock,flags);
+	/* This lock needs to be IRQ save because we might call drdb_pp_free()
+	   from IRQ context. */
 	if ( (page = drbd_pp_pool) ) {
 		drbd_pp_pool = (struct page*)page->U_PRIVATE;
 		drbd_pp_vacant--;
 	}
-	spin_unlock(&drbd_pp_lock);
+	spin_unlock_irqrestore(&drbd_pp_lock,flags);
 	if (page) goto got_page;
 
 	drbd_kick_lo(mdev);
@@ -148,12 +150,12 @@
 		prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
 
 		/* try the pool again, maybe the drbd_kick_log set some free */
-		spin_lock(&drbd_pp_lock);
+		spin_lock_irqsave(&drbd_pp_lock,flags);
 		if ( (page = drbd_pp_pool) ) {
 			drbd_pp_pool = (struct page*)page->U_PRIVATE;
 			drbd_pp_vacant--;
 		}
-		spin_unlock(&drbd_pp_lock);
+		spin_unlock_irqrestore(&drbd_pp_lock,flags);
 
 		if (page) break;
 
@@ -188,18 +190,24 @@
 
 STATIC void drbd_pp_free(drbd_dev *mdev,struct page *page)
 {
-	spin_lock(&drbd_pp_lock);
+	unsigned long flags=0;
+	int free_it;
+
+	spin_lock_irqsave(&drbd_pp_lock,flags);
 	if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
-		__free_page(page);
+		free_it = 1;
 	} else {
 		page->U_PRIVATE = (unsigned long)drbd_pp_pool;
 		drbd_pp_pool = page;
 		drbd_pp_vacant++;
+		free_it = 0;
 	}
-	spin_unlock(&drbd_pp_lock);
+	spin_unlock_irqrestore(&drbd_pp_lock,flags);
 
 	atomic_dec(&mdev->pp_in_use);
 
+	if(free_it) __free_page(page);
+
 	/*
 	 * FIXME
 	 * typically there are no waiters.

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-03-07 13:26:14 UTC (rev 2104)
+++ trunk/drbd/drbd_worker.c	2006-03-08 10:40:24 UTC (rev 2105)
@@ -102,6 +102,7 @@
 	struct Tl_epoch_entry *e=NULL;
 	struct Drbd_Conf* mdev;
 	int do_wake;
+	int is_syncer_req;
 
 	e = bio->bi_private;
 	mdev = e->mdev;
@@ -113,11 +114,13 @@
 	D_ASSERT(e->block_id != ID_VACANT);
 
 	spin_lock_irqsave(&mdev->ee_lock,flags);
-	mdev->epoch_size++;
+	is_syncer_req = is_syncer_block_id(e->block_id);
 	list_del(&e->w.list);
 	list_add_tail(&e->w.list,&mdev->done_ee);
 
-	do_wake = is_syncer_block_id(e->block_id)
+	if(!is_syncer_req) mdev->epoch_size++;
+
+	do_wake = is_syncer_req
 		? list_empty(&mdev->sync_ee)
 		: list_empty(&mdev->active_ee);
 
@@ -371,7 +374,7 @@
 		inc_rs_pending(mdev);
 		if(!drbd_send_drequest(mdev,RSDataRequest,
 				       sector,size,ID_SYNCER)) {
-			ERR("drbd_send_drequest() failed, aborting...");
+			ERR("drbd_send_drequest() failed, aborting...\n");
 			dec_rs_pending(mdev);
 			return 0; // FAILED. worker will abort!
 		}

From drbd-cvs at lists.linbit.com  Wed Mar  8 12:13:38 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Mar  8 12:13:39 2006
Subject: [DRBD-cvs] svn commit by phil - r2106 - trunk/drbd - Fixed an other
	trivial SMP lockup. 
Message-ID: <20060308111338.AA8E215EA7@mail.linbit.com>

Author: phil
Date: 2006-03-08 12:13:37 +0100 (Wed, 08 Mar 2006)
New Revision: 2106

Modified:
   trunk/drbd/drbd_main.c
Log:
Fixed an other trivial SMP lockup. 


Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-08 10:40:24 UTC (rev 2105)
+++ trunk/drbd/drbd_main.c	2006-03-08 11:13:37 UTC (rev 2106)
@@ -722,7 +722,7 @@
 			ascw->os = os;
 			ascw->ns = ns;
 			ascw->w.cb = w_after_state_ch;
-			drbd_queue_work_front(mdev,&mdev->data.work,&ascw->w);
+			_drbd_queue_work_front(&mdev->data.work,&ascw->w);
 		} else {
 			WARN("Could not kmalloc an ascw\n");
 		}

From drbd-cvs at lists.linbit.com  Wed Mar  8 13:14:02 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Wed Mar  8 13:14:04 2006
Subject: [DRBD-cvs] svn commit by lars - r2107 - in branches/drbd-0.7: .
	drbd drbd/linux - * make rpm no longer builds source packages
Message-ID: <20060308121402.9117315EA7@mail.linbit.com>

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

Author: lars
Date: 2006-03-08 13:14:01 +0100 (Wed, 08 Mar 2006)
New Revision: 2107

Modified:
   branches/drbd-0.7/Makefile
   branches/drbd-0.7/drbd/drbd_receiver.c
   branches/drbd-0.7/drbd/linux/drbd_config.h
Log:
* make rpm no longer builds source packages
* uml to_virt finnally is available


Modified: branches/drbd-0.7/Makefile
===================================================================
--- branches/drbd-0.7/Makefile	2006-03-08 11:13:37 UTC (rev 2106)
+++ branches/drbd-0.7/Makefile	2006-03-08 12:14:01 UTC (rev 2107)
@@ -188,7 +188,7 @@
 	       -e "s/^\(Packager:\).*/\1 $(USER)@$(HOSTNAME)/;" < drbd.spec.in \
 	   > dist/SPECS/drbd.spec ; \
 	fi
-	$(RPMBUILD) -ba \
+	$(RPMBUILD) -bb \
 	    --define "_topdir $(PWD)/dist" \
 	    --define "buildroot $(PWD)/dist/install" \
 	    --define "kernelversion $(KVER)" \

Modified: branches/drbd-0.7/drbd/drbd_receiver.c
===================================================================
--- branches/drbd-0.7/drbd/drbd_receiver.c	2006-03-08 11:13:37 UTC (rev 2106)
+++ branches/drbd-0.7/drbd/drbd_receiver.c	2006-03-08 12:14:01 UTC (rev 2107)
@@ -57,8 +57,8 @@
 
 #define is_syncer_blk(A,B) ((B)==ID_SYNCER)
 
-#ifdef __arch_um__
-void *to_virt(unsigned long phys)
+#if defined(__arch_um__) && !defined(HAVE_UML_TO_VIRT)
+static inline void *to_virt(unsigned long phys)
 {
 	return((void *) uml_physmem + phys);
 }

Modified: branches/drbd-0.7/drbd/linux/drbd_config.h
===================================================================
--- branches/drbd-0.7/drbd/linux/drbd_config.h	2006-03-08 11:13:37 UTC (rev 2106)
+++ branches/drbd-0.7/drbd/linux/drbd_config.h	2006-03-08 12:14:01 UTC (rev 2107)
@@ -65,4 +65,8 @@
 // for troubles.
 // #define DRBD_DISABLE_SENDPAGE
 
+// older, unpached kernel sources do not have it, so we added it in drbd_receiver.c
+// but more recent kernels define it in arch/um/include/mem.h
+#define HAVE_UML_TO_VIRT
+
 #endif

From drbd-cvs at lists.linbit.com  Fri Mar 10 12:07:47 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Mar 10 12:07:49 2006
Subject: [DRBD-cvs] svn commit by phil - r2110 - trunk/drbd - Added some
	(disabled) debug code, that could be usefull
Message-ID: <20060310110748.16C1D167D3@mail.linbit.com>

Author: phil
Date: 2006-03-10 12:07:46 +0100 (Fri, 10 Mar 2006)
New Revision: 2110

Modified:
   trunk/drbd/drbd_actlog.c
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_proc.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/lru_cache.c
   trunk/drbd/lru_cache.h
Log:
Added some (disabled) debug code, that could be usefull later on
as well.


Modified: trunk/drbd/drbd_actlog.c
===================================================================
--- trunk/drbd/drbd_actlog.c	2006-03-08 12:33:07 UTC (rev 2109)
+++ trunk/drbd/drbd_actlog.c	2006-03-10 11:07:46 UTC (rev 2110)
@@ -591,7 +591,7 @@
 				      int cleared)
 {
 	struct list_head *le, *tmp;
-	struct bm_extent* ext;
+	struct bm_extent* ext, *ext1;
 	struct update_odbm_work * udw;
 
 	unsigned int enr;
@@ -640,25 +640,34 @@
 	}
 
 	list_for_each_safe(le,tmp,&mdev->resync->lru) {
-		ext=(struct bm_extent *)list_entry(le,struct lc_element,list);
-		if(ext->rs_left == 0) {
+		ext1=(struct bm_extent *)list_entry(le,struct lc_element,list);
+		if(ext1->rs_left == 0) {
+			if(ext1 == ext) ext=NULL;
 			udw=kmalloc(sizeof(*udw),GFP_ATOMIC);
 			if(!udw) {
 				WARN("Could not kmalloc an udw\n");
 				break;
 			}
-			udw->enr = ext->lce.lc_number;
+			udw->enr = ext1->lce.lc_number;
 			udw->w.cb = w_update_odbm;
 			drbd_queue_work_front(mdev,&mdev->data.work,&udw->w);
-			if (ext->flags != 0) {
+			if (ext1->flags != 0) {
 				WARN("deleting resync lce: %d[%u;%02lx]\n",
-				     ext->lce.lc_number, ext->rs_left,
-				     ext->flags);
-				ext->flags = 0;
+				     ext1->lce.lc_number, ext1->rs_left,
+				     ext1->flags);
+				ext1->flags = 0;
 			}
-			lc_del(mdev->resync,&ext->lce);
+			lc_del(mdev->resync,&ext1->lce);
 		}
 	}
+
+	if(ext) {
+		if (ext->rs_left == 0) {
+			ERR("BUG! missed lc_number:%u refcnt: %u\n",
+			    ext->lce.lc_number,
+			    ext->lce.refcnt);
+		}
+	}
 }
 
 /* clear the bit corresponding to the piece of storage in question:

Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-08 12:33:07 UTC (rev 2109)
+++ trunk/drbd/drbd_main.c	2006-03-10 11:07:46 UTC (rev 2110)
@@ -2180,6 +2180,9 @@
 	printk(KERN_ERR "AL_EXTENTS_PT = %d\n",AL_EXTENTS_PT);
 	printk(KERN_ERR "DRBD_MAX_SECTORS = %llu\n",DRBD_MAX_SECTORS);
 	printk(KERN_ERR "DRBD_MAX_SECTORS_FLEX = %llu\n",DRBD_MAX_SECTORS_FLEX);
+#define OOF(t,m) printk(KERN_ERR "offsetof("#t","#m") = %d\n", offsetof(t,m))
+	OOF(struct Drbd_Conf,bitmap);
+	//OOF(struct drbd_bitmap,bm_set);
 	return -EBUSY;
 #endif
 #ifdef __arch_um__

Modified: trunk/drbd/drbd_proc.c
===================================================================
--- trunk/drbd/drbd_proc.c	2006-03-08 12:33:07 UTC (rev 2109)
+++ trunk/drbd/drbd_proc.c	2006-03-10 11:07:46 UTC (rev 2110)
@@ -160,7 +160,18 @@
 	seq_printf(seq," K/sec\n");
 }
 
+#if 0
+STATIC void resync_dump_detail(struct seq_file *seq, struct lc_element * e)
+{
+	struct bm_extent *bme = (struct bm_extent *)e;
 
+	seq_printf(seq,"%5d %s %s\n",bme->rs_left,
+		   bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
+		   bme->flags & BME_LOCKED ? "LOCKED" : "------"
+		   );
+}
+#endif
+
 STATIC int drbd_seq_show(struct seq_file *seq, void *v)
 {
 	int i;
@@ -221,6 +232,13 @@
 		if(drbd_conf[i].act_log) {
 			lc_printf_stats(seq,drbd_conf[i].act_log);
 		}
+#if 0
+		if(drbd_conf[i].resync) {
+			lc_dump(drbd_conf[i].resync,seq,"rs_left",
+				resync_dump_detail);
+		}
+#endif
+
 	}
 
 	return 0;

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-08 12:33:07 UTC (rev 2109)
+++ trunk/drbd/drbd_receiver.c	2006-03-10 11:07:46 UTC (rev 2110)
@@ -1076,8 +1076,6 @@
 						    1);
 				dec_unacked(mdev);
 			}
-			/* FIXME
-			 * explain why we need this SYNC_STARTED flag bit */
 			if (test_bit(SYNC_STARTED,&mdev->flags) )
 				drbd_set_in_sync(mdev,sector,drbd_ee_get_size(e));
 		} else {
@@ -1110,8 +1108,6 @@
 	if(mdev->net_conf->wire_protocol == DRBD_PROT_C) {
 		if(likely(drbd_bio_uptodate(e->private_bio))) {
 			ok &= drbd_send_ack(mdev,WriteAck,e);
-			/* FIXME
-			 * explain why we need this SYNC_STARTED flag bit */
 			if (test_bit(SYNC_STARTED,&mdev->flags))
 				drbd_set_in_sync(mdev,sector,drbd_ee_get_size(e));
 		} else {

Modified: trunk/drbd/lru_cache.c
===================================================================
--- trunk/drbd/lru_cache.c	2006-03-08 12:33:07 UTC (rev 2109)
+++ trunk/drbd/lru_cache.c	2006-03-10 11:07:46 UTC (rev 2110)
@@ -313,3 +313,29 @@
 	list_move(&e->list, e->refcnt ? &lc->in_use : &lc->lru);
 }
 
+#if 0
+/**
+ * lc_dump: Dump a complete LRU cache to seq in textual form.
+ */
+void lc_dump(struct lru_cache* lc, struct seq_file *seq, char* utext,
+	     void (*detail) (struct seq_file *, struct lc_element *) )
+{
+	unsigned int nr_elements = lc->nr_elements;
+	struct lc_element *e;
+	int i;
+
+	seq_printf(seq,"\tnn: lc_number refcnt %s\n ",utext);
+	for(i=0;i<nr_elements;i++) {
+		e = lc_entry(lc,i);
+		if( e->lc_number == LC_FREE ) {
+			seq_printf(seq,"\t%2d: FREE\n",i );
+		} else {
+			seq_printf(seq,"\t%2d: %4u %4u    ", i, 
+				   e->lc_number,
+				   e->refcnt );
+			detail(seq,e);
+		}
+	}
+}
+
+#endif

Modified: trunk/drbd/lru_cache.h
===================================================================
--- trunk/drbd/lru_cache.h	2006-03-08 12:33:07 UTC (rev 2109)
+++ trunk/drbd/lru_cache.h	2006-03-10 11:07:46 UTC (rev 2110)
@@ -110,6 +110,9 @@
 struct seq_file;
 extern size_t lc_printf_stats(struct seq_file *seq, struct lru_cache* lc);
 
+void lc_dump(struct lru_cache* lc, struct seq_file *seq, char* utext,
+	     void (*detail) (struct seq_file *, struct lc_element *) );
+
 /* This can be used to stop lc_get from changing the set of active elements.
  * Note that the reference counts and order on the lru list may still change.
  * returns true if we aquired the lock.

From drbd-cvs at lists.linbit.com  Sat Mar 11 16:59:28 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sat Mar 11 16:59:28 2006
Subject: [DRBD-cvs] svn commit by lars - r2111 - branches/drbd-0.7/drbd -
	maybe that's what deadlocks the stress test of Frank?
Message-ID: <20060311155928.4C68B163F3@mail.linbit.com>

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

Author: lars
Date: 2006-03-11 16:59:27 +0100 (Sat, 11 Mar 2006)
New Revision: 2111

Modified:
   branches/drbd-0.7/drbd/drbd_actlog.c
Log:
maybe that's what deadlocks the stress test of Frank?

Modified: branches/drbd-0.7/drbd/drbd_actlog.c
===================================================================
--- branches/drbd-0.7/drbd/drbd_actlog.c	2006-03-10 11:07:46 UTC (rev 2110)
+++ branches/drbd-0.7/drbd/drbd_actlog.c	2006-03-11 15:59:27 UTC (rev 2111)
@@ -64,7 +64,7 @@
 STATIC int _drbd_md_sync_page_io(drbd_dev *mdev, struct page *page, 
 				 sector_t sector, int rw, int size)
 {
-	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	struct bio *bio = bio_alloc(GFP_NOIO, 1);
 	struct completion event;
 	int ok;
 

From drbd-cvs at lists.linbit.com  Sun Mar 12 09:38:31 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sun Mar 12 09:38:33 2006
Subject: [DRBD-cvs] svn commit by phil - r2112 - trunk/drbd - With the first
	try of the async bitmap stuff, the
Message-ID: <20060312083831.0051D163F3@mail.linbit.com>

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

Author: phil
Date: 2006-03-12 09:38:31 +0100 (Sun, 12 Mar 2006)
New Revision: 2112

Modified:
   trunk/drbd/drbd_bitmap.c
Log:
With the first try of the async bitmap stuff, the
syncer was no longer terminating. Lets start over
with the sync bitmap stuff...


Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-11 15:59:27 UTC (rev 2111)
+++ trunk/drbd/drbd_bitmap.c	2006-03-12 08:38:31 UTC (rev 2112)
@@ -29,7 +29,6 @@
 #include <linux/bitops.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h> // for memset
-#include <linux/swap.h>   // for total_swapcache_pages
 
 #include <linux/drbd.h>
 #include "drbd_int.h"
@@ -58,13 +57,12 @@
 
 /*
  * NOTE
- *  Access to the *bm_pages is protected by bm_lock.
+ *  Access to the *bm is protected by bm_lock.
  *  It is safe to read the other members within the lock.
  *
  *  drbd_bm_set_bit is called from bio_endio callbacks,
  *  so there we need a spin_lock_irqsave.
  *  Everywhere else we need a spin_lock_irq.
- *  And we need the kmap_atomic :-(
  *
  * FIXME
  *  Actually you need to serialize all resize operations.
@@ -80,28 +78,17 @@
  *  than have two resize operations interfere somewhen.
  */
 struct drbd_bitmap {
-	struct page **bm_pages;
+	unsigned long *bm;
 	spinlock_t bm_lock;
-	/* WARNING unsigned long bm_fo and friends:
-	 * 32bit number of bit offset is just enough for 512 MB bitmap.
-	 * it will blow up if we make the bitmap bigger...
-	 * not that it makes much sense to have a bitmap that large,
-	 * rather change the granularity to 16k or 64k or something.
-	 */
 	unsigned long bm_fo;        // next offset for drbd_bm_find_next
 	unsigned long bm_set;       // nr of set bits; THINK maybe atomic_t ?
 	unsigned long bm_bits;
 	size_t   bm_words;
-	size_t   bm_number_of_pages;
 	sector_t bm_dev_capacity;
 	struct semaphore bm_change; // serializes resize operations
 
-	atomic_t bm_async_io;
-	wait_queue_head_t bm_io_wait;
-
-	unsigned long  bm_flags;
-
 	// { REMOVE
+	unsigned long  bm_flags;     // currently debugging aid only
 	unsigned long  bm_line;
 	char          *bm_file;
 	// }
@@ -109,9 +96,7 @@
 
 // { REMOVE once we serialize all state changes properly
 #define D_BUG_ON(x)	ERR_IF(x) { dump_stack(); }
-#define BM_LOCKED      0
-#define BM_MD_IO_ERROR (BITS_PER_LONG-1) // 31? 63?
-
+#define BM_LOCKED 0
 #if 0 // simply disabled for now...
 #define MUST_NOT_BE_LOCKED() do {					\
 	if (test_bit(BM_LOCKED,&b->bm_flags)) {				\
@@ -173,6 +158,7 @@
 // has been very helpful to indicate that rs_total and rs_left have been
 // used in a non-smp safe way...
 #define BM_PARANOIA_CHECK() do {						\
+	D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC);				\
 	D_ASSERT(b->bm_dev_capacity == drbd_get_capacity(mdev->this_bdev));	\
 	if ( (b->bm_set != mdev->rs_total) &&					\
 	     (b->bm_set != mdev->rs_left) ) {					\
@@ -185,6 +171,7 @@
 } while (0)
 #else
 #define BM_PARANOIA_CHECK() do {					\
+	D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC);			\
 	if (b->bm_dev_capacity != drbd_get_capacity(mdev->this_bdev)) {	\
 		ERR("%s:%d: bm_dev_capacity:%llu drbd_get_capacity:%llu\n", \
 		__FILE__, __LINE__,					\
@@ -197,7 +184,6 @@
 
 #if DUMP_MD >= 3
 /* debugging aid */
-#error "FIXME"
 STATIC void bm_end_info(drbd_dev *mdev, const char* where)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
@@ -216,52 +202,9 @@
 #define bm_end_info(ignored...)	((void)(0))
 #endif
 
-#if 0
-#define catch_oob_access_start() do {	\
-	do {				\
-		if ((bm-p_addr) >= PAGE_SIZE/sizeof(long)) { \
-			printk(KERN_ALERT "drbd_bitmap.c:%u %s: p_addr:%p bm:%p %d\n", \
-					__LINE__ , __func__ , p_addr, bm, (bm-p_addr)); \
-			break;		\
-		}
-#define catch_oob_access_end()	\
-	} while(0); } while (0)
-#else
-#define catch_oob_access_start() ((void)0)
-#define catch_oob_access_end() ((void)0)
-#endif
-
-/* word offset to long pointer */
-STATIC unsigned long * bm_map_paddr(struct drbd_bitmap* b, unsigned long offset)
-{
-	struct page * page;
-	unsigned long page_nr;
-
-	// page_nr = (word*sizeof(long)) >> PAGE_SHIFT;
-	page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3);
-	BUG_ON(page_nr >= b->bm_number_of_pages);
-	page = b->bm_pages[page_nr];
-
-	return (unsigned long*) kmap_atomic(page,KM_USER0);
-}
-
-STATIC void bm_unmap(unsigned long *p_addr) {
-	kunmap_atomic(p_addr, KM_USER0);
-};
-
 /* long word offset of _bitmap_ sector */
 #define S2W(s)	((s)<<(BM_EXT_SIZE_B-BM_BLOCK_SIZE_B-LN2_BPL))
-/* word offset from start of bitmap to word number _in_page_
- * modulo longs per page
-#define MLPP(X) ((X) % (PAGE_SIZE/sizeof(long))
- hm, well, Philipp thinks gcc might not optimze the % into & (... - 1)
- so do it explicitly:
- */
-#define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
 
-/* Long words per page */
-#define LWPP (PAGE_SIZE/sizeof(long))
-
 /*
  * actually most functions herein should take a struct drbd_bitmap*, not a
  * drbd_dev*, but for the debug macros I like to have the mdev around
@@ -274,113 +217,7 @@
  * But it is NOT strictly ok.
  */
 
-STATIC void bm_free_pages(struct page ** pages, unsigned long number)
-{
-	unsigned long i;
-	if (!pages)
-		return;
-
-	for(i=0;i<number;i++) {
-		if (!pages[i]) {
-			printk(KERN_ALERT "drbd: bm_free_pages tried to free "
-					  "a NULL pointer; i=%lu n=%lu\n",
-					  i, number);
-			continue;
-		}
-		__free_page(pages[i]);
-		pages[i] = NULL;
-	}
-}
-
 /*
- * "have" and "want" are NUMBER OF PAGES.
- */
-STATIC struct page ** bm_realloc_pages(struct page ** old_pages,
-				       unsigned long have,
-				       unsigned long want)
-{
-	struct page** new_pages, *page;
-	unsigned int i, bytes;
-
-	BUG_ON(have == 0 && old_pages != NULL);
-	BUG_ON(have != 0 && old_pages == NULL);
-
-	if (have == want)
-		return old_pages;
-
-	/* don't even try if it is likely to be too much */
-	if (want > have) {
-		unsigned long nfree, nleft;
-		nfree = nr_free_pages();
-		nleft = nfree + get_page_cache_size()-total_swapcache_pages;
-
-		if (nleft <= (want-have)) {
-			printk(KERN_ALERT "drbd: bm_realloc_pages: OOM!\n");
-			return NULL;
-		}
-
-		nleft -= (want-have);
-
-		/* protect me agains the infamous oom killer.
-		 * FIXME sorry, now it does no longer work on embeded boxes with less than 16MB main ram :-)
-		 */
-		if ( nleft < (10 << (20 - PAGE_SHIFT)) ) {
-			printk(KERN_ALERT "drbd: bm_realloc_pages would have left less than 10MB ram free; OOM!\n");
-			printk(KERN_ALERT "drbd: free:%lu buf+cache:%lu want:%lu have:%lu left:%lu\n"
-			,	nfree
-			,	get_page_cache_size()-total_swapcache_pages
-			,	want, have, nleft
-			);
-			return NULL;
-		}
-	}
-
-	/* To use kmalloc here is ok, as long as we support 4TB at max...
-	 * otherwise this might become bigger than 128KB, which is
-	 * the maximum for kmalloc.
-	 *
-	 * no, it is not: on 64bit boxes, sizeof(void*) == 8,
-	 * 128MB bitmap @ 4K pages -> 256K of page pointers.
-	 * ==> use vmalloc for now again.
-	 * then again, we could do something like
-	 *   if (nr_pages > watermark) vmalloc else kmalloc :*> ...
-	 * or do cascading page arrays:
-	 *   one page for the page array of the page array,
-	 *   those pages for the real bitmap pages.
-	 *   there we could even add some optimization members,
-	 *   so we won't need to kmap_atomic in bm_find_next_bit just to see
-	 *   that the page has no bits set ...
-	 */
-	bytes = sizeof(struct page*)*want;
-	new_pages = vmalloc(bytes);
-	if(!new_pages) return NULL;
-
-	memset(new_pages,0,bytes);
-	if( want >= have ) {
-		for(i=0;i<have;i++) {
-			new_pages[i] = old_pages[i];
-		}
-		for(;i<want;i++) {
-			if ( !(page = alloc_page(GFP_HIGHUSER)) ) {
-				bm_free_pages(new_pages + have, i - have);
-				vfree(new_pages);
-				return NULL;
-			}
-			new_pages[i] = page;
-		}
-	} else {
-		for(i=0;i<want;i++) {
-			new_pages[i] = old_pages[i];
-		}
-		/* NOT HERE, we are outside the spinlock!
-		bm_free_pages(old_pages + want, have - want);
-		*/
-	}
-
-	return new_pages;
-}
-
-/*
  * called on driver init only. TODO call when a device is created.
  * allocates the drbd_bitmap, and stores it in mdev->bitmap.
  */
@@ -394,7 +231,6 @@
 	memset(b,0,sizeof(*b));
 	spin_lock_init(&b->bm_lock);
 	init_MUTEX(&b->bm_change);
-	init_waitqueue_head(&b->bm_io_wait);
 	mdev->bitmap = b;
 	return 0;
 }
@@ -415,8 +251,7 @@
 	 *
 	D_BUG_ON(mdev->bitmap->bm);
 	 */
-	bm_free_pages(mdev->bitmap->bm_pages,mdev->bitmap->bm_number_of_pages);
-	vfree(mdev->bitmap->bm_pages);
+	vfree(mdev->bitmap->bm);
 	kfree(mdev->bitmap);
 	mdev->bitmap = NULL;
 }
@@ -431,25 +266,17 @@
 	const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1;
 	size_t w = b->bm_bits >> LN2_BPL;
 	int cleared=0;
-	unsigned long *p_addr, *bm;
 
-	p_addr = bm_map_paddr(b,w);
-	bm = p_addr + MLPP(w);
 	if ( w < b->bm_words ) {
-		catch_oob_access_start();
-		cleared = hweight_long(*bm & ~mask);
-		*bm &= mask;
-		catch_oob_access_end();
-		w++; bm++;
+		cleared = hweight_long(b->bm[w] & ~mask);
+		b->bm[w++] &= mask;
 	}
 
 	if ( w < b->bm_words ) {
-		catch_oob_access_start();
-		cleared += hweight_long(*bm);
-		*bm=0;
-		catch_oob_access_end();
+		cleared += hweight_long(b->bm[w]);
+		b->bm[w++]=0;
 	}
-	bm_unmap(p_addr);
+
 	return cleared;
 }
 
@@ -457,80 +284,31 @@
 {
 	const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1;
 	size_t w = b->bm_bits >> LN2_BPL;
-	unsigned long *p_addr, *bm;
 
-	p_addr = bm_map_paddr(b,w);
-	bm = p_addr + MLPP(w);
 	if ( w < b->bm_words ) {
-		catch_oob_access_start();
-		*bm |= ~mask;
-		bm++; w++;
-		catch_oob_access_end();
+		b->bm[w++] |= ~mask;
 	}
 
 	if ( w < b->bm_words ) {
-		catch_oob_access_start();
-		*bm = ~(0UL);
-		catch_oob_access_end();
+		b->bm[w++] = ~(0UL);
 	}
-	bm_unmap(p_addr);
 }
 
-STATIC unsigned long bm_count_bits(struct drbd_bitmap * b, int just_read)
+STATIC unsigned long bm_count_bits(struct drbd_bitmap * b)
 {
-	unsigned long *p_addr, *bm, offset = 0;
+	unsigned long *bm = b->bm;
+	unsigned long *ep = b->bm + b->bm_words;
 	unsigned long bits = 0;
-	unsigned long i,do_now;
 
-	while ( offset < b->bm_words ) {
-		i = do_now = min_t( size_t, b->bm_words-offset, LWPP );
-		p_addr = bm_map_paddr(b,offset);
-		bm = p_addr + MLPP(offset);
-		while(i--) {
-			catch_oob_access_start();
-			/* on little endian, this is *bm = *bm;
-			 * and should be optimized away by the compiler */
-			if (just_read) *bm = lel_to_cpu(*bm);
-			bits += hweight_long(*bm++);
-			catch_oob_access_end();
-		}
-		bm_unmap(p_addr);
-		offset += do_now;
+	while ( bm < ep ) {
+		bits += hweight_long(*bm++);
 	}
 
 	return bits;
 }
 
-/* offset and len in long words.*/
-STATIC void bm_memset(struct drbd_bitmap * b, size_t offset, int c, size_t len)
-{
-	unsigned long *p_addr, *bm;
-	size_t do_now, end;
+#define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512)
 
-	end = offset+len;
-
-	if( end > b->bm_words ) {
-		printk(KERN_ALERT "drbd: bm_memset end > bm_words\n");
-		return;
-	}
-
-	while (offset < end) {
-		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
-		p_addr = bm_map_paddr(b,offset);
-		bm = p_addr + MLPP(offset);
-		catch_oob_access_start();
-		if ( bm+do_now > p_addr + LWPP ) {
-			printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n",
-					p_addr, bm, do_now);
-			break;
-		}
-		memset(bm,c,do_now*sizeof(long));
-		catch_oob_access_end();
-		bm_unmap(p_addr);
-		offset += do_now;
-	}
-}
-
 /*
  * make sure the bitmap has enough room for the attached storage,
  * if neccessary, resize.
@@ -542,9 +320,7 @@
 int drbd_bm_resize(drbd_dev *mdev, sector_t capacity)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long bits, words, owords, obits, *p_addr, *bm;
-	unsigned long want, have, onpages; // number of pages
-	struct page **npages, **opages = NULL;
+	unsigned long bits, bytes, words, *nbm, *obm = 0;
 	int err = 0, growing;
 
 	ERR_IF(!b) return -ENOMEM;
@@ -561,89 +337,79 @@
 
 	if (capacity == 0) {
 		spin_lock_irq(&b->bm_lock);
-		opages = b->bm_pages;
-		onpages = b->bm_number_of_pages;
-		owords = b->bm_words;
-		b->bm_pages = NULL;
-		b->bm_number_of_pages =
+		obm = b->bm;
+		b->bm = NULL;
 		b->bm_fo    =
 		b->bm_set   =
 		b->bm_bits  =
 		b->bm_words =
 		b->bm_dev_capacity = 0;
 		spin_unlock_irq(&b->bm_lock);
-		bm_free_pages(opages, onpages);
-		vfree(opages);
-		goto out;
-	}
-	bits  = BM_SECT_TO_BIT(ALIGN(capacity,BM_SECT_PER_BIT));
-
-	/* if we would use
-	   words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL;
-	   a 32bit host could present the wrong number of words
-	   to a 64bit host.
-	*/
-	words = ALIGN(bits,64) >> LN2_BPL;
-
-	D_ASSERT((u64)bits <= (((u64)mdev->bc->md.md_size_sect-MD_BM_OFFSET) << 12));
-
-	/* one extra long to catch off by one errors */
-	want = ALIGN( (words+1)*sizeof(long) ,PAGE_SIZE) >> PAGE_SHIFT;
-	have = b->bm_number_of_pages;
-	if (want == have) {
-		D_ASSERT(b->bm_pages != NULL);
-		npages = b->bm_pages;
+		goto free_obm;
 	} else {
-		npages = bm_realloc_pages(b->bm_pages,have,want);
-	}
+		bits = BM_SECT_TO_BIT(ALIGN(capacity,BM_SECTORS_PER_BIT));
+		DUMPI(bits);
 
-	if (!npages) {
-		err = -ENOMEM;
-		goto out;
-	}
+		/* if we would use
+		   words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL;
+		   a 32bit host could present the wrong number of words
+		   to a 64bit host.
+		*/
+		words = ALIGN(bits,64) >> LN2_BPL;
 
-	spin_lock_irq(&b->bm_lock);
-	opages = b->bm_pages;
-	owords = b->bm_words;
-	obits  = b->bm_bits;
+		D_ASSERT((u64)bits <= (((u64)mdev->bc->md.md_size_sect-MD_BM_OFFSET) << 12));
 
-	growing = bits > obits;
-	if (opages) {
-		bm_set_surplus(b);
+		if ( words == b->bm_words ) {
+			/* optimize: capacity has changed,
+			 * but only within one long word worth of bits.
+			 * just update the bm_dev_capacity and bm_bits members.
+			 */
+			spin_lock_irq(&b->bm_lock);
+			b->bm_bits    = bits;
+			b->bm_dev_capacity = capacity;
+			b->bm_set -= bm_clear_surplus(b);
+			bm_end_info(mdev, __FUNCTION__ );
+			spin_unlock_irq(&b->bm_lock);
+			goto out;
+		} else {
+		        /* one extra long to catch off by one errors */
+			bytes = (words+1)*sizeof(long);
+			nbm = vmalloc(bytes);
+			if (!nbm) {
+				ERR("bitmap: failed to vmalloc %lu bytes\n",bytes);
+				err = -ENOMEM;
+				goto out;
+			}
+		}
+		spin_lock_irq(&b->bm_lock);
+		obm = b->bm;
+		// brgs. move several MB within spinlock...
+		// FIXME this should go into userspace!
+		if (obm) {
+			bm_set_surplus(b);
+			D_ASSERT(b->bm[b->bm_words] == DRBD_MAGIC);
+			memcpy(nbm,obm,min_t(size_t,b->bm_words,words)*sizeof(long));
+		}
+		growing = words > b->bm_words;
+		if (growing) { // set all newly allocated bits
+			// start at -1, just to be sure.
+			memset( nbm + (b->bm_words?:1)-1 , 0xff,
+				(words - ((b->bm_words?:1)-1)) * sizeof(long) );
+			b->bm_set  += bits - b->bm_bits;
+		}
+		nbm[words] = DRBD_MAGIC;
+		b->bm = nbm;
+		b->bm_bits  = bits;
+		b->bm_words = words;
+		b->bm_dev_capacity = capacity;
+		bm_clear_surplus(b);
+		if( !growing ) b->bm_set = bm_count_bits(b);
+		bm_end_info(mdev, __FUNCTION__ );
+		spin_unlock_irq(&b->bm_lock);
+		INFO("resync bitmap: bits=%lu words=%lu\n",bits,words);
 	}
-
-	b->bm_pages = npages;
-	b->bm_number_of_pages = want;
-	b->bm_bits  = bits;
-	b->bm_words = words;
-	b->bm_dev_capacity = capacity;
-
-	if( growing ) {
-		bm_memset(b,owords,0xff,words-owords);
-		b->bm_set += bits - obits;
-	}
-
-	if ( want < have ) {
-		/* implicit: (opages != NULL) && (opages != npages) */
-		bm_free_pages(opages + want, have - want);
-	}
-
-	p_addr = bm_map_paddr(b,words);
-	bm = p_addr + MLPP(words);
-	catch_oob_access_start();
-	*bm = DRBD_MAGIC;
-	catch_oob_access_end();
-	bm_unmap(p_addr);
-
-	(void)bm_clear_surplus(b);
-	if( !growing )
-		b->bm_set = bm_count_bits(b, 0 /* not just read */ );
-
-	bm_end_info(mdev, __FUNCTION__ );
-	spin_unlock_irq(&b->bm_lock);
-	if (opages != npages) vfree(opages);
-	INFO("resync bitmap: bits=%lu words=%lu\n",bits,words);
-
+ free_obm:
+	vfree(obm); // vfree(NULL) is noop
  out:
 	up(&b->bm_change);
 	return err;
@@ -664,7 +430,6 @@
 	unsigned long flags;
 
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm_pages) return 0;
 	// MUST_BE_LOCKED(); well. yes. but ...
 
 	spin_lock_irqsave(&b->bm_lock,flags);
@@ -678,7 +443,6 @@
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm_pages) return 0;
 
 	/* FIXME
 	 * actually yes. really. otherwise it could just change its size ...
@@ -696,42 +460,34 @@
 			unsigned long* buffer )
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr, *bm;
+	unsigned long *bm;
 	unsigned long word, bits;
-	size_t end, do_now;
+	size_t n = number;
 
-	end = offset + number;
-
+	if (number == 0) return;
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm_pages) return;
-	D_BUG_ON(offset >= b->bm_words);
-	D_BUG_ON(end    >  b->bm_words);
+	ERR_IF(!b->bm) return;
+	D_BUG_ON(offset        >= b->bm_words);
+	D_BUG_ON(offset+number >  b->bm_words);
+	D_BUG_ON(number > PAGE_SIZE/sizeof(long));
 
 	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
 	// BM_PARANOIA_CHECK(); no.
-	while(offset < end) {
-		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
-		p_addr = bm_map_paddr(b,offset);
-		bm = p_addr + MLPP(offset);
-		offset += do_now;
-		while(do_now--) {
-			catch_oob_access_start();
-			bits = hweight_long(*bm);
-			word = *bm | lel_to_cpu(*buffer++);
-			*bm++ = word;
-			b->bm_set += hweight_long(word) - bits;
-			catch_oob_access_end();
-		}
-		bm_unmap(p_addr);
+	bm = b->bm + offset;
+	while(n--) {
+		bits = hweight_long(*bm);
+		word = *bm | lel_to_cpu(*buffer++);
+		*bm++ = word;
+		b->bm_set += hweight_long(word) - bits;
 	}
 	/* with 32bit <-> 64bit cross-platform connect
 	 * this is only correct for current usage,
 	 * where we _know_ that we are 64 bit aligned,
 	 * and know that this function is used in this way, too...
 	 */
-	if (end == b->bm_words) {
+	if (offset+number == b->bm_words) {
 		b->bm_set -= bm_clear_surplus(b);
 		bm_end_info(mdev, __FUNCTION__ );
 	}
@@ -745,42 +501,34 @@
 		      unsigned long* buffer )
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr, *bm;
+	unsigned long *bm;
 	unsigned long word, bits;
-	size_t end, do_now;
+	size_t n = number;
 
-	end = offset + number;
-
+	if (number == 0) return;
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm_pages) return;
-	D_BUG_ON(offset >= b->bm_words);
-	D_BUG_ON(end    >  b->bm_words);
+	ERR_IF(!b->bm) return;
+	D_BUG_ON(offset        >= b->bm_words);
+	D_BUG_ON(offset+number >  b->bm_words);
+	D_BUG_ON(number > PAGE_SIZE/sizeof(long));
 
 	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
 	// BM_PARANOIA_CHECK(); no.
-	while(offset < end) {
-		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
-		p_addr = bm_map_paddr(b,offset);
-		bm = p_addr + MLPP(offset);
-		offset += do_now;
-		while(do_now--) {
-			catch_oob_access_start();
-			bits = hweight_long(*bm);
-			word = lel_to_cpu(*buffer++);
-			*bm++ = word;
-			b->bm_set += hweight_long(word) - bits;
-			catch_oob_access_end();
-		}
-		bm_unmap(p_addr);
+	bm = b->bm + offset;
+	while(n--) {
+		bits = hweight_long(*bm);
+		word = lel_to_cpu(*buffer++);
+		*bm++ = word;
+		b->bm_set += hweight_long(word) - bits;
 	}
 	/* with 32bit <-> 64bit cross-platform connect
 	 * this is only correct for current usage,
 	 * where we _know_ that we are 64 bit aligned,
 	 * and know that this function is used in this way, too...
 	 */
-	if (end == b->bm_words) {
+	if (offset+number == b->bm_words) {
 		b->bm_set -= bm_clear_surplus(b);
 		bm_end_info(mdev, __FUNCTION__ );
 	}
@@ -794,16 +542,14 @@
 		      unsigned long* buffer )
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr, *bm;
-	size_t end, do_now;
+	unsigned long *bm;
 
-	end = offset + number;
-
+	if (number == 0) return;
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm_pages) return;
-
-	if ( (offset >= b->bm_words) ||
-	     (end    >  b->bm_words) ||
+	ERR_IF(!b->bm) return;
+	if ( (offset        >= b->bm_words) ||
+	     (offset+number >  b->bm_words) ||
+	     (number > PAGE_SIZE/sizeof(long)) ||
 	     (number <= 0) ) {
 		// yes, there is "%z", but that gives compiler warnings...
 		ERR("offset=%lu number=%lu bm_words=%lu\n",
@@ -817,18 +563,8 @@
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
-	while(offset < end) {
-		do_now = min_t(size_t,ALIGN(offset+1,LWPP),end) - offset;
-		p_addr = bm_map_paddr(b,offset);
-		bm = p_addr + MLPP(offset);
-		offset += do_now;
-		while(do_now--) {
-			catch_oob_access_start();
-			*buffer++ = cpu_to_lel(*bm++);
-			catch_oob_access_end();
-		}
-		bm_unmap(p_addr);
-	}
+	bm = b->bm + offset;
+	while(number--) *buffer++ = cpu_to_lel(*bm++);
 	spin_unlock_irq(&b->bm_lock);
 }
 
@@ -837,62 +573,22 @@
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm_pages) return;
+	ERR_IF(!b->bm) return;
 
+	D_BUG_ON(!b);
+	if (b->bm_bits == 0) return;
+	D_BUG_ON(!b->bm);
+
 	MUST_BE_LOCKED();
 
 	spin_lock_irq(&b->bm_lock);
-	bm_memset(b,0,0xff,b->bm_words);
-	(void)bm_clear_surplus(b);
+	BM_PARANOIA_CHECK();
+	memset(b->bm,0xff,b->bm_words*sizeof(long));
+	bm_clear_surplus(b);
 	b->bm_set = b->bm_bits;
 	spin_unlock_irq(&b->bm_lock);
 }
 
-int drbd_bm_async_io_complete(struct bio *bio, unsigned int bytes_done, int error)
-{
-	struct drbd_bitmap *b = bio->bi_private;
-
-	if (bio->bi_size)
-		return 1;
-
-	if (error) {
-		/* doh. what now?
-		 * for now, set all bits, and flag MD_IO_ERROR
-		 */
-		/* FIXME kmap_atomic memset etc. pp. */
-		__set_bit(BM_MD_IO_ERROR,&b->bm_flags);
-	}
-	if (atomic_dec_and_test(&b->bm_async_io))
-		wake_up(&b->bm_io_wait);
-
-	bio_put(bio);
-
-	return 0;
-}
-
-STATIC void drbd_bm_page_io_async(drbd_dev *mdev, struct drbd_bitmap *b, int page_nr, int rw)
-{
-	/* we are process context. we always get a bio */
-	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
-	unsigned int len;
-	sector_t on_disk_sector = mdev->bc->md.md_offset + mdev->bc->md.bm_offset;
-	on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
-
-	/* this might happen with very small flexible external meta data device */
-	len = min_t(unsigned int, PAGE_SIZE,
-		(drbd_md_last_sector(mdev->bc) - on_disk_sector + 1)<<9);
-
-	D_DUMPLU(on_disk_sector);
-	D_DUMPI(len);
-
-	bio->bi_bdev = mdev->bc->md_bdev;
-	bio->bi_sector = on_disk_sector;
-	bio_add_page(bio, b->bm_pages[page_nr], len, 0);
-	bio->bi_private = b;
-	bio->bi_end_io = drbd_bm_async_io_complete;
-	submit_bio(rw, bio);
-}
-
 /* read one sector of the on disk bitmap into memory.
  * on disk bitmap is little endian.
  * @enr is _sector_ offset from start of on disk bitmap (aka bm-extent nr).
@@ -900,13 +596,11 @@
  */
 int drbd_bm_read_sect(drbd_dev *mdev,unsigned long enr)
 {
-	/* addition of sector_t/u64/s32... works anyways */
 	sector_t on_disk_sector = mdev->bc->md.md_offset + mdev->bc->md.bm_offset + enr;
 	int bm_words, num_words, offset, err  = 0;
 
 	// MUST_BE_LOCKED(); not neccessarily global ...
 
-	D_DUMPLU(on_disk_sector);
 	down(&mdev->md_io_mutex);
 	if(drbd_md_sync_page_io(mdev,mdev->bc,on_disk_sector,READ)) {
 		bm_words  = drbd_bm_words(mdev);
@@ -935,50 +629,12 @@
 
 /**
  * drbd_bm_read: Read the whole bitmap from its on disk location.
- *
- * currently only called from "drbd_ioctl_set_disk"
- * FIXME need to be able to return an error!!
- *
  */
-# if defined(__LITTLE_ENDIAN)
-	/* nothing to do, on disk == in memory */
-# define bm_cpu_to_lel(x) ((void)0)
-# else
-void bm_cpu_to_lel(struct drbd_bitmap *b)
+void drbd_bm_read(struct Drbd_Conf *mdev)
 {
-	/* need to cpu_to_lel all the pages ...
-	 * this may be optimized by using
-	 * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0;
-	 * the following is still not optimal, but better than nothing */
-	if (b->bm_set == 0) {
-		/* no page at all; avoid swap if all is 0 */
-		i = b->bm_number_of_pages;
-	} else if (b->bm_set == b->bm_bits) {
-		/* only the last page */
-		i = b->bm_number_of_pages -1;
-	} else {
-		/* all pages */
-		i = 0;
-	}
-	for (; i < b->bm_number_of_pages; i++) {
-		unsigned long *bm;
-		p_addr = kmap_atomic(b->bm_pages[i],KM_USER0)
-		for (bm = p_addr; bm < p_addr+PAGE_SIZE/sizeof(long); bm++) {
-			*bm = cpu_to_lel(*bm);
-		}
-		kunmap_atomic(p_addr);
-	}
-}
-# endif
-/* lel_to_cpu == cpu_to_lel */
-# define bm_lel_to_cpu(x) bm_cpu_to_lel(x)
-
-STATIC void drbd_bm_rw(struct Drbd_Conf *mdev, int rw)
-{
 	struct drbd_bitmap *b = mdev->bitmap;
-	/* sector_t sector; */
-	int bm_words, num_sectors, i;
-	unsigned long now;
+	sector_t sector;
+	int bm_words, num_sectors;
 	char ppb[10];
 
 	MUST_BE_LOCKED();
@@ -986,62 +642,15 @@
 	bm_words    = drbd_bm_words(mdev);
 	num_sectors = (bm_words*sizeof(long) + 511) >> 9;
 
-	/* OK, I manipulate the bitmap low level,
-	 * and I expect to be the exclusive user.
-	 * If not, I am really in a bad mood...
-	 * to catch such bugs early, make all people who want to access the
-	 * bitmap while I read it dereference a NULL pointer :->
-	 */
-	mdev->bitmap = NULL;
-
-	if(rw == WRITE)	bm_cpu_to_lel(b);
-
-	now = jiffies;
-	atomic_set(&b->bm_async_io, b->bm_number_of_pages);
-	for (i = 0; i < b->bm_number_of_pages; i++) {
-		/* let the layers below us try to merge these bios... */
-		drbd_bm_page_io_async(mdev,b,i,rw);
+	for (sector = 0; sector < num_sectors; sector++) {
+		// FIXME do something on io error here?
+		drbd_bm_read_sect(mdev,sector);
 	}
 
-	blk_run_queue(bdev_get_queue(mdev->bc->md_bdev));
-	wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0);
-	INFO("%s of bitmap took %lu jiffies\n",
-	     rw == READ ? "reading" : "writing", jiffies - now);
-
-	if (test_bit(BM_MD_IO_ERROR,&b->bm_flags)) {
-		/* FIXME correct handling of this.
-		 * detach?
-		 */
-		ALERT("we had at least one MD IO ERROR during bitmap IO\n");
-		drbd_chk_io_error(mdev, 1);
-		drbd_io_error(mdev);
-	}
-
-	now = jiffies;
-	/* just read, if neccessary adjust endianness */
-	if(rw == WRITE) {
-		bm_lel_to_cpu(b);
-	} else /* rw == READ */ {
-		b->bm_set = bm_count_bits(b, 1);
-		INFO("recounting of set bits took additional %lu jiffies\n", 
-		     jiffies - now);
-	}
-
-	/* ok, done,
-	 * now it is visible again
-	 */
-
-	mdev->bitmap = b;
-
 	INFO("%s marked out-of-sync by on disk bit-map.\n",
 	     ppsize(ppb,drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B-10)) );
 }
 
-void drbd_bm_read(struct Drbd_Conf *mdev)
-{
-	drbd_bm_rw(mdev, READ);
-}
-
 /**
  * drbd_bm_write_sect: Writes a 512 byte piece of the bitmap to its
  * on disk location. On disk bitmap is little endian.
@@ -1069,7 +678,6 @@
 	}
 	drbd_bm_get_lel( mdev, offset, num_words,
 			 page_address(mdev->md_io_page) );
-	D_DUMPLU(on_disk_sector);
 	if (!drbd_md_sync_page_io(mdev,mdev->bc,on_disk_sector,WRITE)) {
 		int i;
 		err = -EIO;
@@ -1088,27 +696,25 @@
 
 /**
  * drbd_bm_write: Write the whole bitmap to its on disk location.
- *
- * called at various occasions:
- *
-int drbd_determin_dev_size(struct Drbd_Conf* mdev)
-int drbd_ioctl_set_disk(struct Drbd_Conf *mdev,
-			struct ioctl_disk_config * arg)
-	case DRBD_IOCTL_INVALIDATE:
-	case DRBD_IOCTL_INVALIDATE_REM:
-	case DRBD_IOCTL_SET_DISK_SIZE:
-int _drbd_send_bitmap(drbd_dev *mdev)
-STATIC int drbd_sync_handshake(drbd_dev *mdev, Drbd_Parameter_Packet *p)
-STATIC int receive_BecomeSyncTarget(drbd_dev *mdev, Drbd_Header *h)
-STATIC int receive_BecomeSyncSource(drbd_dev *mdev, Drbd_Header *h)
-STATIC int receive_param(drbd_dev *mdev, Drbd_Header *h)
- *
- * FIXME need to be able to return an error!!
  */
-
 void drbd_bm_write(struct Drbd_Conf *mdev)
 {
-	drbd_bm_rw(mdev, WRITE);
+	struct drbd_bitmap *b = mdev->bitmap;
+	sector_t sector;
+	int bm_words, num_sectors;
+
+	MUST_BE_LOCKED();
+
+	bm_words    = drbd_bm_words(mdev);
+	num_sectors = (bm_words*sizeof(long) + 511) >> 9;
+
+	for (sector = 0; sector < num_sectors; sector++) {
+		// FIXME do something on io error here?
+		drbd_bm_write_sect(mdev,sector);
+	}
+
+	INFO("%lu KB now marked out-of-sync by on disk bit-map.\n",
+	      drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B-10) );
 }
 
 /* clear all bits in the bitmap */
@@ -1117,12 +723,13 @@
 	struct drbd_bitmap *b = mdev->bitmap;
 
 	ERR_IF(!b) return;
-	ERR_IF(!b->bm_pages) return;
+	ERR_IF(!b->bm) return;
 
-	MUST_BE_LOCKED();
+	MUST_BE_LOCKED();						\
 
 	spin_lock_irq(&b->bm_lock);
-	bm_memset(b,0,0x00,b->bm_words);
+	BM_PARANOIA_CHECK();
+	memset(b->bm,0,b->bm_words*sizeof(long));
 	b->bm_set = 0;
 	spin_unlock_irq(&b->bm_lock);
 }
@@ -1145,44 +752,29 @@
 /* NOTE
  * find_first_bit returns int, we return unsigned long.
  * should not make much difference anyways, but ...
- *
  * this returns a bit number, NOT a sector!
  */
-#define BPP_MASK ((1UL << (PAGE_SHIFT+3) ) - 1)
 unsigned long drbd_bm_find_next(drbd_dev *mdev)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	unsigned long i = -1UL;
-	unsigned long *p_addr;
-	unsigned long bit_offset; //bit offset of the mapped page.
 
 	ERR_IF(!b) return i;
-	ERR_IF(!b->bm_pages) return i;
+	ERR_IF(!b->bm) return i;
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
-	if (b->bm_fo > b->bm_bits) {
+	if (b->bm_fo < b->bm_bits) {
+		i = find_next_bit(b->bm,b->bm_bits,b->bm_fo);
+	} else if (b->bm_fo > b->bm_bits) {
 		ERR("bm_fo=%lu bm_bits=%lu\n",b->bm_fo, b->bm_bits);
-	} else {
-		while (b->bm_fo < b->bm_bits) {
-			unsigned long offset;
-			bit_offset = b->bm_fo & ~BPP_MASK; // bit offset of the page
-			offset = bit_offset >> LN2_BPL;    // word offset of the page
-			p_addr = bm_map_paddr(b,offset);
-			i = find_next_bit(p_addr,PAGE_SIZE*8,b->bm_fo&BPP_MASK);
-			bm_unmap(p_addr);
-			if (i < PAGE_SIZE*8) {
-				i = bit_offset + i;
-				if( i >= b->bm_bits ) break;
-				b->bm_fo = i+1;
-				goto found;
-			}
-			b->bm_fo = bit_offset + PAGE_SIZE*8;
-		}
+	}
+	if (i >= b->bm_bits) {
 		i = -1UL;
 		b->bm_fo = 0;
+	} else {
+		b->bm_fo = i+1;
 	}
- found:
 	spin_unlock_irq(&b->bm_lock);
 	return i;
 }
@@ -1203,6 +795,7 @@
 	spin_unlock_irq(&b->bm_lock);
 }
 
+
 int drbd_bm_rs_done(drbd_dev *mdev)
 {
 	return mdev->bitmap->bm_fo == 0;
@@ -1216,11 +809,9 @@
 int drbd_bm_set_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr;
 	int i;
-
 	ERR_IF(!b) return 1;
-	ERR_IF(!b->bm_pages) return 1;
+	ERR_IF(!b->bm) return 1;
 
 /*
  * only called from drbd_set_out_of_sync.
@@ -1240,10 +831,7 @@
 		ERR("bitnr=%lu bm_bits=%lu\n",bitnr, b->bm_bits);
 		i = 0;
 	} else {
-		unsigned long offset = bitnr>>LN2_BPL;
-		p_addr = bm_map_paddr(b,offset);
-		i = (0 != __test_and_set_bit(bitnr & BPP_MASK, p_addr));
-		bm_unmap(p_addr);
+		i = (0 != __test_and_set_bit(bitnr, b->bm));
 		b->bm_set += !i;
 	}
 	spin_unlock_irq(&b->bm_lock);
@@ -1256,12 +844,10 @@
 int drbd_bm_clear_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr;
 	unsigned long flags;
 	int i;
-
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm_pages) return 0;
+	ERR_IF(!b->bm) return 0;
 
 	spin_lock_irqsave(&b->bm_lock,flags);
 	BM_PARANOIA_CHECK();
@@ -1270,10 +856,7 @@
 		ERR("bitnr=%lu bm_bits=%lu\n",bitnr, b->bm_bits);
 		i = 0;
 	} else {
-		unsigned long offset = bitnr>>LN2_BPL;
-		p_addr = bm_map_paddr(b,offset);
-		i = (0 != __test_and_clear_bit(bitnr & BPP_MASK, p_addr));
-		bm_unmap(p_addr);
+		i = (0 != __test_and_clear_bit(bitnr, b->bm));
 		b->bm_set -= i;
 	}
 	spin_unlock_irqrestore(&b->bm_lock,flags);
@@ -1299,19 +882,14 @@
 int drbd_bm_test_bit(drbd_dev *mdev, const unsigned long bitnr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr;
 	int i;
-
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm_pages) return 0;
+	ERR_IF(!b->bm) return 0;
 
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
 	if (bitnr < b->bm_bits) {
-		unsigned long offset = bitnr>>LN2_BPL;
-		p_addr = bm_map_paddr(b,offset);
-		i = test_bit(bitnr & BPP_MASK, p_addr);
-		bm_unmap(p_addr);
+		i = test_bit(bitnr, b->bm) ? 1 : 0;
 	} else if (bitnr == b->bm_bits) {
 		i = -1;
 	} else /* (bitnr > b->bm_bits) */ {
@@ -1342,11 +920,9 @@
 	struct drbd_bitmap *b = mdev->bitmap;
 	int count, s, e;
 	unsigned long flags;
-	unsigned long *p_addr, *bm;
 
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm_pages) return 0;
-
+	ERR_IF(!b->bm) return 0;
 	spin_lock_irqsave(&b->bm_lock,flags);
 	BM_PARANOIA_CHECK();
 
@@ -1354,15 +930,9 @@
 	e = min((size_t)S2W(enr+1),b->bm_words);
 	count = 0;
 	if (s < b->bm_words) {
+		const unsigned long* w = b->bm+s;
 		int n = e-s;
-		p_addr = bm_map_paddr(b,s);
-		bm = p_addr + MLPP(s);
-		while (n--) {
-			catch_oob_access_start();
-			count += hweight_long(*bm++);
-			catch_oob_access_end();
-		}
-		bm_unmap(p_addr);
+		while (n--) count += hweight_long(*w++);
 	} else {
 		ERR("start offset (%d) too large in drbd_bm_e_weight\n", s);
 	}
@@ -1377,11 +947,10 @@
 unsigned long drbd_bm_ALe_set_all(drbd_dev *mdev, unsigned long al_enr)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
-	unsigned long *p_addr, *bm;
 	unsigned long weight;
-	int count, s, e, i, do_now;
+	int count, s, e;
 	ERR_IF(!b) return 0;
-	ERR_IF(!b->bm_pages) return 0;
+	ERR_IF(!b->bm) return 0;
 
 	MUST_BE_LOCKED();
 
@@ -1391,23 +960,14 @@
 
 	s = al_enr * BM_WORDS_PER_AL_EXT;
 	e = min_t(size_t, s + BM_WORDS_PER_AL_EXT, b->bm_words);
-	/* assert that s and e are on the same page */
-	D_ASSERT(  (e-1) >> (PAGE_SHIFT - LN2_BPL + 3)
-		==  s    >> (PAGE_SHIFT - LN2_BPL + 3) );
 	count = 0;
 	if (s < b->bm_words) {
-		i = do_now = e-s;
-		p_addr = bm_map_paddr(b,s);
-		bm = p_addr + MLPP(s);
-		while (i--) {
-			catch_oob_access_start();
-			count += hweight_long(*bm);
-			*bm = -1UL;
-			catch_oob_access_end();
-			bm++;
-		}
-		bm_unmap(p_addr);
-		b->bm_set += do_now*BITS_PER_LONG - count;
+		const unsigned long* w = b->bm+s;
+		int n = e-s;
+		while (n--) count += hweight_long(*w++);
+		n = e-s;
+		memset(b->bm+s,-1,n*sizeof(long));
+		b->bm_set += n*BITS_PER_LONG - count;
 		if (e == b->bm_words) {
 			b->bm_set -= bm_clear_surplus(b);
 		}

From drbd-cvs at lists.linbit.com  Sun Mar 12 09:54:09 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sun Mar 12 09:54:11 2006
Subject: [DRBD-cvs] svn commit by phil - r2113 - trunk/drbd - I guess this
	is the last fix necessary to make the sync
Message-ID: <20060312085410.200BA163F3@mail.linbit.com>

Author: phil
Date: 2006-03-12 09:54:09 +0100 (Sun, 12 Mar 2006)
New Revision: 2113

Modified:
   trunk/drbd/drbd_bitmap.c
Log:
I guess this is the last fix necessary to make the syncer terminate
in every case.


Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-12 08:38:31 UTC (rev 2112)
+++ trunk/drbd/drbd_bitmap.c	2006-03-12 08:54:09 UTC (rev 2113)
@@ -786,11 +786,7 @@
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
 
-	if (i < b->bm_bits) {
-		b->bm_fo = i;
-	} else {
-		b->bm_fo = 0;
-	}
+	b->bm_fo = max_t(unsigned long, i, b->bm_bits);
 
 	spin_unlock_irq(&b->bm_lock);
 }

From drbd-cvs at lists.linbit.com  Sun Mar 12 10:40:27 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sun Mar 12 10:40:28 2006
Subject: [DRBD-cvs] svn commit by phil - r2114 - trunk/drbd - min/max ;) 
Message-ID: <20060312094027.6BC2C163F3@mail.linbit.com>

Author: phil
Date: 2006-03-12 10:40:26 +0100 (Sun, 12 Mar 2006)
New Revision: 2114

Modified:
   trunk/drbd/drbd_bitmap.c
Log:
min/max ;)


Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-12 08:54:09 UTC (rev 2113)
+++ trunk/drbd/drbd_bitmap.c	2006-03-12 09:40:26 UTC (rev 2114)
@@ -786,7 +786,7 @@
 	spin_lock_irq(&b->bm_lock);
 	BM_PARANOIA_CHECK();
 
-	b->bm_fo = max_t(unsigned long, i, b->bm_bits);
+	b->bm_fo = min_t(unsigned long, i, b->bm_bits);
 
 	spin_unlock_irq(&b->bm_lock);
 }

From drbd-cvs at lists.linbit.com  Sun Mar 12 22:01:36 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sun Mar 12 22:01:42 2006
Subject: [DRBD-cvs] svn commit by lars - r2115 - trunk/drbd - next try:
	read/write bitmap asynchonously. again, untes
Message-ID: <20060312210136.4ECEA163F3@mail.linbit.com>

Author: lars
Date: 2006-03-12 22:01:35 +0100 (Sun, 12 Mar 2006)
New Revision: 2115

Modified:
   trunk/drbd/drbd_bitmap.c
   trunk/drbd/drbd_compat_wrappers.h
Log:
next try: read/write bitmap asynchonously. again, untested ...


Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-12 09:40:26 UTC (rev 2114)
+++ trunk/drbd/drbd_bitmap.c	2006-03-12 21:01:35 UTC (rev 2115)
@@ -80,6 +80,12 @@
 struct drbd_bitmap {
 	unsigned long *bm;
 	spinlock_t bm_lock;
+	/* WARNING unsigned long bm_fo and friends:
+	 * 32bit number of bit offset is just enough for 512 MB bitmap.
+	 * it will blow up if we make the bitmap bigger...
+	 * not that it makes much sense to have a bitmap that large,
+	 * rather change the granularity to 16k or 64k or something.
+	 */
 	unsigned long bm_fo;        // next offset for drbd_bm_find_next
 	unsigned long bm_set;       // nr of set bits; THINK maybe atomic_t ?
 	unsigned long bm_bits;
@@ -87,8 +93,12 @@
 	sector_t bm_dev_capacity;
 	struct semaphore bm_change; // serializes resize operations
 
+	atomic_t bm_async_io;
+	wait_queue_head_t bm_io_wait;
+
+	unsigned long  bm_flags;
+
 	// { REMOVE
-	unsigned long  bm_flags;     // currently debugging aid only
 	unsigned long  bm_line;
 	char          *bm_file;
 	// }
@@ -97,6 +107,8 @@
 // { REMOVE once we serialize all state changes properly
 #define D_BUG_ON(x)	ERR_IF(x) { dump_stack(); }
 #define BM_LOCKED 0
+#define BM_MD_IO_ERROR (BITS_PER_LONG-1) // 31? 63?
+
 #if 0 // simply disabled for now...
 #define MUST_NOT_BE_LOCKED() do {					\
 	if (test_bit(BM_LOCKED,&b->bm_flags)) {				\
@@ -294,13 +306,16 @@
 	}
 }
 
-STATIC unsigned long bm_count_bits(struct drbd_bitmap * b)
+STATIC unsigned long bm_count_bits(struct drbd_bitmap * b, int just_read)
 {
 	unsigned long *bm = b->bm;
 	unsigned long *ep = b->bm + b->bm_words;
 	unsigned long bits = 0;
 
 	while ( bm < ep ) {
+		/* on little endian, this is *bm = *bm;
+		 * and should be optimized away by the compiler */
+		if (just_read) *bm = lel_to_cpu(*bm);
 		bits += hweight_long(*bm++);
 	}
 
@@ -403,7 +418,7 @@
 		b->bm_words = words;
 		b->bm_dev_capacity = capacity;
 		bm_clear_surplus(b);
-		if( !growing ) b->bm_set = bm_count_bits(b);
+		if( !growing ) b->bm_set = bm_count_bits(b,0);
 		bm_end_info(mdev, __FUNCTION__ );
 		spin_unlock_irq(&b->bm_lock);
 		INFO("resync bitmap: bits=%lu words=%lu\n",bits,words);
@@ -589,6 +604,52 @@
 	spin_unlock_irq(&b->bm_lock);
 }
 
+int drbd_bm_async_io_complete(struct bio *bio, unsigned int bytes_done, int error)
+{
+	struct drbd_bitmap *b = bio->bi_private;
+
+	if (bio->bi_size)
+		return 1;
+
+	if (error) {
+		/* doh. what now?
+		 * for now, set all bits, and flag MD_IO_ERROR
+		 */
+		/* FIXME kmap_atomic memset etc. pp. */
+		__set_bit(BM_MD_IO_ERROR,&b->bm_flags);
+	}
+	if (atomic_dec_and_test(&b->bm_async_io))
+		wake_up(&b->bm_io_wait);
+
+	bio_put(bio);
+
+	return 0;
+}
+
+STATIC void drbd_bm_page_io_async(drbd_dev *mdev, struct drbd_bitmap *b, int page_nr, int rw)
+{
+	/* we are process context. we always get a bio */
+	/* THINK: do we need GFP_NOIO here? */
+	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	struct page *page = virt_to_page((char*)(b->bm) + (PAGE_SIZE*page_nr));
+	unsigned int len;
+	sector_t on_disk_sector = mdev->bc->md.md_offset + mdev->bc->md.bm_offset;
+	on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
+
+	/* this might happen with very small flexible external meta data device */
+	len = min_t(unsigned int, PAGE_SIZE,
+		(drbd_md_last_sector(mdev->bc) - on_disk_sector + 1)<<9);
+
+	D_DUMPLU(on_disk_sector);
+	D_DUMPI(len);
+
+	bio->bi_bdev = mdev->bc->md_bdev;
+	bio->bi_sector = on_disk_sector;
+	bio_add_page(bio, page, len, 0);
+	bio->bi_private = b;
+	bio->bi_end_io = drbd_bm_async_io_complete;
+	submit_bio(rw, bio);
+}
 /* read one sector of the on disk bitmap into memory.
  * on disk bitmap is little endian.
  * @enr is _sector_ offset from start of on disk bitmap (aka bm-extent nr).
@@ -629,28 +690,110 @@
 
 /**
  * drbd_bm_read: Read the whole bitmap from its on disk location.
+ *
+ * currently only called from "drbd_ioctl_set_disk"
+ * FIXME need to be able to return an error!!
+ *
  */
-void drbd_bm_read(struct Drbd_Conf *mdev)
+# if defined(__LITTLE_ENDIAN)
+	/* nothing to do, on disk == in memory */
+# define bm_cpu_to_lel(x) ((void)0)
+# else
+void bm_cpu_to_lel(struct drbd_bitmap *b)
 {
+	/* need to cpu_to_lel all the pages ...
+	 * this may be optimized by using
+	 * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0;
+	 * the following is still not optimal, but better than nothing */
+	const unsigned long *end = b->bm+b->bm_words;
+	unsigned long *bm;
+	if (b->bm_set == 0) {
+		/* no page at all; avoid swap if all is 0 */
+		return;
+	} else if (b->bm_set == b->bm_bits) {
+		/* only the last words */
+		bm = end-2;
+	} else {
+		/* all pages */
+		bm = b->bm;
+	}
+	for (; bm < end; bm++) {
+		*bm = cpu_to_lel(*bm);
+	}
+}
+# endif
+/* lel_to_cpu == cpu_to_lel */
+# define bm_lel_to_cpu(x) bm_cpu_to_lel(x)
+
+STATIC void drbd_bm_rw(struct Drbd_Conf *mdev, int rw)
+{
 	struct drbd_bitmap *b = mdev->bitmap;
-	sector_t sector;
-	int bm_words, num_sectors;
+	/* sector_t sector; */
+	int bm_words, num_pages, i;
+	unsigned long now;
 	char ppb[10];
 
 	MUST_BE_LOCKED();
 
 	bm_words    = drbd_bm_words(mdev);
-	num_sectors = (bm_words*sizeof(long) + 511) >> 9;
+	num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT;
 
-	for (sector = 0; sector < num_sectors; sector++) {
-		// FIXME do something on io error here?
-		drbd_bm_read_sect(mdev,sector);
+	/* OK, I manipulate the bitmap low level,
+	 * and I expect to be the exclusive user.
+	 * If not, I am really in a bad mood...
+	 * to catch such bugs early, make all people who want to access the
+	 * bitmap while I read/write it dereference a NULL pointer :->
+	 */
+	mdev->bitmap = NULL;
+
+	if(rw == WRITE)	bm_cpu_to_lel(b);
+
+	now = jiffies;
+	atomic_set(&b->bm_async_io, num_pages);
+	for (i = 0; i < num_pages; i++) {
+		/* let the layers below us try to merge these bios... */
+		drbd_bm_page_io_async(mdev,b,i,rw);
 	}
 
+	blk_run_queue(bdev_get_queue(mdev->bc->md_bdev));
+	wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0);
+	INFO("%s of bitmap took %lu jiffies\n", 
+	     rw == READ ? "reading" : "writing", jiffies - now);
+
+	if (test_bit(BM_MD_IO_ERROR,&b->bm_flags)) {
+		/* FIXME correct handling of this.
+		 * detach?
+		 */
+		ALERT("we had at least one MD IO ERROR during bitmap IO\n");
+		drbd_chk_io_error(mdev, 1);
+		drbd_io_error(mdev);
+	}
+
+	now = jiffies;
+	if(rw == WRITE) {
+		bm_lel_to_cpu(b);
+	} else /* rw == READ */ {
+		/* just read, if neccessary adjust endianness */
+		b->bm_set = bm_count_bits(b, 1);
+		INFO("recounting of set bits took additional %lu jiffies\n", 
+		     jiffies - now);
+	}
+
+	/* ok, done,
+	 * now it is visible again
+	 */
+
+	mdev->bitmap = b;
+
 	INFO("%s marked out-of-sync by on disk bit-map.\n",
 	     ppsize(ppb,drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B-10)) );
 }
 
+void drbd_bm_read(struct Drbd_Conf *mdev)
+{
+	drbd_bm_rw(mdev, READ);
+}
+
 /**
  * drbd_bm_write_sect: Writes a 512 byte piece of the bitmap to its
  * on disk location. On disk bitmap is little endian.

Modified: trunk/drbd/drbd_compat_wrappers.h
===================================================================
--- trunk/drbd/drbd_compat_wrappers.h	2006-03-12 09:40:26 UTC (rev 2114)
+++ trunk/drbd/drbd_compat_wrappers.h	2006-03-12 21:01:35 UTC (rev 2115)
@@ -10,7 +10,7 @@
 
 /* struct page has a union in 2.6.15 ...
  * an anonymous union and struct since 2.6.16 */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16))
 #define U_PRIVATE private
 #else
 #define U_PRIVATE u.private

From drbd-cvs at lists.linbit.com  Mon Mar 13 13:10:04 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Mar 13 13:10:05 2006
Subject: [DRBD-cvs] svn commit by phil - r2116 - trunk/drbd - Shaked the
	bugs out. Async bitmap IO seems to work nice
Message-ID: <20060313121005.111F815EA7@mail.linbit.com>

Author: phil
Date: 2006-03-13 13:10:04 +0100 (Mon, 13 Mar 2006)
New Revision: 2116

Modified:
   trunk/drbd/drbd_bitmap.c
Log:
Shaked the bugs out. Async bitmap IO seems to work nicely now...


Modified: trunk/drbd/drbd_bitmap.c
===================================================================
--- trunk/drbd/drbd_bitmap.c	2006-03-12 21:01:35 UTC (rev 2115)
+++ trunk/drbd/drbd_bitmap.c	2006-03-13 12:10:04 UTC (rev 2116)
@@ -243,7 +243,10 @@
 	memset(b,0,sizeof(*b));
 	spin_lock_init(&b->bm_lock);
 	init_MUTEX(&b->bm_change);
+	init_waitqueue_head(&b->bm_io_wait);
+
 	mdev->bitmap = b;
+	
 	return 0;
 }
 
@@ -791,7 +794,11 @@
 
 void drbd_bm_read(struct Drbd_Conf *mdev)
 {
+	struct drbd_bitmap *b = mdev->bitmap;
+
 	drbd_bm_rw(mdev, READ);
+
+	b->bm[b->bm_words] = DRBD_MAGIC;
 }
 
 /**
@@ -842,20 +849,8 @@
  */
 void drbd_bm_write(struct Drbd_Conf *mdev)
 {
-	struct drbd_bitmap *b = mdev->bitmap;
-	sector_t sector;
-	int bm_words, num_sectors;
+	drbd_bm_rw(mdev, WRITE);
 
-	MUST_BE_LOCKED();
-
-	bm_words    = drbd_bm_words(mdev);
-	num_sectors = (bm_words*sizeof(long) + 511) >> 9;
-
-	for (sector = 0; sector < num_sectors; sector++) {
-		// FIXME do something on io error here?
-		drbd_bm_write_sect(mdev,sector);
-	}
-
 	INFO("%lu KB now marked out-of-sync by on disk bit-map.\n",
 	      drbd_bm_total_weight(mdev) << (BM_BLOCK_SIZE_B-10) );
 }

From drbd-cvs at lists.linbit.com  Mon Mar 13 18:38:28 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Mon Mar 13 18:38:29 2006
Subject: [DRBD-cvs] svn commit by phil - r2117 - trunk/drbd - * Made the
	display of a LRU-cache's usage in /proc more
Message-ID: <20060313173828.A7B2515EA7@mail.linbit.com>

Author: phil
Date: 2006-03-13 18:38:25 +0100 (Mon, 13 Mar 2006)
New Revision: 2117

Modified:
   trunk/drbd/drbd_receiver.c
   trunk/drbd/lru_cache.c
   trunk/drbd/lru_cache.h
Log:
* Made the display of a LRU-cache's usage in /proc more usefull by
  printing the currently used elements as well.
* Wrote a drbd_uuid_dump() debug helper.
* Free the peer's UUID set on disconnect. This was the reason why
  DRBD8 did a full sync after interrupting a resync by 
  drbdadm down r0 / drbdadm up r0 on a SyncSource node.



Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-13 12:10:04 UTC (rev 2116)
+++ trunk/drbd/drbd_receiver.c	2006-03-13 17:38:25 UTC (rev 2117)
@@ -1574,6 +1574,16 @@
 	return rv;
 }
 
+STATIC void drbd_uuid_dump(drbd_dev *mdev,char* text,u64* uuid)
+{
+	WARN("%s %016llX:%016llX:%016llX:%016llX\n",
+	     text,
+	     uuid[Current],
+	     uuid[Bitmap],
+	     uuid[History_start],
+	     uuid[History_end]);
+}
+
 /*
   100   after split brain try auto recover
     2   SyncSource set BitMap
@@ -1584,7 +1594,7 @@
  -100   after split brain, disconnect
 -1000   unrelated data
  */
-static int drbd_uuid_compare(drbd_dev *mdev)
+STATIC int drbd_uuid_compare(drbd_dev *mdev)
 {
 	u64 self, peer;
 	int i,j;
@@ -1645,8 +1655,14 @@
 	int hg;
 	drbd_conns_t rv = conn_mask;
 
+
+	//drbd_uuid_dump(mdev,"self",mdev->bc->md.uuid);
+	//drbd_uuid_dump(mdev,"peer",mdev->p_uuid);
+
 	hg = drbd_uuid_compare(mdev);
 
+	//WARN("uuid_compare()=%d\n",hg);
+
 	if (hg == 100) {
 		if ( mdev->state.role==Secondary && peer_role==Secondary ) {
 			hg = drbd_asb_recover_0p(mdev);
@@ -2432,6 +2448,11 @@
 		}
 	}
 
+	if ( mdev->p_uuid ) {
+		kfree(mdev->p_uuid);
+		mdev->p_uuid = NULL;
+	}
+
 	drbd_md_sync(mdev);
 	INFO("Connection lost.\n");
 }

Modified: trunk/drbd/lru_cache.c
===================================================================
--- trunk/drbd/lru_cache.c	2006-03-13 12:10:04 UTC (rev 2116)
+++ trunk/drbd/lru_cache.c	2006-03-13 17:38:25 UTC (rev 2117)
@@ -94,9 +94,9 @@
 	 * misses include "dirty" count (update from an other thread in progress)
 	 * and "changed", when this in fact lead to an successful update of the cache.
 	 */
-	return seq_printf(seq,"\t%s: elements:%u "
+	return seq_printf(seq,"\t%s: used:%u/%u "
 		"hits:%lu misses:%lu starving:%lu dirty:%lu changed:%lu\n",
-		lc->name, lc->nr_elements,
+		lc->name, lc->used, lc->nr_elements,
 		lc->hits, lc->misses, lc->starving, lc->dirty, lc->changed);
 }
 
@@ -223,7 +223,7 @@
 	e = lc_find(lc, enr);
 	if (e) {
 		++lc->hits;
-		++e->refcnt;
+		if( e->refcnt++ == 0) lc->used++;
 		list_move(&e->list,&lc->in_use); // Not evictable...
 		RETURN(e);
 	}
@@ -252,6 +252,7 @@
 
 	clear_bit(__LC_STARVING,&lc->flags);
 	BUG_ON(++e->refcnt != 1);
+	lc->used++;
 
 	lc->changing_element = e;
 	lc->new_number = enr;
@@ -285,6 +286,7 @@
 	BUG_ON(e->refcnt == 0);
 	if ( --e->refcnt == 0) {
 		list_move(&e->list,&lc->lru); // move it to the front of LRU.
+		lc->used--;
 		clear_bit(__LC_STARVING,&lc->flags);
 		smp_mb__after_clear_bit();
 	}

Modified: trunk/drbd/lru_cache.h
===================================================================
--- trunk/drbd/lru_cache.h	2006-03-13 12:10:04 UTC (rev 2116)
+++ trunk/drbd/lru_cache.h	2006-03-13 17:38:25 UTC (rev 2117)
@@ -74,6 +74,7 @@
 
 	/* here may or may not be a pad... */
 
+	unsigned int used;
 	unsigned long flags;
 	unsigned long hits, misses, starving, dirty, changed;
 	struct lc_element *changing_element; // just for paranoia

From drbd-cvs at lists.linbit.com  Tue Mar 14 10:17:57 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Mar 14 10:17:58 2006
Subject: [DRBD-cvs] svn commit by phil - r2118 - in trunk: . drbd drbd/linux
	- Latest fixes from the 0.7 branch. 
Message-ID: <20060314091758.193F916635@mail.linbit.com>

Author: phil
Date: 2006-03-14 10:17:56 +0100 (Tue, 14 Mar 2006)
New Revision: 2118

Modified:
   trunk/
   trunk/Makefile
   trunk/drbd/drbd_actlog.c
   trunk/drbd/drbd_receiver.c
   trunk/drbd/linux/drbd_config.h
Log:
Latest fixes from the 0.7 branch.



Property changes on: trunk
___________________________________________________________________
Name: propagate:at
   - 2097
   + 2117

Modified: trunk/Makefile
===================================================================
--- trunk/Makefile	2006-03-13 17:38:25 UTC (rev 2117)
+++ trunk/Makefile	2006-03-14 09:17:56 UTC (rev 2118)
@@ -188,7 +188,7 @@
 	       -e "s/^\(Packager:\).*/\1 $(USER)@$(HOSTNAME)/;" < drbd.spec.in \
 	   > dist/SPECS/drbd.spec ; \
 	fi
-	$(RPMBUILD) -ba \
+	$(RPMBUILD) -bb \
 	    --define "_topdir $(PWD)/dist" \
 	    --define "buildroot $(PWD)/dist/install" \
 	    --define "kernelversion $(KVER)" \

Modified: trunk/drbd/drbd_actlog.c
===================================================================
--- trunk/drbd/drbd_actlog.c	2006-03-13 17:38:25 UTC (rev 2117)
+++ trunk/drbd/drbd_actlog.c	2006-03-14 09:17:56 UTC (rev 2118)
@@ -38,7 +38,7 @@
 				 struct page *page, sector_t sector, 
 				 int rw, int size)
 {
-	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	struct bio *bio = bio_alloc(GFP_NOIO, 1);
 	struct completion event;
 	int ok;
 

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-13 17:38:25 UTC (rev 2117)
+++ trunk/drbd/drbd_receiver.c	2006-03-14 09:17:56 UTC (rev 2118)
@@ -53,7 +53,7 @@
 #include "drbd_int.h"
 
 #if defined(__arch_um__) && !defined(HAVE_UML_TO_VIRT)
-void *to_virt(unsigned long phys)
+static inline void *to_virt(unsigned long phys)
 {
 	return((void *) uml_physmem + phys);
 }

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-03-13 17:38:25 UTC (rev 2117)
+++ trunk/drbd/linux/drbd_config.h	2006-03-14 09:17:56 UTC (rev 2118)
@@ -47,4 +47,8 @@
 // for troubles.
 // #define DRBD_DISABLE_SENDPAGE
 
+// older, unpached kernel sources do not have it, so we added it in drbd_receiver.c
+// but more recent kernels define it in arch/um/include/mem.h
+#define HAVE_UML_TO_VIRT
+
 #endif

From drbd-cvs at lists.linbit.com  Tue Mar 14 11:17:54 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Mar 14 11:18:01 2006
Subject: [DRBD-cvs] svn commit by phil - r2119 - in trunk: . drbd/linux -
	Preparing the DRBDv8 prerelease phase. 
Message-ID: <20060314101759.A593B26E94@mail.linbit.com>

Author: phil
Date: 2006-03-14 11:17:53 +0100 (Tue, 14 Mar 2006)
New Revision: 2119

Modified:
   trunk/ChangeLog
   trunk/drbd/linux/drbd_config.h
Log:
Preparing the DRBDv8 prerelease phase.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-03-14 09:17:56 UTC (rev 2118)
+++ trunk/ChangeLog	2006-03-14 10:17:53 UTC (rev 2119)
@@ -4,16 +4,37 @@
  Cumulative changes since last tarball.
  For even more detail, use "svn log" and "svn diff".
 
-0.8_pre1
+8.0-pre1 (api:80/proto:80)
 --------
- * remove all kernel 2.4.x compatibility crap
+ * Removed support for Linux-2.4.x
+ * Cleanup of the wire protocol.
+ * Added optional peer authentication with a shared secret.
+ * Consolidated state changes into a central function.
+ * Improved, tunable after-split-braine recovery strategies.
+ * Always verify all IDs used in the protocol that are used as pointers.
+ * Introduced the "outdate" disk state, and commands for managing it.
+ * Introduced the "drbdmeta" command, and require the user to create 
+   meta-data explicitly.
+ * Support for primary/primary (for OCFS2, GFS...) 
+ * Replaced the sync-groups with the sync-after mechanism.
+ * The "common" section in the configuration file.
+ * Replaced the generation counters (GCs) with data-generation-UUIDs
+ * Imporved performance by using Linux-2.6's BIOs with up to 32k per
+   IO request. Before we transfered only up to 4k per IO request.
+ * A Warning if the disk sizes are more than 10% different.
+ * A connection teardown packet to differentiate between a crash
+   of the peer and a peer that is shut down gracefully.
+ * External impasable SyncPause states, to serialize DRBD's resynchronisation
+   with the resynchronisation of backing storage's RAID configurations.
+ * Backing storage can be hot added to disk less nodes.
+ * Prepared for advanced intregration to Heartbeat-2.0
+ * Changed internal APIs so that missed writes of the meta-data super
+   block are reported as they happen.
+ * The http://usage.drbd.org sub project.
+ * Rewrote the scanner/parser of drbd.conf. 10 times smaller/faster and 
+   easier to maintain.
+ * Asynchronous meta-data IO [ Code drop from the DRBD+ branch ]
 
- FIXME mention all those things we did so far
-
-
-0.7 branch
-----------
-
 0.7.13 (api:77/proto:74)
 -----
  * Fixed a SMP race condition that caused the resync process to stall

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-03-14 09:17:56 UTC (rev 2118)
+++ trunk/drbd/linux/drbd_config.h	2006-03-14 10:17:53 UTC (rev 2119)
@@ -22,7 +22,7 @@
 
 extern const char * drbd_buildtag(void);
 
-#define REL_VERSION "0.8-pre2"
+#define REL_VERSION "8.0-pre1"
 #define API_VERSION 80
 #define PRO_VERSION 80
 
@@ -47,8 +47,4 @@
 // for troubles.
 // #define DRBD_DISABLE_SENDPAGE
 
-// older, unpached kernel sources do not have it, so we added it in drbd_receiver.c
-// but more recent kernels define it in arch/um/include/mem.h
-#define HAVE_UML_TO_VIRT
-
 #endif

From drbd-cvs at lists.linbit.com  Tue Mar 14 11:22:47 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Mar 14 11:22:48 2006
Subject: [DRBD-cvs] svn commit by phil - r2120 - trunk - Fixed some of the
	spelling errors. 
Message-ID: <20060314102247.7E3A616AA0@mail.linbit.com>

Author: phil
Date: 2006-03-14 11:22:47 +0100 (Tue, 14 Mar 2006)
New Revision: 2120

Modified:
   trunk/ChangeLog
Log:
Fixed some of the spelling errors.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-03-14 10:17:53 UTC (rev 2119)
+++ trunk/ChangeLog	2006-03-14 10:22:47 UTC (rev 2120)
@@ -10,7 +10,7 @@
  * Cleanup of the wire protocol.
  * Added optional peer authentication with a shared secret.
  * Consolidated state changes into a central function.
- * Improved, tunable after-split-braine recovery strategies.
+ * Improved, tunable after-split-brain recovery strategies.
  * Always verify all IDs used in the protocol that are used as pointers.
  * Introduced the "outdate" disk state, and commands for managing it.
  * Introduced the "drbdmeta" command, and require the user to create 
@@ -19,15 +19,15 @@
  * Replaced the sync-groups with the sync-after mechanism.
  * The "common" section in the configuration file.
  * Replaced the generation counters (GCs) with data-generation-UUIDs
- * Imporved performance by using Linux-2.6's BIOs with up to 32k per
-   IO request. Before we transfered only up to 4k per IO request.
+ * Improved performance by using Linux-2.6's BIOs with up to 32k per
+   IO request. Before we transferred only up to 4k per IO request.
  * A Warning if the disk sizes are more than 10% different.
  * A connection teardown packet to differentiate between a crash
    of the peer and a peer that is shut down gracefully.
- * External impasable SyncPause states, to serialize DRBD's resynchronisation
+ * External imposable SyncPause states, to serialize DRBD's resynchronisation
    with the resynchronisation of backing storage's RAID configurations.
  * Backing storage can be hot added to disk less nodes.
- * Prepared for advanced intregration to Heartbeat-2.0
+ * Prepared for advanced integration to Heartbeat-2.0
  * Changed internal APIs so that missed writes of the meta-data super
    block are reported as they happen.
  * The http://usage.drbd.org sub project.

From drbd-cvs at lists.linbit.com  Tue Mar 14 11:41:44 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Mar 14 11:41:46 2006
Subject: [DRBD-cvs] svn commit by phil - r2121 - in trunk: . debian
	drbd/linux - Latest preparation steps... 
Message-ID: <20060314104144.E750E16879@mail.linbit.com>

Author: phil
Date: 2006-03-14 11:41:44 +0100 (Tue, 14 Mar 2006)
New Revision: 2121

Modified:
   trunk/ChangeLog
   trunk/debian/changelog
   trunk/drbd.spec.in
   trunk/drbd/linux/drbd_config.h
Log:
Latest preparation steps...


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-03-14 10:22:47 UTC (rev 2120)
+++ trunk/ChangeLog	2006-03-14 10:41:44 UTC (rev 2121)
@@ -4,7 +4,7 @@
  Cumulative changes since last tarball.
  For even more detail, use "svn log" and "svn diff".
 
-8.0-pre1 (api:80/proto:80)
+8.0_pre1 (api:80/proto:80)
 --------
  * Removed support for Linux-2.4.x
  * Cleanup of the wire protocol.

Modified: trunk/debian/changelog
===================================================================
--- trunk/debian/changelog	2006-03-14 10:22:47 UTC (rev 2120)
+++ trunk/debian/changelog	2006-03-14 10:41:44 UTC (rev 2121)
@@ -1,3 +1,9 @@
+drbd (8.0_pre1-0) unstable; urgency=low
+
+  * New major release.
+
+ -- Philipp Reisner <phil@linbit.com>  Thu, 14 Mar 2006 11:37:56 +0200
+
 drbd (0.7.13-0) unstable; urgency=low
 
   * New upstream release

Modified: trunk/drbd/linux/drbd_config.h
===================================================================
--- trunk/drbd/linux/drbd_config.h	2006-03-14 10:22:47 UTC (rev 2120)
+++ trunk/drbd/linux/drbd_config.h	2006-03-14 10:41:44 UTC (rev 2121)
@@ -22,7 +22,7 @@
 
 extern const char * drbd_buildtag(void);
 
-#define REL_VERSION "8.0-pre1"
+#define REL_VERSION "8.0_pre1"
 #define API_VERSION 80
 #define PRO_VERSION 80
 

Modified: trunk/drbd.spec.in
===================================================================
--- trunk/drbd.spec.in	2006-03-14 10:22:47 UTC (rev 2120)
+++ trunk/drbd.spec.in	2006-03-14 10:41:44 UTC (rev 2121)
@@ -191,12 +191,37 @@
 
 %changelog
 
-* Tue Jul 26 2005 11:53:11 +0200 Lars Ellenberg <lars@linbit.com>
-- drbd (0.8_pre1-3)
-  * remove all kernel 2.4.x compatibility crap
+* Tue Mar 14 2006 11:37:56 +0200 Philipp Reisner <phil@linbit.com>
+- drbd (8.0_pre1-1)
+ * Removed support for Linux-2.4.x
+ * Cleanup of the wire protocol.
+ * Added optional peer authentication with a shared secret.
+ * Consolidated state changes into a central function.
+ * Improved, tunable after-split-brain recovery strategies.
+ * Always verify all IDs used in the protocol that are used as pointers.
+ * Introduced the "outdate" disk state, and commands for managing it.
+ * Introduced the "drbdmeta" command, and require the user to create 
+   meta-data explicitly.
+ * Support for primary/primary (for OCFS2, GFS...) 
+ * Replaced the sync-groups with the sync-after mechanism.
+ * The "common" section in the configuration file.
+ * Replaced the generation counters (GCs) with data-generation-UUIDs
+ * Improved performance by using Linux-2.6's BIOs with up to 32k per
+   IO request. Before we transferred only up to 4k per IO request.
+ * A Warning if the disk sizes are more than 10% different.
+ * A connection teardown packet to differentiate between a crash
+   of the peer and a peer that is shut down gracefully.
+ * External imposable SyncPause states, to serialize DRBD's resynchronisation
+   with the resynchronisation of backing storage's RAID configurations.
+ * Backing storage can be hot added to disk less nodes.
+ * Prepared for advanced integration to Heartbeat-2.0
+ * Changed internal APIs so that missed writes of the meta-data super
+   block are reported as they happen.
+ * The http://usage.drbd.org sub project.
+ * Rewrote the scanner/parser of drbd.conf. 10 times smaller/faster and 
+   easier to maintain.
+ * Asynchronous meta-data IO [ Code drop from the DRBD+ branch ]
 
-  FIXME mention all the great things we did so far
-
 * Thu Sep  1 2005 10:00:00 +0200 Philipp Reisner <phil@linbit.com>
 - drbd (0.7.13-1)
  * Fixed a SMP race condition that caused the resync process to stall

From drbd-cvs at lists.linbit.com  Tue Mar 14 11:49:00 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Tue Mar 14 11:49:00 2006
Subject: [DRBD-cvs] svn commit by phil - r2122 - tags - Tagging
	drbd-8.0_pre1 
Message-ID: <20060314104900.6F63C16879@mail.linbit.com>

Author: phil
Date: 2006-03-14 11:48:59 +0100 (Tue, 14 Mar 2006)
New Revision: 2122

Added:
   tags/drbd-8.0_pre1/
Log:
Tagging drbd-8.0_pre1


Copied: tags/drbd-8.0_pre1 (from rev 2121, trunk)

From drbd-cvs at lists.linbit.com  Thu Mar 16 17:54:10 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Mar 16 17:54:12 2006
Subject: [DRBD-cvs] svn commit by phil - r2123 - in trunk: drbd user - *
	Fixed two bugs with the expansion of the options from
Message-ID: <20060316165410.69F1416AB9@mail.linbit.com>

Author: phil
Date: 2006-03-16 17:54:09 +0100 (Thu, 16 Mar 2006)
New Revision: 2123

Modified:
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_receiver.c
   trunk/user/drbdadm_main.c
Log:
* Fixed two bugs with the expansion of the options from the common
  section in drbdadm.
* Made it to compile on Linux-2.6.16-rc6 by disabling the barrier 
  code for now.
* Made the md_sync timeout from one second to 5 seconds.


Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-14 10:48:59 UTC (rev 2122)
+++ trunk/drbd/drbd_main.c	2006-03-16 16:54:09 UTC (rev 2123)
@@ -2556,12 +2556,12 @@
  * drbd_md_mark_dirty:
  * Call this function if you change enything that should be written to
  * the meta-data super block. This function sets MD_DIRTY, and starts a 
- * timer that ensures that within one second you have to call drbd_md_sync().
+ * timer that ensures that within five seconds you have to call drbd_md_sync().
  */
 void drbd_md_mark_dirty(drbd_dev *mdev)
 {
 	set_bit(MD_DIRTY,&mdev->flags);
-	mod_timer(&mdev->md_sync_timer,jiffies + HZ );
+	mod_timer(&mdev->md_sync_timer,jiffies + 5*HZ );
 }
 
 static void drbd_uuid_move_history(drbd_dev *mdev)

Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-14 10:48:59 UTC (rev 2122)
+++ trunk/drbd/drbd_receiver.c	2006-03-16 16:54:09 UTC (rev 2123)
@@ -1796,6 +1796,7 @@
 
 STATIC void drbd_setup_order_type(drbd_dev *mdev, int peer)
 {
+#if 0
 	int self = drbd_queue_order_type(mdev);
 	int type;
 
@@ -1824,6 +1825,7 @@
 		     order_txt[type]);
 		blk_queue_ordered(mdev->rq_queue,type);
 	}
+#endif 
 }
 
 /* warn if the arguments differ by more than 12.5% */

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-03-14 10:48:59 UTC (rev 2122)
+++ trunk/user/drbdadm_main.c	2006-03-16 16:54:09 UTC (rev 2123)
@@ -436,8 +436,8 @@
     if(!find_opt(*opts,co->name)) {
       // prepend new item to opts
       no = malloc(sizeof(struct d_option));
-      no->name=strdup(co->name);
-      no->value=strdup(co->value);
+      no->name = strdup(co->name);
+      no->value = co->value ? strdup(co->value) : NULL ;
       no->next = *opts;
       *opts = no;
     }
@@ -1547,12 +1547,13 @@
       if (optind + 1 > argc && !is_dump)
         print_usage_and_exit("missing arguments"); // arguments missing.
 
+      if(!is_dump) expand_common();
+
       if ( optind==argc || !strcmp(argv[optind],"all") ) {
         if (is_dump) {
 	  dump_global_info();
 	  dump_common_info();
 	} else {
-	  expand_common(); // Propagate common options to resources.
 	  global_validate(); 
 	  if(!config_valid) exit(E_config_invalid);
 	}

From drbd-cvs at lists.linbit.com  Thu Mar 23 10:49:10 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Thu Mar 23 10:49:11 2006
Subject: [DRBD-cvs] svn commit by phil - r2124 - trunk/documentation -
	drbdmeta-'s manpage should be built as well.. 
Message-ID: <20060323094910.48DB016AD6@mail.linbit.com>

Author: phil
Date: 2006-03-23 10:49:09 +0100 (Thu, 23 Mar 2006)
New Revision: 2124

Modified:
   trunk/documentation/Makefile
Log:
drbdmeta-'s manpage should be built as well..


Modified: trunk/documentation/Makefile
===================================================================
--- trunk/documentation/Makefile	2006-03-16 16:54:09 UTC (rev 2123)
+++ trunk/documentation/Makefile	2006-03-23 09:49:09 UTC (rev 2124)
@@ -28,7 +28,7 @@
 
 MAKEFILES_LANG := $(foreach dir,$(LANGS),$(dir)/Makefile)
 
-MANPAGES       := drbdsetup.8 drbd.conf.5 drbd.8 drbdadm.8 drbddisk.8
+MANPAGES       := drbdsetup.8 drbd.conf.5 drbd.8 drbdadm.8 drbddisk.8 drbdmeta.8
 
 #
 # Docbook Magic for SuSE, Worksforme...

From drbd-cvs at lists.linbit.com  Sun Mar 26 21:25:24 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Sun Mar 26 21:25:26 2006
Subject: [DRBD-cvs] svn commit by lars - r2125 - branches/drbd-0.7/user -
	forgot to mask out 'DONT_REPORT_FAILED' flag in drbdadm
Message-ID: <20060326192524.364B0143C9@mail.linbit.com>

Author: lars
Date: 2006-03-26 21:25:23 +0200 (Sun, 26 Mar 2006)
New Revision: 2125

Modified:
   branches/drbd-0.7/user/drbdadm_main.c
Log:
forgot to mask out 'DONT_REPORT_FAILED' flag in drbdadm m_system(argv,flags)

Modified: branches/drbd-0.7/user/drbdadm_main.c
===================================================================
--- branches/drbd-0.7/user/drbdadm_main.c	2006-03-23 09:49:09 UTC (rev 2124)
+++ branches/drbd-0.7/user/drbdadm_main.c	2006-03-26 19:25:23 UTC (rev 2125)
@@ -456,10 +456,13 @@
     int timeout;
     sigaction(SIGALRM,&sa,&so);
     alarm_raised=0;
-    switch(flags) {
+    switch(flags & 0x0f) {
     case SLEEPS_SHORT:     timeout = 5; break;
     case SLEEPS_LONG:      timeout = 120; break;
     case SLEEPS_VERY_LONG: timeout = 600; break;
+    default:
+			   fprintf(stderr,"%s:%u: oops... flags=%02x\n", __FILE__ , __LINE__ , flags);
+			   exit(E_thinko);
     }
     alarm(timeout);
   }

From drbd-cvs at lists.linbit.com  Fri Mar 31 14:49:16 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Mar 31 14:49:19 2006
Subject: [DRBD-cvs] svn commit by phil - r2128 - trunk/drbd - improved the
	status display. Now all bits of DRBD's sta
Message-ID: <20060331124916.E1810144CC@mail.linbit.com>

Author: phil
Date: 2006-03-31 14:49:16 +0200 (Fri, 31 Mar 2006)
New Revision: 2128

Modified:
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_proc.c
Log:
improved the status display. Now all bits of DRBD's status
are displayed in /proc/drbd and various kernel log messages.


Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-03-30 12:37:02 UTC (rev 2127)
+++ trunk/drbd/drbd_main.c	2006-03-31 12:49:16 UTC (rev 2128)
@@ -527,16 +527,20 @@
 	return ok;
 }
 
-
 static void print_st(drbd_dev* mdev, char *name, drbd_state_t ns)
 {
-	ERR(" %s = { cs:%s st:%s/%s ds:%s/%s }\n",
+	ERR(" %s = { cs:%s st:%s/%s ds:%s/%s %c%c%c%c }\n",
 	    name,
 	    conns_to_name(ns.conn),
 	    roles_to_name(ns.role),
 	    roles_to_name(ns.peer),
 	    disks_to_name(ns.disk),
-	    disks_to_name(ns.pdsk));
+	    disks_to_name(ns.pdsk),
+	    ns.susp ? 's' : 'r',
+	    ns.aftr_isp ? 'a' : '-',
+	    ns.peer_isp ? 'p' : '-',
+	    ns.user_isp ? 'u' : '-'
+	    );
 }
 
 void print_st_err(drbd_dev* mdev, drbd_state_t os, drbd_state_t ns, int err)
@@ -550,6 +554,11 @@
 #define peers_to_name roles_to_name
 #define pdsks_to_name disks_to_name
 
+#define susps_to_name(A) ( (A) ? "1" : "0" )
+#define aftr_isps_to_name(A) ( (A) ? "1" : "0" )
+#define peer_isps_to_name(A) ( (A) ? "1" : "0" )
+#define user_isps_to_name(A) ( (A) ? "1" : "0" )
+
 #define PSC(A) \
 	({ if( ns.A != os.A ) { \
 		pbp += sprintf(pbp, #A "( %s -> %s ) ", \
@@ -686,11 +695,16 @@
 #if DUMP_MD >= 2
 	char *pbp,pb[300];
 	pbp = pb;
+	*pbp=0;
 	PSC(role);
 	PSC(peer);
 	PSC(conn);
 	PSC(disk);
 	PSC(pdsk);
+	PSC(susp);
+	PSC(aftr_isp);
+	PSC(peer_isp);
+	PSC(user_isp);
 	INFO("%s\n", pb);
 #endif
 

Modified: trunk/drbd/drbd_proc.c
===================================================================
--- trunk/drbd/drbd_proc.c	2006-03-30 12:37:02 UTC (rev 2127)
+++ trunk/drbd/drbd_proc.c	2006-03-31 12:49:16 UTC (rev 2128)
@@ -201,7 +201,7 @@
 			seq_printf( seq, "%2d: cs:Unconfigured\n", i);
 		} else {
 			seq_printf( seq,
-			   "%2d: cs:%s st:%s/%s ds:%s/%s\n"
+			   "%2d: cs:%s st:%s/%s ds:%s/%s %c%c%c%c\n"
 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
 			   "lo:%d pe:%d ua:%d ap:%d\n",
 			   i, sn,
@@ -209,6 +209,10 @@
 			   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,

From drbd-cvs at lists.linbit.com  Fri Mar 31 15:12:56 2006
From: drbd-cvs at lists.linbit.com (drbd-cvs@lists.linbit.com)
Date: Fri Mar 31 15:12:57 2006
Subject: [DRBD-cvs] svn commit by phil - r2129 - trunk/documentation - *
	Updated the manpage of drbdsetup to match release 8.0
Message-ID: <20060331131256.E99AB144CC@mail.linbit.com>

Author: phil
Date: 2006-03-31 15:12:56 +0200 (Fri, 31 Mar 2006)
New Revision: 2129

Modified:
   trunk/documentation/drbdmeta.sgml
   trunk/documentation/drbdsetup.sgml
Log:
* Updated the manpage of drbdsetup to match release 8.0.
* Small updates to the manpage of drbdmeta.


Modified: trunk/documentation/drbdmeta.sgml
===================================================================
--- trunk/documentation/drbdmeta.sgml	2006-03-31 12:49:16 UTC (rev 2128)
+++ trunk/documentation/drbdmeta.sgml	2006-03-31 13:12:56 UTC (rev 2129)
@@ -1,6 +1,6 @@
 <!DOCTYPE RefEntry PUBLIC "-//Davenport//DTD DocBook V3.0//EN">
 <refentry>
-  <docinfo><date>19 Apr 2005</date></docinfo>
+  <docinfo><date>31 March 2006</date></docinfo>
   
   <refmeta>
     <refentrytitle>drbdmeta</refentrytitle>
@@ -17,9 +17,9 @@
       <command>drbdmeta</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
       <group>
-	<arg choice="plain">v06<replaceable>minor</replaceable></arg>
-	<arg choice="plain">v07<replaceable>meta_dev index</replaceable></arg>
-	<arg choice="plain">v08<replaceable>meta_dev index</replaceable></arg>
+	<arg choice="plain">v06 <replaceable>minor</replaceable></arg>
+	<arg choice="plain">v07 <replaceable>meta_dev index</replaceable></arg>
+	<arg choice="plain">v08 <replaceable>meta_dev index</replaceable></arg>
       </group>
       <arg choice="req"><replaceable>command</replaceable></arg>
       <arg rep="repeat"><replaceable>cmd args</replaceable></arg>
@@ -84,6 +84,15 @@
 	  communicate with the DRBD stack on this host.
         </para></listitem>
       </varlistentry>
+      <varlistentry>
+        <term>dstate</term>
+        <listitem><para>
+          Prints the state of the backing storag's data. The output 
+	  is always followed by '/DUnknown' since drbdmeta only looks
+	  at the local meta data.
+        </para></listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
   <refsect1>
@@ -106,6 +115,13 @@
 	  Specify it in the same way as get-gi shows it.
 	</para></listitem>
       </varlistentry>
+      <varlistentry>
+        <term>restore-md <replaceable>dump_file</replaceable></term>
+        <listitem><para>
+          Reads the <replaceable>dump_file</replaceable> and writes
+	  the it to the meta data.
+	</para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 

Modified: trunk/documentation/drbdsetup.sgml
===================================================================
--- trunk/documentation/drbdsetup.sgml	2006-03-31 12:49:16 UTC (rev 2128)
+++ trunk/documentation/drbdsetup.sgml	2006-03-31 13:12:56 UTC (rev 2129)
@@ -1,6 +1,6 @@
 <!DOCTYPE RefEntry PUBLIC "-//Davenport//DTD DocBook V3.0//EN">
 <refentry> 
-  <docinfo><date>6 Apr 2003</date></docinfo>
+  <docinfo><date>30 March 2006</date></docinfo>
 
   <refmeta>
     <refentrytitle>drbdsetup</refentrytitle>
@@ -22,6 +22,7 @@
       <arg choice="req"><replaceable>meta_data_index</replaceable></arg>
       <arg>-d<arg choice="req"><replaceable>size</replaceable></arg></arg>
       <arg>-e<arg choice="req"><replaceable>err_handler</replaceable></arg></arg>
+      <arg>-b</arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>drbdsetup</command>
@@ -38,13 +39,23 @@
       <arg>-S<arg choice="req"><replaceable>size</replaceable></arg></arg>
       <arg>-k<arg choice="req"><replaceable>count</replaceable></arg></arg>
       <arg>-d<arg choice="req"><replaceable>discon_handler</replaceable></arg></arg>
+      <arg>-e<arg choice="req"><replaceable>max_epoch_size</replaceable></arg></arg>
+      <arg>-b<arg choice="req"><replaceable>max_buffers</replaceable></arg></arg>
+      <arg>-m</arg>
+      <arg>-a<arg choice="req"><replaceable>hash_alg</replaceable></arg></arg>
+      <arg>-x<arg choice="req"><replaceable>shared_secret</replaceable></arg></arg>
+      <arg>-A<arg choice="req"><replaceable>asb-0p-policy</replaceable></arg></arg>
+      <arg>-B<arg choice="req"><replaceable>asb-1p-policy</replaceable></arg></arg>
+      <arg>-C<arg choice="req"><replaceable>asb-2p-policy</replaceable></arg></arg>
+      <arg>-D</arg>
+
     </cmdsynopsis>
     <cmdsynopsis>
       <command>drbdsetup</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
       <arg choice="req">syncer</arg>
       <arg>-k</arg>
-      <arg>-g<arg choice="req"><replaceable>group</replaceable></arg></arg>
+      <arg>-a<arg choice="req"><replaceable>dev_minor</replaceable></arg></arg>
       <arg>-r<arg choice="req"><replaceable>rate</replaceable></arg></arg>
       <arg>-e<arg choice="req"><replaceable>extents</replaceable></arg></arg>
     </cmdsynopsis>
@@ -67,8 +78,6 @@
       <command>drbdsetup</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
       <arg choice="req">primary</arg>
-      <arg>-h</arg>
-      <arg>-t</arg>
       <arg>-d</arg>
     </cmdsynopsis>
     <cmdsynopsis>
@@ -79,13 +88,6 @@
     <cmdsynopsis>
       <command>drbdsetup</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
-      <arg choice="req">on_primary</arg>
-      <arg>-h</arg>
-      <arg>-t</arg>
-    </cmdsynopsis>
-    <cmdsynopsis>
-      <command>drbdsetup</command>
-      <arg choice="req"><replaceable>device</replaceable></arg>
       <arg choice="req">invalidate</arg>
     </cmdsynopsis>
     <cmdsynopsis>
@@ -120,12 +122,42 @@
     <cmdsynopsis>
       <command>drbdsetup</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
+      <arg choice="req">dstate</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>drbdsetup</command>
+      <arg choice="req"><replaceable>device</replaceable></arg>
       <arg choice="req">resize</arg>
       <arg>-d<arg choice="req"><replaceable>size</replaceable></arg></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>drbdsetup</command>
       <arg choice="req"><replaceable>device</replaceable></arg>
+      <arg choice="req">pause-sync</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>drbdsetup</command>
+      <arg choice="req"><replaceable>device</replaceable></arg>
+      <arg choice="req">resume-sync</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>drbdsetup</command>
+      <arg choice="req"><replaceable>device</replaceable></arg>
+      <arg choice="req">outdate</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>drbdsetup</command>
+      <arg choice="req"><replaceable>device</replaceable></arg>
+      <arg choice="req">show-gi</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>drbdsetup</command>
+      <arg choice="req"><replaceable>device</replaceable></arg>
+      <arg choice="req">get-gi</arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>drbdsetup</command>
+      <arg choice="req"><replaceable>device</replaceable></arg>
       <arg choice="req">show</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -200,6 +232,22 @@
 	    </para>
 	  </listitem>
 	</varlistentry>
+	<varlistentry>
+	  <term><option>-b</option>,
+	  <option>--split-brain-fix</option></term>
+	  <listitem>
+	    <para>
+	      With that options set a primary node that looses contact to its
+	      its peer tries to outdate the peer. (This communication
+	      may happen over alternative communication pathes, see
+	      the <option>outdate-peer</option> handler). An outdated node
+	      refuses to become primary (although that can be overruled
+	      by an administrator).
+	      This mechanism helps to circumvent after split brain 
+	      situations before they happen.
+	    </para>
+	  </listitem>
+	</varlistentry>
       </variablelist>
     </refsect2>
     <refsect2>
@@ -326,6 +374,147 @@
 	    </para>
 	  </listitem>
 	</varlistentry>
+	<varlistentry>
+	  <term><option>-m</option>,
+	  <option>--allow-two-primaries </option></term>
+	  <listitem>
+	    <para>
+	      With this option set you might make both nodes primary. You
+	      only should use this options if you use a shared storage
+	      file system on top of DRBD. At the time of writing the only
+	      ones are: OCFS2 and GFS. If you use this option with any 
+	      other filesystem you are goint to crash your nodes and to
+	      corrupt your data!
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term><option>-a</option>,
+	  <option>--cram-hmac-alg </option><replaceable>alg</replaceable></term>
+	  <listitem>
+	    <para>
+	      You need to specifying the HMAC algorithm to enable peer
+	      authentication at all. It is strongly enouraged to use
+	      peer authentication.
+	      The HMAC algorithm which will be used for the challenge
+	      response authentication of the peer. You might specify any
+	      digest algorithm that is named in /proc/crypto.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term><option>-x</option>,
+	  <option>--shared-secret </option><replaceable>secret</replaceable></term>
+	  <listitem>
+	    <para>
+	      The shared secret used in peer authentication. May be up to
+	      64 characters.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term><option>-A</option>,
+	  <option>--asb-0p-policy </option><replaceable>asb-0p-policy</replaceable></term>
+	  <listitem>
+	    <para>
+	    possible policies are:
+	    </para>
+            <variablelist>
+              <varlistentry><term><option>disconnect</option></term>
+	        <listitem><para>
+		  No automatic resynchronisation, simply disconnect.
+		</para></listitem></varlistentry>
+	        <varlistentry><term><option>discard-younger-primary</option></term>
+		<listitem><para>
+		  Auto sync from the node that was primary before the split 
+		  brain situation happened.
+		</para></listitem></varlistentry>
+		<varlistentry><term><option>discard-older-primary</option></term> 
+		<listitem><para>
+		Auto sync from the node that became primary as second during 
+		the split brain situation.
+		</para></listitem></varlistentry>
+		<varlistentry><term><option>discard-least-changes</option></term> 
+		<listitem><para>
+		Auto sync from the node that touched more blocks during the 
+		split brain situation.
+		</para></listitem></varlistentry>
+		<varlistentry><term><option>discard-node-NODENAME</option></term> 
+		<listitem><para>
+		Auto sync to the named node.
+		</para></listitem></varlistentry>
+              </variablelist>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-B</option>,
+	  <option>--asb-1p-policy </option><replaceable>asb-1p-policy</replaceable></term>
+	  <listitem>
+	    <para>
+	    possible policies are:
+	    </para>
+            <variablelist>
+              <varlistentry><term><option>disconnect</option></term>
+	        <listitem><para>
+		  No automatic resynchronisation, simply disconnect.
+		</para></listitem></varlistentry>
+	        <varlistentry><term><option>consensus</option></term>
+		<listitem><para>
+		  Discard the version of the secondary if the outcome
+                  if the <option>after-sb-0pri</option> algorithm would also 
+		  destroy the current secondary's data. Otherwise disconnect.
+		</para></listitem></varlistentry>
+		<varlistentry><term><option>discard-secondary</option></term> 
+		<listitem><para>
+		  Discard the secondary's version.
+		</para></listitem></varlistentry>
+		<varlistentry><term><option>panic-primary</option></term> 
+		<listitem><para>
+		  Always honour the outcome of the <option>after-sb-0pri
+		  </option> algorithm. In case it decides the the current
+		  secondary has the right data, it panics the
+		  current primary.
+		</para></listitem></varlistentry>
+              </variablelist>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-C</option>,
+	  <option>--asb-2p-policy </option><replaceable>asb-2p-policy</replaceable></term>
+	  <listitem>
+	    <para>
+	    possible policies are:
+	    </para>
+            <variablelist>
+              <varlistentry><term><option>disconnect</option></term>
+	        <listitem><para>
+		  No automatic resynchronisation, simply disconnect.
+		</para></listitem></varlistentry>
+	        <varlistentry><term><option>panic</option></term>
+		<listitem><para>
+		  Honour the outcome of the <option>after-sb-0pri</option> 
+		  policy and panic the other node.
+		</para></listitem></varlistentry>
+              </variablelist>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term><option>-D</option>,
+	  <option>--discard-my-data </option></term>
+	  <listitem>
+	    <para>
+	      Use this option to manually recover from a split brain 
+	      situation. In case you do not have any automatic after
+	      split brain policies selected, the nodes refuse to 
+	      connect. By passing this option you make a node to
+	      sync target immediatly after sucessfull connect.
+	    </para>
+	  </listitem>
+	</varlistentry>
+
       </variablelist>
     </refsect2>
     <refsect2>
@@ -358,15 +547,13 @@
 	  </para></listitem>
 	</varlistentry>
 	<varlistentry>
-	  <term><option>-g</option>,
-	  <option>--sync-group <replaceable>group</replaceable></option></term>
+	  <term><option>-a</option>,
+	  <option>--after <replaceable>minor</replaceable></option></term>
 	  <listitem>
 	    <para> 
-	      Resynchronization of all devices in one group runs
-	      parallel. Groups are serialized in ascending order. You should
-	      avoid that devices which lower devices share one and the same
-	      physical disk sync in parallel. The default group is
-	      0. I.e. per default all devices sync parallel.
+	      Start resync on this device only if the device with
+	      <replaceable>minor</replaceable> is already in connected 
+	      state. Other wise this device wait in SyncPause state.
 	  </para>
 	  </listitem>
 	</varlistentry>
@@ -530,6 +717,12 @@
       </para>
     </refsect2>
     <refsect2>
+      <title>dstate</title>
+      <para>
+	Show the current state of the backing storeage devices. (local/peer)
+      </para>
+    </refsect2>
+    <refsect2>
       <title>resize</title>
       <para>
 	This causes DRBD to reexamine the size of the
@@ -540,6 +733,43 @@
       </para>
     </refsect2>
     <refsect2>
+      <title>pause-sync</title>
+      <para>
+        Temporarily suspend an ongoing resynchronisation by setting the local
+	pause flag. Resync only progresses if neighter the local nor the
+	remote pause flag is set.It might be desirable to postpone DRBD's 
+	resynchronisation after eventual resynchronisation of the backing
+	storage's RAID setup.
+      </para>
+    </refsect2>
+    <refsect2>
+      <title>resume-sync</title>
+      <para>
+        Unset the local sync pause flag.
+      </para>
+    </refsect2>
+    <refsect2>
+      <title>outdate</title>
+      <para>
+        Mark the data on the local backing storage as outdated. An outdated
+	device refuses to become primary. This is used in conjuction with 
+	<option>split-brain-fix</option> and by the peer's outdate-peer 
+	handler.
+      </para>
+    </refsect2>
+    <refsect2>
+      <title>show-gi</title>
+      <para>
+        Displays the device's data generaion identifiers verbosily.
+      </para>
+    </refsect2>
+    <refsect2>
+      <title>get-gi</title>
+      <para>
+        Displays the device's data generaion identifiers.
+      </para>
+    </refsect2>
+    <refsect2>
       <title>show</title>
       <para>
 	Shows all available configuration information of the
@@ -558,7 +788,7 @@
 
   <refsect1>
     <title>Version</title>
-    <simpara>This document is correct for version 0.7.15 of the DRBD distribution.
+    <simpara>This document is for version 8.0 of the DRBD distribution.
     </simpara>
   </refsect1>
 

