|
@@ -206,15 +206,6 @@ void md_new_event(struct mddev *mddev)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(md_new_event);
|
|
EXPORT_SYMBOL_GPL(md_new_event);
|
|
|
|
|
|
-/* Alternate version that can be called from interrupts
|
|
|
|
- * when calling sysfs_notify isn't needed.
|
|
|
|
- */
|
|
|
|
-static void md_new_event_inintr(struct mddev *mddev)
|
|
|
|
-{
|
|
|
|
- atomic_inc(&md_event_count);
|
|
|
|
- wake_up(&md_event_waiters);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Enables to iterate over all existing md arrays
|
|
* Enables to iterate over all existing md arrays
|
|
* all_mddevs_lock protects this list.
|
|
* all_mddevs_lock protects this list.
|
|
@@ -260,8 +251,7 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
|
|
|
|
|
|
blk_queue_split(q, &bio, q->bio_split);
|
|
blk_queue_split(q, &bio, q->bio_split);
|
|
|
|
|
|
- if (mddev == NULL || mddev->pers == NULL
|
|
|
|
- || !mddev->ready) {
|
|
|
|
|
|
+ if (mddev == NULL || mddev->pers == NULL) {
|
|
bio_io_error(bio);
|
|
bio_io_error(bio);
|
|
return BLK_QC_T_NONE;
|
|
return BLK_QC_T_NONE;
|
|
}
|
|
}
|
|
@@ -1026,8 +1016,9 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
|
|
* (not needed for Linear and RAID0 as metadata doesn't
|
|
* (not needed for Linear and RAID0 as metadata doesn't
|
|
* record this size)
|
|
* record this size)
|
|
*/
|
|
*/
|
|
- if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
|
|
|
|
- rdev->sectors = (2ULL << 32) - 2;
|
|
|
|
|
|
+ if (IS_ENABLED(CONFIG_LBDAF) && (u64)rdev->sectors >= (2ULL << 32) &&
|
|
|
|
+ sb->level >= 1)
|
|
|
|
+ rdev->sectors = (sector_t)(2ULL << 32) - 2;
|
|
|
|
|
|
if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
|
|
if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
|
|
/* "this cannot possibly happen" ... */
|
|
/* "this cannot possibly happen" ... */
|
|
@@ -1199,13 +1190,13 @@ static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev)
|
|
memcpy(&sb->set_uuid2, mddev->uuid+8, 4);
|
|
memcpy(&sb->set_uuid2, mddev->uuid+8, 4);
|
|
memcpy(&sb->set_uuid3, mddev->uuid+12,4);
|
|
memcpy(&sb->set_uuid3, mddev->uuid+12,4);
|
|
|
|
|
|
- sb->ctime = mddev->ctime;
|
|
|
|
|
|
+ sb->ctime = clamp_t(time64_t, mddev->ctime, 0, U32_MAX);
|
|
sb->level = mddev->level;
|
|
sb->level = mddev->level;
|
|
sb->size = mddev->dev_sectors / 2;
|
|
sb->size = mddev->dev_sectors / 2;
|
|
sb->raid_disks = mddev->raid_disks;
|
|
sb->raid_disks = mddev->raid_disks;
|
|
sb->md_minor = mddev->md_minor;
|
|
sb->md_minor = mddev->md_minor;
|
|
sb->not_persistent = 0;
|
|
sb->not_persistent = 0;
|
|
- sb->utime = mddev->utime;
|
|
|
|
|
|
+ sb->utime = clamp_t(time64_t, mddev->utime, 0, U32_MAX);
|
|
sb->state = 0;
|
|
sb->state = 0;
|
|
sb->events_hi = (mddev->events>>32);
|
|
sb->events_hi = (mddev->events>>32);
|
|
sb->events_lo = (u32)mddev->events;
|
|
sb->events_lo = (u32)mddev->events;
|
|
@@ -1320,8 +1311,9 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
|
|
/* Limit to 4TB as metadata cannot record more than that.
|
|
/* Limit to 4TB as metadata cannot record more than that.
|
|
* 4TB == 2^32 KB, or 2*2^32 sectors.
|
|
* 4TB == 2^32 KB, or 2*2^32 sectors.
|
|
*/
|
|
*/
|
|
- if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
|
|
|
|
- num_sectors = (2ULL << 32) - 2;
|
|
|
|
|
|
+ if (IS_ENABLED(CONFIG_LBDAF) && (u64)num_sectors >= (2ULL << 32) &&
|
|
|
|
+ rdev->mddev->level >= 1)
|
|
|
|
+ num_sectors = (sector_t)(2ULL << 32) - 2;
|
|
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
|
|
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
|
|
rdev->sb_page);
|
|
rdev->sb_page);
|
|
md_super_wait(rdev->mddev);
|
|
md_super_wait(rdev->mddev);
|
|
@@ -1542,8 +1534,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
|
|
mddev->patch_version = 0;
|
|
mddev->patch_version = 0;
|
|
mddev->external = 0;
|
|
mddev->external = 0;
|
|
mddev->chunk_sectors = le32_to_cpu(sb->chunksize);
|
|
mddev->chunk_sectors = le32_to_cpu(sb->chunksize);
|
|
- mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
|
|
|
|
- mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
|
|
|
|
|
|
+ mddev->ctime = le64_to_cpu(sb->ctime);
|
|
|
|
+ mddev->utime = le64_to_cpu(sb->utime);
|
|
mddev->level = le32_to_cpu(sb->level);
|
|
mddev->level = le32_to_cpu(sb->level);
|
|
mddev->clevel[0] = 0;
|
|
mddev->clevel[0] = 0;
|
|
mddev->layout = le32_to_cpu(sb->layout);
|
|
mddev->layout = le32_to_cpu(sb->layout);
|
|
@@ -1602,6 +1594,11 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
|
|
mddev->new_chunk_sectors = mddev->chunk_sectors;
|
|
mddev->new_chunk_sectors = mddev->chunk_sectors;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL) {
|
|
|
|
+ set_bit(MD_HAS_JOURNAL, &mddev->flags);
|
|
|
|
+ if (mddev->recovery_cp == MaxSector)
|
|
|
|
+ set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
|
|
|
|
+ }
|
|
} else if (mddev->pers == NULL) {
|
|
} else if (mddev->pers == NULL) {
|
|
/* Insist of good event counter while assembling, except for
|
|
/* Insist of good event counter while assembling, except for
|
|
* spares (which don't need an event count) */
|
|
* spares (which don't need an event count) */
|
|
@@ -1648,8 +1645,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
|
|
}
|
|
}
|
|
set_bit(Journal, &rdev->flags);
|
|
set_bit(Journal, &rdev->flags);
|
|
rdev->journal_tail = le64_to_cpu(sb->journal_tail);
|
|
rdev->journal_tail = le64_to_cpu(sb->journal_tail);
|
|
- if (mddev->recovery_cp == MaxSector)
|
|
|
|
- set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
|
|
|
|
rdev->raid_disk = 0;
|
|
rdev->raid_disk = 0;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
@@ -1669,8 +1664,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
|
|
set_bit(WriteMostly, &rdev->flags);
|
|
set_bit(WriteMostly, &rdev->flags);
|
|
if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT)
|
|
if (le32_to_cpu(sb->feature_map) & MD_FEATURE_REPLACEMENT)
|
|
set_bit(Replacement, &rdev->flags);
|
|
set_bit(Replacement, &rdev->flags);
|
|
- if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL)
|
|
|
|
- set_bit(MD_HAS_JOURNAL, &mddev->flags);
|
|
|
|
} else /* MULTIPATH are always insync */
|
|
} else /* MULTIPATH are always insync */
|
|
set_bit(In_sync, &rdev->flags);
|
|
set_bit(In_sync, &rdev->flags);
|
|
|
|
|
|
@@ -2014,28 +2007,32 @@ int md_integrity_register(struct mddev *mddev)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(md_integrity_register);
|
|
EXPORT_SYMBOL(md_integrity_register);
|
|
|
|
|
|
-/* Disable data integrity if non-capable/non-matching disk is being added */
|
|
|
|
-void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
|
|
|
|
|
|
+/*
|
|
|
|
+ * Attempt to add an rdev, but only if it is consistent with the current
|
|
|
|
+ * integrity profile
|
|
|
|
+ */
|
|
|
|
+int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
|
|
{
|
|
{
|
|
struct blk_integrity *bi_rdev;
|
|
struct blk_integrity *bi_rdev;
|
|
struct blk_integrity *bi_mddev;
|
|
struct blk_integrity *bi_mddev;
|
|
|
|
+ char name[BDEVNAME_SIZE];
|
|
|
|
|
|
if (!mddev->gendisk)
|
|
if (!mddev->gendisk)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
bi_rdev = bdev_get_integrity(rdev->bdev);
|
|
bi_rdev = bdev_get_integrity(rdev->bdev);
|
|
bi_mddev = blk_get_integrity(mddev->gendisk);
|
|
bi_mddev = blk_get_integrity(mddev->gendisk);
|
|
|
|
|
|
if (!bi_mddev) /* nothing to do */
|
|
if (!bi_mddev) /* nothing to do */
|
|
- return;
|
|
|
|
- if (rdev->raid_disk < 0) /* skip spares */
|
|
|
|
- return;
|
|
|
|
- if (bi_rdev && blk_integrity_compare(mddev->gendisk,
|
|
|
|
- rdev->bdev->bd_disk) >= 0)
|
|
|
|
- return;
|
|
|
|
- WARN_ON_ONCE(!mddev->suspended);
|
|
|
|
- printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev));
|
|
|
|
- blk_integrity_unregister(mddev->gendisk);
|
|
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (blk_integrity_compare(mddev->gendisk, rdev->bdev->bd_disk) != 0) {
|
|
|
|
+ printk(KERN_NOTICE "%s: incompatible integrity profile for %s\n",
|
|
|
|
+ mdname(mddev), bdevname(rdev->bdev, name));
|
|
|
|
+ return -ENXIO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(md_integrity_add_rdev);
|
|
EXPORT_SYMBOL(md_integrity_add_rdev);
|
|
|
|
|
|
@@ -2050,8 +2047,9 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
|
|
return -EEXIST;
|
|
return -EEXIST;
|
|
|
|
|
|
/* make sure rdev->sectors exceeds mddev->dev_sectors */
|
|
/* make sure rdev->sectors exceeds mddev->dev_sectors */
|
|
- if (rdev->sectors && (mddev->dev_sectors == 0 ||
|
|
|
|
- rdev->sectors < mddev->dev_sectors)) {
|
|
|
|
|
|
+ if (!test_bit(Journal, &rdev->flags) &&
|
|
|
|
+ rdev->sectors &&
|
|
|
|
+ (mddev->dev_sectors == 0 || rdev->sectors < mddev->dev_sectors)) {
|
|
if (mddev->pers) {
|
|
if (mddev->pers) {
|
|
/* Cannot change size, so fail
|
|
/* Cannot change size, so fail
|
|
* If mddev->level <= 0, then we don't care
|
|
* If mddev->level <= 0, then we don't care
|
|
@@ -2082,7 +2080,8 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
- if (mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
|
|
|
|
|
|
+ if (!test_bit(Journal, &rdev->flags) &&
|
|
|
|
+ mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
|
|
printk(KERN_WARNING "md: %s: array is limited to %d devices\n",
|
|
printk(KERN_WARNING "md: %s: array is limited to %d devices\n",
|
|
mdname(mddev), mddev->max_disks);
|
|
mdname(mddev), mddev->max_disks);
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
@@ -2331,7 +2330,7 @@ repeat:
|
|
|
|
|
|
spin_lock(&mddev->lock);
|
|
spin_lock(&mddev->lock);
|
|
|
|
|
|
- mddev->utime = get_seconds();
|
|
|
|
|
|
+ mddev->utime = ktime_get_real_seconds();
|
|
|
|
|
|
if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
|
|
if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
|
|
force_change = 1;
|
|
force_change = 1;
|
|
@@ -2457,15 +2456,20 @@ static int add_bound_rdev(struct md_rdev *rdev)
|
|
{
|
|
{
|
|
struct mddev *mddev = rdev->mddev;
|
|
struct mddev *mddev = rdev->mddev;
|
|
int err = 0;
|
|
int err = 0;
|
|
|
|
+ bool add_journal = test_bit(Journal, &rdev->flags);
|
|
|
|
|
|
- if (!mddev->pers->hot_remove_disk) {
|
|
|
|
|
|
+ if (!mddev->pers->hot_remove_disk || add_journal) {
|
|
/* If there is hot_add_disk but no hot_remove_disk
|
|
/* If there is hot_add_disk but no hot_remove_disk
|
|
* then added disks for geometry changes,
|
|
* then added disks for geometry changes,
|
|
* and should be added immediately.
|
|
* and should be added immediately.
|
|
*/
|
|
*/
|
|
super_types[mddev->major_version].
|
|
super_types[mddev->major_version].
|
|
validate_super(mddev, rdev);
|
|
validate_super(mddev, rdev);
|
|
|
|
+ if (add_journal)
|
|
|
|
+ mddev_suspend(mddev);
|
|
err = mddev->pers->hot_add_disk(mddev, rdev);
|
|
err = mddev->pers->hot_add_disk(mddev, rdev);
|
|
|
|
+ if (add_journal)
|
|
|
|
+ mddev_resume(mddev);
|
|
if (err) {
|
|
if (err) {
|
|
unbind_rdev_from_array(rdev);
|
|
unbind_rdev_from_array(rdev);
|
|
export_rdev(rdev);
|
|
export_rdev(rdev);
|
|
@@ -5299,7 +5303,6 @@ int md_run(struct mddev *mddev)
|
|
smp_wmb();
|
|
smp_wmb();
|
|
spin_lock(&mddev->lock);
|
|
spin_lock(&mddev->lock);
|
|
mddev->pers = pers;
|
|
mddev->pers = pers;
|
|
- mddev->ready = 1;
|
|
|
|
spin_unlock(&mddev->lock);
|
|
spin_unlock(&mddev->lock);
|
|
rdev_for_each(rdev, mddev)
|
|
rdev_for_each(rdev, mddev)
|
|
if (rdev->raid_disk >= 0)
|
|
if (rdev->raid_disk >= 0)
|
|
@@ -5499,7 +5502,6 @@ static void __md_stop(struct mddev *mddev)
|
|
/* Ensure ->event_work is done */
|
|
/* Ensure ->event_work is done */
|
|
flush_workqueue(md_misc_wq);
|
|
flush_workqueue(md_misc_wq);
|
|
spin_lock(&mddev->lock);
|
|
spin_lock(&mddev->lock);
|
|
- mddev->ready = 0;
|
|
|
|
mddev->pers = NULL;
|
|
mddev->pers = NULL;
|
|
spin_unlock(&mddev->lock);
|
|
spin_unlock(&mddev->lock);
|
|
pers->free(mddev, mddev->private);
|
|
pers->free(mddev, mddev->private);
|
|
@@ -5837,7 +5839,7 @@ static int get_array_info(struct mddev *mddev, void __user *arg)
|
|
info.major_version = mddev->major_version;
|
|
info.major_version = mddev->major_version;
|
|
info.minor_version = mddev->minor_version;
|
|
info.minor_version = mddev->minor_version;
|
|
info.patch_version = MD_PATCHLEVEL_VERSION;
|
|
info.patch_version = MD_PATCHLEVEL_VERSION;
|
|
- info.ctime = mddev->ctime;
|
|
|
|
|
|
+ info.ctime = clamp_t(time64_t, mddev->ctime, 0, U32_MAX);
|
|
info.level = mddev->level;
|
|
info.level = mddev->level;
|
|
info.size = mddev->dev_sectors / 2;
|
|
info.size = mddev->dev_sectors / 2;
|
|
if (info.size != mddev->dev_sectors / 2) /* overflow */
|
|
if (info.size != mddev->dev_sectors / 2) /* overflow */
|
|
@@ -5847,7 +5849,7 @@ static int get_array_info(struct mddev *mddev, void __user *arg)
|
|
info.md_minor = mddev->md_minor;
|
|
info.md_minor = mddev->md_minor;
|
|
info.not_persistent= !mddev->persistent;
|
|
info.not_persistent= !mddev->persistent;
|
|
|
|
|
|
- info.utime = mddev->utime;
|
|
|
|
|
|
+ info.utime = clamp_t(time64_t, mddev->utime, 0, U32_MAX);
|
|
info.state = 0;
|
|
info.state = 0;
|
|
if (mddev->in_sync)
|
|
if (mddev->in_sync)
|
|
info.state = (1<<MD_SB_CLEAN);
|
|
info.state = (1<<MD_SB_CLEAN);
|
|
@@ -6038,8 +6040,23 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info)
|
|
else
|
|
else
|
|
clear_bit(WriteMostly, &rdev->flags);
|
|
clear_bit(WriteMostly, &rdev->flags);
|
|
|
|
|
|
- if (info->state & (1<<MD_DISK_JOURNAL))
|
|
|
|
|
|
+ if (info->state & (1<<MD_DISK_JOURNAL)) {
|
|
|
|
+ struct md_rdev *rdev2;
|
|
|
|
+ bool has_journal = false;
|
|
|
|
+
|
|
|
|
+ /* make sure no existing journal disk */
|
|
|
|
+ rdev_for_each(rdev2, mddev) {
|
|
|
|
+ if (test_bit(Journal, &rdev2->flags)) {
|
|
|
|
+ has_journal = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (has_journal) {
|
|
|
|
+ export_rdev(rdev);
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ }
|
|
set_bit(Journal, &rdev->flags);
|
|
set_bit(Journal, &rdev->flags);
|
|
|
|
+ }
|
|
/*
|
|
/*
|
|
* check whether the device shows up in other nodes
|
|
* check whether the device shows up in other nodes
|
|
*/
|
|
*/
|
|
@@ -6130,15 +6147,11 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev)
|
|
{
|
|
{
|
|
char b[BDEVNAME_SIZE];
|
|
char b[BDEVNAME_SIZE];
|
|
struct md_rdev *rdev;
|
|
struct md_rdev *rdev;
|
|
- int ret = -1;
|
|
|
|
|
|
|
|
rdev = find_rdev(mddev, dev);
|
|
rdev = find_rdev(mddev, dev);
|
|
if (!rdev)
|
|
if (!rdev)
|
|
return -ENXIO;
|
|
return -ENXIO;
|
|
|
|
|
|
- if (mddev_is_clustered(mddev))
|
|
|
|
- ret = md_cluster_ops->metadata_update_start(mddev);
|
|
|
|
-
|
|
|
|
if (rdev->raid_disk < 0)
|
|
if (rdev->raid_disk < 0)
|
|
goto kick_rdev;
|
|
goto kick_rdev;
|
|
|
|
|
|
@@ -6149,7 +6162,7 @@ static int hot_remove_disk(struct mddev *mddev, dev_t dev)
|
|
goto busy;
|
|
goto busy;
|
|
|
|
|
|
kick_rdev:
|
|
kick_rdev:
|
|
- if (mddev_is_clustered(mddev) && ret == 0)
|
|
|
|
|
|
+ if (mddev_is_clustered(mddev))
|
|
md_cluster_ops->remove_disk(mddev, rdev);
|
|
md_cluster_ops->remove_disk(mddev, rdev);
|
|
|
|
|
|
md_kick_rdev_from_array(rdev);
|
|
md_kick_rdev_from_array(rdev);
|
|
@@ -6158,9 +6171,6 @@ kick_rdev:
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
busy:
|
|
busy:
|
|
- if (mddev_is_clustered(mddev) && ret == 0)
|
|
|
|
- md_cluster_ops->metadata_update_cancel(mddev);
|
|
|
|
-
|
|
|
|
printk(KERN_WARNING "md: cannot remove active disk %s from %s ...\n",
|
|
printk(KERN_WARNING "md: cannot remove active disk %s from %s ...\n",
|
|
bdevname(rdev->bdev,b), mdname(mddev));
|
|
bdevname(rdev->bdev,b), mdname(mddev));
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
@@ -6354,13 +6364,13 @@ static int set_array_info(struct mddev *mddev, mdu_array_info_t *info)
|
|
/* ensure mddev_put doesn't delete this now that there
|
|
/* ensure mddev_put doesn't delete this now that there
|
|
* is some minimal configuration.
|
|
* is some minimal configuration.
|
|
*/
|
|
*/
|
|
- mddev->ctime = get_seconds();
|
|
|
|
|
|
+ mddev->ctime = ktime_get_real_seconds();
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
mddev->major_version = MD_MAJOR_VERSION;
|
|
mddev->major_version = MD_MAJOR_VERSION;
|
|
mddev->minor_version = MD_MINOR_VERSION;
|
|
mddev->minor_version = MD_MINOR_VERSION;
|
|
mddev->patch_version = MD_PATCHLEVEL_VERSION;
|
|
mddev->patch_version = MD_PATCHLEVEL_VERSION;
|
|
- mddev->ctime = get_seconds();
|
|
|
|
|
|
+ mddev->ctime = ktime_get_real_seconds();
|
|
|
|
|
|
mddev->level = info->level;
|
|
mddev->level = info->level;
|
|
mddev->clevel[0] = 0;
|
|
mddev->clevel[0] = 0;
|
|
@@ -6602,6 +6612,19 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
|
|
rv = -EINVAL;
|
|
rv = -EINVAL;
|
|
goto err;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
+ if (mddev->bitmap_info.nodes) {
|
|
|
|
+ /* hold PW on all the bitmap lock */
|
|
|
|
+ if (md_cluster_ops->lock_all_bitmaps(mddev) <= 0) {
|
|
|
|
+ printk("md: can't change bitmap to none since the"
|
|
|
|
+ " array is in use by more than one node\n");
|
|
|
|
+ rv = -EPERM;
|
|
|
|
+ md_cluster_ops->unlock_all_bitmaps(mddev);
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mddev->bitmap_info.nodes = 0;
|
|
|
|
+ md_cluster_ops->leave(mddev);
|
|
|
|
+ }
|
|
mddev->pers->quiesce(mddev, 1);
|
|
mddev->pers->quiesce(mddev, 1);
|
|
bitmap_destroy(mddev);
|
|
bitmap_destroy(mddev);
|
|
mddev->pers->quiesce(mddev, 0);
|
|
mddev->pers->quiesce(mddev, 0);
|
|
@@ -7180,7 +7203,7 @@ void md_error(struct mddev *mddev, struct md_rdev *rdev)
|
|
md_wakeup_thread(mddev->thread);
|
|
md_wakeup_thread(mddev->thread);
|
|
if (mddev->event_work.func)
|
|
if (mddev->event_work.func)
|
|
queue_work(md_misc_wq, &mddev->event_work);
|
|
queue_work(md_misc_wq, &mddev->event_work);
|
|
- md_new_event_inintr(mddev);
|
|
|
|
|
|
+ md_new_event(mddev);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(md_error);
|
|
EXPORT_SYMBOL(md_error);
|
|
|
|
|
|
@@ -7704,7 +7727,7 @@ EXPORT_SYMBOL(md_write_end);
|
|
* attempting a GFP_KERNEL allocation while holding the mddev lock.
|
|
* attempting a GFP_KERNEL allocation while holding the mddev lock.
|
|
* Must be called with mddev_lock held.
|
|
* Must be called with mddev_lock held.
|
|
*
|
|
*
|
|
- * In the ->external case MD_CHANGE_CLEAN can not be cleared until mddev->lock
|
|
|
|
|
|
+ * In the ->external case MD_CHANGE_PENDING can not be cleared until mddev->lock
|
|
* is dropped, so return -EAGAIN after notifying userspace.
|
|
* is dropped, so return -EAGAIN after notifying userspace.
|
|
*/
|
|
*/
|
|
int md_allow_write(struct mddev *mddev)
|
|
int md_allow_write(struct mddev *mddev)
|
|
@@ -8169,19 +8192,20 @@ static int remove_and_add_spares(struct mddev *mddev,
|
|
continue;
|
|
continue;
|
|
if (test_bit(Faulty, &rdev->flags))
|
|
if (test_bit(Faulty, &rdev->flags))
|
|
continue;
|
|
continue;
|
|
- if (test_bit(Journal, &rdev->flags))
|
|
|
|
- continue;
|
|
|
|
- if (mddev->ro &&
|
|
|
|
- ! (rdev->saved_raid_disk >= 0 &&
|
|
|
|
- !test_bit(Bitmap_sync, &rdev->flags)))
|
|
|
|
- continue;
|
|
|
|
|
|
+ if (!test_bit(Journal, &rdev->flags)) {
|
|
|
|
+ if (mddev->ro &&
|
|
|
|
+ ! (rdev->saved_raid_disk >= 0 &&
|
|
|
|
+ !test_bit(Bitmap_sync, &rdev->flags)))
|
|
|
|
+ continue;
|
|
|
|
|
|
- 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) {
|
|
if (sysfs_link_rdev(mddev, rdev))
|
|
if (sysfs_link_rdev(mddev, rdev))
|
|
/* failure here is OK */;
|
|
/* failure here is OK */;
|
|
- spares++;
|
|
|
|
|
|
+ if (!test_bit(Journal, &rdev->flags))
|
|
|
|
+ spares++;
|
|
md_new_event(mddev);
|
|
md_new_event(mddev);
|
|
set_bit(MD_CHANGE_DEVS, &mddev->flags);
|
|
set_bit(MD_CHANGE_DEVS, &mddev->flags);
|
|
}
|
|
}
|
|
@@ -8276,6 +8300,7 @@ void md_check_recovery(struct mddev *mddev)
|
|
(mddev->flags & MD_UPDATE_SB_FLAGS & ~ (1<<MD_CHANGE_PENDING)) ||
|
|
(mddev->flags & MD_UPDATE_SB_FLAGS & ~ (1<<MD_CHANGE_PENDING)) ||
|
|
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
|
|
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
|
|
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
|
|
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
|
|
|
|
+ test_bit(MD_RELOAD_SB, &mddev->flags) ||
|
|
(mddev->external == 0 && mddev->safemode == 1) ||
|
|
(mddev->external == 0 && mddev->safemode == 1) ||
|
|
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
|
|
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
|
|
&& !mddev->in_sync && mddev->recovery_cp == MaxSector)
|
|
&& !mddev->in_sync && mddev->recovery_cp == MaxSector)
|
|
@@ -8314,6 +8339,21 @@ void md_check_recovery(struct mddev *mddev)
|
|
goto unlock;
|
|
goto unlock;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (mddev_is_clustered(mddev)) {
|
|
|
|
+ struct md_rdev *rdev;
|
|
|
|
+ /* kick the device if another node issued a
|
|
|
|
+ * remove disk.
|
|
|
|
+ */
|
|
|
|
+ rdev_for_each(rdev, mddev) {
|
|
|
|
+ if (test_and_clear_bit(ClusterRemove, &rdev->flags) &&
|
|
|
|
+ rdev->raid_disk < 0)
|
|
|
|
+ md_kick_rdev_from_array(rdev);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (test_and_clear_bit(MD_RELOAD_SB, &mddev->flags))
|
|
|
|
+ md_reload_sb(mddev, mddev->good_device_nr);
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!mddev->external) {
|
|
if (!mddev->external) {
|
|
int did_change = 0;
|
|
int did_change = 0;
|
|
spin_lock(&mddev->lock);
|
|
spin_lock(&mddev->lock);
|
|
@@ -8635,7 +8675,6 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
|
|
ret = remove_and_add_spares(mddev, rdev2);
|
|
ret = remove_and_add_spares(mddev, rdev2);
|
|
pr_info("Activated spare: %s\n",
|
|
pr_info("Activated spare: %s\n",
|
|
bdevname(rdev2->bdev,b));
|
|
bdevname(rdev2->bdev,b));
|
|
- continue;
|
|
|
|
}
|
|
}
|
|
/* device faulty
|
|
/* device faulty
|
|
* We just want to do the minimum to mark the disk
|
|
* We just want to do the minimum to mark the disk
|