Work around bug in CIFS and vboxsf file systems.

The bug was observed on Ubuntu operating inside a virtual machine,
editing files mounted via CIFS or vboxsf from the MS Windows 7 host.
The workaround introduces a race condition on non-buggy hosts,
but it's an unlikely race and anyway there's a nearly identical
nearby race that can't be fixed.
* fileio.c (valid_timestamp_file_system, timestamp_file_system):
New static vars.
(Fwrite_region): Test for file system time stamp bug.
(init_fileio): New function.
* lisp.h (init_fileio): Declare it.
* emacs.c (main): Call it.

Fixes: debbugs:13149
This commit is contained in:
Paul Eggert 2013-01-18 20:44:34 -08:00
parent fa705c9927
commit 9fe43ff672
4 changed files with 68 additions and 0 deletions

View file

@ -1,5 +1,18 @@
2013-01-19 Paul Eggert <eggert@cs.ucla.edu>
Work around bug in CIFS and vboxsf file systems (Bug#13149).
The bug was observed on Ubuntu operating inside a virtual machine,
editing files mounted via CIFS or vboxsf from the MS Windows 7 host.
The workaround introduces a race condition on non-buggy hosts,
but it's an unlikely race and anyway there's a nearly identical
nearby race that can't be fixed.
* fileio.c (valid_timestamp_file_system, timestamp_file_system):
New static vars.
(Fwrite_region): Test for file system time stamp bug.
(init_fileio): New function.
* lisp.h (init_fileio): Declare it.
* emacs.c (main): Call it.
* fileio.c (Finsert_file_contents): Simplify new diagnostic
and make it more consistent with other stat-failure diagnostics.

View file

@ -1317,6 +1317,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
}
init_callproc (); /* Must follow init_cmdargs but not init_sys_modes. */
init_fileio ();
init_lread ();
#ifdef WINDOWSNT
/* Check to see if Emacs has been installed correctly. */

View file

@ -103,6 +103,11 @@ static mode_t auto_save_mode_bits;
/* Set by auto_save_1 if an error occurred during the last auto-save. */
static bool auto_save_error_occurred;
/* If VALID_TIMESTAMP_FILE_SYSTEM, then TIMESTAMP_FILE_SYSTEM is the device
number of a file system where time stamps were observed to to work. */
static bool valid_timestamp_file_system;
static dev_t timestamp_file_system;
/* The symbol bound to coding-system-for-read when
insert-file-contents is called for recovering a file. This is not
an actual coding system name, but just an indicator to tell
@ -4971,6 +4976,48 @@ This calls `write-region-annotate-functions' at the start, and
/* Discard the unwind protect for close_file_unwind. */
specpdl_ptr = specpdl + count1;
/* Some file systems have a bug where st_mtime is not updated
properly after a write. For example, CIFS might not see the
st_mtime change until after the file is opened again.
Attempt to detect this file system bug, and update MODTIME to the
newer st_mtime if the bug appears to be present. This introduces
a race condition, so to avoid most instances of the race condition
on non-buggy file systems, skip this check if the most recently
encountered non-buggy file system was the current file system.
A race condition can occur if some other process modifies the
file between the fstat above and the fstat below, but the race is
unlikely and a similar race between the last write and the fstat
above cannot possibly be closed anyway. */
if (EMACS_TIME_VALID_P (modtime)
&& ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system))
{
int desc1 = emacs_open (fn, O_WRONLY, 0);
if (0 <= desc1)
{
struct stat st1;
if (fstat (desc1, &st1) == 0
&& st.st_dev == st1.st_dev && st.st_ino == st1.st_ino)
{
EMACS_TIME modtime1 = get_stat_mtime (&st1);
if (EMACS_TIME_EQ (modtime, modtime1)
&& st.st_size == st1.st_size)
{
timestamp_file_system = st.st_dev;
valid_timestamp_file_system = 1;
}
else
{
st.st_size = st1.st_size;
modtime = modtime1;
}
}
emacs_close (desc1);
}
}
/* Call write-region-post-annotation-function. */
while (CONSP (Vwrite_region_annotation_buffers))
{
@ -5767,6 +5814,12 @@ Fread_file_name (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filena
}
void
init_fileio (void)
{
valid_timestamp_file_system = 0;
}
void
syms_of_fileio (void)
{

View file

@ -3299,6 +3299,7 @@ extern _Noreturn void report_file_error (const char *, Lisp_Object);
extern bool internal_delete_file (Lisp_Object);
extern bool file_directory_p (const char *);
extern bool file_accessible_directory_p (const char *);
extern void init_fileio (void);
extern void syms_of_fileio (void);
extern Lisp_Object make_temp_name (Lisp_Object, bool);
extern Lisp_Object Qdelete_file;