aboutsummaryrefslogtreecommitdiffstats
path: root/lib/errseq.c
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@infradead.org>2018-04-24 17:02:57 -0400
committerJeff Layton <jlayton@redhat.com>2018-04-27 08:51:26 -0400
commitb4678df184b314a2bd47d2329feca2c2534aa12b (patch)
tree6c9da9eabee5ab70d5b06d996e380c858496c07e /lib/errseq.c
parent0644f186fc9d77bb5bd198369e59fb28927a3692 (diff)
errseq: Always report a writeback error once
The errseq_t infrastructure assumes that errors which occurred before the file descriptor was opened are of no interest to the application. This turns out to be a regression for some applications, notably Postgres. Before errseq_t, a writeback error would be reported exactly once (as long as the inode remained in memory), so Postgres could open a file, call fsync() and find out whether there had been a writeback error on that file from another process. This patch changes the errseq infrastructure to report errors to all file descriptors which are opened after the error occurred, but before it was reported to any file descriptor. This restores the user-visible behaviour. Cc: stable@vger.kernel.org Fixes: 5660e13d2fd6 ("fs: new infrastructure for writeback error handling and reporting") Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Jeff Layton <jlayton@redhat.com>
Diffstat (limited to 'lib/errseq.c')
-rw-r--r--lib/errseq.c23
1 files changed, 9 insertions, 14 deletions
diff --git a/lib/errseq.c b/lib/errseq.c
index df782418b333..81f9e33aa7e7 100644
--- a/lib/errseq.c
+++ b/lib/errseq.c
@@ -111,27 +111,22 @@ EXPORT_SYMBOL(errseq_set);
111 * errseq_sample() - Grab current errseq_t value. 111 * errseq_sample() - Grab current errseq_t value.
112 * @eseq: Pointer to errseq_t to be sampled. 112 * @eseq: Pointer to errseq_t to be sampled.
113 * 113 *
114 * This function allows callers to sample an errseq_t value, marking it as 114 * This function allows callers to initialise their errseq_t variable.
115 * "seen" if required. 115 * If the error has been "seen", new callers will not see an old error.
116 * If there is an unseen error in @eseq, the caller of this function will
117 * see it the next time it checks for an error.
116 * 118 *
119 * Context: Any context.
117 * Return: The current errseq value. 120 * Return: The current errseq value.
118 */ 121 */
119errseq_t errseq_sample(errseq_t *eseq) 122errseq_t errseq_sample(errseq_t *eseq)
120{ 123{
121 errseq_t old = READ_ONCE(*eseq); 124 errseq_t old = READ_ONCE(*eseq);
122 errseq_t new = old;
123 125
124 /* 126 /* If nobody has seen this error yet, then we can be the first. */
125 * For the common case of no errors ever having been set, we can skip 127 if (!(old & ERRSEQ_SEEN))
126 * marking the SEEN bit. Once an error has been set, the value will 128 old = 0;
127 * never go back to zero. 129 return old;
128 */
129 if (old != 0) {
130 new |= ERRSEQ_SEEN;
131 if (old != new)
132 cmpxchg(eseq, old, new);
133 }
134 return new;
135} 130}
136EXPORT_SYMBOL(errseq_sample); 131EXPORT_SYMBOL(errseq_sample);
137 132