aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/vm/page-types.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index 05654f5e48d5..c4d6d2e20e0d 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -32,6 +32,8 @@
32#include <assert.h> 32#include <assert.h>
33#include <ftw.h> 33#include <ftw.h>
34#include <time.h> 34#include <time.h>
35#include <setjmp.h>
36#include <signal.h>
35#include <sys/types.h> 37#include <sys/types.h>
36#include <sys/errno.h> 38#include <sys/errno.h>
37#include <sys/fcntl.h> 39#include <sys/fcntl.h>
@@ -824,21 +826,38 @@ static void show_file(const char *name, const struct stat *st)
824 atime, now - st->st_atime); 826 atime, now - st->st_atime);
825} 827}
826 828
829static sigjmp_buf sigbus_jmp;
830
831static void * volatile sigbus_addr;
832
833static void sigbus_handler(int sig, siginfo_t *info, void *ucontex)
834{
835 (void)sig;
836 (void)ucontex;
837 sigbus_addr = info ? info->si_addr : NULL;
838 siglongjmp(sigbus_jmp, 1);
839}
840
841static struct sigaction sigbus_action = {
842 .sa_sigaction = sigbus_handler,
843 .sa_flags = SA_SIGINFO,
844};
845
827static void walk_file(const char *name, const struct stat *st) 846static void walk_file(const char *name, const struct stat *st)
828{ 847{
829 uint8_t vec[PAGEMAP_BATCH]; 848 uint8_t vec[PAGEMAP_BATCH];
830 uint64_t buf[PAGEMAP_BATCH], flags; 849 uint64_t buf[PAGEMAP_BATCH], flags;
831 unsigned long nr_pages, pfn, i; 850 unsigned long nr_pages, pfn, i;
851 off_t off, end = st->st_size;
832 int fd; 852 int fd;
833 off_t off;
834 ssize_t len; 853 ssize_t len;
835 void *ptr; 854 void *ptr;
836 int first = 1; 855 int first = 1;
837 856
838 fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW); 857 fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW);
839 858
840 for (off = 0; off < st->st_size; off += len) { 859 for (off = 0; off < end; off += len) {
841 nr_pages = (st->st_size - off + page_size - 1) / page_size; 860 nr_pages = (end - off + page_size - 1) / page_size;
842 if (nr_pages > PAGEMAP_BATCH) 861 if (nr_pages > PAGEMAP_BATCH)
843 nr_pages = PAGEMAP_BATCH; 862 nr_pages = PAGEMAP_BATCH;
844 len = nr_pages * page_size; 863 len = nr_pages * page_size;
@@ -855,11 +874,19 @@ static void walk_file(const char *name, const struct stat *st)
855 if (madvise(ptr, len, MADV_RANDOM)) 874 if (madvise(ptr, len, MADV_RANDOM))
856 fatal("madvice failed: %s", name); 875 fatal("madvice failed: %s", name);
857 876
877 if (sigsetjmp(sigbus_jmp, 1)) {
878 end = off + sigbus_addr ? sigbus_addr - ptr : 0;
879 fprintf(stderr, "got sigbus at offset %lld: %s\n",
880 (long long)end, name);
881 goto got_sigbus;
882 }
883
858 /* populate ptes */ 884 /* populate ptes */
859 for (i = 0; i < nr_pages ; i++) { 885 for (i = 0; i < nr_pages ; i++) {
860 if (vec[i] & 1) 886 if (vec[i] & 1)
861 (void)*(volatile int *)(ptr + i * page_size); 887 (void)*(volatile int *)(ptr + i * page_size);
862 } 888 }
889got_sigbus:
863 890
864 /* turn off harvesting reference bits */ 891 /* turn off harvesting reference bits */
865 if (madvise(ptr, len, MADV_SEQUENTIAL)) 892 if (madvise(ptr, len, MADV_SEQUENTIAL))
@@ -910,6 +937,7 @@ static void walk_page_cache(void)
910 937
911 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY); 938 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
912 pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY); 939 pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY);
940 sigaction(SIGBUS, &sigbus_action, NULL);
913 941
914 if (stat(opt_file, &st)) 942 if (stat(opt_file, &st))
915 fatal("stat failed: %s\n", opt_file); 943 fatal("stat failed: %s\n", opt_file);
@@ -925,6 +953,7 @@ static void walk_page_cache(void)
925 953
926 close(kpageflags_fd); 954 close(kpageflags_fd);
927 close(pagemap_fd); 955 close(pagemap_fd);
956 signal(SIGBUS, SIG_DFL);
928} 957}
929 958
930static void parse_file(const char *name) 959static void parse_file(const char *name)