@@ -1490,18 +1490,20 @@ static void populate_configfs_item(struct netconsole_target *nt,
14901490 init_target_config_group (nt , target_name );
14911491}
14921492
1493- static int sysdata_append_cpu_nr (struct netconsole_target * nt , int offset )
1493+ static int sysdata_append_cpu_nr (struct netconsole_target * nt , int offset ,
1494+ struct nbcon_write_context * wctxt )
14941495{
14951496 return scnprintf (& nt -> sysdata [offset ],
14961497 MAX_EXTRADATA_ENTRY_LEN , " cpu=%u\n" ,
1497- raw_smp_processor_id () );
1498+ wctxt -> cpu );
14981499}
14991500
1500- static int sysdata_append_taskname (struct netconsole_target * nt , int offset )
1501+ static int sysdata_append_taskname (struct netconsole_target * nt , int offset ,
1502+ struct nbcon_write_context * wctxt )
15011503{
15021504 return scnprintf (& nt -> sysdata [offset ],
15031505 MAX_EXTRADATA_ENTRY_LEN , " taskname=%s\n" ,
1504- current -> comm );
1506+ wctxt -> comm );
15051507}
15061508
15071509static int sysdata_append_release (struct netconsole_target * nt , int offset )
@@ -1522,18 +1524,20 @@ static int sysdata_append_msgid(struct netconsole_target *nt, int offset)
15221524/*
15231525 * prepare_sysdata - append sysdata in runtime
15241526 * @nt: target to send message to
1527+ * @wctxt: nbcon write context containing message metadata
15251528 */
1526- static int prepare_sysdata (struct netconsole_target * nt )
1529+ static int prepare_sysdata (struct netconsole_target * nt ,
1530+ struct nbcon_write_context * wctxt )
15271531{
15281532 int sysdata_len = 0 ;
15291533
15301534 if (!nt -> sysdata_fields )
15311535 goto out ;
15321536
15331537 if (nt -> sysdata_fields & SYSDATA_CPU_NR )
1534- sysdata_len += sysdata_append_cpu_nr (nt , sysdata_len );
1538+ sysdata_len += sysdata_append_cpu_nr (nt , sysdata_len , wctxt );
15351539 if (nt -> sysdata_fields & SYSDATA_TASKNAME )
1536- sysdata_len += sysdata_append_taskname (nt , sysdata_len );
1540+ sysdata_len += sysdata_append_taskname (nt , sysdata_len , wctxt );
15371541 if (nt -> sysdata_fields & SYSDATA_RELEASE )
15381542 sysdata_len += sysdata_append_release (nt , sysdata_len );
15391543 if (nt -> sysdata_fields & SYSDATA_MSGID )
@@ -1831,83 +1835,108 @@ static void send_msg_fragmented(struct netconsole_target *nt,
18311835/**
18321836 * send_ext_msg_udp - send extended log message to target
18331837 * @nt: target to send message to
1834- * @msg: extended log message to send
1835- * @msg_len: length of message
1838+ * @wctxt: nbcon write context containing message and metadata
18361839 *
1837- * Transfer extended log @msg to @nt. If @msg is longer than
1840+ * Transfer extended log message to @nt. If message is longer than
18381841 * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
18391842 * ncfrag header field added to identify them.
18401843 */
1841- static void send_ext_msg_udp (struct netconsole_target * nt , const char * msg ,
1842- int msg_len )
1844+ static void send_ext_msg_udp (struct netconsole_target * nt ,
1845+ struct nbcon_write_context * wctxt )
18431846{
18441847 int userdata_len = 0 ;
18451848 int release_len = 0 ;
18461849 int sysdata_len = 0 ;
1850+ int len ;
18471851
18481852#ifdef CONFIG_NETCONSOLE_DYNAMIC
1849- sysdata_len = prepare_sysdata (nt );
1853+ sysdata_len = prepare_sysdata (nt , wctxt );
18501854 userdata_len = nt -> userdata_length ;
18511855#endif
18521856 if (nt -> release )
18531857 release_len = strlen (init_utsname ()-> release ) + 1 ;
18541858
1855- if (msg_len + release_len + sysdata_len + userdata_len <= MAX_PRINT_CHUNK )
1856- return send_msg_no_fragmentation (nt , msg , msg_len , release_len );
1859+ len = wctxt -> len + release_len + sysdata_len + userdata_len ;
1860+ if (len <= MAX_PRINT_CHUNK )
1861+ return send_msg_no_fragmentation (nt , wctxt -> outbuf ,
1862+ wctxt -> len , release_len );
18571863
1858- return send_msg_fragmented (nt , msg , msg_len , release_len ,
1864+ return send_msg_fragmented (nt , wctxt -> outbuf , wctxt -> len , release_len ,
18591865 sysdata_len );
18601866}
18611867
1862- static void write_ext_msg (struct console * con , const char * msg ,
1863- unsigned int len )
1868+ static void send_msg_udp (struct netconsole_target * nt , const char * msg ,
1869+ unsigned int len )
18641870{
1865- struct netconsole_target * nt ;
1866- unsigned long flags ;
1867-
1868- if ((oops_only && !oops_in_progress ) || list_empty (& target_list ))
1869- return ;
1871+ const char * tmp = msg ;
1872+ int frag , left = len ;
18701873
1871- spin_lock_irqsave ( & target_list_lock , flags );
1872- list_for_each_entry ( nt , & target_list , list )
1873- if (nt -> extended && nt -> state == STATE_ENABLED &&
1874- netif_running ( nt -> np . dev ))
1875- send_ext_msg_udp ( nt , msg , len ) ;
1876- spin_unlock_irqrestore ( & target_list_lock , flags );
1874+ while ( left > 0 ) {
1875+ frag = min ( left , MAX_PRINT_CHUNK );
1876+ send_udp (nt , tmp , frag );
1877+ tmp += frag ;
1878+ left -= frag ;
1879+ }
18771880}
18781881
1879- static void write_msg (struct console * con , const char * msg , unsigned int len )
1882+ /**
1883+ * netconsole_write - Generic function to send a msg to all targets
1884+ * @wctxt: nbcon write context
1885+ * @extended: "true" for extended console mode
1886+ *
1887+ * Given an nbcon write context, send the message to the netconsole targets
1888+ */
1889+ static void netconsole_write (struct nbcon_write_context * wctxt , bool extended )
18801890{
1881- int frag , left ;
1882- unsigned long flags ;
18831891 struct netconsole_target * nt ;
1884- const char * tmp ;
18851892
18861893 if (oops_only && !oops_in_progress )
18871894 return ;
1888- /* Avoid taking lock and disabling interrupts unnecessarily */
1889- if (list_empty (& target_list ))
1890- return ;
18911895
1892- spin_lock_irqsave (& target_list_lock , flags );
18931896 list_for_each_entry (nt , & target_list , list ) {
1894- if (!nt -> extended && nt -> state == STATE_ENABLED &&
1895- netif_running (nt -> np .dev )) {
1896- /*
1897- * We nest this inside the for-each-target loop above
1898- * so that we're able to get as much logging out to
1899- * at least one target if we die inside here, instead
1900- * of unnecessarily keeping all targets in lock-step.
1901- */
1902- tmp = msg ;
1903- for (left = len ; left ;) {
1904- frag = min (left , MAX_PRINT_CHUNK );
1905- send_udp (nt , tmp , frag );
1906- tmp += frag ;
1907- left -= frag ;
1908- }
1909- }
1897+ if (nt -> extended != extended || nt -> state != STATE_ENABLED ||
1898+ !netif_running (nt -> np .dev ))
1899+ continue ;
1900+
1901+ /* If nbcon_enter_unsafe() fails, just return given netconsole
1902+ * lost the ownership, and iterating over the targets will not
1903+ * be able to re-acquire.
1904+ */
1905+ if (!nbcon_enter_unsafe (wctxt ))
1906+ return ;
1907+
1908+ if (extended )
1909+ send_ext_msg_udp (nt , wctxt );
1910+ else
1911+ send_msg_udp (nt , wctxt -> outbuf , wctxt -> len );
1912+
1913+ nbcon_exit_unsafe (wctxt );
19101914 }
1915+ }
1916+
1917+ static void netconsole_write_ext (struct console * con __always_unused ,
1918+ struct nbcon_write_context * wctxt )
1919+ {
1920+ netconsole_write (wctxt , true);
1921+ }
1922+
1923+ static void netconsole_write_basic (struct console * con __always_unused ,
1924+ struct nbcon_write_context * wctxt )
1925+ {
1926+ netconsole_write (wctxt , false);
1927+ }
1928+
1929+ static void netconsole_device_lock (struct console * con __always_unused ,
1930+ unsigned long * flags )
1931+ __acquires (& target_list_lock )
1932+ {
1933+ spin_lock_irqsave (& target_list_lock , * flags );
1934+ }
1935+
1936+ static void netconsole_device_unlock (struct console * con __always_unused ,
1937+ unsigned long flags )
1938+ __releases (& target_list_lock )
1939+ {
19111940 spin_unlock_irqrestore (& target_list_lock , flags );
19121941}
19131942
@@ -2071,15 +2100,21 @@ static void free_param_target(struct netconsole_target *nt)
20712100}
20722101
20732102static struct console netconsole_ext = {
2074- .name = "netcon_ext" ,
2075- .flags = CON_ENABLED | CON_EXTENDED ,
2076- .write = write_ext_msg ,
2103+ .name = "netcon_ext" ,
2104+ .flags = CON_ENABLED | CON_EXTENDED | CON_NBCON | CON_NBCON_ATOMIC_UNSAFE ,
2105+ .write_thread = netconsole_write_ext ,
2106+ .write_atomic = netconsole_write_ext ,
2107+ .device_lock = netconsole_device_lock ,
2108+ .device_unlock = netconsole_device_unlock ,
20772109};
20782110
20792111static struct console netconsole = {
2080- .name = "netcon" ,
2081- .flags = CON_ENABLED ,
2082- .write = write_msg ,
2112+ .name = "netcon" ,
2113+ .flags = CON_ENABLED | CON_NBCON | CON_NBCON_ATOMIC_UNSAFE ,
2114+ .write_thread = netconsole_write_basic ,
2115+ .write_atomic = netconsole_write_basic ,
2116+ .device_lock = netconsole_device_lock ,
2117+ .device_unlock = netconsole_device_unlock ,
20832118};
20842119
20852120static int __init init_netconsole (void )
0 commit comments