aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/segment.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-07-28 04:55:29 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-08-01 09:48:32 -0400
commita97778457f22181e8c38c4cd7d7e528378738a98 (patch)
treed2ee3d9491ab2b17551f099d9a6119407700dbd2 /fs/nilfs2/segment.c
parented680c4ad478d0fee9740f7d029087f181346564 (diff)
nilfs2: fix oops due to inconsistent state in page with discrete b-tree nodes
Andrea Gelmini gave me a report that a kernel oops hit on a nilfs filesystem with a 1KB block size when doing rsync. This turned out to be caused by an inconsistency of dirty state between a page and its buffers storing b-tree node blocks. If the page had multiple buffers split over multiple logs, and if the logs were written at a time, a dirty flag remained in the page even every dirty flag in the buffers was cleared. This will fix the failure by dropping the dirty flag properly for pages with the discrete multiple b-tree nodes. Reported-by: Andrea Gelmini <andrea.gelmini@gmail.com> Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Tested-by: Andrea Gelmini <andrea.gelmini@gmail.com> Cc: stable@kernel.org
Diffstat (limited to 'fs/nilfs2/segment.c')
-rw-r--r--fs/nilfs2/segment.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index 8b5e4778cf28..51ff3d0a4ee2 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -1859,12 +1859,26 @@ static void nilfs_end_page_io(struct page *page, int err)
1859 if (!page) 1859 if (!page)
1860 return; 1860 return;
1861 1861
1862 if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page)) 1862 if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page)) {
1863 /* 1863 /*
1864 * For b-tree node pages, this function may be called twice 1864 * For b-tree node pages, this function may be called twice
1865 * or more because they might be split in a segment. 1865 * or more because they might be split in a segment.
1866 */ 1866 */
1867 if (PageDirty(page)) {
1868 /*
1869 * For pages holding split b-tree node buffers, dirty
1870 * flag on the buffers may be cleared discretely.
1871 * In that case, the page is once redirtied for
1872 * remaining buffers, and it must be cancelled if
1873 * all the buffers get cleaned later.
1874 */
1875 lock_page(page);
1876 if (nilfs_page_buffers_clean(page))
1877 __nilfs_clear_page_dirty(page);
1878 unlock_page(page);
1879 }
1867 return; 1880 return;
1881 }
1868 1882
1869 __nilfs_end_page_io(page, err); 1883 __nilfs_end_page_io(page, err);
1870} 1884}