It is possible to use this tracepoint for several purposes, including troubleshooting export permission problems and auditing accesses to files. nfsd-1025 [002] 256.807403: nfsd_permission: xid=0x12147d7a \ type=REG access=WRITE|SATTR|OWNER_OVERRIDE owner=1046/100 \ user=1046/100 name=.clang-format status=OK Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- fs/nfsd/trace.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/vfs.c | 1 + include/trace/events/fs.h | 10 ++++++++++ 3 files changed, 56 insertions(+) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index b4c773530aa8..15b97275b3b4 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -10,6 +10,7 @@ #include <linux/tracepoint.h> #include <trace/events/fs.h> +#include <trace/events/nfs.h> #include "export.h" #include "nfsfh.h" @@ -30,6 +31,50 @@ { NFSD_MAY_READ_IF_EXEC, "READ_IF_EXEC" }, \ { NFSD_MAY_64BIT_COOKIE, "64BIT_COOKIE" }) +TRACE_EVENT(nfsd_access, + TP_PROTO( + const struct svc_rqst *rqstp, + const struct dentry *dentry, + int access, + __be32 status + ), + TP_ARGS(rqstp, dentry, access, status), + TP_STRUCT__entry( + __field(u32, xid) + __field(unsigned long, type) + __field(unsigned long, access) + __field(uid_t, owner) + __field(gid_t, owner_group) + __field(uid_t, user) + __field(gid_t, user_group) + __field(int, status) + __dynamic_array(unsigned char, name, dentry->d_name.len + 1) + ), + TP_fast_assign( + const struct inode *inode = d_inode(dentry); + + __entry->xid = be32_to_cpu(rqstp->rq_xid); + __entry->type = inode->i_mode & S_IFMT; + __entry->access = access; + __entry->owner = __kuid_val(inode->i_uid); + __entry->owner_group = __kgid_val(inode->i_gid); + __entry->user = __kuid_val(current_fsuid()); + __entry->user_group = __kgid_val(current_fsgid()); + __entry->status = be32_to_cpu(status); + memcpy(__get_str(name), dentry->d_name.name, + dentry->d_name.len); + __get_str(name)[dentry->d_name.len] = '\0'; + ), + TP_printk("xid=0x%08x type=%s access=%s owner=%u/%u user=%u/%u name=%s status=%s", + __entry->xid, + show_inode_type(__entry->type), + show_nfsd_may_flags(__entry->access), + __entry->owner, __entry->owner_group, + __entry->user, __entry->user_group, + __get_str(name), show_nfs_status(__entry->status) + ) +); + TRACE_EVENT(nfsd_setattr_args, TP_PROTO( const struct svc_rqst *rqstp, diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a311593ac976..0d354531ed19 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -687,6 +687,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor sresult |= map->access; err2 = nfsd_permission(rqstp, export, dentry, map->how); + trace_nfsd_access(rqstp, dentry, map->how, err2); switch (err2) { case nfs_ok: result |= map->access; diff --git a/include/trace/events/fs.h b/include/trace/events/fs.h index 2b185d81d9a5..49d3dde471ad 100644 --- a/include/trace/events/fs.h +++ b/include/trace/events/fs.h @@ -165,3 +165,13 @@ { ATTR_OPEN, "OPEN" }, \ { ATTR_TIMES_SET, "TIMES_SET" }, \ { ATTR_TOUCH, "TOUCH" }) + +#define show_inode_type(x) \ + __print_symbolic(x, \ + { S_IFIFO, "FIFO" }, \ + { S_IFCHR, "CHR" }, \ + { S_IFDIR, "DIR" }, \ + { S_IFBLK, "BLK" }, \ + { S_IFREG, "REG" }, \ + { S_IFLNK, "LNK" }, \ + { S_IFSOCK, "SOCK" })