diff options
author | Prasad Joshi <prasadjoshi.linux@gmail.com> | 2011-11-26 00:30:47 -0500 |
---|---|---|
committer | Prasad Joshi <prasadjoshi.linux@gmail.com> | 2012-01-28 00:53:10 -0500 |
commit | 96150606e2fb82d242c9e4a414e4e922849f7bf7 (patch) | |
tree | efdb8a85b5838aa13e6c233ebec580c1f956be5d /fs/logfs/readwrite.c | |
parent | f423fc627b05f47bc9305f9661630fce30f208f9 (diff) |
logfs: update page reference count for pined pages
LogFS sets PG_private flag to indicate a pined page. We assumed that
marking a page as private is enough to ensure its existence. But
instead it is necessary to hold a reference count to the page.
The change resolves the following BUG
BUG: Bad page state in process flush-253:16 pfn:6a6d0
page flags: 0x100000000000808(uptodate|private)
Suggested-and-Acked-by: Joern Engel <joern@logfs.org>
Signed-off-by: Prasad Joshi <prasadjoshi.linux@gmail.com>
Diffstat (limited to 'fs/logfs/readwrite.c')
-rw-r--r-- | fs/logfs/readwrite.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 2ac4217b7901..6d663e8ea6da 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c | |||
@@ -560,8 +560,13 @@ static void inode_free_block(struct super_block *sb, struct logfs_block *block) | |||
560 | static void indirect_free_block(struct super_block *sb, | 560 | static void indirect_free_block(struct super_block *sb, |
561 | struct logfs_block *block) | 561 | struct logfs_block *block) |
562 | { | 562 | { |
563 | ClearPagePrivate(block->page); | 563 | struct page *page = block->page; |
564 | block->page->private = 0; | 564 | |
565 | if (PagePrivate(page)) { | ||
566 | ClearPagePrivate(page); | ||
567 | page_cache_release(page); | ||
568 | set_page_private(page, 0); | ||
569 | } | ||
565 | __free_block(sb, block); | 570 | __free_block(sb, block); |
566 | } | 571 | } |
567 | 572 | ||
@@ -650,8 +655,11 @@ static void alloc_data_block(struct inode *inode, struct page *page) | |||
650 | logfs_unpack_index(page->index, &bix, &level); | 655 | logfs_unpack_index(page->index, &bix, &level); |
651 | block = __alloc_block(inode->i_sb, inode->i_ino, bix, level); | 656 | block = __alloc_block(inode->i_sb, inode->i_ino, bix, level); |
652 | block->page = page; | 657 | block->page = page; |
658 | |||
653 | SetPagePrivate(page); | 659 | SetPagePrivate(page); |
654 | page->private = (unsigned long)block; | 660 | page_cache_get(page); |
661 | set_page_private(page, (unsigned long) block); | ||
662 | |||
655 | block->ops = &indirect_block_ops; | 663 | block->ops = &indirect_block_ops; |
656 | } | 664 | } |
657 | 665 | ||
@@ -1901,8 +1909,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page) | |||
1901 | li->li_block = block; | 1909 | li->li_block = block; |
1902 | 1910 | ||
1903 | block->page = NULL; | 1911 | block->page = NULL; |
1904 | page->private = 0; | 1912 | if (PagePrivate(page)) { |
1905 | ClearPagePrivate(page); | 1913 | ClearPagePrivate(page); |
1914 | page_cache_release(page); | ||
1915 | set_page_private(page, 0); | ||
1916 | } | ||
1906 | } | 1917 | } |
1907 | 1918 | ||
1908 | static void move_inode_to_page(struct page *page, struct inode *inode) | 1919 | static void move_inode_to_page(struct page *page, struct inode *inode) |
@@ -1918,8 +1929,12 @@ static void move_inode_to_page(struct page *page, struct inode *inode) | |||
1918 | BUG_ON(PagePrivate(page)); | 1929 | BUG_ON(PagePrivate(page)); |
1919 | block->ops = &indirect_block_ops; | 1930 | block->ops = &indirect_block_ops; |
1920 | block->page = page; | 1931 | block->page = page; |
1921 | page->private = (unsigned long)block; | 1932 | |
1922 | SetPagePrivate(page); | 1933 | if (!PagePrivate(page)) { |
1934 | SetPagePrivate(page); | ||
1935 | page_cache_get(page); | ||
1936 | set_page_private(page, (unsigned long) block); | ||
1937 | } | ||
1923 | 1938 | ||
1924 | block->inode = NULL; | 1939 | block->inode = NULL; |
1925 | li->li_block = NULL; | 1940 | li->li_block = NULL; |