Root/lib/kernel_lock.c

1/*
2 * lib/kernel_lock.c
3 *
4 * This is the traditional BKL - big kernel lock. Largely
5 * relegated to obsolescence, but used by various less
6 * important (or lazy) subsystems.
7 */
8#include <linux/module.h>
9#include <linux/kallsyms.h>
10#include <linux/semaphore.h>
11#include <linux/smp_lock.h>
12
13#define CREATE_TRACE_POINTS
14#include <trace/events/bkl.h>
15
16/*
17 * The 'big kernel lock'
18 *
19 * This spinlock is taken and released recursively by lock_kernel()
20 * and unlock_kernel(). It is transparently dropped and reacquired
21 * over schedule(). It is used to protect legacy code that hasn't
22 * been migrated to a proper locking design yet.
23 *
24 * Don't use in new code.
25 */
26static __cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(kernel_flag);
27
28
29/*
30 * Acquire/release the underlying lock from the scheduler.
31 *
32 * This is called with preemption disabled, and should
33 * return an error value if it cannot get the lock and
34 * TIF_NEED_RESCHED gets set.
35 *
36 * If it successfully gets the lock, it should increment
37 * the preemption count like any spinlock does.
38 *
39 * (This works on UP too - do_raw_spin_trylock will never
40 * return false in that case)
41 */
42int __lockfunc __reacquire_kernel_lock(void)
43{
44    while (!do_raw_spin_trylock(&kernel_flag)) {
45        if (need_resched())
46            return -EAGAIN;
47        cpu_relax();
48    }
49    preempt_disable();
50    return 0;
51}
52
53void __lockfunc __release_kernel_lock(void)
54{
55    do_raw_spin_unlock(&kernel_flag);
56    preempt_enable_no_resched();
57}
58
59/*
60 * These are the BKL spinlocks - we try to be polite about preemption.
61 * If SMP is not on (ie UP preemption), this all goes away because the
62 * do_raw_spin_trylock() will always succeed.
63 */
64#ifdef CONFIG_PREEMPT
65static inline void __lock_kernel(void)
66{
67    preempt_disable();
68    if (unlikely(!do_raw_spin_trylock(&kernel_flag))) {
69        /*
70         * If preemption was disabled even before this
71         * was called, there's nothing we can be polite
72         * about - just spin.
73         */
74        if (preempt_count() > 1) {
75            do_raw_spin_lock(&kernel_flag);
76            return;
77        }
78
79        /*
80         * Otherwise, let's wait for the kernel lock
81         * with preemption enabled..
82         */
83        do {
84            preempt_enable();
85            while (raw_spin_is_locked(&kernel_flag))
86                cpu_relax();
87            preempt_disable();
88        } while (!do_raw_spin_trylock(&kernel_flag));
89    }
90}
91
92#else
93
94/*
95 * Non-preemption case - just get the spinlock
96 */
97static inline void __lock_kernel(void)
98{
99    do_raw_spin_lock(&kernel_flag);
100}
101#endif
102
103static inline void __unlock_kernel(void)
104{
105    /*
106     * the BKL is not covered by lockdep, so we open-code the
107     * unlocking sequence (and thus avoid the dep-chain ops):
108     */
109    do_raw_spin_unlock(&kernel_flag);
110    preempt_enable();
111}
112
113/*
114 * Getting the big kernel lock.
115 *
116 * This cannot happen asynchronously, so we only need to
117 * worry about other CPU's.
118 */
119void __lockfunc _lock_kernel(const char *func, const char *file, int line)
120{
121    int depth = current->lock_depth + 1;
122
123    trace_lock_kernel(func, file, line);
124
125    if (likely(!depth)) {
126        might_sleep();
127        __lock_kernel();
128    }
129    current->lock_depth = depth;
130}
131
132void __lockfunc _unlock_kernel(const char *func, const char *file, int line)
133{
134    BUG_ON(current->lock_depth < 0);
135    if (likely(--current->lock_depth < 0))
136        __unlock_kernel();
137
138    trace_unlock_kernel(func, file, line);
139}
140
141EXPORT_SYMBOL(_lock_kernel);
142EXPORT_SYMBOL(_unlock_kernel);
143
144

Archive Download this file



interactive