cregit-Linux how code gets into the kernel

Release 4.14 init/do_mounts.c

Directory: init
/*
 * Many of the syscalls used in this file expect some of the arguments
 * to be __user pointers not __kernel pointers.  To limit the sparse
 * noise, turn off sparse checking for this file.
 */
#ifdef __CHECKER__

#undef __CHECKER__
#warning "Sparse checking disabled for this file"
#endif

#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>
#include <linux/genhd.h>
#include <linux/mount.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/initrd.h>
#include <linux/async.h>
#include <linux/fs_struct.h>
#include <linux/slab.h>
#include <linux/ramfs.h>
#include <linux/shmem_fs.h>

#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
#include <linux/nfs_mount.h>

#include "do_mounts.h"


int __initdata rd_doload;	
/* 1 = load RAM disk, 0 = don't load */


int root_mountflags = MS_RDONLY | MS_SILENT;

static char * __initdata root_device_name;

static char __initdata saved_root_name[64];

static int root_wait;


dev_t ROOT_DEV;


static int __init load_ramdisk(char *str) { rd_doload = simple_strtol(str,NULL,0) & 3; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds27100.00%3100.00%
Total27100.00%3100.00%

__setup("load_ramdisk=", load_ramdisk);
static int __init readonly(char *str) { if (*str) return 0; root_mountflags |= MS_RDONLY; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds26100.00%2100.00%
Total26100.00%2100.00%


static int __init readwrite(char *str) { if (*str) return 0; root_mountflags &= ~MS_RDONLY; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds27100.00%2100.00%
Total27100.00%2100.00%

__setup("ro", readonly); __setup("rw", readwrite); #ifdef CONFIG_BLOCK struct uuidcmp { const char *uuid; int len; }; /** * match_dev_by_uuid - callback for finding a partition using its uuid * @dev: device passed in by the caller * @data: opaque pointer to the desired struct uuidcmp to match * * Returns 1 if the device matches, and 0 otherwise. */
static int match_dev_by_uuid(struct device *dev, const void *data) { const struct uuidcmp *cmp = data; struct hd_struct *part = dev_to_part(dev); if (!part->info) goto no_match; if (strncasecmp(cmp->uuid, part->info->uuid, cmp->len)) goto no_match; return 1; no_match: return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Will Drewry6486.49%133.33%
Stephen Warren810.81%133.33%
Michał Mirosław22.70%133.33%
Total74100.00%3100.00%

/** * devt_from_partuuid - looks up the dev_t of a partition by its UUID * @uuid_str: char array containing ascii UUID * * 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. * * If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be * extracted and used as an offset from the partition identified by the UUID. * * Returns the matching dev_t on success or 0 on failure. */
static dev_t devt_from_partuuid(const char *uuid_str) { dev_t res = 0; struct uuidcmp cmp; struct device *dev = NULL; struct gendisk *disk; struct hd_struct *part; int offset = 0; bool clear_root_wait = false; char *slash; cmp.uuid = uuid_str; slash = strchr(uuid_str, '/'); /* Check for optional partition number offset attributes. */ if (slash) { char c = 0; /* Explicitly fail on poor PARTUUID syntax. */ if (sscanf(slash + 1, "PARTNROFF=%d%c", &offset, &c) != 1) { clear_root_wait = true; goto done; } cmp.len = slash - uuid_str; } else { cmp.len = strlen(uuid_str); } if (!cmp.len) { clear_root_wait = true; goto done; } dev = class_find_device(&block_class, NULL, &cmp, &match_dev_by_uuid); if (!dev) goto done; res = dev->devt; /* Attempt to find the partition by offset. */ if (!offset) goto no_offset; res = 0; disk = part_to_disk(dev_to_part(dev)); part = disk_get_part(disk, dev_to_part(dev)->partno + offset); if (part) { res = part_devt(part); put_device(part_to_dev(part)); } no_offset: put_device(dev); done: if (clear_root_wait) { pr_err("VFS: PARTUUID= is invalid.\n" "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n"); if (root_wait) pr_err("Disabling rootwait; root= is invalid.\n"); root_wait = 0; } return res; }

Contributors

PersonTokensPropCommitsCommitProp
Will Drewry17665.19%250.00%
Stephen Warren9434.81%250.00%
Total270100.00%4100.00%

#endif /* * Convert a name into device number. We accept the following variants: * * 1) <hex_major><hex_minor> device number in hexadecimal represents itself * no leading 0x, for example b302. * 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. * 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the * unique id of a partition if the partition table provides it. * 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. * 7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to * a partition with a known unique id. * 8) <major>:<minor> major and minor number of the device separated by * a colon. * * 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. */
dev_t name_to_dev_t(const char *name) { char s[32]; char *p; dev_t res = 0; int part; #ifdef CONFIG_BLOCK if (strncmp(name, "PARTUUID=", 9) == 0) { name += 9; res = devt_from_partuuid(name); if (!res) goto fail; goto done; } #endif if (strncmp(name, "/dev/", 5) != 0) { unsigned maj, min, offset; char dummy; if ((sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2) || (sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3)) { res = MKDEV(maj, min); if (maj != MAJOR(res) || min != MINOR(res)) goto fail; } else { res = new_decode_dev(simple_strtoul(name, &p, 16)); if (*p) goto fail; } goto done; } name += 5; res = Root_NFS; if (strcmp(name, "nfs") == 0) goto done; res = Root_RAM0; if (strcmp(name, "ram") == 0) goto done; if (strlen(name) > 31) goto fail; strcpy(s, name); for (p = s; *p; p++) if (*p == '/') *p = '!'; res = blk_lookup_devt(s, 0); if (res) goto done; /* * try non-existent, but valid partition, which may only exist * after revalidating the disk, like partitioned md devices */ while (p > s && isdigit(p[-1])) p--; if (p == s || !*p || *p == '0') goto fail; /* try disk name without <part number> */ part = simple_strtoul(p, NULL, 10); *p = '\0'; res = blk_lookup_devt(s, part); if (res) goto done; /* try disk name without p<part number> */ if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') goto fail; p[-1] = '\0'; res = blk_lookup_devt(s, part); if (res) goto done; fail: return 0; done: return res; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro14533.56%423.53%
Kay Sievers13230.56%211.76%
Andrew Morton5412.50%317.65%
Will Drewry378.56%15.88%
Chen Yu276.25%15.88%
Linus Torvalds194.40%15.88%
Dan Ehrenberg81.85%211.76%
Jens Axboe51.16%15.88%
Alan Cox40.93%15.88%
Lucas De Marchi10.23%15.88%
Total432100.00%17100.00%

EXPORT_SYMBOL_GPL(name_to_dev_t);
static int __init root_dev_setup(char *line) { strlcpy(saved_root_name, line, sizeof(saved_root_name)); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds1765.38%120.00%
Benjamin Collins519.23%120.00%
Al Viro311.54%240.00%
Kai Germaschewski13.85%120.00%
Total26100.00%5100.00%

__setup("root=", root_dev_setup);
static int __init rootwait_setup(char *str) { if (*str) return 0; root_wait = 1; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Pierre Ossman26100.00%1100.00%
Total26100.00%1100.00%

__setup("rootwait", rootwait_setup); static char * __initdata root_mount_data;
static int __init root_data_setup(char *str) { root_mount_data = str; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds1372.22%266.67%
Al Viro527.78%133.33%
Total18100.00%3100.00%

static char * __initdata root_fs_names;
static int __init fs_names_setup(char *str) { root_fs_names = str; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds1055.56%150.00%
Al Viro844.44%150.00%
Total18100.00%2100.00%

static unsigned int __initdata root_delay;
static int __init root_delay_setup(char *str) { root_delay = simple_strtoul(str, NULL, 0); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Drake25100.00%1100.00%
Total25100.00%1100.00%

__setup("rootflags=", root_data_setup); __setup("rootfstype=", fs_names_setup); __setup("rootdelay=", root_delay_setup);
static void __init get_fs_names(char *page) { char *s = page; if (root_fs_names) { strcpy(page, root_fs_names); while (*s++) { if (s[-1] == ',') s[-1] = '\0'; } } else { int len = get_filesystem_list(page); char *p, *next; page[len] = '\0'; for (p = page-1; p; p = next) { next = strchr(++p, '\n'); if (*p++ != '\t') continue; while ((*s++ = *p++) != '\n') ; s[-1] = '\0'; } } *s = '\0'; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds11076.39%150.00%
Al Viro3423.61%150.00%
Total144100.00%2100.00%


static int __init do_mount_root(char *name, char *fs, int flags, void *data) { struct super_block *s; int err = sys_mount(name, "/root", fs, flags, data); if (err) return err; sys_chdir("/root"); s = current->fs->pwd.dentry->d_sb; ROOT_DEV = s->s_dev; printk(KERN_INFO "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n", s->s_type->name, sb_rdonly(s) ? " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kai Germaschewski6560.75%114.29%
Al Viro2523.36%228.57%
Bálint Márton1110.28%114.29%
David Howells32.80%114.29%
Jan Blunck21.87%114.29%
Mandeep Singh Baines10.93%114.29%
Total107100.00%7100.00%


void __init mount_block_root(char *name, int flags) { struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE); char *fs_names = page_address(page); char *p; #ifdef CONFIG_BLOCK char b[BDEVNAME_SIZE]; #else const char *b = name; #endif get_fs_names(fs_names); retry: for (p = fs_names; *p; p += strlen(p)+1) { int err = do_mount_root(name, p, flags, root_mount_data); switch (err) { case 0: goto out; case -EACCES: case -EINVAL: continue; } /* * Allow the user to distinguish between failed sys_open * and bad superblock on root device. * and give them a list of the available devices */ #ifdef CONFIG_BLOCK __bdevname(ROOT_DEV, b); #endif printk("VFS: Cannot open root device \"%s\" or %s: error %d\n", root_device_name, b, err); printk("Please append a correct \"root=\" boot option; here are the available partitions:\n"); printk_all_partitions(); #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify " "explicit textual name for \"root=\" boot option.\n"); #endif panic("VFS: Unable to mount root fs on %s", b); } if (!(flags & SB_RDONLY)) { flags |= SB_RDONLY; goto retry; } printk("List of all partitions:\n"); printk_all_partitions(); printk("No filesystem could mount root, tried: "); for (p = fs_names; *p; p += strlen(p)+1) printk(" %s", p); printk("\n"); #ifdef CONFIG_BLOCK __bdevname(ROOT_DEV, b); #endif panic("VFS: Unable to mount root fs on %s", b); out: put_page(page); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds6424.90%317.65%
Al Viro3714.40%15.88%
Andy Whitcroft3513.62%15.88%
David Howells3212.45%211.76%
Andrew Morton176.61%15.88%
Miklos Szeredi166.23%15.88%
Jeff Layton155.84%15.88%
David Alan Gilbert135.06%15.88%
Tejun Heo114.28%15.88%
Kai Germaschewski93.50%317.65%
Vegard Nossum51.95%15.88%
Bernhard Walle31.17%15.88%
Total257100.00%17100.00%

#ifdef CONFIG_ROOT_NFS #define NFSROOT_TIMEOUT_MIN 5 #define NFSROOT_TIMEOUT_MAX 30 #define NFSROOT_RETRY_MAX 5
static int __init mount_nfs_root(void) { char *root_dev, *root_data; unsigned int timeout; int try, err; err = nfs_root_data(&root_dev, &root_data); if (err != 0) return 0; /* * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Chuck Lever8776.32%228.57%
Al Viro1311.40%114.29%
Linus Torvalds87.02%228.57%
Kai Germaschewski65.26%228.57%
Total114100.00%7100.00%

#endif #if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
void __init change_floppy(char *fmt, ...) { struct termios termios; char buf[80]; char c; int fd; va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); if (fd >= 0) { sys_ioctl(fd, FDEJECT, 0); sys_close(fd); } printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); fd = sys_open("/dev/console", O_RDWR, 0); if (fd >= 0) { sys_ioctl(fd, TCGETS, (long)&termios); termios.c_lflag &= ~ICANON; sys_ioctl(fd, TCSETSF, (long)&termios); sys_read(fd, &c, 1); termios.c_lflag |= ICANON; sys_ioctl(fd, TCSETSF, (long)&termios); sys_close(fd); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro14077.35%125.00%
Linus Torvalds3619.89%250.00%
Andrew Morton52.76%125.00%
Total181100.00%4100.00%

#endif
void __init mount_root(void) { #ifdef CONFIG_ROOT_NFS if (ROOT_DEV == Root_NFS) { if (mount_nfs_root()) return; printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); ROOT_DEV = Root_FD0; } #endif #ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { /* rd_doload is 2 for a dual initrd/ramload setup */ if (rd_doload==2) { if (rd_load_disk(1)) { ROOT_DEV = Root_RAM1; root_device_name = NULL; } } else change_floppy("root floppy"); } #endif #ifdef CONFIG_BLOCK { int err = create_dev("/dev/root", ROOT_DEV); if (err < 0) pr_emerg("Failed to create /dev/root: %d\n", err); mount_block_root("/dev/root", root_mountflags); } #endif }

Contributors

PersonTokensPropCommitsCommitProp
Kai Germaschewski6855.74%225.00%
Al Viro2318.85%112.50%
Vishnu Pratap Singh1814.75%112.50%
Linus Torvalds75.74%225.00%
David Howells54.10%112.50%
Sasha Levin10.82%112.50%
Total122100.00%8100.00%

/* * Prepare the namespace - decide what/where to mount, load ramdisks, etc. */
void __init prepare_namespace(void) { int is_floppy; if (root_delay) { printk(KERN_INFO "Waiting %d sec before mounting root device...\n", root_delay); ssleep(root_delay); } /* * 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(); md_run_setup(); if (saved_root_name[0]) { root_device_name = saved_root_name; if (!strncmp(root_device_name, "mtd", 3) || !strncmp(root_device_name, "ubi", 3)) { mount_block_root(root_device_name, root_mountflags); goto out; } ROOT_DEV = name_to_dev_t(root_device_name); if (strncmp(root_device_name, "/dev/", 5) == 0) root_device_name += 5; } if (initrd_load()) goto out; /* wait for any asynchronous scanning to complete */ if ((ROOT_DEV == 0) && root_wait) { printk(KERN_INFO "Waiting for root device %s...\n", saved_root_name); while (driver_probe_done() != 0 || (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0) msleep(5); async_synchronize_full(); } is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; if (is_floppy && rd_doload && rd_load_disk(0)) ROOT_DEV = Root_RAM0; mount_root(); out: devtmpfs_mount("dev"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); }

Contributors

PersonTokensPropCommitsCommitProp
Pierre Ossman5123.72%17.69%
Kai Germaschewski4621.40%17.69%
Linus Torvalds2712.56%215.38%
Al Viro2511.63%17.69%
Jörn Engel2411.16%17.69%
Daniel Drake188.37%17.69%
Adrian Hunter104.65%17.69%
Arjan van de Ven73.26%215.38%
Kay Sievers52.33%17.69%
Jungseung Lee10.47%17.69%
Toralf Förster10.47%17.69%
Total215100.00%13100.00%

static bool is_tmpfs;
static struct dentry *rootfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { static unsigned long once; void *fill = ramfs_fill_super; if (test_and_set_bit(0, &once)) return ERR_PTR(-ENODEV); if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs) fill = shmem_fill_super; return mount_nodev(fs_type, flags, data, fill); }

Contributors

PersonTokensPropCommitsCommitProp
Rob Landley78100.00%2100.00%
Total78100.00%2100.00%

static struct file_system_type rootfs_fs_type = { .name = "rootfs", .mount = rootfs_mount, .kill_sb = kill_litter_super, };
int __init init_rootfs(void) { int err = register_filesystem(&rootfs_fs_type); if (err) return err; if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { err = shmem_init(); is_tmpfs = true; } else { err = init_ramfs_fs(); } if (err) unregister_filesystem(&rootfs_fs_type); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Rob Landley81100.00%3100.00%
Total81100.00%3100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Al Viro49719.55%78.64%
Linus Torvalds47318.61%67.41%
Will Drewry27710.90%22.47%
Kai Germaschewski2048.03%67.41%
Rob Landley1917.51%33.70%
Kay Sievers1375.39%33.70%
Stephen Warren1164.56%22.47%
Chuck Lever993.89%22.47%
Pierre Ossman883.46%11.23%
Andrew Morton793.11%67.41%
Daniel Drake592.32%11.23%
David Howells401.57%33.70%
Andy Whitcroft351.38%11.23%
Chen Yu271.06%11.23%
Jörn Engel240.94%11.23%
Vishnu Pratap Singh180.71%11.23%
David Alan Gilbert160.63%11.23%
Miklos Szeredi160.63%11.23%
Jeff Layton150.59%11.23%
Tejun Heo140.55%22.47%
Dan Ehrenberg130.51%22.47%
H Hartley Sweeten120.47%11.23%
Bálint Márton110.43%11.23%
Arjan van de Ven100.39%22.47%
Adrian Hunter100.39%11.23%
Jens Axboe100.39%11.23%
Adrian Bunk100.39%44.94%
Greg Kroah-Hartman60.24%22.47%
Benjamin Collins50.20%11.23%
Vegard Nossum50.20%11.23%
Alan Cox40.16%11.23%
Pavel Machek40.16%22.47%
Arnaldo Carvalho de Melo30.12%11.23%
Bernhard Walle30.12%11.23%
Jan Blunck20.08%11.23%
Michał Mirosław20.08%11.23%
Toralf Förster10.04%11.23%
Sasha Levin10.04%11.23%
Jungseung Lee10.04%11.23%
Lucas De Marchi10.04%11.23%
chishanmingshen10.04%11.23%
Mandeep Singh Baines10.04%11.23%
Theodore Y. Ts'o10.04%11.23%
Total2542100.00%81100.00%
Directory: init
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.