xref: /openbmc/linux/init/do_mounts.c (revision 2e54968b)
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