diff options
author | Bryan Cantrill <bryan@joyent.com> | 2016-03-24 20:57:48 -0700 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2016-03-29 13:55:13 -0700 |
commit | 8905f42caceb9f470ffaa19e5f6c9fb6184d12c0 (patch) | |
tree | b7e1fec5b3ae8270ff0de96b7f12f4fbc664a1a4 | |
parent | 49b7860084dbba18bc00b29413d6182197f9fe93 (diff) | |
download | illumos-joyent-8905f42caceb9f470ffaa19e5f6c9fb6184d12c0.tar.gz |
6818 add MADV_PURGE to provide busted Linux MADV_DONTNEED semantics
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
Reviewed by: Cody Mello <melloc@joyent.com>
Approved by: Garrett D'Amore <garrett@damore.org>
-rw-r--r-- | usr/src/cmd/ptools/pmadvise/pmadvise.c | 14 | ||||
-rw-r--r-- | usr/src/cmd/truss/print.c | 1 | ||||
-rw-r--r-- | usr/src/man/man1/pmadvise.1 | 11 | ||||
-rw-r--r-- | usr/src/man/man3c/madvise.3c | 39 | ||||
-rw-r--r-- | usr/src/uts/common/sys/mman.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/memcntl.c | 3 | ||||
-rw-r--r-- | usr/src/uts/common/vm/anon.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/vm/seg_spt.c | 7 | ||||
-rw-r--r-- | usr/src/uts/common/vm/seg_vn.c | 71 | ||||
-rw-r--r-- | usr/src/uts/common/vm/vm_anon.c | 52 |
10 files changed, 158 insertions, 45 deletions
diff --git a/usr/src/cmd/ptools/pmadvise/pmadvise.c b/usr/src/cmd/ptools/pmadvise/pmadvise.c index 8500a00dc6..6b9623508a 100644 --- a/usr/src/cmd/ptools/pmadvise/pmadvise.c +++ b/usr/src/cmd/ptools/pmadvise/pmadvise.c @@ -25,6 +25,10 @@ */ /* + * Copyright (c) 2015, Joyent, Inc. All rights reserved. + */ + +/* * pmadvise * * ptool wrapper for madvise(3C) to apply memory advice to running processes @@ -153,7 +157,7 @@ * Advice that can be passed to madvise fit into three groups that each * contain 3 mutually exclusive options. These groups are defined below: * Group 1: normal, random, sequential - * Group 2: willneed, dontneed, free + * Group 2: willneed, dontneed, free, purge * Group 3: default, accesslwp, accessmany * Thus, advice that includes (at most) one from each group is valid. * @@ -164,7 +168,7 @@ #define GRP1_ADV (1 << MADV_NORMAL | 1 << MADV_RANDOM | \ 1 << MADV_SEQUENTIAL) #define GRP2_ADV (1 << MADV_WILLNEED | 1 << MADV_DONTNEED | \ - 1 << MADV_FREE) + 1 << MADV_FREE | 1 << MADV_PURGE) #define GRP3_ADV (1 << MADV_ACCESS_DEFAULT | 1 << MADV_ACCESS_LWP | \ 1 << MADV_ACCESS_MANY) @@ -346,6 +350,8 @@ get_advice(char *optarg) return (1 << MADV_NORMAL); else if (strcmp(optarg, "free") == 0) return (1 << MADV_FREE); + else if (strcmp(optarg, "purge") == 0) + return (1 << MADV_PURGE); else { (void) fprintf(stderr, gettext("%s: invalid advice: %s\n"), progname, optarg); @@ -676,7 +682,7 @@ apply_advice(saddr_t **advicelist) * with the for loop. */ if (psaddr->adv != NO_ADVICE) { - for (i = MADV_NORMAL; i <= MADV_ACCESS_MANY; i++) { + for (i = MADV_NORMAL; i <= MADV_PURGE; i++) { if ((psaddr->adv & (1 << i)) && (pr_madvise(Pr, (caddr_t)psaddr->addr, psaddr->length, i) < 0)) { @@ -898,7 +904,7 @@ advtostr(int adv) *buf = '\0'; if (adv != NO_ADVICE) { - for (i = MADV_NORMAL; i <= MADV_ACCESS_MANY; i++) { + for (i = MADV_NORMAL; i <= MADV_PURGE; i++) { if (adv & (1 << i)) { /* * check if it's the first advice entry diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c index 6c884386b0..72876bfdb8 100644 --- a/usr/src/cmd/truss/print.c +++ b/usr/src/cmd/truss/print.c @@ -845,6 +845,7 @@ prt_mad(private_t *pri, int raw, long val) /* print madvise() argument */ case MADV_ACCESS_DEFAULT: s = "MADV_ACCESS_DEFAULT"; break; case MADV_ACCESS_LWP: s = "MADV_ACCESS_LWP"; break; case MADV_ACCESS_MANY: s = "MADV_ACCESS_MANY"; break; + case MADV_PURGE: s = "MADV_PURGE"; break; } } diff --git a/usr/src/man/man1/pmadvise.1 b/usr/src/man/man1/pmadvise.1 index 93d3b45576..919588a0c8 100644 --- a/usr/src/man/man1/pmadvise.1 +++ b/usr/src/man/man1/pmadvise.1 @@ -13,7 +13,6 @@ pmadvise \- applies advice about memory to a process .fi .SH DESCRIPTION -.sp .LP \fBpmadvise\fR applies advice about how memory is used in the specified process using \fBmadvise\fR(3C). @@ -24,7 +23,6 @@ specific instant in time. \fBpmadvise\fR differs from \fBmadv.so.1\fR(1) in that \fBmadv.so.1\fR(1) applies the advice throughout execution of the target program to all segments of a specified type. .SH OPTIONS -.sp .LP The following options are supported: .sp @@ -79,6 +77,7 @@ free access_lwp access_many access_default +purge .fi .in -2 .sp @@ -127,14 +126,13 @@ from the other advice within the same group: .in +2 .nf MADV_NORMAL, MADV_RANDOM, MADV_SEQUENTIAL -MADV_WILLNEED, MADV_DONTNEED, MADV_FREE +MADV_WILLNEED, MADV_DONTNEED, MADV_FREE, MADV_PURGE MADV_ACCESS_DEFAULT, MADV_ACCESS_LWP, MADV_ACCESS_MANY .fi .in -2 .sp .SH OPERANDS -.sp .LP The following operands are supported: .sp @@ -147,7 +145,6 @@ Process ID. .RE .SH EXAMPLES -.LP \fBExample 1 \fRApplying Advice to a Segment at Specified Address .sp .LP @@ -218,7 +215,6 @@ FFBFE000 8K rw--- [ stack ] <= access_default .sp .SH EXIT STATUS -.sp .LP The following exit values are returned: .sp @@ -240,7 +236,6 @@ An error occurred. .RE .SH FILES -.sp .ne 2 .na \fB\fB/proc/*\fR\fR @@ -259,7 +254,6 @@ Process files .RE .SH ATTRIBUTES -.sp .LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -278,7 +272,6 @@ Interface Stability See below. .LP The command syntax is Evolving. The output formats are Unstable. .SH SEE ALSO -.sp .LP \fBmadv.so.1\fR(1), \fBpmap\fR(1), \fBproc\fR(1), \fBmadvise\fR(3C), \fBattributes\fR(5) diff --git a/usr/src/man/man3c/madvise.3c b/usr/src/man/man3c/madvise.3c index dd2a72823b..c703409dc2 100644 --- a/usr/src/man/man3c/madvise.3c +++ b/usr/src/man/man3c/madvise.3c @@ -3,7 +3,7 @@ .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH MADVISE 3C "Feb 23, 2005" +.TH MADVISE 3C "Mar 28, 2016" .SH NAME madvise \- provide advice to VM system .SH SYNOPSIS @@ -16,13 +16,15 @@ madvise \- provide advice to VM system .fi .SH DESCRIPTION -.sp .LP The \fBmadvise()\fR function advises the kernel that a region of user mapped memory in the range [\fIaddr\fR, \fIaddr\fR + \fIlen\fR) will be accessed following a type of pattern. The kernel uses this information to optimize the procedure for manipulating and maintaining the resources associated with the -specified mapping range. +specified mapping range. In general (and true to the name of the function), +the advice is merely advisory, and the only user-visible ramifications +are in terms of performance, not semantics. Note that +\fBMADV_PURGE\fR is an exception to this; see below for details. .sp .LP Values for \fIadvice\fR are defined in <\fBsys/mman.h\fR> as: @@ -38,6 +40,7 @@ Values for \fIadvice\fR are defined in <\fBsys/mman.h\fR> as: #define MADV_ACCESS_DEFAULT 0x6 /* default access */ #define MADV_ACCESS_LWP 0x7 /* next LWP to access heavily */ #define MADV_ACCESS_MANY 0x8 /* many processes to access heavily */ +#define MADV_PURGE 0x9 /* contents will be purged */ .fi .in -2 @@ -99,6 +102,12 @@ kernel would need to read in from the file. .RS 23n Tell the kernel that the specified address range is no longer needed, so the system starts to free the resources associated with the address range. +While the semantics of \fBMADV_DONTNEED\fR are similar to other systems, +they differ significantly from the semantics on Linux, where +\fBMADV_DONTNEED\fR will actually synchronously purge the address range, +and subsequent faults will load from either backing store or be +zero-filled on demand. If the peculiar Linux semantics are +desired, \fBMADV_PURGE\fR should be used in lieu of \fBMADV_DONTNEED\fR. .RE .sp @@ -122,6 +131,26 @@ This value cannot be used on mappings that have underlying file objects. .sp .ne 2 .na +\fB\fBMADV_PURGE\fR\fR +.ad +.RS 23n +Tell the kernel to purge the specified address range. The mapping will +be retained, but the pages themselves will be destroyed; subsequent +faults on the range will result in the page being read from backing +store (if file-backed) or being zero-filled on demand (if anonymous). Note +that these semantics are generally inferior to \fBMADV_FREE\fR, which gives the +system more flexibility and results in better performance +when pages are, in fact, reused by the caller. Indeed, \fBMADV_PURGE\fR only +exists to provide an equivalent to the unfortunate +\fBMADV_DONTNEED\fR semantics found in Linux, upon which some programs +have (regrettably) come to depend. In de novo applications, +\fBMADV_PURGE\fR should be avoided; \fBMADV_FREE\fR should always be +preferred. +.RE + +.sp +.ne 2 +.na \fB\fBMADV_ACCESS_LWP\fR\fR .ad .RS 23n @@ -157,12 +186,10 @@ The \fBmadvise()\fR function should be used by applications with specific knowledge of their access patterns over a memory object, such as a mapped file, to increase system performance. .SH RETURN VALUES -.sp .LP Upon successful completion, \fBmadvise()\fR returns \fB0\fR; otherwise, it returns \fB\(mi1\fR and sets \fBerrno\fR to indicate the error. .SH ERRORS -.sp .ne 2 .na \fB\fBEAGAIN\fR\fR @@ -235,7 +262,6 @@ Stale \fBNFS\fR file handle. .RE .SH ATTRIBUTES -.sp .LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -253,6 +279,5 @@ MT-Level MT-Safe .TE .SH SEE ALSO -.sp .LP \fBmeminfo\fR(2), \fBmmap\fR(2), \fBsysconf\fR(3C), \fBattributes\fR(5) diff --git a/usr/src/uts/common/sys/mman.h b/usr/src/uts/common/sys/mman.h index 4976bf09ab..6ec5f4ff41 100644 --- a/usr/src/uts/common/sys/mman.h +++ b/usr/src/uts/common/sys/mman.h @@ -318,6 +318,7 @@ struct memcntl_mha32 { #define MADV_ACCESS_DEFAULT 6 /* default access */ #define MADV_ACCESS_LWP 7 /* next LWP to access heavily */ #define MADV_ACCESS_MANY 8 /* many processes to access heavily */ +#define MADV_PURGE 9 /* contents will be purged */ #endif /* (_POSIX_C_SOURCE <= 2) && !defined(_XPG4_2) ... */ diff --git a/usr/src/uts/common/syscall/memcntl.c b/usr/src/uts/common/syscall/memcntl.c index ae2a0cc45c..1ee4b6a395 100644 --- a/usr/src/uts/common/syscall/memcntl.c +++ b/usr/src/uts/common/syscall/memcntl.c @@ -347,7 +347,8 @@ memcntl(caddr_t addr, size_t len, int cmd, caddr_t arg, int attr, int mask) } return (error); case MC_ADVISE: - if ((uintptr_t)arg == MADV_FREE) { + if ((uintptr_t)arg == MADV_FREE || + (uintptr_t)arg == MADV_PURGE) { len &= PAGEMASK; } switch ((uintptr_t)arg) { diff --git a/usr/src/uts/common/vm/anon.h b/usr/src/uts/common/vm/anon.h index 2a39c896bc..1273b984fb 100644 --- a/usr/src/uts/common/vm/anon.h +++ b/usr/src/uts/common/vm/anon.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -390,7 +391,8 @@ extern int anon_fill_cow_holes(struct seg *, caddr_t, struct anon_hdr *, uint_t, struct vpage [], struct cred *); extern void anon_free(struct anon_hdr *, ulong_t, size_t); extern void anon_free_pages(struct anon_hdr *, ulong_t, size_t, uint_t); -extern void anon_disclaim(struct anon_map *, ulong_t, size_t); +extern int anon_disclaim(struct anon_map *, + ulong_t, size_t, uint_t, pgcnt_t *); extern int anon_getpage(struct anon **, uint_t *, struct page **, size_t, struct seg *, caddr_t, enum seg_rw, struct cred *); extern int swap_getconpage(struct vnode *, u_offset_t, size_t, diff --git a/usr/src/uts/common/vm/seg_spt.c b/usr/src/uts/common/vm/seg_spt.c index 1573e1726b..db23fc6c75 100644 --- a/usr/src/uts/common/vm/seg_spt.c +++ b/usr/src/uts/common/vm/seg_spt.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. */ #include <sys/param.h> @@ -2859,7 +2860,7 @@ segspt_shmadvise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); - if (behav == MADV_FREE) { + if (behav == MADV_FREE || behav == MADV_PURGE) { if ((sptd->spt_flags & SHM_PAGEABLE) == 0) return (0); @@ -2870,7 +2871,7 @@ segspt_shmadvise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) if ((ppa = sptd->spt_ppa) == NULL) { mutex_exit(&sptd->spt_lock); ANON_LOCK_ENTER(&->a_rwlock, RW_READER); - anon_disclaim(amp, pg_idx, len); + (void) anon_disclaim(amp, pg_idx, len, behav, NULL); ANON_LOCK_EXIT(&->a_rwlock); return (0); } @@ -2928,7 +2929,7 @@ segspt_shmadvise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) } ANON_LOCK_ENTER(&->a_rwlock, RW_READER); - anon_disclaim(amp, pg_idx, len); + (void) anon_disclaim(amp, pg_idx, len, behav, NULL); ANON_LOCK_EXIT(&->a_rwlock); } else if (lgrp_optimizations() && (behav == MADV_ACCESS_LWP || behav == MADV_ACCESS_MANY || behav == MADV_ACCESS_DEFAULT)) { diff --git a/usr/src/uts/common/vm/seg_vn.c b/usr/src/uts/common/vm/seg_vn.c index 0c0b1b2692..59141cd5ff 100644 --- a/usr/src/uts/common/vm/seg_vn.c +++ b/usr/src/uts/common/vm/seg_vn.c @@ -8043,7 +8043,7 @@ out: /* * Set advice from user for specified pages - * There are 9 types of advice: + * There are 10 types of advice: * MADV_NORMAL - Normal (default) behavior (whatever that is) * MADV_RANDOM - Random page references * do not allow readahead or 'klustering' @@ -8057,6 +8057,7 @@ out: * MADV_ACCESS_DEFAULT- Default access * MADV_ACCESS_LWP - Next LWP will access heavily * MADV_ACCESS_MANY- Many LWPs or processes will access heavily + * MADV_PURGE - Contents will be immediately discarded */ static int segvn_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) @@ -8075,10 +8076,10 @@ segvn_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as)); /* - * In case of MADV_FREE, we won't be modifying any segment private - * data structures; so, we only need to grab READER's lock + * In case of MADV_FREE/MADV_PURGE, we won't be modifying any segment + * private data structures; so, we only need to grab READER's lock */ - if (behav != MADV_FREE) { + if (behav != MADV_FREE && behav != MADV_PURGE) { SEGVN_LOCK_ENTER(seg->s_as, &svd->lock, RW_WRITER); if (svd->tr_state != SEGVN_TR_OFF) { SEGVN_LOCK_EXIT(seg->s_as, &svd->lock); @@ -8154,27 +8155,65 @@ segvn_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) amp = svd->amp; vp = svd->vp; - if (behav == MADV_FREE) { - /* - * MADV_FREE is not supported for segments with - * underlying object; if anonmap is NULL, anon slots - * are not yet populated and there is nothing for - * us to do. As MADV_FREE is advisory, we don't - * return error in either case. - */ - if (vp != NULL || amp == NULL) { + if (behav == MADV_FREE || behav == MADV_PURGE) { + pgcnt_t purged; + + if (behav == MADV_FREE && (vp != NULL || amp == NULL)) { + /* + * MADV_FREE is not supported for segments with an + * underlying object; if anonmap is NULL, anon slots + * are not yet populated and there is nothing for us + * to do. As MADV_FREE is advisory, we don't return an + * error in either case. + */ SEGVN_LOCK_EXIT(seg->s_as, &svd->lock); return (0); } + if (amp == NULL) { + /* + * If we're here with a NULL anonmap, it's because we + * are doing a MADV_PURGE. We have nothing to do, but + * because MADV_PURGE isn't merely advisory, we return + * an error in this case. + */ + SEGVN_LOCK_EXIT(seg->s_as, &svd->lock); + return (EBUSY); + } + segvn_purge(seg); page = seg_page(seg, addr); ANON_LOCK_ENTER(&->a_rwlock, RW_READER); - anon_disclaim(amp, svd->anon_index + page, len); + err = anon_disclaim(amp, + svd->anon_index + page, len, behav, &purged); + + if (purged != 0 && (svd->flags & MAP_NORESERVE)) { + /* + * If we purged pages on a MAP_NORESERVE mapping, we + * need to be sure to now unreserve our reserved swap. + * (We use the atomic operations to manipulate our + * segment and address space counters because we only + * have the corresponding locks held as reader, not + * writer.) + */ + ssize_t bytes = ptob(purged); + + anon_unresv_zone(bytes, seg->s_as->a_proc->p_zone); + atomic_add_long(&svd->swresv, -bytes); + atomic_add_long(&seg->s_as->a_resvsize, -bytes); + } + ANON_LOCK_EXIT(&->a_rwlock); SEGVN_LOCK_EXIT(seg->s_as, &svd->lock); - return (0); + + /* + * MADV_PURGE and MADV_FREE differ in their return semantics: + * because MADV_PURGE is designed to be bug-for-bug compatible + * with its clumsy Linux forebear, it will fail where MADV_FREE + * does not. + */ + return (behav == MADV_PURGE ? err : 0); } /* @@ -8279,6 +8318,7 @@ segvn_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) case MADV_WILLNEED: /* handled in memcntl */ case MADV_DONTNEED: /* handled in memcntl */ case MADV_FREE: /* handled above */ + case MADV_PURGE: /* handled above */ break; default: err = EINVAL; @@ -8514,6 +8554,7 @@ segvn_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav) case MADV_WILLNEED: /* handled in memcntl */ case MADV_DONTNEED: /* handled in memcntl */ case MADV_FREE: /* handled above */ + case MADV_PURGE: /* handled above */ break; default: err = EINVAL; diff --git a/usr/src/uts/common/vm/vm_anon.c b/usr/src/uts/common/vm/vm_anon.c index fdf9f7790c..86da4f51f9 100644 --- a/usr/src/uts/common/vm/vm_anon.c +++ b/usr/src/uts/common/vm/vm_anon.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -1660,8 +1661,9 @@ anon_free_pages( /* * Make anonymous pages discardable */ -void -anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) +int +anon_disclaim(struct anon_map *amp, ulong_t index, size_t size, + uint_t behav, pgcnt_t *purged) { spgcnt_t npages = btopr(size); struct anon *ap; @@ -1669,11 +1671,13 @@ anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) anoff_t off; page_t *pp, *root_pp; kmutex_t *ahm; - pgcnt_t pgcnt; + pgcnt_t pgcnt, npurged = 0; ulong_t old_idx, idx, i; struct anon_hdr *ahp = amp->ahp; anon_sync_obj_t cookie; + int err = 0; + VERIFY(behav == MADV_FREE || behav == MADV_PURGE); ASSERT(RW_READ_HELD(&->a_rwlock)); pgcnt = 1; for (; npages > 0; index = (pgcnt == 1) ? index + 1 : @@ -1721,6 +1725,7 @@ anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) page_unlock(pp); segadvstat.MADV_FREE_miss.value.ul++; anon_array_exit(&cookie); + err = EBUSY; continue; } @@ -1738,6 +1743,15 @@ anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) continue; } + if (behav == MADV_PURGE && pp->p_szc != 0) { + /* + * If we're purging and we have a large page, simplify + * things a bit by demoting ourselves into the base + * page case. + */ + (void) page_try_demote_pages(pp); + } + if (pp->p_szc == 0) { pgcnt = 1; @@ -1750,7 +1764,27 @@ anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) ap->an_pvp = NULL; ap->an_poff = 0; } - mutex_exit(ahm); + + if (behav == MADV_PURGE) { + /* + * If we're purging (instead of merely freeing), + * rip out this anon structure entirely to + * assure that any subsequent fault pulls from + * the backing vnode (if any). + */ + if (--ap->an_refcnt == 0) + anon_rmhash(ap); + + mutex_exit(ahm); + (void) anon_set_ptr(ahp, index, + NULL, ANON_SLEEP); + npurged++; + ANI_ADD(1); + kmem_cache_free(anon_cache, ap); + } else { + mutex_exit(ahm); + } + segadvstat.MADV_FREE_hit.value.ul++; /* @@ -1759,7 +1793,9 @@ anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) */ (void) hat_pageunload(pp, HAT_FORCE_PGUNLOAD); /*LINTED: constant in conditional context */ - VN_DISPOSE(pp, B_FREE, 0, kcred); + VN_DISPOSE(pp, + behav == MADV_FREE ? B_FREE : B_INVAL, 0, kcred); + anon_array_exit(&cookie); continue; } @@ -1771,6 +1807,7 @@ anon_disclaim(struct anon_map *amp, ulong_t index, size_t size) page_unlock(pp); segadvstat.MADV_FREE_miss.value.ul++; anon_array_exit(&cookie); + err = EBUSY; continue; } else { pgcnt = 1; @@ -1842,6 +1879,11 @@ skiplp: page_unlock(pp); anon_array_exit(&cookie); } + + if (purged != NULL) + *purged = npurged; + + return (err); } /* |