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