Commit 0799a0ea authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Greg Kroah-Hartman

errseq: Always report a writeback error once

commit b4678df1 upstream.

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: 5660e13d ("fs: new infrastructure for writeback error handling and reporting")
Signed-off-by: default avatarMatthew Wilcox <mawilcox@microsoft.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b4f6e858
...@@ -111,25 +111,22 @@ EXPORT_SYMBOL(errseq_set); ...@@ -111,25 +111,22 @@ EXPORT_SYMBOL(errseq_set);
* errseq_sample - grab current errseq_t value * errseq_sample - grab current errseq_t value
* @eseq: pointer to errseq_t to be sampled * @eseq: pointer to errseq_t to be sampled
* *
* This function allows callers to sample an errseq_t value, marking it as * This function allows callers to initialise their errseq_t variable.
* "seen" if required. * If the error has been "seen", new callers will not see an old error.
* If there is an unseen error in @eseq, the caller of this function will
* see it the next time it checks for an error.
*
* Context: Any context.
* Return: The current errseq value.
*/ */
errseq_t errseq_sample(errseq_t *eseq) errseq_t errseq_sample(errseq_t *eseq)
{ {
errseq_t old = READ_ONCE(*eseq); errseq_t old = READ_ONCE(*eseq);
errseq_t new = old;
/* /* If nobody has seen this error yet, then we can be the first. */
* For the common case of no errors ever having been set, we can skip if (!(old & ERRSEQ_SEEN))
* marking the SEEN bit. Once an error has been set, the value will old = 0;
* never go back to zero. return old;
*/
if (old != 0) {
new |= ERRSEQ_SEEN;
if (old != new)
cmpxchg(eseq, old, new);
}
return new;
} }
EXPORT_SYMBOL(errseq_sample); EXPORT_SYMBOL(errseq_sample);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment