Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 2 | #ifndef BLK_STAT_H |
| 3 | #define BLK_STAT_H |
| 4 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 5 | #include <linux/kernel.h> |
| 6 | #include <linux/blkdev.h> |
| 7 | #include <linux/ktime.h> |
| 8 | #include <linux/rcupdate.h> |
| 9 | #include <linux/timer.h> |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 10 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 11 | /** |
| 12 | * struct blk_stat_callback - Block statistics callback. |
| 13 | * |
| 14 | * A &struct blk_stat_callback is associated with a &struct request_queue. While |
| 15 | * @timer is active, that queue's request completion latencies are sorted into |
| 16 | * buckets by @bucket_fn and added to a per-cpu buffer, @cpu_stat. When the |
| 17 | * timer fires, @cpu_stat is flushed to @stat and @timer_fn is invoked. |
| 18 | */ |
| 19 | struct blk_stat_callback { |
| 20 | /* |
| 21 | * @list: RCU list of callbacks for a &struct request_queue. |
| 22 | */ |
| 23 | struct list_head list; |
| 24 | |
| 25 | /** |
| 26 | * @timer: Timer for the next callback invocation. |
| 27 | */ |
| 28 | struct timer_list timer; |
| 29 | |
| 30 | /** |
| 31 | * @cpu_stat: Per-cpu statistics buckets. |
| 32 | */ |
| 33 | struct blk_rq_stat __percpu *cpu_stat; |
| 34 | |
| 35 | /** |
| 36 | * @bucket_fn: Given a request, returns which statistics bucket it |
Stephen Bates | a37244e | 2017-04-20 15:29:16 -0600 | [diff] [blame] | 37 | * should be accounted under. Return -1 for no bucket for this |
| 38 | * request. |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 39 | */ |
Stephen Bates | a37244e | 2017-04-20 15:29:16 -0600 | [diff] [blame] | 40 | int (*bucket_fn)(const struct request *); |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 41 | |
| 42 | /** |
| 43 | * @buckets: Number of statistics buckets. |
| 44 | */ |
| 45 | unsigned int buckets; |
| 46 | |
| 47 | /** |
| 48 | * @stat: Array of statistics buckets. |
| 49 | */ |
| 50 | struct blk_rq_stat *stat; |
| 51 | |
| 52 | /** |
| 53 | * @fn: Callback function. |
| 54 | */ |
| 55 | void (*timer_fn)(struct blk_stat_callback *); |
| 56 | |
| 57 | /** |
| 58 | * @data: Private pointer for the user. |
| 59 | */ |
| 60 | void *data; |
| 61 | |
| 62 | struct rcu_head rcu; |
| 63 | }; |
| 64 | |
| 65 | struct blk_queue_stats *blk_alloc_queue_stats(void); |
| 66 | void blk_free_queue_stats(struct blk_queue_stats *); |
| 67 | |
Omar Sandoval | 522a777 | 2018-05-09 02:08:53 -0700 | [diff] [blame] | 68 | void blk_stat_add(struct request *rq, u64 now); |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 69 | |
Shaohua Li | b9147dd | 2017-03-27 15:19:42 -0700 | [diff] [blame] | 70 | /* record time/size info in request but not add a callback */ |
| 71 | void blk_stat_enable_accounting(struct request_queue *q); |
| 72 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 73 | /** |
| 74 | * blk_stat_alloc_callback() - Allocate a block statistics callback. |
| 75 | * @timer_fn: Timer callback function. |
| 76 | * @bucket_fn: Bucket callback function. |
| 77 | * @buckets: Number of statistics buckets. |
| 78 | * @data: Value for the @data field of the &struct blk_stat_callback. |
| 79 | * |
| 80 | * See &struct blk_stat_callback for details on the callback functions. |
| 81 | * |
| 82 | * Return: &struct blk_stat_callback on success or NULL on ENOMEM. |
| 83 | */ |
| 84 | struct blk_stat_callback * |
| 85 | blk_stat_alloc_callback(void (*timer_fn)(struct blk_stat_callback *), |
Stephen Bates | a37244e | 2017-04-20 15:29:16 -0600 | [diff] [blame] | 86 | int (*bucket_fn)(const struct request *), |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 87 | unsigned int buckets, void *data); |
| 88 | |
| 89 | /** |
| 90 | * blk_stat_add_callback() - Add a block statistics callback to be run on a |
| 91 | * request queue. |
| 92 | * @q: The request queue. |
| 93 | * @cb: The callback. |
| 94 | * |
| 95 | * Note that a single &struct blk_stat_callback can only be added to a single |
| 96 | * &struct request_queue. |
| 97 | */ |
| 98 | void blk_stat_add_callback(struct request_queue *q, |
| 99 | struct blk_stat_callback *cb); |
| 100 | |
| 101 | /** |
| 102 | * blk_stat_remove_callback() - Remove a block statistics callback from a |
| 103 | * request queue. |
| 104 | * @q: The request queue. |
| 105 | * @cb: The callback. |
| 106 | * |
| 107 | * When this returns, the callback is not running on any CPUs and will not be |
| 108 | * called again unless readded. |
| 109 | */ |
| 110 | void blk_stat_remove_callback(struct request_queue *q, |
| 111 | struct blk_stat_callback *cb); |
| 112 | |
| 113 | /** |
| 114 | * blk_stat_free_callback() - Free a block statistics callback. |
| 115 | * @cb: The callback. |
| 116 | * |
| 117 | * @cb may be NULL, in which case this does nothing. If it is not NULL, @cb must |
| 118 | * not be associated with a request queue. I.e., if it was previously added with |
| 119 | * blk_stat_add_callback(), it must also have been removed since then with |
| 120 | * blk_stat_remove_callback(). |
| 121 | */ |
| 122 | void blk_stat_free_callback(struct blk_stat_callback *cb); |
| 123 | |
| 124 | /** |
| 125 | * blk_stat_is_active() - Check if a block statistics callback is currently |
| 126 | * gathering statistics. |
| 127 | * @cb: The callback. |
| 128 | */ |
| 129 | static inline bool blk_stat_is_active(struct blk_stat_callback *cb) |
| 130 | { |
| 131 | return timer_pending(&cb->timer); |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * blk_stat_activate_nsecs() - Gather block statistics during a time window in |
| 136 | * nanoseconds. |
| 137 | * @cb: The callback. |
| 138 | * @nsecs: Number of nanoseconds to gather statistics for. |
| 139 | * |
| 140 | * The timer callback will be called when the window expires. |
| 141 | */ |
| 142 | static inline void blk_stat_activate_nsecs(struct blk_stat_callback *cb, |
| 143 | u64 nsecs) |
| 144 | { |
| 145 | mod_timer(&cb->timer, jiffies + nsecs_to_jiffies(nsecs)); |
| 146 | } |
| 147 | |
Ming Lei | 544fbd1 | 2018-12-12 19:44:34 +0800 | [diff] [blame] | 148 | static inline void blk_stat_deactivate(struct blk_stat_callback *cb) |
| 149 | { |
| 150 | del_timer_sync(&cb->timer); |
| 151 | } |
| 152 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 153 | /** |
| 154 | * blk_stat_activate_msecs() - Gather block statistics during a time window in |
| 155 | * milliseconds. |
| 156 | * @cb: The callback. |
| 157 | * @msecs: Number of milliseconds to gather statistics for. |
| 158 | * |
| 159 | * The timer callback will be called when the window expires. |
| 160 | */ |
| 161 | static inline void blk_stat_activate_msecs(struct blk_stat_callback *cb, |
| 162 | unsigned int msecs) |
| 163 | { |
| 164 | mod_timer(&cb->timer, jiffies + msecs_to_jiffies(msecs)); |
| 165 | } |
| 166 | |
Josef Bacik | 2ecbf45 | 2018-07-03 11:14:57 -0400 | [diff] [blame] | 167 | void blk_rq_stat_add(struct blk_rq_stat *, u64); |
| 168 | void blk_rq_stat_sum(struct blk_rq_stat *, struct blk_rq_stat *); |
| 169 | void blk_rq_stat_init(struct blk_rq_stat *); |
| 170 | |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 171 | #endif |