xref: /dragonfly/sys/vfs/procfs/procfs_map.c (revision eb67213a)
1 /*
2  * Copyright (c) 1993 Jan-Simon Pendry
3  * Copyright (c) 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)procfs_status.c	8.3 (Berkeley) 2/17/94
34  *
35  * $FreeBSD: src/sys/miscfs/procfs/procfs_map.c,v 1.24.2.1 2001/08/04 13:12:24 rwatson Exp $
36  * $DragonFly: src/sys/vfs/procfs/procfs_map.c,v 1.7 2007/02/19 01:14:24 corecode Exp $
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/proc.h>
42 #include <sys/vnode.h>
43 #include <sys/sbuf.h>
44 #include <vfs/procfs/procfs.h>
45 
46 #include <vm/vm.h>
47 #include <sys/lock.h>
48 #include <vm/pmap.h>
49 #include <vm/vm_map.h>
50 #include <vm/vm_page.h>
51 #include <vm/vm_object.h>
52 
53 #include <machine/limits.h>
54 
55 int
56 procfs_domap(struct proc *curp, struct lwp *lp, struct pfsnode *pfs,
57 	     struct uio *uio)
58 {
59 	struct proc *p = lp->lwp_proc;
60 	ssize_t buflen = uio->uio_offset + uio->uio_resid;
61 	struct vnode *vp;
62 	char *fullpath, *freepath;
63 	int error;
64 	vm_map_t map = &p->p_vmspace->vm_map;
65 	vm_map_entry_t entry;
66 	struct sbuf *sb = NULL;
67 	unsigned int last_timestamp;
68 
69 	if (uio->uio_rw != UIO_READ)
70 		return (EOPNOTSUPP);
71 
72 	error = 0;
73 
74 	if (uio->uio_offset < 0 || uio->uio_resid < 0 || buflen >= INT_MAX)
75 		return EINVAL;
76 	sb = sbuf_new (sb, NULL, buflen+1, 0);
77 	if (sb == NULL)
78 		return EIO;
79 
80 	/*
81 	 * Lock the map so we can access it.  Release the process token
82 	 * to avoid unnecessary token stalls while we are processing the
83 	 * map.
84 	 */
85 	vm_map_lock_read(map);
86 	lwkt_reltoken(&p->p_token);
87 
88 	RB_FOREACH(entry, vm_map_rb_tree, &map->rb_root) {
89 		vm_object_t obj, tobj, lobj;
90 		int ref_count, shadow_count, flags;
91 		vm_offset_t e_start, e_end;
92 		vm_eflags_t e_eflags;
93 		vm_prot_t e_prot;
94 		int resident, privateresident;
95 		char *type;
96 
97 		privateresident = 0;
98 		switch(entry->maptype) {
99 		case VM_MAPTYPE_NORMAL:
100 		case VM_MAPTYPE_VPAGETABLE:
101 			obj = entry->object.vm_object;
102 			if (obj != NULL) {
103 				vm_object_hold(obj);
104 				if (obj->shadow_count == 1)
105 					privateresident = obj->resident_page_count;
106 			}
107 			break;
108 		case VM_MAPTYPE_UKSMAP:
109 			obj = NULL;
110 			break;
111 		default:
112 			/* ignore entry */
113 			continue;
114 		}
115 
116 		e_eflags = entry->eflags;
117 		e_prot = entry->protection;
118 		e_start = entry->start;
119 		e_end = entry->end;
120 
121 		/*
122 		 * Don't count resident pages, its impossible on 64-bit.
123 		 * A single mapping could be gigabytes or terrabytes.
124 		 */
125 		resident = -1;
126 #if 0
127 		pmap_t pmap = vmspace_pmap(p->p_vmspace);
128 		vm_offset_t addr;
129 
130 		resident = 0;
131 		addr = entry->start;
132 		while (addr < entry->end) {
133 			if (pmap_extract(pmap, addr, NULL))
134 				resident++;
135 			addr += PAGE_SIZE;
136 		}
137 #endif
138 		if (obj) {
139 			lobj = obj;
140 			while ((tobj = lobj->backing_object) != NULL) {
141 				KKASSERT(tobj != obj);
142 				vm_object_hold(tobj);
143 				if (tobj == lobj->backing_object) {
144 					if (lobj != obj) {
145 						vm_object_lock_swap();
146 						vm_object_drop(lobj);
147 					}
148 					lobj = tobj;
149 				} else {
150 					vm_object_drop(tobj);
151 				}
152 			}
153 		} else {
154 			lobj = NULL;
155 		}
156 		last_timestamp = map->timestamp;
157 		vm_map_unlock(map);
158 
159 		freepath = NULL;
160 		fullpath = "-";
161 		if (lobj) {
162 			switch(lobj->type) {
163 			default:
164 			case OBJT_DEFAULT:
165 				type = "default";
166 				vp = NULL;
167 				break;
168 			case OBJT_VNODE:
169 				type = "vnode";
170 				vp = lobj->handle;
171 				vref(vp);
172 				break;
173 			case OBJT_SWAP:
174 				type = "swap";
175 				vp = NULL;
176 				break;
177 			case OBJT_DEVICE:
178 				type = "device";
179 				vp = NULL;
180 				break;
181 			case OBJT_MGTDEVICE:
182 				type = "mgtdevice";
183 				vp = NULL;
184 				break;
185 			}
186 			if (lobj != obj)
187 				vm_object_drop(lobj);
188 
189 			flags = obj->flags;
190 			ref_count = obj->ref_count;
191 			shadow_count = obj->shadow_count;
192 			vm_object_drop(obj);
193 			if (vp != NULL) {
194 				vn_fullpath(p, vp, &fullpath, &freepath, 1);
195 				vrele(vp);
196 			}
197 		} else {
198 			flags = 0;
199 			ref_count = 0;
200 			shadow_count = 0;
201 			switch(entry->maptype) {
202 			case VM_MAPTYPE_UNSPECIFIED:
203 				type = "unspec";
204 				break;
205 			case VM_MAPTYPE_NORMAL:
206 				type = "none";
207 				break;
208 			case VM_MAPTYPE_VPAGETABLE:
209 				type = "vpgtbl";
210 				break;
211 			case VM_MAPTYPE_SUBMAP:
212 				type = "submap";
213 				break;
214 			case VM_MAPTYPE_UKSMAP:
215 				type = "uksmap";
216 				break;
217 			default:
218 				type = "unknown";
219 				break;
220 			}
221 		}
222 
223 		/*
224 		 * format:
225 		 *  start, end, res, priv res, cow, access, type, (fullpath).
226 		 */
227 		error = sbuf_printf(sb,
228 #if LONG_BIT == 64
229 			  "0x%016lx 0x%016lx %d %d %p %s%s%s %d %d "
230 #else
231 			  "0x%08lx 0x%08lx %d %d %p %s%s%s %d %d "
232 #endif
233 			  "0x%04x %s %s %s %s\n",
234 			(u_long)e_start, (u_long)e_end,
235 			resident, privateresident, obj,
236 			(e_prot & VM_PROT_READ)?"r":"-",
237 			(e_prot & VM_PROT_WRITE)?"w":"-",
238 			(e_prot & VM_PROT_EXECUTE)?"x":"-",
239 			ref_count, shadow_count, flags,
240 			(e_eflags & MAP_ENTRY_COW)?"COW":"NCOW",
241 			(e_eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC",
242 			type, fullpath);
243 
244 		if (freepath != NULL) {
245 			kfree(freepath, M_TEMP);
246 			freepath = NULL;
247 		}
248 
249 		vm_map_lock_read(map);
250 		if (error == -1) {
251 			error = 0;
252 			break;
253 		}
254 
255 		if (last_timestamp != map->timestamp) {
256 			vm_map_entry_t reentry;
257 			vm_map_lookup_entry(map, e_start, &reentry);
258 			entry = reentry;
259 		}
260 	}
261 	vm_map_unlock_read(map);
262 	if (sbuf_finish(sb) == 0)
263 		buflen = sbuf_len(sb);
264 	error = uiomove_frombuf(sbuf_data(sb), buflen, uio);
265 	sbuf_delete(sb);
266 
267 	lwkt_gettoken(&p->p_token);	/* re-acquire */
268 
269 	return error;
270 }
271 
272 int
273 procfs_validmap(struct lwp *lp)
274 {
275 	return ((lp->lwp_proc->p_flags & P_SYSTEM) == 0);
276 }
277