Module Name: src Committed By: riz Date: Sun Aug 17 03:34:02 UTC 2014
Modified Files: src/sbin/mount_ptyfs [netbsd-7]: mount_ptyfs.8 src/sys/fs/ptyfs [netbsd-7]: ptyfs.h ptyfs_subr.c ptyfs_vfsops.c ptyfs_vnops.c Log Message: Pull up following revision(s) (requested by hannken in ticket #29): sbin/mount_ptyfs/mount_ptyfs.8: revision 1.14 sys/fs/ptyfs/ptyfs_vnops.c: revision 1.48 sys/fs/ptyfs/ptyfs_vnops.c: revision 1.49 sys/fs/ptyfs/ptyfs_subr.c: revision 1.30 sys/fs/ptyfs/ptyfs_subr.c: revision 1.31 sys/fs/ptyfs/ptyfs_vfsops.c: revision 1.51 sys/fs/ptyfs/ptyfs_subr.c: revision 1.32 sys/fs/ptyfs/ptyfs_vfsops.c: revision 1.52 sys/fs/ptyfs/ptyfs_vfsops.c: revision 1.53 sys/fs/ptyfs/ptyfs.h: revision 1.13 sys/fs/ptyfs/ptyfs.h: revision 1.14 Needs HASH_SLIST, not HASH_LIST. Change ptyfs to vcache. - Use (type, minor) as key. - Change ptyfs_allocvp to return a referenced vnode and lock where needed. - Remove unneeded vnode backpointer ptyfs_vnode. - Keep a single hashlist for pty nodes to make their attributes persistent. OK: Christos Zoulas Overflow if *data_len == OSIZE and args->version >= PTYFS_ARGSVERSION. Sent on tech-kern@, ok christos@ Adapt to reality -- already open BSD style nodes do not appear on ptyfs mounts (this changed some months ago). - Add a map of active controlling ptys per mount and no longer abuse the vnode lifecycle. - No longer set "recycle" on VOP_INACTIVE(). - Make ptyfs_used_get() private to ptyfs_subr.c - Stop copying device attributes from traditional ptys on first allocation. - Remove unneeded argument "lwp" from ptyfs_allocvp() and ptyfs_free_get(). OK: Christos Zoulas To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.13.4.1 src/sbin/mount_ptyfs/mount_ptyfs.8 cvs rdiff -u -r1.12 -r1.12.4.1 src/sys/fs/ptyfs/ptyfs.h cvs rdiff -u -r1.29 -r1.29.4.1 src/sys/fs/ptyfs/ptyfs_subr.c cvs rdiff -u -r1.50 -r1.50.2.1 src/sys/fs/ptyfs/ptyfs_vfsops.c cvs rdiff -u -r1.47 -r1.47.2.1 src/sys/fs/ptyfs/ptyfs_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sbin/mount_ptyfs/mount_ptyfs.8 diff -u src/sbin/mount_ptyfs/mount_ptyfs.8:1.13 src/sbin/mount_ptyfs/mount_ptyfs.8:1.13.4.1 --- src/sbin/mount_ptyfs/mount_ptyfs.8:1.13 Fri Apr 4 21:19:35 2014 +++ src/sbin/mount_ptyfs/mount_ptyfs.8 Sun Aug 17 03:34:02 2014 @@ -1,4 +1,4 @@ -.\" $NetBSD: mount_ptyfs.8,v 1.13 2014/04/04 21:19:35 christos Exp $ +.\" $NetBSD: mount_ptyfs.8,v 1.13.4.1 2014/08/17 03:34:02 riz Exp $ .\" .\" .\" Copyright (c) 2004, 2014 The NetBSD Foundation, Inc. @@ -28,7 +28,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 4, 2014 +.Dd August 13, 2014 .Dt MOUNT_PTYFS 8 .Os .Sh NAME @@ -57,8 +57,7 @@ at boot time. .Pp The filesystem contains pseudo-terminal slave device nodes which are allocated dynamically via -.Xr ptm 4 , -or they are already open via traditional BSD style ptys. +.Xr ptm 4 . .Pp The options are as follows: .Bl -tag -width indent Index: src/sys/fs/ptyfs/ptyfs.h diff -u src/sys/fs/ptyfs/ptyfs.h:1.12 src/sys/fs/ptyfs/ptyfs.h:1.12.4.1 --- src/sys/fs/ptyfs/ptyfs.h:1.12 Fri Apr 4 18:10:29 2014 +++ src/sys/fs/ptyfs/ptyfs.h Sun Aug 17 03:34:02 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ptyfs.h,v 1.12 2014/04/04 18:10:29 christos Exp $ */ +/* $NetBSD: ptyfs.h,v 1.12.4.1 2014/08/17 03:34:02 riz Exp $ */ /* * Copyright (c) 1993 @@ -87,11 +87,15 @@ typedef enum { /* * control data for the proc file system. */ +struct ptyfskey { + ptyfstype ptk_type; /* type of ptyfs node */ + int ptk_pty; /* the pty index */ +}; struct ptyfsnode { - LIST_ENTRY(ptyfsnode) ptyfs_hash; /* hash chain */ - struct vnode *ptyfs_vnode; /* vnode associated with this ptyfsnode */ - ptyfstype ptyfs_type; /* type of ptyfs node */ - int ptyfs_pty; /* the pty index */ + SLIST_ENTRY(ptyfsnode) ptyfs_hash; /* hash chain */ + struct ptyfskey ptyfs_key; +#define ptyfs_type ptyfs_key.ptk_type +#define ptyfs_pty ptyfs_key.ptk_pty u_long ptyfs_fileno; /* unique file id */ int ptyfs_status; /* status flag for times */ #define PTYFS_ACCESS 1 @@ -106,11 +110,14 @@ struct ptyfsnode { }; struct ptyfsmount { + kmutex_t pmnt_lock; TAILQ_ENTRY(ptyfsmount) pmnt_le; struct mount *pmnt_mp; gid_t pmnt_gid; mode_t pmnt_mode; int pmnt_flags; + int pmnt_bitmap_size; + uint8_t *pmnt_bitmap; }; #define VFSTOPTY(mp) ((struct ptyfsmount *)(mp)->mnt_data) @@ -147,15 +154,14 @@ struct ptyfs_args { * Convert between ptyfsnode vnode */ #define VTOPTYFS(vp) ((struct ptyfsnode *)(vp)->v_data) -#define PTYFSTOV(ptyfs) ((ptyfs)->ptyfs_vnode) -int ptyfs_freevp(struct vnode *); -struct vnode *ptyfs_used_get(ptyfstype, int, struct mount *, int); -int ptyfs_allocvp(struct mount *, struct vnode **, ptyfstype, int, - struct lwp *); +void ptyfs_set_active(struct mount *, int); +void ptyfs_clr_active(struct mount *, int); +int ptyfs_next_active(struct mount *, int); +int ptyfs_allocvp(struct mount *, struct vnode **, ptyfstype, int); void ptyfs_hashinit(void); -void ptyfs_hashreinit(void); void ptyfs_hashdone(void); +struct ptyfsnode *ptyfs_get_node(ptyfstype, int); void ptyfs_itimes(struct ptyfsnode *, const struct timespec *, const struct timespec *, const struct timespec *); Index: src/sys/fs/ptyfs/ptyfs_subr.c diff -u src/sys/fs/ptyfs/ptyfs_subr.c:1.29 src/sys/fs/ptyfs/ptyfs_subr.c:1.29.4.1 --- src/sys/fs/ptyfs/ptyfs_subr.c:1.29 Thu Mar 27 17:31:56 2014 +++ src/sys/fs/ptyfs/ptyfs_subr.c Sun Aug 17 03:34:02 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ptyfs_subr.c,v 1.29 2014/03/27 17:31:56 christos Exp $ */ +/* $NetBSD: ptyfs_subr.c,v 1.29.4.1 2014/08/17 03:34:02 riz Exp $ */ /* * Copyright (c) 1993 @@ -73,7 +73,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ptyfs_subr.c,v 1.29 2014/03/27 17:31:56 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ptyfs_subr.c,v 1.29.4.1 2014/08/17 03:34:02 riz Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -92,180 +92,29 @@ __KERNEL_RCSID(0, "$NetBSD: ptyfs_subr.c #include <sys/lwp.h> #include <fs/ptyfs/ptyfs.h> -#include <miscfs/specfs/specdev.h> static kmutex_t ptyfs_hashlock; -static LIST_HEAD(ptyfs_hashhead, ptyfsnode) *ptyfs_used_tbl, *ptyfs_free_tbl; -static u_long ptyfs_used_mask, ptyfs_free_mask; /* size of hash table - 1 */ -static kmutex_t ptyfs_used_slock, ptyfs_free_slock; - -static void ptyfs_getinfo(struct ptyfsnode *, struct lwp *); - -static void ptyfs_hashins(struct ptyfsnode *); -static void ptyfs_hashrem(struct ptyfsnode *); - -static struct ptyfsnode *ptyfs_free_get(ptyfstype, int, struct lwp *); - -static void ptyfs_rehash(kmutex_t *, struct ptyfs_hashhead **, - u_long *); - -#define PTYHASH(type, pty, mask) (PTYFS_FILENO(type, pty) % (mask + 1)) - - -static void -ptyfs_getinfo(struct ptyfsnode *ptyfs, struct lwp *l) -{ - extern struct ptm_pty *ptyfs_save_ptm; - - if (ptyfs->ptyfs_type == PTYFSroot) { - ptyfs->ptyfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP| - S_IROTH|S_IXOTH; - goto out; - } else - ptyfs->ptyfs_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| - S_IROTH|S_IWOTH; - - if (ptyfs_save_ptm != NULL) { - int error; - struct pathbuf *pb; - struct nameidata nd; - char ttyname[64]; - kauth_cred_t cred; - struct vattr va; - - /* - * We support traditional ptys, so we copy the info - * from the inode - */ - if ((error = (*ptyfs_save_ptm->makename)( - NULL, l, ttyname, sizeof(ttyname), - ptyfs->ptyfs_pty, ptyfs->ptyfs_type == PTYFSpts ? 't' - : 'p')) != 0) - goto out; - pb = pathbuf_create(ttyname); - if (pb == NULL) { - error = ENOMEM; - goto out; - } - NDINIT(&nd, LOOKUP, NOFOLLOW|LOCKLEAF, pb); - if ((error = namei(&nd)) != 0) { - pathbuf_destroy(pb); - goto out; - } - cred = kauth_cred_alloc(); - error = VOP_GETATTR(nd.ni_vp, &va, cred); - kauth_cred_free(cred); - VOP_UNLOCK(nd.ni_vp); - vrele(nd.ni_vp); - pathbuf_destroy(pb); - if (error) - goto out; - ptyfs->ptyfs_uid = va.va_uid; - ptyfs->ptyfs_gid = va.va_gid; - ptyfs->ptyfs_mode = va.va_mode; - ptyfs->ptyfs_flags = va.va_flags; - ptyfs->ptyfs_birthtime = va.va_birthtime; - ptyfs->ptyfs_ctime = va.va_ctime; - ptyfs->ptyfs_mtime = va.va_mtime; - ptyfs->ptyfs_atime = va.va_atime; - return; - } -out: - ptyfs->ptyfs_uid = ptyfs->ptyfs_gid = 0; - ptyfs->ptyfs_status |= PTYFS_CHANGE; - PTYFS_ITIMES(ptyfs, NULL, NULL, NULL); - ptyfs->ptyfs_birthtime = ptyfs->ptyfs_mtime = - ptyfs->ptyfs_atime = ptyfs->ptyfs_ctime; - ptyfs->ptyfs_flags = 0; -} - +static SLIST_HEAD(ptyfs_hashhead, ptyfsnode) *ptyfs_node_tbl; +static u_long ptyfs_node_mask; /* size of hash table - 1 */ /* - * allocate a ptyfsnode/vnode pair. the vnode is - * referenced, and locked. + * allocate a ptyfsnode/vnode pair. the vnode is referenced. * * the pty, ptyfs_type, and mount point uniquely * identify a ptyfsnode. the mount point is needed * because someone might mount this filesystem * twice. - * - * all ptyfsnodes are maintained on a singly-linked - * list. new nodes are only allocated when they cannot - * be found on this list. entries on the list are - * removed when the vfs reclaim entry is called. - * - * a single lock is kept for the entire list. this is - * needed because the getnewvnode() function can block - * waiting for a vnode to become free, in which case there - * may be more than one ptyess trying to get the same - * vnode. this lock is only taken if we are going to - * call getnewvnode, since the kernel itself is single-threaded. - * - * if an entry is found on the list, then call vget() to - * take a reference. this is done because there may be - * zero references to it and so it needs to removed from - * the vnode free list. */ int -ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty, - struct lwp *l) -{ - struct ptyfsnode *ptyfs; - struct vnode *vp; - int error; - - retry: - if ((*vpp = ptyfs_used_get(type, pty, mp, LK_EXCLUSIVE)) != NULL) - return 0; - - error = getnewvnode(VT_PTYFS, mp, ptyfs_vnodeop_p, NULL, &vp); - if (error) { - *vpp = NULL; - return error; - } - - mutex_enter(&ptyfs_hashlock); - if (ptyfs_used_get(type, pty, mp, 0) != NULL) { - mutex_exit(&ptyfs_hashlock); - ungetnewvnode(vp); - goto retry; - } - - vp->v_data = ptyfs = ptyfs_free_get(type, pty, l); - ptyfs->ptyfs_vnode = vp; - - switch (type) { - case PTYFSroot: /* /pts = dr-xr-xr-x */ - vp->v_type = VDIR; - vp->v_vflag = VV_ROOT; - break; - - case PTYFSpts: /* /pts/N = cxxxxxxxxx */ - case PTYFSptc: /* controlling side = cxxxxxxxxx */ - vp->v_type = VCHR; - spec_node_init(vp, PTYFS_MAKEDEV(ptyfs)); - break; - default: - panic("ptyfs_allocvp"); - } - - ptyfs_hashins(ptyfs); - uvm_vnp_setsize(vp, 0); - mutex_exit(&ptyfs_hashlock); - - *vpp = vp; - return 0; -} - -int -ptyfs_freevp(struct vnode *vp) +ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty) { - struct ptyfsnode *ptyfs = VTOPTYFS(vp); + struct ptyfskey key; - ptyfs_hashrem(ptyfs); - vp->v_data = NULL; - return 0; + memset(&key, 0, sizeof(key)); + key.ptk_pty = pty; + key.ptk_type = type; + return vcache_get(mp, &key, sizeof(key), vpp); } /* @@ -274,47 +123,9 @@ ptyfs_freevp(struct vnode *vp) void ptyfs_hashinit(void) { - ptyfs_used_tbl = hashinit(desiredvnodes / 4, HASH_LIST, true, - &ptyfs_used_mask); - ptyfs_free_tbl = hashinit(desiredvnodes / 4, HASH_LIST, true, - &ptyfs_free_mask); - mutex_init(&ptyfs_hashlock, MUTEX_DEFAULT, IPL_NONE); - mutex_init(&ptyfs_used_slock, MUTEX_DEFAULT, IPL_NONE); - mutex_init(&ptyfs_free_slock, MUTEX_DEFAULT, IPL_NONE); -} - -void -ptyfs_hashreinit(void) -{ - ptyfs_rehash(&ptyfs_used_slock, &ptyfs_used_tbl, &ptyfs_used_mask); - ptyfs_rehash(&ptyfs_free_slock, &ptyfs_free_tbl, &ptyfs_free_mask); -} - -static void -ptyfs_rehash(kmutex_t *hlock, struct ptyfs_hashhead **hhead, - u_long *hmask) -{ - struct ptyfsnode *pp; - struct ptyfs_hashhead *oldhash, *hash; - u_long i, oldmask, mask, val; - hash = hashinit(desiredvnodes / 4, HASH_LIST, true, &mask); - - mutex_enter(hlock); - oldhash = *hhead; - oldmask = *hmask; - *hhead = hash; - *hmask = mask; - for (i = 0; i <= oldmask; i++) { - while ((pp = LIST_FIRST(&oldhash[i])) != NULL) { - LIST_REMOVE(pp, ptyfs_hash); - val = PTYHASH(pp->ptyfs_type, pp->ptyfs_pty, - ptyfs_used_mask); - LIST_INSERT_HEAD(&hash[val], pp, ptyfs_hash); - } - } - mutex_exit(hlock); - hashdone(oldhash, HASH_LIST, oldmask); + ptyfs_node_tbl = hashinit(16, HASH_SLIST, true, &ptyfs_node_mask); + mutex_init(&ptyfs_hashlock, MUTEX_DEFAULT, IPL_NONE); } /* @@ -325,105 +136,124 @@ ptyfs_hashdone(void) { mutex_destroy(&ptyfs_hashlock); - mutex_destroy(&ptyfs_used_slock); - mutex_destroy(&ptyfs_free_slock); - hashdone(ptyfs_used_tbl, HASH_LIST, ptyfs_used_mask); - hashdone(ptyfs_free_tbl, HASH_LIST, ptyfs_free_mask); + hashdone(ptyfs_node_tbl, HASH_SLIST, ptyfs_node_mask); } /* - * Get a ptyfsnode from the free table, or allocate one. - * Removes the node from the free table. + * Get a ptyfsnode from the hash table, or allocate one. */ struct ptyfsnode * -ptyfs_free_get(ptyfstype type, int pty, struct lwp *l) +ptyfs_get_node(ptyfstype type, int pty) { struct ptyfs_hashhead *ppp; struct ptyfsnode *pp; - mutex_enter(&ptyfs_free_slock); - ppp = &ptyfs_free_tbl[PTYHASH(type, pty, ptyfs_free_mask)]; - LIST_FOREACH(pp, ppp, ptyfs_hash) { + ppp = &ptyfs_node_tbl[PTYFS_FILENO(type, pty) & ptyfs_node_mask]; + + mutex_enter(&ptyfs_hashlock); + SLIST_FOREACH(pp, ppp, ptyfs_hash) { if (pty == pp->ptyfs_pty && pp->ptyfs_type == type) { - LIST_REMOVE(pp, ptyfs_hash); - mutex_exit(&ptyfs_free_slock); + mutex_exit(&ptyfs_hashlock); return pp; } } - mutex_exit(&ptyfs_free_slock); + mutex_exit(&ptyfs_hashlock); pp = malloc(sizeof(struct ptyfsnode), M_TEMP, M_WAITOK); pp->ptyfs_pty = pty; pp->ptyfs_type = type; pp->ptyfs_fileno = PTYFS_FILENO(pty, type); - ptyfs_getinfo(pp, l); + if (pp->ptyfs_type == PTYFSroot) + pp->ptyfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP| + S_IROTH|S_IXOTH; + else + pp->ptyfs_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| + S_IROTH|S_IWOTH; + + pp->ptyfs_uid = pp->ptyfs_gid = 0; + pp->ptyfs_status = PTYFS_CHANGE; + PTYFS_ITIMES(pp, NULL, NULL, NULL); + pp->ptyfs_birthtime = pp->ptyfs_mtime = + pp->ptyfs_atime = pp->ptyfs_ctime; + pp->ptyfs_flags = 0; + mutex_enter(&ptyfs_hashlock); + SLIST_INSERT_HEAD(ppp, pp, ptyfs_hash); + mutex_exit(&ptyfs_hashlock); return pp; } -struct vnode * -ptyfs_used_get(ptyfstype type, int pty, struct mount *mp, int flags) +/* + * Mark this controlling pty as active. + */ +void +ptyfs_set_active(struct mount *mp, int pty) { - struct ptyfs_hashhead *ppp; - struct ptyfsnode *pp; - struct vnode *vp; + struct ptyfsmount *pmnt = VFSTOPTY(mp); -loop: - mutex_enter(&ptyfs_used_slock); - ppp = &ptyfs_used_tbl[PTYHASH(type, pty, ptyfs_used_mask)]; - LIST_FOREACH(pp, ppp, ptyfs_hash) { - vp = PTYFSTOV(pp); - if (pty == pp->ptyfs_pty && pp->ptyfs_type == type && - vp->v_mount == mp) { - if (flags == 0) { - mutex_exit(&ptyfs_used_slock); - } else { - mutex_enter(vp->v_interlock); - mutex_exit(&ptyfs_used_slock); - if (vget(vp, flags)) - goto loop; - } - return vp; + KASSERT(pty >= 0); + /* Reallocate map if needed. */ + if (pty >= pmnt->pmnt_bitmap_size * NBBY) { + int osize, nsize; + uint8_t *obitmap, *nbitmap; + + nsize = roundup(howmany(pty + 1, NBBY), 64); + nbitmap = kmem_alloc(nsize, KM_SLEEP); + mutex_enter(&pmnt->pmnt_lock); + if (pty < pmnt->pmnt_bitmap_size * NBBY) { + mutex_exit(&pmnt->pmnt_lock); + kmem_free(nbitmap, nsize); + } else { + osize = pmnt->pmnt_bitmap_size; + obitmap = pmnt->pmnt_bitmap; + pmnt->pmnt_bitmap_size = nsize; + pmnt->pmnt_bitmap = nbitmap; + if (osize > 0) + memcpy(pmnt->pmnt_bitmap, obitmap, osize); + memset(pmnt->pmnt_bitmap + osize, 0, nsize - osize); + mutex_exit(&pmnt->pmnt_lock); + if (osize > 0) + kmem_free(obitmap, osize); } } - mutex_exit(&ptyfs_used_slock); - return NULL; + + mutex_enter(&pmnt->pmnt_lock); + setbit(pmnt->pmnt_bitmap, pty); + mutex_exit(&pmnt->pmnt_lock); } /* - * Insert the ptyfsnode into the used table and lock it. + * Mark this controlling pty as inactive. */ -static void -ptyfs_hashins(struct ptyfsnode *pp) +void +ptyfs_clr_active(struct mount *mp, int pty) { - struct ptyfs_hashhead *ppp; - int error __diagused; + struct ptyfsmount *pmnt = VFSTOPTY(mp); - /* lock the ptyfsnode, then put it on the appropriate hash list */ - error = VOP_LOCK(PTYFSTOV(pp), LK_EXCLUSIVE); - KASSERT(error == 0); - - mutex_enter(&ptyfs_used_slock); - ppp = &ptyfs_used_tbl[PTYHASH(pp->ptyfs_type, pp->ptyfs_pty, - ptyfs_used_mask)]; - LIST_INSERT_HEAD(ppp, pp, ptyfs_hash); - mutex_exit(&ptyfs_used_slock); + KASSERT(pty >= 0); + mutex_enter(&pmnt->pmnt_lock); + if (pty >= 0 && pty < pmnt->pmnt_bitmap_size * NBBY) + clrbit(pmnt->pmnt_bitmap, pty); + mutex_exit(&pmnt->pmnt_lock); } /* - * Remove the ptyfsnode from the used table, and add it to the free table + * Lookup the next active controlling pty greater or equal "pty". + * Return -1 if not found. */ -static void -ptyfs_hashrem(struct ptyfsnode *pp) +int +ptyfs_next_active(struct mount *mp, int pty) { - struct ptyfs_hashhead *ppp; + struct ptyfsmount *pmnt = VFSTOPTY(mp); - mutex_enter(&ptyfs_used_slock); - LIST_REMOVE(pp, ptyfs_hash); - mutex_exit(&ptyfs_used_slock); - - mutex_enter(&ptyfs_free_slock); - ppp = &ptyfs_free_tbl[PTYHASH(pp->ptyfs_type, pp->ptyfs_pty, - ptyfs_free_mask)]; - LIST_INSERT_HEAD(ppp, pp, ptyfs_hash); - mutex_exit(&ptyfs_free_slock); + KASSERT(pty >= 0); + mutex_enter(&pmnt->pmnt_lock); + while (pty < pmnt->pmnt_bitmap_size * NBBY) { + if (isset(pmnt->pmnt_bitmap, pty)) { + mutex_exit(&pmnt->pmnt_lock); + return pty; + } + pty++; + } + mutex_exit(&pmnt->pmnt_lock); + return -1; } Index: src/sys/fs/ptyfs/ptyfs_vfsops.c diff -u src/sys/fs/ptyfs/ptyfs_vfsops.c:1.50 src/sys/fs/ptyfs/ptyfs_vfsops.c:1.50.2.1 --- src/sys/fs/ptyfs/ptyfs_vfsops.c:1.50 Wed Apr 16 18:55:18 2014 +++ src/sys/fs/ptyfs/ptyfs_vfsops.c Sun Aug 17 03:34:02 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ptyfs_vfsops.c,v 1.50 2014/04/16 18:55:18 maxv Exp $ */ +/* $NetBSD: ptyfs_vfsops.c,v 1.50.2.1 2014/08/17 03:34:02 riz Exp $ */ /* * Copyright (c) 1992, 1993, 1995 @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ptyfs_vfsops.c,v 1.50 2014/04/16 18:55:18 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ptyfs_vfsops.c,v 1.50.2.1 2014/08/17 03:34:02 riz Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -155,6 +155,7 @@ ptyfs__makename(struct mount *mp, struct { size_t len; const char *np; + int pty = minor(dev); switch (ms) { case 'p': @@ -170,7 +171,7 @@ ptyfs__makename(struct mount *mp, struct */ if (l->l_proc->p_cwdi->cwdi_rdir == NULL && ptyfs_save_ptm != NULL - && ptyfs_used_get(PTYFSptc, minor(dev), mp, 0) == NULL) + && ptyfs_next_active(mp, pty) != pty) return (*ptyfs_save_ptm->makename)(mp, l, tbuf, bufsiz, dev, ms); @@ -193,6 +194,7 @@ static int ptyfs__allocvp(struct mount *mp, struct lwp *l, struct vnode **vpp, dev_t dev, char ms) { + int error; ptyfstype type; switch (ms) { @@ -206,7 +208,18 @@ ptyfs__allocvp(struct mount *mp, struct return EINVAL; } - return ptyfs_allocvp(mp, vpp, type, minor(dev), l); + error = ptyfs_allocvp(mp, vpp, type, minor(dev)); + if (error) + return error; + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return error; + } + if (type == PTYFSptc) + ptyfs_set_active(mp, minor(dev)); + return 0; } @@ -235,7 +248,7 @@ ptyfs_init(void) void ptyfs_reinit(void) { - ptyfs_hashreinit(); + } void @@ -261,8 +274,10 @@ ptyfs_mount(struct mount *mp, const char if (args == NULL) return EINVAL; - if (*data_len != sizeof *args && *data_len != OSIZE) - return EINVAL; + if (*data_len != sizeof *args) { + if (*data_len != OSIZE || args->version >= PTYFS_ARGSVERSION) + return EINVAL; + } if (UIO_MX & (UIO_MX - 1)) { log(LOG_ERR, "ptyfs: invalid directory entry size"); @@ -299,12 +314,15 @@ ptyfs_mount(struct mount *mp, const char pmnt = malloc(sizeof(struct ptyfsmount), M_PTYFSMNT, M_WAITOK); mp->mnt_data = pmnt; + mutex_init(&pmnt->pmnt_lock, MUTEX_DEFAULT, IPL_NONE); pmnt->pmnt_gid = args->gid; pmnt->pmnt_mode = args->mode; if (args->version >= PTYFS_ARGSVERSION) pmnt->pmnt_flags = args->flags; else pmnt->pmnt_flags = 0; + pmnt->pmnt_bitmap_size = 0; + pmnt->pmnt_bitmap = NULL; mp->mnt_flag |= MNT_LOCAL; vfs_getnewfsid(mp); @@ -360,6 +378,9 @@ ptyfs_unmount(struct mount *mp, int mntf /* * Finally, throw away the ptyfsmount structure */ + if (pmnt->pmnt_bitmap_size > 0) + kmem_free(pmnt->pmnt_bitmap, pmnt->pmnt_bitmap_size); + mutex_destroy(&pmnt->pmnt_lock); free(mp->mnt_data, M_PTYFSMNT); mp->mnt_data = NULL; @@ -369,8 +390,19 @@ ptyfs_unmount(struct mount *mp, int mntf int ptyfs_root(struct mount *mp, struct vnode **vpp) { + int error; + /* setup "." */ - return ptyfs_allocvp(mp, vpp, PTYFSroot, 0, NULL); + error = ptyfs_allocvp(mp, vpp, PTYFSroot, 0); + if (error) + return error; + error = vn_lock(*vpp, LK_EXCLUSIVE); + if (error) { + vrele(*vpp); + *vpp = NULL; + return error; + } + return 0; } /*ARGSUSED*/ @@ -382,6 +414,46 @@ ptyfs_sync(struct mount *mp, int waitfor } /* + * Initialize this vnode / ptynode pair. + * Caller assures no other thread will try to load this node. + */ +int +ptyfs_loadvnode(struct mount *mp, struct vnode *vp, + const void *key, size_t key_len, const void **new_key) +{ + struct ptyfskey pkey; + struct ptyfsnode *ptyfs; + + KASSERT(key_len == sizeof(pkey)); + memcpy(&pkey, key, key_len); + + ptyfs = ptyfs_get_node(pkey.ptk_type, pkey.ptk_pty); + KASSERT(memcmp(&ptyfs->ptyfs_key, &pkey, sizeof(pkey)) == 0); + + switch (pkey.ptk_type) { + case PTYFSroot: /* /pts = dr-xr-xr-x */ + vp->v_type = VDIR; + vp->v_vflag = VV_ROOT; + break; + + case PTYFSpts: /* /pts/N = cxxxxxxxxx */ + case PTYFSptc: /* controlling side = cxxxxxxxxx */ + vp->v_type = VCHR; + spec_node_init(vp, PTYFS_MAKEDEV(ptyfs)); + break; + default: + panic("ptyfs_loadvnode"); + } + + vp->v_tag = VT_PTYFS; + vp->v_op = ptyfs_vnodeop_p; + vp->v_data = ptyfs; + uvm_vnp_setsize(vp, 0); + *new_key = &ptyfs->ptyfs_key; + return 0; +} + +/* * Kernfs flat namespace lookup. * Currently unsupported. */ @@ -411,6 +483,7 @@ struct vfsops ptyfs_vfsops = { .vfs_statvfs = genfs_statvfs, .vfs_sync = ptyfs_sync, .vfs_vget = ptyfs_vget, + .vfs_loadvnode = ptyfs_loadvnode, .vfs_fhtovp = (void *)eopnotsupp, .vfs_vptofh = (void *)eopnotsupp, .vfs_init = ptyfs_init, Index: src/sys/fs/ptyfs/ptyfs_vnops.c diff -u src/sys/fs/ptyfs/ptyfs_vnops.c:1.47 src/sys/fs/ptyfs/ptyfs_vnops.c:1.47.2.1 --- src/sys/fs/ptyfs/ptyfs_vnops.c:1.47 Fri Jul 25 08:20:52 2014 +++ src/sys/fs/ptyfs/ptyfs_vnops.c Sun Aug 17 03:34:02 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ptyfs_vnops.c,v 1.47 2014/07/25 08:20:52 dholland Exp $ */ +/* $NetBSD: ptyfs_vnops.c,v 1.47.2.1 2014/08/17 03:34:02 riz Exp $ */ /* * Copyright (c) 1993, 1995 @@ -76,7 +76,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.47 2014/07/25 08:20:52 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.47.2.1 2014/08/17 03:34:02 riz Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -213,10 +213,7 @@ const struct vnodeopv_desc ptyfs_vnodeop { &ptyfs_vnodeop_p, ptyfs_vnodeop_entries }; /* - * _reclaim is called when getnewvnode() - * wants to make use of an entry on the vnode - * free list. at this time the filesystem needs - * to free any private data and remove the node + * free any private data and remove the node * from any private lists. */ int @@ -225,7 +222,12 @@ ptyfs_reclaim(void *v) struct vop_reclaim_args /* { struct vnode *a_vp; } */ *ap = v; - return ptyfs_freevp(ap->a_vp); + struct vnode *vp = ap->a_vp; + struct ptyfsnode *ptyfs = VTOPTYFS(vp); + + vcache_remove(vp->v_mount, &ptyfs->ptyfs_key, sizeof(ptyfs->ptyfs_key)); + vp->v_data = NULL; + return 0; } int @@ -238,15 +240,8 @@ ptyfs_inactive(void *v) struct vnode *vp = ap->a_vp; struct ptyfsnode *ptyfs = VTOPTYFS(vp); - switch (ptyfs->ptyfs_type) { - case PTYFSpts: - case PTYFSptc: - /* Emulate file deletion for call reclaim(). */ - *ap->a_recycle = true; - break; - default: - break; - } + if (ptyfs->ptyfs_type == PTYFSptc) + ptyfs_clr_active(vp->v_mount, ptyfs->ptyfs_pty); return spec_inactive(v); } @@ -640,16 +635,16 @@ ptyfs_lookup(void *v) return EIO; pty = atoi(pname, cnp->cn_namelen); - - if (pty < 0 || pty >= npty || pty_isfree(pty, 1) || - ptyfs_used_get(PTYFSptc, pty, dvp->v_mount, 0) == NULL) + if (pty < 0 || ptyfs_next_active(dvp->v_mount, pty) != pty) break; - - error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty, - curlwp); + error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty); if (error) return error; - VOP_UNLOCK(*vpp); + if (ptyfs_next_active(dvp->v_mount, pty) != pty) { + vrele(*vpp); + *vpp = NULL; + return ENOENT; + } return 0; default: @@ -690,7 +685,7 @@ ptyfs_readdir(void *v) off_t *cookies = NULL; int ncookies; struct vnode *vp; - int nc = 0; + int n, nc = 0; vp = ap->a_vp; ptyfs = VTOPTYFS(vp); @@ -735,20 +730,20 @@ ptyfs_readdir(void *v) *cookies++ = i + 1; nc++; } - for (; uio->uio_resid >= UIO_MX && i < npty; i++) { + while (uio->uio_resid >= UIO_MX) { /* check for used ptys */ - if (pty_isfree(i - 2, 1) || - ptyfs_used_get(PTYFSptc, i - 2, vp->v_mount, 0) == NULL) - continue; - - dp->d_fileno = PTYFS_FILENO(i - 2, PTYFSpts); + n = ptyfs_next_active(vp->v_mount, i - 2); + if (n < 0) + break; + dp->d_fileno = PTYFS_FILENO(n, PTYFSpts); dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name), - "%lld", (long long)(i - 2)); + "%lld", (long long)(n)); dp->d_type = DT_CHR; if ((error = uiomove(dp, UIO_MX, uio)) != 0) goto out; + i = n + 3; if (cookies) - *cookies++ = i + 1; + *cookies++ = i; nc++; }