Skip to content

Commit

Permalink
9p: add support for root file systems
Browse files Browse the repository at this point in the history
This introduces a new kernel command-line option called 'v9fsroot='
which will tell the kernel to mount the root file system by
utilizing the 9p protocol.

This allows us to mount host folder as rootfs for guest linux in qemu.
Bellow is an example which mounts v9fs with tag 'r' as rootfs in qemu
guest via virtio transport.

  $ qemu-system-x86_64 -enable-kvm -cpu host -m 1024 \
      -virtfs local,path=$rootfs_dir,mount_tag=r,security_model=passthrough,id=r \
      -kernel /path/to/linux/arch/x86/boot/bzImage -nographic \
      -append "root=/dev/v9fs v9fsroot=r,trans=virtio rw console=ttyS0 3"

Signed-off-by: Changbin Du <changbin.du@gmail.com>
  • Loading branch information
changbindu authored and intel-lab-lkp committed Jun 6, 2021
1 parent acda97a commit 96098f7
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 0 deletions.
5 changes: 5 additions & 0 deletions MAINTAINERS
Expand Up @@ -239,6 +239,11 @@ F: include/trace/events/9p.h
F: include/uapi/linux/virtio_9p.h
F: net/9p/

9P FILE SYSTEM ROOTFS SUPPORT
R: Changbin Du <changbin.du@gmail.com>
S: Supported
F: fs/9p/v9fsroot.c

A8293 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
Expand Down
6 changes: 6 additions & 0 deletions fs/9p/Kconfig
Expand Up @@ -42,3 +42,9 @@ config 9P_FS_SECURITY

If you are not using a security module that requires using
extended attributes for file security labels, say N.

config 9P_FS_ROOT
bool "9p root file system"
depends on 9P_FS=y
help
Enables root file system support over 9p protocol.
1 change: 1 addition & 0 deletions fs/9p/Makefile
Expand Up @@ -15,3 +15,4 @@ obj-$(CONFIG_9P_FS) := 9p.o

9p-$(CONFIG_9P_FSCACHE) += cache.o
9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
9p-$(CONFIG_9P_FS_ROOT) += v9fsroot.o
64 changes: 64 additions & 0 deletions fs/9p/v9fsroot.c
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0
/*
* 9p root file system support
*
* Copyright (c) 2021 Changbin Du <changbin.du@gmail.com>
*/
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/root_dev.h>
#include <linux/kernel.h>

static char root_dev[2048] __initdata = "";
static char root_opts[1024] __initdata = "";

/* v9fsroot=<path>[,options] */
static int __init v9fs_root_setup(char *line)
{
char *s;
int len;

if (strlen(line) >= 1) {
/* make s point to ',' or '\0' at end of line */
s = strchrnul(line, ',');
/* len is strlen(unc) + '\0' */
len = s - line + 1;
if (len > sizeof(root_dev)) {
pr_err("Root-V9FS: path too long\n");
return 1;
}
strscpy(root_dev, line, len);

if (*s) {
int n = snprintf(root_opts,
sizeof(root_opts), "%s",
s + 1);
if (n >= sizeof(root_opts)) {
pr_err("Root-V9FS: mount options string too long\n");
root_opts[sizeof(root_opts)-1] = '\0';
return 1;
}
}
}

ROOT_DEV = Root_V9FS;
return 1;
}

__setup("v9fsroot=", v9fs_root_setup);

int __init v9fs_root_data(char **dev, char **opts)
{
if (!root_dev[0]) {
pr_err("Root-V9FS: no rootdev specified\n");
return -1;
}

*dev = root_dev;
*opts = root_opts;

return 0;
}
1 change: 1 addition & 0 deletions include/linux/root_dev.h
Expand Up @@ -9,6 +9,7 @@
enum {
Root_NFS = MKDEV(UNNAMED_MAJOR, 255),
Root_CIFS = MKDEV(UNNAMED_MAJOR, 254),
Root_V9FS = MKDEV(UNNAMED_MAJOR, 253),
Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0),
Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1),
Root_FD0 = MKDEV(FLOPPY_MAJOR, 0),
Expand Down
55 changes: 55 additions & 0 deletions init/do_mounts.c
Expand Up @@ -287,6 +287,8 @@ dev_t name_to_dev_t(const char *name)
return Root_NFS;
if (strcmp(name, "/dev/cifs") == 0)
return Root_CIFS;
if (strcmp(name, "/dev/v9fs") == 0)
return Root_V9FS;
if (strcmp(name, "/dev/ram") == 0)
return Root_RAM0;
#ifdef CONFIG_BLOCK
Expand Down Expand Up @@ -536,6 +538,52 @@ static int __init mount_cifs_root(void)
}
#endif

#ifdef CONFIG_9P_FS_ROOT

extern int v9fs_root_data(char **dev, char **opts);

#define V9FSROOT_TIMEOUT_MIN 5
#define V9FSROOT_TIMEOUT_MAX 30
#define V9FSROOT_RETRY_MAX 5

static bool v9fs_should_retry(char *mount_opts)
{
if (strstr(mount_opts, "trans=virtio") || strstr(mount_opts, "trans=fd"))
return false;
return true;
}

static int __init mount_v9fs_root(void)
{
char *root_dev, *root_data;
unsigned int timeout = V9FSROOT_TIMEOUT_MIN;
bool should_retry;
int try, err;

err = v9fs_root_data(&root_dev, &root_data);
if (err != 0)
return 0;

should_retry = v9fs_should_retry(root_data);
for (try = 1; ; try++) {
err = do_mount_root(root_dev, "9p",
root_mountflags, root_data);
if (err == 0)
return 1;

if (!should_retry || try > V9FSROOT_RETRY_MAX)
break;

/* Wait, in case the server refused us immediately */
ssleep(timeout);
timeout <<= 1;
if (timeout > V9FSROOT_TIMEOUT_MAX)
timeout = V9FSROOT_TIMEOUT_MAX;
}
return 0;
}
#endif

void __init mount_root(void)
{
#ifdef CONFIG_ROOT_NFS
Expand All @@ -552,6 +600,13 @@ void __init mount_root(void)
return;
}
#endif
#ifdef CONFIG_9P_FS_ROOT
if (ROOT_DEV == Root_V9FS) {
if (!mount_v9fs_root())
pr_err("VFS: Unable to mount root fs via 9p.\n");
return;
}
#endif
#ifdef CONFIG_BLOCK
{
int err = create_dev("/dev/root", ROOT_DEV);
Expand Down

0 comments on commit 96098f7

Please sign in to comment.