Merge head 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
[pandora-kernel.git] / drivers / md / md.c
index fde8acf..6580e0f 100644 (file)
@@ -195,8 +195,7 @@ static mddev_t * mddev_find(dev_t unit)
                if (mddev->unit == unit) {
                        mddev_get(mddev);
                        spin_unlock(&all_mddevs_lock);
-                       if (new)
-                               kfree(new);
+                       kfree(new);
                        return mddev;
                }
 
@@ -285,7 +284,7 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev)
        return NULL;
 }
 
-inline static sector_t calc_dev_sboffset(struct block_device *bdev)
+static inline sector_t calc_dev_sboffset(struct block_device *bdev)
 {
        sector_t size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
        return MD_NEW_SIZE_BLOCKS(size);
@@ -328,6 +327,41 @@ static void free_disk_sb(mdk_rdev_t * rdev)
 }
 
 
+static int super_written(struct bio *bio, unsigned int bytes_done, int error)
+{
+       mdk_rdev_t *rdev = bio->bi_private;
+       if (bio->bi_size)
+               return 1;
+
+       if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
+               md_error(rdev->mddev, rdev);
+
+       if (atomic_dec_and_test(&rdev->mddev->pending_writes))
+               wake_up(&rdev->mddev->sb_wait);
+       bio_put(bio);
+       return 0;
+}
+
+void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
+                  sector_t sector, int size, struct page *page)
+{
+       /* write first size bytes of page to sector of rdev
+        * Increment mddev->pending_writes before returning
+        * and decrement it on completion, waking up sb_wait
+        * if zero is reached.
+        * If an error occurred, call md_error
+        */
+       struct bio *bio = bio_alloc(GFP_NOIO, 1);
+
+       bio->bi_bdev = rdev->bdev;
+       bio->bi_sector = sector;
+       bio_add_page(bio, page, size, 0);
+       bio->bi_private = rdev;
+       bio->bi_end_io = super_written;
+       atomic_inc(&mddev->pending_writes);
+       submit_bio((1<<BIO_RW)|(1<<BIO_RW_SYNC), bio);
+}
+
 static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
 {
        if (bio->bi_size)
@@ -424,11 +458,8 @@ static int sb_equal(mdp_super_t *sb1, mdp_super_t *sb2)
                ret = 1;
 
 abort:
-       if (tmp1)
-               kfree(tmp1);
-       if (tmp2)
-               kfree(tmp2);
-
+       kfree(tmp1);
+       kfree(tmp2);
        return ret;
 }
 
@@ -813,7 +844,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
        case 0:
                sb_offset = rdev->bdev->bd_inode->i_size >> 9;
                sb_offset -= 8*2;
-               sb_offset &= ~(4*2-1);
+               sb_offset &= ~(sector_t)(4*2-1);
                /* convert from sectors to K */
                sb_offset /= 2;
                break;
@@ -1268,30 +1299,6 @@ void md_print_devices(void)
 }
 
 
-static int write_disk_sb(mdk_rdev_t * rdev)
-{
-       char b[BDEVNAME_SIZE];
-       if (!rdev->sb_loaded) {
-               MD_BUG();
-               return 1;
-       }
-       if (rdev->faulty) {
-               MD_BUG();
-               return 1;
-       }
-
-       dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
-               bdevname(rdev->bdev,b),
-              (unsigned long long)rdev->sb_offset);
-  
-       if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE))
-               return 0;
-
-       printk("md: write_disk_sb failed for device %s\n", 
-               bdevname(rdev->bdev,b));
-       return 1;
-}
-
 static void sync_sbs(mddev_t * mddev)
 {
        mdk_rdev_t *rdev;
@@ -1306,7 +1313,7 @@ static void sync_sbs(mddev_t * mddev)
 
 static void md_update_sb(mddev_t * mddev)
 {
-       int err, count = 100;
+       int err;
        struct list_head *tmp;
        mdk_rdev_t *rdev;
        int sync_req;
@@ -1326,6 +1333,7 @@ repeat:
                MD_BUG();
                mddev->events --;
        }
+       mddev->sb_dirty = 2;
        sync_sbs(mddev);
 
        /*
@@ -1353,24 +1361,24 @@ repeat:
 
                dprintk("%s ", bdevname(rdev->bdev,b));
                if (!rdev->faulty) {
-                       err += write_disk_sb(rdev);
+                       md_super_write(mddev,rdev,
+                                      rdev->sb_offset<<1, MD_SB_BYTES,
+                                      rdev->sb_page);
+                       dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
+                               bdevname(rdev->bdev,b),
+                               (unsigned long long)rdev->sb_offset);
+
                } else
                        dprintk(")\n");
-               if (!err && mddev->level == LEVEL_MULTIPATH)
+               if (mddev->level == LEVEL_MULTIPATH)
                        /* only need to write one superblock... */
                        break;
        }
-       if (err) {
-               if (--count) {
-                       printk(KERN_ERR "md: errors occurred during superblock"
-                               " update, repeating\n");
-                       goto repeat;
-               }
-               printk(KERN_ERR \
-                       "md: excessive errors occurred during superblock update, exiting\n");
-       }
+       wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+       /* if there was a failure, sb_dirty was set to 1, and we re-write super */
+
        spin_lock(&mddev->write_lock);
-       if (mddev->in_sync != sync_req) {
+       if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
                /* have to write it out again */
                spin_unlock(&mddev->write_lock);
                goto repeat;
@@ -2969,8 +2977,7 @@ static int md_thread(void * arg)
                wait_event_interruptible_timeout(thread->wqueue,
                                                 test_bit(THREAD_WAKEUP, &thread->flags),
                                                 thread->timeout);
-               if (current->flags & PF_FREEZE)
-                       refrigerator(PF_FREEZE);
+               try_to_freeze();
 
                clear_bit(THREAD_WAKEUP, &thread->flags);