What will happen if I kill a process which is waiting for the retuan ioctl() syscall?
If I have these: 1. I have implemented a simple ioctl() system call which just delay a period and return. 2. Call this ioctl() from a userspace process, of course, this process will be blocked until ioctl() return. 3. Before ioctl() return, use `kill -9 <pid>` command terminates the process. Question: 1. Can we instantly kill this process? 2. If we can instantly kill this process, does ioctl() still keep delay after killing? 3. If ioctl() still running even after we terminate this process, where does the return value ioctl() will return to? 4. How to keep the device's state consistent when we kill a process when it is invoking a system call? Best regards. Douglas
Hello Douglas, On 03/13/2018 07:56 PM, Douglas Su wrote:
If I have these:
1. I have implemented a simple ioctl() system call which just delay a period and return. 2. Call this ioctl() from a userspace process, of course, this process will be blocked until ioctl() return. 3. Before ioctl() return, use `kill -9 <pid>` command terminates the process.
Question:
1. Can we instantly kill this process? Of course, you can. But whether your behavior will affect your process depends on your implementation. 2. If we can instantly kill this process, does ioctl() still keep delay after killing? It depends on your implementation of your ioctl. If your ioctl has some kind of mechanism to check whether there is a signal received, you can let your ioctl return. 3. If ioctl() still running even after we terminate this process, where does the return value ioctl() will return to? That sounds insane. 4. How to keep the device's state consistent when we kill a process when it is invoking a system call? Sorry, I did not get your point.
Thanks, Larry
Best regards.
Douglas _______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
On 3/13/18 11:27 PM, Larry Chen wrote:
Hello Douglas,
On 03/13/2018 07:56 PM, Douglas Su wrote:
If I have these:
1. I have implemented a simple ioctl() system call which just delay a period and return. 2. Call this ioctl() from a userspace process, of course, this process will be blocked until ioctl() return. 3. Before ioctl() return, use `kill -9 <pid>` command terminates the process.
Question:
1. Can we instantly kill this process? Of course, you can. But whether your behavior will affect your process depends on your implementation. 2. If we can instantly kill this process, does ioctl() still keep delay after killing? It depends on your implementation of your ioctl. If your ioctl has some kind of mechanism to check whether there is a signal received, you can let your ioctl return. 3. If ioctl() still running even after we terminate this process, where does the return value ioctl() will return to? That sounds insane. 4. How to keep the device's state consistent when we kill a process when it is invoking a system call? Sorry, I did not get your point.
3 & 4 seem like perfectly obvious questions - and now I'm pretty curious. It's been a while since I've done any i/o coding, and it wasn't under *nix (the last time might have been Zilos - which dates me a bit) - and this raises all kinds of interesting questions in my mind. Re. 3: One can easily imagine data being left on the call stack (can you say security hole?), or buffers being created and passed to <where?>. Re. 4: One certainly wants to write device drivers that behave predictably under error conditions (like having the calling process die) Given that each ioctl() is different, and that there's stuff that happens in user space, kernel space, hardware - potentially multiple processes involved, handoff of data between user & kernel space, signals, and so forth.... One can envision all kinds of scenarios if the calling process is suspended or killed - orphaned processes, zombies, files left open, buffers copied and then handed to <whom?>, values left on the top of the stack, to be picked up by a now non-existent process (can you say security hole?), etc. ... And none of this seems to be well documented, or even defined. So... what is the actual flow of control when a userspace process makes an ioctl? Flow of data (arguments, return values, buffers, etc.)? Flow of signals? Side effects? Things that block and things that don't? Who owns what data & processes - particularly if the calling process dies? What is common to all ioctl() operations (and file operations in general)? What are constraints on what an ioctl() can/might do? To come back to the OP's question: What are some best practices - to insure that bad things don't happen if a calling process goes away while an ioctl() is in process? Probably not a topic that can be answered fully in an email - but references would be really nice! (I did find this - which gives a lot of interesting info - but I can't vouch for it's accuracy - https://www.slideshare.net/EmertxeSlides/linux-device-drivers-45884477) Miles Fidelman -- In theory, there is no difference between theory and practice. In practice, there is. .... Yogi Berra
Another reference: https://www.slideshare.net/JeremyBrown37/a-bug-hunters-perspective-on-unix-d... On 3/13/18 11:27 PM, Larry Chen wrote:
Hello Douglas,
On 03/13/2018 07:56 PM, Douglas Su wrote:
If I have these:
1. I have implemented a simple ioctl() system call which just delay a period and return. 2. Call this ioctl() from a userspace process, of course, this process will be blocked until ioctl() return. 3. Before ioctl() return, use `kill -9 <pid>` command terminates the process.
Question:
1. Can we instantly kill this process? Of course, you can. But whether your behavior will affect your process depends on your implementation. 2. If we can instantly kill this process, does ioctl() still keep delay after killing? It depends on your implementation of your ioctl. If your ioctl has some kind of mechanism to check whether there is a signal received, you can let your ioctl return. 3. If ioctl() still running even after we terminate this process, where does the return value ioctl() will return to? That sounds insane. 4. How to keep the device's state consistent when we kill a process when it is invoking a system call? Sorry, I did not get your point.
Thanks, Larry
Best regards.
Douglas _______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
-- In theory, there is no difference between theory and practice. In practice, there is. .... Yogi Berra
On Wed, 14 Mar 2018 11:27:41 +0800, Larry Chen said:
3. If ioctl() still running even after we terminate this process, where doe s the return value ioctl() will return to? That sounds insane.
That's because it *is* insane. The ioctl() *can't* "still be running" after the kill -9, because signals are by default not delivered to processes in the kernel until the kernel returns to userspace. In other words, terminating the process won't start happening until the ioctl() call finishes and starts to return. That's why you can't kill -9 a process that's stuck in 'D' state according to 'ps' - the kill remains pending. (And of course, if the driver does an explicit "is there a signal pending" check and returns to userspace without cleaning up it's mess, that's by definition a bug in the driver...) Now, there *is* a possibility that the ioctl() has initiated a hardware action that will take a while to complete (for example, issuing a rewind&offload to a tape drive can take 90 to 120 seconds to complete). If the driver is silly enough to return to userspace before the hardware action finishes, it's the driver's job to do more status checking on the next call for the device (for instance, "is the tape ready to act, or is it unwinding/loading/dropped on the floor by the robot"?) This gets complicated because often, *some* I/O commands can be accepted and executed by the device while others are still pending - but other different commands have to wait until the long-running command completes. (And yes, I've had tapes dropped by an SL8500 robot. Particularly annoying because the robot arm on the lowest rail runs close enough to the floor that an LTO tape cartridge won't fit under it.) https://www.youtube.com/watch?v=IDgXa0ioVTs
4. How to keep the device's state consistent when we kill a process when it is invoking a system call? Sorry, I did not get your point.
That's *totally* device dependent. The things a driver needs to do to ensure consistency for a 40Gbit ethernet adapter are *totally* different from that USB memory stick. But in general, a driver will employ locking the current request and not return early, so at any given time, the next request to be made will not proceed until the device is in a known consistent state (whether that state is suitable for the next request is a totally different question of course - consider a tape drive where the state is 'tape unloaded' and the next reqest is a read from the tape....)
On Wed, Mar 14, 2018 at 12:32:21PM -0400, valdis.kletnieks@vt.edu wrote:
4. How to keep the device's state consistent when we kill a process when it is invoking a system call? Sorry, I did not get your point.
That's *totally* device dependent. The things a driver needs to do to ensure consistency for a 40Gbit ethernet adapter are *totally* different from that USB memory stick.
Not to be "chatty", but that "USB memory stick" is one of the most complex USB devices out there from a protocol standpoint. Only USB video cameras get close to just how complex those things are. Remember, this is really a full SCSI controller talking SCSI commands over USB in a serial manner, which implements a block device, which you then layer a filesystem on top of. It's such a complex beast, in the 2.4 days we had someone write a "simple" driver just to try to cut out the whole SCSI layer as it was not handling device removal/insertion well, if at all, in a dynamic fashion and we wanted to try to avoid dealing with all of the complexities SCSI provides. In the end, it never really worked and we had to use the full SCSI stack instead just to get all devices to work properly, and that driver was deleted from the tree. With USB 3, those USB devices are even more complex, offering up multiple "streams" in which you can pump multiple commands down at the same time, to try to increase the throughput of the device. If you sit on the linux-usb mailing list for any amount of time, you will see the smattering of odd bug reports we get for these devices due to the crazy interactions between SCSI, storage devices, and the xhci (USB 3) driver. So you need a better example of a "simple" device. What about a serial port? Oh wait, that's over 10k lines, kernel programming is hard, let's go shopping... Sorry for the rant/wall-of-text, it's just something I have strong feelings about :) thanks, greg k-h
On Wed, 14 Mar 2018 17:46:16 +0100, Greg KH said:
On Wed, Mar 14, 2018 at 12:32:21PM -0400, valdis.kletnieks@vt.edu wrote:
That's *totally* device dependent. The things a driver needs to do to ensure consistency for a 40Gbit ethernet adapter are *totally* different from that USB memory stick.
Not to be "chatty", but that "USB memory stick" is one of the most complex USB devices out there from a protocol standpoint.
Meanwhile, the 40Gbit interfaces is (comparatively) simple. And I wasn't giving examples of simple/complex, it was "two totally different sets of challenges" ;) But thanks for adding all the info on things that actual device drivers have to deal with...
participants (5)
-
Douglas Su -
Greg KH -
Larry Chen -
Miles Fidelman -
valdis.kletnieks@vt.edu