Commit 240d3e2d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] bio kmapping changes

RAID5 is calling copy_data() under sh->lock.  But copy_data() does kmap(),
which can sleep.

The best fix is to use kmap_atomic() in there.  It is faster than kmap() and
does not block.

The patch removes the unused bio_kmap() and replaces __bio_kmap() with
__bio_kmap_atomic().  I think it's best to withdraw the sleeping-and-slow
bio_kmap() from the kernel API before someone else tries to use it.


Also, I notice that bio_kmap_irq() was using local_save_flags().  This is a
bug - local_save_flags() does not disable interrupts.  Converted that to
local_irq_save().  These names are terribly chosen.

This patch was acked by Jens and Neil.
parent d597f71b
...@@ -204,7 +204,7 @@ may need to abort DMA operations and revert to PIO for the transfer, in ...@@ -204,7 +204,7 @@ may need to abort DMA operations and revert to PIO for the transfer, in
which case a virtual mapping of the page is required. For SCSI it is also which case a virtual mapping of the page is required. For SCSI it is also
done in some scenarios where the low level driver cannot be trusted to done in some scenarios where the low level driver cannot be trusted to
handle a single sg entry correctly. The driver is expected to perform the handle a single sg entry correctly. The driver is expected to perform the
kmaps as needed on such occasions using the bio_kmap and bio_kmap_irq kmaps as needed on such occasions using the __bio_kmap_atomic and bio_kmap_irq
routines as appropriate. A driver could also use the blk_queue_bounce() routines as appropriate. A driver could also use the blk_queue_bounce()
routine on its own to bounce highmem i/o to low memory for specific requests routine on its own to bounce highmem i/o to low memory for specific requests
if so desired. if so desired.
...@@ -1147,9 +1147,9 @@ use blk_rq_map_sg for scatter gather) to be able to ship it to the driver. For ...@@ -1147,9 +1147,9 @@ use blk_rq_map_sg for scatter gather) to be able to ship it to the driver. For
PIO drivers (or drivers that need to revert to PIO transfer once in a PIO drivers (or drivers that need to revert to PIO transfer once in a
while (IDE for example)), where the CPU is doing the actual data while (IDE for example)), where the CPU is doing the actual data
transfer a virtual mapping is needed. If the driver supports highmem I/O, transfer a virtual mapping is needed. If the driver supports highmem I/O,
(Sec 1.1, (ii) ) it needs to use bio_kmap and bio_kmap_irq to temporarily (Sec 1.1, (ii) ) it needs to use __bio_kmap_atomic and bio_kmap_irq to
map a bio into the virtual address space. See how IDE handles this with temporarily map a bio into the virtual address space. See how IDE handles
ide_map_buffer. this with ide_map_buffer.
8. Prior/Related/Impacted patches 8. Prior/Related/Impacted patches
......
...@@ -188,7 +188,7 @@ void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn) ...@@ -188,7 +188,7 @@ void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn)
* Caveat: * Caveat:
* The driver that does this *must* be able to deal appropriately * The driver that does this *must* be able to deal appropriately
* with buffers in "highmemory". This can be accomplished by either calling * with buffers in "highmemory". This can be accomplished by either calling
* bio_kmap() to get a temporary kernel mapping, or by calling * __bio_kmap_atomic() to get a temporary kernel mapping, or by calling
* blk_queue_bounce() to create a buffer in normal memory. * blk_queue_bounce() to create a buffer in normal memory.
**/ **/
void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/raid/raid5.h> #include <linux/raid/raid5.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/highmem.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/atomic.h> #include <asm/atomic.h>
...@@ -634,12 +635,12 @@ static void copy_data(int frombio, struct bio *bio, ...@@ -634,12 +635,12 @@ static void copy_data(int frombio, struct bio *bio,
else clen = len; else clen = len;
if (clen > 0) { if (clen > 0) {
char *ba = __bio_kmap(bio, i); char *ba = __bio_kmap_atomic(bio, i, KM_USER0);
if (frombio) if (frombio)
memcpy(pa+page_offset, ba+b_offset, clen); memcpy(pa+page_offset, ba+b_offset, clen);
else else
memcpy(ba+b_offset, pa+page_offset, clen); memcpy(ba+b_offset, pa+page_offset, clen);
__bio_kunmap(bio, i); __bio_kunmap_atomic(ba, KM_USER0);
} }
if (clen < len) /* hit end of page */ if (clen < len) /* hit end of page */
break; break;
......
...@@ -148,10 +148,11 @@ struct bio { ...@@ -148,10 +148,11 @@ struct bio {
* permanent PIO fall back, user is probably better off disabling highmem * permanent PIO fall back, user is probably better off disabling highmem
* I/O completely on that queue (see ide-dma for example) * I/O completely on that queue (see ide-dma for example)
*/ */
#define __bio_kmap(bio, idx) (kmap(bio_iovec_idx((bio), (idx))->bv_page) + bio_iovec_idx((bio), (idx))->bv_offset) #define __bio_kmap_atomic(bio, idx, kmtype) \
#define bio_kmap(bio) __bio_kmap((bio), (bio)->bi_idx) (kmap_atomic(bio_iovec_idx((bio), (idx))->bv_page, kmtype) + \
#define __bio_kunmap(bio, idx) kunmap(bio_iovec_idx((bio), (idx))->bv_page) bio_iovec_idx((bio), (idx))->bv_offset)
#define bio_kunmap(bio) __bio_kunmap((bio), (bio)->bi_idx)
#define __bio_kunmap_atomic(addr, kmtype) kunmap_atomic(addr, kmtype)
/* /*
* merge helpers etc * merge helpers etc
...@@ -238,7 +239,7 @@ extern inline char *bio_kmap_irq(struct bio *bio, unsigned long *flags) ...@@ -238,7 +239,7 @@ extern inline char *bio_kmap_irq(struct bio *bio, unsigned long *flags)
* might not be a highmem page, but the preempt/irq count * might not be a highmem page, but the preempt/irq count
* balancing is a lot nicer this way * balancing is a lot nicer this way
*/ */
local_save_flags(*flags); local_irq_save(*flags);
addr = (unsigned long) kmap_atomic(bio_page(bio), KM_BIO_SRC_IRQ); addr = (unsigned long) kmap_atomic(bio_page(bio), KM_BIO_SRC_IRQ);
if (addr & ~PAGE_MASK) if (addr & ~PAGE_MASK)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment