1#!/usr/bin/python 2# @lint-avoid-python-3-compatibility-imports 3# 4# filelife Trace the lifespan of short-lived files. 5# For Linux, uses BCC, eBPF. Embedded C. 6# 7# This traces the creation and deletion of files, providing information 8# on who deleted the file, the file age, and the file name. The intent is to 9# provide information on short-lived files, for debugging or performance 10# analysis. 11# 12# USAGE: filelife [-h] [-p PID] 13# 14# Copyright 2016 Netflix, Inc. 15# Licensed under the Apache License, Version 2.0 (the "License") 16# 17# 08-Feb-2015 Brendan Gregg Created this. 18 19from __future__ import print_function 20from bcc import BPF 21import argparse 22from time import strftime 23 24# arguments 25examples = """examples: 26 ./filelife # trace all stat() syscalls 27 ./filelife -p 181 # only trace PID 181 28""" 29parser = argparse.ArgumentParser( 30 description="Trace stat() syscalls", 31 formatter_class=argparse.RawDescriptionHelpFormatter, 32 epilog=examples) 33parser.add_argument("-p", "--pid", 34 help="trace this PID only") 35args = parser.parse_args() 36debug = 0 37 38# define BPF program 39bpf_text = """ 40#include <uapi/linux/ptrace.h> 41#include <linux/fs.h> 42 43BPF_HASH(birth, struct dentry *); 44 45// trace file creation time 46int trace_create(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry) 47{ 48 u32 pid = bpf_get_current_pid_tgid(); 49 FILTER 50 51 u64 ts = bpf_ktime_get_ns(); 52 birth.update(&dentry, &ts); 53 54 return 0; 55}; 56 57// trace file deletion and output details 58int trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry) 59{ 60 u32 pid = bpf_get_current_pid_tgid(); 61 FILTER 62 63 u64 *tsp, delta; 64 tsp = birth.lookup(&dentry); 65 if (tsp == 0) { 66 return 0; // missed create 67 } 68 delta = (bpf_ktime_get_ns() - *tsp) / 1000000; 69 birth.delete(&dentry); 70 71 if (dentry->d_iname[0] == 0) 72 return 0; 73 74 bpf_trace_printk("%d %s\\n", delta, dentry->d_iname); 75 76 return 0; 77} 78""" 79if args.pid: 80 bpf_text = bpf_text.replace('FILTER', 81 'if (pid != %s) { return 0; }' % args.pid) 82else: 83 bpf_text = bpf_text.replace('FILTER', '') 84if debug: 85 print(bpf_text) 86 87# initialize BPF 88b = BPF(text=bpf_text) 89b.attach_kprobe(event="vfs_create", fn_name="trace_create") 90b.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink") 91 92# header 93print("%-8s %-6s %-16s %-7s %s" % ("TIME", "PID", "COMM", "AGE(s)", "FILE")) 94 95start_ts = 0 96 97# format output 98while 1: 99 (task, pid, cpu, flags, ts, msg) = b.trace_fields() 100 (delta, filename) = msg.split(" ", 1) 101 102 # print columns 103 print("%-8s %-6d %-16s %-7.2f %s" % (strftime("%H:%M:%S"), pid, task, 104 float(delta) / 1000, filename)) 105