nfsd: track last inode only in use_wgather case
[safe/jmp/linux-2.6] / block / blk-map.c
index 4849fa3..f103729 100644 (file)
@@ -42,7 +42,7 @@ static int __blk_rq_unmap_user(struct bio *bio)
 
 static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
                             struct rq_map_data *map_data, void __user *ubuf,
-                            unsigned int len, int null_mapped, gfp_t gfp_mask)
+                            unsigned int len, gfp_t gfp_mask)
 {
        unsigned long uaddr;
        struct bio *bio, *orig_bio;
@@ -63,7 +63,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
-       if (null_mapped)
+       if (map_data && map_data->null_mapped)
                bio->bi_flags |= (1 << BIO_NULL_MAPPED);
 
        orig_bio = bio;
@@ -114,17 +114,15 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
 {
        unsigned long bytes_read = 0;
        struct bio *bio = NULL;
-       int ret, null_mapped = 0;
+       int ret;
 
        if (len > (q->max_hw_sectors << 9))
                return -EINVAL;
        if (!len)
                return -EINVAL;
-       if (!ubuf) {
-               if (!map_data || rq_data_dir(rq) != READ)
-                       return -EINVAL;
-               null_mapped = 1;
-       }
+
+       if (!ubuf && (!map_data || !map_data->null_mapped))
+               return -EINVAL;
 
        while (bytes_read != len) {
                unsigned long map_len, end, start;
@@ -143,13 +141,16 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
                        map_len -= PAGE_SIZE;
 
                ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len,
-                                       null_mapped, gfp_mask);
+                                       gfp_mask);
                if (ret < 0)
                        goto unmap_rq;
                if (!bio)
                        bio = rq->bio;
                bytes_read += ret;
                ubuf += ret;
+
+               if (map_data)
+                       map_data->offset += ret;
        }
 
        if (!bio_flagged(bio, BIO_USER_MAPPED))
@@ -217,8 +218,14 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                return PTR_ERR(bio);
 
        if (bio->bi_size != len) {
+               /*
+                * Grab an extra reference to this bio, as bio_unmap_user()
+                * expects to be able to drop it twice as it happens on the
+                * normal IO completion path
+                */
+               bio_get(bio);
                bio_endio(bio, 0);
-               bio_unmap_user(bio);
+               __blk_rq_unmap_user(bio);
                return -EINVAL;
        }