This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
draft RPC tapset
- From: "Gui,Jian" <guij at cn dot ibm dot com>
- To: systemtap at sources dot redhat dot com
- Cc: nfs at lists dot sourceforge dot net
- Date: Tue, 05 Sep 2006 16:45:51 +0800
- Subject: draft RPC tapset
Hi folks,
I am working on RPC trace hooks for Systemtap/LKET. These trace
hooks can help dynamically trace the activities on both RPC
clients and servers.
The functions in the sunrpc module (see net/sunrpc/sunrpc_syms.c
and others) are roughly categorized into several groups:
* for RPC scheduler
* for RPC client
* for RPC client transport
* for RPC client credential cache
* for RPC server
* for RPC statistics
* for RPC caching
* for generic XDR
As a start point, I picked the trace hooks mainly from RPC client,
scheduler and server side. I am sure it is not always enough, so
anyone can extend this tapset whenever necessary.
And I want to make sure the trace hooks I chose are in right places
and the parameters are correctly handled. It will be very appreciated
if you can take a look at it. Please fell free to let me know if
you have any questions/suggestions/comments.
Thanks.
Gui,Jian
===================================================================
# Copyright (C) 2005, 2006 IBM Corp.
#
# 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.
%{
#include <linux/kernel.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
%}
probe sunrpc.entry =
sunrpc.clnt.entry,
sunrpc.svc.entry,
sunrpc.sched.entry
{}
probe sunrpc.return =
sunrpc.clnt.return,
sunrpc.svc.return,
sunrpc.sched.return
{}
####################################################################
# Probe points on RPC client functions #
####################################################################
probe sunrpc.clnt.entry =
sunrpc.clnt.create_client,
sunrpc.clnt.clone_client,
sunrpc.clnt.bind_new_program,
sunrpc.clnt.shutdown_client,
sunrpc.clnt.call_sync,
sunrpc.clnt.call_async,
sunrpc.clnt.restart_call
{}
probe sunrpc.clnt.return =
sunrpc.clnt.create_client.return,
sunrpc.clnt.clone_client.return,
sunrpc.clnt.bind_new_program.return,
sunrpc.clnt.shutdown_client.return,
sunrpc.clnt.call_sync.return,
sunrpc.clnt.call_async.return,
sunrpc.clnt.restart_call.return
{}
#
# Fires when an RPC client is to be created
#
# struct rpc_clnt *
# rpc_create_client(struct rpc_xprt *xprt, char *servname,
# struct rpc_program *info, u32 version,
# rpc_authflavor_t authflavor)
#
probe sunrpc.clnt.create_client = kernel.function("rpc_create_client") ?,
module("sunrpc").function("rpc_create_client") ?
{
servername = kernel_string($servname) /* server name */
progname = kernel_string($info->name) /* program name */
prog = $info->number /* program number */
vers = vers_from_prog($info, $version) /* program version */
prot = $xprt->prot /* IP protocol */
port = $xprt->port /* port number */
authflavor = $authflavor /* authentication flavor */
name = "sunrpc.clnt.create_client"
argstr = sprintf("%s %s %d %d %d %d %d", servername, progname,
prog, vers, prot, port, authflavor)
}
probe sunrpc.clnt.create_client.return =
kernel.function("rpc_create_client").return ?,
module("sunrpc").function("rpc_create_client").return ?
{
name = "sunrpc.clnt.create_client"
}
#
# Fires when the RPC client structure is to be cloned
#
# struct rpc_clnt * rpc_clone_client(struct rpc_clnt *clnt)
#
probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") ?,
module("sunrpc").function("rpc_clone_client") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
port = port_from_clnt($clnt)
authflavor = $clnt->cl_auth->au_flavor
name = "sunrpc.clnt.clone_client"
argstr = sprintf("%s %s %d %d %d %d %d", servname, progname,
prog, vers, prot, port, authflavor)
}
probe sunrpc.clnt.clone_client.return =
kernel.function("rpc_clone_client").return ?,
module("sunrpc").function("rpc_clone_client").return ?
{
name = "sunrpc.clnt.clone_client"
}
#
# Fires when a new RPC program is to be bound an existing client
#
# struct rpc_clnt * rpc_bind_new_program(struct rpc_clnt *old,
# struct rpc_program *program, int vers)
#
probe sunrpc.clnt.bind_new_program =
kernel.function("rpc_bind_new_program") ?,
module("sunrpc").function("rpc_bind_new_program") ?
{
servname = kernel_string($old->cl_server)
old_progname = kernel_string($old->cl_protname)
old_prog = prog_from_clnt($old)
old_vers = vers_from_clnt($old)
progname = kernel_string($program->name)
prog = $program->number
vers = vers_from_prog($program, $vers)
name = "sunrpc.clnt.bind_new_program"
argstr = sprintf("%s %s %d %s %d", servname, old_progname,
old_vers, progname, vers)
}
probe sunrpc.clnt.bind_new_program.return =
kernel.function("rpc_bind_new_program").return ?,
module("sunrpc").function("rpc_bind_new_program").return ?
{
name = "sunrpc.clnt.bind_new_program"
}
#
# Fires when an RPC client is to be shut down.
#
# int rpc_shutdown_client(struct rpc_clnt *clnt)
#
probe sunrpc.clnt.shutdown_client =
kernel.function("rpc_shutdown_client") ?,
module("sunrpc").function("rpc_shutdown_client") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
vers = vers_from_clnt($clnt)
tasks = tasks_from_clnt($clnt)
/* per-program statistics */
netcnt = $clnt->cl_stats->netcnt
netreconn = $clnt->cl_stats->netreconn
rpccnt = $clnt->cl_stats->rpccnt
rpcgarbage = $clnt->cl_stats->rpcgarbage
/* per-client statistics */
om_ops = $clnt->cl_metrics->om_ops /* count of operations */
om_ntrans = $clnt->cl_metrics->om_ntrans/* count of RPC transmissions */
om_bytes_sent = $clnt->cl_metrics->om_bytes_sent /* count of bytes out*/
om_bytes_recv = $clnt->cl_metrics->om_bytes_recv /* count of bytes in */
om_queue = $clnt->cl_metrics->om_queue /* jiffies queued for xmit */
om_rtt = $clnt->cl_metrics->om_rtt /* RPC RTT jiffies */
om_execute = $clnt->cl_metrics->om_execute /* RPC execution jiffies */
name = "sunrpc.clnt.shutdown_client"
argstr = sprintf("%s %s %d %d", servname, progname, vers, tasks)
}
probe sunrpc.clnt.shutdown_client.return =
kernel.function("rpc_shutdown_client").return ?,
module("sunrpc").function("rpc_shutdown_client").return ?
{
name = "sunrpc.clnt.shutdown_client"
retstr = returnstr($return)
}
#
# int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
# int flags)
#
probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") ?,
module("sunrpc").function("rpc_call_sync") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
port = port_from_clnt($clnt)
xid = xid_from_clnt($clnt)
dead = $clnt->cl_dead
proc = proc_from_msg($msg)
procname= $msg->rpc_proc->p_name
? kernel_string($msg->rpc_proc->p_name) : "NULL"
flags = $flags
name = "sunrpc.clnt.call_sync"
argstr = sprintf("%s %d %s %d %s 0x%x", servname, xid,
progname, vers, procname, flags)
}
probe sunrpc.clnt.call_sync.return =
kernel.function("rpc_call_sync").return ?,
module("sunrpc").function("rpc_call_sync").return ?
{
name = "sunrpc.clnt.call_sync"
retstr = returnstr($return)
}
#
# int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
# int flags, const struct rpc_call_ops *tk_ops, void *data)
#
probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") ?,
module("sunrpc").function("rpc_call_async") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
port = port_from_clnt($clnt)
xid = xid_from_clnt($clnt)
dead = $clnt->cl_dead
proc = proc_from_msg($msg)
procname= $msg->rpc_proc->p_name
? kernel_string($msg->rpc_proc->p_name) : "NULL"
flags = $flags
name = "sunrpc.clnt.call_async"
argstr = sprintf("%s %d %s %d %s 0x%x", servname, xid, progname,
vers, procname, flags)
}
probe sunrpc.clnt.call_async.return =
kernel.function("rpc_call_async").return ?,
module("sunrpc").function("rpc_call_async").return ?
{
name = "sunrpc.clnt.call_async"
retstr = returnstr($return)
}
#
# Fires when an (async) RPC call is to be restarted
#
# void rpc_restart_call(struct rpc_task *task)
#
probe sunrpc.clnt.restart_call = kernel.function("rpc_restart_call") ?,
module("sunrpc").function("rpc_restart_call") ?
{
xid = $task->tk_rqstp->rq_xid
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
tk_pid = $task->tk_pid
tk_flags = $task->tk_flags
name = "sunrpc.clnt.restart_call"
argstr = sprintf("%d %d %d %d %d", xid, prog, vers,
tk_pid, tk_flags)
}
probe sunrpc.clnt.restart_call.return =
kernel.function("rpc_restart_call").return ?,
module("sunrpc").function("rpc_restart_call").return ?
{
name = "sunrpc.clnt.restart_call"
}
####################################################################
# Probe points on RPC server interface #
####################################################################
probe sunrpc.svc.entry =
sunrpc.svc.register,
sunrpc.svc.create,
sunrpc.svc.destroy,
sunrpc.svc.process,
sunrpc.svc.authorise,
sunrpc.svc.recv,
sunrpc.svc.send,
sunrpc.svc.drop
{}
probe sunrpc.svc.return =
sunrpc.svc.register.return,
sunrpc.svc.create.return,
sunrpc.svc.destroy.return,
sunrpc.svc.process.return,
sunrpc.svc.authorise.return,
sunrpc.svc.recv.return,
sunrpc.svc.send.return,
sunrpc.svc.drop.return
{}
#
# Fires when an RPC service is to be registered with the local portmapper.
# If proto and port == 0, it means to unregister a service.
#
# int svc_register(struct svc_serv *serv, int proto, unsigned short port)
#
probe sunrpc.svc.register = kernel.function("svc_register") ?,
module("sunrpc").function("svc_register") ?
{
sv_name = kernel_string($serv->sv_name)
progname = kernel_string($serv->sv_program->pg_name)
prog = $serv->sv_program->pg_prog
prot = $proto
port = $port
name = "sunrpc.svc.register"
argstr = sprintf("%s %s %d %d", sv_name, progname, prot, port)
}
probe sunrpc.svc.register.return =
kernel.function("svc_register").return ?,
module("sunrpc").function("svc_register").return ?
{
name = "sunrpc.svc.register"
retstr = returnstr($return)
}
#
# Fires when an RPC service is to be created
#
# struct svc_serv *
# svc_create(struct svc_program *prog, unsigned int bufsize)
#
probe sunrpc.svc.create = kernel.function("svc_create") ?,
module("sunrpc").function("svc_create") ?
{
pg_name = kernel_string($prog->pg_name)
pg_prog = $prog->pg_prog
pg_hivers = $prog->pg_hivers
pg_nvers = $prog->pg_nvers
bufsize = $bufsize
name = "sunrpc.svc.create"
argstr = sprintf("%s %d %d %d %d", pg_name, pg_prog,
pg_hivers, pg_nvers, bufsize)
}
probe sunrpc.svc.create.return = kernel.function("svc_create").return ?,
module("sunrpc").function("svc_create").return ?
{
name = "sunrpc.svc.create"
}
#
# Fires when an RPC service is to be destroyed
#
# void svc_destroy(struct svc_serv *serv)
#
probe sunrpc.svc.destroy = kernel.function("svc_destroy") ?,
module("sunrpc").function("svc_destroy") ?
{
sv_name = kernel_string($serv->sv_name) /* service name */
sv_progname = kernel_string($serv->sv_program->pg_name)
sv_prog = $serv->sv_program->pg_prog
sv_nrthreads = $serv->sv_nrthreads
/* RPC statistics */
netcnt = $serv->sv_stats->netcnt
netcpconn = $serv->sv_stats->nettcpconn
rpccnt = $serv->sv_stats->rpccnt
rpcbadclnt = $serv->sv_stats->rpcbadclnt
name = "sunrpc.svc.destroy"
argstr = sprintf("%s %d %d", sv_name, sv_prog, sv_nrthreads)
}
probe sunrpc.svc.destroy.return = kernel.function("svc_destroy").return ?,
module("sunrpc").function("svc_destroy").return ?
{
name = "sunrpc.svc.destroy"
}
#
# Fires when an RPC request is to be processed
#
# int svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
#
probe sunrpc.svc.process = kernel.function("svc_process") ?,
module("sunrpc").function("svc_process") ?
{
sv_name = kernel_string($serv->sv_name) /* service name */
sv_prog = $serv->sv_program->pg_prog
peer_ip = addr_from_rqst($rqstp)/* peer address */
rq_xid = $rqstp->rq_xid /* transmission id */
rq_prog = $rqstp->rq_prog /* program number */
rq_vers = $rqstp->rq_vers /* program version */
rq_proc = $rqstp->rq_proc /* procedure number */
rq_prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.process"
argstr = sprintf("%s %d %d %d %d %d %d", sv_name, sv_prog, peer_ip,
rq_xid, rq_prog, rq_vers, rq_proc)
}
probe sunrpc.svc.process.return = kernel.function("svc_process").return ?,
module("sunrpc").function("svc_process").return ?
{
name = "sunrpc.svc.process"
retstr = returnstr($return)
}
#
# int svc_authorise(struct svc_rqst *rqstp)
#
probe sunrpc.svc.authorise = kernel.function("svc_authorise")?,
module("sunrpc").function("svc_authorise")?
{
peer_ip = addr_from_rqst($rqstp) /* peer address */
xid = $rqstp->rq_xid /* transmission id */
prog = $rqstp->rq_prog /* program number */
vers = $rqstp->rq_vers /* program version */
proc = $rqstp->rq_proc /* procedure number */
prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.authorise"
argstr = sprintf("%d %d %d %d %d %d %d", peer_ip, xid, prog,
vers, proc, prot, addr)
}
probe sunrpc.svc.authorise.return =
kernel.function("svc_authorise").return ?,
module("sunrpc").function("svc_authorise").return ?
{
name = "sunrpc.svc.authorise"
retstr = returnstr($return)
}
#
# Fires when receiving the next request on any socket.
#
# int svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long
timeout)
#
probe sunrpc.svc.recv = kernel.function("svc_recv")?,
module("sunrpc").function("svc_recv")?
{
sv_name = kernel_string($serv->sv_name)
timeout = $timeout
name = "sunrpc.svc.recv"
argstr = sprintf("%s %d", sv_name, timeout)
}
probe sunrpc.svc.recv.return = kernel.function("svc_recv").return ?,
module("sunrpc").function("svc_recv").return ?
{
name = "sunrpc.svc.recv"
argstr = returnstr($return)
}
#
# Fires when want to return reply to client.
#
# int svc_send(struct svc_rqst *rqstp)
#
probe sunrpc.svc.send = kernel.function("svc_send")?,
module("sunrpc").function("svc_send")?
{
sv_name = kernel_string($rqstp->rq_server->sv_name)
sv_prog = $rqstp->rq_server->sv_program->pg_prog
peer_ip = addr_from_rqst($rqstp) /* peer address */
xid = $rqstp->rq_xid /* transmission id */
prog = $rqstp->rq_prog /* program number */
vers = $rqstp->rq_vers /* program version */
proc = $rqstp->rq_proc /* procedure number */
prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.send"
argstr = sprintf("%s %d %d %d %d %d %d %d", sv_name, sv_prog,
peer_ip, xid, prog, vers, proc, prot)
}
probe sunrpc.svc.send.return = kernel.function("svc_send").return ?,
module("sunrpc").function("svc_send").return ?
{
name = "sunrpc.svc.send"
retstr = returnstr($return)
}
#
# Fires when a request is to be dropped
#
# void svc_drop(struct svc_rqst *rqstp)
#
probe sunrpc.svc.drop = kernel.function("svc_drop")?,
module("sunrpc").function("svc_drop")?
{
sv_name = kernel_string($rqstp->rq_server->sv_name)
sv_prog = $rqstp->rq_server->sv_program->pg_prog
peer_ip = addr_from_rqst($rqstp) /* peer address */
xid = $rqstp->rq_xid /* transmission id */
prog = $rqstp->rq_prog /* program number */
vers = $rqstp->rq_vers /* program version */
proc = $rqstp->rq_proc /* procedure number */
prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.drop"
argstr = sprintf("%s %d %d %d %d %d %d %d", sv_name, sv_prog,
peer_ip, xid, prog, vers, proc, prot)
}
probe sunrpc.svc.drop.return = kernel.function("svc_drop").return ?,
module("sunrpc").function("svc_drop").return ?
{
name = "sunrpc.svc.drop"
}
####################################################################
# Probe points on RPC scheduler #
####################################################################
probe sunrpc.sched.entry =
sunrpc.sched.new_task,
sunrpc.sched.execute,
sunrpc.sched.delay,
sunrpc.sched.release_task
{}
probe sunrpc.sched.return =
sunrpc.sched.new_task.return,
sunrpc.sched.execute.return,
sunrpc.sched.delay.return,
sunrpc.sched.release_task.return
{}
#
# Fires when the RPC `scheduler'(or rather, the finite state machine)
# is to be executed
#
# static int __rpc_execute(struct rpc_task *task)
#
probe sunrpc.sched.execute = kernel.function("__rpc_execute") ?,
module("sunrpc").function("__rpc_execute") ?
{
xid = xid_from_clnt($task->tk_client)
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
prot = prot_from_clnt($task->tk_client)
tk_pid = $task->tk_pid
tk_flags = $task->tk_flags
name = "sunrpc.sched.execute"
argstr = sprintf("%d %d %d %d %d %d", xid, prog,
vers, prot, tk_pid, tk_flags)
}
probe sunrpc.sched.execute.return =
kernel.function("__rpc_execute").return ?,
module("sunrpc").function("__rpc_execute").return ?
{
name = "sunrpc.sched.execute"
retstr = returnstr($return)
}
#
# Fires when a task is to be delayed
#
# void rpc_delay(struct rpc_task *task, unsigned long delay)
#
probe sunrpc.sched.delay = kernel.function("rpc_delay") ?,
module("sunrpc").function("rpc_delay") ?
{
xid = xid_from_clnt($task->tk_client)
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
prot = prot_from_clnt($task->tk_client)
tk_pid = $task->tk_pid
tk_flags = $task->tk_flags
delay = $delay
name = "sunrpc.clnt.delay"
argstr = sprintf("%d %d %d %d %d %d", xid, prog, vers,
prot, tk_pid, tk_flags)
}
probe sunrpc.sched.delay.return = kernel.function("rpc_delay").return ?,
module("sunrpc").function("rpc_delay").return ?
{
name = "sunrpc.clnt.delay"
}
#
# Fires when a new task is to be created for the specified client.
#
# struct rpc_task * rpc_new_task(struct rpc_clnt *clnt, int flags,
# const struct rpc_call_ops *tk_ops, void *calldata)
#
probe sunrpc.sched.new_task = kernel.function("rpc_new_task") ?,
module("sunrpc").function("rpc_new_task") ?
{
xid = xid_from_clnt($clnt)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
flags = $flags
name = "sunrpc.sched.new_task"
argstr = sprintf("%d %d %d %d %d", xid, prog, vers, prot, flags)
}
probe sunrpc.sched.new_task.return =
kernel.function("rpc_new_task").return ?,
module("sunrpc").function("rpc_new_task").return ?
{
name = "sunrpc.sched.new_task"
}
#
# Fires when all resources associated with a task are to be released
#
# void rpc_release_task(struct rpc_task *task)
#
probe sunrpc.sched.release_task = kernel.function("rpc_release_task") ?,
module("sunrpc").function("rpc_release_task") ?
{
xid = xid_from_clnt($task->tk_client)
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
prot = prot_from_clnt($task->tk_client)
flags = $task->tk_flags
name = "sunrpc.sched.release_task"
argstr = sprintf("%d %d %d %d %d", xid, prog, vers, prot, flags)
}
probe sunrpc.sched.release_task.return =
kernel.function("rpc_release_task").return ?,
module("sunrpc").function("rpc_release_task").return ?
{
name = "sunrpc.sched.release_task"
}
####################################################################
# Helpler functions #
####################################################################
function xid_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_xprt->tcp_xid : 0;
%}
function prog_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_prog : 0;
%}
function vers_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_vers : 0;
%}
function prot_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_prot : 0;
%}
function port_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_port : 0;
%}
function tasks_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = atomic_read(&clnt->cl_users);
%}
function proc_from_msg:long(msg:long)
%{
struct rpc_message *msg = (struct rpc_message *)THIS->msg;
THIS->__retvalue = msg ? msg->rpc_proc->p_proc : 0;
%}
function vers_from_prog:long(program:long, vers:long)
%{
struct rpc_program *program = (struct rpc_program *)THIS->program;
if (!program || THIS->vers >= program->nrvers ||
!program->version[THIS->vers])
THIS->__retvalue = 0;
else
THIS->__retvalue = program->version[THIS->vers]->number;
%}
function addr_from_rqst:long(rqstp:long)
%{
struct svc_rqst *rqstp = (struct svc_rqst *)THIS->rqstp;
THIS->__retvalue = rqstp ? rqstp->rq_addr.sin_addr.s_addr : 0;
%}
# Copyright (C) 2005, 2006 IBM Corp.
#
# 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.
%{
#include <linux/kernel.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
%}
probe sunrpc.entry =
sunrpc.clnt.entry,
sunrpc.svc.entry,
sunrpc.sched.entry
{}
probe sunrpc.return =
sunrpc.clnt.return,
sunrpc.svc.return,
sunrpc.sched.return
{}
####################################################################
# Probe points on RPC client functions #
####################################################################
probe sunrpc.clnt.entry =
sunrpc.clnt.create_client,
sunrpc.clnt.clone_client,
sunrpc.clnt.bind_new_program,
sunrpc.clnt.shutdown_client,
sunrpc.clnt.call_sync,
sunrpc.clnt.call_async,
sunrpc.clnt.restart_call
{}
probe sunrpc.clnt.return =
sunrpc.clnt.create_client.return,
sunrpc.clnt.clone_client.return,
sunrpc.clnt.bind_new_program.return,
sunrpc.clnt.shutdown_client.return,
sunrpc.clnt.call_sync.return,
sunrpc.clnt.call_async.return,
sunrpc.clnt.restart_call.return
{}
#
# Fires when an RPC client is to be created
#
# struct rpc_clnt *
# rpc_create_client(struct rpc_xprt *xprt, char *servname,
# struct rpc_program *info, u32 version,
# rpc_authflavor_t authflavor)
#
probe sunrpc.clnt.create_client = kernel.function("rpc_create_client") ?,
module("sunrpc").function("rpc_create_client") ?
{
servername = kernel_string($servname) /* server name */
progname = kernel_string($info->name) /* program name */
prog = $info->number /* program number */
vers = vers_from_prog($info, $version) /* program version */
prot = $xprt->prot /* IP protocol */
port = $xprt->port /* port number */
authflavor = $authflavor /* authentication flavor */
name = "sunrpc.clnt.create_client"
argstr = sprintf("%s %s %d %d %d %d %d", servername, progname,
prog, vers, prot, port, authflavor)
}
probe sunrpc.clnt.create_client.return =
kernel.function("rpc_create_client").return ?,
module("sunrpc").function("rpc_create_client").return ?
{
name = "sunrpc.clnt.create_client"
}
#
# Fires when the RPC client structure is to be cloned
#
# struct rpc_clnt * rpc_clone_client(struct rpc_clnt *clnt)
#
probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") ?,
module("sunrpc").function("rpc_clone_client") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
port = port_from_clnt($clnt)
authflavor = $clnt->cl_auth->au_flavor
name = "sunrpc.clnt.clone_client"
argstr = sprintf("%s %s %d %d %d %d %d", servname, progname,
prog, vers, prot, port, authflavor)
}
probe sunrpc.clnt.clone_client.return =
kernel.function("rpc_clone_client").return ?,
module("sunrpc").function("rpc_clone_client").return ?
{
name = "sunrpc.clnt.clone_client"
}
#
# Fires when a new RPC program is to be bound an existing client
#
# struct rpc_clnt * rpc_bind_new_program(struct rpc_clnt *old,
# struct rpc_program *program, int vers)
#
probe sunrpc.clnt.bind_new_program =
kernel.function("rpc_bind_new_program") ?,
module("sunrpc").function("rpc_bind_new_program") ?
{
servname = kernel_string($old->cl_server)
old_progname = kernel_string($old->cl_protname)
old_prog = prog_from_clnt($old)
old_vers = vers_from_clnt($old)
progname = kernel_string($program->name)
prog = $program->number
vers = vers_from_prog($program, $vers)
name = "sunrpc.clnt.bind_new_program"
argstr = sprintf("%s %s %d %s %d", servname, old_progname,
old_vers, progname, vers)
}
probe sunrpc.clnt.bind_new_program.return =
kernel.function("rpc_bind_new_program").return ?,
module("sunrpc").function("rpc_bind_new_program").return ?
{
name = "sunrpc.clnt.bind_new_program"
}
#
# Fires when an RPC client is to be shut down.
#
# int rpc_shutdown_client(struct rpc_clnt *clnt)
#
probe sunrpc.clnt.shutdown_client = kernel.function("rpc_shutdown_client") ?,
module("sunrpc").function("rpc_shutdown_client") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
vers = vers_from_clnt($clnt)
tasks = tasks_from_clnt($clnt)
/* per-program statistics */
netcnt = $clnt->cl_stats->netcnt
netreconn = $clnt->cl_stats->netreconn
rpccnt = $clnt->cl_stats->rpccnt
rpcgarbage = $clnt->cl_stats->rpcgarbage
/* per-client statistics */
om_ops = $clnt->cl_metrics->om_ops /* count of operations */
om_ntrans = $clnt->cl_metrics->om_ntrans/* count of RPC transmissions */
om_bytes_sent = $clnt->cl_metrics->om_bytes_sent /* count of bytes out*/
om_bytes_recv = $clnt->cl_metrics->om_bytes_recv /* count of bytes in */
om_queue = $clnt->cl_metrics->om_queue /* jiffies queued for xmit */
om_rtt = $clnt->cl_metrics->om_rtt /* RPC RTT jiffies */
om_execute = $clnt->cl_metrics->om_execute /* RPC execution jiffies */
name = "sunrpc.clnt.shutdown_client"
argstr = sprintf("%s %s %d %d", servname, progname, vers, tasks)
}
probe sunrpc.clnt.shutdown_client.return =
kernel.function("rpc_shutdown_client").return ?,
module("sunrpc").function("rpc_shutdown_client").return ?
{
name = "sunrpc.clnt.shutdown_client"
retstr = returnstr($return)
}
#
# int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
# int flags)
#
probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") ?,
module("sunrpc").function("rpc_call_sync") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
port = port_from_clnt($clnt)
xid = xid_from_clnt($clnt)
dead = $clnt->cl_dead
proc = proc_from_msg($msg)
procname= $msg->rpc_proc->p_name
? kernel_string($msg->rpc_proc->p_name) : "NULL"
flags = $flags
name = "sunrpc.clnt.call_sync"
argstr = sprintf("%s %d %s %d %s 0x%x", servname, xid, progname,
vers, procname, flags)
}
probe sunrpc.clnt.call_sync.return = kernel.function("rpc_call_sync").return ?,
module("sunrpc").function("rpc_call_sync").return ?
{
name = "sunrpc.clnt.call_sync"
retstr = returnstr($return)
}
#
# int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
# int flags, const struct rpc_call_ops *tk_ops, void *data)
#
probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") ?,
module("sunrpc").function("rpc_call_async") ?
{
servname = kernel_string($clnt->cl_server)
progname = kernel_string($clnt->cl_protname)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
port = port_from_clnt($clnt)
xid = xid_from_clnt($clnt)
dead = $clnt->cl_dead
proc = proc_from_msg($msg)
procname= $msg->rpc_proc->p_name
? kernel_string($msg->rpc_proc->p_name) : "NULL"
flags = $flags
name = "sunrpc.clnt.call_async"
argstr = sprintf("%s %d %s %d %s 0x%x", servname, xid, progname,
vers, procname, flags)
}
probe sunrpc.clnt.call_async.return =
kernel.function("rpc_call_async").return ?,
module("sunrpc").function("rpc_call_async").return ?
{
name = "sunrpc.clnt.call_async"
retstr = returnstr($return)
}
#
# Fires when an (async) RPC call is to be restarted
#
# void rpc_restart_call(struct rpc_task *task)
#
probe sunrpc.clnt.restart_call = kernel.function("rpc_restart_call") ?,
module("sunrpc").function("rpc_restart_call") ?
{
xid = $task->tk_rqstp->rq_xid
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
tk_pid = $task->tk_pid
tk_flags = $task->tk_flags
name = "sunrpc.clnt.restart_call"
argstr = sprintf("%d %d %d %d %d", xid, prog, vers,
tk_pid, tk_flags)
}
probe sunrpc.clnt.restart_call.return =
kernel.function("rpc_restart_call").return ?,
module("sunrpc").function("rpc_restart_call").return ?
{
name = "sunrpc.clnt.restart_call"
}
####################################################################
# Probe points on RPC server interface #
####################################################################
probe sunrpc.svc.entry =
sunrpc.svc.register,
sunrpc.svc.create,
sunrpc.svc.destroy,
sunrpc.svc.process,
sunrpc.svc.authorise,
sunrpc.svc.recv,
sunrpc.svc.send,
sunrpc.svc.drop
{}
probe sunrpc.svc.return =
sunrpc.svc.register.return,
sunrpc.svc.create.return,
sunrpc.svc.destroy.return,
sunrpc.svc.process.return,
sunrpc.svc.authorise.return,
sunrpc.svc.recv.return,
sunrpc.svc.send.return,
sunrpc.svc.drop.return
{}
#
# Fires when an RPC service is to be registered with the local portmapper.
# If proto and port == 0, it means to unregister a service.
#
# int svc_register(struct svc_serv *serv, int proto, unsigned short port)
#
probe sunrpc.svc.register = kernel.function("svc_register") ?,
module("sunrpc").function("svc_register") ?
{
sv_name = kernel_string($serv->sv_name)
progname = kernel_string($serv->sv_program->pg_name)
prog = $serv->sv_program->pg_prog
prot = $proto
port = $port
name = "sunrpc.svc.register"
argstr = sprintf("%s %s %d %d", sv_name, progname, prot, port)
}
probe sunrpc.svc.register.return = kernel.function("svc_register").return ?,
module("sunrpc").function("svc_register").return ?
{
name = "sunrpc.svc.register"
retstr = returnstr($return)
}
#
# Fires when an RPC service is to be created
#
# struct svc_serv *
# svc_create(struct svc_program *prog, unsigned int bufsize)
#
probe sunrpc.svc.create = kernel.function("svc_create") ?,
module("sunrpc").function("svc_create") ?
{
pg_name = kernel_string($prog->pg_name)
pg_prog = $prog->pg_prog
pg_hivers = $prog->pg_hivers
pg_nvers = $prog->pg_nvers
bufsize = $bufsize
name = "sunrpc.svc.create"
argstr = sprintf("%s %d %d %d %d", pg_name, pg_prog,
pg_hivers, pg_nvers, bufsize)
}
probe sunrpc.svc.create.return = kernel.function("svc_create").return ?,
module("sunrpc").function("svc_create").return ?
{
name = "sunrpc.svc.create"
}
#
# Fires when an RPC service is to be destroyed
#
# void svc_destroy(struct svc_serv *serv)
#
probe sunrpc.svc.destroy = kernel.function("svc_destroy") ?,
module("sunrpc").function("svc_destroy") ?
{
sv_name = kernel_string($serv->sv_name) /* service name */
sv_progname = kernel_string($serv->sv_program->pg_name)
sv_prog = $serv->sv_program->pg_prog
sv_nrthreads = $serv->sv_nrthreads
/* RPC statistics */
netcnt = $serv->sv_stats->netcnt
netcpconn = $serv->sv_stats->nettcpconn
rpccnt = $serv->sv_stats->rpccnt
rpcbadclnt = $serv->sv_stats->rpcbadclnt
name = "sunrpc.svc.destroy"
argstr = sprintf("%s %d %d", sv_name, sv_prog, sv_nrthreads)
}
probe sunrpc.svc.destroy.return = kernel.function("svc_destroy").return ?,
module("sunrpc").function("svc_destroy").return ?
{
name = "sunrpc.svc.destroy"
}
#
# Fires when an RPC request is to be processed
#
# int svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
#
probe sunrpc.svc.process = kernel.function("svc_process") ?,
module("sunrpc").function("svc_process") ?
{
sv_name = kernel_string($serv->sv_name) /* service name */
sv_prog = $serv->sv_program->pg_prog
peer_ip = addr_from_rqst($rqstp)/* peer address */
rq_xid = $rqstp->rq_xid /* transmission id */
rq_prog = $rqstp->rq_prog /* program number */
rq_vers = $rqstp->rq_vers /* program version */
rq_proc = $rqstp->rq_proc /* procedure number */
rq_prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.process"
argstr = sprintf("%s %d %d %d %d %d %d", sv_name, sv_prog, peer_ip,
rq_xid, rq_prog, rq_vers, rq_proc)
}
probe sunrpc.svc.process.return = kernel.function("svc_process").return ?,
module("sunrpc").function("svc_process").return ?
{
name = "sunrpc.svc.process"
retstr = returnstr($return)
}
#
# int svc_authorise(struct svc_rqst *rqstp)
#
probe sunrpc.svc.authorise = kernel.function("svc_authorise")?,
module("sunrpc").function("svc_authorise")?
{
peer_ip = addr_from_rqst($rqstp) /* peer address */
xid = $rqstp->rq_xid /* transmission id */
prog = $rqstp->rq_prog /* program number */
vers = $rqstp->rq_vers /* program version */
proc = $rqstp->rq_proc /* procedure number */
prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.authorise"
argstr = sprintf("%d %d %d %d %d %d %d", peer_ip, xid, prog,
vers, proc, prot, addr)
}
probe sunrpc.svc.authorise.return = kernel.function("svc_authorise").return ?,
module("sunrpc").function("svc_authorise").return ?
{
name = "sunrpc.svc.authorise"
retstr = returnstr($return)
}
#
# Fires when receiving the next request on any socket.
#
# int svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
#
probe sunrpc.svc.recv = kernel.function("svc_recv")?,
module("sunrpc").function("svc_recv")?
{
sv_name = kernel_string($serv->sv_name)
timeout = $timeout
name = "sunrpc.svc.recv"
argstr = sprintf("%s %d", sv_name, timeout)
}
probe sunrpc.svc.recv.return = kernel.function("svc_recv").return ?,
module("sunrpc").function("svc_recv").return ?
{
name = "sunrpc.svc.recv"
argstr = returnstr($return)
}
#
# Fires when want to return reply to client.
#
# int svc_send(struct svc_rqst *rqstp)
#
probe sunrpc.svc.send = kernel.function("svc_send")?,
module("sunrpc").function("svc_send")?
{
sv_name = kernel_string($rqstp->rq_server->sv_name)
sv_prog = $rqstp->rq_server->sv_program->pg_prog
peer_ip = addr_from_rqst($rqstp) /* peer address */
xid = $rqstp->rq_xid /* transmission id */
prog = $rqstp->rq_prog /* program number */
vers = $rqstp->rq_vers /* program version */
proc = $rqstp->rq_proc /* procedure number */
prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.send"
argstr = sprintf("%s %d %d %d %d %d %d %d", sv_name, sv_prog,
peer_ip, xid, prog, vers, proc, prot)
}
probe sunrpc.svc.send.return = kernel.function("svc_send").return ?,
module("sunrpc").function("svc_send").return ?
{
name = "sunrpc.svc.send"
retstr = returnstr($return)
}
#
# Fires when a request is to be dropped
#
# void svc_drop(struct svc_rqst *rqstp)
#
probe sunrpc.svc.drop = kernel.function("svc_drop")?,
module("sunrpc").function("svc_drop")?
{
sv_name = kernel_string($rqstp->rq_server->sv_name)
sv_prog = $rqstp->rq_server->sv_program->pg_prog
peer_ip = addr_from_rqst($rqstp) /* peer address */
xid = $rqstp->rq_xid /* transmission id */
prog = $rqstp->rq_prog /* program number */
vers = $rqstp->rq_vers /* program version */
proc = $rqstp->rq_proc /* procedure number */
prot = $rqstp->rq_prot /* IP protocol */
name = "sunrpc.svc.drop"
argstr = sprintf("%s %d %d %d %d %d %d %d", sv_name, sv_prog,
peer_ip, xid, prog, vers, proc, prot)
}
probe sunrpc.svc.drop.return = kernel.function("svc_drop").return ?,
module("sunrpc").function("svc_drop").return ?
{
name = "sunrpc.svc.drop"
}
####################################################################
# Probe points on RPC scheduler #
####################################################################
probe sunrpc.sched.entry =
sunrpc.sched.new_task,
sunrpc.sched.execute,
sunrpc.sched.delay,
sunrpc.sched.release_task
{}
probe sunrpc.sched.return =
sunrpc.sched.new_task.return,
sunrpc.sched.execute.return,
sunrpc.sched.delay.return,
sunrpc.sched.release_task.return
{}
#
# Fires when the RPC `scheduler'(or rather, the finite state machine)
# is to be executed
#
# static int __rpc_execute(struct rpc_task *task)
#
probe sunrpc.sched.execute = kernel.function("__rpc_execute") ?,
module("sunrpc").function("__rpc_execute") ?
{
xid = xid_from_clnt($task->tk_client)
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
prot = prot_from_clnt($task->tk_client)
tk_pid = $task->tk_pid
tk_flags = $task->tk_flags
name = "sunrpc.sched.execute"
argstr = sprintf("%d %d %d %d %d %d", xid, prog,
vers, prot, tk_pid, tk_flags)
}
probe sunrpc.sched.execute.return = kernel.function("__rpc_execute").return ?,
module("sunrpc").function("__rpc_execute").return ?
{
name = "sunrpc.sched.execute"
retstr = returnstr($return)
}
#
# Fires when a task is to be delayed
#
# void rpc_delay(struct rpc_task *task, unsigned long delay)
#
probe sunrpc.sched.delay = kernel.function("rpc_delay") ?,
module("sunrpc").function("rpc_delay") ?
{
xid = xid_from_clnt($task->tk_client)
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
prot = prot_from_clnt($task->tk_client)
tk_pid = $task->tk_pid
tk_flags = $task->tk_flags
delay = $delay
name = "sunrpc.clnt.delay"
argstr = sprintf("%d %d %d %d %d %d", xid, prog, vers,
prot, tk_pid, tk_flags)
}
probe sunrpc.sched.delay.return = kernel.function("rpc_delay").return ?,
module("sunrpc").function("rpc_delay").return ?
{
name = "sunrpc.clnt.delay"
}
#
# Fires when a new task is to be created for the specified client.
#
# struct rpc_task * rpc_new_task(struct rpc_clnt *clnt, int flags,
# const struct rpc_call_ops *tk_ops, void *calldata)
#
probe sunrpc.sched.new_task = kernel.function("rpc_new_task") ?,
module("sunrpc").function("rpc_new_task") ?
{
xid = xid_from_clnt($clnt)
prog = prog_from_clnt($clnt)
vers = vers_from_clnt($clnt)
prot = prot_from_clnt($clnt)
flags = $flags
name = "sunrpc.sched.new_task"
argstr = sprintf("%d %d %d %d %d", xid, prog, vers, prot, flags)
}
probe sunrpc.sched.new_task.return = kernel.function("rpc_new_task").return ?,
module("sunrpc").function("rpc_new_task").return ?
{
name = "sunrpc.sched.new_task"
}
#
# Fires when all resources associated with a task are to be released
#
# void rpc_release_task(struct rpc_task *task)
#
probe sunrpc.sched.release_task = kernel.function("rpc_release_task") ?,
module("sunrpc").function("rpc_release_task") ?
{
xid = xid_from_clnt($task->tk_client)
prog = prog_from_clnt($task->tk_client)
vers = vers_from_clnt($task->tk_client)
prot = prot_from_clnt($task->tk_client)
flags = $task->tk_flags
name = "sunrpc.sched.release_task"
argstr = sprintf("%d %d %d %d %d", xid, prog, vers, prot, flags)
}
probe sunrpc.sched.release_task.return =
kernel.function("rpc_release_task").return ?,
module("sunrpc").function("rpc_release_task").return ?
{
name = "sunrpc.sched.release_task"
}
####################################################################
# Helpler functions #
####################################################################
function xid_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_xprt->tcp_xid : 0;
%}
function prog_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_prog : 0;
%}
function vers_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_vers : 0;
%}
function prot_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_prot : 0;
%}
function port_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = clnt ? clnt->cl_pmap->pm_port : 0;
%}
function tasks_from_clnt:long(clnt:long)
%{
struct rpc_clnt *clnt = (struct rpc_clnt *)THIS->clnt;
THIS->__retvalue = atomic_read(&clnt->cl_users);
%}
function proc_from_msg:long(msg:long)
%{
struct rpc_message *msg = (struct rpc_message *)THIS->msg;
THIS->__retvalue = msg ? msg->rpc_proc->p_proc : 0;
%}
function vers_from_prog:long(program:long, vers:long)
%{
struct rpc_program *program = (struct rpc_program *)THIS->program;
if (!program || THIS->vers >= program->nrvers || !program->version[THIS->vers])
THIS->__retvalue = 0;
else
THIS->__retvalue = program->version[THIS->vers]->number;
%}
function addr_from_rqst:long(rqstp:long)
%{
struct svc_rqst *rqstp = (struct svc_rqst *)THIS->rqstp;
THIS->__retvalue = rqstp ? rqstp->rq_addr.sin_addr.s_addr : 0;
%}