]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
drbd: narrow rcu_read_lock in drbd_sync_handshake
authorRoland Kammerer <roland.kammerer@linbit.com>
Thu, 20 Dec 2018 16:23:28 +0000 (17:23 +0100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 14 Aug 2019 09:18:49 +0000 (11:18 +0200)
BugLink: https://bugs.launchpad.net/bugs/1837664
[ 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 <baijiaju1990@163.com>
Reviewed-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Roland Kammerer <roland.kammerer@linbit.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/block/drbd/drbd_receiver.c

index cb2fa63f6bc057e7038ef3ef7ae9b7c4a2a63711..b9284a2681206b4c9fb9053c8772cd424d2b3682 100644 (file)
@@ -3361,7 +3361,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)
@@ -3412,8 +3412,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);
@@ -3452,9 +3456,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