LCOV - code coverage report
Current view: top level - lib - lockref.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 40 57 70.2 %
Date: 2021-04-22 12:43:58 Functions: 6 8 75.0 %

          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       69636 : void lockref_get(struct lockref *lockref)
      45             : {
      46       69636 :         CMPXCHG_LOOP(
      47             :                 new.count++;
      48             :         ,
      49             :                 return;
      50             :         );
      51             : 
      52       69636 :         spin_lock(&lockref->lock);
      53       69653 :         lockref->count++;
      54       69653 :         spin_unlock(&lockref->lock);
      55       69657 : }
      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        2489 : int lockref_get_not_zero(struct lockref *lockref)
      64             : {
      65        2489 :         int retval;
      66             : 
      67        2489 :         CMPXCHG_LOOP(
      68             :                 new.count++;
      69             :                 if (old.count <= 0)
      70             :                         return 0;
      71             :         ,
      72             :                 return 1;
      73             :         );
      74             : 
      75        2489 :         spin_lock(&lockref->lock);
      76        2489 :         retval = 0;
      77        2489 :         if (lockref->count > 0) {
      78        2489 :                 lockref->count++;
      79        2489 :                 retval = 1;
      80             :         }
      81        2489 :         spin_unlock(&lockref->lock);
      82        2489 :         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      177602 : int lockref_put_return(struct lockref *lockref)
     147             : {
     148      177602 :         CMPXCHG_LOOP(
     149             :                 new.count--;
     150             :                 if (old.count <= 0)
     151             :                         return -1;
     152             :         ,
     153             :                 return new.count;
     154             :         );
     155      177602 :         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       69714 : int lockref_put_or_lock(struct lockref *lockref)
     165             : {
     166       69714 :         CMPXCHG_LOOP(
     167             :                 new.count--;
     168             :                 if (old.count <= 1)
     169             :                         break;
     170             :         ,
     171             :                 return 1;
     172             :         );
     173             : 
     174       69714 :         spin_lock(&lockref->lock);
     175       69719 :         if (lockref->count <= 1)
     176             :                 return 0;
     177       57453 :         lockref->count--;
     178       57453 :         spin_unlock(&lockref->lock);
     179       57453 :         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       14149 : void lockref_mark_dead(struct lockref *lockref)
     188             : {
     189       14149 :         assert_spin_locked(&lockref->lock);
     190       14149 :         lockref->count = -128;
     191       14149 : }
     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      103315 : int lockref_get_not_dead(struct lockref *lockref)
     200             : {
     201      103315 :         int retval;
     202             : 
     203      103315 :         CMPXCHG_LOOP(
     204             :                 new.count++;
     205             :                 if (old.count < 0)
     206             :                         return 0;
     207             :         ,
     208             :                 return 1;
     209             :         );
     210             : 
     211      103315 :         spin_lock(&lockref->lock);
     212      103316 :         retval = 0;
     213      103316 :         if (lockref->count >= 0) {
     214      103314 :                 lockref->count++;
     215      103314 :                 retval = 1;
     216             :         }
     217      103316 :         spin_unlock(&lockref->lock);
     218      103313 :         return retval;
     219             : }
     220             : EXPORT_SYMBOL(lockref_get_not_dead);

Generated by: LCOV version 1.14