diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2014-05-14 15:34:47 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2014-07-10 12:35:10 -0400 |
commit | a8ba0d606933c34c13ea971491a7e0dfa50208ef (patch) | |
tree | ec5e37875f545b76e4d4b7c447881f6bbf01f0f5 | |
parent | c2258ffc56f2b34573c2917937190c1491620334 (diff) |
drbd: fix drbd_destroy_device reference count updates
drbd_destroy_device means to give up reference counts
on the connection(s) reachable via the peer_device(s).
It must not do that by iterating via device->resource->connections,
resource and connections may have already been disassociated
by drbd_free_resource, and we'd leak connection refs.
Instead, iterate via device->peer_devices->connection.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 92547d16b2c7..56cf11b60cb8 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -2160,7 +2160,7 @@ void drbd_destroy_device(struct kref *kref) | |||
2160 | { | 2160 | { |
2161 | struct drbd_device *device = container_of(kref, struct drbd_device, kref); | 2161 | struct drbd_device *device = container_of(kref, struct drbd_device, kref); |
2162 | struct drbd_resource *resource = device->resource; | 2162 | struct drbd_resource *resource = device->resource; |
2163 | struct drbd_connection *connection; | 2163 | struct drbd_peer_device *peer_device, *tmp_peer_device; |
2164 | 2164 | ||
2165 | del_timer_sync(&device->request_timer); | 2165 | del_timer_sync(&device->request_timer); |
2166 | 2166 | ||
@@ -2191,12 +2191,16 @@ void drbd_destroy_device(struct kref *kref) | |||
2191 | put_disk(device->vdisk); | 2191 | put_disk(device->vdisk); |
2192 | blk_cleanup_queue(device->rq_queue); | 2192 | blk_cleanup_queue(device->rq_queue); |
2193 | kfree(device->rs_plan_s); | 2193 | kfree(device->rs_plan_s); |
2194 | kfree(first_peer_device(device)); | 2194 | |
2195 | /* not for_each_connection(connection, resource): | ||
2196 | * those may have been cleaned up and disassociated already. | ||
2197 | */ | ||
2198 | for_each_peer_device_safe(peer_device, tmp_peer_device, device) { | ||
2199 | kref_put(&peer_device->connection->kref, drbd_destroy_connection); | ||
2200 | kfree(peer_device); | ||
2201 | } | ||
2195 | memset(device, 0xfd, sizeof(*device)); | 2202 | memset(device, 0xfd, sizeof(*device)); |
2196 | kfree(device); | 2203 | kfree(device); |
2197 | |||
2198 | for_each_connection(connection, resource) | ||
2199 | kref_put(&connection->kref, drbd_destroy_connection); | ||
2200 | kref_put(&resource->kref, drbd_destroy_resource); | 2204 | kref_put(&resource->kref, drbd_destroy_resource); |
2201 | } | 2205 | } |
2202 | 2206 | ||