]> git.ipfire.org Git - thirdparty/kernel/stable.git/commit
usb: cdc-wdm: avoid setting WDM_READ for ZLP-s
authorRobert Hodaszi <robert.hodaszi@digi.com>
Thu, 3 Apr 2025 14:40:04 +0000 (16:40 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 6 Jul 2025 08:57:56 +0000 (10:57 +0200)
commitc243ae461f55c2fdef39d1c30e096d8beae317fc
tree7d6230c89b67374daee363e1edb6aaa3d4b1a920
parent5463f3a5e88874a02d3b1eb7c7a1b8e9c2f1e901
usb: cdc-wdm: avoid setting WDM_READ for ZLP-s

[ Upstream commit 387602d8a75574fafb451b7a8215e78dfd67ee63 ]

Don't set WDM_READ flag in wdm_in_callback() for ZLP-s, otherwise when
userspace tries to poll for available data, it might - incorrectly -
believe there is something available, and when it tries to non-blocking
read it, it might get stuck in the read loop.

For example this is what glib does for non-blocking read (briefly):

  1. poll()
  2. if poll returns with non-zero, starts a read data loop:
    a. loop on poll() (EINTR disabled)
    b. if revents was set, reads data
      I. if read returns with EINTR or EAGAIN, goto 2.a.
      II. otherwise return with data

So if ZLP sets WDM_READ (#1), we expect data, and try to read it (#2).
But as that was a ZLP, and we are doing non-blocking read, wdm_read()
returns with EAGAIN (#2.b.I), so loop again, and try to read again
(#2.a.).

With glib, we might stuck in this loop forever, as EINTR is disabled
(#2.a).

Signed-off-by: Robert Hodaszi <robert.hodaszi@digi.com>
Acked-by: Oliver Neukum <oneukum@suse.com>
Link: https://lore.kernel.org/r/20250403144004.3889125-1-robert.hodaszi@digi.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/usb/class/cdc-wdm.c