Blame view

init/do_mounts.c 15.6 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
  #include <linux/module.h>
  #include <linux/sched.h>
  #include <linux/ctype.h>
  #include <linux/fd.h>
  #include <linux/tty.h>
  #include <linux/suspend.h>
  #include <linux/root_dev.h>
  #include <linux/security.h>
  #include <linux/delay.h>
dd2a345f8   Dave Gilbert   Display all possi...
11
  #include <linux/genhd.h>
d53d9f16e   Andrew Morton   [PATCH] name_to_d...
12
  #include <linux/mount.h>
d779249ed   Greg Kroah-Hartman   Driver Core: add ...
13
  #include <linux/device.h>
46595390e   Adrian Bunk   init/do_mounts.c:...
14
  #include <linux/init.h>
011e3fcd1   Adrian Bunk   proper prototype ...
15
  #include <linux/fs.h>
82c8253ac   Adrian Bunk   init/do_mounts.c ...
16
  #include <linux/initrd.h>
22a9d6456   Arjan van de Ven   async: Asynchrono...
17
  #include <linux/async.h>
5ad4e53bd   Al Viro   Get rid of indire...
18
  #include <linux/fs_struct.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
57f150a58   Rob Landley   initmpfs: move ro...
20
  #include <linux/ramfs.h>
16203a7a9   Rob Landley   initmpfs: make ro...
21
  #include <linux/shmem_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
  
  #include <linux/nfs_fs.h>
  #include <linux/nfs_fs_sb.h>
  #include <linux/nfs_mount.h>
4f5b246b3   Christoph Hellwig   md: move the earl...
26
  #include <linux/raid/detect.h>
e262e32d6   David Howells   vfs: Suppress MS_...
27
  #include <uapi/linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  
  #include "do_mounts.h"
9b04c997b   Theodore Ts'o   [PATCH] vfs: MS_V...
30
  int root_mountflags = MS_RDONLY | MS_SILENT;
f56f6d30c   Adrian Bunk   make init/do_moun...
31
  static char * __initdata root_device_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  static char __initdata saved_root_name[64];
79975f132   Will Drewry   init: add root=PA...
33
  static int root_wait;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  dev_t ROOT_DEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  static int __init load_ramdisk(char *str)
  {
c8376994c   Christoph Hellwig   initrd: remove su...
38
39
  	pr_warn("ignoring the deprecated load_ramdisk= option
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  	return 1;
  }
  __setup("load_ramdisk=", load_ramdisk);
  
  static int __init readonly(char *str)
  {
  	if (*str)
  		return 0;
  	root_mountflags |= MS_RDONLY;
  	return 1;
  }
  
  static int __init readwrite(char *str)
  {
  	if (*str)
  		return 0;
  	root_mountflags &= ~MS_RDONLY;
  	return 1;
  }
  
  __setup("ro", readonly);
  __setup("rw", readwrite);
6d0aed7a3   Jens Axboe   do_mounts: only e...
62
  #ifdef CONFIG_BLOCK
1ad7e8994   Stephen Warren   block: store part...
63
64
65
66
  struct uuidcmp {
  	const char *uuid;
  	int len;
  };
b5af921ec   Will Drewry   init: add support...
67
68
69
  /**
   * match_dev_by_uuid - callback for finding a partition using its uuid
   * @dev:	device passed in by the caller
1ad7e8994   Stephen Warren   block: store part...
70
   * @data:	opaque pointer to the desired struct uuidcmp to match
b5af921ec   Will Drewry   init: add support...
71
72
73
   *
   * Returns 1 if the device matches, and 0 otherwise.
   */
9f3b795a6   Michał Mirosław   driver-core: cons...
74
  static int match_dev_by_uuid(struct device *dev, const void *data)
b5af921ec   Will Drewry   init: add support...
75
  {
0d02129e7   Christoph Hellwig   block: merge stru...
76
  	struct block_device *bdev = dev_to_bdev(dev);
9f3b795a6   Michał Mirosław   driver-core: cons...
77
  	const struct uuidcmp *cmp = data;
b5af921ec   Will Drewry   init: add support...
78

0d02129e7   Christoph Hellwig   block: merge stru...
79
80
  	if (!bdev->bd_meta_info ||
  	    strncasecmp(cmp->uuid, bdev->bd_meta_info->uuid, cmp->len))
013b0e96a   Christoph Hellwig   init: cleanup mat...
81
  		return 0;
b5af921ec   Will Drewry   init: add support...
82
  	return 1;
b5af921ec   Will Drewry   init: add support...
83
  }
b5af921ec   Will Drewry   init: add support...
84
85
  /**
   * devt_from_partuuid - looks up the dev_t of a partition by its UUID
a68b31080   chishanmingshen   init/do_mounts.c:...
86
   * @uuid_str:	char array containing ascii UUID
b5af921ec   Will Drewry   init: add support...
87
88
89
90
91
   *
   * The function will return the first partition which contains a matching
   * UUID value in its partition_meta_info struct.  This does not search
   * by filesystem UUIDs.
   *
a68b31080   chishanmingshen   init/do_mounts.c:...
92
   * If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be
79975f132   Will Drewry   init: add root=PA...
93
94
   * extracted and used as an offset from the partition identified by the UUID.
   *
b5af921ec   Will Drewry   init: add support...
95
96
   * Returns the matching dev_t on success or 0 on failure.
   */
1ad7e8994   Stephen Warren   block: store part...
97
  static dev_t devt_from_partuuid(const char *uuid_str)
b5af921ec   Will Drewry   init: add support...
98
  {
1ad7e8994   Stephen Warren   block: store part...
99
  	struct uuidcmp cmp;
b5af921ec   Will Drewry   init: add support...
100
  	struct device *dev = NULL;
e036bb8e0   Christoph Hellwig   init: refactor de...
101
  	dev_t devt = 0;
79975f132   Will Drewry   init: add root=PA...
102
  	int offset = 0;
283f8fc03   Stephen Warren   init: reduce PART...
103
  	char *slash;
79975f132   Will Drewry   init: add root=PA...
104

1ad7e8994   Stephen Warren   block: store part...
105
  	cmp.uuid = uuid_str;
1ad7e8994   Stephen Warren   block: store part...
106

283f8fc03   Stephen Warren   init: reduce PART...
107
  	slash = strchr(uuid_str, '/');
79975f132   Will Drewry   init: add root=PA...
108
  	/* Check for optional partition number offset attributes. */
283f8fc03   Stephen Warren   init: reduce PART...
109
  	if (slash) {
79975f132   Will Drewry   init: add root=PA...
110
  		char c = 0;
e036bb8e0   Christoph Hellwig   init: refactor de...
111

79975f132   Will Drewry   init: add root=PA...
112
  		/* Explicitly fail on poor PARTUUID syntax. */
e036bb8e0   Christoph Hellwig   init: refactor de...
113
114
  		if (sscanf(slash + 1, "PARTNROFF=%d%c", &offset, &c) != 1)
  			goto clear_root_wait;
283f8fc03   Stephen Warren   init: reduce PART...
115
116
117
118
  		cmp.len = slash - uuid_str;
  	} else {
  		cmp.len = strlen(uuid_str);
  	}
e036bb8e0   Christoph Hellwig   init: refactor de...
119
120
  	if (!cmp.len)
  		goto clear_root_wait;
b5af921ec   Will Drewry   init: add support...
121

e036bb8e0   Christoph Hellwig   init: refactor de...
122
  	dev = class_find_device(&block_class, NULL, &cmp, &match_dev_by_uuid);
b5af921ec   Will Drewry   init: add support...
123
  	if (!dev)
e036bb8e0   Christoph Hellwig   init: refactor de...
124
  		return 0;
79975f132   Will Drewry   init: add root=PA...
125

e036bb8e0   Christoph Hellwig   init: refactor de...
126
127
128
129
130
  	if (offset) {
  		/*
  		 * Attempt to find the requested partition by adding an offset
  		 * to the partition number found by UUID.
  		 */
c97d93c31   Christoph Hellwig   block: factor out...
131
132
  		devt = part_devt(dev_to_disk(dev),
  				 dev_to_bdev(dev)->bd_partno + offset);
e036bb8e0   Christoph Hellwig   init: refactor de...
133
134
  	} else {
  		devt = dev->devt;
79975f132   Will Drewry   init: add root=PA...
135
  	}
79975f132   Will Drewry   init: add root=PA...
136
  	put_device(dev);
e036bb8e0   Christoph Hellwig   init: refactor de...
137
138
139
140
141
142
143
144
145
146
147
148
  	return devt;
  
  clear_root_wait:
  	pr_err("VFS: PARTUUID= is invalid.
  "
  	       "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]
  ");
  	if (root_wait)
  		pr_err("Disabling rootwait; root= is invalid.
  ");
  	root_wait = 0;
  	return 0;
b5af921ec   Will Drewry   init: add support...
149
  }
f027c34d8   Nikolaus Voss   init/do_mounts.c:...
150
151
152
153
154
155
156
157
158
159
  
  /**
   * match_dev_by_label - callback for finding a partition using its label
   * @dev:	device passed in by the caller
   * @data:	opaque pointer to the label to match
   *
   * Returns 1 if the device matches, and 0 otherwise.
   */
  static int match_dev_by_label(struct device *dev, const void *data)
  {
0d02129e7   Christoph Hellwig   block: merge stru...
160
  	struct block_device *bdev = dev_to_bdev(dev);
f027c34d8   Nikolaus Voss   init/do_mounts.c:...
161
  	const char *label = data;
f027c34d8   Nikolaus Voss   init/do_mounts.c:...
162

0d02129e7   Christoph Hellwig   block: merge stru...
163
  	if (!bdev->bd_meta_info || strcmp(label, bdev->bd_meta_info->volname))
013b0e96a   Christoph Hellwig   init: cleanup mat...
164
165
  		return 0;
  	return 1;
f027c34d8   Nikolaus Voss   init/do_mounts.c:...
166
  }
c2637e80a   Christoph Hellwig   init: refactor na...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  
  static dev_t devt_from_partlabel(const char *label)
  {
  	struct device *dev;
  	dev_t devt = 0;
  
  	dev = class_find_device(&block_class, NULL, label, &match_dev_by_label);
  	if (dev) {
  		devt = dev->devt;
  		put_device(dev);
  	}
  
  	return devt;
  }
  
  static dev_t devt_from_devname(const char *name)
  {
  	dev_t devt = 0;
  	int part;
  	char s[32];
  	char *p;
  
  	if (strlen(name) > 31)
  		return 0;
  	strcpy(s, name);
  	for (p = s; *p; p++) {
  		if (*p == '/')
  			*p = '!';
  	}
  
  	devt = blk_lookup_devt(s, 0);
  	if (devt)
  		return devt;
  
  	/*
  	 * Try non-existent, but valid partition, which may only exist after
  	 * opening the device, like partitioned md devices.
  	 */
  	while (p > s && isdigit(p[-1]))
  		p--;
  	if (p == s || !*p || *p == '0')
  		return 0;
  
  	/* try disk name without <part number> */
  	part = simple_strtoul(p, NULL, 10);
  	*p = '\0';
  	devt = blk_lookup_devt(s, part);
  	if (devt)
  		return devt;
  
  	/* try disk name without p<part number> */
  	if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
  		return 0;
  	p[-1] = '\0';
  	return blk_lookup_devt(s, part);
  }
  #endif /* CONFIG_BLOCK */
  
  static dev_t devt_from_devnum(const char *name)
  {
  	unsigned maj, min, offset;
  	dev_t devt = 0;
  	char *p, dummy;
  
  	if (sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2 ||
  	    sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3) {
  		devt = MKDEV(maj, min);
  		if (maj != MAJOR(devt) || min != MINOR(devt))
  			return 0;
  	} else {
  		devt = new_decode_dev(simple_strtoul(name, &p, 16));
  		if (*p)
  			return 0;
  	}
  
  	return devt;
  }
b5af921ec   Will Drewry   init: add support...
244

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
  /*
   *	Convert a name into device number.  We accept the following variants:
   *
0bf37ae4c   Pavel Machek   init/do_mounts: b...
248
249
   *	1) <hex_major><hex_minor> device number in hexadecimal represents itself
   *         no leading 0x, for example b302.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
   *	2) /dev/nfs represents Root_NFS (0xff)
   *	3) /dev/<disk_name> represents the device number of disk
   *	4) /dev/<disk_name><decimal> represents the device number
   *         of partition - device number of disk plus the partition number
   *	5) /dev/<disk_name>p<decimal> - same as the above, that form is
   *	   used when disk name of partitioned disk ends on a digit.
b5af921ec   Will Drewry   init: add support...
256
257
   *	6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
   *	   unique id of a partition if the partition table provides it.
d33b98fc8   Stephen Warren   block: partition:...
258
259
260
261
   *	   The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
   *	   partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
   *	   filled hex representation of the 32-bit "NT disk signature", and PP
   *	   is a zero-filled hex representation of the 1-based partition number.
79975f132   Will Drewry   init: add root=PA...
262
263
   *	7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
   *	   a partition with a known unique id.
6c251611c   Sebastian Capella   init/do_mounts.c:...
264
265
   *	8) <major>:<minor> major and minor number of the device separated by
   *	   a colon.
f027c34d8   Nikolaus Voss   init/do_mounts.c:...
266
267
   *	9) PARTLABEL=<name> with name being the GPT partition label.
   *	   MSDOS partitions do not support labels!
8902dd526   Paulo Alcantara (SUSE)   init: Support mou...
268
   *	10) /dev/cifs represents Root_CIFS (0xfe)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
   *
edfaa7c36   Kay Sievers   Driver core: conv...
270
271
272
273
   *	If name doesn't have fall into the categories above, we return (0,0).
   *	block_class is used to check if something is a disk name. If the disk
   *	name contains slashes, the device name has them replaced with
   *	bangs.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
   */
e6e20a7a5   Dan Ehrenberg   init: export name...
275
  dev_t name_to_dev_t(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  {
c2637e80a   Christoph Hellwig   init: refactor na...
277
278
279
280
281
282
  	if (strcmp(name, "/dev/nfs") == 0)
  		return Root_NFS;
  	if (strcmp(name, "/dev/cifs") == 0)
  		return Root_CIFS;
  	if (strcmp(name, "/dev/ram") == 0)
  		return Root_RAM0;
6d0aed7a3   Jens Axboe   do_mounts: only e...
283
  #ifdef CONFIG_BLOCK
c2637e80a   Christoph Hellwig   init: refactor na...
284
285
286
287
288
289
  	if (strncmp(name, "PARTUUID=", 9) == 0)
  		return devt_from_partuuid(name + 9);
  	if (strncmp(name, "PARTLABEL=", 10) == 0)
  		return devt_from_partlabel(name + 10);
  	if (strncmp(name, "/dev/", 5) == 0)
  		return devt_from_devname(name + 5);
6d0aed7a3   Jens Axboe   do_mounts: only e...
290
  #endif
c2637e80a   Christoph Hellwig   init: refactor na...
291
  	return devt_from_devnum(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  }
e6e20a7a5   Dan Ehrenberg   init: export name...
293
  EXPORT_SYMBOL_GPL(name_to_dev_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
301
  
  static int __init root_dev_setup(char *line)
  {
  	strlcpy(saved_root_name, line, sizeof(saved_root_name));
  	return 1;
  }
  
  __setup("root=", root_dev_setup);
cc1ed7542   Pierre Ossman   init: wait for as...
302
303
304
305
306
307
308
309
310
  static int __init rootwait_setup(char *str)
  {
  	if (*str)
  		return 0;
  	root_wait = 1;
  	return 1;
  }
  
  __setup("rootwait", rootwait_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  static char * __initdata root_mount_data;
  static int __init root_data_setup(char *str)
  {
  	root_mount_data = str;
  	return 1;
  }
  
  static char * __initdata root_fs_names;
  static int __init fs_names_setup(char *str)
  {
  	root_fs_names = str;
  	return 1;
  }
  
  static unsigned int __initdata root_delay;
  static int __init root_delay_setup(char *str)
  {
  	root_delay = simple_strtoul(str, NULL, 0);
  	return 1;
  }
  
  __setup("rootflags=", root_data_setup);
  __setup("rootfstype=", fs_names_setup);
  __setup("rootdelay=", root_delay_setup);
b51593c4c   Vivek Goyal   init/do_mounts.c:...
335
336
  /* This can return zero length strings. Caller should check */
  static int __init split_fs_names(char *page, size_t size, char *names)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  {
b51593c4c   Vivek Goyal   init/do_mounts.c:...
338
  	int count = 1;
6e7c1770a   Christoph Hellwig   fs: simplify get_...
339
  	char *p = page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

b51593c4c   Vivek Goyal   init/do_mounts.c:...
341
  	strlcpy(p, root_fs_names, size);
6e7c1770a   Christoph Hellwig   fs: simplify get_...
342
  	while (*p++) {
b51593c4c   Vivek Goyal   init/do_mounts.c:...
343
  		if (p[-1] == ',') {
6e7c1770a   Christoph Hellwig   fs: simplify get_...
344
  			p[-1] = '\0';
b51593c4c   Vivek Goyal   init/do_mounts.c:...
345
346
  			count++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  	}
e24d12b74   Christoph Hellwig   init: split get_f...
348

6e7c1770a   Christoph Hellwig   fs: simplify get_...
349
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  }
cccaa5e33   Dominik Brodowski   init: use do_moun...
351
352
  static int __init do_mount_root(const char *name, const char *fs,
  				 const int flags, const void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  {
d8c9584ea   Al Viro   vfs: prefer ->den...
354
  	struct super_block *s;
7de7de7ca   Linus Torvalds   Fix root mounting...
355
356
  	struct page *p = NULL;
  	char *data_page = NULL;
cccaa5e33   Dominik Brodowski   init: use do_moun...
357
  	int ret;
7de7de7ca   Linus Torvalds   Fix root mounting...
358
  	if (data) {
c60166f04   Christoph Hellwig   init: add an init...
359
  		/* init_mount() requires a full page as fifth argument */
7de7de7ca   Linus Torvalds   Fix root mounting...
360
361
362
363
  		p = alloc_page(GFP_KERNEL);
  		if (!p)
  			return -ENOMEM;
  		data_page = page_address(p);
c60166f04   Christoph Hellwig   init: add an init...
364
  		/* zero-pad. init_mount() will make sure it's terminated */
7de7de7ca   Linus Torvalds   Fix root mounting...
365
366
  		strncpy(data_page, data, PAGE_SIZE);
  	}
cccaa5e33   Dominik Brodowski   init: use do_moun...
367

c60166f04   Christoph Hellwig   init: add an init...
368
  	ret = init_mount(name, "/root", fs, flags, data_page);
cccaa5e33   Dominik Brodowski   init: use do_moun...
369
370
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371

db63f1e31   Christoph Hellwig   init: add an init...
372
  	init_chdir("/root");
d8c9584ea   Al Viro   vfs: prefer ->den...
373
374
  	s = current->fs->pwd.dentry->d_sb;
  	ROOT_DEV = s->s_dev;
80cdc6dae   Mandeep Singh Baines   fs: use appropria...
375
376
377
  	printk(KERN_INFO
  	       "VFS: Mounted root (%s filesystem)%s on device %u:%u.
  ",
d8c9584ea   Al Viro   vfs: prefer ->den...
378
  	       s->s_type->name,
bc98a42c1   David Howells   VFS: Convert sb->...
379
  	       sb_rdonly(s) ? " readonly" : "",
d8c9584ea   Al Viro   vfs: prefer ->den...
380
  	       MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
cccaa5e33   Dominik Brodowski   init: use do_moun...
381
382
  
  out:
7de7de7ca   Linus Torvalds   Fix root mounting...
383
384
  	if (p)
  		put_page(p);
cccaa5e33   Dominik Brodowski   init: use do_moun...
385
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
389
  }
  
  void __init mount_block_root(char *name, int flags)
  {
75f296d93   Levin, Alexander (Sasha Levin)   kmemcheck: stop u...
390
  	struct page *page = alloc_page(GFP_KERNEL);
a608ca21f   Jeff Layton   vfs: allocate pag...
391
  	char *fs_names = page_address(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
  	char *p;
  	char b[BDEVNAME_SIZE];
6e7c1770a   Christoph Hellwig   fs: simplify get_...
394
  	int num_fs, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395

ea3edd4dc   Christoph Hellwig   block: remove __b...
396
397
  	scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)",
  		  MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
e24d12b74   Christoph Hellwig   init: split get_f...
398
  	if (root_fs_names)
b51593c4c   Vivek Goyal   init/do_mounts.c:...
399
  		num_fs = split_fs_names(fs_names, PAGE_SIZE, root_fs_names);
e24d12b74   Christoph Hellwig   init: split get_f...
400
  	else
6e7c1770a   Christoph Hellwig   fs: simplify get_...
401
  		num_fs = list_bdev_fs_names(fs_names, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  retry:
6e7c1770a   Christoph Hellwig   fs: simplify get_...
403
  	for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) {
b51593c4c   Vivek Goyal   init/do_mounts.c:...
404
405
406
407
408
  		int err;
  
  		if (!*p)
  			continue;
  		err = do_mount_root(name, p, flags, root_mount_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
  		switch (err) {
  			case 0:
  				goto out;
  			case -EACCES:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
  			case -EINVAL:
  				continue;
  		}
  	        /*
  		 * Allow the user to distinguish between failed sys_open
  		 * and bad superblock on root device.
dd2a345f8   Dave Gilbert   Display all possi...
419
  		 * and give them a list of the available devices
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  		 */
0e0cb892a   Bernhard Walle   init/do_mounts.c:...
421
422
423
  		printk("VFS: Cannot open root device \"%s\" or %s: error %d
  ",
  				root_device_name, b, err);
dd2a345f8   Dave Gilbert   Display all possi...
424
425
  		printk("Please append a correct \"root=\" boot option; here are the available partitions:
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426

dd2a345f8   Dave Gilbert   Display all possi...
427
  		printk_all_partitions();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
  		panic("VFS: Unable to mount root fs on %s", b);
  	}
e462ec50c   David Howells   VFS: Differentiat...
430
431
  	if (!(flags & SB_RDONLY)) {
  		flags |= SB_RDONLY;
10975933d   Miklos Szeredi   init: fix read-wr...
432
433
  		goto retry;
  	}
be6e028b6   Andy Whitcroft   [PATCH] root moun...
434

dd2a345f8   Dave Gilbert   Display all possi...
435
436
437
  	printk("List of all partitions:
  ");
  	printk_all_partitions();
be6e028b6   Andy Whitcroft   [PATCH] root moun...
438
  	printk("No filesystem could mount root, tried: ");
6e7c1770a   Christoph Hellwig   fs: simplify get_...
439
  	for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1)
be6e028b6   Andy Whitcroft   [PATCH] root moun...
440
441
442
  		printk(" %s", p);
  	printk("
  ");
9361401eb   David Howells   [PATCH] BLOCK: Ma...
443
  	panic("VFS: Unable to mount root fs on %s", b);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  out:
a608ca21f   Jeff Layton   vfs: allocate pag...
445
  	put_page(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
  }
   
  #ifdef CONFIG_ROOT_NFS
43717c7da   Chuck Lever   NFS: Retry mounti...
449
450
451
452
  
  #define NFSROOT_TIMEOUT_MIN	5
  #define NFSROOT_TIMEOUT_MAX	30
  #define NFSROOT_RETRY_MAX	5
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  static int __init mount_nfs_root(void)
  {
56463e50d   Chuck Lever   NFS: Use super.c ...
455
  	char *root_dev, *root_data;
43717c7da   Chuck Lever   NFS: Retry mounti...
456
457
  	unsigned int timeout;
  	int try, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458

43717c7da   Chuck Lever   NFS: Retry mounti...
459
460
  	err = nfs_root_data(&root_dev, &root_data);
  	if (err != 0)
56463e50d   Chuck Lever   NFS: Use super.c ...
461
  		return 0;
43717c7da   Chuck Lever   NFS: Retry mounti...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  
  	/*
  	 * The server or network may not be ready, so try several
  	 * times.  Stop after a few tries in case the client wants
  	 * to fall back to other boot methods.
  	 */
  	timeout = NFSROOT_TIMEOUT_MIN;
  	for (try = 1; ; try++) {
  		err = do_mount_root(root_dev, "nfs",
  					root_mountflags, root_data);
  		if (err == 0)
  			return 1;
  		if (try > NFSROOT_RETRY_MAX)
  			break;
  
  		/* Wait, in case the server refused us immediately */
  		ssleep(timeout);
  		timeout <<= 1;
  		if (timeout > NFSROOT_TIMEOUT_MAX)
  			timeout = NFSROOT_TIMEOUT_MAX;
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
  }
  #endif
8902dd526   Paulo Alcantara (SUSE)   init: Support mou...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  #ifdef CONFIG_CIFS_ROOT
  
  extern int cifs_root_data(char **dev, char **opts);
  
  #define CIFSROOT_TIMEOUT_MIN	5
  #define CIFSROOT_TIMEOUT_MAX	30
  #define CIFSROOT_RETRY_MAX	5
  
  static int __init mount_cifs_root(void)
  {
  	char *root_dev, *root_data;
  	unsigned int timeout;
  	int try, err;
  
  	err = cifs_root_data(&root_dev, &root_data);
  	if (err != 0)
  		return 0;
  
  	timeout = CIFSROOT_TIMEOUT_MIN;
  	for (try = 1; ; try++) {
  		err = do_mount_root(root_dev, "cifs", root_mountflags,
  				    root_data);
  		if (err == 0)
  			return 1;
  		if (try > CIFSROOT_RETRY_MAX)
  			break;
  
  		ssleep(timeout);
  		timeout <<= 1;
  		if (timeout > CIFSROOT_TIMEOUT_MAX)
  			timeout = CIFSROOT_TIMEOUT_MAX;
  	}
  	return 0;
  }
  #endif
f9259be6a   Christoph Hellwig   init: allow mount...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  static bool __init fs_is_nodev(char *fstype)
  {
  	struct file_system_type *fs = get_fs_type(fstype);
  	bool ret = false;
  
  	if (fs) {
  		ret = !(fs->fs_flags & FS_REQUIRES_DEV);
  		put_filesystem(fs);
  	}
  
  	return ret;
  }
  
  static int __init mount_nodev_root(void)
  {
  	char *fs_names, *fstype;
  	int err = -EINVAL;
6e7c1770a   Christoph Hellwig   fs: simplify get_...
538
  	int num_fs, i;
f9259be6a   Christoph Hellwig   init: allow mount...
539
540
541
542
  
  	fs_names = (void *)__get_free_page(GFP_KERNEL);
  	if (!fs_names)
  		return -EINVAL;
b51593c4c   Vivek Goyal   init/do_mounts.c:...
543
  	num_fs = split_fs_names(fs_names, PAGE_SIZE, root_fs_names);
f9259be6a   Christoph Hellwig   init: allow mount...
544

6e7c1770a   Christoph Hellwig   fs: simplify get_...
545
546
  	for (i = 0, fstype = fs_names; i < num_fs;
  	     i++, fstype += strlen(fstype) + 1) {
b51593c4c   Vivek Goyal   init/do_mounts.c:...
547
548
  		if (!*fstype)
  			continue;
f9259be6a   Christoph Hellwig   init: allow mount...
549
550
551
552
553
554
  		if (!fs_is_nodev(fstype))
  			continue;
  		err = do_mount_root(root_device_name, fstype, root_mountflags,
  				    root_mount_data);
  		if (!err)
  			break;
f9259be6a   Christoph Hellwig   init: allow mount...
555
556
557
558
559
  	}
  
  	free_page((unsigned long)fs_names);
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
  void __init mount_root(void)
  {
  #ifdef CONFIG_ROOT_NFS
377485f62   Sasha Levin   init: don't try m...
563
  	if (ROOT_DEV == Root_NFS) {
c8376994c   Christoph Hellwig   initrd: remove su...
564
565
566
567
  		if (!mount_nfs_root())
  			printk(KERN_ERR "VFS: Unable to mount root fs via NFS.
  ");
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	}
  #endif
8902dd526   Paulo Alcantara (SUSE)   init: Support mou...
570
571
  #ifdef CONFIG_CIFS_ROOT
  	if (ROOT_DEV == Root_CIFS) {
c8376994c   Christoph Hellwig   initrd: remove su...
572
573
574
575
  		if (!mount_cifs_root())
  			printk(KERN_ERR "VFS: Unable to mount root fs via SMB.
  ");
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  	}
  #endif
f9259be6a   Christoph Hellwig   init: allow mount...
578
579
580
581
  	if (ROOT_DEV == 0 && root_device_name && root_fs_names) {
  		if (mount_nodev_root() == 0)
  			return;
  	}
9361401eb   David Howells   [PATCH] BLOCK: Ma...
582
  #ifdef CONFIG_BLOCK
c69e3c3a0   Vishnu Pratap Singh   init/do_mounts.c:...
583
584
585
586
587
588
589
590
  	{
  		int err = create_dev("/dev/root", ROOT_DEV);
  
  		if (err < 0)
  			pr_emerg("Failed to create /dev/root: %d
  ", err);
  		mount_block_root("/dev/root", root_mountflags);
  	}
9361401eb   David Howells   [PATCH] BLOCK: Ma...
591
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
597
598
  }
  
  /*
   * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
   */
  void __init prepare_namespace(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  	if (root_delay) {
ca75b4d87   Toralf Förster   insert missing sp...
600
601
  		printk(KERN_INFO "Waiting %d sec before mounting root device...
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  		       root_delay);
  		ssleep(root_delay);
  	}
216773a78   Arjan van de Ven   Consolidate drive...
605
606
607
608
609
610
611
612
  	/*
  	 * wait for the known devices to complete their probing
  	 *
  	 * Note: this is a potential source of long boot delays.
  	 * For example, it is not atypical to wait 5 seconds here
  	 * for the touchpad of a laptop to initialize.
  	 */
  	wait_for_device_probe();
d779249ed   Greg Kroah-Hartman   Driver Core: add ...
613

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
  	md_run_setup();
  
  	if (saved_root_name[0]) {
  		root_device_name = saved_root_name;
2d62f4885   Adrian Hunter   do_mounts: allow ...
618
619
  		if (!strncmp(root_device_name, "mtd", 3) ||
  		    !strncmp(root_device_name, "ubi", 3)) {
e9482b437   Joern Engel   [MTD] Allow alter...
620
621
622
  			mount_block_root(root_device_name, root_mountflags);
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
  		ROOT_DEV = name_to_dev_t(root_device_name);
  		if (strncmp(root_device_name, "/dev/", 5) == 0)
  			root_device_name += 5;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
  	if (initrd_load())
  		goto out;
cc1ed7542   Pierre Ossman   init: wait for as...
629
630
631
632
633
634
635
  	/* wait for any asynchronous scanning to complete */
  	if ((ROOT_DEV == 0) && root_wait) {
  		printk(KERN_INFO "Waiting for root device %s...
  ",
  			saved_root_name);
  		while (driver_probe_done() != 0 ||
  			(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
39a0e975c   Jungseung Lee   init: reduce root...
636
  			msleep(5);
216773a78   Arjan van de Ven   Consolidate drive...
637
  		async_synchronize_full();
cc1ed7542   Pierre Ossman   init: wait for as...
638
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
  	mount_root();
  out:
5e787dbf6   Dominik Brodowski   devtmpfs: use do_...
641
  	devtmpfs_mount();
c60166f04   Christoph Hellwig   init: add an init...
642
  	init_mount(".", "/", NULL, MS_MOVE, NULL);
4b7ca5014   Christoph Hellwig   init: add an init...
643
  	init_chroot(".");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  }
57f150a58   Rob Landley   initmpfs: move ro...
645

6e19eded3   Rob Landley   initmpfs: use ini...
646
  static bool is_tmpfs;
f32356261   David Howells   vfs: Convert ramf...
647
  static int rootfs_init_fs_context(struct fs_context *fc)
57f150a58   Rob Landley   initmpfs: move ro...
648
  {
6e19eded3   Rob Landley   initmpfs: use ini...
649
  	if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
f32356261   David Howells   vfs: Convert ramf...
650
  		return shmem_init_fs_context(fc);
6e19eded3   Rob Landley   initmpfs: use ini...
651

f32356261   David Howells   vfs: Convert ramf...
652
  	return ramfs_init_fs_context(fc);
57f150a58   Rob Landley   initmpfs: move ro...
653
  }
fd3e007f6   Al Viro   don't bother with...
654
  struct file_system_type rootfs_fs_type = {
57f150a58   Rob Landley   initmpfs: move ro...
655
  	.name		= "rootfs",
f32356261   David Howells   vfs: Convert ramf...
656
  	.init_fs_context = rootfs_init_fs_context,
57f150a58   Rob Landley   initmpfs: move ro...
657
658
  	.kill_sb	= kill_litter_super,
  };
037f11b47   Al Viro   mnt_init(): call ...
659
  void __init init_rootfs(void)
57f150a58   Rob Landley   initmpfs: move ro...
660
  {
6e19eded3   Rob Landley   initmpfs: use ini...
661
  	if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
037f11b47   Al Viro   mnt_init(): call ...
662
  		(!root_fs_names || strstr(root_fs_names, "tmpfs")))
6e19eded3   Rob Landley   initmpfs: use ini...
663
  		is_tmpfs = true;
57f150a58   Rob Landley   initmpfs: move ro...
664
  }