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.
26 #pragma ident "%Z%%M% %I% %E% SMI"
37 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/sysmacros.h>
50 extern int gmatch(const char *s
, const char *p
);
52 #pragma init(__madvmain)
54 static FILE *errfp
= NULL
;
55 static const char *madvident
= "madv.so.1";
57 static int advice_all
= -1;
58 static int advice_heap
= -1;
59 static int advice_shm
= -1;
60 static int advice_ism
= -1;
61 static int advice_dism
= -1;
62 static int advice_map
= -1;
63 static int advice_mapshared
= -1;
64 static int advice_mapprivate
= -1;
65 static int advice_mapanon
= -1;
67 /* environment variables */
69 #define ENV_MADV "MADV"
70 #define ENV_MADVCFGFILE "MADVCFGFILE"
71 #define ENV_MADVERRFILE "MADVERRFILE"
75 #define DEF_MADVCFGFILE "/etc/madv.conf"
76 #define MAXLINELEN MAXPATHLEN + 64
77 #define CFGDELIMITER ':'
78 #define ARGDELIMITER ' '
81 * avoid malloc which causes certain applications to crash
83 static char lbuf
[MAXLINELEN
];
84 static char pbuf
[MAXPATHLEN
];
87 #define ENV_MADVDEBUG "MADVDEBUG"
88 #define MADVPRINT(x, y) if (madvdebug & x) (void) fprintf y;
90 static int madvdebug
= 0;
92 #define MADVPRINT(x, y)
98 static char *legal_optstr
[] = {
125 * These need to correspond to the order of the MADV_ flags in mman.h
126 * since the position infers the value for the flag.
128 static char *legal_madvice
[] = {
132 "willneed_NOT_SUPPORTED!",
133 "dontneed_NOT_SUPPORTED!",
134 "free_NOT_SUPPORTED!",
141 #if !defined(TEXT_DOMAIN)
142 #define TEXT_DOMAIN "SYS_TEST"
147 madverr(FILE *fp
, char *fmt
, ...)
152 (void) vfprintf(fp
, fmt
, ap
);
154 vsyslog(LOG_ERR
, fmt
, ap
);
159 * Return the pointer to the fully-resolved path name of the process's
160 * executable file obtained from the AT_SUN_EXECNAME aux vector entry.
165 const char *execname
= NULL
;
169 * The first time through, read the initial aux vector that was
170 * passed to the process at exec(2). Only do this once.
172 int fd
= open("/proc/self/auxv", O_RDONLY
);
175 while (read(fd
, &auxb
, sizeof (auxv_t
)) == sizeof (auxv_t
)) {
176 if (auxb
.a_type
== AT_SUN_EXECNAME
) {
177 execname
= auxb
.a_un
.a_ptr
;
187 * Return the process's current brk base and size.
190 mygetbrk(uintptr_t *base
, size_t *size
)
196 fd
= open("/proc/self/status", O_RDONLY
);
199 if (read(fd
, &ps
, sizeof (ps
)) == sizeof (ps
)) {
200 *base
= ps
.pr_brkbase
;
201 *size
= ps
.pr_brksize
;
214 * Check if exec name matches cfgname found in madv cfg file.
217 fnmatch(const char *execname
, char *cfgname
, char *cwd
)
222 /* cfgname should not have a '/' unless it begins with one */
223 if (cfgname
[0] == '/') {
225 * if execname does not begin with a '/', prepend the
228 if (execname
[0] != '/') {
229 ename
= (const char *)strcat(cwd
, execname
);
232 } else { /* simple cfg name */
233 if (ename
= strrchr(execname
, '/'))
234 /* execname is a path name - get the base name */
239 rc
= gmatch(ename
, cfgname
);
240 MADVPRINT(2, (stderr
, "gmatch: %s %s %s %d\n",
241 cfgname
, ename
, execname
, rc
));
247 * Check if string matches any of exec arguments.
258 fd
= open("/proc/self/psinfo", O_RDONLY
);
261 if (read(fd
, &pi
, sizeof (pi
)) == sizeof (pi
)) {
262 argv
= (char **)pi
.pr_argv
;
264 MADVPRINT(2, (stderr
, "argmatch: %s ", str
));
265 for (arg
= 1; arg
< pi
.pr_argc
; arg
++, argv
++) {
266 if (rc
= gmatch(*argv
, str
)) {
267 MADVPRINT(2, (stderr
, "%s ", *argv
));
271 MADVPRINT(2, (stderr
, "%d\n", rc
));
273 madverr(errfp
, dgettext(TEXT_DOMAIN
,
274 "%s: /proc/self/psinfo read failed [%s]\n"),
275 madvident
, strerror(errno
));
279 madverr(errfp
, dgettext(TEXT_DOMAIN
,
280 "%s: /proc/self/psinfo open failed [%s]\n"),
281 madvident
, strerror(errno
));
291 while ((c
= *str
) == '\n' || c
== ' ' || c
== '\t')
293 return (*str
== '\0');
297 strtoadv(char *advstr
)
299 char *dummy
, *locstr
= advstr
;
301 return (getsubopt(&locstr
, legal_madvice
, &dummy
));
305 advice_opts(char *optstr
, const char *execname
, char *cfgfile
, int lineno
)
311 while (*optstr
!= '\0') {
312 opt
= getsubopt(&optstr
, legal_optstr
, &value
);
314 madverr(errfp
, dgettext(TEXT_DOMAIN
,
315 "%s: invalid advice option (%s)"
316 " for %s - cfgfile: %s, line: %d\n"),
317 madvident
, value
, execname
, cfgfile
, lineno
);
320 madverr(errfp
, dgettext(TEXT_DOMAIN
,
321 "%s: option missing advice"
322 " for %s - cfgfile: %s, line: %d\n"),
323 madvident
, execname
, cfgfile
, lineno
);
326 advice
= strtoadv(value
);
328 madverr(errfp
, dgettext(TEXT_DOMAIN
,
329 "%s: invalid advice specified (%s)"
330 " for %s - cfgfile: %s, line: %d\n"),
331 madvident
, value
, execname
, cfgfile
, lineno
);
339 if (advice_heap
< 0) {
340 advice_heap
= advice
;
342 madverr(errfp
, dgettext(TEXT_DOMAIN
,
343 "%s: duplicate advice specified "
344 "(%s) for %s - cfgfile: %s, line: %d\n"),
345 madvident
, value
, execname
, cfgfile
,
350 if (advice_shm
< 0) {
353 madverr(errfp
, dgettext(TEXT_DOMAIN
,
354 "%s: duplicate advice specified "
355 "(%s) for %s - cfgfile: %s, line: %d\n"),
356 madvident
, value
, execname
, cfgfile
,
361 if (advice_ism
< 0) {
364 madverr(errfp
, dgettext(TEXT_DOMAIN
,
365 "%s: duplicate advice specified "
366 "(%s) for %s - cfgfile: %s, line: %d\n"),
367 madvident
, value
, execname
, cfgfile
,
372 if (advice_dism
< 0) {
373 advice_dism
= advice
;
375 madverr(errfp
, dgettext(TEXT_DOMAIN
,
376 "%s: duplicate advice specified "
377 "(%s) for %s - cfgfile: %s, line: %d\n"),
378 madvident
, value
, execname
, cfgfile
,
383 if (advice_map
< 0) {
386 madverr(errfp
, dgettext(TEXT_DOMAIN
,
387 "%s: duplicate advice specified "
388 "(%s) for %s - cfgfile: %s, line: %d\n"),
389 madvident
, value
, execname
, cfgfile
,
394 if (advice_mapshared
< 0) {
395 advice_mapshared
= advice
;
397 madverr(errfp
, dgettext(TEXT_DOMAIN
,
398 "%s: duplicate advice specified "
399 "(%s) for %s - cfgfile: %s, line: %d\n"),
400 madvident
, value
, execname
, cfgfile
,
405 if (advice_mapprivate
< 0) {
406 advice_mapprivate
= advice
;
408 madverr(errfp
, dgettext(TEXT_DOMAIN
,
409 "%s: duplicate advice specified "
410 "(%s) for %s - cfgfile: %s, line: %d\n"),
411 madvident
, value
, execname
, cfgfile
,
416 if (advice_mapanon
< 0) {
417 advice_mapanon
= advice
;
419 madverr(errfp
, dgettext(TEXT_DOMAIN
,
420 "%s: duplicate advice specified "
421 "(%s) for %s - cfgfile: %s, line: %d\n"),
422 madvident
, value
, execname
, cfgfile
,
427 madverr(errfp
, dgettext(TEXT_DOMAIN
,
428 "%s: invalid advice option (%s)"
429 " for %s - cfgfile: %s, line: %d\n"),
430 madvident
, value
, execname
, cfgfile
, lineno
);
439 char *cfgfile
, *errfile
;
441 const char *execname
;
444 char *tok
, *tokadv
, *tokarg
;
448 uintptr_t brkbase
, brkend
;
454 * If a private error file is indicated then set the locale
455 * for error messages for the duration of this routine.
456 * Error messages destined for syslog should not be translated
457 * and thus come from the default C locale.
459 if ((errfile
= getenv(ENV_MADVERRFILE
)) != NULL
) {
460 errfp
= fopen(errfile
, "aF");
462 locale
= setlocale(LC_MESSAGES
, "");
464 madverr(NULL
, dgettext(TEXT_DOMAIN
,
465 "%s: cannot open error file: %s [%s]\n"),
466 madvident
, errfile
, strerror(errno
));
471 if (str
= getenv(ENV_MADVDEBUG
))
472 madvdebug
= atoi(str
);
475 if (envadv
= getenv(ENV_MADV
)) {
476 if ((advice
= strtoadv(envadv
)) >= 0)
479 madverr(errfp
, dgettext(TEXT_DOMAIN
,
480 "%s: invalid advice specified: MADV=%s\n"),
485 * Open specified cfg file or default one.
487 if (cfgfile
= getenv(ENV_MADVCFGFILE
)) {
488 fp
= fopen(cfgfile
, "rF");
490 madverr(errfp
, dgettext(TEXT_DOMAIN
,
491 "%s: cannot open configuration file: %s [%s]\n"),
492 madvident
, cfgfile
, strerror(errno
));
495 cfgfile
= DEF_MADVCFGFILE
;
496 fp
= fopen(cfgfile
, "rF");
500 execname
= mygetexecname();
502 cwd
= getcwd(pbuf
, MAXPATHLEN
);
506 cwd
= strcat(cwd
, "/");
507 cwdlen
= strlen(cwd
);
509 while (fgets(lbuf
, MAXLINELEN
, fp
)) {
513 * Make sure line wasn't truncated.
515 if (strlen(lbuf
) >= MAXLINELEN
- 1) {
516 madverr(errfp
, dgettext(TEXT_DOMAIN
,
517 "%s: invalid entry, "
518 "line too long - cfgfile:"
520 madvident
, cfgfile
, lineno
);
528 * Get advice options.
529 * Parse right to left in case delimiter is in name.
531 if (!(tokadv
= strrchr(lbuf
, CFGDELIMITER
))) {
532 madverr(errfp
, dgettext(TEXT_DOMAIN
,
533 "%s: no delimiter specified - cfgfile:"
535 madvident
, cfgfile
, lineno
);
541 * Remove newline from end of advice options.
543 if (str
= strrchr(tokadv
, '\n'))
547 * Get optional argument string.
549 if (tokarg
= strrchr(lbuf
, ARGDELIMITER
)) {
557 if (!fnmatch(execname
, tok
, cwd
)) {
558 tokadv
= tokarg
= NULL
;
564 * Compare arguments if argument string specified.
569 tokadv
= tokarg
= NULL
;
575 * Parse advice options.
576 * If empty, any advice from ENV_MADV is reset.
581 advice_opts(tokadv
, execname
, cfgfile
, lineno
);
589 * Pagesize needed for proper aligning by brk interpose.
591 pagesize
= sysconf(_SC_PAGESIZE
);
594 * Apply global advice if set.
595 * Specific options in the cfgfile take precedence.
597 if (advice_all
>= 0) {
599 advice_heap
= advice_all
;
601 advice_shm
= advice_all
;
603 advice_map
= advice_all
;
606 MADVPRINT(2, (stderr
, "advice_all %d\n", advice_all
));
607 MADVPRINT(2, (stderr
, "advice_heap %d\n", advice_heap
));
608 MADVPRINT(2, (stderr
, "advice_shm %d\n", advice_shm
));
609 MADVPRINT(2, (stderr
, "advice_ism %d\n", advice_ism
));
610 MADVPRINT(2, (stderr
, "advice_dism %d\n", advice_dism
));
611 MADVPRINT(2, (stderr
, "advice_map %d\n", advice_map
));
612 MADVPRINT(2, (stderr
, "advice_mapshared %d\n", advice_mapshared
));
613 MADVPRINT(2, (stderr
, "advice_mapprivate %d\n", advice_mapprivate
));
614 MADVPRINT(2, (stderr
, "advice_mapanon %d\n", advice_mapanon
));
617 * If heap advice is specified, apply it to the existing heap.
618 * As the heap grows the kernel applies the advice automatically
619 * to new portions of the heap.
621 if (advice_heap
>= 0) {
622 if (rc
= mygetbrk(&brkbase
, &brksize
)) {
623 madverr(errfp
, dgettext(TEXT_DOMAIN
,
624 "%s: /proc/self/status read failed [%s]\n"),
625 madvident
, strerror(rc
));
627 MADVPRINT(4, (stderr
, "brkbase 0x%x brksize 0x%x\n",
630 * Align start address for memcntl and apply advice
631 * on full pages of heap. Create a page of heap if
632 * it does not already exist.
634 brkend
= roundup(brkbase
+brksize
, pagesize
);
635 brkbase
= roundup(brkbase
, pagesize
);
636 brksize
= brkend
- brkbase
;
637 if (brksize
< pagesize
) {
638 if (sbrk(pagesize
) == (void *)-1) {
639 madverr(errfp
, dgettext(TEXT_DOMAIN
,
640 "%s: sbrk failed [%s]\n"),
641 madvident
, strerror(errno
));
646 MADVPRINT(1, (stderr
, "heap advice: 0x%x 0x%x %d\n",
647 brkbase
, brksize
, advice_heap
));
648 if (memcntl((caddr_t
)brkbase
, brksize
, MC_ADVISE
,
649 (caddr_t
)(intptr_t)advice_heap
, 0, 0) < 0) {
650 madverr(errfp
, dgettext(TEXT_DOMAIN
,
651 "%s: memcntl() failed [%s]: heap advice\n"),
652 madvident
, strerror(errno
));
658 (void) fclose(errfp
);
659 (void) setlocale(LC_MESSAGES
, locale
);
661 /* close log file: no-op if nothing logged to syslog */
671 shmat(int shmid
, const void *shmaddr
, int shmflag
)
673 static caddr_t (*shmatfunc
)() = NULL
;
685 shmatfunc
= (caddr_t (*)()) dlsym(RTLD_NEXT
, "shmat");
689 result
= shmatfunc(shmid
, shmaddr
, shmflag
);
692 * Options ism, dism take precedence over option shm.
694 if (advice_ism
>= 0 && (shmflag
& SHM_SHARE_MMU
)) {
696 } else if (advice_dism
>= 0 && (shmflag
& SHM_PAGEABLE
)) {
697 advice
= advice_dism
;
698 } else if (advice_shm
>= 0) {
703 * Apply advice if specified and shmat succeeded.
705 if (advice
>= 0 && result
!= (void *)-1) {
706 /* First determine segment size */
707 rc
= shmctl(shmid
, IPC_STAT
, &mds
);
708 MADVPRINT(4, (stderr
, "shmctl rc %d errno %d\n",
711 rc
= memcntl(result
, mds
.shm_segsz
, MC_ADVISE
,
712 (caddr_t
)(intptr_t)advice
, 0, 0);
713 MADVPRINT(1, (stderr
,
714 "shmat advice: 0x%x 0x%x %d, rc %d errno %d\n",
715 result
, mds
.shm_segsz
, advice
, rc
, errno
));
725 mmap(caddr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t pos
)
727 static caddr_t (*mmapfunc
)() = NULL
;
738 mmapfunc
= (caddr_t (*)()) dlsym(RTLD_NEXT
, "mmap");
742 result
= mmapfunc(addr
, len
, prot
, flags
, fd
, pos
);
745 * Option mapanon has highest precedence while option map
746 * has lowest precedence.
748 if (advice_mapanon
>= 0 && (flags
& MAP_ANON
)) {
749 advice
= advice_mapanon
;
750 } else if (advice_mapshared
>= 0 && (flags
& MAP_SHARED
)) {
751 advice
= advice_mapshared
;
752 } else if (advice_mapprivate
>= 0 && (flags
& MAP_PRIVATE
)) {
753 advice
= advice_mapprivate
;
754 } else if (advice_map
>= 0) {
759 * Apply advice if specified and mmap succeeded.
761 if (advice
>= 0 && result
!= MAP_FAILED
) {
762 rc
= memcntl(result
, len
, MC_ADVISE
,
763 (caddr_t
)(intptr_t)advice
, 0, 0);
764 MADVPRINT(1, (stderr
,
765 "mmap advice: 0x%x 0x%x %d, rc %d errno %d\n",
766 result
, len
, advice
, rc
, errno
));
777 mmap64(caddr_t addr
, size_t len
, int prot
, int flags
, int fd
, off64_t pos
)
779 static caddr_t (*mmap64func
)();
790 mmap64func
= (caddr_t (*)()) dlsym(RTLD_NEXT
, "mmap64");
794 result
= mmap64func(addr
, len
, prot
, flags
, fd
, pos
);
797 * Option mapanon has highest precedence while option map
798 * has lowest precedence.
800 if (advice_mapanon
>= 0 && (flags
& MAP_ANON
)) {
801 advice
= advice_mapanon
;
802 } else if (advice_mapshared
>= 0 && (flags
& MAP_SHARED
)) {
803 advice
= advice_mapshared
;
804 } else if (advice_mapprivate
>= 0 && (flags
& MAP_PRIVATE
)) {
805 advice
= advice_mapprivate
;
806 } else if (advice_map
>= 0) {
811 * Apply advice if specified and mmap succeeded.
813 if (advice
>= 0 && result
!= MAP_FAILED
) {
814 rc
= memcntl(result
, len
, MC_ADVISE
, (caddr_t
)advice
, 0, 0);
815 MADVPRINT(1, (stderr
,
816 "mmap64 advice: 0x%x 0x%x %d, rc %d errno %d\n",
817 result
, len
, advice
, rc
, errno
));