It works under 2.6.28.
2009/6/30 FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>:
> On Mon, 29 Jun 2009 13:41:20 +0200
> Douglas Gilbert <dgilbert@xxxxxxxxxxxx> wrote:
>
>> The semantics of SG_DXFER_TO_FROM_DEV were:
>> - copy user space buffer to kernel (LLD) buffer
>> - do SCSI command which is assumed to be of the DATA_IN
>> (data from device) variety. This would overwrite
>> some or all of the kernel buffer
>> - copy kernel (LLD) buffer back to the user space.
>>
>> The idea was to detect short reads by filling the original
>> user space buffer with some marker bytes ("0xec" it would
>> seem in this report). The "resid" value is a better way
>> of detecting short reads but that was only added this century
>> and requires co-operation from the LLD.
>>
>> There were major plumbing changes in the sg driver around
>> lk 2.6.28 and it looks like the above nuance was lost.
>> Perhaps the block layer does support the above "double
>> shuffle".
>
> Sorry, I overlooked SG_DXFER_TO_FROM_DEV.
>
> Does this patch work?
>
>
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 8201387..8df3b6a 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -1658,6 +1658,10 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
> md->nr_entries = req_schp->k_use_sg;
> md->offset = 0;
> md->null_mapped = hp->dxferp ? 0 : 1;
> + if (dxfer_dir == SG_DXFER_TO_FROM_DEV)
> + md->from_user = 1;
> + else
> + md->from_user = 0;
> }
>
> if (iov_count) {
> diff --git a/fs/bio.c b/fs/bio.c
> index 24c9140..e467dd8 100644
> --- a/fs/bio.c
> +++ b/fs/bio.c
> @@ -705,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
> }
>
> static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
> - struct sg_iovec *iov, int iov_count, int uncopy,
> - int do_free_page)
> + struct sg_iovec *iov, int iov_count,
> + int to_user, int from_user, int do_free_page)
> {
> int ret = 0, i;
> struct bio_vec *bvec;
> int iov_idx = 0;
> unsigned int iov_off = 0;
> - int read = bio_data_dir(bio) == READ;
>
> __bio_for_each_segment(bvec, bio, i, 0) {
> char *bv_addr = page_address(bvec->bv_page);
> @@ -727,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
> iov_addr = iov[iov_idx].iov_base + iov_off;
>
> if (!ret) {
> - if (!read && !uncopy)
> - ret = copy_from_user(bv_addr, iov_addr,
> - bytes);
> - if (read && uncopy)
> + if (to_user)
> ret = copy_to_user(iov_addr, bv_addr,
> bytes);
>
> + if (from_user)
> + ret = copy_from_user(bv_addr, iov_addr,
> + bytes);
> +
> if (ret)
> ret = -EFAULT;
> }
> @@ -770,7 +770,8 @@ int bio_uncopy_user(struct bio *bio)
>
> if (!bio_flagged(bio, BIO_NULL_MAPPED))
> ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
> - bmd->nr_sgvecs, 1, bmd->is_our_pages);
> + bmd->nr_sgvecs, bio_data_dir(bio) == READ,
> + 0, bmd->is_our_pages);
> bio_free_map_data(bmd);
> bio_put(bio);
> return ret;
> @@ -875,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
> /*
> * success
> */
> - if (!write_to_vm && (!map_data || !map_data->null_mapped)) {
> - ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0);
> + if ((!write_to_vm && (!map_data || !map_data->null_mapped)) ||
> + (map_data && map_data->from_user)) {
> + ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0);
> if (ret)
> goto cleanup;
> }
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 8963d91..36c5ff8 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -730,6 +730,7 @@ struct rq_map_data {
> int nr_entries;
> unsigned long offset;
> int null_mapped;
> + int from_user;
> };
>
> struct req_iterator {
>
--
To unsubscribe from this list: 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
[SCSI Target Devel]
[Linux SCSI Target Infrastructure]
[Kernel Newbies]
[Share Photos]
[IDE]
[Security]
[Git]
[Netfilter]
[Bugtraq]
[Photos]
[Yosemite]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Linux ATA RAID]
[Linux IIO]
[Samba]
[Video 4 Linux]
[Device Mapper]
[Linux Resources]