[Ocfs2-devel] [PATCH 9/9] ocfs2: Fix tiny race in unaligned aio+dio

Sunil Mushran sunil.mushran at oracle.com
Thu Mar 1 11:34:23 PST 2012


This patch fixes a tiny race in unaligned aio+dio that leads to a hang.

Commit a11f7e63c59810a81494d4c4b028af707d4c7ca4 serialized unaligned
aio+dio writes. However the serialize code in end_io() was not
differentiating between writes and reads and thus allowing reads to
interfere with the serialization accounting for writes. This patch
seperates the handler functions to avoid this issue.

Signed-off-by: Sunil Mushran <sunil.mushran at oracle.com>
---
 fs/ocfs2/aops.c |   44 ++++++++++++++++++++++++++++++++------------
 1 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 78b68af..3783ba3 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -558,20 +558,15 @@ bail:
 }
 
 /*
- * ocfs2_dio_end_io is called by the dio core when a dio is finished.  We're
- * particularly interested in the aio/dio case.  We use the rw_lock DLM lock
- * to protect io on one node from truncation on another.
+ * ocfs2_dio_end_io_[read|write] is called by the dio core when a dio is
+ * finished.  We're particularly interested in the aio/dio case.  We use
+ * the rw_lock DLM lock to protect io on one node from truncation on another.
  */
-static void ocfs2_dio_end_io(struct kiocb *iocb,
-			     loff_t offset,
-			     ssize_t bytes,
-			     void *private,
-			     int ret,
-			     bool is_async)
+static void ocfs2_dio_end_io(struct kiocb *iocb, loff_t offset, ssize_t bytes,
+			     void *private, int ret, bool is_async, int rw)
 {
 	struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
 	int level;
-	wait_queue_head_t *wq = ocfs2_ioend_wq(inode);
 
 	/* this io's submitter should not have unlocked this before we could */
 	BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
@@ -579,7 +574,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
 	if (ocfs2_iocb_is_sem_locked(iocb))
 		ocfs2_iocb_clear_sem_locked(iocb);
 
-	if (ocfs2_iocb_is_unaligned_aio(iocb)) {
+	if (rw == WRITE && ocfs2_iocb_is_unaligned_aio(iocb)) {
+		wait_queue_head_t *wq = ocfs2_ioend_wq(inode);
+
 		ocfs2_iocb_clear_unaligned_aio(iocb);
 
 		if (atomic_dec_and_test(&OCFS2_I(inode)->ip_unaligned_aio) &&
@@ -598,6 +595,23 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
 	inode_dio_done(inode);
 }
 
+static void ocfs2_dio_end_io_write(struct kiocb *iocb, loff_t offset,
+				   ssize_t bytes, void *private, int ret,
+				   bool is_async)
+{
+
+	return ocfs2_dio_end_io(iocb, offset, bytes, private, ret,
+				is_async, WRITE);
+}
+
+static void ocfs2_dio_end_io_read(struct kiocb *iocb, loff_t offset,
+				  ssize_t bytes, void *private, int ret,
+				  bool is_async)
+{
+	return ocfs2_dio_end_io(iocb, offset, bytes, private, ret,
+				is_async, READ);
+}
+
 /*
  * ocfs2_invalidatepage() and ocfs2_releasepage() are shamelessly stolen
  * from ext3.  PageChecked() bits have been removed as OCFS2 does not
@@ -627,6 +641,7 @@ static ssize_t ocfs2_direct_IO(int rw,
 {
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
+	dio_iodone_t *end_io;
 
 	/*
 	 * Fallback to buffered I/O if we see an inode without
@@ -639,10 +654,15 @@ static ssize_t ocfs2_direct_IO(int rw,
 	if (i_size_read(inode) <= offset)
 		return 0;
 
+	if (rw == WRITE)
+		end_io = ocfs2_dio_end_io_write;
+	else
+		end_io = ocfs2_dio_end_io_read;
+
 	return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
 				    iov, offset, nr_segs,
 				    ocfs2_direct_IO_get_blocks,
-				    ocfs2_dio_end_io, NULL, 0);
+				    end_io, NULL, 0);
 }
 
 static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb,
-- 
1.7.7.6




More information about the Ocfs2-devel mailing list