Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 Jan 2003 14:14:59 -0800
From:      David Schultz <dschultz@uclink.Berkeley.EDU>
To:        Matthew Dillon <dillon@apollo.backplane.com>
Cc:        Jan Srzednicki <winfried@student.agh.edu.pl>, current@FreeBSD.ORG
Subject:   Re: background fsck did not create lost+found
Message-ID:  <20030120221459.GA3668@HAL9000.homeunix.com>
In-Reply-To: <200301201911.h0KJBZ4g065531@apollo.backplane.com>
References:  <Pine.GSO.4.44.0301201630350.22474-100000@student.uci.agh.edu.pl> <20030120183442.GA2778@HAL9000.homeunix.com> <200301201911.h0KJBZ4g065531@apollo.backplane.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Thus spake Matthew Dillon <dillon@apollo.backplane.com>:
> :However, when you are saving a new version of an important file,
> :you need to be careful that the new version (and its directory
> :entry) hits the disk before the old one goes away.  I know that vi
> :saves files in a safe way, whereas ee and emacs do not.  (Emacs
> :introduces only a small race, though.)  Also, mv will DTRT only if
> :the source and destination files live on the same filesystem.
> :
> 
>     I think you have that reversed.  vi just overwrites the destination
>     file (O_CREAT|O_TRUNC, try ktrace'ing a vi session and you will see). 
>     I believe emacs defaults to a mode where it creates a new file and 
>     renames it over the original. 
> 
>     This means that there is a period of time where a crash may result in
>     the loss of the file if the vi session cannot be recovered (with vi -r)
>     after the fact.

vi writes and fsyncs a recovery file when it opens a file for
editing, and it fsyncs the real file before removing the recovery
file.  (I don't know how reliable vi's recovery mechanism is
because I don't use vi, but at least it's ensuring that the
recovery file is written to disk when it should be.)

In Emacs, if 'make-backup-files' is non-nil (the default), the
original file ${FILE} is renamed to ${FILE}~.  Then it writes out
and fsyncs a new file, which is perfectly safe.  If
'make-backup-files' is nil, emacs simply omits the renaming part,
unsafely overwriting the original file.  The behavior in the
latter case appears to be a bug, or at least an undocumented
feature.  Emacs even causes data loss in this case when the disk
fills up!  It needs to either do an fsync/rename or write and
fsync a backup file for the duration of the save.

Lastly, with ee, there's no backup file and no fsync.

Some ktrace snippets are below.


  3662 vi       CALL  open(0x808e260,0x2,0x180)
  3662 vi       NAMI  "/var/tmp/vi.recover/vi.HjDlgO"
  3662 vi       RET   open 4
...
  3662 vi       CALL  write(0x4,0x809a01c,0x400)
  3662 vi       GIO   fd 4 wrote 1024 bytes
       "[...]old contents[...]"
...
  3662 vi       CALL  fsync(0x4)
  3662 vi       RET   fsync 0
...
[I edit the file from "old contents" to "new contents"]
...
  3662 vi       CALL  open(0x8095140,0x601,0x1b6)
  3662 vi       NAMI  "foo"
  3662 vi       RET   open 7
...
  3662 vi       CALL  write(0x7,0x80bb000,0xd)
  3662 vi       GIO   fd 7 wrote 13 bytes
       "new contents
       "
  3662 vi       RET   write 13/0xd
...
  3662 vi       CALL  fsync(0x7)
  3662 vi       RET   fsync 0
  3662 vi       CALL  close(0x7)
  3662 vi       RET   close 0
...
  3662 vi       CALL  lseek(0x4,0,0x400,0,0)
  3662 vi       RET   lseek 1024/0x400
  3662 vi       CALL  write(0x4,0x809a01c,0x400)
  3662 vi       GIO   fd 4 wrote 1024 bytes
	"[...]new contents[...]"
...
  3662 vi       CALL  fsync(0x4)
  3662 vi       RET   fsync 0

[The following bit only happens if make-backup-files is non-nil]
  3799 emacs    CALL  rename(0x848c328,0x848fba8)
  3799 emacs    NAMI  "/home/test/foo"
  3799 emacs    NAMI  "/home/test/foo~"
  3799 emacs    RET   rename 0
...
[This part happens unconditionally]
  3799 emacs    CALL  open(0x848c328,0x601,0x1b6)
  3799 emacs    NAMI  "/home/test/foo"
  3799 emacs    RET   open 3
  3799 emacs    CALL  write(0x3,0xbfbfae24,0x3)
  3799 emacs    GIO   fd 3 wrote 3 bytes
       "new"
  3799 emacs    RET   write 3
  3799 emacs    CALL  write(0x3,0xbfbfae24,0x9)
  3799 emacs    GIO   fd 3 wrote 9 bytes
       " contents"
  3799 emacs    RET   write 9
  3799 emacs    CALL  fsync(0x3)
  3799 emacs    RET   fsync 0
  3799 emacs    CALL  close(0x3)
  3799 emacs    RET   close 0

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030120221459.GA3668>