Re: tree corrupted on disk quota full
- From
Linus Torvalds <torvalds@osdl.org>
- Date
- Jan 11, 2007, 19:19 UTC
- Message-ID
- <Pine.LNX.4.64.0701111109070.3594@woody.osdl.org>
- In-Reply-To
- <Pine.LNX.4.64.0701111023090.3594@woody.osdl.org>
On Thu, 11 Jan 2007, Linus Torvalds wrote:
> > That said, clearly something didn't check the error return of a write() > call. Some of that got fixed up recently, so it might even be fixed in > current git already.
I'm not convinced.
The "write_in_full()" logic is supposed to help people avoid problems, but it *still* returns a success for a partial write.
Example of extreme breakage:
static int write_buffer(int fd, const void *buf, size_t len)
{
ssize_t size;
size = write_in_full(fd, buf, len);
if (!size)
return error("file write: disk full");
if (size < 0)
return error("file write error (%s)", strerror(errno));
return 0;
}which is TOTAL GARBAGE, because the disk-full event might have happened in the middle of the write, so "write_in_full()" might have returned 4096, for example, even though the buffer length was much bigger.
I personally think write_in_full() is totally mis-designed. If you are ready to handle partial writes, you should use "xwrite()". If you're not ready to handle partial writes, you should either use "write_or_die()", _or_ you should expect a partial write to at least return an error code (which is how "write_buffer()" works).
But that's not how write_in_full() actually works. Write-in-full does not return an error for a partial write, it returns the partial size.
Which is idiotic. It makes the function pointless. Just use xwrite() for that.
I would suggest perhaps a patch like this.. And then you _really_ can just do
if (write_in_full(fd, buf, len) < 0)
die("Not going to work: %s", strerror(errno));and be happy.
Linus
---
diff --git a/write_or_die.c b/write_or_die.c index a119e1d..f95299a 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -37,15 +37,14 @@ int write_in_full(int fd, const void *buf, size_t count) { const char *p = buf; ssize_t total = 0; - ssize_t written = 0; while (count > 0) { - written = xwrite(fd, p, count); - if (written <= 0) { - if (total) - return total; - else - return written; + size_t written = xwrite(fd, p, count); + if (written < 0) + return -1; + if (!written) { + errno = ENOSPC; + return -1 } count -= written; p += written;