summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2011-12-12 10:53:02 -0500
committerTheodore Ts'o <tytso@mit.edu>2011-12-12 10:53:02 -0500
commitb5a7e97039a80fae673ccc115ce595d5b88fb4ee (patch)
treeb8533e2cb3fc30da051487257cd24af6edeea83e /fs
parentdc47ce90c3a822cd7c9e9339fe4d5f61dcb26b50 (diff)
downloadlinux-3.10-b5a7e97039a80fae673ccc115ce595d5b88fb4ee.tar.gz
linux-3.10-b5a7e97039a80fae673ccc115ce595d5b88fb4ee.tar.bz2
linux-3.10-b5a7e97039a80fae673ccc115ce595d5b88fb4ee.zip
ext4: fix ext4_end_io_dio() racing against fsync()
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> Cc: stable@kernel.org
Diffstat (limited to 'fs')
-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 848f436df29..d2c86633811 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2781,10 +2781,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);
@@ -2807,7 +2808,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 */