FAILED: patch "[PATCH] device property: Make modifications of fwnode "flags" thread" failed to apply to 6.12-stable tree
Subsystems (10)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x f72e77c33e4b5657af35125e75bab249256030f3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026042714-catcher-manly-e588@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f72e77c33e4b5657af35125e75bab249256030f3 Mon Sep 17 00:00:00 2001
From: Douglas Anderson <[email protected]>
Date: Tue, 17 Mar 2026 09:01:20 -0700
Subject: [PATCH] device property: Make modifications of fwnode "flags" thread
safe
In various places in the kernel, we modify the fwnode "flags" member by doing either:
fwnode->flags |= SOME_FLAG;
fwnode->flags &= ~SOME_FLAG;
This type of modification is not thread-safe. If two threads are both mucking with the flags at the same time then one can clobber the other.
While flags are often modified while under the "fwnode_link_lock", this is not universally true.
Create some accessor functions for setting, clearing, and testing the FWNODE flags and move all users to these accessor functions. New accessor functions use set_bit() and clear_bit(), which are thread-safe.
[ Fix fwnode_clear_flag() argument alignment, restore dropped blank
line in fwnode_dev_initialized(), and remove unnecessary parentheses around fwnode_test_flag() calls. - Danilo ]
drivers/base/core.c +12 -12
@@ -182,7 +182,7 @@ void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode)if (fwnode->dev)return ; - fwnode->flags |=FWNODE_FLAG_NOT_DEVICE ; +fwnode_set_flag (fwnode,FWNODE_FLAG_NOT_DEVICE );fwnode_links_purge_consumers (fwnode);fwnode_for_each_available_child_node (fwnode, child)
@@ -228,7 +228,7 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode,if (fwnode->dev && fwnode->dev->bus)return ; - fwnode->flags |=FWNODE_FLAG_NOT_DEVICE ; +fwnode_set_flag (fwnode,FWNODE_FLAG_NOT_DEVICE );__fwnode_links_move_consumers (fwnode, new_sup);fwnode_for_each_available_child_node (fwnode, child)
@@ -1012,7 +1012,7 @@ static void device_links_missing_supplier(struct device *dev)static bool dev_is_best_effort (struct device *dev) {return (fw_devlink_best_effort && dev->can_match) || - (dev->fwnode && (dev->fwnode->flags &FWNODE_FLAG_BEST_EFFORT )); + (dev->fwnode &&fwnode_test_flag (dev->fwnode,FWNODE_FLAG_BEST_EFFORT )); } static struct fwnode_handle *fwnode_links_check_suppliers(
@@ -1723,11 +1723,11 @@ bool fw_devlink_is_strict(void)static void fw_devlink_parse_fwnode (struct fwnode_handle *fwnode) { -if (fwnode->flags &FWNODE_FLAG_LINKS_ADDED ) +if (fwnode_test_flag (fwnode,FWNODE_FLAG_LINKS_ADDED ))return ;fwnode_call_int_op (fwnode, add_links); - fwnode->flags |=FWNODE_FLAG_LINKS_ADDED ; +fwnode_set_flag (fwnode,FWNODE_FLAG_LINKS_ADDED ); }static void fw_devlink_parse_fwtree (struct fwnode_handle *fwnode)
@@ -1885,7 +1885,7 @@ static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)struct device *dev;bool ret; -if (!(fwnode->flags &FWNODE_FLAG_INITIALIZED )) +if (!fwnode_test_flag (fwnode,FWNODE_FLAG_INITIALIZED ))return false; dev =get_dev_from_fwnode (fwnode);
@@ -2001,10 +2001,10 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,* We aren't trying to find all cycles. Just a cycle between con and * sup_handle. */ -if (sup_handle->flags &FWNODE_FLAG_VISITED ) +if (fwnode_test_flag (sup_handle,FWNODE_FLAG_VISITED ))return false; - sup_handle->flags |=FWNODE_FLAG_VISITED ; +fwnode_set_flag (sup_handle,FWNODE_FLAG_VISITED );/* Termination condition. */ if (sup_handle == con_handle) {
@@ -2074,7 +2074,7 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle, } out: - sup_handle->flags &= ~FWNODE_FLAG_VISITED ; +fwnode_clear_flag (sup_handle,FWNODE_FLAG_VISITED );put_device (sup_dev);put_device (con_dev);put_device (par_dev);
@@ -2127,7 +2127,7 @@ static int fw_devlink_create_devlink(struct device *con,* When such a flag is set, we can't create device links where P is the * supplier of C as that would delay the probe of C. */ -if (sup_handle->flags &FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD && +if (fwnode_test_flag (sup_handle,FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD ) &&fwnode_is_ancestor_of (sup_handle, con->fwnode))return -EINVAL ;
@@ -2150,7 +2150,7 @@ static int fw_devlink_create_devlink(struct device *con,else flags =FW_DEVLINK_FLAGS_PERMISSIVE ; -if (sup_handle->flags &FWNODE_FLAG_NOT_DEVICE ) +if (fwnode_test_flag (sup_handle,FWNODE_FLAG_NOT_DEVICE )) sup_dev =fwnode_get_next_parent_dev (sup_handle);else sup_dev =get_dev_from_fwnode (sup_handle);
@@ -2162,7 +2162,7 @@ static int fw_devlink_create_devlink(struct device *con,* supplier device indefinitely. */ if (sup_dev->links.status ==DL_DEV_NO_DRIVER && - sup_handle->flags &FWNODE_FLAG_INITIALIZED ) { +fwnode_test_flag (sup_handle,FWNODE_FLAG_INITIALIZED )) {dev_dbg (con,"Not linking %pfwf - dev might never probe\n" , sup_handle);
drivers/bus/imx-weim.c +1 -1
@@ -332,7 +332,7 @@ static int of_weim_notify(struct notifier_block *nb, unsigned long action,* fw_devlink doesn't skip adding consumers to this * device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE );if (!of_platform_device_create (rd->dn,NULL , &pdev->dev)) { dev_err(&pdev->dev, "Failed to create child device '%pOF'\n",
drivers/i2c/i2c-core-of.c +1 -1
@@ -180,7 +180,7 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,* Clear the flag before adding the device so that fw_devlink * doesn't skip adding consumers to this device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE ); client =of_i2c_register_device (adap, rd->dn);if (IS_ERR (client)) { dev_err(&adap->dev, "failed to create client for '%pOF'\n",
drivers/net/phy/mdio_bus_provider.c +2 -2
@@ -294,8 +294,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)return -EINVAL ;if (bus->parent && bus->parent->of_node) - bus->parent->of_node->fwnode.flags |= -FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD ; +fwnode_set_flag (&bus->parent->of_node->fwnode, +FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD ); WARN(bus->state != MDIOBUS_ALLOCATED && bus->state != MDIOBUS_UNREGISTERED,
drivers/of/base.c +1 -1
@@ -1943,7 +1943,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))if (name) of_stdout =of_find_node_opts_by_path (name, &of_stdout_options);if (of_stdout) - of_stdout->fwnode.flags |=FWNODE_FLAG_BEST_EFFORT ; +fwnode_set_flag (&of_stdout->fwnode,FWNODE_FLAG_BEST_EFFORT ); }if (!of_aliases)
drivers/of/dynamic.c +1 -1
@@ -225,7 +225,7 @@ static void __of_attach_node(struct device_node *np) np->sibling = np->parent->child; np->parent->child = np;of_node_clear_flag (np,OF_DETACHED ); - np->fwnode.flags |=FWNODE_FLAG_NOT_DEVICE ; +fwnode_set_flag (&np->fwnode,FWNODE_FLAG_NOT_DEVICE );raw_spin_unlock_irqrestore (&devtree_lock, flags);
drivers/of/platform.c +1 -1
@@ -742,7 +742,7 @@ static int of_platform_notify(struct notifier_block *nb,* Clear the flag before adding the device so that fw_devlink * doesn't skip adding consumers to this device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE );/* pdev_parent may be NULL when no bus platform device */ pdev_parent =of_find_device_by_node (parent); pdev = of_platform_device_create(rd->dn, NULL,
drivers/spi/spi.c +1 -1
@@ -4937,7 +4937,7 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,* Clear the flag before adding the device so that fw_devlink * doesn't skip adding consumers to this device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE ); spi =of_register_spi_device (ctlr, rd->dn);put_device (&ctlr->dev);
include/linux/fwnode.h +33 -11
74 lines not on this page · raw message
PATCH 1/1 device property: Make modifications of fwnode "flags" thread safe
In various places in the kernel, we modify the fwnode "flags" member by doing either:
fwnode->flags |= SOME_FLAG;
fwnode->flags &= ~SOME_FLAG;
This type of modification is not thread-safe. If two threads are both mucking with the flags at the same time then one can clobber the other.
While flags are often modified while under the "fwnode_link_lock", this is not universally true.
Create some accessor functions for setting, clearing, and testing the FWNODE flags and move all users to these accessor functions. New accessor functions use set_bit() and clear_bit(), which are thread-safe.
[ Fix fwnode_clear_flag() argument alignment, restore dropped blank
line in fwnode_dev_initialized(), and remove unnecessary parentheses around fwnode_test_flag() calls. - Danilo ]
--- drivers/base/core.c | 24 ++++++++++----------- drivers/bus/imx-weim.c | 2 +- drivers/i2c/i2c-core-of.c | 2 +- drivers/net/phy/mdio_bus.c | 4 ++-- drivers/of/base.c | 2 +- drivers/of/dynamic.c | 2 +- drivers/of/platform.c | 2 +- drivers/spi/spi.c | 2 +- include/linux/fwnode.h | 44 ++++++++++++++++++++++++++++---------- 9 files changed, 53 insertions(+), 31 deletions(-)
drivers/base/core.c +12 -12
@@ -182,7 +182,7 @@ void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode)if (fwnode->dev)return ; - fwnode->flags |=FWNODE_FLAG_NOT_DEVICE ; +fwnode_set_flag (fwnode,FWNODE_FLAG_NOT_DEVICE );fwnode_links_purge_consumers (fwnode);fwnode_for_each_available_child_node (fwnode, child)
@@ -228,7 +228,7 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode,if (fwnode->dev && fwnode->dev->bus)return ; - fwnode->flags |=FWNODE_FLAG_NOT_DEVICE ; +fwnode_set_flag (fwnode,FWNODE_FLAG_NOT_DEVICE );__fwnode_links_move_consumers (fwnode, new_sup);fwnode_for_each_available_child_node (fwnode, child)
@@ -1013,7 +1013,7 @@ static void device_links_missing_supplier(struct device *dev)static bool dev_is_best_effort (struct device *dev) {return (fw_devlink_best_effort && dev->can_match) || - (dev->fwnode && (dev->fwnode->flags &FWNODE_FLAG_BEST_EFFORT )); + (dev->fwnode &&fwnode_test_flag (dev->fwnode,FWNODE_FLAG_BEST_EFFORT )); } static struct fwnode_handle *fwnode_links_check_suppliers(
@@ -1724,11 +1724,11 @@ bool fw_devlink_is_strict(void)static void fw_devlink_parse_fwnode (struct fwnode_handle *fwnode) { -if (fwnode->flags &FWNODE_FLAG_LINKS_ADDED ) +if (fwnode_test_flag (fwnode,FWNODE_FLAG_LINKS_ADDED ))return ;fwnode_call_int_op (fwnode, add_links); - fwnode->flags |=FWNODE_FLAG_LINKS_ADDED ; +fwnode_set_flag (fwnode,FWNODE_FLAG_LINKS_ADDED ); }static void fw_devlink_parse_fwtree (struct fwnode_handle *fwnode)
@@ -1888,7 +1888,7 @@ static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)struct device *dev;bool ret; -if (!(fwnode->flags &FWNODE_FLAG_INITIALIZED )) +if (!fwnode_test_flag (fwnode,FWNODE_FLAG_INITIALIZED ))return false; dev =get_dev_from_fwnode (fwnode);
@@ -2004,10 +2004,10 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle,* We aren't trying to find all cycles. Just a cycle between con and * sup_handle. */ -if (sup_handle->flags &FWNODE_FLAG_VISITED ) +if (fwnode_test_flag (sup_handle,FWNODE_FLAG_VISITED ))return false; - sup_handle->flags |=FWNODE_FLAG_VISITED ; +fwnode_set_flag (sup_handle,FWNODE_FLAG_VISITED );/* Termination condition. */ if (sup_handle == con_handle) {
@@ -2077,7 +2077,7 @@ static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle, } out: - sup_handle->flags &= ~FWNODE_FLAG_VISITED ; +fwnode_clear_flag (sup_handle,FWNODE_FLAG_VISITED );put_device (sup_dev);put_device (con_dev);put_device (par_dev);
@@ -2130,7 +2130,7 @@ static int fw_devlink_create_devlink(struct device *con,* When such a flag is set, we can't create device links where P is the * supplier of C as that would delay the probe of C. */ -if (sup_handle->flags &FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD && +if (fwnode_test_flag (sup_handle,FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD ) &&fwnode_is_ancestor_of (sup_handle, con->fwnode))return -EINVAL ;
@@ -2153,7 +2153,7 @@ static int fw_devlink_create_devlink(struct device *con,else flags =FW_DEVLINK_FLAGS_PERMISSIVE ; -if (sup_handle->flags &FWNODE_FLAG_NOT_DEVICE ) +if (fwnode_test_flag (sup_handle,FWNODE_FLAG_NOT_DEVICE )) sup_dev =fwnode_get_next_parent_dev (sup_handle);else sup_dev =get_dev_from_fwnode (sup_handle);
@@ -2165,7 +2165,7 @@ static int fw_devlink_create_devlink(struct device *con,* supplier device indefinitely. */ if (sup_dev->links.status ==DL_DEV_NO_DRIVER && - sup_handle->flags &FWNODE_FLAG_INITIALIZED ) { +fwnode_test_flag (sup_handle,FWNODE_FLAG_INITIALIZED )) {dev_dbg (con,"Not linking %pfwf - dev might never probe\n" , sup_handle);
drivers/bus/imx-weim.c +1 -1
@@ -332,7 +332,7 @@ static int of_weim_notify(struct notifier_block *nb, unsigned long action,* fw_devlink doesn't skip adding consumers to this * device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE );if (!of_platform_device_create (rd->dn,NULL , &pdev->dev)) { dev_err(&pdev->dev, "Failed to create child device '%pOF'\n",
drivers/i2c/i2c-core-of.c +1 -1
@@ -182,7 +182,7 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,* Clear the flag before adding the device so that fw_devlink * doesn't skip adding consumers to this device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE ); client =of_i2c_register_device (adap, rd->dn);if (IS_ERR (client)) { dev_err(&adap->dev, "failed to create client for '%pOF'\n",
drivers/net/phy/mdio_bus.c +2 -2
@@ -705,8 +705,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)return -EINVAL ;if (bus->parent && bus->parent->of_node) - bus->parent->of_node->fwnode.flags |= -FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD ; +fwnode_set_flag (&bus->parent->of_node->fwnode, +FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD ); WARN(bus->state != MDIOBUS_ALLOCATED && bus->state != MDIOBUS_UNREGISTERED,
drivers/of/base.c +1 -1
@@ -1793,7 +1793,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))if (name) of_stdout =of_find_node_opts_by_path (name, &of_stdout_options);if (of_stdout) - of_stdout->fwnode.flags |=FWNODE_FLAG_BEST_EFFORT ; +fwnode_set_flag (&of_stdout->fwnode,FWNODE_FLAG_BEST_EFFORT ); }if (!of_aliases)
drivers/of/dynamic.c +1 -1
@@ -225,7 +225,7 @@ static void __of_attach_node(struct device_node *np) np->sibling = np->parent->child; np->parent->child = np;of_node_clear_flag (np,OF_DETACHED ); - np->fwnode.flags |=FWNODE_FLAG_NOT_DEVICE ; +fwnode_set_flag (&np->fwnode,FWNODE_FLAG_NOT_DEVICE );raw_spin_unlock_irqrestore (&devtree_lock, flags);
drivers/of/platform.c +1 -1
@@ -744,7 +744,7 @@ static int of_platform_notify(struct notifier_block *nb,* Clear the flag before adding the device so that fw_devlink * doesn't skip adding consumers to this device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE );/* pdev_parent may be NULL when no bus platform device */ pdev_parent =of_find_device_by_node (parent); pdev = of_platform_device_create(rd->dn, NULL,
drivers/spi/spi.c +1 -1
@@ -4811,7 +4811,7 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,* Clear the flag before adding the device so that fw_devlink * doesn't skip adding consumers to this device. */ - rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE ; +fwnode_clear_flag (&rd->dn->fwnode,FWNODE_FLAG_NOT_DEVICE ); spi =of_register_spi_device (ctlr, rd->dn);put_device (&ctlr->dev);
include/linux/fwnode.h +33 -11
74 lines not on this page · raw message
Signature · 1 line
2.54.0.545.g6539524ca2-goog
Hi,
Quoted 7 lines · On Mon, Apr 27, 2026 at 9:40 AM <[email protected]> wrote:
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Quoted 8 lines
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkoutFETCH_HEAD
git cherry-pick -xf72e77c33e4b5657af35125e75bab249256030f3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026042714-catcher-manly-e588@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
OK, these should be sent out all the way down to 5.15. In each case, I didn't boot test but did confirm that "allmodconfig" passes across a number of architectures and also did code inspection.
If anyone happens to be reviewing, the 5.15 is the one that had the most major changes when backporting since a lot of the code touching these flags wasn't there yet or looked slightly different.
-Doug