From: Takashi Sakamoto o-takashi@sakamocchi.jp
[ Upstream commit aea3493246c474bc917d124d6fb627663ab6bef0 ]
The ALSA HwDep character device of the firewire-motu driver incorrectly returns EPOLLOUT in poll(2), even though the driver implements no operation for write(2). This misleads userspace applications to believe write() is allowed, potentially resulting in unnecessarily wakeups.
This issue dates back to the driver's initial code added by a commit 71c3797779d3 ("ALSA: firewire-motu: add hwdep interface"), and persisted when POLLOUT was updated to EPOLLOUT by a commit a9a08845e9ac ('vfs: do bulk POLL* -> EPOLL* replacement("").').
This commit fixes the bug.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp Link: https://patch.msgid.link/20250829233749.366222-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
Based on my analysis of the commit and the kernel code, here is my backport decision:
**Backport Status: YES**
This commit should be backported to stable kernel trees for the following reasons:
## Bug Fix Analysis
1. **Clear Bug Fix**: The commit fixes a concrete bug where `hwdep_poll()` in `/home/sasha/linux/sound/firewire/motu/motu- hwdep.c:114` incorrectly returned `EPOLLOUT` despite the driver having no write operation implemented. The hwdep_ops structure at line 279-285 clearly shows no `.write` callback is defined.
2. **Long-standing Issue**: This bug has existed since the driver's initial implementation in commit 71c3797779d3c (March 2017), making it an 8+ year old bug affecting all kernel versions with this driver.
3. **User-Visible Impact**: The bug causes real problems for userspace applications: - Spurious wakeups from poll()/epoll() indicating write readiness when write is not supported - Potential busy-wait loops wasting CPU cycles - Applications receiving ENOSYS errors when attempting writes based on incorrect poll results
4. **Minimal and Safe Change**: The fix is a one-line change removing `| EPOLLOUT` from the return statement. This is about as minimal and low-risk as a fix can be: ```c - return events | EPOLLOUT; + return events; ```
5. **No Side Effects**: The change has no architectural impact and only corrects the poll semantics to match the actual driver capabilities. It cannot break existing functionality since write() was never supported.
6. **Subsystem Isolation**: The change is completely contained within the firewire-motu driver's hwdep interface, affecting only MOTU FireWire audio devices. There's no risk to other subsystems.
## Stable Tree Criteria Met
This commit satisfies multiple stable kernel criteria: - **Fixes a real bug**: Incorrect poll() behavior violating POSIX semantics - **Already upstream**: Merged by subsystem maintainer Takashi Iwai - **Minimal change**: Single line removal with clear correctness - **No new features**: Pure bug fix, no functionality additions - **Low regression risk**: Cannot break working code since write was never supported
## Additional Context
My examination of other FireWire audio drivers shows this is the correct pattern - drivers without write operations (bebob, dice, digi00x) correctly return only EPOLLIN flags, while only fireworks (which has a write operation) returns EPOLLOUT. The fireworks driver actually has a similar bug where it unconditionally returns EPOLLOUT without checking write readiness, but that's a separate issue.
The fix brings the motu driver in line with the correct hwdep poll implementation pattern used by other ALSA FireWire drivers.
sound/firewire/motu/motu-hwdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c index 88d1f4b56e4be..a220ac0c8eb83 100644 --- a/sound/firewire/motu/motu-hwdep.c +++ b/sound/firewire/motu/motu-hwdep.c @@ -111,7 +111,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file, events = 0; spin_unlock_irq(&motu->lock);
- return events | EPOLLOUT; + return events; }
static int hwdep_get_info(struct snd_motu *motu, void __user *arg)