summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/md-bitmap.c7
-rw-r--r--drivers/md/md-cluster.c7
-rw-r--r--drivers/md/md-llbitmap.c4
-rw-r--r--drivers/md/md.c188
-rw-r--r--drivers/md/md.h25
-rw-r--r--drivers/md/raid0.c4
-rw-r--r--drivers/md/raid1-10.c5
-rw-r--r--drivers/md/raid1.c88
-rw-r--r--drivers/md/raid1.h5
-rw-r--r--drivers/md/raid10.c178
-rw-r--r--drivers/md/raid10.h5
-rw-r--r--drivers/md/raid5.c143
-rw-r--r--drivers/md/raid5.h4
13 files changed, 310 insertions, 353 deletions
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 84b7e2af6dba..1d4a050dab3a 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -2085,7 +2085,7 @@ static void bitmap_destroy(struct mddev *mddev)
return;
bitmap_wait_behind_writes(mddev);
- if (!mddev->serialize_policy)
+ if (!test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
mddev_destroy_serial_pool(mddev, NULL);
mutex_lock(&mddev->bitmap_info.mutex);
@@ -2453,6 +2453,7 @@ static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks,
memcpy(page_address(store.sb_page),
page_address(bitmap->storage.sb_page),
sizeof(bitmap_super_t));
+ mutex_lock(&bitmap->mddev->bitmap_info.mutex);
spin_lock_irq(&bitmap->counts.lock);
md_bitmap_file_unmap(&bitmap->storage);
bitmap->storage = store;
@@ -2560,7 +2561,7 @@ static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks,
set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
}
spin_unlock_irq(&bitmap->counts.lock);
-
+ mutex_unlock(&bitmap->mddev->bitmap_info.mutex);
if (!init) {
__bitmap_unplug(bitmap);
bitmap->mddev->pers->quiesce(bitmap->mddev, 0);
@@ -2809,7 +2810,7 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len)
mddev->bitmap_info.max_write_behind = backlog;
if (!backlog && mddev->serial_info_pool) {
/* serial_info_pool is not needed if backlog is zero */
- if (!mddev->serialize_policy)
+ if (!test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
mddev_destroy_serial_pool(mddev, NULL);
} else if (backlog && !mddev->serial_info_pool) {
/* serial_info_pool is needed since backlog is not zero */
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index 11f1e91d387d..896279988dfd 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -549,8 +549,13 @@ static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
- /* daemaon thread must exist */
thread = rcu_dereference_protected(mddev->thread, true);
+ if (!thread) {
+ pr_warn("md-cluster: Received metadata update but MD thread is not ready\n");
+ dlm_unlock_sync(cinfo->no_new_dev_lockres);
+ return;
+ }
+
wait_event(thread->wqueue,
(got_lock = mddev_trylock(mddev)) ||
test_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state));
diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
index 9c1ade19b774..cd713a7dc270 100644
--- a/drivers/md/md-llbitmap.c
+++ b/drivers/md/md-llbitmap.c
@@ -712,8 +712,10 @@ static int llbitmap_suspend_timeout(struct llbitmap *llbitmap, int page_idx)
percpu_ref_kill(&pctl->active);
if (!wait_event_timeout(pctl->wait, percpu_ref_is_zero(&pctl->active),
- llbitmap->mddev->bitmap_info.daemon_sleep * HZ))
+ llbitmap->mddev->bitmap_info.daemon_sleep * HZ)) {
+ percpu_ref_resurrect(&pctl->active);
return -ETIMEDOUT;
+ }
return 0;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6d73f6e196a9..59cd303548de 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -279,7 +279,8 @@ void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
rdev_for_each(temp, mddev) {
if (!rdev) {
- if (!mddev->serialize_policy ||
+ if (!test_bit(MD_SERIALIZE_POLICY,
+ &mddev->flags) ||
!rdev_need_serial(temp))
rdev_uninit_serial(temp);
else
@@ -2617,9 +2618,6 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
list_add_rcu(&rdev->same_set, &mddev->disks);
bd_link_disk_holder(rdev->bdev, mddev->gendisk);
- /* May as well allow recovery to be retried once */
- mddev->recovery_disabled++;
-
return 0;
fail:
@@ -5864,11 +5862,11 @@ __ATTR(consistency_policy, S_IRUGO | S_IWUSR, consistency_policy_show,
static ssize_t fail_last_dev_show(struct mddev *mddev, char *page)
{
- return sprintf(page, "%d\n", mddev->fail_last_dev);
+ return sprintf(page, "%d\n", test_bit(MD_FAILLAST_DEV, &mddev->flags));
}
/*
- * Setting fail_last_dev to true to allow last device to be forcibly removed
+ * Setting MD_FAILLAST_DEV to allow last device to be forcibly removed
* from RAID1/RAID10.
*/
static ssize_t
@@ -5881,8 +5879,10 @@ fail_last_dev_store(struct mddev *mddev, const char *buf, size_t len)
if (ret)
return ret;
- if (value != mddev->fail_last_dev)
- mddev->fail_last_dev = value;
+ if (value)
+ set_bit(MD_FAILLAST_DEV, &mddev->flags);
+ else
+ clear_bit(MD_FAILLAST_DEV, &mddev->flags);
return len;
}
@@ -5895,11 +5895,12 @@ static ssize_t serialize_policy_show(struct mddev *mddev, char *page)
if (mddev->pers == NULL || (mddev->pers->head.id != ID_RAID1))
return sprintf(page, "n/a\n");
else
- return sprintf(page, "%d\n", mddev->serialize_policy);
+ return sprintf(page, "%d\n",
+ test_bit(MD_SERIALIZE_POLICY, &mddev->flags));
}
/*
- * Setting serialize_policy to true to enforce write IO is not reordered
+ * Setting MD_SERIALIZE_POLICY enforce write IO is not reordered
* for raid1.
*/
static ssize_t
@@ -5912,7 +5913,7 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len)
if (err)
return err;
- if (value == mddev->serialize_policy)
+ if (value == test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
return len;
err = mddev_suspend_and_lock(mddev);
@@ -5924,11 +5925,13 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len)
goto unlock;
}
- if (value)
+ if (value) {
mddev_create_serial_pool(mddev, NULL);
- else
+ set_bit(MD_SERIALIZE_POLICY, &mddev->flags);
+ } else {
mddev_destroy_serial_pool(mddev, NULL);
- mddev->serialize_policy = value;
+ clear_bit(MD_SERIALIZE_POLICY, &mddev->flags);
+ }
unlock:
mddev_unlock_and_resume(mddev);
return err ?: len;
@@ -6502,7 +6505,7 @@ int md_run(struct mddev *mddev)
* the only valid external interface is through the md
* device.
*/
- mddev->has_superblocks = false;
+ clear_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
rdev_for_each(rdev, mddev) {
if (test_bit(Faulty, &rdev->flags))
continue;
@@ -6515,7 +6518,7 @@ int md_run(struct mddev *mddev)
}
if (rdev->sb_page)
- mddev->has_superblocks = true;
+ set_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
/* perform some consistency tests on the device.
* We don't want the data to overlap the metadata,
@@ -6848,13 +6851,15 @@ static void __md_stop_writes(struct mddev *mddev)
{
timer_delete_sync(&mddev->safemode_timer);
- if (mddev->pers && mddev->pers->quiesce) {
- mddev->pers->quiesce(mddev, 1);
- mddev->pers->quiesce(mddev, 0);
- }
+ if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
+ if (mddev->pers && mddev->pers->quiesce) {
+ mddev->pers->quiesce(mddev, 1);
+ mddev->pers->quiesce(mddev, 0);
+ }
- if (md_bitmap_enabled(mddev, true))
- mddev->bitmap_ops->flush(mddev);
+ if (md_bitmap_enabled(mddev, true))
+ mddev->bitmap_ops->flush(mddev);
+ }
if (md_is_rdwr(mddev) &&
((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
@@ -6865,7 +6870,7 @@ static void __md_stop_writes(struct mddev *mddev)
md_update_sb(mddev, 1);
}
/* disable policy to guarantee rdevs free resources for serialization */
- mddev->serialize_policy = 0;
+ clear_bit(MD_SERIALIZE_POLICY, &mddev->flags);
mddev_destroy_serial_pool(mddev, NULL);
}
@@ -9068,20 +9073,22 @@ static bool is_mddev_idle(struct mddev *mddev, int init)
return idle;
}
-void md_done_sync(struct mddev *mddev, int blocks, int ok)
+void md_done_sync(struct mddev *mddev, int blocks)
{
/* another "blocks" (512byte) blocks have been synced */
atomic_sub(blocks, &mddev->recovery_active);
wake_up(&mddev->recovery_wait);
- if (!ok) {
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- set_bit(MD_RECOVERY_ERROR, &mddev->recovery);
- md_wakeup_thread(mddev->thread);
- // stop recovery, signal do_sync ....
- }
}
EXPORT_SYMBOL(md_done_sync);
+void md_sync_error(struct mddev *mddev)
+{
+ // stop recovery, signal do_sync ....
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+}
+EXPORT_SYMBOL(md_sync_error);
+
/* md_write_start(mddev, bi)
* If we need to update some array metadata (e.g. 'active' flag
* in superblock) before writing, schedule a superblock update
@@ -9125,7 +9132,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)
rcu_read_unlock();
if (did_change)
sysfs_notify_dirent_safe(mddev->sysfs_state);
- if (!mddev->has_superblocks)
+ if (!test_bit(MD_HAS_SUPERBLOCK, &mddev->flags))
return;
wait_event(mddev->sb_wait,
!test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
@@ -9430,6 +9437,53 @@ static bool sync_io_within_limit(struct mddev *mddev)
(raid_is_456(mddev) ? 8 : 128) * sync_io_depth(mddev);
}
+/*
+ * Update sync offset and mddev status when sync completes
+ */
+static void md_finish_sync(struct mddev *mddev, enum sync_action action)
+{
+ struct md_rdev *rdev;
+
+ switch (action) {
+ case ACTION_RESYNC:
+ case ACTION_REPAIR:
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+ mddev->curr_resync = MaxSector;
+ mddev->resync_offset = mddev->curr_resync;
+ break;
+ case ACTION_RECOVER:
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+ mddev->curr_resync = MaxSector;
+ rcu_read_lock();
+ rdev_for_each_rcu(rdev, mddev)
+ if (mddev->delta_disks >= 0 &&
+ rdev_needs_recovery(rdev, mddev->curr_resync))
+ rdev->recovery_offset = mddev->curr_resync;
+ rcu_read_unlock();
+ break;
+ case ACTION_RESHAPE:
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
+ mddev->delta_disks > 0 &&
+ mddev->pers->finish_reshape &&
+ mddev->pers->size &&
+ !mddev_is_dm(mddev)) {
+ mddev_lock_nointr(mddev);
+ md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
+ mddev_unlock(mddev);
+ if (!mddev_is_clustered(mddev))
+ set_capacity_and_notify(mddev->gendisk,
+ mddev->array_sectors);
+ }
+ if (mddev->pers->finish_reshape)
+ mddev->pers->finish_reshape(mddev);
+ break;
+ /* */
+ case ACTION_CHECK:
+ default:
+ break;
+ }
+}
+
#define SYNC_MARKS 10
#define SYNC_MARK_STEP (3*HZ)
#define UPDATE_FREQUENCY (5*60*HZ)
@@ -9445,7 +9499,6 @@ void md_do_sync(struct md_thread *thread)
int last_mark,m;
sector_t last_check;
int skipped = 0;
- struct md_rdev *rdev;
enum sync_action action;
const char *desc;
struct blk_plug plug;
@@ -9731,65 +9784,21 @@ update:
wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
mddev->curr_resync >= MD_RESYNC_ACTIVE) {
+ /* All sync IO completes after recovery_active becomes 0 */
mddev->curr_resync_completed = mddev->curr_resync;
sysfs_notify_dirent_safe(mddev->sysfs_completed);
}
mddev->pers->sync_request(mddev, max_sectors, max_sectors, &skipped);
- if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
- mddev->curr_resync > MD_RESYNC_ACTIVE) {
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
- if (mddev->curr_resync >= mddev->resync_offset) {
- pr_debug("md: checkpointing %s of %s.\n",
- desc, mdname(mddev));
- if (test_bit(MD_RECOVERY_ERROR,
- &mddev->recovery))
- mddev->resync_offset =
- mddev->curr_resync_completed;
- else
- mddev->resync_offset =
- mddev->curr_resync;
- }
- } else
- mddev->resync_offset = MaxSector;
- } else {
- if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
- mddev->curr_resync = MaxSector;
- if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- test_bit(MD_RECOVERY_RECOVER, &mddev->recovery)) {
- rcu_read_lock();
- rdev_for_each_rcu(rdev, mddev)
- if (mddev->delta_disks >= 0 &&
- rdev_needs_recovery(rdev, mddev->curr_resync))
- rdev->recovery_offset = mddev->curr_resync;
- rcu_read_unlock();
- }
- }
- }
+ if (mddev->curr_resync > MD_RESYNC_ACTIVE)
+ md_finish_sync(mddev, action);
skip:
/* set CHANGE_PENDING here since maybe another update is needed,
* so other nodes are informed. It should be harmless for normal
* raid */
set_mask_bits(&mddev->sb_flags, 0,
BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS));
-
- if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
- mddev->delta_disks > 0 &&
- mddev->pers->finish_reshape &&
- mddev->pers->size &&
- !mddev_is_dm(mddev)) {
- mddev_lock_nointr(mddev);
- md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
- mddev_unlock(mddev);
- if (!mddev_is_clustered(mddev))
- set_capacity_and_notify(mddev->gendisk,
- mddev->array_sectors);
- }
-
spin_lock(&mddev->lock);
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
/* We completed so min/max setting can be forgotten if used. */
@@ -10304,7 +10313,7 @@ void md_reap_sync_thread(struct mddev *mddev)
{
struct md_rdev *rdev;
sector_t old_dev_sectors = mddev->dev_sectors;
- bool is_reshaped = false;
+ bool is_reshaped = test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
/* resync has finished, collect result */
md_unregister_thread(mddev, &mddev->sync_thread);
@@ -10320,12 +10329,6 @@ void md_reap_sync_thread(struct mddev *mddev)
set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
}
}
- if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- mddev->pers->finish_reshape) {
- mddev->pers->finish_reshape(mddev);
- if (mddev_is_clustered(mddev))
- is_reshaped = true;
- }
/* If array is no-longer degraded, then any saved_raid_disk
* information must be scrapped.
@@ -10352,8 +10355,9 @@ void md_reap_sync_thread(struct mddev *mddev)
* be changed by md_update_sb, and MD_RECOVERY_RESHAPE is cleared,
* so it is time to update size across cluster.
*/
- if (mddev_is_clustered(mddev) && is_reshaped
- && !test_bit(MD_CLOSING, &mddev->flags))
+ if (mddev_is_clustered(mddev) && is_reshaped &&
+ mddev->pers->finish_reshape &&
+ !test_bit(MD_CLOSING, &mddev->flags))
mddev->cluster_ops->update_size(mddev, old_dev_sectors);
/* flag recovery needed just to double check */
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -10413,8 +10417,14 @@ bool rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
else
s += rdev->data_offset;
- if (!badblocks_set(&rdev->badblocks, s, sectors, 0))
+ if (!badblocks_set(&rdev->badblocks, s, sectors, 0)) {
+ /*
+ * Mark the disk as Faulty when setting badblocks fails,
+ * otherwise, bad sectors may be read.
+ */
+ md_error(mddev, rdev);
return false;
+ }
/* Make sure they get written out promptly */
if (test_bit(ExternalBbl, &rdev->flags))
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 6985f2829bbd..e6d3d88698ed 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -22,6 +22,10 @@
#include <trace/events/block.h>
#define MaxSector (~(sector_t)0)
+/*
+ * Number of guaranteed raid bios in case of extreme VM load:
+ */
+#define NR_RAID_BIOS 256
enum md_submodule_type {
MD_PERSONALITY = 0,
@@ -340,6 +344,9 @@ struct md_cluster_operations;
* array is ready yet.
* @MD_BROKEN: This is used to stop writes and mark array as failed.
* @MD_DELETED: This device is being deleted
+ * @MD_HAS_SUPERBLOCK: There is persistence sb in member disks.
+ * @MD_FAILLAST_DEV: Allow last rdev to be removed.
+ * @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1.
*
* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added
*/
@@ -356,6 +363,9 @@ enum mddev_flags {
MD_BROKEN,
MD_DO_DELETE,
MD_DELETED,
+ MD_HAS_SUPERBLOCK,
+ MD_FAILLAST_DEV,
+ MD_SERIALIZE_POLICY,
};
enum mddev_sb_flags {
@@ -495,12 +505,6 @@ struct mddev {
int ok_start_degraded;
unsigned long recovery;
- /* If a RAID personality determines that recovery (of a particular
- * device) will fail due to a read error on the source device, it
- * takes a copy of this number and does not attempt recovery again
- * until this number changes.
- */
- int recovery_disabled;
int in_sync; /* know to not need resync */
/* 'open_mutex' avoids races between 'md_open' and 'do_md_stop', so
@@ -622,10 +626,6 @@ struct mddev {
/* The sequence number for sync thread */
atomic_t sync_seq;
-
- bool has_superblocks:1;
- bool fail_last_dev:1;
- bool serialize_policy:1;
};
enum recovery_flags {
@@ -646,8 +646,6 @@ enum recovery_flags {
MD_RECOVERY_FROZEN,
/* waiting for pers->start() to finish */
MD_RECOVERY_WAIT,
- /* interrupted because io-error */
- MD_RECOVERY_ERROR,
/* flags determines sync action, see details in enum sync_action */
@@ -912,7 +910,8 @@ extern const char *md_sync_action_name(enum sync_action action);
extern void md_write_start(struct mddev *mddev, struct bio *bi);
extern void md_write_inc(struct mddev *mddev, struct bio *bi);
extern void md_write_end(struct mddev *mddev);
-extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
+extern void md_done_sync(struct mddev *mddev, int blocks);
+extern void md_sync_error(struct mddev *mddev);
extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
extern void md_finish_reshape(struct mddev *mddev);
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 985c377356eb..d83b2b1c0049 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -27,7 +27,9 @@ module_param(default_layout, int, 0644);
(1L << MD_JOURNAL_CLEAN) | \
(1L << MD_FAILFAST_SUPPORTED) |\
(1L << MD_HAS_PPL) | \
- (1L << MD_HAS_MULTIPLE_PPLS))
+ (1L << MD_HAS_MULTIPLE_PPLS) | \
+ (1L << MD_FAILLAST_DEV) | \
+ (1L << MD_SERIALIZE_POLICY))
/*
* inform the user of the raid configuration
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 521625756128..c33099925f23 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -3,11 +3,6 @@
#define RESYNC_BLOCK_SIZE (64*1024)
#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
-/*
- * Number of guaranteed raid bios in case of extreme VM load:
- */
-#define NR_RAID_BIOS 256
-
/* when we get a read error on a read-only array, we redirect to another
* device without failing the first device, or trying to over-write to
* correct the read error. To keep track of bad blocks on a per-bio
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 57d50465eed1..79faec11b79e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -542,7 +542,7 @@ static void raid1_end_write_request(struct bio *bio)
call_bio_endio(r1_bio);
}
}
- } else if (rdev->mddev->serialize_policy)
+ } else if (test_bit(MD_SERIALIZE_POLICY, &rdev->mddev->flags))
remove_serial(rdev, lo, hi);
if (r1_bio->bios[mirror] == NULL)
rdev_dec_pending(rdev, conf->mddev);
@@ -1644,7 +1644,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO,
&mddev->bio_set);
- if (mddev->serialize_policy)
+ if (test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
wait_for_serialization(rdev, r1_bio);
}
@@ -1746,7 +1746,7 @@ static void raid1_status(struct seq_file *seq, struct mddev *mddev)
* - &mddev->degraded is bumped.
*
* @rdev is marked as &Faulty excluding case when array is failed and
- * &mddev->fail_last_dev is off.
+ * MD_FAILLAST_DEV is not set.
*/
static void raid1_error(struct mddev *mddev, struct md_rdev *rdev)
{
@@ -1759,8 +1759,7 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev)
(conf->raid_disks - mddev->degraded) == 1) {
set_bit(MD_BROKEN, &mddev->flags);
- if (!mddev->fail_last_dev) {
- conf->recovery_disabled = mddev->recovery_disabled;
+ if (!test_bit(MD_FAILLAST_DEV, &mddev->flags)) {
spin_unlock_irqrestore(&conf->device_lock, flags);
return;
}
@@ -1904,7 +1903,6 @@ static bool raid1_remove_conf(struct r1conf *conf, int disk)
/* Only remove non-faulty devices if recovery is not possible. */
if (!test_bit(Faulty, &rdev->flags) &&
- rdev->mddev->recovery_disabled != conf->recovery_disabled &&
rdev->mddev->degraded < conf->raid_disks)
return false;
@@ -1924,9 +1922,6 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
int first = 0;
int last = conf->raid_disks - 1;
- if (mddev->recovery_disabled == conf->recovery_disabled)
- return -EBUSY;
-
if (rdev->raid_disk >= 0)
first = last = rdev->raid_disk;
@@ -2062,7 +2057,7 @@ static void abort_sync_write(struct mddev *mddev, struct r1bio *r1_bio)
} while (sectors_to_go > 0);
}
-static void put_sync_write_buf(struct r1bio *r1_bio, int uptodate)
+static void put_sync_write_buf(struct r1bio *r1_bio)
{
if (atomic_dec_and_test(&r1_bio->remaining)) {
struct mddev *mddev = r1_bio->mddev;
@@ -2073,20 +2068,19 @@ static void put_sync_write_buf(struct r1bio *r1_bio, int uptodate)
reschedule_retry(r1_bio);
else {
put_buf(r1_bio);
- md_done_sync(mddev, s, uptodate);
+ md_done_sync(mddev, s);
}
}
}
static void end_sync_write(struct bio *bio)
{
- int uptodate = !bio->bi_status;
struct r1bio *r1_bio = get_resync_r1bio(bio);
struct mddev *mddev = r1_bio->mddev;
struct r1conf *conf = mddev->private;
struct md_rdev *rdev = conf->mirrors[find_bio_disk(r1_bio, bio)].rdev;
- if (!uptodate) {
+ if (bio->bi_status) {
abort_sync_write(mddev, r1_bio);
set_bit(WriteErrorSeen, &rdev->flags);
if (!test_and_set_bit(WantReplacement, &rdev->flags))
@@ -2099,7 +2093,7 @@ static void end_sync_write(struct bio *bio)
set_bit(R1BIO_MadeGood, &r1_bio->state);
}
- put_sync_write_buf(r1_bio, uptodate);
+ put_sync_write_buf(r1_bio);
}
static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
@@ -2116,8 +2110,7 @@ static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
rdev->mddev->recovery);
}
/* need to record an error - either for the block or the device */
- if (!rdev_set_badblocks(rdev, sector, sectors, 0))
- md_error(rdev->mddev, rdev);
+ rdev_set_badblocks(rdev, sector, sectors, 0);
return 0;
}
@@ -2348,9 +2341,8 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)
*/
if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) ||
!fix_sync_read_error(r1_bio)) {
- conf->recovery_disabled = mddev->recovery_disabled;
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_done_sync(mddev, r1_bio->sectors, 0);
+ md_done_sync(mddev, r1_bio->sectors);
+ md_sync_error(mddev);
put_buf(r1_bio);
return;
}
@@ -2385,7 +2377,7 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)
submit_bio_noacct(wbio);
}
- put_sync_write_buf(r1_bio, 1);
+ put_sync_write_buf(r1_bio);
}
/*
@@ -2442,8 +2434,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
if (!success) {
/* Cannot read from anywhere - mark it bad */
struct md_rdev *rdev = conf->mirrors[read_disk].rdev;
- if (!rdev_set_badblocks(rdev, sect, s, 0))
- md_error(mddev, rdev);
+ rdev_set_badblocks(rdev, sect, s, 0);
break;
}
/* write it back and re-read */
@@ -2487,7 +2478,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
}
}
-static bool narrow_write_error(struct r1bio *r1_bio, int i)
+static void narrow_write_error(struct r1bio *r1_bio, int i)
{
struct mddev *mddev = r1_bio->mddev;
struct r1conf *conf = mddev->private;
@@ -2504,17 +2495,16 @@ static bool narrow_write_error(struct r1bio *r1_bio, int i)
* We currently own a reference on the rdev.
*/
- int block_sectors;
+ int block_sectors, lbs = bdev_logical_block_size(rdev->bdev) >> 9;
sector_t sector;
int sectors;
int sect_to_write = r1_bio->sectors;
- bool ok = true;
if (rdev->badblocks.shift < 0)
- return false;
+ block_sectors = lbs;
+ else
+ block_sectors = roundup(1 << rdev->badblocks.shift, lbs);
- block_sectors = roundup(1 << rdev->badblocks.shift,
- bdev_logical_block_size(rdev->bdev) >> 9);
sector = r1_bio->sector;
sectors = ((sector + block_sectors)
& ~(sector_t)(block_sectors - 1))
@@ -2542,18 +2532,21 @@ static bool narrow_write_error(struct r1bio *r1_bio, int i)
bio_trim(wbio, sector - r1_bio->sector, sectors);
wbio->bi_iter.bi_sector += rdev->data_offset;
- if (submit_bio_wait(wbio) < 0)
- /* failure! */
- ok = rdev_set_badblocks(rdev, sector,
- sectors, 0)
- && ok;
+ if (submit_bio_wait(wbio) &&
+ !rdev_set_badblocks(rdev, sector, sectors, 0)) {
+ /*
+ * Badblocks set failed, disk marked Faulty.
+ * No further operations needed.
+ */
+ bio_put(wbio);
+ break;
+ }
bio_put(wbio);
sect_to_write -= sectors;
sector += sectors;
sectors = block_sectors;
}
- return ok;
}
static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
@@ -2566,17 +2559,14 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio
if (bio->bi_end_io == NULL)
continue;
if (!bio->bi_status &&
- test_bit(R1BIO_MadeGood, &r1_bio->state)) {
+ test_bit(R1BIO_MadeGood, &r1_bio->state))
rdev_clear_badblocks(rdev, r1_bio->sector, s, 0);
- }
if (bio->bi_status &&
- test_bit(R1BIO_WriteError, &r1_bio->state)) {
- if (!rdev_set_badblocks(rdev, r1_bio->sector, s, 0))
- md_error(conf->mddev, rdev);
- }
+ test_bit(R1BIO_WriteError, &r1_bio->state))
+ rdev_set_badblocks(rdev, r1_bio->sector, s, 0);
}
put_buf(r1_bio);
- md_done_sync(conf->mddev, s, 1);
+ md_done_sync(conf->mddev, s);
}
static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
@@ -2597,10 +2587,7 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
* errors.
*/
fail = true;
- if (!narrow_write_error(r1_bio, m))
- md_error(conf->mddev,
- conf->mirrors[m].rdev);
- /* an I/O failed, we can't clear the bitmap */
+ narrow_write_error(r1_bio, m);
rdev_dec_pending(conf->mirrors[m].rdev,
conf->mddev);
}
@@ -2955,16 +2942,12 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
*skipped = 1;
put_buf(r1_bio);
- if (!ok) {
- /* Cannot record the badblocks, so need to
+ if (!ok)
+ /* Cannot record the badblocks, md_error has set INTR,
* abort the resync.
- * If there are multiple read targets, could just
- * fail the really bad ones ???
*/
- conf->recovery_disabled = mddev->recovery_disabled;
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
return 0;
- } else
+ else
return min_bad;
}
@@ -3151,7 +3134,6 @@ static struct r1conf *setup_conf(struct mddev *mddev)
init_waitqueue_head(&conf->wait_barrier);
bio_list_init(&conf->pending_bio_list);
- conf->recovery_disabled = mddev->recovery_disabled - 1;
err = -EIO;
for (i = 0; i < conf->raid_disks * 2; i++) {
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index 2ebe35aaa534..c98d43a7ae99 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -93,11 +93,6 @@ struct r1conf {
*/
int fullsync;
- /* When the same as mddev->recovery_disabled we don't allow
- * recovery to be attempted as we expect a read error.
- */
- int recovery_disabled;
-
mempool_t *r1bio_pool;
mempool_t r1buf_pool;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 84be4cc7e873..9debb20cf129 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1990,7 +1990,7 @@ static int enough(struct r10conf *conf, int ignore)
* - &mddev->degraded is bumped.
*
* @rdev is marked as &Faulty excluding case when array is failed and
- * &mddev->fail_last_dev is off.
+ * MD_FAILLAST_DEV is not set.
*/
static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)
{
@@ -2002,7 +2002,7 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)
if (test_bit(In_sync, &rdev->flags) && !enough(conf, rdev->raid_disk)) {
set_bit(MD_BROKEN, &mddev->flags);
- if (!mddev->fail_last_dev) {
+ if (!test_bit(MD_FAILLAST_DEV, &mddev->flags)) {
spin_unlock_irqrestore(&conf->device_lock, flags);
return;
}
@@ -2130,8 +2130,6 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
mirror = first;
for ( ; mirror <= last ; mirror++) {
p = &conf->mirrors[mirror];
- if (p->recovery_disabled == mddev->recovery_disabled)
- continue;
if (p->rdev) {
if (test_bit(WantReplacement, &p->rdev->flags) &&
p->replacement == NULL && repl_slot < 0)
@@ -2143,7 +2141,6 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
if (err)
return err;
p->head_position = 0;
- p->recovery_disabled = mddev->recovery_disabled - 1;
rdev->raid_disk = mirror;
err = 0;
if (rdev->saved_raid_disk != mirror)
@@ -2196,7 +2193,6 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
* is not possible.
*/
if (!test_bit(Faulty, &rdev->flags) &&
- mddev->recovery_disabled != p->recovery_disabled &&
(!p->replacement || p->replacement == rdev) &&
number < conf->geo.raid_disks &&
enough(conf, -1)) {
@@ -2276,7 +2272,7 @@ static void end_sync_request(struct r10bio *r10_bio)
reschedule_retry(r10_bio);
else
put_buf(r10_bio);
- md_done_sync(mddev, s, 1);
+ md_done_sync(mddev, s);
break;
} else {
struct r10bio *r10_bio2 = (struct r10bio *)r10_bio->master_bio;
@@ -2452,7 +2448,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
done:
if (atomic_dec_and_test(&r10_bio->remaining)) {
- md_done_sync(mddev, r10_bio->sectors, 1);
+ md_done_sync(mddev, r10_bio->sectors);
put_buf(r10_bio);
}
}
@@ -2535,8 +2531,6 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
pr_notice("md/raid10:%s: recovery aborted due to read error\n",
mdname(mddev));
- conf->mirrors[dw].recovery_disabled
- = mddev->recovery_disabled;
set_bit(MD_RECOVERY_INTR,
&mddev->recovery);
break;
@@ -2604,8 +2598,7 @@ static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
&rdev->mddev->recovery);
}
/* need to record an error - either for the block or the device */
- if (!rdev_set_badblocks(rdev, sector, sectors, 0))
- md_error(rdev->mddev, rdev);
+ rdev_set_badblocks(rdev, sector, sectors, 0);
return 0;
}
@@ -2686,7 +2679,6 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
r10_bio->devs[slot].addr
+ sect,
s, 0)) {
- md_error(mddev, rdev);
r10_bio->devs[slot].bio
= IO_BLOCKED;
}
@@ -2773,7 +2765,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
}
}
-static bool narrow_write_error(struct r10bio *r10_bio, int i)
+static void narrow_write_error(struct r10bio *r10_bio, int i)
{
struct bio *bio = r10_bio->master_bio;
struct mddev *mddev = r10_bio->mddev;
@@ -2790,17 +2782,16 @@ static bool narrow_write_error(struct r10bio *r10_bio, int i)
* We currently own a reference to the rdev.
*/
- int block_sectors;
+ int block_sectors, lbs = bdev_logical_block_size(rdev->bdev) >> 9;
sector_t sector;
int sectors;
int sect_to_write = r10_bio->sectors;
- bool ok = true;
if (rdev->badblocks.shift < 0)
- return false;
+ block_sectors = lbs;
+ else
+ block_sectors = roundup(1 << rdev->badblocks.shift, lbs);
- block_sectors = roundup(1 << rdev->badblocks.shift,
- bdev_logical_block_size(rdev->bdev) >> 9);
sector = r10_bio->sector;
sectors = ((r10_bio->sector + block_sectors)
& ~(sector_t)(block_sectors - 1))
@@ -2820,18 +2811,21 @@ static bool narrow_write_error(struct r10bio *r10_bio, int i)
choose_data_offset(r10_bio, rdev);
wbio->bi_opf = REQ_OP_WRITE;
- if (submit_bio_wait(wbio) < 0)
- /* Failure! */
- ok = rdev_set_badblocks(rdev, wsector,
- sectors, 0)
- && ok;
+ if (submit_bio_wait(wbio) &&
+ !rdev_set_badblocks(rdev, wsector, sectors, 0)) {
+ /*
+ * Badblocks set failed, disk marked Faulty.
+ * No further operations needed.
+ */
+ bio_put(wbio);
+ break;
+ }
bio_put(wbio);
sect_to_write -= sectors;
sector += sectors;
sectors = block_sectors;
}
- return ok;
}
static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
@@ -2891,35 +2885,29 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
if (r10_bio->devs[m].bio == NULL ||
r10_bio->devs[m].bio->bi_end_io == NULL)
continue;
- if (!r10_bio->devs[m].bio->bi_status) {
+ if (!r10_bio->devs[m].bio->bi_status)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
r10_bio->sectors, 0);
- } else {
- if (!rdev_set_badblocks(
- rdev,
- r10_bio->devs[m].addr,
- r10_bio->sectors, 0))
- md_error(conf->mddev, rdev);
- }
+ else
+ rdev_set_badblocks(rdev,
+ r10_bio->devs[m].addr,
+ r10_bio->sectors, 0);
rdev = conf->mirrors[dev].replacement;
if (r10_bio->devs[m].repl_bio == NULL ||
r10_bio->devs[m].repl_bio->bi_end_io == NULL)
continue;
- if (!r10_bio->devs[m].repl_bio->bi_status) {
+ if (!r10_bio->devs[m].repl_bio->bi_status)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
r10_bio->sectors, 0);
- } else {
- if (!rdev_set_badblocks(
- rdev,
- r10_bio->devs[m].addr,
- r10_bio->sectors, 0))
- md_error(conf->mddev, rdev);
- }
+ else
+ rdev_set_badblocks(rdev,
+ r10_bio->devs[m].addr,
+ r10_bio->sectors, 0);
}
put_buf(r10_bio);
} else {
@@ -2936,8 +2924,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_dec_pending(rdev, conf->mddev);
} else if (bio != NULL && bio->bi_status) {
fail = true;
- if (!narrow_write_error(r10_bio, m))
- md_error(conf->mddev, rdev);
+ narrow_write_error(r10_bio, m);
rdev_dec_pending(rdev, conf->mddev);
}
bio = r10_bio->devs[m].repl_bio;
@@ -3168,11 +3155,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
int i;
int max_sync;
sector_t sync_blocks;
- sector_t sectors_skipped = 0;
- int chunks_skipped = 0;
sector_t chunk_mask = conf->geo.chunk_mask;
int page_idx = 0;
- int error_disk = -1;
/*
* Allow skipping a full rebuild for incremental assembly
@@ -3193,7 +3177,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
if (init_resync(conf))
return 0;
- skipped:
if (sector_nr >= max_sector) {
conf->cluster_sync_low = 0;
conf->cluster_sync_high = 0;
@@ -3245,33 +3228,12 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
mddev->bitmap_ops->close_sync(mddev);
close_sync(conf);
*skipped = 1;
- return sectors_skipped;
+ return 0;
}
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
return reshape_request(mddev, sector_nr, skipped);
- if (chunks_skipped >= conf->geo.raid_disks) {
- pr_err("md/raid10:%s: %s fails\n", mdname(mddev),
- test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? "resync" : "recovery");
- if (error_disk >= 0 &&
- !test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- /*
- * recovery fails, set mirrors.recovery_disabled,
- * device shouldn't be added to there.
- */
- conf->mirrors[error_disk].recovery_disabled =
- mddev->recovery_disabled;
- return 0;
- }
- /*
- * if there has been nothing to do on any drive,
- * then there is nothing to do at all.
- */
- *skipped = 1;
- return (max_sector - sector_nr) + sectors_skipped;
- }
-
if (max_sector > mddev->resync_max)
max_sector = mddev->resync_max; /* Don't do IO beyond here */
@@ -3354,7 +3316,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
/* yep, skip the sync_blocks here, but don't assume
* that there will never be anything to do here
*/
- chunks_skipped = -1;
continue;
}
if (mrdev)
@@ -3402,7 +3363,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
!test_bit(In_sync, &rdev->flags))
continue;
/* This is where we read from */
- any_working = 1;
sector = r10_bio->devs[j].addr;
if (is_badblock(rdev, sector, max_sync,
@@ -3417,6 +3377,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
continue;
}
}
+ any_working = 1;
bio = r10_bio->devs[0].bio;
bio->bi_next = biolist;
biolist = bio;
@@ -3485,29 +3446,19 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
for (k = 0; k < conf->copies; k++)
if (r10_bio->devs[k].devnum == i)
break;
- if (mrdev && !test_bit(In_sync,
- &mrdev->flags)
- && !rdev_set_badblocks(
- mrdev,
- r10_bio->devs[k].addr,
- max_sync, 0))
- any_working = 0;
- if (mreplace &&
- !rdev_set_badblocks(
- mreplace,
- r10_bio->devs[k].addr,
- max_sync, 0))
- any_working = 0;
- }
- if (!any_working) {
- if (!test_and_set_bit(MD_RECOVERY_INTR,
- &mddev->recovery))
- pr_warn("md/raid10:%s: insufficient working devices for recovery.\n",
- mdname(mddev));
- mirror->recovery_disabled
- = mddev->recovery_disabled;
- } else {
- error_disk = i;
+ if (mrdev &&
+ !test_bit(In_sync, &mrdev->flags))
+ rdev_set_badblocks(
+ mrdev,
+ r10_bio->devs[k].addr,
+ max_sync, 0);
+ if (mreplace)
+ rdev_set_badblocks(
+ mreplace,
+ r10_bio->devs[k].addr,
+ max_sync, 0);
+ pr_warn("md/raid10:%s: cannot recovery sector %llu + %d.\n",
+ mdname(mddev), r10_bio->devs[k].addr, max_sync);
}
put_buf(r10_bio);
if (rb2)
@@ -3548,7 +3499,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
rb2->master_bio = NULL;
put_buf(rb2);
}
- goto giveup;
+ *skipped = 1;
+ return max_sync;
}
} else {
/* resync. Schedule a read for every block at this virt offset */
@@ -3572,7 +3524,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
&mddev->recovery)) {
/* We can skip this block */
*skipped = 1;
- return sync_blocks + sectors_skipped;
+ return sync_blocks;
}
if (sync_blocks < max_sync)
max_sync = sync_blocks;
@@ -3664,8 +3616,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
mddev);
}
put_buf(r10_bio);
- biolist = NULL;
- goto giveup;
+ *skipped = 1;
+ return max_sync;
}
}
@@ -3685,7 +3637,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
if (WARN_ON(!bio_add_page(bio, page, len, 0))) {
bio->bi_status = BLK_STS_RESOURCE;
bio_endio(bio);
- goto giveup;
+ *skipped = 1;
+ return max_sync;
}
}
nr_sectors += len>>9;
@@ -3753,25 +3706,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
}
}
- if (sectors_skipped)
- /* pretend they weren't skipped, it makes
- * no important difference in this case
- */
- md_done_sync(mddev, sectors_skipped, 1);
-
- return sectors_skipped + nr_sectors;
- giveup:
- /* There is nowhere to write, so all non-sync
- * drives must be failed or in resync, all drives
- * have a bad block, so try the next chunk...
- */
- if (sector_nr + max_sync < max_sector)
- max_sector = sector_nr + max_sync;
-
- sectors_skipped += (max_sector - sector_nr);
- chunks_skipped ++;
- sector_nr = max_sector;
- goto skipped;
+ return nr_sectors;
}
static sector_t
@@ -4134,8 +4069,6 @@ static int raid10_run(struct mddev *mddev)
disk->replacement->saved_raid_disk < 0) {
conf->fullsync = 1;
}
-
- disk->recovery_disabled = mddev->recovery_disabled - 1;
}
if (mddev->resync_offset != MaxSector)
@@ -4913,7 +4846,8 @@ static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio)
if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
if (handle_reshape_read_error(mddev, r10_bio) < 0) {
/* Reshape has been aborted */
- md_done_sync(mddev, r10_bio->sectors, 0);
+ md_done_sync(mddev, r10_bio->sectors);
+ md_sync_error(mddev);
return;
}
@@ -5071,7 +5005,7 @@ static void end_reshape_request(struct r10bio *r10_bio)
{
if (!atomic_dec_and_test(&r10_bio->remaining))
return;
- md_done_sync(r10_bio->mddev, r10_bio->sectors, 1);
+ md_done_sync(r10_bio->mddev, r10_bio->sectors);
bio_put(r10_bio->master_bio);
put_buf(r10_bio);
}
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index da00a55f7a55..ec79d87fb92f 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -18,11 +18,6 @@
struct raid10_info {
struct md_rdev *rdev, *replacement;
sector_t head_position;
- int recovery_disabled; /* matches
- * mddev->recovery_disabled
- * when we shouldn't try
- * recovering this device.
- */
};
struct r10conf {
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 8dc98f545969..8854e024f311 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -56,7 +56,11 @@
#include "md-bitmap.h"
#include "raid5-log.h"
-#define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED)
+#define UNSUPPORTED_MDDEV_FLAGS \
+ ((1L << MD_FAILFAST_SUPPORTED) | \
+ (1L << MD_FAILLAST_DEV) | \
+ (1L << MD_SERIALIZE_POLICY))
+
#define cpu_to_group(cpu) cpu_to_node(cpu)
#define ANY_GROUP NUMA_NO_NODE
@@ -773,14 +777,14 @@ struct stripe_request_ctx {
/* last sector in the request */
sector_t last_sector;
+ /* the request had REQ_PREFLUSH, cleared after the first stripe_head */
+ bool do_flush;
+
/*
* bitmap to track stripe sectors that have been added to stripes
* add one to account for unaligned requests
*/
- DECLARE_BITMAP(sectors_to_do, RAID5_MAX_REQ_STRIPES + 1);
-
- /* the request had REQ_PREFLUSH, cleared after the first stripe_head */
- bool do_flush;
+ unsigned long sectors_to_do[];
};
/*
@@ -2817,11 +2821,9 @@ static void raid5_end_read_request(struct bio * bi)
else {
clear_bit(R5_ReadError, &sh->dev[i].flags);
clear_bit(R5_ReWrite, &sh->dev[i].flags);
- if (!(set_bad
- && test_bit(In_sync, &rdev->flags)
- && rdev_set_badblocks(
- rdev, sh->sector, RAID5_STRIPE_SECTORS(conf), 0)))
- md_error(conf->mddev, rdev);
+ if (!(set_bad && test_bit(In_sync, &rdev->flags)))
+ rdev_set_badblocks(rdev, sh->sector,
+ RAID5_STRIPE_SECTORS(conf), 0);
}
}
rdev_dec_pending(rdev, conf->mddev);
@@ -2920,7 +2922,6 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev)
if (has_failed(conf)) {
set_bit(MD_BROKEN, &conf->mddev->flags);
- conf->recovery_disabled = mddev->recovery_disabled;
pr_crit("md/raid:%s: Cannot continue operation (%d/%d failed).\n",
mdname(mddev), mddev->degraded, conf->raid_disks);
@@ -3599,11 +3600,10 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
else
rdev = NULL;
if (rdev) {
- if (!rdev_set_badblocks(
- rdev,
- sh->sector,
- RAID5_STRIPE_SECTORS(conf), 0))
- md_error(conf->mddev, rdev);
+ rdev_set_badblocks(rdev,
+ sh->sector,
+ RAID5_STRIPE_SECTORS(conf),
+ 0);
rdev_dec_pending(rdev, conf->mddev);
}
}
@@ -3723,11 +3723,11 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh,
RAID5_STRIPE_SECTORS(conf), 0))
abort = 1;
}
- if (abort)
- conf->recovery_disabled =
- conf->mddev->recovery_disabled;
}
- md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf), !abort);
+ md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf));
+
+ if (abort)
+ md_sync_error(conf->mddev);
}
static int want_replace(struct stripe_head *sh, int disk_idx)
@@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s,
struct r5dev *dev = &sh->dev[disk_idx];
struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]],
&sh->dev[s->failed_num[1]] };
+ struct mddev *mddev = sh->raid_conf->mddev;
+ bool force_rcw = false;
int i;
- bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW);
+ if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW ||
+ (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced &&
+ !mddev->bitmap_ops->blocks_synced(mddev, sh->sector)))
+ force_rcw = true;
if (test_bit(R5_LOCKED, &dev->flags) ||
test_bit(R5_UPTODATE, &dev->flags))
@@ -5157,7 +5162,7 @@ static void handle_stripe(struct stripe_head *sh)
if ((s.syncing || s.replacing) && s.locked == 0 &&
!test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
test_bit(STRIPE_INSYNC, &sh->state)) {
- md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf), 1);
+ md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf));
clear_bit(STRIPE_SYNCING, &sh->state);
if (test_and_clear_bit(R5_Overlap, &sh->dev[sh->pd_idx].flags))
wake_up_bit(&sh->dev[sh->pd_idx].flags, R5_Overlap);
@@ -5224,7 +5229,7 @@ static void handle_stripe(struct stripe_head *sh)
clear_bit(STRIPE_EXPAND_READY, &sh->state);
atomic_dec(&conf->reshape_stripes);
wake_up(&conf->wait_for_reshape);
- md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf), 1);
+ md_done_sync(conf->mddev, RAID5_STRIPE_SECTORS(conf));
}
if (s.expanding && s.locked == 0 &&
@@ -5253,9 +5258,8 @@ finish:
if (test_and_clear_bit(R5_WriteError, &dev->flags)) {
/* We own a safe reference to the rdev */
rdev = conf->disks[i].rdev;
- if (!rdev_set_badblocks(rdev, sh->sector,
- RAID5_STRIPE_SECTORS(conf), 0))
- md_error(conf->mddev, rdev);
+ rdev_set_badblocks(rdev, sh->sector,
+ RAID5_STRIPE_SECTORS(conf), 0);
rdev_dec_pending(rdev, conf->mddev);
}
if (test_and_clear_bit(R5_MadeGood, &dev->flags)) {
@@ -6080,13 +6084,13 @@ static sector_t raid5_bio_lowest_chunk_sector(struct r5conf *conf,
static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
{
DEFINE_WAIT_FUNC(wait, woken_wake_function);
- bool on_wq;
struct r5conf *conf = mddev->private;
- sector_t logical_sector;
- struct stripe_request_ctx ctx = {};
const int rw = bio_data_dir(bi);
+ struct stripe_request_ctx *ctx;
+ sector_t logical_sector;
enum stripe_result res;
int s, stripe_cnt;
+ bool on_wq;
if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
int ret = log_handle_flush_request(conf, bi);
@@ -6098,11 +6102,6 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
return true;
}
/* ret == -EAGAIN, fallback */
- /*
- * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
- * we need to flush journal device
- */
- ctx.do_flush = bi->bi_opf & REQ_PREFLUSH;
}
md_write_start(mddev, bi);
@@ -6125,16 +6124,25 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
}
logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
- ctx.first_sector = logical_sector;
- ctx.last_sector = bio_end_sector(bi);
bi->bi_next = NULL;
- stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx.last_sector - logical_sector,
+ ctx = mempool_alloc(conf->ctx_pool, GFP_NOIO);
+ memset(ctx, 0, conf->ctx_size);
+ ctx->first_sector = logical_sector;
+ ctx->last_sector = bio_end_sector(bi);
+ /*
+ * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
+ * we need to flush journal device
+ */
+ if (unlikely(bi->bi_opf & REQ_PREFLUSH))
+ ctx->do_flush = true;
+
+ stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx->last_sector - logical_sector,
RAID5_STRIPE_SECTORS(conf));
- bitmap_set(ctx.sectors_to_do, 0, stripe_cnt);
+ bitmap_set(ctx->sectors_to_do, 0, stripe_cnt);
pr_debug("raid456: %s, logical %llu to %llu\n", __func__,
- bi->bi_iter.bi_sector, ctx.last_sector);
+ bi->bi_iter.bi_sector, ctx->last_sector);
/* Bail out if conflicts with reshape and REQ_NOWAIT is set */
if ((bi->bi_opf & REQ_NOWAIT) &&
@@ -6142,6 +6150,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
bio_wouldblock_error(bi);
if (rw == WRITE)
md_write_end(mddev);
+ mempool_free(ctx, conf->ctx_pool);
return true;
}
md_account_bio(mddev, &bi);
@@ -6160,10 +6169,10 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
add_wait_queue(&conf->wait_for_reshape, &wait);
on_wq = true;
}
- s = (logical_sector - ctx.first_sector) >> RAID5_STRIPE_SHIFT(conf);
+ s = (logical_sector - ctx->first_sector) >> RAID5_STRIPE_SHIFT(conf);
while (1) {
- res = make_stripe_request(mddev, conf, &ctx, logical_sector,
+ res = make_stripe_request(mddev, conf, ctx, logical_sector,
bi);
if (res == STRIPE_FAIL || res == STRIPE_WAIT_RESHAPE)
break;
@@ -6180,9 +6189,9 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
* raid5_activate_delayed() from making progress
* and thus deadlocking.
*/
- if (ctx.batch_last) {
- raid5_release_stripe(ctx.batch_last);
- ctx.batch_last = NULL;
+ if (ctx->batch_last) {
+ raid5_release_stripe(ctx->batch_last);
+ ctx->batch_last = NULL;
}
wait_woken(&wait, TASK_UNINTERRUPTIBLE,
@@ -6190,21 +6199,23 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
continue;
}
- s = find_next_bit_wrap(ctx.sectors_to_do, stripe_cnt, s);
+ s = find_next_bit_wrap(ctx->sectors_to_do, stripe_cnt, s);
if (s == stripe_cnt)
break;
- logical_sector = ctx.first_sector +
+ logical_sector = ctx->first_sector +
(s << RAID5_STRIPE_SHIFT(conf));
}
if (unlikely(on_wq))
remove_wait_queue(&conf->wait_for_reshape, &wait);
- if (ctx.batch_last)
- raid5_release_stripe(ctx.batch_last);
+ if (ctx->batch_last)
+ raid5_release_stripe(ctx->batch_last);
if (rw == WRITE)
md_write_end(mddev);
+
+ mempool_free(ctx, conf->ctx_pool);
if (res == STRIPE_WAIT_RESHAPE) {
md_free_cloned_bio(bi);
return false;
@@ -7374,6 +7385,9 @@ static void free_conf(struct r5conf *conf)
bioset_exit(&conf->bio_split);
kfree(conf->stripe_hashtbl);
kfree(conf->pending_data);
+
+ mempool_destroy(conf->ctx_pool);
+
kfree(conf);
}
@@ -7536,8 +7550,6 @@ static struct r5conf *setup_conf(struct mddev *mddev)
}
conf->bypass_threshold = BYPASS_THRESHOLD;
- conf->recovery_disabled = mddev->recovery_disabled - 1;
-
conf->raid_disks = mddev->raid_disks;
if (mddev->reshape_position == MaxSector)
conf->previous_raid_disks = mddev->raid_disks;
@@ -7729,6 +7741,25 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded
return 0;
}
+static int raid5_create_ctx_pool(struct r5conf *conf)
+{
+ struct stripe_request_ctx *ctx;
+ int size;
+
+ if (mddev_is_dm(conf->mddev))
+ size = BITS_TO_LONGS(RAID5_MAX_REQ_STRIPES);
+ else
+ size = BITS_TO_LONGS(
+ queue_max_hw_sectors(conf->mddev->gendisk->queue) >>
+ RAID5_STRIPE_SHIFT(conf));
+
+ conf->ctx_size = struct_size(ctx, sectors_to_do, size);
+ conf->ctx_pool = mempool_create_kmalloc_pool(NR_RAID_BIOS,
+ conf->ctx_size);
+
+ return conf->ctx_pool ? 0 : -ENOMEM;
+}
+
static int raid5_set_limits(struct mddev *mddev)
{
struct r5conf *conf = mddev->private;
@@ -7785,6 +7816,8 @@ static int raid5_set_limits(struct mddev *mddev)
* Limit the max sectors based on this.
*/
lim.max_hw_sectors = RAID5_MAX_REQ_STRIPES << RAID5_STRIPE_SHIFT(conf);
+ if ((lim.max_hw_sectors << 9) < lim.io_opt)
+ lim.max_hw_sectors = lim.io_opt >> 9;
/* No restrictions on the number of segments in the request */
lim.max_segments = USHRT_MAX;
@@ -8057,7 +8090,12 @@ static int raid5_run(struct mddev *mddev)
goto abort;
}
- if (log_init(conf, journal_dev, raid5_has_ppl(conf)))
+ ret = raid5_create_ctx_pool(conf);
+ if (ret)
+ goto abort;
+
+ ret = log_init(conf, journal_dev, raid5_has_ppl(conf));
+ if (ret)
goto abort;
return 0;
@@ -8211,7 +8249,6 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
* isn't possible.
*/
if (!test_bit(Faulty, &rdev->flags) &&
- mddev->recovery_disabled != conf->recovery_disabled &&
!has_failed(conf) &&
(!p->replacement || p->replacement == rdev) &&
number < conf->raid_disks) {
@@ -8272,8 +8309,6 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
return 0;
}
- if (mddev->recovery_disabled == conf->recovery_disabled)
- return -EBUSY;
if (rdev->saved_raid_disk < 0 && has_failed(conf))
/* no point adding a device */
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index eafc6e9ed6ee..110b1c2d0a86 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -640,7 +640,6 @@ struct r5conf {
* (fresh device added).
* Cleared when a sync completes.
*/
- int recovery_disabled;
/* per cpu variables */
struct raid5_percpu __percpu *percpu;
int scribble_disks;
@@ -690,6 +689,9 @@ struct r5conf {
struct list_head pending_list;
int pending_data_cnt;
struct r5pending_data *next_pending_data;
+
+ mempool_t *ctx_pool;
+ int ctx_size;
};
#if PAGE_SIZE == DEFAULT_STRIPE_SIZE