diff options
author | rodrigc <rodrigc@FreeBSD.org> | 2008-09-13 18:57:47 +0000 |
---|---|---|
committer | rodrigc <rodrigc@FreeBSD.org> | 2008-09-13 18:57:47 +0000 |
commit | 01526c3ea77546023dc56f8a3faa65e25f6a2d4c (patch) | |
tree | 266abc98a5683d79aff2753829b98561381dba36 /sys/nfsclient | |
parent | 5843973f4a0a18ddcb419cf75eedf0fb820be5b5 (diff) | |
download | FreeBSD-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.c | 277 |
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); |