Re: Fix unlock_buffer() to work the same way as bit_unlock()

From: Zoltan Menyhart
Date: Wed Mar 29 2006 - 07:14:52 EST


Part 2.
There are a couple of different ways of using / implementing bit-op-s.
I try to summarize them:


1. "Stand alone" bit operations:

By "stand alone" I mean that a modification to a bit field member is
independent of any other operation before / after the bit operation
in question. There is no ordering with respect to the other operations.

They do not provide any SMP synch. semantics, there is no need to
implement them as some atomic operations.


2. Atomic bit operations:

As Linux turned to SMP safe, a couple of bit operations have been
re-implemented by use of some atomic operations.
An early implementation on PCs determined the basic semantics of
these operations, including their fencing behavior.

atomic_ops.txt:

" obj->dead = 1;
if (test_and_set_bit(0, &obj->flags))
/* ... */;
obj->killed = 1;

The implementation of test_and_set_bit() must guarentee that
"obj->dead = 1;" is visible to cpus before the atomic memory operation
done by test_and_set_bit() becomes visible. Likewise, the atomic
memory operation done by test_and_set_bit() must become visible before
"obj->killed = 1;" is visible."

I am not convenienced that this is a good sync. strategy.
Unfortunately, the acquisition / release semantics were not defined
in Linux via some architecture independent and explicit way.
People simply abused the fact that the bidirectional fencing is
implicitly provided by some architectures for free.

Theoretically, the code fragments like above have to be cleared up
to use explicit ordering primitives. The description in atomic_ops.txt
should state that this is not the way to do... (see the Fencing bit
operations below).
There can be ~20 "test_and_set_bit()" here or there.


The atomic bit operation with requirements to order the preceding /
following operations are mainly used for locking(-like) purposes:


3. Fencing bit operations:

Should someone still insist on using the atomic bit operations as today,
s/he should change to use e.g.:

obj->dead = 1;
if (test_and_set_bit_N_fence(0, &obj->flags))
/* ... */;
obj->killed = 1;


4. Bit-lock operations:

I summarized the ordering requirements here:
http://marc.theaimsgroup.com/?l=linux-ia64&m=114362989421046&w=2

In order to let the architectures implement these bit-lock
operations efficiently, the usage has to indicate the _minimal_
required ordering semantics, e.g.:

test_and_set_bit_N_acquire()
or ordered_test_and_set_bit(acquire, ...)
release_N_clear_bit()
etc.

The style like:

do_some_ordering_before()
bit_op()
do_some_ordering_after()

is quite correct, however, the compiler is not sufficiently
intelligent to let the architecture dependent part to merge e.g. into
a single machine instruction (if it exists).


Regards,

Zoltan

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/