This adds the function errseq_counter_sample to allow for "subscribers" to take point-in-time snapshots of the errseq_counter, and store the counter + errseq_t. Signed-off-by: Sargun Dhillon <sargun@xxxxxxxxx> --- include/linux/errseq.h | 4 ++++ lib/errseq.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/include/linux/errseq.h b/include/linux/errseq.h index 35818c484290..8998df499a3b 100644 --- a/include/linux/errseq.h +++ b/include/linux/errseq.h @@ -25,4 +25,8 @@ errseq_t errseq_set(errseq_t *eseq, int err); errseq_t errseq_sample(errseq_t *eseq); int errseq_check(errseq_t *eseq, errseq_t since); int errseq_check_and_advance(errseq_t *eseq, errseq_t *since); +void errseq_counter_sample(errseq_t *dst_errseq, int *dst_errors, + struct errseq_counter *counter); +int errseq_counter_check(struct errseq_counter *counter, errseq_t errseq_since, + int errors_since); #endif diff --git a/lib/errseq.c b/lib/errseq.c index d555e7fc18d2..98fcfafa3d97 100644 --- a/lib/errseq.c +++ b/lib/errseq.c @@ -246,3 +246,54 @@ int errseq_check_and_advance(errseq_t *eseq, errseq_t *since) return err; } EXPORT_SYMBOL(errseq_check_and_advance); + +/** + * errseq_counter_sample() - Grab the current errseq_counter value + * @dst_errseq: The errseq_t to copy to + * @dst_errors: The destination overflow to copy to + * @counter: The errseq_counter to copy from + * + * Grabs a point in time sample of the errseq_counter for latter comparison + */ +void errseq_counter_sample(errseq_t *dst_errseq, int *dst_errors, + struct errseq_counter *counter) +{ + errseq_t cur; + + do { + cur = READ_ONCE(counter->errseq); + *dst_errors = atomic_read(&counter->errors); + } while (cur != READ_ONCE(counter->errseq)); + + /* Clear the seen bit to make checking later easier */ + *dst_errseq = cur & ~ERRSEQ_SEEN; +} +EXPORT_SYMBOL(errseq_counter_sample); + +/** + * errseq_counter_check() - Has an error occurred since the sample + * @counter: The errseq_counter from which to check. + * @errseq_since: The errseq_t sampled with errseq_counter_sample to check + * @errors_since: The errors sampled with errseq_counter_sample to check + * + * Returns: The latest error set in the errseq_t or 0 if there have been none. + */ +int errseq_counter_check(struct errseq_counter *counter, errseq_t errseq_since, + int errors_since) +{ + errseq_t cur_errseq; + int cur_errors; + + cur_errors = atomic_read(&counter->errors); + /* To match the barrier in errseq_counter_set */ + smp_rmb(); + + /* Clear / ignore the seen bit as we do at sample time */ + cur_errseq = READ_ONCE(counter->errseq) & ~ERRSEQ_SEEN; + + if (cur_errseq == errseq_since && errors_since == cur_errors) + return 0; + + return -(cur_errseq & MAX_ERRNO); +} +EXPORT_SYMBOL(errseq_counter_check); -- 2.25.1