diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-09 12:38:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-09 12:38:18 -0700 |
commit | e2e694b9e6f3ec7deeb233b6b0fe20b6a47b304b (patch) | |
tree | f98682de600e9b224f73412d855f5a40f635b5ca | |
parent | 7b7699c09f66f180b9a8a5010df352acb8683bfa (diff) | |
parent | 6e7c1770a212239e88ec01ddc7a741505bfd10e5 (diff) |
Merge branch 'work.init' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull root filesystem type handling updates from Al Viro:
"Teach init/do_mounts.c to handle non-block filesystems, hopefully
preventing even more special-cased kludges (such as root=/dev/nfs,
etc)"
* 'work.init' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
fs: simplify get_filesystem_list / get_all_fs_names
init: allow mounting arbitrary non-blockdevice filesystems as root
init: split get_fs_names
-rw-r--r-- | fs/filesystems.c | 27 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | init/do_mounts.c | 90 |
3 files changed, 83 insertions, 36 deletions
diff --git a/fs/filesystems.c b/fs/filesystems.c index 90b8d879fbaf..58b9067b2391 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -209,21 +209,28 @@ SYSCALL_DEFINE3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2) } #endif -int __init get_filesystem_list(char *buf) +int __init list_bdev_fs_names(char *buf, size_t size) { - int len = 0; - struct file_system_type * tmp; + struct file_system_type *p; + size_t len; + int count = 0; read_lock(&file_systems_lock); - tmp = file_systems; - while (tmp && len < PAGE_SIZE - 80) { - len += sprintf(buf+len, "%s\t%s\n", - (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", - tmp->name); - tmp = tmp->next; + for (p = file_systems; p; p = p->next) { + if (!(p->fs_flags & FS_REQUIRES_DEV)) + continue; + len = strlen(p->name) + 1; + if (len > size) { + pr_warn("%s: truncating file system list\n", __func__); + break; + } + memcpy(buf, p->name, len); + buf += len; + size -= len; + count++; } read_unlock(&file_systems_lock); - return len; + return count; } #ifdef CONFIG_PROC_FS diff --git a/include/linux/fs.h b/include/linux/fs.h index 37ad9a730a89..29b355037c08 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3592,7 +3592,7 @@ int proc_nr_dentry(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos); int proc_nr_inodes(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos); -int __init get_filesystem_list(char *buf); +int __init list_bdev_fs_names(char *buf, size_t size); #define __FMODE_EXEC ((__force int) FMODE_EXEC) #define __FMODE_NONOTIFY ((__force int) FMODE_NONOTIFY) diff --git a/init/do_mounts.c b/init/do_mounts.c index b691d6891e51..2ed30ff6c906 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -338,31 +338,22 @@ __setup("rootflags=", root_data_setup); __setup("rootfstype=", fs_names_setup); __setup("rootdelay=", root_delay_setup); -static void __init get_fs_names(char *page) +static int __init split_fs_names(char *page, char *names) { - char *s = page; + int count = 0; + char *p = 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'; - } + strcpy(p, root_fs_names); + while (*p++) { + if (p[-1] == ',') + p[-1] = '\0'; } - *s = '\0'; + *p = '\0'; + + for (p = page; *p; p += strlen(p)+1) + count++; + + return count; } static int __init do_mount_root(const char *name, const char *fs, @@ -408,12 +399,16 @@ void __init mount_block_root(char *name, int flags) char *fs_names = page_address(page); char *p; char b[BDEVNAME_SIZE]; + int num_fs, i; scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); - get_fs_names(fs_names); + if (root_fs_names) + num_fs = split_fs_names(fs_names, root_fs_names); + else + num_fs = list_bdev_fs_names(fs_names, PAGE_SIZE); retry: - for (p = fs_names; *p; p += strlen(p)+1) { + for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) { int err = do_mount_root(name, p, flags, root_mount_data); switch (err) { case 0: @@ -442,7 +437,7 @@ 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) + for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) printk(" %s", p); printk("\n"); panic("VFS: Unable to mount root fs on %s", b); @@ -526,6 +521,47 @@ static int __init mount_cifs_root(void) } #endif +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; + int num_fs, i; + + fs_names = (void *)__get_free_page(GFP_KERNEL); + if (!fs_names) + return -EINVAL; + num_fs = split_fs_names(fs_names, root_fs_names); + + for (i = 0, fstype = fs_names; i < num_fs; + i++, fstype += strlen(fstype) + 1) { + if (!fs_is_nodev(fstype)) + continue; + err = do_mount_root(root_device_name, fstype, root_mountflags, + root_mount_data); + if (!err) + break; + if (err != -EACCES && err != -EINVAL) + panic("VFS: Unable to mount root \"%s\" (%s), err=%d\n", + root_device_name, fstype, err); + } + + free_page((unsigned long)fs_names); + return err; +} + void __init mount_root(void) { #ifdef CONFIG_ROOT_NFS @@ -542,6 +578,10 @@ void __init mount_root(void) return; } #endif + if (ROOT_DEV == 0 && root_device_name && root_fs_names) { + if (mount_nodev_root() == 0) + return; + } #ifdef CONFIG_BLOCK { int err = create_dev("/dev/root", ROOT_DEV); |