"TS" == Timo Sirainen <tss@iki.fi> writes:
TS> - create tmp file
TS> - link() to .lock file
TS> - unlink tmp file
TS> - write to .lock file
TS> - rename() to destination file
I think the problem here is that the rename will return EXDEV in a cross-directory situation if the file in question is also being held open. I think what is at the root of this behaviour is that AFS will buffer writes on the client which get flushed on close.
At least this is the impression I get from running some nasty perl (appended):
pod@not-invented-here$ (cd /tmp; perl ~/tmp/t.PL;) pod@not-invented-here$ (cd ~/afs/tmp; perl ~/tmp/t.PL;) T1: Invalid cross-device link at /home/pod/tmp/t.PL line 34. pod@not-invented-here$
-------------------- barf now -------------------- #! /usr/bin/perl use strict; use warnings; use POSIX qw(link unlink rename);
sub open_link_write_rename { my $s=shift; my $d=shift;
open(F, ">$s") or die; link($s, $s.".lock") or die; unlink($s) or die; print(F scalar localtime, "\n") or die; rename($s.".lock", $d) or die; }
sub open_link_write_close_rename { my $s=shift; my $d=shift;
open(F, ">$s") or die; link($s, $s.".lock") or die; unlink($s) or die; print(F scalar localtime, "\n") or die; close(F) or die; rename($s.".lock", $d) or die; }
mkdir "a" and mkdir "b" or die;
eval { open_link_write_rename("a/foo", "b/foo"); }; warn "T1: $!" if $@; close(F) or warn "$!"; map {unlink $_} "a/foo", "a/foo.lock", "b/foo";
eval { open_link_write_close_rename("a/foo", "b/foo"); }; warn "T2: $!" if $@; map {unlink $_} "a/foo", "a/foo.lock", "b/foo";
eval { open_link_write_rename("a/foo", "a/bar"); }; warn "T3: $!" if $@; close(F) or warn "$!"; map {unlink $_} "a/foo", "a/foo.lock", "a/bar";
eval { open_link_write_close_rename("a/foo", "a/bar"); }; warn "T4: $!" if $@; map {unlink $_} "a/foo", "a/foo.lock", "a/bar";
rmdir "a" and rmdir "b" or die;