diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-map.c | 15 | ||||
-rw-r--r-- | block/scsi_ioctl.c | 27 |
2 files changed, 37 insertions, 5 deletions
diff --git a/block/blk-map.c b/block/blk-map.c index 27fd8d92892d..b18a58fc316a 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -196,6 +196,12 @@ int blk_rq_unmap_user(struct bio *bio) } EXPORT_SYMBOL(blk_rq_unmap_user); +#ifdef CONFIG_AHCI_IMX +extern void *sg_io_buffer_hack; +#else +#define sg_io_buffer_hack NULL +#endif + /** * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage * @q: request queue where request should be inserted @@ -223,7 +229,14 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, if (!len || !kbuf) return -EINVAL; - do_copy = !blk_rq_aligned(q, addr, len) || object_is_on_stack(kbuf); +#ifdef CONFIG_AHCI_IMX + if (kbuf == sg_io_buffer_hack) + do_copy = 0; + else +#endif + do_copy = !blk_rq_aligned(q, addr, len) + || object_is_on_stack(kbuf); + if (do_copy) bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading); else diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index c6fee7437be4..b00647ee3d1c 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -251,6 +251,12 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, return 0; } +#ifdef CONFIG_AHCI_IMX +extern void *sg_io_buffer_hack; +#else +#define sg_io_buffer_hack NULL +#endif + static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, struct bio *bio) { @@ -279,7 +285,12 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, ret = -EFAULT; } - r = blk_rq_unmap_user(bio); + if (sg_io_buffer_hack && !hdr->iovec_count) + r = copy_to_user(hdr->dxferp, sg_io_buffer_hack, + hdr->dxfer_len); + else + r = blk_rq_unmap_user(bio); + if (!ret) ret = r; @@ -303,6 +314,9 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; + if (sg_io_buffer_hack && hdr->dxfer_len > 0x10000) + return -EIO; + if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: @@ -349,9 +363,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, ret = blk_rq_map_user_iov(q, rq, NULL, &i, GFP_KERNEL); kfree(iov); - } else if (hdr->dxfer_len) - ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, - GFP_KERNEL); + } else if (hdr->dxfer_len) { + if (sg_io_buffer_hack) + ret = blk_rq_map_kern(q, rq, sg_io_buffer_hack, + hdr->dxfer_len, GFP_KERNEL); + else + ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, + hdr->dxfer_len, GFP_KERNEL); + } if (ret) goto out_free_cdb; |