1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds #include <linux/module.h>
31da177e4SLinus Torvalds #include <linux/sched.h>
41da177e4SLinus Torvalds #include <linux/ctype.h>
51da177e4SLinus Torvalds #include <linux/fd.h>
61da177e4SLinus Torvalds #include <linux/tty.h>
71da177e4SLinus Torvalds #include <linux/suspend.h>
81da177e4SLinus Torvalds #include <linux/root_dev.h>
91da177e4SLinus Torvalds #include <linux/security.h>
101da177e4SLinus Torvalds #include <linux/delay.h>
11d53d9f16SAndrew Morton #include <linux/mount.h>
12d779249eSGreg Kroah-Hartman #include <linux/device.h>
1346595390SAdrian Bunk #include <linux/init.h>
14011e3fcdSAdrian Bunk #include <linux/fs.h>
1582c8253aSAdrian Bunk #include <linux/initrd.h>
1622a9d645SArjan van de Ven #include <linux/async.h>
175ad4e53bSAl Viro #include <linux/fs_struct.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1957f150a5SRob Landley #include <linux/ramfs.h>
2016203a7aSRob Landley #include <linux/shmem_fs.h>
2145071e1cSLoic Poulain #include <linux/ktime.h>
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds #include <linux/nfs_fs.h>
241da177e4SLinus Torvalds #include <linux/nfs_fs_sb.h>
251da177e4SLinus Torvalds #include <linux/nfs_mount.h>
264f5b246bSChristoph Hellwig #include <linux/raid/detect.h>
27e262e32dSDavid Howells #include <uapi/linux/mount.h>
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds #include "do_mounts.h"
301da177e4SLinus Torvalds
319b04c997STheodore Ts'o int root_mountflags = MS_RDONLY | MS_SILENT;
321da177e4SLinus Torvalds static char __initdata saved_root_name[64];
3379975f13SWill Drewry static int root_wait;
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds dev_t ROOT_DEV;
361da177e4SLinus Torvalds
load_ramdisk(char * str)371da177e4SLinus Torvalds static int __init load_ramdisk(char *str)
381da177e4SLinus Torvalds {
39c8376994SChristoph Hellwig pr_warn("ignoring the deprecated load_ramdisk= option\n");
401da177e4SLinus Torvalds return 1;
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds __setup("load_ramdisk=", load_ramdisk);
431da177e4SLinus Torvalds
readonly(char * str)441da177e4SLinus Torvalds static int __init readonly(char *str)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds if (*str)
471da177e4SLinus Torvalds return 0;
481da177e4SLinus Torvalds root_mountflags |= MS_RDONLY;
491da177e4SLinus Torvalds return 1;
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds
readwrite(char * str)521da177e4SLinus Torvalds static int __init readwrite(char *str)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds if (*str)
551da177e4SLinus Torvalds return 0;
561da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY;
571da177e4SLinus Torvalds return 1;
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds __setup("ro", readonly);
611da177e4SLinus Torvalds __setup("rw", readwrite);
621da177e4SLinus Torvalds
root_dev_setup(char * line)631da177e4SLinus Torvalds static int __init root_dev_setup(char *line)
641da177e4SLinus Torvalds {
65a1d3a6d9SWolfram Sang strscpy(saved_root_name, line, sizeof(saved_root_name));
661da177e4SLinus Torvalds return 1;
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds __setup("root=", root_dev_setup);
701da177e4SLinus Torvalds
rootwait_setup(char * str)71cc1ed754SPierre Ossman static int __init rootwait_setup(char *str)
72cc1ed754SPierre Ossman {
73cc1ed754SPierre Ossman if (*str)
74cc1ed754SPierre Ossman return 0;
7545071e1cSLoic Poulain root_wait = -1;
76cc1ed754SPierre Ossman return 1;
77cc1ed754SPierre Ossman }
78cc1ed754SPierre Ossman
79cc1ed754SPierre Ossman __setup("rootwait", rootwait_setup);
80cc1ed754SPierre Ossman
rootwait_timeout_setup(char * str)8145071e1cSLoic Poulain static int __init rootwait_timeout_setup(char *str)
8245071e1cSLoic Poulain {
8345071e1cSLoic Poulain int sec;
8445071e1cSLoic Poulain
8545071e1cSLoic Poulain if (kstrtoint(str, 0, &sec) || sec < 0) {
8645071e1cSLoic Poulain pr_warn("ignoring invalid rootwait value\n");
8745071e1cSLoic Poulain goto ignore;
8845071e1cSLoic Poulain }
8945071e1cSLoic Poulain
9045071e1cSLoic Poulain if (check_mul_overflow(sec, MSEC_PER_SEC, &root_wait)) {
9145071e1cSLoic Poulain pr_warn("ignoring excessive rootwait value\n");
9245071e1cSLoic Poulain goto ignore;
9345071e1cSLoic Poulain }
9445071e1cSLoic Poulain
9545071e1cSLoic Poulain return 1;
9645071e1cSLoic Poulain
9745071e1cSLoic Poulain ignore:
9845071e1cSLoic Poulain /* Fallback to indefinite wait */
9945071e1cSLoic Poulain root_wait = -1;
10045071e1cSLoic Poulain
10145071e1cSLoic Poulain return 1;
10245071e1cSLoic Poulain }
10345071e1cSLoic Poulain
10445071e1cSLoic Poulain __setup("rootwait=", rootwait_timeout_setup);
10545071e1cSLoic Poulain
1061da177e4SLinus Torvalds static char * __initdata root_mount_data;
root_data_setup(char * str)1071da177e4SLinus Torvalds static int __init root_data_setup(char *str)
1081da177e4SLinus Torvalds {
1091da177e4SLinus Torvalds root_mount_data = str;
1101da177e4SLinus Torvalds return 1;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds static char * __initdata root_fs_names;
fs_names_setup(char * str)1141da177e4SLinus Torvalds static int __init fs_names_setup(char *str)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds root_fs_names = str;
1171da177e4SLinus Torvalds return 1;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds static unsigned int __initdata root_delay;
root_delay_setup(char * str)1211da177e4SLinus Torvalds static int __init root_delay_setup(char *str)
1221da177e4SLinus Torvalds {
1231da177e4SLinus Torvalds root_delay = simple_strtoul(str, NULL, 0);
1241da177e4SLinus Torvalds return 1;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds
1271da177e4SLinus Torvalds __setup("rootflags=", root_data_setup);
1281da177e4SLinus Torvalds __setup("rootfstype=", fs_names_setup);
1291da177e4SLinus Torvalds __setup("rootdelay=", root_delay_setup);
1301da177e4SLinus Torvalds
131b51593c4SVivek Goyal /* This can return zero length strings. Caller should check */
split_fs_names(char * page,size_t size)13226e293f7SYihuan Pan static int __init split_fs_names(char *page, size_t size)
1331da177e4SLinus Torvalds {
134b51593c4SVivek Goyal int count = 1;
1356e7c1770SChristoph Hellwig char *p = page;
1361da177e4SLinus Torvalds
137a1d3a6d9SWolfram Sang strscpy(p, root_fs_names, size);
1386e7c1770SChristoph Hellwig while (*p++) {
139b51593c4SVivek Goyal if (p[-1] == ',') {
1406e7c1770SChristoph Hellwig p[-1] = '\0';
1416e7c1770SChristoph Hellwig count++;
142b51593c4SVivek Goyal }
143b51593c4SVivek Goyal }
1446e7c1770SChristoph Hellwig
1456e7c1770SChristoph Hellwig return count;
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds
do_mount_root(const char * name,const char * fs,const int flags,const void * data)148cccaa5e3SDominik Brodowski static int __init do_mount_root(const char *name, const char *fs,
149cccaa5e3SDominik Brodowski const int flags, const void *data)
1501da177e4SLinus Torvalds {
151d8c9584eSAl Viro struct super_block *s;
1527de7de7cSLinus Torvalds struct page *p = NULL;
1537de7de7cSLinus Torvalds char *data_page = NULL;
154cccaa5e3SDominik Brodowski int ret;
155cccaa5e3SDominik Brodowski
1567de7de7cSLinus Torvalds if (data) {
157c60166f0SChristoph Hellwig /* init_mount() requires a full page as fifth argument */
158cccaa5e3SDominik Brodowski p = alloc_page(GFP_KERNEL);
159cccaa5e3SDominik Brodowski if (!p)
160cccaa5e3SDominik Brodowski return -ENOMEM;
161cccaa5e3SDominik Brodowski data_page = page_address(p);
162c60166f0SChristoph Hellwig /* zero-pad. init_mount() will make sure it's terminated */
1637de7de7cSLinus Torvalds strncpy(data_page, data, PAGE_SIZE);
1647de7de7cSLinus Torvalds }
165cccaa5e3SDominik Brodowski
166c60166f0SChristoph Hellwig ret = init_mount(name, "/root", fs, flags, data_page);
167cccaa5e3SDominik Brodowski if (ret)
168cccaa5e3SDominik Brodowski goto out;
1691da177e4SLinus Torvalds
170db63f1e3SChristoph Hellwig init_chdir("/root");
171d8c9584eSAl Viro s = current->fs->pwd.dentry->d_sb;
172d8c9584eSAl Viro ROOT_DEV = s->s_dev;
17380cdc6daSMandeep Singh Baines printk(KERN_INFO
17480cdc6daSMandeep Singh Baines "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
175d8c9584eSAl Viro s->s_type->name,
176bc98a42cSDavid Howells sb_rdonly(s) ? " readonly" : "",
177d8c9584eSAl Viro MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
178cccaa5e3SDominik Brodowski
179cccaa5e3SDominik Brodowski out:
1807de7de7cSLinus Torvalds if (p)
181cccaa5e3SDominik Brodowski put_page(p);
182cccaa5e3SDominik Brodowski return ret;
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds
mount_root_generic(char * name,char * pretty_name,int flags)185c8643c72SChristoph Hellwig void __init mount_root_generic(char *name, char *pretty_name, int flags)
1861da177e4SLinus Torvalds {
18775f296d9SLevin, Alexander (Sasha Levin) struct page *page = alloc_page(GFP_KERNEL);
188a608ca21SJeff Layton char *fs_names = page_address(page);
1891da177e4SLinus Torvalds char *p;
1901da177e4SLinus Torvalds char b[BDEVNAME_SIZE];
1916e7c1770SChristoph Hellwig int num_fs, i;
1921da177e4SLinus Torvalds
193ea3edd4dSChristoph Hellwig scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)",
194ea3edd4dSChristoph Hellwig MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
195e24d12b7SChristoph Hellwig if (root_fs_names)
19626e293f7SYihuan Pan num_fs = split_fs_names(fs_names, PAGE_SIZE);
197e24d12b7SChristoph Hellwig else
1986e7c1770SChristoph Hellwig num_fs = list_bdev_fs_names(fs_names, PAGE_SIZE);
1991da177e4SLinus Torvalds retry:
2006e7c1770SChristoph Hellwig for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) {
201b51593c4SVivek Goyal int err;
202b51593c4SVivek Goyal
203b51593c4SVivek Goyal if (!*p)
204b51593c4SVivek Goyal continue;
205b51593c4SVivek Goyal err = do_mount_root(name, p, flags, root_mount_data);
2061da177e4SLinus Torvalds switch (err) {
2071da177e4SLinus Torvalds case 0:
2081da177e4SLinus Torvalds goto out;
2091da177e4SLinus Torvalds case -EACCES:
2101da177e4SLinus Torvalds case -EINVAL:
2111da177e4SLinus Torvalds continue;
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds /*
2141da177e4SLinus Torvalds * Allow the user to distinguish between failed sys_open
2151da177e4SLinus Torvalds * and bad superblock on root device.
216dd2a345fSDave Gilbert * and give them a list of the available devices
2171da177e4SLinus Torvalds */
2180e0cb892SBernhard Walle printk("VFS: Cannot open root device \"%s\" or %s: error %d\n",
219c8643c72SChristoph Hellwig pretty_name, b, err);
220dd2a345fSDave Gilbert printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
221dd2a345fSDave Gilbert printk_all_partitions();
2226aee6723SAngus Chen
2236aee6723SAngus Chen if (root_fs_names)
2246aee6723SAngus Chen num_fs = list_bdev_fs_names(fs_names, PAGE_SIZE);
2256aee6723SAngus Chen if (!num_fs)
2266aee6723SAngus Chen pr_err("Can't find any bdev filesystem to be used for mount!\n");
2276aee6723SAngus Chen else {
2286aee6723SAngus Chen pr_err("List of all bdev filesystems:\n");
2296aee6723SAngus Chen for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1)
2306aee6723SAngus Chen pr_err(" %s", p);
2316aee6723SAngus Chen pr_err("\n");
2326aee6723SAngus Chen }
2336aee6723SAngus Chen
2341da177e4SLinus Torvalds panic("VFS: Unable to mount root fs on %s", b);
2351da177e4SLinus Torvalds }
236e462ec50SDavid Howells if (!(flags & SB_RDONLY)) {
237e462ec50SDavid Howells flags |= SB_RDONLY;
23810975933SMiklos Szeredi goto retry;
23910975933SMiklos Szeredi }
240be6e028bSAndy Whitcroft
241dd2a345fSDave Gilbert printk("List of all partitions:\n");
242dd2a345fSDave Gilbert printk_all_partitions();
243be6e028bSAndy Whitcroft printk("No filesystem could mount root, tried: ");
2446e7c1770SChristoph Hellwig for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1)
245be6e028bSAndy Whitcroft printk(" %s", p);
246be6e028bSAndy Whitcroft printk("\n");
2479361401eSDavid Howells panic("VFS: Unable to mount root fs on %s", b);
2481da177e4SLinus Torvalds out:
249a608ca21SJeff Layton put_page(page);
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds
2521da177e4SLinus Torvalds #ifdef CONFIG_ROOT_NFS
25343717c7dSChuck Lever
25443717c7dSChuck Lever #define NFSROOT_TIMEOUT_MIN 5
25543717c7dSChuck Lever #define NFSROOT_TIMEOUT_MAX 30
25643717c7dSChuck Lever #define NFSROOT_RETRY_MAX 5
25743717c7dSChuck Lever
mount_nfs_root(void)258a6a41d39SChristoph Hellwig static void __init mount_nfs_root(void)
2591da177e4SLinus Torvalds {
26056463e50SChuck Lever char *root_dev, *root_data;
26143717c7dSChuck Lever unsigned int timeout;
262a6a41d39SChristoph Hellwig int try;
2631da177e4SLinus Torvalds
264a6a41d39SChristoph Hellwig if (nfs_root_data(&root_dev, &root_data))
265a6a41d39SChristoph Hellwig goto fail;
26643717c7dSChuck Lever
26743717c7dSChuck Lever /*
26843717c7dSChuck Lever * The server or network may not be ready, so try several
26943717c7dSChuck Lever * times. Stop after a few tries in case the client wants
27043717c7dSChuck Lever * to fall back to other boot methods.
27143717c7dSChuck Lever */
27243717c7dSChuck Lever timeout = NFSROOT_TIMEOUT_MIN;
27343717c7dSChuck Lever for (try = 1; ; try++) {
274a6a41d39SChristoph Hellwig if (!do_mount_root(root_dev, "nfs", root_mountflags, root_data))
275a6a41d39SChristoph Hellwig return;
27643717c7dSChuck Lever if (try > NFSROOT_RETRY_MAX)
27743717c7dSChuck Lever break;
27843717c7dSChuck Lever
27943717c7dSChuck Lever /* Wait, in case the server refused us immediately */
28043717c7dSChuck Lever ssleep(timeout);
28143717c7dSChuck Lever timeout <<= 1;
28243717c7dSChuck Lever if (timeout > NFSROOT_TIMEOUT_MAX)
28343717c7dSChuck Lever timeout = NFSROOT_TIMEOUT_MAX;
28443717c7dSChuck Lever }
285a6a41d39SChristoph Hellwig fail:
286a6a41d39SChristoph Hellwig pr_err("VFS: Unable to mount root fs via NFS.\n");
2871da177e4SLinus Torvalds }
288a6a41d39SChristoph Hellwig #else
mount_nfs_root(void)289a6a41d39SChristoph Hellwig static inline void mount_nfs_root(void)
290a6a41d39SChristoph Hellwig {
291a6a41d39SChristoph Hellwig }
292a6a41d39SChristoph Hellwig #endif /* CONFIG_ROOT_NFS */
2931da177e4SLinus Torvalds
2948902dd52SPaulo Alcantara (SUSE) #ifdef CONFIG_CIFS_ROOT
2958902dd52SPaulo Alcantara (SUSE)
2968902dd52SPaulo Alcantara (SUSE) #define CIFSROOT_TIMEOUT_MIN 5
2978902dd52SPaulo Alcantara (SUSE) #define CIFSROOT_TIMEOUT_MAX 30
2988902dd52SPaulo Alcantara (SUSE) #define CIFSROOT_RETRY_MAX 5
2998902dd52SPaulo Alcantara (SUSE)
mount_cifs_root(void)300a6a41d39SChristoph Hellwig static void __init mount_cifs_root(void)
3018902dd52SPaulo Alcantara (SUSE) {
3028902dd52SPaulo Alcantara (SUSE) char *root_dev, *root_data;
3038902dd52SPaulo Alcantara (SUSE) unsigned int timeout;
304a6a41d39SChristoph Hellwig int try;
3058902dd52SPaulo Alcantara (SUSE)
306a6a41d39SChristoph Hellwig if (cifs_root_data(&root_dev, &root_data))
307a6a41d39SChristoph Hellwig goto fail;
3088902dd52SPaulo Alcantara (SUSE)
3098902dd52SPaulo Alcantara (SUSE) timeout = CIFSROOT_TIMEOUT_MIN;
3108902dd52SPaulo Alcantara (SUSE) for (try = 1; ; try++) {
311a6a41d39SChristoph Hellwig if (!do_mount_root(root_dev, "cifs", root_mountflags,
312a6a41d39SChristoph Hellwig root_data))
313a6a41d39SChristoph Hellwig return;
3148902dd52SPaulo Alcantara (SUSE) if (try > CIFSROOT_RETRY_MAX)
3158902dd52SPaulo Alcantara (SUSE) break;
3168902dd52SPaulo Alcantara (SUSE)
3178902dd52SPaulo Alcantara (SUSE) ssleep(timeout);
3188902dd52SPaulo Alcantara (SUSE) timeout <<= 1;
3198902dd52SPaulo Alcantara (SUSE) if (timeout > CIFSROOT_TIMEOUT_MAX)
3208902dd52SPaulo Alcantara (SUSE) timeout = CIFSROOT_TIMEOUT_MAX;
3218902dd52SPaulo Alcantara (SUSE) }
322a6a41d39SChristoph Hellwig fail:
323a6a41d39SChristoph Hellwig pr_err("VFS: Unable to mount root fs via SMB.\n");
3248902dd52SPaulo Alcantara (SUSE) }
325a6a41d39SChristoph Hellwig #else
mount_cifs_root(void)326a6a41d39SChristoph Hellwig static inline void mount_cifs_root(void)
327a6a41d39SChristoph Hellwig {
328a6a41d39SChristoph Hellwig }
329a6a41d39SChristoph Hellwig #endif /* CONFIG_CIFS_ROOT */
3308902dd52SPaulo Alcantara (SUSE)
fs_is_nodev(char * fstype)331f9259be6SChristoph Hellwig static bool __init fs_is_nodev(char *fstype)
332f9259be6SChristoph Hellwig {
333f9259be6SChristoph Hellwig struct file_system_type *fs = get_fs_type(fstype);
334f9259be6SChristoph Hellwig bool ret = false;
335f9259be6SChristoph Hellwig
336f9259be6SChristoph Hellwig if (fs) {
337f9259be6SChristoph Hellwig ret = !(fs->fs_flags & FS_REQUIRES_DEV);
338f9259be6SChristoph Hellwig put_filesystem(fs);
339f9259be6SChristoph Hellwig }
340f9259be6SChristoph Hellwig
341f9259be6SChristoph Hellwig return ret;
342f9259be6SChristoph Hellwig }
343f9259be6SChristoph Hellwig
mount_nodev_root(char * root_device_name)344c8643c72SChristoph Hellwig static int __init mount_nodev_root(char *root_device_name)
345f9259be6SChristoph Hellwig {
346f9259be6SChristoph Hellwig char *fs_names, *fstype;
347f9259be6SChristoph Hellwig int err = -EINVAL;
3486e7c1770SChristoph Hellwig int num_fs, i;
349f9259be6SChristoph Hellwig
350f9259be6SChristoph Hellwig fs_names = (void *)__get_free_page(GFP_KERNEL);
351f9259be6SChristoph Hellwig if (!fs_names)
352f9259be6SChristoph Hellwig return -EINVAL;
35326e293f7SYihuan Pan num_fs = split_fs_names(fs_names, PAGE_SIZE);
354f9259be6SChristoph Hellwig
3556e7c1770SChristoph Hellwig for (i = 0, fstype = fs_names; i < num_fs;
3566e7c1770SChristoph Hellwig i++, fstype += strlen(fstype) + 1) {
357b51593c4SVivek Goyal if (!*fstype)
358b51593c4SVivek Goyal continue;
359f9259be6SChristoph Hellwig if (!fs_is_nodev(fstype))
360f9259be6SChristoph Hellwig continue;
361f9259be6SChristoph Hellwig err = do_mount_root(root_device_name, fstype, root_mountflags,
362f9259be6SChristoph Hellwig root_mount_data);
363f9259be6SChristoph Hellwig if (!err)
364f9259be6SChristoph Hellwig break;
365f9259be6SChristoph Hellwig }
366f9259be6SChristoph Hellwig
367f9259be6SChristoph Hellwig free_page((unsigned long)fs_names);
368f9259be6SChristoph Hellwig return err;
369f9259be6SChristoph Hellwig }
370f9259be6SChristoph Hellwig
3719361401eSDavid Howells #ifdef CONFIG_BLOCK
mount_block_root(char * root_device_name)372c8643c72SChristoph Hellwig static void __init mount_block_root(char *root_device_name)
373c69e3c3aSVishnu Pratap Singh {
374c69e3c3aSVishnu Pratap Singh int err = create_dev("/dev/root", ROOT_DEV);
375c69e3c3aSVishnu Pratap Singh
376c69e3c3aSVishnu Pratap Singh if (err < 0)
377c69e3c3aSVishnu Pratap Singh pr_emerg("Failed to create /dev/root: %d\n", err);
378c8643c72SChristoph Hellwig mount_root_generic("/dev/root", root_device_name, root_mountflags);
379c69e3c3aSVishnu Pratap Singh }
380a6a41d39SChristoph Hellwig #else
mount_block_root(char * root_device_name)381c8643c72SChristoph Hellwig static inline void mount_block_root(char *root_device_name)
382a6a41d39SChristoph Hellwig {
383a6a41d39SChristoph Hellwig }
384a6a41d39SChristoph Hellwig #endif /* CONFIG_BLOCK */
385a6a41d39SChristoph Hellwig
mount_root(char * root_device_name)386c8643c72SChristoph Hellwig void __init mount_root(char *root_device_name)
387a6a41d39SChristoph Hellwig {
388a6a41d39SChristoph Hellwig switch (ROOT_DEV) {
389a6a41d39SChristoph Hellwig case Root_NFS:
390a6a41d39SChristoph Hellwig mount_nfs_root();
391a6a41d39SChristoph Hellwig break;
392a6a41d39SChristoph Hellwig case Root_CIFS:
393a6a41d39SChristoph Hellwig mount_cifs_root();
394a6a41d39SChristoph Hellwig break;
39507d63cbbSChristoph Hellwig case Root_Generic:
39607d63cbbSChristoph Hellwig mount_root_generic(root_device_name, root_device_name,
39707d63cbbSChristoph Hellwig root_mountflags);
39807d63cbbSChristoph Hellwig break;
399a6a41d39SChristoph Hellwig case 0:
400c8643c72SChristoph Hellwig if (root_device_name && root_fs_names &&
401c8643c72SChristoph Hellwig mount_nodev_root(root_device_name) == 0)
402a6a41d39SChristoph Hellwig break;
403a6a41d39SChristoph Hellwig fallthrough;
404a6a41d39SChristoph Hellwig default:
405c8643c72SChristoph Hellwig mount_block_root(root_device_name);
406a6a41d39SChristoph Hellwig break;
407a6a41d39SChristoph Hellwig }
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds
4103701c600SChristoph Hellwig /* wait for any asynchronous scanning to complete */
wait_for_root(char * root_device_name)4113701c600SChristoph Hellwig static void __init wait_for_root(char *root_device_name)
4123701c600SChristoph Hellwig {
41345071e1cSLoic Poulain ktime_t end;
41445071e1cSLoic Poulain
4153701c600SChristoph Hellwig if (ROOT_DEV != 0)
4163701c600SChristoph Hellwig return;
4173701c600SChristoph Hellwig
4183701c600SChristoph Hellwig pr_info("Waiting for root device %s...\n", root_device_name);
4193701c600SChristoph Hellwig
42045071e1cSLoic Poulain end = ktime_add_ms(ktime_get_raw(), root_wait);
42145071e1cSLoic Poulain
422cf056a43SChristoph Hellwig while (!driver_probe_done() ||
42345071e1cSLoic Poulain early_lookup_bdev(root_device_name, &ROOT_DEV) < 0) {
4243701c600SChristoph Hellwig msleep(5);
42545071e1cSLoic Poulain if (root_wait > 0 && ktime_after(ktime_get_raw(), end))
42645071e1cSLoic Poulain break;
42745071e1cSLoic Poulain }
42845071e1cSLoic Poulain
4293701c600SChristoph Hellwig async_synchronize_full();
4303701c600SChristoph Hellwig
4313701c600SChristoph Hellwig }
4323701c600SChristoph Hellwig
parse_root_device(char * root_device_name)43307d63cbbSChristoph Hellwig static dev_t __init parse_root_device(char *root_device_name)
43407d63cbbSChristoph Hellwig {
435079caa35SChristoph Hellwig int error;
436cf056a43SChristoph Hellwig dev_t dev;
437cf056a43SChristoph Hellwig
43807d63cbbSChristoph Hellwig if (!strncmp(root_device_name, "mtd", 3) ||
43907d63cbbSChristoph Hellwig !strncmp(root_device_name, "ubi", 3))
44007d63cbbSChristoph Hellwig return Root_Generic;
441c0c1a7dcSChristoph Hellwig if (strcmp(root_device_name, "/dev/nfs") == 0)
442c0c1a7dcSChristoph Hellwig return Root_NFS;
443c0c1a7dcSChristoph Hellwig if (strcmp(root_device_name, "/dev/cifs") == 0)
444c0c1a7dcSChristoph Hellwig return Root_CIFS;
445c0c1a7dcSChristoph Hellwig if (strcmp(root_device_name, "/dev/ram") == 0)
446c0c1a7dcSChristoph Hellwig return Root_RAM0;
447cf056a43SChristoph Hellwig
448079caa35SChristoph Hellwig error = early_lookup_bdev(root_device_name, &dev);
449079caa35SChristoph Hellwig if (error) {
450079caa35SChristoph Hellwig if (error == -EINVAL && root_wait) {
451079caa35SChristoph Hellwig pr_err("Disabling rootwait; root= is invalid.\n");
452079caa35SChristoph Hellwig root_wait = 0;
453079caa35SChristoph Hellwig }
454cf056a43SChristoph Hellwig return 0;
455079caa35SChristoph Hellwig }
456cf056a43SChristoph Hellwig return dev;
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds
4591da177e4SLinus Torvalds /*
4601da177e4SLinus Torvalds * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
4611da177e4SLinus Torvalds */
prepare_namespace(void)4621da177e4SLinus Torvalds void __init prepare_namespace(void)
4631da177e4SLinus Torvalds {
4641da177e4SLinus Torvalds if (root_delay) {
4651da177e4SLinus Torvalds printk(KERN_INFO "Waiting %d sec before mounting root device...\n",
4661da177e4SLinus Torvalds root_delay);
4671da177e4SLinus Torvalds ssleep(root_delay);
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds
470216773a7SArjan van de Ven /*
471216773a7SArjan van de Ven * wait for the known devices to complete their probing
472216773a7SArjan van de Ven *
473216773a7SArjan van de Ven * Note: this is a potential source of long boot delays.
474216773a7SArjan van de Ven * For example, it is not atypical to wait 5 seconds here
475216773a7SArjan van de Ven * for the touchpad of a laptop to initialize.
476216773a7SArjan van de Ven */
477216773a7SArjan van de Ven wait_for_device_probe();
478d779249eSGreg Kroah-Hartman
4791da177e4SLinus Torvalds md_run_setup();
4801da177e4SLinus Torvalds
48107d63cbbSChristoph Hellwig if (saved_root_name[0])
48207d63cbbSChristoph Hellwig ROOT_DEV = parse_root_device(saved_root_name);
4831da177e4SLinus Torvalds
48473231b58SChristoph Hellwig if (initrd_load(saved_root_name))
4851da177e4SLinus Torvalds goto out;
4861da177e4SLinus Torvalds
4873701c600SChristoph Hellwig if (root_wait)
4883701c600SChristoph Hellwig wait_for_root(saved_root_name);
48973231b58SChristoph Hellwig mount_root(saved_root_name);
4901da177e4SLinus Torvalds out:
4915e787dbfSDominik Brodowski devtmpfs_mount();
492c60166f0SChristoph Hellwig init_mount(".", "/", NULL, MS_MOVE, NULL);
4934b7ca501SChristoph Hellwig init_chroot(".");
4941da177e4SLinus Torvalds }
49557f150a5SRob Landley
4966e19ededSRob Landley static bool is_tmpfs;
rootfs_init_fs_context(struct fs_context * fc)497f3235626SDavid Howells static int rootfs_init_fs_context(struct fs_context *fc)
49857f150a5SRob Landley {
4996e19ededSRob Landley if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
500f3235626SDavid Howells return shmem_init_fs_context(fc);
5016e19ededSRob Landley
502f3235626SDavid Howells return ramfs_init_fs_context(fc);
50357f150a5SRob Landley }
50457f150a5SRob Landley
505fd3e007fSAl Viro struct file_system_type rootfs_fs_type = {
50657f150a5SRob Landley .name = "rootfs",
507f3235626SDavid Howells .init_fs_context = rootfs_init_fs_context,
50857f150a5SRob Landley .kill_sb = kill_litter_super,
50957f150a5SRob Landley };
51057f150a5SRob Landley
init_rootfs(void)511037f11b4SAl Viro void __init init_rootfs(void)
51257f150a5SRob Landley {
513*2e54968bSStefan Berger if (IS_ENABLED(CONFIG_TMPFS)) {
514*2e54968bSStefan Berger if (!saved_root_name[0] && !root_fs_names)
5156e19ededSRob Landley is_tmpfs = true;
516*2e54968bSStefan Berger else if (root_fs_names && !!strstr(root_fs_names, "tmpfs"))
517*2e54968bSStefan Berger is_tmpfs = true;
518*2e54968bSStefan Berger }
51957f150a5SRob Landley }
520