platform/x86: intel-uncore-freq: Fix types in sysfs callbacks
[linux-2.6-microblaze.git] / block / blk-mq.c
index c11c97a..aa87fcf 100644 (file)
@@ -772,11 +772,16 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
                /*
                 * Partial zone append completions cannot be supported as the
                 * BIO fragments may end up not being written sequentially.
+                * For such case, force the completed nbytes to be equal to
+                * the BIO size so that bio_advance() sets the BIO remaining
+                * size to 0 and we end up calling bio_endio() before returning.
                 */
-               if (bio->bi_iter.bi_size != nbytes)
+               if (bio->bi_iter.bi_size != nbytes) {
                        bio->bi_status = BLK_STS_IOERR;
-               else
+                       nbytes = bio->bi_iter.bi_size;
+               } else {
                        bio->bi_iter.bi_sector = rq->__sector;
+               }
        }
 
        bio_advance(bio, nbytes);
@@ -1859,6 +1864,22 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx *hctx,
        wait->flags &= ~WQ_FLAG_EXCLUSIVE;
        __add_wait_queue(wq, wait);
 
+       /*
+        * Add one explicit barrier since blk_mq_get_driver_tag() may
+        * not imply barrier in case of failure.
+        *
+        * Order adding us to wait queue and allocating driver tag.
+        *
+        * The pair is the one implied in sbitmap_queue_wake_up() which
+        * orders clearing sbitmap tag bits and waitqueue_active() in
+        * __sbitmap_queue_wake_up(), since waitqueue_active() is lockless
+        *
+        * Otherwise, re-order of adding wait queue and getting driver tag
+        * may cause __sbitmap_queue_wake_up() to wake up nothing because
+        * the waitqueue_active() may not observe us in wait queue.
+        */
+       smp_mb();
+
        /*
         * It's possible that a tag was freed in the window between the
         * allocation failure and adding the hardware queue to the wait
@@ -2891,8 +2912,11 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q,
        return NULL;
 }
 
-/* return true if this @rq can be used for @bio */
-static bool blk_mq_can_use_cached_rq(struct request *rq, struct blk_plug *plug,
+/*
+ * Check if we can use the passed on request for submitting the passed in bio,
+ * and remove it from the request list if it can be used.
+ */
+static bool blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug,
                struct bio *bio)
 {
        enum hctx_type type = blk_mq_get_hctx_type(bio->bi_opf);
@@ -2952,12 +2976,6 @@ void blk_mq_submit_bio(struct bio *bio)
        blk_status_t ret;
 
        bio = blk_queue_bounce(bio, q);
-       if (bio_may_exceed_limits(bio, &q->limits)) {
-               bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
-               if (!bio)
-                       return;
-       }
-
        bio_set_ioprio(bio);
 
        if (plug) {
@@ -2966,16 +2984,26 @@ void blk_mq_submit_bio(struct bio *bio)
                        rq = NULL;
        }
        if (rq) {
+               if (unlikely(bio_may_exceed_limits(bio, &q->limits))) {
+                       bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
+                       if (!bio)
+                               return;
+               }
                if (!bio_integrity_prep(bio))
                        return;
                if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
                        return;
-               if (blk_mq_can_use_cached_rq(rq, plug, bio))
+               if (blk_mq_use_cached_rq(rq, plug, bio))
                        goto done;
                percpu_ref_get(&q->q_usage_counter);
        } else {
                if (unlikely(bio_queue_enter(bio)))
                        return;
+               if (unlikely(bio_may_exceed_limits(bio, &q->limits))) {
+                       bio = __bio_split_to_limits(bio, &q->limits, &nr_segs);
+                       if (!bio)
+                               goto fail;
+               }
                if (!bio_integrity_prep(bio))
                        goto fail;
        }