Fri Jul 16 10:41:12 2010 UTC ()
Use a kmutex to protect the hash chains and always take this mutex
before removing a node from the hash chain.

Release the hash list lock before calling getnewvnode() and check the
hash list again like other file systems do.

Take v_interlock before calling vget().


(hannken)
diff -r1.110 -r1.111 src/sys/miscfs/fdesc/fdesc_vnops.c

cvs diff -r1.110 -r1.111 src/sys/miscfs/fdesc/fdesc_vnops.c (expand / switch to unified diff)

--- src/sys/miscfs/fdesc/fdesc_vnops.c 2010/06/24 13:03:12 1.110
+++ src/sys/miscfs/fdesc/fdesc_vnops.c 2010/07/16 10:41:12 1.111
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: fdesc_vnops.c,v 1.110 2010/06/24 13:03:12 hannken Exp $ */ 1/* $NetBSD: fdesc_vnops.c,v 1.111 2010/07/16 10:41:12 hannken Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1992, 1993 4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software donated to Berkeley by 7 * This code is derived from software donated to Berkeley by
8 * Jan-Simon Pendry. 8 * Jan-Simon Pendry.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -31,27 +31,27 @@ @@ -31,27 +31,27 @@
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 * 33 *
34 * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95 34 * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95
35 * 35 *
36 * #Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp # 36 * #Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp #
37 */ 37 */
38 38
39/* 39/*
40 * /dev/fd Filesystem 40 * /dev/fd Filesystem
41 */ 41 */
42 42
43#include <sys/cdefs.h> 43#include <sys/cdefs.h>
44__KERNEL_RCSID(0, "$NetBSD: fdesc_vnops.c,v 1.110 2010/06/24 13:03:12 hannken Exp $"); 44__KERNEL_RCSID(0, "$NetBSD: fdesc_vnops.c,v 1.111 2010/07/16 10:41:12 hannken Exp $");
45 45
46#include <sys/param.h> 46#include <sys/param.h>
47#include <sys/systm.h> 47#include <sys/systm.h>
48#include <sys/time.h> 48#include <sys/time.h>
49#include <sys/proc.h> 49#include <sys/proc.h>
50#include <sys/kernel.h> /* boottime */ 50#include <sys/kernel.h> /* boottime */
51#include <sys/resourcevar.h> 51#include <sys/resourcevar.h>
52#include <sys/socketvar.h> 52#include <sys/socketvar.h>
53#include <sys/filedesc.h> 53#include <sys/filedesc.h>
54#include <sys/vnode.h> 54#include <sys/vnode.h>
55#include <sys/malloc.h> 55#include <sys/malloc.h>
56#include <sys/conf.h> 56#include <sys/conf.h>
57#include <sys/file.h> 57#include <sys/file.h>
@@ -59,29 +59,27 @@ __KERNEL_RCSID(0, "$NetBSD: fdesc_vnops. @@ -59,29 +59,27 @@ __KERNEL_RCSID(0, "$NetBSD: fdesc_vnops.
59#include <sys/mount.h> 59#include <sys/mount.h>
60#include <sys/namei.h> 60#include <sys/namei.h>
61#include <sys/buf.h> 61#include <sys/buf.h>
62#include <sys/dirent.h> 62#include <sys/dirent.h>
63#include <sys/tty.h> 63#include <sys/tty.h>
64#include <sys/kauth.h> 64#include <sys/kauth.h>
65#include <sys/atomic.h> 65#include <sys/atomic.h>
66 66
67#include <miscfs/fdesc/fdesc.h> 67#include <miscfs/fdesc/fdesc.h>
68#include <miscfs/genfs/genfs.h> 68#include <miscfs/genfs/genfs.h>
69 69
70#define cttyvp(p) ((p)->p_lflag & PL_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 70#define cttyvp(p) ((p)->p_lflag & PL_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
71 71
72#define FDL_WANT 0x01 72static kmutex_t fdcache_lock;
73#define FDL_LOCKED 0x02 
74static int fdcache_lock; 
75 73
76dev_t devctty; 74dev_t devctty;
77 75
78#if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) 76#if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
79FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 77FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
80#endif 78#endif
81 79
82#define NFDCACHE 4 80#define NFDCACHE 4
83 81
84#define FD_NHASH(ix) \ 82#define FD_NHASH(ix) \
85 (&fdhashtbl[(ix) & fdhash]) 83 (&fdhashtbl[(ix) & fdhash])
86LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; 84LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
87u_long fdhash; 85u_long fdhash;
@@ -177,93 +175,95 @@ const struct vnodeopv_desc fdesc_vnodeop @@ -177,93 +175,95 @@ const struct vnodeopv_desc fdesc_vnodeop
177 { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 175 { &fdesc_vnodeop_p, fdesc_vnodeop_entries };
178 176
179/* 177/*
180 * Initialise cache headers 178 * Initialise cache headers
181 */ 179 */
182void 180void
183fdesc_init(void) 181fdesc_init(void)
184{ 182{
185 int cttymajor; 183 int cttymajor;
186 184
187 /* locate the major number */ 185 /* locate the major number */
188 cttymajor = devsw_name2chr("ctty", NULL, 0); 186 cttymajor = devsw_name2chr("ctty", NULL, 0);
189 devctty = makedev(cttymajor, 0); 187 devctty = makedev(cttymajor, 0);
 188 mutex_init(&fdcache_lock, MUTEX_DEFAULT, IPL_NONE);
190 fdhashtbl = hashinit(NFDCACHE, HASH_LIST, true, &fdhash); 189 fdhashtbl = hashinit(NFDCACHE, HASH_LIST, true, &fdhash);
191} 190}
192 191
193/* 192/*
194 * Free hash table. 193 * Free hash table.
195 */ 194 */
196void 195void
197fdesc_done(void) 196fdesc_done(void)
198{ 197{
199 hashdone(fdhashtbl, HASH_LIST, fdhash); 198 hashdone(fdhashtbl, HASH_LIST, fdhash);
 199 mutex_destroy(&fdcache_lock);
200} 200}
201 201
202/* 202/*
203 * Return a locked vnode of the correct type. 203 * Return a locked vnode of the correct type.
204 */ 204 */
205int 205int
206fdesc_allocvp(fdntype ftype, int ix, struct mount *mp, struct vnode **vpp) 206fdesc_allocvp(fdntype ftype, int ix, struct mount *mp, struct vnode **vpp)
207{ 207{
208 struct fdhashhead *fc; 208 struct fdhashhead *fc;
209 struct fdescnode *fd; 209 struct fdescnode *fd;
210 int error = 0; 210 int error = 0;
211 211
212 fc = FD_NHASH(ix); 212 fc = FD_NHASH(ix);
213loop: 213loop:
214 for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { 214 mutex_enter(&fdcache_lock);
 215 LIST_FOREACH(fd, fc, fd_hash) {
215 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 216 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
216 if (vget(fd->fd_vnode, LK_EXCLUSIVE)) 217 mutex_enter(&fd->fd_vnode->v_interlock);
 218 mutex_exit(&fdcache_lock);
 219 if (vget(fd->fd_vnode, LK_INTERLOCK | LK_EXCLUSIVE))
217 goto loop; 220 goto loop;
218 *vpp = fd->fd_vnode; 221 *vpp = fd->fd_vnode;
219 return (error); 222 return 0;
220 } 223 }
221 } 224 }
222 225 mutex_exit(&fdcache_lock);
223 /* 
224 * otherwise lock the array while we call getnewvnode 
225 * since that can block. 
226 */ 
227 if (fdcache_lock & FDL_LOCKED) { 
228 fdcache_lock |= FDL_WANT; 
229 (void) tsleep(&fdcache_lock, PINOD, "fdcache", 0); 
230 goto loop; 
231 } 
232 fdcache_lock |= FDL_LOCKED; 
233 226
234 error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); 227 error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
235 if (error) 228 if (error)
236 goto out; 229 return error;
 230
 231 mutex_enter(&fdcache_lock);
 232 LIST_FOREACH(fd, fc, fd_hash) {
 233 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
 234 /*
 235 * Another thread beat us, push back freshly
 236 * allocated vnode and retry.
 237 */
 238 mutex_exit(&fdcache_lock);
 239 ungetnewvnode(*vpp);
 240 goto loop;
 241 }
 242 }
 243
237 fd = malloc(sizeof(struct fdescnode), M_TEMP, M_WAITOK); 244 fd = malloc(sizeof(struct fdescnode), M_TEMP, M_WAITOK);
238 (*vpp)->v_data = fd; 245 (*vpp)->v_data = fd;
239 fd->fd_vnode = *vpp; 246 fd->fd_vnode = *vpp;
240 fd->fd_type = ftype; 247 fd->fd_type = ftype;
241 fd->fd_fd = -1; 248 fd->fd_fd = -1;
242 fd->fd_link = 0; 249 fd->fd_link = 0;
243 fd->fd_ix = ix; 250 fd->fd_ix = ix;
244 uvm_vnp_setsize(*vpp, 0); 251 uvm_vnp_setsize(*vpp, 0);
245 VOP_LOCK(*vpp, LK_EXCLUSIVE); 252 VOP_LOCK(*vpp, LK_EXCLUSIVE);
246 LIST_INSERT_HEAD(fc, fd, fd_hash); 253 LIST_INSERT_HEAD(fc, fd, fd_hash);
 254 mutex_exit(&fdcache_lock);
247 255
248out:; 256 return 0;
249 fdcache_lock &= ~FDL_LOCKED; 
250 
251 if (fdcache_lock & FDL_WANT) { 
252 fdcache_lock &= ~FDL_WANT; 
253 wakeup(&fdcache_lock); 
254 } 
255 
256 return (error); 
257} 257}
258 258
259/* 259/*
260 * vp is the current namei directory 260 * vp is the current namei directory
261 * ndp is the name to locate in that directory... 261 * ndp is the name to locate in that directory...
262 */ 262 */
263int 263int
264fdesc_lookup(void *v) 264fdesc_lookup(void *v)
265{ 265{
266 struct vop_lookup_args /* { 266 struct vop_lookup_args /* {
267 struct vnode * a_dvp; 267 struct vnode * a_dvp;
268 struct vnode ** a_vpp; 268 struct vnode ** a_vpp;
269 struct componentname * a_cnp; 269 struct componentname * a_cnp;
@@ -946,29 +946,31 @@ fdesc_inactive(void *v) @@ -946,29 +946,31 @@ fdesc_inactive(void *v)
946 vp->v_type = VNON; 946 vp->v_type = VNON;
947 return (0); 947 return (0);
948} 948}
949 949
950int 950int
951fdesc_reclaim(void *v) 951fdesc_reclaim(void *v)
952{ 952{
953 struct vop_reclaim_args /* { 953 struct vop_reclaim_args /* {
954 struct vnode *a_vp; 954 struct vnode *a_vp;
955 } */ *ap = v; 955 } */ *ap = v;
956 struct vnode *vp = ap->a_vp; 956 struct vnode *vp = ap->a_vp;
957 struct fdescnode *fd = VTOFDESC(vp); 957 struct fdescnode *fd = VTOFDESC(vp);
958 958
 959 mutex_enter(&fdcache_lock);
959 LIST_REMOVE(fd, fd_hash); 960 LIST_REMOVE(fd, fd_hash);
960 free(vp->v_data, M_TEMP); 961 free(vp->v_data, M_TEMP);
961 vp->v_data = 0; 962 vp->v_data = 0;
 963 mutex_exit(&fdcache_lock);
962 964
963 return (0); 965 return (0);
964} 966}
965 967
966/* 968/*
967 * Return POSIX pathconf information applicable to special devices. 969 * Return POSIX pathconf information applicable to special devices.
968 */ 970 */
969int 971int
970fdesc_pathconf(void *v) 972fdesc_pathconf(void *v)
971{ 973{
972 struct vop_pathconf_args /* { 974 struct vop_pathconf_args /* {
973 struct vnode *a_vp; 975 struct vnode *a_vp;
974 int a_name; 976 int a_name;