summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2000-11-21 21:49:58 +0000
committerNiels Provos <provos@cvs.openbsd.org>2000-11-21 21:49:58 +0000
commit94de05185b93d013f30d8874f4fea920b09ed369 (patch)
treeb6263191caa04e1a1a335966375a2a0e1efe3ba3
parenta12c4c01eea21cd09905b7d403f30c7060520a3b (diff)
support for kernel events on vnodes, from jlemon@freebsd.org, okay art@
-rw-r--r--sys/kern/kern_event.c10
-rw-r--r--sys/kern/vfs_vnops.c85
-rw-r--r--sys/sys/vnode.h7
-rw-r--r--sys/ufs/ufs/ufs_readwrite.c13
-rw-r--r--sys/ufs/ufs/ufs_vnops.c37
5 files changed, 137 insertions, 15 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 4c5fed5e9ac..d407ba8ad27 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.5 2000/11/18 22:16:49 provos Exp $ */
+/* $OpenBSD: kern_event.c,v 1.6 2000/11/21 21:49:57 provos Exp $ */
/*-
* Copyright (c) 1999,2000 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -100,8 +100,8 @@ extern struct filterops so_rwfiltops[];
extern struct filterops pipe_rwfiltops[];
#ifdef notyet
extern struct filterops fifo_rwfiltops[];
-extern struct filterops vn_rwfiltops[];
#endif
+extern struct filterops vn_rwfiltops[];
struct filterops kq_rwfiltops[] = {
{ 1, filt_kqattach, filt_kqdetach, filt_kqueue },
@@ -111,8 +111,8 @@ struct filterops kq_rwfiltops[] = {
extern struct filterops sig_filtops;
#ifdef notyet
extern struct filterops aio_filtops;
-extern struct filterops vn_filtops;
#endif
+extern struct filterops vn_filtops;
struct filterops rwtype_filtops =
{ 1, filt_rwtypattach, NULL, NULL };
@@ -125,7 +125,7 @@ struct filterops proc_filtops =
*/
struct filterops *rwtypfilt_sw[] = {
NULL, /* 0 */
- NULL, /* vn_rwfiltops, */ /* DTYPE_VNODE */
+ vn_rwfiltops, /* DTYPE_VNODE */
so_rwfiltops, /* DTYPE_SOCKET */
pipe_rwfiltops, /* DTYPE_PIPE */
/* fifo_rwfiltops, */ /* DTYPE_FIFO */
@@ -139,7 +139,7 @@ struct filterops *sysfilt_ops[] = {
&rwtype_filtops, /* EVFILT_READ */
&rwtype_filtops, /* EVFILT_WRITE */
NULL, /*&aio_filtops,*/ /* EVFILT_AIO */
- NULL, /*&vn_filtops,*/ /* EVFILT_VNODE */
+ &vn_filtops, /* EVFILT_VNODE */
&proc_filtops, /* EVFILT_PROC */
&sig_filtops, /* EVFILT_SIGNAL */
};
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index b9435c46086..6bfcf9614ab 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_vnops.c,v 1.26 2000/04/25 02:10:04 deraadt Exp $ */
+/* $OpenBSD: vfs_vnops.c,v 1.27 2000/11/21 21:49:57 provos Exp $ */
/* $NetBSD: vfs_vnops.c,v 1.20 1996/02/04 02:18:41 christos Exp $ */
/*
@@ -61,6 +61,9 @@
#include <uvm/uvm_extern.h>
#endif
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+
int vn_read __P((struct file *fp, off_t *off, struct uio *uio,
struct ucred *cred));
int vn_write __P((struct file *fp, off_t *off, struct uio *uio,
@@ -73,6 +76,25 @@ int vn_ioctl __P((struct file *fp, u_long com, caddr_t data,
struct fileops vnops =
{ vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
+static int filt_nullattach(struct knote *kn);
+static int filt_vnattach(struct knote *kn);
+static void filt_vndetach(struct knote *kn);
+static int filt_vnode(struct knote *kn, long hint);
+static int filt_vnread(struct knote *kn, long hint);
+
+struct filterops vn_filtops =
+ { 1, filt_vnattach, filt_vndetach, filt_vnode };
+
+/*
+ * XXX
+ * filt_vnread is ufs-specific, so the attach routine should really
+ * switch out to different filterops based on the vn filetype
+ */
+struct filterops vn_rwfiltops[] = {
+ { 1, filt_vnattach, filt_vndetach, filt_vnread },
+ { 1, filt_nullattach, NULL, NULL },
+};
+
/*
* Common code for vnode open operations.
* Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
@@ -508,3 +530,64 @@ vn_closefile(fp, p)
return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
fp->f_cred, p));
}
+
+static int
+filt_vnattach(struct knote *kn)
+{
+ struct vnode *vp;
+
+ if (kn->kn_fp->f_type != DTYPE_VNODE)
+ return (EBADF);
+
+ vp = (struct vnode *)kn->kn_fp->f_data;
+
+ /*
+ * XXX
+ * this is a hack simply to cause the filter attach to fail
+ * for non-ufs filesystems, until the support for them is done.
+ */
+ if ((vp)->v_tag != VT_UFS || (vp)->v_type == VFIFO)
+ return (EOPNOTSUPP);
+
+ simple_lock(&vp->v_selectinfo.vsi_lock);
+ SLIST_INSERT_HEAD(&vp->v_selectinfo.vsi_selinfo.si_note, kn, kn_selnext);
+ simple_unlock(&vp->v_selectinfo.vsi_lock);
+
+ return (0);
+}
+
+static void
+filt_vndetach(struct knote *kn)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_fp->f_data;
+
+ simple_lock(&vp->v_selectinfo.vsi_lock);
+ SLIST_REMOVE(&vp->v_selectinfo.vsi_selinfo.si_note,
+ kn, knote, kn_selnext);
+ simple_unlock(&vp->v_selectinfo.vsi_lock);
+}
+
+static int
+filt_vnode(struct knote *kn, long hint)
+{
+ if (kn->kn_sfflags & hint)
+ kn->kn_fflags |= hint;
+ return (kn->kn_fflags != 0);
+}
+
+static int
+filt_nullattach(struct knote *kn)
+{
+ return (ENXIO);
+}
+
+/*ARGSUSED*/
+static int
+filt_vnread(struct knote *kn, long hint)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_fp->f_data;
+ struct inode *ip = VTOI(vp);
+
+ kn->kn_data = ip->i_ffs_size - kn->kn_fp->f_offset;
+ return (kn->kn_data != 0);
+}
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 47ffb2e8af3..9d5685c67e4 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnode.h,v 1.25 2000/06/17 17:16:05 provos Exp $ */
+/* $OpenBSD: vnode.h,v 1.26 2000/11/21 21:49:56 provos Exp $ */
/* $NetBSD: vnode.h,v 1.38 1996/02/29 20:59:05 cgd Exp $ */
/*
@@ -38,6 +38,7 @@
#include <sys/queue.h>
#include <sys/lock.h>
+#include <sys/select.h>
#ifdef UVM /* XXX: clean up includes later */
#include <vm/pglist.h> /* XXX */
#include <vm/vm_param.h> /* XXX */
@@ -126,6 +127,10 @@ struct vnode {
#endif
enum vtagtype v_tag; /* type of underlying data */
void *v_data; /* private data for fs */
+ struct {
+ struct simplelock vsi_lock; /* lock to protect below */
+ struct selinfo vsi_selinfo; /* identity of poller(s) */
+ } v_selectinfo;
};
#define v_mountedhere v_un.vu_mountedhere
#define v_socket v_un.vu_socket
diff --git a/sys/ufs/ufs/ufs_readwrite.c b/sys/ufs/ufs/ufs_readwrite.c
index 7a9ce5a44eb..4eb92eb225c 100644
--- a/sys/ufs/ufs/ufs_readwrite.c
+++ b/sys/ufs/ufs/ufs_readwrite.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_readwrite.c,v 1.15 1999/02/26 03:35:18 art Exp $ */
+/* $OpenBSD: ufs_readwrite.c,v 1.16 2000/11/21 21:49:57 provos Exp $ */
/* $NetBSD: ufs_readwrite.c,v 1.9 1996/05/11 18:27:57 mycroft Exp $ */
/*-
@@ -57,6 +57,11 @@
#define MAXFILESIZE fs->fs_maxfilesize
#endif
+#include <sys/event.h>
+
+#define VN_KNOTE(vp, b) \
+ KNOTE((struct klist *)&vp->v_selectinfo.vsi_selinfo.si_note, (b))
+
/*
* Vnode op for reading.
*/
@@ -186,9 +191,10 @@ WRITE(v)
struct proc *p;
daddr_t lbn;
off_t osize;
- int blkoffset, error, flags, ioflag, resid, size, xfersize;
+ int blkoffset, error, extended, flags, ioflag, resid, size, xfersize;
struct timespec ts;
+ extended = 0;
ioflag = ap->a_ioflag;
uio = ap->a_uio;
vp = ap->a_vp;
@@ -257,6 +263,7 @@ WRITE(v)
#else
vnode_pager_setsize(vp, (u_long)ip->i_ffs_size);
#endif
+ extended = 1;
}
#if defined(UVM)
(void)uvm_vnp_uncache(vp);
@@ -298,6 +305,8 @@ WRITE(v)
*/
if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
ip->i_ffs_mode &= ~(ISUID | ISGID);
+ if (resid > uio->uio_resid)
+ VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
if (error) {
if (ioflag & IO_UNIT) {
(void)VOP_TRUNCATE(vp, osize,
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 5575728b316..2a648f44883 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_vnops.c,v 1.27 1999/03/09 21:16:28 art Exp $ */
+/* $OpenBSD: ufs_vnops.c,v 1.28 2000/11/21 21:49:57 provos Exp $ */
/* $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $ */
/*
@@ -56,6 +56,7 @@
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/lockf.h>
+#include <sys/event.h>
#include <vm/vm.h>
@@ -93,6 +94,8 @@ union _qcvt {
tmp.val[_QUAD_LOWWORD] = (l); \
(q) = tmp.qcvt; \
}
+#define VN_KNOTE(vp, b) \
+ KNOTE(&vp->v_selectinfo.vsi_selinfo.si_note, (b))
/*
@@ -120,9 +123,15 @@ ufs_create(v)
struct componentname *a_cnp;
struct vattr *a_vap;
} */ *ap = v;
- return
+ int error;
+
+ error =
ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
ap->a_dvp, ap->a_vpp, ap->a_cnp);
+ if (error)
+ return (error);
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+ return (0);
}
/*
@@ -148,6 +157,7 @@ ufs_mknod(v)
ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
ap->a_dvp, vpp, ap->a_cnp)) != 0)
return (error);
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
ip = VTOI(*vpp);
ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
if (vap->va_rdev != VNOVAL) {
@@ -433,6 +443,7 @@ ufs_setattr(v)
return (EROFS);
error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
}
+ VN_KNOTE(vp, NOTE_ATTRIB);
return (error);
}
@@ -677,11 +688,14 @@ ufs_remove(v)
ip = VTOI(vp);
if (vp->v_type == VDIR || (ip->i_ffs_flags & (IMMUTABLE | APPEND)) ||
- (VTOI(dvp)->i_ffs_flags & APPEND))
+ (VTOI(dvp)->i_ffs_flags & APPEND)) {
error = EPERM;
- else
- error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
-
+ goto out;
+ }
+ error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
+ VN_KNOTE(vp, NOTE_DELETE);
+ VN_KNOTE(dvp, NOTE_WRITE);
+ out:
if (dvp == vp)
vrele(vp);
else
@@ -756,6 +770,8 @@ ufs_link(v)
ip->i_flag |= IN_CHANGE;
}
FREE(cnp->cn_pnbuf, M_NAMEI);
+ VN_KNOTE(vp, NOTE_LINK);
+ VN_KNOTE(dvp, NOTE_WRITE);
out1:
if (dvp != vp)
VOP_UNLOCK(vp, 0, p);
@@ -973,6 +989,7 @@ abortit:
oldparent = dp->i_number;
doingdirectory = 1;
}
+ VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */
/* Why? */
vrele(fdvp);
@@ -1079,6 +1096,7 @@ abortit:
}
goto bad;
}
+ VN_KNOTE(tdvp, NOTE_WRITE);
vput(tdvp);
} else {
if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
@@ -1153,7 +1171,9 @@ abortit:
tcnp->cn_cred, tcnp->cn_proc)) != 0)
goto bad;
}
+ VN_KNOTE(tdvp, NOTE_WRITE);
vput(tdvp);
+ VN_KNOTE(tvp, NOTE_DELETE);
vput(tvp);
xp = NULL;
}
@@ -1205,6 +1225,7 @@ abortit:
error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
xp->i_flag &= ~IN_RENAME;
}
+ VN_KNOTE(fvp, NOTE_RENAME);
if (dp)
vput(fdvp);
if (xp)
@@ -1368,6 +1389,7 @@ ufs_mkdir(v)
bad:
if (error == 0) {
+ VN_KNOTE(dvp, NOTE_WRITE);
*ap->a_vpp = tvp;
} else {
dp->i_effnlink--;
@@ -1449,6 +1471,7 @@ ufs_rmdir(v)
*/
if ((error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1)) != 0)
goto out;
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
cache_purge(dvp);
/*
* Truncate inode. The only stuff left in the directory is "." and
@@ -1471,6 +1494,7 @@ ufs_rmdir(v)
}
cache_purge(vp);
out:
+ VN_KNOTE(vp, NOTE_DELETE);
vput(dvp);
vput(vp);
return (error);
@@ -1498,6 +1522,7 @@ ufs_symlink(v)
vpp, ap->a_cnp);
if (error)
return (error);
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
vp = *vpp;
len = strlen(ap->a_target);
if (len < vp->v_mount->mnt_maxsymlinklen) {