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 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | #ifndef __LINUX_SEQLOCK_H | 2 | #ifndef __LINUX_SEQLOCK_H |
| 3 | #define __LINUX_SEQLOCK_H | 3 | #define __LINUX_SEQLOCK_H |
| 4 | |||
| 4 | /* | 5 | /* |
| 5 | * Reader/writer consistent mechanism without starving writers. This type of | 6 | * seqcount_t / seqlock_t - a reader-writer consistency mechanism with |
| 6 | * lock for data where the reader wants a consistent set of information | 7 | * lockless readers (read-only retry loops), and no writer starvation. |
| 7 | * and is willing to retry if the information changes. There are two types | 8 | * |
| 8 | * of readers: | 9 | * See Documentation/locking/seqlock.rst |
| 9 | * 1. Sequence readers which never block a writer but they may have to retry | 10 | * |
| 10 | * if a writer is in progress by detecting change in sequence number. | 11 | * Copyrights: |
| 11 | * Writers do not wait for a sequence reader. | 12 | * - Based on x86_64 vsyscall gettimeofday: Keith Owens, Andrea Arcangeli |
| 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 | ||
| 34 | */ | 13 | */ |
| 35 | 14 | ||
| 36 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
| @@ -41,8 +20,8 @@ · 4 unmodified lines | |||
| 41 | #include <asm/processor.h> | 20 | #include <asm/processor.h> |
| 42 | 21 | ||
| 43 | /* | 22 | /* |
| 44 | * The seqlock interface does not prescribe a precise sequence of read | 23 | * The seqlock seqcount_t interface does not prescribe a precise sequence of |
| 45 | * begin/retry/end. For readers, typically there is a call to | 24 | * read begin/retry/end. For readers, typically there is a call to |
| 46 | * read_seqcount_begin() and read_seqcount_retry(), however, there are more | 25 | * read_seqcount_begin() and read_seqcount_retry(), however, there are more |
| 47 | * esoteric cases which do not follow this pattern. | 26 | * esoteric cases which do not follow this pattern. |
| 48 | * | 27 | * |
| @@ -50,16 +29,30 @@ · 1 unmodified line | |||
| 50 | * via seqcount_t under KCSAN: upon beginning a seq-reader critical section, | 29 | * via seqcount_t under KCSAN: upon beginning a seq-reader critical section, |
| 51 | * pessimistically mark the next KCSAN_SEQLOCK_REGION_MAX memory accesses as | 30 | * pessimistically mark the next KCSAN_SEQLOCK_REGION_MAX memory accesses as |
| 52 | * atomics; if there is a matching read_seqcount_retry() call, no following | 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 | 32 | * memory operations are considered atomic. Usage of the seqlock_t interface |
| 54 | * interface is not affected. | 33 | * is not affected. |
| 55 | */ | 34 | */ |
| 56 | #define KCSAN_SEQLOCK_REGION_MAX 1000 | 35 | #define KCSAN_SEQLOCK_REGION_MAX 1000 |
| 57 | 36 | ||
| 58 | /* | 37 | /* |
| 59 | * Version using sequence counter only. | 38 | * Sequence counters (seqcount_t) |
| 60 | * This can be used when code has its own mutex protecting the | 39 | * |
| 61 | * updating starting before the write_seqcountbeqin() and ending | 40 | * This is the raw counting mechanism, without any writer protection. |
| 62 | * after the write_seqcount_end(). | 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 | typedef struct seqcount { | 57 | typedef struct seqcount { |
| 65 | unsigned sequence; | 58 | unsigned sequence; |
| @@ -398,10 +391,6 @@ static inline void raw_write_seqcount_latch(seqcount_t *s) · 332 unmodified lines | |||
| 398 | smp_wmb(); /* increment "sequence" before following stores */ | 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 | static inline void write_seqcount_begin_nested(seqcount_t *s, int subclass) | 394 | static inline void write_seqcount_begin_nested(seqcount_t *s, int subclass) |
| 406 | { | 395 | { |
| 407 | raw_write_seqcount_begin(s); | 396 | raw_write_seqcount_begin(s); |
| @@ -434,15 +423,21 @@ static inline void write_seqcount_invalidate(seqcount_t *s) · 26 unmodified lines | |||
| 434 | kcsan_nestable_atomic_end(); | 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 | typedef struct { | 436 | typedef struct { |
| 438 | struct seqcount seqcount; | 437 | struct seqcount seqcount; |
| 439 | spinlock_t lock; | 438 | spinlock_t lock; |
| 440 | } seqlock_t; | 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 | #define __SEQLOCK_UNLOCKED(lockname) \ | 441 | #define __SEQLOCK_UNLOCKED(lockname) \ |
| 447 | { \ | 442 | { \ |
| 448 | .seqcount = SEQCNT_ZERO(lockname), \ | 443 | .seqcount = SEQCNT_ZERO(lockname), \ |