mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
mm + fs: store shadow entries in page cache
Reclaim will be leaving shadow entries in the page cache radix tree upon evicting the real page. As those pages are found from the LRU, an iput() can lead to the inode being freed concurrently. At this point, reclaim must no longer install shadow pages because the inode freeing code needs to ensure the page tree is really empty. Add an address_space flag, AS_EXITING, that the inode freeing code sets under the tree lock before doing the final truncate. Reclaim will check for this flag before installing shadow pages. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Reviewed-by: Rik van Riel <riel@redhat.com> Reviewed-by: Minchan Kim <minchan@kernel.org> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Bob Liu <bob.liu@oracle.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Dave Chinner <david@fromorbit.com> Cc: Greg Thelen <gthelen@google.com> Cc: Hugh Dickins <hughd@google.com> Cc: Jan Kara <jack@suse.cz> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Luigi Semenzato <semenzato@google.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Metin Doslu <metin@citusdata.com> Cc: Michel Lespinasse <walken@google.com> Cc: Ozgun Erdogan <ozgun@citusdata.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Roman Gushchin <klamm@yandex-team.ru> Cc: Ryan Mallon <rmallon@gmail.com> Cc: Tejun Heo <tj@kernel.org> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
0cd6144aad
commit
91b0abe36a
@@ -295,9 +295,9 @@ in the beginning of ->setattr unconditionally.
|
||||
->clear_inode() and ->delete_inode() are gone; ->evict_inode() should
|
||||
be used instead. It gets called whenever the inode is evicted, whether it has
|
||||
remaining links or not. Caller does *not* evict the pagecache or inode-associated
|
||||
metadata buffers; getting rid of those is responsibility of method, as it had
|
||||
been for ->delete_inode(). Caller makes sure async writeback cannot be running
|
||||
for the inode while (or after) ->evict_inode() is called.
|
||||
metadata buffers; the method has to use truncate_inode_pages_final() to get rid
|
||||
of those. Caller makes sure async writeback cannot be running for the inode while
|
||||
(or after) ->evict_inode() is called.
|
||||
|
||||
->drop_inode() returns int now; it's called on final iput() with
|
||||
inode->i_lock held and it returns true if filesystems wants the inode to be
|
||||
|
||||
@@ -1877,7 +1877,7 @@ void ll_delete_inode(struct inode *inode)
|
||||
cl_sync_file_range(inode, 0, OBD_OBJECT_EOF,
|
||||
CL_FSYNC_DISCARD, 1);
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
/* Workaround for LU-118 */
|
||||
if (inode->i_data.nrpages) {
|
||||
|
||||
+1
-1
@@ -451,7 +451,7 @@ void v9fs_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct v9fs_inode *v9inode = V9FS_I(inode);
|
||||
|
||||
truncate_inode_pages(inode->i_mapping, 0);
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
clear_inode(inode);
|
||||
filemap_fdatawrite(inode->i_mapping);
|
||||
|
||||
|
||||
+1
-1
@@ -259,7 +259,7 @@ affs_evict_inode(struct inode *inode)
|
||||
{
|
||||
unsigned long cache_page;
|
||||
pr_debug("AFFS: evict_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
if (!inode->i_nlink) {
|
||||
inode->i_size = 0;
|
||||
|
||||
+1
-1
@@ -422,7 +422,7 @@ void afs_evict_inode(struct inode *inode)
|
||||
|
||||
ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
|
||||
afs_give_up_callback(vnode);
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@ static void bfs_evict_inode(struct inode *inode)
|
||||
|
||||
dprintf("ino=%08lx\n", ino);
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
invalidate_inode_buffers(inode);
|
||||
clear_inode(inode);
|
||||
|
||||
|
||||
+2
-2
@@ -83,7 +83,7 @@ void kill_bdev(struct block_device *bdev)
|
||||
{
|
||||
struct address_space *mapping = bdev->bd_inode->i_mapping;
|
||||
|
||||
if (mapping->nrpages == 0)
|
||||
if (mapping->nrpages == 0 && mapping->nrshadows == 0)
|
||||
return;
|
||||
|
||||
invalidate_bh_lrus();
|
||||
@@ -419,7 +419,7 @@ static void bdev_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct block_device *bdev = &BDEV_I(inode)->bdev;
|
||||
struct list_head *p;
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
invalidate_inode_buffers(inode); /* is it needed here? */
|
||||
clear_inode(inode);
|
||||
spin_lock(&bdev_lock);
|
||||
|
||||
+1
-1
@@ -4593,7 +4593,7 @@ static void evict_inode_truncate_pages(struct inode *inode)
|
||||
struct rb_node *node;
|
||||
|
||||
ASSERT(inode->i_state & I_FREEING);
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
write_lock(&map_tree->lock);
|
||||
while (!RB_EMPTY_ROOT(&map_tree->map)) {
|
||||
|
||||
+1
-1
@@ -286,7 +286,7 @@ cifs_destroy_inode(struct inode *inode)
|
||||
static void
|
||||
cifs_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
cifs_fscache_release_inode_cookie(inode);
|
||||
}
|
||||
|
||||
+1
-1
@@ -250,7 +250,7 @@ static void coda_put_super(struct super_block *sb)
|
||||
|
||||
static void coda_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
coda_cache_clear_inode(inode);
|
||||
}
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
*/
|
||||
static void ecryptfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
iput(ecryptfs_inode_to_lower(inode));
|
||||
}
|
||||
|
||||
+1
-1
@@ -1486,7 +1486,7 @@ void exofs_evict_inode(struct inode *inode)
|
||||
struct ore_io_state *ios;
|
||||
int ret;
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
/* TODO: should do better here */
|
||||
if (inode->i_nlink || is_bad_inode(inode))
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ void ext2_evict_inode(struct inode * inode)
|
||||
dquot_drop(inode);
|
||||
}
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
if (want_delete) {
|
||||
sb_start_intwrite(inode->i_sb);
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ void ext3_evict_inode (struct inode *inode)
|
||||
log_wait_commit(journal, commit_tid);
|
||||
filemap_write_and_wait(&inode->i_data);
|
||||
}
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
ext3_discard_reservation(inode);
|
||||
rsv = ei->i_block_alloc_info;
|
||||
|
||||
+2
-2
@@ -215,7 +215,7 @@ void ext4_evict_inode(struct inode *inode)
|
||||
jbd2_complete_transaction(journal, commit_tid);
|
||||
filemap_write_and_wait(&inode->i_data);
|
||||
}
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
WARN_ON(atomic_read(&EXT4_I(inode)->i_ioend_count));
|
||||
goto no_delete;
|
||||
@@ -226,7 +226,7 @@ void ext4_evict_inode(struct inode *inode)
|
||||
|
||||
if (ext4_should_order_data(inode))
|
||||
ext4_begin_ordered_truncate(inode, 0);
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
WARN_ON(atomic_read(&EXT4_I(inode)->i_ioend_count));
|
||||
if (is_bad_inode(inode))
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
|
||||
trace_f2fs_evict_inode(inode);
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
if (inode->i_ino == F2FS_NODE_INO(sbi) ||
|
||||
inode->i_ino == F2FS_META_INO(sbi))
|
||||
|
||||
+1
-1
@@ -490,7 +490,7 @@ EXPORT_SYMBOL_GPL(fat_build_inode);
|
||||
|
||||
static void fat_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
if (!inode->i_nlink) {
|
||||
inode->i_size = 0;
|
||||
fat_truncate_blocks(inode, 0);
|
||||
|
||||
@@ -354,7 +354,7 @@ static void vxfs_i_callback(struct rcu_head *head)
|
||||
void
|
||||
vxfs_evict_inode(struct inode *ip)
|
||||
{
|
||||
truncate_inode_pages(&ip->i_data, 0);
|
||||
truncate_inode_pages_final(&ip->i_data);
|
||||
clear_inode(ip);
|
||||
call_rcu(&ip->i_rcu, vxfs_i_callback);
|
||||
}
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ static void fuse_destroy_inode(struct inode *inode)
|
||||
|
||||
static void fuse_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
if (inode->i_sb->s_flags & MS_ACTIVE) {
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
|
||||
+1
-1
@@ -1558,7 +1558,7 @@ out_unlock:
|
||||
fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
|
||||
out:
|
||||
/* Case 3 starts here */
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
gfs2_rs_delete(ip, NULL);
|
||||
gfs2_ordered_del_inode(ip);
|
||||
clear_inode(inode);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user