Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 6: Device Drivers


❑ ELEVATOR_BACK_MERGEandELEVATOR_FRONT_MERGEcause the new request to be coalesced with
the request at the found position in the request list.ELEVATOR_BACK_MERGEmerges the new data
after the data of the existing request,ELEVATOR_FRONT_MERGEbefore the data.
The existing element is modified to produce a merged request covering the desired areas.
❑ ELEVATOR_NO_MERGEfinds out that the request cannot be coalesced with existing elements on the
request queue and must therefore be added on its own.

These are the only actions that an elevator can take;it cannot influence the request queue in any other
way. This clearly demonstrates the difference between I/O and CPU schedulers. Although both are faced
with a very similar problem, the solutions they provide diverge greatly.

Once the elevator requirements have been satisfied (as far as this is possible), the kernel must generate a
new request.

get_request_waitallocates a newrequestinstance that is then filled with data from thebiousing
init_request_from_bio. If the queue is still empty (this is checked byelv_queue_empty), it is plugged
withblk_plug_device. This is how the kernel prevents the queue from being processed after each new
request; instead, it collects requests for read and/or write operations and executes them in a single action.
I discuss the mechanism used shortly.

After a few kernel statistics have been updated with__elv_add_request_pos,add_requestadds the
request to the request list (this leads to the I/O scheduler-specificelevator_add_req_fnfunction) at the
position selected by the above I/O scheduler call.

If a request is to be processed synchronously (BIO_RW_SYNCmust then be set in thebioinstance of the
request), the kernel must unplug the queue using__generic_unplug_deviceto ensure that the request
can, in fact, be handled synchronously. Requests of this kind are seldom used because they negate the
effect of I/O scheduling.

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 usesqueue pluggingto 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. TheQUEUE_FLAG_PLUGGED
flag in thequeue_flagselement ofrequest_queueis set when a queue is plugged; the kernel provides
theblk_queue_pluggedhelper function to check this flag.

In the description of__make_request, I already noted that the kernel plugs a queue with
blk_plug_devicebut 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 inblk_plug_device.
Free download pdf