| .. | .. |
|---|
| 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 | * |
|---|