NO! doing a reasonable thing should _never_ cause an oops.
> Or do we have to avoid every race condition we know
> of, regardless what cost it has?
It really isn't that expensive. Only lock for writes.
So the algorithm goes like so:
read:
[SMP]atomic_increment reader counter
walk list, looking for format.
if found
use it.
[SMP]atomic decrement reader counter
[SMP]if reader counter == 0 wake up wait queue
add:
down write semaphore.
walk list to appropriate spot.
insert element. (elem->next = insert_point->next;
insert_point->next = elem)
up write semaphore.
delete:
down write semaphore.
find element.
link around element (prev->next = elem->next)
_don't_ change next pointer on element until it is deleted
the safety here is that if someone is looking at
the element you just deleted, they will either
use the element, or will go down the next pointer.
If you change the next pointer, sometimes a format
will fail to work.
if reader_counter == 0
delete element;
else
wait in wait queue
delete element;
The counter is actually safer if it is on all systems, and only does the
atomic increment if it is SMP. That way it doesn't even matter if the
code sleeps while accessing the queue. Assuming of course that this
code is never accessed from interrupts
Note that the insertion/deletion operations are atomic as long as the
write to the next pointer is atomic. (I presume that this is safe
in the linux kernel, if not you need a kernel lock to change it)
Does someone somewhere guarantee that
ptr = val;
is atomic? If not you need to use xchg to write the pointer.
You could probably avoid even the write lock, but it also probably
isn't worth the bother.
-gordo