Index: sys/vm/vm_page.c =================================================================== --- sys/vm/vm_page.c +++ sys/vm/vm_page.c @@ -2601,37 +2601,32 @@ vm_page_assert_locked(m); - /* - * If it's already inactive but still deferred just note that it should be put at the head - */ - if ((m->flags & PG_PAQUEUE) && athead) { - m->flags |= PG_ATHEAD; - return; - } - /* - * Ignore if the page is likely to be reused - note that this is a somewhat expensive way - * of accelerating page free - would likely be faster to mark them with ATHEAD and then - * scan later during fixup + * Ignore if the page is already inactive, unless it is unlikely to be + * reactivated. */ if ((queue = m->queue) == PQ_INACTIVE && !noreuse) return; if (m->wire_count == 0 && (m->oflags & VPO_UNMANAGED) == 0) { - if (queue != PQ_NONE) { - vm_page_dequeue(m); + pq = &vm_phys_domain(m)->vmd_pagequeues[PQ_INACTIVE]; + /* Avoid multiple acquisitions of the inactive queue lock. */ + if (queue == PQ_INACTIVE) { + vm_pagequeue_lock(pq); + vm_page_dequeue_locked(m); + } else { + if (queue != PQ_NONE) + vm_page_dequeue(m); m->flags &= ~PG_WINATCFLS; + vm_pagequeue_lock(pq); } - if (athead) - m->flags |= PG_ATHEAD; - m->flags |= PG_PAQUEUE; m->queue = PQ_INACTIVE; - - pq = &vm_phys_domain(m)->vmd_pagequeues[vm_page_queue_idx(m)]; - TAILQ_INSERT_TAIL(&pq->pq_pl, m, plinks.q); + if (noreuse) + TAILQ_INSERT_BEFORE(&vm_phys_domain(m)->vmd_inacthead, + m, plinks.q); + else + TAILQ_INSERT_TAIL(&pq->pq_pl, m, plinks.q); vm_pagequeue_cnt_inc(pq); - atomic_add_int(&vm_cnt.v_inactive_deferred_count, 1); - if (pq->pq_cnt > vm_paqlenthresh_lwm) - vm_page_queue_fixup(m); + vm_pagequeue_unlock(pq); } } Index: usr.sbin/mountd/exports.5 =================================================================== --- usr.sbin/mountd/exports.5 +++ usr.sbin/mountd/exports.5 @@ -131,6 +131,7 @@ on the local machine (see .Xr id 1 ) . The user may be specified by name or number. +The user string may be quoted, or use backslash escaping. .Pp .Sm off .Fl maproot Li = Sy user:group1:group2:... @@ -140,6 +141,7 @@ The elements of the list may be either names or numbers. Note that user: should be used to distinguish a credential containing no groups from a complete credential for that user. +The group names may be quoted, or use backslash escaping. .Pp .Sm off .Fl mapall Li = Sy user Index: usr.sbin/mountd/mountd.c =================================================================== --- usr.sbin/mountd/mountd.c +++ usr.sbin/mountd/mountd.c @@ -174,6 +174,7 @@ static int checkmask(struct sockaddr *sa); static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, int *, int **); +static char *strsep_quote(char **stringp, const char *delim); static int create_service(struct netconfig *nconf); static void complete_service(struct netconfig *nconf, char *port_str); static void clearout_service(void); @@ -278,6 +279,73 @@ #endif /* + * Similar to strsep(), but it allows for quoted strings + * and escaped characters. + * + * It returns the string (or NULL, if *stringp is NULL), + * which is a de-quoted version of the string if necessary. + * + * It modifies *stringp in place. + */ +static char * +strsep_quote(char **stringp, const char *delim) +{ + char *srcptr, *dstptr, *retval; + char quot = 0; + + if (stringp == NULL || *stringp == NULL) + return (NULL); + + srcptr = dstptr = retval = *stringp; + + while (*srcptr) { + /* + * We're looking for several edge cases here. + * First: if we're in quote state (quot != 0), + * then we ignore the delim characters, but otherwise + * process as normal, unless it is the quote character. + * Second: if the current character is a backslash, + * we take the next character as-is, without checking + * for delim, quote, or backslash. Exception: if the + * next character is a NUL, that's the end of the string. + * Third: if the character is a quote character, we toggle + * quote state. + * Otherwise: check the current character for NUL, or + * being in delim, and end the string if either is true. + */ + if (*srcptr == '\\') { + srcptr++; + /* + * The edge case here is if the next character + * is NUL, we want to stop processing. But if + * it's not NUL, then we simply want to copy it. + */ + if (*srcptr) { + *dstptr++ = *srcptr++; + } + continue; + } + if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { + quot = *srcptr++; + continue; + } + if (quot && *srcptr == quot) { + /* End of the quoted part */ + quot = 0; + srcptr++; + continue; + } + if (!quot && strchr(delim, *srcptr)) + break; + *dstptr++ = *srcptr++; + } + + *dstptr = 0; /* Terminate the string */ + *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; + return (retval); +} + +/* * Mountd server for NFS mount protocol as described in: * NFS: Network File System Protocol Specification, RFC1094, Appendix A * The optional arguments are the exports file name @@ -2831,8 +2899,9 @@ /* * Get the user's password table entry. */ - names = strsep(&namelist, " \t\n"); + names = strsep_quote(&namelist, " \t\n"); name = strsep(&names, ":"); + /* Bug? name could be NULL here */ if (isdigit(*name) || *name == '-') pw = getpwuid(atoi(name)); else