[BusyBox 0002944]: vi truncates the file synchronously in file_write() but does write() asynchronously.

bugs at busybox.net bugs at busybox.net
Sat Apr 19 07:40:01 UTC 2008

A NOTE has been added to this issue. 
Reported By:                kulve
Assigned To:                BusyBox
Project:                    BusyBox
Issue ID:                   2944
Category:                   Other
Reproducibility:            always
Severity:                   minor
Priority:                   normal
Status:                     assigned
Date Submitted:             04-18-2008 11:13 PDT
Last Modified:              04-19-2008 00:40 PDT
Summary:                    vi truncates the file synchronously in file_write()
but does write() asynchronously.
Because the file is truncated to zero synchronously for in-place rewriting
and written asynchronously it's vulnarable to losing all data on power
loss. This is easily reproducable with e.g. UBIFS by editing the file,
exiting and then immediately powering the device off (yeah, I should have
run sync before just powering off).

The file_write() should probably be done in a way that would lose only the
changes, not the original file. With smaller files this could be achieved
with e.g. using mv. 

 vda - 04-18-08 14:42  
What do you mean "written asynchronously"?
It is written this way:

        fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0666);
        if (fd < 0)
                return -1;
        cnt = last - first + 1;
        charcnt = full_write(fd, first, cnt);
        if (charcnt == cnt) {
                // good write
                //file_modified = FALSE; // the file has not been
        } else {
                charcnt = 0;

How do you propose doing it instead? 

 kulve - 04-19-08 00:40  
The write doesn't force (O_SYNC) data to be written to disk but it is left
to cache waiting for the OS to write it to disk at some point. This is the
normal case when writing.

But because the O_TRUNC is synchronous operation on some filesystems, the
file is truncated immediately. I suggest that the open() and write() uses
the same method, either synchronous or not.

With smaller files the content could be first written to a temporary file,
then synced and then the temporary file could be renamed over the real one.
The rename on same filesystem is atomic. This way the file would always be
either the old one or the new one, corruption would not be possible.

With this method the temporary file could be left on the filesystem if the
power loss happens before the rename. And the method won't work with big
files and low free space: if you have 5M free and you try to edit 6M file,
you don't have space for the temporary file.

Maybe the file could be opened with O_SYNC when saving? This would slow
down the write phase compared to current situation but maybe in most use
cases in normal busybox environments this wouldn't be a problem. And the
user might even expect a slow write as he asked to write the file to the
disk. There would still be a small chance for data corruption if the power
loss happens during the write but at least the user wouldn't accidentally
power off too early like I did. 

Issue History 
Date Modified   Username       Field                    Change               
04-18-08 11:13  kulve          New Issue                                    
04-18-08 11:13  kulve          Status                   new => assigned     
04-18-08 11:13  kulve          Assigned To               => BusyBox         
04-18-08 14:42  vda            Note Added: 0006664                          
04-19-08 00:40  kulve          Note Added: 0006674                          

More information about the busybox-cvs mailing list