Commit 96150606 authored by Prasad Joshi's avatar Prasad Joshi

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: default avatarJoern Engel <joern@logfs.org>
Signed-off-by: default avatarPrasad Joshi <prasadjoshi.linux@gmail.com>
parent f423fc62
...@@ -560,8 +560,13 @@ static void inode_free_block(struct super_block *sb, struct logfs_block *block) ...@@ -560,8 +560,13 @@ static void inode_free_block(struct super_block *sb, struct logfs_block *block)
static void indirect_free_block(struct super_block *sb, static void indirect_free_block(struct super_block *sb,
struct logfs_block *block) struct logfs_block *block)
{ {
ClearPagePrivate(block->page); struct page *page = block->page;
block->page->private = 0;
if (PagePrivate(page)) {
ClearPagePrivate(page);
page_cache_release(page);
set_page_private(page, 0);
}
__free_block(sb, block); __free_block(sb, block);
} }
...@@ -650,8 +655,11 @@ static void alloc_data_block(struct inode *inode, struct page *page) ...@@ -650,8 +655,11 @@ static void alloc_data_block(struct inode *inode, struct page *page)
logfs_unpack_index(page->index, &bix, &level); logfs_unpack_index(page->index, &bix, &level);
block = __alloc_block(inode->i_sb, inode->i_ino, bix, level); block = __alloc_block(inode->i_sb, inode->i_ino, bix, level);
block->page = page; block->page = page;
SetPagePrivate(page); SetPagePrivate(page);
page->private = (unsigned long)block; page_cache_get(page);
set_page_private(page, (unsigned long) block);
block->ops = &indirect_block_ops; block->ops = &indirect_block_ops;
} }
...@@ -1901,8 +1909,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page) ...@@ -1901,8 +1909,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page)
li->li_block = block; li->li_block = block;
block->page = NULL; block->page = NULL;
page->private = 0; if (PagePrivate(page)) {
ClearPagePrivate(page); ClearPagePrivate(page);
page_cache_release(page);
set_page_private(page, 0);
}
} }
static void move_inode_to_page(struct page *page, struct inode *inode) 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,8 +1929,12 @@ static void move_inode_to_page(struct page *page, struct inode *inode)
BUG_ON(PagePrivate(page)); BUG_ON(PagePrivate(page));
block->ops = &indirect_block_ops; block->ops = &indirect_block_ops;
block->page = page; block->page = page;
page->private = (unsigned long)block;
SetPagePrivate(page); if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
set_page_private(page, (unsigned long) block);
}
block->inode = NULL; block->inode = NULL;
li->li_block = NULL; li->li_block = NULL;
......
...@@ -86,7 +86,11 @@ int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, ...@@ -86,7 +86,11 @@ int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len,
BUG_ON(!page); /* FIXME: reserve a pool */ BUG_ON(!page); /* FIXME: reserve a pool */
SetPageUptodate(page); SetPageUptodate(page);
memcpy(page_address(page) + offset, buf, copylen); memcpy(page_address(page) + offset, buf, copylen);
SetPagePrivate(page);
if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page); page_cache_release(page);
buf += copylen; buf += copylen;
...@@ -110,7 +114,10 @@ static void pad_partial_page(struct logfs_area *area) ...@@ -110,7 +114,10 @@ static void pad_partial_page(struct logfs_area *area)
page = get_mapping_page(sb, index, 0); page = get_mapping_page(sb, index, 0);
BUG_ON(!page); /* FIXME: reserve a pool */ BUG_ON(!page); /* FIXME: reserve a pool */
memset(page_address(page) + offset, 0xff, len); memset(page_address(page) + offset, 0xff, len);
SetPagePrivate(page); if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page); page_cache_release(page);
} }
} }
...@@ -130,7 +137,10 @@ static void pad_full_pages(struct logfs_area *area) ...@@ -130,7 +137,10 @@ static void pad_full_pages(struct logfs_area *area)
BUG_ON(!page); /* FIXME: reserve a pool */ BUG_ON(!page); /* FIXME: reserve a pool */
SetPageUptodate(page); SetPageUptodate(page);
memset(page_address(page), 0xff, PAGE_CACHE_SIZE); memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
SetPagePrivate(page); if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page); page_cache_release(page);
index++; index++;
no_indizes--; no_indizes--;
...@@ -485,8 +495,12 @@ static void move_btree_to_page(struct inode *inode, struct page *page, ...@@ -485,8 +495,12 @@ static void move_btree_to_page(struct inode *inode, struct page *page,
mempool_free(item, super->s_alias_pool); mempool_free(item, super->s_alias_pool);
} }
block->page = page; block->page = page;
SetPagePrivate(page);
page->private = (unsigned long)block; if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
set_page_private(page, (unsigned long) block);
}
block->ops = &indirect_block_ops; block->ops = &indirect_block_ops;
initialize_block_counters(page, block, data, 0); initialize_block_counters(page, block, data, 0);
} }
...@@ -536,8 +550,12 @@ void move_page_to_btree(struct page *page) ...@@ -536,8 +550,12 @@ void move_page_to_btree(struct page *page)
list_add(&item->list, &block->item_list); list_add(&item->list, &block->item_list);
} }
block->page = NULL; block->page = NULL;
ClearPagePrivate(page);
page->private = 0; if (PagePrivate(page)) {
ClearPagePrivate(page);
page_cache_release(page);
set_page_private(page, 0);
}
block->ops = &btree_block_ops; block->ops = &btree_block_ops;
err = alias_tree_insert(block->sb, block->ino, block->bix, block->level, err = alias_tree_insert(block->sb, block->ino, block->bix, block->level,
block); block);
...@@ -702,7 +720,10 @@ void freeseg(struct super_block *sb, u32 segno) ...@@ -702,7 +720,10 @@ void freeseg(struct super_block *sb, u32 segno)
page = find_get_page(mapping, ofs >> PAGE_SHIFT); page = find_get_page(mapping, ofs >> PAGE_SHIFT);
if (!page) if (!page)
continue; continue;
ClearPagePrivate(page); if (PagePrivate(page)) {
ClearPagePrivate(page);
page_cache_release(page);
}
page_cache_release(page); page_cache_release(page);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment