aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-03-18 17:40:04 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-03-18 17:40:04 -0400
commit71150d226564686ef32d15d29edfd18346f6e929 (patch)
treec591756e18763e1a935b52b7464e5d7b4a77d6ac
parent38f6b38dbb0896511c509fbb6ceabbedbee8e87d (diff)
PNP: Avoid leaving unregistered device objects in lists
pnp_register_protocol() and __pnp_add_device() both have a problem that if device_register() fails, the objects they create will be left in the lists they have been put one beforehand. Unfortunately, that is not handled by the callers of those routines either, so in case of a device registration errors the PNP bus type's data structures will end up in an inconsistent state. Make pnp_register_protocol() and __pnp_add_device() remove the objects from the lists if device registration fails. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/pnp/core.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index ef2f59c4e57c..b54620e53830 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -42,6 +42,13 @@ void *pnp_alloc(long size)
42 return result; 42 return result;
43} 43}
44 44
45static void pnp_remove_protocol(struct pnp_protocol *protocol)
46{
47 mutex_lock(&pnp_lock);
48 list_del(&protocol->protocol_list);
49 mutex_unlock(&pnp_lock);
50}
51
45/** 52/**
46 * pnp_protocol_register - adds a pnp protocol to the pnp layer 53 * pnp_protocol_register - adds a pnp protocol to the pnp layer
47 * @protocol: pointer to the corresponding pnp_protocol structure 54 * @protocol: pointer to the corresponding pnp_protocol structure
@@ -50,12 +57,13 @@ void *pnp_alloc(long size)
50 */ 57 */
51int pnp_register_protocol(struct pnp_protocol *protocol) 58int pnp_register_protocol(struct pnp_protocol *protocol)
52{ 59{
53 int nodenum;
54 struct list_head *pos; 60 struct list_head *pos;
61 int nodenum, ret;
55 62
56 INIT_LIST_HEAD(&protocol->devices); 63 INIT_LIST_HEAD(&protocol->devices);
57 INIT_LIST_HEAD(&protocol->cards); 64 INIT_LIST_HEAD(&protocol->cards);
58 nodenum = 0; 65 nodenum = 0;
66
59 mutex_lock(&pnp_lock); 67 mutex_lock(&pnp_lock);
60 68
61 /* assign the lowest unused number */ 69 /* assign the lowest unused number */
@@ -67,12 +75,18 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
67 } 75 }
68 } 76 }
69 77
78 protocol->number = nodenum;
79 dev_set_name(&protocol->dev, "pnp%d", nodenum);
80
70 list_add_tail(&protocol->protocol_list, &pnp_protocols); 81 list_add_tail(&protocol->protocol_list, &pnp_protocols);
82
71 mutex_unlock(&pnp_lock); 83 mutex_unlock(&pnp_lock);
72 84
73 protocol->number = nodenum; 85 ret = device_register(&protocol->dev);
74 dev_set_name(&protocol->dev, "pnp%d", nodenum); 86 if (ret)
75 return device_register(&protocol->dev); 87 pnp_remove_protocol(protocol);
88
89 return ret;
76} 90}
77 91
78/** 92/**
@@ -81,9 +95,7 @@ int pnp_register_protocol(struct pnp_protocol *protocol)
81 */ 95 */
82void pnp_unregister_protocol(struct pnp_protocol *protocol) 96void pnp_unregister_protocol(struct pnp_protocol *protocol)
83{ 97{
84 mutex_lock(&pnp_lock); 98 pnp_remove_protocol(protocol);
85 list_del(&protocol->protocol_list);
86 mutex_unlock(&pnp_lock);
87 device_unregister(&protocol->dev); 99 device_unregister(&protocol->dev);
88} 100}
89 101
@@ -158,18 +170,36 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id,
158 return dev; 170 return dev;
159} 171}
160 172
173static void pnp_delist_device(struct pnp_dev *dev)
174{
175 mutex_lock(&pnp_lock);
176 list_del(&dev->global_list);
177 list_del(&dev->protocol_list);
178 mutex_unlock(&pnp_lock);
179}
180
161int __pnp_add_device(struct pnp_dev *dev) 181int __pnp_add_device(struct pnp_dev *dev)
162{ 182{
183 int ret;
184
163 pnp_fixup_device(dev); 185 pnp_fixup_device(dev);
164 dev->status = PNP_READY; 186 dev->status = PNP_READY;
187
165 mutex_lock(&pnp_lock); 188 mutex_lock(&pnp_lock);
189
166 list_add_tail(&dev->global_list, &pnp_global); 190 list_add_tail(&dev->global_list, &pnp_global);
167 list_add_tail(&dev->protocol_list, &dev->protocol->devices); 191 list_add_tail(&dev->protocol_list, &dev->protocol->devices);
192
168 mutex_unlock(&pnp_lock); 193 mutex_unlock(&pnp_lock);
169 if (dev->protocol->can_wakeup) 194
195 ret = device_register(&dev->dev);
196 if (ret)
197 pnp_delist_device(dev);
198 else if (dev->protocol->can_wakeup)
170 device_set_wakeup_capable(&dev->dev, 199 device_set_wakeup_capable(&dev->dev,
171 dev->protocol->can_wakeup(dev)); 200 dev->protocol->can_wakeup(dev));
172 return device_register(&dev->dev); 201
202 return ret;
173} 203}
174 204
175/* 205/*
@@ -204,10 +234,7 @@ int pnp_add_device(struct pnp_dev *dev)
204 234
205void __pnp_remove_device(struct pnp_dev *dev) 235void __pnp_remove_device(struct pnp_dev *dev)
206{ 236{
207 mutex_lock(&pnp_lock); 237 pnp_delist_device(dev);
208 list_del(&dev->global_list);
209 list_del(&dev->protocol_list);
210 mutex_unlock(&pnp_lock);
211 device_unregister(&dev->dev); 238 device_unregister(&dev->dev);
212} 239}
213 240