Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Dec 1999 05:50:16 +0800
From:      Peter Wemm <peter@netplex.com.au>
To:        Terry Lambert <tlambert@primenet.com>
Cc:        robert+freebsd@cyrus.watson.org, freebsd-fs@FreeBSD.ORG
Subject:   Re: Request for objections: extended attribute and ACL interfaces 
Message-ID:  <19991218215016.32B321CA0@overcee.netplex.com.au>
In-Reply-To: Message from Terry Lambert <tlambert@primenet.com>  of "Sat, 18 Dec 1999 20:05:04 GMT." <199912182005.NAA01764@usr08.primenet.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
Terry Lambert wrote:
> > Terry, why don't you freaking well *look* at the code every now and then?
> > This *is* implemented and works already, for over a year now.

I note that you carefully deleted your original statements, which I'll
re-quote for context:

> The Heidemann framework supports the ability to add VOP's to an
> existing system.  FreeBSD doesn't currently support this, but it
> could be fixed to do so, simply by making *vfs_op_descs[] a
> pointer reference, and reallocating it as needed in order to
> grow the descriptor list using loaded descriptors.

Fact: you said "FreeBSD doesn't support this", which is wrong.  We do
add VOP's to an existing system.

Fact: your suggestion about making *vfs_op_descs[] a pointer reference
is already done, exactly as you suggested, and it was done over 12 months
ago.

My point that you should *read* the code rather than make blanket
statements still stands.  Now that you appear to have read it (at last,
thank you!), your comments on the implementation are worth something.

> Peter, it should work without any handlers being present.

And what should it do?  OK, suppose there is an expanded VOP_* inline 
compiled into a binary to do the VCALL() etc.  Now, there is no handler or
descriptor present.  How is the stacking layer supposed to deal with that?  It
doesn't have an offset to work with..

> At the
> FreeBSDCon, Kirk agreed that the vfs_default.c stuff damaged the
> abstraction between UFS and FFS layers, which are supposed to be
> seperated as block management policy and directory hierarchy policy
> layers.  Ask Matt Dillon or Poul-Henning.

I'm not talking about UFS/FFS layers.  I was responding to and talking
about one specific part, adding VOPs dynamically.

Have you looked at the vfs_default.c stuff BTW?  It doesn't do anything
unless the target filesystem specifically activates it.  If the target
filesystem supports some sort of passthrough (such as unionfs), then it
doesn't use vop_defaultop() as a catch-all.  Unionfs (for example) provides
it's own and has absolutely no interference from vfs_default.c.  The VOP
layer doesn't use vop_default.c unless the terminal filesystem
*specifically* requests it when it has no passthrough capabilities.   You
will note that ffs/ffs_vnops.c (the upper layer) has it's own vop_default
handler (ufs_vnopoerate) with passes all unknown VOP's to the lower UFS layer.
If UFS can't handle them, then UFS hands it off to vop_defaultop().  FFS is
functioning as a passthrough layer.

ufs_vnops.c (bottom layer):
int
ufs_vnoperate(ap)
        struct vop_generic_args /* {
                struct vnodeop_desc *a_desc;
        } */ *ap;
{
        return (VOCALL(ufs_vnodeop_p, ap->a_desc->vdesc_offset, ap));
}

ffs_vnops.c (top layer):
vop_t **ffs_vnodeop_p;
static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
        { &vop_default_desc,            (vop_t *) ufs_vnoperate },  <<<<
        { &vop_fsync_desc,              (vop_t *) ffs_fsync },
        { &vop_getpages_desc,           (vop_t *) ffs_getpages },
        { &vop_putpages_desc,           (vop_t *) ffs_putpages },
        { &vop_read_desc,               (vop_t *) ffs_read },
        { &vop_balloc_desc,             (vop_t *) ffs_balloc },
        { &vop_reallocblks_desc,        (vop_t *) ffs_reallocblks },
        { &vop_write_desc,              (vop_t *) ffs_write },
        { NULL, NULL }
};

ie: ffs specifically intercepts the functions it's interested and then passes
the rest through to UFS, *without interference from vfs_default.c*!

As UFS is a terminal layer, it (rightly) terminates any unhandled requests.

> Peter, there is no rendevous by name for new VOPs so that they can be
> passed from a loaded stacking layer that knows about a new VOP to
> an underlying stacking layer that knows about the new VOP, through
> one that doesn't.  For example, an ACLFS layer mounted over top of
> a translucent FS mounted over top of a read only FS and backing media
> so that I can put ACLs on the contents of my CDROM that I'm making
> available to user on my system.  If the backing media already knows
> about VOP_ACL, you are screwed: it's not the same VOP_ACL, unless
> you imply a dependency between kernel modules that you should not be
> implying.

The descriptors are global scope..  You can't have two different VOP's by
the same name.

vnode_if.h:
extern struct vnodeop_desc vop_islocked_desc;
static __inline int VOP_ISLOCKED(vp, p)
        struct vnode *vp;
        struct proc *p;
{
        struct vop_islocked_args a;
        int rc;
        a.a_desc = VDESC(vop_islocked);
        a.a_vp = vp;
        a.a_p = p;
        rc = VCALL(vp, VOFFSET(vop_islocked), &a);
        return (rc);
}
(vnode_if.c contains the declarations of the _desc structs.)

VDESC() expands so that it's the equivalent of:  a.a_desc = &vop_islocked_desc;
This cannot work with two global vop_acl_desc's.

We can add and remove descriptors on the fly.  An intermediate layer operating
in passthrough mode (eg: FFS, unionfs) does not need *any* knowledge of the
VOPs being passed through it.

You state:
>  there is no rendevous by name for new VOPs so that they can be
> passed from a loaded stacking layer that knows about a new VOP to
> an underlying stacking layer that knows about the new VOP, through
> one that doesn't.
This is not entirely correct.  There is no "string" as such, but the
rendesvous is a global variable.  (eg: vop_acl_desc).  It *can* pass
through an intermediate layer without interference from vfs_default.c.

> Peter, the decriptor list isn't sorted so that a dereference
> can be done by index.  Not only is the overhead for this higher, the
> addition of a new VOP is an O(3) random traversal instead of O(1)
> linear traversal for existing instanced VFSs.

So?  A once-off cost at boot/load/unload time doesn't mean much as long as
there isn't a runtime penalty.  I don't believe there is a runtime penalty
as it uses the exact same VCALL/VOCALL implementation as before. The cost
of indexing a 30-odd entry array at boot is nothing compared to things like
waiting for IDE disks to stabilize.   If you think you can make it faster,
be my guest.  If you send a single purpose patch that makes it faster without
mixing other changes in, you will have my full attention.

> This change is incomplete; it does not fully solve the problem
> noted in my previous email.

I am not denying that more work can be done, but object to you saying that
"it isn't supported".  The more code I read and check the more I think the
problems you talked about aren't real either - aside from not supporting
two different VOP_ACL()'s in the same kernel at the same time (which I
think is of questionable value - that opens real cans of worms that we
could do without..  like *which* VOP_ACL() is which?).

> Don't assume the code is right and I am wrong, just because you
> are emotionally invested in the code.

I am "emotionally invested" in people spreading misinformation and blanket
statements that are clearly false.  Your claim that FreeBSD does not currently
support dynamically adding VOP's is wrong.

Cheers,
-Peter




To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-fs" in the body of the message




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