diff -Nrup fr1-2.17.orig/Makefile fr1-2.17/Makefile
--- fr1-2.17.orig/Makefile	2005-07-18 02:05:22.185697775 +0200
+++ fr1-2.17/Makefile	2005-07-18 02:09:52.135327528 +0200
@@ -46,11 +46,11 @@ all:    build
 	$(MAKE) -C $(BUILD) -f ../../src/Makefile $@
 else
 all:
-	echo "*******************************************************"
-	echo "* For 2.6 kernels, use the patches for the moment -    "
-	echo "* it\'s presently too hard to do compilation of modules"
-	echo "* outside the kernel source tree.                      "
-	echo "*******************************************************"
+	@echo "*******************************************************"
+	@echo "* For 2.6 kernels, use the patches for the moment -    "
+	@echo "* it's presently too hard to do compilation of modules"
+	@echo "* outside the kernel source tree.                      "
+	@echo "*******************************************************"
 endif
 
 clean:
diff -Nrup fr1-2.17.orig/patches/already-incorporated/async-write-already-incorporated-do-not-apply.patch fr1-2.17/patches/already-incorporated/async-write-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/already-incorporated/async-write-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/already-incorporated/async-write-already-incorporated-do-not-apply.patch	2004-08-19 10:48:12.000000000 +0200
@@ -0,0 +1,126 @@
+--- linux-2.4.24-xfs/drivers/md/raid1.c.orig	Fri Jun 13 16:51:34 2003
++++ linux-2.4.24-xfs/drivers/md/raid1.c	Sun Aug 15 04:38:00 2004
+@@ -55,6 +77,9 @@
+ static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED;
+ struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail;
+ 
++/* PTB module params */
++static int async;   /* async writes */
++
+ static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt)
+ {
+ 	/* return a linked list of "cnt" struct buffer_heads.
+@@ -396,11 +422,18 @@
+ static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate)
+ {
+ 	struct buffer_head *bh = r1_bh->master_bh;
++	raid1_conf_t * conf = mddev_to_conf(r1_bh->mddev);
+ 
+-	io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev),
+-			test_bit(R1BH_SyncPhase, &r1_bh->state));
+ 
+-	bh->b_end_io(bh, uptodate);
++        /* PTB if nobody has done the final end_io yet, do it now */
++	if (!test_and_set_bit(R1BH_AsyncPhase, &r1_bh->state)) {
++
++                PRINTK(KERN_DEBUG "raid1: sync end i/o on sectors %lu-%lu\n",
++                        bh->b_rsector, bh->b_rsector + (bh->b_size >> 9) - 1);
++	        io_request_done(bh->b_rsector, conf,
++	                test_bit(R1BH_SyncPhase, &r1_bh->state));
++	        bh->b_end_io(bh, uptodate);
++	} 
+ 	raid1_free_r1bh(r1_bh);
+ }
+ void raid1_end_request (struct buffer_head *bh, int uptodate)
+@@ -452,10 +522,35 @@
+ 	 *
+ 	 * Let's see if all mirrored write operations have finished 
+ 	 * already.
++	 *
++	 * PTB In any case, do the end io early on the master bh if we are
++	 * uptodate, and AsyncIO is set on the bh. We set AsyncPhase
++	 * when this happens, so we don't do it twice, inadvertently.
+ 	 */
++		
++        if (uptodate
++        &&  test_bit(R1BH_AsyncIO, &r1_bh->state)
++        && !test_and_set_bit(R1BH_AsyncPhase, &r1_bh->state)) {
++
++	        struct buffer_head *mbh = r1_bh->master_bh;
++
++	        raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev);
+ 
++                PRINTK(KERN_DEBUG "raid1: async end i/o on sectors %lu-%lu\n",
++                        mbh->b_rsector, mbh->b_rsector + (mbh->b_size >> 9) - 1);
++
++	        io_request_done(mbh->b_rsector, conf,
++			test_bit(R1BH_SyncPhase, &r1_bh->state));
++	        mbh->b_end_io(mbh, uptodate);
++        }
++
+-	if (atomic_dec_and_test(&r1_bh->remaining))
++	if (atomic_dec_and_test(&r1_bh->remaining)) {
++	        if (test_and_set_bit(R1BH_AsyncIO, &r1_bh->state)) {
++                        /* we made a copy for the buffer, remove it now */
++                        kfree(bh->b_data);
++                }
+ 		raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state));
++        }
+ }
+ 
+ /*
+@@ -581,6 +714,7 @@
+ 	int disks = MD_SB_DISKS;
+	int i, sum_bhs = 0;
+ 	struct mirror_info *mirror;
++	char * async_data; // copy of buffer used for async writes
+ 
+ 	if (!buffer_locked(bh))
+ 		BUG();
+@@ -619,6 +754,7 @@
+ 	r1_bh->master_bh = bh;
+ 	r1_bh->mddev = mddev;
+ 	r1_bh->cmd = rw;
++	async_data = NULL;
+ 
+ 	if (rw == READ) {
+ 		/*
+@@ -643,6 +780,20 @@
+ 	 */
+ 
+ 	bhl = raid1_alloc_bh(conf, conf->raid_disks);
++
++
++       /*
++        * PTB Do async i/o if we marked the bitmap (so it's safe to)
++        * and we are supposed to.
++       */
++       if (async) {
++                async_data = kmalloc(bh->b_size, GFP_KERNEL);
++                if (async_data) {
++                        memcpy(async_data, bh->b_data, bh->b_size);
++                        set_bit(R1BH_AsyncIO, &r1_bh->state);
++                }
++       }
++
+ 	for (i = 0; i < disks; i++) {
+ 		struct buffer_head *mbh;
+ 		if (!conf->mirrors[i].operational) 
+@@ -683,6 +876,8 @@
+  		mbh->b_size       = bh->b_size;
+  		mbh->b_page	  = bh->b_page;
+  		mbh->b_data	  = bh->b_data;
++ 		mbh->b_data       =
++                 test_bit(R1BH_AsyncIO, &r1_bh->state)? async_data : bh->b_data;
+  		mbh->b_list       = BUF_LOCKED;
+  		mbh->b_end_io     = raid1_end_request;
+  		mbh->b_private    = r1_bh;
+--- linux-2.4.24-xfs/include/linux/raid/raid1.h.orig	Mon Feb 16 21:06:33 2004
++++ linux-2.4.24-xfs/include/linux/raid/raid1.h	Mon Aug  9 18:53:57 2004
+@@ -91,4 +91,6 @@
+ #define	R1BH_Uptodate	1
+ #define	R1BH_SyncPhase	2
+ #define	R1BH_PreAlloc	3	/* this was pre-allocated, add to free list */
++#define	R1BH_AsyncPhase 4
++#define	R1BH_AsyncIO    5
+ #endif
diff -Nrup fr1-2.17.orig/patches/already-incorporated/bitmap-base-already-incorporated-do-not-apply.patch fr1-2.17/patches/already-incorporated/bitmap-base-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/already-incorporated/bitmap-base-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/already-incorporated/bitmap-base-already-incorporated-do-not-apply.patch	2004-09-18 09:22:53.000000000 +0200
@@ -0,0 +1,1104 @@
+--- linux-2.4.22-xfs/include/linux/raid/md_p.h.orig	Tue Nov 14 22:16:37 2000
++++ linux-2.4.22-xfs/include/linux/raid/md_p.h	Sun Feb 22 21:03:24 2004
+@@ -154,6 +154,9 @@
+ 	/*
+ 	 * Reserved
+ 	 */
++#define MD_SB_BITMAP_REPAIR(sb) (sb)->reserved[0]
++#define MD_SB_EVENTS_LO(sb)     (sb)->reserved[2]
++#define MD_SB_EVENTS_HI(sb)     (sb)->reserved[3]
+ 	__u32 reserved[MD_SB_RESERVED_WORDS];
+ 
+ 	/*
+--- linux-2.4.24-xfs/drivers/md/md.c.orig	Thu Jan 29 18:19:37 2004
++++ linux-2.4.24-xfs/drivers/md/md.c	Sun Feb 22 21:03:24 2004
+@@ -26,6 +26,16 @@
+    You should have received a copy of the GNU General Public License
+    (for example /usr/src/linux/COPYING); if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++   Changes 31/1/2003 by Peter T.  Breuer <ptb@it.uc3m.es> to support
++   hotadd directly after setfaulty without intervening hotremove
++   ("hotrepair") when there is no persistent superblock, and to flag a
++   potential hotrepair when an old disk is re-added and the uuid matches
++   ours.  The flag is used by the raid1 driver, at the moment, in order
++   to trigger an intelligent resync.
++  
++   Yet more changes by PTB 12/3/2003 to notify devices via ioctls when
++   they have been incorporated or removed from a raid array.
+ */
+ 
+ #include <linux/module.h>
+@@ -58,6 +71,8 @@
+ # define dprintk(x...) do { } while(0)
+ #endif
+ 
++#define MD_BITMAP_SUPPORT 1
++
+ #ifndef MODULE
+ static void autostart_arrays (void);
+ #endif
+@@ -524,7 +543,8 @@
+ 		printk(NO_SB,partition_name(dev));
+ 		return -EINVAL;
+ 	}
+-	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
++	printk(KERN_INFO "%s (read) [events: %08lx]\n",
++                partition_name(rdev->dev), (unsigned long)rdev->sb->events_lo);
+ 	ret = 0;
+ abort:
+ 	return ret;
+@@ -611,6 +631,68 @@
+ 	return 0;
+ }
+ 
++#ifdef MD_BITMAP_SUPPORT
++static int
++md_hot_add_disk(kdev_t dev, int cmd) {
++
++        static mdk_rdev_t * find_rdev_all(kdev_t dev);
++        static int hot_add_disk(mddev_t * mddev, kdev_t dev);
++        static int set_disk_faulty(mddev_t *mddev, kdev_t dev);
++
++        mdk_rdev_t *rdev;
++        mddev_t *mddev;
++        int res;
++
++        rdev = find_rdev_all(dev);
++        if (!rdev)
++                return -EINVAL;
++        mddev = rdev->mddev;
++        if (!mddev)
++                return -EINVAL;
++
++        switch(cmd) {
++            case HOT_ADD_DISK:
++                res = hot_add_disk(mddev, dev);
++                return res;
++            case SET_DISK_FAULTY:
++	        res = set_disk_faulty(mddev, dev);
++                return res;
++        }
++        return -EINVAL;
++}
++
++static void
++notify_device (mddev_t * mddev, kdev_t dev)
++{
++#ifndef BLKMDNTFY
++#define BLKMDNTFY _IOW(0x12,133,sizeof(int))
++#endif
++	struct block_device *bdev;
++	printk (KERN_INFO "md%d: notifying dev %x\n", mdidx(mddev), dev);
++        bdev = bdget (dev);
++	if (!bdev)
++                return;
++        ioctl_by_bdev (bdev, BLKMDNTFY, MKDEV (MD_MAJOR, mddev->__minor));
++#ifndef BLKMDRGTR
++#define BLKMDRGTR _IOW(0x12,135,sizeof(unsigned long))
++#endif
++        ioctl_by_bdev (bdev, BLKMDRGTR, (unsigned long)md_hot_add_disk);
++}
++static void
++unnotify_device (mddev_t * mddev, kdev_t dev)
++{
++#ifndef BLKMDUNTFY
++#define BLKMDUNTFY _IOW(0x12,134,sizeof(int))
++#endif
++	struct block_device *bdev;
++	printk (KERN_INFO "md%d: unnotifying dev %x\n", mdidx(mddev), dev);
++        bdev = bdget (dev);
++	if (!bdev)
++                return;
++        ioctl_by_bdev(bdev, BLKMDUNTFY, MKDEV(MD_MAJOR, mddev->__minor));
++}
++#endif /* MD_BITMAP_SUPPORT */
++
+ static MD_LIST_HEAD(all_raid_disks);
+ static MD_LIST_HEAD(pending_raid_disks);
+ 
+@@ -634,6 +716,9 @@
+ 	rdev->mddev = mddev;
+ 	mddev->nb_dev++;
+ 	printk(KERN_INFO "md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev);
++#ifdef MD_BITMAP_SUPPORT
++        notify_device(mddev, rdev->dev);
++#endif /* MD_BITMAP_SUPPORT */
+ }
+ 
+ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
+@@ -642,6 +727,9 @@
+ 		MD_BUG();
+ 		return;
+ 	}
++#ifdef MD_BITMAP_SUPPORT
++        unnotify_device(rdev->mddev, rdev->dev);
++#endif /* MD_BITMAP_SUPPORT */
+ 	md_list_del(&rdev->same_set);
+ 	MD_INIT_LIST_HEAD(&rdev->same_set);
+ 	rdev->mddev->nb_dev--;
+@@ -2383,6 +2471,9 @@
+ 	unsigned int size;
+ 	mdk_rdev_t *rdev;
+ 	mdp_disk_t *disk;
++#ifdef MD_BITMAP_SUPPORT
++        int hotrepair = 0;
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 	if (!mddev->pers)
+ 		return -ENODEV;
+@@ -2398,11 +2489,47 @@
+ 
+ 	persistent = !mddev->sb->not_persistent;
+ 
++#ifdef MD_BITMAP_SUPPORT
++        /*
++         * This is a do at most once loop because the remove in the loop will
++         * cause the test to fail the next time round. And if that
++         * doesn't break us out, then the hotrepair count will.
++         */
++        while ((rdev = find_rdev(mddev, dev)) != NULL) {
++
++	        if (hotrepair || rdev->dev != dev || !rdev->faulty) {
++	                printk(KERN_WARNING "md%d: cannot add existing component %x\n",
++                                mdidx(mddev), dev);
++	                return -EBUSY;
++                }
++        /*
++         * Allow "hotrepair" of merely faulty device too if no superblock to
++         * go by or (later) if there is a matching superblock. We assume then
++         * that hotadd after setfaulty of the same device is a
++         * hotrepair.
++         */
++	        printk(KERN_WARNING "md%d: repair of faulty disk %x!\n",
++	                mdidx(mddev), dev);
++
++         /* Remove will cause find_rdev to fail next time */
++	        err = hot_remove_disk(mddev, dev);
++                if (err < 0) {
++	                printk(KERN_WARNING "md%d: remove disk %x errored\n",
++                                mdidx(mddev), dev);
++	                return err;       
++                }
++        /* This will inevitably error us out of the loop interior next time */
++                hotrepair = 1;
++        }
++
++	err = md_import_device (dev, persistent);
++#else
+ 	rdev = find_rdev(mddev, dev);
+ 	if (rdev)
+ 		return -EBUSY;
+ 
+ 	err = md_import_device (dev, 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 	if (err) {
+ 		printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
+ 		return -EINVAL;
+@@ -2426,6 +2552,58 @@
+ 		err = -ENOSPC;
+ 		goto abort_export;
+ 	}
++#ifdef MD_BITMAP_SUPPORT
++        /* let's check the new disk sb at this poimt */
++        if (persistent && rdev->sb 
++                && rdev->sb->set_uuid0 == mddev->sb->set_uuid0
++                && rdev->sb->set_uuid1 == mddev->sb->set_uuid1
++                && rdev->sb->set_uuid2 == mddev->sb->set_uuid2
++                && rdev->sb->set_uuid3 == mddev->sb->set_uuid3) {
++                unsigned long long disk_events, bitmap_events;
++                disk_events = rdev->sb->events_lo;
++                bitmap_events = 0;
++                //bitmap_events |= MD_SB_EVENTS_HI(mddev->sb);
++                //bitmap_events <<= 32;
++                bitmap_events |= MD_SB_EVENTS_LO(mddev->sb);
++
++                /* This is where we should examine conf->events_chkpt_*
++                 */
++                if (disk_events == bitmap_events - 1) {
++                        printk(KERN_WARNING "md%d: warning - new disk %x nearly too old for repair (disk %Lu < bitmap %Lu)\n",
++                        mdidx(mddev), dev, disk_events, bitmap_events);
++                }
++                if (disk_events < bitmap_events - 1) {
++                        /* new disk is too old! */
++                        hotrepair = 0;
++                        printk(KERN_INFO "md%d: new disk %x too old for repair (disk %Lu < bitmap %Lu)\n",
++                                mdidx(mddev), dev, disk_events, bitmap_events);
++                } else {
++                        hotrepair = 1;
++                        printk(KERN_INFO "md%d: repairing old mirror component %x (disk %Lu >= bitmap %Lu)\n",
++                                mdidx(mddev), dev, disk_events, bitmap_events);
++                }
++        } else if (!persistent && hotrepair) {
++                hotrepair = 1;
++                printk(KERN_INFO "md: forced repair of mirror component %x\n",
++                        dev);
++        } else {
++                /* failed match */
++                hotrepair = 0;
++                printk(KERN_INFO "md: adding new mirror component %x\n",
++                        dev);
++                printk(KERN_DEBUG "md: old uuid %x %x %x %x\n",
++                        mddev->sb->set_uuid0,
++                        mddev->sb->set_uuid1,
++                        mddev->sb->set_uuid2,
++                        mddev->sb->set_uuid3);
++                printk(KERN_DEBUG "md: new uuid %x %x %x %x\n",
++                        rdev->sb->set_uuid0,
++                        rdev->sb->set_uuid1,
++                        rdev->sb->set_uuid2,
++                        rdev->sb->set_uuid3);
++        }
++#endif /* MD_BITMAP_SUPPORT */
++
+ 	bind_rdev_to_array(rdev, mddev);
+ 
+ 	/*
+@@ -2480,6 +2658,17 @@
+ 	mddev->sb->spare_disks++;
+ 	mddev->sb->working_disks++;
+ 
++#ifdef MD_BITMAP_SUPPORT
++        /*
++         * Maybe say something nice - 1 means we want to respect
++         * the bitmap in raid1 resync if there is one, 0
++         * means we need to kill any bitmap that we have been
++         * saving but we'll do it in the raid1 resync instead of here
++         */
++        printk(KERN_DEBUG "md%d: set repair bit to %d on superblock\n",
++                mdidx(mddev), hotrepair);
++        MD_SB_BITMAP_REPAIR(mddev->sb) = hotrepair;
++#endif /* MD_BITMAP_SUPPORT */
+ 	mddev->sb_dirty = 1;
+ 	md_update_sb(mddev);
+ 
+@@ -3540,8 +3741,12 @@
+ 		 * about not overloading the IO subsystem. (things like an
+ 		 * e2fsck being done on the RAID array should execute fast)
+ 		 */
+-		if (md_need_resched(current))
+-			schedule();
++		if (md_need_resched(current)) {
++                        /* PTB this seems not to progress when over loop dev */
++ 
++		        current->state = TASK_INTERRUPTIBLE;
++			md_schedule_timeout(1);
++                }
+ 
+ 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
+ 
+--- linux-2.4.22-xfs/drivers/md/Makefile.orig	Thu Jan 29 18:00:08 2004
++++ linux-2.4.22-xfs/drivers/md/Makefile	Sun Feb 22 21:05:08 2004
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_MD_LINEAR)		+= linear.o
+ obj-$(CONFIG_MD_RAID0)		+= raid0.o
+ obj-$(CONFIG_MD_RAID1)		+= raid1.o
++obj-$(CONFIG_MD_BITMAP)	+= bitmap.o
+ obj-$(CONFIG_MD_RAID5)		+= raid5.o xor.o
+ obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
+ obj-$(CONFIG_BLK_DEV_MD)	+= md.o
+--- linux-2.4.22-xfs/drivers/md/bitmap.h.orig	Sun Feb 22 21:03:24 2004
++++ linux-2.4.22-xfs/drivers/md/bitmap.h	Sun Feb 22 21:03:24 2004
+@@ -0,0 +1,56 @@
++#ifndef BITMAP_H
++#define BITMAP_H 1
++
++struct bitmap_page {
++        /*
++         * If a page is missing then we use a per
++         * page pending write count instead. pages is the number of
++         * 4k pages in the map.
++         */ 
++        char * map;
++        /*
++         * more precise count per zone (1/16 page), for emergencies.
++         */
++        short *zoneinfo;
++        /*
++         * count of dirty bits on the page
++         */ 
++        unsigned short  count;
++};
++
++struct bitmap {
++	struct bitmap_page * bp;
++	unsigned long pages;
++
++	int (*start) (struct bitmap * bitmap);
++	void (*stop) (struct bitmap * bitmap);
++	int (*testbit) (struct bitmap * bitmap, unsigned long block);
++	int (*setbits) (struct bitmap * bitmap, unsigned long block, unsigned long nrblocks);
++	int (*clearbits) (struct bitmap * bitmap, unsigned long block, unsigned long nrblocks);
++	int (*active) (struct bitmap * bitmap);
++
++        /* bitmap spinlock */
++	rwlock_t lock;
++
++#define BITMAP_ACTIVE 0x01
++        unsigned long flags;
++
++        /* cache of ready to go pages */
++        unsigned char * freelist;
++        unsigned freecount;
++        /* hi and lo water marks for the cache */
++#define BITMAP_FREELO 2
++#define BITMAP_FREEHI 7
++        unsigned freelo, freehi;
++        /*
++         * number of missing zoneinfo sections
++         */
++        unsigned long missing_zones;
++        unsigned long missing_pages;
++};
++
++
++int bitmap_init(struct bitmap * bitmap, unsigned long blocks);
++void bitmap_destr(struct bitmap * bitmap);
++
++#endif
+--- linux-2.4.22-xfs/drivers/md/bitmap.c.orig	Sun Feb 22 21:03:24 2004
++++ linux-2.4.22-xfs/drivers/md/bitmap.c	Sun Feb 22 21:03:24 2004
+@@ -0,0 +1,743 @@
++/*
++ * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
++ *
++ * bitmap_init   - sets nr blks
++ * bitmap->start - then calls the setup part for the 1st
++ *                 level in the bitmap, which uses memory (kmalloc) so
++ *                 can fail. You should examine the return value. 0 is
++ *                 OK. -ve is FAIL.
++ *
++ * bitmap->stop  - inverse to bitmap->start. kfrees the memory claimed in 
++ *                 bitmap_init.
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <linux/wrapper.h>
++#include <linux/proc_fs.h>  // PTB for kmalloc! How?
++#include <linux/vmalloc.h>  // PTB for vmalloc
++#include <linux/init.h>
++#include <linux/locks.h>
++#include <linux/config.h>
++
++# define DEBUG 1
++
++#include "bitmap.h"
++
++/* use 16 bits of the address as extra bitmap */
++#define ZONESHIFT 4
++/* top 16 bits are nonzero */
++#define IS_ADDRESS(x) \
++  ((( ((unsigned long)(x)) >> ((sizeof(char*)<<3) - (1<<ZONESHIFT))) ) != 0)
++
++#ifndef PRINTK
++#  if DEBUG > 0 
++#    define PRINTK(x...) printk(x)
++#  else
++#    define PRINTK(x...)
++#  endif
++#endif
++
++
++/*
++ * frees mamory kmalloced in init
++ */
++void
++bitmap_destr(struct bitmap *bitmap) {
++
++        unsigned long k;
++        struct bitmap_page * bp;
++        unsigned long pages;
++        void * this_page;
++
++        write_lock(&bitmap->lock);
++        bitmap->flags &= ~BITMAP_ACTIVE;
++        bp = bitmap->bp;
++        pages = bitmap->pages;
++        this_page = bitmap->freelist;
++        bitmap->bp = NULL;
++        bitmap->freelist = NULL;
++        bitmap->freecount = 0;
++        bitmap->missing_pages = pages;
++        bitmap->missing_zones = pages;
++        write_unlock(&bitmap->lock);
++
++        if (bp) {
++                for (k = 0; k < pages; k++) {
++                        if (IS_ADDRESS(bp[k].map)) {
++                                kfree (bp[k].map);
++                                bp[k].map = NULL;
++                        }
++                        if (IS_ADDRESS(bp[k].zoneinfo)) {
++                                kfree (bp[k].zoneinfo);
++                                bp[k].zoneinfo = NULL;
++                        }
++                }
++                vfree (bp);
++        }
++
++        /* remove the old freelist entries offline */
++        while (IS_ADDRESS(this_page)) {
++                void * next_page = *(void **)this_page;
++                kfree(this_page);
++                this_page = next_page;
++        }
++}
++
++/* 
++ * tests if the bitmap is marked active (has been started)
++ */
++static int
++bitmap_active(struct bitmap * bitmap) {
++        int res = 0;
++        if (!bitmap)
++                return res;
++        read_lock(&bitmap->lock);
++        res = (bitmap->flags & BITMAP_ACTIVE) != 0;
++        read_unlock(&bitmap->lock);
++        return res;
++}
++
++/*
++ * replaces kmalloc for bitmap pages. Retrieves from the free list
++ * cache frist of all. If the cache is below lowater, then we also call
++ * for more pages at the same time and cache them (upto hiwater).
++ */
++static unsigned char *
++bitmap_alloc_page(struct bitmap *bitmap) {
++        unsigned char *page;
++
++        write_lock(&bitmap->lock);
++
++        /* check if we can return immediately from freelist */
++        if (bitmap->freecount > bitmap->freelo) {
++                page = bitmap->freelist;
++                bitmap->freelist = *(unsigned char **)page;
++                bitmap->freecount--;
++                PRINTK(KERN_DEBUG "bitmap: alloc page exits OK with page count %d\n",
++                        bitmap->freecount);
++                write_unlock(&bitmap->lock);
++                memset(page, 0, PAGE_SIZE); // PTB zero page on alloc
++                return page;
++        }
++
++        /* nope - we have to allocate some more, so go to hiwater */
++        while (bitmap->freecount < bitmap->freehi) {
++                write_unlock(&bitmap->lock);
++	        page = kmalloc (PAGE_SIZE, GFP_KERNEL);
++                write_lock(&bitmap->lock);
++                if (!page)
++                        break;
++                *(unsigned char **)page = bitmap->freelist;
++                bitmap->freelist = page;
++                bitmap->freecount++;
++        }
++
++        /* finally take from the freelist anyway, if we can ! */
++        if (bitmap->freecount > 0) {
++                page = bitmap->freelist;
++                bitmap->freelist = *(unsigned char **)page;
++                bitmap->freecount--;
++                PRINTK(KERN_DEBUG "bitmap: alloc page exits OK with page count %d\n",
++                        bitmap->freecount);
++                write_unlock(&bitmap->lock);
++                memset(page, 0, PAGE_SIZE); // PTB zero page on alloc
++                return page;
++        }
++
++        PRINTK(KERN_DEBUG "bitmap: alloc page exits FAIL with page count %d\n",
++                bitmap->freecount);
++        write_unlock(&bitmap->lock);
++
++        return NULL;
++}
++
++/*
++ * replaces kfree on bitmap pages. Cannot be called under lock.
++ * adds a page that has already been disconnected from the bitmap
++ * struct to the free list, or discards it if the list is at hiwater.
++ */
++static void
++bitmap_free_page(struct bitmap * bitmap, unsigned char * page) {
++        
++        if (!page)
++                return;
++
++        write_lock(&bitmap->lock);
++        PRINTK(KERN_DEBUG "bitmap: free page enters with page count %d\n",
++                bitmap->freecount);
++        if (bitmap->freecount < bitmap->freehi) {
++                /* add to free list */
++                *(unsigned char **)page = bitmap->freelist;
++                bitmap->freelist = page;
++                bitmap->freecount++;
++                PRINTK(KERN_DEBUG "bitmap: free page exits with page count %d\n",
++                        bitmap->freecount);
++                write_unlock(&bitmap->lock);
++                return;
++        }
++        PRINTK(KERN_DEBUG "bitmap: free page exits with page count %d\n",
++                bitmap->freecount);
++        write_unlock(&bitmap->lock);
++        kfree(page);
++}
++
++/*
++ * mark bitmap inactive and maybe prune the page cache
++ */
++static void
++bitmap_stop(struct bitmap * bitmap) {
++
++        void * this_page;
++
++        write_lock(&bitmap->lock);
++        bitmap->flags &= ~BITMAP_ACTIVE;
++        this_page = bitmap->freelist;
++        bitmap->freelist = NULL;
++        bitmap->freecount = 0;
++        write_unlock(&bitmap->lock);
++
++        /* remove the old freelist entries offline */
++        while (IS_ADDRESS(this_page)) {
++                void * next_page = *(void **)this_page;
++                kfree(this_page);
++                this_page = next_page;
++        }
++ }
++
++/* 
++ * marks the bitmap active and primes the free page cache.
++ */
++static int
++bitmap_start(struct bitmap * bitmap) {
++
++        struct bitmap_page * bp;
++        unsigned long pages;
++        
++        /* take lock to read data */
++        write_lock(&bitmap->lock);
++        pages = bitmap->pages;
++        bp    = bitmap->bp;
++        write_unlock(&bitmap->lock);
++
++        if (!bp) {
++
++                int k;
++
++                bp = vmalloc (pages * sizeof(*bp));
++                if (!bp) {
++                        printk("bitmap: cannot get %luB of memory!\n",
++                                pages * sizeof(*bp));
++                        return -ENOMEM;
++                }
++                memset (bp, 0, pages * sizeof(*bp));
++
++                for (k = 0; k < pages; k++) {
++                        if (bp[k].zoneinfo)
++                                continue;
++                        bp[k].zoneinfo =
++                                kmalloc (sizeof(*bp[k].zoneinfo)<<ZONESHIFT,
++                                       GFP_KERNEL);
++                        if (bp[k].zoneinfo)
++                                bitmap->missing_zones--;
++                }
++                if (bitmap->missing_zones > 0) {
++                        printk("bitmap: warning! cannot get %ld*%uB memory!\n",
++                              bitmap->missing_zones,
++                              sizeof(*bp->zoneinfo) << ZONESHIFT);
++                }
++        }
++
++        /*
++         * this is 16 shorts or 32 bytes + 4 bytes extra per page of 4096
++         * bytes, which is a reserve of less that 0.1%. But each page
++         * bitmaps 32MB of disk, so a 1GB disk takes 32 pages or 128KB, and
++         * a 1TB disk takes 128MB of pages. In those circumstances,
++         * adding a capital cost of about 108KB doesn't seem bad.
++         */
++                
++
++        write_lock(&bitmap->lock);
++        bitmap->bp = bp;
++
++        bitmap->flags |= BITMAP_ACTIVE;
++        write_unlock(&bitmap->lock);
++
++        /* seed the page cache */
++        bitmap_free_page(bitmap, bitmap_alloc_page(bitmap));
++
++        return 0;
++}
++
++static int
++bitmap_checkpage (struct bitmap *bitmap, unsigned long page)
++{
++        unsigned char * mappage;
++
++        read_lock(&bitmap->lock);
++        if (page < 0 || page >= bitmap->pages) {
++                read_unlock(&bitmap->lock);
++		return -EINVAL;
++        }
++
++        if (bitmap->bp == NULL) {
++                read_unlock(&bitmap->lock);
++		return -ENODEV;
++        }
++
++
++        if (IS_ADDRESS(bitmap->bp[page].map)) {
++                read_unlock(&bitmap->lock);
++		return 0;
++        }
++        read_unlock(&bitmap->lock);
++
++        /* the page address was NULL */
++
++	if ((mappage = bitmap_alloc_page(bitmap)) == NULL) {
++                /* failed - check to see if we have backup counters */
++                void * tmp;
++                int need_new_zoneinfo = 0;
++
++                write_lock(&bitmap->lock);
++                if (!IS_ADDRESS(bitmap->bp[page].zoneinfo))
++                        need_new_zoneinfo = 1;
++                write_unlock(&bitmap->lock);
++
++                if (need_new_zoneinfo) {
++                        /* rarely, we might make an extra backup counter */
++                        tmp = kmalloc(sizeof(*bitmap->bp->zoneinfo)<<ZONESHIFT,
++                                    GFP_KERNEL);
++                        if (tmp) {
++
++                                write_lock(&bitmap->lock);
++                                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                                    /* somebody else made it first, backout */
++                                        need_new_zoneinfo = 0;
++                                } else {
++                                        bitmap->bp[page].zoneinfo = tmp;
++                                        bitmap->missing_zones--;
++                                }
++                                write_unlock(&bitmap->lock);
++
++                                if (!need_new_zoneinfo)
++                                        kfree(tmp);
++                        }
++                }
++		return -ENOMEM;
++        } 
++
++        /* got a page */
++
++        write_lock(&bitmap->lock);
++
++        /* recheck the page */
++
++        if (IS_ADDRESS(bitmap->bp[page].map)) {
++                /* somebody beat us to getting the page */
++                write_unlock(&bitmap->lock);
++                bitmap_free_page(bitmap, mappage);
++                return 0;
++        }
++
++        /* no page in place and we have one, so maybe install it */
++
++        if (bitmap->bp[page].count != 0) {
++                /* inpage bitmap - can't replace until no pending writes */
++                write_unlock(&bitmap->lock);
++                bitmap_free_page(bitmap, mappage);
++                return -EINVAL;
++        }
++
++        /* good case - we get to make a new page */
++        memset(mappage, 0, PAGE_SIZE);
++        bitmap->bp[page].map = mappage;
++        if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                memset(bitmap->bp[page].zoneinfo, 0,
++                        sizeof(*bitmap->bp->zoneinfo) << ZONESHIFT);
++        }
++        bitmap->missing_pages--;
++        write_unlock(&bitmap->lock);
++	return 0;
++
++}
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset
++ * We call this routine under lock.
++ */
++static int
++bitmap_clear_mask8 (struct bitmap *bitmap, unsigned long offset8,
++		  unsigned char mask, unsigned char **this_page)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        unsigned char oldmask;
++        unsigned char newmask;
++        unsigned char diffmask;
++	
++        page    = offset8 >> PAGE_SHIFT;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int bits = hweight8(mask);
++                bitmap->bp[page].count -= bits;
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1<<ZONESHIFT) - 1);
++                        bitmap->bp[page].zoneinfo[zone] -= bits;
++                }
++                return -EINVAL;
++        }
++
++        pageoff = offset8 & ~PAGE_MASK;
++
++	oldmask = bitmap->bp[page].map[pageoff];
++	newmask = oldmask & ~mask;
++	diffmask = newmask ^ oldmask;
++
++	if (diffmask) {
++	        unsigned bits = hweight8 (diffmask);
++                int newcount = (bitmap->bp[page].count -= bits);
++
++		bitmap->bp[page].map[pageoff] = newmask;
++
++                /* most frequent case is a +ve result and return */
++                if (newcount > 0)
++                        return 0;
++                /* negative count is a major misaccounting */
++                if (newcount < 0) {
++                        printk(KERN_ALERT "bitmap dirty count %d on page %lu\n",
++                                newcount, page);
++                        return 0;
++                }
++                /* newcount == 0 is when we want to detach the page */
++                *this_page = bitmap->bp[page].map;
++                bitmap->bp[page].map = NULL;
++                bitmap->missing_pages++;
++                return 0;
++	}
++        return 0;
++}
++
++static int
++bitmap_clear_mask (struct bitmap *bitmap, unsigned long offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int errs = 0;
++        unsigned char * free_page0 = NULL, *free_page1 = NULL;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++        write_lock(&bitmap->lock);
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (bitmap_clear_mask8 (bitmap, blkgrp, maskdiv, &free_page0) < 0)
++                                errs++;
++                }
++		if (!maskrem) {
++                        goto out;
++                }
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
++                                errs++;
++                        goto out;
++                } 
++
++                if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
++                        errs++;
++                goto out;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (bitmap_clear_mask8 (bitmap, blkgrp, mask, &free_page0) < 0)
++                errs++;
++out:
++        write_unlock(&bitmap->lock);
++        if (free_page0)
++                bitmap_free_page(bitmap, free_page0);
++        if (free_page1)
++                bitmap_free_page(bitmap, free_page1);
++        return errs > 0 ? -EINVAL : 0;
++}
++
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset.
++ * We call this routine under lock.
++ */
++static int
++bitmap_set_mask8 (struct bitmap *bitmap, unsigned long offset8,
++		  unsigned char mask)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        unsigned char oldmask;
++        unsigned char newmask;
++        unsigned char diffmask;
++	
++        page    = offset8 >> PAGE_SHIFT;
++        pageoff = offset8 & ~PAGE_MASK;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int bits = hweight8(mask);
++                bitmap->bp[page].count += bits;
++                /* mark the zone instead - we have 16 low bits markable */
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                        bitmap->bp[page].zoneinfo[zone] += bits;
++                }
++                return -EINVAL;
++        }
++
++	oldmask = bitmap->bp[page].map[pageoff];
++	newmask = oldmask | mask;
++	diffmask = newmask ^ oldmask;
++
++	if (diffmask) {
++                unsigned int bits = hweight8 (diffmask);
++		bitmap->bp[page].map[pageoff] = newmask;
++		bitmap->bp[page].count += bits;
++	}
++        return 0;
++}
++
++/*
++ * here offset is the BIT offset
++ */
++static int
++bitmap_set_mask (struct bitmap *bitmap, unsigned long offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int errs = 0;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        if (bitmap_checkpage(bitmap, page) < 0)
++                errs++;
++
++        /* the page may or may not have been made */
++
++        write_lock(&bitmap->lock);
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (bitmap_set_mask8(bitmap, blkgrp, maskdiv) < 0)
++                                errs++;
++                }
++
++		if (!maskrem) {
++                        write_unlock(&bitmap->lock);
++                        return errs > 0 ? -EINVAL : 0 ;
++                }
++
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
++                                errs++;
++                        write_unlock(&bitmap->lock);
++                        return errs > 0 ? -EINVAL : 0 ;
++                } 
++                write_unlock(&bitmap->lock);
++                if (bitmap_checkpage(bitmap, page+1) < 0)
++                        errs++;
++
++                write_lock(&bitmap->lock);
++
++                if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
++                        errs++;
++                        
++                write_unlock(&bitmap->lock);
++                return errs > 0 ? -EINVAL : 0 ;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (bitmap_set_mask8(bitmap, blkgrp, mask) < 0)
++                errs++;
++
++        write_unlock(&bitmap->lock);
++        return errs > 0 ? -EINVAL : 0;
++}
++
++
++
++static int
++bitmap_clear_bits (struct bitmap *bitmap, unsigned long offset, unsigned long bits)
++{
++
++        unsigned char mask;
++        int errs = 0;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return (errs > 0) ? -EINVAL : 0;
++}
++
++static int
++bitmap_set_bits (struct bitmap *bitmap, unsigned long offset, unsigned long bits)
++{
++
++        unsigned char mask;
++        int errs = 0;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return (errs > 0) ? -EINVAL : 0;
++}
++
++
++static int
++bitmap_test_bit (struct bitmap *bitmap, unsigned long block)
++{
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int res;
++
++	blkgrp = block >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        read_lock(&bitmap->lock);
++        /* high bits zero means no page address */
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int zoneoffset = (blkgrp  >> (PAGE_SHIFT - ZONESHIFT));
++                int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                /* use the counter instead - this is zoned */
++                res = (bitmap->bp[page].count > 0);
++                if (res && IS_ADDRESS(bitmap->bp[page].zoneinfo))
++                        res = (bitmap->bp[page].zoneinfo[zone] > 0);
++                read_unlock(&bitmap->lock);
++                return res;
++        }
++
++	blkoff = block & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	res = test_bit ((pageoff << 3) + blkoff, bitmap->bp[page].map) != 0;
++        read_unlock(&bitmap->lock);
++        return res;
++}
++
++
++int
++bitmap_init(struct bitmap * bitmap, unsigned long blocks) {
++
++        int pages = (blocks + (PAGE_SIZE * 8 - 1)) / (PAGE_SIZE * 8);
++
++        memset(bitmap, 0, sizeof(*bitmap));
++	rwlock_init (&bitmap->lock);
++        write_lock(&bitmap->lock);
++
++        bitmap->start = bitmap_start;
++        bitmap->stop = bitmap_stop;
++        bitmap->testbit = bitmap_test_bit;
++        bitmap->setbits = bitmap_set_bits;
++        bitmap->clearbits = bitmap_clear_bits;
++        bitmap->active = bitmap_active;
++
++        /* now do 1st level init stuff */
++        if (pages < 0) {
++                write_unlock(&bitmap->lock);
++                printk("bitmap: initialised for -ve number of pages (%d)!\n",
++                        pages);
++                return -EINVAL;
++        }
++        bitmap->pages = pages;
++        bitmap->freehi = BITMAP_FREEHI;
++        bitmap->freelo = BITMAP_FREELO;
++        bitmap->missing_zones = pages;
++        bitmap->missing_pages = pages;
++
++        write_unlock(&bitmap->lock);
++        return 0;
++}
++
++void
++bitmap_exit(struct bitmap *bitmap) {
++        bitmap_destr(bitmap);
++}
++
++#ifdef MODULE
++  MODULE_AUTHOR ("Peter T. Breuer");
++  MODULE_DESCRIPTION ("Bitmap support");
++  MODULE_LICENSE("GPL");
++  int linux_version_code = LINUX_VERSION_CODE;
++#endif          /* MODULE */
++
++/* Compile line:
++ *
++ *  gcc -O2 -D__KERNEL__ -DMODULE -c bitmap.c -o bitmap.o
++ *
++ */
++                      
diff -Nrup fr1-2.17.orig/patches/already-incorporated/read-balance-already-incorporated-do-not-apply.patch fr1-2.17/patches/already-incorporated/read-balance-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/already-incorporated/read-balance-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/already-incorporated/read-balance-already-incorporated-do-not-apply.patch	2004-08-11 16:44:31.000000000 +0200
@@ -0,0 +1,160 @@
+--- linux-2.4.25/drivers/md/raid1.c.post-fr1-2.14b,pre-read-balance	Tue Aug 10 21:36:51 2004
++++ linux-2.4.25/drivers/md/raid1.c	Mon Aug  9 19:27:32 2004
+@@ -46,7 +46,10 @@
+ #define MD_DRIVER
+ #define MD_PERSONALITY
+ 
+-#define MAX_WORK_PER_DISK 128
++#define MAX_WORK_PER_DISK (128 * 8)
++#define MAX_TEST_PER_DISK 32
++#define LATENCY_OLD_WEIGHT 9
++#define LATENCY_NEW_WEIGHT 1
+ 
+ #define	NR_RESERVED_BUFS	32
+ 
+@@ -434,6 +434,32 @@
+                         bitmap->clearbits(bitmap, bh->b_rsector >> 1, bh->b_size >> 10);
+                 }
+         }
++        /* PTB calculate the latency of the read device and update the record */
++        if (uptodate && (r1_bh->cmd == READ || r1_bh->cmd == READA)) {
++                unsigned long latency = jiffies - r1_bh->start_jiffies;
++                kdev_t dev = (&r1_bh->bh_req)->b_dev;
++                int i;
++
++                /* PTB find the mirror component being read */
++                for (i = 0; i < conf->raid_disks; i++) {
++                    if (conf->mirrors[i].dev == dev)
++                        break;
++                }
++                if (i < conf->raid_disks) {
++                        if (latency < 120 * HZ && latency >= 0) {
++                                conf->latency[i] = LATENCY_OLD_WEIGHT * conf->latency[i]
++                                                 + LATENCY_NEW_WEIGHT * latency;
++                                conf->latency[i] /= LATENCY_OLD_WEIGHT
++						   + LATENCY_NEW_WEIGHT;
++                        } else {
++		               printk(KERN_ERR "raid1: bad latency %lu jiffies\n", 
++			         latency);
++                        }
++                } else {
++		       printk(KERN_ERR "raid1: could not find dev %02x:%02x\n", 
++                               MAJOR(dev), MINOR(dev));
++                }
++        }
+         raid1_free_r1bh(r1_bh);
+ }
+ 
+@@ -569,7 +594,7 @@
+ 	 * Don't touch anything for sequential reads.
+ 	 */
+ 
+-	if (this_sector == conf->mirrors[new_disk].head_position)
++	if (0 && /* PTB */ this_sector == conf->mirrors[new_disk].head_position)
+ 		goto rb_out;
+ 	
+ 	/*
+@@ -578,22 +603,66 @@
+ 	 * This is for kicking those idling disks so that
+ 	 * they would find work near some hotspot.
+ 	 */
+ 	
+ 	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
++
++		PRINTK(KERN_INFO
++		  "raid1: disk %d latency %d abandoned after %d sectors\n",
++		  new_disk,
++		  conf->latency[new_disk],
++		  conf->sect_count);
+ 		conf->sect_count = 0;
++
++		if (conf->last_fastest < 0) {
++                    /* PTB find the fastest already known and use that */
++
++			int fastest = -1;
++			unsigned long best_latency = 0x7fffffff;
++			int i;
++
++			for (i = 0; i < conf->raid_disks; i++) {
++	                        if (conf->mirrors[i].write_only
++                                || !conf->mirrors[i].operational)
++                                        continue;
++                                if (conf->latency[i] <= best_latency) {
++                                    best_latency = conf->latency[i];
++                                    fastest = i;
++                                }
++			}
++                        if (fastest >= 0)
++                                new_disk = fastest;
++	                conf->mirrors[new_disk].sect_limit =
++                                                MAX_WORK_PER_DISK;
++                        conf->last_fastest = new_disk;
++                } else {
++                    /* PTB move on to run a short test on the next disk */
+ 
+ #if defined(CONFIG_SPARC64) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 92)
+ 		/* Work around a compiler bug in egcs-2.92.11 19980921 */
+ 		new_disk = *(volatile int *)&new_disk;
+ #endif
+-		do {
+-			if (new_disk<=0)
+-				new_disk = conf->raid_disks;
+-			new_disk--;
+-			if (new_disk == disk)
+-				break;
+-		} while ((conf->mirrors[new_disk].write_only) ||
+-			 (!conf->mirrors[new_disk].operational));
++		        do {
++			        if (new_disk<=0)
++				        new_disk = conf->raid_disks;
++			        new_disk--;
++			        if (new_disk == disk)
++				        break; /* nothing else available */
++		        } while ((conf->mirrors[new_disk].write_only) ||
++			         (!conf->mirrors[new_disk].operational));
++                      /* PTB if tested all, will need to choose next time */
++                        if (new_disk == conf->last_fastest) {
++                                conf->last_fastest = -1;
++                                /* PTB don't retest last source at all */
++	                        //conf->mirrors[new_disk].sect_limit = 0;
++                        }
++                        /* PTB only a short test run */
++	                conf->mirrors[new_disk].sect_limit = MAX_TEST_PER_DISK;
++                }
++
++                PRINTK(KERN_INFO
++                  "raid1: choosing disk %d latency %d\n",
++                  new_disk,
++                  conf->latency[new_disk]);
+ 
+ 		goto rb_out;
+ 	}
+@@ -680,6 +749,7 @@
+ 	r1_bh->master_bh = bh;
+ 	r1_bh->mddev = mddev;
+ 	r1_bh->cmd = rw;
++	r1_bh->start_jiffies = jiffies; /* PTB record start time */
+         async_data = NULL;
+ 
+ 	if (rw == READ) {
+--- linux-2.4.25/include/linux/raid/raid1.h.post-fr1-2.14b,pre-read-balance	Tue Aug 10 21:48:31 2004
++++ linux-2.4.25/include/linux/raid/raid1.h	Mon Aug  9 18:53:57 2004
+@@ -59,6+59,10 @@
+ 	md_wait_queue_head_t	wait_done;
+ 	md_wait_queue_head_t	wait_ready;
+ 	md_spinlock_t		segment_lock;
++
++	int			latency[MD_SB_DISKS];
++	int			last_fastest;        /* PTB disk read from */
++
+ };
+ 
+ typedef struct raid1_private_data raid1_conf_t;
+@@ -92,6 +96,7 @@
+ 	struct buffer_head	*mirror_bh_list;
+ 	struct buffer_head	bh_req;
+ 	struct raid1_bh		*next_r1;	/* next for retry or in free list */
++	unsigned long		start_jiffies;  /* PTB when i/o started */
+ };
+ /* bits for raid1_bh.state */
+ #define	R1BH_Uptodate	1
diff -Nrup fr1-2.17.orig/patches/already-incorporated/throttle-correction-already-incorporated-do-not-apply.patch fr1-2.17/patches/already-incorporated/throttle-correction-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/already-incorporated/throttle-correction-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/already-incorporated/throttle-correction-already-incorporated-do-not-apply.patch	2004-08-21 09:50:35.000000000 +0200
@@ -0,0 +1,124 @@
+--- linux-2.4.24-xfs/drivers/md/md.c.orig	Thu Jan 29 18:19:37 2004
++++ linux-2.4.24-xfs/drivers/md/md.c	Sun Feb 22 21:03:24 2004
+@@ -26,6 +26,9 @@
+    You should have received a copy of the GNU General Public License
+    (for example /usr/src/linux/COPYING); if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++  
++   Yet more changes by PTB 26/3/2004 to make the speed calculations
++   appropriate to fr1, and throttle by real i/o, not resync total.
+ */
+ 
+ #include <linux/module.h>
+@@ -108,6 +123,10 @@
+ static int md_hardsect_sizes[MAX_MD_DEVS];
+ static int md_maxreadahead[MAX_MD_DEVS];
+ static mdk_thread_t *md_recovery_thread;
++#ifdef MD_BITMAP_SUPPORT
++/* PTB md_throttle permits speed calculation adjustments from personality */
++static atomic_t md_throttle[MAX_MD_DEVS];
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ int md_size[MAX_MD_DEVS];
+ 
+@@ -3419,6 +3608,10 @@
+ 	mddev_t *mddev2;
+ 	unsigned int max_sectors, currspeed,
+ 		j, window, err, serialize;
++#ifdef MD_BITMAP_SUPPORT
++	/* PTB add realspeed for i/o limiting calculation */
++	unsigned realspeed;
++#endif /* MD_BITMAP_SUPPORT */
+ 	unsigned long mark[SYNC_MARKS];
+ 	unsigned long mark_cnt[SYNC_MARKS];
+ 	int last_mark,m;
+@@ -3488,6 +3682,9 @@
+ 	atomic_set(&mddev->recovery_active, 0);
+ 	init_waitqueue_head(&mddev->recovery_wait);
+ 	last_check = 0;
++#ifdef MD_BITMAP_SUPPORT
++        atomic_set(&md_throttle[mdidx(mddev)], 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 	for (j = 0; j < max_sectors;) {
+ 		int sectors;
+ 
+@@ -3515,6 +3712,10 @@
+ 
+ 			mddev->resync_mark = mark[next];
+ 			mddev->resync_mark_cnt = mark_cnt[next];
++#ifdef MD_BITMAP_SUPPORT
++                        /* PTB reset count of skipped blocks this mark */
++                        atomic_set(&md_throttle[mdidx(mddev)], 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 			mark[next] = jiffies;
+ 			mark_cnt[next] = j - atomic_read(&mddev->recovery_active);
+ 			last_mark = next;
+@@ -3544,12 +3745,25 @@
+ 			schedule();
+ 
+ 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
++#ifdef MD_BITMAP_SUPPORT
++                /*
++                 * PTB some of the blocks are skipped, not synced, so
++                 * should not count when limiting i/o. Let personality say.
++                 */
++		realspeed = (j - mddev->resync_mark_cnt - atomic_read(&md_throttle[mdidx(mddev)]))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 		if (currspeed > sysctl_speed_limit_min) {
+ 			current->nice = 19;
+ 
+-			if ((currspeed > sysctl_speed_limit_max) ||
+-					!is_mddev_idle(mddev)) {
++			if (
++#ifdef MD_BITMAP_SUPPORT
++                        /* PTB use realspeed for upper limit on i/o */
++                            (realspeed > sysctl_speed_limit_max) ||
++#else
++                            (currspeed > sysctl_speed_limit_max) ||
++#endif /* MD_BITMAP_SUPPORT */
++                                        !is_mddev_idle(mddev)) {
+ 				current->state = TASK_INTERRUPTIBLE;
+ 				md_schedule_timeout(HZ/4);
+ 				goto repeat;
+@@ -4127,4 +4345,7 @@
+ MD_EXPORT_SYMBOL(mddev_map);
+ MD_EXPORT_SYMBOL(md_check_ordering);
+ MD_EXPORT_SYMBOL(get_spare);
++#ifdef MD_BITMAP_SUPPORT
++MD_EXPORT_SYMBOL(md_throttle);
++#endif /* MD_BITMAP_SUPPORT */
+ MODULE_LICENSE("GPL");
+--- linux-2.4.24-xfs/drivers/md/raid1.c.orig	Fri Jun 13 16:51:34 2003
++++ linux-2.4.24-xfs/drivers/md/raid1.c	Sun Aug 15 04:38:00 2004
+@@ -23,6 +23,8 @@
+  * More changes by PTB 20/2/2003 to let the bitmap always be present and
+  * thus allow asynchronous mirror writes by using it as a journal log.
+  *
++ * Changes PTB early 2004 to account speed properly.
++ *
+  */
+ 
+ #include <linux/module.h>
+@@ -1362,6 +1665,12 @@
+ 	int disk;
+ 	int block_nr;
+ 	int buffs;
++        /*
++         * PTB discount the skipped sectors back to the md.c code
++         */
++        extern atomic_t md_throttle[];
++
++ 
+ 
+ 	if (!sector_nr) {
+ 		/* we want enough buffers to hold twice the window of 128*/
+@@ -1429,6 +1762,8 @@
+                         conf->last_clean_sector);
+                 }
+  
++                /* PTB - update md driver throttle discount */
++                atomic_add(done, &md_throttle[mdidx(mddev)]);
+	        spin_unlock_irq(&conf->segment_lock);
+ 
+ 		wake_up(&conf->wait_ready);
diff -Nrup fr1-2.17.orig/patches/async-write-already-incorporated-do-not-apply.patch fr1-2.17/patches/async-write-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/async-write-already-incorporated-do-not-apply.patch	2004-08-19 10:48:12.000000000 +0200
+++ fr1-2.17/patches/async-write-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,126 +0,0 @@
---- linux-2.4.24-xfs/drivers/md/raid1.c.orig	Fri Jun 13 16:51:34 2003
-+++ linux-2.4.24-xfs/drivers/md/raid1.c	Sun Aug 15 04:38:00 2004
-@@ -55,6 +77,9 @@
- static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED;
- struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail;
- 
-+/* PTB module params */
-+static int async;   /* async writes */
-+
- static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt)
- {
- 	/* return a linked list of "cnt" struct buffer_heads.
-@@ -396,11 +422,18 @@
- static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate)
- {
- 	struct buffer_head *bh = r1_bh->master_bh;
-+	raid1_conf_t * conf = mddev_to_conf(r1_bh->mddev);
- 
--	io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev),
--			test_bit(R1BH_SyncPhase, &r1_bh->state));
- 
--	bh->b_end_io(bh, uptodate);
-+        /* PTB if nobody has done the final end_io yet, do it now */
-+	if (!test_and_set_bit(R1BH_AsyncPhase, &r1_bh->state)) {
-+
-+                PRINTK(KERN_DEBUG "raid1: sync end i/o on sectors %lu-%lu\n",
-+                        bh->b_rsector, bh->b_rsector + (bh->b_size >> 9) - 1);
-+	        io_request_done(bh->b_rsector, conf,
-+	                test_bit(R1BH_SyncPhase, &r1_bh->state));
-+	        bh->b_end_io(bh, uptodate);
-+	} 
- 	raid1_free_r1bh(r1_bh);
- }
- void raid1_end_request (struct buffer_head *bh, int uptodate)
-@@ -452,10 +522,35 @@
- 	 *
- 	 * Let's see if all mirrored write operations have finished 
- 	 * already.
-+	 *
-+	 * PTB In any case, do the end io early on the master bh if we are
-+	 * uptodate, and AsyncIO is set on the bh. We set AsyncPhase
-+	 * when this happens, so we don't do it twice, inadvertently.
- 	 */
-+		
-+        if (uptodate
-+        &&  test_bit(R1BH_AsyncIO, &r1_bh->state)
-+        && !test_and_set_bit(R1BH_AsyncPhase, &r1_bh->state)) {
-+
-+	        struct buffer_head *mbh = r1_bh->master_bh;
-+
-+	        raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev);
- 
-+                PRINTK(KERN_DEBUG "raid1: async end i/o on sectors %lu-%lu\n",
-+                        mbh->b_rsector, mbh->b_rsector + (mbh->b_size >> 9) - 1);
-+
-+	        io_request_done(mbh->b_rsector, conf,
-+			test_bit(R1BH_SyncPhase, &r1_bh->state));
-+	        mbh->b_end_io(mbh, uptodate);
-+        }
-+
--	if (atomic_dec_and_test(&r1_bh->remaining))
-+	if (atomic_dec_and_test(&r1_bh->remaining)) {
-+	        if (test_and_set_bit(R1BH_AsyncIO, &r1_bh->state)) {
-+                        /* we made a copy for the buffer, remove it now */
-+                        kfree(bh->b_data);
-+                }
- 		raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state));
-+        }
- }
- 
- /*
-@@ -581,6 +714,7 @@
- 	int disks = MD_SB_DISKS;
-	int i, sum_bhs = 0;
- 	struct mirror_info *mirror;
-+	char * async_data; // copy of buffer used for async writes
- 
- 	if (!buffer_locked(bh))
- 		BUG();
-@@ -619,6 +754,7 @@
- 	r1_bh->master_bh = bh;
- 	r1_bh->mddev = mddev;
- 	r1_bh->cmd = rw;
-+	async_data = NULL;
- 
- 	if (rw == READ) {
- 		/*
-@@ -643,6 +780,20 @@
- 	 */
- 
- 	bhl = raid1_alloc_bh(conf, conf->raid_disks);
-+
-+
-+       /*
-+        * PTB Do async i/o if we marked the bitmap (so it's safe to)
-+        * and we are supposed to.
-+       */
-+       if (async) {
-+                async_data = kmalloc(bh->b_size, GFP_KERNEL);
-+                if (async_data) {
-+                        memcpy(async_data, bh->b_data, bh->b_size);
-+                        set_bit(R1BH_AsyncIO, &r1_bh->state);
-+                }
-+       }
-+
- 	for (i = 0; i < disks; i++) {
- 		struct buffer_head *mbh;
- 		if (!conf->mirrors[i].operational) 
-@@ -683,6 +876,8 @@
-  		mbh->b_size       = bh->b_size;
-  		mbh->b_page	  = bh->b_page;
-  		mbh->b_data	  = bh->b_data;
-+ 		mbh->b_data       =
-+                 test_bit(R1BH_AsyncIO, &r1_bh->state)? async_data : bh->b_data;
-  		mbh->b_list       = BUF_LOCKED;
-  		mbh->b_end_io     = raid1_end_request;
-  		mbh->b_private    = r1_bh;
---- linux-2.4.24-xfs/include/linux/raid/raid1.h.orig	Mon Feb 16 21:06:33 2004
-+++ linux-2.4.24-xfs/include/linux/raid/raid1.h	Mon Aug  9 18:53:57 2004
-@@ -91,4 +91,6 @@
- #define	R1BH_Uptodate	1
- #define	R1BH_SyncPhase	2
- #define	R1BH_PreAlloc	3	/* this was pre-allocated, add to free list */
-+#define	R1BH_AsyncPhase 4
-+#define	R1BH_AsyncIO    5
- #endif
diff -Nrup fr1-2.17.orig/patches/bitmap-base-already-incorporated-do-not-apply.patch fr1-2.17/patches/bitmap-base-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/bitmap-base-already-incorporated-do-not-apply.patch	2004-09-18 09:22:53.000000000 +0200
+++ fr1-2.17/patches/bitmap-base-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,1104 +0,0 @@
---- linux-2.4.22-xfs/include/linux/raid/md_p.h.orig	Tue Nov 14 22:16:37 2000
-+++ linux-2.4.22-xfs/include/linux/raid/md_p.h	Sun Feb 22 21:03:24 2004
-@@ -154,6 +154,9 @@
- 	/*
- 	 * Reserved
- 	 */
-+#define MD_SB_BITMAP_REPAIR(sb) (sb)->reserved[0]
-+#define MD_SB_EVENTS_LO(sb)     (sb)->reserved[2]
-+#define MD_SB_EVENTS_HI(sb)     (sb)->reserved[3]
- 	__u32 reserved[MD_SB_RESERVED_WORDS];
- 
- 	/*
---- linux-2.4.24-xfs/drivers/md/md.c.orig	Thu Jan 29 18:19:37 2004
-+++ linux-2.4.24-xfs/drivers/md/md.c	Sun Feb 22 21:03:24 2004
-@@ -26,6 +26,16 @@
-    You should have received a copy of the GNU General Public License
-    (for example /usr/src/linux/COPYING); if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+
-+   Changes 31/1/2003 by Peter T.  Breuer <ptb@it.uc3m.es> to support
-+   hotadd directly after setfaulty without intervening hotremove
-+   ("hotrepair") when there is no persistent superblock, and to flag a
-+   potential hotrepair when an old disk is re-added and the uuid matches
-+   ours.  The flag is used by the raid1 driver, at the moment, in order
-+   to trigger an intelligent resync.
-+  
-+   Yet more changes by PTB 12/3/2003 to notify devices via ioctls when
-+   they have been incorporated or removed from a raid array.
- */
- 
- #include <linux/module.h>
-@@ -58,6 +71,8 @@
- # define dprintk(x...) do { } while(0)
- #endif
- 
-+#define MD_BITMAP_SUPPORT 1
-+
- #ifndef MODULE
- static void autostart_arrays (void);
- #endif
-@@ -524,7 +543,8 @@
- 		printk(NO_SB,partition_name(dev));
- 		return -EINVAL;
- 	}
--	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
-+	printk(KERN_INFO "%s (read) [events: %08lx]\n",
-+                partition_name(rdev->dev), (unsigned long)rdev->sb->events_lo);
- 	ret = 0;
- abort:
- 	return ret;
-@@ -611,6 +631,68 @@
- 	return 0;
- }
- 
-+#ifdef MD_BITMAP_SUPPORT
-+static int
-+md_hot_add_disk(kdev_t dev, int cmd) {
-+
-+        static mdk_rdev_t * find_rdev_all(kdev_t dev);
-+        static int hot_add_disk(mddev_t * mddev, kdev_t dev);
-+        static int set_disk_faulty(mddev_t *mddev, kdev_t dev);
-+
-+        mdk_rdev_t *rdev;
-+        mddev_t *mddev;
-+        int res;
-+
-+        rdev = find_rdev_all(dev);
-+        if (!rdev)
-+                return -EINVAL;
-+        mddev = rdev->mddev;
-+        if (!mddev)
-+                return -EINVAL;
-+
-+        switch(cmd) {
-+            case HOT_ADD_DISK:
-+                res = hot_add_disk(mddev, dev);
-+                return res;
-+            case SET_DISK_FAULTY:
-+	        res = set_disk_faulty(mddev, dev);
-+                return res;
-+        }
-+        return -EINVAL;
-+}
-+
-+static void
-+notify_device (mddev_t * mddev, kdev_t dev)
-+{
-+#ifndef BLKMDNTFY
-+#define BLKMDNTFY _IOW(0x12,133,sizeof(int))
-+#endif
-+	struct block_device *bdev;
-+	printk (KERN_INFO "md%d: notifying dev %x\n", mdidx(mddev), dev);
-+        bdev = bdget (dev);
-+	if (!bdev)
-+                return;
-+        ioctl_by_bdev (bdev, BLKMDNTFY, MKDEV (MD_MAJOR, mddev->__minor));
-+#ifndef BLKMDRGTR
-+#define BLKMDRGTR _IOW(0x12,135,sizeof(unsigned long))
-+#endif
-+        ioctl_by_bdev (bdev, BLKMDRGTR, (unsigned long)md_hot_add_disk);
-+}
-+static void
-+unnotify_device (mddev_t * mddev, kdev_t dev)
-+{
-+#ifndef BLKMDUNTFY
-+#define BLKMDUNTFY _IOW(0x12,134,sizeof(int))
-+#endif
-+	struct block_device *bdev;
-+	printk (KERN_INFO "md%d: unnotifying dev %x\n", mdidx(mddev), dev);
-+        bdev = bdget (dev);
-+	if (!bdev)
-+                return;
-+        ioctl_by_bdev(bdev, BLKMDUNTFY, MKDEV(MD_MAJOR, mddev->__minor));
-+}
-+#endif /* MD_BITMAP_SUPPORT */
-+
- static MD_LIST_HEAD(all_raid_disks);
- static MD_LIST_HEAD(pending_raid_disks);
- 
-@@ -634,6 +716,9 @@
- 	rdev->mddev = mddev;
- 	mddev->nb_dev++;
- 	printk(KERN_INFO "md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev);
-+#ifdef MD_BITMAP_SUPPORT
-+        notify_device(mddev, rdev->dev);
-+#endif /* MD_BITMAP_SUPPORT */
- }
- 
- static void unbind_rdev_from_array(mdk_rdev_t * rdev)
-@@ -642,6 +727,9 @@
- 		MD_BUG();
- 		return;
- 	}
-+#ifdef MD_BITMAP_SUPPORT
-+        unnotify_device(rdev->mddev, rdev->dev);
-+#endif /* MD_BITMAP_SUPPORT */
- 	md_list_del(&rdev->same_set);
- 	MD_INIT_LIST_HEAD(&rdev->same_set);
- 	rdev->mddev->nb_dev--;
-@@ -2383,6 +2471,9 @@
- 	unsigned int size;
- 	mdk_rdev_t *rdev;
- 	mdp_disk_t *disk;
-+#ifdef MD_BITMAP_SUPPORT
-+        int hotrepair = 0;
-+#endif /* MD_BITMAP_SUPPORT */
- 
- 	if (!mddev->pers)
- 		return -ENODEV;
-@@ -2398,11 +2489,47 @@
- 
- 	persistent = !mddev->sb->not_persistent;
- 
-+#ifdef MD_BITMAP_SUPPORT
-+        /*
-+         * This is a do at most once loop because the remove in the loop will
-+         * cause the test to fail the next time round. And if that
-+         * doesn't break us out, then the hotrepair count will.
-+         */
-+        while ((rdev = find_rdev(mddev, dev)) != NULL) {
-+
-+	        if (hotrepair || rdev->dev != dev || !rdev->faulty) {
-+	                printk(KERN_WARNING "md%d: cannot add existing component %x\n",
-+                                mdidx(mddev), dev);
-+	                return -EBUSY;
-+                }
-+        /*
-+         * Allow "hotrepair" of merely faulty device too if no superblock to
-+         * go by or (later) if there is a matching superblock. We assume then
-+         * that hotadd after setfaulty of the same device is a
-+         * hotrepair.
-+         */
-+	        printk(KERN_WARNING "md%d: repair of faulty disk %x!\n",
-+	                mdidx(mddev), dev);
-+
-+         /* Remove will cause find_rdev to fail next time */
-+	        err = hot_remove_disk(mddev, dev);
-+                if (err < 0) {
-+	                printk(KERN_WARNING "md%d: remove disk %x errored\n",
-+                                mdidx(mddev), dev);
-+	                return err;       
-+                }
-+        /* This will inevitably error us out of the loop interior next time */
-+                hotrepair = 1;
-+        }
-+
-+	err = md_import_device (dev, persistent);
-+#else
- 	rdev = find_rdev(mddev, dev);
- 	if (rdev)
- 		return -EBUSY;
- 
- 	err = md_import_device (dev, 0);
-+#endif /* MD_BITMAP_SUPPORT */
- 	if (err) {
- 		printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
- 		return -EINVAL;
-@@ -2426,6 +2552,58 @@
- 		err = -ENOSPC;
- 		goto abort_export;
- 	}
-+#ifdef MD_BITMAP_SUPPORT
-+        /* let's check the new disk sb at this poimt */
-+        if (persistent && rdev->sb 
-+                && rdev->sb->set_uuid0 == mddev->sb->set_uuid0
-+                && rdev->sb->set_uuid1 == mddev->sb->set_uuid1
-+                && rdev->sb->set_uuid2 == mddev->sb->set_uuid2
-+                && rdev->sb->set_uuid3 == mddev->sb->set_uuid3) {
-+                unsigned long long disk_events, bitmap_events;
-+                disk_events = rdev->sb->events_lo;
-+                bitmap_events = 0;
-+                //bitmap_events |= MD_SB_EVENTS_HI(mddev->sb);
-+                //bitmap_events <<= 32;
-+                bitmap_events |= MD_SB_EVENTS_LO(mddev->sb);
-+
-+                /* This is where we should examine conf->events_chkpt_*
-+                 */
-+                if (disk_events == bitmap_events - 1) {
-+                        printk(KERN_WARNING "md%d: warning - new disk %x nearly too old for repair (disk %Lu < bitmap %Lu)\n",
-+                        mdidx(mddev), dev, disk_events, bitmap_events);
-+                }
-+                if (disk_events < bitmap_events - 1) {
-+                        /* new disk is too old! */
-+                        hotrepair = 0;
-+                        printk(KERN_INFO "md%d: new disk %x too old for repair (disk %Lu < bitmap %Lu)\n",
-+                                mdidx(mddev), dev, disk_events, bitmap_events);
-+                } else {
-+                        hotrepair = 1;
-+                        printk(KERN_INFO "md%d: repairing old mirror component %x (disk %Lu >= bitmap %Lu)\n",
-+                                mdidx(mddev), dev, disk_events, bitmap_events);
-+                }
-+        } else if (!persistent && hotrepair) {
-+                hotrepair = 1;
-+                printk(KERN_INFO "md: forced repair of mirror component %x\n",
-+                        dev);
-+        } else {
-+                /* failed match */
-+                hotrepair = 0;
-+                printk(KERN_INFO "md: adding new mirror component %x\n",
-+                        dev);
-+                printk(KERN_DEBUG "md: old uuid %x %x %x %x\n",
-+                        mddev->sb->set_uuid0,
-+                        mddev->sb->set_uuid1,
-+                        mddev->sb->set_uuid2,
-+                        mddev->sb->set_uuid3);
-+                printk(KERN_DEBUG "md: new uuid %x %x %x %x\n",
-+                        rdev->sb->set_uuid0,
-+                        rdev->sb->set_uuid1,
-+                        rdev->sb->set_uuid2,
-+                        rdev->sb->set_uuid3);
-+        }
-+#endif /* MD_BITMAP_SUPPORT */
-+
- 	bind_rdev_to_array(rdev, mddev);
- 
- 	/*
-@@ -2480,6 +2658,17 @@
- 	mddev->sb->spare_disks++;
- 	mddev->sb->working_disks++;
- 
-+#ifdef MD_BITMAP_SUPPORT
-+        /*
-+         * Maybe say something nice - 1 means we want to respect
-+         * the bitmap in raid1 resync if there is one, 0
-+         * means we need to kill any bitmap that we have been
-+         * saving but we'll do it in the raid1 resync instead of here
-+         */
-+        printk(KERN_DEBUG "md%d: set repair bit to %d on superblock\n",
-+                mdidx(mddev), hotrepair);
-+        MD_SB_BITMAP_REPAIR(mddev->sb) = hotrepair;
-+#endif /* MD_BITMAP_SUPPORT */
- 	mddev->sb_dirty = 1;
- 	md_update_sb(mddev);
- 
-@@ -3540,8 +3741,12 @@
- 		 * about not overloading the IO subsystem. (things like an
- 		 * e2fsck being done on the RAID array should execute fast)
- 		 */
--		if (md_need_resched(current))
--			schedule();
-+		if (md_need_resched(current)) {
-+                        /* PTB this seems not to progress when over loop dev */
-+ 
-+		        current->state = TASK_INTERRUPTIBLE;
-+			md_schedule_timeout(1);
-+                }
- 
- 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
- 
---- linux-2.4.22-xfs/drivers/md/Makefile.orig	Thu Jan 29 18:00:08 2004
-+++ linux-2.4.22-xfs/drivers/md/Makefile	Sun Feb 22 21:05:08 2004
-@@ -16,6 +16,7 @@
- obj-$(CONFIG_MD_LINEAR)		+= linear.o
- obj-$(CONFIG_MD_RAID0)		+= raid0.o
- obj-$(CONFIG_MD_RAID1)		+= raid1.o
-+obj-$(CONFIG_MD_BITMAP)	+= bitmap.o
- obj-$(CONFIG_MD_RAID5)		+= raid5.o xor.o
- obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
- obj-$(CONFIG_BLK_DEV_MD)	+= md.o
---- linux-2.4.22-xfs/drivers/md/bitmap.h.orig	Sun Feb 22 21:03:24 2004
-+++ linux-2.4.22-xfs/drivers/md/bitmap.h	Sun Feb 22 21:03:24 2004
-@@ -0,0 +1,56 @@
-+#ifndef BITMAP_H
-+#define BITMAP_H 1
-+
-+struct bitmap_page {
-+        /*
-+         * If a page is missing then we use a per
-+         * page pending write count instead. pages is the number of
-+         * 4k pages in the map.
-+         */ 
-+        char * map;
-+        /*
-+         * more precise count per zone (1/16 page), for emergencies.
-+         */
-+        short *zoneinfo;
-+        /*
-+         * count of dirty bits on the page
-+         */ 
-+        unsigned short  count;
-+};
-+
-+struct bitmap {
-+	struct bitmap_page * bp;
-+	unsigned long pages;
-+
-+	int (*start) (struct bitmap * bitmap);
-+	void (*stop) (struct bitmap * bitmap);
-+	int (*testbit) (struct bitmap * bitmap, unsigned long block);
-+	int (*setbits) (struct bitmap * bitmap, unsigned long block, unsigned long nrblocks);
-+	int (*clearbits) (struct bitmap * bitmap, unsigned long block, unsigned long nrblocks);
-+	int (*active) (struct bitmap * bitmap);
-+
-+        /* bitmap spinlock */
-+	rwlock_t lock;
-+
-+#define BITMAP_ACTIVE 0x01
-+        unsigned long flags;
-+
-+        /* cache of ready to go pages */
-+        unsigned char * freelist;
-+        unsigned freecount;
-+        /* hi and lo water marks for the cache */
-+#define BITMAP_FREELO 2
-+#define BITMAP_FREEHI 7
-+        unsigned freelo, freehi;
-+        /*
-+         * number of missing zoneinfo sections
-+         */
-+        unsigned long missing_zones;
-+        unsigned long missing_pages;
-+};
-+
-+
-+int bitmap_init(struct bitmap * bitmap, unsigned long blocks);
-+void bitmap_destr(struct bitmap * bitmap);
-+
-+#endif
---- linux-2.4.22-xfs/drivers/md/bitmap.c.orig	Sun Feb 22 21:03:24 2004
-+++ linux-2.4.22-xfs/drivers/md/bitmap.c	Sun Feb 22 21:03:24 2004
-@@ -0,0 +1,743 @@
-+/*
-+ * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
-+ *
-+ * bitmap_init   - sets nr blks
-+ * bitmap->start - then calls the setup part for the 1st
-+ *                 level in the bitmap, which uses memory (kmalloc) so
-+ *                 can fail. You should examine the return value. 0 is
-+ *                 OK. -ve is FAIL.
-+ *
-+ * bitmap->stop  - inverse to bitmap->start. kfrees the memory claimed in 
-+ *                 bitmap_init.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/errno.h>
-+#include <linux/wrapper.h>
-+#include <linux/proc_fs.h>  // PTB for kmalloc! How?
-+#include <linux/vmalloc.h>  // PTB for vmalloc
-+#include <linux/init.h>
-+#include <linux/locks.h>
-+#include <linux/config.h>
-+
-+# define DEBUG 1
-+
-+#include "bitmap.h"
-+
-+/* use 16 bits of the address as extra bitmap */
-+#define ZONESHIFT 4
-+/* top 16 bits are nonzero */
-+#define IS_ADDRESS(x) \
-+  ((( ((unsigned long)(x)) >> ((sizeof(char*)<<3) - (1<<ZONESHIFT))) ) != 0)
-+
-+#ifndef PRINTK
-+#  if DEBUG > 0 
-+#    define PRINTK(x...) printk(x)
-+#  else
-+#    define PRINTK(x...)
-+#  endif
-+#endif
-+
-+
-+/*
-+ * frees mamory kmalloced in init
-+ */
-+void
-+bitmap_destr(struct bitmap *bitmap) {
-+
-+        unsigned long k;
-+        struct bitmap_page * bp;
-+        unsigned long pages;
-+        void * this_page;
-+
-+        write_lock(&bitmap->lock);
-+        bitmap->flags &= ~BITMAP_ACTIVE;
-+        bp = bitmap->bp;
-+        pages = bitmap->pages;
-+        this_page = bitmap->freelist;
-+        bitmap->bp = NULL;
-+        bitmap->freelist = NULL;
-+        bitmap->freecount = 0;
-+        bitmap->missing_pages = pages;
-+        bitmap->missing_zones = pages;
-+        write_unlock(&bitmap->lock);
-+
-+        if (bp) {
-+                for (k = 0; k < pages; k++) {
-+                        if (IS_ADDRESS(bp[k].map)) {
-+                                kfree (bp[k].map);
-+                                bp[k].map = NULL;
-+                        }
-+                        if (IS_ADDRESS(bp[k].zoneinfo)) {
-+                                kfree (bp[k].zoneinfo);
-+                                bp[k].zoneinfo = NULL;
-+                        }
-+                }
-+                vfree (bp);
-+        }
-+
-+        /* remove the old freelist entries offline */
-+        while (IS_ADDRESS(this_page)) {
-+                void * next_page = *(void **)this_page;
-+                kfree(this_page);
-+                this_page = next_page;
-+        }
-+}
-+
-+/* 
-+ * tests if the bitmap is marked active (has been started)
-+ */
-+static int
-+bitmap_active(struct bitmap * bitmap) {
-+        int res = 0;
-+        if (!bitmap)
-+                return res;
-+        read_lock(&bitmap->lock);
-+        res = (bitmap->flags & BITMAP_ACTIVE) != 0;
-+        read_unlock(&bitmap->lock);
-+        return res;
-+}
-+
-+/*
-+ * replaces kmalloc for bitmap pages. Retrieves from the free list
-+ * cache frist of all. If the cache is below lowater, then we also call
-+ * for more pages at the same time and cache them (upto hiwater).
-+ */
-+static unsigned char *
-+bitmap_alloc_page(struct bitmap *bitmap) {
-+        unsigned char *page;
-+
-+        write_lock(&bitmap->lock);
-+
-+        /* check if we can return immediately from freelist */
-+        if (bitmap->freecount > bitmap->freelo) {
-+                page = bitmap->freelist;
-+                bitmap->freelist = *(unsigned char **)page;
-+                bitmap->freecount--;
-+                PRINTK(KERN_DEBUG "bitmap: alloc page exits OK with page count %d\n",
-+                        bitmap->freecount);
-+                write_unlock(&bitmap->lock);
-+                memset(page, 0, PAGE_SIZE); // PTB zero page on alloc
-+                return page;
-+        }
-+
-+        /* nope - we have to allocate some more, so go to hiwater */
-+        while (bitmap->freecount < bitmap->freehi) {
-+                write_unlock(&bitmap->lock);
-+	        page = kmalloc (PAGE_SIZE, GFP_KERNEL);
-+                write_lock(&bitmap->lock);
-+                if (!page)
-+                        break;
-+                *(unsigned char **)page = bitmap->freelist;
-+                bitmap->freelist = page;
-+                bitmap->freecount++;
-+        }
-+
-+        /* finally take from the freelist anyway, if we can ! */
-+        if (bitmap->freecount > 0) {
-+                page = bitmap->freelist;
-+                bitmap->freelist = *(unsigned char **)page;
-+                bitmap->freecount--;
-+                PRINTK(KERN_DEBUG "bitmap: alloc page exits OK with page count %d\n",
-+                        bitmap->freecount);
-+                write_unlock(&bitmap->lock);
-+                memset(page, 0, PAGE_SIZE); // PTB zero page on alloc
-+                return page;
-+        }
-+
-+        PRINTK(KERN_DEBUG "bitmap: alloc page exits FAIL with page count %d\n",
-+                bitmap->freecount);
-+        write_unlock(&bitmap->lock);
-+
-+        return NULL;
-+}
-+
-+/*
-+ * replaces kfree on bitmap pages. Cannot be called under lock.
-+ * adds a page that has already been disconnected from the bitmap
-+ * struct to the free list, or discards it if the list is at hiwater.
-+ */
-+static void
-+bitmap_free_page(struct bitmap * bitmap, unsigned char * page) {
-+        
-+        if (!page)
-+                return;
-+
-+        write_lock(&bitmap->lock);
-+        PRINTK(KERN_DEBUG "bitmap: free page enters with page count %d\n",
-+                bitmap->freecount);
-+        if (bitmap->freecount < bitmap->freehi) {
-+                /* add to free list */
-+                *(unsigned char **)page = bitmap->freelist;
-+                bitmap->freelist = page;
-+                bitmap->freecount++;
-+                PRINTK(KERN_DEBUG "bitmap: free page exits with page count %d\n",
-+                        bitmap->freecount);
-+                write_unlock(&bitmap->lock);
-+                return;
-+        }
-+        PRINTK(KERN_DEBUG "bitmap: free page exits with page count %d\n",
-+                bitmap->freecount);
-+        write_unlock(&bitmap->lock);
-+        kfree(page);
-+}
-+
-+/*
-+ * mark bitmap inactive and maybe prune the page cache
-+ */
-+static void
-+bitmap_stop(struct bitmap * bitmap) {
-+
-+        void * this_page;
-+
-+        write_lock(&bitmap->lock);
-+        bitmap->flags &= ~BITMAP_ACTIVE;
-+        this_page = bitmap->freelist;
-+        bitmap->freelist = NULL;
-+        bitmap->freecount = 0;
-+        write_unlock(&bitmap->lock);
-+
-+        /* remove the old freelist entries offline */
-+        while (IS_ADDRESS(this_page)) {
-+                void * next_page = *(void **)this_page;
-+                kfree(this_page);
-+                this_page = next_page;
-+        }
-+ }
-+
-+/* 
-+ * marks the bitmap active and primes the free page cache.
-+ */
-+static int
-+bitmap_start(struct bitmap * bitmap) {
-+
-+        struct bitmap_page * bp;
-+        unsigned long pages;
-+        
-+        /* take lock to read data */
-+        write_lock(&bitmap->lock);
-+        pages = bitmap->pages;
-+        bp    = bitmap->bp;
-+        write_unlock(&bitmap->lock);
-+
-+        if (!bp) {
-+
-+                int k;
-+
-+                bp = vmalloc (pages * sizeof(*bp));
-+                if (!bp) {
-+                        printk("bitmap: cannot get %luB of memory!\n",
-+                                pages * sizeof(*bp));
-+                        return -ENOMEM;
-+                }
-+                memset (bp, 0, pages * sizeof(*bp));
-+
-+                for (k = 0; k < pages; k++) {
-+                        if (bp[k].zoneinfo)
-+                                continue;
-+                        bp[k].zoneinfo =
-+                                kmalloc (sizeof(*bp[k].zoneinfo)<<ZONESHIFT,
-+                                       GFP_KERNEL);
-+                        if (bp[k].zoneinfo)
-+                                bitmap->missing_zones--;
-+                }
-+                if (bitmap->missing_zones > 0) {
-+                        printk("bitmap: warning! cannot get %ld*%uB memory!\n",
-+                              bitmap->missing_zones,
-+                              sizeof(*bp->zoneinfo) << ZONESHIFT);
-+                }
-+        }
-+
-+        /*
-+         * this is 16 shorts or 32 bytes + 4 bytes extra per page of 4096
-+         * bytes, which is a reserve of less that 0.1%. But each page
-+         * bitmaps 32MB of disk, so a 1GB disk takes 32 pages or 128KB, and
-+         * a 1TB disk takes 128MB of pages. In those circumstances,
-+         * adding a capital cost of about 108KB doesn't seem bad.
-+         */
-+                
-+
-+        write_lock(&bitmap->lock);
-+        bitmap->bp = bp;
-+
-+        bitmap->flags |= BITMAP_ACTIVE;
-+        write_unlock(&bitmap->lock);
-+
-+        /* seed the page cache */
-+        bitmap_free_page(bitmap, bitmap_alloc_page(bitmap));
-+
-+        return 0;
-+}
-+
-+static int
-+bitmap_checkpage (struct bitmap *bitmap, unsigned long page)
-+{
-+        unsigned char * mappage;
-+
-+        read_lock(&bitmap->lock);
-+        if (page < 0 || page >= bitmap->pages) {
-+                read_unlock(&bitmap->lock);
-+		return -EINVAL;
-+        }
-+
-+        if (bitmap->bp == NULL) {
-+                read_unlock(&bitmap->lock);
-+		return -ENODEV;
-+        }
-+
-+
-+        if (IS_ADDRESS(bitmap->bp[page].map)) {
-+                read_unlock(&bitmap->lock);
-+		return 0;
-+        }
-+        read_unlock(&bitmap->lock);
-+
-+        /* the page address was NULL */
-+
-+	if ((mappage = bitmap_alloc_page(bitmap)) == NULL) {
-+                /* failed - check to see if we have backup counters */
-+                void * tmp;
-+                int need_new_zoneinfo = 0;
-+
-+                write_lock(&bitmap->lock);
-+                if (!IS_ADDRESS(bitmap->bp[page].zoneinfo))
-+                        need_new_zoneinfo = 1;
-+                write_unlock(&bitmap->lock);
-+
-+                if (need_new_zoneinfo) {
-+                        /* rarely, we might make an extra backup counter */
-+                        tmp = kmalloc(sizeof(*bitmap->bp->zoneinfo)<<ZONESHIFT,
-+                                    GFP_KERNEL);
-+                        if (tmp) {
-+
-+                                write_lock(&bitmap->lock);
-+                                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
-+                                    /* somebody else made it first, backout */
-+                                        need_new_zoneinfo = 0;
-+                                } else {
-+                                        bitmap->bp[page].zoneinfo = tmp;
-+                                        bitmap->missing_zones--;
-+                                }
-+                                write_unlock(&bitmap->lock);
-+
-+                                if (!need_new_zoneinfo)
-+                                        kfree(tmp);
-+                        }
-+                }
-+		return -ENOMEM;
-+        } 
-+
-+        /* got a page */
-+
-+        write_lock(&bitmap->lock);
-+
-+        /* recheck the page */
-+
-+        if (IS_ADDRESS(bitmap->bp[page].map)) {
-+                /* somebody beat us to getting the page */
-+                write_unlock(&bitmap->lock);
-+                bitmap_free_page(bitmap, mappage);
-+                return 0;
-+        }
-+
-+        /* no page in place and we have one, so maybe install it */
-+
-+        if (bitmap->bp[page].count != 0) {
-+                /* inpage bitmap - can't replace until no pending writes */
-+                write_unlock(&bitmap->lock);
-+                bitmap_free_page(bitmap, mappage);
-+                return -EINVAL;
-+        }
-+
-+        /* good case - we get to make a new page */
-+        memset(mappage, 0, PAGE_SIZE);
-+        bitmap->bp[page].map = mappage;
-+        if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
-+                memset(bitmap->bp[page].zoneinfo, 0,
-+                        sizeof(*bitmap->bp->zoneinfo) << ZONESHIFT);
-+        }
-+        bitmap->missing_pages--;
-+        write_unlock(&bitmap->lock);
-+	return 0;
-+
-+}
-+
-+/* 
-+ * offset8 is the BYTE offset, not the bit offset
-+ * We call this routine under lock.
-+ */
-+static int
-+bitmap_clear_mask8 (struct bitmap *bitmap, unsigned long offset8,
-+		  unsigned char mask, unsigned char **this_page)
-+{
-+
-+        unsigned long page  ;
-+        unsigned long pageoff;
-+
-+        unsigned char oldmask;
-+        unsigned char newmask;
-+        unsigned char diffmask;
-+	
-+        page    = offset8 >> PAGE_SHIFT;
-+
-+        if (!IS_ADDRESS(bitmap->bp[page].map)) {
-+                int bits = hweight8(mask);
-+                bitmap->bp[page].count -= bits;
-+                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
-+                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
-+                        int zone = zoneoffset & ((1<<ZONESHIFT) - 1);
-+                        bitmap->bp[page].zoneinfo[zone] -= bits;
-+                }
-+                return -EINVAL;
-+        }
-+
-+        pageoff = offset8 & ~PAGE_MASK;
-+
-+	oldmask = bitmap->bp[page].map[pageoff];
-+	newmask = oldmask & ~mask;
-+	diffmask = newmask ^ oldmask;
-+
-+	if (diffmask) {
-+	        unsigned bits = hweight8 (diffmask);
-+                int newcount = (bitmap->bp[page].count -= bits);
-+
-+		bitmap->bp[page].map[pageoff] = newmask;
-+
-+                /* most frequent case is a +ve result and return */
-+                if (newcount > 0)
-+                        return 0;
-+                /* negative count is a major misaccounting */
-+                if (newcount < 0) {
-+                        printk(KERN_ALERT "bitmap dirty count %d on page %lu\n",
-+                                newcount, page);
-+                        return 0;
-+                }
-+                /* newcount == 0 is when we want to detach the page */
-+                *this_page = bitmap->bp[page].map;
-+                bitmap->bp[page].map = NULL;
-+                bitmap->missing_pages++;
-+                return 0;
-+	}
-+        return 0;
-+}
-+
-+static int
-+bitmap_clear_mask (struct bitmap *bitmap, unsigned long offset, unsigned char mask)
-+{
-+
-+	unsigned long blkgrp;
-+	unsigned char blkoff;
-+        unsigned long page  ;
-+        unsigned long pageoff;
-+        int errs = 0;
-+        unsigned char * free_page0 = NULL, *free_page1 = NULL;
-+
-+	blkgrp = offset >> 3;
-+        page   = blkgrp >> PAGE_SHIFT;
-+
-+	blkoff = offset & 7;
-+        pageoff= blkgrp & ~PAGE_MASK;
-+
-+        write_lock(&bitmap->lock);
-+
-+	if (blkoff) {
-+		unsigned char maskdiv = 0xff & (mask << blkoff);
-+		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
-+
-+                if (maskdiv) {
-+                        if (bitmap_clear_mask8 (bitmap, blkgrp, maskdiv, &free_page0) < 0)
-+                                errs++;
-+                }
-+		if (!maskrem) {
-+                        goto out;
-+                }
-+                if (pageoff + 1 < PAGE_SIZE) {
-+
-+                        if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
-+                                errs++;
-+                        goto out;
-+                } 
-+
-+                if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
-+                        errs++;
-+                goto out;
-+	}
-+
-+        // normal situation. Offset is multiple of 8
-+	
-+        if (bitmap_clear_mask8 (bitmap, blkgrp, mask, &free_page0) < 0)
-+                errs++;
-+out:
-+        write_unlock(&bitmap->lock);
-+        if (free_page0)
-+                bitmap_free_page(bitmap, free_page0);
-+        if (free_page1)
-+                bitmap_free_page(bitmap, free_page1);
-+        return errs > 0 ? -EINVAL : 0;
-+}
-+
-+
-+/* 
-+ * offset8 is the BYTE offset, not the bit offset.
-+ * We call this routine under lock.
-+ */
-+static int
-+bitmap_set_mask8 (struct bitmap *bitmap, unsigned long offset8,
-+		  unsigned char mask)
-+{
-+
-+        unsigned long page  ;
-+        unsigned long pageoff;
-+
-+        unsigned char oldmask;
-+        unsigned char newmask;
-+        unsigned char diffmask;
-+	
-+        page    = offset8 >> PAGE_SHIFT;
-+        pageoff = offset8 & ~PAGE_MASK;
-+
-+        if (!IS_ADDRESS(bitmap->bp[page].map)) {
-+                int bits = hweight8(mask);
-+                bitmap->bp[page].count += bits;
-+                /* mark the zone instead - we have 16 low bits markable */
-+                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
-+                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
-+                        int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
-+                        bitmap->bp[page].zoneinfo[zone] += bits;
-+                }
-+                return -EINVAL;
-+        }
-+
-+	oldmask = bitmap->bp[page].map[pageoff];
-+	newmask = oldmask | mask;
-+	diffmask = newmask ^ oldmask;
-+
-+	if (diffmask) {
-+                unsigned int bits = hweight8 (diffmask);
-+		bitmap->bp[page].map[pageoff] = newmask;
-+		bitmap->bp[page].count += bits;
-+	}
-+        return 0;
-+}
-+
-+/*
-+ * here offset is the BIT offset
-+ */
-+static int
-+bitmap_set_mask (struct bitmap *bitmap, unsigned long offset, unsigned char mask)
-+{
-+
-+	unsigned long blkgrp;
-+	unsigned char blkoff;
-+        unsigned long page  ;
-+        unsigned long pageoff;
-+        int errs = 0;
-+
-+	blkgrp = offset >> 3;
-+        page   = blkgrp >> PAGE_SHIFT;
-+
-+        if (bitmap_checkpage(bitmap, page) < 0)
-+                errs++;
-+
-+        /* the page may or may not have been made */
-+
-+        write_lock(&bitmap->lock);
-+	blkoff = offset & 7;
-+        pageoff= blkgrp & ~PAGE_MASK;
-+
-+	if (blkoff) {
-+		unsigned char maskdiv = 0xff & (mask << blkoff);
-+		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
-+
-+                if (maskdiv) {
-+                        if (bitmap_set_mask8(bitmap, blkgrp, maskdiv) < 0)
-+                                errs++;
-+                }
-+
-+		if (!maskrem) {
-+                        write_unlock(&bitmap->lock);
-+                        return errs > 0 ? -EINVAL : 0 ;
-+                }
-+
-+                if (pageoff + 1 < PAGE_SIZE) {
-+
-+                        if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
-+                                errs++;
-+                        write_unlock(&bitmap->lock);
-+                        return errs > 0 ? -EINVAL : 0 ;
-+                } 
-+                write_unlock(&bitmap->lock);
-+                if (bitmap_checkpage(bitmap, page+1) < 0)
-+                        errs++;
-+
-+                write_lock(&bitmap->lock);
-+
-+                if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
-+                        errs++;
-+                        
-+                write_unlock(&bitmap->lock);
-+                return errs > 0 ? -EINVAL : 0 ;
-+	}
-+
-+        // normal situation. Offset is multiple of 8
-+	
-+        if (bitmap_set_mask8(bitmap, blkgrp, mask) < 0)
-+                errs++;
-+
-+        write_unlock(&bitmap->lock);
-+        return errs > 0 ? -EINVAL : 0;
-+}
-+
-+
-+
-+static int
-+bitmap_clear_bits (struct bitmap *bitmap, unsigned long offset, unsigned long bits)
-+{
-+
-+        unsigned char mask;
-+        int errs = 0;
-+
-+        while (offset + bits >= (offset | 7) + 1) {
-+                int more = (offset | 7) + 1 - offset;
-+                mask = (1 << more) - 1;
-+                /* ignore errors and do what we can */
-+                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
-+                        errs++;
-+                }
-+                bits -= more;
-+                offset |= 7;
-+                offset++;
-+        }
-+
-+        if (bits > 0) {
-+                mask = (1 << bits) - 1;
-+                /* ignore errors and do what we can */
-+                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
-+                        errs++;
-+                }
-+                bits = 0;
-+                offset += bits;
-+        }
-+
-+        return (errs > 0) ? -EINVAL : 0;
-+}
-+
-+static int
-+bitmap_set_bits (struct bitmap *bitmap, unsigned long offset, unsigned long bits)
-+{
-+
-+        unsigned char mask;
-+        int errs = 0;
-+
-+        while (offset + bits >= (offset | 7) + 1) {
-+                int more = (offset | 7) + 1 - offset;
-+                mask = (1 << more) - 1;
-+                /* ignore errors and do what we can */
-+                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
-+                        errs++;
-+                }
-+                bits -= more;
-+                offset |= 7;
-+                offset++;
-+        }
-+
-+        if (bits > 0) {
-+                mask = (1 << bits) - 1;
-+                /* ignore errors and do what we can */
-+                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
-+                        errs++;
-+                }
-+                bits = 0;
-+                offset += bits;
-+        }
-+
-+        return (errs > 0) ? -EINVAL : 0;
-+}
-+
-+
-+static int
-+bitmap_test_bit (struct bitmap *bitmap, unsigned long block)
-+{
-+	unsigned long blkgrp;
-+	unsigned char blkoff;
-+        unsigned long page  ;
-+        unsigned long pageoff;
-+        int res;
-+
-+	blkgrp = block >> 3;
-+        page   = blkgrp >> PAGE_SHIFT;
-+
-+        read_lock(&bitmap->lock);
-+        /* high bits zero means no page address */
-+        if (!IS_ADDRESS(bitmap->bp[page].map)) {
-+                int zoneoffset = (blkgrp  >> (PAGE_SHIFT - ZONESHIFT));
-+                int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
-+                /* use the counter instead - this is zoned */
-+                res = (bitmap->bp[page].count > 0);
-+                if (res && IS_ADDRESS(bitmap->bp[page].zoneinfo))
-+                        res = (bitmap->bp[page].zoneinfo[zone] > 0);
-+                read_unlock(&bitmap->lock);
-+                return res;
-+        }
-+
-+	blkoff = block & 7;
-+        pageoff= blkgrp & ~PAGE_MASK;
-+
-+	res = test_bit ((pageoff << 3) + blkoff, bitmap->bp[page].map) != 0;
-+        read_unlock(&bitmap->lock);
-+        return res;
-+}
-+
-+
-+int
-+bitmap_init(struct bitmap * bitmap, unsigned long blocks) {
-+
-+        int pages = (blocks + (PAGE_SIZE * 8 - 1)) / (PAGE_SIZE * 8);
-+
-+        memset(bitmap, 0, sizeof(*bitmap));
-+	rwlock_init (&bitmap->lock);
-+        write_lock(&bitmap->lock);
-+
-+        bitmap->start = bitmap_start;
-+        bitmap->stop = bitmap_stop;
-+        bitmap->testbit = bitmap_test_bit;
-+        bitmap->setbits = bitmap_set_bits;
-+        bitmap->clearbits = bitmap_clear_bits;
-+        bitmap->active = bitmap_active;
-+
-+        /* now do 1st level init stuff */
-+        if (pages < 0) {
-+                write_unlock(&bitmap->lock);
-+                printk("bitmap: initialised for -ve number of pages (%d)!\n",
-+                        pages);
-+                return -EINVAL;
-+        }
-+        bitmap->pages = pages;
-+        bitmap->freehi = BITMAP_FREEHI;
-+        bitmap->freelo = BITMAP_FREELO;
-+        bitmap->missing_zones = pages;
-+        bitmap->missing_pages = pages;
-+
-+        write_unlock(&bitmap->lock);
-+        return 0;
-+}
-+
-+void
-+bitmap_exit(struct bitmap *bitmap) {
-+        bitmap_destr(bitmap);
-+}
-+
-+#ifdef MODULE
-+  MODULE_AUTHOR ("Peter T. Breuer");
-+  MODULE_DESCRIPTION ("Bitmap support");
-+  MODULE_LICENSE("GPL");
-+  int linux_version_code = LINUX_VERSION_CODE;
-+#endif          /* MODULE */
-+
-+/* Compile line:
-+ *
-+ *  gcc -O2 -D__KERNEL__ -DMODULE -c bitmap.c -o bitmap.o
-+ *
-+ */
-+                      
diff -Nrup fr1-2.17.orig/patches/linux-2.4.31.patch fr1-2.17/patches/linux-2.4.31.patch
--- fr1-2.17.orig/patches/linux-2.4.31.patch	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/linux-2.4.31.patch	2005-07-18 02:13:30.285238883 +0200
@@ -0,0 +1,2379 @@
+--- linux-2.4.30/include/linux/raid/raid1.h.pre-fr1	Sun Aug 12 21:39:02 2001
++++ linux-2.4.30/include/linux/raid/raid1.h	Wed Apr  6 19:17:25 2005
+@@ -59,6 +59,15 @@
+ 	md_wait_queue_head_t	wait_done;
+ 	md_wait_queue_head_t	wait_ready;
+ 	md_spinlock_t		segment_lock;
++
++	long                    last_clean_sector;  /* helps debugging */
++	long                    last_dirty_sector;
++	int                     sync_mode;          /* clean/dirty in sync? */
++	void                    *bitmap;            /* the array bitmap */
++	int                     bitmap_dirty;       /* flag */
++	int                     latency[MD_SB_DISKS];
++	int                     last_source;        /* PTB disk read from */
++
+ };
+ 
+ typedef struct raid1_private_data raid1_conf_t;
+@@ -86,9 +95,19 @@
+ 	struct buffer_head	*mirror_bh_list;
+ 	struct buffer_head	bh_req;
+ 	struct raid1_bh		*next_r1;	/* next for retry or in free list */
++	int		        nonoperational; /* no of bad mirror comps */
++        unsigned long           start_jiffies;  /* PTB when i/o started */
+ };
+ /* bits for raid1_bh.state */
+ #define	R1BH_Uptodate	1
+ #define	R1BH_SyncPhase	2
+ #define	R1BH_PreAlloc	3	/* this was pre-allocated, add to free list */
++#define	R1BH_AsyncPhase 4
++#define	R1BH_AsyncIO    5
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++#define	R1BH_ReadRetry  6
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
++#ifdef CONFIG_MD_RAID1_READ_WRITE_CORRECT
++#define	R1BH_ReadRewrite 7
++#endif /* CONFIG_MD_RAID1_READ_WRITE_CORRECT */
+ #endif
+--- linux-2.4.30/include/linux/raid/md_p.h.pre-fr1	Tue Nov 14 22:16:37 2000
++++ linux-2.4.30/include/linux/raid/md_p.h	Wed Apr  6 18:18:04 2005
+@@ -66,7 +66,7 @@
+ #define MD_SB_GENERIC_WORDS		(MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS)
+ #define MD_SB_PERSONALITY_WORDS		64
+ #define MD_SB_DESCRIPTOR_WORDS		32
+-#define MD_SB_DISKS			27
++#define MD_SB_DISKS			26
+ #define MD_SB_DISKS_WORDS		(MD_SB_DISKS*MD_SB_DESCRIPTOR_WORDS)
+ #define MD_SB_RESERVED_WORDS		(1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS)
+ #define MD_SB_EQUAL_WORDS		(MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS)
+@@ -154,6 +154,9 @@
+ 	/*
+ 	 * Reserved
+ 	 */
++#define MD_SB_BITMAP_REPAIR(sb) (sb)->reserved[0]
++#define MD_SB_EVENTS_LO(sb)     (sb)->reserved[2]
++#define MD_SB_EVENTS_HI(sb)     (sb)->reserved[3]
+ 	__u32 reserved[MD_SB_RESERVED_WORDS];
+ 
+ 	/*
+--- linux-2.4.30/drivers/md/md.c.pre-fr1	Mon Aug 25 13:44:42 2003
++++ linux-2.4.30/drivers/md/md.c	Wed Apr  6 22:41:29 2005
+@@ -26,6 +26,19 @@
+    You should have received a copy of the GNU General Public License
+    (for example /usr/src/linux/COPYING); if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++   Changes 31/1/2003 by Peter T.  Breuer <ptb@it.uc3m.es> to support
++   hotadd directly after setfaulty without intervening hotremove
++   ("hotrepair") when there is no persistent superblock, and to flag a
++   potential hotrepair when an old disk is re-added and the uuid matches
++   ours.  The flag is used by the raid1 driver, at the moment, in order
++   to trigger an intelligent resync.
++  
++   Yet more changes by PTB 12/3/2003 to notify devices via ioctls when
++   they have been incorporated or removed from a raid array.
++  
++   Yet more changes by PTB 26/3/2004 to make the speed calculations
++   appropriate to fr1, and throttle by real i/o, not resync total.
+ */
+ 
+ #include <linux/module.h>
+@@ -108,6 +121,13 @@
+ static int md_hardsect_sizes[MAX_MD_DEVS];
+ static int md_maxreadahead[MAX_MD_DEVS];
+ static mdk_thread_t *md_recovery_thread;
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++/* PTB md_throttle permits speed calculation adjustments from personality */
++#ifdef MODULE
++static
++#endif /* MODULE */
++atomic_t md_throttle[MAX_MD_DEVS];
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ int md_size[MAX_MD_DEVS];
+ 
+@@ -524,7 +544,8 @@
+ 		printk(NO_SB,partition_name(dev));
+ 		return -EINVAL;
+ 	}
+-	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
++	printk(KERN_INFO "%s (read) [events: %08lx]\n",
++                partition_name(rdev->dev), (unsigned long)rdev->sb->events_lo);
+ 	ret = 0;
+ abort:
+ 	return ret;
+@@ -611,6 +632,68 @@
+ 	return 0;
+ }
+ 
++static int
++md_hot_add_disk(kdev_t dev, int cmd) {
++
++        static mdk_rdev_t * find_rdev_all(kdev_t dev);
++        static int hot_add_disk(mddev_t * mddev, kdev_t dev);
++        static int set_disk_faulty(mddev_t *mddev, kdev_t dev);
++
++        mdk_rdev_t *rdev;
++        mddev_t *mddev;
++        int res;
++
++        rdev = find_rdev_all(dev);
++        if (!rdev)
++                return -EINVAL;
++        mddev = rdev->mddev;
++        if (!mddev)
++                return -EINVAL;
++
++        switch(cmd) {
++            case HOT_ADD_DISK:
++                res = hot_add_disk(mddev, dev);
++                return res;
++            case SET_DISK_FAULTY:
++	        res = set_disk_faulty(mddev, dev);
++                return res;
++        }
++        return -EINVAL;
++}
++
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++static void
++notify_device (mddev_t * mddev, kdev_t dev)
++{
++#ifndef BLKMDNTFY
++#define BLKMDNTFY _IOW(0x12,133,int)
++#endif
++	struct block_device *bdev;
++	printk (KERN_INFO "md%d: notifying dev %x\n", mdidx(mddev), dev);
++        bdev = bdget (dev);
++	if (!bdev)
++                return;
++        ioctl_by_bdev (bdev, BLKMDNTFY, MKDEV (MD_MAJOR, mddev->__minor));
++#ifndef BLKMDRGTR
++#define BLKMDRGTR _IOW(0x12,135,unsigned long)
++#endif
++        ioctl_by_bdev (bdev, BLKMDRGTR, (unsigned long)md_hot_add_disk);
++}
++static void
++unnotify_device (mddev_t * mddev, kdev_t dev)
++{
++#ifndef BLKMDUNTFY
++#define BLKMDUNTFY _IOW(0x12,134,int)
++#endif
++	struct block_device *bdev;
++	printk (KERN_INFO "md%d: unnotifying dev %x\n", mdidx(mddev), dev);
++        bdev = bdget (dev);
++	if (!bdev)
++                return;
++        ioctl_by_bdev(bdev, BLKMDUNTFY, MKDEV(MD_MAJOR, mddev->__minor));
++}
++#endif /* MD_BITMAP_SUPPORT */
++
+ static MD_LIST_HEAD(all_raid_disks);
+ static MD_LIST_HEAD(pending_raid_disks);
+ 
+@@ -634,6 +717,9 @@
+ 	rdev->mddev = mddev;
+ 	mddev->nb_dev++;
+ 	printk(KERN_INFO "md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev);
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        notify_device(mddev, rdev->dev);
++#endif /* MD_BITMAP_SUPPORT */
+ }
+ 
+ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
+@@ -642,6 +728,9 @@
+ 		MD_BUG();
+ 		return;
+ 	}
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        unnotify_device(rdev->mddev, rdev->dev);
++#endif /* MD_BITMAP_SUPPORT */
+ 	md_list_del(&rdev->same_set);
+ 	MD_INIT_LIST_HEAD(&rdev->same_set);
+ 	rdev->mddev->nb_dev--;
+@@ -2383,6 +2472,9 @@
+ 	unsigned int size;
+ 	mdk_rdev_t *rdev;
+ 	mdp_disk_t *disk;
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        int hotrepair = 0;
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 	if (!mddev->pers)
+ 		return -ENODEV;
+@@ -2398,11 +2490,48 @@
+ 
+ 	persistent = !mddev->sb->not_persistent;
+ 
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        /*
++         * This is a do at most once loop because the remove in the loop will
++         * cause the test to fail the next time round. And if that
++         * doesn't break us out, then the hotrepair count will.
++         */
++        while ((rdev = find_rdev(mddev, dev)) != NULL) {
++
++	        if (hotrepair || rdev->dev != dev || !rdev->faulty) {
++	                printk(KERN_WARNING "md%d: cannot add existing component %x\n",
++                                mdidx(mddev), dev);
++	                return -EBUSY;
++                }
++        /*
++         * Allow "hotrepair" of merely faulty device too if no superblock to
++         * go by or (later) if there is a matching superblock. We assume then
++         * that hotadd after setfaulty of the same device is a
++         * hotrepair.
++         */
++	        printk(KERN_WARNING "md%d: repair of faulty disk %x!\n",
++	                mdidx(mddev), dev);
++
++         /* Remove will cause find_rdev to fail next time */
++	        err = hot_remove_disk(mddev, dev);
++                if (err < 0) {
++	                printk(KERN_WARNING "md%d: remove disk %x errored\n",
++                                mdidx(mddev), dev);
++	                return err;       
++                }
++        /* This will inevitably error us out of the loop interior next time */
++                hotrepair = 1;
++                rdev = NULL;
++        }
++
++	err = md_import_device (dev, persistent);
++#else
+ 	rdev = find_rdev(mddev, dev);
+ 	if (rdev)
+ 		return -EBUSY;
+ 
+ 	err = md_import_device (dev, 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 	if (err) {
+ 		printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
+ 		return -EINVAL;
+@@ -2426,6 +2554,58 @@
+ 		err = -ENOSPC;
+ 		goto abort_export;
+ 	}
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        /* let's check the new disk sb at this poimt */
++        if (persistent && rdev->sb 
++                && rdev->sb->set_uuid0 == mddev->sb->set_uuid0
++                && rdev->sb->set_uuid1 == mddev->sb->set_uuid1
++                && rdev->sb->set_uuid2 == mddev->sb->set_uuid2
++                && rdev->sb->set_uuid3 == mddev->sb->set_uuid3) {
++                unsigned long long disk_events, bitmap_events;
++                disk_events = rdev->sb->events_lo;
++                bitmap_events = 0;
++                //bitmap_events |= MD_SB_EVENTS_HI(mddev->sb);
++                //bitmap_events <<= 32;
++                bitmap_events |= MD_SB_EVENTS_LO(mddev->sb);
++
++                /* This is where we should examine conf->events_chkpt_*
++                 */
++                if (disk_events == bitmap_events - 1) {
++                        printk(KERN_WARNING "md%d: warning - new disk %x nearly too old for repair (disk %Lu < bitmap %Lu)\n",
++                        mdidx(mddev), dev, disk_events, bitmap_events);
++                }
++                if (disk_events < bitmap_events - 1) {
++                        /* new disk is too old! */
++                        hotrepair = 0;
++                        printk(KERN_INFO "md%d: new disk %x too old for repair (disk %Lu < bitmap %Lu)\n",
++                                mdidx(mddev), dev, disk_events, bitmap_events);
++                } else {
++                        hotrepair = 1;
++                        printk(KERN_INFO "md%d: repairing old mirror component %x (disk %Lu >= bitmap %Lu)\n",
++                                mdidx(mddev), dev, disk_events, bitmap_events);
++                }
++        } else if (!persistent && hotrepair) {
++                hotrepair = 1;
++                printk(KERN_INFO "md: forced repair of mirror component %x\n",
++                        dev);
++        } else {
++                /* failed match */
++                hotrepair = 0;
++                printk(KERN_INFO "md: adding new mirror component %x\n",
++                        dev);
++                printk(KERN_DEBUG "md: old uuid %x %x %x %x\n",
++                        mddev->sb->set_uuid0,
++                        mddev->sb->set_uuid1,
++                        mddev->sb->set_uuid2,
++                        mddev->sb->set_uuid3);
++                printk(KERN_DEBUG "md: new uuid %x %x %x %x\n",
++                        rdev->sb->set_uuid0,
++                        rdev->sb->set_uuid1,
++                        rdev->sb->set_uuid2,
++                        rdev->sb->set_uuid3);
++        }
++#endif /* MD_BITMAP_SUPPORT */
++
+ 	bind_rdev_to_array(rdev, mddev);
+ 
+ 	/*
+@@ -2480,6 +2660,17 @@
+ 	mddev->sb->spare_disks++;
+ 	mddev->sb->working_disks++;
+ 
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        /*
++         * Maybe say something nice - 1 means we want to respect
++         * the bitmap in raid1 resync if there is one, 0
++         * means we need to kill any bitmap that we have been
++         * saving but we'll do it in the raid1 resync instead of here
++         */
++        printk(KERN_DEBUG "md%d: set repair bit to %d on superblock\n",
++                mdidx(mddev), hotrepair);
++        MD_SB_BITMAP_REPAIR(mddev->sb) = hotrepair;
++#endif /* MD_BITMAP_SUPPORT */
+ 	mddev->sb_dirty = 1;
+ 	md_update_sb(mddev);
+ 
+@@ -3419,6 +3610,10 @@
+ 	mddev_t *mddev2;
+ 	unsigned int max_sectors, currspeed,
+ 		j, window, err, serialize;
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++	/* PTB add realspeed for i/o limiting calculation */
++	unsigned realspeed;
++#endif /* MD_BITMAP_SUPPORT */
+ 	unsigned long mark[SYNC_MARKS];
+ 	unsigned long mark_cnt[SYNC_MARKS];
+ 	int last_mark,m;
+@@ -3488,6 +3683,9 @@
+ 	atomic_set(&mddev->recovery_active, 0);
+ 	init_waitqueue_head(&mddev->recovery_wait);
+ 	last_check = 0;
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++        atomic_set(&md_throttle[mdidx(mddev)], 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 	for (j = 0; j < max_sectors;) {
+ 		int sectors;
+ 
+@@ -3515,6 +3713,10 @@
+ 
+ 			mddev->resync_mark = mark[next];
+ 			mddev->resync_mark_cnt = mark_cnt[next];
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++                        /* PTB reset count of skipped blocks this mark */
++                        atomic_set(&md_throttle[mdidx(mddev)], 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 			mark[next] = jiffies;
+ 			mark_cnt[next] = j - atomic_read(&mddev->recovery_active);
+ 			last_mark = next;
+@@ -3540,16 +3742,34 @@
+ 		 * about not overloading the IO subsystem. (things like an
+ 		 * e2fsck being done on the RAID array should execute fast)
+ 		 */
+-		if (md_need_resched(current))
+-			schedule();
++		if (md_need_resched(current)) {
++			/* PTB this seems not to progress when over loop dev */
++ 
++			current->state = TASK_INTERRUPTIBLE;
++			md_schedule_timeout(1);
++                }
+ 
+ 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
+ 
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++                /*
++                 * PTB some of the blocks are skipped, not synced, so
++                 * should not count when limiting i/o. Let personality say.
++                 */
++		realspeed = (j - mddev->resync_mark_cnt - atomic_read(&md_throttle[mdidx(mddev)]))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
++#endif /* MD_BITMAP_SUPPORT */
++ 
+ 		if (currspeed > sysctl_speed_limit_min) {
+ 			current->nice = 19;
+ 
+-			if ((currspeed > sysctl_speed_limit_max) ||
+-					!is_mddev_idle(mddev)) {
++			if (
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++                        /* PTB use realspeed for upper limit on i/o */
++                            (realspeed > sysctl_speed_limit_max) ||
++#else
++                            (currspeed > sysctl_speed_limit_max) ||
++#endif /* MD_BITMAP_SUPPORT */
++                                        !is_mddev_idle(mddev)) {
+ 				current->state = TASK_INTERRUPTIBLE;
+ 				md_schedule_timeout(HZ/4);
+ 				goto repeat;
+@@ -4108,6 +4328,9 @@
+ }
+ #endif
+ 
++#if defined(CONFIG_MD_BITMAP) || defined(CONFIG_MD_BITMAP_MODULE)
++MD_EXPORT_SYMBOL(md_throttle);
++#endif /* MD_BITMAP_SUPPORT */
+ MD_EXPORT_SYMBOL(md_size);
+ MD_EXPORT_SYMBOL(register_md_personality);
+ MD_EXPORT_SYMBOL(unregister_md_personality);
+--- linux-2.4.30/drivers/md/bitmap.c.pre-fr1	Wed Apr  6 18:18:04 2005
++++ linux-2.4.30/drivers/md/bitmap.c	Wed Apr  6 18:18:04 2005
+@@ -0,0 +1,880 @@
++/*
++ * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
++ *
++ * bitmap_init   - sets nr blks
++ * bitmap->start - then calls the setup part for the 1st
++ *                 level in the bitmap, which uses memory (kmalloc) so
++ *                 can fail. You should examine the return value. 0 is
++ *                 OK. -ve is FAIL.
++ *
++ * bitmap->stop  - inverse to bitmap->start. kfrees the memory claimed in 
++ *                 bitmap_init.
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <linux/wrapper.h>
++#include <linux/proc_fs.h>  // PTB for kmalloc! How?
++#include <linux/vmalloc.h>  // PTB for vmalloc
++#include <linux/init.h>
++#include <linux/locks.h>
++#include <linux/config.h>
++
++# define DEBUG 1
++
++#include "bitmap.h"
++
++/* use 16 bits of the address as extra bitmap */
++#define ZONESHIFT 4
++/* top 16 bits are nonzero */
++#define IS_ADDRESS(x) \
++  ((( ((unsigned long)(x)) >> ((sizeof(char*)<<3) - (1<<ZONESHIFT))) ) != 0)
++
++#ifndef PRINTK
++#  if DEBUG > 0 
++#    define PRINTK(x...) printk(x)
++#  else
++#    define PRINTK(x...)
++#  endif
++#endif
++
++/* common cache of ready to go pages */
++static kmem_cache_t * bitmap_page_cache;
++/* list of all created bitmaps */
++struct list_head bitmap_list;
++
++/*
++ * replaces kfree on bitmap pages.
++ */
++static void
++bitmap_free_page(struct bitmap * bitmap, unsigned char * page) {
++        
++        if (!page)
++                return;
++
++        kmem_cache_free(bitmap_page_cache, (void *)page);
++}
++
++/*
++ * frees mamory kmalloced in bitmap_init
++ */
++void
++bitmap_destr(struct bitmap *bitmap) {
++
++        unsigned long k;
++        struct bitmap_page * bp;
++        unsigned long pages;
++        static void bitmap_stop(struct bitmap * bitmap);
++
++        bitmap_stop(bitmap);
++
++        write_lock(&bitmap->lock);
++        bitmap->flags &= ~BITMAP_ACTIVE;
++        bp = bitmap->bp;
++        pages = bitmap->pages;
++        bitmap->bp = NULL;
++        list_del(&bitmap->list);
++        write_unlock(&bitmap->lock);
++
++        if (bp) {
++                for (k = 0; k < pages; k++) {
++                        unsigned char *mappage;
++                        void *zoneinfo;
++
++                        mappage  = bp[k].map;
++                        zoneinfo = bp[k].zoneinfo;
++                        bp[k].map = NULL;
++                        bp[k].zoneinfo = NULL;
++
++                        if (IS_ADDRESS(mappage)) {
++                                /* zero page returned to cache via abort */
++                                memset (mappage, 0, PAGE_SIZE);
++                                bitmap_free_page (bitmap, mappage);
++                        	bitmap->missing_pages++;
++                        }
++                        if (IS_ADDRESS(zoneinfo)) {
++                                kfree (zoneinfo);
++        			bitmap->missing_zones++;
++                        }
++                }
++                if (bitmap->missing_pages < pages) {
++                        printk(KERN_WARNING "bitmap: mislaid %lu pages. Oops!\n",
++                        	pages - bitmap->missing_pages);
++                }
++                if (bitmap->missing_pages > pages) {
++                        printk(KERN_WARNING "bitmap: freed %lu extra pages. Oops!\n",
++                        	bitmap->missing_pages - pages);
++                }
++                if (bitmap->missing_zones < pages) {
++                        printk(KERN_WARNING "bitmap: mislaid %lu zoneinfo block. Oops!\n",
++                        	pages - bitmap->missing_zones);
++                }
++                if (bitmap->missing_zones > pages) {
++                        printk(KERN_WARNING "bitmap: freed %lu extra zoneinfo block. Oops!\n",
++                        	bitmap->missing_zones - pages);
++                }
++                vfree (bp);
++        }
++
++        bitmap_stop(bitmap);
++
++}
++
++/* 
++ * tests if the bitmap is marked active (has been started)
++ */
++static int
++bitmap_active(struct bitmap * bitmap) {
++        int res = 0;
++        if (!bitmap)
++                return res;
++        read_lock(&bitmap->lock);
++        res = bitmap->bp != NULL && (bitmap->flags & BITMAP_ACTIVE) != 0;
++        read_unlock(&bitmap->lock);
++        return res;
++}
++
++/*
++ * replaces kmalloc for bitmap pages.
++ */
++static unsigned char *
++bitmap_alloc_page(struct bitmap *bitmap) {
++        unsigned char *page;
++
++        page = kmem_cache_alloc(bitmap_page_cache, GFP_KERNEL);
++        /* PTB zeroing is done by the constructor and only
++         *     clean pages are returned to the cache
++         */
++        return page;
++}
++
++/*
++ * mark bitmap inactive and maybe prune the page cache
++ */
++static void
++bitmap_stop(struct bitmap * bitmap) {
++
++        write_lock(&bitmap->lock);
++        bitmap->flags &= ~BITMAP_ACTIVE;
++        write_unlock(&bitmap->lock);
++
++}
++
++/* 
++ * marks the bitmap active and primes the free page cache.
++ */
++static int
++bitmap_start(struct bitmap * bitmap, u64 events) {
++
++        struct bitmap_page * bp;
++        unsigned long pages;
++        
++        /* take lock to read data */
++        write_lock(&bitmap->lock);
++        pages = bitmap->pages;
++        bp    = bitmap->bp;
++        write_unlock(&bitmap->lock);
++
++        if (!bp) {
++
++                int k;
++
++                bp = vmalloc (pages * sizeof(*bp));
++                if (!bp) {
++                        printk(KERN_WARNING "bitmap: cannot get %luB of memory!\n",
++                                pages * sizeof(*bp));
++                        return -ENOMEM;
++                }
++                memset (bp, 0, pages * sizeof(*bp));
++
++                for (k = 0; k < pages; k++) {
++                        if (bp[k].zoneinfo)
++                                continue;
++                        bp[k].zoneinfo =
++                                kmalloc (sizeof(*bp[k].zoneinfo)<<ZONESHIFT,
++                                       GFP_KERNEL);
++                        if (bp[k].zoneinfo)
++                                bitmap->missing_zones--;
++                }
++                if (bitmap->missing_zones > 0) {
++                        printk(KERN_WARNING "bitmap: warning! cannot get %ld*%uB memory!\n",
++                              bitmap->missing_zones,
++                              sizeof(*bp->zoneinfo) << ZONESHIFT);
++                }
++        }
++
++        /*
++         * this is 16 shorts or 32 bytes + 4 bytes extra per page of 4096
++         * bytes, which is a reserve of less than 0.1%. Each page
++         * bitmaps 32MB of disk, so a 1GB disk takes 32 pages or 128KB, and
++         * a 1TB disk takes 128MB of pages. In those circumstances,
++         * adding a capital cost of about 1.08MB/TB doesn't seem bad.
++         */
++                
++
++        write_lock(&bitmap->lock);
++        bitmap->bp = bp;
++
++        /* bp is nonzero here */
++        bitmap->flags |= BITMAP_ACTIVE;
++        bitmap->events = events;
++        write_unlock(&bitmap->lock);
++
++        /* seed the page cache */
++        bitmap_free_page(bitmap, bitmap_alloc_page(bitmap));
++
++        return 0;
++}
++
++static int
++bitmap_checkpage (struct bitmap *bitmap, unsigned long page)
++{
++        unsigned char * mappage;
++
++        read_lock(&bitmap->lock);
++        if (page < 0 || page >= bitmap->pages) {
++                read_unlock(&bitmap->lock);
++		return -EINVAL;
++        }
++
++        if (bitmap->bp == NULL) {
++                read_unlock(&bitmap->lock);
++		return -ENODEV;
++        }
++
++
++        if (IS_ADDRESS(bitmap->bp[page].map)) {
++                read_unlock(&bitmap->lock);
++		return 0;
++        }
++        read_unlock(&bitmap->lock);
++
++        /* the page address was NULL */
++
++	if ((mappage = bitmap_alloc_page(bitmap)) == NULL) {
++                /* failed - check to see if we have backup counters */
++                void * tmp;
++                int need_new_zoneinfo = 0;
++
++                write_lock(&bitmap->lock);
++                if (!IS_ADDRESS(bitmap->bp[page].zoneinfo))
++                        need_new_zoneinfo = 1;
++                write_unlock(&bitmap->lock);
++
++                if (need_new_zoneinfo) {
++                        /* rarely, we might make an extra backup counter */
++                        tmp = kmalloc(sizeof(*bitmap->bp->zoneinfo)<<ZONESHIFT,
++                                    GFP_KERNEL);
++                        if (tmp) {
++
++                                write_lock(&bitmap->lock);
++                                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                                    /* somebody else made it first, backout */
++                                        need_new_zoneinfo = 0;
++                                } else {
++                                        bitmap->bp[page].zoneinfo = tmp;
++                                        bitmap->missing_zones--;
++                                }
++                                write_unlock(&bitmap->lock);
++
++                                if (!need_new_zoneinfo)
++                                        kfree(tmp);
++                        }
++                }
++		return -ENOMEM;
++        } 
++
++        /* got a page */
++
++        write_lock(&bitmap->lock);
++
++        /* recheck the page */
++
++        if (IS_ADDRESS(bitmap->bp[page].map)) {
++                /* somebody beat us to getting the page */
++                write_unlock(&bitmap->lock);
++                bitmap_free_page(bitmap, mappage);
++                return 0;
++        }
++
++        /* no page in place and we have one, so maybe install it */
++
++        if (bitmap->bp[page].count != 0) {
++                /* inpage bitmap - can't replace until no pending writes */
++                write_unlock(&bitmap->lock);
++                bitmap_free_page(bitmap, mappage);
++                return -EINVAL;
++        }
++
++        /* good case - we get to make a new page */
++        memset(mappage, 0, PAGE_SIZE);
++        bitmap->bp[page].map = mappage;
++        if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                memset(bitmap->bp[page].zoneinfo, 0,
++                        sizeof(*bitmap->bp->zoneinfo) << ZONESHIFT);
++        }
++        bitmap->missing_pages--;
++        write_unlock(&bitmap->lock);
++	return 0;
++
++}
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset
++ * We call this routine under lock.
++ */
++static int
++bitmap_clear_mask8 (struct bitmap *bitmap, bitmap_offset_t offset8,
++		  unsigned char mask, unsigned char **this_page)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        unsigned char oldmask;
++        unsigned char newmask;
++        unsigned char diffmask;
++	
++        page    = offset8 >> PAGE_SHIFT;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int bits = hweight8(mask);
++                bitmap->bp[page].count -= bits;
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1<<ZONESHIFT) - 1);
++                        bitmap->bp[page].zoneinfo[zone] -= bits;
++                }
++                return -EINVAL;
++        }
++
++        pageoff = offset8 & ~PAGE_MASK;
++
++	oldmask = bitmap->bp[page].map[pageoff];
++	newmask = oldmask & ~mask;
++	diffmask = newmask ^ oldmask;
++
++	if (diffmask) {
++	        unsigned bits = hweight8 (diffmask);
++                int newcount = (bitmap->bp[page].count -= bits);
++
++		bitmap->bp[page].map[pageoff] = newmask;
++
++                /* most frequent case is a +ve result and return */
++                if (newcount > 0)
++                        return 0;
++                /* negative count is a major misaccounting */
++                if (newcount < 0) {
++                        printk(KERN_WARNING "bitmap: dirty count %d on page %lu\n",
++                                newcount, page);
++                        return 0;
++                }
++                /* newcount == 0 is when we want to detach the page */
++                *this_page = bitmap->bp[page].map;
++                bitmap->bp[page].map = NULL;
++                bitmap->missing_pages++;
++                return 0;
++	}
++        return 0;
++}
++
++static int
++bitmap_clear_mask (struct bitmap *bitmap, bitmap_offset_t offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int errs = 0;
++        unsigned char * free_page0 = NULL, *free_page1 = NULL;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++        write_lock(&bitmap->lock);
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (bitmap_clear_mask8 (bitmap, blkgrp, maskdiv, &free_page0) < 0)
++                                errs++;
++                }
++		if (!maskrem) {
++                        goto out;
++                }
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
++                                errs++;
++                        goto out;
++                } 
++
++                if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
++                        errs++;
++                goto out;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (bitmap_clear_mask8 (bitmap, blkgrp, mask, &free_page0) < 0)
++                errs++;
++out:
++        write_unlock(&bitmap->lock);
++        if (free_page0)
++                bitmap_free_page(bitmap, free_page0);
++        if (free_page1)
++                bitmap_free_page(bitmap, free_page1);
++        return errs > 0 ? -EINVAL : 0;
++}
++
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset.
++ * We call this routine under lock.
++ */
++static int
++bitmap_set_mask8 (struct bitmap *bitmap, bitmap_offset_t offset8,
++		  unsigned char mask)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        unsigned char oldmask;
++        unsigned char newmask;
++        unsigned char diffmask;
++	
++        page    = offset8 >> PAGE_SHIFT;
++        pageoff = offset8 & ~PAGE_MASK;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int bits = hweight8(mask);
++                bitmap->bp[page].count += bits;
++                /* mark the zone instead - we have 16 low bits markable */
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                        bitmap->bp[page].zoneinfo[zone] += bits;
++                }
++                return -EINVAL;
++        }
++
++	oldmask = bitmap->bp[page].map[pageoff];
++	newmask = oldmask | mask;
++	diffmask = newmask ^ oldmask;
++
++	if (diffmask) {
++                unsigned int bits = hweight8 (diffmask);
++		bitmap->bp[page].map[pageoff] = newmask;
++		bitmap->bp[page].count += bits;
++	}
++        return 0;
++}
++
++/*
++ * here offset is the BIT offset
++ */
++static int
++bitmap_set_mask (struct bitmap *bitmap, bitmap_offset_t offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int errs = 0;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        if (bitmap_checkpage(bitmap, page) < 0)
++                errs++;
++
++        /* the page may or may not have been made */
++
++        write_lock(&bitmap->lock);
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (bitmap_set_mask8(bitmap, blkgrp, maskdiv) < 0)
++                                errs++;
++                }
++
++		if (!maskrem) {
++                        write_unlock(&bitmap->lock);
++                        return errs > 0 ? -EINVAL : 0 ;
++                }
++
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
++                                errs++;
++                        write_unlock(&bitmap->lock);
++                        return errs > 0 ? -EINVAL : 0 ;
++                } 
++                write_unlock(&bitmap->lock);
++                if (bitmap_checkpage(bitmap, page+1) < 0)
++                        errs++;
++
++                write_lock(&bitmap->lock);
++
++                if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
++                        errs++;
++                        
++                write_unlock(&bitmap->lock);
++                return errs > 0 ? -EINVAL : 0 ;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (bitmap_set_mask8(bitmap, blkgrp, mask) < 0)
++                errs++;
++
++        write_unlock(&bitmap->lock);
++        return errs > 0 ? -EINVAL : 0;
++}
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset.
++ * We call this routine under lock.
++ */
++static int
++bitmap_test_mask8 (struct bitmap *bitmap, bitmap_offset_t offset8,
++		  unsigned char mask)
++{
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        if (!mask)
++                return 0;
++	
++        page    = offset8 >> PAGE_SHIFT;
++        pageoff = offset8 & ~PAGE_MASK;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                /* look at zone instead - we have 16 low bits markable */
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                        if (bitmap->bp[page].zoneinfo[zone] > 0)
++                                return 1;
++                        return 0;
++                }
++                /* try the count */
++                if (bitmap->bp[page].count > 0)
++                        return 1;
++                return 0;
++        }
++
++	return (bitmap->bp[page].map[pageoff] & mask) != 0;
++}
++
++/*
++ * here offset is the BIT offset
++ */
++static int
++bitmap_test_mask (struct bitmap *bitmap, bitmap_offset_t offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int err;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        if (bitmap_checkpage(bitmap, page) < 0)
++                ; // ignore. We'll react below
++
++        /* the page may or may not have been made */
++
++        write_lock(&bitmap->lock);
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (err = bitmap_test_mask8(bitmap, blkgrp, maskdiv), err) {
++                                write_unlock(&bitmap->lock);
++                                return err;
++                        }
++                }
++
++		if (!maskrem) {
++                        write_unlock(&bitmap->lock);
++                        return 0 ;
++                }
++
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (err = bitmap_test_mask8(bitmap, blkgrp + 1, maskrem), err) {
++                                write_unlock(&bitmap->lock);
++                                return err;
++                        }
++                        write_unlock(&bitmap->lock);
++                        return  0 ;
++                } 
++                write_unlock(&bitmap->lock);
++                if (err = bitmap_checkpage(bitmap, page+1), err < 0)
++                        ; // ignore errors
++ 
++                write_lock(&bitmap->lock);
++
++                if (err = bitmap_test_mask8(bitmap, blkgrp + 1, maskrem), err) {
++                        write_unlock(&bitmap->lock);
++                        return err;
++                }
++                        
++                write_unlock(&bitmap->lock);
++                return 0 ;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (err = bitmap_test_mask8(bitmap, blkgrp, mask), err) {
++                write_unlock(&bitmap->lock);
++                return err ;
++        }
++
++        write_unlock(&bitmap->lock);
++        return 0;
++}
++ 
++static int
++bitmap_clear_bits (struct bitmap *bitmap, bitmap_offset_t offset, unsigned long bits)
++{
++
++        unsigned char mask;
++        int errs = 0;
++
++        while (offset + bits > (offset | 7)) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return (errs > 0) ? -EINVAL : 0;
++}
++
++static int
++bitmap_set_bits (struct bitmap *bitmap, bitmap_offset_t offset, unsigned long bits)
++{
++        unsigned char mask;
++        int errs = 0;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return (errs > 0) ? -EINVAL : 0;
++}
++
++static int
++bitmap_test_bits (struct bitmap *bitmap, bitmap_offset_t offset, unsigned long bits)
++{
++        unsigned char mask;
++        int err;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (err = bitmap_test_mask(bitmap, offset, mask), err) {
++                        return err;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (err = bitmap_test_mask(bitmap, offset, mask), err) {
++                        return err;
++                }
++                bits = 0;
++                offset += bits;
++        }
++        return 0;
++}
++
++/*
++static int
++bitmap_test_bit (struct bitmap *bitmap, unsigned long block)
++{
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int res;
++
++	blkgrp = block >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        read_lock(&bitmap->lock);
++        // high bits zero means no page address
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int zoneoffset = (blkgrp  >> (PAGE_SHIFT - ZONESHIFT));
++                int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                // use the counter instead - this is zoned
++                res = (bitmap->bp[page].count > 0);
++                if (res && IS_ADDRESS(bitmap->bp[page].zoneinfo))
++                        res = (bitmap->bp[page].zoneinfo[zone] > 0);
++                read_unlock(&bitmap->lock);
++                return res;
++        }
++
++	blkoff = block & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	res = test_bit ((pageoff << 3) + blkoff, bitmap->bp[page].map) != 0;
++        read_unlock(&bitmap->lock);
++        return res;
++}
++*/
++
++
++int
++bitmap_init(struct bitmap * bitmap, bitmap_offset_t bits) {
++
++        int pages = (bits + (PAGE_SIZE * 8 - 1)) / (PAGE_SIZE * 8);
++
++        memset(bitmap, 0, sizeof(*bitmap));
++	rwlock_init (&bitmap->lock);
++        write_lock(&bitmap->lock);
++
++        bitmap->start = bitmap_start;
++        bitmap->stop = bitmap_stop;
++        bitmap->testbits = bitmap_test_bits;
++        bitmap->setbits = bitmap_set_bits;
++        bitmap->clearbits = bitmap_clear_bits;
++        bitmap->active = bitmap_active;
++
++        /* now do 1st level init stuff */
++        if (pages < 0) {
++                write_unlock(&bitmap->lock);
++                printk(KERN_WARNING "bitmap: initialised for -ve number of pages (%d)!\n",
++                        pages);
++                return -EINVAL;
++        }
++        bitmap->pages = pages;
++        bitmap->missing_zones = pages;
++        bitmap->missing_pages = pages;
++        list_add(&bitmap->list, &bitmap_list);
++        write_unlock(&bitmap->lock);
++        return 0;
++}
++
++static void
++bitmap_clear_page(void *data, kmem_cache_t *cache, unsigned long flags) {
++
++        if (! (flags & SLAB_CTOR_CONSTRUCTOR))
++                return;
++        if (!data)
++                return;
++        memset(data, 0, PAGE_SIZE);
++}
++
++int
++bitmap_init_list(void) {
++        INIT_LIST_HEAD(&bitmap_list);
++        return 0;
++}
++
++int
++bitmap_init_page_cache(void) {
++        
++        bitmap_page_cache =
++            kmem_cache_create("bitmap_page", PAGE_SIZE, 0, 0, bitmap_clear_page, NULL);
++        if (!bitmap_page_cache)
++                return -ENOMEM;
++        return 0;
++}
++
++#ifdef MODULE
++void cleanup_module(void)
++{
++        struct bitmap *bitmap, *tbm;
++        list_for_each_entry_safe(bitmap, tbm, &bitmap_list, list)  {
++            printk(KERN_WARNING "bitmap: destroyed leftover bitmap %p in cleanup.\n", bitmap);
++            bitmap_destr(bitmap);
++        }
++        INIT_LIST_HEAD(&bitmap_list);
++        if (!bitmap_page_cache)
++                return;
++        kmem_cache_destroy(bitmap_page_cache);
++        bitmap_page_cache = NULL;
++}
++
++int init_module(void)
++{
++        return bitmap_init_list() || bitmap_init_page_cache();
++}
++
++  MODULE_AUTHOR ("Peter T. Breuer");
++  MODULE_DESCRIPTION ("Bitmap support");
++  MODULE_LICENSE("GPL");
++  int linux_version_code = LINUX_VERSION_CODE;
++#else           /* MODULE */
++__initcall(bitmap_init_list);
++__initcall(bitmap_init_page_cache);
++#endif          /* MODULE */
++
++/* Compile line:
++ *
++ *  gcc -O2 -D__KERNEL__ -DMODULE -c bitmap.c -o bitmap.o
++ *
++ */
++                      
+--- linux-2.4.30/drivers/md/bitmap.h.pre-fr1	Wed Apr  6 18:18:04 2005
++++ linux-2.4.30/drivers/md/bitmap.h	Wed Apr  6 18:18:04 2005
+@@ -0,0 +1,57 @@
++#ifndef BITMAP_H
++#define BITMAP_H 1
++
++typedef __s64 bitmap_offset_t;
++
++struct bitmap_page {
++        /*
++         * If a page is missing then we use a per
++         * page pending write count instead. pages is the number of
++         * 4k pages in the map.
++         */ 
++        char * map;
++        /*
++         * more precise count per zone (1/16 page), for emergencies.
++         */
++        short *zoneinfo;
++        /*
++         * count of dirty bits on the page
++         */ 
++        unsigned short  count;
++};
++
++struct bitmap {
++	struct bitmap_page * bp;
++	unsigned long pages;
++
++	int (*start) (struct bitmap * bitmap, __u64 events);
++	void (*stop) (struct bitmap * bitmap);
++	int (*testbits) (struct bitmap * bitmap, bitmap_offset_t shift, unsigned long nbits);
++	int (*setbits) (struct bitmap * bitmap, bitmap_offset_t shift, unsigned long nbits);
++	int (*clearbits) (struct bitmap * bitmap, bitmap_offset_t shift, unsigned long nbits);
++	int (*active) (struct bitmap * bitmap);
++
++        /* bitmap spinlock */
++	rwlock_t lock;
++
++#define BITMAP_ACTIVE 0x01
++        unsigned long flags;
++
++        /*
++         * events count at startup of the bitmap
++         */
++        __u64 events;
++
++        /*
++         * number of missing zoneinfo sections
++         */
++        unsigned long missing_zones;
++        unsigned long missing_pages;
++        struct list_head list;
++};
++
++
++int bitmap_init(struct bitmap * bitmap, bitmap_offset_t bits);
++void bitmap_destr(struct bitmap * bitmap);
++
++#endif
+--- linux-2.4.30/drivers/md/Makefile.pre-fr1	Sun Nov 11 19:09:32 2001
++++ linux-2.4.30/drivers/md/Makefile	Wed Apr  6 18:18:04 2005
+@@ -7,6 +7,7 @@
+ export-objs	:= md.o xor.o
+ list-multi	:= lvm-mod.o
+ lvm-mod-objs	:= lvm.o lvm-snap.o lvm-fs.o
++fr1-objs	:= raid1.o
+ 
+ # Note: link order is important.  All raid personalities
+ # and xor.o must come before md.o, as they each initialise 
+@@ -17,6 +18,8 @@
+ obj-$(CONFIG_MD_RAID0)		+= raid0.o
+ obj-$(CONFIG_MD_RAID1)		+= raid1.o
+ obj-$(CONFIG_MD_RAID5)		+= raid5.o xor.o
++obj-$(CONFIG_MD_BITMAP)		+= bitmap.o
++obj-$(CONFIG_MD_FR1)		+= fr1.o
+ obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
+ obj-$(CONFIG_BLK_DEV_MD)	+= md.o
+ obj-$(CONFIG_BLK_DEV_LVM)	+= lvm-mod.o
+@@ -25,3 +28,9 @@
+ 
+ lvm-mod.o: $(lvm-mod-objs)
+ 	$(LD) -r -o $@ $(lvm-mod-objs)
++
++fr1.o: $(fr1-objs)
++	$(LD) -r -o $@ $(fr1-objs)
++
++clean:
++	rm -f *.o .*.sw?
+--- linux-2.4.30/drivers/md/Config.in.pre-fr1	Fri Sep 14 23:22:18 2001
++++ linux-2.4.30/drivers/md/Config.in	Wed Apr  6 18:18:04 2005
+@@ -10,7 +10,14 @@
+ dep_tristate '  Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD
+ dep_tristate '  RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD
+ dep_tristate '  RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD
++if [ "$CONFIG_MD_RAID1" != "n" ]; then
++  dep_bool     '   RAID-1 robust read protocol' CONFIG_MD_RAID1_ROBUST_READ $CONFIG_BLK_DEV_MD
++fi
+ dep_tristate '  RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD
++dep_tristate '  Bitmap support for fast raid' CONFIG_MD_BITMAP $CONFIG_BLK_DEV_MD
++if [ "$CONFIG_MD_RAID1" != "y" ]; then
++  dep_tristate '  FR-1 (fast intelligent mirroring) mode' CONFIG_MD_FR1 $CONFIG__MD_BITMAP
++fi
+ dep_tristate '  Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
+ 
+ dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD
+--- linux-2.4.30/Documentation/Configure.help.pre-fr1	Mon Apr  4 03:42:19 2005
++++ linux-2.4.30/Documentation/Configure.help	Wed Apr  6 18:18:04 2005
+@@ -2050,6 +2050,53 @@
+ 
+   If unsure, say Y.
+ 
++FAST RAID-1 (mirroring) mode
++CONFIG_MD_FR1
++  This driver offers a faster software RAID-1 performance when
++  resynchronizing disks and reading, offers asynchronous writes, and has
++  various optimizations designed to automate administration.
++
++  Information about Software RAID on Linux is contained in the
++  Software-RAID mini-HOWTO, available from
++  <http://www.tldp.org/docs.html#howto>.  There you will also
++  learn where to get the supporting user space utilities raidtools.
++
++  If you want to use a FR-1 array, say Y. This code is also
++  available as a module called fr1.o ( = code which can be inserted
++  in and removed from the running kernel whenever you want).  If you
++  want to compile it as a module, say M here and read
++  <file:Documentation/modules.txt>. You cannot compile both this and
++  RAID1 into the kernel, so you may prefer to say M.
++
++  If unsure, say Y.
++
++FAST RAID-1 bitmap support
++CONFIG_MD_BITMAP
++  This driver provides the needed bitmap support for the Fast RAID-1
++  module FR1.
++
++  Information about Software RAID on Linux is contained in the
++  Software-RAID mini-HOWTO, available from
++  <http://www.tldp.org/docs.html#howto>.  There you will also
++  learn where to get the supporting user space utilities raidtools.
++
++  If you want to use Fast RAID-1, say Y. This code is also
++  available as a module called bitmap.o ( = code which can be inserted
++  in and removed from the running kernel whenever you want).  If you
++  want to compile it as a module, say M here and read
++  <file:Documentation/modules.txt>. You cannot compile both this and
++  FR1 into the kernel, so you may prefer to say M.
++
++  If unsure, say Y.
++
++Robust RAID-1 read protocol
++CONFIG_MD_RAID1_ROBUST_READ
++  This modifcation changes the RAID-1 read protocol to withstand read
++  errors without ejecting the disk from the array. The read is retried
++  from another mirror instead.
++
++  If unsure, say N.
++
+ RAID-4/RAID-5 mode
+ CONFIG_MD_RAID5
+   A RAID-5 set of N drives with a capacity of C MB per drive provides
+--- linux-2.4/drivers/md/raid1.c.ORIG	2005-07-03 02:03:29.483821024 +0200
++++ linux-2.4/drivers/md/raid1.c	2005-07-03 02:51:03.211090929 +0200
+@@ -20,6 +20,28 @@
+  * You should have received a copy of the GNU General Public License
+  * (for example /usr/src/linux/COPYING); if not, write to the Free
+  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Changes by Peter T. Breuer <ptb@it.uc3m.es> 31/1/2003 to support
++ * bitmapped intelligence in resync:
++ *
++ *      - bitmap attached on setfaulty (mark bad)
++ *      - bitmap marked during normal i/o if faulty disk
++ *      - bitmap used to skip nondirty blocks during sync
++ *      - bitmap removed on set active
++ *
++ *   Minor changes are needed in raid1.h (extra fields in conf) and in
++ *   md.c (support hotadd directly after setfaulty, or disk recognition).
++ *
++ * More changes by PTB 20/2/2003 to let the bitmap always be present and
++ * thus allow asynchronous mirror writes by using it as a journal log.
++ *
++ * Changes by PTB 10/8/2004 to redo read-balancing so that it reads
++ * from the fastest disk, as determined by latency testing every so
++ * often.
++ *
++ * Changes by PTB 6/1/2005 to make read errors not fault the disk out
++ * of the array but cause retries instead. And also (with CORRECT set)
++ * trigger rewrite of the bad sector.
+  */
+ 
+ #include <linux/module.h>
+@@ -32,7 +54,15 @@
+ #define MD_DRIVER
+ #define MD_PERSONALITY
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++#define MAX_WORK_PER_DISK (128 * 8)
++#define MAX_TEST_PER_DISK 64
++#define LATENCY_OLD_WEIGHT 9
++#define LATENCY_NEW_WEIGHT 1
++#define LATENCY_SUM_WEIGHT (LATENCY_OLD_WEIGHT + LATENCY_NEW_WEIGHT)
++#else
+ #define MAX_WORK_PER_DISK 128
++#endif /* CONFIG_MD_FR1 */
+ 
+ #define	NR_RESERVED_BUFS	32
+ 
+@@ -50,11 +80,19 @@
+ #define PRINTK(x...)  do { } while (0)
+ #endif
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++#include "bitmap.h"
++#endif /* CONFIG_MD_FR1 */
+ 
+ static mdk_personality_t raid1_personality;
+ static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED;
+ struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail;
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++/* module params */
++static int async;   /* async writes */
++#endif /* CONFIG_MD_FR1 */
++
+ static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt)
+ {
+ 	/* return a linked list of "cnt" struct buffer_heads.
+@@ -325,6 +363,9 @@ static int raid1_map (mddev_t *mddev, kd
+ {
+ 	raid1_conf_t *conf = mddev_to_conf(mddev);
+ 	int i, disks = MD_SB_DISKS;
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++        kdev_t dev = *rdev;
++#endif /* CONFIG_MD_RAID1_READ_WRITE_CORRECT */
+ 	unsigned long flags;
+ 
+ 	/*
+@@ -332,6 +373,30 @@ static int raid1_map (mddev_t *mddev, kd
+ 	 * now we use the first available disk.
+ 	 */
+ 
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++        /*
++         * Uh, no. Choose the next disk if we can, not the first.
++         */
++	md_spin_lock_irqsave(&conf->device_lock, flags);
++	for (i = 0; i < conf->raid_disks; i++) {
++		if (conf->mirrors[i].dev == dev)
++                    	break;
++        }
++        i++;
++	if (i >= conf->raid_disks)
++		i = 0;
++	for (; i < conf->raid_disks; i++) {
++		if (conf->mirrors[i].operational) {
++			*rdev = conf->mirrors[i].dev;
++			return (0);
++		}
++        }
++	md_spin_unlock_irqrestore(&conf->device_lock, flags);
++        /*
++         * If for some reason we found nothing, dropthru and use the old
++         * routine.
++         */
++#endif /* CONFIG_MD_RAID1_READ_WRITE_CORRECT */
+ 	md_spin_lock_irqsave(&conf->device_lock, flags);
+ 	for (i = 0; i < disks; i++) {
+ 		if (conf->mirrors[i].operational) {
+@@ -400,13 +465,65 @@ static void inline sync_request_done (un
+ static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate)
+ {
+ 	struct buffer_head *bh = r1_bh->master_bh;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	raid1_conf_t * conf = mddev_to_conf(r1_bh->mddev);
++
++	/* if nobody has done the final end_io yet, do it now */
++	if (!test_and_set_bit(R1BH_AsyncPhase, &r1_bh->state)) {
++
++		PRINTK(KERN_DEBUG "raid1: sync end i/o on sectors %lu-%lu\n",
++			bh->b_rsector, bh->b_rsector + (bh->b_size >> 9) - 1);
+ 
++		io_request_done(bh->b_rsector, conf,
++			test_bit(R1BH_SyncPhase, &r1_bh->state));
++		bh->b_end_io(bh, uptodate);
++	}
++#else
+ 	io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev),
+ 			test_bit(R1BH_SyncPhase, &r1_bh->state));
+ 
+ 	bh->b_end_io(bh, uptodate);
++#endif /* CONFIG_MD_FR1 */
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	/* if we should mark the bitmap clean, do so */
++	if (uptodate && r1_bh->cmd == WRITE && r1_bh->nonoperational <= 0) {
++	struct bitmap * bitmap = conf->bitmap;
++		if (bitmap && bitmap->active(bitmap)) {
++			bitmap->clearbits(bitmap, (bitmap_offset_t) (bh->b_rsector >> 1), bh->b_size >> 10);
++		}
++	}
++	/* PTB calculate the latency of the read device */
++	if (uptodate && (r1_bh->cmd == READ || r1_bh->cmd == READA)) {
++		unsigned long latency = jiffies - r1_bh->start_jiffies;
++		kdev_t dev = (&r1_bh->bh_req)->b_dev;
++		int i;
++
++		/* PTB find the mirror component being read */
++		for (i = 0; i < conf->raid_disks; i++) {
++			if (conf->mirrors[i].dev == dev)
++			break;
++		}
++		if (i < conf->raid_disks) {
++			if (latency < 120 * HZ && latency >= 0) {
++				/* PTB count in 1/10ths if we have total weights 9+1 = 10 */
++				latency *= LATENCY_SUM_WEIGHT * LATENCY_SUM_WEIGHT;
++				conf->latency[i] = LATENCY_OLD_WEIGHT * conf->latency[i]
++						+ LATENCY_NEW_WEIGHT * latency;
++				conf->latency[i] /= LATENCY_SUM_WEIGHT;
++			} else {
++				printk(KERN_ERR "raid1: bad latency %lu jiffies\n", 
++				latency);
++			}
++		} else {
++			printk(KERN_ERR "raid1: could not find dev %02x:%02x\n", 
++			MAJOR(dev), MINOR(dev));
++		}
++	}
++#endif /* CONFIG_MD_FR1 */
+ 	raid1_free_r1bh(r1_bh);
+ }
++
+ void raid1_end_request (struct buffer_head *bh, int uptodate)
+ {
+ 	struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private);
+@@ -414,9 +531,27 @@ void raid1_end_request (struct buffer_he
+ 	/*
+ 	 * this branch is our 'one mirror IO has finished' event handler:
+ 	 */
+-	if (!uptodate)
+-		md_error (r1_bh->mddev, bh->b_dev);
+-	else
++	if (!uptodate) {
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++		/*
++		 * Only fault disk out of array on write error, not read.
++		 */
++                if (r1_bh->cmd == WRITE)
++                       	if (printk(KERN_ALERT
++                          "raid1: erroring bh WRITE for sector %ld\n",
++                                  bh->b_rsector), 1)
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
++			md_error (r1_bh->mddev, bh->b_dev);
++#ifdef CONFIG_MD_RAID1_READ_WRITE_CORRECT
++                } else {  /* tell next time we're here that we're a retry */
++                       	printk(KERN_ALERT
++                          "raid1: set retry bit on bh READ for sector %ld\n",
++                                  bh->b_rsector);
++			set_bit(R1BH_ReadRetry, &r1_bh->state);
++                }
++#endif /* CONFIG_MD_RAID1_READ_WRITE_CORRECT */
++
++        } else
+ 		/*
+ 		 * Set R1BH_Uptodate in our master buffer_head, so that
+ 		 * we will return a good error code for to the higher
+@@ -438,7 +573,21 @@ void raid1_end_request (struct buffer_he
+ 		 * we have only one buffer_head on the read side
+ 		 */
+ 		
+-		if (uptodate) {
++               if (uptodate
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++			/* Give up and error if we're last */
++			|| atomic_dec_and_test(&r1_bh->remaining)
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
++			) {
++#ifdef CONFIG_MD_RAID1_READ_WRITE_CORRECT
++			if (uptodate && test_bit(R1BH_ReadRewrite, &r1_bh->state)) {
++				/* Success at last - rewrite failed reads */
++                                r1_bh->cmd = SPECIAL;
++				raid1_reschedule_retry(r1_bh);
++                                return;
++			} else
++#endif /* CONFIG_MD_RAID1_READ_WRITE_CORRECT */
++
+ 			raid1_end_bh_io(r1_bh, uptodate);
+ 			return;
+ 		}
+@@ -447,6 +596,13 @@ void raid1_end_request (struct buffer_he
+ 		 */
+ 		printk(KERN_ERR "raid1: %s: rescheduling block %lu\n", 
+ 			 partition_name(bh->b_dev), bh->b_blocknr);
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++               /*
++                * if not uptodate and not the last possible try,
++                * bh will be rescheduled and repointed while on the
++                * queue, by raid1_map.
++                */
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
+ 		raid1_reschedule_retry(r1_bh);
+ 		return;
+ 	}
+@@ -456,10 +612,39 @@ void raid1_end_request (struct buffer_he
+ 	 *
+ 	 * Let's see if all mirrored write operations have finished 
+ 	 * already.
++         *
++         * In any case, do the end io early on the master bh if we are
++         * uptodate, and AsyncIO is set on the bh. We set AsyncPhase
++         * when this happens, so we don't do it twice, inadvertently.
+ 	 */
++		
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        if (uptodate
++        &&  test_bit(R1BH_AsyncIO, &r1_bh->state)
++        && !test_and_set_bit(R1BH_AsyncPhase, &r1_bh->state)) {
++
++	        struct buffer_head *mbh = r1_bh->master_bh;
+ 
+-	if (atomic_dec_and_test(&r1_bh->remaining))
++	        raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev);
++
++                PRINTK(KERN_DEBUG "raid1: async end i/o on sectors %lu-%lu\n",
++                        mbh->b_rsector, mbh->b_rsector + (mbh->b_size >> 9) - 1);
++
++	        io_request_done(mbh->b_rsector, conf,
++			test_bit(R1BH_SyncPhase, &r1_bh->state));
++	        mbh->b_end_io(mbh, uptodate);
++        }
++#endif /* CONFIG_MD_FR1 */
++
++	if (atomic_dec_and_test(&r1_bh->remaining)) {
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	        if (test_and_set_bit(R1BH_AsyncIO, &r1_bh->state)) {
++                        /* we made a copy for the buffer, remove it now */
++                        kfree(bh->b_data);
++                }
++#endif /* CONFIG_MD_FR1 */
+ 		raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state));
++        }
+ }
+ 
+ /*
+@@ -520,7 +705,7 @@ static int raid1_read_balance (raid1_con
+ 	 * Don't touch anything for sequential reads.
+ 	 */
+ 
+-	if (this_sector == conf->mirrors[new_disk].head_position)
++	if (0 && /* PTB */ this_sector == conf->mirrors[new_disk].head_position)
+ 		goto rb_out;
+ 	
+ 	/*
+@@ -531,7 +716,16 @@ static int raid1_read_balance (raid1_con
+ 	 */
+ 	
+ 	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
+-		conf->sect_count = 0;
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                PRINTK(KERN_INFO
++                  "raid1: disk %d latency %d abandoned after %d sectors\n",
++                  new_disk,
++                  conf->latency[new_disk],
++	          conf->sect_count);
++
++                /* PTB move on to run a short test on the next disk */
++#endif /* CONFIG_MD_FR1 */
+ 
+ #if defined(CONFIG_SPARC64) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 92)
+ 		/* Work around a compiler bug in egcs-2.92.11 19980921 */
+@@ -546,6 +740,39 @@ static int raid1_read_balance (raid1_con
+ 		} while ((conf->mirrors[new_disk].write_only) ||
+ 			 (!conf->mirrors[new_disk].operational));
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                /* PTB if tested all, need to choose best */
++                if (new_disk == conf->last_source) {
++
++                        int fastest = -1;
++                        unsigned long best_latency = 0x7fffffff;
++                        int i;
++
++	                for (i = 0; i < conf->raid_disks; i++) {
++	                        if (conf->mirrors[i].write_only
++                                || !conf->mirrors[i].operational)
++                                        continue;
++                                if (conf->latency[i] <= best_latency) {
++                                    best_latency = conf->latency[i];
++                                    fastest = i;
++                                }
++                        }
++                        if (fastest >= 0)
++                                new_disk = fastest;
++	                conf->mirrors[new_disk].sect_limit = MAX_WORK_PER_DISK;
++                        conf->last_source = new_disk;
++                } else {
++                        /* PTB only a short test run */
++	                conf->mirrors[new_disk].sect_limit = MAX_TEST_PER_DISK;
++                }
++
++		conf->sect_count = 0;
++                PRINTK(KERN_DEBUG
++                  "raid1: choosing disk %d latency %d\n",
++                  new_disk,
++                  conf->latency[new_disk]);
++#endif /* CONFIG_MD_FR1 */
++
+ 		goto rb_out;
+ 	}
+ 	
+@@ -596,6 +823,11 @@ static int raid1_make_request (mddev_t *
+ 	int disks = MD_SB_DISKS;
+ 	int i, sum_bhs = 0;
+ 	struct mirror_info *mirror;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	int sum_nobhs = 0;
++	struct bitmap * bitmap = conf->bitmap;
++	char * async_data; // copy of buffer used for async writes
++#endif /* CONFIG_MD_FR1 */
+ 	kdev_t dev;
+ 
+ 	if (!buffer_locked(bh))
+@@ -635,6 +867,10 @@ static int raid1_make_request (mddev_t *
+ 	r1_bh->master_bh = bh;
+ 	r1_bh->mddev = mddev;
+ 	r1_bh->cmd = rw;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	r1_bh->start_jiffies = jiffies; /* PTB record start time */
++	async_data = NULL;
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	if (rw == READ) {
+ 		/*
+@@ -653,6 +889,20 @@ static int raid1_make_request (mddev_t *
+ 	/*	bh_req->b_rsector = bh->n_rsector; */
+ 		bh_req->b_end_io = raid1_end_request;
+ 		bh_req->b_private = r1_bh;
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++		atomic_set(&r1_bh->remaining, 0);
++		/* count target devices under spinlock */
++		md_spin_lock_irq(&conf->device_lock);
++		for (i = 0;  i < disks; i++) {
++	                if (!conf->mirrors[i].operational
++                        ||  !conf->mirrors[i].used_slot) {
++                                	continue;
++			} 
++			atomic_inc(&r1_bh->remaining);
++		}
++		md_spin_unlock_irq(&conf->device_lock);
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
++
+ 		generic_make_request (rw, bh_req);
+ 		return 0;
+ 	}
+@@ -662,11 +912,65 @@ static int raid1_make_request (mddev_t *
+ 	 */
+ 
+ 	bhl = raid1_alloc_bh(conf, conf->raid_disks);
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        if (bitmap->active(bitmap)) {
++
++                int err = bitmap->setbits(bitmap, (bitmap_offset_t) (bh->b_rsector >> 1),
++                        bh->b_size >> 10);
++
++                /*
++                 * PTB Do async i/o if we marked the bitmap (so it's safe to)
++                 * and we are supposed to.
++                 */
++                if (async && err >= 0) {
++                        async_data = kmalloc(bh->b_size, GFP_KERNEL);
++                        if (async_data) {
++                                memcpy(async_data, bh->b_data, bh->b_size);
++                                set_bit(R1BH_AsyncIO, &r1_bh->state);
++                        }
++                }
++                /*
++                 * PTB Even if the async bit is not set then we STILL need to
++                 * balance the setbits above with a clearbits in the end_io 
++                 * whether setbits errored or not above. That's because
++                 * setbits errors if the bitmap page is not there and
++                 * then we can only count attempted writes in the bitmap,
++                 * not actual writes, so we have to balance that with
++                 * attempted clears. And we do. See the end_io.
++                 */
++        }
++#endif /* CONFIG_MD_FR1 */
+ 	spin_lock_irq(&conf->device_lock);
+ 	for (i = 0; i < disks; i++) {
+ 		struct buffer_head *mbh;
+-		if (!conf->mirrors[i].operational) 
++		if (!conf->mirrors[i].operational) {
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                        struct bitmap * bitmap = conf->bitmap;
++
++                        if (!conf->mirrors[i].used_slot) {
++                                continue; 
++                        }
++
++                        /* notionally mark bitmap here */
++                        if (sum_nobhs++ <= 0) {
++                                PRINTK(KERN_DEBUG "raid1: mark mirror %d blk %lu-%lu\n",
++                                i, bh->b_rsector >> 1,
++                                (bh->b_rsector >> 1) + (bh->b_size >> 10) - 1);
++                        }
++
++                        if (!conf->bitmap_dirty && bitmap->active(bitmap)) {
++                                conf->bitmap_dirty = 1;
++                                MD_SB_EVENTS_LO(mddev->sb) =
++                                    mddev->sb->events_lo;
++                                MD_SB_EVENTS_HI(mddev->sb) =
++                                    mddev->sb->events_hi;
++                        }
++
++#endif /* CONFIG_MD_FR1 */
+ 			continue;
++                }
+  
+ 	/*
+ 	 * We should use a private pool (size depending on NR_REQUEST),
+@@ -703,6 +1007,10 @@ static int raid1_make_request (mddev_t *
+  		mbh->b_size       = bh->b_size;
+  		mbh->b_page	  = bh->b_page;
+  		mbh->b_data	  = bh->b_data;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++ 		mbh->b_data       =
++                 test_bit(R1BH_AsyncIO, &r1_bh->state)? async_data : bh->b_data;
++#endif /* CONFIG_MD_FR1 */
+  		mbh->b_list       = BUF_LOCKED;
+  		mbh->b_end_io     = raid1_end_request;
+  		mbh->b_private    = r1_bh;
+@@ -719,6 +1027,9 @@ static int raid1_make_request (mddev_t *
+ 		return 0;
+ 	}
+ 	md_atomic_set(&r1_bh->remaining, sum_bhs);
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	r1_bh->nonoperational = sum_nobhs;
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	/*
+ 	 * We have to be a bit careful about the semaphore above, thats
+@@ -769,6 +1080,85 @@ static void raid1_status(struct seq_file
+ #define ALREADY_SYNCING KERN_INFO \
+ "raid1: syncing already in progress.\n"
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++static int
++raid1_create_bitmap(mddev_t *mddev) {
++
++        struct bitmap * bitmap;
++        unsigned long blocks;
++	raid1_conf_t *conf = mddev_to_conf(mddev);
++
++        /* need size to have been set already */
++        blocks = mddev->sb->size << 1;
++
++        bitmap = kmalloc (sizeof (*bitmap), GFP_KERNEL);
++	if (!bitmap) {
++                printk(KERN_WARNING "raid1: out of memory for bitmap head\n");
++                return -ENOMEM;
++        }
++
++	if (bitmap_init (bitmap, blocks) < 0) {
++                printk(KERN_WARNING "raid1: failed to init bitmap\n");
++                kfree(bitmap);
++                return -ENOMEM;
++        }
++
++        /* take the spinlock for the ops on the configuration */
++	spin_lock_irq(&conf->segment_lock);
++        conf->bitmap = bitmap;
++        conf->bitmap_dirty = 0;
++	spin_unlock_irq(&conf->segment_lock);
++        return 0;
++}
++
++static void
++raid1_remove_bitmap (mddev_t *mddev) {
++
++	raid1_conf_t *conf = mddev_to_conf(mddev);
++        struct bitmap * bitmap;
++
++	spin_lock_irq(&conf->segment_lock);
++        bitmap = conf->bitmap;
++        if (!bitmap) {
++	        spin_unlock_irq(&conf->segment_lock);
++                return;
++        }
++        conf->bitmap = NULL;
++	spin_unlock_irq(&conf->segment_lock);
++
++        bitmap_destr(bitmap);
++        kfree(bitmap);
++}
++
++static int
++raid1_start_bitmap (mddev_t *mddev) {
++
++	raid1_conf_t *conf = mddev_to_conf(mddev);
++        struct bitmap * bitmap;
++
++	spin_lock_irq(&conf->segment_lock);
++        bitmap = conf->bitmap;
++	spin_unlock_irq(&conf->segment_lock);
++        if (!bitmap) {
++                return -EINVAL;
++        }
++
++        if (bitmap->active(bitmap)) {
++                printk(KERN_WARNING "raid1: bitmap %x already active!\n",
++                    (unsigned) bitmap);
++                return 0;
++        }
++	if (bitmap->start(bitmap, md_event(mddev->sb)) < 0) {
++                printk(KERN_WARNING "raid1: bitmap %x failed to start!\n",
++                    (unsigned) bitmap);
++                return -EINVAL;
++        }
++
++        PRINTK(KERN_DEBUG "raid1: made bitmap %x\n", (unsigned) bitmap);
++        return 0;
++}
++#endif /* CONFIG_MD_FR1 */
++
+ static void mark_disk_bad (mddev_t *mddev, int failed)
+ {
+ 	raid1_conf_t *conf = mddev_to_conf(mddev);
+@@ -777,6 +1167,13 @@ static void mark_disk_bad (mddev_t *mdde
+ 
+ 	mirror->operational = 0;
+ 	mark_disk_faulty(sb->disks+mirror->number);
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        /*
++         * Activate the bitmap on a mirror just marked faulty (and
++         * nonoperational).
++         */
++	raid1_start_bitmap (mddev);
++#endif /* CONFIG_MD_FR1 */
+ 	mark_disk_nonsync(sb->disks+mirror->number);
+ 	mark_disk_inactive(sb->disks+mirror->number);
+ 	if (!mirror->write_only)
+@@ -848,6 +1245,14 @@ static void print_raid1_conf (raid1_conf
+ 
+ 	for (i = 0; i < MD_SB_DISKS; i++) {
+ 		tmp = conf->mirrors + i;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++		/*
++		 * Remove repeats from debug printout.
++		 */
++		if (i > 0 && memcmp(tmp, &conf->mirrors[i-1], sizeof(*tmp)) == 0) {
++			continue;
++		}
++#endif /* CONFIG_MD_FR1 */
+ 		printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n",
+ 			i, tmp->spare,tmp->operational,
+ 			tmp->number,tmp->raid_disk,tmp->used_slot,
+@@ -939,16 +1344,36 @@ static int raid1_diskop(mddev_t *mddev, 
+ 	case DISKOP_SPARE_WRITE:
+ 	case DISKOP_SPARE_INACTIVE:
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                PRINTK(KERN_DEBUG "raid1: diskop SPARE %s\n",
++                        state == DISKOP_SPARE_WRITE ? "WRITE" : 
++                        state == DISKOP_SPARE_INACTIVE ? "INACTIVE" : 
++                        state == DISKOP_SPARE_ACTIVE ? "ACTIVE" : ""
++                        );
++#endif /* CONFIG_MD_FR1 */
+ 		/*
+ 		 * Find the spare disk ... (can only be in the 'high'
+ 		 * area of the array)
+ 		 */
+ 		for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+ 			tmp = conf->mirrors + i;
+-			if (tmp->spare && tmp->number == (*d)->number) {
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++			if (tmp->spare
++                        && (tmp->number == (*d)->number
++                        /*
++                         * I'm not sure we now need to allow match by
++                         * device number too. FIXME.
++                         */
++                            || tmp->dev == MKDEV((*d)->major,(*d)->minor))) {
+ 				spare_disk = i;
+ 				break;
+ 			}
++#else
++			if (tmp->spare && tmp->number == (*d)->number) {
++				spare_disk = i;
++				break;
++                        }
++#endif /* CONFIG_MD_FR1 */
+ 		}
+ 		if (spare_disk == -1) {
+ 			MD_BUG();
+@@ -1104,6 +1529,10 @@ static int raid1_diskop(mddev_t *mddev, 
+ 		fdisk->spare = 0;
+ 		fdisk->write_only = 0;
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                PRINTK(KERN_DEBUG "raid1: diskop SPARE device %x now ACTIVE\n",
++                        fdisk->dev);
++#endif /* CONFIG_MD_FR1 */
+ 		/*
+ 		 * if we activate a spare, we definitely replace a
+ 		 * non-operational disk slot in the 'low' area of
+@@ -1115,6 +1544,11 @@ static int raid1_diskop(mddev_t *mddev, 
+ 		break;
+ 
+ 	case DISKOP_HOT_REMOVE_DISK:
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                PRINTK(KERN_DEBUG "raid1: diskop HOT REMOVE\n");
++#endif /* CONFIG_MD_FR1 */
++
+ 		rdisk = conf->mirrors + removed_disk;
+ 
+ 		if (rdisk->spare && (removed_disk < conf->raid_disks)) {
+@@ -1148,6 +1582,11 @@ static int raid1_diskop(mddev_t *mddev, 
+ 		adisk->head_position = 0;
+ 		conf->nr_disks++;
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                PRINTK(KERN_DEBUG "raid1: diskop HOT ADDed mirror %d disk %d bitmap %x\n",
++                        added_disk, adisk->number, (unsigned)conf->bitmap);
++#endif /* CONFIG_MD_FR1 */
++
+ 		break;
+ 
+ 	default:
+@@ -1292,6 +1731,13 @@ static void raid1d (void *data)
+ 		case READA:
+ 			dev = bh->b_dev;
+ 			raid1_map (mddev, &bh->b_dev);
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++                        /* raid1_map incorrectly used to change target to
++                         * 0th disk always - now I hope it does a
++                         * better job that before and switches target to
++                         * next disk in the mirror.
++                         */
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
+ 			if (bh->b_dev == dev) {
+ 				printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr);
+ 				raid1_end_bh_io(r1_bh, 0);
+@@ -1398,6 +1844,22 @@ static int raid1_sync_request (mddev_t *
+ 	int block_nr;
+ 	int buffs;
+ 	kdev_t dev;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        /*
++         * Will need to count mirror components currently with a bitmap
++         * which have been marked faulty and nonoperational at some
++         * point beforehand, and have been accumulating marks on the
++         * bitmap to indicate dirty blocks that need syncing.
++         */
++        struct bitmap * bitmap = conf->bitmap;
++        int count, block_not_dirty;
++        int targets[MD_SB_DISKS];
++        /*
++         * PTB discount the skipped sectors back to the md.c code
++         */
++        extern atomic_t md_throttle[];
++
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	if (!sector_nr) {
+ 		/* we want enough buffers to hold twice the window of 128*/
+@@ -1406,9 +1868,29 @@ static int raid1_sync_request (mddev_t *
+ 		if (buffs < 2)
+ 			goto nomem;
+ 		conf->window = buffs*(PAGE_SIZE>>9)/2;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                /* also remove bitmap if not indicated */
++                if (! MD_SB_BITMAP_REPAIR(mddev->sb)) {
++                        /* has to be outside spinlock as it takes it */
++                        printk(KERN_WARNING "md%d: removed bitmap %x\n",
++                                mdidx(mddev), (unsigned)bitmap);
++                        bitmap->stop (bitmap);
++                } else {
++                        printk(KERN_WARNING "md%d: retained bitmap %x\n",
++                                mdidx(mddev), (unsigned)bitmap);
++                }
++                /* reset the bitmap indicator always */
++                MD_SB_BITMAP_REPAIR(mddev->sb) = 0;
++#endif /* CONFIG_MD_FR1 */
+ 	}
+ 	spin_lock_irq(&conf->segment_lock);
+ 	if (!sector_nr) {
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                /* setup extra report counters for skipped/synced blocks */
++                conf->sync_mode = -1;
++                conf->last_clean_sector = -1;
++                conf->last_dirty_sector = -1;
++#endif /* CONFIG_MD_FR1 */
+ 		/* initialize ...*/
+ 		conf->start_active = 0;
+ 		conf->start_ready = 0;
+@@ -1422,7 +1904,7 @@ static int raid1_sync_request (mddev_t *
+ 			MD_BUG();
+ 	}
+ 	while (sector_nr >= conf->start_pending) {
+-		PRINTK("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n",
++		PRINTK("wait .. sect=%lu start_active=%ld ready=%ld pending=%ld future=%ld, cnt_done=%d active=%d ready=%d pending=%d future=%d\n",
+ 			sector_nr, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future,
+ 			conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future);
+ 		wait_event_lock_irq(conf->wait_done,
+@@ -1463,9 +1945,71 @@ static int raid1_sync_request (mddev_t *
+ 	conf->last_used = disk;
+ 	
+ 	mirror = conf->mirrors+conf->last_used;
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        /* PTB go looking for the faulted (nonoperational) mirrors, under lock */
++        count = 0;
++	while (1) {
++                const int maxdisk = 2 * conf->raid_disks - conf->working_disks;
++		if (disk <= 0)
++                        disk = maxdisk > MD_SB_DISKS ? MD_SB_DISKS : maxdisk;
++		disk--;
++		if (disk == conf->last_used)
++			break;
++                if (!conf->mirrors[disk].operational)
++                        continue;
++                /* We need them to be writable */
++                if (conf->mirrors[disk].write_only) {
++                        targets[count++] = disk;
++                }
++	}
++
++        bitmap = conf->bitmap;
++        block_not_dirty = bitmap->active(bitmap)
++            && !bitmap->testbits(bitmap, (bitmap_offset_t) (sector_nr >> 1), 1);
++#endif /* CONFIG_MD_FR1 */
++
+ 	dev = mirror->dev;
+ 	spin_unlock_irq(&conf->device_lock);
+-	
++
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        if (count > 0 && block_not_dirty) {
++
++                const int done = 2 - (sector_nr & 1);
++
++	        md_sync_acct(mirror->dev, done);
++                sync_request_done(sector_nr, conf);
++		md_done_sync(mddev, done, 1);
++
++                /* do these conf accesses under lock, though only accounting */
++	        spin_lock_irq(&conf->segment_lock);
++                if (conf->sync_mode != 0) {
++                        if (conf->sync_mode == 1) {
++                                printk(KERN_INFO "raid1: synced dirty sectors %lu-%lu\n",
++                                conf->last_clean_sector+1,
++                                conf->last_dirty_sector);
++                        }
++                        conf->sync_mode = 0;
++                }
++
++                conf->last_clean_sector = sector_nr + done - 1;
++                if (mddev->sb && sector_nr + done >= mddev->sb->size<<1) {
++                        printk(KERN_INFO "raid1: skipped clean sectors %lu-%lu\n",
++                        conf->last_dirty_sector+1,
++                        conf->last_clean_sector);
++                }
++ 
++                /* PTB here be dragons - update md driver throttle discount */
++                atomic_add(done, &md_throttle[mdidx(mddev)]);
++	        spin_unlock_irq(&conf->segment_lock);
++
++		wake_up(&conf->wait_ready);
++                /* skip remainder of block */
++                return done;
++        }
++  	
++        /* read */
++#endif /* CONFIG_MD_FR1 */
+ 	r1_bh = raid1_alloc_buf (conf);
+ 	r1_bh->master_bh = NULL;
+ 	r1_bh->mddev = mddev;
+@@ -1499,6 +2043,30 @@ static int raid1_sync_request (mddev_t *
+ 	generic_make_request(READ, bh);
+ 	md_sync_acct(bh->b_dev, bh->b_size/512);
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        /* printout info from time to time */
++	spin_lock_irq(&conf->segment_lock);
++        if (conf->sync_mode != 1) {
++                if (conf->sync_mode == 0) {
++                        printk(KERN_INFO "raid1: skipped clean sectors %lu-%lu\n",
++                        conf->last_dirty_sector+1,
++                        conf->last_clean_sector);
++ 
++ 
++                }
++                conf->sync_mode = 1;
++        }
++        conf->last_dirty_sector = sector_nr + (bsize >> 9) - 1;
++
++        if (mddev->sb && sector_nr + (bsize >> 9) >= mddev->sb->size<<1) {
++                printk(KERN_INFO "raid1: synced dirty sectors %lu-%lu\n",
++                conf->last_clean_sector+1,
++                conf->last_dirty_sector);
++        }
++ 
++	spin_unlock_irq(&conf->segment_lock);
++#endif /* CONFIG_MD_FR1 */
++
+ 	return (bsize >> 9);
+ 
+ nomem:
+@@ -1531,6 +2099,14 @@ static void end_sync_write(struct buffer
+ 		mddev_t *mddev = r1_bh->mddev;
+  		unsigned long sect = bh->b_blocknr;
+ 		int size = bh->b_size;
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++                raid1_conf_t * conf = mddev_to_conf(mddev);
++                struct bitmap * bitmap = conf->bitmap;
++                if (bitmap && bitmap->active(bitmap)) {
++                        /* PTB clean the bitmap after resync */
++                        bitmap->clearbits(bitmap, (bitmap_offset_t)(sect >> 1), size >> 10);
++                }
++#endif /* CONFIG_MD_FR1 */
+ 		raid1_free_buf(r1_bh);
+ 		sync_request_done(sect, mddev_to_conf(mddev));
+ 		md_done_sync(mddev,size>>9, uptodate);
+@@ -1576,6 +2152,11 @@ static void end_sync_write(struct buffer
+ #define START_RESYNC KERN_WARNING \
+ "raid1: raid set md%d not clean; reconstructing mirrors\n"
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++#define BITMAP_ERROR KERN_ERR \
++"raid1: out of memory for bitmap on md%d\n"
++#endif /* CONFIG_MD_FR1 */
++
+ static int raid1_run (mddev_t *mddev)
+ {
+ 	raid1_conf_t *conf;
+@@ -1744,6 +2325,16 @@ static int raid1_run (mddev_t *mddev)
+ 		/* nothing */;
+ 	conf->last_used = j;
+ 
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++        /* make the bitmap at this point - hope mddev->size exists already */
++        if (raid1_create_bitmap(mddev) < 0) {
++                printk(BITMAP_ERROR, mdidx(mddev));
++		goto out_free_conf;
++        }
++
++        /* set it active too */
++        raid1_start_bitmap (mddev);
++#endif /* CONFIG_MD_FR1 */
+ 
+ 
+ 	{
+@@ -1803,6 +2394,9 @@ out_free_conf:
+ 	raid1_shrink_r1bh(conf);
+ 	raid1_shrink_bh(conf);
+ 	raid1_shrink_buffers(conf);
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	raid1_remove_bitmap (mddev);
++#endif /* CONFIG_MD_FR1 */
+ 	kfree(conf);
+ 	mddev->private = NULL;
+ out:
+@@ -1864,6 +2458,9 @@ static int raid1_stop (mddev_t *mddev)
+ 	raid1_shrink_r1bh(conf);
+ 	raid1_shrink_bh(conf);
+ 	raid1_shrink_buffers(conf);
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++	raid1_remove_bitmap (mddev);
++#endif /* CONFIG_MD_FR1 */
+ 	kfree(conf);
+ 	mddev->private = NULL;
+ 	MOD_DEC_USE_COUNT;
+@@ -1896,4 +2493,8 @@ static void raid1_exit (void)
+ 
+ module_init(raid1_init);
+ module_exit(raid1_exit);
++#if defined(CONFIG_MD_FR1) || defined(CONFIG_MD_FR1_MODULE)
++MODULE_PARM(async, "i");
++MODULE_PARM_DESC(async, "Do async writes");
++#endif /* CONFIG_MD_FR1 */
+ MODULE_LICENSE("GPL");
diff -Nrup fr1-2.17.orig/patches/linux-2.6.12.2.patch fr1-2.17/patches/linux-2.6.12.2.patch
--- fr1-2.17.orig/patches/linux-2.6.12.2.patch	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/linux-2.6.12.2.patch	2005-07-18 02:14:45.037844525 +0200
@@ -0,0 +1,2466 @@
+--- linux-2.6.11.6/drivers/md/bitmap.h.orig	Sun Jun 12 00:11:44 2005
++++ linux-2.6.11.6/drivers/md/bitmap.h	Sun Jun 12 00:11:44 2005
+@@ -0,0 +1,62 @@
++#ifndef BITMAP_H
++#define BITMAP_H 1
++
++struct bitmap_page {
++        /*
++         * If a page is missing then we use a per
++         * page pending write count instead. pages is the number of
++         * 4k pages in the map.
++         */ 
++        char * map;
++        /*
++         * more precise count per zone (1/16 page), for emergencies.
++         */
++        short *zoneinfo;
++        /*
++         * count of dirty bits on the page
++         */ 
++        unsigned short  count;
++};
++
++struct bitmap {
++	struct bitmap_page * bp;  // array of size pages
++	unsigned long pages;      // maximum #pages, mapping 32k blocks each
++
++	int (*start) (struct bitmap * bitmap, __u64 events);
++	void (*stop) (struct bitmap * bitmap);
++	int (*testbits) (struct bitmap * bitmap, sector_t shift, unsigned long bits);
++	int (*setbits) (struct bitmap * bitmap, sector_t shift, unsigned long bits);
++	int (*clearbits) (struct bitmap * bitmap, sector_t shift, unsigned long bits);
++	int (*active) (struct bitmap * bitmap);
++
++        /* bitmap spinlock */
++	rwlock_t lock;
++
++#define BITMAP_ACTIVE 0x01
++        unsigned long flags;
++
++        /*
++         * events count at startup of the bitmap
++         */
++        __u64 events;
++
++        /*
++         * number of missing zoneinfo sections
++         */
++        unsigned long missing_zones;
++        unsigned long missing_pages;
++
++        /*
++         * pages currently in the map
++         */
++        unsigned long current_pages;
++        unsigned long alloced_pages;
++
++	void (*print_stats) (struct bitmap * bitmap);
++};
++
++
++int bitmap_init(struct bitmap * bitmap, unsigned long long bits);
++void bitmap_destr(struct bitmap * bitmap);
++
++#endif
+--- linux-2.6.11.6/drivers/md/bitmap.c.orig	Sun Jun 12 00:11:44 2005
++++ linux-2.6.11.6/drivers/md/bitmap.c	Sun Jun 12 00:11:44 2005
+@@ -0,0 +1,887 @@
++/*
++ * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003
++ *
++ * bitmap_init   - sets nr blks
++ * bitmap->start - then calls the setup part for the 1st
++ *                 level in the bitmap, which uses memory (kmalloc) so
++ *                 can fail. You should examine the return value. 0 is
++ *                 OK. -ve is FAIL.
++ *
++ * bitmap->stop  - inverse to bitmap->start. kfrees the memory claimed in 
++ *                 bitmap_init.
++ *
++ * bitmap_detr   - inverse to init. Detroys pages, etc.
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <linux/proc_fs.h>  // PTB for kmalloc! How?
++#include <linux/vmalloc.h>  // PTB for vmalloc
++#include <linux/init.h>
++#include <linux/config.h>
++
++# define DEBUG 1
++
++#include "bitmap.h"
++
++/* use 16 bits of the address as extra bitmap */
++#define ZONESHIFT 4
++/* top 16 bits are nonzero */
++#define IS_ADDRESS(x) \
++  ((( ((unsigned long)(x)) >> ((sizeof(char*)<<3) - (1<<ZONESHIFT))) ) != 0)
++
++#ifndef PRINTK
++#  if DEBUG > 0 
++#    define PRINTK(x...) printk(x)
++#  else
++#    define PRINTK(x...)
++#  endif
++#endif
++
++/* cache of ready to go pages */
++static kmem_cache_t * bitmap_page_cache;
++
++/*
++ * replaces kfree on bitmap pages.
++ */
++static void
++bitmap_free_page(struct bitmap * bitmap, unsigned char * page) {
++        
++        if (!page)
++                return;
++
++        kmem_cache_free(bitmap_page_cache, (void *)page);
++        bitmap->alloced_pages--;
++}
++
++static void
++bitmap_print_stats(struct bitmap * bitmap) {
++        printk(KERN_INFO "bitmap: %lu pages in use\n",
++                bitmap->current_pages);
++        printk(KERN_INFO "bitmap: %lu pages allocated\n",
++                bitmap->alloced_pages);
++        printk(KERN_INFO "bitmap: %lu pages pre-allocated \n",
++                bitmap->alloced_pages - bitmap->current_pages);
++}
++
++/*
++ * mark bitmap inactive and maybe prune the page cache
++ */
++static void
++bitmap_stop(struct bitmap * bitmap) {
++
++        write_lock(&bitmap->lock);
++        bitmap->flags &= ~BITMAP_ACTIVE;
++        write_unlock(&bitmap->lock);
++}
++
++/*
++ * frees mamory kmalloced in bitmap_init
++ */
++void
++bitmap_destr(struct bitmap *bitmap) {
++
++        unsigned long k;
++        struct bitmap_page * bp;
++        unsigned long pages;
++
++        printk(KERN_DEBUG "destroying bitmap %p\n", bitmap);
++
++        bitmap_stop(bitmap);
++        bitmap_print_stats(bitmap);
++
++        write_lock(&bitmap->lock);
++        bitmap->flags &= ~BITMAP_ACTIVE;
++        bp = bitmap->bp;
++        pages = bitmap->pages;
++        bitmap->bp = NULL;
++        bitmap->missing_pages = pages;
++        bitmap->current_pages = 0;
++        bitmap->alloced_pages = 0;
++        bitmap->missing_zones = pages;
++        write_unlock(&bitmap->lock);
++
++        if (bp) {
++                for (k = 0; k < pages; k++) {
++                        if (IS_ADDRESS(bp[k].map)) {
++                                bitmap_free_page (bitmap, bp[k].map);
++                                bp[k].map = NULL;
++                        }
++                        if (IS_ADDRESS(bp[k].zoneinfo)) {
++                                kfree (bp[k].zoneinfo);
++                                bp[k].zoneinfo = NULL;
++                        }
++                }
++                vfree (bp);
++        }
++
++        bitmap_stop(bitmap);
++
++        MOD_DEC_USE_COUNT;
++        THIS_MODULE->unsafe = 0;
++}
++
++/* 
++ * tests if the bitmap is marked active (has been started)
++ * Returns the events count on the bitmap.
++ */
++static int
++bitmap_active(struct bitmap * bitmap) {
++        int res = 0;
++        if (!bitmap)
++                return res;
++        read_lock(&bitmap->lock);
++        if (bitmap->flags & BITMAP_ACTIVE) {
++            res = (unsigned int)bitmap->events;
++            if (res <= 0)
++                res = 1;
++        } else {
++            res = 0;
++        }
++        read_unlock(&bitmap->lock);
++        return res;
++}
++
++/*
++ * replaces kmalloc for bitmap pages.
++ */
++static unsigned char *
++bitmap_alloc_page(struct bitmap *bitmap) {
++        unsigned char *page;
++
++        page = kmem_cache_alloc(bitmap_page_cache, GFP_KERNEL);
++        /* PTB zeroing is done by the constructor and only
++         *     clean pages are returned to the cache
++         */
++        if (page)
++                bitmap->alloced_pages++;
++        return page;
++}
++
++
++
++/* 
++ * marks the bitmap active and primes the free page cache.
++ */
++static int
++bitmap_start(struct bitmap * bitmap, u64 events) {
++
++        struct bitmap_page * bp;
++        unsigned long pages;
++        
++        /* take lock to read data */
++        write_lock(&bitmap->lock);
++        pages = bitmap->pages;
++        bp    = bitmap->bp;
++        write_unlock(&bitmap->lock);
++
++        if (!bp) {
++
++                int k;
++
++                bp = vmalloc (pages * sizeof(*bp));
++                if (!bp) {
++                        printk(KERN_WARNING "bitmap: cannot get %luB of memory!\n",
++                                pages * sizeof(*bp));
++                        return -ENOMEM;
++                }
++                memset (bp, 0, pages * sizeof(*bp));
++
++                for (k = 0; k < pages; k++) {
++                        if (bp[k].zoneinfo)
++                                continue;
++                        bp[k].zoneinfo =
++                                kmalloc (sizeof(*bp[k].zoneinfo)<<ZONESHIFT,
++                                       GFP_KERNEL);
++                        if (bp[k].zoneinfo)
++                                bitmap->missing_zones--;
++                }
++                if (bitmap->missing_zones > 0) {
++                        printk(KERN_WARNING "bitmap: warning! cannot get %ld*%uB memory!\n",
++                              bitmap->missing_zones,
++                              sizeof(*bp->zoneinfo) << ZONESHIFT);
++                }
++        }
++
++        /*
++         * this is 16 shorts or 32 bytes + 4 bytes extra per page of 4096
++         * bytes, which is a reserve of less that 0.1%. But each page
++         * bitmaps 32MB of disk, so a 1GB disk takes 32 pages or 128KB, and
++         * a 1TB disk takes 128MB of pages. In those circumstances,
++         * adding a capital cost of about 108KB doesn't seem bad.
++         */
++                
++
++        write_lock(&bitmap->lock);
++        bitmap->bp = bp;
++
++        bitmap->flags |= BITMAP_ACTIVE;
++        bitmap->events = events;
++        write_unlock(&bitmap->lock);
++
++        /* seed the page cache */
++        bitmap_free_page(bitmap, bitmap_alloc_page(bitmap));
++
++        return 0;
++}
++
++/*
++ * Test if the page is in the map, and bring it in if not. 
++ *
++ * Return 0 for success.
++ */
++static int
++bitmap_checkpage (struct bitmap *bitmap, unsigned long page)
++{
++        unsigned char * mappage;
++
++        read_lock(&bitmap->lock);
++        if (page < 0 || page >= bitmap->pages) {
++                read_unlock(&bitmap->lock);
++		return -EINVAL;
++        }
++
++        if (bitmap->bp == NULL) {
++                read_unlock(&bitmap->lock);
++		return -ENODEV;
++        }
++
++
++        if (IS_ADDRESS(bitmap->bp[page].map)) {
++                read_unlock(&bitmap->lock);
++		return 0;
++        }
++        read_unlock(&bitmap->lock);
++
++        /* the page address was NULL */
++
++	if ((mappage = bitmap_alloc_page(bitmap)) == NULL) {
++                /* failed - check to see if we have backup counters */
++                void * tmp;
++                int need_new_zoneinfo = 0;
++
++                write_lock(&bitmap->lock);
++                if (!IS_ADDRESS(bitmap->bp[page].zoneinfo))
++                        need_new_zoneinfo = 1;
++                write_unlock(&bitmap->lock);
++
++                if (need_new_zoneinfo) {
++                        /* rarely, we might make an extra backup counter */
++                        tmp = kmalloc(sizeof(*bitmap->bp->zoneinfo)<<ZONESHIFT,
++                                    GFP_KERNEL);
++                        if (tmp) {
++
++                                write_lock(&bitmap->lock);
++                                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                                    /* somebody else made it first, backout */
++                                        need_new_zoneinfo = 0;
++                                } else {
++                                        bitmap->bp[page].zoneinfo = tmp;
++                                        bitmap->missing_zones--;
++                                }
++                                write_unlock(&bitmap->lock);
++
++                                if (!need_new_zoneinfo)
++                                        kfree(tmp);
++                        }
++                }
++		return -ENOMEM;
++        } 
++
++        /* got a page */
++
++        write_lock(&bitmap->lock);
++
++        /* recheck the page */
++
++        if (IS_ADDRESS(bitmap->bp[page].map)) {
++                /* somebody beat us to getting the page */
++                write_unlock(&bitmap->lock);
++                bitmap_free_page(bitmap, mappage);
++                return 0;
++        }
++
++        /* no page in place and we have one, so maybe install it */
++
++        if (bitmap->bp[page].count != 0) {
++                /* inpage bitmap - can't replace until no pending writes */
++                write_unlock(&bitmap->lock);
++                bitmap_free_page(bitmap, mappage);
++                return -EINVAL;
++        }
++
++        /* good case - we get to make a new page */
++        memset(mappage, 0, PAGE_SIZE);
++        bitmap->bp[page].map = mappage;
++        if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                memset(bitmap->bp[page].zoneinfo, 0,
++                        sizeof(*bitmap->bp->zoneinfo) << ZONESHIFT);
++        }
++        bitmap->missing_pages--;
++        bitmap->current_pages++;
++        write_unlock(&bitmap->lock);
++	return 0;
++
++}
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset
++ * We call this routine under lock.
++ */
++static int
++bitmap_clear_mask8 (struct bitmap *bitmap, sector_t offset8,
++		  unsigned char mask, unsigned char **this_page)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        unsigned char oldmask;
++        unsigned char newmask;
++        unsigned char diffmask;
++	
++        page    = offset8 >> PAGE_SHIFT;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int bits = hweight8(mask);
++                bitmap->bp[page].count -= bits;
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1<<ZONESHIFT) - 1);
++                        bitmap->bp[page].zoneinfo[zone] -= bits;
++                }
++                return -EINVAL;
++        }
++
++        pageoff = offset8 & ~PAGE_MASK;
++
++	oldmask = bitmap->bp[page].map[pageoff];
++	newmask = oldmask & ~mask;
++	diffmask = newmask ^ oldmask;
++
++	if (diffmask) {
++	        unsigned bits = hweight8 (diffmask);
++                int newcount = (bitmap->bp[page].count -= bits);
++
++		bitmap->bp[page].map[pageoff] = newmask;
++
++                /* most frequent case is a +ve result and return */
++                if (newcount > 0)
++                        return 0;
++                /* negative count is a major misaccounting */
++                if (newcount < 0) {
++                        printk(KERN_WARNING "bitmap: dirty count %d on page %lu\n",
++                                newcount, page);
++                        return 0;
++                }
++                /* newcount == 0 is when we want to detach the page */
++                *this_page = bitmap->bp[page].map;
++                bitmap->bp[page].map = NULL;
++                bitmap->missing_pages++;
++                bitmap->current_pages--;
++                return 0;
++	}
++        return 0;
++}
++
++/*
++ * offset is the bit count, i.e. the block number.
++ */
++static int
++bitmap_clear_mask (struct bitmap *bitmap, sector_t offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int errs = 0;
++        unsigned char * free_page0 = NULL, *free_page1 = NULL;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++        write_lock(&bitmap->lock);
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (bitmap_clear_mask8 (bitmap, blkgrp, maskdiv, &free_page0) < 0)
++                                errs++;
++                }
++		if (!maskrem) {
++                        goto out;
++                }
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
++                                errs++;
++                        goto out;
++                } 
++
++                if (bitmap_clear_mask8 (bitmap, blkgrp + 1, maskrem, &free_page1) < 0)
++                        errs++;
++                goto out;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (bitmap_clear_mask8 (bitmap, blkgrp, mask, &free_page0) < 0)
++                errs++;
++out:
++        write_unlock(&bitmap->lock);
++        if (free_page0)
++                bitmap_free_page(bitmap, free_page0);
++        if (free_page1)
++                bitmap_free_page(bitmap, free_page1);
++        return errs > 0 ? -EINVAL : 0;
++}
++
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset.
++ * We call this routine under lock.
++ */
++static int
++bitmap_set_mask8 (struct bitmap *bitmap, sector_t offset8,
++		  unsigned char mask)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        unsigned char oldmask;
++        unsigned char newmask;
++        unsigned char diffmask;
++	
++        page    = offset8 >> PAGE_SHIFT;
++        pageoff = offset8 & ~PAGE_MASK;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int bits = hweight8(mask);
++                bitmap->bp[page].count += bits;
++                /* mark the zone instead - we have 16 low bits markable */
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                        bitmap->bp[page].zoneinfo[zone] += bits;
++                }
++                return -EINVAL;
++        }
++
++	oldmask = bitmap->bp[page].map[pageoff];
++	newmask = oldmask | mask;
++	diffmask = newmask ^ oldmask;
++
++	if (diffmask) {
++                unsigned int bits = hweight8 (diffmask);
++		bitmap->bp[page].map[pageoff] = newmask;
++		bitmap->bp[page].count += bits;
++	}
++        return 0;
++}
++
++/* 
++ * offset8 is the BYTE offset, not the bit offset.
++ * We call this routine under lock.
++ */
++static int
++bitmap_test_mask8 (struct bitmap *bitmap, sector_t offset8,
++		  unsigned char mask)
++{
++
++        unsigned long page  ;
++        unsigned long pageoff;
++
++        if (!mask)
++                return 0;
++	
++        page    = offset8 >> PAGE_SHIFT;
++        pageoff = offset8 & ~PAGE_MASK;
++
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                /* look at zone instead - we have 16 low bits markable */
++                if (IS_ADDRESS(bitmap->bp[page].zoneinfo)) {
++                        int zoneoffset = (offset8  >> (PAGE_SHIFT - ZONESHIFT));
++                        int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                        if (bitmap->bp[page].zoneinfo[zone] > 0)
++                                return 1;
++                        return 0;
++                }
++                /* try the count */
++                if (bitmap->bp[page].count > 0)
++                        return 1;
++                return 0;
++        }
++
++	return (bitmap->bp[page].map[pageoff] & mask) != 0;
++}
++
++/*
++ * here offset is the BIT offset
++ */
++static int
++bitmap_set_mask (struct bitmap *bitmap, sector_t offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int errs = 0;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        if (bitmap_checkpage(bitmap, page) < 0)
++                errs++;
++
++        /* the page may or may not have been made */
++
++        write_lock(&bitmap->lock);
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (bitmap_set_mask8(bitmap, blkgrp, maskdiv) < 0)
++                                errs++;
++                }
++
++		if (!maskrem) {
++                        write_unlock(&bitmap->lock);
++                        return errs > 0 ? -EINVAL : 0 ;
++                }
++
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
++                                errs++;
++                        write_unlock(&bitmap->lock);
++                        return errs > 0 ? -EINVAL : 0 ;
++                } 
++                write_unlock(&bitmap->lock);
++                if (bitmap_checkpage(bitmap, page+1) < 0)
++                        errs++;
++
++                write_lock(&bitmap->lock);
++
++                if (bitmap_set_mask8(bitmap, blkgrp + 1, maskrem) < 0)
++                        errs++;
++                        
++                write_unlock(&bitmap->lock);
++                return errs > 0 ? -EINVAL : 0 ;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (bitmap_set_mask8(bitmap, blkgrp, mask) < 0)
++                errs++;
++
++        write_unlock(&bitmap->lock);
++        return errs > 0 ? -EINVAL : 0;
++}
++
++/*
++ * here offset is the BIT offset
++ */
++static int
++bitmap_test_mask (struct bitmap *bitmap, sector_t offset, unsigned char mask)
++{
++
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int err;
++
++	blkgrp = offset >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        if (bitmap_checkpage(bitmap, page) < 0)
++                ; // ignore. We'll react below
++
++        /* the page may or may not have been made */
++
++        write_lock(&bitmap->lock);
++	blkoff = offset & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	if (blkoff) {
++		unsigned char maskdiv = 0xff & (mask << blkoff);
++		unsigned char maskrem = 0xff & (mask >> (8 - blkoff));
++
++                if (maskdiv) {
++                        if (err = bitmap_test_mask8(bitmap, blkgrp, maskdiv), err) {
++                                write_unlock(&bitmap->lock);
++                                return err;
++                        }
++                }
++
++		if (!maskrem) {
++                        write_unlock(&bitmap->lock);
++                        return 0 ;
++                }
++
++                if (pageoff + 1 < PAGE_SIZE) {
++
++                        if (err = bitmap_test_mask8(bitmap, blkgrp + 1, maskrem), err) {
++                                write_unlock(&bitmap->lock);
++                                return err;
++                        }
++                        write_unlock(&bitmap->lock);
++                        return  0 ;
++                } 
++                write_unlock(&bitmap->lock);
++                if (err = bitmap_checkpage(bitmap, page+1), err < 0)
++                        ; // ignore errors
++
++                write_lock(&bitmap->lock);
++
++                if (err = bitmap_test_mask8(bitmap, blkgrp + 1, maskrem), err) {
++                        write_unlock(&bitmap->lock);
++                        return err;
++                }
++                        
++                write_unlock(&bitmap->lock);
++                return 0 ;
++	}
++
++        // normal situation. Offset is multiple of 8
++	
++        if (err = bitmap_test_mask8(bitmap, blkgrp, mask), err) {
++                write_unlock(&bitmap->lock);
++                return err ;
++        }
++
++        write_unlock(&bitmap->lock);
++        return 0;
++}
++
++static int
++bitmap_clear_bits (struct bitmap *bitmap, sector_t offset, unsigned long bits)
++{
++
++        unsigned char mask;
++        int errs = 0;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_clear_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return (errs > 0) ? -EINVAL : 0;
++}
++
++static int
++bitmap_set_bits (struct bitmap *bitmap, sector_t offset, unsigned long bits)
++{
++
++        unsigned char mask;
++        int errs = 0;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (bitmap_set_mask(bitmap, offset, mask) < 0) {
++                        errs++;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return (errs > 0) ? -EINVAL : 0;
++}
++
++static int
++bitmap_test_bits (struct bitmap *bitmap, sector_t offset, unsigned long bits)
++{
++        unsigned char mask;
++        int err;
++
++        while (offset + bits >= (offset | 7) + 1) {
++                int more = (offset | 7) + 1 - offset;
++                mask = (1 << more) - 1;
++                /* ignore errors and do what we can */
++                if (err = bitmap_test_mask(bitmap, offset, mask), err) {
++                        return err;
++                }
++                bits -= more;
++                offset |= 7;
++                offset++;
++        }
++
++        if (bits > 0) {
++                mask = (1 << bits) - 1;
++                /* ignore errors and do what we can */
++                if (err = bitmap_test_mask(bitmap, offset, mask), err) {
++                        return err;
++                }
++                bits = 0;
++                offset += bits;
++        }
++
++        return 0;
++}
++
++/*
++static int
++bitmap_test_bit (struct bitmap *bitmap, unsigned long block)
++{
++	unsigned long blkgrp;
++	unsigned char blkoff;
++        unsigned long page  ;
++        unsigned long pageoff;
++        int res;
++
++	blkgrp = block >> 3;
++        page   = blkgrp >> PAGE_SHIFT;
++
++        read_lock(&bitmap->lock);
++        // high bits zero means no page address
++        if (!IS_ADDRESS(bitmap->bp[page].map)) {
++                int zoneoffset = (blkgrp  >> (PAGE_SHIFT - ZONESHIFT));
++                int zone = zoneoffset & ((1 << ZONESHIFT) - 1);
++                // use the counter instead - this is zoned
++                res = (bitmap->bp[page].count > 0);
++                if (res && IS_ADDRESS(bitmap->bp[page].zoneinfo))
++                        res = (bitmap->bp[page].zoneinfo[zone] > 0);
++                read_unlock(&bitmap->lock);
++                return res;
++        }
++
++	blkoff = block & 7;
++        pageoff= blkgrp & ~PAGE_MASK;
++
++	res = test_bit ((pageoff << 3) + blkoff, bitmap->bp[page].map) != 0;
++        read_unlock(&bitmap->lock);
++        return res;
++}
++*/
++
++int
++bitmap_init(struct bitmap * bitmap, unsigned long long blocks) {
++
++        unsigned long pages = (blocks + (PAGE_SIZE * 8 - 1)) / (PAGE_SIZE * 8);
++
++        memset(bitmap, 0, sizeof(*bitmap));
++	rwlock_init (&bitmap->lock);
++        write_lock(&bitmap->lock);
++
++        bitmap->start = bitmap_start;
++        bitmap->stop = bitmap_stop;
++        bitmap->testbits = bitmap_test_bits;
++        bitmap->setbits = bitmap_set_bits;
++        bitmap->clearbits = bitmap_clear_bits;
++        bitmap->active = bitmap_active;
++        bitmap->print_stats = bitmap_print_stats;
++
++        /* now do 1st level init stuff */
++        if (pages < 0) {
++                write_unlock(&bitmap->lock);
++                printk(KERN_WARNING "bitmap: initialised for -ve number of pages (%ld)!\n",
++                        pages);
++                return -EINVAL;
++        }
++        bitmap->pages = pages;
++        bitmap->missing_zones = pages;
++        bitmap->missing_pages = pages;
++        bitmap->current_pages = 0;
++        bitmap->alloced_pages = 0;
++
++        // we are all using the same page cache.
++        MOD_INC_USE_COUNT;
++        THIS_MODULE->unsafe = 0;
++
++        write_unlock(&bitmap->lock);
++        return 0;
++}
++
++static void
++bitmap_clear_page(void *data, kmem_cache_t *cache, unsigned long flags) {
++
++        if (! (flags & SLAB_CTOR_CONSTRUCTOR))
++                return;
++        if (!data)
++                return;
++        memset(data, 0, PAGE_SIZE);
++}
++
++int
++bitmap_init_page_cache(void) {
++        bitmap_page_cache =
++            kmem_cache_create("bitmap_page", PAGE_SIZE, 0, 0, bitmap_clear_page, NULL);
++        if (!bitmap_page_cache)
++                return -ENOMEM;
++        return 0;
++}
++
++#ifdef MODULE
++void cleanup_module(void)
++{
++        if (!bitmap_page_cache)
++                return;
++        kmem_cache_destroy(bitmap_page_cache);
++        bitmap_page_cache = NULL;
++}
++
++int init_module(void)
++{
++        return bitmap_init_page_cache();
++}
++
++  MODULE_AUTHOR ("Peter T. Breuer");
++  MODULE_DESCRIPTION ("Bitmap support");
++  MODULE_LICENSE("GPL");
++  int linux_version_code = LINUX_VERSION_CODE;
++#else           /* MODULE */
++__initcall(bitmap_init_page_cache);
++#endif          /* MODULE */
++
++EXPORT_SYMBOL(bitmap_destr);
++EXPORT_SYMBOL(bitmap_init);
++
++/* Compile line:
++ *
++ *  gcc -O2 -D__KERNEL__ -DMODULE -c bitmap.c -o bitmap.o
++ *
++ */
++                      
+--- linux-2.6.11.6/include/linux/raid/raid1.h.orig	Sat Mar 26 04:28:22 2005
++++ linux-2.6.11.6/include/linux/raid/raid1.h	Sun Jun 12 00:11:44 2005
+@@ -50,6 +50,17 @@
+ 
+ 	mempool_t *r1bio_pool;
+ 	mempool_t *r1buf_pool;
++
++#ifdef CONFIG_MD_FR1
++        long                    last_clean_sector;  /* helps debugging   */
++        long                    last_dirty_sector;
++        int                     sync_mode;          /* clean/dirty pass? */
++        void                    *bitmap;            /* the array bitmap  */
++        int                     bitmap_dirty;       /* flag              */
++        int                     latency[MD_SB_DISKS];
++        int                     last_source;        /* disk read from    */
++#endif /* CONFIG_MD_FR1 */
++
+ };
+ 
+ typedef struct r1_private_data_s conf_t;
+@@ -85,6 +96,12 @@
+ 	int			read_disk;
+ 
+ 	struct list_head	retry_list;
++
++#ifdef CONFIG_MD_FR1
++        int                     nonoperational; /* no of bad mirrors */
++        unsigned long           start_jiffies;  /* when i/o started  */
++#endif /* CONFIG_MD_FR1 */
++
+ 	/*
+ 	 * if the IO is in WRITE direction, then multiple bios are used.
+ 	 * We choose the number when they are allocated.
+@@ -95,4 +112,12 @@
+ /* bits for r1bio.state */
+ #define	R1BIO_Uptodate	0
+ #define	R1BIO_IsSync	1
++#ifdef CONFIG_MD_FR1
++  #define R1BIO_AsyncPhase 4
++  #define R1BIO_AsyncIO    5
++#endif /* CONFIG_MD_FR1 */
++#ifdef DO_ADD_READ_WRITE_CORRECT
++#define R1BIO_ReadRetry    6
++#endif /* DO_ADD_READ_WRITE_CORRECT */
++
+ #endif
+--- linux-2.6.11.6/include/linux/raid/md_p.h.orig	Sat Mar 26 04:28:16 2005
++++ linux-2.6.11.6/include/linux/raid/md_p.h	Sun Jun 12 09:11:53 2005
+@@ -140,7 +140,20 @@
+ 	__u32 cp_events_hi;	/* 10 high-order of checkpoint update count   */
+ #endif
+ 	__u32 recovery_cp;	/* 11 recovery checkpoint sector count	      */
+-	__u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 12];
++#ifdef __BIG_ENDIAN
++        __u32 bitmap_events_hi; /* 12 high-order bits of bitmap events count  */
++        __u32 bitmap_events_lo; /* 13 low-order bits of bitmap events count   */
++#else
++        __u32 bitmap_events_lo; /* 12 low-order bits of bitmap events count   */
++        __u32 bitmap_events_hi; /* 13 high-order bits of bitmap events count  */
++#endif
++        /* Begin macros to use 2 ints to support fast raid */
++#define MD_SB_BITMAP_EVENTS_LO(sb)     (sb)->bitmap_events_lo
++#define MD_SB_BITMAP_EVENTS_HI(sb)     (sb)->bitmap_events_hi
++#define MD_SB_BITMAP_EVENTS(sb) \
++    (((u64)MD_SB_BITMAP_EVENTS_HI(sb) << 32)|((u64)MD_SB_BITMAP_EVENTS_LO(sb)))
++        /* End macros to use 2 ints to support fast raid */
++	__u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 14];
+ 
+ 	/*
+ 	 * Personality information
+@@ -215,7 +228,15 @@
+ 	__u64	resync_offset;	/* data before this offset (from data_offset) known to be in sync */
+ 	__u32	sb_csum;	/* checksum upto devs[max_dev] */
+ 	__u32	max_dev;	/* size of devs[] array to consider */
+-	__u8	pad3[64-32];	/* set to 0 when writing */
++        __u32 bitmap_events_lo; /* low-order bits of bitmap events count   */
++        __u32 bitmap_events_hi; /* high-order bits of bitmap events count  */
++        /* Begin macros to use 2 ints to support fast raid */
++#define MD_SB_BITMAP_EVENTS_LO_1(sb)     (sb)->bitmap_events_lo
++#define MD_SB_BITMAP_EVENTS_HI_1(sb)     (sb)->bitmap_events_hi
++#define MD_SB_BITMAP_EVENTS_1(sb) \
++    (((u64)MD_SB_BITMAP_EVENTS_HI_1(sb) << 32)|((u64)MD_SB_BITMAP_EVENTS_LO_1(sb)))
++        /* End macros to use 2 ints to support fast raid */
++	__u8	pad3[64-40];	/* set to 0 when writing */
+ 
+ 	/* device state information. Indexed by dev_number.
+ 	 * 2 bytes per device
+--- linux-2.6.11.6/include/linux/raid/md_k.h.orig	Sat Mar 26 04:28:14 2005
++++ linux-2.6.11.6/include/linux/raid/md_k.h	Sun Jun 12 00:11:44 2005
+@@ -238,6 +238,9 @@
+ #define	MD_RECOVERY_INTR	3
+ #define	MD_RECOVERY_DONE	4
+ #define	MD_RECOVERY_NEEDED	5
++        /* begin bits added to support fast raid */
++#define MD_BITMAP_REPAIR	8
++        /* end bits added to support fast raid */
+ 	unsigned long			recovery;
+ 
+ 	int				in_sync;	/* know to not need resync */
+@@ -261,6 +264,9 @@
+ 	request_queue_t			*queue;	/* for plugging ... */
+ 
+ 	struct list_head		all_mddevs;
++/* added for bitmap */
++	__u64				bitmap_events; /* last bitmap stamp */
++/* end of additions for bitmap */
+ };
+ 
+ 
+--- linux-2.6/drivers/md/raid1.c.orig	2005-07-13 13:48:25.922131227 +0200
++++ linux-2.6/drivers/md/raid1.c	2005-07-18 01:21:25.475150139 +0200
+@@ -20,6 +20,30 @@
+  * You should have received a copy of the GNU General Public License
+  * (for example /usr/src/linux/COPYING); if not, write to the Free
+  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Changes by Peter T. Breuer <ptb@it.uc3m.es> 31/1/2003 to support
++ * bitmapped intelligence in resync:
++ *
++ *      - bitmap attached on setfaulty (mark bad)
++ *      - bitmap marked during normal i/o if faulty disk
++ *      - bitmap used to skip nondirty blocks during sync
++ *      - bitmap removed on set active
++ *
++ *   Minor changes are needed in raid1.h (extra fields in conf) and in
++ *   md.c (support hotadd directly after setfaulty, or disk recognition).
++ *
++ * Changes by PTB 10/8/2004 to redo read-balancing so that it reads
++ * from the fastest disk, as determined by latency testing every so
++ * often.
++ * Changes by PTB 6/1/2005 to make read errors not fault the disk out
++ * of the array but cause retries instead. And also (with CORRECT set)
++ * trigger rewrite of the bad sector.
++ * Changes by PTB 15/3/2005 to keep rdev from being kfreed in
++ * export_rdev in md.c and instead free it here during replacement of the rdev
++ * in add_disk. Otherwise we would trace along a freed struct to see if
++ * it represents the dev we are interested in replacing. Thanks to
++ * Denis Bonnenfant (denis DOT bonnenfant AT diderot DOT org) for finding
++ * this and several other associated problems in the 2.6.8.1 port.
+  */
+ 
+ #include <linux/raid/raid1.h>
+@@ -29,6 +53,22 @@
+  */
+ #define	NR_RAID1_BIOS 256
+ 
++#ifdef CONFIG_MD_FR1
++/*
++ * When to consider switching read disks:
++ */
++#define MAX_WORK_PER_DISK (128 * 8)
++/*
++ * Weightings for calculating latency:
++ */
++#define MAX_TEST_PER_DISK 64
++#define LATENCY_OLD_WEIGHT 9
++#define LATENCY_NEW_WEIGHT 1
++#define LATENCY_SUM_WEIGHT (LATENCY_OLD_WEIGHT + LATENCY_NEW_WEIGHT)
++
++#include "bitmap.h"
++#endif /* CONFIG_MD_FR1 */
++
+ static mdk_personality_t raid1_personality;
+ 
+ static void unplug_slaves(mddev_t *mddev);
+@@ -182,6 +222,60 @@ static inline void put_buf(r1bio_t *r1_b
+ 	spin_unlock_irqrestore(&conf->resync_lock, flags);
+ }
+ 
++static int
++map (mddev_t * mddev, mdk_rdev_t ** rdevp)
++{
++        conf_t *conf = mddev_to_conf (mddev);
++        int i, disks = conf->raid_disks;
++
++        /*
++         * Later we do read balancing on the read side
++         * now we use the first available disk.
++         */
++
++        spin_lock_irq (&conf->device_lock);
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++        /*
++         * Uh, no. Choose the next disk if we can, not the first.
++         */
++        for (i = 0; i < disks; i++) {
++                if (conf->mirrors[i].rdev == *rdevp) {
++                        i++;
++                        break;
++                }
++        }
++        if (i >= disks)
++                i = 0;
++        for (; i < disks; i++) {
++                mdk_rdev_t *rdev = conf->mirrors[i].rdev;
++                if (rdev && rdev != *rdevp && rdev->in_sync) {
++                        *rdevp = rdev;
++                        atomic_inc (&rdev->nr_pending);
++                        spin_unlock_irq (&conf->device_lock);
++                        return i;
++                }
++        }
++        /*
++         * If for some reason we found nothing, dropthru and use the old
++         * routine.
++         */
++#endif          /* CONFIG_MD_RAID1_ROBUST_READ */
++        for (i = 0; i < disks; i++) {
++                mdk_rdev_t *rdev = conf->mirrors[i].rdev;
++                if (rdev && rdev->in_sync) {
++                        *rdevp = rdev;
++                        atomic_inc (&rdev->nr_pending);
++                        spin_unlock_irq (&conf->device_lock);
++                        return i;
++                }
++        }
++        spin_unlock_irq (&conf->device_lock);
++
++        printk (KERN_ERR
++                "raid1_map(): huh, no more operational devices?\n");
++        return -1;
++}
++
+ static void reschedule_retry(r1bio_t *r1_bio)
+ {
+ 	unsigned long flags;
+@@ -203,9 +297,51 @@ static void reschedule_retry(r1bio_t *r1
+ static void raid_end_bio_io(r1bio_t *r1_bio)
+ {
+ 	struct bio *bio = r1_bio->master_bio;
++#ifdef CONFIG_MD_FR1
++        /*
++         * calculate latency on reads, and fold into rolling average
++         * under lock.
++         *
++         * on writes, clear the bitmap if all disks were written
++         */
++        int uptodate = test_bit(R1BIO_Uptodate, &r1_bio->state);
++	conf_t *conf = mddev_to_conf(r1_bio->mddev);
+ 
++        /* if we should mark the bitmap clean, do so */
++        if (uptodate && bio_data_dir(bio) == WRITE
++                     && r1_bio->nonoperational <= 0) {
++                struct bitmap * bitmap = conf->bitmap;
++                if (bitmap && bitmap->active(bitmap)) {
++                        bitmap->clearbits(bitmap,
++                                bio->bi_sector >> 1, bio->bi_size >> 10);
++                }
++        }
++        /* calculate the latency of the read device */
++        if (uptodate && (bio_data_dir(bio) == READ
++                      || bio_data_dir(bio) == READA)) {
++                unsigned long latency = jiffies - r1_bio->start_jiffies;
++                /* find the mirror component being read */
++                int mirror = r1_bio->read_disk;
++
++                if (latency < 120 * HZ && latency >= 0) {
++                        /* count in 1/10ths if we have total weights 9+1 = 10 */
++                        latency *= LATENCY_SUM_WEIGHT * LATENCY_SUM_WEIGHT;
++	                spin_lock_irq(&conf->device_lock);
++                        conf->latency[mirror] *= LATENCY_OLD_WEIGHT;
++                        conf->latency[mirror] += LATENCY_NEW_WEIGHT * latency;
++                        conf->latency[mirror] /= LATENCY_SUM_WEIGHT;
++	                spin_unlock_irq(&conf->device_lock);
++                } else {
++                        printk(KERN_ERR
++                            "raid1: bad latency %lu jiffies on disk %d\n", 
++                            latency, mirror);
++                }
++        }
++        bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
++#else
+ 	bio_endio(bio, bio->bi_size,
+ 		test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
++#endif /* CONFIG_MD_FR1 */
+ 	free_r1bio(r1_bio);
+ }
+ 
+@@ -234,9 +370,19 @@ static int raid1_end_read_request(struct
+ 	/*
+ 	 * this branch is our 'one mirror IO has finished' event handler:
+ 	 */
+-	if (!uptodate)
++	if (!uptodate) {
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++	        /*
++                 * Only fault disk out of array on write error, not read.
++                 */
++	        if (0)
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
+ 		md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
+-	else
++#ifdef DO_ADD_READ_WRITE_CORRECT
++	        else    /* tell next time we're here that we're a retry */
++	                set_bit(R1BIO_ReadRetry, &r1_bio->state);
++#endif /* DO_ADD_READ_WRITE_CORRECT */
++        } else
+ 		/*
+ 		 * Set R1BIO_Uptodate in our master bio, so that
+ 		 * we will return a good error code for to the higher
+@@ -253,7 +399,19 @@ static int raid1_end_read_request(struct
+ 	/*
+ 	 * we have only one bio on the read side
+ 	 */
+-	if (uptodate)
++	if (uptodate
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++                /* Give up and error if we're last */
++                || (atomic_dec_and_test(&r1_bio->remaining))
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
++                )
++#ifdef DO_ADD_READ_WRITE_CORRECT
++	        if (uptodate && test_bit(R1BIO_ReadRetry, &r1_bio->state)) {
++	                /* Success at last - rewrite failed reads */
++                        set_bit(R1BIO_IsSync, &r1_bio->state);
++			reschedule_retry(r1_bio);
++		} else
++#endif /* DO_ADD_READ_WRITE_CORRECT */
+ 		raid_end_bio_io(r1_bio);
+ 	else {
+ 		/*
+@@ -383,12 +541,22 @@ static int read_balance(conf_t *conf, r1
+ 	 */
+ 	if (conf->next_seq_sect == this_sector)
+ 		goto rb_out;
++#ifdef CONFIG_MD_FR1
++        /*
++         * Make slower disks appear more distant.
++         */
++	current_distance = abs(this_sector - conf->mirrors[disk].head_position)
++                         * conf->latency[disk];
++
++	/* Find the disk whose head is closest (weighting by latency) */
++#else
+ 	if (this_sector == conf->mirrors[new_disk].head_position)
+ 		goto rb_out;
+ 
+ 	current_distance = abs(this_sector - conf->mirrors[disk].head_position);
+ 
+ 	/* Find the disk whose head is closest */
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	do {
+ 		if (disk <= 0)
+@@ -404,7 +572,16 @@ static int read_balance(conf_t *conf, r1
+ 			new_rdev = rdev;
+ 			break;
+ 		}
++
++#ifdef CONFIG_MD_FR1
++                /*
++                 * Make slower disks appear more distant.
++                 */
++		new_distance = abs(this_sector - conf->mirrors[disk].head_position)
++                             * conf->latency[disk] - 1;
++#else
+ 		new_distance = abs(this_sector - conf->mirrors[disk].head_position);
++#endif /* CONFIG_MD_FR1 */
+ 		if (new_distance < current_distance) {
+ 			current_distance = new_distance;
+ 			new_disk = disk;
+@@ -524,6 +701,13 @@ static int make_request(request_queue_t 
+ 	struct bio *read_bio;
+ 	int i, disks;
+ 	mdk_rdev_t *rdev;
++#ifdef CONFIG_MD_FR1
++        /* 
++         * counts of working and non-working (absent, faulty) disks.
++         */
++	int sum_bios = 0, sum_nobios = 0;
++	struct bitmap * bitmap = conf->bitmap;
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	/*
+ 	 * Register the new request and wait if the reconstruction
+@@ -555,6 +739,9 @@ static int make_request(request_queue_t 
+ 
+ 	r1_bio->mddev = mddev;
+ 	r1_bio->sector = bio->bi_sector;
++#ifdef CONFIG_MD_FR1
++	r1_bio->start_jiffies = jiffies;
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	r1_bio->state = 0;
+ 
+@@ -582,6 +769,19 @@ static int make_request(request_queue_t 
+ 		read_bio->bi_end_io = raid1_end_read_request;
+ 		read_bio->bi_rw = READ;
+ 		read_bio->bi_private = r1_bio;
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++		atomic_set(&r1_bio->remaining, 0);
++		/* count source devices under spinlock */
++		spin_lock_irq(&conf->device_lock);
++	        disks = conf->raid_disks;
++		for (i = 0;  i < disks; i++) {
++			if (conf->mirrors[i].rdev &&
++			!conf->mirrors[i].rdev->faulty) {
++				atomic_inc(&r1_bio->remaining);
++			} 
++		}
++		spin_unlock_irq(&conf->device_lock);
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
+ 
+ 		generic_make_request(read_bio);
+ 		return 0;
+@@ -605,13 +805,45 @@ static int make_request(request_queue_t 
+ 				r1_bio->bios[i] = NULL;
+ 			} else
+ 				r1_bio->bios[i] = bio;
+-		} else
++		} else {
++#ifdef CONFIG_MD_FR1
++                        sum_bios++;
++#endif /* CONFIG_MD_FR1 */
+ 			r1_bio->bios[i] = NULL;
+-	}
++#ifdef CONFIG_MD_FR1
++                        sum_nobios++;
++#endif /* CONFIG_MD_FR1 */
++                }
++        /* zero the bad disk count on the r1bio by default */
++	}
++#ifdef CONFIG_MD_FR1
++        r1_bio->nonoperational = 0;
++#endif /* CONFIG_MD_FR1 */
+ 	rcu_read_unlock();
+ 
++#ifdef CONFIG_MD_FR1
++        /* mark the bitmap before write, just in case */
++        if (bitmap->active(bitmap)) {
++                 bitmap->setbits(bitmap, r1_bio->sector >> 1,
++                          r1_bio->sectors >> 1);
++        }
++#endif /* CONFIG_MD_FR1 */
++
+ 	atomic_set(&r1_bio->remaining, 1);
+ 	md_write_start(mddev);
++#ifdef CONFIG_MD_FR1
++        /* count inactive disks, note bitmap dirty if didn't know before */
++	if (sum_nobios > 0) {
++                 /* mark bitmap as dirty if it wasn't so marked */
++	        spin_lock_irq(&conf->device_lock);
++                if (!conf->bitmap_dirty && bitmap->active(bitmap)) {
++                        conf->bitmap_dirty = 1;
++                        mddev->bitmap_events = mddev->events;
++                }
++	        spin_unlock_irq(&conf->device_lock);
++        }
++        r1_bio->nonoperational = sum_nobios;
++#endif /* CONFIG_MD_FR1 */
+ 	for (i = 0; i < disks; i++) {
+ 		struct bio *mbio;
+ 		if (!r1_bio->bios[i])
+@@ -652,6 +884,89 @@ static void status(struct seq_file *seq,
+ 	seq_printf(seq, "]");
+ }
+ 
++#ifdef CONFIG_MD_FR1
++/*
++ * Local bitmap  support functions.
++ */
++static int
++create_bitmap(conf_t *conf) {
++
++        struct bitmap * bitmap;
++        unsigned long blocks;
++        mddev_t *mddev = conf->mddev;
++
++        /* need size to have been set already */
++        blocks = mddev->size;
++
++        bitmap = kmalloc (sizeof (*bitmap), GFP_KERNEL);
++        if (!bitmap) {
++                printk(KERN_WARNING "raid1: out of memory for bitmap head\n");
++                return -ENOMEM;
++        }
++
++        if (bitmap_init (bitmap, blocks) < 0) {
++                printk(KERN_WARNING "raid1: failed to init bitmap\n");
++                kfree(bitmap);
++                return -ENOMEM;
++        }
++
++        /* take the spinlock for the ops on the configuration */
++        spin_lock_irq(&conf->device_lock);
++        conf->bitmap = bitmap;
++        conf->bitmap_dirty = 0;
++        spin_unlock_irq(&conf->device_lock);
++        return 0;
++}
++
++static void
++remove_bitmap (conf_t *conf) {
++
++        struct bitmap * bitmap;
++
++        spin_lock_irq(&conf->device_lock);
++        bitmap = conf->bitmap;
++        if (!bitmap) {
++                spin_unlock_irq(&conf->device_lock);
++                return;
++        }
++        conf->bitmap = NULL;
++        spin_unlock_irq(&conf->device_lock);
++
++        bitmap_destr(bitmap);
++        kfree(bitmap);
++}
++
++static int
++start_bitmap (conf_t *conf) {
++
++        mddev_t *mddev;
++        struct bitmap * bitmap;
++
++        spin_lock_irq(&conf->device_lock);
++        mddev  = conf->mddev;
++        bitmap = conf->bitmap;
++        spin_unlock_irq(&conf->device_lock);
++        if (!bitmap) {
++                return -EINVAL;
++        }
++
++        if (bitmap->active(bitmap)) {
++                printk(KERN_WARNING "raid1: bitmap %x already active!\n",
++                    (unsigned) bitmap);
++                return 0;
++        }
++        if (bitmap->start(bitmap, mddev->events) < 0) {
++                printk(KERN_WARNING "raid1: bitmap %x failed to start!\n",
++                    (unsigned) bitmap);
++                return -EINVAL;
++        }
++
++        printk(KERN_INFO "raid1: made bitmap %x at events %x:%x\n",
++                (unsigned) bitmap, (unsigned)(u32)(mddev->events >> 32),
++                (unsigned)(u32)(mddev->events));
++        return 0;
++}
++#endif /* CONFIG_MD_FR1 */
+ 
+ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
+ {
+@@ -685,6 +1000,9 @@ static void error(mddev_t *mddev, mdk_rd
+ 	printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
+ 		"	Operation continuing on %d devices\n",
+ 		bdevname(rdev->bdev,b), conf->working_disks);
++#ifdef CONFIG_MD_FR1
++        start_bitmap(conf);
++#endif /* CONFIG_MD_FR1 */
+ }
+ 
+ static void print_conf(conf_t *conf)
+@@ -703,6 +1021,14 @@ static void print_conf(conf_t *conf)
+ 	for (i = 0; i < conf->raid_disks; i++) {
+ 		char b[BDEVNAME_SIZE];
+ 		tmp = conf->mirrors + i;
++#ifdef CONFIG_MD_FR1
++                /*
++                 * Remove repeats from debug printout.
++                 */
++                if (i > 0 && memcmp(tmp, &conf->mirrors[i-1], sizeof(*tmp)) == 0) {
++                        continue;
++                }
++#endif /* CONFIG_MD_FR1 */
+ 		if (tmp->rdev)
+ 			printk(" disk %d, wo:%d, o:%d, dev:%s\n",
+ 				i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+@@ -722,6 +1048,14 @@ static void close_sync(conf_t *conf)
+ 
+ 	mempool_destroy(conf->r1buf_pool);
+ 	conf->r1buf_pool = NULL;
++
++#ifdef CONFIG_MD_FR1
++        if (conf->bitmap) {
++                struct bitmap *bitmap = conf->bitmap;
++                bitmap->stop(bitmap);
++                bitmap->print_stats(bitmap);
++        }
++#endif /* CONFIG_MD_FR1 */
+ }
+ 
+ static int raid1_spare_active(mddev_t *mddev)
+@@ -757,9 +1091,42 @@ static int raid1_add_disk(mddev_t *mddev
+ 	int mirror;
+ 	mirror_info_t *p;
+ 
+-	for (mirror=0; mirror < mddev->raid_disks; mirror++)
++	for (mirror=0; mirror < mddev->raid_disks; mirror++) {
++#ifdef CONFIG_MD_FR1
++            /*
++             * allow a disk which has only been set faulty but not
++             * removed yet to be reinserted, thus triggering a hot
++             * repair.
++             */
++		p = &conf->mirrors[mirror]; 
++                if (unlikely(!p->rdev))
++                        goto insert_or_replace;
++	        printk(KERN_DEBUG "raid1: testing p->rdev %p\n", p->rdev);
++                if (unlikely(p->rdev == rdev))
++                        goto insert_or_replace;
++	        printk(KERN_DEBUG "raid1: testing p->rdev->bdev %p\n",
++                        p->rdev->bdev);
++                if (!p->rdev->bdev)
++                        goto insert_or_replace; // weird!
++	        printk(KERN_DEBUG "raid1: testing p->rdev->bdev->bd_dev %x\n",
++                        p->rdev->bdev->bd_dev);
++                if (p->rdev->bdev->bd_dev == rdev->bdev->bd_dev)
++                        goto insert_or_replace;
++                continue;
++
++insert_or_replace:
++               if (1) {
++                        if (p->rdev && p->rdev != rdev) {
++                        /* kill the rdev left by export_rdev() */
++	                        printk(KERN_INFO
++                                "raid1: late free of exported rdev %p\n",
++                                        p->rdev);
++                                kfree(p->rdev);
++                        }
++		        p->rdev = rdev;
++#else
+ 		if ( !(p=conf->mirrors+mirror)->rdev) {
+-
++#endif /* CONFIG_MD_FR1 */
+ 			blk_queue_stack_limits(mddev->queue,
+ 					       rdev->bdev->bd_disk->queue);
+ 			/* as we don't honour merge_bvec_fn, we must never risk
+@@ -776,7 +1143,7 @@ static int raid1_add_disk(mddev_t *mddev
+ 			p->rdev = rdev;
+ 			break;
+ 		}
+-
++        }
+ 	print_conf(conf);
+ 	return found;
+ }
+@@ -860,6 +1227,14 @@ static int end_sync_write(struct bio *bi
+ 	update_head_pos(mirror, r1_bio);
+ 
+ 	if (atomic_dec_and_test(&r1_bio->remaining)) {
++#ifdef CONFIG_MD_FR1
++                /* clean the bitmap after resync */
++                struct bitmap * bitmap = conf->bitmap;
++                if (bitmap && bitmap->active(bitmap)) {
++                        bitmap->clearbits(bitmap, r1_bio->sector >> 1,
++                                r1_bio->sectors >> 1);
++                }
++#endif /* CONFIG_MD_FR1 */
+ 		md_done_sync(mddev, r1_bio->sectors, uptodate);
+ 		put_buf(r1_bio);
+ 	}
+@@ -950,7 +1325,10 @@ static void raid1d(mddev_t *mddev)
+ 		} else {
+ 			int disk;
+ 			bio = r1_bio->bios[r1_bio->read_disk];
+-			if ((disk=read_balance(conf, r1_bio)) == -1) {
++#ifdef CONFIG_MD_RAID1_ROBUST_READ
++                        rdev = conf->mirrors[r1_bio->read_disk].rdev;
++#endif /* CONFIG_MD_RAID1_ROBUST_READ */
++			if ((disk=map(mddev, &rdev)) == -1) {
+ 				printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
+ 				       " read error for block %llu\n",
+ 				       bdevname(bio->bi_bdev,b),
+@@ -1020,6 +1398,22 @@ static int sync_request(mddev_t *mddev, 
+ 	int i;
+ 	int write_targets = 0;
+ 
++#ifdef CONFIG_MD_FR1
++        /*
++         * Will need to count mirror components currently with a bitmap
++         * which have been marked faulty and nonoperational at some
++         * point beforehand, and have been accumulating marks on the
++         * bitmap to indicate dirty blocks that need syncing.
++         */
++        struct bitmap * bitmap = conf->bitmap;
++        int count, block_not_dirty;
++        int targets[MD_SB_DISKS];
++        /*
++         * discount the skipped sectors back to the md.c code
++         */
++        extern atomic_t md_throttle[];
++#endif /* CONFIG_MD_FR1 */
++
+ 	if (!conf->r1buf_pool)
+ 		if (init_resync(conf))
+ 			return -ENOMEM;
+@@ -1030,6 +1424,25 @@ static int sync_request(mddev_t *mddev, 
+ 		return 0;
+ 	}
+ 
++#ifdef CONFIG_MD_FR1
++        /* also remove bitmap if not indicated */
++        if (!sector_nr) {
++                if (! test_and_clear_bit(MD_BITMAP_REPAIR, &mddev->recovery)) {
++                        /* has to be outside spinlock as it takes it */
++                        printk(KERN_WARNING
++                            "%s: no repair bit on sb so removed bitmap %x\n",
++                            mdname(mddev), (unsigned)bitmap);
++                        if (bitmap)
++                                bitmap->stop (bitmap);
++                } else {
++                        printk(KERN_WARNING
++                            "%s: repair bit set on sb so retained bitmap %x\n",
++                            mdname(mddev), (unsigned)bitmap);
++                }
++                /* reset the bitmap indicator always */
++        }
++#endif /* CONFIG_MD_FR1 */
++
+ 	/*
+ 	 * If there is non-resync activity waiting for us then
+ 	 * put in a delay to throttle resync.
+@@ -1045,6 +1458,34 @@ static int sync_request(mddev_t *mddev, 
+ 	 */
+ 	disk = conf->last_used;
+ 	/* make sure disk is operational */
++#ifdef CONFIG_MD_FR1
++        /* setup extra report counters for skipped/synced blocks */
++        if (!sector_nr) {
++                conf->sync_mode = -1;
++                conf->last_clean_sector = -1;
++                conf->last_dirty_sector = -1;
++        }
++
++	nr_sectors = RESYNC_SECTORS;
++	if (max_sector - sector_nr < nr_sectors)
++		nr_sectors = max_sector - sector_nr;
++
++        /* go looking for the faulted (nonoperational) mirrors, under lock */
++        count = 0;
++	while(1) {
++		if (disk <= 0)
++			disk = conf->raid_disks;
++                disk--;
++		if (conf->mirrors[disk].rdev
++                && !conf->mirrors[disk].rdev->faulty
++                && (!conf->mirrors[disk].rdev->in_sync ||
++			    sector_nr + nr_sectors > mddev->recovery_cp)) {
++                        targets[count++] = disk;
++                }
++		if (disk == conf->last_used)
++			break;
++        }
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	while (conf->mirrors[disk].rdev == NULL ||
+ 	       !conf->mirrors[disk].rdev->in_sync) {
+@@ -1053,12 +1494,66 @@ static int sync_request(mddev_t *mddev, 
+ 		disk--;
+ 		if (disk == conf->last_used)
+ 			break;
++// #ifdef CONFIG_MD_FR1
++//                if (0)
++// #endif /* CONFIG_MD_FR1 */
+ 	}
+ 	conf->last_used = disk;
+ 	atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+ 
+ 
+ 	mirror = conf->mirrors + disk;
++#ifdef CONFIG_MD_FR1
++        /*
++         * check if bitmap says reync block can be skipped, and do so
++         */
++        block_not_dirty = bitmap->active(bitmap)
++            && !bitmap->testbits(bitmap, sector_nr >> 1, nr_sectors >> 1);
++
++        if (count > 0 && block_not_dirty) {
++                /* skip */
++
++	        md_sync_acct(mirror->rdev->bdev, nr_sectors);
++                // sync_request_done(sector_nr, conf);
++		md_done_sync(mddev, nr_sectors, 1);
++
++                for (i = 0; i < count; i++) {
++                        int mirror = targets[i];
++	                atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
++                }
++
++                /* do these conf accesses under lock, though only accounting */
++                spin_lock_irq(&conf->resync_lock);
++                if (conf->sync_mode != 0) {
++                        if (conf->sync_mode == 1) {
++                                printk(KERN_INFO "raid1: synced dirty sectors %lu-%lu\n",
++                                conf->last_clean_sector+1,
++                                conf->last_dirty_sector);
++                        }
++                        conf->sync_mode = 0;
++                }
++                conf->last_clean_sector = sector_nr + nr_sectors - 1;
++                if (sector_nr + nr_sectors >= mddev->size << 1) {
++                        printk(KERN_INFO "raid1: skipped clean sectors %lu-%lu\n",
++                        conf->last_dirty_sector+1,
++                        conf->last_clean_sector);
++                }
++                /* update md driver throttle discount */
++                atomic_add(nr_sectors, &md_throttle[mddev->md_minor]);
++
++	        /*
++	        * Wake up any possible resync thread that waits for the device
++	        * to go idle.
++	        */
++	        --conf->barrier;
++                wake_up(&conf->wait_idle);
++	        wake_up(&conf->wait_resume);
++                spin_unlock_irq(&conf->resync_lock);
++
++	        md_wakeup_thread(mddev->thread);
++                return nr_sectors;
++        }
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO);
+ 
+@@ -1152,6 +1647,28 @@ static int sync_request(mddev_t *mddev, 
+ 
+ 	generic_make_request(bio);
+ 
++#ifdef CONFIG_MD_FR1
++        /* printout info from time to time */
++        spin_lock_irq(&conf->resync_lock);
++        if (conf->sync_mode != 1) {
++                if (conf->sync_mode == 0) {
++                        printk(KERN_INFO
++                                "raid1: skipped clean sectors %lu-%lu\n",
++                        conf->last_dirty_sector+1,
++                        conf->last_clean_sector);
++                }
++                conf->sync_mode = 1;
++        }
++        conf->last_dirty_sector = sector_nr + nr_sectors - 1;
++
++        if (sector_nr + nr_sectors >= mddev->size << 1) {
++                printk(KERN_INFO "raid1: synced dirty sectors %lu-%lu\n",
++                conf->last_clean_sector+1,
++                conf->last_dirty_sector);
++        }
++        spin_unlock_irq(&conf->resync_lock);
++#endif /* CONFIG_MD_FR1 */
++
+ 	return nr_sectors;
+ }
+ 
+@@ -1259,6 +1776,17 @@ static int run(mddev_t *mddev)
+ 	conf->last_used = j;
+ 
+ 
++#ifdef CONFIG_MD_FR1
++        /* make the bitmap now - hope mddev->size exists already */
++        if (create_bitmap(conf) < 0) {
++                printk(KERN_ERR "raid1: out of memory for bitmap on %s\n",
++                        mdname(mddev));
++                goto out_free_conf;
++        }
++
++        /* PTB set it active too */
++        start_bitmap (conf);
++#endif /* CONFIG_MD_FR1 */
+ 
+ 	{
+ 		mddev->thread = md_register_thread(raid1d, mddev, "%s_raid1");
+@@ -1295,6 +1823,9 @@ out_free_conf:
+ 			kfree(conf->mirrors);
+ 		if (conf->poolinfo)
+ 			kfree(conf->poolinfo);
++#ifdef CONFIG_MD_FR1
++        	remove_bitmap (conf);
++#endif /* CONFIG_MD_FR1 */
+ 		kfree(conf);
+ 		mddev->private = NULL;
+ 	}
+@@ -1315,6 +1846,9 @@ static int stop(mddev_t *mddev)
+ 		kfree(conf->mirrors);
+ 	if (conf->poolinfo)
+ 		kfree(conf->poolinfo);
++#ifdef CONFIG_MD_FR1
++        remove_bitmap (conf);
++#endif /* CONFIG_MD_FR1 */
+ 	kfree(conf);
+ 	mddev->private = NULL;
+ 	return 0;
+--- linux-2.6/drivers/md/md.c.orig	2005-07-13 15:54:26.194462796 +0200
++++ linux-2.6/drivers/md/md.c	2005-07-18 00:49:02.201350780 +0200
+@@ -27,6 +27,27 @@
+    You should have received a copy of the GNU General Public License
+    (for example /usr/src/linux/COPYING); if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++   Changes 31/1/2003 by Peter T.  Breuer <ptb@it.uc3m.es> to support
++   hotadd directly after setfaulty without intervening hotremove
++   ("hotrepair") when there is no persistent superblock, and to flag a
++   potential hotrepair when an old disk is re-added and the uuid matches
++   ours.  The flag is used by the raid1 driver, at the moment, in order
++   to trigger an intelligent resync.
++  
++   Yet more changes by PTB 12/3/2003 to notify devices via ioctls when
++   they have been incorporated or removed from a raid array.
++  
++   Yet more changes by PTB 26/3/2004 to make the speed calculations
++   appropriate to fr1, and throttle by real i/o, not resync total.
++
++   Changes by PTB 15/3/2005 to make sure the sb of the rdev is read
++   just before we check its uuid.
++
++   Changes by PTB 15/3/2005 to keep rdev from being kfreed in
++   export_rdev c and instead free it in raid1 during 
++   pers->add_disk. Otherwise we would trace along a freed struct there
++   to see if it represents a dev we are interested in repairing.
+ */
+ 
+ #include <linux/module.h>
+@@ -55,6 +76,7 @@
+ #define DEBUG 0
+ #define dprintk(x...) ((void)(DEBUG && printk(x)))
+ 
++#define MD_BITMAP_SUPPORT 1
+ 
+ #ifndef MODULE
+ static void autostart_arrays (int part);
+@@ -122,6 +144,14 @@ static ctl_table raid_root_table[] = {
+ 	{ .ctl_name = 0 }
+ };
+ 
++#ifdef MD_BITMAP_SUPPORT
++/* PTB md_throttle permits speed calculation adjustments from personality */
++#ifdef MODULE
++static
++#endif /* MODULE */
++atomic_t md_throttle[MAX_MD_DEVS];
++#endif /* MD_BITMAP_SUPPORT */
++
+ static struct block_device_operations md_fops;
+ 
+ /*
+@@ -173,7 +203,14 @@ static void mddev_put(mddev_t *mddev)
+ 		return;
+ 	if (!mddev->raid_disks && list_empty(&mddev->disks)) {
+ 		list_del(&mddev->all_mddevs);
++#ifdef MD_BITMAP_SUPPORT
++	        spin_unlock(&all_mddevs_lock);
++                /* blk_put_queue calls kblockd_flush, which can sleep */
++#endif /* MD_BITMAP_SUPPORT */
+ 		blk_put_queue(mddev->queue);
++#ifdef MD_BITMAP_SUPPORT
++	        spin_lock(&all_mddevs_lock);
++#endif /* MD_BITMAP_SUPPORT */
+ 		kfree(mddev);
+ 	}
+ 	spin_unlock(&all_mddevs_lock);
+@@ -355,6 +392,10 @@ static int sync_page_io(struct block_dev
+ static int read_disk_sb(mdk_rdev_t * rdev)
+ {
+ 	char b[BDEVNAME_SIZE];
++#ifdef MD_BITMAP_SUPPORT
++	mdp_super_t *sb;
++#endif /* MD_BITMAP_SUPPORT */
++
+ 	if (!rdev->sb_page) {
+ 		MD_BUG();
+ 		return -EINVAL;
+@@ -366,6 +407,11 @@ static int read_disk_sb(mdk_rdev_t * rde
+ 	if (!sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ))
+ 		goto fail;
+ 	rdev->sb_loaded = 1;
++#ifdef MD_BITMAP_SUPPORT
++	sb = (mdp_super_t *)page_address(rdev->sb_page);
++	printk(KERN_INFO "%s (read) [events: %08lx]\n",
++		bdevname(rdev->bdev,b), (unsigned long)sb->events_lo);
++#endif /* MD_BITMAP_SUPPORT */
+ 	return 0;
+ 
+ fail:
+@@ -582,6 +628,9 @@ static int super_90_validate(mddev_t *md
+ 		mddev->raid_disks = sb->raid_disks;
+ 		mddev->size = sb->size;
+ 		mddev->events = md_event(sb);
++#ifdef MD_BITMAP_SUPPORT
++                mddev->bitmap_events = MD_SB_BITMAP_EVENTS(sb);
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 		if (sb->state & (1<<MD_SB_CLEAN))
+ 			mddev->recovery_cp = MaxSector;
+@@ -669,6 +718,10 @@ static void super_90_sync(mddev_t *mddev
+ 	sb->state = 0;
+ 	sb->events_hi = (mddev->events>>32);
+ 	sb->events_lo = (u32)mddev->events;
++#ifdef MD_BITMAP_SUPPORT
++        MD_SB_BITMAP_EVENTS_HI(sb) = (u32)(mddev->bitmap_events >> 32);
++        MD_SB_BITMAP_EVENTS_LO(sb) = (u32)mddev->bitmap_events;
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 	if (mddev->in_sync)
+ 	{
+@@ -872,6 +925,11 @@ static int super_1_validate(mddev_t *mdd
+ 		mddev->raid_disks = le32_to_cpu(sb->raid_disks);
+ 		mddev->size = le64_to_cpu(sb->size)/2;
+ 		mddev->events = le64_to_cpu(sb->events);
++#ifdef MD_BITMAP_SUPPORT
++		mddev->bitmap_events =
++		    (((__u64)le32_to_cpu(MD_SB_BITMAP_EVENTS_HI_1(sb)))<<32)
++                    | (__u64)le32_to_cpu(MD_SB_BITMAP_EVENTS_LO_1(sb));
++#endif /* MD_BITMAP_SUPPORT */
+ 		
+ 		mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
+ 		memcpy(mddev->uuid, sb->set_uuid, 16);
+@@ -928,6 +986,10 @@ static void super_1_sync(mddev_t *mddev,
+ 
+ 	sb->utime = cpu_to_le64((__u64)mddev->utime);
+ 	sb->events = cpu_to_le64(mddev->events);
++#ifdef MD_BITMAP_SUPPORT
++        MD_SB_BITMAP_EVENTS_HI_1(sb) = (u32)cpu_to_le32(mddev->bitmap_events >> 32);
++        MD_SB_BITMAP_EVENTS_LO_1(sb) = (u32)cpu_to_le32(mddev->bitmap_events);
++#endif /* MD_BITMAP_SUPPORT */
+ 	if (mddev->in_sync)
+ 		sb->resync_offset = cpu_to_le64(mddev->recovery_cp);
+ 	else
+@@ -998,6 +1060,91 @@ static int match_mddev_units(mddev_t *md
+ 	return 0;
+ }
+ 
++#ifdef MD_BITMAP_SUPPORT
++static mdk_rdev_t *
++find_rdev_all (dev_t dev)
++{
++	struct list_head *tmp;
++        mddev_t *mddev;
++        static mdk_rdev_t * find_rdev(mddev_t *mddev, dev_t dev);
++
++        ITERATE_MDDEV(mddev, tmp) {
++                mdk_rdev_t *rdev = find_rdev(mddev, dev);
++                if (rdev)
++                        return rdev;
++        }
++        return NULL;
++}
++
++/*
++ * This is registered to other devices as a callback
++ */
++static int
++md_hot_cmd_disk(dev_t dev, int cmd) {
++
++        static int hot_add_disk(mddev_t * mddev, dev_t dev);
++        static int set_disk_faulty(mddev_t *mddev, dev_t dev);
++
++        mdk_rdev_t *rdev;
++        mddev_t *mddev;
++        int res;
++
++        rdev = find_rdev_all(dev);
++        if (!rdev)
++                return -EINVAL;
++        mddev = rdev->mddev;
++        if (!mddev)
++                return -EINVAL;
++
++        switch(cmd) {
++            case HOT_ADD_DISK:
++                res = hot_add_disk(mddev, dev);
++                return res;
++            case SET_DISK_FAULTY:
++               res = set_disk_faulty(mddev, dev);
++                return res;
++        }
++        return -EINVAL;
++}
++
++static void
++notify_device (mddev_t * mddev, dev_t dev)
++{
++#ifndef BLKMDNTFY
++#define BLKMDNTFY _IOW(0x12,133,int)
++#endif
++        struct block_device *bdev;
++
++        bdev = bdget (dev);
++        if (!bdev)
++                return;
++        printk (KERN_INFO "%s: notifying dev %x it is now in array\n",
++                mdname(mddev), dev);
++        ioctl_by_bdev (bdev, BLKMDNTFY, MKDEV (MD_MAJOR, mddev->md_minor));
++#ifndef BLKMDRGTR
++#define BLKMDRGTR _IOW(0x12,135,unsigned long)
++#endif
++        ioctl_by_bdev (bdev, BLKMDRGTR, (unsigned long)md_hot_cmd_disk);
++	bdput(bdev);
++}
++static void
++unnotify_device (mddev_t * mddev, dev_t dev)
++{
++#ifndef BLKMDUNTFY
++#define BLKMDUNTFY _IOW(0x12,134,int)
++#endif
++        struct block_device *bdev;
++
++        bdev = bdget (dev);
++        if (!bdev)
++                return;
++        printk (KERN_INFO "%s: notifying dev %x it is no longer in array\n",
++                mdname(mddev), dev);
++        ioctl_by_bdev(bdev, BLKMDUNTFY, MKDEV(MD_MAJOR, mddev->md_minor));
++	bdput(bdev);
++}
++#endif /* MD_BITMAP_SUPPORT */
++
+ static LIST_HEAD(pending_raid_disks);
+ 
+ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
+@@ -1036,6 +1183,9 @@ static int bind_rdev_to_array(mdk_rdev_t
+ 	list_add(&rdev->same_set, &mddev->disks);
+ 	rdev->mddev = mddev;
+ 	printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));
++#ifdef MD_BITMAP_SUPPORT
++        notify_device(mddev, rdev->bdev->bd_inode->i_rdev);
++#endif /* MD_BITMAP_SUPPORT */
+ 	return 0;
+ }
+ 
+@@ -1046,6 +1196,9 @@ static void unbind_rdev_from_array(mdk_r
+ 		MD_BUG();
+ 		return;
+ 	}
++#ifdef MD_BITMAP_SUPPORT
++        unnotify_device(rdev->mddev, rdev->bdev->bd_inode->i_rdev);
++#endif /* MD_BITMAP_SUPPORT */
+ 	list_del_init(&rdev->same_set);
+ 	printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
+ 	rdev->mddev = NULL;
+@@ -1075,6 +1228,10 @@ static int lock_rdev(mdk_rdev_t *rdev, d
+ 		blkdev_put(bdev);
+ 		return err;
+ 	}
++#ifdef MD_BITMAP_SUPPORT
++        printk(KERN_DEBUG "md %d: %s restores bdev %x rdev(%p)->bdev(%p)\n",
++                __LINE__, __FUNCTION__, dev, rdev, bdev);
++#endif /* MD_BITMAP_SUPPORT */
+ 	rdev->bdev = bdev;
+ 	return err;
+ }
+@@ -1082,6 +1239,9 @@ static int lock_rdev(mdk_rdev_t *rdev, d
+ static void unlock_rdev(mdk_rdev_t *rdev)
+ {
+ 	struct block_device *bdev = rdev->bdev;
++#ifdef MD_BITMAP_SUPPORT
++        printk(KERN_DEBUG "md %d: %s nulls bdev\n", __LINE__, __FUNCTION__);
++#endif /* MD_BITMAP_SUPPORT */
+ 	rdev->bdev = NULL;
+ 	if (!bdev)
+ 		MD_BUG();
+@@ -1104,6 +1264,16 @@ static void export_rdev(mdk_rdev_t * rde
+ 	md_autodetect_dev(rdev->bdev->bd_dev);
+ #endif
+ 	unlock_rdev(rdev);
++#ifdef MD_BITMAP_SUPPORT
++#ifdef CONFIG_MD_FR1
++            /* FIXME only kfree if pers hot_add does not kfree instead.
++             * Use some flag in future! 
++             */
++	printk(KERN_WARNING
++                "md: WARNING: delaying free of exported rdev %p\n", rdev);
++        if (0)
++#endif /* CONFIG_MD_FR1 */
++#endif /* MD_BITMAP_SUPPORT */
+ 	kfree(rdev);
+ }
+ 
+@@ -2169,6 +2339,10 @@ static int hot_add_disk(mddev_t * mddev,
+ 	int err;
+ 	unsigned int size;
+ 	mdk_rdev_t *rdev;
++#ifdef MD_BITMAP_SUPPORT
++        int hotrepair = 0;
++	mdp_super_t *sb;
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 	if (!mddev->pers)
+ 		return -ENODEV;
+@@ -2186,7 +2360,42 @@ static int hot_add_disk(mddev_t * mddev,
+ 		return -EINVAL;
+ 	}
+ 
++#ifdef MD_BITMAP_SUPPORT
++        /*
++         * This is a do at most once loop because the remove in the loop will
++         * cause the test to fail the next time round. And if that
++         * doesn't break us out, then the hotrepair count will.
++         */
++        rdev = find_rdev(mddev, dev);
++        if (rdev) {
++                int mirror;
++
++        /* found it in array, so it's not yet been removed */
++               if (rdev->bdev->bd_inode->i_rdev != dev
++               || !rdev->faulty) {
++                       printk(KERN_WARNING "%s: cannot add existing component %x\n",
++                                mdname(mddev), dev);
++                       return -EBUSY;
++                }
++        /*
++         * Allow "hotrepair" of faulty device. Have rdev->faulty;
++         */
++                printk(KERN_WARNING "%s: repair of faulty disk %x!\n",
++                       mdname(mddev), dev);
++
++                mirror = rdev->raid_disk;
++                rdev->raid_disk = -1;
++                err = hot_remove_disk(mddev, dev);
++                if (err < 0) {
++                       printk(KERN_WARNING "%s: remove disk %x errored\n",
++                                mdname(mddev), dev);
++                       return err;       
++                }
++        }
++	rdev = md_import_device (dev, 0, 0); // PTB -1 == don't check sb
++#else
+ 	rdev = md_import_device (dev, -1, 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 	if (IS_ERR(rdev)) {
+ 		printk(KERN_WARNING 
+ 			"md: error, md_import_device() returned %ld\n",
+@@ -2219,6 +2428,71 @@ static int hot_add_disk(mddev_t * mddev,
+ 		err = -EINVAL;
+ 		goto abort_export;
+ 	}
++
++#ifdef MD_BITMAP_SUPPORT
++        printk(KERN_INFO "md: old uuid %x %x %x %x\n",
++                *(__u32 *)(mddev->uuid+0),
++                *(__u32 *)(mddev->uuid+4),
++                *(__u32 *)(mddev->uuid+8),
++                *(__u32 *)(mddev->uuid+12));
++        /* get the component's superblock */
++        if (!rdev->sb_loaded)
++                read_disk_sb(rdev);
++	sb = (mdp_super_t *)page_address(rdev->sb_page);
++        if (sb) {
++                printk(KERN_INFO "md: new uuid %x %x %x %x\n",
++                        sb->set_uuid0,
++                        sb->set_uuid1,
++                        sb->set_uuid2,
++                        sb->set_uuid3);
++        } else {
++                printk(KERN_INFO "md: new component device has no sb\n");
++        }
++        /* let's check the new disk sb at this poimt */
++        if (mddev->persistent && sb 
++                && sb->set_uuid0 == *(__u32 *)(mddev->uuid+0)
++                && sb->set_uuid1 == *(__u32 *)(mddev->uuid+4)
++                && sb->set_uuid2 == *(__u32 *)(mddev->uuid+8)
++                && sb->set_uuid3 == *(__u32 *)(mddev->uuid+12)) {
++                long long disk_events, bitmap_events;
++                disk_events   = sb->events_hi;
++                disk_events <<= 32;
++                disk_events  |= sb->events_lo;
++                bitmap_events = mddev->bitmap_events;
++
++                /* This is where we should examine conf->events_chkpt_*
++                 */
++                if (disk_events <  bitmap_events
++                &&  disk_events >= bitmap_events - 2
++                        ) {
++                        printk(KERN_WARNING
++                        "%s: warning - new disk %x nearly too old for repair (disk %Ld < bitmap %Ld)\n",
++                        mdname(mddev), dev, disk_events, bitmap_events);
++                }
++                if (disk_events < bitmap_events - 2) {
++                        /* new disk is too old! */
++                        printk(KERN_INFO
++                        "%s: new disk %x too old for repair (disk %Ld < bitmap %Ld)\n",
++                                mdname(mddev), dev, disk_events, bitmap_events);
++                        hotrepair = 0;
++                } else {
++                        printk(KERN_INFO
++                        "%s: repairing old mirror component %x (disk %Ld >= bitmap %Ld)\n",
++                                mdname(mddev), dev, disk_events, bitmap_events);
++                        hotrepair = 1;
++                }
++        } else if (!mddev->persistent && hotrepair) {
++                printk(KERN_INFO
++                        "md: forced repair of mirror component %x\n",
++                        dev);
++                hotrepair = 1;
++        } else {
++                /* failed match */
++                printk(KERN_INFO "md: adding new mirror component %x\n", dev);
++                hotrepair = 0;
++        }
++#endif /* MD_BITMAP_SUPPORT */
++
+ 	rdev->in_sync = 0;
+ 	rdev->desc_nr = -1;
+ 	bind_rdev_to_array(rdev, mddev);
+@@ -2235,6 +2509,21 @@ static int hot_add_disk(mddev_t * mddev,
+ 		goto abort_unbind_export;
+ 	}
+ 
++#ifdef MD_BITMAP_SUPPORT
++        /*
++         * Maybe say something nice - 1 means we want to respect
++         * the bitmap in raid1 resync if there is one, 0
++         * means we need to kill any bitmap that we have been
++         * saving but we'll do it in the raid1 resync instead of here
++         */
++        printk(KERN_DEBUG "%s: set repair bit to %d on superblock %p\n",
++                mdname(mddev), hotrepair, mddev);
++        if (hotrepair)
++                set_bit  (MD_BITMAP_REPAIR, &mddev->recovery);
++        else
++                clear_bit(MD_BITMAP_REPAIR, &mddev->recovery);
++#endif /* MD_BITMAP_SUPPORT */
++
+ 	rdev->raid_disk = -1;
+ 
+ 	md_update_sb(mddev);
+@@ -3241,6 +3530,10 @@ static void md_do_sync(mddev_t *mddev)
+ 	mddev_t *mddev2;
+ 	unsigned int currspeed = 0,
+ 		 window;
++#ifdef MD_BITMAP_SUPPORT
++        /* PTB add realspeed for i/o limiting calculation */
++        unsigned realspeed;
++#endif /* MD_BITMAP_SUPPORT */
+ 	sector_t max_sectors,j;
+ 	unsigned long mark[SYNC_MARKS];
+ 	sector_t mark_cnt[SYNC_MARKS];
+@@ -3319,7 +3612,7 @@ static void md_do_sync(mddev_t *mddev)
+ 		/* recovery follows the physical size of devices */
+ 		max_sectors = mddev->size << 1;
+ 
+-	printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
++	printk(KERN_INFO "md: syncing RAID array %s)\n", mdname(mddev));
+ 	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
+ 		" %d KB/sec/disc.\n", sysctl_speed_limit_min);
+ 	printk(KERN_INFO "md: using maximum available idle IO bandwith "
+@@ -3349,6 +3642,9 @@ static void md_do_sync(mddev_t *mddev)
+ 	atomic_set(&mddev->recovery_active, 0);
+ 	init_waitqueue_head(&mddev->recovery_wait);
+ 	last_check = 0;
++#ifdef MD_BITMAP_SUPPORT
++        atomic_set(&md_throttle[mddev->md_minor], 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 	if (j>2) {
+ 		printk(KERN_INFO 
+@@ -3385,6 +3681,10 @@ static void md_do_sync(mddev_t *mddev)
+ 
+ 			mddev->resync_mark = mark[next];
+ 			mddev->resync_mark_cnt = mark_cnt[next];
++#ifdef MD_BITMAP_SUPPORT
++                        /* PTB reset count of skipped blocks this mark */
++                        atomic_set(&md_throttle[mddev->md_minor], 0);
++#endif /* MD_BITMAP_SUPPORT */
+ 			mark[next] = jiffies;
+ 			mark_cnt[next] = j - atomic_read(&mddev->recovery_active);
+ 			last_mark = next;
+@@ -3414,10 +3714,23 @@ static void md_do_sync(mddev_t *mddev)
+ 		cond_resched();
+ 
+ 		currspeed = ((unsigned long)(j-mddev->resync_mark_cnt))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
++#ifdef MD_BITMAP_SUPPORT
++                /*
++                 * some of the blocks are skipped, not synced, so
++                 * should not count when limiting i/o. Let personality say.
++                 */
++                realspeed = ((unsigned long)(j - mddev->resync_mark_cnt - atomic_read(&md_throttle[mddev->md_minor])))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
++#endif /* MD_BITMAP_SUPPORT */
+ 
+ 		if (currspeed > sysctl_speed_limit_min) {
++#ifdef MD_BITMAP_SUPPORT
++                        /* PTB use realspeed for upper limit on i/o */
++			if ((realspeed > sysctl_speed_limit_max) ||
++					!is_mddev_idle(mddev)) {
++#else
+ 			if ((currspeed > sysctl_speed_limit_max) ||
+ 					!is_mddev_idle(mddev)) {
++#endif /* MD_BITMAP_SUPPORT */
+ 				msleep_interruptible(250);
+ 				goto repeat;
+ 			}
+@@ -3515,15 +3828,35 @@ void md_check_recovery(mddev_t *mddev)
+ 				mddev->pers->spare_active(mddev);
+ 			}
+ 			md_update_sb(mddev);
++#ifdef MD_BITMAP_SUPPORT
++                        mddev->recovery &= 1 << MD_BITMAP_REPAIR;
++
++                        printk(KERN_ERR
++                            "%s: md_check_recovery 1:"
++                            " repair bit %lx on sb %p preserved\n",
++                            mdname(mddev), mddev->recovery, mddev);
++#else
+ 			mddev->recovery = 0;
++#endif /* MD_BITMAP_SUPPORT */
+ 			/* flag recovery needed just to double check */
+ 			set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ 			goto unlock;
+ 		}
+ 		if (mddev->recovery)
+ 			/* probably just the RECOVERY_NEEDED flag */
++#ifdef MD_BITMAP_SUPPORT
++                {
++                        mddev->recovery &= 1 << MD_BITMAP_REPAIR;
++
++                        printk(KERN_ERR
++                            "%s: md_check_recovery 2:"
++                            " repair bit %lx on sb %p preserved\n",
++                            mdname(mddev), mddev->recovery, mddev);
++                }
++#else
+ 			mddev->recovery = 0;
+-
++			/* flag recovery needed just to double check */
++#endif /* MD_BITMAP_SUPPORT */
+ 		/* no recovery is running.
+ 		 * remove any failed drives, then
+ 		 * add spares if possible.
+@@ -3565,7 +3898,16 @@ void md_check_recovery(mddev_t *mddev)
+ 					" thread...\n", 
+ 					mdname(mddev));
+ 				/* leave the spares where they are, it shouldn't hurt */
++#ifdef MD_BITMAP_SUPPORT
++                                mddev->recovery &= 1 << MD_BITMAP_REPAIR;
++
++                                printk(KERN_ERR
++                                    "%s: md_check_recovery 3:"
++                                    " repair bit %lx on sb %p preserved\n",
++                                    mdname(mddev), mddev->recovery, mddev);
++#else
+ 				mddev->recovery = 0;
++#endif /* MD_BITMAP_SUPPORT */
+ 			} else {
+ 				md_wakeup_thread(mddev->sync_thread);
+ 			}
+@@ -3745,4 +4087,7 @@ EXPORT_SYMBOL(md_unregister_thread);
+ EXPORT_SYMBOL(md_wakeup_thread);
+ EXPORT_SYMBOL(md_print_devices);
+ EXPORT_SYMBOL(md_check_recovery);
++#ifdef MD_BITMAP_SUPPORT
++EXPORT_SYMBOL(md_throttle);
++#endif /* MD_BITMAP_SUPPORT */
+ MODULE_LICENSE("GPL");
+--- linux-2.6/drivers/md/Kconfig.orig	2005-07-13 13:27:18.467236952 +0200
++++ linux-2.6/drivers/md/Kconfig	2005-07-18 00:49:28.215689466 +0200
+@@ -104,6 +104,29 @@ config MD_RAID10
+ 
+ 	  If unsure, say Y.
+ 
++config MD_FR1
++        bool "FR-1 (fast intelligent mirroring) mode (EXPERIMENTAL)"
++        depends on BLK_DEV_MD && EXPERIMENTAL && MD_RAID1
++        ---help---
++          This driver offers a faster software RAID-1 performance than
++          standard RAID1 when resynchronizing disks and reading and has
++          various optimizations designed to automate administration.
++
++          If you want to use the FR-1 driver instead of a standard RAID1
++          driver, say Y. This option modifies the raid1 code directly.
++
++          If unsure, say N.
++
++config MD_RAID1_ROBUST_READ
++        bool "Robust reads for RAID1 (EXPERIMENTAL)"
++        depends on BLK_DEV_MD && EXPERIMENTAL && MD_RAID1
++        ---help---
++          This option makes RAID1 more robust in the face of read
++          errors from component disks. The disk will not be faulted but
++          the read will be retried from redundent data.
++
++          If unsure, say N.
++
+ config MD_RAID5
+ 	tristate "RAID-4/RAID-5 mode"
+ 	depends on BLK_DEV_MD
+@@ -161,6 +184,26 @@ config MD_MULTIPATH
+ 
+ 	  If unsure, say N.
+ 
++config MD_BITMAP
++        tristate "Bitmap support for fast raid (EXPERIMENTAL)"
++        depends on MD_FR1
++        ---help---
++          This driver provides bitmap support for Fast RAID.
++
++          Information about Software RAID on Linux is contained in the
++          Software-RAID mini-HOWTO, available from
++          <http://www.tldp.org/docs.html#howto>.  There you will also
++          learn where to get the supporting user space utilities raidtools.
++
++          If you want to use any of the Fast RAID driver options like FR1,
++          say Y.  This code is also available as a module called
++          bitmap.ko ( = code which can be inserted in and removed from
++          the running kernel whenever you want).  If you want to compile
++          it as a module, say M here and read
++          <file:Documentation/modules.txt>. 
++
++          If unsure, say N.
++
+ config MD_FAULTY
+ 	tristate "Faulty test module for MD"
+ 	depends on BLK_DEV_MD
+--- linux-2.6/drivers/md/Makefile.orig	2005-07-13 13:27:25.354002964 +0200
++++ linux-2.6/drivers/md/Makefile	2005-07-18 00:49:43.003039832 +0200
+@@ -26,6 +26,7 @@ obj-$(CONFIG_MD_RAID1)		+= raid1.o
+ obj-$(CONFIG_MD_RAID10)		+= raid10.o
+ obj-$(CONFIG_MD_RAID5)		+= raid5.o xor.o
+ obj-$(CONFIG_MD_RAID6)		+= raid6.o xor.o
++obj-$(CONFIG_MD_BITMAP)		+= bitmap.o
+ obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
+ obj-$(CONFIG_MD_FAULTY)		+= faulty.o
+ obj-$(CONFIG_BLK_DEV_MD)	+= md.o
diff -Nrup fr1-2.17.orig/patches/linux-2.6.12.2.patch.README fr1-2.17/patches/linux-2.6.12.2.patch.README
--- fr1-2.17.orig/patches/linux-2.6.12.2.patch.README	1970-01-01 01:00:00.000000000 +0100
+++ fr1-2.17/patches/linux-2.6.12.2.patch.README	2005-07-18 02:14:45.046842913 +0200
@@ -0,0 +1,19 @@
+
+This patch is based on linux-2.6.11.6.patch from the fr1-2.17 [1] package
+from  Peter T. Breuer (ptb@ot.uc3m.es). He did all the brainwork, i just
+edited the patch to make it apply to a pristine linux 2.6.12.2 kernel.
+
+Before applying, you may want to have a look at line 1708 of this patch:
+
++// #ifdef CONFIG_MD_FR1
++//                if (0)
++// #endif /* CONFIG_MD_FR1 */
+
+This is from broken-out/linux-2.6.11.6.patch_2.2. it does not 
+apply on 2.6.12.2 any more and i really don't know where it
+belongs. so I commented it out. It compiles but perhaps your 
+(my?) RAID will blow up. not good :(
+
+
+[1] http://www.it.uc3m.es/~ptb/nbd/
+    ftp://oboe.it.uc3m.es/pub/Programs/
diff -Nrup fr1-2.17.orig/patches/read-balance-already-incorporated-do-not-apply.patch fr1-2.17/patches/read-balance-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/read-balance-already-incorporated-do-not-apply.patch	2004-08-11 16:44:31.000000000 +0200
+++ fr1-2.17/patches/read-balance-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,160 +0,0 @@
---- linux-2.4.25/drivers/md/raid1.c.post-fr1-2.14b,pre-read-balance	Tue Aug 10 21:36:51 2004
-+++ linux-2.4.25/drivers/md/raid1.c	Mon Aug  9 19:27:32 2004
-@@ -46,7 +46,10 @@
- #define MD_DRIVER
- #define MD_PERSONALITY
- 
--#define MAX_WORK_PER_DISK 128
-+#define MAX_WORK_PER_DISK (128 * 8)
-+#define MAX_TEST_PER_DISK 32
-+#define LATENCY_OLD_WEIGHT 9
-+#define LATENCY_NEW_WEIGHT 1
- 
- #define	NR_RESERVED_BUFS	32
- 
-@@ -434,6 +434,32 @@
-                         bitmap->clearbits(bitmap, bh->b_rsector >> 1, bh->b_size >> 10);
-                 }
-         }
-+        /* PTB calculate the latency of the read device and update the record */
-+        if (uptodate && (r1_bh->cmd == READ || r1_bh->cmd == READA)) {
-+                unsigned long latency = jiffies - r1_bh->start_jiffies;
-+                kdev_t dev = (&r1_bh->bh_req)->b_dev;
-+                int i;
-+
-+                /* PTB find the mirror component being read */
-+                for (i = 0; i < conf->raid_disks; i++) {
-+                    if (conf->mirrors[i].dev == dev)
-+                        break;
-+                }
-+                if (i < conf->raid_disks) {
-+                        if (latency < 120 * HZ && latency >= 0) {
-+                                conf->latency[i] = LATENCY_OLD_WEIGHT * conf->latency[i]
-+                                                 + LATENCY_NEW_WEIGHT * latency;
-+                                conf->latency[i] /= LATENCY_OLD_WEIGHT
-+						   + LATENCY_NEW_WEIGHT;
-+                        } else {
-+		               printk(KERN_ERR "raid1: bad latency %lu jiffies\n", 
-+			         latency);
-+                        }
-+                } else {
-+		       printk(KERN_ERR "raid1: could not find dev %02x:%02x\n", 
-+                               MAJOR(dev), MINOR(dev));
-+                }
-+        }
-         raid1_free_r1bh(r1_bh);
- }
- 
-@@ -569,7 +594,7 @@
- 	 * Don't touch anything for sequential reads.
- 	 */
- 
--	if (this_sector == conf->mirrors[new_disk].head_position)
-+	if (0 && /* PTB */ this_sector == conf->mirrors[new_disk].head_position)
- 		goto rb_out;
- 	
- 	/*
-@@ -578,22 +603,66 @@
- 	 * This is for kicking those idling disks so that
- 	 * they would find work near some hotspot.
- 	 */
- 	
- 	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
-+
-+		PRINTK(KERN_INFO
-+		  "raid1: disk %d latency %d abandoned after %d sectors\n",
-+		  new_disk,
-+		  conf->latency[new_disk],
-+		  conf->sect_count);
- 		conf->sect_count = 0;
-+
-+		if (conf->last_fastest < 0) {
-+                    /* PTB find the fastest already known and use that */
-+
-+			int fastest = -1;
-+			unsigned long best_latency = 0x7fffffff;
-+			int i;
-+
-+			for (i = 0; i < conf->raid_disks; i++) {
-+	                        if (conf->mirrors[i].write_only
-+                                || !conf->mirrors[i].operational)
-+                                        continue;
-+                                if (conf->latency[i] <= best_latency) {
-+                                    best_latency = conf->latency[i];
-+                                    fastest = i;
-+                                }
-+			}
-+                        if (fastest >= 0)
-+                                new_disk = fastest;
-+	                conf->mirrors[new_disk].sect_limit =
-+                                                MAX_WORK_PER_DISK;
-+                        conf->last_fastest = new_disk;
-+                } else {
-+                    /* PTB move on to run a short test on the next disk */
- 
- #if defined(CONFIG_SPARC64) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 92)
- 		/* Work around a compiler bug in egcs-2.92.11 19980921 */
- 		new_disk = *(volatile int *)&new_disk;
- #endif
--		do {
--			if (new_disk<=0)
--				new_disk = conf->raid_disks;
--			new_disk--;
--			if (new_disk == disk)
--				break;
--		} while ((conf->mirrors[new_disk].write_only) ||
--			 (!conf->mirrors[new_disk].operational));
-+		        do {
-+			        if (new_disk<=0)
-+				        new_disk = conf->raid_disks;
-+			        new_disk--;
-+			        if (new_disk == disk)
-+				        break; /* nothing else available */
-+		        } while ((conf->mirrors[new_disk].write_only) ||
-+			         (!conf->mirrors[new_disk].operational));
-+                      /* PTB if tested all, will need to choose next time */
-+                        if (new_disk == conf->last_fastest) {
-+                                conf->last_fastest = -1;
-+                                /* PTB don't retest last source at all */
-+	                        //conf->mirrors[new_disk].sect_limit = 0;
-+                        }
-+                        /* PTB only a short test run */
-+	                conf->mirrors[new_disk].sect_limit = MAX_TEST_PER_DISK;
-+                }
-+
-+                PRINTK(KERN_INFO
-+                  "raid1: choosing disk %d latency %d\n",
-+                  new_disk,
-+                  conf->latency[new_disk]);
- 
- 		goto rb_out;
- 	}
-@@ -680,6 +749,7 @@
- 	r1_bh->master_bh = bh;
- 	r1_bh->mddev = mddev;
- 	r1_bh->cmd = rw;
-+	r1_bh->start_jiffies = jiffies; /* PTB record start time */
-         async_data = NULL;
- 
- 	if (rw == READ) {
---- linux-2.4.25/include/linux/raid/raid1.h.post-fr1-2.14b,pre-read-balance	Tue Aug 10 21:48:31 2004
-+++ linux-2.4.25/include/linux/raid/raid1.h	Mon Aug  9 18:53:57 2004
-@@ -59,6+59,10 @@
- 	md_wait_queue_head_t	wait_done;
- 	md_wait_queue_head_t	wait_ready;
- 	md_spinlock_t		segment_lock;
-+
-+	int			latency[MD_SB_DISKS];
-+	int			last_fastest;        /* PTB disk read from */
-+
- };
- 
- typedef struct raid1_private_data raid1_conf_t;
-@@ -92,6 +96,7 @@
- 	struct buffer_head	*mirror_bh_list;
- 	struct buffer_head	bh_req;
- 	struct raid1_bh		*next_r1;	/* next for retry or in free list */
-+	unsigned long		start_jiffies;  /* PTB when i/o started */
- };
- /* bits for raid1_bh.state */
- #define	R1BH_Uptodate	1
diff -Nrup fr1-2.17.orig/patches/throttle-correction-already-incorporated-do-not-apply.patch fr1-2.17/patches/throttle-correction-already-incorporated-do-not-apply.patch
--- fr1-2.17.orig/patches/throttle-correction-already-incorporated-do-not-apply.patch	2004-08-21 09:50:35.000000000 +0200
+++ fr1-2.17/patches/throttle-correction-already-incorporated-do-not-apply.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,124 +0,0 @@
---- linux-2.4.24-xfs/drivers/md/md.c.orig	Thu Jan 29 18:19:37 2004
-+++ linux-2.4.24-xfs/drivers/md/md.c	Sun Feb 22 21:03:24 2004
-@@ -26,6 +26,9 @@
-    You should have received a copy of the GNU General Public License
-    (for example /usr/src/linux/COPYING); if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+  
-+   Yet more changes by PTB 26/3/2004 to make the speed calculations
-+   appropriate to fr1, and throttle by real i/o, not resync total.
- */
- 
- #include <linux/module.h>
-@@ -108,6 +123,10 @@
- static int md_hardsect_sizes[MAX_MD_DEVS];
- static int md_maxreadahead[MAX_MD_DEVS];
- static mdk_thread_t *md_recovery_thread;
-+#ifdef MD_BITMAP_SUPPORT
-+/* PTB md_throttle permits speed calculation adjustments from personality */
-+static atomic_t md_throttle[MAX_MD_DEVS];
-+#endif /* MD_BITMAP_SUPPORT */
- 
- int md_size[MAX_MD_DEVS];
- 
-@@ -3419,6 +3608,10 @@
- 	mddev_t *mddev2;
- 	unsigned int max_sectors, currspeed,
- 		j, window, err, serialize;
-+#ifdef MD_BITMAP_SUPPORT
-+	/* PTB add realspeed for i/o limiting calculation */
-+	unsigned realspeed;
-+#endif /* MD_BITMAP_SUPPORT */
- 	unsigned long mark[SYNC_MARKS];
- 	unsigned long mark_cnt[SYNC_MARKS];
- 	int last_mark,m;
-@@ -3488,6 +3682,9 @@
- 	atomic_set(&mddev->recovery_active, 0);
- 	init_waitqueue_head(&mddev->recovery_wait);
- 	last_check = 0;
-+#ifdef MD_BITMAP_SUPPORT
-+        atomic_set(&md_throttle[mdidx(mddev)], 0);
-+#endif /* MD_BITMAP_SUPPORT */
- 	for (j = 0; j < max_sectors;) {
- 		int sectors;
- 
-@@ -3515,6 +3712,10 @@
- 
- 			mddev->resync_mark = mark[next];
- 			mddev->resync_mark_cnt = mark_cnt[next];
-+#ifdef MD_BITMAP_SUPPORT
-+                        /* PTB reset count of skipped blocks this mark */
-+                        atomic_set(&md_throttle[mdidx(mddev)], 0);
-+#endif /* MD_BITMAP_SUPPORT */
- 			mark[next] = jiffies;
- 			mark_cnt[next] = j - atomic_read(&mddev->recovery_active);
- 			last_mark = next;
-@@ -3544,12 +3745,25 @@
- 			schedule();
- 
- 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
-+#ifdef MD_BITMAP_SUPPORT
-+                /*
-+                 * PTB some of the blocks are skipped, not synced, so
-+                 * should not count when limiting i/o. Let personality say.
-+                 */
-+		realspeed = (j - mddev->resync_mark_cnt - atomic_read(&md_throttle[mdidx(mddev)]))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
-+#endif /* MD_BITMAP_SUPPORT */
- 
- 		if (currspeed > sysctl_speed_limit_min) {
- 			current->nice = 19;
- 
--			if ((currspeed > sysctl_speed_limit_max) ||
--					!is_mddev_idle(mddev)) {
-+			if (
-+#ifdef MD_BITMAP_SUPPORT
-+                        /* PTB use realspeed for upper limit on i/o */
-+                            (realspeed > sysctl_speed_limit_max) ||
-+#else
-+                            (currspeed > sysctl_speed_limit_max) ||
-+#endif /* MD_BITMAP_SUPPORT */
-+                                        !is_mddev_idle(mddev)) {
- 				current->state = TASK_INTERRUPTIBLE;
- 				md_schedule_timeout(HZ/4);
- 				goto repeat;
-@@ -4127,4 +4345,7 @@
- MD_EXPORT_SYMBOL(mddev_map);
- MD_EXPORT_SYMBOL(md_check_ordering);
- MD_EXPORT_SYMBOL(get_spare);
-+#ifdef MD_BITMAP_SUPPORT
-+MD_EXPORT_SYMBOL(md_throttle);
-+#endif /* MD_BITMAP_SUPPORT */
- MODULE_LICENSE("GPL");
---- linux-2.4.24-xfs/drivers/md/raid1.c.orig	Fri Jun 13 16:51:34 2003
-+++ linux-2.4.24-xfs/drivers/md/raid1.c	Sun Aug 15 04:38:00 2004
-@@ -23,6 +23,8 @@
-  * More changes by PTB 20/2/2003 to let the bitmap always be present and
-  * thus allow asynchronous mirror writes by using it as a journal log.
-  *
-+ * Changes PTB early 2004 to account speed properly.
-+ *
-  */
- 
- #include <linux/module.h>
-@@ -1362,6 +1665,12 @@
- 	int disk;
- 	int block_nr;
- 	int buffs;
-+        /*
-+         * PTB discount the skipped sectors back to the md.c code
-+         */
-+        extern atomic_t md_throttle[];
-+
-+ 
- 
- 	if (!sector_nr) {
- 		/* we want enough buffers to hold twice the window of 128*/
-@@ -1429,6 +1762,8 @@
-                         conf->last_clean_sector);
-                 }
-  
-+                /* PTB - update md driver throttle discount */
-+                atomic_add(done, &md_throttle[mdidx(mddev)]);
-	        spin_unlock_irq(&conf->segment_lock);
- 
- 		wake_up(&conf->wait_ready);

