svn commit: r367631 - in head/sys: kern sys

Conrad Meyer cem at freebsd.org
Fri Nov 13 16:24:54 UTC 2020


Hi Konstantin,

On Fri, Nov 13, 2020 at 1:32 AM Konstantin Belousov <kib at freebsd.org> wrote:
>
> Author: kib
> Date: Fri Nov 13 09:31:57 2020
> New Revision: 367631
> URL: https://svnweb.freebsd.org/changeset/base/367631
>
> Log:
>   Implement vn_lock_pair().
>
> Modified: head/sys/kern/vfs_vnops.c
> ==============================================================================
> --- head/sys/kern/vfs_vnops.c   Fri Nov 13 02:05:45 2020        (r367630)
> +++ head/sys/kern/vfs_vnops.c   Fri Nov 13 09:31:57 2020        (r367631)
> @@ -3317,4 +3325,92 @@ vn_fallocate(struct file *fp, off_t offset, off_t len,
> ...
> +
> +static void
> +vn_lock_pair_pause(const char *wmesg)
> +{
> +       atomic_add_long(&vn_lock_pair_pause_cnt, 1);
> +       pause(wmesg, prng32_bounded(hz / 10));
> +}

This function is called when the try-lock of the second lock in the
pair (either order) fails.  The back-off period is up to 100ms,
expected average 50ms.  That seems really high?

Separately: prng32_bounded() may return 0, which is transparently
converted to the equivalent of 1 by pause_sbt(9).  This means a 1 tick
pause is marginally more likely than any other possible duration.  It
probably doesn't matter.

Thanks,
Conrad

> +
> +/*
> + * Lock pair of vnodes vp1, vp2, avoiding lock order reversal.
> + * vp1_locked indicates whether vp1 is exclusively locked; if not, vp1
> + * must be unlocked.  Same for vp2 and vp2_locked.  One of the vnodes
> + * can be NULL.
> + *
> + * The function returns with both vnodes exclusively locked, and
> + * guarantees that it does not create lock order reversal with other
> + * threads during its execution.  Both vnodes could be unlocked
> + * temporary (and reclaimed).
> + */
> +void
> +vn_lock_pair(struct vnode *vp1, bool vp1_locked, struct vnode *vp2,
> +    bool vp2_locked)
> +{
> +       int error;
> +
> +       if (vp1 == NULL && vp2 == NULL)
> +               return;
> +       if (vp1 != NULL) {
> +               if (vp1_locked)
> +                       ASSERT_VOP_ELOCKED(vp1, "vp1");
> +               else
> +                       ASSERT_VOP_UNLOCKED(vp1, "vp1");
> +       } else {
> +               vp1_locked = true;
> +       }
> +       if (vp2 != NULL) {
> +               if (vp2_locked)
> +                       ASSERT_VOP_ELOCKED(vp2, "vp2");
> +               else
> +                       ASSERT_VOP_UNLOCKED(vp2, "vp2");
> +       } else {
> +               vp2_locked = true;
> +       }
> +       if (!vp1_locked && !vp2_locked) {
> +               vn_lock(vp1, LK_EXCLUSIVE | LK_RETRY);
> +               vp1_locked = true;
> +       }
> +
> +       for (;;) {
> +               if (vp1_locked && vp2_locked)
> +                       break;
> +               if (vp1_locked && vp2 != NULL) {
> +                       if (vp1 != NULL) {
> +                               error = VOP_LOCK1(vp2, LK_EXCLUSIVE | LK_NOWAIT,
> +                                   __FILE__, __LINE__);
> +                               if (error == 0)
> +                                       break;
> +                               VOP_UNLOCK(vp1);
> +                               vp1_locked = false;
> +                               vn_lock_pair_pause("vlp1");

(Pause called here and in similar elided case for vp2 -> vp1 below.)

> +                       }
> +                       vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY);
> +                       vp2_locked = true;
> +               }


More information about the svn-src-head mailing list