@@ -877,7 +877,12 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
if (unlikely(!current->io_context))
create_task_io_context(current, GFP_ATOMIC, q->node);
- if ((bio->bi_opf & REQ_HIPRI) && blk_queue_support_bio_poll(q))
+ /*
+ * If REQ_POLL_CTX isn't set for this HIPRI bio, we think it
+ * originated from FS and allocate io polling context.
+ */
+ if ((bio->bi_opf & REQ_HIPRI) && !(bio->bi_opf & REQ_POLL_CTX) &&
+ blk_queue_support_bio_poll(q))
blk_create_io_poll_context(q);
blk_poll_prepare(q, bio);
@@ -393,11 +393,30 @@ static inline struct blk_bio_poll_ctx *blk_get_bio_poll_ctx(void)
static inline void blk_poll_prepare(struct request_queue *q,
struct bio *bio)
{
+ bool mq;
+
if (!(bio->bi_opf & REQ_HIPRI))
return;
- if (!blk_queue_poll(q) || (!queue_is_mq(q) && !blk_get_bio_poll_ctx()))
+ /*
+ * Can't support bio based IO polling without per-task poll ctx
+ *
+ * We have created per-task io poll context, and mark this
+ * bio as REQ_POLL_CTX, so: 1) if any cloned bio from this bio is
+ * submitted from another kernel context, we won't create bio
+ * poll context for it, and that bio can be completed by IRQ;
+ * 2) If such bio is submitted from current context, we will
+ * complete it via blk_poll(); 3) If driver knows that one
+ * underlying bio allocated from driver is for FS bio, meantime
+ * it is submitted in current context, driver can mark such bio
+ * as REQ_HIPRI & REQ_POLL_CTX manually, so the bio can be completed
+ * via blk_poll too.
+ */
+ mq = queue_is_mq(q);
+ if (!blk_queue_poll(q) || (!mq && !blk_get_bio_poll_ctx()))
bio->bi_opf &= ~REQ_HIPRI;
+ else if (!mq)
+ bio->bi_opf |= REQ_POLL_CTX;
}
static inline void blk_create_io_poll_context(struct request_queue *q)
@@ -394,6 +394,9 @@ enum req_flag_bits {
__REQ_HIPRI,
+ /* for marking IOs originated from same FS bio in same context */
+ __REQ_POLL_CTX,
+
/* for driver use */
__REQ_DRV,
__REQ_SWAP, /* swapping request. */
@@ -418,6 +421,7 @@ enum req_flag_bits {
#define REQ_NOUNMAP (1ULL << __REQ_NOUNMAP)
#define REQ_HIPRI (1ULL << __REQ_HIPRI)
+#define REQ_POLL_CTX (1ULL << __REQ_POLL_CTX)
#define REQ_DRV (1ULL << __REQ_DRV)
#define REQ_SWAP (1ULL << __REQ_SWAP)