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. This check is intended to help catch cases where overflow could lead to problems.
Since v2: - Uses atomic_inc_return() for incrementing the sequence number. - No longer uses atomic_read()
Shuah Khan (7): seqnum_ops: Introduce Sequence Number Ops selftests: lib:test_seqnum_ops: add new test for seqnum_ops drivers/acpi: convert seqno to use seqnum_ops drivers/acpi/apei: convert seqno to seqnum_ops drivers/staging/rtl8723bs: convert event_seq to use seqnum_ops drivers/staging/rtl8188eu: convert event_seq to use seqnum_ops kobject: convert uevent_seqnum to seqnum_ops
Documentation/core-api/index.rst | 1 + Documentation/core-api/seqnum_ops.rst | 62 ++++++++ MAINTAINERS | 8 ++ drivers/acpi/acpi_extlog.c | 8 +- drivers/acpi/apei/ghes.c | 8 +- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 23 ++- .../staging/rtl8188eu/include/rtw_mlme_ext.h | 3 +- drivers/staging/rtl8723bs/core/rtw_cmd.c | 3 +- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 33 +++-- drivers/staging/rtl8723bs/include/rtw_cmd.h | 3 +- .../staging/rtl8723bs/include/rtw_mlme_ext.h | 3 +- include/linux/kobject.h | 3 +- include/linux/seqnum_ops.h | 131 +++++++++++++++++ kernel/ksysfs.c | 3 +- lib/Kconfig | 9 ++ lib/Makefile | 1 + lib/kobject_uevent.c | 9 +- lib/test_seqnum_ops.c | 133 ++++++++++++++++++ tools/testing/selftests/lib/Makefile | 1 + tools/testing/selftests/lib/config | 1 + .../testing/selftests/lib/test_seqnum_ops.sh | 10 ++ 21 files changed, 423 insertions(+), 33 deletions(-) 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 create mode 100755 tools/testing/selftests/lib/test_seqnum_ops.sh
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/index.rst b/Documentation/core-api/index.rst index f1c9d20bd42d..adc8b1ae2acf 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -54,6 +54,7 @@ How Linux keeps everything from happening at the same time. See :maxdepth: 1
refcount-vs-atomic + seqnum_ops irq/index local_ops padata 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. + +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 + * 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 + */ +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 + * + */ +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/Kconfig b/lib/Kconfig index 46806332a8cc..518de7d34606 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -663,6 +663,15 @@ config OBJAGG config STRING_SELFTEST tristate "Test string functions"
+config TEST_SEQNUM_OPS + tristate "Test Sequence Number Ops API" + help + A test module for Sequence Number Ops API. A corresponding + selftest can be used to test the Seqnum Ops API. Select this + for testing Sequence Number Ops API. + + See Documentation/core-api/seqnum_ops.rst + endmenu
config GENERIC_IOREMAP diff --git a/lib/Makefile b/lib/Makefile index afeff05fa8c5..917686063cb3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o obj-$(CONFIG_TEST_HMM) += test_hmm.o obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o +obj-$(CONFIG_TEST_SEQNUM_OPS) += test_seqnum_ops.o
# # CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns 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 inline void +test_seqnum32_result(char *msg, u32 start, u32 end, u32 expected) +{ + pr_info("%s: %u to %u - %s\n", + msg, start, end, + ((expected == end) ? "PASS" : "FAIL")); +} + + +static void test_seqnum32(void) +{ + u32 start_val = 0; + struct seqnum32 seq = SEQNUM_INIT(start_val); + u32 end_val; + + end_val = seqnum32_inc(&seq); + test_seqnum32_result("Test increment", + start_val, end_val, start_val+1); + + /* Initialize sequence number to 0 */ + seqnum32_init(&seq, 0); + end_val = seqnum32_inc(&seq); + /* If seqnum32_init() works correctly end_val should be 1 */ + test_seqnum32_result("Test init", start_val, end_val, 1); + + /* seqnum32_get() test for seqnum value == 1 */ + start_val = end_val = seqnum32_get(&seq); + test_seqnum32_result("Test get", start_val, end_val, 1); +} + +static void test_seqnum32_overflow(u32 val) +{ + u32 start_val; + struct seqnum32 seq; + u32 end_val; + + pr_info("Test with start_val UINT_MAX-1 + %u\n", val); + start_val = UINT_MAX-1 + val; + seqnum32_init(&seq, start_val); + end_val = seqnum32_inc(&seq); + test_seqnum32_result("Test UINT_MAX limit compare with (val+1)", + start_val, end_val, start_val+1); + test_seqnum32_result("Test UINT_MAX limit compare with (UINT_MAX)", + start_val, end_val, UINT_MAX+val); +} + +static inline void +test_seqnum64_result(char *msg, u64 start, u64 end, u64 expected) +{ + pr_info("%s: %llu to %llu - %s\n", + msg, start, end, + ((expected == end) ? "PASS" : "FAIL")); +} + +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 */ + 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); +} + +static void test_seqnum64_overflow(u64 val) +{ + u64 start_val; + struct seqnum64 seq; + u64 end_val; + + pr_info("Test with start_val SEQ_UINT64_MAX-1 + %llu\n", val); + start_val = SEQ_UINT64_MAX-1 + val; + seqnum64_init(&seq, start_val); + end_val = seqnum64_inc(&seq); + test_seqnum64_result("Test UINT64_MAX limit compare with (val+1)", + start_val, end_val, start_val+1); + test_seqnum64_result("Test UINT64_MAX limit compare with (UINT64_MAX)", + start_val, end_val, SEQ_UINT64_MAX+val); +} + +static int __init test_seqnum_ops_init(void) +{ + pr_info("Start seqnum32_*() interfaces test\n"); + test_seqnum32(); + test_seqnum32_overflow(0); + test_seqnum32_overflow(5); + pr_info("End seqnum32_*() interfaces test\n\n"); + + pr_info("Start seqnum64_*() interfaces test\n"); + test_seqnum64(); + test_seqnum64_overflow(0); + test_seqnum64_overflow(5); + pr_info("End seqnum64_*() interfaces test\n\n"); + + return 0; +} + +module_init(test_seqnum_ops_init); + +static void __exit test_seqnum_ops_exit(void) +{ + pr_info("exiting.\n"); +} + +module_exit(test_seqnum_ops_exit); + +MODULE_AUTHOR("Shuah Khan skhan@linuxfoundation.org"); +MODULE_LICENSE("GPL v2");
On Wed, Feb 03, 2021 at 11:11:57AM -0700, Shuah Khan wrote:
+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;
+}
What kind of broken garbage is that?
On Wed, Feb 03, 2021 at 11:11:57AM -0700, Shuah Khan wrote:
+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;
As Peter points out, this is doing doing what you think it is doing :(
Why do you not just have seq->seqnum be a real atomic variable? Trying to switch to/from one like this does not work as there is no "atomic-ness" happening here at all.
Oh, and checkpatch should have complained about the extra ' ' in your cast :)
thanks,
greg k-h
On 2/5/21 2:58 AM, Greg KH wrote:
On Wed, Feb 03, 2021 at 11:11:57AM -0700, Shuah Khan wrote:
+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;
As Peter points out, this is doing doing what you think it is doing :(
Why do you not just have seq->seqnum be a real atomic variable? Trying to switch to/from one like this does not work as there is no "atomic-ness" happening here at all.
Yes. This is sloppy on my part. As Peter and Rafael also pointed. I have to start paying more attention to my inner voice.
thanks, -- Shuah
On Fri, Feb 05, 2021 at 01:03:18PM -0700, Shuah Khan wrote:
On 2/5/21 2:58 AM, Greg KH wrote:
On Wed, Feb 03, 2021 at 11:11:57AM -0700, Shuah Khan wrote:
+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;
As Peter points out, this is doing doing what you think it is doing :(
Why do you not just have seq->seqnum be a real atomic variable? Trying to switch to/from one like this does not work as there is no "atomic-ness" happening here at all.
Yes. This is sloppy on my part. As Peter and Rafael also pointed. I have to start paying more attention to my inner voice.
What's the end goal with this sequence number type?
Apart from the functional issues with this code already pointed out, it doesn't seem overly useful to just print the *value* of the sequence number when it hits the max value. It might be more helpful if each instance had a seq->name field that is used here to tell the user *which* user of sequence numbers had seen the wrap arounnd.
But that just begs the question of what should users of sequence numbers do when wrap around occurs? Any user that can run through sequence numbers at greater than 10 Hz is going to cause a problem for systems that stay running for years.
Maybe you should force users to code for wraparound by initializing to something like 0xffffff00 so that they all get a wraparound event quickly, rather than slowly, (same as was done with jiffies)?
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);
+}
Add a new selftest for testing seqnum_ops. This test loads test_seqnum_ops test module and unloads it. The test module runs tests and prints results to dmesg.
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath.
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/seqnum_ops.rst | 9 +++++++++ MAINTAINERS | 1 + include/linux/seqnum_ops.h | 2 ++ tools/testing/selftests/lib/Makefile | 1 + tools/testing/selftests/lib/config | 1 + tools/testing/selftests/lib/test_seqnum_ops.sh | 10 ++++++++++ 6 files changed, 24 insertions(+) create mode 100755 tools/testing/selftests/lib/test_seqnum_ops.sh
diff --git a/Documentation/core-api/seqnum_ops.rst b/Documentation/core-api/seqnum_ops.rst index ed4eba394799..6db2c9120885 100644 --- a/Documentation/core-api/seqnum_ops.rst +++ b/Documentation/core-api/seqnum_ops.rst @@ -51,3 +51,12 @@ Returns sequence number value. ::
.. warning:: seqnum32 wraps around to INT_MIN when it overflows. + +Where are the seqnum_ops and how to use and test them? +------------------------------------------------------ + +.. kernel-doc:: include/linux/seqnum_ops.h + +Please see lib/test_seqnum_ops.c for examples usages and test module. +Please find selftest: testing/selftests/lib/test_seqnum_ops.sh +Please check dmesg for results after running test_seqnum_ops.sh. diff --git a/MAINTAINERS b/MAINTAINERS index f9fe1438a8cd..70b9eeb995f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16241,6 +16241,7 @@ L: linux-kernel@vger.kernel.org S: Maintained F: include/linux/seqnum_ops.h F: lib/test_seqnum_ops.c +F: tools/testing/selftests/lib/test_seqnum_ops.sh
SIMPLE FIRMWARE INTERFACE (SFI) S: Obsolete diff --git a/include/linux/seqnum_ops.h b/include/linux/seqnum_ops.h index e8d8481445d3..d540b62d1aa4 100644 --- a/include/linux/seqnum_ops.h +++ b/include/linux/seqnum_ops.h @@ -18,6 +18,8 @@ * * Reference and API guide: * Documentation/core-api/seqnum_ops.rst for more information. + * lib/test_seqnum_ops.c - example usages and test module + * tools/testing/selftests/lib/test_seqnum_ops.sh */
#ifndef __LINUX_SEQNUM_OPS_H diff --git a/tools/testing/selftests/lib/Makefile b/tools/testing/selftests/lib/Makefile index a105f094676e..1818444f0e97 100644 --- a/tools/testing/selftests/lib/Makefile +++ b/tools/testing/selftests/lib/Makefile @@ -5,5 +5,6 @@ all:
TEST_PROGS := printf.sh bitmap.sh prime_numbers.sh strscpy.sh +TEST_PROGS += test_seqnum_ops.sh
include ../lib.mk diff --git a/tools/testing/selftests/lib/config b/tools/testing/selftests/lib/config index b80ee3f6e265..674ed2a2ac82 100644 --- a/tools/testing/selftests/lib/config +++ b/tools/testing/selftests/lib/config @@ -3,3 +3,4 @@ CONFIG_TEST_BITMAP=m CONFIG_PRIME_NUMBERS=m CONFIG_TEST_STRSCPY=m CONFIG_TEST_BITOPS=m +CONFIG_TEST_SEQNUM_OPS=m diff --git a/tools/testing/selftests/lib/test_seqnum_ops.sh b/tools/testing/selftests/lib/test_seqnum_ops.sh new file mode 100755 index 000000000000..fdce16b220ba --- /dev/null +++ b/tools/testing/selftests/lib/test_seqnum_ops.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2020 Shuah Khan skhan@linuxfoundation.org +# Copyright (c) 2020 The Linux Foundation +# +# Tests the Sequence Number Ops interfaces using test_seqnum_ops +# kernel module +# +$(dirname $0)/../kselftest/module.sh "test_seqnum_ops" test_seqnum_ops
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath.
Convert seqno atomic counter to use seqnum_ops.
Signed-off-by: Shuah Khan skhan@linuxfoundation.org --- drivers/acpi/acpi_extlog.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 72f1fb77abcd..16a4928645a1 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -12,6 +12,7 @@ #include <linux/ratelimit.h> #include <linux/edac.h> #include <linux/ras.h> +#include <linux/seqnum_ops.h> #include <asm/cpu.h> #include <asm/mce.h>
@@ -93,8 +94,7 @@ static struct acpi_hest_generic_status *extlog_elog_entry_check(int cpu, int ban static void __print_extlog_rcd(const char *pfx, struct acpi_hest_generic_status *estatus, int cpu) { - static atomic_t seqno; - unsigned int curr_seqno; + static struct seqnum32 seqno; char pfx_seq[64];
if (!pfx) { @@ -103,8 +103,8 @@ static void __print_extlog_rcd(const char *pfx, else pfx = KERN_ERR; } - curr_seqno = atomic_inc_return(&seqno); - snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}", pfx, curr_seqno); + snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}", pfx, + seqnum32_inc(&seqno)); printk("%s""Hardware error detected on CPU%d\n", pfx_seq, cpu); cper_estatus_print(pfx_seq, estatus); }
Hi Shuah,
First off, please indicate the component in the subject, for example:
"ACPI: extlog: convert seqno to use seqnum_ops"
On Wed, Feb 3, 2021 at 7:12 PM Shuah Khan skhan@linuxfoundation.org wrote:
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath.
Convert seqno atomic counter to use seqnum_ops.
Apart from the above, it would be good to say why the change is an improvement.
It looks like the rationale is that using struct seqnum32 would allow tools to easily detect the usage of sequence numbers, but is there anything else in this particular case?
Signed-off-by: Shuah Khan skhan@linuxfoundation.org
drivers/acpi/acpi_extlog.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 72f1fb77abcd..16a4928645a1 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -12,6 +12,7 @@ #include <linux/ratelimit.h> #include <linux/edac.h> #include <linux/ras.h> +#include <linux/seqnum_ops.h> #include <asm/cpu.h> #include <asm/mce.h>
@@ -93,8 +94,7 @@ static struct acpi_hest_generic_status *extlog_elog_entry_check(int cpu, int ban static void __print_extlog_rcd(const char *pfx, struct acpi_hest_generic_status *estatus, int cpu) {
static atomic_t seqno;
unsigned int curr_seqno;
static struct seqnum32 seqno; char pfx_seq[64]; if (!pfx) {
@@ -103,8 +103,8 @@ static void __print_extlog_rcd(const char *pfx, else pfx = KERN_ERR; }
curr_seqno = atomic_inc_return(&seqno);
snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}", pfx, curr_seqno);
snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}", pfx,
seqnum32_inc(&seqno)); printk("%s""Hardware error detected on CPU%d\n", pfx_seq, cpu); cper_estatus_print(pfx_seq, estatus);
}
2.27.0
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath.
Convert seqno atomic counter to use seqnum_ops.
Signed-off-by: Shuah Khan skhan@linuxfoundation.org --- drivers/acpi/apei/ghes.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index fce7ade2aba9..103f67edee1a 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -41,6 +41,7 @@ #include <linux/uuid.h> #include <linux/ras.h> #include <linux/task_work.h> +#include <linux/seqnum_ops.h>
#include <acpi/actbl1.h> #include <acpi/ghes.h> @@ -625,8 +626,7 @@ static void __ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, const struct acpi_hest_generic_status *estatus) { - static atomic_t seqno; - unsigned int curr_seqno; + static struct seqnum32 seqno; char pfx_seq[64];
if (pfx == NULL) { @@ -636,8 +636,8 @@ static void __ghes_print_estatus(const char *pfx, else pfx = KERN_ERR; } - curr_seqno = atomic_inc_return(&seqno); - snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); + snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, + seqnum32_inc(&seqno)); printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", pfx_seq, generic->header.source_id); cper_estatus_print(pfx_seq, estatus);
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath. Convert it to use seqnum_ops.
event_seq atomic_t variables are atomic counters. Convert them to use seqnum_ops.
Signed-off-by: Shuah Khan skhan@linuxfoundation.org --- drivers/staging/rtl8723bs/core/rtw_cmd.c | 3 +- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 33 +++++++++++++------ drivers/staging/rtl8723bs/include/rtw_cmd.h | 3 +- .../staging/rtl8723bs/include/rtw_mlme_ext.h | 3 +- 4 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 3fe79169a811..4db737cd748e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -10,6 +10,7 @@ #include <rtw_debug.h> #include <hal_btcoex.h> #include <linux/jiffies.h> +#include <linux/seqnum_ops.h>
static struct _cmd_callback rtw_cmd_callback[] = { {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ @@ -207,7 +208,7 @@ static void c2h_wk_callback(_workitem * work); int rtw_init_evt_priv(struct evt_priv *pevtpriv) { /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ - atomic_set(&pevtpriv->event_seq, 0); + seqnum32_init(&pevtpriv->event_seq, 0); pevtpriv->evt_done_cnt = 0;
_init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index fa4b0259c5ae..46e7f487a5ba 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -11,6 +11,7 @@ #include <rtw_wifi_regd.h> #include <hal_btcoex.h> #include <linux/kernel.h> +#include <linux/seqnum_ops.h> #include <asm/unaligned.h>
static struct mlme_handler mlme_sta_tbl[] = { @@ -281,7 +282,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- atomic_set(&pmlmeext->event_seq, 0); + seqnum32_init(&pmlmeext->event_seq, 0); pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ pmlmeext->sa_query_seq = 0; pmlmeext->mgnt_80211w_IPN = 0; @@ -5049,7 +5050,9 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct survey_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -5102,7 +5105,9 @@ void report_surveydone_event(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct surveydone_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; @@ -5149,7 +5154,9 @@ void report_join_res(struct adapter *padapter, int res) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct joinbss_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); @@ -5200,7 +5207,9 @@ void report_wmm_edca_update(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct wmm_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); pwmm_event->wmm = 0; @@ -5247,7 +5256,9 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stadel_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); @@ -5300,7 +5311,9 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stassoc_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); @@ -6616,10 +6629,10 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
#ifdef CHECK_EVENT_SEQ /* checking event sequence... */ - if (evt_seq != (atomic_read(&pevt_priv->event_seq) & 0x7f)) { + if (evt_seq != (seqnum32_get(&pevt_priv->event_seq) & 0x7f)) { RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("Event Seq Error! %d vs %d\n", (evt_seq & 0x7f), - (atomic_read(&pevt_priv->event_seq) & 0x7f))); + (seqnum32_get(&pevt_priv->event_seq) & 0x7f)));
pevt_priv->event_seq = (evt_seq+1)&0x7f;
@@ -6643,7 +6656,7 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
}
- atomic_inc(&pevt_priv->event_seq); + seqnum32_inc(&pevt_priv->event_seq);
peventbuf += 2;
diff --git a/drivers/staging/rtl8723bs/include/rtw_cmd.h b/drivers/staging/rtl8723bs/include/rtw_cmd.h index 56c77bc7ca81..cc0ea649388b 100644 --- a/drivers/staging/rtl8723bs/include/rtw_cmd.h +++ b/drivers/staging/rtl8723bs/include/rtw_cmd.h @@ -8,6 +8,7 @@ #define __RTW_CMD_H_
#include <linux/completion.h> +#include <linux/seqnum_ops.h>
#define C2H_MEM_SZ (16*1024)
@@ -62,7 +63,7 @@ struct rtw_cbuf *c2h_queue; #define C2H_QUEUE_MAX_LEN 10
- atomic_t event_seq; + struct seqnum32 event_seq; u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */ u8 *evt_allocated_buf; u32 evt_done_cnt; diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 1567831caf91..537813c00670 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -7,6 +7,7 @@ #ifndef __RTW_MLME_EXT_H_ #define __RTW_MLME_EXT_H_
+#include <linux/seqnum_ops.h>
/* Commented by Albert 20101105 */ /* Increase the SURVEY_TO value from 100 to 150 (100ms to 150ms) */ @@ -461,7 +462,7 @@ struct p2p_oper_class_map { struct mlme_ext_priv { struct adapter *padapter; u8 mlmeext_init; - atomic_t event_seq; + struct seqnum32 event_seq; u16 mgnt_seq; u16 sa_query_seq; u64 mgnt_80211w_IPN;
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath. Convert it to use seqnum_ops.
event_seq atomic_t variables are atomic counters. Convert them to use seqnum_ops.
Signed-off-by: Shuah Khan skhan@linuxfoundation.org --- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 23 ++++++++++++++----- .../staging/rtl8188eu/include/rtw_mlme_ext.h | 3 ++- 2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 8794907a39f4..2fa5a8c44d28 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -7,6 +7,7 @@ #define _RTW_MLME_EXT_C_
#include <linux/ieee80211.h> +#include <linux/seqnum_ops.h> #include <asm/unaligned.h>
#include <osdep_service.h> @@ -3860,7 +3861,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) _12M_RATE_, _24M_RATE_, 0xff, };
- atomic_set(&pmlmeext->event_seq, 0); + seqnum32_init(&pmlmeext->event_seq, 0); pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */
pmlmeext->cur_channel = padapter->registrypriv.channel; @@ -4189,7 +4190,9 @@ void report_survey_event(struct adapter *padapter, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct survey_event); pc2h_evt_hdr->ID = _Survey_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
@@ -4239,7 +4242,9 @@ void report_surveydone_event(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct surveydone_event); pc2h_evt_hdr->ID = _SurveyDone_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; @@ -4283,7 +4288,9 @@ void report_join_res(struct adapter *padapter, int res) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct joinbss_event); pc2h_evt_hdr->ID = _JoinBss_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&pjoinbss_evt->network.network), &pmlmeinfo->network, sizeof(struct wlan_bssid_ex)); @@ -4333,7 +4340,9 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stadel_event); pc2h_evt_hdr->ID = _DelSTA_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ether_addr_copy((unsigned char *)(&pdel_sta_evt->macaddr), MacAddr); @@ -4386,7 +4395,9 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stassoc_event); pc2h_evt_hdr->ID = _AddSTA_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc(&pmlmeext->event_seq);
padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ether_addr_copy((unsigned char *)(&padd_sta_evt->macaddr), MacAddr); diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h index b11a6886a083..09b7e3bb2738 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h @@ -7,6 +7,7 @@ #ifndef __RTW_MLME_EXT_H_ #define __RTW_MLME_EXT_H_
+#include <linux/seqnum_ops.h> #include <osdep_service.h> #include <drv_types.h> #include <wlan_bssdef.h> @@ -393,7 +394,7 @@ struct p2p_oper_class_map { struct mlme_ext_priv { struct adapter *padapter; u8 mlmeext_init; - atomic_t event_seq; + struct seqnum32 event_seq; u16 mgnt_seq;
unsigned char cur_channel;
Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath.
Convert uevent_seqnum atomic counter to use seqnum_ops.
Signed-off-by: Shuah Khan skhan@linuxfoundation.org --- include/linux/kobject.h | 3 ++- kernel/ksysfs.c | 3 ++- lib/kobject_uevent.c | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/include/linux/kobject.h b/include/linux/kobject.h index ea30529fba08..8990e40344a2 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -27,6 +27,7 @@ #include <linux/atomic.h> #include <linux/workqueue.h> #include <linux/uidgid.h> +#include <linux/seqnum_ops.h>
#define UEVENT_HELPER_PATH_LEN 256 #define UEVENT_NUM_ENVP 64 /* number of env pointers */ @@ -38,7 +39,7 @@ extern char uevent_helper[]; #endif
/* counter to tag the uevent, read only except for the kobject core */ -extern u64 uevent_seqnum; +extern struct seqnum64 uevent_seqnum;
/* * The actions here must match the index to the string array diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 35859da8bd4f..15836f6e5998 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -17,6 +17,7 @@ #include <linux/sched.h> #include <linux/capability.h> #include <linux/compiler.h> +#include <linux/seqnum_ops.h>
#include <linux/rcupdate.h> /* rcu_expedited and rcu_normal */
@@ -31,7 +32,7 @@ static struct kobj_attribute _name##_attr = \ static ssize_t uevent_seqnum_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%llu\n", (unsigned long long)uevent_seqnum); + return sprintf(buf, "%llu\n", seqnum64_get(&uevent_seqnum)); } KERNEL_ATTR_RO(uevent_seqnum);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 7998affa45d4..3a7b2648f084 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -28,9 +28,10 @@ #include <net/sock.h> #include <net/netlink.h> #include <net/net_namespace.h> +#include <linux/seqnum_ops.h>
-u64 uevent_seqnum; +struct seqnum64 uevent_seqnum; #ifdef CONFIG_UEVENT_HELPER char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; #endif @@ -584,7 +585,8 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
mutex_lock(&uevent_sock_mutex); /* we will send an event, so request a new sequence number */ - retval = add_uevent_var(env, "SEQNUM=%llu", ++uevent_seqnum); + retval = add_uevent_var(env, "SEQNUM=%llu", + seqnum64_inc(&uevent_seqnum)); if (retval) { mutex_unlock(&uevent_sock_mutex); goto exit; @@ -687,7 +689,8 @@ static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb, int ret;
/* bump and prepare sequence number */ - ret = snprintf(buf, sizeof(buf), "SEQNUM=%llu", ++uevent_seqnum); + ret = snprintf(buf, sizeof(buf), "SEQNUM=%llu", + seqnum64_inc(&uevent_seqnum)); if (ret < 0 || (size_t)ret >= sizeof(buf)) return -ENOMEM; ret++;
linux-kselftest-mirror@lists.linaro.org