Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Regen for:



details:   https://anonhg.NetBSD.org/src/rev/026b83d462e3
branches:  trunk
changeset: 1024347:026b83d462e3
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Wed Oct 20 03:13:14 2021 +0000

description:
Regen for:

Overhaul of the EVFILT_VNODE kevent(2) filter:

- Centralize vnode kevent handling in the VOP_*() wrappers, rather than
  forcing each individual file system to deal with it (except VOP_RENAME(),
  because VOP_RENAME() is a mess and we currently have 2 different ways
  of handling it; at least it's reasonably well-centralized in the "new"
  way).
- Add support for NOTE_OPEN, NOTE_CLOSE, NOTE_CLOSE_WRITE, and NOTE_READ,
  compatible with the same events in FreeBSD.
- Track which kevent notifications clients are interested in receiving
  to avoid doing work for events no one cares about (avoiding, e.g.
  taking locks and traversing the klist to send a NOTE_WRITE when
  someone is merely watching for a file to be deleted, for example).

In support of the above:

- Add support in vnode_if.sh for specifying PRE- and POST-op handlers,
  to be invoked before and after vop_pre() and vop_post(), respectively.
  Basic idea from FreeBSD, but implemented differently.
- Add support in vnode_if.sh for specifying CONTEXT fields in the
  vop_*_args structures.  These context fields are used to convey information
  between the file system VOP function and the VOP wrapper, but do not
  occupy an argument slot in the VOP_*() call itself.  These context fields
  are initialized and subsequently interpreted by PRE- and POST-op handlers.
- Version VOP_REMOVE(), uses the a context field for the file system to report
  back the resulting link count of the target vnode.  Return this in tmpfs,
  udf, nfs, chfs, ext2fs, lfs, and ufs.

NetBSD 9.99.92.

diffstat:

 sys/kern/vnode_if.c                     |  227 ++++++++++++++++++++++++++++++-
 sys/rump/include/rump/rumpvnode_if.h    |    6 +-
 sys/rump/librump/rumpvfs/rumpvnode_if.c |    9 +-
 sys/sys/vnode_if.h                      |    9 +-
 4 files changed, 232 insertions(+), 19 deletions(-)

diffs (truncated from 477 to 300 lines):

diff -r 4cea3c34a2d2 -r 026b83d462e3 sys/kern/vnode_if.c
--- a/sys/kern/vnode_if.c       Wed Oct 20 03:08:16 2021 +0000
+++ b/sys/kern/vnode_if.c       Wed Oct 20 03:13:14 2021 +0000
@@ -1,13 +1,13 @@
-/*     $NetBSD: vnode_if.c,v 1.114 2021/07/02 16:57:15 dholland Exp $  */
+/*     $NetBSD: vnode_if.c,v 1.115 2021/10/20 03:13:14 thorpej Exp $   */
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
  * (Modifications made here may easily be lost!)
  *
  * Created from the file:
- *     NetBSD: vnode_if.src,v 1.82 2021/07/02 16:56:22 dholland Exp
+ *     NetBSD: vnode_if.src,v 1.83 2021/10/20 03:08:18 thorpej Exp
  * by the script:
- *     NetBSD: vnode_if.sh,v 1.70 2020/05/16 18:31:50 christos Exp
+ *     NetBSD: vnode_if.sh,v 1.72 2021/10/20 03:08:18 thorpej Exp
  */
 
 /*
@@ -40,11 +40,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vnode_if.c,v 1.114 2021/07/02 16:57:15 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vnode_if.c,v 1.115 2021/10/20 03:13:14 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/buf.h>
+#include <sys/fcntl.h>
 #include <sys/vnode.h>
 #include <sys/lock.h>
 #include <sys/fstrans.h>
@@ -89,6 +90,199 @@
        return 0;
 }
 
+static inline u_quad_t
+vop_pre_get_size(struct vnode *vp)
+{
+       mutex_enter(vp->v_interlock);
+       KASSERT(vp->v_size != VSIZENOTSET);
+       u_quad_t rv = (u_quad_t)vp->v_size;
+       mutex_exit(vp->v_interlock);
+
+       return rv;
+}
+
+/*
+ * VOP_RMDIR(), VOP_REMOVE(), and VOP_RENAME() need special handling
+ * because they each drop the caller's references on one or more of
+ * their arguments.  While there must be an open file descriptor in
+ * associated with a vnode in order for knotes to be attached to it,
+ * that status could change during the course of the operation.  So,
+ * for the vnode arguments that are WILLRELE or WILLPUT, we check
+ * pre-op if there are registered knotes, take a hold count if so,
+ * and post-op release the hold after activating any knotes still
+ * associated with the vnode.
+ */
+
+#define        VOP_POST_KNOTE(thisvp, e, n)                                    \
+do {                                                                   \
+       if (__predict_true((e) == 0)) {                                 \
+               /*                                                      \
+                * VN_KNOTE() does the VN_KEVENT_INTEREST()             \
+                * check for us.                                        \
+                */                                                     \
+               VN_KNOTE((thisvp), (n));                                \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define        VOP_POST_KNOTE_HELD(thisvp, e, n)                               \
+do {                                                                   \
+       /*                                                              \
+        * We don't perform a VN_KEVENT_INTEREST() check here; it       \
+        * was already performed when we did the pre-op work that       \
+        * caused the vnode to be held in the first place.              \
+        */                                                             \
+       mutex_enter((thisvp)->v_interlock);                             \
+       if (__predict_true((e) == 0)) {                                 \
+               knote(&(thisvp)->v_klist, (n));                         \
+       }                                                               \
+       holdrelel((thisvp));                                            \
+       mutex_exit((thisvp)->v_interlock);                              \
+       /*                                                              \
+        * thisvp might be gone now!  Don't touch!                      \
+        */                                                             \
+} while (/*CONSTCOND*/0)
+
+#define        vop_create_post(ap, e)                                          \
+       VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE)
+
+#define        vop_mknod_post(ap, e)                                           \
+       VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE)
+
+#define        vop_setattr_pre(ap)                                             \
+       u_quad_t osize = 0;                                             \
+       long vp_events =                                                \
+           VN_KEVENT_INTEREST((ap)->a_vp, NOTE_ATTRIB | NOTE_EXTEND)   \
+           ? NOTE_ATTRIB : 0;                                          \
+       bool check_extend = false;                                      \
+       if (__predict_false(vp_events != 0 &&                           \
+           (ap)->a_vap->va_size != VNOVALSIZE)) {                      \
+               check_extend = true;                                    \
+               osize = vop_pre_get_size((ap)->a_vp);                   \
+       }
+
+#define        vop_setattr_post(ap, e)                                         \
+do {                                                                   \
+       if (__predict_false(vp_events != 0)) {                          \
+               if (__predict_false(check_extend &&                     \
+                   (ap)->a_vap->va_size > osize)) {                    \
+                       vp_events |= NOTE_EXTEND;                       \
+               }                                                       \
+               VOP_POST_KNOTE((ap)->a_vp, (e), vp_events);             \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define        vop_setacl_post(ap, e)                                          \
+       VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_ATTRIB)
+
+#define        vop_link_post(ap, e)                                            \
+do {                                                                   \
+       VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE);                   \
+       VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_LINK);                     \
+} while (/*CONSTCOND*/0)
+
+#define        vop_mkdir_post(ap, e)                                           \
+       VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE | NOTE_LINK)
+
+#define        vop_remove_pre_common(ap)                                       \
+       bool post_event_vp =                                            \
+           VN_KEVENT_INTEREST((ap)->a_vp, NOTE_DELETE | NOTE_LINK);    \
+       if (__predict_false(post_event_vp)) {                           \
+               vhold((ap)->a_vp);                                      \
+       }
+
+#define        vop_remove_post_common(ap, e, dn, lc)                           \
+do {                                                                   \
+       VOP_POST_KNOTE((ap)->a_dvp, (e), (dn));                         \
+       if (__predict_false(post_event_vp)) {                           \
+               VOP_POST_KNOTE_HELD((ap)->a_vp, (e),                    \
+                   (lc) ? NOTE_LINK : NOTE_DELETE);                    \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+/*
+ * One could make the argument that VOP_REMOVE() should send NOTE_LINK
+ * on vp if the resulting link count is not zero, but that's not what
+ * the documentation says.
+ *
+ * We could change this easily by passing ap->ctx_vp_new_nlink to
+ * vop_remove_post_common().
+ */
+#define        vop_remove_pre(ap)                                              \
+       vop_remove_pre_common((ap));                                    \
+       /*                                                              \
+        * We will assume that the file being removed is deleted unless \
+        * the file system tells us otherwise by updating vp_new_nlink. \
+        */                                                             \
+       (ap)->ctx_vp_new_nlink = 0;
+
+#define        vop_remove_post(ap, e)                                          \
+       vop_remove_post_common((ap), (e), NOTE_WRITE, 0)
+
+#define        vop_rmdir_pre(ap)                                               \
+       vop_remove_pre_common(ap)
+
+#define        vop_rmdir_post(ap, e)                                           \
+       vop_remove_post_common((ap), (e), NOTE_WRITE | NOTE_LINK, 0)
+
+#define        vop_symlink_post(ap, e)                                         \
+       VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE)
+
+#define        vop_open_post(ap, e)                                            \
+       VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_OPEN)
+
+#define        vop_close_post(ap, e)                                           \
+do {                                                                   \
+       extern int (**dead_vnodeop_p)(void *);                          \
+                                                                       \
+       /* See the definition of VN_KNOTE() in <sys/vnode.h>. */        \
+       if (__predict_false(VN_KEVENT_INTEREST((ap)->a_vp,              \
+           NOTE_CLOSE_WRITE | NOTE_CLOSE) && (e) == 0)) {              \
+               struct vnode *thisvp = (ap)->a_vp;                      \
+               mutex_enter(thisvp->v_interlock);                       \
+               /*                                                      \
+                * Don't send NOTE_CLOSE when closing a vnode that's    \
+                * been reclaimed or otherwise revoked; a NOTE_REVOKE   \
+                * has already been sent, and this close is effectively \
+                * meaningless from the watcher's perspective.          \
+                */                                                     \
+               if (__predict_true(thisvp->v_op != dead_vnodeop_p)) {   \
+                       knote(&thisvp->v_klist,                         \
+                           ((ap)->a_fflag & FWRITE)                    \
+                           ? NOTE_CLOSE_WRITE : NOTE_CLOSE);           \
+               }                                                       \
+               mutex_exit(thisvp->v_interlock);                        \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
+#define        vop_read_post(ap, e)                                            \
+       VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_READ)
+
+#define        vop_write_pre(ap)                                               \
+       off_t ooffset = 0, noffset = 0;                                 \
+       u_quad_t osize = 0;                                             \
+       long vp_events =                                                \
+           VN_KEVENT_INTEREST((ap)->a_vp, NOTE_WRITE | NOTE_EXTEND)    \
+           ? NOTE_WRITE : 0;                                           \
+       if (__predict_false(vp_events != 0)) {                          \
+               ooffset = (ap)->a_uio->uio_offset;                      \
+               osize = vop_pre_get_size((ap)->a_vp);                   \
+       }
+
+#define        vop_write_post(ap, e)                                           \
+do {                                                                   \
+       /*                                                              \
+        * If any data was written, we'll post an event, even if        \
+        * there was an error.                                          \
+        */                                                             \
+       noffset = (ap)->a_uio->uio_offset;                              \
+       if (__predict_false(vp_events != 0 && noffset > ooffset)) {     \
+               if (noffset > osize) {                                  \
+                       vp_events |= NOTE_EXTEND;                       \
+               }                                                       \
+               VN_KNOTE((ap)->a_vp, vp_events);                        \
+       }                                                               \
+} while (/*CONSTCOND*/0)
+
 static inline void
 vop_post(vnode_t *vp, struct mount *mp, bool mpsafe, enum fst_op op)
 {
@@ -251,6 +445,7 @@
                return error;
        error = (VCALL(dvp, VOFFSET(vop_create), &a));
        vop_post(dvp, mp, mpsafe, FST_NO);
+       vop_create_post(&a, error);
 #ifdef DIAGNOSTIC
        if (error == 0)
                KASSERT((*vpp)->v_size != VSIZENOTSET
@@ -292,6 +487,7 @@
                return error;
        error = (VCALL(dvp, VOFFSET(vop_mknod), &a));
        vop_post(dvp, mp, mpsafe, FST_NO);
+       vop_mknod_post(&a, error);
 #ifdef DIAGNOSTIC
        if (error == 0)
                KASSERT((*vpp)->v_size != VSIZENOTSET
@@ -331,6 +527,7 @@
                return error;
        error = (VCALL(vp, VOFFSET(vop_open), &a));
        vop_post(vp, mp, mpsafe, FST_NO);
+       vop_open_post(&a, error);
        return error;
 }
 
@@ -365,6 +562,7 @@
                return error;
        error = (VCALL(vp, VOFFSET(vop_close), &a));
        vop_post(vp, mp, mpsafe, FST_NO);
+       vop_close_post(&a, error);
        return error;
 }
 
@@ -496,11 +694,13 @@
        a.a_vp = vp;
        a.a_vap = vap;
        a.a_cred = cred;
+       vop_setattr_pre(&a);
        error = vop_pre(vp, &mp, &mpsafe, FST_NO);
        if (error)
                return error;
        error = (VCALL(vp, VOFFSET(vop_setattr), &a));
        vop_post(vp, mp, mpsafe, FST_NO);
+       vop_setattr_post(&a, error);
        return error;
 }
 
@@ -537,6 +737,7 @@
                return error;
        error = (VCALL(vp, VOFFSET(vop_read), &a));
        vop_post(vp, mp, mpsafe, FST_NO);
+       vop_read_post(&a, error);
        return error;
 }
 
@@ -568,11 +769,13 @@
        a.a_uio = uio;
        a.a_ioflag = ioflag;
        a.a_cred = cred;
+       vop_write_pre(&a);
        error = vop_pre(vp, &mp, &mpsafe, FST_NO);
        if (error)
                return error;
        error = (VCALL(vp, VOFFSET(vop_write), &a));
        vop_post(vp, mp, mpsafe, FST_NO);
+       vop_write_post(&a, error);
        return error;



Home | Main Index | Thread Index | Old Index