@@ -1940,6 +1940,76 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
1940
1940
}
1941
1941
}
1942
1942
1943
+ /*
1944
+ * Recursion is tracked separately on each CPU. If NMIs are supported, an
1945
+ * additional NMI context per CPU is also separately tracked. Until per-CPU
1946
+ * is available, a separate "early tracking" is performed.
1947
+ */
1948
+ static DEFINE_PER_CPU (u8 , printk_count ) ;
1949
+ static u8 printk_count_early ;
1950
+ #ifdef CONFIG_HAVE_NMI
1951
+ static DEFINE_PER_CPU (u8 , printk_count_nmi ) ;
1952
+ static u8 printk_count_nmi_early ;
1953
+ #endif
1954
+
1955
+ /*
1956
+ * Recursion is limited to keep the output sane. printk() should not require
1957
+ * more than 1 level of recursion (allowing, for example, printk() to trigger
1958
+ * a WARN), but a higher value is used in case some printk-internal errors
1959
+ * exist, such as the ringbuffer validation checks failing.
1960
+ */
1961
+ #define PRINTK_MAX_RECURSION 3
1962
+
1963
+ /*
1964
+ * Return a pointer to the dedicated counter for the CPU+context of the
1965
+ * caller.
1966
+ */
1967
+ static u8 * __printk_recursion_counter (void )
1968
+ {
1969
+ #ifdef CONFIG_HAVE_NMI
1970
+ if (in_nmi ()) {
1971
+ if (printk_percpu_data_ready ())
1972
+ return this_cpu_ptr (& printk_count_nmi );
1973
+ return & printk_count_nmi_early ;
1974
+ }
1975
+ #endif
1976
+ if (printk_percpu_data_ready ())
1977
+ return this_cpu_ptr (& printk_count );
1978
+ return & printk_count_early ;
1979
+ }
1980
+
1981
+ /*
1982
+ * Enter recursion tracking. Interrupts are disabled to simplify tracking.
1983
+ * The caller must check the boolean return value to see if the recursion is
1984
+ * allowed. On failure, interrupts are not disabled.
1985
+ *
1986
+ * @recursion_ptr must be a variable of type (u8 *) and is the same variable
1987
+ * that is passed to printk_exit_irqrestore().
1988
+ */
1989
+ #define printk_enter_irqsave (recursion_ptr , flags ) \
1990
+ ({ \
1991
+ bool success = true; \
1992
+ \
1993
+ typecheck(u8 *, recursion_ptr); \
1994
+ local_irq_save(flags); \
1995
+ (recursion_ptr) = __printk_recursion_counter(); \
1996
+ if (*(recursion_ptr) > PRINTK_MAX_RECURSION) { \
1997
+ local_irq_restore(flags); \
1998
+ success = false; \
1999
+ } else { \
2000
+ (*(recursion_ptr))++; \
2001
+ } \
2002
+ success; \
2003
+ })
2004
+
2005
+ /* Exit recursion tracking, restoring interrupts. */
2006
+ #define printk_exit_irqrestore (recursion_ptr , flags ) \
2007
+ do { \
2008
+ typecheck(u8 *, recursion_ptr); \
2009
+ (*(recursion_ptr))--; \
2010
+ local_irq_restore(flags); \
2011
+ } while (0)
2012
+
1943
2013
int printk_delay_msec __read_mostly ;
1944
2014
1945
2015
static inline void printk_delay (void )
@@ -2040,11 +2110,14 @@ int vprintk_store(int facility, int level,
2040
2110
struct prb_reserved_entry e ;
2041
2111
enum log_flags lflags = 0 ;
2042
2112
struct printk_record r ;
2113
+ unsigned long irqflags ;
2043
2114
u16 trunc_msg_len = 0 ;
2044
2115
char prefix_buf [8 ];
2116
+ u8 * recursion_ptr ;
2045
2117
u16 reserve_size ;
2046
2118
va_list args2 ;
2047
2119
u16 text_len ;
2120
+ int ret = 0 ;
2048
2121
u64 ts_nsec ;
2049
2122
2050
2123
/*
@@ -2055,6 +2128,9 @@ int vprintk_store(int facility, int level,
2055
2128
*/
2056
2129
ts_nsec = local_clock ();
2057
2130
2131
+ if (!printk_enter_irqsave (recursion_ptr , irqflags ))
2132
+ return 0 ;
2133
+
2058
2134
/*
2059
2135
* The sprintf needs to come first since the syslog prefix might be
2060
2136
* passed in as a parameter. An extra byte must be reserved so that
@@ -2092,7 +2168,8 @@ int vprintk_store(int facility, int level,
2092
2168
prb_commit (& e );
2093
2169
}
2094
2170
2095
- return text_len ;
2171
+ ret = text_len ;
2172
+ goto out ;
2096
2173
}
2097
2174
}
2098
2175
@@ -2108,7 +2185,7 @@ int vprintk_store(int facility, int level,
2108
2185
2109
2186
prb_rec_init_wr (& r , reserve_size + trunc_msg_len );
2110
2187
if (!prb_reserve (& e , prb , & r ))
2111
- return 0 ;
2188
+ goto out ;
2112
2189
}
2113
2190
2114
2191
/* fill message */
@@ -2130,7 +2207,10 @@ int vprintk_store(int facility, int level,
2130
2207
else
2131
2208
prb_final_commit (& e );
2132
2209
2133
- return (text_len + trunc_msg_len );
2210
+ ret = text_len + trunc_msg_len ;
2211
+ out :
2212
+ printk_exit_irqrestore (recursion_ptr , irqflags );
2213
+ return ret ;
2134
2214
}
2135
2215
2136
2216
asmlinkage int vprintk_emit (int facility , int level ,
0 commit comments