From f4952688ebe4447ce9e8b98068fd9f42d26c6baf Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 27 Jun 2011 16:18:10 -0700 Subject: [PATCH] --- yaml --- r: 254107 b: refs/heads/master c: 08142579b6ca35883c1ed066a2681de6f6917062 h: refs/heads/master i: 254105: b964aa17fdcbb23073e109554a6db44ddfbda8f0 254103: 0039840dabdb856805b4dd5c9a38341fb97662bf v: v3 --- [refs] | 2 +- trunk/fs/inode.c | 7 +++++++ trunk/include/linux/fs.h | 1 + trunk/mm/truncate.c | 5 +++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index d0d6f009e57a..f09281b0a936 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9b679320a5fbf46454011e5c62e0b8991b0956d1 +refs/heads/master: 08142579b6ca35883c1ed066a2681de6f6917062 diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index 0f7e88a7803f..43566d17d1b8 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -423,7 +423,14 @@ EXPORT_SYMBOL(remove_inode_hash); void end_writeback(struct inode *inode) { might_sleep(); + /* + * We have to cycle tree_lock here because reclaim can be still in the + * process of removing the last page (in __delete_from_page_cache()) + * and we must not free mapping under it. + */ + spin_lock_irq(&inode->i_data.tree_lock); BUG_ON(inode->i_data.nrpages); + spin_unlock_irq(&inode->i_data.tree_lock); BUG_ON(!list_empty(&inode->i_data.private_list)); BUG_ON(!(inode->i_state & I_FREEING)); BUG_ON(inode->i_state & I_CLEAR); diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index 6e73e2e9ae33..b5b979247863 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -639,6 +639,7 @@ struct address_space { struct prio_tree_root i_mmap; /* tree of private and shared mappings */ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ struct mutex i_mmap_mutex; /* protect tree, count, list */ + /* Protected by tree_lock together with the radix tree */ unsigned long nrpages; /* number of total pages */ pgoff_t writeback_index;/* writeback starts here */ const struct address_space_operations *a_ops; /* methods */ diff --git a/trunk/mm/truncate.c b/trunk/mm/truncate.c index 29a9b8a5a31a..e13f22efaad7 100644 --- a/trunk/mm/truncate.c +++ b/trunk/mm/truncate.c @@ -304,6 +304,11 @@ EXPORT_SYMBOL(truncate_inode_pages_range); * @lstart: offset from which to truncate * * Called under (and serialised by) inode->i_mutex. + * + * Note: When this function returns, there can be a page in the process of + * deletion (inside __delete_from_page_cache()) in the specified range. Thus + * mapping->nrpages can be non-zero when this function returns even after + * truncation of the whole mapping. */ void truncate_inode_pages(struct address_space *mapping, loff_t lstart) {