3 ms·
It doesn't... or rather, it doesn't unless the kernel can safely unroll the write from it's insides. Famously NFS mounts can get eternally stuck processes when
by zaarn 6y ago
It doesn't... or rather, it doesn't unless the kernel can safely unroll the write from it's insides. Famously NFS mounts can get eternally stuck processes when they die because the other end of the file descriptor doesn't exist and there is nothing the kernel can reasonably do about it.
- Joker_vD 6y agoUh, return EIO? Or EINVAL?
- zaarn 6y agoEINVAL would mean the fd is invalid, which isn't true. The application already opened the file and possibly wrote to it, so EINVAL is not a valid error code. EIO sounds like it would make sense but can only be returned for errors relating to modifying inodes, the EIO that makes sense for NFS to be gone would be occuring when you call close(2) on the fd, or fsync(2) which has very unpredictable behaviour when it returns errors anyways. Either way, NFS doesn't handle inodes, so an EIO cannot be returned.
- Joker_vD 6y agoThat's an overly pedantic reading of the Linux manpage, IMHO. Even then, a) any of those error conditions may be extended to cover NFS failure; b) EINVAL's description already says "fd is attached to an object which is unsuitable for writing" — who says that such unsuitability is an immutable property? After all, writing into read-only fds is EBADF, and c) a new error code could be invented, if one is so inclined. But then again, POSIX merely states that while EIO shall be returned if "a physical I/O error has occurred", it "may also be returned under implementation-defined conditions". Heck, if you squint at the right angle, even ENXIO could be somewhat appropriate. I don't think that extending the meaning of EIO is worse than making unkillable zombie processes, to be fair.
- Asooka 6y agoNo, when the process is waiting on read/write to a file, it cannot be interrupted. The signal literally will not reach it until the syscall finishes. This is a deficiency of Linux design inherited from Unix and something that is being addressed over time. However it stems from the real requirement that a device can't just have its operation cancelled, once you've asked the HDD to read a sector, it won't respond until it has finished reading. So the process is stuck in the kernel HDD driver which literally cannot be interrupted. When it's a network or other removable storage obviously interrupts should happen at the media level, but the design did not permit it originally. Currently you can kill an fuse process and NFS has bits to allow signals in the middle of a read, but cifs for example doesn't.
- Joker_vD 6y agoMmm, but don't modern HDDs use DMA+IRQ for data transfer? The disk driver issues the read instruction and then it's done until the interrupt arrives? Anyhow, what are the peripheral devices that support only synchronous access? I don't believe there are any such ones in the modern PCs, but maybe there are some in mobile devices? Old floppy drives?
- asveikau 6y agoIsn't that the same as EINTR with a different name? And what happens if some bytes have made it to disk, network, or pipe? Don't you want to tell the caller how many, in case they want to recover somehow? Congrats, you reinvented the status quo. One improvement would be to separate the error indication from bytes written. Then you could have a write that fails, with nonzero output. Windows' API allows for this, but I don't know how common it is. It would probably be a source of bugs the same way these write(2) corner cases we are talking about are.
- Joker_vD 6y agoI was discussing a different scenario, "NFS mounts can get eternally stuck processes when they die because the other end of the file descriptor doesn't exist and there is nothing the kernel can reasonably do about it" — the kernel absolutely can do a reasonable thing and return from write(2) with whatever error code. And yes, Windows API's WriteFile does actually return less lpNumberOfBytesWritten than was passed in nNumberOfBytesToWrite, but only when writing to a non-blocking pipe; the disk writes are either fully written or fully failed. Sockets use their own special API that generally follows the write(2) semantics (although there are some hilarious corner cases with internal buffers: e.g., you can make a 1 GB write to a write-ready non-blocking socket and the internal buffer will grow to accomodate it, but further write requests will return EAGAIN).