Make it possible to reroot into NFS. This means one can have
eg an NFSv4 root over WiFi: boot from md_root (small rootfs image preloaded by loader(8)), setup WiFi, and then reroot into the actual root, over NFS. Note that it's currently limited to NFSv4, and due to problems with nfsuserd(8) it requres a workaround on the server side: one needs to set the vfs.nfsd.enable_stringtouid=1 sysctl and not run nfsuserd(8) on either the server or the client side. Reviewed by: rmacklem@ MFC after: 1 month Relnotes: yes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D6347
This commit is contained in:
parent
e542607041
commit
0d1654c39b
@ -740,6 +740,101 @@ static const char *nfs_opts[] = { "from", "nfs_args",
|
||||
"pnfs", "wcommitsize",
|
||||
NULL };
|
||||
|
||||
/*
|
||||
* Parse the "from" mountarg, passed by the generic mount(8) program
|
||||
* or the mountroot code. This is used when rerooting into NFS.
|
||||
*
|
||||
* Note that the "hostname" is actually a "hostname:/share/path" string.
|
||||
*/
|
||||
static int
|
||||
nfs_mount_parse_from(struct vfsoptlist *opts, char **hostnamep,
|
||||
struct sockaddr_in **sinp, char *dirpath, size_t dirpathsize, int *dirlenp)
|
||||
{
|
||||
char nam[MNAMELEN + 1];
|
||||
char *delimp, *hostp, *spec;
|
||||
int error, have_bracket = 0, offset, rv, speclen;
|
||||
struct sockaddr_in *sin;
|
||||
size_t len;
|
||||
|
||||
error = vfs_getopt(opts, "from", (void **)&spec, &speclen);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* This part comes from sbin/mount_nfs/mount_nfs.c:getnfsargs().
|
||||
*/
|
||||
if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
|
||||
*(delimp + 1) == ':') {
|
||||
hostp = spec + 1;
|
||||
spec = delimp + 2;
|
||||
have_bracket = 1;
|
||||
} else if ((delimp = strrchr(spec, ':')) != NULL) {
|
||||
hostp = spec;
|
||||
spec = delimp + 1;
|
||||
} else if ((delimp = strrchr(spec, '@')) != NULL) {
|
||||
printf("%s: path@server syntax is deprecated, "
|
||||
"use server:path\n", __func__);
|
||||
hostp = delimp + 1;
|
||||
} else {
|
||||
printf("%s: no <host>:<dirpath> nfs-name\n", __func__);
|
||||
return (EINVAL);
|
||||
}
|
||||
*delimp = '\0';
|
||||
|
||||
/*
|
||||
* If there has been a trailing slash at mounttime it seems
|
||||
* that some mountd implementations fail to remove the mount
|
||||
* entries from their mountlist while unmounting.
|
||||
*/
|
||||
for (speclen = strlen(spec);
|
||||
speclen > 1 && spec[speclen - 1] == '/';
|
||||
speclen--)
|
||||
spec[speclen - 1] = '\0';
|
||||
if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
|
||||
printf("%s: %s:%s: name too long", __func__, hostp, spec);
|
||||
return (EINVAL);
|
||||
}
|
||||
/* Make both '@' and ':' notations equal */
|
||||
if (*hostp != '\0') {
|
||||
len = strlen(hostp);
|
||||
offset = 0;
|
||||
if (have_bracket)
|
||||
nam[offset++] = '[';
|
||||
memmove(nam + offset, hostp, len);
|
||||
if (have_bracket)
|
||||
nam[len + offset++] = ']';
|
||||
nam[len + offset++] = ':';
|
||||
memmove(nam + len + offset, spec, speclen);
|
||||
nam[len + speclen + offset] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: IPv6
|
||||
*/
|
||||
sin = malloc(sizeof(*sin), M_SONAME, M_WAITOK);
|
||||
rv = inet_pton(AF_INET, hostp, &sin->sin_addr);
|
||||
if (rv != 1) {
|
||||
printf("%s: cannot parse '%s', inet_pton() returned %d\n",
|
||||
__func__, hostp, rv);
|
||||
free(sin, M_SONAME);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
sin->sin_len = sizeof(*sin);
|
||||
sin->sin_family = AF_INET;
|
||||
/*
|
||||
* XXX: hardcoded port number.
|
||||
*/
|
||||
sin->sin_port = htons(2049);
|
||||
|
||||
*hostnamep = strdup(nam, M_NEWNFSMNT);
|
||||
*sinp = sin;
|
||||
strlcpy(dirpath, spec, dirpathsize);
|
||||
*dirlenp = strlen(dirpath);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS Operations.
|
||||
*
|
||||
@ -785,17 +880,20 @@ nfs_mount(struct mount *mp)
|
||||
int nametimeo = NFS_DEFAULT_NAMETIMEO;
|
||||
int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
|
||||
int minvers = 0;
|
||||
int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen;
|
||||
int dirlen, has_nfs_args_opt, has_nfs_from_opt,
|
||||
krbnamelen, srvkrbnamelen;
|
||||
size_t hstlen;
|
||||
|
||||
has_nfs_args_opt = 0;
|
||||
has_nfs_from_opt = 0;
|
||||
if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
td = curthread;
|
||||
if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
|
||||
if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
|
||||
nfs_diskless_valid != 0) {
|
||||
error = nfs_mountroot(mp);
|
||||
goto out;
|
||||
}
|
||||
@ -1135,6 +1233,19 @@ nfs_mount(struct mount *mp)
|
||||
args.addrlen);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
} else if (nfs_mount_parse_from(mp->mnt_optnew,
|
||||
&args.hostname, (struct sockaddr_in **)&nam, dirpath,
|
||||
sizeof(dirpath), &dirlen) == 0) {
|
||||
has_nfs_from_opt = 1;
|
||||
bcopy(args.hostname, hst, MNAMELEN);
|
||||
hst[MNAMELEN - 1] = '\0';
|
||||
|
||||
/*
|
||||
* This only works with NFSv4 for now.
|
||||
*/
|
||||
args.fhsize = 0;
|
||||
args.flags |= NFSMNT_NFSV4;
|
||||
args.sotype = SOCK_STREAM;
|
||||
} else {
|
||||
if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
|
||||
&args.fhsize) == 0) {
|
||||
@ -1174,13 +1285,16 @@ nfs_mount(struct mount *mp)
|
||||
krbname[0] = '\0';
|
||||
krbnamelen = strlen(krbname);
|
||||
|
||||
if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
|
||||
strlcpy(dirpath, name, sizeof (dirpath));
|
||||
else
|
||||
dirpath[0] = '\0';
|
||||
dirlen = strlen(dirpath);
|
||||
if (has_nfs_from_opt == 0) {
|
||||
if (vfs_getopt(mp->mnt_optnew,
|
||||
"dirpath", (void **)&name, NULL) == 0)
|
||||
strlcpy(dirpath, name, sizeof (dirpath));
|
||||
else
|
||||
dirpath[0] = '\0';
|
||||
dirlen = strlen(dirpath);
|
||||
}
|
||||
|
||||
if (has_nfs_args_opt == 0) {
|
||||
if (has_nfs_args_opt == 0 && has_nfs_from_opt == 0) {
|
||||
if (vfs_getopt(mp->mnt_optnew, "addr",
|
||||
(void **)&args.addr, &args.addrlen) == 0) {
|
||||
if (args.addrlen > SOCK_MAXADDRLEN) {
|
||||
|
Loading…
Reference in New Issue
Block a user