[ARM] Add cmpxchg support for ARMv6+ systems (v5)
[pandora-kernel.git] / block / scsi_ioctl.c
index ee9c67d..82a0ca2 100644 (file)
@@ -214,17 +214,6 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
        return 0;
 }
 
-/*
- * unmap a request that was previously mapped to this sg_io_hdr. handles
- * both sg and non-sg sg_io_hdr.
- */
-static int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr)
-{
-       blk_rq_unmap_user(rq->bio);
-       blk_put_request(rq);
-       return 0;
-}
-
 static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
                                 struct bio *bio)
 {
@@ -253,12 +242,12 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
                        ret = -EFAULT;
        }
 
-       rq->bio = bio;
-       r = blk_unmap_sghdr_rq(rq, hdr);
-       if (ret)
-               r = ret;
+       r = blk_rq_unmap_user(bio);
+       if (!ret)
+               ret = r;
+       blk_put_request(rq);
 
-       return r;
+       return ret;
 }
 
 static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
@@ -301,6 +290,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 
        if (hdr->iovec_count) {
                const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
+               size_t iov_data_len;
                struct sg_iovec *iov;
 
                iov = kmalloc(size, GFP_KERNEL);
@@ -315,8 +305,18 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
                        goto out;
                }
 
+               /* SG_IO howto says that the shorter of the two wins */
+               iov_data_len = iov_length((struct iovec *)iov,
+                                         hdr->iovec_count);
+               if (hdr->dxfer_len < iov_data_len) {
+                       hdr->iovec_count = iov_shorten((struct iovec *)iov,
+                                                      hdr->iovec_count,
+                                                      hdr->dxfer_len);
+                       iov_data_len = hdr->dxfer_len;
+               }
+
                ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count,
-                                         hdr->dxfer_len, GFP_KERNEL);
+                                         iov_data_len, GFP_KERNEL);
                kfree(iov);
        } else if (hdr->dxfer_len)
                ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,