Regarding vop_vector
Kirk McKusick
mckusick at mckusick.com
Sun Feb 25 06:42:02 UTC 2018
> From: Aijaz Baig <aijazbaig1 at gmail.com>
> Date: Sun, 25 Feb 2018 07:24:12 +0530
> Subject: Regarding vop_vector
> To: freebsd-fs at freebsd.org
>
> Hello
>
> I am trying to understand how the VFS layer within FreeBSD and I was rather
> stumped while trying to find where vop_vector was declared. Upon searching
> the internet, realized that an awk script is used to "generate" this like so:
>
> /sys/tools/vnode_if.awk /sys/kern/vnode_if.src -q
>
> So I was wondering if anyone could provide me a (brief would be fine as
> well) walk through the memory lane as to why such an 'odd looking' way was
> adopted (perhaps it is brilliant but my thick skull is unable to fathom
> it's brilliance).
>
> Keen to hear from you experts out there please!
> --
> Best Regards,
> Aijaz Baig
As the person that came up with this idea (in the 1980's) let me try to
explain my thinking. Suppose you want to add a new VFS operation. Before
I created the script, you had to create macros for it in at least four
different files. Now you just need to add a concise and readable description
of it in /sys/kern/vnode_if.src then run the script and all the boilerplate
gets generated for you.
Let me give you a short example. Consider the VFS operator to check to
see if a vnode is locked, typically used as
if (VOP_ISLOCKED(vp)) {
do something with locked vp;
}
The description of it in /sys/kern/vnode_if.src is three lines:
vop_islocked {
IN struct vnode *vp;
};
Here is what is generated for it in the compile directory by the awk script.
In /sys/amd64/compile/GENERIC/vnode_if.c:
static int vop_islocked_vp_offsets[] = {
VOPARG_OFFSETOF(struct vop_islocked_args,a_vp),
VDESC_NO_OFFSET
};
SDT_PROBE_DEFINE2(vfs, vop, vop_islocked, entry, "struct vnode *", "struct vop_islocked_args *");
SDT_PROBE_DEFINE3(vfs, vop, vop_islocked, return, "struct vnode *", "struct vop_islocked_args *", "int");
int
VOP_ISLOCKED_AP(struct vop_islocked_args *a)
{
return(VOP_ISLOCKED_APV(a->a_vp->v_op, a));
}
int
VOP_ISLOCKED_APV(struct vop_vector *vop, struct vop_islocked_args *a)
{
int rc;
VNASSERT(a->a_gen.a_desc == &vop_islocked_desc, a->a_vp,
("Wrong a_desc in vop_islocked(%p, %p)", a->a_vp, a));
while(vop != NULL && \
vop->vop_islocked == NULL && vop->vop_bypass == NULL)
vop = vop->vop_default;
VNASSERT(vop != NULL, a->a_vp, ("No vop_islocked(%p, %p)", a->a_vp, a));
SDT_PROBE2(vfs, vop, vop_islocked, entry, a->a_vp, a);
KTR_START1(KTR_VOP, "VOP", "VOP_ISLOCKED", (uintptr_t)a,
"vp:0x%jX", (uintptr_t)a->a_vp);
VFS_PROLOGUE(a->a_vp->v_mount);
if (vop->vop_islocked != NULL)
rc = vop->vop_islocked(a);
else
rc = vop->vop_bypass(&a->a_gen);
VFS_EPILOGUE(a->a_vp->v_mount);
SDT_PROBE3(vfs, vop, vop_islocked, return, a->a_vp, a, rc);
if (rc == 0) {
} else {
}
KTR_STOP1(KTR_VOP, "VOP", "VOP_ISLOCKED", (uintptr_t)a,
"vp:0x%jX", (uintptr_t)a->a_vp);
return (rc);
}
struct vnodeop_desc vop_islocked_desc = {
"vop_islocked",
0,
(vop_bypass_t *)VOP_ISLOCKED_AP,
vop_islocked_vp_offsets,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
};
In /sys/amd64/compile/GENERIC/vnode_if.h:
struct vop_islocked_args {
struct vop_generic_args a_gen;
struct vnode *a_vp;
};
extern struct vnodeop_desc vop_islocked_desc;
int VOP_ISLOCKED_AP(struct vop_islocked_args *);
int VOP_ISLOCKED_APV(struct vop_vector *vop, struct vop_islocked_args *);
static __inline int VOP_ISLOCKED(
struct vnode *vp)
{
struct vop_islocked_args a;
a.a_gen.a_desc = &vop_islocked_desc;
a.a_vp = vp;
return (VOP_ISLOCKED_APV(vp->v_op, &a));
}
In /sys/amd64/compile/GENERIC/vnode_if_newproto.h,
an entry in the vop_vector array:
struct vop_vector {
struct vop_vector *vop_default;
vop_bypass_t *vop_bypass;
vop_islocked_t *vop_islocked;
...
};
And finally in /sys/amd64/compile/GENERIC/vnode_if_typedef.h:
struct vop_islocked_args;
typedef int vop_islocked_t(struct vop_islocked_args *);
And absent this script, every time you wanted to make a change in the
boilerplate, you would have to go through and fix it for every existing
VFS operator (and trust me the boilerplate has changed a *lot* since I
first did it in the 1980's :-)
Kirk McKusick
More information about the freebsd-fs
mailing list