[SPARC64]: Don't clobber alt-global %g4 on window fixups.
[safe/jmp/linux-2.6] / drivers / md / raid5.c
index 53a0f2c..2dba305 100644 (file)
 #define STRIPE_SHIFT           (PAGE_SHIFT - 9)
 #define STRIPE_SECTORS         (STRIPE_SIZE>>9)
 #define        IO_THRESHOLD            1
-#define HASH_PAGES             1
-#define HASH_PAGES_ORDER       0
-#define NR_HASH                        (HASH_PAGES * PAGE_SIZE / sizeof(struct stripe_head *))
+#define NR_HASH                        (PAGE_SIZE / sizeof(struct hlist_head))
 #define HASH_MASK              (NR_HASH - 1)
 
-#define stripe_hash(conf, sect)        ((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK])
+#define stripe_hash(conf, sect)        (&((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK]))
 
 /* bio's attached to a stripe+device for I/O are linked together in bi_sector
  * order without overlap.  There may be several bio's per stripe+device, and
@@ -71,7 +69,7 @@
 
 static void print_raid5_conf (raid5_conf_t *conf);
 
-static inline void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
+static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
 {
        if (atomic_dec_and_test(&sh->count)) {
                if (!list_empty(&sh->lru))
@@ -113,29 +111,21 @@ static void release_stripe(struct stripe_head *sh)
        spin_unlock_irqrestore(&conf->device_lock, flags);
 }
 
-static void remove_hash(struct stripe_head *sh)
+static inline void remove_hash(struct stripe_head *sh)
 {
        PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector);
 
-       if (sh->hash_pprev) {
-               if (sh->hash_next)
-                       sh->hash_next->hash_pprev = sh->hash_pprev;
-               *sh->hash_pprev = sh->hash_next;
-               sh->hash_pprev = NULL;
-       }
+       hlist_del_init(&sh->hash);
 }
 
-static __inline__ void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
+static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
 {
-       struct stripe_head **shp = &stripe_hash(conf, sh->sector);
+       struct hlist_head *hp = stripe_hash(conf, sh->sector);
 
        PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector);
 
        CHECK_DEVLOCK();
-       if ((sh->hash_next = *shp) != NULL)
-               (*shp)->hash_pprev = &sh->hash_next;
-       *shp = sh;
-       sh->hash_pprev = shp;
+       hlist_add_head(&sh->hash, hp);
 }
 
 
@@ -167,7 +157,7 @@ static void shrink_buffers(struct stripe_head *sh, int num)
                if (!p)
                        continue;
                sh->dev[i].page = NULL;
-               page_cache_release(p);
+               put_page(p);
        }
 }
 
@@ -188,7 +178,7 @@ static int grow_buffers(struct stripe_head *sh, int num)
 
 static void raid5_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)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int disks = conf->raid_disks, i;
@@ -228,10 +218,11 @@ static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_i
 static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector)
 {
        struct stripe_head *sh;
+       struct hlist_node *hn;
 
        CHECK_DEVLOCK();
        PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
-       for (sh = stripe_hash(conf, sector); sh; sh = sh->hash_next)
+       hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash)
                if (sh->sector == sector)
                        return sh;
        PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
@@ -359,7 +350,8 @@ static void shrink_stripes(raid5_conf_t *conf)
        while (drop_one_stripe(conf))
                ;
 
-       kmem_cache_destroy(conf->slab_cache);
+       if (conf->slab_cache)
+               kmem_cache_destroy(conf->slab_cache);
        conf->slab_cache = NULL;
 }
 
@@ -961,11 +953,11 @@ static void handle_stripe(struct stripe_head *sh)
        syncing = test_bit(STRIPE_SYNCING, &sh->state);
        /* Now to look around and see what can be done */
 
+       rcu_read_lock();
        for (i=disks; i--; ) {
                mdk_rdev_t *rdev;
                dev = &sh->dev[i];
                clear_bit(R5_Insync, &dev->flags);
-               clear_bit(R5_Syncio, &dev->flags);
 
                PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
                        i, dev->flags, dev->toread, dev->towrite, dev->written);
@@ -1004,7 +996,7 @@ static void handle_stripe(struct stripe_head *sh)
                                non_overwrite++;
                }
                if (dev->written) written++;
-               rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
+               rdev = rcu_dereference(conf->disks[i].rdev);
                if (!rdev || !test_bit(In_sync, &rdev->flags)) {
                        /* The ReadError flag will just be confusing now */
                        clear_bit(R5_ReadError, &dev->flags);
@@ -1017,6 +1009,7 @@ static void handle_stripe(struct stripe_head *sh)
                } else
                        set_bit(R5_Insync, &dev->flags);
        }
+       rcu_read_unlock();
        PRINTK("locked=%d uptodate=%d to_read=%d"
                " to_write=%d failed=%d failed_num=%d\n",
                locked, uptodate, to_read, to_write, failed, failed_num);
@@ -1028,10 +1021,13 @@ static void handle_stripe(struct stripe_head *sh)
                        int bitmap_end = 0;
 
                        if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
-                               mdk_rdev_t *rdev = conf->disks[i].rdev;
+                               mdk_rdev_t *rdev;
+                               rcu_read_lock();
+                               rdev = rcu_dereference(conf->disks[i].rdev);
                                if (rdev && test_bit(In_sync, &rdev->flags))
                                        /* multiple read failures in one stripe */
                                        md_error(conf->mddev, rdev);
+                               rcu_read_unlock();
                        }
 
                        spin_lock_irq(&conf->device_lock);
@@ -1180,9 +1176,6 @@ static void handle_stripe(struct stripe_head *sh)
                                        locked++;
                                        PRINTK("Reading block %d (sync=%d)\n", 
                                                i, syncing);
-                                       if (syncing)
-                                               md_sync_acct(conf->disks[i].rdev->bdev,
-                                                            STRIPE_SECTORS);
                                }
                        }
                }
@@ -1326,7 +1319,6 @@ static void handle_stripe(struct stripe_head *sh)
                        clear_bit(STRIPE_DEGRADED, &sh->state);
                        locked++;
                        set_bit(STRIPE_INSYNC, &sh->state);
-                       set_bit(R5_Syncio, &dev->flags);
                }
        }
        if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
@@ -1392,7 +1384,7 @@ static void handle_stripe(struct stripe_head *sh)
                rcu_read_unlock();
  
                if (rdev) {
-                       if (test_bit(R5_Syncio, &sh->dev[i].flags))
+                       if (syncing)
                                md_sync_acct(rdev->bdev, STRIPE_SECTORS);
 
                        bi->bi_bdev = rdev->bdev;
@@ -1409,6 +1401,9 @@ static void handle_stripe(struct stripe_head *sh)
                        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)
@@ -1421,7 +1416,7 @@ static void handle_stripe(struct stripe_head *sh)
        }
 }
 
-static inline void raid5_activate_delayed(raid5_conf_t *conf)
+static void raid5_activate_delayed(raid5_conf_t *conf)
 {
        if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
                while (!list_empty(&conf->delayed_list)) {
@@ -1437,7 +1432,7 @@ static inline void raid5_activate_delayed(raid5_conf_t *conf)
        }
 }
 
-static inline void activate_bit_delay(raid5_conf_t *conf)
+static void activate_bit_delay(raid5_conf_t *conf)
 {
        /* device_lock is held */
        struct list_head head;
@@ -1827,17 +1822,16 @@ static int run(mddev_t *mddev)
                return -EIO;
        }
 
-       mddev->private = kmalloc (sizeof (raid5_conf_t)
-                                 + mddev->raid_disks * sizeof(struct disk_info),
-                                 GFP_KERNEL);
+       mddev->private = kzalloc(sizeof (raid5_conf_t)
+                                + mddev->raid_disks * sizeof(struct disk_info),
+                                GFP_KERNEL);
        if ((conf = mddev->private) == NULL)
                goto abort;
-       memset (conf, 0, sizeof (*conf) + mddev->raid_disks * sizeof(struct disk_info) );
+
        conf->mddev = mddev;
 
-       if ((conf->stripe_hashtbl = (struct stripe_head **) __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER)) == NULL)
+       if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
                goto abort;
-       memset(conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE);
 
        spin_lock_init(&conf->device_lock);
        init_waitqueue_head(&conf->wait_for_stripe);
@@ -1956,7 +1950,7 @@ static int run(mddev_t *mddev)
         */
        {
                int stripe = (mddev->raid_disks-1) * mddev->chunk_size
-                       / PAGE_CACHE_SIZE;
+                       / PAGE_SIZE;
                if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
                        mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
        }
@@ -1964,9 +1958,6 @@ static int run(mddev_t *mddev)
        /* Ok, everything is just fine now */
        sysfs_create_group(&mddev->kobj, &raid5_attrs_group);
 
-       if (mddev->bitmap)
-               mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
-
        mddev->queue->unplug_fn = raid5_unplug_device;
        mddev->queue->issue_flush_fn = raid5_issue_flush;
 
@@ -1975,9 +1966,7 @@ static int run(mddev_t *mddev)
 abort:
        if (conf) {
                print_raid5_conf(conf);
-               if (conf->stripe_hashtbl)
-                       free_pages((unsigned long) conf->stripe_hashtbl,
-                                                       HASH_PAGES_ORDER);
+               kfree(conf->stripe_hashtbl);
                kfree(conf);
        }
        mddev->private = NULL;
@@ -1994,7 +1983,7 @@ static int stop(mddev_t *mddev)
        md_unregister_thread(mddev->thread);
        mddev->thread = NULL;
        shrink_stripes(conf);
-       free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
+       kfree(conf->stripe_hashtbl);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
        kfree(conf);
@@ -2022,12 +2011,12 @@ static void print_sh (struct stripe_head *sh)
 static void printall (raid5_conf_t *conf)
 {
        struct stripe_head *sh;
+       struct hlist_node *hn;
        int i;
 
        spin_lock_irq(&conf->device_lock);
        for (i = 0; i < NR_HASH; i++) {
-               sh = conf->stripe_hashtbl[i];
-               for (; sh; sh = sh->hash_next) {
+               hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) {
                        if (sh->raid_conf != conf)
                                continue;
                        print_sh(sh);
@@ -2200,17 +2189,12 @@ static void raid5_quiesce(mddev_t *mddev, int state)
                spin_unlock_irq(&conf->device_lock);
                break;
        }
-       if (mddev->thread) {
-               if (mddev->bitmap)
-                       mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
-               else
-                       mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
-               md_wakeup_thread(mddev->thread);
-       }
 }
-static mdk_personality_t raid5_personality=
+
+static struct mdk_personality raid5_personality =
 {
        .name           = "raid5",
+       .level          = 5,
        .owner          = THIS_MODULE,
        .make_request   = make_request,
        .run            = run,
@@ -2225,17 +2209,42 @@ static mdk_personality_t raid5_personality=
        .quiesce        = raid5_quiesce,
 };
 
-static int __init raid5_init (void)
+static struct mdk_personality raid4_personality =
 {
-       return register_md_personality (RAID5, &raid5_personality);
+       .name           = "raid4",
+       .level          = 4,
+       .owner          = THIS_MODULE,
+       .make_request   = make_request,
+       .run            = run,
+       .stop           = stop,
+       .status         = status,
+       .error_handler  = error,
+       .hot_add_disk   = raid5_add_disk,
+       .hot_remove_disk= raid5_remove_disk,
+       .spare_active   = raid5_spare_active,
+       .sync_request   = sync_request,
+       .resize         = raid5_resize,
+       .quiesce        = raid5_quiesce,
+};
+
+static int __init raid5_init(void)
+{
+       register_md_personality(&raid5_personality);
+       register_md_personality(&raid4_personality);
+       return 0;
 }
 
-static void raid5_exit (void)
+static void raid5_exit(void)
 {
-       unregister_md_personality (RAID5);
+       unregister_md_personality(&raid5_personality);
+       unregister_md_personality(&raid4_personality);
 }
 
 module_init(raid5_init);
 module_exit(raid5_exit);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("md-personality-4"); /* RAID5 */
+MODULE_ALIAS("md-raid5");
+MODULE_ALIAS("md-raid4");
+MODULE_ALIAS("md-level-5");
+MODULE_ALIAS("md-level-4");