Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cifs: Add support for root file systems

Introduce a new CONFIG_CIFS_ROOT option to handle root file systems
over a SMB share.

In order to mount the root file system during the init process, make
cifs.ko perform non-blocking socket operations while mounting and
accessing it.

Cc: Steve French <smfrench@gmail.com>
Reviewed-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Paulo Alcantara (SUSE) <paulo@paulo.ac>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Paulo Alcantara (SUSE) and committed by
Steve French
8eecd1c2 0892ba69

+207 -3
+97
Documentation/filesystems/cifs/cifsroot.txt
··· 1 + Mounting root file system via SMB (cifs.ko) 2 + =========================================== 3 + 4 + Written 2019 by Paulo Alcantara <palcantara@suse.de> 5 + Written 2019 by Aurelien Aptel <aaptel@suse.com> 6 + 7 + The CONFIG_CIFS_ROOT option enables experimental root file system 8 + support over the SMB protocol via cifs.ko. 9 + 10 + It introduces a new kernel command-line option called 'cifsroot=' 11 + which will tell the kernel to mount the root file system over the 12 + network by utilizing SMB or CIFS protocol. 13 + 14 + In order to mount, the network stack will also need to be set up by 15 + using 'ip=' config option. For more details, see 16 + Documentation/filesystems/nfs/nfsroot.txt. 17 + 18 + A CIFS root mount currently requires the use of SMB1+UNIX Extensions 19 + which is only supported by the Samba server. SMB1 is the older 20 + deprecated version of the protocol but it has been extended to support 21 + POSIX features (See [1]). The equivalent extensions for the newer 22 + recommended version of the protocol (SMB3) have not been fully 23 + implemented yet which means SMB3 doesn't support some required POSIX 24 + file system objects (e.g. block devices, pipes, sockets). 25 + 26 + As a result, a CIFS root will default to SMB1 for now but the version 27 + to use can nonetheless be changed via the 'vers=' mount option. This 28 + default will change once the SMB3 POSIX extensions are fully 29 + implemented. 30 + 31 + Server configuration 32 + ==================== 33 + 34 + To enable SMB1+UNIX extensions you will need to set these global 35 + settings in Samba smb.conf: 36 + 37 + [global] 38 + server min protocol = NT1 39 + unix extension = yes # default 40 + 41 + Kernel command line 42 + =================== 43 + 44 + root=/dev/cifs 45 + 46 + This is just a virtual device that basically tells the kernel to mount 47 + the root file system via SMB protocol. 48 + 49 + cifsroot=//<server-ip>/<share>[,options] 50 + 51 + Enables the kernel to mount the root file system via SMB that are 52 + located in the <server-ip> and <share> specified in this option. 53 + 54 + The default mount options are set in fs/cifs/cifsroot.c. 55 + 56 + server-ip 57 + IPv4 address of the server. 58 + 59 + share 60 + Path to SMB share (rootfs). 61 + 62 + options 63 + Optional mount options. For more information, see mount.cifs(8). 64 + 65 + Examples 66 + ======== 67 + 68 + Export root file system as a Samba share in smb.conf file. 69 + 70 + ... 71 + [linux] 72 + path = /path/to/rootfs 73 + read only = no 74 + guest ok = yes 75 + force user = root 76 + force group = root 77 + browseable = yes 78 + writeable = yes 79 + admin users = root 80 + public = yes 81 + create mask = 0777 82 + directory mask = 0777 83 + ... 84 + 85 + Restart smb service. 86 + 87 + # systemctl restart smb 88 + 89 + Test it under QEMU on a kernel built with CONFIG_CIFS_ROOT and 90 + CONFIG_IP_PNP options enabled. 91 + 92 + # qemu-system-x86_64 -enable-kvm -cpu host -m 1024 \ 93 + -kernel /path/to/linux/arch/x86/boot/bzImage -nographic \ 94 + -append "root=/dev/cifs rw ip=dhcp cifsroot=//10.0.2.2/linux,username=foo,password=bar console=ttyS0 3" 95 + 96 + 97 + 1: https://wiki.samba.org/index.php/UNIX_Extensions
+8
fs/cifs/Kconfig
··· 211 211 Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data 212 212 to be cached locally on disk through the general filesystem cache 213 213 manager. If unsure, say N. 214 + 215 + config CIFS_ROOT 216 + bool "SMB root file system (Experimental)" 217 + depends on CIFS=y && IP_PNP 218 + help 219 + Enables root file system support over SMB protocol. 220 + 221 + Most people say N here.
+2
fs/cifs/Makefile
··· 21 21 cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o 22 22 23 23 cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o 24 + 25 + cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o
+2
fs/cifs/cifsglob.h
··· 607 607 __u32 handle_timeout; /* persistent and durable handle timeout in ms */ 608 608 unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ 609 609 __u16 compression; /* compression algorithm 0xFFFF default 0=disabled */ 610 + bool rootfs:1; /* if it's a SMB root file system */ 610 611 }; 611 612 612 613 /** ··· 765 764 * reconnect. 766 765 */ 767 766 int nr_targets; 767 + bool noblockcnt; /* use non-blocking connect() */ 768 768 }; 769 769 770 770 struct cifs_credits {
+83
fs/cifs/cifsroot.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * SMB root file system support 4 + * 5 + * Copyright (c) 2019 Paulo Alcantara <palcantara@suse.de> 6 + */ 7 + #include <linux/init.h> 8 + #include <linux/fs.h> 9 + #include <linux/types.h> 10 + #include <linux/ctype.h> 11 + #include <linux/string.h> 12 + #include <linux/root_dev.h> 13 + #include <linux/kernel.h> 14 + #include <linux/in.h> 15 + #include <linux/inet.h> 16 + #include <net/ipconfig.h> 17 + 18 + #define DEFAULT_MNT_OPTS \ 19 + "vers=1.0,cifsacl,mfsymlinks,rsize=1048576,wsize=65536,uid=0,gid=0," \ 20 + "hard,rootfs" 21 + 22 + static char root_dev[2048] __initdata = ""; 23 + static char root_opts[1024] __initdata = DEFAULT_MNT_OPTS; 24 + 25 + static __be32 __init parse_srvaddr(char *start, char *end) 26 + { 27 + char addr[sizeof("aaa.bbb.ccc.ddd")]; 28 + int i = 0; 29 + 30 + while (start < end && i < sizeof(addr) - 1) { 31 + if (isdigit(*start) || *start == '.') 32 + addr[i++] = *start; 33 + start++; 34 + } 35 + addr[i] = '\0'; 36 + return in_aton(addr); 37 + } 38 + 39 + /* cifsroot=//<server-ip>/<share>[,options] */ 40 + static int __init cifs_root_setup(char *line) 41 + { 42 + char *s; 43 + int len; 44 + __be32 srvaddr = htonl(INADDR_NONE); 45 + 46 + ROOT_DEV = Root_CIFS; 47 + 48 + if (strlen(line) > 3 && line[0] == '/' && line[1] == '/') { 49 + s = strchr(&line[2], '/'); 50 + if (!s || s[1] == '\0') 51 + return 1; 52 + 53 + s = strchrnul(s, ','); 54 + len = s - line + 1; 55 + if (len <= sizeof(root_dev)) { 56 + strlcpy(root_dev, line, len); 57 + srvaddr = parse_srvaddr(&line[2], s); 58 + if (*s) { 59 + snprintf(root_opts, sizeof(root_opts), "%s,%s", 60 + DEFAULT_MNT_OPTS, s + 1); 61 + } 62 + } 63 + } 64 + 65 + root_server_addr = srvaddr; 66 + 67 + return 1; 68 + } 69 + 70 + __setup("cifsroot=", cifs_root_setup); 71 + 72 + int __init cifs_root_data(char **dev, char **opts) 73 + { 74 + if (!root_dev[0] || root_server_addr == htonl(INADDR_NONE)) { 75 + printk(KERN_ERR "Root-CIFS: no SMB server address\n"); 76 + return -1; 77 + } 78 + 79 + *dev = root_dev; 80 + *opts = root_opts; 81 + 82 + return 0; 83 + }
+14 -3
fs/cifs/connect.c
··· 96 96 Opt_multiuser, Opt_sloppy, Opt_nosharesock, 97 97 Opt_persistent, Opt_nopersistent, 98 98 Opt_resilient, Opt_noresilient, 99 - Opt_domainauto, Opt_rdma, Opt_modesid, 99 + Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs, 100 100 Opt_compress, 101 101 102 102 /* Mount options which take numeric value */ ··· 266 266 { Opt_ignore, "nomand" }, 267 267 { Opt_ignore, "relatime" }, 268 268 { Opt_ignore, "_netdev" }, 269 + { Opt_rootfs, "rootfs" }, 269 270 270 271 { Opt_err, NULL } 271 272 }; ··· 1778 1777 case Opt_nodfs: 1779 1778 vol->nodfs = 1; 1780 1779 break; 1780 + case Opt_rootfs: 1781 + #ifdef CONFIG_CIFS_ROOT 1782 + vol->rootfs = true; 1783 + #endif 1784 + break; 1781 1785 case Opt_posixpaths: 1782 1786 vol->posix_paths = 1; 1783 1787 break; ··· 2733 2727 goto out_err_crypto_release; 2734 2728 } 2735 2729 2736 - tcp_ses->noblocksnd = volume_info->noblocksnd; 2730 + tcp_ses->noblockcnt = volume_info->rootfs; 2731 + tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs; 2737 2732 tcp_ses->noautotune = volume_info->noautotune; 2738 2733 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; 2739 2734 tcp_ses->rdma = volume_info->rdma; ··· 3880 3873 socket->sk->sk_sndbuf, 3881 3874 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); 3882 3875 3883 - rc = socket->ops->connect(socket, saddr, slen, 0); 3876 + rc = socket->ops->connect(socket, saddr, slen, 3877 + server->noblockcnt ? O_NONBLOCK : 0); 3878 + 3879 + if (rc == -EINPROGRESS) 3880 + rc = 0; 3884 3881 if (rc < 0) { 3885 3882 cifs_dbg(FYI, "Error %d connecting to server\n", rc); 3886 3883 sock_release(socket);
+1
include/linux/root_dev.h
··· 8 8 9 9 enum { 10 10 Root_NFS = MKDEV(UNNAMED_MAJOR, 255), 11 + Root_CIFS = MKDEV(UNNAMED_MAJOR, 254), 11 12 Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0), 12 13 Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1), 13 14 Root_FD0 = MKDEV(FLOPPY_MAJOR, 0),