aboutsummaryrefslogtreecommitdiffstats
path: root/fs/logfs
diff options
context:
space:
mode:
authorPrasad Joshi <prasadjoshi.linux@gmail.com>2011-11-26 00:30:47 -0500
committerPrasad Joshi <prasadjoshi.linux@gmail.com>2012-01-28 00:53:10 -0500
commit96150606e2fb82d242c9e4a414e4e922849f7bf7 (patch)
treeefdb8a85b5838aa13e6c233ebec580c1f956be5d /fs/logfs
parentf423fc627b05f47bc9305f9661630fce30f208f9 (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')
-rw-r--r--fs/logfs/readwrite.c29
-rw-r--r--fs/logfs/segment.c37
2 files changed, 51 insertions, 15 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)
560static void indirect_free_block(struct super_block *sb, 560static 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
1908static void move_inode_to_page(struct page *page, struct inode *inode) 1919static 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;
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c
index 9d5187353255..6aee6092860d 100644
--- a/fs/logfs/segment.c
+++ b/fs/logfs/segment.c
@@ -86,7 +86,11 @@ int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len,
86 BUG_ON(!page); /* FIXME: reserve a pool */ 86 BUG_ON(!page); /* FIXME: reserve a pool */
87 SetPageUptodate(page); 87 SetPageUptodate(page);
88 memcpy(page_address(page) + offset, buf, copylen); 88 memcpy(page_address(page) + offset, buf, copylen);
89 SetPagePrivate(page); 89
90 if (!PagePrivate(page)) {
91 SetPagePrivate(page);
92 page_cache_get(page);
93 }
90 page_cache_release(page); 94 page_cache_release(page);
91 95
92 buf += copylen; 96 buf += copylen;
@@ -110,7 +114,10 @@ static void pad_partial_page(struct logfs_area *area)
110 page = get_mapping_page(sb, index, 0); 114 page = get_mapping_page(sb, index, 0);
111 BUG_ON(!page); /* FIXME: reserve a pool */ 115 BUG_ON(!page); /* FIXME: reserve a pool */
112 memset(page_address(page) + offset, 0xff, len); 116 memset(page_address(page) + offset, 0xff, len);
113 SetPagePrivate(page); 117 if (!PagePrivate(page)) {
118 SetPagePrivate(page);
119 page_cache_get(page);
120 }
114 page_cache_release(page); 121 page_cache_release(page);
115 } 122 }
116} 123}
@@ -130,7 +137,10 @@ static void pad_full_pages(struct logfs_area *area)
130 BUG_ON(!page); /* FIXME: reserve a pool */ 137 BUG_ON(!page); /* FIXME: reserve a pool */
131 SetPageUptodate(page); 138 SetPageUptodate(page);
132 memset(page_address(page), 0xff, PAGE_CACHE_SIZE); 139 memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
133 SetPagePrivate(page); 140 if (!PagePrivate(page)) {
141 SetPagePrivate(page);
142 page_cache_get(page);
143 }
134 page_cache_release(page); 144 page_cache_release(page);
135 index++; 145 index++;
136 no_indizes--; 146 no_indizes--;
@@ -485,8 +495,12 @@ static void move_btree_to_page(struct inode *inode, struct page *page,
485 mempool_free(item, super->s_alias_pool); 495 mempool_free(item, super->s_alias_pool);
486 } 496 }
487 block->page = page; 497 block->page = page;
488 SetPagePrivate(page); 498
489 page->private = (unsigned long)block; 499 if (!PagePrivate(page)) {
500 SetPagePrivate(page);
501 page_cache_get(page);
502 set_page_private(page, (unsigned long) block);
503 }
490 block->ops = &indirect_block_ops; 504 block->ops = &indirect_block_ops;
491 initialize_block_counters(page, block, data, 0); 505 initialize_block_counters(page, block, data, 0);
492} 506}
@@ -536,8 +550,12 @@ void move_page_to_btree(struct page *page)
536 list_add(&item->list, &block->item_list); 550 list_add(&item->list, &block->item_list);
537 } 551 }
538 block->page = NULL; 552 block->page = NULL;
539 ClearPagePrivate(page); 553
540 page->private = 0; 554 if (PagePrivate(page)) {
555 ClearPagePrivate(page);
556 page_cache_release(page);
557 set_page_private(page, 0);
558 }
541 block->ops = &btree_block_ops; 559 block->ops = &btree_block_ops;
542 err = alias_tree_insert(block->sb, block->ino, block->bix, block->level, 560 err = alias_tree_insert(block->sb, block->ino, block->bix, block->level,
543 block); 561 block);
@@ -702,7 +720,10 @@ void freeseg(struct super_block *sb, u32 segno)
702 page = find_get_page(mapping, ofs >> PAGE_SHIFT); 720 page = find_get_page(mapping, ofs >> PAGE_SHIFT);
703 if (!page) 721 if (!page)
704 continue; 722 continue;
705 ClearPagePrivate(page); 723 if (PagePrivate(page)) {
724 ClearPagePrivate(page);
725 page_cache_release(page);
726 }
706 page_cache_release(page); 727 page_cache_release(page);
707 } 728 }
708} 729}