aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/page.c
diff options
context:
space:
mode:
authorVyacheslav Dubeyko <slava@dubeyko.com>2013-04-30 18:27:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 20:04:04 -0400
commit8c26c4e2694a163d525976e804d81cd955bbb40c (patch)
treee3205cc7bd1be43d93e10475e5b5bc9483d41e1d /fs/nilfs2/page.c
parent9151b3982dafaa87bca3834c4d20db831ca98bcb (diff)
nilfs2: fix issue with flush kernel thread after remount in RO mode because of driver's internal error or metadata corruption
The NILFS2 driver remounts itself in RO mode in the case of discovering metadata corruption (for example, discovering a broken bmap). But usually, this takes place when there have been file system operations before remounting in RO mode. Thereby, NILFS2 driver can be in RO mode with presence of dirty pages in modified inodes' address spaces. It results in flush kernel thread's infinite trying to flush dirty pages in RO mode. As a result, it is possible to see such side effects as: (1) flush kernel thread occupies 50% - 99% of CPU time; (2) system can't be shutdowned without manual power switch off. SYMPTOMS: (1) System log contains error message: "Remounting filesystem read-only". (2) The flush kernel thread occupies 50% - 99% of CPU time. (3) The system can't be shutdowned without manual power switch off. REPRODUCTION PATH: (1) Create volume group with name "unencrypted" by means of vgcreate utility. (2) Run script (prepared by Anthony Doggett <Anthony2486@interfaces.org.uk>): ----------------[BEGIN SCRIPT]-------------------- #!/bin/bash VG=unencrypted #apt-get install nilfs-tools darcs lvcreate --size 2G --name ntest $VG mkfs.nilfs2 -b 1024 -B 8192 /dev/mapper/$VG-ntest mkdir /var/tmp/n mkdir /var/tmp/n/ntest mount /dev/mapper/$VG-ntest /var/tmp/n/ntest mkdir /var/tmp/n/ntest/thedir cd /var/tmp/n/ntest/thedir sleep 2 date darcs init sleep 2 dmesg|tail -n 5 date darcs whatsnew || true date sleep 2 dmesg|tail -n 5 ----------------[END SCRIPT]-------------------- (3) Try to shutdown the system. REPRODUCIBILITY: 100% FIX: This patch implements checking mount state of NILFS2 driver in nilfs_writepage(), nilfs_writepages() and nilfs_mdt_write_page() methods. If it is detected the RO mount state then all dirty pages are simply discarded with warning messages is written in system log. [akpm@linux-foundation.org: fix printk warning] Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com> Acked-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Cc: Anthony Doggett <Anthony2486@interfaces.org.uk> Cc: ARAI Shun-ichi <hermes@ceres.dti.ne.jp> Cc: Piotr Szymaniak <szarpaj@grubelek.pl> Cc: Zahid Chowdhury <zahid.chowdhury@starsolutions.com> Cc: Elmer Zhang <freeboy6716@gmail.com> Cc: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nilfs2/page.c')
-rw-r--r--fs/nilfs2/page.c70
1 files changed, 52 insertions, 18 deletions
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
index 07f76db04ec7..131a5841a070 100644
--- a/fs/nilfs2/page.c
+++ b/fs/nilfs2/page.c
@@ -370,7 +370,12 @@ repeat:
370 goto repeat; 370 goto repeat;
371} 371}
372 372
373void nilfs_clear_dirty_pages(struct address_space *mapping) 373/**
374 * nilfs_clear_dirty_pages - discard dirty pages in address space
375 * @mapping: address space with dirty pages for discarding
376 * @silent: suppress [true] or print [false] warning messages
377 */
378void nilfs_clear_dirty_pages(struct address_space *mapping, bool silent)
374{ 379{
375 struct pagevec pvec; 380 struct pagevec pvec;
376 unsigned int i; 381 unsigned int i;
@@ -382,25 +387,9 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
382 PAGEVEC_SIZE)) { 387 PAGEVEC_SIZE)) {
383 for (i = 0; i < pagevec_count(&pvec); i++) { 388 for (i = 0; i < pagevec_count(&pvec); i++) {
384 struct page *page = pvec.pages[i]; 389 struct page *page = pvec.pages[i];
385 struct buffer_head *bh, *head;
386 390
387 lock_page(page); 391 lock_page(page);
388 ClearPageUptodate(page); 392 nilfs_clear_dirty_page(page, silent);
389 ClearPageMappedToDisk(page);
390 bh = head = page_buffers(page);
391 do {
392 lock_buffer(bh);
393 clear_buffer_dirty(bh);
394 clear_buffer_nilfs_volatile(bh);
395 clear_buffer_nilfs_checked(bh);
396 clear_buffer_nilfs_redirected(bh);
397 clear_buffer_uptodate(bh);
398 clear_buffer_mapped(bh);
399 unlock_buffer(bh);
400 bh = bh->b_this_page;
401 } while (bh != head);
402
403 __nilfs_clear_page_dirty(page);
404 unlock_page(page); 393 unlock_page(page);
405 } 394 }
406 pagevec_release(&pvec); 395 pagevec_release(&pvec);
@@ -408,6 +397,51 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
408 } 397 }
409} 398}
410 399
400/**
401 * nilfs_clear_dirty_page - discard dirty page
402 * @page: dirty page that will be discarded
403 * @silent: suppress [true] or print [false] warning messages
404 */
405void nilfs_clear_dirty_page(struct page *page, bool silent)
406{
407 struct inode *inode = page->mapping->host;
408 struct super_block *sb = inode->i_sb;
409
410 BUG_ON(!test_bit(PG_locked, &page->flags));
411
412 if (!silent) {
413 nilfs_warning(sb, __func__,
414 "discard page: offset %lld, ino %lu",
415 page_offset(page), inode->i_ino);
416 }
417
418 ClearPageUptodate(page);
419 ClearPageMappedToDisk(page);
420
421 if (page_has_buffers(page)) {
422 struct buffer_head *bh, *head;
423
424 bh = head = page_buffers(page);
425 do {
426 lock_buffer(bh);
427 if (!silent) {
428 nilfs_warning(sb, __func__,
429 "discard block %llu, size %zu",
430 (u64)bh->b_blocknr, bh->b_size);
431 }
432 clear_buffer_dirty(bh);
433 clear_buffer_nilfs_volatile(bh);
434 clear_buffer_nilfs_checked(bh);
435 clear_buffer_nilfs_redirected(bh);
436 clear_buffer_uptodate(bh);
437 clear_buffer_mapped(bh);
438 unlock_buffer(bh);
439 } while (bh = bh->b_this_page, bh != head);
440 }
441
442 __nilfs_clear_page_dirty(page);
443}
444
411unsigned nilfs_page_count_clean_buffers(struct page *page, 445unsigned nilfs_page_count_clean_buffers(struct page *page,
412 unsigned from, unsigned to) 446 unsigned from, unsigned to)
413{ 447{