forked from Minki/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>
This commit is contained in:
parent
0892ba693f
commit
8eecd1c2e5
97
Documentation/filesystems/cifs/cifsroot.txt
Normal file
97
Documentation/filesystems/cifs/cifsroot.txt
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
Mounting root file system via SMB (cifs.ko)
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Written 2019 by Paulo Alcantara <palcantara@suse.de>
|
||||||
|
Written 2019 by Aurelien Aptel <aaptel@suse.com>
|
||||||
|
|
||||||
|
The CONFIG_CIFS_ROOT option enables experimental root file system
|
||||||
|
support over the SMB protocol via cifs.ko.
|
||||||
|
|
||||||
|
It introduces a new kernel command-line option called 'cifsroot='
|
||||||
|
which will tell the kernel to mount the root file system over the
|
||||||
|
network by utilizing SMB or CIFS protocol.
|
||||||
|
|
||||||
|
In order to mount, the network stack will also need to be set up by
|
||||||
|
using 'ip=' config option. For more details, see
|
||||||
|
Documentation/filesystems/nfs/nfsroot.txt.
|
||||||
|
|
||||||
|
A CIFS root mount currently requires the use of SMB1+UNIX Extensions
|
||||||
|
which is only supported by the Samba server. SMB1 is the older
|
||||||
|
deprecated version of the protocol but it has been extended to support
|
||||||
|
POSIX features (See [1]). The equivalent extensions for the newer
|
||||||
|
recommended version of the protocol (SMB3) have not been fully
|
||||||
|
implemented yet which means SMB3 doesn't support some required POSIX
|
||||||
|
file system objects (e.g. block devices, pipes, sockets).
|
||||||
|
|
||||||
|
As a result, a CIFS root will default to SMB1 for now but the version
|
||||||
|
to use can nonetheless be changed via the 'vers=' mount option. This
|
||||||
|
default will change once the SMB3 POSIX extensions are fully
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
Server configuration
|
||||||
|
====================
|
||||||
|
|
||||||
|
To enable SMB1+UNIX extensions you will need to set these global
|
||||||
|
settings in Samba smb.conf:
|
||||||
|
|
||||||
|
[global]
|
||||||
|
server min protocol = NT1
|
||||||
|
unix extension = yes # default
|
||||||
|
|
||||||
|
Kernel command line
|
||||||
|
===================
|
||||||
|
|
||||||
|
root=/dev/cifs
|
||||||
|
|
||||||
|
This is just a virtual device that basically tells the kernel to mount
|
||||||
|
the root file system via SMB protocol.
|
||||||
|
|
||||||
|
cifsroot=//<server-ip>/<share>[,options]
|
||||||
|
|
||||||
|
Enables the kernel to mount the root file system via SMB that are
|
||||||
|
located in the <server-ip> and <share> specified in this option.
|
||||||
|
|
||||||
|
The default mount options are set in fs/cifs/cifsroot.c.
|
||||||
|
|
||||||
|
server-ip
|
||||||
|
IPv4 address of the server.
|
||||||
|
|
||||||
|
share
|
||||||
|
Path to SMB share (rootfs).
|
||||||
|
|
||||||
|
options
|
||||||
|
Optional mount options. For more information, see mount.cifs(8).
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
Export root file system as a Samba share in smb.conf file.
|
||||||
|
|
||||||
|
...
|
||||||
|
[linux]
|
||||||
|
path = /path/to/rootfs
|
||||||
|
read only = no
|
||||||
|
guest ok = yes
|
||||||
|
force user = root
|
||||||
|
force group = root
|
||||||
|
browseable = yes
|
||||||
|
writeable = yes
|
||||||
|
admin users = root
|
||||||
|
public = yes
|
||||||
|
create mask = 0777
|
||||||
|
directory mask = 0777
|
||||||
|
...
|
||||||
|
|
||||||
|
Restart smb service.
|
||||||
|
|
||||||
|
# systemctl restart smb
|
||||||
|
|
||||||
|
Test it under QEMU on a kernel built with CONFIG_CIFS_ROOT and
|
||||||
|
CONFIG_IP_PNP options enabled.
|
||||||
|
|
||||||
|
# qemu-system-x86_64 -enable-kvm -cpu host -m 1024 \
|
||||||
|
-kernel /path/to/linux/arch/x86/boot/bzImage -nographic \
|
||||||
|
-append "root=/dev/cifs rw ip=dhcp cifsroot=//10.0.2.2/linux,username=foo,password=bar console=ttyS0 3"
|
||||||
|
|
||||||
|
|
||||||
|
1: https://wiki.samba.org/index.php/UNIX_Extensions
|
|
@ -211,3 +211,11 @@ config CIFS_FSCACHE
|
||||||
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
|
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
|
||||||
to be cached locally on disk through the general filesystem cache
|
to be cached locally on disk through the general filesystem cache
|
||||||
manager. If unsure, say N.
|
manager. If unsure, say N.
|
||||||
|
|
||||||
|
config CIFS_ROOT
|
||||||
|
bool "SMB root file system (Experimental)"
|
||||||
|
depends on CIFS=y && IP_PNP
|
||||||
|
help
|
||||||
|
Enables root file system support over SMB protocol.
|
||||||
|
|
||||||
|
Most people say N here.
|
||||||
|
|
|
@ -21,3 +21,5 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o
|
||||||
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
||||||
|
|
||||||
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
|
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
|
||||||
|
|
||||||
|
cifs-$(CONFIG_CIFS_ROOT) += cifsroot.o
|
||||||
|
|
|
@ -607,6 +607,7 @@ struct smb_vol {
|
||||||
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
|
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
|
||||||
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
|
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
|
||||||
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
|
__u16 compression; /* compression algorithm 0xFFFF default 0=disabled */
|
||||||
|
bool rootfs:1; /* if it's a SMB root file system */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -764,6 +765,7 @@ struct TCP_Server_Info {
|
||||||
* reconnect.
|
* reconnect.
|
||||||
*/
|
*/
|
||||||
int nr_targets;
|
int nr_targets;
|
||||||
|
bool noblockcnt; /* use non-blocking connect() */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cifs_credits {
|
struct cifs_credits {
|
||||||
|
|
83
fs/cifs/cifsroot.c
Normal file
83
fs/cifs/cifsroot.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* SMB root file system support
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Paulo Alcantara <palcantara@suse.de>
|
||||||
|
*/
|
||||||
|
#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>
|
||||||
|
#include <linux/in.h>
|
||||||
|
#include <linux/inet.h>
|
||||||
|
#include <net/ipconfig.h>
|
||||||
|
|
||||||
|
#define DEFAULT_MNT_OPTS \
|
||||||
|
"vers=1.0,cifsacl,mfsymlinks,rsize=1048576,wsize=65536,uid=0,gid=0," \
|
||||||
|
"hard,rootfs"
|
||||||
|
|
||||||
|
static char root_dev[2048] __initdata = "";
|
||||||
|
static char root_opts[1024] __initdata = DEFAULT_MNT_OPTS;
|
||||||
|
|
||||||
|
static __be32 __init parse_srvaddr(char *start, char *end)
|
||||||
|
{
|
||||||
|
char addr[sizeof("aaa.bbb.ccc.ddd")];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (start < end && i < sizeof(addr) - 1) {
|
||||||
|
if (isdigit(*start) || *start == '.')
|
||||||
|
addr[i++] = *start;
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
addr[i] = '\0';
|
||||||
|
return in_aton(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cifsroot=//<server-ip>/<share>[,options] */
|
||||||
|
static int __init cifs_root_setup(char *line)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int len;
|
||||||
|
__be32 srvaddr = htonl(INADDR_NONE);
|
||||||
|
|
||||||
|
ROOT_DEV = Root_CIFS;
|
||||||
|
|
||||||
|
if (strlen(line) > 3 && line[0] == '/' && line[1] == '/') {
|
||||||
|
s = strchr(&line[2], '/');
|
||||||
|
if (!s || s[1] == '\0')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
s = strchrnul(s, ',');
|
||||||
|
len = s - line + 1;
|
||||||
|
if (len <= sizeof(root_dev)) {
|
||||||
|
strlcpy(root_dev, line, len);
|
||||||
|
srvaddr = parse_srvaddr(&line[2], s);
|
||||||
|
if (*s) {
|
||||||
|
snprintf(root_opts, sizeof(root_opts), "%s,%s",
|
||||||
|
DEFAULT_MNT_OPTS, s + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root_server_addr = srvaddr;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__setup("cifsroot=", cifs_root_setup);
|
||||||
|
|
||||||
|
int __init cifs_root_data(char **dev, char **opts)
|
||||||
|
{
|
||||||
|
if (!root_dev[0] || root_server_addr == htonl(INADDR_NONE)) {
|
||||||
|
printk(KERN_ERR "Root-CIFS: no SMB server address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dev = root_dev;
|
||||||
|
*opts = root_opts;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -96,7 +96,7 @@ enum {
|
||||||
Opt_multiuser, Opt_sloppy, Opt_nosharesock,
|
Opt_multiuser, Opt_sloppy, Opt_nosharesock,
|
||||||
Opt_persistent, Opt_nopersistent,
|
Opt_persistent, Opt_nopersistent,
|
||||||
Opt_resilient, Opt_noresilient,
|
Opt_resilient, Opt_noresilient,
|
||||||
Opt_domainauto, Opt_rdma, Opt_modesid,
|
Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs,
|
||||||
Opt_compress,
|
Opt_compress,
|
||||||
|
|
||||||
/* Mount options which take numeric value */
|
/* Mount options which take numeric value */
|
||||||
|
@ -266,6 +266,7 @@ static const match_table_t cifs_mount_option_tokens = {
|
||||||
{ Opt_ignore, "nomand" },
|
{ Opt_ignore, "nomand" },
|
||||||
{ Opt_ignore, "relatime" },
|
{ Opt_ignore, "relatime" },
|
||||||
{ Opt_ignore, "_netdev" },
|
{ Opt_ignore, "_netdev" },
|
||||||
|
{ Opt_rootfs, "rootfs" },
|
||||||
|
|
||||||
{ Opt_err, NULL }
|
{ Opt_err, NULL }
|
||||||
};
|
};
|
||||||
|
@ -1777,6 +1778,11 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
||||||
case Opt_nodfs:
|
case Opt_nodfs:
|
||||||
vol->nodfs = 1;
|
vol->nodfs = 1;
|
||||||
break;
|
break;
|
||||||
|
case Opt_rootfs:
|
||||||
|
#ifdef CONFIG_CIFS_ROOT
|
||||||
|
vol->rootfs = true;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
case Opt_posixpaths:
|
case Opt_posixpaths:
|
||||||
vol->posix_paths = 1;
|
vol->posix_paths = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -2727,7 +2733,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
||||||
goto out_err_crypto_release;
|
goto out_err_crypto_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp_ses->noblocksnd = volume_info->noblocksnd;
|
tcp_ses->noblockcnt = volume_info->rootfs;
|
||||||
|
tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs;
|
||||||
tcp_ses->noautotune = volume_info->noautotune;
|
tcp_ses->noautotune = volume_info->noautotune;
|
||||||
tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
|
tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
|
||||||
tcp_ses->rdma = volume_info->rdma;
|
tcp_ses->rdma = volume_info->rdma;
|
||||||
|
@ -3873,7 +3880,11 @@ generic_ip_connect(struct TCP_Server_Info *server)
|
||||||
socket->sk->sk_sndbuf,
|
socket->sk->sk_sndbuf,
|
||||||
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
|
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
|
||||||
|
|
||||||
rc = socket->ops->connect(socket, saddr, slen, 0);
|
rc = socket->ops->connect(socket, saddr, slen,
|
||||||
|
server->noblockcnt ? O_NONBLOCK : 0);
|
||||||
|
|
||||||
|
if (rc == -EINPROGRESS)
|
||||||
|
rc = 0;
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
cifs_dbg(FYI, "Error %d connecting to server\n", rc);
|
cifs_dbg(FYI, "Error %d connecting to server\n", rc);
|
||||||
sock_release(socket);
|
sock_release(socket);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Root_NFS = MKDEV(UNNAMED_MAJOR, 255),
|
Root_NFS = MKDEV(UNNAMED_MAJOR, 255),
|
||||||
|
Root_CIFS = MKDEV(UNNAMED_MAJOR, 254),
|
||||||
Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0),
|
Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0),
|
||||||
Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1),
|
Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1),
|
||||||
Root_FD0 = MKDEV(FLOPPY_MAJOR, 0),
|
Root_FD0 = MKDEV(FLOPPY_MAJOR, 0),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user