Print this page
3746 ZRLs are racy
Reviewed by: Boris Protopopov <bprotopopov@hotmail.com>
Reviewed by: Pavel Zakharov <pavel.zakha@gmail.com>
Reviewed by: Yuri Pankov <yuri.pankov@gmail.com>
Reviewed by: Justin T. Gibbs <gibbs@scsiguy.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/zrlock.c
          +++ new/usr/src/uts/common/fs/zfs/zrlock.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 2014, 2015 by Delphix. All rights reserved.
       24 + * Copyright 2016 Spectra Logic Corporation. All rights reserved.
       25 + * Copyright 2016 The MathWorks, Inc. All rights reserved.
  24   26   */
  25   27  
  26   28  /*
  27   29   * A Zero Reference Lock (ZRL) is a reference count that can lock out new
  28   30   * references only when the count is zero and only without waiting if the count
  29   31   * is not already zero. It is similar to a read-write lock in that it allows
  30   32   * multiple readers and only a single writer, but it does not allow a writer to
  31   33   * block while waiting for readers to exit, and therefore the question of
  32   34   * reader/writer priority is moot (no WRWANT bit). Since the equivalent of
  33   35   * rw_enter(&lock, RW_WRITER) is disallowed and only tryenter() is allowed, it
↓ open down ↓ 30 lines elided ↑ open up ↑
  64   66          ASSERT0(zrl->zr_refcount);
  65   67  
  66   68          mutex_destroy(&zrl->zr_mtx);
  67   69          zrl->zr_refcount = ZRL_DESTROYED;
  68   70          cv_destroy(&zrl->zr_cv);
  69   71  }
  70   72  
  71   73  void
  72   74  zrl_add_impl(zrlock_t *zrl, const char *zc)
  73   75  {
  74      -        uint32_t n = (uint32_t)zrl->zr_refcount;
       76 +        for (;;) {
       77 +                uint32_t n = (uint32_t)zrl->zr_refcount;
  75   78  
  76      -        while (n != ZRL_LOCKED) {
  77      -                uint32_t cas = atomic_cas_32(
  78      -                    (uint32_t *)&zrl->zr_refcount, n, n + 1);
  79      -                if (cas == n) {
  80      -                        ASSERT3S((int32_t)n, >=, 0);
       79 +                while (n != ZRL_LOCKED) {
       80 +                        uint32_t cas = atomic_cas_32(
       81 +                            (uint32_t *)&zrl->zr_refcount, n, n + 1);
       82 +
       83 +                        if (cas == n) {
       84 +                                ASSERT3S((int32_t)n, >=, 0);
  81   85  #ifdef  ZFS_DEBUG
  82      -                        if (zrl->zr_owner == curthread) {
  83      -                                DTRACE_PROBE2(zrlock__reentry,
  84      -                                    zrlock_t *, zrl, uint32_t, n);
  85      -                        }
  86      -                        zrl->zr_owner = curthread;
  87      -                        zrl->zr_caller = zc;
       86 +                                if (zrl->zr_owner == curthread) {
       87 +                                        DTRACE_PROBE2(zrlock__reentry,
       88 +                                            zrlock_t *, zrl, uint32_t, n);
       89 +                                }
       90 +                                zrl->zr_owner = curthread;
       91 +                                zrl->zr_caller = zc;
  88   92  #endif
  89      -                        return;
       93 +                                return;
       94 +                        }
       95 +                        n = cas;
  90   96                  }
  91      -                n = cas;
  92      -        }
  93   97  
  94      -        mutex_enter(&zrl->zr_mtx);
  95      -        while (zrl->zr_refcount == ZRL_LOCKED) {
  96      -                cv_wait(&zrl->zr_cv, &zrl->zr_mtx);
       98 +                mutex_enter(&zrl->zr_mtx);
       99 +                while (zrl->zr_refcount == ZRL_LOCKED) {
      100 +                        cv_wait(&zrl->zr_cv, &zrl->zr_mtx);
      101 +                }
      102 +                mutex_exit(&zrl->zr_mtx);
  97  103          }
  98      -        ASSERT3S(zrl->zr_refcount, >=, 0);
  99      -        zrl->zr_refcount++;
 100      -#ifdef  ZFS_DEBUG
 101      -        zrl->zr_owner = curthread;
 102      -        zrl->zr_caller = zc;
 103      -#endif
 104      -        mutex_exit(&zrl->zr_mtx);
 105  104  }
 106  105  
 107  106  void
 108  107  zrl_remove(zrlock_t *zrl)
 109  108  {
 110  109          uint32_t n;
 111  110  
 112  111  #ifdef  ZFS_DEBUG
 113  112          if (zrl->zr_owner == curthread) {
 114  113                  zrl->zr_owner = NULL;
↓ open down ↓ 77 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX