|
@@ -553,6 +553,90 @@ int filemap_write_and_wait_range(struct address_space *mapping,
|
|
|
}
|
|
|
EXPORT_SYMBOL(filemap_write_and_wait_range);
|
|
|
|
|
|
+void __filemap_set_wb_err(struct address_space *mapping, int err)
|
|
|
+{
|
|
|
+ errseq_t eseq = __errseq_set(&mapping->wb_err, err);
|
|
|
+
|
|
|
+ trace_filemap_set_wb_err(mapping, eseq);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(__filemap_set_wb_err);
|
|
|
+
|
|
|
+/**
|
|
|
+ * file_check_and_advance_wb_err - report wb error (if any) that was previously
|
|
|
+ * and advance wb_err to current one
|
|
|
+ * @file: struct file on which the error is being reported
|
|
|
+ *
|
|
|
+ * When userland calls fsync (or something like nfsd does the equivalent), we
|
|
|
+ * want to report any writeback errors that occurred since the last fsync (or
|
|
|
+ * since the file was opened if there haven't been any).
|
|
|
+ *
|
|
|
+ * Grab the wb_err from the mapping. If it matches what we have in the file,
|
|
|
+ * then just quickly return 0. The file is all caught up.
|
|
|
+ *
|
|
|
+ * If it doesn't match, then take the mapping value, set the "seen" flag in
|
|
|
+ * it and try to swap it into place. If it works, or another task beat us
|
|
|
+ * to it with the new value, then update the f_wb_err and return the error
|
|
|
+ * portion. The error at this point must be reported via proper channels
|
|
|
+ * (a'la fsync, or NFS COMMIT operation, etc.).
|
|
|
+ *
|
|
|
+ * While we handle mapping->wb_err with atomic operations, the f_wb_err
|
|
|
+ * value is protected by the f_lock since we must ensure that it reflects
|
|
|
+ * the latest value swapped in for this file descriptor.
|
|
|
+ */
|
|
|
+int file_check_and_advance_wb_err(struct file *file)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ errseq_t old = READ_ONCE(file->f_wb_err);
|
|
|
+ struct address_space *mapping = file->f_mapping;
|
|
|
+
|
|
|
+ /* Locklessly handle the common case where nothing has changed */
|
|
|
+ if (errseq_check(&mapping->wb_err, old)) {
|
|
|
+ /* Something changed, must use slow path */
|
|
|
+ spin_lock(&file->f_lock);
|
|
|
+ old = file->f_wb_err;
|
|
|
+ err = errseq_check_and_advance(&mapping->wb_err,
|
|
|
+ &file->f_wb_err);
|
|
|
+ trace_file_check_and_advance_wb_err(file, old);
|
|
|
+ spin_unlock(&file->f_lock);
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(file_check_and_advance_wb_err);
|
|
|
+
|
|
|
+/**
|
|
|
+ * file_write_and_wait_range - write out & wait on a file range
|
|
|
+ * @file: file pointing to address_space with pages
|
|
|
+ * @lstart: offset in bytes where the range starts
|
|
|
+ * @lend: offset in bytes where the range ends (inclusive)
|
|
|
+ *
|
|
|
+ * Write out and wait upon file offsets lstart->lend, inclusive.
|
|
|
+ *
|
|
|
+ * Note that @lend is inclusive (describes the last byte to be written) so
|
|
|
+ * that this function can be used to write to the very end-of-file (end = -1).
|
|
|
+ *
|
|
|
+ * After writing out and waiting on the data, we check and advance the
|
|
|
+ * f_wb_err cursor to the latest value, and return any errors detected there.
|
|
|
+ */
|
|
|
+int file_write_and_wait_range(struct file *file, loff_t lstart, loff_t lend)
|
|
|
+{
|
|
|
+ int err = 0, err2;
|
|
|
+ struct address_space *mapping = file->f_mapping;
|
|
|
+
|
|
|
+ if ((!dax_mapping(mapping) && mapping->nrpages) ||
|
|
|
+ (dax_mapping(mapping) && mapping->nrexceptional)) {
|
|
|
+ err = __filemap_fdatawrite_range(mapping, lstart, lend,
|
|
|
+ WB_SYNC_ALL);
|
|
|
+ /* See comment of filemap_write_and_wait() */
|
|
|
+ if (err != -EIO)
|
|
|
+ __filemap_fdatawait_range(mapping, lstart, lend);
|
|
|
+ }
|
|
|
+ err2 = file_check_and_advance_wb_err(file);
|
|
|
+ if (!err)
|
|
|
+ err = err2;
|
|
|
+ return err;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(file_write_and_wait_range);
|
|
|
+
|
|
|
/**
|
|
|
* replace_page_cache_page - replace a pagecache page with a new one
|
|
|
* @old: page to be replaced
|