1 /* $NetBSD: ptyfs_subr.c,v 1.17 2008/12/17 20:51:35 cegger Exp $ */
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)ptyfs_subr.c 8.6 (Berkeley) 5/14/95
38 * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
39 * Copyright (c) 1993 Jan-Simon Pendry
41 * This code is derived from software contributed to Berkeley by
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
75 #include <sys/cdefs.h>
76 __KERNEL_RCSID(0, "$NetBSD: ptyfs_subr.c,v 1.17 2008/12/17 20:51:35 cegger Exp $");
78 #include <sys/param.h>
79 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/vnode.h>
84 #include <sys/malloc.h>
86 #include <sys/namei.h>
87 #include <sys/filedesc.h>
88 #include <sys/select.h>
91 #include <sys/kauth.h>
94 #include <fs/ptyfs/ptyfs.h>
95 #include <miscfs/specfs/specdev.h>
97 static kmutex_t ptyfs_hashlock
;
99 static LIST_HEAD(ptyfs_hashhead
, ptyfsnode
) *ptyfs_used_tbl
, *ptyfs_free_tbl
;
100 static u_long ptyfs_used_mask
, ptyfs_free_mask
; /* size of hash table - 1 */
101 static kmutex_t ptyfs_used_slock
, ptyfs_free_slock
;
103 static void ptyfs_getinfo(struct ptyfsnode
*, struct lwp
*);
105 static void ptyfs_hashins(struct ptyfsnode
*);
106 static void ptyfs_hashrem(struct ptyfsnode
*);
108 static struct vnode
*ptyfs_used_get(ptyfstype
, int, struct mount
*, int);
109 static struct ptyfsnode
*ptyfs_free_get(ptyfstype
, int, struct lwp
*);
111 static void ptyfs_rehash(kmutex_t
*, struct ptyfs_hashhead
**,
114 #define PTYHASH(type, pty, mask) (PTYFS_FILENO(type, pty) % (mask + 1))
118 ptyfs_getinfo(struct ptyfsnode
*ptyfs
, struct lwp
*l
)
120 extern struct ptm_pty
*ptyfs_save_ptm
, ptm_ptyfspty
;
122 if (ptyfs
->ptyfs_type
== PTYFSroot
) {
123 ptyfs
->ptyfs_mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|
127 ptyfs
->ptyfs_mode
= S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|
130 if (ptyfs_save_ptm
!= NULL
&& ptyfs_save_ptm
!= &ptm_ptyfspty
) {
137 * We support traditional ptys, so we copy the info
140 if ((error
= (*ptyfs_save_ptm
->makename
)(
141 ptyfs_save_ptm
, l
, ttyname
, sizeof(ttyname
),
142 ptyfs
->ptyfs_pty
, ptyfs
->ptyfs_type
== PTYFSpts
? 't'
145 NDINIT(&nd
, LOOKUP
, NOFOLLOW
|LOCKLEAF
, UIO_SYSSPACE
, ttyname
);
146 if ((error
= namei(&nd
)) != 0)
148 cred
= kauth_cred_alloc();
149 error
= VOP_GETATTR(nd
.ni_vp
, &va
, cred
);
150 kauth_cred_free(cred
);
151 VOP_UNLOCK(nd
.ni_vp
, 0);
155 ptyfs
->ptyfs_uid
= va
.va_uid
;
156 ptyfs
->ptyfs_gid
= va
.va_gid
;
157 ptyfs
->ptyfs_mode
= va
.va_mode
;
158 ptyfs
->ptyfs_flags
= va
.va_flags
;
159 ptyfs
->ptyfs_birthtime
= va
.va_birthtime
;
160 ptyfs
->ptyfs_ctime
= va
.va_ctime
;
161 ptyfs
->ptyfs_mtime
= va
.va_mtime
;
162 ptyfs
->ptyfs_atime
= va
.va_atime
;
166 ptyfs
->ptyfs_uid
= ptyfs
->ptyfs_gid
= 0;
167 ptyfs
->ptyfs_flags
|= PTYFS_CHANGE
;
168 PTYFS_ITIMES(ptyfs
, NULL
, NULL
, NULL
);
169 ptyfs
->ptyfs_birthtime
= ptyfs
->ptyfs_mtime
=
170 ptyfs
->ptyfs_atime
= ptyfs
->ptyfs_ctime
;
171 ptyfs
->ptyfs_flags
= 0;
176 * allocate a ptyfsnode/vnode pair. the vnode is
177 * referenced, and locked.
179 * the pid, ptyfs_type, and mount point uniquely
180 * identify a ptyfsnode. the mount point is needed
181 * because someone might mount this filesystem
184 * all ptyfsnodes are maintained on a singly-linked
185 * list. new nodes are only allocated when they cannot
186 * be found on this list. entries on the list are
187 * removed when the vfs reclaim entry is called.
189 * a single lock is kept for the entire list. this is
190 * needed because the getnewvnode() function can block
191 * waiting for a vnode to become free, in which case there
192 * may be more than one ptyess trying to get the same
193 * vnode. this lock is only taken if we are going to
194 * call getnewvnode, since the kernel itself is single-threaded.
196 * if an entry is found on the list, then call vget() to
197 * take a reference. this is done because there may be
198 * zero references to it and so it needs to removed from
199 * the vnode free list.
202 ptyfs_allocvp(struct mount
*mp
, struct vnode
**vpp
, ptyfstype type
, int pty
,
205 struct ptyfsnode
*ptyfs
;
210 if ((*vpp
= ptyfs_used_get(type
, pty
, mp
, LK_EXCLUSIVE
)) != NULL
)
213 if ((error
= getnewvnode(VT_PTYFS
, mp
, ptyfs_vnodeop_p
, &vp
)) != 0) {
218 mutex_enter(&ptyfs_hashlock
);
219 if (ptyfs_used_get(type
, pty
, mp
, 0) != NULL
) {
220 mutex_exit(&ptyfs_hashlock
);
225 vp
->v_data
= ptyfs
= ptyfs_free_get(type
, pty
, l
);
226 ptyfs
->ptyfs_vnode
= vp
;
229 case PTYFSroot
: /* /pts = dr-xr-xr-x */
231 vp
->v_vflag
= VV_ROOT
;
234 case PTYFSpts
: /* /pts/N = cxxxxxxxxx */
235 case PTYFSptc
: /* controlling side = cxxxxxxxxx */
237 spec_node_init(vp
, PTYFS_MAKEDEV(ptyfs
));
240 panic("ptyfs_allocvp");
243 ptyfs_hashins(ptyfs
);
244 uvm_vnp_setsize(vp
, 0);
245 mutex_exit(&ptyfs_hashlock
);
252 ptyfs_freevp(struct vnode
*vp
)
254 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
256 ptyfs_hashrem(ptyfs
);
262 * Initialize ptyfsnode hash table.
267 ptyfs_used_tbl
= hashinit(desiredvnodes
/ 4, HASH_LIST
, true,
269 ptyfs_free_tbl
= hashinit(desiredvnodes
/ 4, HASH_LIST
, true,
271 mutex_init(&ptyfs_hashlock
, MUTEX_DEFAULT
, IPL_NONE
);
272 mutex_init(&ptyfs_used_slock
, MUTEX_DEFAULT
, IPL_NONE
);
273 mutex_init(&ptyfs_free_slock
, MUTEX_DEFAULT
, IPL_NONE
);
277 ptyfs_hashreinit(void)
279 ptyfs_rehash(&ptyfs_used_slock
, &ptyfs_used_tbl
, &ptyfs_used_mask
);
280 ptyfs_rehash(&ptyfs_free_slock
, &ptyfs_free_tbl
, &ptyfs_free_mask
);
284 ptyfs_rehash(kmutex_t
*hlock
, struct ptyfs_hashhead
**hhead
,
287 struct ptyfsnode
*pp
;
288 struct ptyfs_hashhead
*oldhash
, *hash
;
289 u_long i
, oldmask
, mask
, val
;
291 hash
= hashinit(desiredvnodes
/ 4, HASH_LIST
, true, &mask
);
298 for (i
= 0; i
<= oldmask
; i
++) {
299 while ((pp
= LIST_FIRST(&oldhash
[i
])) != NULL
) {
300 LIST_REMOVE(pp
, ptyfs_hash
);
301 val
= PTYHASH(pp
->ptyfs_type
, pp
->ptyfs_pty
,
303 LIST_INSERT_HEAD(&hash
[val
], pp
, ptyfs_hash
);
307 hashdone(oldhash
, HASH_LIST
, oldmask
);
311 * Free ptyfsnode hash table.
317 mutex_destroy(&ptyfs_hashlock
);
318 mutex_destroy(&ptyfs_used_slock
);
319 mutex_destroy(&ptyfs_free_slock
);
320 hashdone(ptyfs_used_tbl
, HASH_LIST
, ptyfs_used_mask
);
321 hashdone(ptyfs_free_tbl
, HASH_LIST
, ptyfs_free_mask
);
325 * Get a ptyfsnode from the free table, or allocate one.
326 * Removes the node from the free table.
329 ptyfs_free_get(ptyfstype type
, int pty
, struct lwp
*l
)
331 struct ptyfs_hashhead
*ppp
;
332 struct ptyfsnode
*pp
;
334 mutex_enter(&ptyfs_free_slock
);
335 ppp
= &ptyfs_free_tbl
[PTYHASH(type
, pty
, ptyfs_free_mask
)];
336 LIST_FOREACH(pp
, ppp
, ptyfs_hash
) {
337 if (pty
== pp
->ptyfs_pty
&& pp
->ptyfs_type
== type
) {
338 LIST_REMOVE(pp
, ptyfs_hash
);
339 mutex_exit(&ptyfs_free_slock
);
343 mutex_exit(&ptyfs_free_slock
);
345 pp
= malloc(sizeof(struct ptyfsnode
), M_TEMP
, M_WAITOK
);
347 pp
->ptyfs_type
= type
;
348 pp
->ptyfs_fileno
= PTYFS_FILENO(pty
, type
);
349 ptyfs_getinfo(pp
, l
);
354 ptyfs_used_get(ptyfstype type
, int pty
, struct mount
*mp
, int flags
)
356 struct ptyfs_hashhead
*ppp
;
357 struct ptyfsnode
*pp
;
361 mutex_enter(&ptyfs_used_slock
);
362 ppp
= &ptyfs_used_tbl
[PTYHASH(type
, pty
, ptyfs_used_mask
)];
363 LIST_FOREACH(pp
, ppp
, ptyfs_hash
) {
365 if (pty
== pp
->ptyfs_pty
&& pp
->ptyfs_type
== type
&&
368 mutex_exit(&ptyfs_used_slock
);
370 mutex_enter(&vp
->v_interlock
);
371 mutex_exit(&ptyfs_used_slock
);
372 if (vget(vp
, flags
| LK_INTERLOCK
))
378 mutex_exit(&ptyfs_used_slock
);
383 * Insert the ptyfsnode into the used table and lock it.
386 ptyfs_hashins(struct ptyfsnode
*pp
)
388 struct ptyfs_hashhead
*ppp
;
390 /* lock the ptyfsnode, then put it on the appropriate hash list */
391 vlockmgr(&pp
->ptyfs_vnode
->v_lock
, LK_EXCLUSIVE
);
393 mutex_enter(&ptyfs_used_slock
);
394 ppp
= &ptyfs_used_tbl
[PTYHASH(pp
->ptyfs_type
, pp
->ptyfs_pty
,
396 LIST_INSERT_HEAD(ppp
, pp
, ptyfs_hash
);
397 mutex_exit(&ptyfs_used_slock
);
401 * Remove the ptyfsnode from the used table, and add it to the free table
404 ptyfs_hashrem(struct ptyfsnode
*pp
)
406 struct ptyfs_hashhead
*ppp
;
408 mutex_enter(&ptyfs_used_slock
);
409 LIST_REMOVE(pp
, ptyfs_hash
);
410 mutex_exit(&ptyfs_used_slock
);
412 mutex_enter(&ptyfs_free_slock
);
413 ppp
= &ptyfs_free_tbl
[PTYHASH(pp
->ptyfs_type
, pp
->ptyfs_pty
,
415 LIST_INSERT_HEAD(ppp
, pp
, ptyfs_hash
);
416 mutex_exit(&ptyfs_free_slock
);