]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.14.57/rbd-don-t-leak-parent_spec-in-rbd_dev_probe_parent.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.14.57 / rbd-don-t-leak-parent_spec-in-rbd_dev_probe_parent.patch
CommitLineData
b75945de
GKH
1From 1f2c6651f69c14d0d3a9cfbda44ea101b02160ba Mon Sep 17 00:00:00 2001
2From: Ilya Dryomov <idryomov@gmail.com>
3Date: Sun, 11 Oct 2015 19:38:00 +0200
4Subject: rbd: don't leak parent_spec in rbd_dev_probe_parent()
5
6From: Ilya Dryomov <idryomov@gmail.com>
7
8commit 1f2c6651f69c14d0d3a9cfbda44ea101b02160ba upstream.
9
10Currently we leak parent_spec and trigger a "parent reference
11underflow" warning if rbd_dev_create() in rbd_dev_probe_parent() fails.
12The problem is we take the !parent out_err branch and that only drops
13refcounts; parent_spec that would've been freed had we called
14rbd_dev_unparent() remains and triggers rbd_warn() in
15rbd_dev_parent_put() - at that point we have parent_spec != NULL and
16parent_ref == 0, so counter ends up being -1 after the decrement.
17
18Redo rbd_dev_probe_parent() to fix this.
19
20Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
21[idryomov@gmail.com: backport to < 4.2: rbd_dev->opts]
22Reviewed-by: Alex Elder <elder@linaro.org>
23Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
24
25---
26 drivers/block/rbd.c | 35 +++++++++++++++--------------------
27 1 file changed, 15 insertions(+), 20 deletions(-)
28
29--- a/drivers/block/rbd.c
30+++ b/drivers/block/rbd.c
31@@ -4825,41 +4825,36 @@ out_err:
32 static int rbd_dev_probe_parent(struct rbd_device *rbd_dev)
33 {
34 struct rbd_device *parent = NULL;
35- struct rbd_spec *parent_spec;
36- struct rbd_client *rbdc;
37 int ret;
38
39 if (!rbd_dev->parent_spec)
40 return 0;
41- /*
42- * We need to pass a reference to the client and the parent
43- * spec when creating the parent rbd_dev. Images related by
44- * parent/child relationships always share both.
45- */
46- parent_spec = rbd_spec_get(rbd_dev->parent_spec);
47- rbdc = __rbd_get_client(rbd_dev->rbd_client);
48
49- ret = -ENOMEM;
50- parent = rbd_dev_create(rbdc, parent_spec);
51- if (!parent)
52+ parent = rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
53+ if (!parent) {
54+ ret = -ENOMEM;
55 goto out_err;
56+ }
57+
58+ /*
59+ * Images related by parent/child relationships always share
60+ * rbd_client and spec/parent_spec, so bump their refcounts.
61+ */
62+ __rbd_get_client(rbd_dev->rbd_client);
63+ rbd_spec_get(rbd_dev->parent_spec);
64
65 ret = rbd_dev_image_probe(parent, false);
66 if (ret < 0)
67 goto out_err;
68+
69 rbd_dev->parent = parent;
70 atomic_set(&rbd_dev->parent_ref, 1);
71-
72 return 0;
73+
74 out_err:
75- if (parent) {
76- rbd_dev_unparent(rbd_dev);
77+ rbd_dev_unparent(rbd_dev);
78+ if (parent)
79 rbd_dev_destroy(parent);
80- } else {
81- rbd_put_client(rbdc);
82- rbd_spec_put(parent_spec);
83- }
84-
85 return ret;
86 }
87