1 #include <linux/export.h> 2 #include <linux/lockref.h> 3 4 #ifdef CONFIG_CMPXCHG_LOCKREF 5 6 /* 7 * Note that the "cmpxchg()" reloads the "old" value for the 8 * failure case. 9 */ 10 #define CMPXCHG_LOOP(CODE, SUCCESS) do { \ 11 struct lockref old; \ 12 BUILD_BUG_ON(sizeof(old) != 8); \ 13 old.lock_count = ACCESS_ONCE(lockref->lock_count); \ 14 while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) { \ 15 struct lockref new = old, prev = old; \ 16 CODE \ 17 old.lock_count = cmpxchg(&lockref->lock_count, \ 18 old.lock_count, new.lock_count); \ 19 if (likely(old.lock_count == prev.lock_count)) { \ 20 SUCCESS; \ 21 } \ 22 } \ 23 } while (0) 24 25 #else 26 27 #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0) 28 29 #endif 30 31 /** 32 * lockref_get - Increments reference count unconditionally 33 * @lockcnt: pointer to lockref structure 34 * 35 * This operation is only valid if you already hold a reference 36 * to the object, so you know the count cannot be zero. 37 */ 38 void lockref_get(struct lockref *lockref) 39 { 40 CMPXCHG_LOOP( 41 new.count++; 42 , 43 return; 44 ); 45 46 spin_lock(&lockref->lock); 47 lockref->count++; 48 spin_unlock(&lockref->lock); 49 } 50 EXPORT_SYMBOL(lockref_get); 51 52 /** 53 * lockref_get_not_zero - Increments count unless the count is 0 54 * @lockcnt: pointer to lockref structure 55 * Return: 1 if count updated successfully or 0 if count was zero 56 */ 57 int lockref_get_not_zero(struct lockref *lockref) 58 { 59 int retval; 60 61 CMPXCHG_LOOP( 62 new.count++; 63 if (!old.count) 64 return 0; 65 , 66 return 1; 67 ); 68 69 spin_lock(&lockref->lock); 70 retval = 0; 71 if (lockref->count) { 72 lockref->count++; 73 retval = 1; 74 } 75 spin_unlock(&lockref->lock); 76 return retval; 77 } 78 EXPORT_SYMBOL(lockref_get_not_zero); 79 80 /** 81 * lockref_get_or_lock - Increments count unless the count is 0 82 * @lockcnt: pointer to lockref structure 83 * Return: 1 if count updated successfully or 0 if count was zero 84 * and we got the lock instead. 85 */ 86 int lockref_get_or_lock(struct lockref *lockref) 87 { 88 CMPXCHG_LOOP( 89 new.count++; 90 if (!old.count) 91 break; 92 , 93 return 1; 94 ); 95 96 spin_lock(&lockref->lock); 97 if (!lockref->count) 98 return 0; 99 lockref->count++; 100 spin_unlock(&lockref->lock); 101 return 1; 102 } 103 EXPORT_SYMBOL(lockref_get_or_lock); 104 105 /** 106 * lockref_put_or_lock - decrements count unless count <= 1 before decrement 107 * @lockcnt: pointer to lockref structure 108 * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken 109 */ 110 int lockref_put_or_lock(struct lockref *lockref) 111 { 112 CMPXCHG_LOOP( 113 new.count--; 114 if (old.count <= 1) 115 break; 116 , 117 return 1; 118 ); 119 120 spin_lock(&lockref->lock); 121 if (lockref->count <= 1) 122 return 0; 123 lockref->count--; 124 spin_unlock(&lockref->lock); 125 return 1; 126 } 127 EXPORT_SYMBOL(lockref_put_or_lock); 128