diff options
author | jh <jh@FreeBSD.org> | 2011-04-22 07:26:09 +0000 |
---|---|---|
committer | jh <jh@FreeBSD.org> | 2011-04-22 07:26:09 +0000 |
commit | 91fe746b183b300c41d18f93e99c4a70efe59439 (patch) | |
tree | db2ae8dfab99123e481e55c813e37f3a1d851551 | |
parent | f0e5a695e9eedf13d440df2d5f8a3218f3a0c9d3 (diff) | |
download | FreeBSD-src-91fe746b183b300c41d18f93e99c4a70efe59439.zip FreeBSD-src-91fe746b183b300c41d18f93e99c4a70efe59439.tar.gz |
Utilize vfs_sanitizeopts() in vfs_mergeopts() to merge options. Because
vfs_sanitizeopts() can handle "ro" and "rw" options properly, there is
no more need to add "noro" in vfs_donmount() to cancel "ro".
This also fixes a problem of canceling options beginning with "no".
For example, "noatime" didn't cancel "nonoatime". Thus it was possible
that both "noatime" and "nonoatime" were active at the same time.
Reviewed by: bde
-rw-r--r-- | sys/kern/vfs_mount.c | 71 |
1 files changed, 14 insertions, 57 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 554521a..7bdb29c 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -336,50 +336,28 @@ bad: * Merge the old mount options with the new ones passed * in the MNT_UPDATE case. * - * XXX This function will keep a "nofoo" option in the - * new options if there is no matching "foo" option - * to be cancelled in the old options. This is a bug - * if the option's canonical name is "foo". E.g., "noro" - * shouldn't end up in the mount point's active options, - * but it can. + * XXX: This function will keep a "nofoo" option in the new + * options. E.g, if the option's canonical name is "foo", + * "nofoo" ends up in the mount point's active options. */ static void -vfs_mergeopts(struct vfsoptlist *toopts, struct vfsoptlist *opts) +vfs_mergeopts(struct vfsoptlist *toopts, struct vfsoptlist *oldopts) { - struct vfsopt *opt, *opt2, *new; + struct vfsopt *opt, *new; - TAILQ_FOREACH(opt, opts, link) { - /* - * Check that this option hasn't been redefined - * nor cancelled with a "no" mount option. - */ - opt2 = TAILQ_FIRST(toopts); - while (opt2 != NULL) { - if (strcmp(opt2->name, opt->name) == 0) - goto next; - if (strncmp(opt2->name, "no", 2) == 0 && - strcmp(opt2->name + 2, opt->name) == 0) { - vfs_freeopt(toopts, opt2); - goto next; - } - opt2 = TAILQ_NEXT(opt2, link); - } - /* We want this option, duplicate it. */ + TAILQ_FOREACH(opt, oldopts, link) { new = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK); - new->name = malloc(strlen(opt->name) + 1, M_MOUNT, M_WAITOK); - strcpy(new->name, opt->name); + new->name = strdup(opt->name, M_MOUNT); if (opt->len != 0) { new->value = malloc(opt->len, M_MOUNT, M_WAITOK); bcopy(opt->value, new->value, opt->len); - } else { + } else new->value = NULL; - } new->len = opt->len; new->seen = opt->seen; - TAILQ_INSERT_TAIL(toopts, new, link); -next: - continue; + TAILQ_INSERT_HEAD(toopts, new, link); } + vfs_sanitizeopts(toopts); } /* @@ -542,13 +520,12 @@ int vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions) { struct vfsoptlist *optlist; - struct vfsopt *opt, *noro_opt, *tmp_opt; + struct vfsopt *opt, *tmp_opt; char *fstype, *fspath, *errmsg; int error, fstypelen, fspathlen, errmsg_len, errmsg_pos; - int has_rw, has_noro; errmsg = fspath = NULL; - errmsg_len = has_noro = has_rw = fspathlen = 0; + errmsg_len = fspathlen = 0; errmsg_pos = -1; error = vfs_buildopts(fsoptions, &optlist); @@ -641,14 +618,10 @@ vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions) free(opt->name, M_MOUNT); opt->name = strdup("nonosymfollow", M_MOUNT); } - else if (strcmp(opt->name, "noro") == 0) { + else if (strcmp(opt->name, "noro") == 0) fsflags &= ~MNT_RDONLY; - has_noro = 1; - } - else if (strcmp(opt->name, "rw") == 0) { + else if (strcmp(opt->name, "rw") == 0) fsflags &= ~MNT_RDONLY; - has_rw = 1; - } else if (strcmp(opt->name, "ro") == 0) fsflags |= MNT_RDONLY; else if (strcmp(opt->name, "rdonly") == 0) { @@ -665,22 +638,6 @@ vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions) } /* - * If "rw" was specified as a mount option, and we - * are trying to update a mount-point from "ro" to "rw", - * we need a mount option "noro", since in vfs_mergeopts(), - * "noro" will cancel "ro", but "rw" will not do anything. - */ - if (has_rw && !has_noro) { - noro_opt = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK); - noro_opt->name = strdup("noro", M_MOUNT); - noro_opt->value = NULL; - noro_opt->len = 0; - noro_opt->pos = -1; - noro_opt->seen = 1; - TAILQ_INSERT_TAIL(optlist, noro_opt, link); - } - - /* * Be ultra-paranoid about making sure the type and fspath * variables will fit in our mp buffers, including the * terminating NUL. |