raid0.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.    raid0.c : Multiple Devices driver for Linux
  3.              Copyright (C) 1994-96 Marc ZYNGIER
  4.      <zyngier@ufr-info-p7.ibp.fr> or
  5.      <maz@gloups.fdn.fr>
  6.              Copyright (C) 1999, 2000 Ingo Molnar, Red Hat
  7.    RAID-0 management functions.
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2, or (at your option)
  11.    any later version.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    (for example /usr/src/linux/COPYING); if not, write to the Free
  15.    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
  16. */
  17. #include <linux/module.h>
  18. #include <linux/raid/raid0.h>
  19. #define MAJOR_NR MD_MAJOR
  20. #define MD_DRIVER
  21. #define MD_PERSONALITY
  22. static int create_strip_zones (mddev_t *mddev)
  23. {
  24. int i, c, j, j1, j2;
  25. unsigned long current_offset, curr_zone_offset;
  26. raid0_conf_t *conf = mddev_to_conf(mddev);
  27. mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev;
  28.  
  29. /*
  30.  * The number of 'same size groups'
  31.  */
  32. conf->nr_strip_zones = 0;
  33.  
  34. ITERATE_RDEV_ORDERED(mddev,rdev1,j1) {
  35. printk("raid0: looking at %sn", partition_name(rdev1->dev));
  36. c = 0;
  37. ITERATE_RDEV_ORDERED(mddev,rdev2,j2) {
  38. printk("raid0:   comparing %s(%ld) with %s(%ld)n", partition_name(rdev1->dev), rdev1->size, partition_name(rdev2->dev), rdev2->size);
  39. if (rdev2 == rdev1) {
  40. printk("raid0:   ENDn");
  41. break;
  42. }
  43. if (rdev2->size == rdev1->size)
  44. {
  45. /*
  46.  * Not unique, dont count it as a new
  47.  * group
  48.  */
  49. printk("raid0:   EQUALn");
  50. c = 1;
  51. break;
  52. }
  53. printk("raid0:   NOT EQUALn");
  54. }
  55. if (!c) {
  56. printk("raid0:   ==> UNIQUEn");
  57. conf->nr_strip_zones++;
  58. printk("raid0: %d zonesn", conf->nr_strip_zones);
  59. }
  60. }
  61. printk("raid0: FINAL %d zonesn", conf->nr_strip_zones);
  62. conf->strip_zone = vmalloc(sizeof(struct strip_zone)*
  63. conf->nr_strip_zones);
  64. if (!conf->strip_zone)
  65. return 1;
  66. conf->smallest = NULL;
  67. current_offset = 0;
  68. curr_zone_offset = 0;
  69. for (i = 0; i < conf->nr_strip_zones; i++)
  70. {
  71. struct strip_zone *zone = conf->strip_zone + i;
  72. printk("raid0: zone %dn", i);
  73. zone->dev_offset = current_offset;
  74. smallest = NULL;
  75. c = 0;
  76. ITERATE_RDEV_ORDERED(mddev,rdev,j) {
  77. printk("raid0: checking %s ...", partition_name(rdev->dev));
  78. if (rdev->size > current_offset)
  79. {
  80. printk(" contained as device %dn", c);
  81. zone->dev[c] = rdev;
  82. c++;
  83. if (!smallest || (rdev->size <smallest->size)) {
  84. smallest = rdev;
  85. printk("  (%ld) is smallest!.n", rdev->size);
  86. }
  87. } else
  88. printk(" nope.n");
  89. }
  90. zone->nb_dev = c;
  91. zone->size = (smallest->size - current_offset) * c;
  92. printk("raid0: zone->nb_dev: %d, size: %ldn",zone->nb_dev,zone->size);
  93. if (!conf->smallest || (zone->size < conf->smallest->size))
  94. conf->smallest = zone;
  95. zone->zone_offset = curr_zone_offset;
  96. curr_zone_offset += zone->size;
  97. current_offset = smallest->size;
  98. printk("raid0: current zone offset: %ldn", current_offset);
  99. }
  100. printk("raid0: done.n");
  101. return 0;
  102. }
  103. static int raid0_run (mddev_t *mddev)
  104. {
  105. unsigned long cur=0, i=0, size, zone0_size, nb_zone;
  106. raid0_conf_t *conf;
  107. MOD_INC_USE_COUNT;
  108. conf = vmalloc(sizeof (raid0_conf_t));
  109. if (!conf)
  110. goto out;
  111. mddev->private = (void *)conf;
  112.  
  113. if (md_check_ordering(mddev)) {
  114. printk("raid0: disks are not ordered, aborting!n");
  115. goto out_free_conf;
  116. }
  117. if (create_strip_zones (mddev)) 
  118. goto out_free_conf;
  119. printk("raid0 : md_size is %d blocks.n", md_size[mdidx(mddev)]);
  120. printk("raid0 : conf->smallest->size is %ld blocks.n", conf->smallest->size);
  121. nb_zone = md_size[mdidx(mddev)]/conf->smallest->size +
  122. (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0);
  123. printk("raid0 : nb_zone is %ld.n", nb_zone);
  124. conf->nr_zones = nb_zone;
  125. printk("raid0 : Allocating %ld bytes for hash.n",
  126. nb_zone*sizeof(struct raid0_hash));
  127. conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone);
  128. if (!conf->hash_table)
  129. goto out_free_zone_conf;
  130. size = conf->strip_zone[cur].size;
  131. i = 0;
  132. while (cur < conf->nr_strip_zones) {
  133. conf->hash_table[i].zone0 = conf->strip_zone + cur;
  134. /*
  135.  * If we completely fill the slot
  136.  */
  137. if (size >= conf->smallest->size) {
  138. conf->hash_table[i++].zone1 = NULL;
  139. size -= conf->smallest->size;
  140. if (!size) {
  141. if (++cur == conf->nr_strip_zones)
  142. continue;
  143. size = conf->strip_zone[cur].size;
  144. }
  145. continue;
  146. }
  147. if (++cur == conf->nr_strip_zones) {
  148. /*
  149.  * Last dev, set unit1 as NULL
  150.  */
  151. conf->hash_table[i].zone1=NULL;
  152. continue;
  153. }
  154. /*
  155.  * Here we use a 2nd dev to fill the slot
  156.  */
  157. zone0_size = size;
  158. size = conf->strip_zone[cur].size;
  159. conf->hash_table[i++].zone1 = conf->strip_zone + cur;
  160. size -= (conf->smallest->size - zone0_size);
  161. }
  162. return 0;
  163. out_free_zone_conf:
  164. vfree(conf->strip_zone);
  165. conf->strip_zone = NULL;
  166. out_free_conf:
  167. vfree(conf);
  168. mddev->private = NULL;
  169. out:
  170. MOD_DEC_USE_COUNT;
  171. return 1;
  172. }
  173. static int raid0_stop (mddev_t *mddev)
  174. {
  175. raid0_conf_t *conf = mddev_to_conf(mddev);
  176. vfree (conf->hash_table);
  177. conf->hash_table = NULL;
  178. vfree (conf->strip_zone);
  179. conf->strip_zone = NULL;
  180. vfree (conf);
  181. mddev->private = NULL;
  182. MOD_DEC_USE_COUNT;
  183. return 0;
  184. }
  185. /*
  186.  * FIXME - We assume some things here :
  187.  * - requested buffers NEVER bigger than chunk size,
  188.  * - requested buffers NEVER cross stripes limits.
  189.  * Of course, those facts may not be valid anymore (and surely won't...)
  190.  * Hey guys, there's some work out there ;-)
  191.  */
  192. static int raid0_make_request (mddev_t *mddev,
  193.        int rw, struct buffer_head * bh)
  194. {
  195. unsigned int sect_in_chunk, chunksize_bits,  chunk_size;
  196. raid0_conf_t *conf = mddev_to_conf(mddev);
  197. struct raid0_hash *hash;
  198. struct strip_zone *zone;
  199. mdk_rdev_t *tmp_dev;
  200. unsigned long chunk, block, rsect;
  201. chunk_size = mddev->param.chunk_size >> 10;
  202. chunksize_bits = ffz(~chunk_size);
  203. block = bh->b_rsector >> 1;
  204. hash = conf->hash_table + block / conf->smallest->size;
  205. /* Sanity check */
  206. if (chunk_size < (block % chunk_size) + (bh->b_size >> 10))
  207. goto bad_map;
  208.  
  209. if (!hash)
  210. goto bad_hash;
  211. if (!hash->zone0)
  212. goto bad_zone0;
  213.  
  214. if (block >= (hash->zone0->size + hash->zone0->zone_offset)) {
  215. if (!hash->zone1)
  216. goto bad_zone1;
  217. zone = hash->zone1;
  218. } else
  219. zone = hash->zone0;
  220.     
  221. sect_in_chunk = bh->b_rsector & ((chunk_size<<1) -1);
  222. chunk = (block - zone->zone_offset) / (zone->nb_dev << chunksize_bits);
  223. tmp_dev = zone->dev[(block >> chunksize_bits) % zone->nb_dev];
  224. rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1)
  225. + sect_in_chunk;
  226.  
  227. /*
  228.  * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
  229.  * is the only IO operation happening on this bh.
  230.  */
  231. bh->b_rdev = tmp_dev->dev;
  232. bh->b_rsector = rsect;
  233. /*
  234.  * Let the main block layer submit the IO and resolve recursion:
  235.  */
  236. return 1;
  237. bad_map:
  238. printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %dn", chunk_size, bh->b_rsector, bh->b_size >> 10);
  239. goto outerr;
  240. bad_hash:
  241. printk("raid0_make_request bug: hash==NULL for block %ldn", block);
  242. goto outerr;
  243. bad_zone0:
  244. printk ("raid0_make_request bug: hash->zone0==NULL for block %ldn", block);
  245. goto outerr;
  246. bad_zone1:
  247. printk ("raid0_make_request bug: hash->zone1==NULL for block %ldn", block);
  248.  outerr:
  249. buffer_IO_error(bh);
  250. return 0;
  251. }
  252.    
  253. static int raid0_status (char *page, mddev_t *mddev)
  254. {
  255. int sz = 0;
  256. #undef MD_DEBUG
  257. #ifdef MD_DEBUG
  258. int j, k;
  259. raid0_conf_t *conf = mddev_to_conf(mddev);
  260.   
  261. sz += sprintf(page + sz, "      ");
  262. for (j = 0; j < conf->nr_zones; j++) {
  263. sz += sprintf(page + sz, "[z%d",
  264. conf->hash_table[j].zone0 - conf->strip_zone);
  265. if (conf->hash_table[j].zone1)
  266. sz += sprintf(page+sz, "/z%d] ",
  267. conf->hash_table[j].zone1 - conf->strip_zone);
  268. else
  269. sz += sprintf(page+sz, "] ");
  270. }
  271.   
  272. sz += sprintf(page + sz, "n");
  273.   
  274. for (j = 0; j < conf->nr_strip_zones; j++) {
  275. sz += sprintf(page + sz, "      z%d=[", j);
  276. for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
  277. sz += sprintf (page+sz, "%s/", partition_name(
  278. conf->strip_zone[j].dev[k]->dev));
  279. sz--;
  280. sz += sprintf (page+sz, "] zo=%d do=%d s=%dn",
  281. conf->strip_zone[j].zone_offset,
  282. conf->strip_zone[j].dev_offset,
  283. conf->strip_zone[j].size);
  284. }
  285. #endif
  286. sz += sprintf(page + sz, " %dk chunks", mddev->param.chunk_size/1024);
  287. return sz;
  288. }
  289. static mdk_personality_t raid0_personality=
  290. {
  291. name: "raid0",
  292. make_request: raid0_make_request,
  293. run: raid0_run,
  294. stop: raid0_stop,
  295. status: raid0_status,
  296. };
  297. static int md__init raid0_init (void)
  298. {
  299. return register_md_personality (RAID0, &raid0_personality);
  300. }
  301. static void raid0_exit (void)
  302. {
  303. unregister_md_personality (RAID0);
  304. }
  305. module_init(raid0_init);
  306. module_exit(raid0_exit);
  307. MODULE_LICENSE("GPL");