Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / block / blk-wbt.c
index f92fc84b5e2c497b77578408c10c22bf37929384..4f89b28fa6524d117b5ad6a53a605ebda8e57b93 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/wbt.h>
 
+static inline void wbt_clear_state(struct request *rq)
+{
+       rq->wbt_flags = 0;
+}
+
+static inline enum wbt_flags wbt_flags(struct request *rq)
+{
+       return rq->wbt_flags;
+}
+
+static inline bool wbt_is_tracked(struct request *rq)
+{
+       return rq->wbt_flags & WBT_TRACKED;
+}
+
+static inline bool wbt_is_read(struct request *rq)
+{
+       return rq->wbt_flags & WBT_READ;
+}
+
 enum {
        /*
         * Default setting, we'll scale up (to 75% of QD max) or down (min 1)
@@ -101,9 +121,15 @@ static bool wb_recent_wait(struct rq_wb *rwb)
        return time_before(jiffies, wb->dirty_sleep + HZ);
 }
 
-static inline struct rq_wait *get_rq_wait(struct rq_wb *rwb, bool is_kswapd)
+static inline struct rq_wait *get_rq_wait(struct rq_wb *rwb,
+                                         enum wbt_flags wb_acct)
 {
-       return &rwb->rq_wait[is_kswapd];
+       if (wb_acct & WBT_KSWAPD)
+               return &rwb->rq_wait[WBT_RWQ_KSWAPD];
+       else if (wb_acct & WBT_DISCARD)
+               return &rwb->rq_wait[WBT_RWQ_DISCARD];
+
+       return &rwb->rq_wait[WBT_RWQ_BG];
 }
 
 static void rwb_wake_all(struct rq_wb *rwb)
@@ -126,7 +152,7 @@ void __wbt_done(struct rq_wb *rwb, enum wbt_flags wb_acct)
        if (!(wb_acct & WBT_TRACKED))
                return;
 
-       rqw = get_rq_wait(rwb, wb_acct & WBT_KSWAPD);
+       rqw = get_rq_wait(rwb, wb_acct);
        inflight = atomic_dec_return(&rqw->inflight);
 
        /*
@@ -139,10 +165,13 @@ void __wbt_done(struct rq_wb *rwb, enum wbt_flags wb_acct)
        }
 
        /*
-        * If the device does write back caching, drop further down
-        * before we wake people up.
+        * For discards, our limit is always the background. For writes, if
+        * the device does write back caching, drop further down before we
+        * wake people up.
         */
-       if (rwb->wc && !wb_recent_wait(rwb))
+       if (wb_acct & WBT_DISCARD)
+               limit = rwb->wb_background;
+       else if (rwb->wc && !wb_recent_wait(rwb))
                limit = 0;
        else
                limit = rwb->wb_normal;
@@ -165,24 +194,24 @@ void __wbt_done(struct rq_wb *rwb, enum wbt_flags wb_acct)
  * Called on completion of a request. Note that it's also called when
  * a request is merged, when the request gets freed.
  */
-void wbt_done(struct rq_wb *rwb, struct blk_issue_stat *stat)
+void wbt_done(struct rq_wb *rwb, struct request *rq)
 {
        if (!rwb)
                return;
 
-       if (!wbt_is_tracked(stat)) {
-               if (rwb->sync_cookie == stat) {
+       if (!wbt_is_tracked(rq)) {
+               if (rwb->sync_cookie == rq) {
                        rwb->sync_issue = 0;
                        rwb->sync_cookie = NULL;
                }
 
-               if (wbt_is_read(stat))
+               if (wbt_is_read(rq))
                        wb_timestamp(rwb, &rwb->last_comp);
        } else {
-               WARN_ON_ONCE(stat == rwb->sync_cookie);
-               __wbt_done(rwb, wbt_stat_to_mask(stat));
+               WARN_ON_ONCE(rq == rwb->sync_cookie);
+               __wbt_done(rwb, wbt_flags(rq));
        }
-       wbt_clear_state(stat);
+       wbt_clear_state(rq);
 }
 
 /*
@@ -479,6 +508,9 @@ static inline unsigned int get_limit(struct rq_wb *rwb, unsigned long rw)
 {
        unsigned int limit;
 
+       if ((rw & REQ_OP_MASK) == REQ_OP_DISCARD)
+               return rwb->wb_background;
+
        /*
         * At this point we know it's a buffered write. If this is
         * kswapd trying to free memory, or REQ_SYNC is set, then
@@ -529,11 +561,12 @@ static inline bool may_queue(struct rq_wb *rwb, struct rq_wait *rqw,
  * Block if we will exceed our limit, or if we are currently waiting for
  * the timer to kick off queuing again.
  */
-static void __wbt_wait(struct rq_wb *rwb, unsigned long rw, spinlock_t *lock)
+static void __wbt_wait(struct rq_wb *rwb, enum wbt_flags wb_acct,
+                      unsigned long rw, spinlock_t *lock)
        __releases(lock)
        __acquires(lock)
 {
-       struct rq_wait *rqw = get_rq_wait(rwb, current_is_kswapd());
+       struct rq_wait *rqw = get_rq_wait(rwb, wb_acct);
        DEFINE_WAIT(wait);
 
        if (may_queue(rwb, rqw, &wait, rw))
@@ -559,21 +592,20 @@ static void __wbt_wait(struct rq_wb *rwb, unsigned long rw, spinlock_t *lock)
 
 static inline bool wbt_should_throttle(struct rq_wb *rwb, struct bio *bio)
 {
-       const int op = bio_op(bio);
-
-       /*
-        * If not a WRITE, do nothing
-        */
-       if (op != REQ_OP_WRITE)
-               return false;
-
-       /*
-        * Don't throttle WRITE_ODIRECT
-        */
-       if ((bio->bi_opf & (REQ_SYNC | REQ_IDLE)) == (REQ_SYNC | REQ_IDLE))
+       switch (bio_op(bio)) {
+       case REQ_OP_WRITE:
+               /*
+                * Don't throttle WRITE_ODIRECT
+                */
+               if ((bio->bi_opf & (REQ_SYNC | REQ_IDLE)) ==
+                   (REQ_SYNC | REQ_IDLE))
+                       return false;
+               /* fallthrough */
+       case REQ_OP_DISCARD:
+               return true;
+       default:
                return false;
-
-       return true;
+       }
 }
 
 /*
@@ -584,7 +616,7 @@ static inline bool wbt_should_throttle(struct rq_wb *rwb, struct bio *bio)
  */
 enum wbt_flags wbt_wait(struct rq_wb *rwb, struct bio *bio, spinlock_t *lock)
 {
-       unsigned int ret = 0;
+       enum wbt_flags ret = 0;
 
        if (!rwb_enabled(rwb))
                return 0;
@@ -598,41 +630,42 @@ enum wbt_flags wbt_wait(struct rq_wb *rwb, struct bio *bio, spinlock_t *lock)
                return ret;
        }
 
-       __wbt_wait(rwb, bio->bi_opf, lock);
+       if (current_is_kswapd())
+               ret |= WBT_KSWAPD;
+       if (bio_op(bio) == REQ_OP_DISCARD)
+               ret |= WBT_DISCARD;
+
+       __wbt_wait(rwb, ret, bio->bi_opf, lock);
 
        if (!blk_stat_is_active(rwb->cb))
                rwb_arm_timer(rwb);
 
-       if (current_is_kswapd())
-               ret |= WBT_KSWAPD;
-
        return ret | WBT_TRACKED;
 }
 
-void wbt_issue(struct rq_wb *rwb, struct blk_issue_stat *stat)
+void wbt_issue(struct rq_wb *rwb, struct request *rq)
 {
        if (!rwb_enabled(rwb))
                return;
 
        /*
-        * Track sync issue, in case it takes a long time to complete. Allows
-        * us to react quicker, if a sync IO takes a long time to complete.
-        * Note that this is just a hint. 'stat' can go away when the
-        * request completes, so it's important we never dereference it. We
-        * only use the address to compare with, which is why we store the
-        * sync_issue time locally.
+        * Track sync issue, in case it takes a long time to complete. Allows us
+        * to react quicker, if a sync IO takes a long time to complete. Note
+        * that this is just a hint. The request can go away when it completes,
+        * so it's important we never dereference it. We only use the address to
+        * compare with, which is why we store the sync_issue time locally.
         */
-       if (wbt_is_read(stat) && !rwb->sync_issue) {
-               rwb->sync_cookie = stat;
-               rwb->sync_issue = blk_stat_time(stat);
+       if (wbt_is_read(rq) && !rwb->sync_issue) {
+               rwb->sync_cookie = rq;
+               rwb->sync_issue = rq->io_start_time_ns;
        }
 }
 
-void wbt_requeue(struct rq_wb *rwb, struct blk_issue_stat *stat)
+void wbt_requeue(struct rq_wb *rwb, struct request *rq)
 {
        if (!rwb_enabled(rwb))
                return;
-       if (stat == rwb->sync_cookie) {
+       if (rq == rwb->sync_cookie) {
                rwb->sync_issue = 0;
                rwb->sync_cookie = NULL;
        }
@@ -701,7 +734,7 @@ static int wbt_data_dir(const struct request *rq)
 
        if (op == REQ_OP_READ)
                return READ;
-       else if (op == REQ_OP_WRITE || op == REQ_OP_FLUSH)
+       else if (op_is_write(op))
                return WRITE;
 
        /* don't account */
@@ -713,8 +746,6 @@ int wbt_init(struct request_queue *q)
        struct rq_wb *rwb;
        int i;
 
-       BUILD_BUG_ON(WBT_NR_BITS > BLK_STAT_RES_BITS);
-
        rwb = kzalloc(sizeof(*rwb), GFP_KERNEL);
        if (!rwb)
                return -ENOMEM;