Proper documentation for the design and usage of sequence counters and sequential locks does not exist. Complete the seqlock.h documentation as follows: - Divide all documentation on a seqcount_t vs. seqlock_t basis. The description for both mechanisms was intermingled, which is incorrect since the usage constrains for each type are vastly different. - Add an introductory paragraph describing the internal design of, and rationale for, sequence counters. - Document seqcount_t writer non-preemptibility requirement, which was not previously documented anywhere, and provide a clear rationale. - Provide template code for seqcount_t and seqlock_t initialization and reader/writer critical sections. - Recommend using seqlock_t by default. It implicitly handles the serialization and non-preemptibility requirements of writers. At seqlock.h: - Remove references to brlocks as they've long been removed from the kernel. - Remove references to gcc-3.x since the kernel's minimum supported gcc version is 4.9.
Showing the changes to include/linux (1 of 3 files). Show all
Unified · Split
| @@ -1,36 +1,15 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | 2 | #ifndef __LINUX_SEQLOCK_H |
| 3 | 3 | #define __LINUX_SEQLOCK_H |
| 4 | + | |
| 4 | 5 | /* |
| 5 | − * Reader/writer consistent mechanism without starving writers. This type of | |
| 6 | − * lock for data where the reader wants a consistent set of information | |
| 7 | − * and is willing to retry if the information changes. There are two types | |
| 8 | − * of readers: | |
| 9 | − * 1. Sequence readers which never block a writer but they may have to retry | |
| 10 | − * if a writer is in progress by detecting change in sequence number. | |
| 11 | − * Writers do not wait for a sequence reader. | |
| 12 | − * 2. Locking readers which will wait if a writer or another locking reader | |
| 13 | − * is in progress. A locking reader in progress will also block a writer | |
| 14 | − * from going forward. Unlike the regular rwlock, the read lock here is | |
| 15 | − * exclusive so that only one locking reader can get it. | |
| 16 | − * | |
| 17 | − * This is not as cache friendly as brlock. Also, this may not work well | |
| 18 | − * for data that contains pointers, because any writer could | |
| 19 | − * invalidate a pointer that a reader was following. | |
| 20 | − * | |
| 21 | − * Expected non-blocking reader usage: | |
| 22 | − * do { | |
| 23 | − * seq = read_seqbegin(&foo); | |
| 24 | − * ... | |
| 25 | − * } while (read_seqretry(&foo, seq)); | |
| 26 | − * | |
| 27 | − * | |
| 28 | − * On non-SMP the spin locks disappear but the writer still needs | |
| 29 | − * to increment the sequence variables because an interrupt routine could | |
| 30 | − * change the state of the data. | |
| 31 | − * | |
| 32 | − * Based on x86_64 vsyscall gettimeofday | |
| 33 | − * by Keith Owens and Andrea Arcangeli | |
| 6 | + * seqcount_t / seqlock_t - a reader-writer consistency mechanism with | |
| 7 | + * lockless readers (read-only retry loops), and no writer starvation. | |
| 8 | + * | |
| 9 | + * See Documentation/locking/seqlock.rst | |
| 10 | + * | |
| 11 | + * Copyrights: | |
| 12 | + * - Based on x86_64 vsyscall gettimeofday: Keith Owens, Andrea Arcangeli | |
| 34 | 13 | */ |
| 35 | 14 | |
| 36 | 15 | #include <linux/spinlock.h> |
| @@ -41,8 +20,8 @@ · 4 unmodified lines | ||
| 41 | 20 | #include <asm/processor.h> |
| 42 | 21 | |
| 43 | 22 | /* |
| 44 | − * The seqlock interface does not prescribe a precise sequence of read | |
| 45 | − * begin/retry/end. For readers, typically there is a call to | |
| 23 | + * The seqlock seqcount_t interface does not prescribe a precise sequence of | |
| 24 | + * read begin/retry/end. For readers, typically there is a call to | |
| 46 | 25 | * read_seqcount_begin() and read_seqcount_retry(), however, there are more |
| 47 | 26 | * esoteric cases which do not follow this pattern. |
| 48 | 27 | * |
| @@ -50,16 +29,30 @@ · 1 unmodified line | ||
| 50 | 29 | * via seqcount_t under KCSAN: upon beginning a seq-reader critical section, |
| 51 | 30 | * pessimistically mark the next KCSAN_SEQLOCK_REGION_MAX memory accesses as |
| 52 | 31 | * atomics; if there is a matching read_seqcount_retry() call, no following |
| 53 | − * memory operations are considered atomic. Usage of seqlocks via seqlock_t | |
| 54 | − * interface is not affected. | |
| 32 | + * memory operations are considered atomic. Usage of the seqlock_t interface | |
| 33 | + * is not affected. | |
| 55 | 34 | */ |
| 56 | 35 | #define KCSAN_SEQLOCK_REGION_MAX 1000 |
| 57 | 36 | |
| 58 | 37 | /* |
| 59 | − * Version using sequence counter only. | |
| 60 | − * This can be used when code has its own mutex protecting the | |
| 61 | − * updating starting before the write_seqcountbeqin() and ending | |
| 62 | − * after the write_seqcount_end(). | |
| 38 | + * Sequence counters (seqcount_t) | |
| 39 | + * | |
| 40 | + * This is the raw counting mechanism, without any writer protection. | |
| 41 | + * | |
| 42 | + * Write side critical sections must be serialized and non-preemptible. | |
| 43 | + * | |
| 44 | + * If readers can be invoked from hardirq or softirq contexts, | |
| 45 | + * interrupts or bottom halves must also be respectively disabled before | |
| 46 | + * entering the write section. | |
| 47 | + * | |
| 48 | + * This mechanism can't be used if the protected data contains pointers, | |
| 49 | + * as the writer can invalidate a pointer that a reader is following. | |
| 50 | + * | |
| 51 | + * If it's desired to automatically handle the sequence counter writer | |
| 52 | + * serialization and non-preemptibility requirements, use a sequential | |
| 53 | + * lock (seqlock_t) instead. | |
| 54 | + * | |
| 55 | + * See Documentation/locking/seqlock.rst | |
| 63 | 56 | */ |
| 64 | 57 | typedef struct seqcount { |
| 65 | 58 | unsigned sequence; |
| @@ -398,10 +391,6 @@ static inline void raw_write_seqcount_latch(seqcount_t *s) · 332 unmodified lines | ||
| 398 | 391 | smp_wmb(); /* increment "sequence" before following stores */ |
| 399 | 392 | } |
| 400 | 393 | |
| 401 | −/* | |
| 402 | − * Sequence counter only version assumes that callers are using their | |
| 403 | − * own mutexing. | |
| 404 | − */ | |
| 405 | 394 | static inline void write_seqcount_begin_nested(seqcount_t *s, int subclass) |
| 406 | 395 | { |
| 407 | 396 | raw_write_seqcount_begin(s); |
| @@ -434,15 +423,21 @@ static inline void write_seqcount_invalidate(seqcount_t *s) · 26 unmodified lines | ||
| 434 | 423 | kcsan_nestable_atomic_end(); |
| 435 | 424 | } |
| 436 | 425 | |
| 426 | +/* | |
| 427 | + * Sequential locks (seqlock_t) | |
| 428 | + * | |
| 429 | + * Sequence counters with an embedded spinlock for writer serialization | |
| 430 | + * and non-preemptibility. | |
| 431 | + * | |
| 432 | + * For more info, see: | |
| 433 | + * - Comments on top of seqcount_t | |
| 434 | + * - Documentation/locking/seqlock.rst | |
| 435 | + */ | |
| 437 | 436 | typedef struct { |
| 438 | 437 | struct seqcount seqcount; |
| 439 | 438 | spinlock_t lock; |
| 440 | 439 | } seqlock_t; |
| 441 | 440 | |
| 442 | −/* | |
| 443 | − * These macros triggered gcc-3.x compile-time problems. We think these are | |
| 444 | − * OK now. Be cautious. | |
| 445 | − */ | |
| 446 | 441 | #define __SEQLOCK_UNLOCKED(lockname) \ |
| 447 | 442 | { \ |
| 448 | 443 | .seqcount = SEQCNT_ZERO(lockname), \ |