1 #ifndef _LINUX_MMAP_LOCK_H 2 #define _LINUX_MMAP_LOCK_H 3 4 #include <linux/lockdep.h> 5 #include <linux/mm_types.h> 6 #include <linux/mmdebug.h> 7 #include <linux/rwsem.h> 8 #include <linux/tracepoint-defs.h> 9 #include <linux/types.h> 10 11 #define MMAP_LOCK_INITIALIZER(name) \ 12 .mmap_lock = __RWSEM_INITIALIZER((name).mmap_lock), 13 14 DECLARE_TRACEPOINT(mmap_lock_start_locking); 15 DECLARE_TRACEPOINT(mmap_lock_acquire_returned); 16 DECLARE_TRACEPOINT(mmap_lock_released); 17 18 #ifdef CONFIG_TRACING 19 20 void __mmap_lock_do_trace_start_locking(struct mm_struct *mm, bool write); 21 void __mmap_lock_do_trace_acquire_returned(struct mm_struct *mm, bool write, 22 bool success); 23 void __mmap_lock_do_trace_released(struct mm_struct *mm, bool write); 24 25 static inline void __mmap_lock_trace_start_locking(struct mm_struct *mm, 26 bool write) 27 { 28 if (tracepoint_enabled(mmap_lock_start_locking)) 29 __mmap_lock_do_trace_start_locking(mm, write); 30 } 31 32 static inline void __mmap_lock_trace_acquire_returned(struct mm_struct *mm, 33 bool write, bool success) 34 { 35 if (tracepoint_enabled(mmap_lock_acquire_returned)) 36 __mmap_lock_do_trace_acquire_returned(mm, write, success); 37 } 38 39 static inline void __mmap_lock_trace_released(struct mm_struct *mm, bool write) 40 { 41 if (tracepoint_enabled(mmap_lock_released)) 42 __mmap_lock_do_trace_released(mm, write); 43 } 44 45 #else /* !CONFIG_TRACING */ 46 47 static inline void __mmap_lock_trace_start_locking(struct mm_struct *mm, 48 bool write) 49 { 50 } 51 52 static inline void __mmap_lock_trace_acquire_returned(struct mm_struct *mm, 53 bool write, bool success) 54 { 55 } 56 57 static inline void __mmap_lock_trace_released(struct mm_struct *mm, bool write) 58 { 59 } 60 61 #endif /* CONFIG_TRACING */ 62 63 static inline void mmap_assert_locked(struct mm_struct *mm) 64 { 65 lockdep_assert_held(&mm->mmap_lock); 66 VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_lock), mm); 67 } 68 69 static inline void mmap_assert_write_locked(struct mm_struct *mm) 70 { 71 lockdep_assert_held_write(&mm->mmap_lock); 72 VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_lock), mm); 73 } 74 75 #ifdef CONFIG_PER_VMA_LOCK 76 static inline void vma_end_write_all(struct mm_struct *mm) 77 { 78 mmap_assert_write_locked(mm); 79 /* 80 * Nobody can concurrently modify mm->mm_lock_seq due to exclusive 81 * mmap_lock being held. 82 * We need RELEASE semantics here to ensure that preceding stores into 83 * the VMA take effect before we unlock it with this store. 84 * Pairs with ACQUIRE semantics in vma_start_read(). 85 */ 86 smp_store_release(&mm->mm_lock_seq, mm->mm_lock_seq + 1); 87 } 88 #else 89 static inline void vma_end_write_all(struct mm_struct *mm) {} 90 #endif 91 92 static inline void mmap_init_lock(struct mm_struct *mm) 93 { 94 init_rwsem(&mm->mmap_lock); 95 } 96 97 static inline void mmap_write_lock(struct mm_struct *mm) 98 { 99 __mmap_lock_trace_start_locking(mm, true); 100 down_write(&mm->mmap_lock); 101 __mmap_lock_trace_acquire_returned(mm, true, true); 102 } 103 104 static inline void mmap_write_lock_nested(struct mm_struct *mm, int subclass) 105 { 106 __mmap_lock_trace_start_locking(mm, true); 107 down_write_nested(&mm->mmap_lock, subclass); 108 __mmap_lock_trace_acquire_returned(mm, true, true); 109 } 110 111 static inline int mmap_write_lock_killable(struct mm_struct *mm) 112 { 113 int ret; 114 115 __mmap_lock_trace_start_locking(mm, true); 116 ret = down_write_killable(&mm->mmap_lock); 117 __mmap_lock_trace_acquire_returned(mm, true, ret == 0); 118 return ret; 119 } 120 121 static inline bool mmap_write_trylock(struct mm_struct *mm) 122 { 123 bool ret; 124 125 __mmap_lock_trace_start_locking(mm, true); 126 ret = down_write_trylock(&mm->mmap_lock) != 0; 127 __mmap_lock_trace_acquire_returned(mm, true, ret); 128 return ret; 129 } 130 131 static inline void mmap_write_unlock(struct mm_struct *mm) 132 { 133 __mmap_lock_trace_released(mm, true); 134 vma_end_write_all(mm); 135 up_write(&mm->mmap_lock); 136 } 137 138 static inline void mmap_write_downgrade(struct mm_struct *mm) 139 { 140 __mmap_lock_trace_acquire_returned(mm, false, true); 141 vma_end_write_all(mm); 142 downgrade_write(&mm->mmap_lock); 143 } 144 145 static inline void mmap_read_lock(struct mm_struct *mm) 146 { 147 __mmap_lock_trace_start_locking(mm, false); 148 down_read(&mm->mmap_lock); 149 __mmap_lock_trace_acquire_returned(mm, false, true); 150 } 151 152 static inline int mmap_read_lock_killable(struct mm_struct *mm) 153 { 154 int ret; 155 156 __mmap_lock_trace_start_locking(mm, false); 157 ret = down_read_killable(&mm->mmap_lock); 158 __mmap_lock_trace_acquire_returned(mm, false, ret == 0); 159 return ret; 160 } 161 162 static inline bool mmap_read_trylock(struct mm_struct *mm) 163 { 164 bool ret; 165 166 __mmap_lock_trace_start_locking(mm, false); 167 ret = down_read_trylock(&mm->mmap_lock) != 0; 168 __mmap_lock_trace_acquire_returned(mm, false, ret); 169 return ret; 170 } 171 172 static inline void mmap_read_unlock(struct mm_struct *mm) 173 { 174 __mmap_lock_trace_released(mm, false); 175 up_read(&mm->mmap_lock); 176 } 177 178 static inline void mmap_read_unlock_non_owner(struct mm_struct *mm) 179 { 180 __mmap_lock_trace_released(mm, false); 181 up_read_non_owner(&mm->mmap_lock); 182 } 183 184 static inline int mmap_lock_is_contended(struct mm_struct *mm) 185 { 186 return rwsem_is_contended(&mm->mmap_lock); 187 } 188 189 #endif /* _LINUX_MMAP_LOCK_H */ 190