summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/nfsclient/nfs_vfsops.c277
1 files changed, 254 insertions, 23 deletions
diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c
index a653a0e..f5b442d 100644
--- a/sys/nfsclient/nfs_vfsops.c
+++ b/sys/nfsclient/nfs_vfsops.c
@@ -721,8 +721,10 @@ static const char *nfs_opts[] = { "from", "nfs_args",
"noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
"noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
"async", "dumbtimer", "noconn", "nolockd", "intr", "rdirplus", "resvport",
- "readdirsize", "soft", "hard", "mntudp", "tcp", "wsize", "rsize",
+ "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
"retrans", "acregmin", "acregmax", "acdirmin", "acdirmax",
+ "deadthresh", "hostname", "timeout", "addr", "fh", "nfsv3",
+ "maxgroups",
NULL };
/*
@@ -763,12 +765,19 @@ nfs_mount(struct mount *mp, struct thread *td)
.acdirmin = NFS_MINDIRATTRTIMO,
.acdirmax = NFS_MAXDIRATTRTIMO,
};
- int error;
+ int error, ret, has_nfs_args_opt;
+ int has_addr_opt, has_fh_opt, has_hostname_opt;
struct sockaddr *nam;
struct vnode *vp;
char hst[MNAMELEN];
size_t len;
u_char nfh[NFSX_V3FHMAX];
+ char *opt;
+
+ has_nfs_args_opt = 0;
+ has_addr_opt = 0;
+ has_fh_opt = 0;
+ has_hostname_opt = 0;
if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
error = EINVAL;
@@ -780,12 +789,219 @@ nfs_mount(struct mount *mp, struct thread *td)
goto out;
}
- error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, sizeof args);
- if (error)
- goto out;
+ /*
+ * The old mount_nfs program passed the struct nfs_args
+ * from userspace to kernel. The new mount_nfs program
+ * passes string options via nmount() from userspace to kernel
+ * and we populate the struct nfs_args in the kernel.
+ */
+ if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
+ error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
+ sizeof args);
+ if (error)
+ goto out;
- if (args.version != NFS_ARGSVERSION) {
- error = EPROGMISMATCH;
+ if (args.version != NFS_ARGSVERSION) {
+ error = EPROGMISMATCH;
+ goto out;
+ }
+ has_nfs_args_opt = 1;
+ }
+
+ if (vfs_getopt(mp->mnt_optnew, "dumbtimer", NULL, NULL) == 0)
+ args.flags |= NFSMNT_DUMBTIMR;
+ if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
+ args.flags |= NFSMNT_NOCONN;
+ if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
+ args.flags |= NFSMNT_NOCONN;
+ if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
+ args.flags |= NFSMNT_NOLOCKD;
+ if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
+ args.flags &= ~NFSMNT_NOLOCKD;
+ if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
+ args.flags |= NFSMNT_INT;
+ if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
+ args.flags |= NFSMNT_RDIRPLUS;
+ if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
+ args.flags |= NFSMNT_RESVPORT;
+ if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
+ args.flags &= ~NFSMNT_RESVPORT;
+ if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
+ args.flags |= NFSMNT_SOFT;
+ if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
+ args.flags &= ~NFSMNT_SOFT;
+ if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
+ args.sotype = SOCK_DGRAM;
+ if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
+ args.sotype = SOCK_DGRAM;
+ if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
+ args.sotype = SOCK_STREAM;
+ if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
+ args.flags |= NFSMNT_NFSV3;
+ if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
+ if (opt == NULL) {
+ vfs_mount_error(mp, "illegal readdirsize");
+ error = EINVAL;
+ goto out;
+ }
+ ret = sscanf(opt, "%d", &args.readdirsize);
+ if (ret != 1 || args.readdirsize <= 0) {
+ vfs_mount_error(mp, "illegal readdirsize: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_READDIRSIZE;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
+ if (opt == NULL) {
+ vfs_mount_error(mp, "illegal readahead");
+ error = EINVAL;
+ goto out;
+ }
+ ret = sscanf(opt, "%d", &args.readahead);
+ if (ret != 1 || args.readahead <= 0) {
+ vfs_mount_error(mp, "illegal readahead: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_READAHEAD;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
+ if (opt == NULL) {
+ vfs_mount_error(mp, "illegal wsize");
+ error = EINVAL;
+ goto out;
+ }
+ ret = sscanf(opt, "%d", &args.wsize);
+ if (ret != 1 || args.wsize <= 0) {
+ vfs_mount_error(mp, "illegal wsize: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_WSIZE;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
+ if (opt == NULL) {
+ vfs_mount_error(mp, "illegal rsize");
+ error = EINVAL;
+ goto out;
+ }
+ ret = sscanf(opt, "%d", &args.rsize);
+ if (ret != 1 || args.rsize <= 0) {
+ vfs_mount_error(mp, "illegal wsize: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_RSIZE;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
+ if (opt == NULL) {
+ vfs_mount_error(mp, "illegal retrans");
+ error = EINVAL;
+ goto out;
+ }
+ ret = sscanf(opt, "%d", &args.retrans);
+ if (ret != 1 || args.retrans <= 0) {
+ vfs_mount_error(mp, "illegal retrans: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_RETRANS;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.acregmin);
+ if (ret != 1 || args.acregmin <= 0) {
+ vfs_mount_error(mp, "illegal acregmin: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ }
+ if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.acregmax);
+ if (ret != 1 || args.acregmax <= 0) {
+ vfs_mount_error(mp, "illegal acregmax: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ }
+ if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.acdirmin);
+ if (ret != 1 || args.acdirmin <= 0) {
+ vfs_mount_error(mp, "illegal acdirmin: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ }
+ if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.acdirmax);
+ if (ret != 1 || args.acdirmax <= 0) {
+ vfs_mount_error(mp, "illegal acdirmax: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ }
+ if (vfs_getopt(mp->mnt_optnew, "deadthresh", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.deadthresh);
+ if (ret != 1 || args.deadthresh <= 0) {
+ vfs_mount_error(mp, "illegal deadthresh: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_DEADTHRESH;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.timeo);
+ if (ret != 1 || args.timeo <= 0) {
+ vfs_mount_error(mp, "illegal timeout: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_TIMEO;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "maxgroups", (void **)&opt, NULL) == 0) {
+ ret = sscanf(opt, "%d", &args.maxgrouplist);
+ if (ret != 1 || args.timeo <= 0) {
+ vfs_mount_error(mp, "illegal maxgroups: %s",
+ opt);
+ error = EINVAL;
+ goto out;
+ }
+ args.flags |= NFSMNT_MAXGRPS;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr,
+ &args.addrlen) == 0) {
+ has_addr_opt = 1;
+ if (args.addrlen > SOCK_MAXADDRLEN) {
+ error = ENAMETOOLONG;
+ goto out;
+ }
+ MALLOC(nam, struct sockaddr *, args.addrlen, M_SONAME,
+ M_WAITOK);
+ bcopy(args.addr, nam, args.addrlen);
+ nam->sa_len = args.addrlen;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
+ &args.fhsize) == 0) {
+ has_fh_opt = 1;
+ }
+ if (vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname,
+ NULL) == 0) {
+ has_hostname_opt = 1;
+ }
+ if (args.hostname == NULL) {
+ vfs_mount_error(mp, "Invalid hostname");
+ error = EINVAL;
goto out;
}
@@ -819,23 +1035,38 @@ nfs_mount(struct mount *mp, struct thread *td)
*/
if (nfs_ip_paranoia == 0)
args.flags |= NFSMNT_NOCONN;
- if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
- error = EINVAL;
- goto out;
+
+ if (has_nfs_args_opt) {
+ /*
+ * In the 'nfs_args' case, the pointers in the args
+ * structure are in userland - we copy them in here.
+ */
+ if (!has_fh_opt) {
+ error = copyin((caddr_t)args.fh, (caddr_t)nfh,
+ args.fhsize);
+ if (error) {
+ goto out;
+ }
+ args.fh = nfh;
+ }
+ if (!has_hostname_opt) {
+ error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
+ if (error) {
+ goto out;
+ }
+ bzero(&hst[len], MNAMELEN - len);
+ args.hostname = hst;
+ }
+ if (!has_addr_opt) {
+ /* sockargs() call must be after above copyin() calls */
+ error = getsockaddr(&nam, (caddr_t)args.addr,
+ args.addrlen);
+ if (error) {
+ goto out;
+ }
+ }
}
- error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
- if (error)
- goto out;
- error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
- if (error)
- goto out;
- bzero(&hst[len], MNAMELEN - len);
- /* sockargs() call must be after above copyin() calls */
- error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
- if (error)
- goto out;
- args.fh = nfh;
- error = mountnfs(&args, mp, nam, hst, &vp, td->td_ucred);
+ error = mountnfs(&args, mp, nam, args.hostname, &vp, td->td_ucred);
out:
if (!error) {
MNT_ILOCK(mp);
OpenPOWER on IntegriCloud