* [4.19-stable PATCH 1/2] dax: Don't access a freed inode
2019-01-05 19:45 [4.19-stable PATCH 0/2] dax: Don't access a freed inode Dan Williams
@ 2019-01-05 19:45 ` Dan Williams
2019-01-05 19:45 ` [4.19-stable PATCH 2/2] dax: Use non-exclusive wait in wait_entry_unlocked() Dan Williams
2019-01-06 17:45 ` [4.19-stable PATCH 0/2] dax: Don't access a freed inode Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Dan Williams @ 2019-01-05 19:45 UTC (permalink / raw)
To: stable; +Cc: Matthew Wilcox, Jan Kara, sashal, gregkh, linux-kernel
From: Matthew Wilcox <willy@infradead.org>
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: c2a7d2a11552 ("filesystem-dax: Introduce dax_lock_mapping_entry()")
Cc: <stable@vger.kernel.org>
Signed-off-by: Matthew Wilcox <willy@infradead.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
fs/dax.c | 69 +++++++++++++++++++++++++++++---------------------------------
1 file changed, 32 insertions(+), 37 deletions(-)
diff --git a/fs/dax.c b/fs/dax.c
index 3a2682a6c832..415605fafaeb 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -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);
^ permalink raw reply related [flat|nested] 4+ messages in thread* [4.19-stable PATCH 2/2] dax: Use non-exclusive wait in wait_entry_unlocked()
2019-01-05 19:45 [4.19-stable PATCH 0/2] dax: Don't access a freed inode Dan Williams
2019-01-05 19:45 ` [4.19-stable PATCH 1/2] " Dan Williams
@ 2019-01-05 19:45 ` Dan Williams
2019-01-06 17:45 ` [4.19-stable PATCH 0/2] dax: Don't access a freed inode Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Dan Williams @ 2019-01-05 19:45 UTC (permalink / raw)
To: stable
Cc: Matthew Wilcox, Linus Torvalds, Jan Kara, sashal, gregkh,
linux-kernel
commit d8a706414af4827fc0b4b1c0c631c607351938b9 upstream.
get_unlocked_entry() uses an exclusive wait because it is guaranteed to
eventually obtain the lock and follow on with an unlock+wakeup cycle.
The wait_entry_unlocked() path does not have the same guarantee. Rather
than open-code an extra wakeup, just switch to a non-exclusive wait.
Cc: Matthew Wilcox <willy@infradead.org>
Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
fs/dax.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/fs/dax.c b/fs/dax.c
index 415605fafaeb..09fa70683c41 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -275,18 +275,16 @@ static void wait_entry_unlocked(struct address_space *mapping, pgoff_t index,
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);
+ /*
+ * Unlike get_unlocked_entry() there is no guarantee that this
+ * path ever successfully retrieves an unlocked entry before an
+ * inode dies. Perform a non-exclusive wait in case this path
+ * never successfully performs its own wake up.
+ */
+ prepare_to_wait(wq, &ewait.wait, TASK_UNINTERRUPTIBLE);
xa_unlock_irq(&mapping->i_pages);
schedule();
finish_wait(wq, &ewait.wait);
-
- /*
- * 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.
- */
- if (waitqueue_active(wq))
- __wake_up(wq, TASK_NORMAL, 1, &ewait.key);
}
static void unlock_mapping_entry(struct address_space *mapping, pgoff_t index)
^ permalink raw reply related [flat|nested] 4+ messages in thread