Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

jbd2: don't clear and reset errors after waiting on writeback

Resetting this flag is almost certainly racy, and will be problematic
with some coming changes.

Make filemap_fdatawait_keep_errors return int, but not clear the flag(s).
Have jbd2 call it instead of filemap_fdatawait and don't attempt to
re-set the error flag if it fails.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>

+19 -15
+4 -12
fs/jbd2/commit.c
··· 263 263 continue; 264 264 jinode->i_flags |= JI_COMMIT_RUNNING; 265 265 spin_unlock(&journal->j_list_lock); 266 - err = filemap_fdatawait(jinode->i_vfs_inode->i_mapping); 267 - if (err) { 268 - /* 269 - * Because AS_EIO is cleared by 270 - * filemap_fdatawait_range(), set it again so 271 - * that user process can get -EIO from fsync(). 272 - */ 273 - mapping_set_error(jinode->i_vfs_inode->i_mapping, -EIO); 274 - 275 - if (!ret) 276 - ret = err; 277 - } 266 + err = filemap_fdatawait_keep_errors( 267 + jinode->i_vfs_inode->i_mapping); 268 + if (!ret) 269 + ret = err; 278 270 spin_lock(&journal->j_list_lock); 279 271 jinode->i_flags &= ~JI_COMMIT_RUNNING; 280 272 smp_mb();
+1 -1
include/linux/fs.h
··· 2514 2514 extern int filemap_fdatawrite(struct address_space *); 2515 2515 extern int filemap_flush(struct address_space *); 2516 2516 extern int filemap_fdatawait(struct address_space *); 2517 - extern void filemap_fdatawait_keep_errors(struct address_space *); 2517 + extern int filemap_fdatawait_keep_errors(struct address_space *mapping); 2518 2518 extern int filemap_fdatawait_range(struct address_space *, loff_t lstart, 2519 2519 loff_t lend); 2520 2520 extern int filemap_write_and_wait(struct address_space *mapping);
+14 -2
mm/filemap.c
··· 309 309 } 310 310 EXPORT_SYMBOL(filemap_check_errors); 311 311 312 + static int filemap_check_and_keep_errors(struct address_space *mapping) 313 + { 314 + /* Check for outstanding write errors */ 315 + if (test_bit(AS_EIO, &mapping->flags)) 316 + return -EIO; 317 + if (test_bit(AS_ENOSPC, &mapping->flags)) 318 + return -ENOSPC; 319 + return 0; 320 + } 321 + 312 322 /** 313 323 * __filemap_fdatawrite_range - start writeback on mapping dirty pages in range 314 324 * @mapping: address space structure to write ··· 463 453 * call sites are system-wide / filesystem-wide data flushers: e.g. sync(2), 464 454 * fsfreeze(8) 465 455 */ 466 - void filemap_fdatawait_keep_errors(struct address_space *mapping) 456 + int filemap_fdatawait_keep_errors(struct address_space *mapping) 467 457 { 468 458 loff_t i_size = i_size_read(mapping->host); 469 459 470 460 if (i_size == 0) 471 - return; 461 + return 0; 472 462 473 463 __filemap_fdatawait_range(mapping, 0, i_size - 1); 464 + return filemap_check_and_keep_errors(mapping); 474 465 } 466 + EXPORT_SYMBOL(filemap_fdatawait_keep_errors); 475 467 476 468 /** 477 469 * filemap_fdatawait - wait for all under-writeback pages to complete