Commit 5c85121b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'md/3.14' of git://neil.brown.name/md

Pull md updates from Neil Brown:
 "All bug fixes, two tagged for -stable"

* tag 'md/3.14' of git://neil.brown.name/md:
  md/raid5: close recently introduced race in stripe_head management.
  md/raid5: fix long-standing problem with bitmap handling on write failure.
  md: check command validity early in md_ioctl().
  md: ensure metadata is writen after raid level change.
  md/raid10: avoid fullsync when not necessary.
  md: allow a partially recovered device to be hot-added to an array.
  md: Change handling of save_raid_disk and metadata update during recovery.
parents 4d8880a0 7da9d450
...@@ -1173,6 +1173,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1173,6 +1173,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
desc->raid_disk < mddev->raid_disks */) { desc->raid_disk < mddev->raid_disks */) {
set_bit(In_sync, &rdev->flags); set_bit(In_sync, &rdev->flags);
rdev->raid_disk = desc->raid_disk; rdev->raid_disk = desc->raid_disk;
rdev->saved_raid_disk = desc->raid_disk;
} else if (desc->state & (1<<MD_DISK_ACTIVE)) { } else if (desc->state & (1<<MD_DISK_ACTIVE)) {
/* active but not in sync implies recovery up to /* active but not in sync implies recovery up to
* reshape position. We don't know exactly where * reshape position. We don't know exactly where
...@@ -1671,10 +1672,14 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1671,10 +1672,14 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
set_bit(Faulty, &rdev->flags); set_bit(Faulty, &rdev->flags);
break; break;
default: default:
rdev->saved_raid_disk = role;
if ((le32_to_cpu(sb->feature_map) & if ((le32_to_cpu(sb->feature_map) &
MD_FEATURE_RECOVERY_OFFSET)) MD_FEATURE_RECOVERY_OFFSET)) {
rdev->recovery_offset = le64_to_cpu(sb->recovery_offset); rdev->recovery_offset = le64_to_cpu(sb->recovery_offset);
else if (!(le32_to_cpu(sb->feature_map) &
MD_FEATURE_RECOVERY_BITMAP))
rdev->saved_raid_disk = -1;
} else
set_bit(In_sync, &rdev->flags); set_bit(In_sync, &rdev->flags);
rdev->raid_disk = role; rdev->raid_disk = role;
break; break;
...@@ -1736,6 +1741,9 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1736,6 +1741,9 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET); cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
sb->recovery_offset = sb->recovery_offset =
cpu_to_le64(rdev->recovery_offset); cpu_to_le64(rdev->recovery_offset);
if (rdev->saved_raid_disk >= 0 && mddev->bitmap)
sb->feature_map |=
cpu_to_le32(MD_FEATURE_RECOVERY_BITMAP);
} }
if (test_bit(Replacement, &rdev->flags)) if (test_bit(Replacement, &rdev->flags))
sb->feature_map |= sb->feature_map |=
...@@ -2477,8 +2485,7 @@ static void md_update_sb(struct mddev * mddev, int force_change) ...@@ -2477,8 +2485,7 @@ static void md_update_sb(struct mddev * mddev, int force_change)
if (rdev->sb_loaded != 1) if (rdev->sb_loaded != 1)
continue; /* no noise on spare devices */ continue; /* no noise on spare devices */
if (!test_bit(Faulty, &rdev->flags) && if (!test_bit(Faulty, &rdev->flags)) {
rdev->saved_raid_disk == -1) {
md_super_write(mddev,rdev, md_super_write(mddev,rdev,
rdev->sb_start, rdev->sb_size, rdev->sb_start, rdev->sb_size,
rdev->sb_page); rdev->sb_page);
...@@ -2494,11 +2501,9 @@ static void md_update_sb(struct mddev * mddev, int force_change) ...@@ -2494,11 +2501,9 @@ static void md_update_sb(struct mddev * mddev, int force_change)
rdev->badblocks.size = 0; rdev->badblocks.size = 0;
} }
} else if (test_bit(Faulty, &rdev->flags)) } else
pr_debug("md: %s (skipping faulty)\n", pr_debug("md: %s (skipping faulty)\n",
bdevname(rdev->bdev, b)); bdevname(rdev->bdev, b));
else
pr_debug("(skipping incremental s/r ");
if (mddev->level == LEVEL_MULTIPATH) if (mddev->level == LEVEL_MULTIPATH)
/* only need to write one superblock... */ /* only need to write one superblock... */
...@@ -2614,6 +2619,8 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) ...@@ -2614,6 +2619,8 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
* blocked - sets the Blocked flags * blocked - sets the Blocked flags
* -blocked - clears the Blocked and possibly simulates an error * -blocked - clears the Blocked and possibly simulates an error
* insync - sets Insync providing device isn't active * insync - sets Insync providing device isn't active
* -insync - clear Insync for a device with a slot assigned,
* so that it gets rebuilt based on bitmap
* write_error - sets WriteErrorSeen * write_error - sets WriteErrorSeen
* -write_error - clears WriteErrorSeen * -write_error - clears WriteErrorSeen
*/ */
...@@ -2662,6 +2669,11 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) ...@@ -2662,6 +2669,11 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
} else if (cmd_match(buf, "insync") && rdev->raid_disk == -1) { } else if (cmd_match(buf, "insync") && rdev->raid_disk == -1) {
set_bit(In_sync, &rdev->flags); set_bit(In_sync, &rdev->flags);
err = 0; err = 0;
} else if (cmd_match(buf, "-insync") && rdev->raid_disk >= 0) {
clear_bit(In_sync, &rdev->flags);
rdev->saved_raid_disk = rdev->raid_disk;
rdev->raid_disk = -1;
err = 0;
} else if (cmd_match(buf, "write_error")) { } else if (cmd_match(buf, "write_error")) {
set_bit(WriteErrorSeen, &rdev->flags); set_bit(WriteErrorSeen, &rdev->flags);
err = 0; err = 0;
...@@ -3589,6 +3601,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -3589,6 +3601,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
pers->run(mddev); pers->run(mddev);
set_bit(MD_CHANGE_DEVS, &mddev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags);
mddev_resume(mddev); mddev_resume(mddev);
if (!mddev->thread)
md_update_sb(mddev, 1);
sysfs_notify(&mddev->kobj, NULL, "level"); sysfs_notify(&mddev->kobj, NULL, "level");
md_new_event(mddev); md_new_event(mddev);
return rv; return rv;
...@@ -5770,6 +5784,7 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info) ...@@ -5770,6 +5784,7 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
clear_bit(Bitmap_sync, &rdev->flags); clear_bit(Bitmap_sync, &rdev->flags);
} else } else
rdev->raid_disk = -1; rdev->raid_disk = -1;
rdev->saved_raid_disk = rdev->raid_disk;
} else } else
super_types[mddev->major_version]. super_types[mddev->major_version].
validate_super(mddev, rdev); validate_super(mddev, rdev);
...@@ -5782,11 +5797,6 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info) ...@@ -5782,11 +5797,6 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
return -EINVAL; return -EINVAL;
} }
if (test_bit(In_sync, &rdev->flags))
rdev->saved_raid_disk = rdev->raid_disk;
else
rdev->saved_raid_disk = -1;
clear_bit(In_sync, &rdev->flags); /* just to be sure */ clear_bit(In_sync, &rdev->flags); /* just to be sure */
if (info->state & (1<<MD_DISK_WRITEMOSTLY)) if (info->state & (1<<MD_DISK_WRITEMOSTLY))
set_bit(WriteMostly, &rdev->flags); set_bit(WriteMostly, &rdev->flags);
...@@ -6336,6 +6346,32 @@ static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo) ...@@ -6336,6 +6346,32 @@ static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0; return 0;
} }
static inline bool md_ioctl_valid(unsigned int cmd)
{
switch (cmd) {
case ADD_NEW_DISK:
case BLKROSET:
case GET_ARRAY_INFO:
case GET_BITMAP_FILE:
case GET_DISK_INFO:
case HOT_ADD_DISK:
case HOT_REMOVE_DISK:
case PRINT_RAID_DEBUG:
case RAID_AUTORUN:
case RAID_VERSION:
case RESTART_ARRAY_RW:
case RUN_ARRAY:
case SET_ARRAY_INFO:
case SET_BITMAP_FILE:
case SET_DISK_FAULTY:
case STOP_ARRAY:
case STOP_ARRAY_RO:
return true;
default:
return false;
}
}
static int md_ioctl(struct block_device *bdev, fmode_t mode, static int md_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
...@@ -6344,6 +6380,9 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -6344,6 +6380,9 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
struct mddev *mddev = NULL; struct mddev *mddev = NULL;
int ro; int ro;
if (!md_ioctl_valid(cmd))
return -ENOTTY;
switch (cmd) { switch (cmd) {
case RAID_VERSION: case RAID_VERSION:
case GET_ARRAY_INFO: case GET_ARRAY_INFO:
...@@ -7718,6 +7757,7 @@ static int remove_and_add_spares(struct mddev *mddev, ...@@ -7718,6 +7757,7 @@ static int remove_and_add_spares(struct mddev *mddev,
!test_bit(Bitmap_sync, &rdev->flags))) !test_bit(Bitmap_sync, &rdev->flags)))
continue; continue;
if (rdev->saved_raid_disk < 0)
rdev->recovery_offset = 0; rdev->recovery_offset = 0;
if (mddev->pers-> if (mddev->pers->
hot_add_disk(mddev, rdev) == 0) { hot_add_disk(mddev, rdev) == 0) {
...@@ -7938,14 +7978,10 @@ void md_reap_sync_thread(struct mddev *mddev) ...@@ -7938,14 +7978,10 @@ void md_reap_sync_thread(struct mddev *mddev)
mddev->pers->finish_reshape(mddev); mddev->pers->finish_reshape(mddev);
/* If array is no-longer degraded, then any saved_raid_disk /* If array is no-longer degraded, then any saved_raid_disk
* information must be scrapped. Also if any device is now * information must be scrapped.
* In_sync we must scrape the saved_raid_disk for that device
* do the superblock for an incrementally recovered device
* written out.
*/ */
if (!mddev->degraded)
rdev_for_each(rdev, mddev) rdev_for_each(rdev, mddev)
if (!mddev->degraded ||
test_bit(In_sync, &rdev->flags))
rdev->saved_raid_disk = -1; rdev->saved_raid_disk = -1;
md_update_sb(mddev, 1); md_update_sb(mddev, 1);
......
...@@ -3747,7 +3747,8 @@ static int run(struct mddev *mddev) ...@@ -3747,7 +3747,8 @@ static int run(struct mddev *mddev)
!test_bit(In_sync, &disk->rdev->flags)) { !test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0; disk->head_position = 0;
mddev->degraded++; mddev->degraded++;
if (disk->rdev) if (disk->rdev &&
disk->rdev->saved_raid_disk < 0)
conf->fullsync = 1; conf->fullsync = 1;
} }
disk->recovery_disabled = mddev->recovery_disabled - 1; disk->recovery_disabled = mddev->recovery_disabled - 1;
......
...@@ -675,8 +675,10 @@ get_active_stripe(struct r5conf *conf, sector_t sector, ...@@ -675,8 +675,10 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
|| !conf->inactive_blocked), || !conf->inactive_blocked),
*(conf->hash_locks + hash)); *(conf->hash_locks + hash));
conf->inactive_blocked = 0; conf->inactive_blocked = 0;
} else } else {
init_stripe(sh, sector, previous); init_stripe(sh, sector, previous);
atomic_inc(&sh->count);
}
} else { } else {
spin_lock(&conf->device_lock); spin_lock(&conf->device_lock);
if (atomic_read(&sh->count)) { if (atomic_read(&sh->count)) {
...@@ -695,13 +697,11 @@ get_active_stripe(struct r5conf *conf, sector_t sector, ...@@ -695,13 +697,11 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
sh->group = NULL; sh->group = NULL;
} }
} }
atomic_inc(&sh->count);
spin_unlock(&conf->device_lock); spin_unlock(&conf->device_lock);
} }
} while (sh == NULL); } while (sh == NULL);
if (sh)
atomic_inc(&sh->count);
spin_unlock_irq(conf->hash_locks + hash); spin_unlock_irq(conf->hash_locks + hash);
return sh; return sh;
} }
...@@ -2111,6 +2111,7 @@ static void raid5_end_write_request(struct bio *bi, int error) ...@@ -2111,6 +2111,7 @@ static void raid5_end_write_request(struct bio *bi, int error)
set_bit(R5_MadeGoodRepl, &sh->dev[i].flags); set_bit(R5_MadeGoodRepl, &sh->dev[i].flags);
} else { } else {
if (!uptodate) { if (!uptodate) {
set_bit(STRIPE_DEGRADED, &sh->state);
set_bit(WriteErrorSeen, &rdev->flags); set_bit(WriteErrorSeen, &rdev->flags);
set_bit(R5_WriteError, &sh->dev[i].flags); set_bit(R5_WriteError, &sh->dev[i].flags);
if (!test_and_set_bit(WantReplacement, &rdev->flags)) if (!test_and_set_bit(WantReplacement, &rdev->flags))
......
...@@ -292,6 +292,9 @@ struct mdp_superblock_1 { ...@@ -292,6 +292,9 @@ struct mdp_superblock_1 {
* backwards anyway. * backwards anyway.
*/ */
#define MD_FEATURE_NEW_OFFSET 64 /* new_offset must be honoured */ #define MD_FEATURE_NEW_OFFSET 64 /* new_offset must be honoured */
#define MD_FEATURE_RECOVERY_BITMAP 128 /* recovery that is happening
* is guided by bitmap.
*/
#define MD_FEATURE_ALL (MD_FEATURE_BITMAP_OFFSET \ #define MD_FEATURE_ALL (MD_FEATURE_BITMAP_OFFSET \
|MD_FEATURE_RECOVERY_OFFSET \ |MD_FEATURE_RECOVERY_OFFSET \
|MD_FEATURE_RESHAPE_ACTIVE \ |MD_FEATURE_RESHAPE_ACTIVE \
...@@ -299,6 +302,7 @@ struct mdp_superblock_1 { ...@@ -299,6 +302,7 @@ struct mdp_superblock_1 {
|MD_FEATURE_REPLACEMENT \ |MD_FEATURE_REPLACEMENT \
|MD_FEATURE_RESHAPE_BACKWARDS \ |MD_FEATURE_RESHAPE_BACKWARDS \
|MD_FEATURE_NEW_OFFSET \ |MD_FEATURE_NEW_OFFSET \
|MD_FEATURE_RECOVERY_BITMAP \
) )
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment