Skip to content

Commit

Permalink
Merge tag 'md-3.11' of git://neil.brown.name/md
Browse files Browse the repository at this point in the history
Pull md updates from NeilBrown:
 "Mostly fixes, with a few minor features (eg 'last_sync_action' sysfs
  file)

  A couple marked for -stable including one recent bug which causes a
  RAID10 reshape to complete without moving any data :-(

  A couple more bugfixes (at least) to come, but haven't confirmed the
  right solution yet."

* tag 'md-3.11' of git://neil.brown.name/md:
  md/raid10: fix bug which causes all RAID10 reshapes to move no data.
  md/raid5: allow 5-device RAID6 to be reshaped to 4-device.
  md/raid10: fix two bugs affecting RAID10 reshape.
  md: remove doubled description for sync_max, merging it within sync_min/sync_max
  MD: Remember the last sync operation that was performed
  md: fix buglet in RAID5 -> RAID0 conversion.
  md/raid10: check In_sync flag in 'enough()'.
  md/raid10: locking changes for 'enough()'.
  md: replace strict_strto*() with kstrto*()
  md: Wait for md_check_recovery before attempting device removal.
  dm-raid: silence compiler warning on rebuilds_per_group.
  DM RAID: Fix raid_resume not reviving failed devices in all cases
  DM RAID: Break-up untidy function
  DM RAID: Add ability to restore transiently failed devices on resume
  • Loading branch information
Linus Torvalds committed Jul 4, 2013
2 parents e61aca5 + 1376512 commit 697a067
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 70 deletions.
2 changes: 2 additions & 0 deletions Documentation/device-mapper/dm-raid.txt
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,5 @@ Version History
1.4.2 Add RAID10 "far" and "offset" algorithm support.
1.5.0 Add message interface to allow manipulation of the sync_action.
New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
1.5.1 Add ability to restore transiently failed devices on resume.
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
13 changes: 6 additions & 7 deletions Documentation/md.txt
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,6 @@ also have
when it reaches the current sync_max (below) and possibly at
other times.

sync_max
This is a number of sectors at which point a resync/recovery
process will pause. When a resync is active, the value can
only ever be increased, never decreased. The value of 'max'
effectively disables the limit.


sync_speed
This shows the current actual speed, in K/sec, of the current
sync_action. It is averaged over the last 30 seconds.
Expand All @@ -593,6 +586,12 @@ also have
that number to reach sync_max. Then you can either increase
"sync_max", or can write 'idle' to "sync_action".

The value of 'max' for "sync_max" effectively disables the limit.
When a resync is active, the value can only ever be increased,
never decreased.
The value of '0' is the minimum for "sync_min".



Each active md device may also have attributes specific to the
personality module that manages it.
Expand Down
8 changes: 4 additions & 4 deletions drivers/md/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2002,9 +2002,9 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
} else {
int rv;
if (buf[0] == '+')
rv = strict_strtoll(buf+1, 10, &offset);
rv = kstrtoll(buf+1, 10, &offset);
else
rv = strict_strtoll(buf, 10, &offset);
rv = kstrtoll(buf, 10, &offset);
if (rv)
return rv;
if (offset == 0)
Expand Down Expand Up @@ -2139,7 +2139,7 @@ static ssize_t
backlog_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long backlog;
int rv = strict_strtoul(buf, 10, &backlog);
int rv = kstrtoul(buf, 10, &backlog);
if (rv)
return rv;
if (backlog > COUNTER_MAX)
Expand All @@ -2165,7 +2165,7 @@ chunksize_store(struct mddev *mddev, const char *buf, size_t len)
unsigned long csize;
if (mddev->bitmap)
return -EBUSY;
rv = strict_strtoul(buf, 10, &csize);
rv = kstrtoul(buf, 10, &csize);
if (rv)
return rv;
if (csize < 512 ||
Expand Down
76 changes: 70 additions & 6 deletions drivers/md/dm-raid.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
static int validate_raid_redundancy(struct raid_set *rs)
{
unsigned i, rebuild_cnt = 0;
unsigned rebuilds_per_group, copies, d;
unsigned rebuilds_per_group = 0, copies, d;
unsigned group_size, last_group_start;

for (i = 0; i < rs->md.raid_disks; i++)
Expand Down Expand Up @@ -504,7 +504,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
* First, parse the in-order required arguments
* "chunk_size" is the only argument of this type.
*/
if ((strict_strtoul(argv[0], 10, &value) < 0)) {
if ((kstrtoul(argv[0], 10, &value) < 0)) {
rs->ti->error = "Bad chunk size";
return -EINVAL;
} else if (rs->raid_type->level == 1) {
Expand Down Expand Up @@ -585,7 +585,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
continue;
}

if (strict_strtoul(argv[i], 10, &value) < 0) {
if (kstrtoul(argv[i], 10, &value) < 0) {
rs->ti->error = "Bad numerical argument given in raid params";
return -EINVAL;
}
Expand Down Expand Up @@ -1181,7 +1181,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
argv++;

/* number of RAID parameters */
if (strict_strtoul(argv[0], 10, &num_raid_params) < 0) {
if (kstrtoul(argv[0], 10, &num_raid_params) < 0) {
ti->error = "Cannot understand number of RAID parameters";
return -EINVAL;
}
Expand All @@ -1194,7 +1194,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
return -EINVAL;
}

if ((strict_strtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
if ((kstrtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
(num_raid_devs >= INT_MAX)) {
ti->error = "Cannot understand number of raid devices";
return -EINVAL;
Expand Down Expand Up @@ -1388,6 +1388,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
* performing a "check" of the array.
*/
DMEMIT(" %llu",
(strcmp(rs->md.last_sync_action, "check")) ? 0 :
(unsigned long long)
atomic64_read(&rs->md.resync_mismatches));
break;
Expand Down Expand Up @@ -1572,6 +1573,62 @@ static void raid_postsuspend(struct dm_target *ti)
mddev_suspend(&rs->md);
}

static void attempt_restore_of_faulty_devices(struct raid_set *rs)
{
int i;
uint64_t failed_devices, cleared_failed_devices = 0;
unsigned long flags;
struct dm_raid_superblock *sb;
struct md_rdev *r;

for (i = 0; i < rs->md.raid_disks; i++) {
r = &rs->dev[i].rdev;
if (test_bit(Faulty, &r->flags) && r->sb_page &&
sync_page_io(r, 0, r->sb_size, r->sb_page, READ, 1)) {
DMINFO("Faulty %s device #%d has readable super block."
" Attempting to revive it.",
rs->raid_type->name, i);

/*
* Faulty bit may be set, but sometimes the array can
* be suspended before the personalities can respond
* by removing the device from the array (i.e. calling
* 'hot_remove_disk'). If they haven't yet removed
* the failed device, its 'raid_disk' number will be
* '>= 0' - meaning we must call this function
* ourselves.
*/
if ((r->raid_disk >= 0) &&
(r->mddev->pers->hot_remove_disk(r->mddev, r) != 0))
/* Failed to revive this device, try next */
continue;

r->raid_disk = i;
r->saved_raid_disk = i;
flags = r->flags;
clear_bit(Faulty, &r->flags);
clear_bit(WriteErrorSeen, &r->flags);
clear_bit(In_sync, &r->flags);
if (r->mddev->pers->hot_add_disk(r->mddev, r)) {
r->raid_disk = -1;
r->saved_raid_disk = -1;
r->flags = flags;
} else {
r->recovery_offset = 0;
cleared_failed_devices |= 1 << i;
}
}
}
if (cleared_failed_devices) {
rdev_for_each(r, &rs->md) {
sb = page_address(r->sb_page);
failed_devices = le64_to_cpu(sb->failed_devices);
failed_devices &= ~cleared_failed_devices;
sb->failed_devices = cpu_to_le64(failed_devices);
}
}
}

static void raid_resume(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
Expand All @@ -1580,6 +1637,13 @@ static void raid_resume(struct dm_target *ti)
if (!rs->bitmap_loaded) {
bitmap_load(&rs->md);
rs->bitmap_loaded = 1;
} else {
/*
* A secondary resume while the device is active.
* Take this opportunity to check whether any failed
* devices are reachable again.
*/
attempt_restore_of_faulty_devices(rs);
}

clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
Expand All @@ -1588,7 +1652,7 @@ static void raid_resume(struct dm_target *ti)

static struct target_type raid_target = {
.name = "raid",
.version = {1, 5, 0},
.version = {1, 5, 2},
.module = THIS_MODULE,
.ctr = raid_ctr,
.dtr = raid_dtr,
Expand Down
53 changes: 37 additions & 16 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ void mddev_init(struct mddev *mddev)
init_waitqueue_head(&mddev->recovery_wait);
mddev->reshape_position = MaxSector;
mddev->reshape_backwards = 0;
mddev->last_sync_action = "none";
mddev->resync_min = 0;
mddev->resync_max = MaxSector;
mddev->level = LEVEL_NONE;
Expand Down Expand Up @@ -2867,7 +2868,7 @@ static ssize_t
offset_store(struct md_rdev *rdev, const char *buf, size_t len)
{
unsigned long long offset;
if (strict_strtoull(buf, 10, &offset) < 0)
if (kstrtoull(buf, 10, &offset) < 0)
return -EINVAL;
if (rdev->mddev->pers && rdev->raid_disk >= 0)
return -EBUSY;
Expand Down Expand Up @@ -2895,7 +2896,7 @@ static ssize_t new_offset_store(struct md_rdev *rdev,
unsigned long long new_offset;
struct mddev *mddev = rdev->mddev;

if (strict_strtoull(buf, 10, &new_offset) < 0)
if (kstrtoull(buf, 10, &new_offset) < 0)
return -EINVAL;

if (mddev->sync_thread)
Expand Down Expand Up @@ -2961,7 +2962,7 @@ static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
unsigned long long blocks;
sector_t new;

if (strict_strtoull(buf, 10, &blocks) < 0)
if (kstrtoull(buf, 10, &blocks) < 0)
return -EINVAL;

if (blocks & 1ULL << (8 * sizeof(blocks) - 1))
Expand Down Expand Up @@ -3069,7 +3070,7 @@ static ssize_t recovery_start_store(struct md_rdev *rdev, const char *buf, size_

if (cmd_match(buf, "none"))
recovery_start = MaxSector;
else if (strict_strtoull(buf, 10, &recovery_start))
else if (kstrtoull(buf, 10, &recovery_start))
return -EINVAL;

if (rdev->mddev->pers &&
Expand Down Expand Up @@ -3497,7 +3498,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
if (clevel[len-1] == '\n')
len--;
clevel[len] = 0;
if (strict_strtol(clevel, 10, &level))
if (kstrtol(clevel, 10, &level))
level = LEVEL_NONE;

if (request_module("md-%s", clevel) != 0)
Expand Down Expand Up @@ -4272,6 +4273,17 @@ action_store(struct mddev *mddev, const char *page, size_t len)
return len;
}

static struct md_sysfs_entry md_scan_mode =
__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);

static ssize_t
last_sync_action_show(struct mddev *mddev, char *page)
{
return sprintf(page, "%s\n", mddev->last_sync_action);
}

static struct md_sysfs_entry md_last_scan_mode = __ATTR_RO(last_sync_action);

static ssize_t
mismatch_cnt_show(struct mddev *mddev, char *page)
{
Expand All @@ -4280,10 +4292,6 @@ mismatch_cnt_show(struct mddev *mddev, char *page)
atomic64_read(&mddev->resync_mismatches));
}

static struct md_sysfs_entry md_scan_mode =
__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);


static struct md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);

static ssize_t
Expand Down Expand Up @@ -4356,7 +4364,7 @@ sync_force_parallel_store(struct mddev *mddev, const char *buf, size_t len)
{
long n;

if (strict_strtol(buf, 10, &n))
if (kstrtol(buf, 10, &n))
return -EINVAL;

if (n != 0 && n != 1)
Expand Down Expand Up @@ -4424,7 +4432,7 @@ static ssize_t
min_sync_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long long min;
if (strict_strtoull(buf, 10, &min))
if (kstrtoull(buf, 10, &min))
return -EINVAL;
if (min > mddev->resync_max)
return -EINVAL;
Expand Down Expand Up @@ -4461,7 +4469,7 @@ max_sync_store(struct mddev *mddev, const char *buf, size_t len)
mddev->resync_max = MaxSector;
else {
unsigned long long max;
if (strict_strtoull(buf, 10, &max))
if (kstrtoull(buf, 10, &max))
return -EINVAL;
if (max < mddev->resync_min)
return -EINVAL;
Expand Down Expand Up @@ -4686,6 +4694,7 @@ static struct attribute *md_default_attrs[] = {

static struct attribute *md_redundancy_attrs[] = {
&md_scan_mode.attr,
&md_last_scan_mode.attr,
&md_mismatches.attr,
&md_sync_min.attr,
&md_sync_max.attr,
Expand Down Expand Up @@ -6405,6 +6414,12 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
/* need to ensure md_delayed_delete() has completed */
flush_workqueue(md_misc_wq);

if (cmd == HOT_REMOVE_DISK)
/* need to ensure recovery thread has run */
wait_event_interruptible_timeout(mddev->sb_wait,
!test_bit(MD_RECOVERY_NEEDED,
&mddev->flags),
msecs_to_jiffies(5000));
err = mddev_lock(mddev);
if (err) {
printk(KERN_INFO
Expand Down Expand Up @@ -7323,7 +7338,7 @@ void md_do_sync(struct md_thread *thread)
sector_t last_check;
int skipped = 0;
struct md_rdev *rdev;
char *desc;
char *desc, *action = NULL;
struct blk_plug plug;

/* just incase thread restarts... */
Expand All @@ -7333,17 +7348,21 @@ void md_do_sync(struct md_thread *thread)
return;

if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
desc = "data-check";
else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
action = "check";
} else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
desc = "requested-resync";
else
action = "repair";
} else
desc = "resync";
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
desc = "reshape";
else
desc = "recovery";

mddev->last_sync_action = action ?: desc;

/* we overload curr_resync somewhat here.
* 0 == not engaged in resync at all
* 2 == checking that there is no conflict with another sync
Expand Down Expand Up @@ -7892,6 +7911,8 @@ void md_check_recovery(struct mddev *mddev)
md_new_event(mddev);
}
unlock:
wake_up(&mddev->sb_wait);

if (!mddev->sync_thread) {
clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
if (test_and_clear_bit(MD_RECOVERY_RECOVER,
Expand Down
8 changes: 8 additions & 0 deletions drivers/md/md.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,14 @@ struct mddev {

struct md_thread *thread; /* management thread */
struct md_thread *sync_thread; /* doing resync or reconstruct */

/* 'last_sync_action' is initialized to "none". It is set when a
* sync operation (i.e "data-check", "requested-resync", "resync",
* "recovery", or "reshape") is started. It holds this value even
* when the sync thread is "frozen" (interrupted) or "idle" (stopped
* or finished). It is overwritten when a new sync operation is begun.
*/
char *last_sync_action;
sector_t curr_resync; /* last block scheduled */
/* As resync requests can complete out of order, we cannot easily track
* how much resync has been completed. So we occasionally pause until
Expand Down
1 change: 1 addition & 0 deletions drivers/md/raid0.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ static void *raid0_takeover_raid45(struct mddev *mddev)
mdname(mddev));
return ERR_PTR(-EINVAL);
}
rdev->sectors = mddev->dev_sectors;
}

/* Set new parameters */
Expand Down
Loading

0 comments on commit 697a067

Please sign in to comment.