4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/sysmacros.h>
48 extern int gmatch(const char *s
, const char *p
);
50 #pragma init(__madvmain)
52 static FILE *errfp
= NULL
;
53 static const char *madvident
= "madv.so.1";
55 static int advice_all
= -1;
56 static int advice_heap
= -1;
57 static int advice_shm
= -1;
58 static int advice_ism
= -1;
59 static int advice_dism
= -1;
60 static int advice_map
= -1;
61 static int advice_mapshared
= -1;
62 static int advice_mapprivate
= -1;
63 static int advice_mapanon
= -1;
65 /* environment variables */
67 #define ENV_MADV "MADV"
68 #define ENV_MADVCFGFILE "MADVCFGFILE"
69 #define ENV_MADVERRFILE "MADVERRFILE"
73 #define DEF_MADVCFGFILE "/etc/madv.conf"
74 #define MAXLINELEN MAXPATHLEN + 64
75 #define CFGDELIMITER ':'
76 #define ARGDELIMITER ' '
79 * avoid malloc which causes certain applications to crash
81 static char lbuf
[MAXLINELEN
];
82 static char pbuf
[MAXPATHLEN
];
85 #define ENV_MADVDEBUG "MADVDEBUG"
86 #define MADVPRINT(x, y) if (madvdebug & x) (void) fprintf y;
88 static int madvdebug
= 0;
90 #define MADVPRINT(x, y)
96 static char *legal_optstr
[] = {
123 * These need to correspond to the order of the MADV_ flags in mman.h
124 * since the position infers the value for the flag.
126 static char *legal_madvice
[] = {
130 "willneed_NOT_SUPPORTED!",
131 "dontneed_NOT_SUPPORTED!",
132 "free_NOT_SUPPORTED!",
139 #if !defined(TEXT_DOMAIN)
140 #define TEXT_DOMAIN "SYS_TEST"
145 madverr(FILE *fp
, char *fmt
, ...)
150 (void) vfprintf(fp
, fmt
, ap
);
152 vsyslog(LOG_ERR
, fmt
, ap
);
157 * Return the pointer to the fully-resolved path name of the process's
158 * executable file obtained from the AT_SUN_EXECNAME aux vector entry.
163 const char *execname
= NULL
;
167 * The first time through, read the initial aux vector that was
168 * passed to the process at exec(2). Only do this once.
170 int fd
= open("/proc/self/auxv", O_RDONLY
);
173 while (read(fd
, &auxb
, sizeof (auxv_t
)) == sizeof (auxv_t
)) {
174 if (auxb
.a_type
== AT_SUN_EXECNAME
) {
175 execname
= auxb
.a_un
.a_ptr
;
185 * Return the process's current brk base and size.
188 mygetbrk(uintptr_t *base
, size_t *size
)
194 fd
= open("/proc/self/status", O_RDONLY
);
197 if (read(fd
, &ps
, sizeof (ps
)) == sizeof (ps
)) {
198 *base
= ps
.pr_brkbase
;
199 *size
= ps
.pr_brksize
;
212 * Check if exec name matches cfgname found in madv cfg file.
215 fnmatch(const char *execname
, char *cfgname
, char *cwd
)
220 /* cfgname should not have a '/' unless it begins with one */
221 if (cfgname
[0] == '/') {
223 * if execname does not begin with a '/', prepend the
226 if (execname
[0] != '/') {
227 ename
= (const char *)strcat(cwd
, execname
);
230 } else { /* simple cfg name */
231 if (ename
= strrchr(execname
, '/'))
232 /* execname is a path name - get the base name */
237 rc
= gmatch(ename
, cfgname
);
238 MADVPRINT(2, (stderr
, "gmatch: %s %s %s %d\n",
239 cfgname
, ename
, execname
, rc
));
245 * Check if string matches any of exec arguments.
256 fd
= open("/proc/self/psinfo", O_RDONLY
);
259 if (read(fd
, &pi
, sizeof (pi
)) == sizeof (pi
)) {
260 argv
= (char **)pi
.pr_argv
;
262 MADVPRINT(2, (stderr
, "argmatch: %s ", str
));
263 for (arg
= 1; arg
< pi
.pr_argc
; arg
++, argv
++) {
264 if (rc
= gmatch(*argv
, str
)) {
265 MADVPRINT(2, (stderr
, "%s ", *argv
));
269 MADVPRINT(2, (stderr
, "%d\n", rc
));
271 madverr(errfp
, dgettext(TEXT_DOMAIN
,
272 "%s: /proc/self/psinfo read failed [%s]\n"),
273 madvident
, strerror(errno
));
277 madverr(errfp
, dgettext(TEXT_DOMAIN
,
278 "%s: /proc/self/psinfo open failed [%s]\n"),
279 madvident
, strerror(errno
));
289 while ((c
= *str
) == '\n' || c
== ' ' || c
== '\t')
291 return (*str
== '\0');
295 strtoadv(char *advstr
)
297 char *dummy
, *locstr
= advstr
;
299 return (getsubopt(&locstr
, legal_madvice
, &dummy
));
303 advice_opts(char *optstr
, const char *execname
, char *cfgfile
, int lineno
)
309 while (*optstr
!= '\0') {
310 opt
= getsubopt(&optstr
, legal_optstr
, &value
);
312 madverr(errfp
, dgettext(TEXT_DOMAIN
,
313 "%s: invalid advice option (%s)"
314 " for %s - cfgfile: %s, line: %d\n"),
315 madvident
, value
, execname
, cfgfile
, lineno
);
318 madverr(errfp
, dgettext(TEXT_DOMAIN
,
319 "%s: option missing advice"
320 " for %s - cfgfile: %s, line: %d\n"),
321 madvident
, execname
, cfgfile
, lineno
);
324 advice
= strtoadv(value
);
326 madverr(errfp
, dgettext(TEXT_DOMAIN
,
327 "%s: invalid advice specified (%s)"
328 " for %s - cfgfile: %s, line: %d\n"),
329 madvident
, value
, execname
, cfgfile
, lineno
);
337 if (advice_heap
< 0) {
338 advice_heap
= advice
;
340 madverr(errfp
, dgettext(TEXT_DOMAIN
,
341 "%s: duplicate advice specified "
342 "(%s) for %s - cfgfile: %s, line: %d\n"),
343 madvident
, value
, execname
, cfgfile
,
348 if (advice_shm
< 0) {
351 madverr(errfp
, dgettext(TEXT_DOMAIN
,
352 "%s: duplicate advice specified "
353 "(%s) for %s - cfgfile: %s, line: %d\n"),
354 madvident
, value
, execname
, cfgfile
,
359 if (advice_ism
< 0) {
362 madverr(errfp
, dgettext(TEXT_DOMAIN
,
363 "%s: duplicate advice specified "
364 "(%s) for %s - cfgfile: %s, line: %d\n"),
365 madvident
, value
, execname
, cfgfile
,
370 if (advice_dism
< 0) {
371 advice_dism
= advice
;
373 madverr(errfp
, dgettext(TEXT_DOMAIN
,
374 "%s: duplicate advice specified "
375 "(%s) for %s - cfgfile: %s, line: %d\n"),
376 madvident
, value
, execname
, cfgfile
,
381 if (advice_map
< 0) {
384 madverr(errfp
, dgettext(TEXT_DOMAIN
,
385 "%s: duplicate advice specified "
386 "(%s) for %s - cfgfile: %s, line: %d\n"),
387 madvident
, value
, execname
, cfgfile
,
392 if (advice_mapshared
< 0) {
393 advice_mapshared
= advice
;
395 madverr(errfp
, dgettext(TEXT_DOMAIN
,
396 "%s: duplicate advice specified "
397 "(%s) for %s - cfgfile: %s, line: %d\n"),
398 madvident
, value
, execname
, cfgfile
,
403 if (advice_mapprivate
< 0) {
404 advice_mapprivate
= advice
;
406 madverr(errfp
, dgettext(TEXT_DOMAIN
,
407 "%s: duplicate advice specified "
408 "(%s) for %s - cfgfile: %s, line: %d\n"),
409 madvident
, value
, execname
, cfgfile
,
414 if (advice_mapanon
< 0) {
415 advice_mapanon
= advice
;
417 madverr(errfp
, dgettext(TEXT_DOMAIN
,
418 "%s: duplicate advice specified "
419 "(%s) for %s - cfgfile: %s, line: %d\n"),
420 madvident
, value
, execname
, cfgfile
,
425 madverr(errfp
, dgettext(TEXT_DOMAIN
,
426 "%s: invalid advice option (%s)"
427 " for %s - cfgfile: %s, line: %d\n"),
428 madvident
, value
, execname
, cfgfile
, lineno
);
437 char *cfgfile
, *errfile
;
439 const char *execname
;
442 char *tok
, *tokadv
, *tokarg
;
446 uintptr_t brkbase
, brkend
;
452 * If a private error file is indicated then set the locale
453 * for error messages for the duration of this routine.
454 * Error messages destined for syslog should not be translated
455 * and thus come from the default C locale.
457 if ((errfile
= getenv(ENV_MADVERRFILE
)) != NULL
) {
458 errfp
= fopen(errfile
, "aF");
460 locale
= setlocale(LC_MESSAGES
, "");
462 madverr(NULL
, dgettext(TEXT_DOMAIN
,
463 "%s: cannot open error file: %s [%s]\n"),
464 madvident
, errfile
, strerror(errno
));
469 if (str
= getenv(ENV_MADVDEBUG
))
470 madvdebug
= atoi(str
);
473 if (envadv
= getenv(ENV_MADV
)) {
474 if ((advice
= strtoadv(envadv
)) >= 0)
477 madverr(errfp
, dgettext(TEXT_DOMAIN
,
478 "%s: invalid advice specified: MADV=%s\n"),
483 * Open specified cfg file or default one.
485 if (cfgfile
= getenv(ENV_MADVCFGFILE
)) {
486 fp
= fopen(cfgfile
, "rF");
488 madverr(errfp
, dgettext(TEXT_DOMAIN
,
489 "%s: cannot open configuration file: %s [%s]\n"),
490 madvident
, cfgfile
, strerror(errno
));
493 cfgfile
= DEF_MADVCFGFILE
;
494 fp
= fopen(cfgfile
, "rF");
498 execname
= mygetexecname();
500 cwd
= getcwd(pbuf
, MAXPATHLEN
);
504 cwd
= strcat(cwd
, "/");
505 cwdlen
= strlen(cwd
);
507 while (fgets(lbuf
, MAXLINELEN
, fp
)) {
511 * Make sure line wasn't truncated.
513 if (strlen(lbuf
) >= MAXLINELEN
- 1) {
514 madverr(errfp
, dgettext(TEXT_DOMAIN
,
515 "%s: invalid entry, "
516 "line too long - cfgfile:"
518 madvident
, cfgfile
, lineno
);
526 * Get advice options.
527 * Parse right to left in case delimiter is in name.
529 if (!(tokadv
= strrchr(lbuf
, CFGDELIMITER
))) {
530 madverr(errfp
, dgettext(TEXT_DOMAIN
,
531 "%s: no delimiter specified - cfgfile:"
533 madvident
, cfgfile
, lineno
);
539 * Remove newline from end of advice options.
541 if (str
= strrchr(tokadv
, '\n'))
545 * Get optional argument string.
547 if (tokarg
= strrchr(lbuf
, ARGDELIMITER
)) {
555 if (!fnmatch(execname
, tok
, cwd
)) {
556 tokadv
= tokarg
= NULL
;
562 * Compare arguments if argument string specified.
567 tokadv
= tokarg
= NULL
;
573 * Parse advice options.
574 * If empty, any advice from ENV_MADV is reset.
579 advice_opts(tokadv
, execname
, cfgfile
, lineno
);
587 * Pagesize needed for proper aligning by brk interpose.
589 pagesize
= sysconf(_SC_PAGESIZE
);
592 * Apply global advice if set.
593 * Specific options in the cfgfile take precedence.
595 if (advice_all
>= 0) {
597 advice_heap
= advice_all
;
599 advice_shm
= advice_all
;
601 advice_map
= advice_all
;
604 MADVPRINT(2, (stderr
, "advice_all %d\n", advice_all
));
605 MADVPRINT(2, (stderr
, "advice_heap %d\n", advice_heap
));
606 MADVPRINT(2, (stderr
, "advice_shm %d\n", advice_shm
));
607 MADVPRINT(2, (stderr
, "advice_ism %d\n", advice_ism
));
608 MADVPRINT(2, (stderr
, "advice_dism %d\n", advice_dism
));
609 MADVPRINT(2, (stderr
, "advice_map %d\n", advice_map
));
610 MADVPRINT(2, (stderr
, "advice_mapshared %d\n", advice_mapshared
));
611 MADVPRINT(2, (stderr
, "advice_mapprivate %d\n", advice_mapprivate
));
612 MADVPRINT(2, (stderr
, "advice_mapanon %d\n", advice_mapanon
));
615 * If heap advice is specified, apply it to the existing heap.
616 * As the heap grows the kernel applies the advice automatically
617 * to new portions of the heap.
619 if (advice_heap
>= 0) {
620 if (rc
= mygetbrk(&brkbase
, &brksize
)) {
621 madverr(errfp
, dgettext(TEXT_DOMAIN
,
622 "%s: /proc/self/status read failed [%s]\n"),
623 madvident
, strerror(rc
));
625 MADVPRINT(4, (stderr
, "brkbase 0x%x brksize 0x%x\n",
628 * Align start address for memcntl and apply advice
629 * on full pages of heap. Create a page of heap if
630 * it does not already exist.
632 brkend
= roundup(brkbase
+brksize
, pagesize
);
633 brkbase
= roundup(brkbase
, pagesize
);
634 brksize
= brkend
- brkbase
;
635 if (brksize
< pagesize
) {
636 if (sbrk(pagesize
) == (void *)-1) {
637 madverr(errfp
, dgettext(TEXT_DOMAIN
,
638 "%s: sbrk failed [%s]\n"),
639 madvident
, strerror(errno
));
644 MADVPRINT(1, (stderr
, "heap advice: 0x%x 0x%x %d\n",
645 brkbase
, brksize
, advice_heap
));
646 if (memcntl((caddr_t
)brkbase
, brksize
, MC_ADVISE
,
647 (caddr_t
)(intptr_t)advice_heap
, 0, 0) < 0) {
648 madverr(errfp
, dgettext(TEXT_DOMAIN
,
649 "%s: memcntl() failed [%s]: heap advice\n"),
650 madvident
, strerror(errno
));
656 (void) fclose(errfp
);
657 (void) setlocale(LC_MESSAGES
, locale
);
659 /* close log file: no-op if nothing logged to syslog */
669 shmat(int shmid
, const void *shmaddr
, int shmflag
)
671 static caddr_t (*shmatfunc
)() = NULL
;
680 shmatfunc
= (caddr_t (*)()) dlsym(RTLD_NEXT
, "shmat");
684 result
= shmatfunc(shmid
, shmaddr
, shmflag
);
687 * Options ism, dism take precedence over option shm.
689 if (advice_ism
>= 0 && (shmflag
& SHM_SHARE_MMU
)) {
691 } else if (advice_dism
>= 0 && (shmflag
& SHM_PAGEABLE
)) {
692 advice
= advice_dism
;
693 } else if (advice_shm
>= 0) {
698 * Apply advice if specified and shmat succeeded.
700 if (advice
>= 0 && result
!= (void *)-1) {
702 /* First determine segment size */
703 rc
= shmctl(shmid
, IPC_STAT
, &mds
);
704 MADVPRINT(4, (stderr
, "shmctl rc %d errno %d\n", rc
, errno
));
705 rc
= memcntl(result
, mds
.shm_segsz
, MC_ADVISE
,
706 (caddr_t
)(intptr_t)advice
, 0, 0);
707 MADVPRINT(1, (stderr
,
708 "shmat advice: 0x%x 0x%x %d, rc %d errno %d\n",
709 result
, mds
.shm_segsz
, advice
, rc
, errno
));
711 /* First determine segment size */
712 (void) shmctl(shmid
, IPC_STAT
, &mds
);
713 (void) memcntl(result
, mds
.shm_segsz
, MC_ADVISE
,
714 (caddr_t
)(intptr_t)advice
, 0, 0);
726 mmap(void *addr
, size_t len
, int prot
, int flags
, int fd
, off_t pos
)
728 static void *(*mmapfunc
)();
733 mmapfunc
= dlsym(RTLD_NEXT
, "mmap");
737 result
= mmapfunc(addr
, len
, prot
, flags
, fd
, pos
);
740 * Option mapanon has highest precedence while option map
741 * has lowest precedence.
743 if (advice_mapanon
>= 0 && (flags
& MAP_ANON
)) {
744 advice
= advice_mapanon
;
745 } else if (advice_mapshared
>= 0 && (flags
& MAP_SHARED
)) {
746 advice
= advice_mapshared
;
747 } else if (advice_mapprivate
>= 0 && (flags
& MAP_PRIVATE
)) {
748 advice
= advice_mapprivate
;
749 } else if (advice_map
>= 0) {
754 * Apply advice if specified and mmap succeeded.
756 if (advice
>= 0 && result
!= MAP_FAILED
) {
760 rc
= memcntl(result
, len
, MC_ADVISE
,
761 (caddr_t
)(intptr_t)advice
, 0, 0);
762 MADVPRINT(1, (stderr
,
763 "mmap advice: %p 0x%x %d, rc %d errno %d\n",
764 result
, len
, advice
, rc
, errno
));
766 (void) memcntl(result
, len
, MC_ADVISE
,
767 (caddr_t
)(intptr_t)advice
, 0, 0);
779 mmap(void *addr
, size_t len
, int prot
, int flags
, int fd
, off64_t pos
)
781 static void *(*mmap64func
)();
786 mmap64func
= dlsym(RTLD_NEXT
, "mmap64");
790 result
= mmap64func(addr
, len
, prot
, flags
, fd
, pos
);
793 * Option mapanon has highest precedence while option map
794 * has lowest precedence.
796 if (advice_mapanon
>= 0 && (flags
& MAP_ANON
)) {
797 advice
= advice_mapanon
;
798 } else if (advice_mapshared
>= 0 && (flags
& MAP_SHARED
)) {
799 advice
= advice_mapshared
;
800 } else if (advice_mapprivate
>= 0 && (flags
& MAP_PRIVATE
)) {
801 advice
= advice_mapprivate
;
802 } else if (advice_map
>= 0) {
807 * Apply advice if specified and mmap succeeded.
809 if (advice
>= 0 && result
!= MAP_FAILED
) {
813 rc
= memcntl(result
, len
, MC_ADVISE
, (caddr_t
)advice
, 0, 0);
814 MADVPRINT(1, (stderr
,
815 "mmap64 advice: %p 0x%x %d, rc %d errno %d\n",
816 result
, len
, advice
, rc
, errno
));
818 (void) memcntl(result
, len
, MC_ADVISE
, (caddr_t
)advice
, 0, 0);