Commit edafeee3 authored by Stephen C. Tweedie's avatar Stephen C. Tweedie Committed by Linus Torvalds

[PATCH] ext3 directio block leak fix

The orphan list holds inodes that need to be truncated on recovery.  In the
O_DIRECT case, it's used if we extend the inode --- the truncate on recovery
means we'll recover the newly-allocated disk blocks if we crash after the IO
starts but before i_size is updated on disk.

Now, the orphan list is *also* used to delete inodes that are unlinked but
still-open.  Those get truncated but also deleted on recovery.

The orphan list is held both in memory and on disk.  So the rules are that the
inode can't be reclaimed while on the orphan list.  There are only two cases
--- either the inode is actively being written(O_DIRECT) or truncated (in
which case the inode is by definition not going to be reused), or it's
unlinked but still open (again, non-reclaimable).

But in the case where you're truncating or write(O_DIRECT)ing a file that is
*ALSO* unlinked, there's a problem --- the final unlink would put the inode on
the orphan list, but the write/truncate would try to add/remove it.  End
result is that the inode disappears from the orphan list while it's still
unlinked-but-in-use.

That's just a leak-on-crash, it's not going to be detectable in normal use. 
But it's still a bug, and the way we fix it is for direct-IO and truncate not
to do the ext3_orphan_del if the file is unlinked (ie.  i_nlink==0).
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4003261d
......@@ -1589,7 +1589,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
if (handle) {
int err;
if (orphan)
if (orphan && inode->i_nlink)
ext3_orphan_del(handle, inode);
if (orphan && ret > 0) {
loff_t end = offset + ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment