Regarding vop_vector

Aijaz Baig aijazbaig1 at gmail.com
Sun Apr 1 10:09:49 UTC 2018


Thank you for the detailed summary! Will go through

On Sun, Feb 25, 2018 at 12:12 PM, Kirk McKusick <mckusick at mckusick.com>
wrote:

> > 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
>



-- 

Best Regards,
Aijaz Baig


More information about the freebsd-fs mailing list