errseq.c (70a02f840c5113cd9255ce4c1b1848bb48b0bd21) errseq.c (14ebc28e07e68ff412aa42f7d8b67969e2f63d00)
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/err.h>
3#include <linux/bug.h>
4#include <linux/atomic.h>
5#include <linux/errseq.h>
6
7/*
8 * An errseq_t is a way of recording errors in one place, and allowing any

--- 32 unchanged lines hidden (view full) ---

41/* The lowest bit of the counter */
42#define ERRSEQ_CTR_INC (1 << (ERRSEQ_SHIFT + 1))
43
44/**
45 * errseq_set - set a errseq_t for later reporting
46 * @eseq: errseq_t field that should be set
47 * @err: error to set (must be between -1 and -MAX_ERRNO)
48 *
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/err.h>
3#include <linux/bug.h>
4#include <linux/atomic.h>
5#include <linux/errseq.h>
6
7/*
8 * An errseq_t is a way of recording errors in one place, and allowing any

--- 32 unchanged lines hidden (view full) ---

41/* The lowest bit of the counter */
42#define ERRSEQ_CTR_INC (1 << (ERRSEQ_SHIFT + 1))
43
44/**
45 * errseq_set - set a errseq_t for later reporting
46 * @eseq: errseq_t field that should be set
47 * @err: error to set (must be between -1 and -MAX_ERRNO)
48 *
49 * This function sets the error in *eseq, and increments the sequence counter
49 * This function sets the error in @eseq, and increments the sequence counter
50 * if the last sequence was sampled at some point in the past.
51 *
52 * Any error set will always overwrite an existing error.
53 *
50 * if the last sequence was sampled at some point in the past.
51 *
52 * Any error set will always overwrite an existing error.
53 *
54 * We do return the latest value here, primarily for debugging purposes. The
55 * return value should not be used as a previously sampled value in later calls
56 * as it will not have the SEEN flag set.
54 * Return: The previous value, primarily for debugging purposes. The
55 * return value should not be used as a previously sampled value in later
56 * calls as it will not have the SEEN flag set.
57 */
58errseq_t errseq_set(errseq_t *eseq, int err)
59{
60 errseq_t cur, old;
61
62 /* MAX_ERRNO must be able to serve as a mask */
63 BUILD_BUG_ON_NOT_POWER_OF_2(MAX_ERRNO + 1);
64

--- 38 unchanged lines hidden (view full) ---

103 /* Raced with an update, try again */
104 old = cur;
105 }
106 return cur;
107}
108EXPORT_SYMBOL(errseq_set);
109
110/**
57 */
58errseq_t errseq_set(errseq_t *eseq, int err)
59{
60 errseq_t cur, old;
61
62 /* MAX_ERRNO must be able to serve as a mask */
63 BUILD_BUG_ON_NOT_POWER_OF_2(MAX_ERRNO + 1);
64

--- 38 unchanged lines hidden (view full) ---

103 /* Raced with an update, try again */
104 old = cur;
105 }
106 return cur;
107}
108EXPORT_SYMBOL(errseq_set);
109
110/**
111 * errseq_sample - grab current errseq_t value
112 * @eseq: pointer to errseq_t to be sampled
111 * errseq_sample() - Grab current errseq_t value.
112 * @eseq: Pointer to errseq_t to be sampled.
113 *
114 * This function allows callers to sample an errseq_t value, marking it as
115 * "seen" if required.
113 *
114 * This function allows callers to sample an errseq_t value, marking it as
115 * "seen" if required.
116 *
117 * Return: The current errseq value.
116 */
117errseq_t errseq_sample(errseq_t *eseq)
118{
119 errseq_t old = READ_ONCE(*eseq);
120 errseq_t new = old;
121
122 /*
123 * For the common case of no errors ever having been set, we can skip

--- 5 unchanged lines hidden (view full) ---

129 if (old != new)
130 cmpxchg(eseq, old, new);
131 }
132 return new;
133}
134EXPORT_SYMBOL(errseq_sample);
135
136/**
118 */
119errseq_t errseq_sample(errseq_t *eseq)
120{
121 errseq_t old = READ_ONCE(*eseq);
122 errseq_t new = old;
123
124 /*
125 * For the common case of no errors ever having been set, we can skip

--- 5 unchanged lines hidden (view full) ---

131 if (old != new)
132 cmpxchg(eseq, old, new);
133 }
134 return new;
135}
136EXPORT_SYMBOL(errseq_sample);
137
138/**
137 * errseq_check - has an error occurred since a particular sample point?
138 * @eseq: pointer to errseq_t value to be checked
139 * @since: previously-sampled errseq_t from which to check
139 * errseq_check() - Has an error occurred since a particular sample point?
140 * @eseq: Pointer to errseq_t value to be checked.
141 * @since: Previously-sampled errseq_t from which to check.
140 *
142 *
141 * Grab the value that eseq points to, and see if it has changed "since"
142 * the given value was sampled. The "since" value is not advanced, so there
143 * Grab the value that eseq points to, and see if it has changed @since
144 * the given value was sampled. The @since value is not advanced, so there
143 * is no need to mark the value as seen.
144 *
145 * is no need to mark the value as seen.
146 *
145 * Returns the latest error set in the errseq_t or 0 if it hasn't changed.
147 * Return: The latest error set in the errseq_t or 0 if it hasn't changed.
146 */
147int errseq_check(errseq_t *eseq, errseq_t since)
148{
149 errseq_t cur = READ_ONCE(*eseq);
150
151 if (likely(cur == since))
152 return 0;
153 return -(cur & MAX_ERRNO);
154}
155EXPORT_SYMBOL(errseq_check);
156
157/**
148 */
149int errseq_check(errseq_t *eseq, errseq_t since)
150{
151 errseq_t cur = READ_ONCE(*eseq);
152
153 if (likely(cur == since))
154 return 0;
155 return -(cur & MAX_ERRNO);
156}
157EXPORT_SYMBOL(errseq_check);
158
159/**
158 * errseq_check_and_advance - check an errseq_t and advance to current value
159 * @eseq: pointer to value being checked and reported
160 * @since: pointer to previously-sampled errseq_t to check against and advance
160 * errseq_check_and_advance() - Check an errseq_t and advance to current value.
161 * @eseq: Pointer to value being checked and reported.
162 * @since: Pointer to previously-sampled errseq_t to check against and advance.
161 *
163 *
162 * Grab the eseq value, and see whether it matches the value that "since"
164 * Grab the eseq value, and see whether it matches the value that @since
163 * points to. If it does, then just return 0.
164 *
165 * If it doesn't, then the value has changed. Set the "seen" flag, and try to
166 * swap it into place as the new eseq value. Then, set that value as the new
167 * "since" value, and return whatever the error portion is set to.
168 *
169 * Note that no locking is provided here for concurrent updates to the "since"
170 * value. The caller must provide that if necessary. Because of this, callers
171 * may want to do a lockless errseq_check before taking the lock and calling
172 * this.
165 * points to. If it does, then just return 0.
166 *
167 * If it doesn't, then the value has changed. Set the "seen" flag, and try to
168 * swap it into place as the new eseq value. Then, set that value as the new
169 * "since" value, and return whatever the error portion is set to.
170 *
171 * Note that no locking is provided here for concurrent updates to the "since"
172 * value. The caller must provide that if necessary. Because of this, callers
173 * may want to do a lockless errseq_check before taking the lock and calling
174 * this.
175 *
176 * Return: Negative errno if one has been stored, or 0 if no new error has
177 * occurred.
173 */
174int errseq_check_and_advance(errseq_t *eseq, errseq_t *since)
175{
176 int err = 0;
177 errseq_t old, new;
178
179 /*
180 * Most callers will want to use the inline wrapper to check this,

--- 26 unchanged lines hidden ---
178 */
179int errseq_check_and_advance(errseq_t *eseq, errseq_t *since)
180{
181 int err = 0;
182 errseq_t old, new;
183
184 /*
185 * Most callers will want to use the inline wrapper to check this,

--- 26 unchanged lines hidden ---