| @@ -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 | | 72 | static kmutex_t fdcache_lock; |
73 | #define FDL_LOCKED 0x02 | | | |
74 | static int fdcache_lock; | | | |
75 | | | 73 | |
76 | dev_t devctty; | | 74 | dev_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) |
79 | FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 | | 77 | FD_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]) |
86 | LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; | | 84 | LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; |
87 | u_long fdhash; | | 85 | u_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 | */ |
182 | void | | 180 | void |
183 | fdesc_init(void) | | 181 | fdesc_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 | */ |
196 | void | | 195 | void |
197 | fdesc_done(void) | | 196 | fdesc_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 | */ |
205 | int | | 205 | int |
206 | fdesc_allocvp(fdntype ftype, int ix, struct mount *mp, struct vnode **vpp) | | 206 | fdesc_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); |
213 | loop: | | 213 | loop: |
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 | |
248 | out:; | | 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 | */ |
263 | int | | 263 | int |
264 | fdesc_lookup(void *v) | | 264 | fdesc_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 | |
950 | int | | 950 | int |
951 | fdesc_reclaim(void *v) | | 951 | fdesc_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 | */ |
969 | int | | 971 | int |
970 | fdesc_pathconf(void *v) | | 972 | fdesc_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; |