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
This commit is contained in:
riz 2014-08-17 03:34:02 +00:00
parent ada2977984
commit 9459951c73
5 changed files with 224 additions and 321 deletions

View File

@ -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

View File

@ -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 *);

View File

@ -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,v 1.29 2014/03/27 17:31:56 christos Exp
#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)
ptyfs_allocvp(struct mount *mp, struct vnode **vpp, ptyfstype type, int pty)
{
struct ptyfsnode *ptyfs;
struct vnode *vp;
int error;
struct ptyfskey key;
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)
{
struct ptyfsnode *ptyfs = VTOPTYFS(vp);
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);
ptyfs_node_tbl = hashinit(16, HASH_SLIST, true, &ptyfs_node_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);
}
/*
@ -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;
}

View File

@ -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 lwp *l, char *tbuf, size_t bufsiz,
{
size_t len;
const char *np;
int pty = minor(dev);
switch (ms) {
case 'p':
@ -170,7 +171,7 @@ ptyfs__makename(struct mount *mp, struct lwp *l, char *tbuf, size_t bufsiz,
*/
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 lwp *l, struct vnode **vpp,
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 *path, void *data, size_t *data_len)
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 *path, void *data, size_t *data_len)
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 mntflags)
/*
* 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 mntflags)
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*/
@ -381,6 +413,46 @@ ptyfs_sync(struct mount *mp, int waitfor,
return 0;
}
/*
* 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,

View File

@ -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_opv_desc =
{ &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++;
}