intelfb: add vsync interrupt support
[safe/jmp/linux-2.6] / drivers / md / raid6main.c
index 06b32bd..bc69355 100644 (file)
@@ -88,13 +88,11 @@ static inline int raid6_next_disk(int disk, int raid_disks)
 
 static void print_raid6_conf (raid6_conf_t *conf);
 
-static inline void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
+static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
 {
        if (atomic_dec_and_test(&sh->count)) {
-               if (!list_empty(&sh->lru))
-                       BUG();
-               if (atomic_read(&conf->active_stripes)==0)
-                       BUG();
+               BUG_ON(!list_empty(&sh->lru));
+               BUG_ON(atomic_read(&conf->active_stripes)==0);
                if (test_bit(STRIPE_HANDLE, &sh->state)) {
                        if (test_bit(STRIPE_DELAYED, &sh->state))
                                list_add_tail(&sh->lru, &conf->delayed_list);
@@ -115,7 +113,7 @@ static inline void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
                        list_add_tail(&sh->lru, &conf->inactive_list);
                        atomic_dec(&conf->active_stripes);
                        if (!conf->inactive_blocked ||
-                           atomic_read(&conf->active_stripes) < (NR_STRIPES*3/4))
+                           atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
                                wake_up(&conf->wait_for_stripe);
                }
        }
@@ -197,15 +195,13 @@ static int grow_buffers(struct stripe_head *sh, int num)
 
 static void raid6_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
        raid6_conf_t *conf = sh->raid_conf;
        int disks = conf->raid_disks, i;
 
-       if (atomic_read(&sh->count) != 0)
-               BUG();
-       if (test_bit(STRIPE_HANDLE, &sh->state))
-               BUG();
+       BUG_ON(atomic_read(&sh->count) != 0);
+       BUG_ON(test_bit(STRIPE_HANDLE, &sh->state));
 
        CHECK_DEVLOCK();
        PRINTK("init_stripe called, stripe %llu\n",
@@ -273,7 +269,8 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
                                conf->inactive_blocked = 1;
                                wait_event_lock_irq(conf->wait_for_stripe,
                                                    !list_empty(&conf->inactive_list) &&
-                                                   (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4)
+                                                   (atomic_read(&conf->active_stripes)
+                                                    < (conf->max_nr_stripes *3/4)
                                                     || !conf->inactive_blocked),
                                                    conf->device_lock,
                                                    unplug_slaves(conf->mddev);
@@ -283,13 +280,11 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
                                init_stripe(sh, sector, pd_idx);
                } else {
                        if (atomic_read(&sh->count)) {
-                               if (!list_empty(&sh->lru))
-                                       BUG();
+                               BUG_ON(!list_empty(&sh->lru));
                        } else {
                                if (!test_bit(STRIPE_HANDLE, &sh->state))
                                        atomic_inc(&conf->active_stripes);
-                               if (list_empty(&sh->lru))
-                                       BUG();
+                               BUG_ON(list_empty(&sh->lru));
                                list_del_init(&sh->lru);
                        }
                }
@@ -302,59 +297,70 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
        return sh;
 }
 
-static int grow_stripes(raid6_conf_t *conf, int num)
+static int grow_one_stripe(raid6_conf_t *conf)
 {
        struct stripe_head *sh;
+       sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+       if (!sh)
+               return 0;
+       memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+       sh->raid_conf = conf;
+       spin_lock_init(&sh->lock);
+
+       if (grow_buffers(sh, conf->raid_disks)) {
+               shrink_buffers(sh, conf->raid_disks);
+               kmem_cache_free(conf->slab_cache, sh);
+               return 0;
+       }
+       /* we just created an active stripe so... */
+       atomic_set(&sh->count, 1);
+       atomic_inc(&conf->active_stripes);
+       INIT_LIST_HEAD(&sh->lru);
+       release_stripe(sh);
+       return 1;
+}
+
+static int grow_stripes(raid6_conf_t *conf, int num)
+{
        kmem_cache_t *sc;
        int devs = conf->raid_disks;
 
-       sprintf(conf->cache_name, "raid6/%s", mdname(conf->mddev));
+       sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev));
 
-       sc = kmem_cache_create(conf->cache_name,
+       sc = kmem_cache_create(conf->cache_name[0],
                               sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
                               0, 0, NULL, NULL);
        if (!sc)
                return 1;
        conf->slab_cache = sc;
-       while (num--) {
-               sh = kmem_cache_alloc(sc, GFP_KERNEL);
-               if (!sh)
+       while (num--)
+               if (!grow_one_stripe(conf))
                        return 1;
-               memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
-               sh->raid_conf = conf;
-               spin_lock_init(&sh->lock);
-
-               if (grow_buffers(sh, conf->raid_disks)) {
-                       shrink_buffers(sh, conf->raid_disks);
-                       kmem_cache_free(sc, sh);
-                       return 1;
-               }
-               /* we just created an active stripe so... */
-               atomic_set(&sh->count, 1);
-               atomic_inc(&conf->active_stripes);
-               INIT_LIST_HEAD(&sh->lru);
-               release_stripe(sh);
-       }
        return 0;
 }
 
-static void shrink_stripes(raid6_conf_t *conf)
+static int drop_one_stripe(raid6_conf_t *conf)
 {
        struct stripe_head *sh;
+       spin_lock_irq(&conf->device_lock);
+       sh = get_free_stripe(conf);
+       spin_unlock_irq(&conf->device_lock);
+       if (!sh)
+               return 0;
+       BUG_ON(atomic_read(&sh->count));
+       shrink_buffers(sh, conf->raid_disks);
+       kmem_cache_free(conf->slab_cache, sh);
+       atomic_dec(&conf->active_stripes);
+       return 1;
+}
 
-       while (1) {
-               spin_lock_irq(&conf->device_lock);
-               sh = get_free_stripe(conf);
-               spin_unlock_irq(&conf->device_lock);
-               if (!sh)
-                       break;
-               if (atomic_read(&sh->count))
-                       BUG();
-               shrink_buffers(sh, conf->raid_disks);
-               kmem_cache_free(conf->slab_cache, sh);
-               atomic_dec(&conf->active_stripes);
-       }
-       kmem_cache_destroy(conf->slab_cache);
+static void shrink_stripes(raid6_conf_t *conf)
+{
+       while (drop_one_stripe(conf))
+               ;
+
+       if (conf->slab_cache)
+               kmem_cache_destroy(conf->slab_cache);
        conf->slab_cache = NULL;
 }
 
@@ -767,7 +773,7 @@ static void compute_parity(struct stripe_head *sh, int method)
                                if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
                                        wake_up(&conf->wait_for_overlap);
 
-                               if (sh->dev[i].written) BUG();
+                               BUG_ON(sh->dev[i].written);
                                sh->dev[i].written = chosen;
                        }
                break;
@@ -957,8 +963,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
        if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9))
                goto overlap;
 
-       if (*bip && bi->bi_next && (*bip) != bi->bi_next)
-               BUG();
+       BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next);
        if (*bip)
                bi->bi_next = *bip;
        *bip = bi;
@@ -1562,6 +1567,9 @@ static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
                        bi->bi_io_vec[0].bv_offset = 0;
                        bi->bi_size = STRIPE_SIZE;
                        bi->bi_next = NULL;
+                       if (rw == WRITE &&
+                           test_bit(R5_ReWrite, &sh->dev[i].flags))
+                               atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
                        generic_make_request(bi);
                } else {
                        if (rw == 1)
@@ -1574,7 +1582,7 @@ static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
        }
 }
 
-static inline void raid6_activate_delayed(raid6_conf_t *conf)
+static void raid6_activate_delayed(raid6_conf_t *conf)
 {
        if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
                while (!list_empty(&conf->delayed_list)) {
@@ -1590,7 +1598,7 @@ static inline void raid6_activate_delayed(raid6_conf_t *conf)
        }
 }
 
-static inline void activate_bit_delay(raid6_conf_t *conf)
+static void activate_bit_delay(raid6_conf_t *conf)
 {
        /* device_lock is held */
        struct list_head head;
@@ -1890,8 +1898,7 @@ static void raid6d (mddev_t *mddev)
 
                list_del_init(first);
                atomic_inc(&sh->count);
-               if (atomic_read(&sh->count)!= 1)
-                       BUG();
+               BUG_ON(atomic_read(&sh->count)!= 1);
                spin_unlock_irq(&conf->device_lock);
 
                handled++;
@@ -1909,6 +1916,74 @@ static void raid6d (mddev_t *mddev)
        PRINTK("--- raid6d inactive\n");
 }
 
+static ssize_t
+raid6_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       if (conf)
+               return sprintf(page, "%d\n", conf->max_nr_stripes);
+       else
+               return 0;
+}
+
+static ssize_t
+raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       char *end;
+       int new;
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       new = simple_strtoul(page, &end, 10);
+       if (!*page || (*end && *end != '\n') )
+               return -EINVAL;
+       if (new <= 16 || new > 32768)
+               return -EINVAL;
+       while (new < conf->max_nr_stripes) {
+               if (drop_one_stripe(conf))
+                       conf->max_nr_stripes--;
+               else
+                       break;
+       }
+       while (new > conf->max_nr_stripes) {
+               if (grow_one_stripe(conf))
+                       conf->max_nr_stripes++;
+               else break;
+       }
+       return len;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+                               raid6_show_stripe_cache_size,
+                               raid6_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+       raid6_conf_t *conf = mddev_to_conf(mddev);
+       if (conf)
+               return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+       else
+               return 0;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid6_attrs[] =  {
+       &raid6_stripecache_size.attr,
+       &raid6_stripecache_active.attr,
+       NULL,
+};
+static struct attribute_group raid6_attrs_group = {
+       .name = NULL,
+       .attrs = raid6_attrs,
+};
+
 static int run(mddev_t *mddev)
 {
        raid6_conf_t *conf;
@@ -1922,11 +1997,14 @@ static int run(mddev_t *mddev)
                return -EIO;
        }
 
-       mddev->private = kzalloc(sizeof (raid6_conf_t)
-                                + mddev->raid_disks * sizeof(struct disk_info),
-                                GFP_KERNEL);
+       mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL);
        if ((conf = mddev->private) == NULL)
                goto abort;
+       conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info),
+                                GFP_KERNEL);
+       if (!conf->disks)
+               goto abort;
+
        conf->mddev = mddev;
 
        if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
@@ -2064,6 +2142,8 @@ static int run(mddev_t *mddev)
        }
 
        /* Ok, everything is just fine now */
+       sysfs_create_group(&mddev->kobj, &raid6_attrs_group);
+
        mddev->array_size =  mddev->size * (mddev->raid_disks - 2);
 
        mddev->queue->unplug_fn = raid6_unplug_device;
@@ -2074,6 +2154,7 @@ abort:
                print_raid6_conf(conf);
                safe_put_page(conf->spare_page);
                kfree(conf->stripe_hashtbl);
+               kfree(conf->disks);
                kfree(conf);
        }
        mddev->private = NULL;
@@ -2092,6 +2173,7 @@ static int stop (mddev_t *mddev)
        shrink_stripes(conf);
        kfree(conf->stripe_hashtbl);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+       sysfs_remove_group(&mddev->kobj, &raid6_attrs_group);
        kfree(conf);
        mddev->private = NULL;
        return 0;
@@ -2341,4 +2423,5 @@ module_init(raid6_init);
 module_exit(raid6_exit);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("md-personality-8"); /* RAID6 */
+MODULE_ALIAS("md-raid6");
 MODULE_ALIAS("md-level-6");