vserver 1.9.5.x5
[linux-2.6.git] / drivers / md / linear.c
index 0f57e5e..161e9aa 100644 (file)
@@ -31,7 +31,7 @@
  */
 static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector)
 {
-       struct linear_hash *hash;
+       dev_info_t *hash;
        linear_conf_t *conf = mddev_to_conf(mddev);
        sector_t block = sector >> 1;
 
@@ -39,12 +39,11 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector)
         * sector_div(a,b) returns the remainer and sets a to a/b
         */
        (void)sector_div(block, conf->smallest->size);
-       hash = conf->hash_table + block;
+       hash = conf->hash_table[block];
 
-       if ((sector>>1) >= (hash->dev0->size + hash->dev0->offset))
-               return hash->dev1;
-       else
-               return hash->dev0;
+       while ((sector>>1) >= (hash->size + hash->offset))
+               hash++;
+       return hash;
 }
 
 /**
@@ -99,17 +98,14 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
        linear_conf_t *conf = mddev_to_conf(mddev);
        int i, ret = 0;
 
-       for (i=0; i < mddev->raid_disks; i++) {
+       for (i=0; i < mddev->raid_disks && ret == 0; i++) {
                struct block_device *bdev = conf->disks[i].rdev->bdev;
                request_queue_t *r_queue = bdev_get_queue(bdev);
 
-               if (!r_queue->issue_flush_fn) {
+               if (!r_queue->issue_flush_fn)
                        ret = -EOPNOTSUPP;
-                       break;
-               }
-               ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
-               if (ret)
-                       break;
+               else
+                       ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
        }
        return ret;
 }
@@ -117,10 +113,11 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
 static int linear_run (mddev_t *mddev)
 {
        linear_conf_t *conf;
-       struct linear_hash *table;
+       dev_info_t **table;
        mdk_rdev_t *rdev;
-       int size, i, nb_zone, cnt;
-       unsigned int curr_offset;
+       int i, nb_zone, cnt;
+       sector_t start;
+       sector_t curr_offset;
        struct list_head *tmp;
 
        conf = kmalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t),
@@ -186,7 +183,7 @@ static int linear_run (mddev_t *mddev)
                nb_zone = conf->nr_zones = sz + (round ? 1 : 0);
        }
                        
-       conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone,
+       conf->hash_table = kmalloc (sizeof (dev_info_t*) * nb_zone,
                                        GFP_KERNEL);
        if (!conf->hash_table)
                goto out;
@@ -195,7 +192,7 @@ static int linear_run (mddev_t *mddev)
         * Here we generate the linear hash table
         */
        table = conf->hash_table;
-       size = 0;
+       start = 0;
        curr_offset = 0;
        for (i = 0; i < cnt; i++) {
                dev_info_t *disk = conf->disks + i;
@@ -203,16 +200,12 @@ static int linear_run (mddev_t *mddev)
                disk->offset = curr_offset;
                curr_offset += disk->size;
 
-               if (size < 0) {
-                       table[-1].dev1 = disk;
-               }
-               size += disk->size;
-
-               while (size>0) {
-                       table->dev0 = disk;
-                       table->dev1 = NULL;
-                       size -= conf->smallest->size;
-                       table++;
+               /* 'curr_offset' is the end of this disk
+                * 'start' is the start of table
+                */
+               while (start < curr_offset) {
+                       *table++ = disk;
+                       start += conf->smallest->size;
                }
        }
        if (table-conf->hash_table != nb_zone)
@@ -233,6 +226,7 @@ static int linear_stop (mddev_t *mddev)
 {
        linear_conf_t *conf = mddev_to_conf(mddev);
   
+       blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        kfree(conf->hash_table);
        kfree(conf);
 
@@ -255,23 +249,17 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
 
        tmp_dev = which_dev(mddev, bio->bi_sector);
        block = bio->bi_sector >> 1;
-  
-       if (unlikely(!tmp_dev)) {
-               printk("linear_make_request: hash->dev1==NULL for block %llu\n",
-                       (unsigned long long)block);
-               bio_io_error(bio, bio->bi_size);
-               return 0;
-       }
     
        if (unlikely(block >= (tmp_dev->size + tmp_dev->offset)
                     || block < tmp_dev->offset)) {
                char b[BDEVNAME_SIZE];
 
                printk("linear_make_request: Block %llu out of bounds on "
-                       "dev %s size %ld offset %ld\n",
+                       "dev %s size %llu offset %llu\n",
                        (unsigned long long)block,
                        bdevname(tmp_dev->rdev->bdev, b),
-                       tmp_dev->size, tmp_dev->offset);
+                       (unsigned long long)tmp_dev->size,
+                       (unsigned long long)tmp_dev->offset);
                bio_io_error(bio, bio->bi_size);
                return 0;
        }
@@ -305,17 +293,20 @@ static void linear_status (struct seq_file *seq, mddev_t *mddev)
 #ifdef MD_DEBUG
        int j;
        linear_conf_t *conf = mddev_to_conf(mddev);
+       sector_t s = 0;
   
        seq_printf(seq, "      ");
        for (j = 0; j < conf->nr_zones; j++)
        {
                char b[BDEVNAME_SIZE];
+               s += conf->smallest_size;
                seq_printf(seq, "[%s",
-                          bdevname(conf->hash_table[j].dev0->rdev->bdev,b));
+                          bdevname(conf->hash_table[j][0].rdev->bdev,b));
 
-               if (conf->hash_table[j].dev1)
+               while (s > conf->hash_table[j][0].offset +
+                          conf->hash_table[j][0].size)
                        seq_printf(seq, "/%s] ",
-                                  bdevname(conf->hash_table[j].dev1->rdev->bdev,b));
+                                  bdevname(conf->hash_table[j][1].rdev->bdev,b));
                else
                        seq_printf(seq, "] ");
        }