svn commit: r302066 - in stable/10: share/man/man4 sys/dev/filemon sys/kern sys/sys

Bryan Drewery bdrewery at FreeBSD.org
Tue Jun 21 20:13:21 UTC 2016


Author: bdrewery
Date: Tue Jun 21 20:13:19 2016
New Revision: 302066
URL: https://svnweb.freebsd.org/changeset/base/302066

Log:
  MFC r297156,r297157,r297158,r297159,r297161,r297172,r297200,r297201,r297202,
      r297203,r297256:
  
    r297156:
      Track filemon usage via a proc.p_filemon pointer rather than its own lists.
    r297157:
      Stop tracking stat(2).
    r297158:
      Consolidate open(2) and openat(2) code.
    r297159:
      Use curthread for vn_fullpath.
    r297161:
      Attempt to use the namecache for openat(2) path resolution.
    r297172:
      Consolidate common link(2) logic.
    r297200:
      Follow-up r297156: Close the log in filemon_dtr rather than in the last
      reference.
    r297201:
      Return any log write failure encountered when closing the filemon fd.
    r297202:
      Remove unused done argument to copyinstr(9).
    r297203:
      Handle copyin failures.
    r297256:
      Remove unneeded return left from refactoring.
  
  Relnotes:	yes (filemon stability/performance updates)
  Sponsored by:	EMC / Isilon Storage Division

Deleted:
  stable/10/sys/dev/filemon/filemon_lock.c
Modified:
  stable/10/share/man/man4/filemon.4
  stable/10/sys/dev/filemon/filemon.c
  stable/10/sys/dev/filemon/filemon_wrapper.c
  stable/10/sys/kern/kern_fork.c
  stable/10/sys/sys/param.h
  stable/10/sys/sys/proc.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/share/man/man4/filemon.4
==============================================================================
--- stable/10/share/man/man4/filemon.4	Tue Jun 21 18:16:45 2016	(r302065)
+++ stable/10/share/man/man4/filemon.4	Tue Jun 21 20:13:19 2016	(r302066)
@@ -31,7 +31,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 9, 2016
+.Dd June 21, 2016
 .Dt FILEMON 4
 .Os
 .Sh NAME
@@ -83,8 +83,6 @@ System calls are denoted using the follo
 .It Ql R
 .Xr open 2
 for read
-.It Ql S
-.Xr stat 2
 .It Ql W
 .Xr open 2
 for write
@@ -116,6 +114,10 @@ Each takes a single argument.
 Write the internal tracing buffer to the supplied open file descriptor.
 .It Dv FILEMON_SET_PID
 Child process ID to trace.
+This should normally be done under the control of a parent in the child after
+.Xr fork 2
+but before anything else.
+See the example below.
 .El
 .Sh RETURN VALUES
 .\" .Rv -std ioctl
@@ -138,6 +140,35 @@ The
 .Nm
 handle is already associated with a file descriptor.
 .El
+.Pp
+The
+.Fn ioctl
+system call
+with
+.Dv FILEMON_SET_PID
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+No process having the specified process ID exists.
+.It Bq Er EBUSY
+The process ID specified is already being traced and was not the current
+process.
+.El
+.Pp
+The
+.Fn close
+system call on the filemon file descriptor may fail with the errors from
+.Xr write 2
+if any error is encountered while writing the log.
+It may also fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+An invalid address was used for a traced system call argument, resulting in
+no log entry for the system call.
+.It Bq Er ENAMETOOLONG
+An argument for a traced system call was too long, resulting in
+no log entry for the system call.
+.El
 .Sh FILES
 .Bl -tag -width ".Pa /dev/filemon"
 .It Pa /dev/filemon
@@ -198,14 +229,5 @@ A
 device appeared in
 .Fx 9.1 .
 .Sh BUGS
-Loading
-.Nm
-may reduce system performance for the noted syscalls.
-.Pp
-Only children of the set process are logged.
-Processes can escape being traced by double forking.
-This is not seen as a problem as the intended use is build monitoring, which
-does not make sense to have daemons for.
-.Pp
 Unloading the module may panic the system, thus requires using
 .Ic kldunload -f .

Modified: stable/10/sys/dev/filemon/filemon.c
==============================================================================
--- stable/10/sys/dev/filemon/filemon.c	Tue Jun 21 18:16:45 2016	(r302065)
+++ stable/10/sys/dev/filemon/filemon.c	Tue Jun 21 20:13:19 2016	(r302066)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2011, David E. O'Brien.
  * Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/poll.h>
 #include <sys/proc.h>
-#include <sys/queue.h>
 #include <sys/sx.h>
 #include <sys/syscall.h>
 #include <sys/sysent.h>
@@ -80,23 +79,112 @@ static struct cdevsw filemon_cdevsw = {
 MALLOC_DECLARE(M_FILEMON);
 MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor");
 
+/*
+ * The filemon->lock protects several things currently:
+ * - fname1/fname2/msgbufr are pre-allocated and used per syscall
+ *   for logging and copyins rather than stack variables.
+ * - Serializing the filemon's log output.
+ * - Preventing inheritance or removal of the filemon into proc.p_filemon.
+ */
 struct filemon {
-	TAILQ_ENTRY(filemon) link;	/* Link into the in-use list. */
-	struct sx	lock;		/* Lock mutex for this filemon. */
+	struct sx	lock;		/* Lock for this filemon. */
 	struct file	*fp;		/* Output file pointer. */
-	struct proc     *p;		/* The process being monitored. */
 	char		fname1[MAXPATHLEN]; /* Temporary filename buffer. */
 	char		fname2[MAXPATHLEN]; /* Temporary filename buffer. */
 	char		msgbufr[1024];	/* Output message buffer. */
+	int		error;		/* Log write error, returned on close(2). */
+	u_int		refcnt;		/* Pointer reference count. */
+	u_int		proccnt;	/* Process count. */
 };
 
-static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse);
-static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free);
-static struct sx access_lock;
-
 static struct cdev *filemon_dev;
+static void filemon_output(struct filemon *filemon, char *msg, size_t len);
+
+static __inline struct filemon *
+filemon_acquire(struct filemon *filemon)
+{
+
+	if (filemon != NULL)
+		refcount_acquire(&filemon->refcnt);
+	return (filemon);
+}
+
+/*
+ * Release a reference and free on the last one.
+ */
+static void
+filemon_release(struct filemon *filemon)
+{
+
+	if (refcount_release(&filemon->refcnt) == 0)
+		return;
+	/*
+	 * There are valid cases of releasing while locked, such as in
+	 * filemon_untrack_processes, but none which are done where there
+	 * is not at least 1 reference remaining.
+	 */
+	sx_assert(&filemon->lock, SA_UNLOCKED);
+
+	sx_destroy(&filemon->lock);
+	free(filemon, M_FILEMON);
+}
+
+/*
+ * Acquire the proc's p_filemon reference and lock the filemon.
+ * The proc's p_filemon may not match this filemon on return.
+ */
+static struct filemon *
+filemon_proc_get(struct proc *p)
+{
+	struct filemon *filemon;
+
+	PROC_LOCK(p);
+	filemon = filemon_acquire(p->p_filemon);
+	PROC_UNLOCK(p);
+
+	if (filemon == NULL)
+		return (NULL);
+	/*
+	 * The p->p_filemon may have changed by now.  That case is handled
+	 * by the exit and fork hooks and filemon_attach_proc specially.
+	 */
+	sx_xlock(&filemon->lock);
+	return (filemon);
+}
+
+/* Remove and release the filemon on the given process. */
+static void
+filemon_proc_drop(struct proc *p)
+{
+	struct filemon *filemon;
+
+	KASSERT(p->p_filemon != NULL, ("%s: proc %p NULL p_filemon",
+	    __func__, p));
+	sx_assert(&p->p_filemon->lock, SA_XLOCKED);
+	PROC_LOCK(p);
+	filemon = p->p_filemon;
+	p->p_filemon = NULL;
+	--filemon->proccnt;
+	PROC_UNLOCK(p);
+	/*
+	 * This should not be the last reference yet.  filemon_release()
+	 * cannot be called with filemon locked, which the caller expects
+	 * will stay locked.
+	 */
+	KASSERT(filemon->refcnt > 1, ("%s: proc %p dropping filemon %p "
+	    "with last reference", __func__, p, filemon));
+	filemon_release(filemon);
+}
+
+/* Unlock and release the filemon. */
+static __inline void
+filemon_drop(struct filemon *filemon)
+{
+
+	sx_xunlock(&filemon->lock);
+	filemon_release(filemon);
+}
 
-#include "filemon_lock.c"
 #include "filemon_wrapper.c"
 
 static void
@@ -115,35 +203,151 @@ filemon_comment(struct filemon *filemon)
 	filemon_output(filemon, filemon->msgbufr, len);
 }
 
+/*
+ * Invalidate the passed filemon in all processes.
+ */
 static void
-filemon_dtr(void *data)
+filemon_untrack_processes(struct filemon *filemon)
 {
-	struct filemon *filemon = data;
+	struct proc *p;
 
-	if (filemon != NULL) {
-		struct file *fp;
+	sx_assert(&filemon->lock, SA_XLOCKED);
 
-		/* Follow same locking order as filemon_pid_check. */
-		filemon_lock_write();
-		sx_xlock(&filemon->lock);
+	/* Avoid allproc loop if there is no need. */
+	if (filemon->proccnt == 0)
+		return;
+
+	/*
+	 * Processes in this list won't go away while here since
+	 * filemon_event_process_exit() will lock on filemon->lock
+	 * which we hold.
+	 */
+	sx_slock(&allproc_lock);
+	FOREACH_PROC_IN_SYSTEM(p) {
+		/*
+		 * No PROC_LOCK is needed to compare here since it is
+		 * guaranteed to not change since we have its filemon
+		 * locked.  Everything that changes this p_filemon will
+		 * be locked on it.
+		 */
+		if (p->p_filemon == filemon)
+			filemon_proc_drop(p);
+	}
+	sx_sunlock(&allproc_lock);
+
+	/*
+	 * It's possible some references were acquired but will be
+	 * dropped shortly as they are restricted from being
+	 * inherited.  There is at least the reference in cdevpriv remaining.
+	 */
+	KASSERT(filemon->refcnt > 0, ("%s: filemon %p should have "
+	    "references still.", __func__, filemon));
+	KASSERT(filemon->proccnt == 0, ("%s: filemon %p should not have "
+	    "attached procs still.", __func__, filemon));
+}
 
-		/* Remove from the in-use list. */
-		TAILQ_REMOVE(&filemons_inuse, filemon, link);
+/*
+ * Close out the log.
+ */
+static void
+filemon_close_log(struct filemon *filemon)
+{
+	struct file *fp;
+	struct timeval now;
+	size_t len;
 
-		fp = filemon->fp;
-		filemon->fp = NULL;
-		filemon->p = NULL;
+	sx_assert(&filemon->lock, SA_XLOCKED);
+	if (filemon->fp == NULL)
+		return;
 
-		/* Add to the free list. */
-		TAILQ_INSERT_TAIL(&filemons_free, filemon, link);
+	getmicrotime(&now);
 
-		/* Give up write access. */
-		sx_xunlock(&filemon->lock);
-		filemon_unlock_write();
+	len = snprintf(filemon->msgbufr,
+	    sizeof(filemon->msgbufr),
+	    "# Stop %ju.%06ju\n# Bye bye\n",
+	    (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
+
+	filemon_output(filemon, filemon->msgbufr, len);
+	fp = filemon->fp;
+	filemon->fp = NULL;
+
+	sx_xunlock(&filemon->lock);
+	fdrop(fp, curthread);
+	sx_xlock(&filemon->lock);
+}
 
-		if (fp != NULL)
-			fdrop(fp, curthread);
+/*
+ * The devfs file is being closed.  Untrace all processes.  It is possible
+ * filemon_close/close(2) was not called.
+ */
+static void
+filemon_dtr(void *data)
+{
+	struct filemon *filemon = data;
+
+	if (filemon == NULL)
+		return;
+
+	sx_xlock(&filemon->lock);
+	/*
+	 * Detach the filemon.  It cannot be inherited after this.
+	 */
+	filemon_untrack_processes(filemon);
+	filemon_close_log(filemon);
+	filemon_drop(filemon);
+}
+
+/* Attach the filemon to the process. */
+static int
+filemon_attach_proc(struct filemon *filemon, struct proc *p)
+{
+	struct filemon *filemon2;
+
+	sx_assert(&filemon->lock, SA_XLOCKED);
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+	KASSERT((p->p_flag & P_WEXIT) == 0,
+	    ("%s: filemon %p attaching to exiting process %p",
+	    __func__, filemon, p));
+
+	if (p->p_filemon == filemon)
+		return (0);
+	/*
+	 * Don't allow truncating other process traces.  It is
+	 * not really intended to trace procs other than curproc
+	 * anyhow.
+	 */
+	if (p->p_filemon != NULL && p != curproc)
+		return (EBUSY);
+	/*
+	 * Historic behavior of filemon has been to let a child initiate
+	 * tracing on itself and cease existing tracing.  Bmake
+	 * .META + .MAKE relies on this.  It is only relevant for attaching to
+	 * curproc.
+	 */
+	while (p->p_filemon != NULL) {
+		PROC_UNLOCK(p);
+		sx_xunlock(&filemon->lock);
+		while ((filemon2 = filemon_proc_get(p)) != NULL) {
+			/* It may have changed. */
+			if (p->p_filemon == filemon2)
+				filemon_proc_drop(p);
+			filemon_drop(filemon2);
+		}
+		sx_xlock(&filemon->lock);
+		PROC_LOCK(p);
+		/*
+		 * It may have been attached to, though unlikely.
+		 * Try again if needed.
+		 */
 	}
+
+	KASSERT(p->p_filemon == NULL,
+	    ("%s: proc %p didn't detach filemon %p", __func__, p,
+	    p->p_filemon));
+	p->p_filemon = filemon_acquire(filemon);
+	++filemon->proccnt;
+
+	return (0);
 }
 
 static int
@@ -178,10 +382,16 @@ filemon_ioctl(struct cdev *dev, u_long c
 
 	/* Set the monitored process ID. */
 	case FILEMON_SET_PID:
+		/* Invalidate any existing processes already set. */
+		filemon_untrack_processes(filemon);
+
 		error = pget(*((pid_t *)data), PGET_CANDEBUG | PGET_NOTWEXIT,
 		    &p);
 		if (error == 0) {
-			filemon->p = p;
+			KASSERT(p->p_filemon != filemon,
+			    ("%s: proc %p didn't untrack filemon %p",
+			    __func__, p, filemon));
+			error = filemon_attach_proc(filemon, p);
 			PROC_UNLOCK(p);
 		}
 		break;
@@ -199,49 +409,48 @@ static int
 filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused,
     struct thread *td __unused)
 {
+	int error;
 	struct filemon *filemon;
 
-	/* Get exclusive write access. */
-	filemon_lock_write();
-
-	if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL)
-		TAILQ_REMOVE(&filemons_free, filemon, link);
-
-	/* Give up write access. */
-	filemon_unlock_write();
-
-	if (filemon == NULL) {
-		filemon = malloc(sizeof(struct filemon), M_FILEMON,
-		    M_WAITOK | M_ZERO);
-		sx_init(&filemon->lock, "filemon");
-	}
-
-	devfs_set_cdevpriv(filemon, filemon_dtr);
+	filemon = malloc(sizeof(*filemon), M_FILEMON,
+	    M_WAITOK | M_ZERO);
+	sx_init(&filemon->lock, "filemon");
+	refcount_init(&filemon->refcnt, 1);
+
+	error = devfs_set_cdevpriv(filemon, filemon_dtr);
+	if (error != 0)
+		filemon_release(filemon);
 
-	/* Get exclusive write access. */
-	filemon_lock_write();
-
-	/* Add to the in-use list. */
-	TAILQ_INSERT_TAIL(&filemons_inuse, filemon, link);
-
-	/* Give up write access. */
-	filemon_unlock_write();
-
-	return (0);
+	return (error);
 }
 
+/* Called on close of last devfs file handle, before filemon_dtr(). */
 static int
 filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused,
     struct thread *td __unused)
 {
+	struct filemon *filemon;
+	int error;
 
-	return (0);
+	if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0)
+		return (error);
+
+	sx_xlock(&filemon->lock);
+	filemon_close_log(filemon);
+	error = filemon->error;
+	sx_xunlock(&filemon->lock);
+	/*
+	 * Processes are still being traced but won't log anything
+	 * now.  After this call returns filemon_dtr() is called which
+	 * will detach processes.
+	 */
+
+	return (error);
 }
 
 static void
 filemon_load(void *dummy __unused)
 {
-	sx_init(&access_lock, "filemons_inuse");
 
 	/* Install the syscall wrappers. */
 	filemon_wrapper_install();
@@ -253,38 +462,11 @@ filemon_load(void *dummy __unused)
 static int
 filemon_unload(void)
 {
- 	struct filemon *filemon;
-	int error = 0;
-
-	/* Get exclusive write access. */
-	filemon_lock_write();
-
-	if (TAILQ_FIRST(&filemons_inuse) != NULL)
-		error = EBUSY;
-	else {
-		destroy_dev(filemon_dev);
-
-		/* Deinstall the syscall wrappers. */
-		filemon_wrapper_deinstall();
-	}
 
-	/* Give up write access. */
-	filemon_unlock_write();
+	destroy_dev(filemon_dev);
+	filemon_wrapper_deinstall();
 
-	if (error == 0) {
-		/* free() filemon structs free list. */
-		filemon_lock_write();
-		while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) {
-			TAILQ_REMOVE(&filemons_free, filemon, link);
-			sx_destroy(&filemon->lock);
-			free(filemon, M_FILEMON);
-		}
-		filemon_unlock_write();
-
-		sx_destroy(&access_lock);
-	}
-
-	return (error);
+	return (0);
 }
 
 static int

Modified: stable/10/sys/dev/filemon/filemon_wrapper.c
==============================================================================
--- stable/10/sys/dev/filemon/filemon_wrapper.c	Tue Jun 21 18:16:45 2016	(r302065)
+++ stable/10/sys/dev/filemon/filemon_wrapper.c	Tue Jun 21 20:13:19 2016	(r302066)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2011, David E. O'Brien.
  * Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,9 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include <sys/imgact.h>
 #include <sys/eventhandler.h>
+#include <sys/filedesc.h>
+#include <sys/imgact.h>
 #include <sys/sx.h>
 #include <sys/vnode.h>
 
@@ -45,6 +46,7 @@ filemon_output(struct filemon *filemon, 
 {
 	struct uio auio;
 	struct iovec aiov;
+	int error;
 
 	if (filemon->fp == NULL)
 		return;
@@ -62,56 +64,33 @@ filemon_output(struct filemon *filemon, 
 	if (filemon->fp->f_type == DTYPE_VNODE)
 		bwillwrite();
 
-	fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
-}
-
-static struct filemon *
-filemon_pid_check(struct proc *p)
-{
-	struct filemon *filemon;
-
-	filemon_lock_read();
-	if (TAILQ_EMPTY(&filemons_inuse)) {
-		filemon_unlock_read();
-		return (NULL);
-	}
-	sx_slock(&proctree_lock);
-	while (p->p_pid != 0) {
-		TAILQ_FOREACH(filemon, &filemons_inuse, link) {
-			if (p == filemon->p) {
-				sx_sunlock(&proctree_lock);
-				sx_xlock(&filemon->lock);
-				filemon_unlock_read();
-				return (filemon);
-			}
-		}
-		p = proc_realparent(p);
-	}
-	sx_sunlock(&proctree_lock);
-	filemon_unlock_read();
-	return (NULL);
+	error = fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
+	if (error != 0)
+		filemon->error = error;
 }
 
 static int
 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
 {
-	int ret;
-	size_t done;
+	int error, ret;
 	size_t len;
 	struct filemon *filemon;
 
 	if ((ret = sys_chdir(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
+		if ((filemon = filemon_proc_get(curproc)) != NULL) {
+			if ((error = copyinstr(uap->path, filemon->fname1,
+			    sizeof(filemon->fname1), NULL)) != 0) {
+				filemon->error = error;
+				goto copyfail;
+			}
 
 			len = snprintf(filemon->msgbufr,
 			    sizeof(filemon->msgbufr), "C %d %s\n",
 			    curproc->p_pid, filemon->fname1);
 
 			filemon_output(filemon, filemon->msgbufr, len);
-
-			sx_xunlock(&filemon->lock);
+copyfail:
+			filemon_drop(filemon);
 		}
 	}
 
@@ -126,12 +105,11 @@ filemon_event_process_exec(void *arg __u
 	char *fullpath, *freepath;
 	size_t len;
 
-	if ((filemon = filemon_pid_check(p)) != NULL) {
+	if ((filemon = filemon_proc_get(p)) != NULL) {
 		fullpath = "<unknown>";
 		freepath = NULL;
 
-		vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
-		    &freepath);
+		vn_fullpath(curthread, imgp->vp, &fullpath, &freepath);
 
 		len = snprintf(filemon->msgbufr,
 		    sizeof(filemon->msgbufr), "E %d %s\n",
@@ -139,321 +117,244 @@ filemon_event_process_exec(void *arg __u
 
 		filemon_output(filemon, filemon->msgbufr, len);
 
-		sx_xunlock(&filemon->lock);
+		filemon_drop(filemon);
 
 		free(freepath, M_TEMP);
 	}
 }
 
-static int
-filemon_wrapper_open(struct thread *td, struct open_args *uap)
+static void
+_filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd)
 {
-	int ret;
-	size_t done;
+	int error;
 	size_t len;
+	struct file *fp;
 	struct filemon *filemon;
+	char *atpath, *freepath;
+	cap_rights_t rights;
 
-	if ((ret = sys_open(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-
-			if (uap->flags & O_RDWR) {
-				/*
-				 * We'll get the W record below, but need
-				 * to also output an R to distingish from
-				 * O_WRONLY.
-				 */
-				len = snprintf(filemon->msgbufr,
-				    sizeof(filemon->msgbufr), "R %d %s\n",
-				    curproc->p_pid, filemon->fname1);
-				filemon_output(filemon, filemon->msgbufr, len);
-			}
-
+	if ((filemon = filemon_proc_get(curproc)) != NULL) {
+		atpath = "";
+		freepath = NULL;
+		fp = NULL;
 
+		if ((error = copyinstr(upath, filemon->fname1,
+		    sizeof(filemon->fname1), NULL)) != 0) {
+			filemon->error = error;
+			goto copyfail;
+		}
+
+		if (filemon->fname1[0] != '/' && fd != AT_FDCWD) {
+			/*
+			 * rats - we cannot do too much about this.
+			 * the trace should show a dir we read
+			 * recently.. output an A record as a clue
+			 * until we can do better.
+			 * XXX: This may be able to come out with
+			 * the namecache lookup now.
+			 */
 			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "%c %d %s\n",
-			    (uap->flags & O_ACCMODE) ? 'W':'R',
+			    sizeof(filemon->msgbufr), "A %d %s\n",
 			    curproc->p_pid, filemon->fname1);
 			filemon_output(filemon, filemon->msgbufr, len);
-
-			sx_xunlock(&filemon->lock);
+			/*
+			 * Try to resolve the path from the vnode using the
+			 * namecache.  It may be inaccurate, but better
+			 * than nothing.
+			 */
+			if (getvnode(td->td_proc->p_fd, fd,
+			    cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) {
+				vn_fullpath(td, fp->f_vnode, &atpath,
+				    &freepath);
+			}
+		}
+		if (flags & O_RDWR) {
+			/*
+			 * We'll get the W record below, but need
+			 * to also output an R to distinguish from
+			 * O_WRONLY.
+			 */
+			len = snprintf(filemon->msgbufr,
+			    sizeof(filemon->msgbufr), "R %d %s%s%s\n",
+			    curproc->p_pid, atpath,
+			    atpath[0] != '\0' ? "/" : "", filemon->fname1);
+			filemon_output(filemon, filemon->msgbufr, len);
 		}
-	}
 
-	return (ret);
+		len = snprintf(filemon->msgbufr,
+		    sizeof(filemon->msgbufr), "%c %d %s%s%s\n",
+		    (flags & O_ACCMODE) ? 'W':'R',
+		    curproc->p_pid, atpath,
+		    atpath[0] != '\0' ? "/" : "", filemon->fname1);
+		filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+		filemon_drop(filemon);
+		if (fp != NULL)
+			fdrop(fp, td);
+		free(freepath, M_TEMP);
+	}
 }
 
 static int
-filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
+filemon_wrapper_open(struct thread *td, struct open_args *uap)
 {
 	int ret;
-	size_t done;
-	size_t len;
-	struct filemon *filemon;
-
-	if ((ret = sys_openat(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-
-			filemon->fname2[0] = '\0';
-			if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
-				/*
-				 * rats - we cannot do too much about this.
-				 * the trace should show a dir we read
-				 * recently.. output an A record as a clue
-				 * until we can do better.
-				 */
-				len = snprintf(filemon->msgbufr,
-				    sizeof(filemon->msgbufr), "A %d %s\n",
-				    curproc->p_pid, filemon->fname1);
-				filemon_output(filemon, filemon->msgbufr, len);
-			}
-			if (uap->flag & O_RDWR) {
-				/*
-				 * We'll get the W record below, but need
-				 * to also output an R to distingish from
-				 * O_WRONLY.
-				 */
-				len = snprintf(filemon->msgbufr,
-				    sizeof(filemon->msgbufr), "R %d %s%s\n",
-				    curproc->p_pid, filemon->fname2, filemon->fname1);
-				filemon_output(filemon, filemon->msgbufr, len);
-			}
-
-
-			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "%c %d %s%s\n",
-			    (uap->flag & O_ACCMODE) ? 'W':'R',
-			    curproc->p_pid, filemon->fname2, filemon->fname1);
-			filemon_output(filemon, filemon->msgbufr, len);
 
-			sx_xunlock(&filemon->lock);
-		}
-	}
+	if ((ret = sys_open(td, uap)) == 0)
+		_filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
 
 	return (ret);
 }
 
 static int
-filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
+filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
 {
 	int ret;
-	size_t done;
-	size_t len;
-	struct filemon *filemon;
 
-	if ((ret = sys_rename(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->from, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-			copyinstr(uap->to, filemon->fname2,
-			    sizeof(filemon->fname2), &done);
-
-			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
-			    curproc->p_pid, filemon->fname1, filemon->fname2);
-
-			filemon_output(filemon, filemon->msgbufr, len);
-
-			sx_xunlock(&filemon->lock);
-		}
-	}
+	if ((ret = sys_openat(td, uap)) == 0)
+		_filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
 
 	return (ret);
 }
 
 static int
-filemon_wrapper_link(struct thread *td, struct link_args *uap)
+filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
 {
-	int ret;
-	size_t done;
+	int error, ret;
 	size_t len;
 	struct filemon *filemon;
 
-	if ((ret = sys_link(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-			copyinstr(uap->link, filemon->fname2,
-			    sizeof(filemon->fname2), &done);
+	if ((ret = sys_rename(td, uap)) == 0) {
+		if ((filemon = filemon_proc_get(curproc)) != NULL) {
+			if (((error = copyinstr(uap->from, filemon->fname1,
+			     sizeof(filemon->fname1), NULL)) != 0) ||
+			    ((error = copyinstr(uap->to, filemon->fname2,
+			     sizeof(filemon->fname2), NULL)) != 0)) {
+				filemon->error = error;
+				goto copyfail;
+			}
 
 			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+			    sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
 			    curproc->p_pid, filemon->fname1, filemon->fname2);
 
 			filemon_output(filemon, filemon->msgbufr, len);
-
-			sx_xunlock(&filemon->lock);
+copyfail:
+			filemon_drop(filemon);
 		}
 	}
 
 	return (ret);
 }
 
-static int
-filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
+static void
+_filemon_wrapper_link(struct thread *td, char *upath1, char *upath2)
 {
-	int ret;
-	size_t done;
-	size_t len;
 	struct filemon *filemon;
+	size_t len;
+	int error;
 
-	if ((ret = sys_symlink(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-			copyinstr(uap->link, filemon->fname2,
-			    sizeof(filemon->fname2), &done);
-
-			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
-			    curproc->p_pid, filemon->fname1, filemon->fname2);
+	if ((filemon = filemon_proc_get(curproc)) != NULL) {
+		if (((error = copyinstr(upath1, filemon->fname1,
+		     sizeof(filemon->fname1), NULL)) != 0) ||
+		    ((error = copyinstr(upath2, filemon->fname2,
+		     sizeof(filemon->fname2), NULL)) != 0)) {
+			filemon->error = error;
+			goto copyfail;
+		}
 
-			filemon_output(filemon, filemon->msgbufr, len);
+		len = snprintf(filemon->msgbufr,
+		    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+		    curproc->p_pid, filemon->fname1, filemon->fname2);
 
-			sx_xunlock(&filemon->lock);
-		}
+		filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+		filemon_drop(filemon);
 	}
-
-	return (ret);
 }
 
 static int
-filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
+filemon_wrapper_link(struct thread *td, struct link_args *uap)
 {
 	int ret;
-	size_t done;
-	size_t len;
-	struct filemon *filemon;
-
-	if ((ret = sys_linkat(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path1, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-			copyinstr(uap->path2, filemon->fname2,
-			    sizeof(filemon->fname2), &done);
-
-			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
-			    curproc->p_pid, filemon->fname1, filemon->fname2);
-
-			filemon_output(filemon, filemon->msgbufr, len);
 
-			sx_xunlock(&filemon->lock);
-		}
-	}
+	if ((ret = sys_link(td, uap)) == 0)
+		_filemon_wrapper_link(td, uap->path, uap->link);
 
 	return (ret);
 }
 
 static int
-filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
+filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
 {
 	int ret;
-	size_t done;
-	size_t len;
-	struct filemon *filemon;
 
-	if ((ret = sys_stat(td, uap)) == 0) {
-		if ((filemon = filemon_pid_check(curproc)) != NULL) {
-			copyinstr(uap->path, filemon->fname1,
-			    sizeof(filemon->fname1), &done);
-
-			len = snprintf(filemon->msgbufr,
-			    sizeof(filemon->msgbufr), "S %d %s\n",
-			    curproc->p_pid, filemon->fname1);
-
-			filemon_output(filemon, filemon->msgbufr, len);
-
-			sx_xunlock(&filemon->lock);
-		}
-	}
+	if ((ret = sys_symlink(td, uap)) == 0)
+		_filemon_wrapper_link(td, uap->path, uap->link);
 
 	return (ret);
 }
 
-#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
 static int
-filemon_wrapper_freebsd32_stat(struct thread *td,
-    struct freebsd32_stat_args *uap)
+filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
 {
 	int ret;
-	size_t done;
-	size_t len;
-	struct filemon *filemon;
-
-	if ((ret = freebsd32_stat(td, uap)) == 0) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list