.. | .. |
---|
236 | 236 | mutex_unlock(&attribute_container_mutex); |
---|
237 | 237 | } |
---|
238 | 238 | |
---|
| 239 | +static int |
---|
| 240 | +do_attribute_container_device_trigger_safe(struct device *dev, |
---|
| 241 | + struct attribute_container *cont, |
---|
| 242 | + int (*fn)(struct attribute_container *, |
---|
| 243 | + struct device *, struct device *), |
---|
| 244 | + int (*undo)(struct attribute_container *, |
---|
| 245 | + struct device *, struct device *)) |
---|
| 246 | +{ |
---|
| 247 | + int ret; |
---|
| 248 | + struct internal_container *ic, *failed; |
---|
| 249 | + struct klist_iter iter; |
---|
| 250 | + |
---|
| 251 | + if (attribute_container_no_classdevs(cont)) |
---|
| 252 | + return fn(cont, dev, NULL); |
---|
| 253 | + |
---|
| 254 | + klist_for_each_entry(ic, &cont->containers, node, &iter) { |
---|
| 255 | + if (dev == ic->classdev.parent) { |
---|
| 256 | + ret = fn(cont, dev, &ic->classdev); |
---|
| 257 | + if (ret) { |
---|
| 258 | + failed = ic; |
---|
| 259 | + klist_iter_exit(&iter); |
---|
| 260 | + goto fail; |
---|
| 261 | + } |
---|
| 262 | + } |
---|
| 263 | + } |
---|
| 264 | + return 0; |
---|
| 265 | + |
---|
| 266 | +fail: |
---|
| 267 | + if (!undo) |
---|
| 268 | + return ret; |
---|
| 269 | + |
---|
| 270 | + /* Attempt to undo the work partially done. */ |
---|
| 271 | + klist_for_each_entry(ic, &cont->containers, node, &iter) { |
---|
| 272 | + if (ic == failed) { |
---|
| 273 | + klist_iter_exit(&iter); |
---|
| 274 | + break; |
---|
| 275 | + } |
---|
| 276 | + if (dev == ic->classdev.parent) |
---|
| 277 | + undo(cont, dev, &ic->classdev); |
---|
| 278 | + } |
---|
| 279 | + return ret; |
---|
| 280 | +} |
---|
| 281 | + |
---|
| 282 | +/** |
---|
| 283 | + * attribute_container_device_trigger_safe - execute a trigger for each |
---|
| 284 | + * matching classdev or fail all of them. |
---|
| 285 | + * |
---|
| 286 | + * @dev: The generic device to run the trigger for |
---|
| 287 | + * @fn the function to execute for each classdev. |
---|
| 288 | + * @undo A function to undo the work previously done in case of error |
---|
| 289 | + * |
---|
| 290 | + * This function is a safe version of |
---|
| 291 | + * attribute_container_device_trigger. It stops on the first error and |
---|
| 292 | + * undo the partial work that has been done, on previous classdev. It |
---|
| 293 | + * is guaranteed that either they all succeeded, or none of them |
---|
| 294 | + * succeeded. |
---|
| 295 | + */ |
---|
| 296 | +int |
---|
| 297 | +attribute_container_device_trigger_safe(struct device *dev, |
---|
| 298 | + int (*fn)(struct attribute_container *, |
---|
| 299 | + struct device *, |
---|
| 300 | + struct device *), |
---|
| 301 | + int (*undo)(struct attribute_container *, |
---|
| 302 | + struct device *, |
---|
| 303 | + struct device *)) |
---|
| 304 | +{ |
---|
| 305 | + struct attribute_container *cont, *failed = NULL; |
---|
| 306 | + int ret = 0; |
---|
| 307 | + |
---|
| 308 | + mutex_lock(&attribute_container_mutex); |
---|
| 309 | + |
---|
| 310 | + list_for_each_entry(cont, &attribute_container_list, node) { |
---|
| 311 | + |
---|
| 312 | + if (!cont->match(cont, dev)) |
---|
| 313 | + continue; |
---|
| 314 | + |
---|
| 315 | + ret = do_attribute_container_device_trigger_safe(dev, cont, |
---|
| 316 | + fn, undo); |
---|
| 317 | + if (ret) { |
---|
| 318 | + failed = cont; |
---|
| 319 | + break; |
---|
| 320 | + } |
---|
| 321 | + } |
---|
| 322 | + |
---|
| 323 | + if (ret && !WARN_ON(!undo)) { |
---|
| 324 | + list_for_each_entry(cont, &attribute_container_list, node) { |
---|
| 325 | + |
---|
| 326 | + if (failed == cont) |
---|
| 327 | + break; |
---|
| 328 | + |
---|
| 329 | + if (!cont->match(cont, dev)) |
---|
| 330 | + continue; |
---|
| 331 | + |
---|
| 332 | + do_attribute_container_device_trigger_safe(dev, cont, |
---|
| 333 | + undo, NULL); |
---|
| 334 | + } |
---|
| 335 | + } |
---|
| 336 | + |
---|
| 337 | + mutex_unlock(&attribute_container_mutex); |
---|
| 338 | + return ret; |
---|
| 339 | + |
---|
| 340 | +} |
---|
| 341 | + |
---|
239 | 342 | /** |
---|
240 | 343 | * attribute_container_device_trigger - execute a trigger for each matching classdev |
---|
241 | 344 | * |
---|