Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: drivers: base: Support atomic version of attribute_container_device_trigger

attribute_container_device_trigger invokes callbacks that may fail for one
or more classdevs, for instance, the transport_add_class_device callback,
called during transport creation, does memory allocation. This
information, though, is not propagated to upper layers, and any driver
using the attribute_container_device_trigger API will not know whether any,
some, or all callbacks succeeded.

This patch implements a safe version of this dispatcher, to either succeed
all the callbacks or revert to the original state.

Link: https://lore.kernel.org/r/20200106185817.640331-2-krisman@collabora.com
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Gabriel Krisman Bertazi and committed by
Martin K. Petersen
7c1ef338 54155ed4

+110
+103
drivers/base/attribute_container.c
··· 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 *
+7
include/linux/attribute_container.h
··· 54 54 int (*fn)(struct attribute_container *, 55 55 struct device *, 56 56 struct device *)); 57 + int attribute_container_device_trigger_safe(struct device *dev, 58 + int (*fn)(struct attribute_container *, 59 + struct device *, 60 + struct device *), 61 + int (*undo)(struct attribute_container *, 62 + struct device *, 63 + struct device *)); 57 64 void attribute_container_trigger(struct device *dev, 58 65 int (*fn)(struct attribute_container *, 59 66 struct device *));