3.18-stable review patch.  If anyone has any objections, please let me know.

------------------

[ Upstream commit d29e89e34952a9ad02c77109c71a80043544296e ]

So far there was the possibility that we called
genlmsg_new(GFP_NOIO)/mutex_lock() while holding an rcu_read_lock().

This included cases like:

drbd_sync_handshake (acquire the RCU lock)
  drbd_asb_recover_1p
    drbd_khelper
      drbd_bcast_event
        genlmsg_new(GFP_NOIO) --> may sleep

drbd_sync_handshake (acquire the RCU lock)
  drbd_asb_recover_1p
    drbd_khelper
      notify_helper
        genlmsg_new(GFP_NOIO) --> may sleep

drbd_sync_handshake (acquire the RCU lock)
  drbd_asb_recover_1p
    drbd_khelper
      notify_helper
        mutex_lock --> may sleep

While using GFP_ATOMIC whould have been possible in the first two cases,
the real fix is to narrow the rcu_read_lock.

Reported-by: Jia-Ju Bai <baijiaju1...@163.com>
Reviewed-by: Lars Ellenberg <lars.ellenb...@linbit.com>
Signed-off-by: Roland Kammerer <roland.kamme...@linbit.com>
Signed-off-by: Jens Axboe <ax...@kernel.dk>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/block/drbd/drbd_receiver.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/block/drbd/drbd_receiver.c 
b/drivers/block/drbd/drbd_receiver.c
index 6960fb064731..4f18ec5198fb 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -3125,7 +3125,7 @@ static enum drbd_conns drbd_sync_handshake(struct 
drbd_peer_device *peer_device,
        enum drbd_conns rv = C_MASK;
        enum drbd_disk_state mydisk;
        struct net_conf *nc;
-       int hg, rule_nr, rr_conflict, tentative;
+       int hg, rule_nr, rr_conflict, tentative, always_asbp;
 
        mydisk = device->state.disk;
        if (mydisk == D_NEGOTIATING)
@@ -3167,8 +3167,12 @@ static enum drbd_conns drbd_sync_handshake(struct 
drbd_peer_device *peer_device,
 
        rcu_read_lock();
        nc = rcu_dereference(peer_device->connection->net_conf);
+       always_asbp = nc->always_asbp;
+       rr_conflict = nc->rr_conflict;
+       tentative = nc->tentative;
+       rcu_read_unlock();
 
-       if (hg == 100 || (hg == -100 && nc->always_asbp)) {
+       if (hg == 100 || (hg == -100 && always_asbp)) {
                int pcount = (device->state.role == R_PRIMARY)
                           + (peer_role == R_PRIMARY);
                int forced = (hg == -100);
@@ -3207,9 +3211,6 @@ static enum drbd_conns drbd_sync_handshake(struct 
drbd_peer_device *peer_device,
                             "Sync from %s node\n",
                             (hg < 0) ? "peer" : "this");
        }
-       rr_conflict = nc->rr_conflict;
-       tentative = nc->tentative;
-       rcu_read_unlock();
 
        if (hg == -100) {
                /* FIXME this log message is not correct if we end up here
-- 
2.19.1



Reply via email to