summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2011-12-12 10:53:02 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-12-21 12:58:33 -0800
commit6415da6d18a55702cee3f01662733d0501635bbc (patch)
treee475b41774ea3f1310d0c28843bc6a26a6286946
parentd7587810a40aee32ec6bdfc2d4bce7ba9fd03c3e (diff)
ext4: fix ext4_end_io_dio() racing against fsync()
commit b5a7e97039a80fae673ccc115ce595d5b88fb4ee upstream. We need to make sure iocb->private is cleared *before* we put the io_end structure on i_completed_io_list. Otherwise fsync() could potentially run on another CPU and free the iocb structure out from under us. Reported-by: Kent Overstreet <koverstreet@google.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--fs/ext4/inode.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b644b9c164a7..00de8e8a133d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2630,10 +2630,11 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
iocb->private, io_end->inode->i_ino, iocb, offset,
size);
+ iocb->private = NULL;
+
/* if not aio dio with unwritten extents, just free io and return */
if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
ext4_free_io_end(io_end);
- iocb->private = NULL;
out:
if (is_async)
aio_complete(iocb, ret, 0);
@@ -2656,7 +2657,6 @@ out:
spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
/* queue the work to convert unwritten extents to written */
- iocb->private = NULL;
queue_work(wq, &io_end->work);
/* XXX: probably should move into the real I/O completion handler */