LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Nate Diller <nate@agami.com>
To: Nate Diller <nate.diller@gmail.com>,
	Andrew Morton <akpm@osdl.org>,
	Alan Cox <alan@lxorguk.ukuu.org.uk>,
	Trond Myklebust <trond.myklebust@fys.uio.no>,
	Benjamin LaHaise <bcrl@kvack.org>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	Suparna Bhattacharya <suparna@in.ibm.com>,
	Kenneth W Chen <kenneth.w.chen@intel.com>,
	David Brownell <dbrownell@users.sourceforge.net>,
	Christoph Hellwig <hch@infradead.org>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	netdev@vger.kernel.org, ocfs2-devel@oss.oracle.com,
	linux-aio@kvack.org, xfs-masters@oss.sgi.com
Subject: [PATCH -mm 5/10][RFC] aio: make blk_directIO use file_endio_t
Date: Mon, 15 Jan 2007 17:54:50 -0800	[thread overview]
Message-ID: <20070116015450.9764.84003.patchbomb.py@nate-64.agami.com> (raw)
In-Reply-To: <20070116015450.9764.37697.patchbomb.py@nate-64.agami.com>

Convert the internals of blkdev_direct_IO to use a generic endio function,
instead of directly calling aio_complete.  This may also fix some bugs/races
in this code, for instance it checks bio->bi_size instead of assuming it's
zero, and it atomically accumulates the bytes_done counter (assuming that
the bio completion handler can't race with itself *might* be valid here, but
the direct-io code makes no such assumption).  I'm also pretty sure that
the address_space->directIO functions aren't supposed to mess with the
iocb->ki_pos or ->ki_left.

---

diff -urpN -X dontdiff a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	2007-01-12 20:26:25.000000000 -0800
+++ b/fs/block_dev.c	2007-01-12 20:23:55.000000000 -0800
@@ -131,10 +131,32 @@ blkdev_get_block(struct inode *inode, se
 	return 0;
 }
 
-static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error)
+struct bdev_aio {
+	atomic_t		iocount;	/* refcount */
+	atomic_t		bytes_done;	/* byte counter */
+	int			err;		/* error handling */
+	file_endio_t		*endio;		/* end I/O notify fn */
+	void			*endio_data;	/* notify fn private data */
+};
+
+static void blk_io_put(struct bdev_aio *io)
+{
+	if (!atomic_dec_and_test(&io->iocount))
+		return;
+
+	if (!io->endio)
+		return complete((struct completion*)io->endio_data);
+
+	io->endio(io->endio_data, atomic_read(&io->bytes_done), io->err);
+	kfree(io);
+}
+
+static int blk_bio_endio(struct bio *bio, unsigned int bytes_done, int error)
 {
-	struct kiocb *iocb = bio->bi_private;
-	atomic_t *bio_count = &iocb->ki_bio_count;
+	struct bdev_aio *io = bio->bi_private;
+
+	if (bio->bi_size)
+		return 1;
 
 	if (bio_data_dir(bio) == READ)
 		bio_check_pages_dirty(bio);
@@ -143,16 +165,21 @@ static int blk_end_aio(struct bio *bio, 
 		bio_put(bio);
 	}
 
-	/* iocb->ki_nbytes stores error code from LLDD */
-	if (error)
-		iocb->ki_nbytes = -EIO;
-
-	if (atomic_dec_and_test(bio_count))
-		aio_complete(iocb, iocb->ki_left, iocb->ki_nbytes);
+  	if (error)
+		io->err = error;
+	atomic_add(bytes_done, &io->bytes_done);
 
+	blk_io_put(io);
 	return 0;
 }
 
+static void blk_io_init(struct bdev_aio *io)
+{
+	atomic_set(&io->iocount, 1);
+	atomic_set(&io->bytes_done, 0);
+	io->err = 0;
+}
+
 #define VEC_SIZE	16
 struct pvec {
 	unsigned short nr;
@@ -208,24 +235,33 @@ blkdev_direct_IO(int rw, struct kiocb *i
 
 	unsigned long addr;	/* user iovec address */
 	size_t count;		/* user iovec len */
-	size_t nbytes = iocb->ki_nbytes = iocb->ki_left; /* total xfer size */
+	size_t nbytes;		 /* total xfer size */
 	loff_t size;		/* size of block device */
 	struct bio *bio;
-	atomic_t *bio_count = &iocb->ki_bio_count;
+	struct bdev_aio stack_io, *io;
+	file_endio_t *endio = aio_complete;
+	void *endio_data = iocb;
 	struct page *page;
 	struct pvec pvec;
 
 	pvec.nr = 0;
 	pvec.idx = 0;
 
+	io = &stack_io;
+	if (endio) {
+		io = kmalloc(sizeof(struct bdev_aio), GFP_KERNEL);
+		if (!io)
+			return -ENOMEM;
+	}
+	blk_io_init(io);
+
 	if (pos & blocksize_mask)
 		return -EINVAL;
 
+	nbytes = iov_length(iov, nr_segs);
 	size = i_size_read(inode);
-	if (pos + nbytes > size) {
+	if (pos + nbytes > size)
 		nbytes = size - pos;
-		iocb->ki_left = nbytes;
-	}
 
 	/*
 	 * check first non-zero iov alignment, the remaining
@@ -237,7 +273,6 @@ blkdev_direct_IO(int rw, struct kiocb *i
 		if (addr & blocksize_mask || count & blocksize_mask)
 			return -EINVAL;
 	} while (!count && ++seg < nr_segs);
-	atomic_set(bio_count, 1);
 
 	while (nbytes) {
 		/* roughly estimate number of bio vec needed */
@@ -248,8 +283,8 @@ blkdev_direct_IO(int rw, struct kiocb *i
 		/* bio_alloc should not fail with GFP_KERNEL flag */
 		bio = bio_alloc(GFP_KERNEL, nvec);
 		bio->bi_bdev = I_BDEV(inode);
-		bio->bi_end_io = blk_end_aio;
-		bio->bi_private = iocb;
+		bio->bi_end_io = blk_bio_endio;
+		bio->bi_private = io;
 		bio->bi_sector = pos >> blkbits;
 same_bio:
 		cur_off = addr & ~PAGE_MASK;
@@ -289,18 +324,27 @@ same_bio:
 		/* bio is ready, submit it */
 		if (rw == READ)
 			bio_set_pages_dirty(bio);
-		atomic_inc(bio_count);
+		atomic_inc(&io->iocount);
 		submit_bio(rw, bio);
 	}
 
 completion:
-	iocb->ki_left -= nbytes;
-	nbytes = iocb->ki_left;
-	iocb->ki_pos += nbytes;
+	if (!endio) {
+		struct completion event;
+
+		init_completion(&event);
+		io->endio = NULL;
+		io->endio_data = &event;
+
+		if (!atomic_dec_and_test(&io->iocount))
+			wait_for_completion(&event);
+		return io->err ? io->err : atomic_read(&io->bytes_done);
+	}
 
-	if (atomic_dec_and_test(bio_count))
-		aio_complete(iocb, nbytes, 0);
+	io->endio = endio;
+	io->endio_data = endio_data;
 
+	blk_io_put(io);
 	return -EIOCBQUEUED;
 
 backout:
@@ -316,7 +360,7 @@ backout:
 	 * if no bio was submmitted, return the error code.
 	 * otherwise, proceed with pending I/O completion.
 	 */
-	if (atomic_read(bio_count) == 1)
+	if (atomic_read(&io->iocount) == 1)
 		return PTR_ERR(page);
 	goto completion;
 }

  parent reply	other threads:[~2007-01-16  2:04 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-01-16  1:54 [PATCH -mm 0/10][RFC] aio: make struct kiocb private Nate Diller
2007-01-16  1:54 ` [PATCH -mm 7/10][RFC] aio: make __blockdev_direct_IO use file_endio_t Nate Diller
2007-01-16  1:54 ` [PATCH -mm 4/10][RFC] aio: convert aio_complete to file_endio_t Nate Diller
2007-01-16  5:53   ` David Brownell
2007-01-16  9:21     ` Nate Diller
2007-01-16  1:54 ` Nate Diller [this message]
2007-01-16  1:54 ` [PATCH -mm 8/10][RFC] aio: make direct_IO aops use file_endio_t Nate Diller
2007-01-16  1:54 ` [PATCH -mm 1/10][RFC] aio: scm remove struct siocb Nate Diller
2007-01-16  1:54 ` [PATCH -mm 6/10][RFC] aio: make nfs_directIO use file_endio_t Nate Diller
2007-01-16  1:54 ` [PATCH -mm 10/10][RFC] aio: convert file aio to file_endio_t Nate Diller
2007-01-16  1:54 ` [PATCH -mm 2/10][RFC] aio: net use struct socket for io Nate Diller
2007-01-16  5:44   ` Stephen Hemminger
2007-01-16 10:24     ` Evgeniy Polyakov
2007-01-16  1:54 ` [PATCH -mm 9/10][RFC] aio: usb gadget remove aio file ops Nate Diller
2007-01-16  6:05   ` David Brownell
2007-01-16  9:13     ` Nate Diller
2007-01-16 18:36       ` David Brownell
2007-01-16  1:54 ` [PATCH -mm 3/10][RFC] aio: use iov_length instead of ki_left Nate Diller
2007-01-16  2:14   ` Christoph Hellwig
2007-01-16  5:37     ` Nate Diller
2007-01-16 23:36       ` Ingo Oeser
2007-01-18  4:27     ` Vectored AIO breakage for sockets and pipes ? Suparna Bhattacharya
2007-01-18 21:40       ` Zach Brown
2007-01-16  3:23 ` [PATCH -mm 0/10][RFC] aio: make struct kiocb private Christoph Hellwig
2007-01-16  4:25   ` Nate Diller
2007-01-16  8:22     ` David Brownell
2007-01-17 21:52     ` Benjamin LaHaise
2007-01-17 23:30       ` Nate Diller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070116015450.9764.84003.patchbomb.py@nate-64.agami.com \
    --to=nate@agami.com \
    --cc=akpm@osdl.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=bcrl@kvack.org \
    --cc=dbrownell@users.sourceforge.net \
    --cc=hch@infradead.org \
    --cc=kenneth.w.chen@intel.com \
    --cc=linux-aio@kvack.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nate.diller@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=ocfs2-devel@oss.oracle.com \
    --cc=suparna@in.ibm.com \
    --cc=trond.myklebust@fys.uio.no \
    --cc=viro@zeniv.linux.org.uk \
    --cc=xfs-masters@oss.sgi.com \
    --subject='Re: [PATCH -mm 5/10][RFC] aio: make blk_directIO use file_endio_t' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).