Modify blk_rq_map_user so that is does not always try to do zero copy. This is needed becuase the sg driver's old interface can do a sg_write to send the command to the driver then later do a sg_read and pass a pointer to a buffer to transfer the data to. For SG_IO we know the detination buffer at sg_write time, so we can set everything up at blk_rq_map_user time. Also export some functions and add some wrappers for struct request handling. I am still working on these patches and I thought I saw Jens was going on vacation so I left him off the cc. Signed-off-by: Mike Christie <michaelc@xxxxxxxxxxx> diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2107,6 +2107,7 @@ EXPORT_SYMBOL(blk_insert_request); * @rw: READ or WRITE data * @ubuf: the user buffer * @len: length of user data + * @zero_copy: 1 to try zero copy, 0 for kernel bounce buffer * * Description: * Data will be mapped directly for zero copy io, if possible. Otherwise @@ -2122,7 +2123,7 @@ EXPORT_SYMBOL(blk_insert_request); * unmapping. */ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, - unsigned int len) + unsigned int len, int zero_copy) { unsigned long uaddr; struct bio *bio; @@ -2140,7 +2141,8 @@ int blk_rq_map_user(request_queue_t *q, * direct dma. else, set up kernel bounce buffers */ uaddr = (unsigned long) ubuf; - if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) + if (zero_copy && + !(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) bio = bio_map_user(q, NULL, uaddr, len, reading); else bio = bio_copy_user(q, uaddr, len, reading); @@ -2210,12 +2212,13 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); * blk_rq_unmap_user - unmap a request with user data * @rq: request to be unmapped * @bio: bio for the request + * @ubuf: buffer to copy data to for the kernel bounce buffer case * @ulen: length of user buffer * * Description: * Unmap a request previously mapped by blk_rq_map_user(). */ -int blk_rq_unmap_user(struct bio *bio, unsigned int ulen) +int blk_rq_unmap_user(struct bio *bio, void __user *ubuf, unsigned int ulen) { int ret = 0; @@ -2223,7 +2226,7 @@ int blk_rq_unmap_user(struct bio *bio, u if (bio_flagged(bio, BIO_USER_MAPPED)) bio_unmap_user(bio); else - ret = bio_uncopy_user(bio); + ret = bio_uncopy_user(bio, ubuf); } return 0; @@ -2278,6 +2281,8 @@ void blk_execute_rq_nowait(request_queue generic_unplug_device(q); } +EXPORT_SYMBOL_GPL(blk_execute_rq_nowait); + /** * blk_execute_rq - insert a request into queue for execution * @q: queue to insert the request in @@ -2421,7 +2426,7 @@ void disk_round_stats(struct gendisk *di /* * queue lock must be held */ -static void __blk_put_request(request_queue_t *q, struct request *req) +void __blk_put_request(request_queue_t *q, struct request *req) { struct request_list *rl = req->rl; @@ -2449,6 +2454,8 @@ static void __blk_put_request(request_qu } } +EXPORT_SYMBOL_GPL(__blk_put_request); + void blk_put_request(struct request *req) { /* diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -269,7 +269,7 @@ static int sg_io(struct file *file, requ ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count); kfree(iov); } else if (hdr->dxfer_len) - ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); + ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len, 1); if (ret) goto out; @@ -330,7 +330,7 @@ static int sg_io(struct file *file, requ hdr->sb_len_wr = len; } - if (blk_rq_unmap_user(bio, hdr->dxfer_len)) + if (blk_rq_unmap_user(bio, hdr->dxferp, hdr->dxfer_len)) ret = -EFAULT; /* may not have succeeded, but output values written to control diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2112,7 +2112,7 @@ static int cdrom_read_cdda_bpc(struct cd len = nr * CD_FRAMESIZE_RAW; - ret = blk_rq_map_user(q, rq, ubuf, len); + ret = blk_rq_map_user(q, rq, ubuf, len, 1); if (ret) break; @@ -2142,7 +2142,7 @@ static int cdrom_read_cdda_bpc(struct cd cdi->last_sense = s->sense_key; } - if (blk_rq_unmap_user(bio, len)) + if (blk_rq_unmap_user(bio, ubuf, len)) ret = -EFAULT; if (ret) diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1267,6 +1267,16 @@ void scsi_print_sense(const char *devcla } EXPORT_SYMBOL(scsi_print_sense); +void scsi_print_rq_sense(const char *devclass, struct request *rq) +{ + const char *name = devclass; + + if (rq->rq_disk) + name = rq->rq_disk->disk_name; + __scsi_print_sense(name, rq->sense, sizeof(rq->sense)); +} +EXPORT_SYMBOL_GPL(scsi_print_rq_sense); + void scsi_print_req_sense(const char *devclass, struct scsi_request *sreq) { const char *name = devclass; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1896,6 +1896,12 @@ int scsi_request_normalize_sense(struct } EXPORT_SYMBOL(scsi_request_normalize_sense); +int scsi_rq_normalize_sense(struct request *rq, struct scsi_sense_hdr *sshdr) +{ + return scsi_normalize_sense(rq->sense, sizeof(rq->sense), sshdr); +} +EXPORT_SYMBOL_GPL(scsi_rq_normalize_sense); + int scsi_command_normalize_sense(struct scsi_cmnd *cmd, struct scsi_sense_hdr *sshdr) { diff --git a/fs/bio.c b/fs/bio.c --- a/fs/bio.c +++ b/fs/bio.c @@ -401,7 +401,6 @@ int bio_add_page(struct bio *bio, struct struct bio_map_data { struct bio_vec *iovecs; - void __user *userptr; }; static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio) @@ -434,11 +433,12 @@ static struct bio_map_data *bio_alloc_ma /** * bio_uncopy_user - finish previously mapped bio * @bio: bio being terminated + * @userptr: user addr to copy data to * * Free pages allocated from bio_copy_user() and write back data * to user space in case of a read. */ -int bio_uncopy_user(struct bio *bio) +int bio_uncopy_user(struct bio *bio, void __user *userptr) { struct bio_map_data *bmd = bio->bi_private; const int read = bio_data_dir(bio) == READ; @@ -449,11 +449,11 @@ int bio_uncopy_user(struct bio *bio) char *addr = page_address(bvec->bv_page); unsigned int len = bmd->iovecs[i].bv_len; - if (read && !ret && copy_to_user(bmd->userptr, addr, len)) + if (read && !ret && copy_to_user(userptr, addr, len)) ret = -EFAULT; __free_page(bvec->bv_page); - bmd->userptr += len; + userptr += len; } bio_free_map_data(bmd); bio_put(bio); @@ -463,7 +463,7 @@ int bio_uncopy_user(struct bio *bio) /** * bio_copy_user - copy user data to bio * @q: destination block queue - * @uaddr: start of user address + * @uaddr: for writes start of user address and undefined for reads * @len: length in bytes * @write_to_vm: bool indicating writing to pages or not * @@ -486,8 +486,6 @@ struct bio *bio_copy_user(request_queue_ if (!bmd) return ERR_PTR(-ENOMEM); - bmd->userptr = (void __user *) uaddr; - ret = -ENOMEM; bio = bio_alloc(GFP_KERNEL, end - start); if (!bio) diff --git a/include/linux/bio.h b/include/linux/bio.h --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -305,7 +305,7 @@ extern struct bio *bio_map_kern(struct r extern void bio_set_pages_dirty(struct bio *bio); extern void bio_check_pages_dirty(struct bio *bio); extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); -extern int bio_uncopy_user(struct bio *); +extern int bio_uncopy_user(struct bio *, void __user *); void zero_fill_bio(struct bio *bio); #ifdef CONFIG_HIGHMEM diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -547,6 +547,7 @@ extern void blk_unregister_queue(struct extern void register_disk(struct gendisk *dev); extern void generic_make_request(struct bio *bio); extern void blk_put_request(struct request *); +extern void __blk_put_request(request_queue_t *, struct request *); extern void blk_end_sync_rq(struct request *rq); extern void blk_attempt_remerge(request_queue_t *, struct request *); extern struct request *blk_get_request(request_queue_t *, int, int); @@ -562,12 +563,16 @@ extern void blk_sync_queue(struct reques extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); -extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); -extern int blk_rq_unmap_user(struct bio *, unsigned int); +extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int, int); +extern int blk_rq_unmap_user(struct bio *, void __user *, unsigned int); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, unsigned int); extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *, int); +extern void blk_execute_rq_nowait(request_queue_t *, struct gendisk *, + struct request *, int, + void (*done)(struct request *)); + static inline request_queue_t *bdev_get_queue(struct block_device *bdev) { return bdev->bd_disk->queue; diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -10,6 +10,7 @@ extern void scsi_print_sense_hdr(const c extern void __scsi_print_command(unsigned char *); extern void scsi_print_sense(const char *, struct scsi_cmnd *); extern void scsi_print_req_sense(const char *, struct scsi_request *); +extern void scsi_print_rq_sense(const char *, struct request *); extern void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, int sense_len); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -47,6 +47,7 @@ extern int scsi_request_normalize_sense( struct scsi_sense_hdr *sshdr); extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd, struct scsi_sense_hdr *sshdr); +extern int scsi_rq_normalize_sense(struct request *, struct scsi_sense_hdr *); static inline int scsi_sense_is_deferred(struct scsi_sense_hdr *sshdr) { - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html