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.
This commit is contained in:
thorpej 2021-10-20 03:13:14 +00:00
parent 982ae832c3
commit 051986d92d
4 changed files with 232 additions and 19 deletions

View File

@ -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 @@ vop_pre(vnode_t *vp, struct mount **mp, bool *mpsafe, enum fst_op op)
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 @@ VOP_CREATE(struct vnode *dvp,
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 @@ VOP_MKNOD(struct vnode *dvp,
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 @@ VOP_OPEN(struct vnode *vp,
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 @@ VOP_CLOSE(struct vnode *vp,
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 @@ VOP_SETATTR(struct vnode *vp,
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 @@ VOP_READ(struct vnode *vp,
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 @@ VOP_WRITE(struct vnode *vp,
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;
}
@ -925,8 +1128,8 @@ VOP_SEEK(struct vnode *vp,
}
const int vop_remove_vp_offsets[] = {
VOPARG_OFFSETOF(struct vop_remove_v2_args,a_dvp),
VOPARG_OFFSETOF(struct vop_remove_v2_args,a_vp),
VOPARG_OFFSETOF(struct vop_remove_v3_args,a_dvp),
VOPARG_OFFSETOF(struct vop_remove_v3_args,a_vp),
VDESC_NO_OFFSET
};
const struct vnodeop_desc vop_remove_desc = {
@ -936,7 +1139,7 @@ const struct vnodeop_desc vop_remove_desc = {
vop_remove_vp_offsets,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VOPARG_OFFSETOF(struct vop_remove_v2_args, a_cnp),
VOPARG_OFFSETOF(struct vop_remove_v3_args, a_cnp),
};
int
VOP_REMOVE(struct vnode *dvp,
@ -945,17 +1148,19 @@ VOP_REMOVE(struct vnode *dvp,
{
int error;
bool mpsafe;
struct vop_remove_v2_args a;
struct vop_remove_v3_args a;
struct mount *mp;
a.a_desc = VDESC(vop_remove);
a.a_dvp = dvp;
a.a_vp = vp;
a.a_cnp = cnp;
vop_remove_pre(&a);
error = vop_pre(dvp, &mp, &mpsafe, FST_NO);
if (error)
return error;
error = (VCALL(dvp, VOFFSET(vop_remove), &a));
vop_post(dvp, mp, mpsafe, FST_NO);
vop_remove_post(&a, error);
return error;
}
@ -991,6 +1196,7 @@ VOP_LINK(struct vnode *dvp,
return error;
error = (VCALL(dvp, VOFFSET(vop_link), &a));
vop_post(dvp, mp, mpsafe, FST_NO);
vop_link_post(&a, error);
return error;
}
@ -1070,6 +1276,7 @@ VOP_MKDIR(struct vnode *dvp,
return error;
error = (VCALL(dvp, VOFFSET(vop_mkdir), &a));
vop_post(dvp, mp, mpsafe, FST_NO);
vop_mkdir_post(&a, error);
#ifdef DIAGNOSTIC
if (error == 0)
KASSERT((*vpp)->v_size != VSIZENOTSET
@ -1105,11 +1312,13 @@ VOP_RMDIR(struct vnode *dvp,
a.a_dvp = dvp;
a.a_vp = vp;
a.a_cnp = cnp;
vop_rmdir_pre(&a);
error = vop_pre(dvp, &mp, &mpsafe, FST_NO);
if (error)
return error;
error = (VCALL(dvp, VOFFSET(vop_rmdir), &a));
vop_post(dvp, mp, mpsafe, FST_NO);
vop_rmdir_post(&a, error);
return error;
}
@ -1148,6 +1357,7 @@ VOP_SYMLINK(struct vnode *dvp,
return error;
error = (VCALL(dvp, VOFFSET(vop_symlink), &a));
vop_post(dvp, mp, mpsafe, FST_NO);
vop_symlink_post(&a, error);
#ifdef DIAGNOSTIC
if (error == 0)
KASSERT((*vpp)->v_size != VSIZENOTSET
@ -1771,6 +1981,7 @@ VOP_SETACL(struct vnode *vp,
return error;
error = (VCALL(vp, VOFFSET(vop_setacl), &a));
vop_post(vp, mp, mpsafe, FST_YES);
vop_setacl_post(&a, error);
return error;
}

View File

@ -1,13 +1,13 @@
/* $NetBSD: rumpvnode_if.h,v 1.36 2021/07/02 16:57:15 dholland Exp $ */
/* $NetBSD: rumpvnode_if.h,v 1.37 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
*/
/*

View File

@ -1,13 +1,13 @@
/* $NetBSD: rumpvnode_if.c,v 1.36 2021/07/02 16:57:16 dholland Exp $ */
/* $NetBSD: rumpvnode_if.c,v 1.37 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: rumpvnode_if.c,v 1.36 2021/07/02 16:57:16 dholland Exp $");
__KERNEL_RCSID(0, "$NetBSD: rumpvnode_if.c,v 1.37 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 <rump/rumpvnode_if.h>

View File

@ -1,13 +1,13 @@
/* $NetBSD: vnode_if.h,v 1.107 2021/07/02 16:57:15 dholland Exp $ */
/* $NetBSD: vnode_if.h,v 1.108 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
*/
/*
@ -290,11 +290,12 @@ extern const struct vnodeop_desc vop_seek_desc;
int VOP_SEEK(struct vnode *, off_t, off_t, kauth_cred_t);
#define VOP_REMOVE_DESCOFFSET 24
struct vop_remove_v2_args {
struct vop_remove_v3_args {
const struct vnodeop_desc *a_desc;
struct vnode *a_dvp;
struct vnode *a_vp;
struct componentname *a_cnp;
nlink_t ctx_vp_new_nlink;
};
extern const struct vnodeop_desc vop_remove_desc;
int VOP_REMOVE(struct vnode *, struct vnode *, struct componentname *);