// nfs tapset
// Copyright (C) 2006-2007 IBM Corp.
// Copyright (C) 2007 Intel Corporation.
// Copyright (C) 2007 Bull S.A.S
// Copyright (C) 2010,2014-2019 Red Hat Inc.
//
// This file is part of systemtap, and is free software.  You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.


%{
#include <linux/stat.h>

#include <linux/sunrpc/svc.h>

#include <linux/nfsd/nfsfh.h>
#include <linux/nfs3.h>
#include <linux/nfs4.h>
%}

/*
 *1 : nfsd.proc2.lookup
 *2 : nfsd.proc3.lookup
 *3 : nfsd.proc2.read
 *4 : nfsd.proc3.read
 *5 : nfsd.proc2.write
 *6 : nfsd.proc3.write
 *7 : nfsd.proc3.commit
 *8 : nfsd.proc2.create
 *9 : nfsd.proc3.create
 *10: nfsd.proc2.remove
 *11: nfsd.proc3.remove
 *12 :nfsd.proc2.rename.ffh
 *13 :nfsd.proc2.rename.tfh
 *14 :nfsd.proc3.rename.ffh
 *15 :nfsd.proc3.rename.tfh
 */

# In newer kernels, the 'rq_argp' and 'rq_resp' pointers in a
# 'svc_rqst' structure are a void pointers that we need to cast to the
# right nfsd private types, based on the protocol version. These
# macros make all the casting easier.

@define nfsd2_createargs(ptr)
%(
    @cast(@ptr, "nfsd_createargs", "kernel:nfsd")
%)
@define nfsd2_diropargs(ptr)
%(
    @cast(@ptr, "nfsd_diropargs", "kernel:nfsd")
%)
@define nfsd2_readargs(ptr)
%(
    @cast(@ptr, "nfsd_readargs", "kernel:nfsd")
%)
@define nfsd2_renameargs(ptr)
%(
    @cast(@ptr, "nfsd_renameargs", "kernel:nfsd")
%)
@define nfsd2_writeargs(ptr)
%(
    @cast(@ptr, "nfsd_writeargs", "kernel:nfsd")
%)

@define nfsd3_commitargs(ptr)
%(
    @cast(@ptr, "nfsd3_commitargs", "kernel:nfsd")
%)
@define nfsd3_createargs(ptr)
%(
    @cast(@ptr, "nfsd3_createargs", "kernel:nfsd")
%)
@define nfsd3_diropargs(ptr)
%(
    @cast(@ptr, "nfsd3_diropargs", "kernel:nfsd")
%)
@define nfsd3_readargs(ptr)
%(
    @cast(@ptr, "nfsd3_readargs", "kernel:nfsd")
%)
@define nfsd3_renameargs(ptr)
%(
    @cast(@ptr, "nfsd3_renameargs", "kernel:nfsd")
%)
@define nfsd3_writeargs(ptr)
%(
    @cast(@ptr, "nfsd3_writeargs", "kernel:nfsd")
%)
@define nfsd3_writeres(ptr)
%(
    @cast(@ptr, "nfsd3_writeres", "kernel:nfsd")
%)

@define nfsd4_compound_state(ptr)
%(
    @cast(@ptr, "nfsd4_compound_state", "kernel:nfsd")
%)    


/* Get file handle data from struct svc_fh. */
@__private30 function __svc_fh:string(fhp:long)
{
	svc_fh = &@cast(fhp, "svc_fh", "kernel:nfsd")->fh_handle
	return sprintf("%d: %08x %08x %08x %08x %08x %08x", svc_fh->fh_size,
		       svc_fh->fh_base->fh_pad[0], svc_fh->fh_base->fh_pad[1],
		       svc_fh->fh_base->fh_pad[2], svc_fh->fh_base->fh_pad[3],
		       svc_fh->fh_base->fh_pad[4], svc_fh->fh_base->fh_pad[5])
}

function nfs3_cmode:string(cmode:long) %{ /* pure */
	int cmode = (int)(long)STAP_ARG_cmode;
	
	switch (cmode) {
	case NFS3_CREATE_UNCHECKED:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "UNCHECKED");
		break;
	case NFS3_CREATE_GUARDED:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "GUARDED");
		break;
	case NFS3_CREATE_EXCLUSIVE:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "EXCLUSIVE");
		break;
	default: 
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "Bad Value(%d)", 
			cmode);
	}
	CATCH_DEREF_FAULT();
%}

function nfs4_ctype:string(cmode:long) %{ /* pure */
	int cmode = (int)(long)STAP_ARG_cmode;
	
	switch (cmode) {
	case NF4BAD:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4BAD");
		break;
	case NF4REG:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4REG");
		break;
	case NF4DIR:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4DIR");
		break;
	case NF4BLK:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4BLK");
		break;
	case NF4CHR:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4CHR");
		break;
	case NF4LNK:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4LNK");
		break;
	case NF4SOCK:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4SOCK");
		break;
	case NF4FIFO:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4FIFO");
		break;
	case NF4ATTRDIR:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4ATTRDIR");
		break;
	case NF4NAMEDATTR:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "NF4NAMEDATTR");
		break;
	default: 
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"Bad Value(%d)", cmode);
	}
	CATCH_DEREF_FAULT();
%}

function ftype:string(type:long) %{ /* pure */
	int type = (int)(long)STAP_ARG_type;

	if (S_ISLNK(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISLNK)", type);
	} else if (S_ISREG(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISREG)", type);
	} else if (S_ISDIR(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISDIR)", type);
	} else if (S_ISCHR(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISCHR)", type);
	} else if (S_ISBLK(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISBLK)", type);
	} else if (S_ISFIFO(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISFIFO)", type);
	} else if (S_ISSOCK(type)) {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (ISSOCK)", type);
	} else  {
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, 
			"0%o (Unknown)", type);
	}
%}

@__private30 function __rqstp_uid:long(rqstp:long)
%{ /* pure */
	// Notice we're using the 'init_user_ns' here, not
	// 'current_user_ns()'. This matches up with the use in
	// net/sunrpc/auth_generic.c.
	struct svc_rqst *rqstp
		= (struct svc_rqst *)(uintptr_t)STAP_ARG_rqstp;
#ifndef STAPCONF_LINUX_UIDGID_H
	uid_t cr_uid = KUIDT_INIT(kread(&(rqstp->rq_cred.cr_uid)));
#else
	kuid_t cr_uid;
	/* Make sure the cr_uid struct is valid to read. */
	(void)kderef_buffer(NULL, &(rqstp->rq_cred.cr_uid), sizeof(kuid_t));
	cr_uid = KUIDT_INIT(__kuid_val(rqstp->rq_cred.cr_uid));
#endif
#if defined(CONFIG_USER_NS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
	STAP_RETVALUE = from_kuid_munged(&init_user_ns, cr_uid);
#else
	STAP_RETVALUE = cr_uid;
#endif
	CATCH_DEREF_FAULT();
%}

@__private30 function __rqstp_gid:long(rqstp:long)
%{ /* pure */
	// Notice we're using the 'init_user_ns' here, not
	// 'current_user_ns()'. This matches up with the use in
	// net/sunrpc/auth_generic.c.
	struct svc_rqst *rqstp
		= (struct svc_rqst *)(uintptr_t)STAP_ARG_rqstp;
#ifndef STAPCONF_LINUX_UIDGID_H
	gid_t cr_gid = KGIDT_INIT(kread(&(rqstp->rq_cred.cr_gid)));
#else
	kgid_t cr_gid;
	/* Make sure the cr_gid struct is valid to read. */
	(void)kderef_buffer(NULL, &(rqstp->rq_cred.cr_gid), sizeof(kgid_t));
	cr_gid = KGIDT_INIT(__kgid_val(rqstp->rq_cred.cr_gid));
#endif
#if defined(CONFIG_USER_NS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
	STAP_RETVALUE = from_kgid_munged(&init_user_ns, cr_gid);
#else
	STAP_RETVALUE = cr_gid;
#endif
	CATCH_DEREF_FAULT();
%}

/**
 * probe nfsd.dispatch - NFS server receives an operation from client 
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @xid: transmission id
 * @prog: program number
 * @proc: procedure number
 */
probe nfsd.dispatch = kernel.function("nfsd_dispatch") !,
                      module("nfsd").function("nfsd_dispatch") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = $rqstp->rq_vers

	xid = $rqstp->rq_xid
	prog = $rqstp->rq_prog
	proc = $rqstp->rq_proc

	name = "nfsd.dispatch"
	argstr = sprintf("%d,%d",version,proto)
}

probe nfsd.dispatch.return = kernel.function("nfsd_dispatch").return !,
                             module("nfsd").function("nfsd_dispatch").return ?
{
	name = "nfsd.dispatch.return"
	retstr = sprintf("%d",$return)
}

probe nfsd.proc.entries = nfsd.proc.lookup,
                          nfsd.proc.read,
                          nfsd.proc.write,
                          nfsd.proc.commit,
                          nfsd.proc.remove,
                          nfsd.proc.rename,
                          nfsd.proc.create
{} 

probe nfsd.proc.return = nfsd.proc.lookup.return,
                         nfsd.proc.read.return,
                         nfsd.proc.write.return,
                         nfsd.proc.commit.return,
                         nfsd.proc.remove.return,
                         nfsd.proc.rename.return,
                         nfsd.proc.create.return
{} 

/**
 * probe nfsd.proc.lookup - NFS server opening or searching for a file for client
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @fh: file handle of parent dir (the first part is the length of the file handle)
 * @filename: file name 
 * @filelen: the length of file name
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.lookup = 
      nfsd.proc4.lookup ?,
      nfsd.proc3.lookup,
      nfsd.proc2.lookup
{}

probe nfsd.proc.lookup.return = 
      nfsd.proc4.lookup.return ?,
      nfsd.proc3.lookup.return,
      nfsd.proc2.lookup.return
{}

probe nfsd.proc2.lookup = kernel.function("nfsd_proc_lookup") !,
                          module("nfsd").function("nfsd_proc_lookup") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 2

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd2_diropargs($rqstp->rq_argp)->fh
		filelen = @nfsd2_diropargs($rqstp->rq_argp)->len
		filename = kernel_string_n(@nfsd2_diropargs($rqstp->rq_argp)->name,
					   @nfsd2_diropargs($rqstp->rq_argp)->len)
	}
	else {
		fh = & @nfsd2_diropargs($argp)->fh
		filelen = $argp->len
		filename = kernel_string_n($argp->name, $argp->len)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc2.lookup"
	argstr = sprintf("%s", filename)
}

probe nfsd.proc2.lookup.return =
		kernel.function("nfsd_proc_lookup").return !,
		module("nfsd").function("nfsd_proc_lookup").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc2.lookup.return"
	version = 2
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc3.lookup = kernel.function("nfsd3_proc_lookup") !,
                          module("nfsd").function("nfsd3_proc_lookup") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
        version = 3

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_diropargs($rqstp->rq_argp)->fh
		filelen = @nfsd3_diropargs($rqstp->rq_argp)->len
		filename = kernel_string_n(@nfsd3_diropargs($rqstp->rq_argp)->name,
					   @nfsd3_diropargs($rqstp->rq_argp)->len)
	}
	else {
		fh = & @nfsd3_diropargs($argp)->fh
		filelen = $argp->len
		filename = kernel_string_n($argp->name, $argp->len)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.lookup"
	argstr = sprintf("%s", filename)
} 

probe nfsd.proc3.lookup.return =
		kernel.function("nfsd3_proc_lookup").return !,
		module("nfsd").function("nfsd3_proc_lookup").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.lookup.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
}

/*
 * Several of the nfsd.proc4.* entry probes use '.call'.  Why?  On
 * kernels <= 2.6.18 (i.e. RHEL4 and RHEL5), those are inline
 * functions.  Besides having different arguments, because those
 * functions are inline systemtap has trouble finding their arguments
 * (PR 1155).  Finally, those functions are just simple wrappers
 * around their nfsd_* counterparts (for example, nfsd4_lookup() is a
 * wrapper for nfsd_lookup).  As a comment in fs/nfsd/nfs4proc.c says:
 *
 *    Note: some routines in this file are just trivial wrappers
 *    (e.g. nfsd4_lookup()) defined solely for the sake of consistent
 *    naming.
 *
 * So, we'll just ignore those inline wrappers by specifying
 * '.call'. which means the function must be a "real" (non-inline)
 * function.
 */

probe nfsd.proc4.lookup = kernel.function("nfsd4_lookup").call !,
                          module("nfsd").function("nfsd4_lookup").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = & @nfsd4_compound_state($cstate)->current_fh

	if (@defined($u)) {
		filelen = $u->lookup->lo_len
		filename = kernel_string_n($u->lookup->lo_name,
					   $u->lookup->lo_len)
	}
	else {
		filelen = $lookup->lo_len
		filename = kernel_string_n($lookup->lo_name, $lookup->lo_len)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.lookup"
	argstr = sprintf("%s", filename)
} 

probe nfsd.proc4.lookup.return =
		kernel.function("nfsd4_lookup").return !,
		module("nfsd").function("nfsd4_lookup").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.lookup.return"
	version = 4
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.proc.read - NFS server reading file for client
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @fh: file handle (the first part is the length of the file handle)
 * @size: read bytes
 * @count: read bytes
 * @offset: the offset of file 
 * @vec: struct kvec, includes buf address in kernel address and length of each buffer
 * @vlen: read blocks 
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.read = 
      nfsd.proc4.read ?,
      nfsd.proc3.read,
      nfsd.proc2.read
{}

probe nfsd.proc.read.return = 
      nfsd.proc4.read.return ?,
      nfsd.proc3.read.return,
      nfsd.proc2.read.return
{}

probe nfsd.proc2.read = kernel.function("nfsd_proc_read") !,
                        module("nfsd").function("nfsd_proc_read") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
        version = 2
	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd2_readargs($rqstp->rq_argp)->fh
		count = @nfsd2_readargs($rqstp->rq_argp)->count 
		offset = @nfsd2_readargs($rqstp->rq_argp)->offset 
		vec = $rqstp->rq_vec
		vlen = @nfsd2_readargs($rqstp->rq_argp)->vlen
	}
	else {
		fh = & @nfsd2_readargs($argp)->fh
		count = $argp->count 
		offset = $argp->offset 
		vec = @choose_defined($rqstp->rq_vec, $argp->vec)
		vlen = $argp->vlen
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc2.read"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
}

probe nfsd.proc2.read.return =
		kernel.function("nfsd_proc_read").return !,
		module("nfsd").function("nfsd_proc_read").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc2.read.return"
	version = 2
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc3.read = kernel.function("nfsd3_proc_read") !,
                        module("nfsd").function("nfsd3_proc_read") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 3
	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_readargs($rqstp->rq_argp)->fh
		count = @nfsd3_readargs($rqstp->rq_argp)->count 
		offset = @nfsd3_readargs($rqstp->rq_argp)->offset 
		vec = $rqstp->rq_vec
		vlen = @nfsd3_readargs($rqstp->rq_argp)->vlen
	}
	else {
		fh = & @nfsd3_readargs($argp)->fh
		count = $argp->count 
		offset = $argp->offset 
		vec = @choose_defined($rqstp->rq_vec, $argp->vec)
		vlen = $argp->vlen
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.read"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
}
 
probe nfsd.proc3.read.return =
		kernel.function("nfsd3_proc_read").return !,
		module("nfsd").function("nfsd3_proc_read").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.read.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc4.read = kernel.function("nfsd4_read").call !,
                        module("nfsd").function("nfsd4_read").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = & @nfsd4_compound_state($cstate)->current_fh

        if (@defined($u)) {
             count = $u->read->rd_length
             offset = $u->read->rd_offset
             vec = $rqstp->rq_vec
             vlen = $u->read->rd_vlen
        } else {
             count = $read->rd_length
             offset = $read->rd_offset
             vec = $rqstp->rq_vec
             vlen = $read->rd_vlen
        }

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.read"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
}

probe nfsd.proc4.read.return = kernel.function("nfsd4_read").return !,
                               module("nfsd").function("nfsd4_read").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.read.return"
	version = 4
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.proc.write - NFS server writing data to file for client
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @fh: file handle (the first part is the length of the file handle)
 * @size: read bytes
 * @count: read bytes
 * @offset: the offset of file 
 * @vec: struct kvec, includes buf address in kernel address and length of each buffer
 * @vlen: read blocks 
 * @stable: argp->stable
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.write = 
      nfsd.proc4.write ?,
      nfsd.proc3.write,
      nfsd.proc2.write
{}

probe nfsd.proc.write.return = 
      nfsd.proc4.write.return ?,
      nfsd.proc3.write.return,
      nfsd.proc2.write.return
{}

probe nfsd.proc2.write = kernel.function("nfsd_proc_write") !,
                         module("nfsd").function("nfsd_proc_write") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
        version = 2
	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd2_writeargs($rqstp->rq_argp)->fh
		count = @nfsd2_writeargs($rqstp->rq_argp)->len
		offset = @nfsd2_writeargs($rqstp->rq_argp)->offset 
		vec = $rqstp->rq_vec
		vlen = @choose_defined(@nfsd2_writeargs($rqstp->rq_argp)->vlen, 0)
	}
	else {
		fh = & @nfsd2_writeargs($argp)->fh
		count = $argp->len
		offset = $argp->offset 
		vec = @choose_defined($rqstp->rq_vec, $argp->vec)
		vlen = @choose_defined($argp->vlen, 0)
	}

	stable = 1			# hardcoded in nfsd_proc_write()

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc2.write"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
}
 
probe nfsd.proc2.write.return =
		kernel.function("nfsd_proc_write").return !,
		module("nfsd").function("nfsd_proc_write").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc2.write.return"
	version = 2
	retstr = sprintf("%s", nfsderror($return))
	if (@defined(@entry($rqstp->rq_argp))) {
		count = ($return == 0
			 ? @entry(@nfsd2_writeargs($rqstp->rq_argp)->len)
			 : $return)
	}
	else {
		count = ($return == 0 ? @entry($argp->len) : $return)
	}
	stable = 1
}

probe nfsd.proc3.write = kernel.function("nfsd3_proc_write") !,
                         module("nfsd").function("nfsd3_proc_write") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 3
	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_writeargs($rqstp->rq_argp)->fh
		count = @nfsd3_writeargs($rqstp->rq_argp)->count 
		offset = @nfsd3_writeargs($rqstp->rq_argp)->offset 
		vec = $rqstp->rq_vec
		vlen = @choose_defined(@nfsd3_writeargs($rqstp->rq_argp)->vlen, 0)
		stable = @nfsd3_writeargs($rqstp->rq_argp)->stable
	}
	else {
		fh = & @nfsd3_writeargs($argp)->fh
		count = $argp->count 
		offset = $argp->offset 
		vec = @choose_defined($rqstp->rq_vec, $argp->vec)
		vlen = @choose_defined($argp->vlen, 0)
		stable = $argp->stable
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.write"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
}
 
probe nfsd.proc3.write.return =
		kernel.function("nfsd3_proc_write").return !,
		module("nfsd").function("nfsd3_proc_write").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.write.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
	if (@defined(@entry($rqstp->rq_resp))) {
		count = @entry(@nfsd3_writeres($rqstp->rq_resp)->count)
		stable = @entry(@nfsd3_writeres($rqstp->rq_resp)->committed)
	}
	else {
		count = @entry($resp->count)
		stable = @entry($resp->committed)
	}
}

probe nfsd.proc4.write = kernel.function("nfsd4_write").call !,
                         module("nfsd").function("nfsd4_write").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = & @nfsd4_compound_state($cstate)->current_fh
	vec = $rqstp->rq_vec
	if (@defined($u)) {
		count = $u->write->wr_buflen
		offset = $u->write->wr_offset
		vlen = @choose_defined($u->write->wr_vlen, 0)
		stable = $u->write->wr_stable_how
	}
	else {
		count = $write->wr_buflen
		offset = $write->wr_offset
		vlen = @choose_defined($write->wr_vlen, 0)
		stable = $write->wr_stable_how
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.write"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
} 

probe nfsd.proc4.write.return =
		kernel.function("nfsd4_write").return !,
		module("nfsd").function("nfsd4_write").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.write.return"
	version = 4
	if (@defined(@entry($u))) {
		count = @entry($u->write->wr_bytes_written)
		stable = @entry($u->write->wr_how_written)
	}
	else {
		count = @entry($write->wr_bytes_written)
		stable = @entry($write->wr_how_written)
	}

	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.proc.commit - NFS server performing a commit operation for client
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @fh: file handle (the first part is the length of the file handle)
 * @size: read bytes
 * @count: read bytes
 * @offset: the offset of file 
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.commit =  
      nfsd.proc4.commit ?,
      nfsd.proc3.commit
{}

probe nfsd.proc.commit.return = 
      nfsd.proc4.commit.return ?,
      nfsd.proc3.commit.return
{}

probe nfsd.proc3.commit = kernel.function("nfsd3_proc_commit") !,
                          module("nfsd").function("nfsd3_proc_commit") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
        version = 3

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_commitargs($rqstp->rq_argp)->fh
		count = @nfsd3_commitargs($rqstp->rq_argp)->count 
		offset = @nfsd3_commitargs($rqstp->rq_argp)->offset 
	}
	else {
		fh = & @nfsd3_commitargs($argp)->fh
		count = $argp->count 
		offset = $argp->offset 
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.commit"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
}

probe nfsd.proc3.commit.return =
		kernel.function("nfsd3_proc_commit").return !,
		module("nfsd").function("nfsd3_proc_commit").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.commit.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc4.commit = kernel.function("nfsd4_commit").call !,
                          module("nfsd").function("nfsd4_commit").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = & @nfsd4_compound_state($cstate)->current_fh
        if (@defined($u)) {
	    count = $u->commit->co_count 
	    offset = $u->commit->co_offset
        } else {
   	    count = $commit->co_count 
	    offset = $commit->co_offset
        }

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.commit"
	argstr = sprintf("%d,%d",count,offset)

	size = count
	units = "bytes"
} 

probe nfsd.proc4.commit.return =
		kernel.function("nfsd4_commit").return !,
		module("nfsd").function("nfsd4_commit").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.commit.return"
	version = 4
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.proc.create - NFS server creating a file for client
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @fh: file handle (the first part is the length of the file handle)
 * @filename: file name
 * @filelen: length of file name
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.create = 
      nfsd.proc4.create ?,
      nfsd.proc3.create,
      nfsd.proc2.create
{}
probe nfsd.proc.create.return = 
      nfsd.proc4.create.return ?,
      nfsd.proc3.create.return,
      nfsd.proc2.create.return
{}

probe nfsd.proc2.create = kernel.function("nfsd_proc_create") !,
                          module("nfsd").function("nfsd_proc_create") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 2

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd2_createargs($rqstp->rq_argp)->fh
		filelen = @nfsd2_createargs($rqstp->rq_argp)->len
		filename = kernel_string_n(@nfsd2_createargs($rqstp->rq_argp)->name,
					   @nfsd2_createargs($rqstp->rq_argp)->len)
	}
	else {
		fh = & @nfsd2_createargs($argp)->fh
		filelen = $argp->len
		filename = kernel_string_n($argp->name, $argp->len)
	}

	createmode = 0			# gets computed by nfsd_proc_create

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc2.create"
	argstr = sprintf("%s", filename)
}

probe nfsd.proc2.create.return =
		kernel.function("nfsd_proc_create").return !,
		module("nfsd").function("nfsd_proc_create").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc2.create.return"
	version = 2
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc3.create = kernel.function("nfsd3_proc_create") !,
                          module("nfsd").function("nfsd3_proc_create") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 3

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_createargs($rqstp->rq_argp)->fh
		filelen = @nfsd3_createargs($rqstp->rq_argp)->len
		filename = kernel_string_n(@nfsd3_createargs($rqstp->rq_argp)->name,
					   @nfsd3_createargs($rqstp->rq_argp)->len)
		createmode = @nfsd3_createargs($rqstp->rq_argp)->createmode
	}
	else {
		fh = & @nfsd3_createargs($argp)->fh
		filelen = $argp->len
		filename = kernel_string_n($argp->name, $argp->len)
		createmode = $argp->createmode
	}
	
	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.create"
	argstr = sprintf("%s (mode=%s)", filename, nfs3_cmode(createmode))
}

probe nfsd.proc3.create.return =
		kernel.function("nfsd3_proc_create").return !,
		module("nfsd").function("nfsd3_proc_create").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.create.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc4.create = kernel.function("nfsd4_create").call !,
                          module("nfsd").function("nfsd4_create").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = (@defined($cstate)
	      ? & @nfsd4_compound_state($cstate)->current_fh
	      : $current_fh)
	if (@defined($u)) {
		filelen = $u->create->cr_namelen
		filename = kernel_string_n($u->create->cr_name,
					   $u->create->cr_namelen)
		createmode = $u->create->cr_type
	}
	else {
		filelen = $create->cr_namelen
		filename = kernel_string_n($create->cr_name, $create->cr_namelen)
		createmode = $create->cr_type
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.create"
	argstr = sprintf("%s (type=%s)", filename, nfs4_ctype(createmode))

} 

probe nfsd.proc4.create.return =
		kernel.function("nfsd4_create").return !,
		module("nfsd").function("nfsd4_create").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.create.return"
	version = 4
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.proc.remove - NFS server removing a file for client
 *
 * @client_ip: the ip address of client
 * @proto: transfer protocol
 * @version: nfs version
 * @fh: file handle (the first part is the length of the file handle)
 * @filename: file name
 * @filelen: length of file name
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.remove = 
      nfsd.proc4.remove ?,
      nfsd.proc3.remove,
      nfsd.proc2.remove
{}
probe nfsd.proc.remove.return = 
      nfsd.proc4.remove.return ?,
      nfsd.proc3.remove.return,
      nfsd.proc2.remove.return
{}

probe nfsd.proc2.remove = kernel.function("nfsd_proc_remove") !,
                          module("nfsd").function("nfsd_proc_remove") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 2
	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd2_diropargs($rqstp->rq_argp)->fh
		filelen = @nfsd2_diropargs($rqstp->rq_argp)->len
		filename = kernel_string_n(@nfsd2_diropargs($rqstp->rq_argp)->name,
					   @nfsd2_diropargs($rqstp->rq_argp)->len)
	}
	else {
		fh = & @nfsd2_diropargs($argp)->fh
		filelen = $argp->len
		filename = kernel_string_n($argp->name, $argp->len)
	}
	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc2.remove"
	argstr = sprintf("%s", filename)
}

probe nfsd.proc2.remove.return =
		kernel.function("nfsd_proc_remove").return !,
		module("nfsd").function("nfsd_proc_remove").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc2.remove.return"
	version = 2
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc3.remove = kernel.function("nfsd3_proc_remove") !,
                          module("nfsd").function("nfsd3_proc_remove") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 3
	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_diropargs($rqstp->rq_argp)->fh
		filelen = @nfsd3_diropargs($rqstp->rq_argp)->len
		filename = kernel_string_n(@nfsd3_diropargs($rqstp->rq_argp)->name,
					   @nfsd3_diropargs($rqstp->rq_argp)->len)
	}
	else {
		fh = & @nfsd3_diropargs($argp)->fh
		filelen = $argp->len
		filename = kernel_string_n($argp->name, $argp->len)
	}
	
	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.remove"
	argstr = sprintf("%s", filename)
}

probe nfsd.proc3.remove.return =
		kernel.function("nfsd3_proc_remove").return !,
		module("nfsd").function("nfsd3_proc_remove").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.remove.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc4.remove = kernel.function("nfsd4_remove").call !,
                          module("nfsd").function("nfsd4_remove").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = & @nfsd4_compound_state($cstate)->current_fh
	if (@defined($u)) {
		filelen = $u->remove->rm_namelen
		filename = kernel_string_n($u->remove->rm_name,
					   $u->remove->rm_namelen)
	}
	else {
		filelen = $remove->rm_namelen
		filename = kernel_string_n($remove->rm_name,
					   $remove->rm_namelen)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.remove"
	argstr = sprintf("%s", filename)
} 

probe nfsd.proc4.remove.return =
		kernel.function("nfsd4_remove").return !,
		module("nfsd").function("nfsd4_remove").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.remove.return"
	version = 4
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.proc.rename - NFS Server renaming a file for client
 *
 * @client_ip: the ip address of client
 * @fh: file handler of old path
 * @tfh: file handler of new path
 * @filename: old file name 
 * @tname: new file name
 * @flen: length of old file name 
 * @tlen: length of new file name
 * @uid: requester's user id
 * @gid: requester's group id
 */
probe nfsd.proc.rename = 
      nfsd.proc4.rename ?,
      nfsd.proc3.rename,
      nfsd.proc2.rename
{}

probe nfsd.proc.rename.return = 
      nfsd.proc4.rename.return ?,
      nfsd.proc3.rename.return,
      nfsd.proc2.rename.return
{}

probe nfsd.proc2.rename = kernel.function("nfsd_proc_rename") !,
                          module("nfsd").function("nfsd_proc_rename") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 2

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd2_renameargs($rqstp->rq_argp)->ffh
		tfh = & @nfsd2_renameargs($rqstp->rq_argp)->tfh
		filelen = @nfsd2_renameargs($rqstp->rq_argp)->flen
		filename = kernel_string_n(@nfsd2_renameargs($rqstp->rq_argp)->fname,
					   @nfsd2_renameargs($rqstp->rq_argp)->flen)	
		tlen = @nfsd2_renameargs($rqstp->rq_argp)->tlen
		tname = kernel_string_n(@nfsd2_renameargs($rqstp->rq_argp)->tname,
					@nfsd2_renameargs($rqstp->rq_argp)->tlen)
	}
	else {
		fh = & @nfsd2_renameargs($argp)->ffh
		tfh = & @nfsd2_renameargs($argp)->tfh
		filelen = $argp->flen
		filename = kernel_string_n($argp->fname, $argp->flen)	
		tlen = $argp->tlen
		tname = kernel_string_n($argp->tname, $argp->tlen)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc2.rename"
	argstr = sprintf("%s to %s", filename, tname)
}

probe nfsd.proc2.rename.return =
		kernel.function("nfsd_proc_rename").return !,
		module("nfsd").function("nfsd_proc_rename").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc2.rename.return"
	version = 2
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc3.rename = kernel.function("nfsd3_proc_rename") !,
                          module("nfsd").function("nfsd3_proc_rename") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 3

	if (@defined($rqstp->rq_argp)) {
		fh = & @nfsd3_renameargs($rqstp->rq_argp)->ffh
		tfh = & @nfsd3_renameargs($rqstp->rq_argp)->tfh
		filelen = @nfsd3_renameargs($rqstp->rq_argp)->flen
		filename = kernel_string_n(@nfsd3_renameargs($rqstp->rq_argp)->fname,
					   @nfsd3_renameargs($rqstp->rq_argp)->flen)	
		tlen = @nfsd3_renameargs($rqstp->rq_argp)->tlen
		tname = kernel_string_n(@nfsd3_renameargs($rqstp->rq_argp)->tname,
					@nfsd3_renameargs($rqstp->rq_argp)->tlen)
	}
	else {
		fh = & @nfsd3_renameargs($argp)->ffh
		tfh = & @nfsd3_renameargs($argp)->tfh
		filelen = $argp->flen
		filename = kernel_string_n($argp->fname, $argp->flen)	
		tlen = $argp->tlen
		tname = kernel_string_n($argp->tname, $argp->tlen)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc3.rename"
	argstr = sprintf("%s to %s", filename, tname)
}

probe nfsd.proc3.rename.return =
		kernel.function("nfsd3_proc_rename").return !,
		module("nfsd").function("nfsd3_proc_rename").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc3.rename.return"
	version = 3
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.proc4.rename = kernel.function("nfsd4_rename").call !,
                          module("nfsd").function("nfsd4_rename").call ?
{
	client_ip = addr_from_rqst_str($rqstp)
	proto = $rqstp->rq_prot
	version = 4
	fh = & @nfsd4_compound_state($cstate)->save_fh
	tfh = & @nfsd4_compound_state($cstate)->current_fh

	if (@defined($rename)) {
		filelen = $rename->rn_snamelen
		filename = kernel_string_n($rename->rn_sname,
					   $rename->rn_snamelen)
		tlen = $rename->rn_tnamelen
		tname = kernel_string_n($rename->rn_tname, $rename->rn_tnamelen)
	} else {
		filelen = $u->rename->rn_snamelen
		filename = kernel_string_n($u->rename->rn_sname,
					   $u->rename->rn_snamelen)
		tlen = $u->rename->rn_tnamelen
		tname = kernel_string_n($u->rename->rn_tname,
					$u->rename->rn_tnamelen)
	}

	uid = __rqstp_uid($rqstp)
	gid = __rqstp_gid($rqstp)

	name = "nfsd.proc4.rename"
	argstr = sprintf("%s to %s", filename, tname)
} 

probe nfsd.proc4.rename.return =
		kernel.function("nfsd4_rename").return !,
		module("nfsd").function("nfsd4_rename").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))

	name = "nfsd.proc4.rename.return"
	version = 4
	retstr = sprintf("%s", nfsderror($return))
}

probe nfsd.entries = nfsd.open,
                     nfsd.read,
                     nfsd.write,
                     nfsd.lookup,
                     nfsd.commit,
                     nfsd.create,
                     nfsd.createv3,
                     nfsd.unlink,
                     nfsd.rename,
                     nfsd.close ?
{}

probe nfsd.return = nfsd.open.return,
                    nfsd.read.return,
                    nfsd.write.return,
                    nfsd.lookup.return,
                    nfsd.commit.return,
                    nfsd.create.return,
                    nfsd.createv3.return,
                    nfsd.unlink.return,
                    nfsd.rename.return,
		    nfsd.close.return ?
{}

/**
 * probe nfsd.open - NFS server opening a file for client
 *
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @access: indicates the type of open (read/write/commit/readdir...) 
 * @type: type of file (regular file or dir)
 */
probe nfsd.open = kernel.function("nfsd_open") !,
                  module("nfsd").function("nfsd_open") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	access = @choose_defined($access, $may_flags)
	type = $type

	name = "nfsd.open"
	argstr = sprintf("access: %d type: %s", access, ftype(type))
}

probe nfsd.open.return = kernel.function("nfsd_open").return !,
                         module("nfsd").function("nfsd_open").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.open.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.close - NFS server closing a file for client
 *
 * @filename: file name
 *
 * This probe point does not exist in kernels starting with 4.2.
 */
probe nfsd.close = __nfsd.call_close ?, __nfsd.inlined_close ?
{
	client_ip ="N/A"
	name = "nfsd.close"
	argstr = sprintf("%s",filename)
}
/*
 * Why split nfsd.close up into '__nfsd.call_close' and
 * '__nfds.inlined_close'? We need the '@choose_defined()' since
 * SystemTap has trouble accessing the arguments of inlined functions
 * (PR 1155). But, if we only used '@choose_defined()', we wouldn't
 * automatically notice a change in the argument name.
 */
probe __nfsd.call_close = kernel.function("nfsd_close").call !,
			  module("nfsd").function("nfsd_close").call ?
{
	filename = __file_filename($filp)
}
probe __nfsd.inlined_close = kernel.function("nfsd_close").inline !,
			     module("nfsd").function("nfsd_close").inline ?
{
	filename = __file_filename(@choose_defined($filp, 0))
}

probe nfsd.close.return = kernel.function("nfsd_close").return !,
                          module("nfsd").function("nfsd_close").return ?
{
	name = "nfsd.close.return"
	retstr = "N/A"
}

/**
 * probe nfsd.read - NFS server reading data from a file for client
 *
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @file: argument file, indicates if the file has been opened.
 * @size: read bytes
 * @count: read bytes
 * @offset: the offset of file 
 * @vec: struct kvec, includes buf address in kernel address and length of each buffer
 * @vlen: read blocks 
 */
probe nfsd.read = kernel.function("nfsd_read") !,
                  module("nfsd").function("nfsd_read") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	file = @choose_defined($file, 0)
	count = kernel_long($count)
	offset = $offset
	vec = $vec
	vlen = $vlen

	name = "nfsd.read"
	argstr = sprintf("count: %d offset: %d",count,offset)

	size = count
	units = "bytes"
} 

probe nfsd.read.return = kernel.function("nfsd_read").return !,
                         module("nfsd").function("nfsd_read").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.read.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.write - NFS server writing data to a file for client
 *
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @file: argument file, indicates if the file has been opened.
 * @size: read bytes
 * @count: read bytes
 * @offset: the offset of file 
 * @vec: struct kvec, includes buf address in kernel address and length of each buffer
 * @vlen: read blocks 
 */
probe nfsd.write = kernel.function("nfsd_write") !,
                   module("nfsd").function("nfsd_write") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	file = @choose_defined($file, 0)
%( kernel_v >= "2.6.30" %?
	count = kernel_long($cnt)
%:
	count = $cnt
%)
	offset = $offset
	vec = $vec
	vlen = $vlen

	name = "nfsd.write"
	argstr = sprintf("count: %d  offset: %d",count,offset)

	size = count
	units = "bytes"
}

probe nfsd.write.return = kernel.function("nfsd_write").return !,
                          module("nfsd").function("nfsd_write").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.write.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.commit - NFS server committing all pending writes to stable storage
 *
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @flag: indicates whether this execution is a sync operation
 * @size: read bytes
 * @count: read bytes
 * @offset: the offset of file
 */
probe nfsd.commit = kernel.function("nfsd_commit") !,
                    module("nfsd").function("nfsd_commit") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	count = $count
	offset = $offset
	flag = $fhp->fh_export->ex_flags

	name = "nfsd.commit"
	argstr = sprintf("count: %d offset: %d",count,offset)

	size = count 
	units = "bytes"
}

probe nfsd.commit.return = kernel.function("nfsd_commit").return !,
                           module("nfsd").function("nfsd_commit").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.commit.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.lookup - NFS server opening or searching file for a file for client
 *
 * @client_ip: the ip address of client
 * @fh: file handle of parent dir(the first part is the length of the file handle)
 * @filename: file name 
 * @filelen: the length of file name
 */
probe nfsd.lookup = kernel.function("nfsd_lookup") !,
                    module("nfsd").function("nfsd_lookup") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	filelen = $len
	filename = kernel_string_n($name, $len)

	name = "nfsd.lookup"
	argstr = sprintf("name: %s", kernel_string_n($name, $len))
}

probe nfsd.lookup.return = kernel.function("nfsd_lookup").return !,
                           module("nfsd").function("nfsd_lookup").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.lookup.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.create - NFS server creating a file(regular,dir,device,fifo) for client
*
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @filename: file name 
 * @filelen: the length of file name
 * @type: file type(regular,dir,device,fifo ...)
 * @iap_valid: Attribute flags
 * @iap_mode: file access mode
 *
 *  Sometimes nfsd will call nfsd_create_v3 instead of this this probe point.
 */
probe nfsd.create = kernel.function("nfsd_create") !,
                    module("nfsd").function("nfsd_create") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	filelen = $flen
	filename = kernel_string_n($fname, $flen)
	type = $type
	iap_valid = $iap->ia_valid
	iap_mode = $iap->ia_mode

	name = "nfsd.create"
	argstr = sprintf("name: %s type: %s", kernel_string_n($fname, $flen), 
		ftype(type))
}

probe nfsd.create.return = kernel.function("nfsd_create").return !,
                           module("nfsd").function("nfsd_create").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.create.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.createv3 - NFS server creating a regular file or set file attributes for client
 *
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @filename: file name 
 * @filelen: the length of file name
 * @iap_valid: Attribute flags
 * @iap_mode: file access mode
 * @createmode: create mode .The possible values could be: NFS3_CREATE_EXCLUSIVE, NFS3_CREATE_UNCHECKED, or NFS3_CREATE_GUARDED
 * @truncp: trunp arguments, indicates if the file shouldbe truncate
*  @verifier: file attributes (atime,mtime,mode). It's used to reset file attributes for CREATE_EXCLUSIVE
 *
 *  This probepoints is only called by nfsd3_proc_create and
 *  nfsd4_open when op_claim_type is NFS4_OPEN_CLAIM_NULL.
 */
probe nfsd.createv3 = kernel.function("do_nfsd_create") !,
                      module("nfsd").function("do_nfsd_create") !,
                      kernel.function("nfsd_create_v3") !,
                      module("nfsd").function("nfsd_create_v3") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	filelen = $flen
	filename = kernel_string_n($fname, $flen)
	iap_valid = $iap->ia_valid
	iap_mode = $iap->ia_mode
	truncp = $truncp
	verifier = $verifier
	createmode = $createmode

	name = "nfsd.createv3"
	argstr = sprintf("name: %s mode: %s",  kernel_string_n($fname, $flen), 
		nfs3_cmode(createmode))
}

probe nfsd.createv3.return =
		kernel.function("do_nfsd_create").return !,
		module("nfsd").function("do_nfsd_create").return !,
		kernel.function("nfsd_create_v3").return !,
		module("nfsd").function("nfsd_create_v3").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.createv3.return"
	retstr = sprintf("%s", nfsderror($return))
}

/** 
 * probe nfsd.unlink - NFS server removing a file or a directory for client
 *
 * @client_ip: the ip address of client
 * @fh: file handle (the first part is the length of the file handle)
 * @filename: file name 
 * @filelen: the length of file name
 * @type: file type (file or dir)
 */
probe nfsd.unlink = kernel.function("nfsd_unlink") !,
                    module("nfsd").function("nfsd_unlink") ?
{
	client_ip = addr_from_rqst_str($rqstp)
	fh = __svc_fh($fhp)

	filelen = $flen
	filename = kernel_string_n($fname, $flen)
	type = $type

	name = "nfsd.unlink"
	argstr = sprintf("name: %s", kernel_string_n($fname, $flen))
}

probe nfsd.unlink.return = kernel.function("nfsd_unlink").return !,
                           module("nfsd").function("nfsd_unlink").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($fhp))

	name = "nfsd.unlink.return"
	retstr = sprintf("%s", nfsderror($return))
}

/**
 * probe nfsd.rename -NFS server renaming a file for client
 *
 * @client_ip: the ip address of client
 * @fh: file handler of old path
 * @tfh: file handler of new path
 * @filename: old file name 
 * @tname: new file name
 * @flen: length of old file name 
 * @tlen: length of new file name
 */
probe nfsd.rename = kernel.function("nfsd_rename") !,
                    module("nfsd").function("nfsd_rename") ?
{
	client_ip = addr_from_rqst_str($rqstp)

	fh = __svc_fh($ffhp)
	tfh = __svc_fh($tfhp)

	filelen = $flen
	filename = kernel_string_n($fname, $flen)
	tlen = $tlen
	tname = kernel_string_n($tname, $tlen)

	name = "nfsd.rename"
	argstr = sprintf("%s to %s", kernel_string_n($fname, $flen),
		kernel_string_n($tname, $tlen))
}

probe nfsd.rename.return =  kernel.function("nfsd_rename").return !,
                            module("nfsd").function("nfsd_rename").return ?
{
	client_ip = addr_from_rqst_str(@entry($rqstp))
	fh = __svc_fh(@entry($ffhp))

	name = "nfsd.rename.return"
	retstr = sprintf("%s", nfsderror($return))
}
