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

Francois-Xavier Bourlet <[email protected]>
Newsgroups gmane.comp.db.rrdtool.devel
Message-ID <[email protected]>
Here's the patch.

It only modify the mmap part of rrd_open and so you need to HAVE_MMAP.

Before the patch, rrd_open open the file, mmap it, and then fill it
(and so force the allocation of the file space) with a memset.

If the filesystem get full before/during the memset, you're fine for a
bus error.

So this patch d fill up the file by consecutive writes before the
mmap. Write()s errors can be easily caught so now rdd_open return an
error when trying to fill the file.

Example when starting a collectd (using librrd) on a (too) small tmpfs:

before the patch:

Initialization complete, entering read-loop.
rrdtool plugin: Adjusting "RandomTimeout" to 0.000 seconds.
./test.sh: line 20:  6885 Bus error               (core dumped)
./build/src/collectd -C collectd.conf -f

After the patch:

Initialization complete, entering read-loop.
rrdtool plugin: Adjusting "RandomTimeout" to 0.000 seconds.
rrdtool plugin: rrd_create_r
(/home/bombela/dotcloud/collectd/rrd/bombela-laptop/lxc/lxc_containers.rrd)
failed: creating
'/home/bombela/dotcloud/collectd/rrd/bombela-laptop/lxc/lxc_containers.rrd':
No space left on device

let me know what do you think about it,
Regards,

On Tue, Apr 19, 2011 at 11:32 PM, Francois-Xavier Bourlet
<[email protected]> wrote:
> working on it
>
> On Mon, Apr 18, 2011 at 1:48 PM, Tobias Oetiker <[email protected]> wrote:
>> Today Francois-Xavier Bourlet wrote:
>>
>>> When I was speaking about a SIGBUS handler, I was not really thinking
>>> about something to recover from errors, but simply check if the SIGBUS
>>> signal have a file descriptor associated with, and so check the free
>>> space to print an hint to users. Like:
>>>
>>> Bus error (your disk seem full, the error could be a result of an
>>> impossibility to allocate disk space for a file)
>>>
>>> I believe that the strongest way seem to writes zeros before mapping
>>> the file, using plain old write()s, and so simply check write return
>>> code / errno and make rrd_open return nicely and error.
>>
>> fine with me too ... lets see the patch ...
>>
>> cheers
>> tobi
>>
>>>
>>> On Mon, Apr 18, 2011 at 12:01 AM, Tobias Oetiker <[email protected]> wrote:
>>> > Hi Francois,
>>> >
>>> > Yesterday Francois-Xavier Bourlet wrote:
>>> >
>>> >> Hi Tobi,
>>> >>
>>> >> Yes it happen at create time.
>>> >>
>>> >> Checking available free space before the creation process would lead
>>> >> to some race condition, because between the time you check the free
>>> >> space and the time you allocate it you can still have some others
>>> >> process/thread allocating it.
>>> >
>>> > yes ...
>>> >
>>> >> But it could be used in another way, by setting up an handler for bus
>>> >> error that check the free space and print a little hint message before
>>> >> exiting the application? The advantage would be zero overhead (until
>>> >> you crash... but do you really care at crash time ;) ) and no
>>> >> modification of the current rrd_open function. What do you think?
>>> >
>>> > having a handler for sigbus sounds like a sensible idea ...
>>> >
>>> > http://www.linuxprogrammingblog.com/code-examples/SIGBUS-handling
>>> >
>>> > as for early vfsstat this could save time for people who try to
>>> > create unreasonably large rrd files by alerting them before
>>> > gigabytes of 0s have been allocated ...
>>> >
>>> > cheers
>>> > tob
>>> >
>>> >> On Sun, Apr 17, 2011 at 10:07 PM, Tobias Oetiker <[email protected]> wrote:
>>> >> > Hi Francois,
>>> >> >
>>> >> > Yesterday Francois-Xavier Bourlet wrote:
>>> >> >
>>> >> >> Hello,
>>> >> >>
>>> >> >> On my system rrd_open use mmap and my system support sparse file.
>>> >> >> That's mean when my disk get full rdd_open can bus error. Here's the
>>> >> >> scenario in rrd_open:
>>> >> >>
>>> >> >> Disk really close to full, few kbytes free
>>> >> >> open file -> ok
>>> >> >> seek to end -1 -> ok
>>> >> >> write 1 -> ok
>>> >> >> the system will only write the last chunk of the file, every others
>>> >> >> will be allocated lazily later because of the sparse file feature.
>>> >> >> So we have a file bigger than the free space available on the system.
>>> >> >> Next attempt to write on this file, even without extending the size of
>>> >> >> it will fail with a disk full error.
>>> >> >>
>>> >> >> next rrd_open map the file and then
>>> >> >> memset to zero the whole file... leading to a buserror since the
>>> >> >> kernel can't write into the file because the filesystem is full.
>>> >> >
>>> >> > this happens at create time, right ?
>>> >> >
>>> >> >> In my case I just have to extend the disk space available and it's
>>> >> >> fine. But the problem is you don't have any clue that the bus error
>>> >> >> happen because you're disk is full, and I really wasted a lots of time
>>> >> >> before I thought simply checking the free space...
>>> >> >>
>>> >> >> I don't really now how to fix the code, maybe we can catch SIGBUS
>>> >> >> signals, and when discovering that the error is about a file mapping,
>>> >> >> provide an human readable message on terminal/log?
>>> >> >>
>>> >> >> Trying to recover from a bus error on file mapped memory seem to be
>>> >> >> another challenge...
>>> >> >>
>>> >> >> Or rather than memsetting the file to zero, we could simply write
>>> >> >> zeros in the file before mapping it, and so it would be easy to catch
>>> >> >> write error.
>>> >> >
>>> >> >> Let me know what do you think about it, I am available to patch rrd
>>> >> >> with the best proposed solution.
>>> >> >
>>> >> > how about a cal to statvfs before starting the whole creation
>>> >> > process ? (for win32 this would bprobably be GetDiskFreeSpaceEx)
>>> >> >
>>> >> > cheers
>>> >> > tobi
>>> >> >
>>> >> >
>>> >> >
>>> >> >>
>>> >> >> Regards,
>>> >> >>
>>> >> >
>>> >> > --
>>> >> > Tobi Oetiker, OETIKER+PARTNER AG, Aarweg 15 CH-4600 Olten, Switzerland
>>> >> > http://it.oetiker.ch [email protected] ++41 62 775 9902 / sb: -9900
>>> >> >
>>> >>
>>> >>
>>> >>
>>> >>
>>> >
>>> > --
>>> > Tobi Oetiker, OETIKER+PARTNER AG, Aarweg 15 CH-4600 Olten, Switzerland
>>> > http://it.oetiker.ch [email protected] ++41 62 775 9902 / sb: -9900
>>> >
>>>
>>>
>>>
>>>
>>
>> --
>> Tobi Oetiker, OETIKER+PARTNER AG, Aarweg 15 CH-4600 Olten, Switzerland
>> http://it.oetiker.ch [email protected] ++41 62 775 9902 / sb: -9900
>>
>
>
>
> --
> François-Xavier Bourlet
>
-- 
François-Xavier Bourlet
http://www.dotcloud.com/

_______________________________________________
rrd-developers mailing list
[email protected]
https://lists.oetiker.ch/cgi-bin/listinfo/rrd-developers
rrd_open_bus_error_when_disk_full_fix.diff (application/octet-stream, 1.4 KB)
Index: src/rrd_open.c
===================================================================
--- src/rrd_open.c	(revision 2180)
+++ src/rrd_open.c	(working copy)
@@ -248,6 +248,38 @@
 */
 
 #ifdef HAVE_MMAP
+	/* force allocating the file on the underlaying filesystem to prevent any
+	 * future bus error when the filesystem is full and attempting to write
+	 * trough the file mapping. Filling the file using memset on the file
+	 * mapping can also lead some bus error, so we use the old fashioned
+	 * write().
+	 */
+    if (rdwr & RRD_CREAT) {
+		char     buf[4096];
+		unsigned i;
+
+		memset(buf, DNAN, sizeof buf);
+		lseek(rrd_simple_file->fd, offset, SEEK_SET);
+        
+		for (i = 0; i < (newfile_size - 1) / sizeof buf; ++i)
+		{
+			if (write(rrd_simple_file->fd, buf, sizeof buf) == -1)
+			{
+				rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
+				goto out_close;
+			}
+		}
+		
+		if (write(rrd_simple_file->fd, buf,
+					(newfile_size - 1) % sizeof buf) == -1)
+		{
+			rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
+			goto out_close;
+		}
+
+		lseek(rrd_simple_file->fd, 0, SEEK_SET);
+    }
+
     data = mmap(0, rrd_file->file_len, 
         rrd_simple_file->mm_prot, rrd_simple_file->mm_flags,
         rrd_simple_file->fd, offset);
@@ -260,7 +292,6 @@
     }
     rrd_simple_file->file_start = data;
     if (rdwr & RRD_CREAT) {
-        memset(data, DNAN, newfile_size - 1);
         goto out_done;
     }
 #endif
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.