diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/vm/page-types.c | 35 |
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 | ||
829 | static sigjmp_buf sigbus_jmp; | ||
830 | |||
831 | static void * volatile sigbus_addr; | ||
832 | |||
833 | static 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 | |||
841 | static struct sigaction sigbus_action = { | ||
842 | .sa_sigaction = sigbus_handler, | ||
843 | .sa_flags = SA_SIGINFO, | ||
844 | }; | ||
845 | |||
827 | static void walk_file(const char *name, const struct stat *st) | 846 | static 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 | } |
889 | got_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 | ||
930 | static void parse_file(const char *name) | 959 | static void parse_file(const char *name) |