@@ -39,40 +39,65 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
39
39
return 1 ;
40
40
41
41
/*
42
- * If we contend on this state's lock then almost
43
- * by definition we are too busy to print a message,
44
- * in addition to the one that will be printed by
45
- * the entity that is holding the lock already:
42
+ * If we contend on this state's lock then just check if
43
+ * the current burst is used or not. It might cause
44
+ * false positive when we are past the interval and
45
+ * the current lock owner is just about to reset it.
46
46
*/
47
47
if (!raw_spin_trylock_irqsave (& rs -> lock , flags )) {
48
+ unsigned int rs_flags = READ_ONCE (rs -> flags );
49
+
50
+ if (rs_flags & RATELIMIT_INITIALIZED && burst ) {
51
+ int n_left ;
52
+
53
+ n_left = atomic_dec_return (& rs -> rs_n_left );
54
+ if (n_left >= 0 )
55
+ return 1 ;
56
+ }
57
+
48
58
ratelimit_state_inc_miss (rs );
49
59
return 0 ;
50
60
}
51
61
52
62
if (!(rs -> flags & RATELIMIT_INITIALIZED )) {
53
63
rs -> begin = jiffies ;
54
64
rs -> flags |= RATELIMIT_INITIALIZED ;
65
+ atomic_set (& rs -> rs_n_left , rs -> burst );
55
66
}
56
67
57
68
if (time_is_before_jiffies (rs -> begin + interval )) {
58
- int m = ratelimit_state_reset_miss (rs );
69
+ int m ;
70
+
71
+ /*
72
+ * Reset rs_n_left ASAP to reduce false positives
73
+ * in parallel calls, see above.
74
+ */
75
+ atomic_set (& rs -> rs_n_left , rs -> burst );
76
+ rs -> begin = jiffies ;
59
77
78
+ m = ratelimit_state_reset_miss (rs );
60
79
if (m ) {
61
80
if (!(rs -> flags & RATELIMIT_MSG_ON_RELEASE )) {
62
81
printk_deferred (KERN_WARNING
63
82
"%s: %d callbacks suppressed\n" , func , m );
64
83
}
65
84
}
66
- rs -> begin = jiffies ;
67
- rs -> printed = 0 ;
68
85
}
69
- if (burst && burst > rs -> printed ) {
70
- rs -> printed ++ ;
71
- ret = 1 ;
72
- } else {
73
- ratelimit_state_inc_miss (rs );
74
- ret = 0 ;
86
+ if (burst ) {
87
+ int n_left ;
88
+
89
+ /* The burst might have been taken by a parallel call. */
90
+ n_left = atomic_dec_return (& rs -> rs_n_left );
91
+ if (n_left >= 0 ) {
92
+ ret = 1 ;
93
+ goto unlock_ret ;
94
+ }
75
95
}
96
+
97
+ ratelimit_state_inc_miss (rs );
98
+ ret = 0 ;
99
+
100
+ unlock_ret :
76
101
raw_spin_unlock_irqrestore (& rs -> lock , flags );
77
102
78
103
return ret ;
0 commit comments