Chuck Ebbert 6c58ce8
From: Christoph Hellwig <hch@infradead.org>
Chuck Ebbert 6c58ce8
Date: Sun, 18 Jul 2010 21:17:09 +0000 (+0000)
Chuck Ebbert 6c58ce8
Subject: direct-io: move aio_complete into ->end_io
Chuck Ebbert 6c58ce8
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=40e2e97316af6e62affab7a392e792494b8d9dde
Chuck Ebbert 6c58ce8
Chuck Ebbert 6c58ce8
direct-io: move aio_complete into ->end_io
Chuck Ebbert 6c58ce8
Chuck Ebbert 6c58ce8
Filesystems with unwritten extent support must not complete an AIO request
Chuck Ebbert 6c58ce8
until the transaction to convert the extent has been commited.  That means
Chuck Ebbert 6c58ce8
the aio_complete calls needs to be moved into the ->end_io callback so
Chuck Ebbert 6c58ce8
that the filesystem can control when to call it exactly.
Chuck Ebbert 6c58ce8
Chuck Ebbert 6c58ce8
This makes a bit of a mess out of dio_complete and the ->end_io callback
Chuck Ebbert 6c58ce8
prototype even more complicated.
Chuck Ebbert 6c58ce8
Chuck Ebbert 6c58ce8
Signed-off-by: Christoph Hellwig <hch@lst.de>
Chuck Ebbert 6c58ce8
Reviewed-by: Jan Kara <jack@suse.cz>
Chuck Ebbert 6c58ce8
Signed-off-by: Alex Elder <aelder@sgi.com>
Chuck Ebbert 6c58ce8
---
Chuck Ebbert 6c58ce8
Chuck Ebbert 6c58ce8
diff --git a/fs/direct-io.c b/fs/direct-io.c
Chuck Ebbert 6c58ce8
index 7600aac..a10cb91 100644
Chuck Ebbert 6c58ce8
--- a/fs/direct-io.c
Chuck Ebbert 6c58ce8
+++ b/fs/direct-io.c
Chuck Ebbert 6c58ce8
@@ -218,7 +218,7 @@ static struct page *dio_get_page(struct dio *dio)
Chuck Ebbert 6c58ce8
  * filesystems can use it to hold additional state between get_block calls and
Chuck Ebbert 6c58ce8
  * dio_complete.
Chuck Ebbert 6c58ce8
  */
Chuck Ebbert 6c58ce8
-static int dio_complete(struct dio *dio, loff_t offset, int ret)
Chuck Ebbert 6c58ce8
+static int dio_complete(struct dio *dio, loff_t offset, int ret, bool is_async)
Chuck Ebbert 6c58ce8
 {
Chuck Ebbert 6c58ce8
 	ssize_t transferred = 0;
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
@@ -239,14 +239,6 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret)
Chuck Ebbert 6c58ce8
 			transferred = dio->i_size - offset;
Chuck Ebbert 6c58ce8
 	}
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
-	if (dio->end_io && dio->result)
Chuck Ebbert 6c58ce8
-		dio->end_io(dio->iocb, offset, transferred,
Chuck Ebbert 6c58ce8
-			    dio->map_bh.b_private);
Chuck Ebbert 6c58ce8
-
Chuck Ebbert 6c58ce8
-	if (dio->flags & DIO_LOCKING)
Chuck Ebbert 6c58ce8
-		/* lockdep: non-owner release */
Chuck Ebbert 6c58ce8
-		up_read_non_owner(&dio->inode->i_alloc_sem);
Chuck Ebbert 6c58ce8
-
Chuck Ebbert 6c58ce8
 	if (ret == 0)
Chuck Ebbert 6c58ce8
 		ret = dio->page_errors;
Chuck Ebbert 6c58ce8
 	if (ret == 0)
Chuck Ebbert 6c58ce8
@@ -254,6 +246,17 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret)
Chuck Ebbert 6c58ce8
 	if (ret == 0)
Chuck Ebbert 6c58ce8
 		ret = transferred;
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
+	if (dio->end_io && dio->result) {
Chuck Ebbert 6c58ce8
+		dio->end_io(dio->iocb, offset, transferred,
Chuck Ebbert 6c58ce8
+			    dio->map_bh.b_private, ret, is_async);
Chuck Ebbert 6c58ce8
+	} else if (is_async) {
Chuck Ebbert 6c58ce8
+		aio_complete(dio->iocb, ret, 0);
Chuck Ebbert 6c58ce8
+	}
Chuck Ebbert 6c58ce8
+
Chuck Ebbert 6c58ce8
+	if (dio->flags & DIO_LOCKING)
Chuck Ebbert 6c58ce8
+		/* lockdep: non-owner release */
Chuck Ebbert 6c58ce8
+		up_read_non_owner(&dio->inode->i_alloc_sem);
Chuck Ebbert 6c58ce8
+
Chuck Ebbert 6c58ce8
 	return ret;
Chuck Ebbert 6c58ce8
 }
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
@@ -277,8 +280,7 @@ static void dio_bio_end_aio(struct bio *bio, int error)
Chuck Ebbert 6c58ce8
 	spin_unlock_irqrestore(&dio->bio_lock, flags);
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 	if (remaining == 0) {
Chuck Ebbert 6c58ce8
-		int ret = dio_complete(dio, dio->iocb->ki_pos, 0);
Chuck Ebbert 6c58ce8
-		aio_complete(dio->iocb, ret, 0);
Chuck Ebbert 6c58ce8
+		dio_complete(dio, dio->iocb->ki_pos, 0, true);
Chuck Ebbert 6c58ce8
 		kfree(dio);
Chuck Ebbert 6c58ce8
 	}
Chuck Ebbert 6c58ce8
 }
Chuck Ebbert 6c58ce8
@@ -1126,7 +1128,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
Chuck Ebbert 6c58ce8
 	spin_unlock_irqrestore(&dio->bio_lock, flags);
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 	if (ret2 == 0) {
Chuck Ebbert 6c58ce8
-		ret = dio_complete(dio, offset, ret);
Chuck Ebbert 6c58ce8
+		ret = dio_complete(dio, offset, ret, false);
Chuck Ebbert 6c58ce8
 		kfree(dio);
Chuck Ebbert 6c58ce8
 	} else
Chuck Ebbert 6c58ce8
 		BUG_ON(ret != -EIOCBQUEUED);
Chuck Ebbert 6c58ce8
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
Chuck Ebbert 6c58ce8
index 42272d6..0afc8c1 100644
Chuck Ebbert 6c58ce8
--- a/fs/ext4/inode.c
Chuck Ebbert 6c58ce8
+++ b/fs/ext4/inode.c
Chuck Ebbert 6c58ce8
@@ -3775,7 +3775,8 @@ static ext4_io_end_t *ext4_init_io_end (struct inode *inode, gfp_t flags)
Chuck Ebbert 6c58ce8
 }
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
Chuck Ebbert 6c58ce8
-			    ssize_t size, void *private)
Chuck Ebbert 6c58ce8
+			    ssize_t size, void *private, int ret,
Chuck Ebbert 6c58ce8
+			    bool is_async)
Chuck Ebbert 6c58ce8
 {
Chuck Ebbert 6c58ce8
         ext4_io_end_t *io_end = iocb->private;
Chuck Ebbert 6c58ce8
 	struct workqueue_struct *wq;
Chuck Ebbert 6c58ce8
@@ -3784,7 +3785,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 	/* if not async direct IO or dio with 0 bytes write, just return */
Chuck Ebbert 6c58ce8
 	if (!io_end || !size)
Chuck Ebbert 6c58ce8
-		return;
Chuck Ebbert 6c58ce8
+		goto out;
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 	ext_debug("ext4_end_io_dio(): io_end 0x%p"
Chuck Ebbert 6c58ce8
 		  "for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
Chuck Ebbert 6c58ce8
@@ -3795,7 +3796,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
Chuck Ebbert 6c58ce8
 	if (io_end->flag != EXT4_IO_UNWRITTEN){
Chuck Ebbert 6c58ce8
 		ext4_free_io_end(io_end);
Chuck Ebbert 6c58ce8
 		iocb->private = NULL;
Chuck Ebbert 6c58ce8
-		return;
Chuck Ebbert 6c58ce8
+		goto out;
Chuck Ebbert 6c58ce8
 	}
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 	io_end->offset = offset;
Chuck Ebbert 6c58ce8
@@ -3812,6 +3813,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
Chuck Ebbert 6c58ce8
 	list_add_tail(&io_end->list, &ei->i_completed_io_list);
Chuck Ebbert 6c58ce8
 	spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
Chuck Ebbert 6c58ce8
 	iocb->private = NULL;
Chuck Ebbert 6c58ce8
+out:
Chuck Ebbert 6c58ce8
+	if (is_async)
Chuck Ebbert 6c58ce8
+		aio_complete(iocb, ret, 0);
Chuck Ebbert 6c58ce8
 }
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
Chuck Ebbert 6c58ce8
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
Chuck Ebbert 6c58ce8
index 356e976..96337a4 100644
Chuck Ebbert 6c58ce8
--- a/fs/ocfs2/aops.c
Chuck Ebbert 6c58ce8
+++ b/fs/ocfs2/aops.c
Chuck Ebbert 6c58ce8
@@ -578,7 +578,9 @@ bail:
Chuck Ebbert 6c58ce8
 static void ocfs2_dio_end_io(struct kiocb *iocb,
Chuck Ebbert 6c58ce8
 			     loff_t offset,
Chuck Ebbert 6c58ce8
 			     ssize_t bytes,
Chuck Ebbert 6c58ce8
-			     void *private)
Chuck Ebbert 6c58ce8
+			     void *private,
Chuck Ebbert 6c58ce8
+			     int ret,
Chuck Ebbert 6c58ce8
+			     bool is_async)
Chuck Ebbert 6c58ce8
 {
Chuck Ebbert 6c58ce8
 	struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
Chuck Ebbert 6c58ce8
 	int level;
Chuck Ebbert 6c58ce8
@@ -592,6 +594,9 @@ static void ocfs2_dio_end_io(struct kiocb *iocb,
Chuck Ebbert 6c58ce8
 	if (!level)
Chuck Ebbert 6c58ce8
 		up_read(&inode->i_alloc_sem);
Chuck Ebbert 6c58ce8
 	ocfs2_rw_unlock(inode, level);
Chuck Ebbert 6c58ce8
+
Chuck Ebbert 6c58ce8
+	if (is_async)
Chuck Ebbert 6c58ce8
+		aio_complete(iocb, ret, 0);
Chuck Ebbert 6c58ce8
 }
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 /*
Chuck Ebbert 6c58ce8
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
Chuck Ebbert 6c58ce8
index 8abbf05..95d1e26 100644
Chuck Ebbert 6c58ce8
--- a/fs/xfs/linux-2.6/xfs_aops.c
Chuck Ebbert 6c58ce8
+++ b/fs/xfs/linux-2.6/xfs_aops.c
Chuck Ebbert 6c58ce8
@@ -1406,7 +1406,9 @@ xfs_end_io_direct(
Chuck Ebbert 6c58ce8
 	struct kiocb	*iocb,
Chuck Ebbert 6c58ce8
 	loff_t		offset,
Chuck Ebbert 6c58ce8
 	ssize_t		size,
Chuck Ebbert 6c58ce8
-	void		*private)
Chuck Ebbert 6c58ce8
+	void		*private,
Chuck Ebbert 6c58ce8
+	int		ret,
Chuck Ebbert 6c58ce8
+	bool		is_async)
Chuck Ebbert 6c58ce8
 {
Chuck Ebbert 6c58ce8
 	xfs_ioend_t	*ioend = iocb->private;
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
@@ -1452,6 +1454,9 @@ xfs_end_io_direct(
Chuck Ebbert 6c58ce8
 	 * against double-freeing.
Chuck Ebbert 6c58ce8
 	 */
Chuck Ebbert 6c58ce8
 	iocb->private = NULL;
Chuck Ebbert 6c58ce8
+
Chuck Ebbert 6c58ce8
+	if (is_async)
Chuck Ebbert 6c58ce8
+		aio_complete(iocb, ret, 0);
Chuck Ebbert 6c58ce8
 }
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 STATIC ssize_t
Chuck Ebbert 6c58ce8
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h
Chuck Ebbert 6c58ce8
index 319da17..c5057fb 100644
Chuck Ebbert 6c58ce8
--- a/fs/xfs/linux-2.6/xfs_aops.h
Chuck Ebbert 6c58ce8
+++ b/fs/xfs/linux-2.6/xfs_aops.h
Chuck Ebbert 6c58ce8
@@ -37,6 +37,8 @@ typedef struct xfs_ioend {
Chuck Ebbert 6c58ce8
 	size_t			io_size;	/* size of the extent */
Chuck Ebbert 6c58ce8
 	xfs_off_t		io_offset;	/* offset in the file */
Chuck Ebbert 6c58ce8
 	struct work_struct	io_work;	/* xfsdatad work queue */
Chuck Ebbert 6c58ce8
+	struct kiocb		*io_iocb;
Chuck Ebbert 6c58ce8
+	int			io_result;
Chuck Ebbert 6c58ce8
 } xfs_ioend_t;
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 extern const struct address_space_operations xfs_address_space_operations;
Chuck Ebbert 6c58ce8
diff --git a/include/linux/fs.h b/include/linux/fs.h
Chuck Ebbert 6c58ce8
index 68ca1b0..f91affb 100644
Chuck Ebbert 6c58ce8
--- a/include/linux/fs.h
Chuck Ebbert 6c58ce8
+++ b/include/linux/fs.h
Chuck Ebbert 6c58ce8
@@ -415,7 +415,8 @@ struct buffer_head;
Chuck Ebbert 6c58ce8
 typedef int (get_block_t)(struct inode *inode, sector_t iblock,
Chuck Ebbert 6c58ce8
 			struct buffer_head *bh_result, int create);
Chuck Ebbert 6c58ce8
 typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
Chuck Ebbert 6c58ce8
-			ssize_t bytes, void *private);
Chuck Ebbert 6c58ce8
+			ssize_t bytes, void *private, int ret,
Chuck Ebbert 6c58ce8
+			bool is_async);
Chuck Ebbert 6c58ce8
 
Chuck Ebbert 6c58ce8
 /*
Chuck Ebbert 6c58ce8
  * Attribute flags.  These should be or-ed together to figure out what