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(const struct mm_struct *mm) 64 { 65 rwsem_assert_held(&mm->mmap_lock); 66 } 67 68 static inline void mmap_assert_write_locked(const struct mm_struct *mm) 69 { 70 rwsem_assert_held_write(&mm->mmap_lock); 71 } 72 73 #ifdef CONFIG_PER_VMA_LOCK 74 75 static inline void mm_lock_seqcount_init(struct mm_struct *mm) 76 { 77 seqcount_init(&mm->mm_lock_seq); 78 } 79 80 static inline void mm_lock_seqcount_begin(struct mm_struct *mm) 81 { 82 do_raw_write_seqcount_begin(&mm->mm_lock_seq); 83 } 84 85 static inline void mm_lock_seqcount_end(struct mm_struct *mm) 86 { 87 ASSERT_EXCLUSIVE_WRITER(mm->mm_lock_seq); 88 do_raw_write_seqcount_end(&mm->mm_lock_seq); 89 } 90 91 static inline bool mmap_lock_speculate_try_begin(struct mm_struct *mm, unsigned int *seq) 92 { 93 /* 94 * Since mmap_lock is a sleeping lock, and waiting for it to become 95 * unlocked is more or less equivalent with taking it ourselves, don't 96 * bother with the speculative path if mmap_lock is already write-locked 97 * and take the slow path, which takes the lock. 98 */ 99 return raw_seqcount_try_begin(&mm->mm_lock_seq, *seq); 100 } 101 102 static inline bool mmap_lock_speculate_retry(struct mm_struct *mm, unsigned int seq) 103 { 104 return read_seqcount_retry(&mm->mm_lock_seq, seq); 105 } 106 107 #else /* CONFIG_PER_VMA_LOCK */ 108 109 static inline void mm_lock_seqcount_init(struct mm_struct *mm) {} 110 static inline void mm_lock_seqcount_begin(struct mm_struct *mm) {} 111 static inline void mm_lock_seqcount_end(struct mm_struct *mm) {} 112 113 static inline bool mmap_lock_speculate_try_begin(struct mm_struct *mm, unsigned int *seq) 114 { 115 return false; 116 } 117 118 static inline bool mmap_lock_speculate_retry(struct mm_struct *mm, unsigned int seq) 119 { 120 return true; 121 } 122 123 #endif /* CONFIG_PER_VMA_LOCK */ 124 125 static inline void mmap_init_lock(struct mm_struct *mm) 126 { 127 init_rwsem(&mm->mmap_lock); 128 mm_lock_seqcount_init(mm); 129 } 130 131 static inline void mmap_write_lock(struct mm_struct *mm) 132 { 133 __mmap_lock_trace_start_locking(mm, true); 134 down_write(&mm->mmap_lock); 135 mm_lock_seqcount_begin(mm); 136 __mmap_lock_trace_acquire_returned(mm, true, true); 137 } 138 139 static inline void mmap_write_lock_nested(struct mm_struct *mm, int subclass) 140 { 141 __mmap_lock_trace_start_locking(mm, true); 142 down_write_nested(&mm->mmap_lock, subclass); 143 mm_lock_seqcount_begin(mm); 144 __mmap_lock_trace_acquire_returned(mm, true, true); 145 } 146 147 static inline int mmap_write_lock_killable(struct mm_struct *mm) 148 { 149 int ret; 150 151 __mmap_lock_trace_start_locking(mm, true); 152 ret = down_write_killable(&mm->mmap_lock); 153 if (!ret) 154 mm_lock_seqcount_begin(mm); 155 __mmap_lock_trace_acquire_returned(mm, true, ret == 0); 156 return ret; 157 } 158 159 /* 160 * Drop all currently-held per-VMA locks. 161 * This is called from the mmap_lock implementation directly before releasing 162 * a write-locked mmap_lock (or downgrading it to read-locked). 163 * This should normally NOT be called manually from other places. 164 * If you want to call this manually anyway, keep in mind that this will release 165 * *all* VMA write locks, including ones from further up the stack. 166 */ 167 static inline void vma_end_write_all(struct mm_struct *mm) 168 { 169 mmap_assert_write_locked(mm); 170 mm_lock_seqcount_end(mm); 171 } 172 173 static inline void mmap_write_unlock(struct mm_struct *mm) 174 { 175 __mmap_lock_trace_released(mm, true); 176 vma_end_write_all(mm); 177 up_write(&mm->mmap_lock); 178 } 179 180 static inline void mmap_write_downgrade(struct mm_struct *mm) 181 { 182 __mmap_lock_trace_acquire_returned(mm, false, true); 183 vma_end_write_all(mm); 184 downgrade_write(&mm->mmap_lock); 185 } 186 187 static inline void mmap_read_lock(struct mm_struct *mm) 188 { 189 __mmap_lock_trace_start_locking(mm, false); 190 down_read(&mm->mmap_lock); 191 __mmap_lock_trace_acquire_returned(mm, false, true); 192 } 193 194 static inline int mmap_read_lock_killable(struct mm_struct *mm) 195 { 196 int ret; 197 198 __mmap_lock_trace_start_locking(mm, false); 199 ret = down_read_killable(&mm->mmap_lock); 200 __mmap_lock_trace_acquire_returned(mm, false, ret == 0); 201 return ret; 202 } 203 204 static inline bool mmap_read_trylock(struct mm_struct *mm) 205 { 206 bool ret; 207 208 __mmap_lock_trace_start_locking(mm, false); 209 ret = down_read_trylock(&mm->mmap_lock) != 0; 210 __mmap_lock_trace_acquire_returned(mm, false, ret); 211 return ret; 212 } 213 214 static inline void mmap_read_unlock(struct mm_struct *mm) 215 { 216 __mmap_lock_trace_released(mm, false); 217 up_read(&mm->mmap_lock); 218 } 219 220 static inline void mmap_read_unlock_non_owner(struct mm_struct *mm) 221 { 222 __mmap_lock_trace_released(mm, false); 223 up_read_non_owner(&mm->mmap_lock); 224 } 225 226 static inline int mmap_lock_is_contended(struct mm_struct *mm) 227 { 228 return rwsem_is_contended(&mm->mmap_lock); 229 } 230 231 #endif /* _LINUX_MMAP_LOCK_H */ 232