dont always try zero copy for blk_rq_map_user
Subsystems (4)
PATCH 1/2 dont always try zero copy for blk_rq_map_user
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 <[email protected]>
drivers/block/ll_rw_blk.c +12 -5
@@ -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, uif (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_queuegeneric_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) {/*
drivers/block/scsi_ioctl.c +2 -2
@@ -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
drivers/cdrom/cdrom.c +2 -2
@@ -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)
drivers/scsi/constants.c +10 -0
@@ -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;
drivers/scsi/scsi_error.c +6 -0
@@ -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) {
fs/bio.c +5 -7
@@ -401,7 +401,6 @@ int bio_add_page(struct bio *bio, structstruct 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 &©_to_user (bmd->userptr, addr, len)) +if (read && !ret &©_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)
include/linux/bio.h +1 -1
@@ -305,7 +305,7 @@ extern struct bio *bio_map_kern(struct rextern 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
include/linux/blkdev.h +7 -2
@@ -547,6 +547,7 @@ extern void blk_unregister_queue(structextern 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 requesextern 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;
include/scsi/scsi_dbg.h +1 -0
@@ -10,6 +10,7 @@ extern void scsi_print_sense_hdr(const cextern 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);
include/scsi/scsi_eh.h +1 -0
@@ -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) {