提交 c555772c 编写于 作者: M Matthew Wilcox 提交者: Greg Kroah-Hartman

dax: Don't access a freed inode

commit 55e56f06ed71d9441f3abd5b1d3c1a870812b3fe upstream.

After we drop the i_pages lock, the inode can be freed at any time.
The get_unlocked_entry() code has no choice but to reacquire the lock,
so it can't be used here.  Create a new wait_entry_unlocked() which takes
care not to acquire the lock or dereference the address_space in any way.

Fixes: c2a7d2a1 ("filesystem-dax: Introduce dax_lock_mapping_entry()")
Cc: <stable@vger.kernel.org>
Signed-off-by: NMatthew Wilcox <willy@infradead.org>
Reviewed-by: NJan Kara <jack@suse.cz>
Signed-off-by: NDan Williams <dan.j.williams@intel.com>
Signed-off-by: NSasha Levin <sashal@kernel.org>
上级 a9935a12
......@@ -229,8 +229,8 @@ static void put_unlocked_mapping_entry(struct address_space *mapping,
*
* Must be called with the i_pages lock held.
*/
static void *__get_unlocked_mapping_entry(struct address_space *mapping,
pgoff_t index, void ***slotp, bool (*wait_fn)(void))
static void *get_unlocked_mapping_entry(struct address_space *mapping,
pgoff_t index, void ***slotp)
{
void *entry, **slot;
struct wait_exceptional_entry_queue ewait;
......@@ -240,8 +240,6 @@ static void *__get_unlocked_mapping_entry(struct address_space *mapping,
ewait.wait.func = wake_exceptional_entry_func;
for (;;) {
bool revalidate;
entry = __radix_tree_lookup(&mapping->i_pages, index, NULL,
&slot);
if (!entry ||
......@@ -256,30 +254,39 @@ static void *__get_unlocked_mapping_entry(struct address_space *mapping,
prepare_to_wait_exclusive(wq, &ewait.wait,
TASK_UNINTERRUPTIBLE);
xa_unlock_irq(&mapping->i_pages);
revalidate = wait_fn();
schedule();
finish_wait(wq, &ewait.wait);
xa_lock_irq(&mapping->i_pages);
if (revalidate) {
put_unlocked_mapping_entry(mapping, index, entry);
return ERR_PTR(-EAGAIN);
}
}
}
static bool entry_wait(void)
/*
* The only thing keeping the address space around is the i_pages lock
* (it's cycled in clear_inode() after removing the entries from i_pages)
* After we call xas_unlock_irq(), we cannot touch xas->xa.
*/
static void wait_entry_unlocked(struct address_space *mapping, pgoff_t index,
void ***slotp, void *entry)
{
struct wait_exceptional_entry_queue ewait;
wait_queue_head_t *wq;
init_wait(&ewait.wait);
ewait.wait.func = wake_exceptional_entry_func;
wq = dax_entry_waitqueue(mapping, index, entry, &ewait.key);
prepare_to_wait_exclusive(wq, &ewait.wait, TASK_UNINTERRUPTIBLE);
xa_unlock_irq(&mapping->i_pages);
schedule();
finish_wait(wq, &ewait.wait);
/*
* Never return an ERR_PTR() from
* __get_unlocked_mapping_entry(), just keep looping.
* Entry lock waits are exclusive. Wake up the next waiter since
* we aren't sure we will acquire the entry lock and thus wake
* the next waiter up on unlock.
*/
return false;
}
static void *get_unlocked_mapping_entry(struct address_space *mapping,
pgoff_t index, void ***slotp)
{
return __get_unlocked_mapping_entry(mapping, index, slotp, entry_wait);
if (waitqueue_active(wq))
__wake_up(wq, TASK_NORMAL, 1, &ewait.key);
}
static void unlock_mapping_entry(struct address_space *mapping, pgoff_t index)
......@@ -398,19 +405,6 @@ static struct page *dax_busy_page(void *entry)
return NULL;
}
static bool entry_wait_revalidate(void)
{
rcu_read_unlock();
schedule();
rcu_read_lock();
/*
* Tell __get_unlocked_mapping_entry() to take a break, we need
* to revalidate page->mapping after dropping locks
*/
return true;
}
bool dax_lock_mapping_entry(struct page *page)
{
pgoff_t index;
......@@ -446,14 +440,15 @@ bool dax_lock_mapping_entry(struct page *page)
}
index = page->index;
entry = __get_unlocked_mapping_entry(mapping, index, &slot,
entry_wait_revalidate);
entry = __radix_tree_lookup(&mapping->i_pages, index,
NULL, &slot);
if (!entry) {
xa_unlock_irq(&mapping->i_pages);
break;
} else if (IS_ERR(entry)) {
xa_unlock_irq(&mapping->i_pages);
WARN_ON_ONCE(PTR_ERR(entry) != -EAGAIN);
} else if (slot_locked(mapping, slot)) {
rcu_read_unlock();
wait_entry_unlocked(mapping, index, &slot, entry);
rcu_read_lock();
continue;
}
lock_slot(mapping, slot);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册