summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient
diff options
context:
space:
mode:
authorrodrigc <rodrigc@FreeBSD.org>2008-09-13 18:57:47 +0000
committerrodrigc <rodrigc@FreeBSD.org>2008-09-13 18:57:47 +0000
commit01526c3ea77546023dc56f8a3faa65e25f6a2d4c (patch)
tree266abc98a5683d79aff2753829b98561381dba36 /sys/nfsclient
parent5843973f4a0a18ddcb419cf75eedf0fb820be5b5 (diff)
downloadFreeBSD-src-01526c3ea77546023dc56f8a3faa65e25f6a2d4c.zip
FreeBSD-src-01526c3ea77546023dc56f8a3faa65e25f6a2d4c.tar.gz
Add code to parse NFS mount options passed as individual
items of the nmount() iovec. This will allow us to move away from gathering up all the NFS mount options as a single "struct nfs_args" to be passed down through nmount(). This will make adding new NFS mount options much easier. Many, many thanks to Doug Rabson, who took my initial patches and cleaned them up. Reviewed by: dfr MFC after: 3 months
Diffstat (limited to 'sys/nfsclient')
-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