|
@@ -1308,7 +1308,12 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
|
|
}
|
|
}
|
|
if (mddev->level != LEVEL_MULTIPATH) {
|
|
if (mddev->level != LEVEL_MULTIPATH) {
|
|
int role;
|
|
int role;
|
|
- role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
|
|
|
|
|
|
+ if (rdev->desc_nr < 0 ||
|
|
|
|
+ rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
|
|
|
|
+ role = 0xffff;
|
|
|
|
+ rdev->desc_nr = -1;
|
|
|
|
+ } else
|
|
|
|
+ role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
|
|
switch(role) {
|
|
switch(role) {
|
|
case 0xffff: /* spare */
|
|
case 0xffff: /* spare */
|
|
break;
|
|
break;
|
|
@@ -1394,8 +1399,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
|
|
if (rdev2->desc_nr+1 > max_dev)
|
|
if (rdev2->desc_nr+1 > max_dev)
|
|
max_dev = rdev2->desc_nr+1;
|
|
max_dev = rdev2->desc_nr+1;
|
|
|
|
|
|
- if (max_dev > le32_to_cpu(sb->max_dev))
|
|
|
|
|
|
+ if (max_dev > le32_to_cpu(sb->max_dev)) {
|
|
|
|
+ int bmask;
|
|
sb->max_dev = cpu_to_le32(max_dev);
|
|
sb->max_dev = cpu_to_le32(max_dev);
|
|
|
|
+ rdev->sb_size = max_dev * 2 + 256;
|
|
|
|
+ bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
|
|
|
|
+ if (rdev->sb_size & bmask)
|
|
|
|
+ rdev->sb_size = (rdev->sb_size | bmask) + 1;
|
|
|
|
+ }
|
|
for (i=0; i<max_dev;i++)
|
|
for (i=0; i<max_dev;i++)
|
|
sb->dev_roles[i] = cpu_to_le16(0xfffe);
|
|
sb->dev_roles[i] = cpu_to_le16(0xfffe);
|
|
|
|
|
|
@@ -1487,37 +1498,76 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
|
|
|
|
|
|
static LIST_HEAD(pending_raid_disks);
|
|
static LIST_HEAD(pending_raid_disks);
|
|
|
|
|
|
-static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev)
|
|
|
|
|
|
+/*
|
|
|
|
+ * Try to register data integrity profile for an mddev
|
|
|
|
+ *
|
|
|
|
+ * This is called when an array is started and after a disk has been kicked
|
|
|
|
+ * from the array. It only succeeds if all working and active component devices
|
|
|
|
+ * are integrity capable with matching profiles.
|
|
|
|
+ */
|
|
|
|
+int md_integrity_register(mddev_t *mddev)
|
|
|
|
+{
|
|
|
|
+ mdk_rdev_t *rdev, *reference = NULL;
|
|
|
|
+
|
|
|
|
+ if (list_empty(&mddev->disks))
|
|
|
|
+ return 0; /* nothing to do */
|
|
|
|
+ if (blk_get_integrity(mddev->gendisk))
|
|
|
|
+ return 0; /* already registered */
|
|
|
|
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
|
|
|
|
+ /* skip spares and non-functional disks */
|
|
|
|
+ if (test_bit(Faulty, &rdev->flags))
|
|
|
|
+ continue;
|
|
|
|
+ if (rdev->raid_disk < 0)
|
|
|
|
+ continue;
|
|
|
|
+ /*
|
|
|
|
+ * If at least one rdev is not integrity capable, we can not
|
|
|
|
+ * enable data integrity for the md device.
|
|
|
|
+ */
|
|
|
|
+ if (!bdev_get_integrity(rdev->bdev))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ if (!reference) {
|
|
|
|
+ /* Use the first rdev as the reference */
|
|
|
|
+ reference = rdev;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ /* does this rdev's profile match the reference profile? */
|
|
|
|
+ if (blk_integrity_compare(reference->bdev->bd_disk,
|
|
|
|
+ rdev->bdev->bd_disk) < 0)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * All component devices are integrity capable and have matching
|
|
|
|
+ * profiles, register the common profile for the md device.
|
|
|
|
+ */
|
|
|
|
+ if (blk_integrity_register(mddev->gendisk,
|
|
|
|
+ bdev_get_integrity(reference->bdev)) != 0) {
|
|
|
|
+ printk(KERN_ERR "md: failed to register integrity for %s\n",
|
|
|
|
+ mdname(mddev));
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ printk(KERN_NOTICE "md: data integrity on %s enabled\n",
|
|
|
|
+ mdname(mddev));
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(md_integrity_register);
|
|
|
|
+
|
|
|
|
+/* Disable data integrity if non-capable/non-matching disk is being added */
|
|
|
|
+void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
|
|
{
|
|
{
|
|
- struct mdk_personality *pers = mddev->pers;
|
|
|
|
- struct gendisk *disk = mddev->gendisk;
|
|
|
|
struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev);
|
|
struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev);
|
|
- struct blk_integrity *bi_mddev = blk_get_integrity(disk);
|
|
|
|
|
|
+ struct blk_integrity *bi_mddev = blk_get_integrity(mddev->gendisk);
|
|
|
|
|
|
- /* Data integrity passthrough not supported on RAID 4, 5 and 6 */
|
|
|
|
- if (pers && pers->level >= 4 && pers->level <= 6)
|
|
|
|
|
|
+ if (!bi_mddev) /* nothing to do */
|
|
return;
|
|
return;
|
|
-
|
|
|
|
- /* If rdev is integrity capable, register profile for mddev */
|
|
|
|
- if (!bi_mddev && bi_rdev) {
|
|
|
|
- if (blk_integrity_register(disk, bi_rdev))
|
|
|
|
- printk(KERN_ERR "%s: %s Could not register integrity!\n",
|
|
|
|
- __func__, disk->disk_name);
|
|
|
|
- else
|
|
|
|
- printk(KERN_NOTICE "Enabling data integrity on %s\n",
|
|
|
|
- disk->disk_name);
|
|
|
|
|
|
+ if (rdev->raid_disk < 0) /* skip spares */
|
|
return;
|
|
return;
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Check that mddev and rdev have matching profiles */
|
|
|
|
- if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) {
|
|
|
|
- printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__,
|
|
|
|
- disk->disk_name, rdev->bdev->bd_disk->disk_name);
|
|
|
|
- printk(KERN_NOTICE "Disabling data integrity on %s\n",
|
|
|
|
- disk->disk_name);
|
|
|
|
- blk_integrity_unregister(disk);
|
|
|
|
- }
|
|
|
|
|
|
+ if (bi_rdev && blk_integrity_compare(mddev->gendisk,
|
|
|
|
+ rdev->bdev->bd_disk) >= 0)
|
|
|
|
+ return;
|
|
|
|
+ printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev));
|
|
|
|
+ blk_integrity_unregister(mddev->gendisk);
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL(md_integrity_add_rdev);
|
|
|
|
|
|
static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
|
|
static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
|
|
{
|
|
{
|
|
@@ -1591,7 +1641,6 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
|
|
/* May as well allow recovery to be retried once */
|
|
/* May as well allow recovery to be retried once */
|
|
mddev->recovery_disabled = 0;
|
|
mddev->recovery_disabled = 0;
|
|
|
|
|
|
- md_integrity_check(rdev, mddev);
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
fail:
|
|
fail:
|
|
@@ -2657,6 +2706,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
|
|
ssize_t rv = len;
|
|
ssize_t rv = len;
|
|
struct mdk_personality *pers;
|
|
struct mdk_personality *pers;
|
|
void *priv;
|
|
void *priv;
|
|
|
|
+ mdk_rdev_t *rdev;
|
|
|
|
|
|
if (mddev->pers == NULL) {
|
|
if (mddev->pers == NULL) {
|
|
if (len == 0)
|
|
if (len == 0)
|
|
@@ -2736,6 +2786,12 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
|
|
mddev_suspend(mddev);
|
|
mddev_suspend(mddev);
|
|
mddev->pers->stop(mddev);
|
|
mddev->pers->stop(mddev);
|
|
module_put(mddev->pers->owner);
|
|
module_put(mddev->pers->owner);
|
|
|
|
+ /* Invalidate devices that are now superfluous */
|
|
|
|
+ list_for_each_entry(rdev, &mddev->disks, same_set)
|
|
|
|
+ if (rdev->raid_disk >= mddev->raid_disks) {
|
|
|
|
+ rdev->raid_disk = -1;
|
|
|
|
+ clear_bit(In_sync, &rdev->flags);
|
|
|
|
+ }
|
|
mddev->pers = pers;
|
|
mddev->pers = pers;
|
|
mddev->private = priv;
|
|
mddev->private = priv;
|
|
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
|
|
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
|
|
@@ -3685,17 +3741,8 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len)
|
|
|
|
|
|
mddev->array_sectors = sectors;
|
|
mddev->array_sectors = sectors;
|
|
set_capacity(mddev->gendisk, mddev->array_sectors);
|
|
set_capacity(mddev->gendisk, mddev->array_sectors);
|
|
- if (mddev->pers) {
|
|
|
|
- struct block_device *bdev = bdget_disk(mddev->gendisk, 0);
|
|
|
|
-
|
|
|
|
- if (bdev) {
|
|
|
|
- mutex_lock(&bdev->bd_inode->i_mutex);
|
|
|
|
- i_size_write(bdev->bd_inode,
|
|
|
|
- (loff_t)mddev->array_sectors << 9);
|
|
|
|
- mutex_unlock(&bdev->bd_inode->i_mutex);
|
|
|
|
- bdput(bdev);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (mddev->pers)
|
|
|
|
+ revalidate_disk(mddev->gendisk);
|
|
|
|
|
|
return len;
|
|
return len;
|
|
}
|
|
}
|
|
@@ -4048,10 +4095,6 @@ static int do_md_run(mddev_t * mddev)
|
|
}
|
|
}
|
|
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
|
|
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
|
|
|
|
|
|
- if (pers->level >= 4 && pers->level <= 6)
|
|
|
|
- /* Cannot support integrity (yet) */
|
|
|
|
- blk_integrity_unregister(mddev->gendisk);
|
|
|
|
-
|
|
|
|
if (mddev->reshape_position != MaxSector &&
|
|
if (mddev->reshape_position != MaxSector &&
|
|
pers->start_reshape == NULL) {
|
|
pers->start_reshape == NULL) {
|
|
/* This personality cannot handle reshaping... */
|
|
/* This personality cannot handle reshaping... */
|
|
@@ -4189,6 +4232,7 @@ static int do_md_run(mddev_t * mddev)
|
|
md_wakeup_thread(mddev->thread);
|
|
md_wakeup_thread(mddev->thread);
|
|
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
|
|
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
|
|
|
|
|
|
|
|
+ revalidate_disk(mddev->gendisk);
|
|
mddev->changed = 1;
|
|
mddev->changed = 1;
|
|
md_new_event(mddev);
|
|
md_new_event(mddev);
|
|
sysfs_notify_dirent(mddev->sysfs_state);
|
|
sysfs_notify_dirent(mddev->sysfs_state);
|
|
@@ -5087,18 +5131,8 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
}
|
|
}
|
|
rv = mddev->pers->resize(mddev, num_sectors);
|
|
rv = mddev->pers->resize(mddev, num_sectors);
|
|
- if (!rv) {
|
|
|
|
- struct block_device *bdev;
|
|
|
|
-
|
|
|
|
- bdev = bdget_disk(mddev->gendisk, 0);
|
|
|
|
- if (bdev) {
|
|
|
|
- mutex_lock(&bdev->bd_inode->i_mutex);
|
|
|
|
- i_size_write(bdev->bd_inode,
|
|
|
|
- (loff_t)mddev->array_sectors << 9);
|
|
|
|
- mutex_unlock(&bdev->bd_inode->i_mutex);
|
|
|
|
- bdput(bdev);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (!rv)
|
|
|
|
+ revalidate_disk(mddev->gendisk);
|
|
return rv;
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
|