INIT_LIST_HEAD(&new->all_mddevs);
        init_timer(&new->safemode_timer);
        atomic_set(&new->active, 1);
+       bio_list_init(&new->write_list);
+       spin_lock_init(&new->write_lock);
 
        new->queue = blk_alloc_queue(GFP_KERNEL);
        if (!new->queue) {
        int err, count = 100;
        struct list_head *tmp;
        mdk_rdev_t *rdev;
+       int sync_req;
 
-       mddev->sb_dirty = 0;
 repeat:
+       spin_lock(&mddev->write_lock);
+       sync_req = mddev->in_sync;
        mddev->utime = get_seconds();
        mddev->events ++;
 
         * do not write anything to disk if using
         * nonpersistent superblocks
         */
-       if (!mddev->persistent)
+       if (!mddev->persistent) {
+               mddev->sb_dirty = 0;
+               spin_unlock(&mddev->write_lock);
                return;
+       }
+       spin_unlock(&mddev->write_lock);
 
        dprintk(KERN_INFO 
                "md: updating %s RAID superblock on device (in sync %d)\n",
                printk(KERN_ERR \
                        "md: excessive errors occurred during superblock update, exiting\n");
        }
+       spin_lock(&mddev->write_lock);
+       if (mddev->in_sync != sync_req) {
+               /* have to write it out again */
+               spin_unlock(&mddev->write_lock);
+               goto repeat;
+       }
+       mddev->sb_dirty = 0;
+       spin_unlock(&mddev->write_lock);
+
 }
 
 /*
 }
 
 
-void md_write_start(mddev_t *mddev)
+/* md_write_start(mddev, bi)
+ * If we need to update some array metadata (e.g. 'active' flag
+ * in superblock) before writing, queue bi for later writing
+ * and return 0, else return 1 and it will be written now
+ */
+int md_write_start(mddev_t *mddev, struct bio *bi)
 {
-       if (!atomic_read(&mddev->writes_pending)) {
-               mddev_lock_uninterruptible(mddev);
-               if (mddev->in_sync) {
-                       mddev->in_sync = 0;
-                       del_timer(&mddev->safemode_timer);
-                       md_update_sb(mddev);
-               }
-               atomic_inc(&mddev->writes_pending);
-               mddev_unlock(mddev);
-       } else
-               atomic_inc(&mddev->writes_pending);
+       if (bio_data_dir(bi) != WRITE)
+               return 1;
+
+       atomic_inc(&mddev->writes_pending);
+       spin_lock(&mddev->write_lock);
+       if (mddev->in_sync == 0 && mddev->sb_dirty == 0) {
+               spin_unlock(&mddev->write_lock);
+               return 1;
+       }
+       bio_list_add(&mddev->write_list, bi);
+
+       if (mddev->in_sync) {
+               mddev->in_sync = 0;
+               mddev->sb_dirty = 1;
+       }
+       spin_unlock(&mddev->write_lock);
+       md_wakeup_thread(mddev->thread);
+       return 0;
 }
 
 void md_write_end(mddev_t *mddev)
                mddev->sb_dirty ||
                test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
                test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
+               mddev->write_list.head ||
                (mddev->safemode == 1) ||
                (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
                 && !mddev->in_sync && mddev->recovery_cp == MaxSector)
 
        if (mddev_trylock(mddev)==0) {
                int spares =0;
+               struct bio *blist;
 
+               spin_lock(&mddev->write_lock);
                if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
                    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
                        mddev->in_sync = 1;
                }
                if (mddev->safemode == 1)
                        mddev->safemode = 0;
+               blist = bio_list_get(&mddev->write_list);
+               spin_unlock(&mddev->write_lock);
 
                if (mddev->sb_dirty)
                        md_update_sb(mddev);
+
+               while (blist) {
+                       struct bio *b = blist;
+                       blist = blist->bi_next;
+                       b->bi_next = NULL;
+                       generic_make_request(b);
+                       /* we already counted this, so need to un-count */
+                       md_write_end(mddev);
+               }
+
+
                if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
                    !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
                        /* resync/recovery still happening */