tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Vnode API change: add global vnode cache



On 07 Apr 2014, at 03:22, Taylor R Campbell 
<campbell+netbsd-tech-kern%mumble.net@localhost> wrote:

>   Date: Sun, 6 Apr 2014 12:14:24 +0200
>   From: "J. Hannken-Illjes" <hannken%eis.cs.tu-bs.de@localhost>
> 
>   Currently all file systems have to implement their own cache of
>   vnode / fs node pairs.  Most file systems use a copy and pasted
>   version of ufs_ihash.
> 
>   So add a global vnode cache with lookup and remove:
>   [...]
>   http://www.netbsd.org/~hannken/vnode-pass6-1.diff
> 
>   Comments or objections anyone?
> 
> Generally looks pretty good, and largely better than the draft I threw
> together last month to do more or less the same thing.
> 
> There are a number of file systems that have copypasta of ufs_ihash;
> adapting these too to vcache should be a piece of cake.  Have you
> surveyed the more different file systems -- e.g., nfs, coda, tmpfs,
> puffs -- to see whether this abstraction will make sense there too?
> 
> Some specific comments:
> 
>   int
>   vcache_lookup(struct mount *mp, void *key, size_t key_len, struct vnode 
> **vpp)
> 
> Call it vcache_intern rather than vcache_lookup, since it inserts if
> not already there?

Ok.

> Why `void *key' and not `const void *key'?
> 
>   void
>   vcache_remove(struct mount *mp, void *key, size_t key_len)
> 
> Same about `void *key'.
> 
>   int
>   vfs_load_node(struct mount *mp, struct vnode *vp,
>       const void *key, size_t key_len, void **new_key)
> 
> Same about `void **new_key'.

Ok - all const now.

>   +static kmutex_t                vcache_lock             __cacheline_aligned;
>   +static kcondvar_t      vcache_cv               __cacheline_aligned;
>   +static rb_tree_t       vcache_rb_tree          __cacheline_aligned;
> 
> Do these all need to be cacheline-aligned separately?  Is vcache_lock
> not enough, since the others will be used only while vcache_lock is
> held?  Or, how about this?
> 
> struct {
>       kmutex_t lock;
>       kcondvar_t cv;
>       rb_tree_t tree;
> } vcache __cacheline_aligned;

Ok - using a struct looks good.

>   +int
>   +vcache_lookup(struct mount *mp, void *key, size_t key_len, struct vnode 
> **vpp)
>   +{
>   ...
>   +#ifdef DIAGNOSTICS
> 
> DIAGNOSTIC, not DIAGNOSTICS.
> 
>   +       new_key = NULL;
>   +       *vpp = NULL;
>   +#endif
> 
> Why not just make these unconditional, or remove the unconditional
> assertions that rely on them?  We generally ought to avoid assertions
> that are true only if DIAGNOSTIC -- it makes code harder to reason
> about.  If I see KASSERT(*vpp != NULL), I am going to assume that *vpp
> is nonnull, whether DIAGNOSTIC is set or not.

Removed the #ifdef and always clear new_key and *vpp on top.

>   +       if (node != NULL /* && node->vn_node == NULL */) {
> 
> Turn the commented fragment into a kassert.

Ok.

>   +       new_node = kmem_alloc(sizeof(*new_node), KM_SLEEP);
> 
> Should use pool_cache(9) rather than kmem(9) for fixed allocation.

Ok.

>   +       vp = vnalloc(NULL);
>   +       vp->v_usecount = 1;
>   +       vp->v_type = VNON;
>   +       vp->v_size = vp->v_writesize = VSIZENOTSET;
> 
> Is the plan to nix getnewvnode and ungetnewvnode?  It would be good to
> avoid long-term duplication of its body.  But I suspect we'll want to
> keep those for, e.g., tmpfs, in which case this should use getnewvnode
> and ungetnewvnode instead of vnalloc/setup/teardown/vnfree.

Not sure if we have to keep getnewvnode() in the long term.

It cannot be used here as we don't want the partially initialised
vnode (before VFS_LOAD_NODE) on the mnt_vnodelist.

If we end up replacing getnewvnode() with a two-stage allocator that
initialises in the first stage and finalises in the second stage we
may use it here.

>   +       /* Load the fs node.  Exclusive as new_node->vn_vnode is NULL. */
>   +       error = VFS_LOAD_NODE(mp, vp, key, key_len, &new_key);
>   +       if (error == 0) {
> 
> Switch the sense of this branch so the main-line code is success and
> the indented (and shorter) alternative is failure.

Ok.

>    /*
>   + * Look up and return a vnode/inode pair by inode number.
>   + */
>   +int
>   +ufs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
>   +{
> 
> Does anything use VFS_VGET in ufs now?  If so, why?  If not, this
> should just fail.  (Eventually we ought to nix VFS_VGET, I think.)

VFS_VGET() is used by NFS V3 readdirplus so we have to keep it.

> The one call in ufs_rename.c should be easy to fix -- just replace
> 
>       VOP_UNLOCK(vp);
>       error = VFS_VGET(mp, dotdot_ino, &dvp);
>       vrele(vp);
> 
> by
> 
>       error = vcache_intern(mp, &dotdot_ino, sizeof(dotdot_ino), &dvp);
>       vput(vp);

This is wrong, did you mean

        error = vcache_intern(mp, &dotdot_ino, sizeof(dotdot_ino), &dvp);
        vput(vp);
        if (error)
                return error;
        error = vn_lock(dvp, LK_EXCLUSIVE);
        if (error)
                return error;

Anyway, not now.

New diff at http://www.netbsd.org/~hannken/vnode-pass6-2.diff

--
J. Hannken-Illjes - hannken%eis.cs.tu-bs.de@localhost - TU Braunschweig 
(Germany)



Home | Main Index | Thread Index | Old Index