Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 24 Feb 2018 22:42:08 -0800
From:      Kirk McKusick <mckusick@mckusick.com>
To:        Aijaz Baig <aijazbaig1@gmail.com>
Cc:        freebsd-fs@freebsd.org
Subject:   Re: Regarding vop_vector
Message-ID:  <201802250642.w1P6g8Wm064509@chez.mckusick.com>
In-Reply-To: <CAHB2L%2BeDUEsJzzoECAKAYVa4KyndDGX2ZLCX_RgL_Y21%2BO4=jA@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
> From: Aijaz Baig <aijazbaig1@gmail.com>
> Date: Sun, 25 Feb 2018 07:24:12 +0530
> Subject: Regarding vop_vector
> To: freebsd-fs@freebsd.org
> =

> Hello
> =

> I am trying to understand how the VFS layer within FreeBSD and I was rat=
her
> stumped while trying to find where vop_vector was declared. Upon searchi=
ng
> the internet, realized that an awk script is used to "generate" this lik=
e 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 w=
as
> 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 descripti=
on
of it in /sys/kern/vnode_if.src then run the script and all the boilerplat=
e
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 scrip=
t.
In /sys/amd64/compile/GENERIC/vnode_if.c:

static int vop_islocked_vp_offsets[] =3D {
	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 *", "struc=
t 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 =3D=3D &vop_islocked_desc, a->a_vp,
	    ("Wrong a_desc in vop_islocked(%p, %p)", a->a_vp, a));
	while(vop !=3D NULL && \
	    vop->vop_islocked =3D=3D NULL && vop->vop_bypass =3D=3D NULL)
		vop =3D vop->vop_default;
	VNASSERT(vop !=3D 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 !=3D NULL)
		rc =3D vop->vop_islocked(a);
	else
		rc =3D 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 =3D=3D 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 =3D {
	"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 =3D &vop_islocked_desc;
	a.a_vp =3D 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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802250642.w1P6g8Wm064509>