Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Dec 2014 15:19:31 -0800
From:      <dteske@FreeBSD.org>
To:        <markj@freebsd.org>
Cc:        'Devin Teske' <dteske@freebsd.org>, 'Julian Elischer' <julian@freebsd.org>, freebsd-dtrace@freebsd.org
Subject:   DTrace script to trace processes entering vfs::vop_remove
Message-ID:  <032e01d00f4f$98a04e20$c9e0ea60$@FreeBSD.org>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi markj, list,

I wrote a script for $work to help me find out "who on Earth
keeps deleting files XYZ?" from a particular storage server.

Please find attached a copy of watch_vop_remove.d which
has the following sample output:

2014 Dec  3 11:58:52 rm[75596]: /tmp/foo
 -+= 72846 0.0 -bash
  \-+= 75589 0.0 /bin/bash /usr/home/support/bash_script
    \-+= 75596 0.0 rm -f /tmp/foo

The above sample output was displayed when executing the following shell
script:

#!/bin/bash
touch /tmp/foo
rm -f /tmp/foo

The output format displayed for each vop_remove() call is as follows:

DATE process[PID]: PATH_TO_DELETE
 -+= GPID UID.GID grandparent_process [arguments (up to 3)]
  \-+= PPID UID.GID parent_process [arguments (up to 3)]
    \-+= PID UID.GID process [arguments (up to 3)]

NB: Requires "kldload dtraceall" to be performed prior to execution
-- 
Cheers,
Devin

[-- Attachment #2 --]
#!/usr/sbin/dtrace -s
/* -
 * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Title: dtrace(1) script to log process(es) entering vfs::vop_remove $
 */

#pragma D option quiet
#pragma D option dynvarsize=16m
#pragma D option switchrate=10hz

/*********************************************************/

vfs::vop_remove:entry
{
	this->vp = (struct vnode *)arg0;
	this->ncp = &(this->vp->v_cache_dst) != NULL ?
		this->vp->v_cache_dst.tqh_first : 0;
        this->fi_name = args[1] ? (
		args[1]->a_cnp != NULL ?
			stringof(args[1]->a_cnp->cn_nameptr) : ""
	) : "";
	this->mount = this->vp->v_mount; /* ptr to vfs we are in */
	this->fi_fs = this->mount != 0 ?
		stringof(this->mount->mnt_stat.f_fstypename) : "";
	this->fi_mount = this->mount != 0 ?
		stringof(this->mount->mnt_stat.f_mntonname) : "";
	this->d_name = args[0]->v_cache_dd != NULL ?
		stringof(args[0]->v_cache_dd->nc_name) : "";
	this->ts = timestamp;
	@c = count();
}

vfs::vop_remove:entry /this->vp == 0 || this->fi_fs == 0 ||
	this->fi_fs == "devfs" || this->fi_fs == "" ||
	this->fi_name == ""/
{
	this->ncp = 0;
}

/*********************************************************/

vfs::vop_remove:entry /this->ncp/ /* depth == 1 */
{
	this->dvp = this->ncp->nc_dvp != NULL ? (
		&(this->ncp->nc_dvp->v_cache_dst) != NULL ?
			this->ncp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->depth = 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /self->name[1] == 0 || this->fi_fs == 0 ||
	this->fi_fs == "devfs" || this->fi_fs == "" ||
	self->name[1] == "/" || self->name[1] == ""/
{
	this->dvp = 0;
}

/*********************************************************/

/*
 * BEGIN Pathname-depth iterators (copy/paste as many times as-desired)
 */

vfs::vop_remove:entry /this->dvp/ /* depth == 2 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 3 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 4 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 5 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 6 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 7 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 8 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 9 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 10 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 11 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 12 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 13 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 14 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 15 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 16 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 17 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 18 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 19 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

vfs::vop_remove:entry /this->dvp/ /* depth == 20 */
{
	this->dvp = this->dvp->nc_dvp != NULL ? (
		&(this->dvp->nc_dvp->v_cache_dst) != NULL ?
			this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
	) : 0;
	self->name[++self->depth] = this->dvp != 0 ? (
		this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
	) : "";
}

/*
 * END Pathname-depth iterators
 */

/*********************************************************/

vfs::vop_remove:entry /this->fi_mount != 0/
{
	printf("%Y %s[%d]: ", timestamp + 1406598400000000000, execname, pid);

	/*
	 * Print full path of file to delete
	 * NB: Up-to but not including the parent directory (printed below)
	 */
	printf("%s%s", this->fi_mount, this->fi_mount != 0 ? (
		this->fi_mount == "/" ? "" : "/"
	) : "/");
	name = self->name[self->depth--]; /* 20 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 19 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 18 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 17 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 16 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 15 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 14 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 13 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 12 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 11 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 10 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 9 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 8 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 7 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 6 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 5 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 4 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 3 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 2 */
	printf("%s%s", name, name != "" ? "/" : "");
	name = self->name[self->depth--]; /* 1 */
	printf("%s%s", name, name != "" ? "/" : "");

	/* Print the parent directory name */
	printf("%s%s", this->d_name != 0 ? this->d_name : "",
	               this->d_name != 0 ? "/" : "");

	/* Print the entry name */
	printf("%s", this->fi_name != 0 ? this->fi_name : "");

	printf("\n");

	/*
	 * Examine process, parent process, and grandparent process details
	 */

	/******************* CURPROC *******************/

	pn = 0;
	proc = curthread->td_proc;
	_pid[pn] = proc->p_pid;
	_uid[pn] = proc->p_ucred->cr_uid;
	_gid[pn] = proc->p_ucred->cr_rgid;
	p_args = proc->p_args;
	ar_length = p_args ? p_args->ar_length : 0;
	ar_args = (char *)(p_args ? p_args->ar_args : 0);
	ad = 0;

	arg[pn,ad++] = ar_length > 0 ? stringof(ar_args) : proc->p_comm;
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? "..." : "";

	/******************* PPARENT *******************/

	pn++;
	proc = proc->p_pptr;
	_pid[pn] = proc->p_pid;
	_uid[pn] = proc->p_ucred->cr_uid;
	_gid[pn] = proc->p_ucred->cr_rgid;
	p_args = proc ? proc->p_args : 0;
	ar_length = p_args ? p_args->ar_length : 0;
	ar_args = (char *)(p_args ? p_args->ar_args : 0);
	ad = 0;
	offset = 0;

	arg[pn,ad++] = ar_length > 0 ? ar_args : proc->p_comm;
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? "..." : "";

	/******************* GPARENT *******************/

	pn++;
	proc = proc->p_pptr;
	_pid[pn] = proc->p_pid;
	_uid[pn] = proc->p_ucred->cr_uid;
	_gid[pn] = proc->p_ucred->cr_rgid;
	p_args = proc ? proc->p_args : 0;
	ar_length = p_args ? p_args->ar_length : 0;
	ar_args = (char *)(p_args ? p_args->ar_args : 0);
	ad = 0;
	offset = 0;

	arg[pn,ad++] = ar_length > 0 ? ar_args : proc->p_comm;
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? ar_args : "";
	len = ar_length > 0 ? strlen(ar_args) + 1 : 0;
	ar_args += len;
	ar_length -= len;

	arg[pn,ad++] = ar_length > 0 ? "..." : "";

	/***********************************************/

	/*
	 * Print process, parent, and grandparent details
	 */

	printf(" -+= %05d %d.%d %s", _pid[pn], _uid[pn], _gid[pn], arg[pn,0]);
	printf("%s%s", arg[pn,1] != "" ? " " : "", arg[pn,1]);
	printf("%s%s", arg[pn,2] != "" ? " " : "", arg[pn,2]);
	printf("%s%s", arg[pn,3] != "" ? " " : "", arg[pn,3]);
	printf("%s%s", arg[pn,4] != "" ? " " : "", arg[pn,4]);
	printf("%s", arg[pn,0] != "" ? "\n" : "");

	pn--;
	printf("  \-+= %05d %d.%d %s",
		_pid[pn], _uid[pn], _gid[pn], arg[pn,0]);
	printf("%s%s", arg[pn,1] != "" ? " " : "", arg[pn,1]);
	printf("%s%s", arg[pn,2] != "" ? " " : "", arg[pn,2]);
	printf("%s%s", arg[pn,3] != "" ? " " : "", arg[pn,3]);
	printf("%s%s", arg[pn,4] != "" ? " " : "", arg[pn,4]);
	printf("%s", arg[pn,0] != "" ? "\n" : "");

	pn--;
	printf("    \-+= %05d %d.%d %s",
		_pid[pn], _uid[pn], _gid[pn], arg[pn,0]);
	printf("%s%s", arg[pn,1] != "" ? " " : "", arg[pn,1]);
	printf("%s%s", arg[pn,2] != "" ? " " : "", arg[pn,2]);
	printf("%s%s", arg[pn,3] != "" ? " " : "", arg[pn,3]);
	printf("%s%s", arg[pn,4] != "" ? " " : "", arg[pn,4]);
	printf("%s", arg[pn,0] != "" ? "\n" : "");
}

/*********************************************************/

vfs::vop_remove:entry
{
	self->name[self->depth++] = 0;
	self->name[2] = 0;
	self->name[3] = 0;
	self->name[4] = 0;
	self->name[5] = 0;
	self->name[6] = 0;
	self->name[7] = 0;
	self->name[8] = 0;
	self->name[9] = 0;
	self->name[10] = 0;
	self->name[11] = 0;
	self->name[12] = 0;
	self->name[13] = 0;
	self->name[14] = 0;
	self->name[15] = 0;
	self->name[16] = 0;
	self->name[17] = 0;
	self->name[18] = 0;
	self->name[19] = 0;
	self->name[20] = 0;
	self->depth = 0;
}
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?032e01d00f4f$98a04e20$c9e0ea60$>