aboutsummaryrefslogtreecommitdiffstats
path: root/tools/vm
diff options
context:
space:
mode:
authorKonstantin Khlebnikov <koct9i@gmail.com>2014-06-04 19:05:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-04 19:53:51 -0400
commit1d46598b7903cd5ec83c49adbd741f43bb0ffcdc (patch)
tree162df1711beca7f301a0c1d8b1967dde7012e72c /tools/vm
parentd27050641e9bc056446deb0814e7ba1aa7911f5a (diff)
tools/vm/page-types.c: catch sigbus if raced with truncate
Recently added page-cache dumping is known to be a little bit racy. But after race with truncate it just dies due to unhandled SIGBUS when it tries to poke pages beyond the new end of file. This patch adds handler for SIGBUS which skips the rest of the file. Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools/vm')
-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)