Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.135 retrieving revision 1.135.2.1 diff -u -p -r1.135 -r1.135.2.1 --- src/sys/miscfs/specfs/spec_vnops.c 2012/04/29 22:54:00 1.135 +++ src/sys/miscfs/specfs/spec_vnops.c 2013/02/25 00:29:59 1.135.2.1 @@ -1,4 +1,4 @@ -/* $NetBSD: spec_vnops.c,v 1.135 2012/04/29 22:54:00 chs Exp $ */ +/* $NetBSD: spec_vnops.c,v 1.135.2.1 2013/02/25 00:29:59 tls Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.135 2012/04/29 22:54:00 chs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.135.2.1 2013/02/25 00:29:59 tls Exp $"); #include #include @@ -93,7 +93,14 @@ const char devout[] = "devout"; const char devioc[] = "devioc"; const char devcls[] = "devcls"; -vnode_t *specfs_hash[SPECHSZ]; +#define SPECHSZ 64 +#if ((SPECHSZ&(SPECHSZ-1)) == 0) +#define SPECHASH(rdev) (((rdev>>5)+(rdev))&(SPECHSZ-1)) +#else +#define SPECHASH(rdev) (((unsigned)((rdev>>5)+(rdev)))%SPECHSZ) +#endif + +static vnode_t *specfs_hash[SPECHSZ]; /* * This vnode operations vector is used for special device nodes @@ -268,6 +275,82 @@ spec_node_init(vnode_t *vp, dev_t rdev) } /* + * Lookup a vnode by device number and return it referenced. + */ +int +spec_node_lookup_by_dev(enum vtype type, dev_t dev, vnode_t **vpp) +{ + int error; + vnode_t *vp; + + mutex_enter(&device_lock); + for (vp = specfs_hash[SPECHASH(dev)]; vp; vp = vp->v_specnext) { + if (type == vp->v_type && dev == vp->v_rdev) { + mutex_enter(vp->v_interlock); + /* If clean or being cleaned, then ignore it. */ + if ((vp->v_iflag & (VI_CLEAN | VI_XLOCK)) == 0) + break; + mutex_exit(vp->v_interlock); + } + } + KASSERT(vp == NULL || mutex_owned(vp->v_interlock)); + if (vp == NULL) { + mutex_exit(&device_lock); + return ENOENT; + } + /* + * If it is an opened block device return the opened vnode. + */ + if (type == VBLK && vp->v_specnode->sn_dev->sd_bdevvp != NULL) { + mutex_exit(vp->v_interlock); + vp = vp->v_specnode->sn_dev->sd_bdevvp; + mutex_enter(vp->v_interlock); + } + mutex_exit(&device_lock); + error = vget(vp, 0); + if (error != 0) + return error; + *vpp = vp; + + return 0; +} + +/* + * Lookup a vnode by file system mounted on and return it referenced. + */ +int +spec_node_lookup_by_mount(struct mount *mp, vnode_t **vpp) +{ + int i, error; + vnode_t *vp, *vq; + + mutex_enter(&device_lock); + for (i = 0, vq = NULL; i < SPECHSZ && vq == NULL; i++) { + for (vp = specfs_hash[i]; vp; vp = vp->v_specnext) { + if (vp->v_type != VBLK) + continue; + vq = vp->v_specnode->sn_dev->sd_bdevvp; + if (vq != NULL && vq->v_specmountpoint == mp) + break; + vq = NULL; + } + } + if (vq == NULL) { + mutex_exit(&device_lock); + return ENOENT; + } + mutex_enter(vq->v_interlock); + mutex_exit(&device_lock); + error = vget(vq, 0); + if (error != 0) + return error; + *vpp = vq; + + return 0; + +} + +/* * A vnode representing a special device is going away. Close * the device if the vnode holds it open. */ @@ -612,11 +695,10 @@ spec_read(void *v) on = uio->uio_offset % bsize; n = min((unsigned)(bsize - on), uio->uio_resid); error = bread(vp, bn, bsize, NOCRED, 0, &bp); - n = min(n, bsize - bp->b_resid); if (error) { - brelse(bp, 0); return (error); } + n = min(n, bsize - bp->b_resid); error = uiomove((char *)bp->b_data + on, n, uio); brelse(bp, 0); } while (error == 0 && uio->uio_resid > 0 && n != 0); @@ -691,7 +773,6 @@ spec_write(void *v) error = bread(vp, bn, bsize, NOCRED, B_MODIFY, &bp); if (error) { - brelse(bp, 0); return (error); } n = min(n, bsize - bp->b_resid);