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