1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# nfsslower Trace slow NFS operations 5*387f9dfdSAndroid Build Coastguard Worker# for Linux using BCC & eBPF 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# Usage: nfsslower [-h] [-p PID] [min_ms] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# This script traces some common NFS operations: read, write, opens and 10*387f9dfdSAndroid Build Coastguard Worker# getattr. It measures the time spent in these operations, and prints details 11*387f9dfdSAndroid Build Coastguard Worker# for each that exceeded a threshold. 12*387f9dfdSAndroid Build Coastguard Worker# The script also traces commit operations, which is specific to nfs and could 13*387f9dfdSAndroid Build Coastguard Worker# be pretty slow. 14*387f9dfdSAndroid Build Coastguard Worker# 15*387f9dfdSAndroid Build Coastguard Worker# WARNING: This adds low-overhead instrumentation to these NFS operations, 16*387f9dfdSAndroid Build Coastguard Worker# including reads and writes from the file system cache. Such reads and writes 17*387f9dfdSAndroid Build Coastguard Worker# can be very frequent (depending on the workload; eg, 1M/sec), at which 18*387f9dfdSAndroid Build Coastguard Worker# point the overhead of this tool (even if it prints no "slower" events) can 19*387f9dfdSAndroid Build Coastguard Worker# begin to become significant. 20*387f9dfdSAndroid Build Coastguard Worker# 21*387f9dfdSAndroid Build Coastguard Worker# Most of this code is copied from similar tools (ext4slower, zfsslower etc) 22*387f9dfdSAndroid Build Coastguard Worker# 23*387f9dfdSAndroid Build Coastguard Worker# By default, a minimum millisecond threshold of 10 is used. 24*387f9dfdSAndroid Build Coastguard Worker# 25*387f9dfdSAndroid Build Coastguard Worker# This tool uses kprobes to instrument the kernel for entry and exit 26*387f9dfdSAndroid Build Coastguard Worker# information, in the future a preferred way would be to use tracepoints. 27*387f9dfdSAndroid Build Coastguard Worker# Currently there aren't any tracepoints available for nfs_read_file, 28*387f9dfdSAndroid Build Coastguard Worker# nfs_write_file and nfs_open_file, nfs_getattr does have entry and exit 29*387f9dfdSAndroid Build Coastguard Worker# tracepoints but we chose to use kprobes for consistency 30*387f9dfdSAndroid Build Coastguard Worker# Raw tracepoints are used to trace nfs:nfs_initiate_commit and 31*387f9dfdSAndroid Build Coastguard Worker# nfs:nfs_commit_done. 32*387f9dfdSAndroid Build Coastguard Worker# 33*387f9dfdSAndroid Build Coastguard Worker# 31-Aug-2017 Samuel Nair created this. Should work with NFSv{3,4} 34*387f9dfdSAndroid Build Coastguard Worker 35*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 36*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 37*387f9dfdSAndroid Build Coastguard Workerimport argparse 38*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime 39*387f9dfdSAndroid Build Coastguard Worker 40*387f9dfdSAndroid Build Coastguard Workerexamples = """ 41*387f9dfdSAndroid Build Coastguard Worker ./nfsslower # trace operations slower than 10ms 42*387f9dfdSAndroid Build Coastguard Worker ./nfsslower 1 # trace operations slower than 1ms 43*387f9dfdSAndroid Build Coastguard Worker ./nfsslower -j 1 # ... 1 ms, parsable output (csv) 44*387f9dfdSAndroid Build Coastguard Worker ./nfsslower 0 # trace all nfs operations 45*387f9dfdSAndroid Build Coastguard Worker ./nfsslower -p 121 # trace pid 121 only 46*387f9dfdSAndroid Build Coastguard Worker""" 47*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 48*387f9dfdSAndroid Build Coastguard Worker description="""Trace READ, WRITE, OPEN, GETATTR \ 49*387f9dfdSAndroid Build Coastguard Workerand COMMIT NFS calls slower than a threshold,\ 50*387f9dfdSAndroid Build Coastguard Workersupports NFSv{3,4}""", 51*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 52*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 53*387f9dfdSAndroid Build Coastguard Worker 54*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-j", "--csv", action="store_true", 55*387f9dfdSAndroid Build Coastguard Worker help="just print fields: comma-separated values") 56*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", help="Trace this pid only") 57*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("min_ms", nargs="?", default='10', 58*387f9dfdSAndroid Build Coastguard Worker help="Minimum IO duration to trace in ms (default=10ms)") 59*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 60*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 61*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 62*387f9dfdSAndroid Build Coastguard Workermin_ms = int(args.min_ms) 63*387f9dfdSAndroid Build Coastguard Workerpid = args.pid 64*387f9dfdSAndroid Build Coastguard Workercsv = args.csv 65*387f9dfdSAndroid Build Coastguard Workerdebug = 0 66*387f9dfdSAndroid Build Coastguard Worker 67*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 68*387f9dfdSAndroid Build Coastguard Worker 69*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 70*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h> 71*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 72*387f9dfdSAndroid Build Coastguard Worker#include <linux/dcache.h> 73*387f9dfdSAndroid Build Coastguard Worker#include <linux/nfs_fs.h> 74*387f9dfdSAndroid Build Coastguard Worker 75*387f9dfdSAndroid Build Coastguard Worker#define TRACE_READ 0 76*387f9dfdSAndroid Build Coastguard Worker#define TRACE_WRITE 1 77*387f9dfdSAndroid Build Coastguard Worker#define TRACE_OPEN 2 78*387f9dfdSAndroid Build Coastguard Worker#define TRACE_GETATTR 3 79*387f9dfdSAndroid Build Coastguard Worker#define TRACE_COMMIT 4 80*387f9dfdSAndroid Build Coastguard Worker 81*387f9dfdSAndroid Build Coastguard Workerstruct val_t { 82*387f9dfdSAndroid Build Coastguard Worker u64 ts; 83*387f9dfdSAndroid Build Coastguard Worker u64 offset; 84*387f9dfdSAndroid Build Coastguard Worker struct file *fp; 85*387f9dfdSAndroid Build Coastguard Worker struct dentry *d; 86*387f9dfdSAndroid Build Coastguard Worker}; 87*387f9dfdSAndroid Build Coastguard Worker 88*387f9dfdSAndroid Build Coastguard Workerstruct commit_t { 89*387f9dfdSAndroid Build Coastguard Worker u64 ts; 90*387f9dfdSAndroid Build Coastguard Worker u64 offset; 91*387f9dfdSAndroid Build Coastguard Worker u64 count; 92*387f9dfdSAndroid Build Coastguard Worker}; 93*387f9dfdSAndroid Build Coastguard Worker 94*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 95*387f9dfdSAndroid Build Coastguard Worker // XXX: switch some to u32's when supported 96*387f9dfdSAndroid Build Coastguard Worker u64 ts_us; 97*387f9dfdSAndroid Build Coastguard Worker u64 type; 98*387f9dfdSAndroid Build Coastguard Worker u64 size; 99*387f9dfdSAndroid Build Coastguard Worker u64 offset; 100*387f9dfdSAndroid Build Coastguard Worker u64 delta_us; 101*387f9dfdSAndroid Build Coastguard Worker u32 pid; 102*387f9dfdSAndroid Build Coastguard Worker char task[TASK_COMM_LEN]; 103*387f9dfdSAndroid Build Coastguard Worker char file[DNAME_INLINE_LEN]; 104*387f9dfdSAndroid Build Coastguard Worker}; 105*387f9dfdSAndroid Build Coastguard Worker 106*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(entryinfo, u64, struct val_t); 107*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 108*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(commitinfo, u64, struct commit_t); 109*387f9dfdSAndroid Build Coastguard Worker 110*387f9dfdSAndroid Build Coastguard Workerint trace_rw_entry(struct pt_regs *ctx, struct kiocb *iocb, 111*387f9dfdSAndroid Build Coastguard Worker struct iov_iter *data) 112*387f9dfdSAndroid Build Coastguard Worker{ 113*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 114*387f9dfdSAndroid Build Coastguard Worker u32 pid = id >> 32; // PID is higher part 115*387f9dfdSAndroid Build Coastguard Worker 116*387f9dfdSAndroid Build Coastguard Worker if(FILTER_PID) 117*387f9dfdSAndroid Build Coastguard Worker return 0; 118*387f9dfdSAndroid Build Coastguard Worker 119*387f9dfdSAndroid Build Coastguard Worker // store filep and timestamp by id 120*387f9dfdSAndroid Build Coastguard Worker struct val_t val = {}; 121*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 122*387f9dfdSAndroid Build Coastguard Worker val.fp = iocb->ki_filp; 123*387f9dfdSAndroid Build Coastguard Worker val.d = NULL; 124*387f9dfdSAndroid Build Coastguard Worker val.offset = iocb->ki_pos; 125*387f9dfdSAndroid Build Coastguard Worker 126*387f9dfdSAndroid Build Coastguard Worker if (val.fp) 127*387f9dfdSAndroid Build Coastguard Worker entryinfo.update(&id, &val); 128*387f9dfdSAndroid Build Coastguard Worker 129*387f9dfdSAndroid Build Coastguard Worker return 0; 130*387f9dfdSAndroid Build Coastguard Worker} 131*387f9dfdSAndroid Build Coastguard Worker 132*387f9dfdSAndroid Build Coastguard Workerint trace_file_open_entry (struct pt_regs *ctx, struct inode *inode, 133*387f9dfdSAndroid Build Coastguard Worker struct file *filp) 134*387f9dfdSAndroid Build Coastguard Worker{ 135*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 136*387f9dfdSAndroid Build Coastguard Worker u32 pid = id >> 32; // PID is higher part 137*387f9dfdSAndroid Build Coastguard Worker 138*387f9dfdSAndroid Build Coastguard Worker if(FILTER_PID) 139*387f9dfdSAndroid Build Coastguard Worker return 0; 140*387f9dfdSAndroid Build Coastguard Worker 141*387f9dfdSAndroid Build Coastguard Worker // store filep and timestamp by id 142*387f9dfdSAndroid Build Coastguard Worker struct val_t val = {}; 143*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 144*387f9dfdSAndroid Build Coastguard Worker val.fp = filp; 145*387f9dfdSAndroid Build Coastguard Worker val.d = NULL; 146*387f9dfdSAndroid Build Coastguard Worker val.offset = 0; 147*387f9dfdSAndroid Build Coastguard Worker if (val.fp) 148*387f9dfdSAndroid Build Coastguard Worker entryinfo.update(&id, &val); 149*387f9dfdSAndroid Build Coastguard Worker 150*387f9dfdSAndroid Build Coastguard Worker return 0; 151*387f9dfdSAndroid Build Coastguard Worker} 152*387f9dfdSAndroid Build Coastguard Worker 153*387f9dfdSAndroid Build Coastguard Workerint trace_getattr_entry(struct pt_regs *ctx, struct vfsmount *mnt, 154*387f9dfdSAndroid Build Coastguard Worker struct dentry *dentry, struct kstat *stat) 155*387f9dfdSAndroid Build Coastguard Worker{ 156*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 157*387f9dfdSAndroid Build Coastguard Worker u32 pid = id >> 32; // PID is higher part 158*387f9dfdSAndroid Build Coastguard Worker 159*387f9dfdSAndroid Build Coastguard Worker if(FILTER_PID) 160*387f9dfdSAndroid Build Coastguard Worker return 0; 161*387f9dfdSAndroid Build Coastguard Worker 162*387f9dfdSAndroid Build Coastguard Worker struct val_t val = {}; 163*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 164*387f9dfdSAndroid Build Coastguard Worker val.fp = NULL; 165*387f9dfdSAndroid Build Coastguard Worker val.d = dentry; 166*387f9dfdSAndroid Build Coastguard Worker val.offset = 0; 167*387f9dfdSAndroid Build Coastguard Worker if (val.d) 168*387f9dfdSAndroid Build Coastguard Worker entryinfo.update(&id, &val); 169*387f9dfdSAndroid Build Coastguard Worker 170*387f9dfdSAndroid Build Coastguard Worker return 0; 171*387f9dfdSAndroid Build Coastguard Worker} 172*387f9dfdSAndroid Build Coastguard Worker 173*387f9dfdSAndroid Build Coastguard Workerstatic int trace_exit(struct pt_regs *ctx, int type) 174*387f9dfdSAndroid Build Coastguard Worker{ 175*387f9dfdSAndroid Build Coastguard Worker struct val_t *valp; 176*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 177*387f9dfdSAndroid Build Coastguard Worker u32 pid = id >> 32; // PID is higher part 178*387f9dfdSAndroid Build Coastguard Worker 179*387f9dfdSAndroid Build Coastguard Worker valp = entryinfo.lookup(&id); 180*387f9dfdSAndroid Build Coastguard Worker if (valp == 0) { 181*387f9dfdSAndroid Build Coastguard Worker // missed tracing issue or filtered 182*387f9dfdSAndroid Build Coastguard Worker return 0; 183*387f9dfdSAndroid Build Coastguard Worker } 184*387f9dfdSAndroid Build Coastguard Worker 185*387f9dfdSAndroid Build Coastguard Worker // calculate delta 186*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 187*387f9dfdSAndroid Build Coastguard Worker u64 delta_us = (ts - valp->ts) / 1000; 188*387f9dfdSAndroid Build Coastguard Worker entryinfo.delete(&id); 189*387f9dfdSAndroid Build Coastguard Worker 190*387f9dfdSAndroid Build Coastguard Worker if (FILTER_US) 191*387f9dfdSAndroid Build Coastguard Worker return 0; 192*387f9dfdSAndroid Build Coastguard Worker 193*387f9dfdSAndroid Build Coastguard Worker // populate output struct 194*387f9dfdSAndroid Build Coastguard Worker u32 size = PT_REGS_RC(ctx); 195*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 196*387f9dfdSAndroid Build Coastguard Worker data.type = type; 197*387f9dfdSAndroid Build Coastguard Worker data.size = size; 198*387f9dfdSAndroid Build Coastguard Worker data.delta_us = delta_us; 199*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 200*387f9dfdSAndroid Build Coastguard Worker data.ts_us = ts / 1000; 201*387f9dfdSAndroid Build Coastguard Worker data.offset = valp->offset; 202*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.task, sizeof(data.task)); 203*387f9dfdSAndroid Build Coastguard Worker 204*387f9dfdSAndroid Build Coastguard Worker // workaround (rewriter should handle file to d_name in one step): 205*387f9dfdSAndroid Build Coastguard Worker struct dentry *de = NULL; 206*387f9dfdSAndroid Build Coastguard Worker struct qstr qs = {}; 207*387f9dfdSAndroid Build Coastguard Worker if(type == TRACE_GETATTR) 208*387f9dfdSAndroid Build Coastguard Worker { 209*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&de,sizeof(de), &valp->d); 210*387f9dfdSAndroid Build Coastguard Worker } 211*387f9dfdSAndroid Build Coastguard Worker else 212*387f9dfdSAndroid Build Coastguard Worker { 213*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&de, sizeof(de), &valp->fp->f_path.dentry); 214*387f9dfdSAndroid Build Coastguard Worker } 215*387f9dfdSAndroid Build Coastguard Worker 216*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&qs, sizeof(qs), (void *)&de->d_name); 217*387f9dfdSAndroid Build Coastguard Worker if (qs.len == 0) 218*387f9dfdSAndroid Build Coastguard Worker return 0; 219*387f9dfdSAndroid Build Coastguard Worker 220*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.file, sizeof(data.file), (void *)qs.name); 221*387f9dfdSAndroid Build Coastguard Worker // output 222*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 223*387f9dfdSAndroid Build Coastguard Worker return 0; 224*387f9dfdSAndroid Build Coastguard Worker} 225*387f9dfdSAndroid Build Coastguard Worker 226*387f9dfdSAndroid Build Coastguard Workerint trace_file_open_return(struct pt_regs *ctx) 227*387f9dfdSAndroid Build Coastguard Worker{ 228*387f9dfdSAndroid Build Coastguard Worker return trace_exit(ctx, TRACE_OPEN); 229*387f9dfdSAndroid Build Coastguard Worker} 230*387f9dfdSAndroid Build Coastguard Worker 231*387f9dfdSAndroid Build Coastguard Workerint trace_read_return(struct pt_regs *ctx) 232*387f9dfdSAndroid Build Coastguard Worker{ 233*387f9dfdSAndroid Build Coastguard Worker return trace_exit(ctx, TRACE_READ); 234*387f9dfdSAndroid Build Coastguard Worker} 235*387f9dfdSAndroid Build Coastguard Worker 236*387f9dfdSAndroid Build Coastguard Workerint trace_write_return(struct pt_regs *ctx) 237*387f9dfdSAndroid Build Coastguard Worker{ 238*387f9dfdSAndroid Build Coastguard Worker return trace_exit(ctx, TRACE_WRITE); 239*387f9dfdSAndroid Build Coastguard Worker} 240*387f9dfdSAndroid Build Coastguard Worker 241*387f9dfdSAndroid Build Coastguard Workerint trace_getattr_return(struct pt_regs *ctx) 242*387f9dfdSAndroid Build Coastguard Worker{ 243*387f9dfdSAndroid Build Coastguard Worker return trace_exit(ctx, TRACE_GETATTR); 244*387f9dfdSAndroid Build Coastguard Worker} 245*387f9dfdSAndroid Build Coastguard Worker 246*387f9dfdSAndroid Build Coastguard Workerstatic int trace_initiate_commit(struct nfs_commit_data *cd) 247*387f9dfdSAndroid Build Coastguard Worker{ 248*387f9dfdSAndroid Build Coastguard Worker u64 key = (u64)cd; 249*387f9dfdSAndroid Build Coastguard Worker struct commit_t c = { 0 }; 250*387f9dfdSAndroid Build Coastguard Worker 251*387f9dfdSAndroid Build Coastguard Worker c.ts = bpf_ktime_get_ns(); 252*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&c.offset, sizeof(cd->args.offset), 253*387f9dfdSAndroid Build Coastguard Worker &cd->args.offset); 254*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&c.count, sizeof(cd->args.count), &cd->args.count); 255*387f9dfdSAndroid Build Coastguard Worker commitinfo.update(&key, &c); 256*387f9dfdSAndroid Build Coastguard Worker return 0; 257*387f9dfdSAndroid Build Coastguard Worker} 258*387f9dfdSAndroid Build Coastguard Worker 259*387f9dfdSAndroid Build Coastguard Worker""" 260*387f9dfdSAndroid Build Coastguard Worker 261*387f9dfdSAndroid Build Coastguard Workerbpf_text_raw_tp = """ 262*387f9dfdSAndroid Build Coastguard WorkerRAW_TRACEPOINT_PROBE(nfs_initiate_commit) 263*387f9dfdSAndroid Build Coastguard Worker{ 264*387f9dfdSAndroid Build Coastguard Worker // TP_PROTO(const struct nfs_commit_data *data) 265*387f9dfdSAndroid Build Coastguard Worker struct nfs_commit_data *cd = (struct nfs_commit_data *)ctx->args[0]; 266*387f9dfdSAndroid Build Coastguard Worker return trace_initiate_commit(cd); 267*387f9dfdSAndroid Build Coastguard Worker} 268*387f9dfdSAndroid Build Coastguard Worker 269*387f9dfdSAndroid Build Coastguard WorkerRAW_TRACEPOINT_PROBE(nfs_commit_done) 270*387f9dfdSAndroid Build Coastguard Worker{ 271*387f9dfdSAndroid Build Coastguard Worker // TP_PROTO(const struct rpc_task *task, const struct nfs_commit_data *data) 272*387f9dfdSAndroid Build Coastguard Worker struct nfs_commit_data *cd = (struct nfs_commit_data *)ctx->args[1]; 273*387f9dfdSAndroid Build Coastguard Worker u64 key = (u64)cd; 274*387f9dfdSAndroid Build Coastguard Worker struct commit_t *cp = commitinfo.lookup(&key); 275*387f9dfdSAndroid Build Coastguard Worker 276*387f9dfdSAndroid Build Coastguard Worker if (cp) { 277*387f9dfdSAndroid Build Coastguard Worker struct nfs_open_context *p; 278*387f9dfdSAndroid Build Coastguard Worker struct dentry *de; 279*387f9dfdSAndroid Build Coastguard Worker struct qstr qs; 280*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 281*387f9dfdSAndroid Build Coastguard Worker u64 delta_us = (ts - cp->ts) / 1000; 282*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 283*387f9dfdSAndroid Build Coastguard Worker 284*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 285*387f9dfdSAndroid Build Coastguard Worker data.type = TRACE_COMMIT; 286*387f9dfdSAndroid Build Coastguard Worker data.offset = cp->offset; 287*387f9dfdSAndroid Build Coastguard Worker data.size = cp->count; 288*387f9dfdSAndroid Build Coastguard Worker data.ts_us = ts/1000; 289*387f9dfdSAndroid Build Coastguard Worker data.delta_us = delta_us; 290*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 291*387f9dfdSAndroid Build Coastguard Worker 292*387f9dfdSAndroid Build Coastguard Worker commitinfo.delete(&key); 293*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.task, sizeof(data.task)); 294*387f9dfdSAndroid Build Coastguard Worker 295*387f9dfdSAndroid Build Coastguard Worker if(FILTER_PID) 296*387f9dfdSAndroid Build Coastguard Worker return 0; 297*387f9dfdSAndroid Build Coastguard Worker 298*387f9dfdSAndroid Build Coastguard Worker if (FILTER_US) 299*387f9dfdSAndroid Build Coastguard Worker return 0; 300*387f9dfdSAndroid Build Coastguard Worker 301*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&p, sizeof(p), &cd->context); 302*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&de, sizeof(de), &p->dentry); 303*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&qs, sizeof(qs), &de->d_name); 304*387f9dfdSAndroid Build Coastguard Worker if (qs.len) { 305*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.file, sizeof(data.file), 306*387f9dfdSAndroid Build Coastguard Worker (void *)qs.name); 307*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 308*387f9dfdSAndroid Build Coastguard Worker } 309*387f9dfdSAndroid Build Coastguard Worker } 310*387f9dfdSAndroid Build Coastguard Worker return 0; 311*387f9dfdSAndroid Build Coastguard Worker} 312*387f9dfdSAndroid Build Coastguard Worker""" 313*387f9dfdSAndroid Build Coastguard Worker 314*387f9dfdSAndroid Build Coastguard Workerbpf_text_kprobe = """ 315*387f9dfdSAndroid Build Coastguard Workerint trace_nfs_initiate_commit(struct pt_regs *ctx, void *clnt, struct nfs_commit_data *cd) 316*387f9dfdSAndroid Build Coastguard Worker{ 317*387f9dfdSAndroid Build Coastguard Worker return trace_initiate_commit(cd); 318*387f9dfdSAndroid Build Coastguard Worker} 319*387f9dfdSAndroid Build Coastguard Worker 320*387f9dfdSAndroid Build Coastguard Workerint trace_nfs_commit_done(struct pt_regs *ctx, void *task, void *calldata) 321*387f9dfdSAndroid Build Coastguard Worker{ 322*387f9dfdSAndroid Build Coastguard Worker struct nfs_commit_data *cd = (struct nfs_commit_data *)calldata; 323*387f9dfdSAndroid Build Coastguard Worker u64 key = (u64)cd; 324*387f9dfdSAndroid Build Coastguard Worker struct commit_t *cp = commitinfo.lookup(&key); 325*387f9dfdSAndroid Build Coastguard Worker 326*387f9dfdSAndroid Build Coastguard Worker if (cp) { 327*387f9dfdSAndroid Build Coastguard Worker struct nfs_open_context *p; 328*387f9dfdSAndroid Build Coastguard Worker struct dentry *de; 329*387f9dfdSAndroid Build Coastguard Worker struct qstr qs; 330*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 331*387f9dfdSAndroid Build Coastguard Worker u64 delta_us = (ts - cp->ts) / 1000; 332*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 333*387f9dfdSAndroid Build Coastguard Worker 334*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 335*387f9dfdSAndroid Build Coastguard Worker data.type = TRACE_COMMIT; 336*387f9dfdSAndroid Build Coastguard Worker data.offset = cp->offset; 337*387f9dfdSAndroid Build Coastguard Worker data.size = cp->count; 338*387f9dfdSAndroid Build Coastguard Worker data.ts_us = ts/1000; 339*387f9dfdSAndroid Build Coastguard Worker data.delta_us = delta_us; 340*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 341*387f9dfdSAndroid Build Coastguard Worker 342*387f9dfdSAndroid Build Coastguard Worker commitinfo.delete(&key); 343*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.task, sizeof(data.task)); 344*387f9dfdSAndroid Build Coastguard Worker 345*387f9dfdSAndroid Build Coastguard Worker if(FILTER_PID) 346*387f9dfdSAndroid Build Coastguard Worker return 0; 347*387f9dfdSAndroid Build Coastguard Worker 348*387f9dfdSAndroid Build Coastguard Worker if (FILTER_US) 349*387f9dfdSAndroid Build Coastguard Worker return 0; 350*387f9dfdSAndroid Build Coastguard Worker 351*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&p, sizeof(p), &cd->context); 352*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&de, sizeof(de), &p->dentry); 353*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&qs, sizeof(qs), &de->d_name); 354*387f9dfdSAndroid Build Coastguard Worker if (qs.len) { 355*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.file, sizeof(data.file), 356*387f9dfdSAndroid Build Coastguard Worker (void *)qs.name); 357*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 358*387f9dfdSAndroid Build Coastguard Worker } 359*387f9dfdSAndroid Build Coastguard Worker } 360*387f9dfdSAndroid Build Coastguard Worker return 0; 361*387f9dfdSAndroid Build Coastguard Worker} 362*387f9dfdSAndroid Build Coastguard Worker""" 363*387f9dfdSAndroid Build Coastguard Workeris_support_raw_tp = BPF.support_raw_tracepoint() 364*387f9dfdSAndroid Build Coastguard Workerif is_support_raw_tp: 365*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_raw_tp 366*387f9dfdSAndroid Build Coastguard Workerelse: 367*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_kprobe 368*387f9dfdSAndroid Build Coastguard Worker 369*387f9dfdSAndroid Build Coastguard Workerif min_ms == 0: 370*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_US', '0') 371*387f9dfdSAndroid Build Coastguard Workerelse: 372*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_US', 373*387f9dfdSAndroid Build Coastguard Worker 'delta_us <= %s' % str(min_ms * 1000)) 374*387f9dfdSAndroid Build Coastguard Workerif args.pid: 375*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_PID', 'pid != %s' % pid) 376*387f9dfdSAndroid Build Coastguard Workerelse: 377*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_PID', '0') 378*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 379*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 380*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 381*387f9dfdSAndroid Build Coastguard Worker exit() 382*387f9dfdSAndroid Build Coastguard Worker 383*387f9dfdSAndroid Build Coastguard Worker# process event 384*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 385*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 386*387f9dfdSAndroid Build Coastguard Worker 387*387f9dfdSAndroid Build Coastguard Worker type = 'R' 388*387f9dfdSAndroid Build Coastguard Worker if event.type == 1: 389*387f9dfdSAndroid Build Coastguard Worker type = 'W' 390*387f9dfdSAndroid Build Coastguard Worker elif event.type == 2: 391*387f9dfdSAndroid Build Coastguard Worker type = 'O' 392*387f9dfdSAndroid Build Coastguard Worker elif event.type == 3: 393*387f9dfdSAndroid Build Coastguard Worker type = 'G' 394*387f9dfdSAndroid Build Coastguard Worker elif event.type == 4: 395*387f9dfdSAndroid Build Coastguard Worker type = 'C' 396*387f9dfdSAndroid Build Coastguard Worker 397*387f9dfdSAndroid Build Coastguard Worker if(csv): 398*387f9dfdSAndroid Build Coastguard Worker print("%d,%s,%d,%s,%d,%d,%d,%s" % ( 399*387f9dfdSAndroid Build Coastguard Worker event.ts_us, event.task, event.pid, type, event.size, 400*387f9dfdSAndroid Build Coastguard Worker event.offset, event.delta_us, event.file)) 401*387f9dfdSAndroid Build Coastguard Worker return 402*387f9dfdSAndroid Build Coastguard Worker print("%-8s %-14.14s %-6s %1s %-7s %-8d %7.2f %s" % 403*387f9dfdSAndroid Build Coastguard Worker (strftime("%H:%M:%S"), 404*387f9dfdSAndroid Build Coastguard Worker event.task.decode('utf-8', 'replace'), 405*387f9dfdSAndroid Build Coastguard Worker event.pid, 406*387f9dfdSAndroid Build Coastguard Worker type, 407*387f9dfdSAndroid Build Coastguard Worker event.size, 408*387f9dfdSAndroid Build Coastguard Worker event.offset / 1024, 409*387f9dfdSAndroid Build Coastguard Worker float(event.delta_us) / 1000, 410*387f9dfdSAndroid Build Coastguard Worker event.file.decode('utf-8', 'replace'))) 411*387f9dfdSAndroid Build Coastguard Worker 412*387f9dfdSAndroid Build Coastguard Worker 413*387f9dfdSAndroid Build Coastguard Worker# Currently specifically works for NFSv4, the other kprobes are generic 414*387f9dfdSAndroid Build Coastguard Worker# so it should work with earlier NFS versions 415*387f9dfdSAndroid Build Coastguard Worker 416*387f9dfdSAndroid Build Coastguard Worker# The following warning is shown on kernels after linux-5.18 when using bcc. 417*387f9dfdSAndroid Build Coastguard Worker# Add compile option to silence it. 418*387f9dfdSAndroid Build Coastguard Worker# In file included from /virtual/main.c:7: 419*387f9dfdSAndroid Build Coastguard Worker# In file included from include/linux/nfs_fs.h:31: 420*387f9dfdSAndroid Build Coastguard Worker# In file included from include/linux/sunrpc/auth.h:13: 421*387f9dfdSAndroid Build Coastguard Worker# In file included from include/linux/sunrpc/sched.h:19: 422*387f9dfdSAndroid Build Coastguard Worker# include/linux/sunrpc/xdr.h:751:10: warning: result of comparison of constant 4611686018427387903 with expression of type '__u32' (aka 'unsigned int') is always false [-Wtautological-constant-out-of-range-compare] 423*387f9dfdSAndroid Build Coastguard Worker# if (len > SIZE_MAX / sizeof(*p)) 424*387f9dfdSAndroid Build Coastguard Worker# ~~~ ^ ~~~~~~~~~~~~~~~~~~~~~ 425*387f9dfdSAndroid Build Coastguard Worker# 1 warning generated. 426*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text, 427*387f9dfdSAndroid Build Coastguard Worker cflags=["-Wno-tautological-constant-out-of-range-compare"]) 428*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_read", fn_name="trace_rw_entry") 429*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_write", fn_name="trace_rw_entry") 430*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_file_open", fn_name="trace_file_open_entry") 431*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="nfs_getattr", fn_name="trace_getattr_entry") 432*387f9dfdSAndroid Build Coastguard Worker 433*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_read", fn_name="trace_read_return") 434*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_write", fn_name="trace_write_return") 435*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_file_open", fn_name="trace_file_open_return") 436*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="nfs_getattr", fn_name="trace_getattr_return") 437*387f9dfdSAndroid Build Coastguard Worker 438*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b'nfs4_file_open'): 439*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="nfs4_file_open", fn_name="trace_file_open_entry") 440*387f9dfdSAndroid Build Coastguard Worker b.attach_kretprobe(event="nfs4_file_open", fn_name="trace_file_open_return") 441*387f9dfdSAndroid Build Coastguard Worker 442*387f9dfdSAndroid Build Coastguard Workerif not is_support_raw_tp: 443*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="nfs_initiate_commit", 444*387f9dfdSAndroid Build Coastguard Worker fn_name="trace_nfs_initiate_commit") 445*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="nfs_commit_done", 446*387f9dfdSAndroid Build Coastguard Worker fn_name="trace_nfs_commit_done") 447*387f9dfdSAndroid Build Coastguard Worker 448*387f9dfdSAndroid Build Coastguard Workerif(csv): 449*387f9dfdSAndroid Build Coastguard Worker print("ENDTIME_us,TASK,PID,TYPE,BYTES,OFFSET_b,LATENCY_us,FILE") 450*387f9dfdSAndroid Build Coastguard Workerelse: 451*387f9dfdSAndroid Build Coastguard Worker if min_ms == 0: 452*387f9dfdSAndroid Build Coastguard Worker print("Tracing NFS operations... Ctrl-C to quit") 453*387f9dfdSAndroid Build Coastguard Worker else: 454*387f9dfdSAndroid Build Coastguard Worker print("""Tracing NFS operations that are slower than \ 455*387f9dfdSAndroid Build Coastguard Worker%d ms... Ctrl-C to quit""" 456*387f9dfdSAndroid Build Coastguard Worker % min_ms) 457*387f9dfdSAndroid Build Coastguard Worker print("%-8s %-14s %-6s %1s %-7s %-8s %7s %s" % ("TIME", 458*387f9dfdSAndroid Build Coastguard Worker "COMM", 459*387f9dfdSAndroid Build Coastguard Worker "PID", 460*387f9dfdSAndroid Build Coastguard Worker "T", 461*387f9dfdSAndroid Build Coastguard Worker "BYTES", 462*387f9dfdSAndroid Build Coastguard Worker "OFF_KB", 463*387f9dfdSAndroid Build Coastguard Worker "LAT(ms)", 464*387f9dfdSAndroid Build Coastguard Worker "FILENAME")) 465*387f9dfdSAndroid Build Coastguard Worker 466*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64) 467*387f9dfdSAndroid Build Coastguard Workerwhile 1: 468*387f9dfdSAndroid Build Coastguard Worker try: 469*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 470*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 471*387f9dfdSAndroid Build Coastguard Worker exit() 472