diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 8e58c4cc2cb96519359e45d66acd34191972786f..84f20e932499354123c1547b7303bf5627e46d1c 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1052,10 +1052,7 @@ static int f2fs_write_end(struct file *file, trace_f2fs_write_end(inode, pos, len, copied); - if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) - register_inmem_page(inode, page); - else - set_page_dirty(page); + set_page_dirty(page); if (pos + copied > i_size_read(inode)) { i_size_write(inode, pos + copied); @@ -1138,6 +1135,12 @@ static int f2fs_set_data_page_dirty(struct page *page) trace_f2fs_set_page_dirty(page, DATA); SetPageUptodate(page); + + if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) { + register_inmem_page(inode, page); + return 1; + } + mark_inode_dirty(inode); if (!PageDirty(page)) { diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8171e80b2ee9f9709c953b4264ea92bee01011c6..28f24ea13cb2204342eac9b7d07205028882f015 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -269,6 +269,7 @@ struct f2fs_inode_info { struct extent_info ext; /* in-memory extent cache entry */ struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */ + struct radix_tree_root inmem_root; /* radix tree for inmem pages */ struct list_head inmem_pages; /* inmemory pages managed by f2fs */ struct mutex inmem_lock; /* lock for inmemory pages */ }; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 923cb76fdc46e1e9f26b3a5014690e5c58d59fd0..9d4a7ab33b06ba203d19f89091f21312ccbdc092 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -178,7 +178,8 @@ void register_inmem_page(struct inode *inode, struct page *page) { struct f2fs_inode_info *fi = F2FS_I(inode); struct inmem_pages *new; - + int err; +retry: new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); /* add atomic page indices to the list */ @@ -187,6 +188,16 @@ void register_inmem_page(struct inode *inode, struct page *page) /* increase reference count with clean state */ mutex_lock(&fi->inmem_lock); + err = radix_tree_insert(&fi->inmem_root, page->index, new); + if (err == -EEXIST) { + mutex_unlock(&fi->inmem_lock); + kmem_cache_free(inmem_entry_slab, new); + return; + } else if (err) { + mutex_unlock(&fi->inmem_lock); + kmem_cache_free(inmem_entry_slab, new); + goto retry; + } get_page(page); list_add_tail(&new->list, &fi->inmem_pages); mutex_unlock(&fi->inmem_lock); @@ -216,6 +227,7 @@ void commit_inmem_pages(struct inode *inode, bool abort) do_write_data_page(cur->page, &fio); submit_bio = true; } + radix_tree_delete(&fi->inmem_root, cur->page->index); f2fs_put_page(cur->page, 1); list_del(&cur->list); kmem_cache_free(inmem_entry_slab, cur); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 41d6f700f4ee66fc1f3c0f297187a8ef9d4cab11..76b14c8c7e166154d781d6041054eccd11f1c343 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -373,6 +373,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) fi->i_advise = 0; rwlock_init(&fi->ext.ext_lock); init_rwsem(&fi->i_sem); + INIT_RADIX_TREE(&fi->inmem_root, GFP_NOFS); INIT_LIST_HEAD(&fi->inmem_pages); mutex_init(&fi->inmem_lock);