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
This commit is contained in:
Craig Rodrigues 2008-09-13 18:57:47 +00:00
parent d676c049d7
commit b968101764

View File

@ -721,8 +721,10 @@ static const char *nfs_opts[] = { "from", "nfs_args",
"noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
"noclusterr", "noclusterw", "multilabel", "acls", "force", "update", "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
"async", "dumbtimer", "noconn", "nolockd", "intr", "rdirplus", "resvport", "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", "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax",
"deadthresh", "hostname", "timeout", "addr", "fh", "nfsv3",
"maxgroups",
NULL }; NULL };
/* /*
@ -763,12 +765,19 @@ nfs_mount(struct mount *mp, struct thread *td)
.acdirmin = NFS_MINDIRATTRTIMO, .acdirmin = NFS_MINDIRATTRTIMO,
.acdirmax = NFS_MAXDIRATTRTIMO, .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 sockaddr *nam;
struct vnode *vp; struct vnode *vp;
char hst[MNAMELEN]; char hst[MNAMELEN];
size_t len; size_t len;
u_char nfh[NFSX_V3FHMAX]; 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)) { if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
error = EINVAL; error = EINVAL;
@ -780,12 +789,219 @@ nfs_mount(struct mount *mp, struct thread *td)
goto out; goto out;
} }
error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, sizeof args); /*
if (error) * The old mount_nfs program passed the struct nfs_args
goto out; * 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) { if (args.version != NFS_ARGSVERSION) {
error = EPROGMISMATCH; 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; goto out;
} }
@ -819,23 +1035,38 @@ nfs_mount(struct mount *mp, struct thread *td)
*/ */
if (nfs_ip_paranoia == 0) if (nfs_ip_paranoia == 0)
args.flags |= NFSMNT_NOCONN; args.flags |= NFSMNT_NOCONN;
if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
error = EINVAL; if (has_nfs_args_opt) {
goto out; /*
* 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); error = mountnfs(&args, mp, nam, args.hostname, &vp, td->td_ucred);
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);
out: out:
if (!error) { if (!error) {
MNT_ILOCK(mp); MNT_ILOCK(mp);