// IO scheduler tapset // Copyright (C) 2005, 2006 IBM Corp. // Copyright (C) 2010 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. // // This family of probe points is used to probe IO scheduler activities. // %{ #include #include %} /** * probe ioscheduler.elv_next_request - Fires when a request is retrieved from the request queue * @elevator_name: The type of I/O elevator currently enabled */ probe ioscheduler.elv_next_request = kernel.function("blk_peek_request") !, kernel.function("elv_next_request") { elevator_name = kernel_string(@defined($q->elevator->elevator_type) ? $q->elevator->elevator_type->elevator_name : $q->elevator->elevator_name) } /** * probe ioscheduler.elv_next_request.return - Fires when a request retrieval issues a return signal * @req: Address of the request * @req_flags: Request flags * @disk_major: Disk major number of the request * @disk_minor: Disk minor number of the request */ probe ioscheduler.elv_next_request.return = kernel.function("blk_peek_request").return !, kernel.function("elv_next_request").return { if($return == 0) { req = 0 req_flags = 0 disk_major = -1 disk_minor = -1 } else { req = $return req_flags = (@defined($return->cmd_flags) ? $return->cmd_flags : $return->flags) if($return->rq_disk == 0) { disk_major = -1 disk_minor = -1 } else { disk_major = $return->rq_disk->major disk_minor = $return->rq_disk->first_minor } } } /** * probe ioscheduler.elv_add_request.kp - kprobe based probe to indicate that a request was added to the request queue * @elevator_name: The type of I/O elevator currently enabled * @q: pointer to request queue * @req: Address of the request * @req_flags: Request flags * @disk_major: Disk major number of the request * @disk_minor: Disk minor number of the request */ // when a request is added to the request queue probe ioscheduler.elv_add_request.kp = kernel.function("elv_insert") { elevator_name = kernel_string(@defined($q->elevator->elevator_type) ? $q->elevator->elevator_type->elevator_name : $q->elevator->elevator_name) q = $q if($rq == 0) { disk_major = -1 disk_minor = -1 } else { if($rq->rq_disk == 0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } } req = $rq req_flags = $rq==0 ? 0 : (@defined($rq->cmd_flags) ? $rq->cmd_flags : $rq->flags) } /** * probe ioscheduler.elv_completed_request - Fires when a request is completed * @elevator_name: The type of I/O elevator currently enabled * @req: Address of the request * @req_flags: Request flags * @disk_major: Disk major number of the request * @disk_minor: Disk minor number of the request */ probe ioscheduler.elv_completed_request = kernel.function("elv_completed_request") { elevator_name = kernel_string(@defined($q->elevator->elevator_type) ? $q->elevator->elevator_type->elevator_name : $q->elevator->elevator_name) if($rq == 0) { disk_major = -1 disk_minor = -1 } else { if($rq->rq_disk == 0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } } req = $rq req_flags = $rq==0 ? 0 : (@defined($rq->cmd_flags) ? $rq->cmd_flags : $rq->flags) } /** * probe ioscheduler.elv_add_request.tp - tracepoint based probe to indicate a request is added to the request queue. * @elevator_name : The type of I/O elevator currently enabled. * @q : Pointer to request queue. * @rq : Address of request. * @rq_flags : Request flags. * @disk_major : Disk major no of request. * @disk_minor : Disk minor number of request. * */ probe ioscheduler.elv_add_request.tp = kernel.trace("block_rq_insert") ? { q = $q elevator_name = kernel_string($q->elevator->elevator_type->elevator_name) rq = $rq if ($rq == 0 || $rq->rq_disk ==0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } rq_flags = $rq==0? 0:$rq->cmd_flags } /** * probe ioscheduler.elv_add_request - probe to indicate request is added to the request queue. * @elevator_name : The type of I/O elevator currently enabled. * @q : Pointer to request queue. * @rq : Address of request. * @rq_flags : Request flags. * @disk_major : Disk major no of request. * @disk_minor : Disk minor number of request. * */ probe ioscheduler.elv_add_request = ioscheduler.elv_add_request.tp !, ioscheduler.elv_add_request.kp {} /** * probe ioscheduler_trace.elv_completed_request - Fires when a request is * completed. * @elevator_name : The type of I/O elevator currently enabled. * @rq : Address of request. * @rq_flags : Request flags. * @disk_major : Disk major no of request. * @disk_minor : Disk minor number of request. * */ probe ioscheduler_trace.elv_completed_request = kernel.trace("block_rq_complete") ? { elevator_name = kernel_string($q->elevator->elevator_type->elevator_name) rq = $rq if ($rq == 0 || $rq->rq_disk ==0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } rq_flags = $rq==0? 0:$rq->cmd_flags } /** * probe ioscheduler_trace.elv_issue_request - Fires when a request is * scheduled. * @elevator_name : The type of I/O elevator currently enabled. * @rq : Address of request. * @rq_flags : Request flags. * @disk_major : Disk major no of request. * @disk_minor : Disk minor number of request. * */ probe ioscheduler_trace.elv_issue_request = kernel.trace("block_rq_issue") ? { elevator_name = kernel_string($q->elevator->elevator_type->elevator_name) rq = $rq if ($rq == 0 || $rq->rq_disk ==0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } rq_flags = $rq==0? 0:$rq->cmd_flags } /** * probe ioscheduler_trace.elv_requeue_request - Fires when a request is * put back on the queue, when the hadware cannot accept more requests. * @elevator_name : The type of I/O elevator currently enabled. * @rq : Address of request. * @rq_flags : Request flags. * @disk_major : Disk major no of request. * @disk_minor : Disk minor number of request. * */ probe ioscheduler_trace.elv_requeue_request = kernel.trace("block_rq_requeue") ? { elevator_name = kernel_string($q->elevator->elevator_type->elevator_name) rq = $rq if ($rq == 0 || $rq->rq_disk ==0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } rq_flags = $rq==0? 0:$rq->cmd_flags } /** * probe ioscheduler_trace.elv_abort_request - Fires when a request is aborted. * @elevator_name : The type of I/O elevator currently enabled. * @rq : Address of request. * @rq_flags : Request flags. * @disk_major : Disk major no of request. * @disk_minor : Disk minor number of request. * */ probe ioscheduler_trace.elv_abort_request = kernel.trace("block_rq_abort") ? { elevator_name = kernel_string($q->elevator->elevator_type->elevator_name) rq = $rq if ($rq == 0 || $rq->rq_disk ==0) { disk_major = -1 disk_minor = -1 } else { disk_major = $rq->rq_disk->major disk_minor = $rq->rq_disk->first_minor } rq_flags = $rq==0? 0:$rq->cmd_flags } /** * probe ioscheduler_trace.plug - Fires when a request queue is plugged; * ie, requests in the queue cannot be serviced by block driver. * @rq_queue : request queue * */ probe ioscheduler_trace.plug = kernel.trace("block_plug") ? { rq_queue = $q } /** * probe ioscheduler_trace.unplug_io - Fires when a request queue is unplugged; * Either, when number of pending requests in the queue exceeds threshold * or, upon expiration of timer that was activated when queue was plugged. * @rq_queue : request queue * */ probe ioscheduler_trace.unplug_io = kernel.trace("block_unplug_io") ? { rq_queue = $q } /** * probe ioscheduler_trace.unplug_timer - Fires when unplug timer associated * with a request queue expires. * @rq_queue : request queue * */ probe ioscheduler_trace.unplug_timer = kernel.trace("block_unplug_timer") ? { rq_queue = $q } function disk_major_from_request:long(var_q:long) %{ /* pure */ struct request_queue *q = (struct request_queue *)((long)THIS->var_q); /* We need to make sure there isn't a deref hazard here when * reading 'q->queue_head'. However, kread() wants a pointer to * a pointer, and we can't provide that for 'q->queue_head' * since the list_head structure is directly embedded in the * 'struct request_queue'. So, we validate all the members of * the list_head structure instead. */ (void) kread(&(q->queue_head.next)); (void) kread(&(q->queue_head.prev)); if (list_empty(&(q->queue_head))) THIS->__retvalue = -1; else { struct request *rq = list_entry_rq(q->queue_head.next); struct gendisk *rq_disk = kread(&(rq->rq_disk)); THIS->__retvalue = kread(&(rq_disk->major)); } CATCH_DEREF_FAULT(); %} function disk_minor_from_request:long(var_q:long) %{ /* pure */ struct request_queue *q = (struct request_queue *)((long)THIS->var_q); /* We need to make sure there isn't a deref hazard here when * reading 'q->queue_head'. However, kread() wants a pointer to * a pointer, and we can't provide that for 'q->queue_head' * since the list_head structure is directly embedded in the * 'struct request_queue'. So, we validate all the members of * the list_head structure instead. */ (void) kread(&(q->queue_head.next)); (void) kread(&(q->queue_head.prev)); if (list_empty(&(q->queue_head))) THIS->__retvalue = -1; else { struct request *rq = list_entry_rq(q->queue_head.next); struct gendisk *rq_disk = kread(&(rq->rq_disk)); THIS->__retvalue = kread(&(rq_disk->first_minor)); } CATCH_DEREF_FAULT(); %}