md: make merge_bvec_fn more robust in face of personality changes.
[deliverable/linux.git] / drivers / md / md.c
index 709755fb6d7b62823d2291c99397ca0111adcbaf..9f0ff718713622f13ed3af9a94ddd5c7d9bf747d 100644 (file)
@@ -321,10 +321,47 @@ EXPORT_SYMBOL_GPL(mddev_resume);
 
 int mddev_congested(struct mddev *mddev, int bits)
 {
-       return mddev->suspended;
+       struct md_personality *pers = mddev->pers;
+       int ret = 0;
+
+       rcu_read_lock();
+       if (mddev->suspended)
+               ret = 1;
+       else if (pers && pers->congested)
+               ret = pers->congested(mddev, bits);
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mddev_congested);
+static int md_congested(void *data, int bits)
+{
+       struct mddev *mddev = data;
+       return mddev_congested(mddev, bits);
 }
-EXPORT_SYMBOL(mddev_congested);
 
+static int md_mergeable_bvec(struct request_queue *q,
+                            struct bvec_merge_data *bvm,
+                            struct bio_vec *biovec)
+{
+       struct mddev *mddev = q->queuedata;
+       int ret;
+       rcu_read_lock();
+       if (mddev->suspended) {
+               /* Must always allow one vec */
+               if (bvm->bi_size == 0)
+                       ret = biovec->bv_len;
+               else
+                       ret = 0;
+       } else {
+               struct md_personality *pers = mddev->pers;
+               if (pers && pers->mergeable_bvec)
+                       ret = pers->mergeable_bvec(mddev, bvm, biovec);
+               else
+                       ret = biovec->bv_len;
+       }
+       rcu_read_unlock();
+       return ret;
+}
 /*
  * Generic flush handling for md
  */
@@ -397,12 +434,12 @@ static void md_submit_flush_data(struct work_struct *ws)
 
 void md_flush_request(struct mddev *mddev, struct bio *bio)
 {
-       spin_lock_irq(&mddev->write_lock);
+       spin_lock_irq(&mddev->lock);
        wait_event_lock_irq(mddev->sb_wait,
                            !mddev->flush_bio,
-                           mddev->write_lock);
+                           mddev->lock);
        mddev->flush_bio = bio;
-       spin_unlock_irq(&mddev->write_lock);
+       spin_unlock_irq(&mddev->lock);
 
        INIT_WORK(&mddev->flush_work, submit_flushes);
        queue_work(md_wq, &mddev->flush_work);
@@ -465,7 +502,7 @@ void mddev_init(struct mddev *mddev)
        atomic_set(&mddev->active, 1);
        atomic_set(&mddev->openers, 0);
        atomic_set(&mddev->active_io, 0);
-       spin_lock_init(&mddev->write_lock);
+       spin_lock_init(&mddev->lock);
        atomic_set(&mddev->flush_pending, 0);
        init_waitqueue_head(&mddev->sb_wait);
        init_waitqueue_head(&mddev->recovery_wait);
@@ -2230,7 +2267,7 @@ repeat:
                return;
        }
 
-       spin_lock_irq(&mddev->write_lock);
+       spin_lock(&mddev->lock);
 
        mddev->utime = get_seconds();
 
@@ -2287,7 +2324,7 @@ repeat:
        }
 
        sync_sbs(mddev, nospares);
-       spin_unlock_irq(&mddev->write_lock);
+       spin_unlock(&mddev->lock);
 
        pr_debug("md: updating %s RAID superblock on device (in sync %d)\n",
                 mdname(mddev), mddev->in_sync);
@@ -2326,15 +2363,15 @@ repeat:
        md_super_wait(mddev);
        /* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */
 
-       spin_lock_irq(&mddev->write_lock);
+       spin_lock(&mddev->lock);
        if (mddev->in_sync != sync_req ||
            test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
                /* have to write it out again */
-               spin_unlock_irq(&mddev->write_lock);
+               spin_unlock(&mddev->lock);
                goto repeat;
        }
        clear_bit(MD_CHANGE_PENDING, &mddev->flags);
-       spin_unlock_irq(&mddev->write_lock);
+       spin_unlock(&mddev->lock);
        wake_up(&mddev->sb_wait);
        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                sysfs_notify(&mddev->kobj, NULL, "sync_completed");
@@ -3722,7 +3759,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        case clean:
                if (mddev->pers) {
                        restart_array(mddev);
-                       spin_lock_irq(&mddev->write_lock);
+                       spin_lock(&mddev->lock);
                        if (atomic_read(&mddev->writes_pending) == 0) {
                                if (mddev->in_sync == 0) {
                                        mddev->in_sync = 1;
@@ -3733,7 +3770,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
                                err = 0;
                        } else
                                err = -EBUSY;
-                       spin_unlock_irq(&mddev->write_lock);
+                       spin_unlock(&mddev->lock);
                } else
                        err = -EINVAL;
                break;
@@ -4908,6 +4945,11 @@ int md_run(struct mddev *mddev)
                bitmap_destroy(mddev);
                return err;
        }
+       if (mddev->queue) {
+               mddev->queue->backing_dev_info.congested_data = mddev;
+               mddev->queue->backing_dev_info.congested_fn = md_congested;
+               blk_queue_merge_bvec(mddev->queue, md_mergeable_bvec);
+       }
        if (mddev->pers->sync_request) {
                if (mddev->kobj.sd &&
                    sysfs_create_group(&mddev->kobj, &md_redundancy_group))
@@ -7102,7 +7144,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)
        if (mddev->safemode == 1)
                mddev->safemode = 0;
        if (mddev->in_sync) {
-               spin_lock_irq(&mddev->write_lock);
+               spin_lock(&mddev->lock);
                if (mddev->in_sync) {
                        mddev->in_sync = 0;
                        set_bit(MD_CHANGE_CLEAN, &mddev->flags);
@@ -7110,7 +7152,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)
                        md_wakeup_thread(mddev->thread);
                        did_change = 1;
                }
-               spin_unlock_irq(&mddev->write_lock);
+               spin_unlock(&mddev->lock);
        }
        if (did_change)
                sysfs_notify_dirent_safe(mddev->sysfs_state);
@@ -7148,7 +7190,7 @@ int md_allow_write(struct mddev *mddev)
        if (!mddev->pers->sync_request)
                return 0;
 
-       spin_lock_irq(&mddev->write_lock);
+       spin_lock(&mddev->lock);
        if (mddev->in_sync) {
                mddev->in_sync = 0;
                set_bit(MD_CHANGE_CLEAN, &mddev->flags);
@@ -7156,11 +7198,11 @@ int md_allow_write(struct mddev *mddev)
                if (mddev->safemode_delay &&
                    mddev->safemode == 0)
                        mddev->safemode = 1;
-               spin_unlock_irq(&mddev->write_lock);
+               spin_unlock(&mddev->lock);
                md_update_sb(mddev, 0);
                sysfs_notify_dirent_safe(mddev->sysfs_state);
        } else
-               spin_unlock_irq(&mddev->write_lock);
+               spin_unlock(&mddev->lock);
 
        if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
                return -EAGAIN;
@@ -7688,7 +7730,7 @@ void md_check_recovery(struct mddev *mddev)
 
                if (!mddev->external) {
                        int did_change = 0;
-                       spin_lock_irq(&mddev->write_lock);
+                       spin_lock(&mddev->lock);
                        if (mddev->safemode &&
                            !atomic_read(&mddev->writes_pending) &&
                            !mddev->in_sync &&
@@ -7699,7 +7741,7 @@ void md_check_recovery(struct mddev *mddev)
                        }
                        if (mddev->safemode == 1)
                                mddev->safemode = 0;
-                       spin_unlock_irq(&mddev->write_lock);
+                       spin_unlock(&mddev->lock);
                        if (did_change)
                                sysfs_notify_dirent_safe(mddev->sysfs_state);
                }
This page took 0.029804 seconds and 5 git commands to generate.