xref: /openbmc/linux/init/do_mounts.c (revision a6a41d39)
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>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include <linux/nfs_fs.h>
231da177e4SLinus Torvalds #include <linux/nfs_fs_sb.h>
241da177e4SLinus Torvalds #include <linux/nfs_mount.h>
254f5b246bSChristoph Hellwig #include <linux/raid/detect.h>
26e262e32dSDavid Howells #include <uapi/linux/mount.h>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include "do_mounts.h"
291da177e4SLinus Torvalds 
309b04c997STheodore Ts'o int root_mountflags = MS_RDONLY | MS_SILENT;
31f56f6d30SAdrian Bunk static char * __initdata root_device_name;
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 
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 
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 
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 
636d0aed7aSJens Axboe #ifdef CONFIG_BLOCK
641ad7e899SStephen Warren struct uuidcmp {
651ad7e899SStephen Warren 	const char *uuid;
661ad7e899SStephen Warren 	int len;
671ad7e899SStephen Warren };
681ad7e899SStephen Warren 
69b5af921eSWill Drewry /**
70b5af921eSWill Drewry  * match_dev_by_uuid - callback for finding a partition using its uuid
71b5af921eSWill Drewry  * @dev:	device passed in by the caller
721ad7e899SStephen Warren  * @data:	opaque pointer to the desired struct uuidcmp to match
73b5af921eSWill Drewry  *
74b5af921eSWill Drewry  * Returns 1 if the device matches, and 0 otherwise.
75b5af921eSWill Drewry  */
769f3b795aSMichał Mirosław static int match_dev_by_uuid(struct device *dev, const void *data)
77b5af921eSWill Drewry {
780d02129eSChristoph Hellwig 	struct block_device *bdev = dev_to_bdev(dev);
799f3b795aSMichał Mirosław 	const struct uuidcmp *cmp = data;
80b5af921eSWill Drewry 
810d02129eSChristoph Hellwig 	if (!bdev->bd_meta_info ||
820d02129eSChristoph Hellwig 	    strncasecmp(cmp->uuid, bdev->bd_meta_info->uuid, cmp->len))
83b5af921eSWill Drewry 		return 0;
84013b0e96SChristoph Hellwig 	return 1;
85b5af921eSWill Drewry }
86b5af921eSWill Drewry 
87b5af921eSWill Drewry /**
88b5af921eSWill Drewry  * devt_from_partuuid - looks up the dev_t of a partition by its UUID
89a68b3108Schishanmingshen  * @uuid_str:	char array containing ascii UUID
90b5af921eSWill Drewry  *
91b5af921eSWill Drewry  * The function will return the first partition which contains a matching
92b5af921eSWill Drewry  * UUID value in its partition_meta_info struct.  This does not search
93b5af921eSWill Drewry  * by filesystem UUIDs.
94b5af921eSWill Drewry  *
95a68b3108Schishanmingshen  * If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be
9679975f13SWill Drewry  * extracted and used as an offset from the partition identified by the UUID.
9779975f13SWill Drewry  *
98b5af921eSWill Drewry  * Returns the matching dev_t on success or 0 on failure.
99b5af921eSWill Drewry  */
1001ad7e899SStephen Warren static dev_t devt_from_partuuid(const char *uuid_str)
101b5af921eSWill Drewry {
1021ad7e899SStephen Warren 	struct uuidcmp cmp;
103b5af921eSWill Drewry 	struct device *dev = NULL;
104e036bb8eSChristoph Hellwig 	dev_t devt = 0;
10579975f13SWill Drewry 	int offset = 0;
106283f8fc0SStephen Warren 	char *slash;
10779975f13SWill Drewry 
1081ad7e899SStephen Warren 	cmp.uuid = uuid_str;
1091ad7e899SStephen Warren 
110283f8fc0SStephen Warren 	slash = strchr(uuid_str, '/');
11179975f13SWill Drewry 	/* Check for optional partition number offset attributes. */
112283f8fc0SStephen Warren 	if (slash) {
11379975f13SWill Drewry 		char c = 0;
114e036bb8eSChristoph Hellwig 
11579975f13SWill Drewry 		/* Explicitly fail on poor PARTUUID syntax. */
116e036bb8eSChristoph Hellwig 		if (sscanf(slash + 1, "PARTNROFF=%d%c", &offset, &c) != 1)
117e036bb8eSChristoph Hellwig 			goto clear_root_wait;
118283f8fc0SStephen Warren 		cmp.len = slash - uuid_str;
119283f8fc0SStephen Warren 	} else {
120283f8fc0SStephen Warren 		cmp.len = strlen(uuid_str);
121283f8fc0SStephen Warren 	}
122283f8fc0SStephen Warren 
123e036bb8eSChristoph Hellwig 	if (!cmp.len)
124e036bb8eSChristoph Hellwig 		goto clear_root_wait;
125b5af921eSWill Drewry 
126e036bb8eSChristoph Hellwig 	dev = class_find_device(&block_class, NULL, &cmp, &match_dev_by_uuid);
127b5af921eSWill Drewry 	if (!dev)
128e036bb8eSChristoph Hellwig 		return 0;
129b5af921eSWill Drewry 
130e036bb8eSChristoph Hellwig 	if (offset) {
131e036bb8eSChristoph Hellwig 		/*
132e036bb8eSChristoph Hellwig 		 * Attempt to find the requested partition by adding an offset
133e036bb8eSChristoph Hellwig 		 * to the partition number found by UUID.
134e036bb8eSChristoph Hellwig 		 */
135c97d93c3SChristoph Hellwig 		devt = part_devt(dev_to_disk(dev),
1360d02129eSChristoph Hellwig 				 dev_to_bdev(dev)->bd_partno + offset);
137e036bb8eSChristoph Hellwig 	} else {
138e036bb8eSChristoph Hellwig 		devt = dev->devt;
139e036bb8eSChristoph Hellwig 	}
14079975f13SWill Drewry 
14179975f13SWill Drewry 	put_device(dev);
142e036bb8eSChristoph Hellwig 	return devt;
143e036bb8eSChristoph Hellwig 
144e036bb8eSChristoph Hellwig clear_root_wait:
145283f8fc0SStephen Warren 	pr_err("VFS: PARTUUID= is invalid.\n"
146283f8fc0SStephen Warren 	       "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
147283f8fc0SStephen Warren 	if (root_wait)
148283f8fc0SStephen Warren 		pr_err("Disabling rootwait; root= is invalid.\n");
149283f8fc0SStephen Warren 	root_wait = 0;
150e036bb8eSChristoph Hellwig 	return 0;
151b5af921eSWill Drewry }
152f027c34dSNikolaus Voss 
153f027c34dSNikolaus Voss /**
154f027c34dSNikolaus Voss  * match_dev_by_label - callback for finding a partition using its label
155f027c34dSNikolaus Voss  * @dev:	device passed in by the caller
156f027c34dSNikolaus Voss  * @data:	opaque pointer to the label to match
157f027c34dSNikolaus Voss  *
158f027c34dSNikolaus Voss  * Returns 1 if the device matches, and 0 otherwise.
159f027c34dSNikolaus Voss  */
160f027c34dSNikolaus Voss static int match_dev_by_label(struct device *dev, const void *data)
161f027c34dSNikolaus Voss {
1620d02129eSChristoph Hellwig 	struct block_device *bdev = dev_to_bdev(dev);
163f027c34dSNikolaus Voss 	const char *label = data;
164f027c34dSNikolaus Voss 
1650d02129eSChristoph Hellwig 	if (!bdev->bd_meta_info || strcmp(label, bdev->bd_meta_info->volname))
166f027c34dSNikolaus Voss 		return 0;
167013b0e96SChristoph Hellwig 	return 1;
168f027c34dSNikolaus Voss }
169c2637e80SChristoph Hellwig 
170c2637e80SChristoph Hellwig static dev_t devt_from_partlabel(const char *label)
171c2637e80SChristoph Hellwig {
172c2637e80SChristoph Hellwig 	struct device *dev;
173c2637e80SChristoph Hellwig 	dev_t devt = 0;
174c2637e80SChristoph Hellwig 
175c2637e80SChristoph Hellwig 	dev = class_find_device(&block_class, NULL, label, &match_dev_by_label);
176c2637e80SChristoph Hellwig 	if (dev) {
177c2637e80SChristoph Hellwig 		devt = dev->devt;
178c2637e80SChristoph Hellwig 		put_device(dev);
179c2637e80SChristoph Hellwig 	}
180c2637e80SChristoph Hellwig 
181c2637e80SChristoph Hellwig 	return devt;
182c2637e80SChristoph Hellwig }
183c2637e80SChristoph Hellwig 
184c2637e80SChristoph Hellwig static dev_t devt_from_devname(const char *name)
185c2637e80SChristoph Hellwig {
186c2637e80SChristoph Hellwig 	dev_t devt = 0;
187c2637e80SChristoph Hellwig 	int part;
188c2637e80SChristoph Hellwig 	char s[32];
189c2637e80SChristoph Hellwig 	char *p;
190c2637e80SChristoph Hellwig 
191c2637e80SChristoph Hellwig 	if (strlen(name) > 31)
192c2637e80SChristoph Hellwig 		return 0;
193c2637e80SChristoph Hellwig 	strcpy(s, name);
194c2637e80SChristoph Hellwig 	for (p = s; *p; p++) {
195c2637e80SChristoph Hellwig 		if (*p == '/')
196c2637e80SChristoph Hellwig 			*p = '!';
197c2637e80SChristoph Hellwig 	}
198c2637e80SChristoph Hellwig 
199c2637e80SChristoph Hellwig 	devt = blk_lookup_devt(s, 0);
200c2637e80SChristoph Hellwig 	if (devt)
201c2637e80SChristoph Hellwig 		return devt;
202c2637e80SChristoph Hellwig 
203c2637e80SChristoph Hellwig 	/*
204c2637e80SChristoph Hellwig 	 * Try non-existent, but valid partition, which may only exist after
205c2637e80SChristoph Hellwig 	 * opening the device, like partitioned md devices.
206c2637e80SChristoph Hellwig 	 */
207c2637e80SChristoph Hellwig 	while (p > s && isdigit(p[-1]))
208c2637e80SChristoph Hellwig 		p--;
209c2637e80SChristoph Hellwig 	if (p == s || !*p || *p == '0')
210c2637e80SChristoph Hellwig 		return 0;
211c2637e80SChristoph Hellwig 
212c2637e80SChristoph Hellwig 	/* try disk name without <part number> */
213c2637e80SChristoph Hellwig 	part = simple_strtoul(p, NULL, 10);
214c2637e80SChristoph Hellwig 	*p = '\0';
215c2637e80SChristoph Hellwig 	devt = blk_lookup_devt(s, part);
216c2637e80SChristoph Hellwig 	if (devt)
217c2637e80SChristoph Hellwig 		return devt;
218c2637e80SChristoph Hellwig 
219c2637e80SChristoph Hellwig 	/* try disk name without p<part number> */
220c2637e80SChristoph Hellwig 	if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
221c2637e80SChristoph Hellwig 		return 0;
222c2637e80SChristoph Hellwig 	p[-1] = '\0';
223c2637e80SChristoph Hellwig 	return blk_lookup_devt(s, part);
224c2637e80SChristoph Hellwig }
225c2637e80SChristoph Hellwig #endif /* CONFIG_BLOCK */
226c2637e80SChristoph Hellwig 
227c2637e80SChristoph Hellwig static dev_t devt_from_devnum(const char *name)
228c2637e80SChristoph Hellwig {
229c2637e80SChristoph Hellwig 	unsigned maj, min, offset;
230c2637e80SChristoph Hellwig 	dev_t devt = 0;
231c2637e80SChristoph Hellwig 	char *p, dummy;
232c2637e80SChristoph Hellwig 
233c2637e80SChristoph Hellwig 	if (sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2 ||
234c2637e80SChristoph Hellwig 	    sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3) {
235c2637e80SChristoph Hellwig 		devt = MKDEV(maj, min);
236c2637e80SChristoph Hellwig 		if (maj != MAJOR(devt) || min != MINOR(devt))
237c2637e80SChristoph Hellwig 			return 0;
238c2637e80SChristoph Hellwig 	} else {
239c2637e80SChristoph Hellwig 		devt = new_decode_dev(simple_strtoul(name, &p, 16));
240c2637e80SChristoph Hellwig 		if (*p)
241c2637e80SChristoph Hellwig 			return 0;
242c2637e80SChristoph Hellwig 	}
243c2637e80SChristoph Hellwig 
244c2637e80SChristoph Hellwig 	return devt;
245c2637e80SChristoph Hellwig }
246b5af921eSWill Drewry 
2471da177e4SLinus Torvalds /*
2481da177e4SLinus Torvalds  *	Convert a name into device number.  We accept the following variants:
2491da177e4SLinus Torvalds  *
2500bf37ae4SPavel Machek  *	1) <hex_major><hex_minor> device number in hexadecimal represents itself
2510bf37ae4SPavel Machek  *         no leading 0x, for example b302.
2521da177e4SLinus Torvalds  *	2) /dev/nfs represents Root_NFS (0xff)
2531da177e4SLinus Torvalds  *	3) /dev/<disk_name> represents the device number of disk
2541da177e4SLinus Torvalds  *	4) /dev/<disk_name><decimal> represents the device number
2551da177e4SLinus Torvalds  *         of partition - device number of disk plus the partition number
2561da177e4SLinus Torvalds  *	5) /dev/<disk_name>p<decimal> - same as the above, that form is
2571da177e4SLinus Torvalds  *	   used when disk name of partitioned disk ends on a digit.
258b5af921eSWill Drewry  *	6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
259b5af921eSWill Drewry  *	   unique id of a partition if the partition table provides it.
260d33b98fcSStephen Warren  *	   The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
261d33b98fcSStephen Warren  *	   partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
262d33b98fcSStephen Warren  *	   filled hex representation of the 32-bit "NT disk signature", and PP
263d33b98fcSStephen Warren  *	   is a zero-filled hex representation of the 1-based partition number.
26479975f13SWill Drewry  *	7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
26579975f13SWill Drewry  *	   a partition with a known unique id.
2666c251611SSebastian Capella  *	8) <major>:<minor> major and minor number of the device separated by
2676c251611SSebastian Capella  *	   a colon.
268f027c34dSNikolaus Voss  *	9) PARTLABEL=<name> with name being the GPT partition label.
269f027c34dSNikolaus Voss  *	   MSDOS partitions do not support labels!
2708902dd52SPaulo Alcantara (SUSE)  *	10) /dev/cifs represents Root_CIFS (0xfe)
2711da177e4SLinus Torvalds  *
272edfaa7c3SKay Sievers  *	If name doesn't have fall into the categories above, we return (0,0).
273edfaa7c3SKay Sievers  *	block_class is used to check if something is a disk name. If the disk
274edfaa7c3SKay Sievers  *	name contains slashes, the device name has them replaced with
275edfaa7c3SKay Sievers  *	bangs.
2761da177e4SLinus Torvalds  */
277e6e20a7aSDan Ehrenberg dev_t name_to_dev_t(const char *name)
2781da177e4SLinus Torvalds {
279c2637e80SChristoph Hellwig 	if (strcmp(name, "/dev/nfs") == 0)
280c2637e80SChristoph Hellwig 		return Root_NFS;
281c2637e80SChristoph Hellwig 	if (strcmp(name, "/dev/cifs") == 0)
282c2637e80SChristoph Hellwig 		return Root_CIFS;
283c2637e80SChristoph Hellwig 	if (strcmp(name, "/dev/ram") == 0)
284c2637e80SChristoph Hellwig 		return Root_RAM0;
2856d0aed7aSJens Axboe #ifdef CONFIG_BLOCK
286c2637e80SChristoph Hellwig 	if (strncmp(name, "PARTUUID=", 9) == 0)
287c2637e80SChristoph Hellwig 		return devt_from_partuuid(name + 9);
288c2637e80SChristoph Hellwig 	if (strncmp(name, "PARTLABEL=", 10) == 0)
289c2637e80SChristoph Hellwig 		return devt_from_partlabel(name + 10);
290c2637e80SChristoph Hellwig 	if (strncmp(name, "/dev/", 5) == 0)
291c2637e80SChristoph Hellwig 		return devt_from_devname(name + 5);
2926d0aed7aSJens Axboe #endif
293c2637e80SChristoph Hellwig 	return devt_from_devnum(name);
2941da177e4SLinus Torvalds }
295e6e20a7aSDan Ehrenberg EXPORT_SYMBOL_GPL(name_to_dev_t);
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds static int __init root_dev_setup(char *line)
2981da177e4SLinus Torvalds {
299a1d3a6d9SWolfram Sang 	strscpy(saved_root_name, line, sizeof(saved_root_name));
3001da177e4SLinus Torvalds 	return 1;
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds __setup("root=", root_dev_setup);
3041da177e4SLinus Torvalds 
305cc1ed754SPierre Ossman static int __init rootwait_setup(char *str)
306cc1ed754SPierre Ossman {
307cc1ed754SPierre Ossman 	if (*str)
308cc1ed754SPierre Ossman 		return 0;
309cc1ed754SPierre Ossman 	root_wait = 1;
310cc1ed754SPierre Ossman 	return 1;
311cc1ed754SPierre Ossman }
312cc1ed754SPierre Ossman 
313cc1ed754SPierre Ossman __setup("rootwait", rootwait_setup);
314cc1ed754SPierre Ossman 
3151da177e4SLinus Torvalds static char * __initdata root_mount_data;
3161da177e4SLinus Torvalds static int __init root_data_setup(char *str)
3171da177e4SLinus Torvalds {
3181da177e4SLinus Torvalds 	root_mount_data = str;
3191da177e4SLinus Torvalds 	return 1;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds static char * __initdata root_fs_names;
3231da177e4SLinus Torvalds static int __init fs_names_setup(char *str)
3241da177e4SLinus Torvalds {
3251da177e4SLinus Torvalds 	root_fs_names = str;
3261da177e4SLinus Torvalds 	return 1;
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds static unsigned int __initdata root_delay;
3301da177e4SLinus Torvalds static int __init root_delay_setup(char *str)
3311da177e4SLinus Torvalds {
3321da177e4SLinus Torvalds 	root_delay = simple_strtoul(str, NULL, 0);
3331da177e4SLinus Torvalds 	return 1;
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds __setup("rootflags=", root_data_setup);
3371da177e4SLinus Torvalds __setup("rootfstype=", fs_names_setup);
3381da177e4SLinus Torvalds __setup("rootdelay=", root_delay_setup);
3391da177e4SLinus Torvalds 
340b51593c4SVivek Goyal /* This can return zero length strings. Caller should check */
341b51593c4SVivek Goyal static int __init split_fs_names(char *page, size_t size, char *names)
3421da177e4SLinus Torvalds {
343b51593c4SVivek Goyal 	int count = 1;
3446e7c1770SChristoph Hellwig 	char *p = page;
3451da177e4SLinus Torvalds 
346a1d3a6d9SWolfram Sang 	strscpy(p, root_fs_names, size);
3476e7c1770SChristoph Hellwig 	while (*p++) {
348b51593c4SVivek Goyal 		if (p[-1] == ',') {
3496e7c1770SChristoph Hellwig 			p[-1] = '\0';
3506e7c1770SChristoph Hellwig 			count++;
351b51593c4SVivek Goyal 		}
352b51593c4SVivek Goyal 	}
3536e7c1770SChristoph Hellwig 
3546e7c1770SChristoph Hellwig 	return count;
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds 
357cccaa5e3SDominik Brodowski static int __init do_mount_root(const char *name, const char *fs,
358cccaa5e3SDominik Brodowski 				 const int flags, const void *data)
3591da177e4SLinus Torvalds {
360d8c9584eSAl Viro 	struct super_block *s;
3617de7de7cSLinus Torvalds 	struct page *p = NULL;
3627de7de7cSLinus Torvalds 	char *data_page = NULL;
363cccaa5e3SDominik Brodowski 	int ret;
364cccaa5e3SDominik Brodowski 
3657de7de7cSLinus Torvalds 	if (data) {
366c60166f0SChristoph Hellwig 		/* init_mount() requires a full page as fifth argument */
367cccaa5e3SDominik Brodowski 		p = alloc_page(GFP_KERNEL);
368cccaa5e3SDominik Brodowski 		if (!p)
369cccaa5e3SDominik Brodowski 			return -ENOMEM;
370cccaa5e3SDominik Brodowski 		data_page = page_address(p);
371c60166f0SChristoph Hellwig 		/* zero-pad. init_mount() will make sure it's terminated */
3727de7de7cSLinus Torvalds 		strncpy(data_page, data, PAGE_SIZE);
3737de7de7cSLinus Torvalds 	}
374cccaa5e3SDominik Brodowski 
375c60166f0SChristoph Hellwig 	ret = init_mount(name, "/root", fs, flags, data_page);
376cccaa5e3SDominik Brodowski 	if (ret)
377cccaa5e3SDominik Brodowski 		goto out;
3781da177e4SLinus Torvalds 
379db63f1e3SChristoph Hellwig 	init_chdir("/root");
380d8c9584eSAl Viro 	s = current->fs->pwd.dentry->d_sb;
381d8c9584eSAl Viro 	ROOT_DEV = s->s_dev;
38280cdc6daSMandeep Singh Baines 	printk(KERN_INFO
38380cdc6daSMandeep Singh Baines 	       "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
384d8c9584eSAl Viro 	       s->s_type->name,
385bc98a42cSDavid Howells 	       sb_rdonly(s) ? " readonly" : "",
386d8c9584eSAl Viro 	       MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
387cccaa5e3SDominik Brodowski 
388cccaa5e3SDominik Brodowski out:
3897de7de7cSLinus Torvalds 	if (p)
390cccaa5e3SDominik Brodowski 		put_page(p);
391cccaa5e3SDominik Brodowski 	return ret;
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
394e3102722SChristoph Hellwig void __init mount_root_generic(char *name, int flags)
3951da177e4SLinus Torvalds {
39675f296d9SLevin, Alexander (Sasha Levin) 	struct page *page = alloc_page(GFP_KERNEL);
397a608ca21SJeff Layton 	char *fs_names = page_address(page);
3981da177e4SLinus Torvalds 	char *p;
3991da177e4SLinus Torvalds 	char b[BDEVNAME_SIZE];
4006e7c1770SChristoph Hellwig 	int num_fs, i;
4011da177e4SLinus Torvalds 
402ea3edd4dSChristoph Hellwig 	scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)",
403ea3edd4dSChristoph Hellwig 		  MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
404e24d12b7SChristoph Hellwig 	if (root_fs_names)
405b51593c4SVivek Goyal 		num_fs = split_fs_names(fs_names, PAGE_SIZE, root_fs_names);
406e24d12b7SChristoph Hellwig 	else
4076e7c1770SChristoph Hellwig 		num_fs = list_bdev_fs_names(fs_names, PAGE_SIZE);
4081da177e4SLinus Torvalds retry:
4096e7c1770SChristoph Hellwig 	for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) {
410b51593c4SVivek Goyal 		int err;
411b51593c4SVivek Goyal 
412b51593c4SVivek Goyal 		if (!*p)
413b51593c4SVivek Goyal 			continue;
414b51593c4SVivek Goyal 		err = do_mount_root(name, p, flags, root_mount_data);
4151da177e4SLinus Torvalds 		switch (err) {
4161da177e4SLinus Torvalds 			case 0:
4171da177e4SLinus Torvalds 				goto out;
4181da177e4SLinus Torvalds 			case -EACCES:
4191da177e4SLinus Torvalds 			case -EINVAL:
4201da177e4SLinus Torvalds 				continue;
4211da177e4SLinus Torvalds 		}
4221da177e4SLinus Torvalds 	        /*
4231da177e4SLinus Torvalds 		 * Allow the user to distinguish between failed sys_open
4241da177e4SLinus Torvalds 		 * and bad superblock on root device.
425dd2a345fSDave Gilbert 		 * and give them a list of the available devices
4261da177e4SLinus Torvalds 		 */
4270e0cb892SBernhard Walle 		printk("VFS: Cannot open root device \"%s\" or %s: error %d\n",
4280e0cb892SBernhard Walle 				root_device_name, b, err);
429dd2a345fSDave Gilbert 		printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
4301da177e4SLinus Torvalds 
431dd2a345fSDave Gilbert 		printk_all_partitions();
4321da177e4SLinus Torvalds 		panic("VFS: Unable to mount root fs on %s", b);
4331da177e4SLinus Torvalds 	}
434e462ec50SDavid Howells 	if (!(flags & SB_RDONLY)) {
435e462ec50SDavid Howells 		flags |= SB_RDONLY;
43610975933SMiklos Szeredi 		goto retry;
43710975933SMiklos Szeredi 	}
438be6e028bSAndy Whitcroft 
439dd2a345fSDave Gilbert 	printk("List of all partitions:\n");
440dd2a345fSDave Gilbert 	printk_all_partitions();
441be6e028bSAndy Whitcroft 	printk("No filesystem could mount root, tried: ");
4426e7c1770SChristoph Hellwig 	for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1)
443be6e028bSAndy Whitcroft 		printk(" %s", p);
444be6e028bSAndy Whitcroft 	printk("\n");
4459361401eSDavid Howells 	panic("VFS: Unable to mount root fs on %s", b);
4461da177e4SLinus Torvalds out:
447a608ca21SJeff Layton 	put_page(page);
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds #ifdef CONFIG_ROOT_NFS
45143717c7dSChuck Lever 
45243717c7dSChuck Lever #define NFSROOT_TIMEOUT_MIN	5
45343717c7dSChuck Lever #define NFSROOT_TIMEOUT_MAX	30
45443717c7dSChuck Lever #define NFSROOT_RETRY_MAX	5
45543717c7dSChuck Lever 
456*a6a41d39SChristoph Hellwig static void __init mount_nfs_root(void)
4571da177e4SLinus Torvalds {
45856463e50SChuck Lever 	char *root_dev, *root_data;
45943717c7dSChuck Lever 	unsigned int timeout;
460*a6a41d39SChristoph Hellwig 	int try;
4611da177e4SLinus Torvalds 
462*a6a41d39SChristoph Hellwig 	if (nfs_root_data(&root_dev, &root_data))
463*a6a41d39SChristoph Hellwig 		goto fail;
46443717c7dSChuck Lever 
46543717c7dSChuck Lever 	/*
46643717c7dSChuck Lever 	 * The server or network may not be ready, so try several
46743717c7dSChuck Lever 	 * times.  Stop after a few tries in case the client wants
46843717c7dSChuck Lever 	 * to fall back to other boot methods.
46943717c7dSChuck Lever 	 */
47043717c7dSChuck Lever 	timeout = NFSROOT_TIMEOUT_MIN;
47143717c7dSChuck Lever 	for (try = 1; ; try++) {
472*a6a41d39SChristoph Hellwig 		if (!do_mount_root(root_dev, "nfs", root_mountflags, root_data))
473*a6a41d39SChristoph Hellwig 			return;
47443717c7dSChuck Lever 		if (try > NFSROOT_RETRY_MAX)
47543717c7dSChuck Lever 			break;
47643717c7dSChuck Lever 
47743717c7dSChuck Lever 		/* Wait, in case the server refused us immediately */
47843717c7dSChuck Lever 		ssleep(timeout);
47943717c7dSChuck Lever 		timeout <<= 1;
48043717c7dSChuck Lever 		if (timeout > NFSROOT_TIMEOUT_MAX)
48143717c7dSChuck Lever 			timeout = NFSROOT_TIMEOUT_MAX;
48243717c7dSChuck Lever 	}
483*a6a41d39SChristoph Hellwig fail:
484*a6a41d39SChristoph Hellwig 	pr_err("VFS: Unable to mount root fs via NFS.\n");
4851da177e4SLinus Torvalds }
486*a6a41d39SChristoph Hellwig #else
487*a6a41d39SChristoph Hellwig static inline void mount_nfs_root(void)
488*a6a41d39SChristoph Hellwig {
489*a6a41d39SChristoph Hellwig }
490*a6a41d39SChristoph Hellwig #endif /* CONFIG_ROOT_NFS */
4911da177e4SLinus Torvalds 
4928902dd52SPaulo Alcantara (SUSE) #ifdef CONFIG_CIFS_ROOT
4938902dd52SPaulo Alcantara (SUSE) 
4948902dd52SPaulo Alcantara (SUSE) extern int cifs_root_data(char **dev, char **opts);
4958902dd52SPaulo Alcantara (SUSE) 
4968902dd52SPaulo Alcantara (SUSE) #define CIFSROOT_TIMEOUT_MIN	5
4978902dd52SPaulo Alcantara (SUSE) #define CIFSROOT_TIMEOUT_MAX	30
4988902dd52SPaulo Alcantara (SUSE) #define CIFSROOT_RETRY_MAX	5
4998902dd52SPaulo Alcantara (SUSE) 
500*a6a41d39SChristoph Hellwig static void __init mount_cifs_root(void)
5018902dd52SPaulo Alcantara (SUSE) {
5028902dd52SPaulo Alcantara (SUSE) 	char *root_dev, *root_data;
5038902dd52SPaulo Alcantara (SUSE) 	unsigned int timeout;
504*a6a41d39SChristoph Hellwig 	int try;
5058902dd52SPaulo Alcantara (SUSE) 
506*a6a41d39SChristoph Hellwig 	if (cifs_root_data(&root_dev, &root_data))
507*a6a41d39SChristoph Hellwig 		goto fail;
5088902dd52SPaulo Alcantara (SUSE) 
5098902dd52SPaulo Alcantara (SUSE) 	timeout = CIFSROOT_TIMEOUT_MIN;
5108902dd52SPaulo Alcantara (SUSE) 	for (try = 1; ; try++) {
511*a6a41d39SChristoph Hellwig 		if (!do_mount_root(root_dev, "cifs", root_mountflags,
512*a6a41d39SChristoph Hellwig 				   root_data))
513*a6a41d39SChristoph Hellwig 			return;
5148902dd52SPaulo Alcantara (SUSE) 		if (try > CIFSROOT_RETRY_MAX)
5158902dd52SPaulo Alcantara (SUSE) 			break;
5168902dd52SPaulo Alcantara (SUSE) 
5178902dd52SPaulo Alcantara (SUSE) 		ssleep(timeout);
5188902dd52SPaulo Alcantara (SUSE) 		timeout <<= 1;
5198902dd52SPaulo Alcantara (SUSE) 		if (timeout > CIFSROOT_TIMEOUT_MAX)
5208902dd52SPaulo Alcantara (SUSE) 			timeout = CIFSROOT_TIMEOUT_MAX;
5218902dd52SPaulo Alcantara (SUSE) 	}
522*a6a41d39SChristoph Hellwig fail:
523*a6a41d39SChristoph Hellwig 	pr_err("VFS: Unable to mount root fs via SMB.\n");
5248902dd52SPaulo Alcantara (SUSE) }
525*a6a41d39SChristoph Hellwig #else
526*a6a41d39SChristoph Hellwig static inline void mount_cifs_root(void)
527*a6a41d39SChristoph Hellwig {
528*a6a41d39SChristoph Hellwig }
529*a6a41d39SChristoph Hellwig #endif /* CONFIG_CIFS_ROOT */
5308902dd52SPaulo Alcantara (SUSE) 
531f9259be6SChristoph Hellwig static bool __init fs_is_nodev(char *fstype)
532f9259be6SChristoph Hellwig {
533f9259be6SChristoph Hellwig 	struct file_system_type *fs = get_fs_type(fstype);
534f9259be6SChristoph Hellwig 	bool ret = false;
535f9259be6SChristoph Hellwig 
536f9259be6SChristoph Hellwig 	if (fs) {
537f9259be6SChristoph Hellwig 		ret = !(fs->fs_flags & FS_REQUIRES_DEV);
538f9259be6SChristoph Hellwig 		put_filesystem(fs);
539f9259be6SChristoph Hellwig 	}
540f9259be6SChristoph Hellwig 
541f9259be6SChristoph Hellwig 	return ret;
542f9259be6SChristoph Hellwig }
543f9259be6SChristoph Hellwig 
544f9259be6SChristoph Hellwig static int __init mount_nodev_root(void)
545f9259be6SChristoph Hellwig {
546f9259be6SChristoph Hellwig 	char *fs_names, *fstype;
547f9259be6SChristoph Hellwig 	int err = -EINVAL;
5486e7c1770SChristoph Hellwig 	int num_fs, i;
549f9259be6SChristoph Hellwig 
550f9259be6SChristoph Hellwig 	fs_names = (void *)__get_free_page(GFP_KERNEL);
551f9259be6SChristoph Hellwig 	if (!fs_names)
552f9259be6SChristoph Hellwig 		return -EINVAL;
553b51593c4SVivek Goyal 	num_fs = split_fs_names(fs_names, PAGE_SIZE, root_fs_names);
554f9259be6SChristoph Hellwig 
5556e7c1770SChristoph Hellwig 	for (i = 0, fstype = fs_names; i < num_fs;
5566e7c1770SChristoph Hellwig 	     i++, fstype += strlen(fstype) + 1) {
557b51593c4SVivek Goyal 		if (!*fstype)
558b51593c4SVivek Goyal 			continue;
559f9259be6SChristoph Hellwig 		if (!fs_is_nodev(fstype))
560f9259be6SChristoph Hellwig 			continue;
561f9259be6SChristoph Hellwig 		err = do_mount_root(root_device_name, fstype, root_mountflags,
562f9259be6SChristoph Hellwig 				    root_mount_data);
563f9259be6SChristoph Hellwig 		if (!err)
564f9259be6SChristoph Hellwig 			break;
565f9259be6SChristoph Hellwig 	}
566f9259be6SChristoph Hellwig 
567f9259be6SChristoph Hellwig 	free_page((unsigned long)fs_names);
568f9259be6SChristoph Hellwig 	return err;
569f9259be6SChristoph Hellwig }
570f9259be6SChristoph Hellwig 
5719361401eSDavid Howells #ifdef CONFIG_BLOCK
572*a6a41d39SChristoph Hellwig static void __init mount_block_root(void)
573c69e3c3aSVishnu Pratap Singh {
574c69e3c3aSVishnu Pratap Singh 	int err = create_dev("/dev/root", ROOT_DEV);
575c69e3c3aSVishnu Pratap Singh 
576c69e3c3aSVishnu Pratap Singh 	if (err < 0)
577c69e3c3aSVishnu Pratap Singh 		pr_emerg("Failed to create /dev/root: %d\n", err);
578e3102722SChristoph Hellwig 	mount_root_generic("/dev/root", root_mountflags);
579c69e3c3aSVishnu Pratap Singh }
580*a6a41d39SChristoph Hellwig #else
581*a6a41d39SChristoph Hellwig static inline void mount_block_root(void)
582*a6a41d39SChristoph Hellwig {
583*a6a41d39SChristoph Hellwig }
584*a6a41d39SChristoph Hellwig #endif /* CONFIG_BLOCK */
585*a6a41d39SChristoph Hellwig 
586*a6a41d39SChristoph Hellwig void __init mount_root(void)
587*a6a41d39SChristoph Hellwig {
588*a6a41d39SChristoph Hellwig 	switch (ROOT_DEV) {
589*a6a41d39SChristoph Hellwig 	case Root_NFS:
590*a6a41d39SChristoph Hellwig 		mount_nfs_root();
591*a6a41d39SChristoph Hellwig 		break;
592*a6a41d39SChristoph Hellwig 	case Root_CIFS:
593*a6a41d39SChristoph Hellwig 		mount_cifs_root();
594*a6a41d39SChristoph Hellwig 		break;
595*a6a41d39SChristoph Hellwig 	case 0:
596*a6a41d39SChristoph Hellwig 		if (root_device_name && root_fs_names && mount_nodev_root() == 0)
597*a6a41d39SChristoph Hellwig 			break;
598*a6a41d39SChristoph Hellwig 		fallthrough;
599*a6a41d39SChristoph Hellwig 	default:
600*a6a41d39SChristoph Hellwig 		mount_block_root();
601*a6a41d39SChristoph Hellwig 		break;
602*a6a41d39SChristoph Hellwig 	}
6031da177e4SLinus Torvalds }
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds /*
6061da177e4SLinus Torvalds  * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
6071da177e4SLinus Torvalds  */
6081da177e4SLinus Torvalds void __init prepare_namespace(void)
6091da177e4SLinus Torvalds {
6101da177e4SLinus Torvalds 	if (root_delay) {
6111da177e4SLinus Torvalds 		printk(KERN_INFO "Waiting %d sec before mounting root device...\n",
6121da177e4SLinus Torvalds 		       root_delay);
6131da177e4SLinus Torvalds 		ssleep(root_delay);
6141da177e4SLinus Torvalds 	}
6151da177e4SLinus Torvalds 
616216773a7SArjan van de Ven 	/*
617216773a7SArjan van de Ven 	 * wait for the known devices to complete their probing
618216773a7SArjan van de Ven 	 *
619216773a7SArjan van de Ven 	 * Note: this is a potential source of long boot delays.
620216773a7SArjan van de Ven 	 * For example, it is not atypical to wait 5 seconds here
621216773a7SArjan van de Ven 	 * for the touchpad of a laptop to initialize.
622216773a7SArjan van de Ven 	 */
623216773a7SArjan van de Ven 	wait_for_device_probe();
624d779249eSGreg Kroah-Hartman 
6251da177e4SLinus Torvalds 	md_run_setup();
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	if (saved_root_name[0]) {
6281da177e4SLinus Torvalds 		root_device_name = saved_root_name;
6292d62f488SAdrian Hunter 		if (!strncmp(root_device_name, "mtd", 3) ||
6302d62f488SAdrian Hunter 		    !strncmp(root_device_name, "ubi", 3)) {
631e3102722SChristoph Hellwig 			mount_root_generic(root_device_name, root_mountflags);
632e9482b43SJoern Engel 			goto out;
633e9482b43SJoern Engel 		}
6341da177e4SLinus Torvalds 		ROOT_DEV = name_to_dev_t(root_device_name);
6351da177e4SLinus Torvalds 		if (strncmp(root_device_name, "/dev/", 5) == 0)
6361da177e4SLinus Torvalds 			root_device_name += 5;
6371da177e4SLinus Torvalds 	}
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds 	if (initrd_load())
6401da177e4SLinus Torvalds 		goto out;
6411da177e4SLinus Torvalds 
642cc1ed754SPierre Ossman 	/* wait for any asynchronous scanning to complete */
643cc1ed754SPierre Ossman 	if ((ROOT_DEV == 0) && root_wait) {
644cc1ed754SPierre Ossman 		printk(KERN_INFO "Waiting for root device %s...\n",
645cc1ed754SPierre Ossman 			saved_root_name);
646aa5f6ed8SChristoph Hellwig 		while (!driver_probe_done() ||
647cc1ed754SPierre Ossman 			(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
64839a0e975SJungseung Lee 			msleep(5);
649216773a7SArjan van de Ven 		async_synchronize_full();
650cc1ed754SPierre Ossman 	}
651cc1ed754SPierre Ossman 
6521da177e4SLinus Torvalds 	mount_root();
6531da177e4SLinus Torvalds out:
6545e787dbfSDominik Brodowski 	devtmpfs_mount();
655c60166f0SChristoph Hellwig 	init_mount(".", "/", NULL, MS_MOVE, NULL);
6564b7ca501SChristoph Hellwig 	init_chroot(".");
6571da177e4SLinus Torvalds }
65857f150a5SRob Landley 
6596e19ededSRob Landley static bool is_tmpfs;
660f3235626SDavid Howells static int rootfs_init_fs_context(struct fs_context *fc)
66157f150a5SRob Landley {
6626e19ededSRob Landley 	if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
663f3235626SDavid Howells 		return shmem_init_fs_context(fc);
6646e19ededSRob Landley 
665f3235626SDavid Howells 	return ramfs_init_fs_context(fc);
66657f150a5SRob Landley }
66757f150a5SRob Landley 
668fd3e007fSAl Viro struct file_system_type rootfs_fs_type = {
66957f150a5SRob Landley 	.name		= "rootfs",
670f3235626SDavid Howells 	.init_fs_context = rootfs_init_fs_context,
67157f150a5SRob Landley 	.kill_sb	= kill_litter_super,
67257f150a5SRob Landley };
67357f150a5SRob Landley 
674037f11b4SAl Viro void __init init_rootfs(void)
67557f150a5SRob Landley {
6766e19ededSRob Landley 	if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
677037f11b4SAl Viro 		(!root_fs_names || strstr(root_fs_names, "tmpfs")))
6786e19ededSRob Landley 		is_tmpfs = true;
67957f150a5SRob Landley }
680