Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Documentation/admin-guide/md.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ Boot time autodetection of RAID arrays
When md is compiled into the kernel (not as module), partitions of
type 0xfd are scanned and automatically assembled into RAID arrays.
This autodetection may be suppressed with the kernel parameter
``raid=noautodetect``. As of kernel 2.6.9, only drives with a type 0
superblock can be autodetected and run at boot time.
``raid=noautodetect``.

The kernel parameter ``raid=partitionable`` (or ``raid=part``) means
that all auto-detected arrays are assembled as partitionable.
Expand Down
56 changes: 41 additions & 15 deletions drivers/md/md-autodetect.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,48 @@ static void __init md_setup_drive(struct md_setup_args *args)
ainfo.raid_disks++;
}

err = md_set_array_info(mddev, &ainfo);

for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
struct mdu_disk_info_s dinfo = {
.major = MAJOR(devices[i]),
.minor = MINOR(devices[i]),
};

if (args->level != LEVEL_NONE) {
dinfo.number = i;
dinfo.raid_disk = i;
dinfo.state =
(1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
}
if (args->level != LEVEL_NONE) {
err = md_set_array_info(mddev, &ainfo);
for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
struct mdu_disk_info_s dinfo = {
.major = MAJOR(devices[i]),
.minor = MINOR(devices[i]),
};

if (args->level != LEVEL_NONE) {
dinfo.number = i;
dinfo.raid_disk = i;
dinfo.state =
(1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
}

md_add_new_disk(mddev, &dinfo);
md_add_new_disk(mddev, &dinfo);
}
} else {
ainfo.major_version = -1;
ainfo.minor_version = -1;
for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
struct md_rdev *rdev = NULL;

if (ainfo.major_version < 0) {
rdev = md_guess_super_import_device(devices[i]);
if (rdev == NULL)
continue;
ainfo.major_version = rdev->sb_major_version;
ainfo.minor_version = rdev->sb_minor_version;
err = md_set_array_info(mddev, &ainfo);
if (err) {
pr_warn("md: couldn't update array info. %d\n", err);
break;
}
} else {
rdev = md_import_device(devices[i],
ainfo.major_version, ainfo.minor_version);
if (rdev == NULL)
continue;
}
md_autodetect_bind_export_rdev(rdev, mddev);
}
}

if (!err)
Expand Down
89 changes: 79 additions & 10 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -2521,6 +2521,15 @@ static void export_rdev(struct md_rdev *rdev, struct mddev *mddev)
kobject_put(&rdev->kobj);
}

int md_autodetect_bind_export_rdev(struct md_rdev *rdev, struct mddev *mddev)
{
int err = bind_rdev_to_array(rdev, mddev);

if (err)
export_rdev(rdev, mddev);
return err;
}

static void md_kick_rdev_from_array(struct md_rdev *rdev)
{
struct mddev *mddev = rdev->mddev;
Expand Down Expand Up @@ -3686,7 +3695,7 @@ EXPORT_SYMBOL_GPL(md_rdev_init);
*
* a faulty rdev _never_ has rdev->sb set.
*/
static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
{
struct md_rdev *rdev;
sector_t size;
Expand Down Expand Up @@ -3740,10 +3749,13 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
}
}

rdev->sb_major_version = super_format;
rdev->sb_minor_version = super_minor;

return rdev;

out_blkdev_put:
fput(rdev->bdev_file);
bdev_fput(rdev->bdev_file);
out_clear_rdev:
md_rdev_clear(rdev);
out_free_rdev:
Expand Down Expand Up @@ -6695,6 +6707,11 @@ static void autorun_devices(int part)
{
struct md_rdev *rdev0, *rdev, *tmp;
struct mddev *mddev;
/*
* Version 1 superblocks don't store a preferred minor number,
* assign a high one here so we get no conflicts
*/
int preferred_minor_1 = 0xffff;

pr_info("md: autorun ...\n");
while (!list_empty(&pending_raid_disks)) {
Expand All @@ -6706,28 +6723,50 @@ static void autorun_devices(int part)

pr_debug("md: considering %pg ...\n", rdev0->bdev);
INIT_LIST_HEAD(&candidates);
rdev_for_each_list(rdev, tmp, &pending_raid_disks)
if (super_90_load(rdev, rdev0, 0) >= 0) {
rdev_for_each_list(rdev, tmp, &pending_raid_disks) {
if (rdev0->sb_major_version != rdev->sb_major_version ||
rdev0->sb_minor_version != rdev->sb_minor_version) {
pr_debug("md: Versions don't match with %pg ...\n",
rdev->bdev);
continue;
}
if (super_types[rdev->sb_major_version].load_super(rdev,
rdev0,
rdev0->sb_minor_version
) >= 0) {
pr_debug("md: adding %pg ...\n",
rdev->bdev);
list_move(&rdev->same_set, &candidates);
}
}
/*
* now we have a set of devices, with all of them having
* mostly sane superblocks. It's time to allocate the
* mddev.
*/

int minor = rdev0->preferred_minor;

if (rdev0->sb_major_version == 1) {
if (preferred_minor_1 < 0) {
pr_warn("md: no free minor number left for v1 superblock\n");
break;
}
minor = preferred_minor_1;
preferred_minor_1--;
}

if (part) {
dev = MKDEV(mdp_major,
rdev0->preferred_minor << MdpMinorShift);
minor << MdpMinorShift);
unit = MINOR(dev) >> MdpMinorShift;
} else {
dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
dev = MKDEV(MD_MAJOR, minor);
unit = MINOR(dev);
}
if (rdev0->preferred_minor != unit) {
if (minor != unit) {
pr_warn("md: unit number in %pg is bad: %d\n",
rdev0->bdev, rdev0->preferred_minor);
rdev0->bdev, minor);
break;
}

Expand All @@ -6745,6 +6784,10 @@ static void autorun_devices(int part)
} else {
pr_debug("md: created %s\n", mdname(mddev));
mddev->persistent = 1;

mddev->major_version = rdev0->sb_major_version;
mddev->minor_version = rdev0->sb_minor_version;

rdev_for_each_list(rdev, tmp, &candidates) {
list_del_init(&rdev->same_set);
if (bind_rdev_to_array(rdev, mddev))
Expand Down Expand Up @@ -10261,6 +10304,32 @@ void md_autodetect_dev(dev_t dev)
}
}

struct md_sb_type {
int major;
int minor;
};

static const struct md_sb_type super_versions[4] = {
{0, 90},
{1, 2},
{1, 1},
{1, 0}
};

struct md_rdev *md_guess_super_import_device(dev_t dev)
{
const struct md_sb_type *super;
struct md_rdev *rdev;

for (int i = 0; i < ARRAY_SIZE(super_versions); i++) {
super = &super_versions[i];
rdev = md_import_device(dev, super->major, super->minor);
if (!IS_ERR_OR_NULL(rdev))
return rdev;
}
return NULL; /* No valid superblock found */
}

void md_autostart_arrays(int part)
{
struct md_rdev *rdev;
Expand All @@ -10282,9 +10351,9 @@ void md_autostart_arrays(int part)
dev = node_detected_dev->dev;
kfree(node_detected_dev);
mutex_unlock(&detected_devices_mutex);
rdev = md_import_device(dev,0, 90);
rdev = md_guess_super_import_device(dev);
mutex_lock(&detected_devices_mutex);
if (IS_ERR(rdev))
if (rdev == NULL)
continue;

if (test_bit(Faulty, &rdev->flags))
Expand Down
4 changes: 4 additions & 0 deletions drivers/md/md.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ struct md_rdev {

struct page *sb_page, *bb_page;
int sb_loaded;
int sb_major_version, sb_minor_version;
__u64 sb_events;
sector_t data_offset; /* start of data in array */
sector_t new_data_offset;/* only relevant while reshaping */
Expand Down Expand Up @@ -899,6 +900,7 @@ extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev);
int md_autodetect_bind_export_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);

extern int mddev_init(struct mddev *mddev);
Expand All @@ -911,6 +913,7 @@ extern int md_start(struct mddev *mddev);
extern void md_stop(struct mddev *mddev);
extern void md_stop_writes(struct mddev *mddev);
extern int md_rdev_init(struct md_rdev *rdev);
struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor);
extern void md_rdev_clear(struct md_rdev *rdev);

extern bool md_handle_request(struct mddev *mddev, struct bio *bio);
Expand Down Expand Up @@ -992,6 +995,7 @@ struct mdu_disk_info_s;

extern int mdp_major;
extern struct workqueue_struct *md_bitmap_wq;
struct md_rdev *md_guess_super_import_device(dev_t dev);
void md_autostart_arrays(int part);
int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info);
int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info);
Expand Down