Queue Plugging

In terms of performance, it is, of course, desirable to re-sort individual requests and merge them into larger units to optimize data transfer. Obviously, this only works if the queue contains several requests that can be merged. The kernel must therefore first collect a few requests in the queue before it can process them in a single operation; this automatically generates opportunities for merging.

The kernel uses queue plugging to intentionally prevent requests from being processed. A request queue may be in one of two states — either free or plugged. If it is free, the requests waiting in the queue are processed. Otherwise, new requests are added to the list but not processed. The QUEUE_FLAG_PLUGGED flag in the queue_flags element of request_queue is set when a queue is plugged; the kernel provides the blk_queue_plugged helper function to check this flag.

In the description of_make_request, I already noted that the kernel plugs a queue with blk_plug_device but does not explicitly unplug the queue if no synchronous request is sent. How is it possible to ensure that queues will be processed again at some time in the future? The solution is to be found in blk_plug_device.

drivers/block/ll_rw_blk.c void blk_plug_device(request_queue_t *q)

if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {

mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);

This section of code ensures that the unplug timer of the queue is enabled after q->unplug_delay jiffies [typically (3 * HZ) / 1000, or 3 milliseconds]; in turn, this invokes blk_unplug_timeout to unplug the queue.

A second mechanism is also available to unplug the queue. If the number of current read and write requests (stored in the two entries of the count array of the request list) corresponds to the threshold specified by unplug_thresh,_generic_unplug_device is invoked in elv_insert14 to trigger unplugging so that waiting requests are processed.

_generic_unplug_device is not very complicated.

block/ll_rw_blk.c void _generic_unplug_device(request_queue_t *q)

request_fn is invoked to process the waiting requests after blk_remove_plug has removed the plug of the queue and the timer used for automatic unplugging (unplug_timer) is set. That's all that need be done!

The kernel is also able to perform unplugging manually when important I/O operations are pending. This ensures that important read operations, for example, are carried out immediately if data are urgently required. This situation arises when synchronous requests (mentioned briefly above) need to be satisfied.

Continue reading here: Executing Requests

Was this article helpful?

0 0