From iedowse@maths.tcd.ie  Wed Mar 22 12:17:05 2000
Return-Path: <iedowse@maths.tcd.ie>
Received: from salmon.maths.tcd.ie (salmon.maths.tcd.ie [134.226.81.11])
	by hub.freebsd.org (Postfix) with SMTP id 1322F37C285
	for <freebsd-gnats-submit@freebsd.org>; Wed, 22 Mar 2000 12:16:35 -0800 (PST)
	(envelope-from iedowse@maths.tcd.ie)
Received: from bell.maths.tcd.ie by salmon.maths.tcd.ie with SMTP
          id <aa31907@salmon>; 22 Mar 2000 20:16:25 +0000 (GMT)
Message-Id: <200003222016.aa54468@bell.maths.tcd.ie>
Date: Wed, 22 Mar 2000 20:16:25 +0000 (GMT)
From: iedowse@maths.tcd.ie
Sender: iedowse@maths.tcd.ie
Reply-To: iedowse@maths.tcd.ie
To: FreeBSD-gnats-submit@freebsd.org
Subject: fstat(1) doesn't show memory-mapped files
X-Send-Pr-Version: 3.2

>Number:         17555
>Category:       bin
>Synopsis:       fstat(1) doesn't show memory-mapped files
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    green
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 22 12:20:01 PST 2000
>Closed-Date:    Thu Jan 4 17:14:33 PST 2001
>Last-Modified:  Thu Jan 04 17:24:06 PST 2001
>Originator:     Ian Dowse
>Release:        FreeBSD 3.3-STABLE i386
>Organization:
		School of Mathematics
		Trinity College, Dublin
>Environment:

	FreeBSD -current or -stable
	(patch included is for RELENG_4 or -current)

>Description:

	fstat(1) is a useful tool for determining which processes hold
	references to a filesystem - I use it frequently to help resolve
	'Device busy' errors when attempting to unmount a filesystem.

	However, files that are memory-mapped into a process's address
	space don't show up (unless the file descriptor is still open).

	The patch included below makes fstat include mmap()'d files in
	its listing of open files for each process. The word 'mmap'
	appears in the FD column to indicate that this is a mmap()'d
	file.

	Most of the logic in the new dommap() function below is taken
	from procfs_map.c.

>How-To-Repeat:

>Fix:


--- fstat.1.orig	Sun Oct 17 23:59:50 1999
+++ fstat.1	Wed Mar 22 19:56:21 2000
@@ -50,6 +50,7 @@
 .Nm Fstat
 identifies open files.
 A file is considered open by a process if it was explicitly opened,
+memory-mapped,
 is the working directory, root directory, active executable text, or kernel
 trace file for that process.
 If no options are specified,
@@ -117,6 +118,7 @@
 wd 	- current working directory
 root	- root inode
 tr	- kernel trace file
+mmap	- memory-mapped file
 .Ed
 .Pp
 If the file number is followed by an asterisk (``*''), the file is

--- fstat.c.orig	Wed Mar 22 19:33:17 2000
+++ fstat.c	Wed Mar 22 19:56:18 2000
@@ -74,6 +74,10 @@
 #include <nfs/nfsnode.h>
 
 
+#include <vm/vm.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
 #include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -100,6 +104,7 @@
 #define	CDIR	-2
 #define	RDIR	-3
 #define	TRACE	-4
+#define	MMAP	-5
 
 DEVS *devs;
 
@@ -132,6 +137,7 @@
 kvm_t *kd;
 
 void dofiles __P((struct kinfo_proc *kp));
+void dommap __P((struct kinfo_proc *kp));
 void vtrans __P((struct vnode *vp, int i, int flag));
 int  ufs_filestat __P((struct vnode *vp, struct filestat *fsp));
 int  nfs_filestat __P((struct vnode *vp, struct filestat *fsp));
@@ -246,6 +252,7 @@
 		if (p->kp_proc.p_stat == SZOMB)
 			continue;
 		dofiles(p);
+		dommap(p);
 	}
 	exit(0);
 }
@@ -267,6 +274,9 @@
 	case TRACE: \
 		printf("   tr"); \
 		break; \
+	case MMAP: \
+		printf(" mmap"); \
+		break; \
 	default: \
 		printf(" %4d", i); \
 		break; \
@@ -356,6 +366,65 @@
 			dprintf(stderr,
 				"unknown file type %d for file %d of pid %d\n",
 				file.f_type, i, Pid);
+		}
+	}
+}
+
+void
+dommap(kp)
+	struct kinfo_proc *kp;
+{
+	struct proc *p = &kp->kp_proc;
+	struct vmspace vmspace;
+	vm_map_t map;
+	struct vm_map_entry entry;
+	vm_map_entry_t entryp;
+	struct vm_object object;
+	vm_object_t objp;
+	int prot, fflags;
+
+	if (!KVM_READ(p->p_vmspace, &vmspace, sizeof(vmspace))) {
+		dprintf(stderr, "can't read vmspace at %p for pid %d\n",
+		    (void *)p->p_vmspace, Pid);
+		return;
+	}
+
+	map = &vmspace.vm_map;
+
+	for (entryp = map->header.next; entryp != &p->p_vmspace->vm_map.header;
+	    entryp = entry.next) {
+		if (!KVM_READ(entryp, &entry, sizeof(entry))) {
+			dprintf(stderr,
+			    "can't read vm_map_entry at %p for pid %d\n",
+			    (void *)entryp, Pid);
+			return;
+		}
+
+		if (entry.eflags & MAP_ENTRY_IS_SUB_MAP)
+			continue;
+
+		if ((objp = entry.object.vm_object) == NULL)
+			continue;
+
+		for (; objp; objp = object.backing_object) {
+			if (!KVM_READ(objp, &object, sizeof(object))) {
+				dprintf(stderr,
+				    "can't read vm_object at %p for pid %d\n",
+				    (void *)objp, Pid);
+				return;
+			}
+		}
+
+		prot = entry.protection;
+		fflags = (prot & VM_PROT_READ ? FREAD : 0) |
+		    (prot & VM_PROT_WRITE ? FWRITE : 0);
+
+		switch (object.type) {
+		case OBJT_VNODE:
+			vtrans((struct vnode *)object.handle, MMAP, fflags);
+			break;
+		default:
+			break;
 		}
 	}
 }

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->green 
Responsible-Changed-By: sheldonh 
Responsible-Changed-When: Wed Mar 29 03:47:15 PST 2000 
Responsible-Changed-Why:  
Brian, since you seem to be beefing up fstat(1), could you look 
at this one?  Ian submits good PR's. :-) 
State-Changed-From-To: open->feedback 
State-Changed-By: green 
State-Changed-When: Mon Apr 3 19:33:05 PDT 2000 
State-Changed-Why:  
Do you think you could make it conditional on a flag?  This can potentially 
add 
a lot of overhead, so it shouldn't (IMHO) be default.  If you can take care 
of that, I'll commit it; however, if you don't have the time, I could do 
it, too. 
State-Changed-From-To: feedback->closed 
State-Changed-By: iedowse 
State-Changed-When: Thu Jan 4 17:14:33 PST 2001 
State-Changed-Why:  
This was committed to -current some time ago, and has already been 
MFC'd (I submitted this PR, so I'll close it). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=17555 
>Unformatted:
