afs: Fix missing lock when replacing VL server list
authorDavid Howells <dhowells@redhat.com>
Tue, 7 May 2019 14:16:26 +0000 (15:16 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 15 May 2019 16:35:53 +0000 (17:35 +0100)
When afs_update_cell() replaces the cell->vl_servers list, it uses RCU
protocol so that proc is protected, but doesn't take ->vl_servers_lock to
protect afs_start_vl_iteration() (which does actually take a shared lock).

Fix this by making afs_update_cell() take an exclusive lock when replacing
->vl_servers.

Fixes: 0a5143f2f89c ("afs: Implement VL server rotation")
Signed-off-by: David Howells <dhowells@redhat.com>
fs/afs/cell.c

index 9de46116c7492a712ede0c8a241eea71ef94230b..9ca075e112393e12055e45c41c49c2435f35207a 100644 (file)
@@ -404,12 +404,11 @@ static void afs_update_cell(struct afs_cell *cell)
                clear_bit(AFS_CELL_FL_DNS_FAIL, &cell->flags);
                clear_bit(AFS_CELL_FL_NOT_FOUND, &cell->flags);
 
-               /* Exclusion on changing vl_addrs is achieved by a
-                * non-reentrant work item.
-                */
+               write_lock(&cell->vl_servers_lock);
                old = rcu_dereference_protected(cell->vl_servers, true);
                rcu_assign_pointer(cell->vl_servers, vllist);
                cell->dns_expiry = expiry;
+               write_unlock(&cell->vl_servers_lock);
 
                if (old)
                        afs_put_vlserverlist(cell->net, old);