Index: kern/vfs_subr.c =================================================================== RCS file: /space2/ncvs/src/sys/kern/vfs_subr.c,v retrieving revision 1.360 diff -u -p -r1.360 vfs_subr.c --- kern/vfs_subr.c 6 Jun 2002 15:50:22 -0000 1.360 +++ kern/vfs_subr.c 19 Jun 2002 15:38:30 -0000 @@ -489,6 +489,49 @@ vfs_timestamp(tsp) } /* + * Build a linked list of mount options from a struct uio. + */ +int +vfs_buildopts(struct uio *auio, struct vfsoptlist **options) +{ + struct vfsoptlist *opts; + struct vfsopt *opt; + unsigned int i, iovcnt; + int error, namelen, optlen; + + iovcnt = auio->uio_iovcnt; + opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK); + TAILQ_INIT(opts); + for (i = 0; i < iovcnt; i += 2) { + opt = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK); + namelen = auio->uio_iov[i].iov_len; + optlen = auio->uio_iov[i + 1].iov_len; + opt->name = malloc(namelen, M_MOUNT, M_WAITOK); + opt->value = malloc(optlen, M_MOUNT, M_WAITOK); + opt->len = optlen; + if (auio->uio_segflg == UIO_SYSSPACE) { + bcopy(auio->uio_iov[i].iov_base, opt->name, namelen); + bcopy(auio->uio_iov[i + 1].iov_base, opt->value, + optlen); + } else { + error = copyin(auio->uio_iov[i].iov_base, opt->name, + namelen); + if (!error) + error = copyin(auio->uio_iov[i + 1].iov_base, + opt->value, optlen); + if (error) + goto bad; + } + TAILQ_INSERT_TAIL(opts, opt, link); + } + *options = opts; + return (0); +bad: + vfs_freeopts(opts); + return (error); +} + +/* * Get a mount option by its name. * * Return 0 if the option was found, ENOENT otherwise. @@ -504,11 +547,8 @@ vfs_getopt(opts, name, buf, len) int *len; { struct vfsopt *opt; - int i; - i = 0; - opt = opts->opt; - while (i++ < opts->optcnt) { + TAILQ_FOREACH(opt, opts, link) { if (strcmp(name, opt->name) == 0) { if (len != NULL) *len = opt->len; @@ -516,7 +556,6 @@ vfs_getopt(opts, name, buf, len) *buf = opt->value; return (0); } - opt++; } return (ENOENT); } @@ -538,11 +577,8 @@ vfs_copyopt(opts, name, dest, len, done) int len, *done; { struct vfsopt *opt; - int i; - i = 0; - opt = opts->opt; - while (i++ < opts->optcnt) { + TAILQ_FOREACH(opt, opts, link) { if (strcmp(name, opt->name) == 0) { if (len < opt->len) return (EINVAL); @@ -551,7 +587,6 @@ vfs_copyopt(opts, name, dest, len, done) *done = opt->len; return (0); } - opt++; } return (ENOENT); } Index: kern/vfs_syscalls.c =================================================================== RCS file: /space2/ncvs/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.258 diff -u -p -r1.258 vfs_syscalls.c --- kern/vfs_syscalls.c 28 May 2002 13:27:55 -0000 1.258 +++ kern/vfs_syscalls.c 19 Jun 2002 16:06:41 -0000 @@ -87,7 +87,6 @@ static int setutimes(struct thread *td, const struct timespec *, int); static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, struct thread *td); -static void vfs_freeopts(struct vfsoptlist *opt); static int vfs_nmount(struct thread *td, int, struct uio *); static int usermount = 0; /* if 1, non-root can mount fs. */ @@ -167,13 +166,19 @@ finish: * Release all resources related to the * mount options. */ -static void -vfs_freeopts(struct vfsoptlist *opt) +void +vfs_freeopts(struct vfsoptlist *opts) { + struct vfsopt *opt; - free(opt->opt, M_MOUNT); - free(opt->optbuf, M_MOUNT); - free(opt, M_MOUNT); + while (!TAILQ_EMPTY(opts)) { + opt = TAILQ_FIRST(opts); + TAILQ_REMOVE(opts, opt, link); + free(opt->name, M_MOUNT); + free(opt->value, M_MOUNT); + free(opt, M_MOUNT); + } + free(opts, M_MOUNT); } int @@ -275,63 +280,16 @@ vfs_nmount(td, fsflags, fsoptions) struct vnode *vp; struct mount *mp; struct vfsconf *vfsp; - struct iovec *cur; struct vfsoptlist *optlist; - struct vfsopt *opt; - char *buf, *fstype, *fspath; - int error, flag = 0, kern_flag = 0, i, len, optcnt; - int offset, iovcnt, fstypelen, fspathlen; + char *fstype, *fspath; + int error, flag = 0, kern_flag = 0; + int fstypelen, fspathlen; struct vattr va; struct nameidata nd; - /* - * Allocate memory to hold the vfsopt structures. - */ - iovcnt = fsoptions->uio_iovcnt; - optcnt = iovcnt >> 1; - opt = malloc(sizeof (struct vfsopt) * optcnt, - M_MOUNT, M_WAITOK | M_ZERO); - - /* - * Count the size of the buffer for options, - * allocate it, and fill in the vfsopt structures. - */ - cur = fsoptions->uio_iov; - len = fsoptions->uio_resid; - buf = malloc(len, M_TEMP, M_WAITOK | M_ZERO); - - optlist = malloc(sizeof (struct vfsoptlist), M_MOUNT, M_WAITOK); - optlist->opt = opt; - optlist->optbuf = buf; - optlist->optcnt = optcnt; - - offset = i = 0; - cur = fsoptions->uio_iov; - while (i < optcnt) { - opt[i].name = buf + offset; - /* Ensure the name of an option is a string. */ - if (opt[i].name[cur->iov_len - 1] != '\0') { - error = EINVAL; - goto bad; - } - offset += cur->iov_len; - cur++; - opt[i].len = cur->iov_len; - /* - * Prevent consumers from trying to - * read the value of a 0 length option - * by setting it to NULL. - */ - if (opt[i].len == 0) - opt[i].value = NULL; - else - opt[i].value = buf + offset; - offset += cur->iov_len; - cur++; i++; - } - - if ((error = uiomove(buf, len, fsoptions)) != 0) - goto bad; + error = vfs_buildopts(fsoptions, &optlist); + if (error) + return (error); /* * We need these two options before the others, Index: sys/mount.h =================================================================== RCS file: /space2/ncvs/src/sys/sys/mount.h,v retrieving revision 1.126 diff -u -p -r1.126 mount.h --- sys/mount.h 23 May 2002 23:18:25 -0000 1.126 +++ sys/mount.h 19 Jun 2002 15:37:53 -0000 @@ -120,13 +120,9 @@ struct statfs { */ TAILQ_HEAD(vnodelst, vnode); -struct vfsoptlist { - struct vfsopt *opt; - unsigned int optcnt; - char *optbuf; -}; - +TAILQ_HEAD(vfsoptlist, vfsopt); struct vfsopt { + TAILQ_ENTRY(vfsopt) link; char *name; void *value; int len; @@ -439,6 +435,8 @@ extern char *mountrootfsname; int dounmount(struct mount *, int, struct thread *td); int kernel_mount(struct iovec *iovp, unsigned int iovcnt, int flags); int kernel_vmount(int flags, ...); +int vfs_buildopts(struct uio *, struct vfsoptlist **); +void vfs_freeopts(struct vfsoptlist *); int vfs_getopt(struct vfsoptlist *, const char *, void **, int *); int vfs_copyopt(struct vfsoptlist *, const char *, void *, int, int *); int vfs_mount(struct thread *td, const char *type, char *path,