5.1. Pitfalls in scull
Let us take a quick look at a
fragment
of the
scull memory management code. Deep down inside
the write logic, scull must
decide whether the memory it requires has been allocated yet or not.
One piece of the code that handles this task is:
if (!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if (!dptr->data[s_pos])
goto out;
}
Suppose for a moment that two processes (we'll call
them "A" and
"B") are independently attempting
to write to the same offset within the same
scull device. Each process reaches the
if test in the first line of the fragment above at
the same time. If the pointer in question is NULL,
each process will decide to allocate memory, and each will assign the
resulting pointer to dptr->data[s_pos]. Since
both processes are assigning to the same location, clearly only one
of the assignments will prevail.
What will happen, of course, is that the process that completes the
assignment second will "win." If
process A assigns first, its assignment will be overwritten by
process B. At that point, scull will forget
entirely about the memory that A allocated; it only has a pointer to
B's memory. The memory allocated by A, thus, will be
dropped and never returned to the system.
This sequence of events is a demonstration of a race
condition
. Race conditions are a result of
uncontrolled access to shared data. When the wrong access pattern
happens, something unexpected results. For the race condition
discussed here, the result is a memory leak. That is bad enough, but
race conditions can often lead to system crashes, corrupted data, or
security problems as well. Programmers can be tempted to disregard
race conditions as extremely low probability events. But, in the
computing world, one-in-a-million events can happen every few
seconds, and the consequences can be grave.
We will eliminate race conditions from scull
shortly, but first we need to take a more general view of
concurrency.
|