From 4617721c502b2ddaa4e324e86da4997edf738fa5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 2 Sep 2026 09:55:01 -0400 Subject: ftrace: Synchronize the initialization of ftrace_ops There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt --- drivers/net/usb/gl620a.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 drivers/net/usb/gl620a.c (limited to 'drivers/net/usb/gl620a.c') diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c new file mode 100644 index 000000000..09afd137b --- /dev/null +++ b/drivers/net/usb/gl620a.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * GeneSys GL620USB-A based links + * Copyright (C) 2001 by Jiun-Jie Huang + * Copyright (C) 2001 by Stanislav Brabec + */ + +// #define DEBUG // error path messages, extra info +// #define VERBOSE // more; success messages + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * GeneSys GL620USB-A (www.genesyslogic.com.tw) + * + * ... should partially interop with the Win32 driver for this hardware. + * The GeneSys docs imply there's some NDIS issue motivating this framing. + * + * Some info from GeneSys: + * - GL620USB-A is full duplex; GL620USB is only half duplex for bulk. + * (Some cables, like the BAFO-100c, use the half duplex version.) + * - For the full duplex model, the low bit of the version code says + * which side is which ("left/right"). + * - For the half duplex type, a control/interrupt handshake settles + * the transfer direction. (That's disabled here, partially coded.) + * A control URB would block until other side writes an interrupt. + * + * Original code from Jiun-Jie Huang + * and merged into "usbnet" by Stanislav Brabec . + */ + +// control msg write command +#define GENELINK_CONNECT_WRITE 0xF0 +// interrupt pipe index +#define GENELINK_INTERRUPT_PIPE 0x03 +// interrupt read buffer size +#define INTERRUPT_BUFSIZE 0x08 +// interrupt pipe interval value +#define GENELINK_INTERRUPT_INTERVAL 0x10 +// max transmit packet number per transmit +#define GL_MAX_TRANSMIT_PACKETS 32 +// max packet length +#define GL_MAX_PACKET_LEN 1514 +// max receive buffer size +#define GL_RCV_BUF_SIZE \ + (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) + +struct gl_packet { + __le32 packet_length; + char packet_data[]; +}; + +struct gl_header { + __le32 packet_count; + struct gl_packet packets; +}; + +static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct gl_header *header; + struct gl_packet *packet; + struct sk_buff *gl_skb; + u32 size; + u32 count; + + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + + header = (struct gl_header *) skb->data; + + // get the packet count of the received skb + count = le32_to_cpu(header->packet_count); + if (count > GL_MAX_TRANSMIT_PACKETS) { + netdev_dbg(dev->net, + "genelink: invalid received packet count %u\n", + count); + return 0; + } + + // set the current packet pointer to the first packet + packet = &header->packets; + + // decrement the length for the packet count size 4 bytes + skb_pull(skb, 4); + + while (count > 1) { + // get the packet length + size = le32_to_cpu(packet->packet_length); + + // this may be a broken packet + if (size > GL_MAX_PACKET_LEN) { + netdev_dbg(dev->net, "genelink: invalid rx length %d\n", + size); + return 0; + } + + if (!skb_pull(skb, size + 4)) + return 0; + + // allocate the skb for the individual packet + gl_skb = alloc_skb(size, GFP_ATOMIC); + if (gl_skb) { + + // copy the packet data to the new skb + skb_put_data(gl_skb, packet->packet_data, size); + usbnet_skb_return(dev, gl_skb); + } + + // advance to the next packet + packet = (struct gl_packet *)&packet->packet_data[size]; + count--; + } + + // skip the packet length field 4 bytes + skb_pull(skb, 4); + + if (skb->len > GL_MAX_PACKET_LEN) { + netdev_dbg(dev->net, "genelink: invalid rx length %d\n", + skb->len); + return 0; + } + return 1; +} + +static struct sk_buff * +genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ + int padlen; + int length = skb->len; + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + __le32 *packet_count; + __le32 *packet_len; + + // FIXME: magic numbers, bleech + padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; + + if ((!skb_cloned(skb)) + && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { + if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { + skb->data = memmove(skb->head + (4 + 4*1), + skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + } + } else { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + // attach the packet count to the header + packet_count = skb_push(skb, (4 + 4 * 1)); + packet_len = packet_count + 1; + + *packet_count = cpu_to_le32(1); + *packet_len = cpu_to_le32(length); + + // add padding byte + if ((skb->len % dev->maxpacket) == 0) + skb_put(skb, 1); + + return skb; +} + +static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) +{ + dev->hard_mtu = GL_RCV_BUF_SIZE; + dev->net->hard_header_len += 4; + return usbnet_get_endpoints(dev, intf); +} + +static const struct driver_info genelink_info = { + .description = "Genesys GeneLink", + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT, + .bind = genelink_bind, + .rx_fixup = genelink_rx_fixup, + .tx_fixup = genelink_tx_fixup, + + .in = 1, .out = 2, + +#ifdef GENELINK_ACK + .check_connect =genelink_check_connect, +#endif +}; + +static const struct usb_device_id products [] = { + +{ + USB_DEVICE(0x05e3, 0x0502), // GL620USB-A + .driver_info = (unsigned long) &genelink_info, +}, + /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB + * that's half duplex, not currently supported + */ + { }, // END +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver gl620a_driver = { + .name = "gl620a", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, +}; + +module_usb_driver(gl620a_driver); + +MODULE_AUTHOR("Jiun-Jie Huang"); +MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables"); +MODULE_LICENSE("GPL"); + -- cgit v1.3.1