[Drbd-dev] How to leak a peer_devices idr instance

David Butterfield dab21774 at gmail.com
Mon Jul 1 00:46:51 CEST 2019


I've been valgrinding the SCST/DRBD usermode server to look for bugs in my kernel function
emulation.  Once in a while it points me at a problem in DRBD.  I mentioned in a message last
week about the "resync_fifo" leak (which appears consistently in the valgrind output).

Ideally I could get a clean valgrind run, with all allocations having been freed before exit.
After deleting objects using drbdsetup and then running the server's exit handlers, it is very
close, with a couple of "usual suspects", plus whatever I discover from time to time as I try 
different operations.

Today's discovery is the ability to leak a peer_devices idr instance by a sequence of six
drbdsetup create and delete steps.  Whether or not it leaks depends on the order of the delete
steps.  After a fresh restart of the server the first sequence below leaks, but not the second.

If I delete the peer before the minor it leaks the peer_devices idr.
    sudo drbdsetup new-resource r0 0
    sudo drbdsetup new-minor r0 1 0 
    sudo drbdsetup new-peer r0 1 --_name=vagrant
    sudo drbdsetup del-peer r0 1                # delete peer first leaks peer_devices idr 
    sudo drbdsetup del-minor 1
    sudo drbdsetup del-resource r0

If I delete the minor before the peer it doesn't leak.
    sudo drbdsetup new-resource r0 0
    sudo drbdsetup new-minor r0 1 0 
    sudo drbdsetup new-peer r0 1 --_name=vagrant
    sudo drbdsetup del-minor 1                  # delete minor first doesn't leak
    sudo drbdsetup del-peer r0 1
    sudo drbdsetup del-resource r0

What appears to be happening:

    During del-minor, the peer_devices idr gets removed in drbd_unregister_device(), for each
    connection it finds.  That appears to be the only place that idr gets removed after use.

    But in the leaking sequence, the connection has already been removed by the del-peer command
    before the later del-minor command runs.  So the connection loop in drbd_unregister_device()
    (line 3935 below) iterates zero times and does not free any peer_devices idr.

    3928 void drbd_unregister_device(struct drbd_device *device)
    ... 
    3934         spin_lock_irq(&resource->req_lock);
    3935         for_each_connection(connection, resource) {
    3936                 idr_remove(&connection->peer_devices, device->vnr);
    3937         }
    3938         idr_remove(&resource->devices, device->vnr);
    3939         idr_remove(&drbd_devices, device_to_minor(device));
    3940         spin_unlock_irq(&resource->req_lock);

Regards,
David Butterfield


More information about the drbd-dev mailing list