diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-12-30 20:57:53 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-01-05 01:40:51 +0100 |
commit | fa6ac76083b8ffc1309876459f54f9f0e2843731 (patch) | |
tree | 5169233d54825b07e63da5d11fbc3b4e248aa38b /src/test/test-sigbus.c | |
parent | update TODO (diff) | |
download | systemd-fa6ac76083b8ffc1309876459f54f9f0e2843731.tar.xz systemd-fa6ac76083b8ffc1309876459f54f9f0e2843731.zip |
journald: process SIGBUS for the memory maps we set up
Even though we use fallocate() it appears that file systems like btrfs
will trigger SIGBUS on certain low-disk-space situation. We should
handle that, hence catch the signal, add it to a list of invalidated
pages, and replace the page with an empty memory area. After each write
check if SIGBUS was triggered, and consider the write invalid if it was.
This should make journald a lot more robust with file systems where
fallocate() is not reliable, for example all CoW file systems
(btrfs...), where changing written data can fail with disk full errors.
https://bugzilla.redhat.com/show_bug.cgi?id=1045810
Diffstat (limited to 'src/test/test-sigbus.c')
-rw-r--r-- | src/test/test-sigbus.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c new file mode 100644 index 0000000000..39d0fec894 --- /dev/null +++ b/src/test/test-sigbus.c @@ -0,0 +1,62 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/mman.h> + +#include "util.h" +#include "sigbus.h" + +int main(int argc, char *argv[]) { + _cleanup_close_ int fd = -1; + char template[] = "/tmp/sigbus-test-XXXXXX"; + void *addr = NULL; + uint8_t *p; + + sigbus_install(); + + assert(sigbus_pop(&addr) == 0); + + assert_se((fd = mkostemp(template, O_RDWR|O_CREAT|O_EXCL)) >= 0); + assert_se(unlink(template) >= 0); + assert_se(fallocate(fd, 0, 0, page_size() * 8) >= 0); + + p = mmap(NULL, page_size() * 16, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + assert_se(p != MAP_FAILED); + + assert_se(sigbus_pop(&addr) == 0); + + p[0] = 0xFF; + assert_se(sigbus_pop(&addr) == 0); + + p[page_size()] = 0xFF; + assert_se(sigbus_pop(&addr) == 0); + + p[page_size()*8] = 0xFF; + p[page_size()*8+1] = 0xFF; + p[page_size()*10] = 0xFF; + assert_se(sigbus_pop(&addr) > 0); + assert_se(addr == p + page_size() * 8); + assert_se(sigbus_pop(&addr) > 0); + assert_se(addr == p + page_size() * 10); + assert_se(sigbus_pop(&addr) == 0); + + sigbus_reset(); +} |