linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] bio walking for 2.5.68-bk6
@ 2003-04-25 22:09 Bartlomiej Zolnierkiewicz
  2003-05-06 18:05 ` Jens Axboe
  0 siblings, 1 reply; 2+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2003-04-25 22:09 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-kernel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 512 bytes --]


Hi,

I have updated and reworked bio traversal patch.

Main idea is now reversed - instead of introducing rq->hard_bio as
pointer for bio to be completed and using rq->bio as pointer for bio
to be submitted, rq->cbio is introduced for submissions and rq->bio
is used for completions.

This minimizes changes to block layer and assures that all existing
block users are not affected by this patch.

Please check it and forward to Linus, or tell what changes you
need to find this code acceptable.

--
Bartlomiej

[-- Attachment #2: Type: TEXT/PLAIN, Size: 11735 bytes --]

# bio walking (separate submittion / completion bio pointers).
#
# Originally by Suparna Bhattacharya.
#
# Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>

diff -uNr linux-2.5.68-bk6/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.5.68-bk6/drivers/block/ll_rw_blk.c	Fri Apr 25 16:08:52 2003
+++ linux/drivers/block/ll_rw_blk.c	Fri Apr 25 22:00:18 2003
@@ -1684,7 +1684,8 @@
 
 	sector = bio->bi_sector;
 	nr_sectors = bio_sectors(bio);
-	cur_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+	cur_nr_sectors = bio_cur_sectors(bio);
+
 	rw = bio_data_dir(bio);
 
 	/*
@@ -1740,7 +1741,10 @@
 			}
 
 			bio->bi_next = req->bio;
-			req->bio = bio;
+			req->cbio = req->bio = bio;
+			req->nr_cbio_segments = bio_segments(bio);
+			req->nr_cbio_sectors = bio_sectors(bio);
+
 			/*
 			 * may not be valid. if the low level driver said
 			 * it didn't need a bounce buffer then it better
@@ -1808,9 +1812,11 @@
 	req->current_nr_sectors = req->hard_cur_sectors = cur_nr_sectors;
 	req->nr_phys_segments = bio_phys_segments(q, bio);
 	req->nr_hw_segments = bio_hw_segments(q, bio);
+	req->nr_cbio_segments = bio_segments(bio);
+	req->nr_cbio_sectors = bio_sectors(bio);
 	req->buffer = bio_data(bio);	/* see ->buffer comment above */
 	req->waiting = NULL;
-	req->bio = req->biotail = bio;
+	req->cbio = req->bio = req->biotail = bio;
 	req->rq_disk = bio->bi_bdev->bd_disk;
 	req->start_time = jiffies;
 	add_request(q, req, insert_here);
@@ -1981,6 +1987,81 @@
 	return 1;
 }
 
+/**
+ * blk_rq_next_segment
+ * @rq:		the request being processed
+ *
+ * Description:
+ *	Points to the next segment in the request if the current segment
+ *	is complete. Leaves things unchanged if this segment is not over
+ *	or if no more segments are left in this request.
+ *
+ *	Meant to be used for bio traversal during I/O submission
+ *	Does not affect any I/O completions or update completion state
+ *	in the request, and does not modify any bio fields.
+ *
+ *	Decrementing rq->nr_sectors, rq->current_nr_sectors and
+ *	rq->nr_cbio_sectors as data is transferred is the caller's
+ *	responsibility and should be done before calling this routine.
+ **/
+void blk_rq_next_segment(struct request *rq)
+{
+	if (rq->current_nr_sectors > 0)
+		return;
+
+	if (rq->nr_cbio_sectors > 0) {
+		--rq->nr_cbio_segments;
+		rq->current_nr_sectors = blk_rq_vec(rq)->bv_len >> 9;
+	} else {
+		if ((rq->cbio = rq->cbio->bi_next)) {
+			rq->nr_cbio_segments = bio_segments(rq->cbio);
+			rq->nr_cbio_sectors = bio_sectors(rq->cbio);
+ 			rq->current_nr_sectors = bio_cur_sectors(rq->cbio);
+		}
+ 	}
+
+	/* remember the size of this segment before we start I/O */
+	rq->hard_cur_sectors = rq->current_nr_sectors;
+}
+
+/**
+ * process_that_request_first	-	process partial request submission
+ * @req:	the request being processed
+ * @nr_sectors:	number of sectors I/O has been submitted on
+ *
+ * Description:
+ *	May be used for processing bio's while submitting I/O without
+ *	signalling completion. Fails if more data is requested than is
+ *	available in the request in which case it doesn't advance any
+ *	pointers.
+ *
+ *	Assumes a request is correctly set up. No sanity checks.
+ *
+ * Return:
+ *	0 - no more data left to submit (not processed)
+ *	1 - data available to submit for this request (processed)
+ **/
+int process_that_request_first(struct request *req, unsigned int nr_sectors)
+{
+	unsigned int nsect;
+
+	if (req->nr_sectors < nr_sectors)
+		return 0;
+
+	req->nr_sectors -= nr_sectors;
+	req->sector += nr_sectors;
+	while (nr_sectors) {
+		nsect = min_t(unsigned, req->current_nr_sectors, nr_sectors);
+		req->current_nr_sectors -= nsect;
+		nr_sectors -= nsect;
+		if (req->cbio) {
+			req->nr_cbio_sectors -= nsect;
+			blk_rq_next_segment(req);
+		}
+	}
+	return 1;
+}
+
 void blk_recalc_rq_segments(struct request *rq)
 {
 	struct bio *bio;
@@ -1989,8 +2070,6 @@
 	if (!rq->bio)
 		return;
 
-	rq->buffer = bio_data(rq->bio);
-
 	nr_phys_segs = nr_hw_segs = 0;
 	rq_for_each_bio(bio, rq) {
 		/* Force bio hw/phys segs to be recalculated. */
@@ -2008,11 +2087,24 @@
 {
 	if (blk_fs_request(rq)) {
 		rq->hard_sector += nsect;
-		rq->nr_sectors = rq->hard_nr_sectors -= nsect;
-		rq->sector = rq->hard_sector;
+		rq->hard_nr_sectors -= nsect;
 
-		rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
-		rq->hard_cur_sectors = rq->current_nr_sectors;
+		/*
+		 * Move the I/O submission pointers ahead if required,
+		 * i.e. for drivers not aware of rq->cbio.
+		 */
+		if ((rq->nr_sectors >= rq->hard_nr_sectors) &&
+		    (rq->sector <= rq->hard_sector)) {
+			rq->sector = rq->hard_sector;
+			rq->nr_sectors = rq->hard_nr_sectors;
+			rq->hard_cur_sectors = bio_cur_sectors(rq->bio);
+			rq->current_nr_sectors = rq->hard_cur_sectors;
+			rq->nr_cbio_segments = bio_segments(rq->bio);
+			rq->nr_cbio_sectors = bio_sectors(rq->bio);
+			rq->buffer = bio_data(rq->bio);
+
+			rq->cbio = rq->bio;
+		}
 
 		/*
 		 * if total number of sectors is less than the first segment
@@ -2206,9 +2298,11 @@
 	rq->current_nr_sectors = bio_cur_sectors(bio);
 	rq->hard_cur_sectors = rq->current_nr_sectors;
 	rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio);
+	rq->nr_cbio_segments = bio_segments(bio);
+	rq->nr_cbio_sectors = bio_sectors(bio);
 	rq->buffer = bio_data(bio);
 
-	rq->bio = rq->biotail = bio;
+	rq->cbio = rq->bio = rq->biotail = bio;
 }
 
 int __init blk_dev_init(void)
@@ -2250,6 +2344,7 @@
 	return 0;
 };
 
+EXPORT_SYMBOL(process_that_request_first);
 EXPORT_SYMBOL(end_that_request_first);
 EXPORT_SYMBOL(end_that_request_chunk);
 EXPORT_SYMBOL(end_that_request_last);
diff -uNr linux-2.5.68-bk6/include/linux/bio.h linux/include/linux/bio.h
--- linux-2.5.68-bk6/include/linux/bio.h	Sun Apr 20 04:50:35 2003
+++ linux/include/linux/bio.h	Fri Apr 25 22:32:17 2003
@@ -131,6 +131,7 @@
 #define bio_iovec(bio)		bio_iovec_idx((bio), (bio)->bi_idx)
 #define bio_page(bio)		bio_iovec((bio))->bv_page
 #define bio_offset(bio)		bio_iovec((bio))->bv_offset
+#define bio_segments(bio)	((bio)->bi_vcnt - (bio)->bi_idx)
 #define bio_sectors(bio)	((bio)->bi_size >> 9)
 #define bio_cur_sectors(bio)	(bio_iovec(bio)->bv_len >> 9)
 #define bio_data(bio)		(page_address(bio_page((bio))) + bio_offset((bio)))
@@ -226,12 +227,12 @@
 #ifdef CONFIG_HIGHMEM
 /*
  * remember to add offset! and never ever reenable interrupts between a
- * bio_kmap_irq and bio_kunmap_irq!!
+ * bvec_kmap_irq and bvec_kunmap_irq!!
  *
  * This function MUST be inlined - it plays with the CPU interrupt flags.
  * Hence the `extern inline'.
  */
-extern inline char *bio_kmap_irq(struct bio *bio, unsigned long *flags)
+extern inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags)
 {
 	unsigned long addr;
 
@@ -240,15 +241,15 @@
 	 * balancing is a lot nicer this way
 	 */
 	local_irq_save(*flags);
-	addr = (unsigned long) kmap_atomic(bio_page(bio), KM_BIO_SRC_IRQ);
+	addr = (unsigned long) kmap_atomic(bvec->bv_page, KM_BIO_SRC_IRQ);
 
 	if (addr & ~PAGE_MASK)
 		BUG();
 
-	return (char *) addr + bio_offset(bio);
+	return (char *) addr + bvec->bv_offset;
 }
 
-extern inline void bio_kunmap_irq(char *buffer, unsigned long *flags)
+extern inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
 {
 	unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
 
@@ -257,8 +258,19 @@
 }
 
 #else
-#define bio_kmap_irq(bio, flags)	(bio_data(bio))
-#define bio_kunmap_irq(buf, flags)	do { *(flags) = 0; } while (0)
+#define bvec_kmap_irq(bvec, flags)	(page_address((bvec)->bv_page) + (bvec)->bv_offset)
+#define bvec_kunmap_irq(buf, flags)	do { *(flags) = 0; } while (0)
 #endif
 
+extern inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx,
+				   unsigned long *flags)
+{
+	return bvec_kmap_irq(bio_iovec_idx(bio, idx), flags);
+}
+#define __bio_kunmap_irq(buf, flags)	bvec_kunmap_irq(buf, flags)
+
+#define bio_kmap_irq(bio, flags) \
+	__bio_kmap_irq((bio), (bio)->bi_idx, (flags))
+#define bio_kunmap_irq(buf,flags)	__bio_kunmap_irq(buf, flags)
+
 #endif /* __LINUX_BIO_H */
diff -uNr linux-2.5.68-bk6/include/linux/blk.h linux/include/linux/blk.h
--- linux-2.5.68-bk6/include/linux/blk.h	Fri Apr 25 16:08:53 2003
+++ linux/include/linux/blk.h	Fri Apr 25 21:38:07 2003
@@ -22,6 +22,7 @@
  * code duplication in drivers.
  */
 
+extern int process_that_request_first(struct request *, unsigned int);
 extern int end_that_request_first(struct request *, int, int);
 extern int end_that_request_chunk(struct request *, int, int);
 extern void end_that_request_last(struct request *);
diff -uNr linux-2.5.68-bk6/include/linux/blkdev.h linux/include/linux/blkdev.h
--- linux-2.5.68-bk6/include/linux/blkdev.h	Fri Apr 25 16:08:53 2003
+++ linux/include/linux/blkdev.h	Fri Apr 25 22:33:15 2003
@@ -10,6 +10,7 @@
 #include <linux/pagemap.h>
 #include <linux/backing-dev.h>
 #include <linux/wait.h>
+#include <linux/bio.h>
 
 #include <asm/scatterlist.h>
 
@@ -33,25 +34,35 @@
 				     * blkdev_dequeue_request! */
 	unsigned long flags;		/* see REQ_ bits below */
 
-	sector_t sector;
-	unsigned long nr_sectors;
+	/* Maintain bio traversal state for part by part I/O submission.
+	 * hard_* are block layer internals, no driver should touch them!
+	 */
+
+	sector_t sector;		/* next sector to submit */
+	unsigned long nr_sectors;	/* no. of sectors left to submit */
+	/* no. of sectors left to submit in the current segment */
 	unsigned int current_nr_sectors;
 
+	sector_t hard_sector;		/* next sector to complete */
+	unsigned long hard_nr_sectors;	/* no. of sectors left to complete */
+	/* no. of sectors left to complete in the current segment */
+	unsigned int hard_cur_sectors;
+
+	/* no. of segments left to submit in the current bio */
+	unsigned short nr_cbio_segments;
+	/* no. of sectors left to submit in the current bio */
+	unsigned long nr_cbio_sectors;
+
+	struct bio *cbio;		/* next bio to submit */
+	struct bio *bio;		/* next unfinished bio to complete */
+	struct bio *biotail;
+
 	void *elevator_private;
 
 	int rq_status;	/* should split this into a few status bits */
 	struct gendisk *rq_disk;
 	int errors;
 	unsigned long start_time;
-	sector_t hard_sector;		/* the hard_* are block layer
-					 * internals, no driver should
-					 * touch them
-					 */
-	unsigned long hard_nr_sectors;
-	unsigned int hard_cur_sectors;
-
-	struct bio *bio;
-	struct bio *biotail;
 
 	/* Number of scatter-gather DMA addr+len pairs after
 	 * physical address coalescing is performed.
@@ -281,6 +292,32 @@
  */
 #define blk_queue_headactive(q, head_active)
 
+/* current index into bio being processed for submission */
+#define blk_rq_idx(rq)	((rq)->cbio->bi_vcnt - (rq)->nr_cbio_segments)
+
+/* current bio vector being processed */
+#define blk_rq_vec(rq)	(bio_iovec_idx((rq)->cbio, blk_rq_idx(rq)))
+
+/* current offset with respect to start of the segment being submitted */
+#define blk_rq_offset(rq) \
+	(((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
+
+/*
+ * temporarily mapping a (possible) highmem bio (typically for PIO transfer)
+ */
+
+/* Assumes rq->cbio != NULL */
+static inline char * rq_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return (__bio_kmap_irq(rq->cbio, blk_rq_idx(rq), flags)
+		+ blk_rq_offset(rq));
+}
+
+static inline void rq_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	__bio_kunmap_irq(buffer, flags);
+}
+
 /*
  * q->prep_rq_fn return values
  */

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] bio walking for 2.5.68-bk6
  2003-04-25 22:09 [PATCH] bio walking for 2.5.68-bk6 Bartlomiej Zolnierkiewicz
@ 2003-05-06 18:05 ` Jens Axboe
  0 siblings, 0 replies; 2+ messages in thread
From: Jens Axboe @ 2003-05-06 18:05 UTC (permalink / raw)
  To: Bartlomiej Zolnierkiewicz; +Cc: linux-kernel

On Sat, Apr 26 2003, Bartlomiej Zolnierkiewicz wrote:
> 
> Hi,
> 
> I have updated and reworked bio traversal patch.
> 
> Main idea is now reversed - instead of introducing rq->hard_bio as
> pointer for bio to be completed and using rq->bio as pointer for bio
> to be submitted, rq->cbio is introduced for submissions and rq->bio
> is used for completions.
> 
> This minimizes changes to block layer and assures that all existing
> block users are not affected by this patch.

This looks good, I like this concept a whole lot better.

> Please check it and forward to Linus, or tell what changes you
> need to find this code acceptable.

Will do, I've merged it into bk current right now. I'll submit after a
bit of testing.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-05-06 17:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-04-25 22:09 [PATCH] bio walking for 2.5.68-bk6 Bartlomiej Zolnierkiewicz
2003-05-06 18:05 ` Jens Axboe

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).