Re: bus error when disk is full, with mmap & sparse file

Richard Laager <[email protected]> Wed, 01 Feb 2012 23:35:16 -0600
Newsgroups gmane.comp.db.rrdtool.devel
Message-ID <1328160916.3572.5.camel__30311.9817785502$1328160962$gmane$org@watermelon.coderich.net>
I stumbled across this thread:
http://permalink.gmane.org/gmane.comp.db.rrdtool.devel/4102

I've attached a patch that uses fallocate(), which may address this
issue. Also, it should be faster than filling the file with zeros from
userspace and may also decrease file fragmentation. I've only lightly
tested the patch.

Sorry my reply isn't threaded properly. I couldn't find an mbox-format
archive to use for replying.

-- 
Richard

_______________________________________________
rrd-developers mailing list
[email protected]
https://lists.oetiker.ch/cgi-bin/listinfo/rrd-developers
rrdtool-fallocate.patch (text/x-patch, 3 KB)
Index: src/rrd_open.c
===================================================================
--- src/rrd_open.c	(revision 2268)
+++ src/rrd_open.c	(working copy)
@@ -15,6 +15,9 @@
 #include <sys/stat.h>
 #endif
 
+#ifdef HAVE_FALLOCATE
+#include <fcntl.h>
+#endif
 
 #ifdef HAVE_BROKEN_MS_ASYNC
 #include <sys/types.h>
@@ -104,7 +107,10 @@
 #ifdef HAVE_MMAP
     ssize_t   _page_size = sysconf(_SC_PAGESIZE);
     char     *data = MAP_FAILED;
+#ifdef HAVE_FALLOCATE
+    int       allocated = 0;
 #endif
+#endif
     off_t     offset = 0;
     struct stat statb;
     rrd_file_t *rrd_file = NULL;
@@ -221,13 +227,34 @@
     if (newfile_size == 0) {
         rrd_file->file_len = statb.st_size;
     } else {
+#ifdef HAVE_FALLOCATE
+        int err;
+#endif
         rrd_file->file_len = newfile_size;
-        lseek(rrd_simple_file->fd, newfile_size - 1, SEEK_SET);
-        if ( write(rrd_simple_file->fd, "\0", 1) == -1){    /* poke */
-            rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
-            goto out_close;
+#ifdef HAVE_FALLOCATE
+        err = fallocate(rrd_simple_file->fd, 0, 0, newfile_size);
+#ifdef HAVE_MMAP
+        if (err == 0) {
+            allocated = 1;
+        } else {
+#else
+        if (err == -1) {
+#endif
+            if (errno != EOPNOTSUPP) {
+                rrd_set_error("fallocate '%s': %s", file_name,
+                              rrd_strerror(errno));
+                goto out_close;
+            }
+#endif
+            lseek(rrd_simple_file->fd, newfile_size - 1, SEEK_SET);
+            if ( write(rrd_simple_file->fd, "\0", 1) == -1){    /* poke */
+                rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
+                goto out_close;
+            }
+            lseek(rrd_simple_file->fd, 0, SEEK_SET);
+#ifdef HAVE_FALLOCATE
         }
-        lseek(rrd_simple_file->fd, 0, SEEK_SET);
+#endif
     }
 #ifdef HAVE_POSIX_FADVISE
     /* In general we need no read-ahead when dealing with rrd_files.
@@ -254,7 +281,11 @@
 	 * mapping can also lead some bus error, so we use the old fashioned
 	 * write().
 	 */
+#ifdef HAVE_FALLOCATE
+    if (rdwr & RRD_CREAT && !allocated) {
+#else
     if (rdwr & RRD_CREAT) {
+#endif
 		char     buf[4096];
 		unsigned i;
 
@@ -263,7 +294,7 @@
         
 		for (i = 0; i < (newfile_size - 1) / sizeof buf; ++i)
 		{
-			if (write(rrd_simple_file->fd, buf, sizeof buf) == -1)
+		if (write(rrd_simple_file->fd, buf, sizeof buf) == -1)
 			{
 				rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
 				goto out_close;
Index: configure.ac
===================================================================
--- configure.ac	(revision 2268)
+++ configure.ac	(working copy)
@@ -225,6 +225,8 @@
 
 CONFIGURE_PART(Map/Fadvis/Madvise checking)
 
+AC_CHECK_FUNCS(fallocate)
+
 dnl Could use these to know if we need to provide a prototype
 dnl AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
signature.asc (application/pgp-signature, 198 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iEYEABECAAYFAk8qIIMACgkQbfU6uV4fG84zcQCg0uB03Xf82zyd2Br2OxB/sSlS
q8kAoOkssUjEvVdzOT8E2swfO4vG83sX
=GvGx
-----END PGP SIGNATURE-----