]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
patches for 4.19
authorSasha Levin <sashal@kernel.org>
Sun, 6 Jan 2019 17:59:59 +0000 (12:59 -0500)
committerSasha Levin <sashal@kernel.org>
Sun, 6 Jan 2019 17:59:59 +0000 (12:59 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.19/dax-don-t-access-a-freed-inode.patch [new file with mode: 0644]
queue-4.19/dax-use-non-exclusive-wait-in-wait_entry_unlocked.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/dax-don-t-access-a-freed-inode.patch b/queue-4.19/dax-don-t-access-a-freed-inode.patch
new file mode 100644 (file)
index 0000000..405e2c8
--- /dev/null
@@ -0,0 +1,145 @@
+From cd8fb60e27dab055d163177e5eb262cfac694b5f Mon Sep 17 00:00:00 2001
+From: Matthew Wilcox <willy@infradead.org>
+Date: Sat, 5 Jan 2019 11:45:08 -0800
+Subject: 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: 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>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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);
+-- 
+2.19.1
+
diff --git a/queue-4.19/dax-use-non-exclusive-wait-in-wait_entry_unlocked.patch b/queue-4.19/dax-use-non-exclusive-wait-in-wait_entry_unlocked.patch
new file mode 100644 (file)
index 0000000..0e1ea0c
--- /dev/null
@@ -0,0 +1,54 @@
+From ca92d3af8c4389636807fe386f178b2076f75d7a Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Sat, 5 Jan 2019 11:45:13 -0800
+Subject: dax: Use non-exclusive wait in wait_entry_unlocked()
+
+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>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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)
+-- 
+2.19.1
+
index 967bd0156437a8a8afcdb054cd5b1cbb9c3638f5..35311f91caa9ea612c449753abc65c6cfc57da2b 100644 (file)
@@ -133,3 +133,5 @@ brcmfmac-fix-roamoff-1-modparam.patch
 brcmfmac-fix-out-of-bounds-memory-access-during-fw-load.patch
 powerpc-tm-set-msr-just-prior-to-recheckpoint.patch
 powerpc-tm-unset-msr-if-not-recheckpointing.patch
+dax-don-t-access-a-freed-inode.patch
+dax-use-non-exclusive-wait-in-wait_entry_unlocked.patch