1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 2cf43e6beSJens Axboe #ifndef BLK_STAT_H 3cf43e6beSJens Axboe #define BLK_STAT_H 4cf43e6beSJens Axboe 534dbad5dSOmar Sandoval #include <linux/kernel.h> 634dbad5dSOmar Sandoval #include <linux/blkdev.h> 734dbad5dSOmar Sandoval #include <linux/ktime.h> 834dbad5dSOmar Sandoval #include <linux/rcupdate.h> 934dbad5dSOmar Sandoval #include <linux/timer.h> 10cf43e6beSJens Axboe 11cf43e6beSJens Axboe /* 1288eeca49SShaohua Li * from upper: 1388eeca49SShaohua Li * 3 bits: reserved for other usage 1488eeca49SShaohua Li * 12 bits: size 1588eeca49SShaohua Li * 49 bits: time 16cf43e6beSJens Axboe */ 17cf43e6beSJens Axboe #define BLK_STAT_RES_BITS 3 1888eeca49SShaohua Li #define BLK_STAT_SIZE_BITS 12 1988eeca49SShaohua Li #define BLK_STAT_RES_SHIFT (64 - BLK_STAT_RES_BITS) 2088eeca49SShaohua Li #define BLK_STAT_SIZE_SHIFT (BLK_STAT_RES_SHIFT - BLK_STAT_SIZE_BITS) 2188eeca49SShaohua Li #define BLK_STAT_TIME_MASK ((1ULL << BLK_STAT_SIZE_SHIFT) - 1) 2288eeca49SShaohua Li #define BLK_STAT_SIZE_MASK \ 2388eeca49SShaohua Li (((1ULL << BLK_STAT_SIZE_BITS) - 1) << BLK_STAT_SIZE_SHIFT) 2488eeca49SShaohua Li #define BLK_STAT_RES_MASK (~((1ULL << BLK_STAT_RES_SHIFT) - 1)) 25cf43e6beSJens Axboe 2634dbad5dSOmar Sandoval /** 2734dbad5dSOmar Sandoval * struct blk_stat_callback - Block statistics callback. 2834dbad5dSOmar Sandoval * 2934dbad5dSOmar Sandoval * A &struct blk_stat_callback is associated with a &struct request_queue. While 3034dbad5dSOmar Sandoval * @timer is active, that queue's request completion latencies are sorted into 3134dbad5dSOmar Sandoval * buckets by @bucket_fn and added to a per-cpu buffer, @cpu_stat. When the 3234dbad5dSOmar Sandoval * timer fires, @cpu_stat is flushed to @stat and @timer_fn is invoked. 3334dbad5dSOmar Sandoval */ 3434dbad5dSOmar Sandoval struct blk_stat_callback { 3534dbad5dSOmar Sandoval /* 3634dbad5dSOmar Sandoval * @list: RCU list of callbacks for a &struct request_queue. 3734dbad5dSOmar Sandoval */ 3834dbad5dSOmar Sandoval struct list_head list; 3934dbad5dSOmar Sandoval 4034dbad5dSOmar Sandoval /** 4134dbad5dSOmar Sandoval * @timer: Timer for the next callback invocation. 4234dbad5dSOmar Sandoval */ 4334dbad5dSOmar Sandoval struct timer_list timer; 4434dbad5dSOmar Sandoval 4534dbad5dSOmar Sandoval /** 4634dbad5dSOmar Sandoval * @cpu_stat: Per-cpu statistics buckets. 4734dbad5dSOmar Sandoval */ 4834dbad5dSOmar Sandoval struct blk_rq_stat __percpu *cpu_stat; 4934dbad5dSOmar Sandoval 5034dbad5dSOmar Sandoval /** 5134dbad5dSOmar Sandoval * @bucket_fn: Given a request, returns which statistics bucket it 52a37244e4SStephen Bates * should be accounted under. Return -1 for no bucket for this 53a37244e4SStephen Bates * request. 5434dbad5dSOmar Sandoval */ 55a37244e4SStephen Bates int (*bucket_fn)(const struct request *); 5634dbad5dSOmar Sandoval 5734dbad5dSOmar Sandoval /** 5834dbad5dSOmar Sandoval * @buckets: Number of statistics buckets. 5934dbad5dSOmar Sandoval */ 6034dbad5dSOmar Sandoval unsigned int buckets; 6134dbad5dSOmar Sandoval 6234dbad5dSOmar Sandoval /** 6334dbad5dSOmar Sandoval * @stat: Array of statistics buckets. 6434dbad5dSOmar Sandoval */ 6534dbad5dSOmar Sandoval struct blk_rq_stat *stat; 6634dbad5dSOmar Sandoval 6734dbad5dSOmar Sandoval /** 6834dbad5dSOmar Sandoval * @fn: Callback function. 6934dbad5dSOmar Sandoval */ 7034dbad5dSOmar Sandoval void (*timer_fn)(struct blk_stat_callback *); 7134dbad5dSOmar Sandoval 7234dbad5dSOmar Sandoval /** 7334dbad5dSOmar Sandoval * @data: Private pointer for the user. 7434dbad5dSOmar Sandoval */ 7534dbad5dSOmar Sandoval void *data; 7634dbad5dSOmar Sandoval 7734dbad5dSOmar Sandoval struct rcu_head rcu; 7834dbad5dSOmar Sandoval }; 7934dbad5dSOmar Sandoval 8034dbad5dSOmar Sandoval struct blk_queue_stats *blk_alloc_queue_stats(void); 8134dbad5dSOmar Sandoval void blk_free_queue_stats(struct blk_queue_stats *); 8234dbad5dSOmar Sandoval 8334dbad5dSOmar Sandoval void blk_stat_add(struct request *); 8434dbad5dSOmar Sandoval 85cf43e6beSJens Axboe static inline u64 __blk_stat_time(u64 time) 86cf43e6beSJens Axboe { 87cf43e6beSJens Axboe return time & BLK_STAT_TIME_MASK; 88cf43e6beSJens Axboe } 89cf43e6beSJens Axboe 90cf43e6beSJens Axboe static inline u64 blk_stat_time(struct blk_issue_stat *stat) 91cf43e6beSJens Axboe { 9288eeca49SShaohua Li return __blk_stat_time(stat->stat); 9388eeca49SShaohua Li } 9488eeca49SShaohua Li 9588eeca49SShaohua Li static inline sector_t blk_capped_size(sector_t size) 9688eeca49SShaohua Li { 9788eeca49SShaohua Li return size & ((1ULL << BLK_STAT_SIZE_BITS) - 1); 9888eeca49SShaohua Li } 9988eeca49SShaohua Li 10088eeca49SShaohua Li static inline sector_t blk_stat_size(struct blk_issue_stat *stat) 10188eeca49SShaohua Li { 10288eeca49SShaohua Li return (stat->stat & BLK_STAT_SIZE_MASK) >> BLK_STAT_SIZE_SHIFT; 10388eeca49SShaohua Li } 10488eeca49SShaohua Li 10588eeca49SShaohua Li static inline void blk_stat_set_issue(struct blk_issue_stat *stat, 10688eeca49SShaohua Li sector_t size) 10788eeca49SShaohua Li { 10888eeca49SShaohua Li stat->stat = (stat->stat & BLK_STAT_RES_MASK) | 10988eeca49SShaohua Li (ktime_to_ns(ktime_get()) & BLK_STAT_TIME_MASK) | 11088eeca49SShaohua Li (((u64)blk_capped_size(size)) << BLK_STAT_SIZE_SHIFT); 111cf43e6beSJens Axboe } 112cf43e6beSJens Axboe 113b9147dd1SShaohua Li /* record time/size info in request but not add a callback */ 114b9147dd1SShaohua Li void blk_stat_enable_accounting(struct request_queue *q); 115b9147dd1SShaohua Li 11634dbad5dSOmar Sandoval /** 11734dbad5dSOmar Sandoval * blk_stat_alloc_callback() - Allocate a block statistics callback. 11834dbad5dSOmar Sandoval * @timer_fn: Timer callback function. 11934dbad5dSOmar Sandoval * @bucket_fn: Bucket callback function. 12034dbad5dSOmar Sandoval * @buckets: Number of statistics buckets. 12134dbad5dSOmar Sandoval * @data: Value for the @data field of the &struct blk_stat_callback. 12234dbad5dSOmar Sandoval * 12334dbad5dSOmar Sandoval * See &struct blk_stat_callback for details on the callback functions. 12434dbad5dSOmar Sandoval * 12534dbad5dSOmar Sandoval * Return: &struct blk_stat_callback on success or NULL on ENOMEM. 12634dbad5dSOmar Sandoval */ 12734dbad5dSOmar Sandoval struct blk_stat_callback * 12834dbad5dSOmar Sandoval blk_stat_alloc_callback(void (*timer_fn)(struct blk_stat_callback *), 129a37244e4SStephen Bates int (*bucket_fn)(const struct request *), 13034dbad5dSOmar Sandoval unsigned int buckets, void *data); 13134dbad5dSOmar Sandoval 13234dbad5dSOmar Sandoval /** 13334dbad5dSOmar Sandoval * blk_stat_add_callback() - Add a block statistics callback to be run on a 13434dbad5dSOmar Sandoval * request queue. 13534dbad5dSOmar Sandoval * @q: The request queue. 13634dbad5dSOmar Sandoval * @cb: The callback. 13734dbad5dSOmar Sandoval * 13834dbad5dSOmar Sandoval * Note that a single &struct blk_stat_callback can only be added to a single 13934dbad5dSOmar Sandoval * &struct request_queue. 14034dbad5dSOmar Sandoval */ 14134dbad5dSOmar Sandoval void blk_stat_add_callback(struct request_queue *q, 14234dbad5dSOmar Sandoval struct blk_stat_callback *cb); 14334dbad5dSOmar Sandoval 14434dbad5dSOmar Sandoval /** 14534dbad5dSOmar Sandoval * blk_stat_remove_callback() - Remove a block statistics callback from a 14634dbad5dSOmar Sandoval * request queue. 14734dbad5dSOmar Sandoval * @q: The request queue. 14834dbad5dSOmar Sandoval * @cb: The callback. 14934dbad5dSOmar Sandoval * 15034dbad5dSOmar Sandoval * When this returns, the callback is not running on any CPUs and will not be 15134dbad5dSOmar Sandoval * called again unless readded. 15234dbad5dSOmar Sandoval */ 15334dbad5dSOmar Sandoval void blk_stat_remove_callback(struct request_queue *q, 15434dbad5dSOmar Sandoval struct blk_stat_callback *cb); 15534dbad5dSOmar Sandoval 15634dbad5dSOmar Sandoval /** 15734dbad5dSOmar Sandoval * blk_stat_free_callback() - Free a block statistics callback. 15834dbad5dSOmar Sandoval * @cb: The callback. 15934dbad5dSOmar Sandoval * 16034dbad5dSOmar Sandoval * @cb may be NULL, in which case this does nothing. If it is not NULL, @cb must 16134dbad5dSOmar Sandoval * not be associated with a request queue. I.e., if it was previously added with 16234dbad5dSOmar Sandoval * blk_stat_add_callback(), it must also have been removed since then with 16334dbad5dSOmar Sandoval * blk_stat_remove_callback(). 16434dbad5dSOmar Sandoval */ 16534dbad5dSOmar Sandoval void blk_stat_free_callback(struct blk_stat_callback *cb); 16634dbad5dSOmar Sandoval 16734dbad5dSOmar Sandoval /** 16834dbad5dSOmar Sandoval * blk_stat_is_active() - Check if a block statistics callback is currently 16934dbad5dSOmar Sandoval * gathering statistics. 17034dbad5dSOmar Sandoval * @cb: The callback. 17134dbad5dSOmar Sandoval */ 17234dbad5dSOmar Sandoval static inline bool blk_stat_is_active(struct blk_stat_callback *cb) 17334dbad5dSOmar Sandoval { 17434dbad5dSOmar Sandoval return timer_pending(&cb->timer); 17534dbad5dSOmar Sandoval } 17634dbad5dSOmar Sandoval 17734dbad5dSOmar Sandoval /** 17834dbad5dSOmar Sandoval * blk_stat_activate_nsecs() - Gather block statistics during a time window in 17934dbad5dSOmar Sandoval * nanoseconds. 18034dbad5dSOmar Sandoval * @cb: The callback. 18134dbad5dSOmar Sandoval * @nsecs: Number of nanoseconds to gather statistics for. 18234dbad5dSOmar Sandoval * 18334dbad5dSOmar Sandoval * The timer callback will be called when the window expires. 18434dbad5dSOmar Sandoval */ 18534dbad5dSOmar Sandoval static inline void blk_stat_activate_nsecs(struct blk_stat_callback *cb, 18634dbad5dSOmar Sandoval u64 nsecs) 18734dbad5dSOmar Sandoval { 18834dbad5dSOmar Sandoval mod_timer(&cb->timer, jiffies + nsecs_to_jiffies(nsecs)); 18934dbad5dSOmar Sandoval } 19034dbad5dSOmar Sandoval 19134dbad5dSOmar Sandoval /** 19234dbad5dSOmar Sandoval * blk_stat_activate_msecs() - Gather block statistics during a time window in 19334dbad5dSOmar Sandoval * milliseconds. 19434dbad5dSOmar Sandoval * @cb: The callback. 19534dbad5dSOmar Sandoval * @msecs: Number of milliseconds to gather statistics for. 19634dbad5dSOmar Sandoval * 19734dbad5dSOmar Sandoval * The timer callback will be called when the window expires. 19834dbad5dSOmar Sandoval */ 19934dbad5dSOmar Sandoval static inline void blk_stat_activate_msecs(struct blk_stat_callback *cb, 20034dbad5dSOmar Sandoval unsigned int msecs) 20134dbad5dSOmar Sandoval { 20234dbad5dSOmar Sandoval mod_timer(&cb->timer, jiffies + msecs_to_jiffies(msecs)); 20334dbad5dSOmar Sandoval } 20434dbad5dSOmar Sandoval 205cf43e6beSJens Axboe #endif 206