summaryrefslogtreecommitdiff
path: root/sys/dev/vnd.c
diff options
context:
space:
mode:
authorPedro Martelletto <pedro@cvs.openbsd.org>2006-09-20 13:51:20 +0000
committerPedro Martelletto <pedro@cvs.openbsd.org>2006-09-20 13:51:20 +0000
commitaff164e3dc2d93984a5509aeefb0efe5542f6343 (patch)
tree1d0039490fd7f266c9a0ec3db21ea11f1e8905da /sys/dev/vnd.c
parentf36fa7376b2cb66322f3072979cb62f703828e1f (diff)
Make vnd(4) work on read-only file systems, from Paul Stoeber, okay tedu@
Diffstat (limited to 'sys/dev/vnd.c')
-rw-r--r--sys/dev/vnd.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/sys/dev/vnd.c b/sys/dev/vnd.c
index 535cbb42014..a8d132a8641 100644
--- a/sys/dev/vnd.c
+++ b/sys/dev/vnd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnd.c,v 1.62 2006/08/13 17:55:07 thib Exp $ */
+/* $OpenBSD: vnd.c,v 1.63 2006/09/20 13:51:19 pedro Exp $ */
/* $NetBSD: vnd.c,v 1.26 1996/03/30 23:06:11 christos Exp $ */
/*
@@ -142,6 +142,9 @@ struct vnd_softc {
#define VNF_HAVELABEL 0x0400
#define VNF_BUSY 0x0800
#define VNF_SIMPLE 0x1000
+#define VNF_READONLY 0x2000
+
+#define VNDRW(v) ((v)->sc_flags & VNF_READONLY ? FREAD : FREAD|FWRITE)
struct vnd_softc *vnd_softc;
int numvnd = 0;
@@ -234,6 +237,11 @@ vndopen(dev, flags, mode, p)
if ((error = vndlock(sc)) != 0)
return (error);
+ if ((flags & FWRITE) && (sc->sc_flags & VNF_READONLY)) {
+ error = EROFS;
+ goto bad;
+ }
+
if ((sc->sc_flags & VNF_INITED) &&
(sc->sc_flags & VNF_HAVELABEL) == 0) {
sc->sc_flags |= VNF_HAVELABEL;
@@ -817,20 +825,26 @@ vndioctl(dev, cmd, addr, flag, p)
}
/*
- * 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.
+ * Open for read and write first. This lets vn_open() weed out
+ * directories, sockets, etc. so we don't have to worry about
+ * them.
*/
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
- if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
+ vnd->sc_flags &= ~VNF_READONLY;
+ error = vn_open(&nd, FREAD|FWRITE, 0);
+ if (error == EROFS) {
+ vnd->sc_flags |= VNF_READONLY;
+ error = vn_open(&nd, FREAD, 0);
+ }
+ if (error) {
vndunlock(vnd);
return (error);
}
+
error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
if (error) {
VOP_UNLOCK(nd.ni_vp, 0, p);
- (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
+ (void) vn_close(nd.ni_vp, VNDRW(vnd), p->p_ucred, p);
vndunlock(vnd);
return (error);
}
@@ -838,7 +852,7 @@ vndioctl(dev, cmd, addr, flag, p)
vnd->sc_vp = nd.ni_vp;
vnd->sc_size = btodb(vattr.va_size); /* note truncation */
if ((error = vndsetcred(vnd, p->p_ucred)) != 0) {
- (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
+ (void) vn_close(nd.ni_vp, VNDRW(vnd), p->p_ucred, p);
vndunlock(vnd);
return (error);
}
@@ -851,7 +865,7 @@ vndioctl(dev, cmd, addr, flag, p)
if ((error = copyin(vio->vnd_key, key,
vio->vnd_keylen)) != 0) {
- (void) vn_close(nd.ni_vp, FREAD|FWRITE,
+ (void) vn_close(nd.ni_vp, VNDRW(vnd),
p->p_ucred, p);
vndunlock(vnd);
return (error);
@@ -1087,7 +1101,7 @@ vndclear(vnd)
vnd->sc_flags &= ~VNF_INITED;
if (vp == (struct vnode *)0)
panic("vndioctl: null vp");
- (void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
+ (void) vn_close(vp, VNDRW(vnd), vnd->sc_cred, p);
crfree(vnd->sc_cred);
vnd->sc_vp = (struct vnode *)0;
vnd->sc_cred = (struct ucred *)0;