Hi-- Comments are inline.
On 2/3/21 10:11 AM, Shuah Khan wrote:
Sequence Number api provides interfaces for unsigned atomic up counters.
There are a number of atomic_t usages in the kernel where atomic_t api is used for counting sequence numbers and other statistical counters. Several of these usages, convert atomic_read() and atomic_inc_return() return values to unsigned. Introducing sequence number ops supports these use-cases with a standard core-api.
Sequence Number ops provide interfaces to initialize, increment and get the sequence number. These ops also check for overflow and log message to indicate when overflow occurs.
Signed-off-by: Shuah Khan skhan@linuxfoundation.org
Documentation/core-api/index.rst | 1 + Documentation/core-api/seqnum_ops.rst | 53 ++++++++++ MAINTAINERS | 7 ++ include/linux/seqnum_ops.h | 129 +++++++++++++++++++++++++ lib/Kconfig | 9 ++ lib/Makefile | 1 + lib/test_seqnum_ops.c | 133 ++++++++++++++++++++++++++ 7 files changed, 333 insertions(+) create mode 100644 Documentation/core-api/seqnum_ops.rst create mode 100644 include/linux/seqnum_ops.h create mode 100644 lib/test_seqnum_ops.c
diff --git a/Documentation/core-api/seqnum_ops.rst b/Documentation/core-api/seqnum_ops.rst new file mode 100644 index 000000000000..ed4eba394799 --- /dev/null +++ b/Documentation/core-api/seqnum_ops.rst @@ -0,0 +1,53 @@ +.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+.. _seqnum_ops:
+========================== +Sequence Number Operations +==========================
+:Author: Shuah Khan +:Copyright: |copy| 2021, The Linux Foundation +:Copyright: |copy| 2021, Shuah Khan skhan@linuxfoundation.org
+Sequence Number api provides interfaces for unsigned up counters.
API
+Sequence Number Ops +===================
+seqnum32 and seqnum64 types support implementing unsigned up counters. ::
struct seqnum32 { u32 seqnum; };
struct seqnum64 { u64 seqnum; };
+Initializers +------------
+Interfaces for initializing sequence numbers. ::
#define SEQNUM_INIT(i) { .seqnum = i }
seqnum32_init(seqnum, val)
seqnum64_init(seqnum, val)
+Increment interface +-------------------
+Increments sequence number and returns the new value. Checks for overflow +conditions and logs message when overflow occurs. This check is intended +to help catch cases where overflow could lead to problems. ::
seqnum32_inc(seqnum): Calls atomic_inc_return(seqnum).
seqnum64_inc(seqnum): Calls atomic64_inc_return(seqnum).
+Return/get value interface +--------------------------
+Returns sequence number value. ::
seqnum32_get() - return seqnum value.
seqnum64_get() - return seqnum value.
+.. warning::
seqnum32 wraps around to INT_MIN when it overflows.
diff --git a/MAINTAINERS b/MAINTAINERS index cc1e6a5ee6e6..f9fe1438a8cd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16235,6 +16235,13 @@ S: Maintained F: Documentation/fb/sm712fb.rst F: drivers/video/fbdev/sm712* +SEQNUM OPS +M: Shuah Khan skhan@linuxfoundation.org +L: linux-kernel@vger.kernel.org +S: Maintained +F: include/linux/seqnum_ops.h +F: lib/test_seqnum_ops.c
SIMPLE FIRMWARE INTERFACE (SFI) S: Obsolete W: http://simplefirmware.org/ diff --git a/include/linux/seqnum_ops.h b/include/linux/seqnum_ops.h new file mode 100644 index 000000000000..e8d8481445d3 --- /dev/null +++ b/include/linux/seqnum_ops.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- seqnum_ops.h - Interfaces for unsigned atomic sequential up counters.
- Copyright (c) 2021 Shuah Khan skhan@linuxfoundation.org
- Copyright (c) 2021 The Linux Foundation
- Sequence Number functions provide support for unsgined atomic up
unsigned
- counters.
- The interface provides:
- seqnumu32 & seqnumu64 functions:
- initialization
- increment and return
- seqnumu32 and seqnumu64 functions leverage/use atomic*_t ops to
- implement support for unsigned atomic up counters.
- Reference and API guide:
- Documentation/core-api/seqnum_ops.rst for more information.
- */
+#ifndef __LINUX_SEQNUM_OPS_H +#define __LINUX_SEQNUM_OPS_H
+#include <linux/atomic.h>
+/**
- struct seqnum32 - Sequence number atomic counter
- @seqnum: atomic_t
- **/
+struct seqnum32 {
- u32 seqnum;
+};
+#define SEQNUM_INIT(i) { .seqnum = i }
+/*
- seqnum32_init() - initialize seqnum value
- @seq: struct seqnum32 pointer
- */
+static inline void seqnum32_init(struct seqnum32 *seq, u32 val) +{
- seq->seqnum = val;
+}
+/*
- seqnum32_inc() - increment seqnum value and return the new value
- @seq: struct seqnum32 pointer
- Return u32
It would be good to convert that to kernel-doc notation.
- */
+static inline u32 seqnum32_inc(struct seqnum32 *seq) +{
- atomic_t val = ATOMIC_INIT(seq->seqnum);
- seq->seqnum = (u32) atomic_inc_return(&val);
- if (seq->seqnum >= UINT_MAX)
pr_info("Sequence Number overflow %u detected\n",
seq->seqnum);
- return seq->seqnum;
+}
+/*
- seqnum32_get() - get seqnum value
- @seq: struct seqnum32 pointer
- Return u32
- */
+static inline u32 seqnum32_get(struct seqnum32 *seq) +{
- return seq->seqnum;
+}
+/*
- struct seqnum64 - Sequential/Statistical atomic counter
- @seq: atomic64_t
- */
+struct seqnum64 {
- u64 seqnum;
+};
+/* Add to a global include/vdso/limits.h and fix all other UINT64_MAX
- duplicate defines?
- */
+#define SEQ_UINT64_MAX ((u64)(~((u64) 0))) /* 0xFFFFFFFFFFFFFFFF */
+/*
- seqnum64_init() - initialize seqnum value
- @seq: struct seqnum64 pointer
- */
and kernel-doc there also.
+static inline void seqnum64_init(struct seqnum64 *seq, u64 val) +{
- seq->seqnum = val;
+}
+/*
- seqnum64_inc() - increment seqnum value and return the new value
- @seq: struct seqnum64 pointer
- Return u64
- */
+static inline u64 seqnum64_inc(struct seqnum64 *seq) +{
- atomic64_t val = ATOMIC_INIT(seq->seqnum);
- seq->seqnum = (u64) atomic64_inc_return(&val);
- if (seq->seqnum >= SEQ_UINT64_MAX)
pr_info("Sequence Number overflow %llu detected\n",
seq->seqnum);
- return seq->seqnum;
+}
+/*
- seqnum64_get() - get seqnum value
- @seq: struct seqnum64 pointer
- Return u64
- */
+static inline u64 seqnum64_get(struct seqnum64 *seq) +{
- return (u64) seq->seqnum;
+}
+#endif /* __LINUX_SEQNUM_OPS_H */
diff --git a/lib/test_seqnum_ops.c b/lib/test_seqnum_ops.c new file mode 100644 index 000000000000..173278314f26 --- /dev/null +++ b/lib/test_seqnum_ops.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/*
- test_seqnum_ops.c - Kernel module for testing Seqnum API
- Copyright (c) 2021 Shuah Khan skhan@linuxfoundation.org
- Copyright (c) 2021 The Linux Foundation
- */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h> +#include <linux/seqnum_ops.h>
...
+static void test_seqnum64(void) +{
- u64 start_val = 0;
- struct seqnum64 seq = SEQNUM_INIT(start_val);
- u64 end_val;
- end_val = seqnum64_inc(&seq);
- test_seqnum64_result("Test increment",
start_val, end_val, start_val+1);
- /* Initialize sequence number to 0 */
- seqnum64_init(&seq, start_val);
- end_val = seqnum64_inc(&seq);
- /* if seqnum642_init() works correctly end_val should be 1 */
seqnum64_init() AFAICT.
- test_seqnum64_result("Test init", start_val, end_val, 1);
- /* seqnum64_get() test for seqnum value == 1 */
- start_val = end_val = seqnum64_get(&seq);
- test_seqnum64_result("Test get", start_val, end_val, 1);
+}