14f5b246bSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
24f5b246bSChristoph Hellwig #include <linux/kernel.h>
34f5b246bSChristoph Hellwig #include <linux/blkdev.h>
44f5b246bSChristoph Hellwig #include <linux/init.h>
54f5b246bSChristoph Hellwig #include <linux/mount.h>
64f5b246bSChristoph Hellwig #include <linux/major.h>
74f5b246bSChristoph Hellwig #include <linux/delay.h>
8716308a5SChristoph Hellwig #include <linux/init_syscalls.h>
94f5b246bSChristoph Hellwig #include <linux/raid/detect.h>
104f5b246bSChristoph Hellwig #include <linux/raid/md_u.h>
114f5b246bSChristoph Hellwig #include <linux/raid/md_p.h>
12d82fa81cSChristoph Hellwig #include "md.h"
134f5b246bSChristoph Hellwig
144f5b246bSChristoph Hellwig /*
154f5b246bSChristoph Hellwig * When md (and any require personalities) are compiled into the kernel
164f5b246bSChristoph Hellwig * (not a module), arrays can be assembles are boot time using with AUTODETECT
174f5b246bSChristoph Hellwig * where specially marked partitions are registered with md_autodetect_dev(),
184f5b246bSChristoph Hellwig * and with MD_BOOT where devices to be collected are given on the boot line
194f5b246bSChristoph Hellwig * with md=.....
204f5b246bSChristoph Hellwig * The code for that is here.
214f5b246bSChristoph Hellwig */
224f5b246bSChristoph Hellwig
234f5b246bSChristoph Hellwig #ifdef CONFIG_MD_AUTODETECT
244f5b246bSChristoph Hellwig static int __initdata raid_noautodetect;
254f5b246bSChristoph Hellwig #else
264f5b246bSChristoph Hellwig static int __initdata raid_noautodetect=1;
274f5b246bSChristoph Hellwig #endif
284f5b246bSChristoph Hellwig static int __initdata raid_autopart;
294f5b246bSChristoph Hellwig
30d1100488SChristoph Hellwig static struct md_setup_args {
314f5b246bSChristoph Hellwig int minor;
324f5b246bSChristoph Hellwig int partitioned;
334f5b246bSChristoph Hellwig int level;
344f5b246bSChristoph Hellwig int chunk;
354f5b246bSChristoph Hellwig char *device_names;
364f5b246bSChristoph Hellwig } md_setup_args[256] __initdata;
374f5b246bSChristoph Hellwig
384f5b246bSChristoph Hellwig static int md_setup_ents __initdata;
394f5b246bSChristoph Hellwig
404f5b246bSChristoph Hellwig /*
414f5b246bSChristoph Hellwig * Parse the command-line parameters given our kernel, but do not
424f5b246bSChristoph Hellwig * actually try to invoke the MD device now; that is handled by
434f5b246bSChristoph Hellwig * md_setup_drive after the low-level disk drivers have initialised.
444f5b246bSChristoph Hellwig *
454f5b246bSChristoph Hellwig * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which
464f5b246bSChristoph Hellwig * assigns the task of parsing integer arguments to the
474f5b246bSChristoph Hellwig * invoked program now). Added ability to initialise all
484f5b246bSChristoph Hellwig * the MD devices (by specifying multiple "md=" lines)
494f5b246bSChristoph Hellwig * instead of just one. -- KTK
504f5b246bSChristoph Hellwig * 18May2000: Added support for persistent-superblock arrays:
514f5b246bSChristoph Hellwig * md=n,0,factor,fault,device-list uses RAID0 for device n
524f5b246bSChristoph Hellwig * md=n,-1,factor,fault,device-list uses LINEAR for device n
534f5b246bSChristoph Hellwig * md=n,device-list reads a RAID superblock from the devices
544f5b246bSChristoph Hellwig * elements in device-list are read by name_to_kdev_t so can be
554f5b246bSChristoph Hellwig * a hex number or something like /dev/hda1 /dev/sdb
564f5b246bSChristoph Hellwig * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
574f5b246bSChristoph Hellwig * Shifted name_to_kdev_t() and related operations to md_set_drive()
584f5b246bSChristoph Hellwig * for later execution. Rewrote section to make devfs compatible.
594f5b246bSChristoph Hellwig */
md_setup(char * str)604f5b246bSChristoph Hellwig static int __init md_setup(char *str)
614f5b246bSChristoph Hellwig {
624f5b246bSChristoph Hellwig int minor, level, factor, fault, partitioned = 0;
634f5b246bSChristoph Hellwig char *pername = "";
644f5b246bSChristoph Hellwig char *str1;
654f5b246bSChristoph Hellwig int ent;
664f5b246bSChristoph Hellwig
674f5b246bSChristoph Hellwig if (*str == 'd') {
684f5b246bSChristoph Hellwig partitioned = 1;
694f5b246bSChristoph Hellwig str++;
704f5b246bSChristoph Hellwig }
714f5b246bSChristoph Hellwig if (get_option(&str, &minor) != 2) { /* MD Number */
724f5b246bSChristoph Hellwig printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
734f5b246bSChristoph Hellwig return 0;
744f5b246bSChristoph Hellwig }
754f5b246bSChristoph Hellwig str1 = str;
764f5b246bSChristoph Hellwig for (ent=0 ; ent< md_setup_ents ; ent++)
774f5b246bSChristoph Hellwig if (md_setup_args[ent].minor == minor &&
784f5b246bSChristoph Hellwig md_setup_args[ent].partitioned == partitioned) {
794f5b246bSChristoph Hellwig printk(KERN_WARNING "md: md=%s%d, Specified more than once. "
804f5b246bSChristoph Hellwig "Replacing previous definition.\n", partitioned?"d":"", minor);
814f5b246bSChristoph Hellwig break;
824f5b246bSChristoph Hellwig }
834f5b246bSChristoph Hellwig if (ent >= ARRAY_SIZE(md_setup_args)) {
844f5b246bSChristoph Hellwig printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor);
854f5b246bSChristoph Hellwig return 0;
864f5b246bSChristoph Hellwig }
874f5b246bSChristoph Hellwig if (ent >= md_setup_ents)
884f5b246bSChristoph Hellwig md_setup_ents++;
894f5b246bSChristoph Hellwig switch (get_option(&str, &level)) { /* RAID level */
904f5b246bSChristoph Hellwig case 2: /* could be 0 or -1.. */
914f5b246bSChristoph Hellwig if (level == 0 || level == LEVEL_LINEAR) {
924f5b246bSChristoph Hellwig if (get_option(&str, &factor) != 2 || /* Chunk Size */
934f5b246bSChristoph Hellwig get_option(&str, &fault) != 2) {
944f5b246bSChristoph Hellwig printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
954f5b246bSChristoph Hellwig return 0;
964f5b246bSChristoph Hellwig }
974f5b246bSChristoph Hellwig md_setup_args[ent].level = level;
984f5b246bSChristoph Hellwig md_setup_args[ent].chunk = 1 << (factor+12);
994f5b246bSChristoph Hellwig if (level == LEVEL_LINEAR)
1004f5b246bSChristoph Hellwig pername = "linear";
1014f5b246bSChristoph Hellwig else
1024f5b246bSChristoph Hellwig pername = "raid0";
1034f5b246bSChristoph Hellwig break;
1044f5b246bSChristoph Hellwig }
105df561f66SGustavo A. R. Silva fallthrough;
1064f5b246bSChristoph Hellwig case 1: /* the first device is numeric */
1074f5b246bSChristoph Hellwig str = str1;
108df561f66SGustavo A. R. Silva fallthrough;
1094f5b246bSChristoph Hellwig case 0:
1104f5b246bSChristoph Hellwig md_setup_args[ent].level = LEVEL_NONE;
1114f5b246bSChristoph Hellwig pername="super-block";
1124f5b246bSChristoph Hellwig }
1134f5b246bSChristoph Hellwig
1144f5b246bSChristoph Hellwig printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
1154f5b246bSChristoph Hellwig minor, pername, str);
1164f5b246bSChristoph Hellwig md_setup_args[ent].device_names = str;
1174f5b246bSChristoph Hellwig md_setup_args[ent].partitioned = partitioned;
1184f5b246bSChristoph Hellwig md_setup_args[ent].minor = minor;
1194f5b246bSChristoph Hellwig
1204f5b246bSChristoph Hellwig return 1;
1214f5b246bSChristoph Hellwig }
1224f5b246bSChristoph Hellwig
md_setup_drive(struct md_setup_args * args)123d1100488SChristoph Hellwig static void __init md_setup_drive(struct md_setup_args *args)
1244f5b246bSChristoph Hellwig {
1257e0adbfcSChristoph Hellwig char *devname = args->device_names;
1267e0adbfcSChristoph Hellwig dev_t devices[MD_SB_DISKS + 1], mdev;
1277e0adbfcSChristoph Hellwig struct mdu_array_info_s ainfo = { };
1287e0adbfcSChristoph Hellwig struct mddev *mddev;
1297e0adbfcSChristoph Hellwig int err = 0, i;
1304f5b246bSChristoph Hellwig char name[16];
1314f5b246bSChristoph Hellwig
1327e0adbfcSChristoph Hellwig if (args->partitioned) {
1337e0adbfcSChristoph Hellwig mdev = MKDEV(mdp_major, args->minor << MdpMinorShift);
1347e0adbfcSChristoph Hellwig sprintf(name, "md_d%d", args->minor);
1357e0adbfcSChristoph Hellwig } else {
1367e0adbfcSChristoph Hellwig mdev = MKDEV(MD_MAJOR, args->minor);
1377e0adbfcSChristoph Hellwig sprintf(name, "md%d", args->minor);
1387e0adbfcSChristoph Hellwig }
1394f5b246bSChristoph Hellwig
1404f5b246bSChristoph Hellwig for (i = 0; i < MD_SB_DISKS && devname != NULL; i++) {
1414f5b246bSChristoph Hellwig struct kstat stat;
1424f5b246bSChristoph Hellwig char *p;
1434f5b246bSChristoph Hellwig char comp_name[64];
1447e0adbfcSChristoph Hellwig dev_t dev;
1454f5b246bSChristoph Hellwig
1464f5b246bSChristoph Hellwig p = strchr(devname, ',');
1474f5b246bSChristoph Hellwig if (p)
1484f5b246bSChristoph Hellwig *p++ = 0;
1494f5b246bSChristoph Hellwig
150*cf056a43SChristoph Hellwig if (early_lookup_bdev(devname, &dev))
151*cf056a43SChristoph Hellwig dev = 0;
1524f5b246bSChristoph Hellwig if (strncmp(devname, "/dev/", 5) == 0)
1534f5b246bSChristoph Hellwig devname += 5;
1544f5b246bSChristoph Hellwig snprintf(comp_name, 63, "/dev/%s", devname);
155716308a5SChristoph Hellwig if (init_stat(comp_name, &stat, 0) == 0 && S_ISBLK(stat.mode))
1564f5b246bSChristoph Hellwig dev = new_decode_dev(stat.rdev);
1574f5b246bSChristoph Hellwig if (!dev) {
1587e0adbfcSChristoph Hellwig pr_warn("md: Unknown device name: %s\n", devname);
1594f5b246bSChristoph Hellwig break;
1604f5b246bSChristoph Hellwig }
1614f5b246bSChristoph Hellwig
1624f5b246bSChristoph Hellwig devices[i] = dev;
1634f5b246bSChristoph Hellwig devname = p;
1644f5b246bSChristoph Hellwig }
1654f5b246bSChristoph Hellwig devices[i] = 0;
1664f5b246bSChristoph Hellwig
1674f5b246bSChristoph Hellwig if (!i)
168d1100488SChristoph Hellwig return;
1694f5b246bSChristoph Hellwig
1707e0adbfcSChristoph Hellwig pr_info("md: Loading %s: %s\n", name, args->device_names);
1714f5b246bSChristoph Hellwig
17234cb92c0SChristoph Hellwig mddev = md_alloc(mdev, name);
17334cb92c0SChristoph Hellwig if (IS_ERR(mddev)) {
17434cb92c0SChristoph Hellwig pr_err("md: md_alloc failed - cannot start array %s\n", name);
175d1100488SChristoph Hellwig return;
1764f5b246bSChristoph Hellwig }
1777e0adbfcSChristoph Hellwig
1787e0adbfcSChristoph Hellwig err = mddev_lock(mddev);
1797e0adbfcSChristoph Hellwig if (err) {
1807e0adbfcSChristoph Hellwig pr_err("md: failed to lock array %s\n", name);
18134cb92c0SChristoph Hellwig goto out_mddev_put;
1827e0adbfcSChristoph Hellwig }
1837e0adbfcSChristoph Hellwig
1847e0adbfcSChristoph Hellwig if (!list_empty(&mddev->disks) || mddev->raid_disks) {
1857e0adbfcSChristoph Hellwig pr_warn("md: Ignoring %s, already autodetected. (Use raid=noautodetect)\n",
1867e0adbfcSChristoph Hellwig name);
1877e0adbfcSChristoph Hellwig goto out_unlock;
1884f5b246bSChristoph Hellwig }
1894f5b246bSChristoph Hellwig
190d1100488SChristoph Hellwig if (args->level != LEVEL_NONE) {
1914f5b246bSChristoph Hellwig /* non-persistent */
192d1100488SChristoph Hellwig ainfo.level = args->level;
1937e0adbfcSChristoph Hellwig ainfo.md_minor = args->minor;
1947e0adbfcSChristoph Hellwig ainfo.not_persistent = 1;
1957e0adbfcSChristoph Hellwig ainfo.state = (1 << MD_SB_CLEAN);
1967e0adbfcSChristoph Hellwig ainfo.chunk_size = args->chunk;
1974f5b246bSChristoph Hellwig while (devices[ainfo.raid_disks])
1984f5b246bSChristoph Hellwig ainfo.raid_disks++;
1997e0adbfcSChristoph Hellwig }
2004f5b246bSChristoph Hellwig
2017e0adbfcSChristoph Hellwig err = md_set_array_info(mddev, &ainfo);
2027e0adbfcSChristoph Hellwig
2037e0adbfcSChristoph Hellwig for (i = 0; i <= MD_SB_DISKS && devices[i]; i++) {
2047e0adbfcSChristoph Hellwig struct mdu_disk_info_s dinfo = {
2057e0adbfcSChristoph Hellwig .major = MAJOR(devices[i]),
2067e0adbfcSChristoph Hellwig .minor = MINOR(devices[i]),
2077e0adbfcSChristoph Hellwig };
2087e0adbfcSChristoph Hellwig
2097e0adbfcSChristoph Hellwig if (args->level != LEVEL_NONE) {
2104f5b246bSChristoph Hellwig dinfo.number = i;
2114f5b246bSChristoph Hellwig dinfo.raid_disk = i;
2127e0adbfcSChristoph Hellwig dinfo.state =
2137e0adbfcSChristoph Hellwig (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
2144f5b246bSChristoph Hellwig }
2157e0adbfcSChristoph Hellwig
2167e0adbfcSChristoph Hellwig md_add_new_disk(mddev, &dinfo);
2174f5b246bSChristoph Hellwig }
2187e0adbfcSChristoph Hellwig
2194f5b246bSChristoph Hellwig if (!err)
2207e0adbfcSChristoph Hellwig err = do_md_run(mddev);
2214f5b246bSChristoph Hellwig if (err)
2227e0adbfcSChristoph Hellwig pr_warn("md: starting %s failed\n", name);
2237e0adbfcSChristoph Hellwig out_unlock:
2247e0adbfcSChristoph Hellwig mddev_unlock(mddev);
22534cb92c0SChristoph Hellwig out_mddev_put:
22634cb92c0SChristoph Hellwig mddev_put(mddev);
2274f5b246bSChristoph Hellwig }
2284f5b246bSChristoph Hellwig
raid_setup(char * str)2294f5b246bSChristoph Hellwig static int __init raid_setup(char *str)
2304f5b246bSChristoph Hellwig {
2314f5b246bSChristoph Hellwig int len, pos;
2324f5b246bSChristoph Hellwig
2334f5b246bSChristoph Hellwig len = strlen(str) + 1;
2344f5b246bSChristoph Hellwig pos = 0;
2354f5b246bSChristoph Hellwig
2364f5b246bSChristoph Hellwig while (pos < len) {
2374f5b246bSChristoph Hellwig char *comma = strchr(str+pos, ',');
2384f5b246bSChristoph Hellwig int wlen;
2394f5b246bSChristoph Hellwig if (comma)
2404f5b246bSChristoph Hellwig wlen = (comma-str)-pos;
2414f5b246bSChristoph Hellwig else wlen = (len-1)-pos;
2424f5b246bSChristoph Hellwig
2434f5b246bSChristoph Hellwig if (!strncmp(str, "noautodetect", wlen))
2444f5b246bSChristoph Hellwig raid_noautodetect = 1;
2454f5b246bSChristoph Hellwig if (!strncmp(str, "autodetect", wlen))
2464f5b246bSChristoph Hellwig raid_noautodetect = 0;
2474f5b246bSChristoph Hellwig if (strncmp(str, "partitionable", wlen)==0)
2484f5b246bSChristoph Hellwig raid_autopart = 1;
2494f5b246bSChristoph Hellwig if (strncmp(str, "part", wlen)==0)
2504f5b246bSChristoph Hellwig raid_autopart = 1;
2514f5b246bSChristoph Hellwig pos += wlen+1;
2524f5b246bSChristoph Hellwig }
2534f5b246bSChristoph Hellwig return 1;
2544f5b246bSChristoph Hellwig }
2554f5b246bSChristoph Hellwig
2564f5b246bSChristoph Hellwig __setup("raid=", raid_setup);
2574f5b246bSChristoph Hellwig __setup("md=", md_setup);
2584f5b246bSChristoph Hellwig
autodetect_raid(void)2594f5b246bSChristoph Hellwig static void __init autodetect_raid(void)
2604f5b246bSChristoph Hellwig {
2614f5b246bSChristoph Hellwig /*
2624f5b246bSChristoph Hellwig * Since we don't want to detect and use half a raid array, we need to
2634f5b246bSChristoph Hellwig * wait for the known devices to complete their probing
2644f5b246bSChristoph Hellwig */
2654f5b246bSChristoph Hellwig printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
2664f5b246bSChristoph Hellwig printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
2674f5b246bSChristoph Hellwig
2684f5b246bSChristoph Hellwig wait_for_device_probe();
269d82fa81cSChristoph Hellwig md_autostart_arrays(raid_autopart);
2704f5b246bSChristoph Hellwig }
2714f5b246bSChristoph Hellwig
md_run_setup(void)2724f5b246bSChristoph Hellwig void __init md_run_setup(void)
2734f5b246bSChristoph Hellwig {
274d1100488SChristoph Hellwig int ent;
275d1100488SChristoph Hellwig
2764f5b246bSChristoph Hellwig if (raid_noautodetect)
2774f5b246bSChristoph Hellwig printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=autodetect will force)\n");
2784f5b246bSChristoph Hellwig else
2794f5b246bSChristoph Hellwig autodetect_raid();
280d1100488SChristoph Hellwig
281d1100488SChristoph Hellwig for (ent = 0; ent < md_setup_ents; ent++)
282d1100488SChristoph Hellwig md_setup_drive(&md_setup_args[ent]);
2834f5b246bSChristoph Hellwig }
284