The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/zfs/zrlock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 /*
   22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   23  * Copyright (c) 2014, 2015 by Delphix. All rights reserved.
   24  * Copyright 2016 The MathWorks, Inc. All rights reserved.
   25  */
   26 
   27 /*
   28  * A Zero Reference Lock (ZRL) is a reference count that can lock out new
   29  * references only when the count is zero and only without waiting if the count
   30  * is not already zero. It is similar to a read-write lock in that it allows
   31  * multiple readers and only a single writer, but it does not allow a writer to
   32  * block while waiting for readers to exit, and therefore the question of
   33  * reader/writer priority is moot (no WRWANT bit). Since the equivalent of
   34  * rw_enter(&lock, RW_WRITER) is disallowed and only tryenter() is allowed, it
   35  * is perfectly safe for the same reader to acquire the same lock multiple
   36  * times. The fact that a ZRL is reentrant for readers (through multiple calls
   37  * to zrl_add()) makes it convenient for determining whether something is
   38  * actively referenced without the fuss of flagging lock ownership across
   39  * function calls.
   40  */
   41 #include <sys/zrlock.h>
   42 #include <sys/trace_zfs.h>
   43 
   44 /*
   45  * A ZRL can be locked only while there are zero references, so ZRL_LOCKED is
   46  * treated as zero references.
   47  */
   48 #define ZRL_LOCKED      -1
   49 #define ZRL_DESTROYED   -2
   50 
   51 void
   52 zrl_init(zrlock_t *zrl)
   53 {
   54         mutex_init(&zrl->zr_mtx, NULL, MUTEX_DEFAULT, NULL);
   55         zrl->zr_refcount = 0;
   56         cv_init(&zrl->zr_cv, NULL, CV_DEFAULT, NULL);
   57 #ifdef  ZFS_DEBUG
   58         zrl->zr_owner = NULL;
   59         zrl->zr_caller = NULL;
   60 #endif
   61 }
   62 
   63 void
   64 zrl_destroy(zrlock_t *zrl)
   65 {
   66         ASSERT0(zrl->zr_refcount);
   67 
   68         mutex_destroy(&zrl->zr_mtx);
   69         zrl->zr_refcount = ZRL_DESTROYED;
   70         cv_destroy(&zrl->zr_cv);
   71 }
   72 
   73 void
   74 zrl_add_impl(zrlock_t *zrl, const char *zc)
   75 {
   76         for (;;) {
   77                 uint32_t n = (uint32_t)zrl->zr_refcount;
   78                 while (n != ZRL_LOCKED) {
   79                         uint32_t cas = atomic_cas_32(
   80                             (uint32_t *)&zrl->zr_refcount, n, n + 1);
   81                         if (cas == n) {
   82                                 ASSERT3S((int32_t)n, >=, 0);
   83 #ifdef  ZFS_DEBUG
   84                                 if (zrl->zr_owner == curthread) {
   85                                         DTRACE_PROBE3(zrlock__reentry,
   86                                             zrlock_t *, zrl,
   87                                             kthread_t *, curthread,
   88                                             uint32_t, n);
   89                                 }
   90                                 zrl->zr_owner = curthread;
   91                                 zrl->zr_caller = zc;
   92 #endif
   93                                 return;
   94                         }
   95                         n = cas;
   96                 }
   97 
   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);
  103         }
  104 }
  105 
  106 void
  107 zrl_remove(zrlock_t *zrl)
  108 {
  109 #ifdef  ZFS_DEBUG
  110         if (zrl->zr_owner == curthread) {
  111                 zrl->zr_owner = NULL;
  112                 zrl->zr_caller = NULL;
  113         }
  114         int32_t n = atomic_dec_32_nv((uint32_t *)&zrl->zr_refcount);
  115         ASSERT3S(n, >=, 0);
  116 #else
  117         atomic_dec_32((uint32_t *)&zrl->zr_refcount);
  118 #endif
  119 }
  120 
  121 int
  122 zrl_tryenter(zrlock_t *zrl)
  123 {
  124         uint32_t n = (uint32_t)zrl->zr_refcount;
  125 
  126         if (n == 0) {
  127                 uint32_t cas = atomic_cas_32(
  128                     (uint32_t *)&zrl->zr_refcount, 0, ZRL_LOCKED);
  129                 if (cas == 0) {
  130 #ifdef  ZFS_DEBUG
  131                         ASSERT3P(zrl->zr_owner, ==, NULL);
  132                         zrl->zr_owner = curthread;
  133 #endif
  134                         return (1);
  135                 }
  136         }
  137 
  138         ASSERT3S((int32_t)n, >, ZRL_DESTROYED);
  139 
  140         return (0);
  141 }
  142 
  143 void
  144 zrl_exit(zrlock_t *zrl)
  145 {
  146         ASSERT3S(zrl->zr_refcount, ==, ZRL_LOCKED);
  147 
  148         mutex_enter(&zrl->zr_mtx);
  149 #ifdef  ZFS_DEBUG
  150         ASSERT3P(zrl->zr_owner, ==, curthread);
  151         zrl->zr_owner = NULL;
  152         membar_producer();      /* make sure the owner store happens first */
  153 #endif
  154         zrl->zr_refcount = 0;
  155         cv_broadcast(&zrl->zr_cv);
  156         mutex_exit(&zrl->zr_mtx);
  157 }
  158 
  159 int
  160 zrl_is_zero(zrlock_t *zrl)
  161 {
  162         ASSERT3S(zrl->zr_refcount, >, ZRL_DESTROYED);
  163 
  164         return (zrl->zr_refcount <= 0);
  165 }
  166 
  167 int
  168 zrl_is_locked(zrlock_t *zrl)
  169 {
  170         ASSERT3S(zrl->zr_refcount, >, ZRL_DESTROYED);
  171 
  172         return (zrl->zr_refcount == ZRL_LOCKED);
  173 }
  174 
  175 #ifdef  ZFS_DEBUG
  176 kthread_t *
  177 zrl_owner(zrlock_t *zrl)
  178 {
  179         return (zrl->zr_owner);
  180 }
  181 #endif
  182 
  183 #if defined(_KERNEL)
  184 
  185 EXPORT_SYMBOL(zrl_add_impl);
  186 EXPORT_SYMBOL(zrl_remove);
  187 
  188 #endif

Cache object: a53bdce29e76ed7999de2b143247a12a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.