LCOV - code coverage report
Current view: top level - lib - lockref.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 24 40 60.0 %
Date: 2023-08-24 13:40:31 Functions: 5 7 71.4 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/export.h>
       3             : #include <linux/lockref.h>
       4             : 
       5             : #if USE_CMPXCHG_LOCKREF
       6             : 
       7             : /*
       8             :  * Note that the "cmpxchg()" reloads the "old" value for the
       9             :  * failure case.
      10             :  */
      11             : #define CMPXCHG_LOOP(CODE, SUCCESS) do {                                        \
      12             :         int retry = 100;                                                        \
      13             :         struct lockref old;                                                     \
      14             :         BUILD_BUG_ON(sizeof(old) != 8);                                         \
      15             :         old.lock_count = READ_ONCE(lockref->lock_count);                     \
      16             :         while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) {     \
      17             :                 struct lockref new = old;                                       \
      18             :                 CODE                                                            \
      19             :                 if (likely(try_cmpxchg64_relaxed(&lockref->lock_count,           \
      20             :                                                  &old.lock_count,           \
      21             :                                                  new.lock_count))) {            \
      22             :                         SUCCESS;                                                \
      23             :                 }                                                               \
      24             :                 if (!--retry)                                                   \
      25             :                         break;                                                  \
      26             :         }                                                                       \
      27             : } while (0)
      28             : 
      29             : #else
      30             : 
      31             : #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
      32             : 
      33             : #endif
      34             : 
      35             : /**
      36             :  * lockref_get - Increments reference count unconditionally
      37             :  * @lockref: pointer to lockref structure
      38             :  *
      39             :  * This operation is only valid if you already hold a reference
      40             :  * to the object, so you know the count cannot be zero.
      41             :  */
      42          35 : void lockref_get(struct lockref *lockref)
      43             : {
      44             :         CMPXCHG_LOOP(
      45             :                 new.count++;
      46             :         ,
      47             :                 return;
      48             :         );
      49             : 
      50          70 :         spin_lock(&lockref->lock);
      51          35 :         lockref->count++;
      52          70 :         spin_unlock(&lockref->lock);
      53          35 : }
      54             : EXPORT_SYMBOL(lockref_get);
      55             : 
      56             : /**
      57             :  * lockref_get_not_zero - Increments count unless the count is 0 or dead
      58             :  * @lockref: pointer to lockref structure
      59             :  * Return: 1 if count updated successfully or 0 if count was zero
      60             :  */
      61           0 : int lockref_get_not_zero(struct lockref *lockref)
      62             : {
      63             :         int retval;
      64             : 
      65             :         CMPXCHG_LOOP(
      66             :                 new.count++;
      67             :                 if (old.count <= 0)
      68             :                         return 0;
      69             :         ,
      70             :                 return 1;
      71             :         );
      72             : 
      73           0 :         spin_lock(&lockref->lock);
      74           0 :         retval = 0;
      75           0 :         if (lockref->count > 0) {
      76           0 :                 lockref->count++;
      77           0 :                 retval = 1;
      78             :         }
      79           0 :         spin_unlock(&lockref->lock);
      80           0 :         return retval;
      81             : }
      82             : EXPORT_SYMBOL(lockref_get_not_zero);
      83             : 
      84             : /**
      85             :  * lockref_put_not_zero - Decrements count unless count <= 1 before decrement
      86             :  * @lockref: pointer to lockref structure
      87             :  * Return: 1 if count updated successfully or 0 if count would become zero
      88             :  */
      89           0 : int lockref_put_not_zero(struct lockref *lockref)
      90             : {
      91             :         int retval;
      92             : 
      93             :         CMPXCHG_LOOP(
      94             :                 new.count--;
      95             :                 if (old.count <= 1)
      96             :                         return 0;
      97             :         ,
      98             :                 return 1;
      99             :         );
     100             : 
     101           0 :         spin_lock(&lockref->lock);
     102           0 :         retval = 0;
     103           0 :         if (lockref->count > 1) {
     104           0 :                 lockref->count--;
     105           0 :                 retval = 1;
     106             :         }
     107           0 :         spin_unlock(&lockref->lock);
     108           0 :         return retval;
     109             : }
     110             : EXPORT_SYMBOL(lockref_put_not_zero);
     111             : 
     112             : /**
     113             :  * lockref_put_return - Decrement reference count if possible
     114             :  * @lockref: pointer to lockref structure
     115             :  *
     116             :  * Decrement the reference count and return the new value.
     117             :  * If the lockref was dead or locked, return an error.
     118             :  */
     119          27 : int lockref_put_return(struct lockref *lockref)
     120             : {
     121             :         CMPXCHG_LOOP(
     122             :                 new.count--;
     123             :                 if (old.count <= 0)
     124             :                         return -1;
     125             :         ,
     126             :                 return new.count;
     127             :         );
     128          27 :         return -1;
     129             : }
     130             : EXPORT_SYMBOL(lockref_put_return);
     131             : 
     132             : /**
     133             :  * lockref_put_or_lock - decrements count unless count <= 1 before decrement
     134             :  * @lockref: pointer to lockref structure
     135             :  * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
     136             :  */
     137           4 : int lockref_put_or_lock(struct lockref *lockref)
     138             : {
     139             :         CMPXCHG_LOOP(
     140             :                 new.count--;
     141             :                 if (old.count <= 1)
     142             :                         break;
     143             :         ,
     144             :                 return 1;
     145             :         );
     146             : 
     147           8 :         spin_lock(&lockref->lock);
     148           4 :         if (lockref->count <= 1)
     149             :                 return 0;
     150           4 :         lockref->count--;
     151           8 :         spin_unlock(&lockref->lock);
     152           4 :         return 1;
     153             : }
     154             : EXPORT_SYMBOL(lockref_put_or_lock);
     155             : 
     156             : /**
     157             :  * lockref_mark_dead - mark lockref dead
     158             :  * @lockref: pointer to lockref structure
     159             :  */
     160           5 : void lockref_mark_dead(struct lockref *lockref)
     161             : {
     162             :         assert_spin_locked(&lockref->lock);
     163           5 :         lockref->count = -128;
     164           5 : }
     165             : EXPORT_SYMBOL(lockref_mark_dead);
     166             : 
     167             : /**
     168             :  * lockref_get_not_dead - Increments count unless the ref is dead
     169             :  * @lockref: pointer to lockref structure
     170             :  * Return: 1 if count updated successfully or 0 if lockref was dead
     171             :  */
     172           3 : int lockref_get_not_dead(struct lockref *lockref)
     173             : {
     174             :         int retval;
     175             : 
     176             :         CMPXCHG_LOOP(
     177             :                 new.count++;
     178             :                 if (old.count < 0)
     179             :                         return 0;
     180             :         ,
     181             :                 return 1;
     182             :         );
     183             : 
     184           6 :         spin_lock(&lockref->lock);
     185           3 :         retval = 0;
     186           3 :         if (lockref->count >= 0) {
     187           3 :                 lockref->count++;
     188           3 :                 retval = 1;
     189             :         }
     190           6 :         spin_unlock(&lockref->lock);
     191           3 :         return retval;
     192             : }
     193             : EXPORT_SYMBOL(lockref_get_not_dead);

Generated by: LCOV version 1.14