Change the way we internally store the mount options to
a linked list. This is to allow the merging of the mount options in the MNT_UPDATE case, as the current data structure is unsuitable for this. There are no functional differences in this commit. Reviewed by: phk
This commit is contained in:
parent
9f3d7bf758
commit
7d2d440991
@ -87,7 +87,6 @@ static int setutimes(struct thread *td, struct vnode *,
|
||||
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 @@ nmount(td, uap)
|
||||
* 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,
|
||||
|
@ -488,6 +488,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.
|
||||
*
|
||||
@ -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);
|
||||
}
|
||||
@ -537,18 +576,14 @@ vfs_copyopt(opts, name, dest, 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 != opt->len)
|
||||
return (EINVAL);
|
||||
bcopy(opt->value, dest, opt->len);
|
||||
return (0);
|
||||
}
|
||||
opt++;
|
||||
}
|
||||
return (ENOENT);
|
||||
}
|
||||
|
@ -87,7 +87,6 @@ static int setutimes(struct thread *td, struct vnode *,
|
||||
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 @@ nmount(td, uap)
|
||||
* 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,
|
||||
|
@ -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 vfs_mount(struct thread *td, const char *type, char *path,
|
||||
|
Loading…
Reference in New Issue
Block a user