pseudofs_vncache.c (167497) | pseudofs_vncache.c (168637) |
---|---|
1/*- 2 * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/sys/fs/pseudofs/pseudofs_vncache.c 167497 2007-03-13 01:50:27Z tegge $"); | 30__FBSDID("$FreeBSD: head/sys/fs/pseudofs/pseudofs_vncache.c 168637 2007-04-11 22:40:57Z des $"); |
31 32#include "opt_pseudofs.h" 33 34#include <sys/param.h> 35#include <sys/kernel.h> 36#include <sys/systm.h> 37#include <sys/eventhandler.h> 38#include <sys/lock.h> --- 83 unchanged lines hidden (view full) --- 122 if (pvd->pvd_pn == pn && pvd->pvd_pid == pid && 123 pvd->pvd_vnode->v_mount == mp) { 124 vp = pvd->pvd_vnode; 125 VI_LOCK(vp); 126 mtx_unlock(&pfs_vncache_mutex); 127 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, curthread) == 0) { 128 ++pfs_vncache_hits; 129 *vpp = vp; | 31 32#include "opt_pseudofs.h" 33 34#include <sys/param.h> 35#include <sys/kernel.h> 36#include <sys/systm.h> 37#include <sys/eventhandler.h> 38#include <sys/lock.h> --- 83 unchanged lines hidden (view full) --- 122 if (pvd->pvd_pn == pn && pvd->pvd_pid == pid && 123 pvd->pvd_vnode->v_mount == mp) { 124 vp = pvd->pvd_vnode; 125 VI_LOCK(vp); 126 mtx_unlock(&pfs_vncache_mutex); 127 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, curthread) == 0) { 128 ++pfs_vncache_hits; 129 *vpp = vp; |
130 /* XXX see comment at top of pfs_lookup() */ 131 cache_purge(vp); | 130 /* 131 * Some callers cache_enter(vp) later, so 132 * we have to make sure it's not in the 133 * VFS cache so it doesn't get entered 134 * twice. A better solution would be to 135 * make pfs_vncache_alloc() responsible 136 * for entering the vnode in the VFS 137 * cache. 138 */ 139 cache_purge(vp); |
132 return (0); 133 } 134 goto retry; 135 } 136 } 137 mtx_unlock(&pfs_vncache_mutex); 138 ++pfs_vncache_misses; 139 --- 79 unchanged lines hidden (view full) --- 219 220 --pfs_vncache_entries; 221 FREE(pvd, M_PFSVNCACHE); 222 vp->v_data = NULL; 223 return (0); 224} 225 226/* | 140 return (0); 141 } 142 goto retry; 143 } 144 } 145 mtx_unlock(&pfs_vncache_mutex); 146 ++pfs_vncache_misses; 147 --- 79 unchanged lines hidden (view full) --- 227 228 --pfs_vncache_entries; 229 FREE(pvd, M_PFSVNCACHE); 230 vp->v_data = NULL; 231 return (0); 232} 233 234/* |
227 * Free all vnodes associated with a defunct process | 235 * Purge the cache of dead / disabled entries |
228 * | 236 * |
229 * XXXRW: It is unfortunate that pfs_exit() always acquires and releases two 230 * mutexes (one of which is Giant) for every process exit, even if procfs 231 * isn't mounted. | 237 * This is extremely inefficient due to the fact that vgone() not only 238 * indirectly modifies the vnode cache, but may also sleep. We can 239 * neither hold pfs_vncache_mutex across a vgone() call, nor make any 240 * assumptions about the state of the cache after vgone() returns. In 241 * consequence, we must start over after every vgone() call, and keep 242 * trying until we manage to traverse the entire cache. 243 * 244 * The only way to improve this situation is to change the data structure 245 * used to implement the cache. |
232 */ | 246 */ |
233static void 234pfs_exit(void *arg, struct proc *p) | 247void 248pfs_purge(struct pfs_node *pn) |
235{ 236 struct pfs_vdata *pvd; 237 struct vnode *vnp; 238 | 249{ 250 struct pfs_vdata *pvd; 251 struct vnode *vnp; 252 |
239 if (pfs_vncache == NULL) 240 return; 241 mtx_lock(&Giant); 242 /* 243 * This is extremely inefficient due to the fact that vgone() not 244 * only indirectly modifies the vnode cache, but may also sleep. 245 * We can neither hold pfs_vncache_mutex across a vgone() call, 246 * nor make any assumptions about the state of the cache after 247 * vgone() returns. In consequence, we must start over after 248 * every vgone() call, and keep trying until we manage to traverse 249 * the entire cache. 250 * 251 * The only way to improve this situation is to change the data 252 * structure used to implement the cache. An obvious choice in 253 * this particular case would be a BST sorted by PID. 254 */ | |
255 mtx_lock(&pfs_vncache_mutex); 256 pvd = pfs_vncache; 257 while (pvd != NULL) { | 253 mtx_lock(&pfs_vncache_mutex); 254 pvd = pfs_vncache; 255 while (pvd != NULL) { |
258 if (pvd->pvd_pid == p->p_pid) { | 256 if (pvd->pvd_dead || (pn != NULL && pvd->pvd_pn == pn)) { |
259 vnp = pvd->pvd_vnode; 260 vhold(vnp); 261 mtx_unlock(&pfs_vncache_mutex); 262 VOP_LOCK(vnp, LK_EXCLUSIVE, curthread); 263 vgone(vnp); 264 VOP_UNLOCK(vnp, 0, curthread); 265 vdrop(vnp); 266 mtx_lock(&pfs_vncache_mutex); 267 pvd = pfs_vncache; 268 } else { 269 pvd = pvd->pvd_next; 270 } 271 } 272 mtx_unlock(&pfs_vncache_mutex); | 257 vnp = pvd->pvd_vnode; 258 vhold(vnp); 259 mtx_unlock(&pfs_vncache_mutex); 260 VOP_LOCK(vnp, LK_EXCLUSIVE, curthread); 261 vgone(vnp); 262 VOP_UNLOCK(vnp, 0, curthread); 263 vdrop(vnp); 264 mtx_lock(&pfs_vncache_mutex); 265 pvd = pfs_vncache; 266 } else { 267 pvd = pvd->pvd_next; 268 } 269 } 270 mtx_unlock(&pfs_vncache_mutex); |
271} 272 273/* 274 * Free all vnodes associated with a defunct process 275 * 276 * XXXRW: It is unfortunate that pfs_exit() always acquires and releases two 277 * mutexes (one of which is Giant) for every process exit, even if procfs 278 * isn't mounted. 279 */ 280static void 281pfs_exit(void *arg, struct proc *p) 282{ 283 struct pfs_vdata *pvd; 284 int dead; 285 286 if (pfs_vncache == NULL) 287 return; 288 mtx_lock(&Giant); 289 mtx_lock(&pfs_vncache_mutex); 290 for (pvd = pfs_vncache, dead = 0; pvd != NULL; pvd = pvd->pvd_next) 291 if (pvd->pvd_pid == p->p_pid) 292 dead = pvd->pvd_dead = 1; 293 mtx_unlock(&pfs_vncache_mutex); 294 if (dead) 295 pfs_purge(NULL); |
|
273 mtx_unlock(&Giant); 274} 275 276/* 277 * Disable a pseudofs node, and free all vnodes associated with it 278 */ 279int 280pfs_disable(struct pfs_node *pn) 281{ | 296 mtx_unlock(&Giant); 297} 298 299/* 300 * Disable a pseudofs node, and free all vnodes associated with it 301 */ 302int 303pfs_disable(struct pfs_node *pn) 304{ |
282 struct pfs_vdata *pvd; 283 struct vnode *vnp; 284 | |
285 if (pn->pn_flags & PFS_DISABLED) 286 return (0); 287 pn->pn_flags |= PFS_DISABLED; | 305 if (pn->pn_flags & PFS_DISABLED) 306 return (0); 307 pn->pn_flags |= PFS_DISABLED; |
288 /* XXX see comment above nearly identical code in pfs_exit() */ 289 mtx_lock(&pfs_vncache_mutex); 290 pvd = pfs_vncache; 291 while (pvd != NULL) { 292 if (pvd->pvd_pn == pn) { 293 vnp = pvd->pvd_vnode; 294 vhold(vnp); 295 mtx_unlock(&pfs_vncache_mutex); 296 VOP_LOCK(vnp, LK_EXCLUSIVE, curthread); 297 vgone(vnp); 298 VOP_UNLOCK(vnp, 0, curthread); 299 vdrop(vnp); 300 mtx_lock(&pfs_vncache_mutex); 301 pvd = pfs_vncache; 302 } else { 303 pvd = pvd->pvd_next; 304 } 305 } 306 mtx_unlock(&pfs_vncache_mutex); | 308 pfs_purge(pn); |
307 return (0); 308} 309 310/* 311 * Re-enable a disabled pseudofs node 312 */ 313int 314pfs_enable(struct pfs_node *pn) 315{ 316 pn->pn_flags &= ~PFS_DISABLED; 317 return (0); 318} | 309 return (0); 310} 311 312/* 313 * Re-enable a disabled pseudofs node 314 */ 315int 316pfs_enable(struct pfs_node *pn) 317{ 318 pn->pn_flags &= ~PFS_DISABLED; 319 return (0); 320} |