#include <linux/kthread.h>
#include <linux/raid/md.h>
-#include <linux/raid/bitmap.h>
#include <linux/sysctl.h>
#include <linux/buffer_head.h> /* for invalidate_bdev */
#include <linux/poll.h>
#include <linux/reboot.h>
#include <linux/file.h>
#include <linux/delay.h>
-
-#define MAJOR_NR MD_MAJOR
+#include "bitmap.h"
/* 63 partitions with the alternate major number (mdp) */
#define MdpMinorShift 6
* causes ENOTSUPP, we allocate a spare bio...
*/
struct bio *bio = bio_alloc(GFP_NOIO, 1);
- int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNC);
+ int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNCIO) | (1<<BIO_RW_UNPLUG);
bio->bi_bdev = rdev->bdev;
bio->bi_sector = sector;
struct completion event;
int ret;
- rw |= (1 << BIO_RW_SYNC);
+ rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
bio->bi_bdev = bdev;
bio->bi_sector = sector;
static LIST_HEAD(pending_raid_disks);
+static void md_integrity_check(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_mddev = blk_get_integrity(disk);
+
+ /* Data integrity passthrough not supported on RAID 4, 5 and 6 */
+ if (pers && pers->level >= 4 && pers->level <= 6)
+ 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);
+ 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);
+ }
+}
+
static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
{
char b[BDEVNAME_SIZE];
if (find_rdev_nr(mddev, rdev->desc_nr))
return -EBUSY;
}
+ if (mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
+ printk(KERN_WARNING "md: %s: array is limited to %d devices\n",
+ mdname(mddev), mddev->max_disks);
+ return -EBUSY;
+ }
bdevname(rdev->bdev,b);
while ( (s=strchr(b, '/')) != NULL)
*s = '!';
/* May as well allow recovery to be retried once */
mddev->recovery_disabled = 0;
+
+ md_integrity_check(rdev, mddev);
return 0;
fail:
i = 0;
rdev_for_each(rdev, tmp, mddev) {
+ if (rdev->desc_nr >= mddev->max_disks ||
+ i > mddev->max_disks) {
+ printk(KERN_WARNING
+ "md: %s: %s: only %d devices permitted\n",
+ mdname(mddev), bdevname(rdev->bdev, b),
+ mddev->max_disks);
+ kick_rdev_from_array(rdev);
+ continue;
+ }
if (rdev != freshest)
if (super_types[mddev->major_version].
validate_super(mddev, rdev)) {
mddev->level = pers->level;
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 &&
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
printk(KERN_INFO "md: %s switched to read-only mode.\n",
mdname(mddev));
err = 0;
+ blk_integrity_unregister(disk);
md_new_event(mddev);
sysfs_notify_dirent(mddev->sysfs_state);
out:
* noticed in interrupt contexts ...
*/
- if (rdev->desc_nr == mddev->max_disks) {
- printk(KERN_WARNING "%s: can not hot-add to full array!\n",
- mdname(mddev));
- err = -EBUSY;
- goto abort_unbind_export;
- }
-
rdev->raid_disk = -1;
md_update_sb(mddev, 1);
md_new_event(mddev);
return 0;
-abort_unbind_export:
- unbind_rdev_from_array(rdev);
-
abort_export:
export_rdev(rdev);
return err;
return 0;
}
-static int is_mddev_idle(mddev_t *mddev)
+static int is_mddev_idle(mddev_t *mddev, int init)
{
mdk_rdev_t * rdev;
int idle;
- long curr_events;
+ int curr_events;
idle = 1;
rcu_read_lock();
rdev_for_each_rcu(rdev, mddev) {
struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
- curr_events = part_stat_read(&disk->part0, sectors[0]) +
- part_stat_read(&disk->part0, sectors[1]) -
- atomic_read(&disk->sync_io);
+ curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
+ (int)part_stat_read(&disk->part0, sectors[1]) -
+ atomic_read(&disk->sync_io);
/* sync IO will cause sync_io to increase before the disk_stats
* as sync_io is counted when a request starts, and
* disk_stats is counted when it completes.
* always make curr_events less than last_events.
*
*/
- if (curr_events - rdev->last_events > 4096) {
+ if (init || curr_events - rdev->last_events > 64) {
rdev->last_events = curr_events;
idle = 0;
}
"(but not more than %d KB/sec) for %s.\n",
speed_max(mddev), desc);
- is_mddev_idle(mddev); /* this also initializes IO event counters */
+ is_mddev_idle(mddev, 1); /* this initializes IO event counters */
io_sectors = 0;
for (m = 0; m < SYNC_MARKS; m++) {
if (currspeed > speed_min(mddev)) {
if ((currspeed > speed_max(mddev)) ||
- !is_mddev_idle(mddev)) {
+ !is_mddev_idle(mddev, 0)) {
msleep(500);
goto repeat;
}
static int __init md_init(void)
{
- if (register_blkdev(MAJOR_NR, "md"))
+ if (register_blkdev(MD_MAJOR, "md"))
return -1;
if ((mdp_major=register_blkdev(0, "mdp"))<=0) {
- unregister_blkdev(MAJOR_NR, "md");
+ unregister_blkdev(MD_MAJOR, "md");
return -1;
}
- blk_register_region(MKDEV(MAJOR_NR, 0), 1UL<<MINORBITS, THIS_MODULE,
+ blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE,
md_probe, NULL, NULL);
blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,
md_probe, NULL, NULL);
mddev_t *mddev;
struct list_head *tmp;
- blk_unregister_region(MKDEV(MAJOR_NR,0), 1U << MINORBITS);
+ blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS);
blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);
- unregister_blkdev(MAJOR_NR,"md");
+ unregister_blkdev(MD_MAJOR,"md");
unregister_blkdev(mdp_major, "mdp");
unregister_reboot_notifier(&md_notifier);
unregister_sysctl_table(raid_table_header);