diff options
Diffstat (limited to 'drivers/md/md.c')
| -rw-r--r-- | drivers/md/md.c | 160 |
1 files changed, 122 insertions, 38 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 2b4315d7e5d6..65814b0340cb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | */ | 33 | */ |
| 34 | 34 | ||
| 35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
| 36 | #include <linux/kernel.h> | ||
| 36 | #include <linux/kthread.h> | 37 | #include <linux/kthread.h> |
| 37 | #include <linux/linkage.h> | 38 | #include <linux/linkage.h> |
| 38 | #include <linux/raid/md.h> | 39 | #include <linux/raid/md.h> |
| @@ -273,6 +274,7 @@ static mddev_t * mddev_find(dev_t unit) | |||
| 273 | atomic_set(&new->active, 1); | 274 | atomic_set(&new->active, 1); |
| 274 | spin_lock_init(&new->write_lock); | 275 | spin_lock_init(&new->write_lock); |
| 275 | init_waitqueue_head(&new->sb_wait); | 276 | init_waitqueue_head(&new->sb_wait); |
| 277 | new->reshape_position = MaxSector; | ||
| 276 | 278 | ||
| 277 | new->queue = blk_alloc_queue(GFP_KERNEL); | 279 | new->queue = blk_alloc_queue(GFP_KERNEL); |
| 278 | if (!new->queue) { | 280 | if (!new->queue) { |
| @@ -589,14 +591,41 @@ abort: | |||
| 589 | return ret; | 591 | return ret; |
| 590 | } | 592 | } |
| 591 | 593 | ||
| 594 | |||
| 595 | static u32 md_csum_fold(u32 csum) | ||
| 596 | { | ||
| 597 | csum = (csum & 0xffff) + (csum >> 16); | ||
| 598 | return (csum & 0xffff) + (csum >> 16); | ||
| 599 | } | ||
| 600 | |||
| 592 | static unsigned int calc_sb_csum(mdp_super_t * sb) | 601 | static unsigned int calc_sb_csum(mdp_super_t * sb) |
| 593 | { | 602 | { |
| 603 | u64 newcsum = 0; | ||
| 604 | u32 *sb32 = (u32*)sb; | ||
| 605 | int i; | ||
| 594 | unsigned int disk_csum, csum; | 606 | unsigned int disk_csum, csum; |
| 595 | 607 | ||
| 596 | disk_csum = sb->sb_csum; | 608 | disk_csum = sb->sb_csum; |
| 597 | sb->sb_csum = 0; | 609 | sb->sb_csum = 0; |
| 598 | csum = csum_partial((void *)sb, MD_SB_BYTES, 0); | 610 | |
| 611 | for (i = 0; i < MD_SB_BYTES/4 ; i++) | ||
| 612 | newcsum += sb32[i]; | ||
| 613 | csum = (newcsum & 0xffffffff) + (newcsum>>32); | ||
| 614 | |||
| 615 | |||
| 616 | #ifdef CONFIG_ALPHA | ||
| 617 | /* This used to use csum_partial, which was wrong for several | ||
| 618 | * reasons including that different results are returned on | ||
| 619 | * different architectures. It isn't critical that we get exactly | ||
| 620 | * the same return value as before (we always csum_fold before | ||
| 621 | * testing, and that removes any differences). However as we | ||
| 622 | * know that csum_partial always returned a 16bit value on | ||
| 623 | * alphas, do a fold to maximise conformity to previous behaviour. | ||
| 624 | */ | ||
| 625 | sb->sb_csum = md_csum_fold(disk_csum); | ||
| 626 | #else | ||
| 599 | sb->sb_csum = disk_csum; | 627 | sb->sb_csum = disk_csum; |
| 628 | #endif | ||
| 600 | return csum; | 629 | return csum; |
| 601 | } | 630 | } |
| 602 | 631 | ||
| @@ -684,7 +713,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version | |||
| 684 | if (sb->raid_disks <= 0) | 713 | if (sb->raid_disks <= 0) |
| 685 | goto abort; | 714 | goto abort; |
| 686 | 715 | ||
| 687 | if (csum_fold(calc_sb_csum(sb)) != csum_fold(sb->sb_csum)) { | 716 | if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) { |
| 688 | printk(KERN_WARNING "md: invalid superblock checksum on %s\n", | 717 | printk(KERN_WARNING "md: invalid superblock checksum on %s\n", |
| 689 | b); | 718 | b); |
| 690 | goto abort; | 719 | goto abort; |
| @@ -694,6 +723,17 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version | |||
| 694 | rdev->data_offset = 0; | 723 | rdev->data_offset = 0; |
| 695 | rdev->sb_size = MD_SB_BYTES; | 724 | rdev->sb_size = MD_SB_BYTES; |
| 696 | 725 | ||
| 726 | if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) { | ||
| 727 | if (sb->level != 1 && sb->level != 4 | ||
| 728 | && sb->level != 5 && sb->level != 6 | ||
| 729 | && sb->level != 10) { | ||
| 730 | /* FIXME use a better test */ | ||
| 731 | printk(KERN_WARNING | ||
| 732 | "md: bitmaps not supported for this level.\n"); | ||
| 733 | goto abort; | ||
| 734 | } | ||
| 735 | } | ||
| 736 | |||
| 697 | if (sb->level == LEVEL_MULTIPATH) | 737 | if (sb->level == LEVEL_MULTIPATH) |
| 698 | rdev->desc_nr = -1; | 738 | rdev->desc_nr = -1; |
| 699 | else | 739 | else |
| @@ -792,16 +832,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 792 | mddev->max_disks = MD_SB_DISKS; | 832 | mddev->max_disks = MD_SB_DISKS; |
| 793 | 833 | ||
| 794 | if (sb->state & (1<<MD_SB_BITMAP_PRESENT) && | 834 | if (sb->state & (1<<MD_SB_BITMAP_PRESENT) && |
| 795 | mddev->bitmap_file == NULL) { | 835 | mddev->bitmap_file == NULL) |
| 796 | if (mddev->level != 1 && mddev->level != 4 | ||
| 797 | && mddev->level != 5 && mddev->level != 6 | ||
| 798 | && mddev->level != 10) { | ||
| 799 | /* FIXME use a better test */ | ||
| 800 | printk(KERN_WARNING "md: bitmaps not supported for this level.\n"); | ||
| 801 | return -EINVAL; | ||
| 802 | } | ||
| 803 | mddev->bitmap_offset = mddev->default_bitmap_offset; | 836 | mddev->bitmap_offset = mddev->default_bitmap_offset; |
| 804 | } | ||
| 805 | 837 | ||
| 806 | } else if (mddev->pers == NULL) { | 838 | } else if (mddev->pers == NULL) { |
| 807 | /* Insist on good event counter while assembling */ | 839 | /* Insist on good event counter while assembling */ |
| @@ -1058,6 +1090,18 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) | |||
| 1058 | bdevname(rdev->bdev,b)); | 1090 | bdevname(rdev->bdev,b)); |
| 1059 | return -EINVAL; | 1091 | return -EINVAL; |
| 1060 | } | 1092 | } |
| 1093 | if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) { | ||
| 1094 | if (sb->level != cpu_to_le32(1) && | ||
| 1095 | sb->level != cpu_to_le32(4) && | ||
| 1096 | sb->level != cpu_to_le32(5) && | ||
| 1097 | sb->level != cpu_to_le32(6) && | ||
| 1098 | sb->level != cpu_to_le32(10)) { | ||
| 1099 | printk(KERN_WARNING | ||
| 1100 | "md: bitmaps not supported for this level.\n"); | ||
| 1101 | return -EINVAL; | ||
| 1102 | } | ||
| 1103 | } | ||
| 1104 | |||
| 1061 | rdev->preferred_minor = 0xffff; | 1105 | rdev->preferred_minor = 0xffff; |
| 1062 | rdev->data_offset = le64_to_cpu(sb->data_offset); | 1106 | rdev->data_offset = le64_to_cpu(sb->data_offset); |
| 1063 | atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); | 1107 | atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read)); |
| @@ -1141,14 +1185,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 1141 | mddev->max_disks = (4096-256)/2; | 1185 | mddev->max_disks = (4096-256)/2; |
| 1142 | 1186 | ||
| 1143 | if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) && | 1187 | if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) && |
| 1144 | mddev->bitmap_file == NULL ) { | 1188 | mddev->bitmap_file == NULL ) |
| 1145 | if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6 | ||
| 1146 | && mddev->level != 10) { | ||
| 1147 | printk(KERN_WARNING "md: bitmaps not supported for this level.\n"); | ||
| 1148 | return -EINVAL; | ||
| 1149 | } | ||
| 1150 | mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset); | 1189 | mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset); |
| 1151 | } | 1190 | |
| 1152 | if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) { | 1191 | if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) { |
| 1153 | mddev->reshape_position = le64_to_cpu(sb->reshape_position); | 1192 | mddev->reshape_position = le64_to_cpu(sb->reshape_position); |
| 1154 | mddev->delta_disks = le32_to_cpu(sb->delta_disks); | 1193 | mddev->delta_disks = le32_to_cpu(sb->delta_disks); |
| @@ -2204,6 +2243,10 @@ static ssize_t | |||
| 2204 | layout_show(mddev_t *mddev, char *page) | 2243 | layout_show(mddev_t *mddev, char *page) |
| 2205 | { | 2244 | { |
| 2206 | /* just a number, not meaningful for all levels */ | 2245 | /* just a number, not meaningful for all levels */ |
| 2246 | if (mddev->reshape_position != MaxSector && | ||
| 2247 | mddev->layout != mddev->new_layout) | ||
| 2248 | return sprintf(page, "%d (%d)\n", | ||
| 2249 | mddev->new_layout, mddev->layout); | ||
| 2207 | return sprintf(page, "%d\n", mddev->layout); | 2250 | return sprintf(page, "%d\n", mddev->layout); |
| 2208 | } | 2251 | } |
| 2209 | 2252 | ||
| @@ -2212,13 +2255,16 @@ layout_store(mddev_t *mddev, const char *buf, size_t len) | |||
| 2212 | { | 2255 | { |
| 2213 | char *e; | 2256 | char *e; |
| 2214 | unsigned long n = simple_strtoul(buf, &e, 10); | 2257 | unsigned long n = simple_strtoul(buf, &e, 10); |
| 2215 | if (mddev->pers) | ||
| 2216 | return -EBUSY; | ||
| 2217 | 2258 | ||
| 2218 | if (!*buf || (*e && *e != '\n')) | 2259 | if (!*buf || (*e && *e != '\n')) |
| 2219 | return -EINVAL; | 2260 | return -EINVAL; |
| 2220 | 2261 | ||
| 2221 | mddev->layout = n; | 2262 | if (mddev->pers) |
| 2263 | return -EBUSY; | ||
| 2264 | if (mddev->reshape_position != MaxSector) | ||
| 2265 | mddev->new_layout = n; | ||
| 2266 | else | ||
| 2267 | mddev->layout = n; | ||
| 2222 | return len; | 2268 | return len; |
| 2223 | } | 2269 | } |
| 2224 | static struct md_sysfs_entry md_layout = | 2270 | static struct md_sysfs_entry md_layout = |
| @@ -2230,6 +2276,10 @@ raid_disks_show(mddev_t *mddev, char *page) | |||
| 2230 | { | 2276 | { |
| 2231 | if (mddev->raid_disks == 0) | 2277 | if (mddev->raid_disks == 0) |
| 2232 | return 0; | 2278 | return 0; |
| 2279 | if (mddev->reshape_position != MaxSector && | ||
| 2280 | mddev->delta_disks != 0) | ||
| 2281 | return sprintf(page, "%d (%d)\n", mddev->raid_disks, | ||
| 2282 | mddev->raid_disks - mddev->delta_disks); | ||
| 2233 | return sprintf(page, "%d\n", mddev->raid_disks); | 2283 | return sprintf(page, "%d\n", mddev->raid_disks); |
| 2234 | } | 2284 | } |
| 2235 | 2285 | ||
| @@ -2247,7 +2297,11 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len) | |||
| 2247 | 2297 | ||
| 2248 | if (mddev->pers) | 2298 | if (mddev->pers) |
| 2249 | rv = update_raid_disks(mddev, n); | 2299 | rv = update_raid_disks(mddev, n); |
| 2250 | else | 2300 | else if (mddev->reshape_position != MaxSector) { |
| 2301 | int olddisks = mddev->raid_disks - mddev->delta_disks; | ||
| 2302 | mddev->delta_disks = n - olddisks; | ||
| 2303 | mddev->raid_disks = n; | ||
| 2304 | } else | ||
| 2251 | mddev->raid_disks = n; | 2305 | mddev->raid_disks = n; |
| 2252 | return rv ? rv : len; | 2306 | return rv ? rv : len; |
| 2253 | } | 2307 | } |
| @@ -2257,6 +2311,10 @@ __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store); | |||
| 2257 | static ssize_t | 2311 | static ssize_t |
| 2258 | chunk_size_show(mddev_t *mddev, char *page) | 2312 | chunk_size_show(mddev_t *mddev, char *page) |
| 2259 | { | 2313 | { |
| 2314 | if (mddev->reshape_position != MaxSector && | ||
| 2315 | mddev->chunk_size != mddev->new_chunk) | ||
| 2316 | return sprintf(page, "%d (%d)\n", mddev->new_chunk, | ||
| 2317 | mddev->chunk_size); | ||
| 2260 | return sprintf(page, "%d\n", mddev->chunk_size); | 2318 | return sprintf(page, "%d\n", mddev->chunk_size); |
| 2261 | } | 2319 | } |
| 2262 | 2320 | ||
| @@ -2267,12 +2325,15 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len) | |||
| 2267 | char *e; | 2325 | char *e; |
| 2268 | unsigned long n = simple_strtoul(buf, &e, 10); | 2326 | unsigned long n = simple_strtoul(buf, &e, 10); |
| 2269 | 2327 | ||
| 2270 | if (mddev->pers) | ||
| 2271 | return -EBUSY; | ||
| 2272 | if (!*buf || (*e && *e != '\n')) | 2328 | if (!*buf || (*e && *e != '\n')) |
| 2273 | return -EINVAL; | 2329 | return -EINVAL; |
| 2274 | 2330 | ||
| 2275 | mddev->chunk_size = n; | 2331 | if (mddev->pers) |
| 2332 | return -EBUSY; | ||
| 2333 | else if (mddev->reshape_position != MaxSector) | ||
| 2334 | mddev->new_chunk = n; | ||
| 2335 | else | ||
| 2336 | mddev->chunk_size = n; | ||
| 2276 | return len; | 2337 | return len; |
| 2277 | } | 2338 | } |
| 2278 | static struct md_sysfs_entry md_chunk_size = | 2339 | static struct md_sysfs_entry md_chunk_size = |
| @@ -2637,8 +2698,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len) | |||
| 2637 | minor = simple_strtoul(buf, &e, 10); | 2698 | minor = simple_strtoul(buf, &e, 10); |
| 2638 | if (e==buf || (*e && *e != '\n') ) | 2699 | if (e==buf || (*e && *e != '\n') ) |
| 2639 | return -EINVAL; | 2700 | return -EINVAL; |
| 2640 | if (major >= sizeof(super_types)/sizeof(super_types[0]) || | 2701 | if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL) |
| 2641 | super_types[major].name == NULL) | ||
| 2642 | return -ENOENT; | 2702 | return -ENOENT; |
| 2643 | mddev->major_version = major; | 2703 | mddev->major_version = major; |
| 2644 | mddev->minor_version = minor; | 2704 | mddev->minor_version = minor; |
| @@ -2859,6 +2919,37 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len) | |||
| 2859 | static struct md_sysfs_entry md_suspend_hi = | 2919 | static struct md_sysfs_entry md_suspend_hi = |
| 2860 | __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); | 2920 | __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); |
| 2861 | 2921 | ||
| 2922 | static ssize_t | ||
| 2923 | reshape_position_show(mddev_t *mddev, char *page) | ||
| 2924 | { | ||
| 2925 | if (mddev->reshape_position != MaxSector) | ||
| 2926 | return sprintf(page, "%llu\n", | ||
| 2927 | (unsigned long long)mddev->reshape_position); | ||
| 2928 | strcpy(page, "none\n"); | ||
| 2929 | return 5; | ||
| 2930 | } | ||
| 2931 | |||
| 2932 | static ssize_t | ||
| 2933 | reshape_position_store(mddev_t *mddev, const char *buf, size_t len) | ||
| 2934 | { | ||
| 2935 | char *e; | ||
| 2936 | unsigned long long new = simple_strtoull(buf, &e, 10); | ||
| 2937 | if (mddev->pers) | ||
| 2938 | return -EBUSY; | ||
| 2939 | if (buf == e || (*e && *e != '\n')) | ||
| 2940 | return -EINVAL; | ||
| 2941 | mddev->reshape_position = new; | ||
| 2942 | mddev->delta_disks = 0; | ||
| 2943 | mddev->new_level = mddev->level; | ||
| 2944 | mddev->new_layout = mddev->layout; | ||
| 2945 | mddev->new_chunk = mddev->chunk_size; | ||
| 2946 | return len; | ||
| 2947 | } | ||
| 2948 | |||
| 2949 | static struct md_sysfs_entry md_reshape_position = | ||
| 2950 | __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show, | ||
| 2951 | reshape_position_store); | ||
| 2952 | |||
| 2862 | 2953 | ||
| 2863 | static struct attribute *md_default_attrs[] = { | 2954 | static struct attribute *md_default_attrs[] = { |
| 2864 | &md_level.attr, | 2955 | &md_level.attr, |
| @@ -2871,6 +2962,7 @@ static struct attribute *md_default_attrs[] = { | |||
| 2871 | &md_new_device.attr, | 2962 | &md_new_device.attr, |
| 2872 | &md_safe_delay.attr, | 2963 | &md_safe_delay.attr, |
| 2873 | &md_array_state.attr, | 2964 | &md_array_state.attr, |
| 2965 | &md_reshape_position.attr, | ||
| 2874 | NULL, | 2966 | NULL, |
| 2875 | }; | 2967 | }; |
| 2876 | 2968 | ||
| @@ -3409,6 +3501,7 @@ static int do_md_stop(mddev_t * mddev, int mode) | |||
| 3409 | mddev->size = 0; | 3501 | mddev->size = 0; |
| 3410 | mddev->raid_disks = 0; | 3502 | mddev->raid_disks = 0; |
| 3411 | mddev->recovery_cp = 0; | 3503 | mddev->recovery_cp = 0; |
| 3504 | mddev->reshape_position = MaxSector; | ||
| 3412 | 3505 | ||
| 3413 | } else if (mddev->pers) | 3506 | } else if (mddev->pers) |
| 3414 | printk(KERN_INFO "md: %s switched to read-only mode.\n", | 3507 | printk(KERN_INFO "md: %s switched to read-only mode.\n", |
| @@ -4019,7 +4112,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) | |||
| 4019 | if (info->raid_disks == 0) { | 4112 | if (info->raid_disks == 0) { |
| 4020 | /* just setting version number for superblock loading */ | 4113 | /* just setting version number for superblock loading */ |
| 4021 | if (info->major_version < 0 || | 4114 | if (info->major_version < 0 || |
| 4022 | info->major_version >= sizeof(super_types)/sizeof(super_types[0]) || | 4115 | info->major_version >= ARRAY_SIZE(super_types) || |
| 4023 | super_types[info->major_version].name == NULL) { | 4116 | super_types[info->major_version].name == NULL) { |
| 4024 | /* maybe try to auto-load a module? */ | 4117 | /* maybe try to auto-load a module? */ |
| 4025 | printk(KERN_INFO | 4118 | printk(KERN_INFO |
| @@ -4941,15 +5034,6 @@ static int md_seq_open(struct inode *inode, struct file *file) | |||
| 4941 | return error; | 5034 | return error; |
| 4942 | } | 5035 | } |
| 4943 | 5036 | ||
| 4944 | static int md_seq_release(struct inode *inode, struct file *file) | ||
| 4945 | { | ||
| 4946 | struct seq_file *m = file->private_data; | ||
| 4947 | struct mdstat_info *mi = m->private; | ||
| 4948 | m->private = NULL; | ||
| 4949 | kfree(mi); | ||
| 4950 | return seq_release(inode, file); | ||
| 4951 | } | ||
| 4952 | |||
| 4953 | static unsigned int mdstat_poll(struct file *filp, poll_table *wait) | 5037 | static unsigned int mdstat_poll(struct file *filp, poll_table *wait) |
| 4954 | { | 5038 | { |
| 4955 | struct seq_file *m = filp->private_data; | 5039 | struct seq_file *m = filp->private_data; |
| @@ -4971,7 +5055,7 @@ static const struct file_operations md_seq_fops = { | |||
| 4971 | .open = md_seq_open, | 5055 | .open = md_seq_open, |
| 4972 | .read = seq_read, | 5056 | .read = seq_read, |
| 4973 | .llseek = seq_lseek, | 5057 | .llseek = seq_lseek, |
| 4974 | .release = md_seq_release, | 5058 | .release = seq_release_private, |
| 4975 | .poll = mdstat_poll, | 5059 | .poll = mdstat_poll, |
| 4976 | }; | 5060 | }; |
| 4977 | 5061 | ||
