* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-11 16:32 [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect syzbot
@ 2026-01-13 3:11 ` weipeng
2026-01-13 4:22 ` syzbot
2026-01-13 6:25 ` weipeng
` (3 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: weipeng @ 2026-01-13 3:11 UTC (permalink / raw)
To: syzbot+30b78308ba7e64647ff8
Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
#syz test
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index 57dfe5f1a7d9..79b7c97514c9 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -172,6 +173,8 @@ struct i2c_tiny_usb {
struct usb_device *usb_dev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct i2c_adapter adapter; /* i2c related things */
+ bool disconnected; /* set to true on disconnect */
+ struct work_struct release_work; /* work struct to release the adapter */
};
static int usb_read(struct i2c_adapter *adapter, int cmd,
@@ -184,6 +187,11 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ if (READ_ONCE(dev->disconnected)) {
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
@@ -204,6 +212,11 @@ static int usb_write(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ if (READ_ONCE(dev->disconnected)) {
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -219,6 +232,15 @@ static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
kfree(dev);
}
+static void i2c_tiny_usb_release(struct work_struct *work)
+{
+ struct i2c_tiny_usb *dev = container_of(work, struct i2c_tiny_usb,
+ release_work);
+
+ i2c_del_adapter(&dev->adapter);
+ i2c_tiny_usb_free(dev);
+}
+
static int i2c_tiny_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -268,6 +290,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->adapter.dev.parent = &dev->interface->dev;
+ INIT_WORK(&dev->release_work, i2c_tiny_usb_release);
+
/* and finally attach to i2c layer */
i2c_add_adapter(&dev->adapter);
@@ -287,9 +311,9 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
{
struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
- i2c_del_adapter(&dev->adapter);
usb_set_intfdata(interface, NULL);
- i2c_tiny_usb_free(dev);
+ WRITE_ONCE(dev->disconnected, true);
+ queue_work(system_long_wq, &dev->release_work);
dev_dbg(&interface->dev, "disconnected\n");
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 3:11 ` weipeng
@ 2026-01-13 4:22 ` syzbot
0 siblings, 0 replies; 16+ messages in thread
From: syzbot @ 2026-01-13 4:22 UTC (permalink / raw)
To: anna-maria, coderlogicwei, frederic, linux-kernel, linux-usb,
syzkaller-bugs, tglx
Hello,
syzbot tried to test the proposed patch but the build/boot failed:
:sysadm_r:sysadm_t tcontext=system_u:object_r:nsfs_t tclass=file permissive=1
[ 72.435490][ T30] audit: type=1400 audit(1768278064.403:80): avc: denied { open } for pid=5828 comm="syz-executor" path="net:[4026531833]" dev="nsfs" ino=4026531833 scontext=root:sysadm_r:sysadm_t tcontext=system_u:object_r:nsfs_t tclass=file permissive=1
[ 72.472115][ T30] audit: type=1400 audit(1768278064.423:81): avc: denied { mounton } for pid=5828 comm="syz-executor" path="/" dev="sda1" ino=2 scontext=root:sysadm_r:sysadm_t tcontext=system_u:object_r:root_t tclass=dir permissive=1
[ 72.614307][ T30] audit: type=1400 audit(1768278064.723:82): avc: denied { mounton } for pid=5827 comm="syz-executor" path="/root/syzkaller.oRvwjY/syz-tmp" dev="sda1" ino=2042 scontext=root:sysadm_r:sysadm_t tcontext=root:object_r:user_home_t tclass=dir permissive=1
[ 72.647781][ T30] audit: type=1400 audit(1768278064.723:83): avc: denied { mount } for pid=5827 comm="syz-executor" name="/" dev="tmpfs" ino=1 scontext=root:sysadm_r:sysadm_t tcontext=system_u:object_r:tmpfs_t tclass=filesystem permissive=1
[ 72.680449][ T5827] soft_limit_in_bytes is deprecated and will be removed. Please report your usecase to linux-mm@kvack.org if you depend on this functionality.
[ 72.710613][ T30] audit: type=1400 audit(1768278064.723:84): avc: denied { mounton } for pid=5827 comm="syz-executor" path="/root/syzkaller.oRvwjY/syz-tmp/newroot/dev" dev="tmpfs" ino=3 scontext=root:sysadm_r:sysadm_t tcontext=root:object_r:user_tmpfs_t tclass=dir permissive=1
[ 72.747865][ T30] audit: type=1400 audit(1768278064.723:85): avc: denied { mount } for pid=5827 comm="syz-executor" name="/" dev="proc" ino=1 scontext=root:sysadm_r:sysadm_t tcontext=system_u:object_r:proc_t tclass=filesystem permissive=1
[ 72.770404][ T50] wlan0: Created IBSS using preconfigured BSSID 50:50:50:50:50:50
[ 72.778851][ T50] wlan0: Creating new IBSS network, BSSID 50:50:50:50:50:50
[ 72.834660][ T34] wlan1: Created IBSS using preconfigured BSSID 50:50:50:50:50:50
[ 72.843508][ T34] wlan1: Creating new IBSS network, BSSID 50:50:50:50:50:50
[ 73.164131][ T5138] Bluetooth: hci0: unexpected cc 0x0c03 length: 249 > 1
[ 73.172297][ T5138] Bluetooth: hci0: unexpected cc 0x1003 length: 249 > 9
[ 73.180246][ T5138] Bluetooth: hci0: unexpected cc 0x1001 length: 249 > 9
[ 73.196749][ T5138] Bluetooth: hci0: unexpected cc 0x0c23 length: 249 > 4
[ 73.204345][ T5138] Bluetooth: hci0: unexpected cc 0x0c38 length: 249 > 2
[ 74.264425][ T5845] chnl_net:caif_netlink_parms(): no params data found
[ 74.807351][ T5845] bridge0: port 1(bridge_slave_0) entered blocking state
[ 74.821439][ T5845] bridge0: port 1(bridge_slave_0) entered disabled state
[ 74.828899][ T5845] bridge_slave_0: entered allmulticast mode
[ 74.836593][ T5845] bridge_slave_0: entered promiscuous mode
[ 74.864560][ T5845] bridge0: port 2(bridge_slave_1) entered blocking state
[ 74.871733][ T5845] bridge0: port 2(bridge_slave_1) entered disabled state
[ 74.879122][ T5845] bridge_slave_1: entered allmulticast mode
[ 74.886071][ T5845] bridge_slave_1: entered promiscuous mode
[ 74.955828][ T5845] bond0: (slave bond_slave_0): Enslaving as an active interface with an up link
[ 74.987690][ T5845] bond0: (slave bond_slave_1): Enslaving as an active interface with an up link
[ 75.079143][ T5845] team0: Port device team_slave_0 added
[ 75.098503][ T5845] team0: Port device team_slave_1 added
[ 75.204805][ T5845] batman_adv: batadv0: Adding interface: batadv_slave_0
[ 75.211766][ T5845] batman_adv: batadv0: The MTU of interface batadv_slave_0 is too small (1500) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to 1532 would solve the problem.
[ 75.239767][ T5845] batman_adv: batadv0: Not using interface batadv_slave_0 (retrying later): interface not active
[ 75.255335][ T5845] batman_adv: batadv0: Adding interface: batadv_slave_1
[ 75.262370][ T5845] batman_adv: batadv0: The MTU of interface batadv_slave_1 is too small (1500) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to 1532 would solve the problem.
[ 75.298894][ T5845] batman_adv: batadv0: Not using interface batadv_slave_1 (retrying later): interface not active
[ 75.443715][ T5845] hsr_slave_0: entered promiscuous mode
[ 75.449871][ T5845] hsr_slave_1: entered promiscuous mode
[ 75.592860][ T5845] netdevsim netdevsim0 netdevsim0: renamed from eth0
[ 75.608307][ T5845] netdevsim netdevsim0 netdevsim1: renamed from eth1
[ 75.617970][ T5845] netdevsim netdevsim0 netdevsim2: renamed from eth2
[ 75.628160][ T5845] netdevsim netdevsim0 netdevsim3: renamed from eth3
[ 75.708538][ T5845] 8021q: adding VLAN 0 to HW filter on device bond0
[ 75.728539][ T5845] 8021q: adding VLAN 0 to HW filter on device team0
[ 75.742231][ T34] bridge0: port 1(bridge_slave_0) entered blocking state
[ 75.749498][ T34] bridge0: port 1(bridge_slave_0) entered forwarding state
[ 75.768885][ T50] bridge0: port 2(bridge_slave_1) entered blocking state
[ 75.776013][ T50] bridge0: port 2(bridge_slave_1) entered forwarding state
[ 75.907923][ T5845] 8021q: adding VLAN 0 to HW filter on device batadv0
[ 75.945758][ T5845] veth0_vlan: entered promiscuous mode
[ 75.957083][ T5845] veth1_vlan: entered promiscuous mode
[ 75.981363][ T5845] veth0_macvtap: entered promiscuous mode
[ 75.990660][ T5845] veth1_macvtap: entered promiscuous mode
[ 76.006870][ T5845] batman_adv: batadv0: Interface activated: batadv_slave_0
[ 76.021233][ T5845] batman_adv: batadv0: Interface activated: batadv_slave_1
[ 76.035693][ T50] netdevsim netdevsim0 netdevsim0: set [1, 0] type 2 family 0 port 6081 - 0
[ 76.046111][ T50] netdevsim netdevsim0 netdevsim1: set [1, 0] type 2 family 0 port 6081 - 0
[ 76.056220][ T50] netdevsim netdevsim0 netdevsim2: set [1, 0] type 2 family 0 port 6081 - 0
[ 76.065691][ T50] netdevsim netdevsim0 netdevsim3: set [1, 0] type 2 family 0 port 6081 - 0
2026/01/13 04:21:08 executed programs: 0
[ 76.180451][ T52] Bluetooth: hci0: unexpected cc 0x0c03 length: 249 > 1
[ 76.188555][ T52] Bluetooth: hci0: unexpected cc 0x1003 length: 249 > 9
[ 76.196772][ T52] Bluetooth: hci0: unexpected cc 0x1001 length: 249 > 9
[ 76.210549][ T52] Bluetooth: hci0: unexpected cc 0x0c23 length: 249 > 4
[ 76.220325][ T52] Bluetooth: hci0: unexpected cc 0x0c38 length: 249 > 2
[ 76.223744][ T72] netdevsim netdevsim0 netdevsim3 (unregistering): unset [1, 0] type 2 family 0 port 6081 - 0
[ 76.302193][ T72] netdevsim netdevsim0 netdevsim2 (unregistering): unset [1, 0] type 2 family 0 port 6081 - 0
[ 76.393644][ T72] netdevsim netdevsim0 netdevsim1 (unregistering): unset [1, 0] type 2 family 0 port 6081 - 0
[ 76.413627][ T5926] chnl_net:caif_netlink_parms(): no params data found
[ 76.438442][ T72] netdevsim netdevsim0 netdevsim0 (unregistering): unset [1, 0] type 2 family 0 port 6081 - 0
[ 76.494052][ T5926] bridge0: port 1(bridge_slave_0) entered blocking state
[ 76.501225][ T5926] bridge0: port 1(bridge_slave_0) entered disabled state
[ 76.508469][ T5926] bridge_slave_0: entered allmulticast mode
[ 76.515622][ T5926] bridge_slave_0: entered promiscuous mode
[ 76.523432][ T5926] bridge0: port 2(bridge_slave_1) entered blocking state
[ 76.530728][ T5926] bridge0: port 2(bridge_slave_1) entered disabled state
[ 76.538432][ T5926] bridge_slave_1: entered allmulticast mode
[ 76.546031][ T5926] bridge_slave_1: entered promiscuous mode
[ 76.578006][ T5926] bond0: (slave bond_slave_0): Enslaving as an active interface with an up link
[ 76.589208][ T5926] bond0: (slave bond_slave_1): Enslaving as an active interface with an up link
[ 76.615543][ T5926] team0: Port device team_slave_0 added
[ 76.622696][ T5926] team0: Port device team_slave_1 added
[ 76.645027][ T5926] batman_adv: batadv0: Adding interface: batadv_slave_0
[ 76.651985][ T5926] batman_adv: batadv0: The MTU of interface batadv_slave_0 is too small (1500) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to 1532 would solve the problem.
[ 76.678290][ T5926] batman_adv: batadv0: Not using interface batadv_slave_0 (retrying later): interface not active
[ 76.690400][ T5926] batman_adv: batadv0: Adding interface: batadv_slave_1
[ 76.697754][ T5926] batman_adv: batadv0: The MTU of interface batadv_slave_1 is too small (1500) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to 1532 would solve the problem.
[ 76.726622][ T5926] batman_adv: batadv0: Not using interface batadv_slave_1 (retrying later): interface not active
[ 76.762434][ T5926] hsr_slave_0: entered promiscuous mode
[ 76.768716][ T5926] hsr_slave_1: entered promiscuous mode
[ 76.775549][ T5926] debugfs: 'hsr0' already exists in 'hsr'
[ 76.781345][ T5926] Cannot create hsr debugfs directory
[ 78.304272][ T5138] Bluetooth: hci0: command tx timeout
[ 78.996240][ T72] bridge_slave_1: left allmulticast mode
[ 79.002028][ T72] bridge_slave_1: left promiscuous mode
[ 79.009209][ T72] bridge0: port 2(bridge_slave_1) entered disabled state
[ 79.021301][ T72] bridge_slave_0: left allmulticast mode
[ 79.027964][ T72] bridge_slave_0: left promiscuous mode
[ 79.034032][ T72] bridge0: port 1(bridge_slave_0) entered disabled state
[ 79.289281][ T72] bond0 (unregistering): (slave bond_slave_0): Releasing backup interface
[ 79.302958][ T72] bond0 (unregistering): (slave bond_slave_1): Releasing backup interface
[ 79.313901][ T72] bond0 (unregistering): Released all slaves
[ 79.411479][ T72] hsr_slave_0: left promiscuous mode
[ 79.418172][ T72] hsr_slave_1: left promiscuous mode
[ 79.424372][ T72] batman_adv: batadv0: Interface deactivated: batadv_slave_0
[ 79.431764][ T72] batman_adv: batadv0: Removing interface: batadv_slave_0
[ 79.443151][ T72] batman_adv: batadv0: Interface deactivated: batadv_slave_1
[ 79.450543][ T72] batman_adv: batadv0: Removing interface: batadv_slave_1
[ 79.464996][ T72] veth1_macvtap: left promiscuous mode
[ 79.470591][ T72] veth0_macvtap: left promiscuous mode
[ 79.476732][ T72] veth1_vlan: left promiscuous mode
[ 79.482025][ T72] veth0_vlan: left promiscuous mode
[ 79.704321][ T72] team0 (unregistering): Port device team_slave_1 removed
[ 79.727145][ T72] team0 (unregistering): Port device team_slave_0 removed
[ 80.255625][ T5926] netdevsim netdevsim0 netdevsim0: renamed from eth0
[ 80.269626][ T5926] netdevsim netdevsim0 netdevsim1: renamed from eth1
[ 80.282305][ T5926] netdevsim netdevsim0 netdevsim2: renamed from eth2
[ 80.301156][ T5926] netdevsim netdevsim0 netdevsim3: renamed from eth3
[ 80.379053][ T5926] 8021q: adding VLAN 0 to HW filter on device bond0
[ 80.393475][ T5138] Bluetooth: hci0: command tx timeout
[ 80.396938][ T5926] 8021q: adding VLAN 0 to HW filter on device team0
[ 80.418036][ T3673] bridge0: port 1(bridge_slave_0) entered blocking state
[ 80.425216][ T3673] bridge0: port 1(bridge_slave_0) entered forwarding state
[ 80.436608][ T3673] bridge0: port 2(bridge_slave_1) entered blocking state
[ 80.443785][ T3673] bridge0: port 2(bridge_slave_1) entered forwarding state
[ 80.681996][ T5926] 8021q: adding VLAN 0 to HW filter on device batadv0
[ 80.742496][ T5926] veth0_vlan: entered promiscuous mode
[ 80.755265][ T5926] veth1_vlan: entered promiscuous mode
[ 80.789608][ T5926] veth0_macvtap: entered promiscuous mode
[ 80.800489][ T5926] veth1_macvtap: entered promiscuous mode
[ 80.822452][ T5926] batman_adv: batadv0: Interface activated: batadv_slave_0
[ 80.838062][ T5926] batman_adv: batadv0: Interface activated: batadv_slave_1
[ 80.854331][ T72] netdevsim netdevsim0 netdevsim0: set [1, 0] type 2 family 0 port 6081 - 0
[ 80.875850][ T72] netdevsim netdevsim0 netdevsim1: set [1, 0] type 2 family 0 port 6081 - 0
[ 80.887437][ T72] netdevsim netdevsim0 netdevsim2: set [1, 0] type 2 family 0 port 6081 - 0
[ 80.903437][ T72] netdevsim netdevsim0 netdevsim3: set [1, 0] type 2 family 0 port 6081 - 0
[ 80.982693][ T1093] wlan0: Created IBSS using preconfigured BSSID 50:50:50:50:50:50
[ 81.002995][ T1093] wlan0: Creating new IBSS network, BSSID 50:50:50:50:50:50
[ 81.039017][ T3673] wlan1: Created IBSS using preconfigured BSSID 50:50:50:50:50:50
[ 81.047802][ T3673] wlan1: Creating new IBSS network, BSSID 50:50:50:50:50:50
SYZFAIL: failed to recv rpc
fd=3 want=4 recv=0 n=0 (errno 9: Bad file descriptor)
[ 81.437183][ T43] cfg80211: failed to load regulatory.db
syzkaller build log:
go env (err=<nil>)
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE='auto'
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/syzkaller/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/syzkaller/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2779563656=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/syzkaller/jobs-2/linux/gopath/src/github.com/google/syzkaller/go.mod'
GOMODCACHE='/syzkaller/jobs-2/linux/gopath/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/syzkaller/jobs-2/linux/gopath'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/syzkaller/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.4'
GOWORK=''
PKG_CONFIG='pkg-config'
git status (err=<nil>)
HEAD detached at d6526ea3e
nothing to commit, working tree clean
tput: No value for $TERM and no -T specified
tput: No value for $TERM and no -T specified
Makefile:31: run command via tools/syz-env for best compatibility, see:
Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env
go list -f '{{.Stale}}' -ldflags="-s -w -X github.com/google/syzkaller/prog.GitRevision=d6526ea3e6ad9081c902859bbb80f9f840377cb4 -X github.com/google/syzkaller/prog.gitRevisionDate=20251126-113115" ./sys/syz-sysgen | grep -q false || go install -ldflags="-s -w -X github.com/google/syzkaller/prog.GitRevision=d6526ea3e6ad9081c902859bbb80f9f840377cb4 -X github.com/google/syzkaller/prog.gitRevisionDate=20251126-113115" ./sys/syz-sysgen
make .descriptions
tput: No value for $TERM and no -T specified
tput: No value for $TERM and no -T specified
Makefile:31: run command via tools/syz-env for best compatibility, see:
Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env
bin/syz-sysgen
touch .descriptions
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X github.com/google/syzkaller/prog.GitRevision=d6526ea3e6ad9081c902859bbb80f9f840377cb4 -X github.com/google/syzkaller/prog.gitRevisionDate=20251126-113115" -o ./bin/linux_amd64/syz-execprog github.com/google/syzkaller/tools/syz-execprog
mkdir -p ./bin/linux_amd64
g++ -o ./bin/linux_amd64/syz-executor executor/executor.cc \
-m64 -O2 -pthread -Wall -Werror -Wparentheses -Wunused-const-variable -Wframe-larger-than=16384 -Wno-stringop-overflow -Wno-array-bounds -Wno-format-overflow -Wno-unused-but-set-variable -Wno-unused-command-line-argument -static-pie -std=c++17 -I. -Iexecutor/_include -DGOOS_linux=1 -DGOARCH_amd64=1 \
-DHOSTGOOS_linux=1 -DGIT_REVISION=\"d6526ea3e6ad9081c902859bbb80f9f840377cb4\"
/usr/bin/ld: /tmp/cchrMEKM.o: in function `Connection::Connect(char const*, char const*)':
executor.cc:(.text._ZN10Connection7ConnectEPKcS1_[_ZN10Connection7ConnectEPKcS1_]+0x104): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
./tools/check-syzos.sh 2>/dev/null
Error text is too large and was truncated, full error text is at:
https://syzkaller.appspot.com/x/error.txt?x=15184052580000
Tested on:
commit: b71e635f Merge tag 'cgroup-for-6.19-rc5-fixes' of git:..
git tree: upstream
kernel config: https://syzkaller.appspot.com/x/.config?x=1859476832863c41
dashboard link: https://syzkaller.appspot.com/bug?extid=30b78308ba7e64647ff8
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=153f8052580000
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-11 16:32 [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect syzbot
2026-01-13 3:11 ` weipeng
@ 2026-01-13 6:25 ` weipeng
2026-01-13 7:28 ` syzbot
2026-01-13 7:52 ` weipeng
` (2 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: weipeng @ 2026-01-13 6:25 UTC (permalink / raw)
To: syzbot+30b78308ba7e64647ff8
Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git mater
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index 57dfe5f1a7d9..79b7c97514c9 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -172,6 +173,8 @@ struct i2c_tiny_usb {
struct usb_device *usb_dev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct i2c_adapter adapter; /* i2c related things */
+ bool disconnected; /* set to true on disconnect */
+ struct work_struct release_work; /* work struct to release the adapter */
};
static int usb_read(struct i2c_adapter *adapter, int cmd,
@@ -184,6 +187,11 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ if (READ_ONCE(dev->disconnected)) {
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
@@ -204,6 +212,11 @@ static int usb_write(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ if (READ_ONCE(dev->disconnected)) {
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -219,6 +232,15 @@ static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
kfree(dev);
}
+static void i2c_tiny_usb_release(struct work_struct *work)
+{
+ struct i2c_tiny_usb *dev = container_of(work, struct i2c_tiny_usb,
+ release_work);
+
+ i2c_del_adapter(&dev->adapter);
+ i2c_tiny_usb_free(dev);
+}
+
static int i2c_tiny_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -268,6 +290,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->adapter.dev.parent = &dev->interface->dev;
+ INIT_WORK(&dev->release_work, i2c_tiny_usb_release);
+
/* and finally attach to i2c layer */
i2c_add_adapter(&dev->adapter);
@@ -287,9 +311,9 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
{
struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
- i2c_del_adapter(&dev->adapter);
usb_set_intfdata(interface, NULL);
- i2c_tiny_usb_free(dev);
+ WRITE_ONCE(dev->disconnected, true);
+ queue_work(system_long_wq, &dev->release_work);
dev_dbg(&interface->dev, "disconnected\n");
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-11 16:32 [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect syzbot
2026-01-13 3:11 ` weipeng
2026-01-13 6:25 ` weipeng
@ 2026-01-13 7:52 ` weipeng
2026-01-13 8:35 ` syzbot
2026-01-13 9:49 ` Oliver Neukum
2026-01-13 15:45 ` weipeng
2026-01-13 15:47 ` weipeng
4 siblings, 2 replies; 16+ messages in thread
From: weipeng @ 2026-01-13 7:52 UTC (permalink / raw)
To: syzbot+30b78308ba7e64647ff8
Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index 57dfe5f1a7d9..79b7c97514c9 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -172,6 +173,8 @@ struct i2c_tiny_usb {
struct usb_device *usb_dev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct i2c_adapter adapter; /* i2c related things */
+ bool disconnected; /* set to true on disconnect */
+ struct work_struct release_work; /* work struct to release the adapter */
};
static int usb_read(struct i2c_adapter *adapter, int cmd,
@@ -184,6 +187,11 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ if (READ_ONCE(dev->disconnected)) {
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
@@ -204,6 +212,11 @@ static int usb_write(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ if (READ_ONCE(dev->disconnected)) {
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -219,6 +232,15 @@ static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
kfree(dev);
}
+static void i2c_tiny_usb_release(struct work_struct *work)
+{
+ struct i2c_tiny_usb *dev = container_of(work, struct i2c_tiny_usb,
+ release_work);
+
+ i2c_del_adapter(&dev->adapter);
+ i2c_tiny_usb_free(dev);
+}
+
static int i2c_tiny_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -268,6 +290,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->adapter.dev.parent = &dev->interface->dev;
+ INIT_WORK(&dev->release_work, i2c_tiny_usb_release);
+
/* and finally attach to i2c layer */
i2c_add_adapter(&dev->adapter);
@@ -287,9 +311,9 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
{
struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
- i2c_del_adapter(&dev->adapter);
usb_set_intfdata(interface, NULL);
- i2c_tiny_usb_free(dev);
+ WRITE_ONCE(dev->disconnected, true);
+ queue_work(system_long_wq, &dev->release_work);
dev_dbg(&interface->dev, "disconnected\n");
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 7:52 ` weipeng
@ 2026-01-13 8:35 ` syzbot
2026-01-13 9:49 ` Oliver Neukum
1 sibling, 0 replies; 16+ messages in thread
From: syzbot @ 2026-01-13 8:35 UTC (permalink / raw)
To: anna-maria, coderlogicwei, frederic, linux-kernel, linux-usb,
syzkaller-bugs, tglx
Hello,
syzbot has tested the proposed patch and the reproducer did not trigger any issue:
Reported-by: syzbot+30b78308ba7e64647ff8@syzkaller.appspotmail.com
Tested-by: syzbot+30b78308ba7e64647ff8@syzkaller.appspotmail.com
Tested on:
commit: b71e635f Merge tag 'cgroup-for-6.19-rc5-fixes' of git:..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=17f0699a580000
kernel config: https://syzkaller.appspot.com/x/.config?x=1859476832863c41
dashboard link: https://syzkaller.appspot.com/bug?extid=30b78308ba7e64647ff8
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=117d15fa580000
Note: testing is done by a robot and is best-effort only.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 7:52 ` weipeng
2026-01-13 8:35 ` syzbot
@ 2026-01-13 9:49 ` Oliver Neukum
2026-01-13 15:35 ` weipeng
1 sibling, 1 reply; 16+ messages in thread
From: Oliver Neukum @ 2026-01-13 9:49 UTC (permalink / raw)
To: weipeng, syzbot+30b78308ba7e64647ff8
Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
On 13.01.26 08:52, weipeng wrote:
> @@ -287,9 +311,9 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
> {
> struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
>
> - i2c_del_adapter(&dev->adapter);
> usb_set_intfdata(interface, NULL);
> - i2c_tiny_usb_free(dev);
> + WRITE_ONCE(dev->disconnected, true);
> + queue_work(system_long_wq, &dev->release_work);
Hi,
I am sorry, but this fix is looking a bit fishy.
For once what prevents the driver from being unloaded
with a work item queued after disconnect() has run?
How do you make sure that the disconnected flag is ever read?
Regards
Oliver
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 9:49 ` Oliver Neukum
@ 2026-01-13 15:35 ` weipeng
0 siblings, 0 replies; 16+ messages in thread
From: weipeng @ 2026-01-13 15:35 UTC (permalink / raw)
To: oneukum
Cc: anna-maria, coderlogicwei, frederic, linux-kernel, linux-usb,
syzbot+30b78308ba7e64647ff8, syzkaller-bugs, tglx
On Tue, 13 Jan 2026 10:49:16, Oliver Neukum wrote:
> For once what prevents the driver from being unloaded
> with a work item queued after disconnect() has run?
> How do you make sure that the disconnected flag is ever read?
Hi,
Did you say that we can't make sure the usb_read() and usb_write()
is prevented after the dev->disconnected is set to true?
It is indeed a problem. I will send a new patch soon.
Thanks for review!
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-11 16:32 [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect syzbot
` (2 preceding siblings ...)
2026-01-13 7:52 ` weipeng
@ 2026-01-13 15:45 ` weipeng
2026-01-13 15:47 ` weipeng
4 siblings, 0 replies; 16+ messages in thread
From: weipeng @ 2026-01-13 15:45 UTC (permalink / raw)
To: syzbot+30b78308ba7e64647ff8, oneukum
Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index 57dfe5f1a7d9..30679c2b787b 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -172,6 +173,9 @@ struct i2c_tiny_usb {
struct usb_device *usb_dev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct i2c_adapter adapter; /* i2c related things */
+ bool disconnected; /* set to true on disconnect */
+ struct work_struct release_work; /* work struct to release the adapter */
+ struct mutex usb_lock; /* lock for usb operations */
};
static int usb_read(struct i2c_adapter *adapter, int cmd,
@@ -184,11 +188,20 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ mutex_lock(&dev->usb_lock);
+ if (dev->disconnected) {
+ mutex_unlock(&dev->usb_lock);
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
USB_DIR_IN, value, index, dmadata, len, 2000);
+ mutex_unlock(&dev->usb_lock);
+
memcpy(data, dmadata, len);
kfree(dmadata);
return ret;
@@ -204,11 +217,20 @@ static int usb_write(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ mutex_lock(&dev->usb_lock);
+ if (dev->disconnected) {
+ mutex_unlock(&dev->usb_lock);
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
value, index, dmadata, len, 2000);
+ mutex_unlock(&dev->usb_lock);
+
kfree(dmadata);
return ret;
}
@@ -219,6 +241,15 @@ static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
kfree(dev);
}
+static void i2c_tiny_usb_release(struct work_struct *work)
+{
+ struct i2c_tiny_usb *dev = container_of(work, struct i2c_tiny_usb,
+ release_work);
+
+ i2c_del_adapter(&dev->adapter);
+ i2c_tiny_usb_free(dev);
+}
+
static int i2c_tiny_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -239,6 +270,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
+ mutex_init(&dev->usb_lock);
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
@@ -268,6 +300,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->adapter.dev.parent = &dev->interface->dev;
+ INIT_WORK(&dev->release_work, i2c_tiny_usb_release);
+
/* and finally attach to i2c layer */
i2c_add_adapter(&dev->adapter);
@@ -287,9 +321,12 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
{
struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
- i2c_del_adapter(&dev->adapter);
+ mutex_lock(&dev->usb_lock);
usb_set_intfdata(interface, NULL);
- i2c_tiny_usb_free(dev);
+ dev->disconnected = true;
+ mutex_unlock(&dev->usb_lock);
+
+ queue_work(system_long_wq, &dev->release_work);
dev_dbg(&interface->dev, "disconnected\n");
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-11 16:32 [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect syzbot
` (3 preceding siblings ...)
2026-01-13 15:45 ` weipeng
@ 2026-01-13 15:47 ` weipeng
2026-01-13 16:18 ` syzbot
2026-01-13 20:23 ` Oliver Neukum
4 siblings, 2 replies; 16+ messages in thread
From: weipeng @ 2026-01-13 15:47 UTC (permalink / raw)
To: syzbot+30b78308ba7e64647ff8, oneukum
Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
index 57dfe5f1a7d9..30679c2b787b 100644
--- a/drivers/i2c/busses/i2c-tiny-usb.c
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
/* include interfaces to usb layer */
#include <linux/usb.h>
@@ -172,6 +173,9 @@ struct i2c_tiny_usb {
struct usb_device *usb_dev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct i2c_adapter adapter; /* i2c related things */
+ bool disconnected; /* set to true on disconnect */
+ struct work_struct release_work; /* work struct to release the adapter */
+ struct mutex usb_lock; /* lock for usb operations */
};
static int usb_read(struct i2c_adapter *adapter, int cmd,
@@ -184,11 +188,20 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ mutex_lock(&dev->usb_lock);
+ if (dev->disconnected) {
+ mutex_unlock(&dev->usb_lock);
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
USB_DIR_IN, value, index, dmadata, len, 2000);
+ mutex_unlock(&dev->usb_lock);
+
memcpy(data, dmadata, len);
kfree(dmadata);
return ret;
@@ -204,11 +217,20 @@ static int usb_write(struct i2c_adapter *adapter, int cmd,
if (!dmadata)
return -ENOMEM;
+ mutex_lock(&dev->usb_lock);
+ if (dev->disconnected) {
+ mutex_unlock(&dev->usb_lock);
+ kfree(dmadata);
+ return -ENODEV;
+ }
+
/* do control transfer */
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
value, index, dmadata, len, 2000);
+ mutex_unlock(&dev->usb_lock);
+
kfree(dmadata);
return ret;
}
@@ -219,6 +241,15 @@ static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
kfree(dev);
}
+static void i2c_tiny_usb_release(struct work_struct *work)
+{
+ struct i2c_tiny_usb *dev = container_of(work, struct i2c_tiny_usb,
+ release_work);
+
+ i2c_del_adapter(&dev->adapter);
+ i2c_tiny_usb_free(dev);
+}
+
static int i2c_tiny_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -239,6 +270,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
+ mutex_init(&dev->usb_lock);
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
@@ -268,6 +300,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
dev->adapter.dev.parent = &dev->interface->dev;
+ INIT_WORK(&dev->release_work, i2c_tiny_usb_release);
+
/* and finally attach to i2c layer */
i2c_add_adapter(&dev->adapter);
@@ -287,9 +321,12 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
{
struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
- i2c_del_adapter(&dev->adapter);
+ mutex_lock(&dev->usb_lock);
usb_set_intfdata(interface, NULL);
- i2c_tiny_usb_free(dev);
+ dev->disconnected = true;
+ mutex_unlock(&dev->usb_lock);
+
+ queue_work(system_long_wq, &dev->release_work);
dev_dbg(&interface->dev, "disconnected\n");
}
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 15:47 ` weipeng
@ 2026-01-13 16:18 ` syzbot
2026-01-13 20:23 ` Oliver Neukum
1 sibling, 0 replies; 16+ messages in thread
From: syzbot @ 2026-01-13 16:18 UTC (permalink / raw)
To: anna-maria, coderlogicwei, frederic, linux-kernel, linux-usb,
oneukum, syzkaller-bugs, tglx
Hello,
syzbot has tested the proposed patch and the reproducer did not trigger any issue:
Reported-by: syzbot+30b78308ba7e64647ff8@syzkaller.appspotmail.com
Tested-by: syzbot+30b78308ba7e64647ff8@syzkaller.appspotmail.com
Tested on:
commit: b71e635f Merge tag 'cgroup-for-6.19-rc5-fixes' of git:..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=14a0a59a580000
kernel config: https://syzkaller.appspot.com/x/.config?x=1859476832863c41
dashboard link: https://syzkaller.appspot.com/bug?extid=30b78308ba7e64647ff8
compiler: gcc (Debian 12.2.0-14+deb12u1) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40
patch: https://syzkaller.appspot.com/x/patch.diff?x=1331f922580000
Note: testing is done by a robot and is best-effort only.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 15:47 ` weipeng
2026-01-13 16:18 ` syzbot
@ 2026-01-13 20:23 ` Oliver Neukum
2026-01-14 8:11 ` weipeng
1 sibling, 1 reply; 16+ messages in thread
From: Oliver Neukum @ 2026-01-13 20:23 UTC (permalink / raw)
To: weipeng; +Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
Hi,
On 13.01.26 16:47, weipeng wrote:
> @@ -287,9 +321,12 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
> {
> struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
>
> - i2c_del_adapter(&dev->adapter);
> + mutex_lock(&dev->usb_lock);
> usb_set_intfdata(interface, NULL);
> - i2c_tiny_usb_free(dev);
> + dev->disconnected = true;
> + mutex_unlock(&dev->usb_lock);
> +
> + queue_work(system_long_wq, &dev->release_work);
>
> dev_dbg(&interface->dev, "disconnected\n");
> }
what prevents the following sequence:
i2c_tiny_usb_disconnect() -> module unload -> i2c_tiny_usb_release()
As far as I can tell, this can happen and you'd execute already
freed memory.
Regards
Oliver
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-13 20:23 ` Oliver Neukum
@ 2026-01-14 8:11 ` weipeng
2026-01-14 8:26 ` Oliver Neukum
0 siblings, 1 reply; 16+ messages in thread
From: weipeng @ 2026-01-14 8:11 UTC (permalink / raw)
To: oneukum
Cc: anna-maria, coderlogicwei, frederic, linux-kernel, linux-usb,
syzkaller-bugs, tglx
On 2026-01-13 20:23, Oliver Neukum wrote:
> what prevents the following sequence:
>
> i2c_tiny_usb_disconnect() -> module unload -> i2c_tiny_usb_release()
>
> As far as I can tell, this can happen and you'd execute already
> freed memory.
Hi,
I got it. It can be solved by using wait_for_completion in the module exit
function to wait for all the i2c_tiny_usb_release() to be done.
But after think twice, I think it is not a good idea. Because that would be
too complicated for a driver. Almost all the usb drivers does not do like this.
They just call release functions in the disconnect() rather than put all the
release works to another task. So I think the key point is not the disconnect().
The key point is the i2c subsystem:
> void i2c_del_adapter(struct i2c_adapter *adap)
> {
> ...
> /* wait until all references to the device are gone
> *
> * FIXME: This is old code and should ideally be replaced by an
> * alternative which results in decoupling the lifetime of the struct
> * device from the i2c_adapter, like spi or netdev do. Any solution
> * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled!
> */
> init_completion(&adap->dev_released);
> device_unregister(&adap->dev);
> wait_for_completion(&adap->dev_released);
> ...
> }
The i2c_del_adapter() will wait for all the users to put the reference of the adapter.
It is not a good idea. We can't control the users. So the i2c_del_adapter() can wait
for any time.
Best Regards
weipeng
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-14 8:11 ` weipeng
@ 2026-01-14 8:26 ` Oliver Neukum
2026-01-14 8:51 ` weipeng
0 siblings, 1 reply; 16+ messages in thread
From: Oliver Neukum @ 2026-01-14 8:26 UTC (permalink / raw)
To: weipeng; +Cc: anna-maria, frederic, linux-kernel, linux-usb, syzkaller-bugs,
tglx
Hi,
On 14.01.26 09:11, weipeng wrote:
> I got it. It can be solved by using wait_for_completion in the module exit
> function to wait for all the i2c_tiny_usb_release() to be done.
At that point the module unload would potentially take forever,
because you cannot control how long it takes to complete.
> The i2c_del_adapter() will wait for all the users to put the reference of the adapter.
That seems reasonable.
> It is not a good idea. We can't control the users. So the i2c_del_adapter() can wait
> for any time.
Who exactly takes references? I think at this point you have a design issue
with the i2c layer and seems proper to include the linux-i2c list.
Regards
Oliver
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [syzbot] [usb?] INFO: task hung in i2c_tiny_usb_disconnect
2026-01-14 8:26 ` Oliver Neukum
@ 2026-01-14 8:51 ` weipeng
0 siblings, 0 replies; 16+ messages in thread
From: weipeng @ 2026-01-14 8:51 UTC (permalink / raw)
To: oneukum, linux-i2c
Cc: anna-maria, coderlogicwei, frederic, linux-kernel, linux-usb,
syzkaller-bugs, tglx
Hi,
i2c_del_adapter in i2c-core-base.c:
> void i2c_del_adapter(struct i2c_adapter *adap)
> {
> ...
> /* wait until all references to the device are gone
> *
> * FIXME: This is old code and should ideally be replaced by an
> * alternative which results in decoupling the lifetime of the struct
> * device from the i2c_adapter, like spi or netdev do. Any solution
> * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled!
> */
> init_completion(&adap->dev_released);
> device_unregister(&adap->dev);
> wait_for_completion(&adap->dev_released);
> ...
> }
This issue looks like caused by i2c_del_adapter(). It waits for too long so
it may cause the hung.
Thanks,
weipeng
^ permalink raw reply [flat|nested] 16+ messages in thread