LCOV - code coverage report
Current view: top level - lib - lockref.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 18 56 32.1 %
Date: 2022-03-28 13:20:08 Functions: 6 8 75.0 %
Branches: 17 66 25.8 %

           Branch data     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, prev = old;                           \
      18                 :            :                 CODE                                                            \
      19                 :            :                 old.lock_count = cmpxchg64_relaxed(&lockref->lock_count, \
      20                 :            :                                                    old.lock_count,              \
      21                 :            :                                                    new.lock_count);             \
      22                 :            :                 if (likely(old.lock_count == prev.lock_count)) {                \
      23                 :            :                         SUCCESS;                                                \
      24                 :            :                 }                                                               \
      25                 :            :                 if (!--retry)                                                   \
      26                 :            :                         break;                                                  \
      27                 :            :                 cpu_relax();                                                    \
      28                 :            :         }                                                                       \
      29                 :            : } while (0)
      30                 :            : 
      31                 :            : #else
      32                 :            : 
      33                 :            : #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
      34                 :            : 
      35                 :            : #endif
      36                 :            : 
      37                 :            : /**
      38                 :            :  * lockref_get - Increments reference count unconditionally
      39                 :            :  * @lockref: pointer to lockref structure
      40                 :            :  *
      41                 :            :  * This operation is only valid if you already hold a reference
      42                 :            :  * to the object, so you know the count cannot be zero.
      43                 :            :  */
      44                 :    3324631 : void lockref_get(struct lockref *lockref)
      45                 :            : {
      46   [ +  -  -  -  :    3324631 :         CMPXCHG_LOOP(
                   +  - ]
      47                 :            :                 new.count++;
      48                 :            :         ,
      49                 :            :                 return;
      50                 :            :         );
      51                 :            : 
      52                 :          0 :         spin_lock(&lockref->lock);
      53                 :          0 :         lockref->count++;
      54                 :          0 :         spin_unlock(&lockref->lock);
      55                 :            : }
      56                 :            : EXPORT_SYMBOL(lockref_get);
      57                 :            : 
      58                 :            : /**
      59                 :            :  * lockref_get_not_zero - Increments count unless the count is 0 or dead
      60                 :            :  * @lockref: pointer to lockref structure
      61                 :            :  * Return: 1 if count updated successfully or 0 if count was zero
      62                 :            :  */
      63                 :      88859 : int lockref_get_not_zero(struct lockref *lockref)
      64                 :            : {
      65                 :      88859 :         int retval;
      66                 :            : 
      67   [ +  -  -  +  :      88859 :         CMPXCHG_LOOP(
             -  -  +  - ]
      68                 :            :                 new.count++;
      69                 :            :                 if (old.count <= 0)
      70                 :            :                         return 0;
      71                 :            :         ,
      72                 :            :                 return 1;
      73                 :            :         );
      74                 :            : 
      75                 :          0 :         spin_lock(&lockref->lock);
      76                 :          0 :         retval = 0;
      77         [ #  # ]:          0 :         if (lockref->count > 0) {
      78                 :          0 :                 lockref->count++;
      79                 :          0 :                 retval = 1;
      80                 :            :         }
      81                 :          0 :         spin_unlock(&lockref->lock);
      82                 :          0 :         return retval;
      83                 :            : }
      84                 :            : EXPORT_SYMBOL(lockref_get_not_zero);
      85                 :            : 
      86                 :            : /**
      87                 :            :  * lockref_put_not_zero - Decrements count unless count <= 1 before decrement
      88                 :            :  * @lockref: pointer to lockref structure
      89                 :            :  * Return: 1 if count updated successfully or 0 if count would become zero
      90                 :            :  */
      91                 :          0 : int lockref_put_not_zero(struct lockref *lockref)
      92                 :            : {
      93                 :          0 :         int retval;
      94                 :            : 
      95   [ #  #  #  #  :          0 :         CMPXCHG_LOOP(
             #  #  #  # ]
      96                 :            :                 new.count--;
      97                 :            :                 if (old.count <= 1)
      98                 :            :                         return 0;
      99                 :            :         ,
     100                 :            :                 return 1;
     101                 :            :         );
     102                 :            : 
     103                 :          0 :         spin_lock(&lockref->lock);
     104                 :          0 :         retval = 0;
     105         [ #  # ]:          0 :         if (lockref->count > 1) {
     106                 :          0 :                 lockref->count--;
     107                 :          0 :                 retval = 1;
     108                 :            :         }
     109                 :          0 :         spin_unlock(&lockref->lock);
     110                 :          0 :         return retval;
     111                 :            : }
     112                 :            : EXPORT_SYMBOL(lockref_put_not_zero);
     113                 :            : 
     114                 :            : /**
     115                 :            :  * lockref_get_or_lock - Increments count unless the count is 0 or dead
     116                 :            :  * @lockref: pointer to lockref structure
     117                 :            :  * Return: 1 if count updated successfully or 0 if count was zero
     118                 :            :  * and we got the lock instead.
     119                 :            :  */
     120                 :          0 : int lockref_get_or_lock(struct lockref *lockref)
     121                 :            : {
     122   [ #  #  #  #  :          0 :         CMPXCHG_LOOP(
             #  #  #  # ]
     123                 :            :                 new.count++;
     124                 :            :                 if (old.count <= 0)
     125                 :            :                         break;
     126                 :            :         ,
     127                 :            :                 return 1;
     128                 :            :         );
     129                 :            : 
     130                 :          0 :         spin_lock(&lockref->lock);
     131         [ #  # ]:          0 :         if (lockref->count <= 0)
     132                 :            :                 return 0;
     133                 :          0 :         lockref->count++;
     134                 :          0 :         spin_unlock(&lockref->lock);
     135                 :          0 :         return 1;
     136                 :            : }
     137                 :            : EXPORT_SYMBOL(lockref_get_or_lock);
     138                 :            : 
     139                 :            : /**
     140                 :            :  * lockref_put_return - Decrement reference count if possible
     141                 :            :  * @lockref: pointer to lockref structure
     142                 :            :  *
     143                 :            :  * Decrement the reference count and return the new value.
     144                 :            :  * If the lockref was dead or locked, return an error.
     145                 :            :  */
     146                 :    8477159 : int lockref_put_return(struct lockref *lockref)
     147                 :            : {
     148   [ +  -  +  -  :    8477159 :         CMPXCHG_LOOP(
             -  -  +  - ]
     149                 :            :                 new.count--;
     150                 :            :                 if (old.count <= 0)
     151                 :            :                         return -1;
     152                 :            :         ,
     153                 :            :                 return new.count;
     154                 :            :         );
     155                 :          0 :         return -1;
     156                 :            : }
     157                 :            : EXPORT_SYMBOL(lockref_put_return);
     158                 :            : 
     159                 :            : /**
     160                 :            :  * lockref_put_or_lock - decrements count unless count <= 1 before decrement
     161                 :            :  * @lockref: pointer to lockref structure
     162                 :            :  * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
     163                 :            :  */
     164                 :    2101358 : int lockref_put_or_lock(struct lockref *lockref)
     165                 :            : {
     166   [ +  +  +  -  :    2101358 :         CMPXCHG_LOOP(
             -  -  +  - ]
     167                 :            :                 new.count--;
     168                 :            :                 if (old.count <= 1)
     169                 :            :                         break;
     170                 :            :         ,
     171                 :            :                 return 1;
     172                 :            :         );
     173                 :            : 
     174                 :     261900 :         spin_lock(&lockref->lock);
     175         [ -  + ]:     261900 :         if (lockref->count <= 1)
     176                 :            :                 return 0;
     177                 :          0 :         lockref->count--;
     178                 :          0 :         spin_unlock(&lockref->lock);
     179                 :          0 :         return 1;
     180                 :            : }
     181                 :            : EXPORT_SYMBOL(lockref_put_or_lock);
     182                 :            : 
     183                 :            : /**
     184                 :            :  * lockref_mark_dead - mark lockref dead
     185                 :            :  * @lockref: pointer to lockref structure
     186                 :            :  */
     187                 :     348025 : void lockref_mark_dead(struct lockref *lockref)
     188                 :            : {
     189         [ -  + ]:     348025 :         assert_spin_locked(&lockref->lock);
     190                 :     348025 :         lockref->count = -128;
     191                 :     348025 : }
     192                 :            : EXPORT_SYMBOL(lockref_mark_dead);
     193                 :            : 
     194                 :            : /**
     195                 :            :  * lockref_get_not_dead - Increments count unless the ref is dead
     196                 :            :  * @lockref: pointer to lockref structure
     197                 :            :  * Return: 1 if count updated successfully or 0 if lockref was dead
     198                 :            :  */
     199                 :    4122214 : int lockref_get_not_dead(struct lockref *lockref)
     200                 :            : {
     201                 :    4122214 :         int retval;
     202                 :            : 
     203   [ +  -  -  +  :    4122214 :         CMPXCHG_LOOP(
             -  -  +  - ]
     204                 :            :                 new.count++;
     205                 :            :                 if (old.count < 0)
     206                 :            :                         return 0;
     207                 :            :         ,
     208                 :            :                 return 1;
     209                 :            :         );
     210                 :            : 
     211                 :          0 :         spin_lock(&lockref->lock);
     212                 :          0 :         retval = 0;
     213         [ #  # ]:          0 :         if (lockref->count >= 0) {
     214                 :          0 :                 lockref->count++;
     215                 :          0 :                 retval = 1;
     216                 :            :         }
     217                 :          0 :         spin_unlock(&lockref->lock);
     218                 :          0 :         return retval;
     219                 :            : }
     220                 :            : EXPORT_SYMBOL(lockref_get_not_dead);

Generated by: LCOV version 1.14