From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Adam J. Richter" Date: Thu, 08 Feb 2001 16:45:56 +0000 Subject: Algorithm for hotplugging without an event queue (was: Adding PCMCIA support to the kernel tree -- d Message-Id: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: linux-hotplug@vger.kernel.org >From: Oliver Neukum >> >You need to prevent any changes to the bus while you do the scanning. >> >Running hotplug support is not enough. You need further kernel support >> >to do racefree scanning. >> >> You cannot lock physical reality. >To a certain extent you can. You cannot hide removal, but you can hide >addition. That's enough. You'll have to show me an example of where not hiding addition casses trouble. >> In any case, the doubt that I originally expressed was about >> the need to queue hotplug events _before_ the hot plug system was >> initialized. In your example, the events occur after the hot plug >> system is initialized. >No, it occurs while you are initialising the hotplug system. In the timeline that you listed, the hot plug events occurred *after* the hot plug system was initialized (but while the existing hardware was being scanned). The doubt that I originally expressed was about the need to queue hotplug events *before* the hot plug system was initialized. >You cannot scan a bus without locking it. You have not shown that or even defined it well at this point. >While you lock the bus what do you do with the events ? While you *scan* the bus, the kernel would continue to generate asynchronous calls to /sbin/hotplug, which would block on the lock held by the currently running /sbin/hotplug in the algorithm that I described. When the currently running /sbin/hotplug finishes, the second /sbin/hotplug that is waiting will catch any changes that happend while the previous one was running. >You could indeed do without queueing initial events, if you did >scan the bus under lock. >Provided that you give stable names (David's definition) to the agents >in order to be able to loose information about ordering of events. For the algorithm that I posted, a naming scheme like the one used by /proc/bus/usb is sufficient and there is no need to do anything more to preserve the order of events. >> However, now that you mention it, let's talk about handling >> events that occur after initialization. I think we can avoid the >> need to queue those events too. >> >> First of all, we should recognize that for most hardware, >> the events caused by unplugging are handled directly by the kernel, >> not by the user level hot plugging code. For example, with a DHCP >> configured ethernet, removal of the ethernet interface card should >> cause the socket that dhcp has open on the ethernet interface to >> return an IO exception condition, and dhclient should get -EIO >> and abort when it tries to execute the ioctl to check the status. >I am afraid I have to disagree. Most hardware is associated with device nodes >in /dev which retain their permission bits. You have to reset them on removal. I am not talking about returing -EPERM on open (which should fail if a device is no longer present anyhow), I am talking about returning -EIO or something similar on already open file descriptors. >> Secondly, there is a way to get this processing right >> where necessary without the need to queue events (which can overflow, >> and involve maintiaining arbitrary large dynamic data strucutres). >> All you need is a "new" flag that the kernel would set when on a device >> when it is inserted. The hot plug code would be called by the kernel >> with an argument indicating what device to check, without necessarily >> even indicating whether it was a hot plug or a remove event. >> >> userland_hotplug_handler(dev) >> { >> // was_plugged_in[dev] is persistent data, perhaps >> // stored in a file. >> >> acquire_lock(dev); // Flock some file; could just have >> // one global lock. Whatever. >> if (was_plugged_in[dev] >> && (new[dev] || !is_plugged_in[dev])) { > ^ race condition, the condition you check for might change >> was_plugged_in[dev] = 0; >> handle_remove_event(dev); >> } >and you may forget a removal event this way, which is bad >> if (new[dev]) { >> new[dev] = 0; >> if (is_plugged_in[dev]) { >> was_plugged_in[dev] = 1; >> handle_insert_event(device); >> } >> } >> release_lock(dev); >> } (Note: I have deleted the line near the bottom that read "old_status[dev] = new_status;". It was left over from a previous edit and did not belong in this listing.) The "race condition" that you described is not a problem because the kernel only *sets* new[dev], and only does so when it detects an insertion, and then spawns a new /sbin/hotplug, which will run after the currently running /sbin/hotplug releases its lock and will process the new device if the previous /sbin/hotplug instance did not already do so. /sbin/hotplug only *clears* new[dev]. If you do not understand, try making a timeline of an example. Adam J. Richter __ ______________ 4880 Stevens Creek Blvd, Suite 104 adam@yggdrasil.com \ / San Jose, California 95129-1034 +1 408 261-6630 | g g d r a s i l United States of America fax +1 408 261-6631 "Free Software For The Rest Of Us." _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net http://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel