tty_reopen() returning -EIO because port is closing
During testing of a tty driver that's just been updated to use the tty_port_ helper functions, I'm seeing a test failure in user-space when open() returns -EIO.
The failure occurs sporadically (maybe 1 failure per 100 opens) when running a test that has multiple threads all opening and closing the same serial port (more or less at random).
It's worth noting that my port activate and shutdown functions sleep.
Typically, they sleep for a few ms [this is the case during the tests I've been running]. But, there are use cases where they could sleep for hundreds of ms.
I've tracked the failure to tty_reopen() in tty_io.c [3.8-rc3]:
1331 static int tty_reopen(struct tty_struct *tty)
1332 {
1333 struct tty_driver *driver = tty->driver;
1334
1335 if (test_bit(TTY_CLOSING, &tty->flags) ||
1336 test_bit(TTY_HUPPING, &tty->flags) ||
1337 test_bit(TTY_LDISC_CHANGING, &tty->flags))
1338 return -EIO;Line 1338 is returning -EIO because test_bit(TTY_CLOSING, &tty->flags) is true.
Can this be caused by a bug in my driver?
If not, is it a bug in the tty layer?
Does Posix say than an open() may fail if it's called while another process is calling close()? IOW, is user-space code expected to retry an open() call that returns EIO? [I've never seen user-space code that did that...]
Signature · 3 lines
Grant Edwards grant.b.edwards Yow! I'm having a RELIGIOUS
at EXPERIENCE ... and I don't
gmail.com take any DRUGSQuoted 1 line
If not, is it a bug in the tty layer?
Our tty layer has always done this.
Quoted 4 lines
Does Posix say than an
open()may fail if it's called while another process is callingclose()? IOW, is user-space code expected to retry anopen()call that returns EIO? [I've never seen user-space code that did that...]
Interesting question. I've never liked the fact we do it (its rude to the userspace) but it's not clear what the correct semantics are of an open as a port closes, given the close must complete first including any drains and control changes and the open may well not expect to block or hang for a long time.
Alan
Quoted 4 lines · Alan Cox
Quoted 2 lines
If not, is it a bug in the tty layer?
Our tty layer has always done this.
We'll call it a feature, then.
I don't remember ever seeing it before. Either the test is different (which might be), or the old non-helper tty driver would somehow cause the open() to block/retry.
It looks like the old open() code checked to see if the port was closing, waited for the close to finish, and then returned either EAGAIN or ERESTARTSYS:
// If we are in the process of closing, wait for it to complete, then return
if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING)
{
wait_event_interruptible(info->close_wait, !(info->flags & ASYNC_CLOSING));
return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS;
}I do think I recall seeing a user-space open() block for some time under certain circumstances.
Quoted 10 lines
Quoted 4 lines
Does Posix say than an
open()may fail if it's called while another process is callingclose()? IOW, is user-space code expected to retry anopen()call that returns EIO? [I've never seen user-space code that did that...]Interesting question. I've never liked the fact we do it (its rude to the userspace) but it's not clear what the correct semantics are of an open as a port closes, given the close must complete first including any drains and control changes and the open may well not expect to block or hang for a long time.
If my driver now behaves the same as the "standard" driver where it didn't used to, I'm going to claim it's an improvement.
Signature · 4 lines
Grant Edwards grant.b.edwards Yow! I'm sitting on my
at SPEED QUEEN ... To me,
gmail.com it's ENJOYABLE ... I'm WARM
... I'm VIBRATORY ...Quoted 2 lines
If my driver now behaves the same as the "standard" driver where it didn't used to, I'm going to claim it's an improvement.
And given any fix for that behaviour in future would be in the generic shared code it also means you'll automatically pick it up. That's one of the big reasons for the tty_port code - to kill the hundreds of replicated differently buggy open implementations we had in drivers
Alan