mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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>
This commit is contained in:
parent
f423fc627b
commit
96150606e2
@ -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,
|
||||
struct logfs_block *block)
|
||||
{
|
||||
ClearPagePrivate(block->page);
|
||||
block->page->private = 0;
|
||||
struct page *page = block->page;
|
||||
|
||||
if (PagePrivate(page)) {
|
||||
ClearPagePrivate(page);
|
||||
page_cache_release(page);
|
||||
set_page_private(page, 0);
|
||||
}
|
||||
__free_block(sb, block);
|
||||
}
|
||||
|
||||
@ -650,8 +655,11 @@ static void alloc_data_block(struct inode *inode, struct page *page)
|
||||
logfs_unpack_index(page->index, &bix, &level);
|
||||
block = __alloc_block(inode->i_sb, inode->i_ino, bix, level);
|
||||
block->page = page;
|
||||
|
||||
SetPagePrivate(page);
|
||||
page->private = (unsigned long)block;
|
||||
page_cache_get(page);
|
||||
set_page_private(page, (unsigned long) block);
|
||||
|
||||
block->ops = &indirect_block_ops;
|
||||
}
|
||||
|
||||
@ -1901,8 +1909,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page)
|
||||
li->li_block = block;
|
||||
|
||||
block->page = NULL;
|
||||
page->private = 0;
|
||||
ClearPagePrivate(page);
|
||||
if (PagePrivate(page)) {
|
||||
ClearPagePrivate(page);
|
||||
page_cache_release(page);
|
||||
set_page_private(page, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
block->ops = &indirect_block_ops;
|
||||
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;
|
||||
li->li_block = NULL;
|
||||
|
@ -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 */
|
||||
SetPageUptodate(page);
|
||||
memcpy(page_address(page) + offset, buf, copylen);
|
||||
SetPagePrivate(page);
|
||||
|
||||
if (!PagePrivate(page)) {
|
||||
SetPagePrivate(page);
|
||||
page_cache_get(page);
|
||||
}
|
||||
page_cache_release(page);
|
||||
|
||||
buf += copylen;
|
||||
@ -110,7 +114,10 @@ static void pad_partial_page(struct logfs_area *area)
|
||||
page = get_mapping_page(sb, index, 0);
|
||||
BUG_ON(!page); /* FIXME: reserve a pool */
|
||||
memset(page_address(page) + offset, 0xff, len);
|
||||
SetPagePrivate(page);
|
||||
if (!PagePrivate(page)) {
|
||||
SetPagePrivate(page);
|
||||
page_cache_get(page);
|
||||
}
|
||||
page_cache_release(page);
|
||||
}
|
||||
}
|
||||
@ -130,7 +137,10 @@ static void pad_full_pages(struct logfs_area *area)
|
||||
BUG_ON(!page); /* FIXME: reserve a pool */
|
||||
SetPageUptodate(page);
|
||||
memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
|
||||
SetPagePrivate(page);
|
||||
if (!PagePrivate(page)) {
|
||||
SetPagePrivate(page);
|
||||
page_cache_get(page);
|
||||
}
|
||||
page_cache_release(page);
|
||||
index++;
|
||||
no_indizes--;
|
||||
@ -485,8 +495,12 @@ static void move_btree_to_page(struct inode *inode, struct page *page,
|
||||
mempool_free(item, super->s_alias_pool);
|
||||
}
|
||||
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;
|
||||
initialize_block_counters(page, block, data, 0);
|
||||
}
|
||||
@ -536,8 +550,12 @@ void move_page_to_btree(struct page *page)
|
||||
list_add(&item->list, &block->item_list);
|
||||
}
|
||||
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;
|
||||
err = alias_tree_insert(block->sb, block->ino, block->bix, block->level,
|
||||
block);
|
||||
@ -702,7 +720,10 @@ void freeseg(struct super_block *sb, u32 segno)
|
||||
page = find_get_page(mapping, ofs >> PAGE_SHIFT);
|
||||
if (!page)
|
||||
continue;
|
||||
ClearPagePrivate(page);
|
||||
if (PagePrivate(page)) {
|
||||
ClearPagePrivate(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
page_cache_release(page);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user