aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Feldman <green@FreeBSD.org>1999-08-28 06:21:39 +0000
committerBrian Feldman <green@FreeBSD.org>1999-08-28 06:21:39 +0000
commitb519d997a1530c51429bcee9a1f882d780230b91 (patch)
tree473de9cf8366123b8dbe4b3cfd3cfcc29b3d4c30
parenta1a4f1a0d87b594d3f17a97dc0127eec1417e6f6 (diff)
downloadsrc-b519d997a1530c51429bcee9a1f882d780230b91.tar.gz
src-b519d997a1530c51429bcee9a1f882d780230b91.zip
Unevilize vn(4) somewhat:
1. implement read-only ability 2. make it play nice with cdevsw (use cdevsw_remove() uon kldunload)
Notes
Notes: svn path=/head/; revision=50490
-rw-r--r--sys/dev/vn/vn.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/sys/dev/vn/vn.c b/sys/dev/vn/vn.c
index 8254f873620d..b7aace9565a8 100644
--- a/sys/dev/vn/vn.c
+++ b/sys/dev/vn/vn.c
@@ -152,6 +152,7 @@ static SLIST_HEAD(, vn_softc) vn_list;
/* sc_flags */
#define VNF_INITED 0x01
+#define VNF_READONLY 0x02
static u_long vn_options;
@@ -215,6 +216,9 @@ vnopen(dev_t dev, int flags, int mode, struct proc *p)
if (!vn)
vn = vnfindvn(dev);
+ if (flags & FWRITE && vn->sc_flags & VNF_READONLY)
+ return (EACCES);
+
IFOPT(vn, VN_FOLLOW)
printf("vnopen(%s, 0x%x, 0x%x, %p)\n",
devtoname(dev), flags, mode, (void *)p);
@@ -479,23 +483,25 @@ vniocattach_file(vn, vio, dev, flag, p)
{
struct vattr vattr;
struct nameidata nd;
- int error;
+ int error, flags;
- /*
- * Always open for read and write.
- * This is probably bogus, but it lets vn_open()
- * weed out directories, sockets, etc. so we don't
- * have to worry about them.
- */
+ flags = FREAD|FWRITE;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p);
- error = vn_open(&nd, FREAD|FWRITE, 0);
- if (error)
- return(error);
- error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
+ error = vn_open(&nd, flags, 0);
if (error) {
+ if (error != EACCES && error != EPERM && error != EROFS)
+ return (error);
+ flags &= ~FWRITE;
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p);
+ error = vn_open(&nd, flags, 0);
+ if (error)
+ return (error);
+ }
+ if (nd.ni_vp->v_type != VREG ||
+ (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p))) {
VOP_UNLOCK(nd.ni_vp, 0, p);
- (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
- return(error);
+ (void) vn_close(nd.ni_vp, flags, p->p_ucred, p);
+ return (error ? error : EINVAL);
}
VOP_UNLOCK(nd.ni_vp, 0, p);
vn->sc_secsize = DEV_BSIZE;
@@ -503,7 +509,7 @@ vniocattach_file(vn, vio, dev, flag, p)
vn->sc_size = vattr.va_size / vn->sc_secsize; /* note truncation */
error = vnsetcred(vn, p->p_ucred);
if (error) {
- (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
+ (void) vn_close(nd.ni_vp, flags, p->p_ucred, p);
return(error);
}
if (dev->si_bsize_phys < vn->sc_secsize)
@@ -511,6 +517,8 @@ vniocattach_file(vn, vio, dev, flag, p)
if (dev->si_bsize_best < vn->sc_secsize)
dev->si_bsize_best = vn->sc_secsize;
vn->sc_flags |= VNF_INITED;
+ if (flags == FREAD)
+ vn->sc_flags |= VNF_READONLY;
IFOPT(vn, VN_LABELS) {
/*
* Reopen so that `ds' knows which devices are open.
@@ -650,9 +658,11 @@ vnclear(struct vn_softc *vn)
dsgone(&vn->sc_slices);
vn->sc_flags &= ~VNF_INITED;
if (vn->sc_vp != NULL) {
- (void)vn_close(vn->sc_vp, FREAD|FWRITE, vn->sc_cred, p);
+ (void)vn_close(vn->sc_vp, vn->sc_flags & VNF_READONLY ?
+ FREAD : (FREAD|FWRITE), vn->sc_cred, p);
vn->sc_vp = NULL;
}
+ vn->sc_flags &= ~VNF_READONLY;
if (vn->sc_cred) {
crfree(vn->sc_cred);
vn->sc_cred = NULL;
@@ -699,6 +709,7 @@ vn_modevent(module_t mod, int type, void *data)
vnclear(vn);
free(vn, M_DEVBUF);
}
+ cdevsw_remove(&vn_cdevsw);
break;
default:
break;