Bug#447153: /usr/bin/scp: Fails to notice write errors

Colin Watson cjwatson at debian.org
Tue Nov 13 05:33:54 EST 2007


# For linux-cifs-client: this paragraph is for the Debian bug tracking
# system control robot. Please ignore it.
reassign 447153 linux-2.6
thanks

On Fri, Oct 19, 2007 at 12:03:01AM +0200, Michal Suchanek wrote:
> On 18/10/2007, Colin Watson <cjwatson at debian.org> wrote:
> > On Thu, Oct 18, 2007 at 03:32:27PM +0200, Hramrach wrote:
> > > When copying to a cifs share scp fails to notice write errors and
> > > happily continues copying when there is no disk space.
> > > Note that cifs probably only reports these errors on close(), not
> > > write().
> 
> cp reports the error:
> 
> cp firefox-2.0.0.4.tar.gz /mnt/
> cp: closing `/mnt/firefox-2.0.0.4.tar.gz': No space left on device
> 
> scp produces files of the same size with different content for small
> files and truncated (although not always zero) files for larger files,
> and notices no problem.

I've reproduced this locally and I believe it's a kernel bug. Here's an
strace excerpt:

[pid 25301] <... read resumed> "C", 1)  = 1
[pid 25301] read(0, "0", 1)             = 1
[pid 25301] read(0, "6", 1)             = 1
[pid 25301] read(0, "4", 1)             = 1
[pid 25301] read(0, "4", 1)             = 1
[pid 25301] read(0, " ", 1)             = 1
[pid 25301] read(0, "1", 1)             = 1
[pid 25301] read(0, "4", 1)             = 1
[pid 25301] read(0, "1", 1)             = 1
[pid 25301] read(0, " ", 1)             = 1
[pid 25301] read(0, "t", 1)             = 1
[pid 25301] read(0, ".", 1)             = 1
[pid 25301] read(0, "p", 1)             = 1
[pid 25301] read(0, "y", 1)             = 1
[pid 25301] read(0, "\n", 1)            = 1
[pid 25301] stat64("cifstest-mount//t.py", {st_mode=S_IFREG|0744, st_size=141, ...}) = 0
[pid 25301] open("cifstest-mount//t.py", O_WRONLY|O_CREAT|O_LARGEFILE, 0644) = 3
[pid 25301] write(1, "\0", 1)           = 1
[pid 25301] fstat64(3,  <unfinished ...>
[pid 25301] <... fstat64 resumed> {st_mode=S_IFREG|0744, st_size=141, ...}) = 0
[pid 25301] read(0,  <unfinished ...>
[pid 25301] <... read resumed> "import gtk\nimport locale\nlocale."..., 141) = 141
[pid 25301] write(3, "import gtk\nimport locale\nlocale."..., 141) = 141
[pid 25301] ftruncate64(3, 141)         = 0
[pid 25301] close(3)                    = 0
[pid 25301] read(0, "\0", 1)            = 1
[pid 25301] write(1, "\0", 1)           = 1
[pid 25301] read(0,  <unfinished ...>
[pid 25301] <... read resumed> "", 1)   = 0
[pid 25301] exit_group(0)               = ?

As you can see, it simply isn't getting any error back from the kernel.

Here's a reduced test program that exhibits the same problem as scp when
run with a filename on a CIFS mount of a full filesystem:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char **argv)
{
    int fd;
    if (argc <= 1) {
        fprintf(stderr, "Usage: %s filename\n", argv[0]);
        return 1;
    }
    fd = open(argv[1], O_CREAT | O_WRONLY, 0644);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    while (write(fd, "x", 1) < 1) {
        if (errno == EINTR)
            continue;
        perror("write");
        return 1;
    }
    if (ftruncate(fd, 1) < 0) {
        perror("ftruncate");
        return 1;
    }
    if (close(fd) < 0) {
        perror("close");
        return 1;
    }
    return 0;
}

No error, but you end up with a one-byte hole rather than either (a) "x"
or (b) an error. If you leave out the ftruncate, then close returns
ENOSPC. In either case, you get "CIFS VFS: Write2 ret -28, written = 0"
in syslog, but the error code doesn't make it to userspace if there's an
ftruncate between write and close. Is this a CIFS bug? I can't find
anything in the ftruncate documentation that suggests it is allowed to
do this; I think that if write claims to have written all the bytes then
userspace ought to be able to assume that ftruncate(fd, st_size) is a
no-op.


To openssh-unix-dev: does anyone think this is worth a workaround? The
ftruncate seems rather unnecessary if we've already written out the
required number of bytes anyway. I've attached a patch which only does
it if that isn't the case (although I have some trouble seeing how we
could ever get to the ftruncate without either writing the required
number of bytes or encountering a write error). If people think it's a
good idea I'll file it in Bugzilla.

Thanks,

-- 
Colin Watson                                       [cjwatson at debian.org]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: scp-ftruncate.patch
Type: text/x-diff
Size: 1443 bytes
Desc: not available
Url : http://lists.mindrot.org/pipermail/openssh-unix-dev/attachments/20071112/28e8e46a/attachment.bin 


More information about the openssh-unix-dev mailing list