@@ -840,11 +840,30 @@ static inline bool blk_queue_support_bio_poll(struct request_queue *q)
static inline void blk_bio_poll_preprocess(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 noinline_for_stack bool submit_bio_checks(struct bio *bio)
@@ -900,7 +919,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 (blk_queue_support_bio_poll(q) && (bio->bi_opf & REQ_HIPRI))
+ /*
+ * If REQ_POLL_CTX isn't set for this HIPRI bio, we think it
+ * originated from FS and allocate io polling context.
+ */
+ if (blk_queue_support_bio_poll(q) && (bio->bi_opf & REQ_HIPRI) &&
+ !(bio->bi_opf & REQ_POLL_CTX))
blk_create_io_poll_context(q);
blk_bio_poll_preprocess(q, bio);
@@ -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)