[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