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

fpga: bridge: add owner module and take its refcount

The current implementation of the fpga bridge assumes that the low-level
module registers a driver for the parent device and uses its owner pointer
to take the module's refcount. This approach is problematic since it can
lead to a null pointer dereference while attempting to get the bridge if
the parent device does not have a driver.

To address this problem, add a module owner pointer to the fpga_bridge
struct and use it to take the module's refcount. Modify the function for
registering a bridge to take an additional owner module parameter and
rename it to avoid conflicts. Use the old function name for a helper macro
that automatically sets the module that registers the bridge as the owner.
This ensures compatibility with existing low-level control modules and
reduces the chances of registering a bridge without setting the owner.

Also, update the documentation to keep it consistent with the new interface
for registering an fpga bridge.

Other changes: opportunistically move put_device() from __fpga_bridge_get()
to fpga_bridge_get() and of_fpga_bridge_get() to improve code clarity since
the bridge device is taken in these functions.

Fixes: 21aeda950c5f ("fpga: add fpga bridge framework")
Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Suggested-by: Xu Yilun <yilun.xu@intel.com>
Reviewed-by: Russ Weight <russ.weight@linux.dev>
Signed-off-by: Marco Pagani <marpagan@redhat.com>
Acked-by: Xu Yilun <yilun.xu@intel.com>
Link: https://lore.kernel.org/r/20240322171839.233864-1-marpagan@redhat.com
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>

authored by

Marco Pagani and committed by
Xu Yilun
1da11f82 4d4d2d43

+43 -31
+5 -2
Documentation/driver-api/fpga/fpga-bridge.rst
··· 6 6 7 7 * struct fpga_bridge - The FPGA Bridge structure 8 8 * struct fpga_bridge_ops - Low level Bridge driver ops 9 - * fpga_bridge_register() - Create and register a bridge 9 + * __fpga_bridge_register() - Create and register a bridge 10 10 * fpga_bridge_unregister() - Unregister a bridge 11 + 12 + The helper macro ``fpga_bridge_register()`` automatically sets 13 + the module that registers the FPGA bridge as the owner. 11 14 12 15 .. kernel-doc:: include/linux/fpga/fpga-bridge.h 13 16 :functions: fpga_bridge ··· 19 16 :functions: fpga_bridge_ops 20 17 21 18 .. kernel-doc:: drivers/fpga/fpga-bridge.c 22 - :functions: fpga_bridge_register 19 + :functions: __fpga_bridge_register 23 20 24 21 .. kernel-doc:: drivers/fpga/fpga-bridge.c 25 22 :functions: fpga_bridge_unregister
+31 -26
drivers/fpga/fpga-bridge.c
··· 55 55 } 56 56 EXPORT_SYMBOL_GPL(fpga_bridge_disable); 57 57 58 - static struct fpga_bridge *__fpga_bridge_get(struct device *dev, 58 + static struct fpga_bridge *__fpga_bridge_get(struct device *bridge_dev, 59 59 struct fpga_image_info *info) 60 60 { 61 61 struct fpga_bridge *bridge; 62 - int ret = -ENODEV; 63 62 64 - bridge = to_fpga_bridge(dev); 63 + bridge = to_fpga_bridge(bridge_dev); 65 64 66 65 bridge->info = info; 67 66 68 - if (!mutex_trylock(&bridge->mutex)) { 69 - ret = -EBUSY; 70 - goto err_dev; 71 - } 67 + if (!mutex_trylock(&bridge->mutex)) 68 + return ERR_PTR(-EBUSY); 72 69 73 - if (!try_module_get(dev->parent->driver->owner)) 74 - goto err_ll_mod; 70 + if (!try_module_get(bridge->br_ops_owner)) { 71 + mutex_unlock(&bridge->mutex); 72 + return ERR_PTR(-ENODEV); 73 + } 75 74 76 75 dev_dbg(&bridge->dev, "get\n"); 77 76 78 77 return bridge; 79 - 80 - err_ll_mod: 81 - mutex_unlock(&bridge->mutex); 82 - err_dev: 83 - put_device(dev); 84 - return ERR_PTR(ret); 85 78 } 86 79 87 80 /** ··· 91 98 struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, 92 99 struct fpga_image_info *info) 93 100 { 94 - struct device *dev; 101 + struct fpga_bridge *bridge; 102 + struct device *bridge_dev; 95 103 96 - dev = class_find_device_by_of_node(&fpga_bridge_class, np); 97 - if (!dev) 104 + bridge_dev = class_find_device_by_of_node(&fpga_bridge_class, np); 105 + if (!bridge_dev) 98 106 return ERR_PTR(-ENODEV); 99 107 100 - return __fpga_bridge_get(dev, info); 108 + bridge = __fpga_bridge_get(bridge_dev, info); 109 + if (IS_ERR(bridge)) 110 + put_device(bridge_dev); 111 + 112 + return bridge; 101 113 } 102 114 EXPORT_SYMBOL_GPL(of_fpga_bridge_get); 103 115 ··· 123 125 struct fpga_bridge *fpga_bridge_get(struct device *dev, 124 126 struct fpga_image_info *info) 125 127 { 128 + struct fpga_bridge *bridge; 126 129 struct device *bridge_dev; 127 130 128 131 bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev, ··· 131 132 if (!bridge_dev) 132 133 return ERR_PTR(-ENODEV); 133 134 134 - return __fpga_bridge_get(bridge_dev, info); 135 + bridge = __fpga_bridge_get(bridge_dev, info); 136 + if (IS_ERR(bridge)) 137 + put_device(bridge_dev); 138 + 139 + return bridge; 135 140 } 136 141 EXPORT_SYMBOL_GPL(fpga_bridge_get); 137 142 ··· 149 146 dev_dbg(&bridge->dev, "put\n"); 150 147 151 148 bridge->info = NULL; 152 - module_put(bridge->dev.parent->driver->owner); 149 + module_put(bridge->br_ops_owner); 153 150 mutex_unlock(&bridge->mutex); 154 151 put_device(&bridge->dev); 155 152 } ··· 319 316 ATTRIBUTE_GROUPS(fpga_bridge); 320 317 321 318 /** 322 - * fpga_bridge_register - create and register an FPGA Bridge device 319 + * __fpga_bridge_register - create and register an FPGA Bridge device 323 320 * @parent: FPGA bridge device from pdev 324 321 * @name: FPGA bridge name 325 322 * @br_ops: pointer to structure of fpga bridge ops 326 323 * @priv: FPGA bridge private data 324 + * @owner: owner module containing the br_ops 327 325 * 328 326 * Return: struct fpga_bridge pointer or ERR_PTR() 329 327 */ 330 328 struct fpga_bridge * 331 - fpga_bridge_register(struct device *parent, const char *name, 332 - const struct fpga_bridge_ops *br_ops, 333 - void *priv) 329 + __fpga_bridge_register(struct device *parent, const char *name, 330 + const struct fpga_bridge_ops *br_ops, 331 + void *priv, struct module *owner) 334 332 { 335 333 struct fpga_bridge *bridge; 336 334 int id, ret; ··· 361 357 362 358 bridge->name = name; 363 359 bridge->br_ops = br_ops; 360 + bridge->br_ops_owner = owner; 364 361 bridge->priv = priv; 365 362 366 363 bridge->dev.groups = br_ops->groups; ··· 391 386 392 387 return ERR_PTR(ret); 393 388 } 394 - EXPORT_SYMBOL_GPL(fpga_bridge_register); 389 + EXPORT_SYMBOL_GPL(__fpga_bridge_register); 395 390 396 391 /** 397 392 * fpga_bridge_unregister - unregister an FPGA bridge
+7 -3
include/linux/fpga/fpga-bridge.h
··· 45 45 * @dev: FPGA bridge device 46 46 * @mutex: enforces exclusive reference to bridge 47 47 * @br_ops: pointer to struct of FPGA bridge ops 48 + * @br_ops_owner: module containing the br_ops 48 49 * @info: fpga image specific information 49 50 * @node: FPGA bridge list node 50 51 * @priv: low level driver private date ··· 55 54 struct device dev; 56 55 struct mutex mutex; /* for exclusive reference to bridge */ 57 56 const struct fpga_bridge_ops *br_ops; 57 + struct module *br_ops_owner; 58 58 struct fpga_image_info *info; 59 59 struct list_head node; 60 60 void *priv; ··· 81 79 struct fpga_image_info *info, 82 80 struct list_head *bridge_list); 83 81 82 + #define fpga_bridge_register(parent, name, br_ops, priv) \ 83 + __fpga_bridge_register(parent, name, br_ops, priv, THIS_MODULE) 84 84 struct fpga_bridge * 85 - fpga_bridge_register(struct device *parent, const char *name, 86 - const struct fpga_bridge_ops *br_ops, 87 - void *priv); 85 + __fpga_bridge_register(struct device *parent, const char *name, 86 + const struct fpga_bridge_ops *br_ops, void *priv, 87 + struct module *owner); 88 88 void fpga_bridge_unregister(struct fpga_bridge *br); 89 89 90 90 #endif /* _LINUX_FPGA_BRIDGE_H */