Split the inner workings of rt_mutex_slowlock() out into a separate function, which can be reused by the upcoming RT lock substitutions, e.g. for rw_semaphores.
Showing the changes to kernel/locking (2 of 2 files). Show all
Unified · Split
| @@ -1106,7 +1106,7 @@ static void __sched remove_waiter(struct rt_mutex_base *lock, · 1105 unmodified lines | ||
| 1106 | 1106 | } |
| 1107 | 1107 | |
| 1108 | 1108 | /** |
| 1109 | − * __rt_mutex_slowlock() - Perform the wait-wake-try-to-take loop | |
| 1109 | + * rt_mutex_slowlock_block() - Perform the wait-wake-try-to-take loop | |
| 1110 | 1110 | * @lock: the rt_mutex to take |
| 1111 | 1111 | * @state: the state the task should block in (TASK_INTERRUPTIBLE |
| 1112 | 1112 | * or TASK_UNINTERRUPTIBLE) |
| @@ -1115,10 +1115,10 @@ static void __sched remove_waiter(struct rt_mutex_base *lock, · 2 unmodified lines | ||
| 1115 | 1115 | * |
| 1116 | 1116 | * Must be called with lock->wait_lock held and interrupts disabled |
| 1117 | 1117 | */ |
| 1118 | −static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock, | |
| 1119 | − unsigned int state, | |
| 1120 | − struct hrtimer_sleeper *timeout, | |
| 1121 | − struct rt_mutex_waiter *waiter) | |
| 1118 | +static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock, | |
| 1119 | + unsigned int state, | |
| 1120 | + struct hrtimer_sleeper *timeout, | |
| 1121 | + struct rt_mutex_waiter *waiter) | |
| 1122 | 1122 | { |
| 1123 | 1123 | int ret = 0; |
| 1124 | 1124 | |
| @@ -1168,52 +1168,37 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock, · 43 unmodified lines | ||
| 1168 | 1168 | } |
| 1169 | 1169 | } |
| 1170 | 1170 | |
| 1171 | −/* | |
| 1172 | − * Slow path lock function: | |
| 1171 | +/** | |
| 1172 | + * __rt_mutex_slowlock - Locking slowpath invoked with lock::wait_lock held | |
| 1173 | + * @lock: The rtmutex to block lock | |
| 1174 | + * @state: The task state for sleeping | |
| 1175 | + * @chwalk: Indicator whether full or partial chainwalk is requested | |
| 1176 | + * @waiter: Initializer waiter for blocking | |
| 1173 | 1177 | */ |
| 1174 | −static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, | |
| 1175 | − unsigned int state, | |
| 1176 | − struct hrtimer_sleeper *timeout, | |
| 1177 | − enum rtmutex_chainwalk chwalk) | |
| 1178 | +static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock, | |
| 1179 | + unsigned int state, | |
| 1180 | + enum rtmutex_chainwalk chwalk, | |
| 1181 | + struct rt_mutex_waiter *waiter) | |
| 1178 | 1182 | { |
| 1179 | − struct rt_mutex_waiter waiter; | |
| 1180 | − unsigned long flags; | |
| 1181 | − int ret = 0; | |
| 1182 | − | |
| 1183 | − rt_mutex_init_waiter(&waiter); | |
| 1183 | + int ret; | |
| 1184 | 1184 | |
| 1185 | − /* | |
| 1186 | − * Technically we could use raw_spin_[un]lock_irq() here, but this can | |
| 1187 | − * be called in early boot if the cmpxchg() fast path is disabled | |
| 1188 | − * (debug, no architecture support). In this case we will acquire the | |
| 1189 | − * rtmutex with lock->wait_lock held. But we cannot unconditionally | |
| 1190 | − * enable interrupts in that early boot case. So we need to use the | |
| 1191 | − * irqsave/restore variants. | |
| 1192 | − */ | |
| 1193 | − raw_spin_lock_irqsave(&lock->wait_lock, flags); | |
| 1185 | + lockdep_assert_held(&lock->wait_lock); | |
| 1194 | 1186 | |
| 1195 | 1187 | /* Try to acquire the lock again: */ |
| 1196 | − if (try_to_take_rt_mutex(lock, current, NULL)) { | |
| 1197 | − raw_spin_unlock_irqrestore(&lock->wait_lock, flags); | |
| 1188 | + if (try_to_take_rt_mutex(lock, current, NULL)) | |
| 1198 | 1189 | return 0; |
| 1199 | − } | |
| 1200 | 1190 | |
| 1201 | 1191 | set_current_state(state); |
| 1202 | 1192 | |
| 1203 | − /* Setup the timer, when timeout != NULL */ | |
| 1204 | − if (unlikely(timeout)) | |
| 1205 | − hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS); | |
| 1206 | − | |
| 1207 | − ret = task_blocks_on_rt_mutex(lock, &waiter, current, chwalk); | |
| 1193 | + ret = task_blocks_on_rt_mutex(lock, waiter, current, chwalk); | |
| 1208 | 1194 | |
| 1209 | 1195 | if (likely(!ret)) |
| 1210 | − /* sleep on the mutex */ | |
| 1211 | − ret = __rt_mutex_slowlock(lock, state, timeout, &waiter); | |
| 1196 | + ret = rt_mutex_slowlock_block(lock, state, NULL, waiter); | |
| 1212 | 1197 | |
| 1213 | 1198 | if (unlikely(ret)) { |
| 1214 | 1199 | __set_current_state(TASK_RUNNING); |
| 1215 | − remove_waiter(lock, &waiter); | |
| 1216 | − rt_mutex_handle_deadlock(ret, chwalk, &waiter); | |
| 1200 | + remove_waiter(lock, waiter); | |
| 1201 | + rt_mutex_handle_deadlock(ret, chwalk, waiter); | |
| 1217 | 1202 | } |
| 1218 | 1203 | |
| 1219 | 1204 | /* |
| @@ -1221,14 +1206,45 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, · 1 unmodified line | ||
| 1221 | 1206 | * unconditionally. We might have to fix that up. |
| 1222 | 1207 | */ |
| 1223 | 1208 | fixup_rt_mutex_waiters(lock); |
| 1209 | + return ret; | |
| 1210 | +} | |
| 1224 | 1211 | |
| 1225 | − raw_spin_unlock_irqrestore(&lock->wait_lock, flags); | |
| 1212 | +static inline int __rt_mutex_slowlock_locked(struct rt_mutex_base *lock, | |
| 1213 | + unsigned int state) | |
| 1214 | +{ | |
| 1215 | + struct rt_mutex_waiter waiter; | |
| 1216 | + int ret; | |
| 1217 | + | |
| 1218 | + rt_mutex_init_waiter(&waiter); | |
| 1226 | 1219 | |
| 1227 | − /* Remove pending timer: */ | |
| 1228 | − if (unlikely(timeout)) | |
| 1229 | − hrtimer_cancel(&timeout->timer); | |
| 1220 | + ret = __rt_mutex_slowlock(lock, state, RT_MUTEX_MIN_CHAINWALK, &waiter); | |
| 1230 | 1221 | |
| 1231 | 1222 | debug_rt_mutex_free_waiter(&waiter); |
| 1223 | + return ret; | |
| 1224 | +} | |
| 1225 | + | |
| 1226 | +/* | |
| 1227 | + * rt_mutex_slowlock - Locking slowpath invoked when fast path fails | |
| 1228 | + * @lock: The rtmutex to block lock | |
| 1229 | + * @state: The task state for sleeping | |
| 1230 | + */ | |
| 1231 | +static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock, | |
| 1232 | + unsigned int state) | |
| 1233 | +{ | |
| 1234 | + unsigned long flags; | |
| 1235 | + int ret; | |
| 1236 | + | |
| 1237 | + /* | |
| 1238 | + * Technically we could use raw_spin_[un]lock_irq() here, but this can | |
| 1239 | + * be called in early boot if the cmpxchg() fast path is disabled | |
| 1240 | + * (debug, no architecture support). In this case we will acquire the | |
| 1241 | + * rtmutex with lock->wait_lock held. But we cannot unconditionally | |
| 1242 | + * enable interrupts in that early boot case. So we need to use the | |
| 1243 | + * irqsave/restore variants. | |
| 1244 | + */ | |
| 1245 | + raw_spin_lock_irqsave(&lock->wait_lock, flags); | |
| 1246 | + ret = __rt_mutex_slowlock_locked(lock, state); | |
| 1247 | + raw_spin_unlock_irqrestore(&lock->wait_lock, flags); | |
| 1232 | 1248 | |
| 1233 | 1249 | return ret; |
| 1234 | 1250 | } |
| @@ -1239,7 +1255,7 @@ static __always_inline int __rt_mutex_lock(struct rt_mutex_base *lock, · 4 unmodified lines | ||
| 1239 | 1255 | if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current))) |
| 1240 | 1256 | return 0; |
| 1241 | 1257 | |
| 1242 | − return rt_mutex_slowlock(lock, state, NULL, RT_MUTEX_MIN_CHAINWALK); | |
| 1258 | + return rt_mutex_slowlock(lock, state); | |
| 1243 | 1259 | } |
| 1244 | 1260 | |
| 1245 | 1261 | static int __sched __rt_mutex_slowtrylock(struct rt_mutex_base *lock) |
| @@ -342,7 +342,7 @@ int __sched rt_mutex_wait_proxy_lock(struct rt_mutex_base *lock, · 341 unmodified lines | ||
| 342 | 342 | raw_spin_lock_irq(&lock->wait_lock); |
| 343 | 343 | /* sleep on the mutex */ |
| 344 | 344 | set_current_state(TASK_INTERRUPTIBLE); |
| 345 | − ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter); | |
| 345 | + ret = rt_mutex_slowlock_block(lock, TASK_INTERRUPTIBLE, to, waiter); | |
| 346 | 346 | /* |
| 347 | 347 | * try_to_take_rt_mutex() sets the waiter bit unconditionally. We might |
| 348 | 348 | * have to fix that up. |