The Samba-Bugzilla – Bug 4182
rename operations upon locked files "succeed" when they should fail
Last modified: 2009-07-26 08:23:26 UTC
Under FC4 and FC5, with samba-3.0.23c, a cifs-based mount point of a Win2K3 server fails to listen to errors from the SMB server regarding locking conditions during rename operations.
e.g. I opened a word document under XP, then under linux mounted the same Win2K3 server and try to copy a file on top of that word doc.
cp /tmp/file.txt filename.doc
cp: cannot create regular file `filename.doc': Text file busy
that is correct.
Then I tried renaming a file in the same directory onto the same file
mv file1.txt file.doc
No error - exit status zero. That shouldn't happen.
Running Ethereal shows the server reporting several errors during the move operation. It starts with a rename call - which triggers a "STATUS_OBJECT_NAME_COLLISION" error from the server. Then cifsfs attempts a "delete-and-create" attempt - both of which fail too with "STATUS_SHARING_VIOLATION" errors from the server. Then cifsfs returns success to the Linux OS...
I can get you ethereal traces if you want
I have reproduced this on 2.6.16 - will reboot to current cifs (2.6.19) and make sure it still fails.
A couple of other interesting things - it seems to fail as you expected with mv of local file going to remote mount. Also windows seems to return an illegally formatted smb (wrong length) on the cp case you mention (which causes i/o error instead of sharing violation due to this).
Actually it's got worse than I first reported.
I first noticed it with rsync. Let me explain:
I had a cifs-mounted server as the destination, and was mirroring files onto it
rsync -a /unix/dir/ /cifs/server/share/dirtree/dir
rsync copies files to be mirrored to /cifs/server/share/dirtree/dir/.TEMPNAME and then RENAMES them on top of the original - i.e. a remote-to-remote rename as you mention. Poor old rsync receives an "OK" from cifsfs for the rename and thinks everything's fine.
Anyway, the extra problem I have since discovered is that sometimes the rename actually succeeds in overwriting the file - except the remote file ends up zero-length!
As that actually means the Windows server has ignored it's own lock - you can't really say it's a cifsfs problem - but certainly catching this condition earlier so as not to expose that Microsoft bug would be a good thing too! :-)
Created attachment 2194 [details]
fix to report errors on retry of rename request
This returns the error that is occurring on the retry of the rename request (when we try rename-by-handle, after the rename by path failed). Could someone verify that this (rename over target file which is open) fails on Services for Unix (SFU) on Windows locally or over NET USEd drive (so we can see if cifs should be trying a third strategy to rename in this particular case). I expect that SFU also fails in the same case (returning equivalent of sharing violation)
I have compiled up a 2.6.18 kernel with your patch, and things have got weirder...
Now if I do a copy or rename of a file on the remote share on top of an open file in the same remote dir, I get an error (yay!). "text file busy" for copy command, "permission denied" for rename. This is good.
However... the copy command actually overwrites the file! I end up with a Zero-length file - even though Linux reported "text file busy"
So it seems you have totally fixed the rename bug - but I'm now mentioning a copy bug :-)
I have tried this on an unpatched CentOS4.4 (2.6.12 kernel) server and my FC5 (patched 2.6.18) workstation - and in both cases a copy command can trash the contents of a locked file - even though an error is reported.
Should this bug be reopened, or is this really a new bug?
Thanks for your efforts! The rename fix will mean rsync works correctly now - so I'm happy.
I am having trouble reproducing this (in part I think because the return code for sharing violation is not returned by XP in the same way that it used to be) What is the easiest way to get the target file open on windows (with deny write or deny all presumably). I have tried edlin (does not open exclusively unfortunately) and also tried "more" which seems to mmap it causing a different return code
Never mind - I have reproduced the problem now. Seems odd that Windows allows you to set a file to size zero when it is open deny write, and it is unfortunate that the setfilesize comes before the open on the Linux side (not sure yet if this is caused by cp or libc or ...)
This look nasty or impossible to fix without changing the Linux vfs (not just cifs - the cifs change would be trivial ...).
The issue is straightforward - Linux VFS (fs/namei.c namei_open) calls setattr first to set the file size to zero (which is allowed by Windows whether or not the file is open as long as ACLs permit writing attributes) - only after the setattr succeeds does open of the target get sent (which fails). This needs to be made an atomic operation - but it can't be without exporting namei_open as an inode operation.
Is this still an issue that needs to be addressed (after Steve's comment in #8)?
I haven't noticed the (rsync to CIFS mountpoint) problem in ages - so I assume it is fixed now
Closing case as FIXED based on last comment. Please reopen if it isn't.