* [PATCH net 2/4] net: add the driver-facing netdev_work scheduling API
From: Jakub Kicinski @ 2026-06-24 18:20 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, jv, sdf,
dongchenchen2, idosch, n05ec, yuantan098, kuniyu, nb,
aleksandr.loktionov, dtatulea, Jakub Kicinski
In-Reply-To: <20260624182018.2445732-1-kuba@kernel.org>
With an extra event mask we can easily extend the netdev work
to also service driver-defined events. For advanced drivers
this is probably not a perfect match, but it makes running
deferred work easier in simple cases.
Expose the netdev_work facility to drivers. Add helpers
to schedule work and a dedicated ndo to perform the driver-
-scheduled actions.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
include/linux/netdevice.h | 11 ++++++
net/core/netdev_work.c | 81 ++++++++++++++++++++++++++++++---------
2 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 732506787db3..9981d637f8b5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1131,6 +1131,9 @@ struct netdev_net_notifier {
* netdev_hw_addr_list_for_each(ha, uc). Return 0 on success or a
* negative errno to request a retry via the core backoff.
*
+ * void (*ndo_work)(struct net_device *dev, unsigned long events);
+ * Run deferred work scheduled with netdev_work_sched(@events).
+ *
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
* This function is called when the Media Access Control address
* needs to be changed. If this interface is not defined, the
@@ -1460,6 +1463,8 @@ struct net_device_ops {
struct net_device *dev,
struct netdev_hw_addr_list *uc,
struct netdev_hw_addr_list *mc);
+ void (*ndo_work)(struct net_device *dev,
+ unsigned long events);
int (*ndo_set_mac_address)(struct net_device *dev,
void *addr);
int (*ndo_validate_addr)(struct net_device *dev);
@@ -1932,6 +1937,8 @@ enum netdev_reg_state {
* does not implement ndo_set_rx_mode()
* @work_node: List entry for async netdev_work processing
* @work_tracker: Refcount tracker for async netdev_work
+ * @work_pending: Driver-defined pending netdev_work, passed to
+ * ndo_work() (see netdev_work_sched())
* @work_core_pending: Core-defined pending netdev_work (NETDEV_WORK_*)
* @rx_mode_addr_cache: Recycled snapshot entries for rx_mode work
* @rx_mode_retry_timer: Timer that re-queues rx_mode work after failure
@@ -2329,6 +2336,7 @@ struct net_device {
bool uc_promisc;
struct list_head work_node;
netdevice_tracker work_tracker;
+ unsigned long work_pending;
unsigned long work_core_pending;
struct netdev_hw_addr_list rx_mode_addr_cache;
struct timer_list rx_mode_retry_timer;
@@ -5178,6 +5186,9 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s,
const struct pcpu_sw_netstats __percpu *netstats);
void dev_get_tstats64(struct net_device *dev, struct rtnl_link_stats64 *s);
+void netdev_work_sched(struct net_device *dev, unsigned long events);
+unsigned long netdev_work_cancel(struct net_device *dev, unsigned long mask);
+
enum {
NESTED_SYNC_IMM_BIT,
NESTED_SYNC_TODO_BIT,
diff --git a/net/core/netdev_work.c b/net/core/netdev_work.c
index c121c24dc493..3109fae132ad 100644
--- a/net/core/netdev_work.c
+++ b/net/core/netdev_work.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/export.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
@@ -16,32 +17,63 @@ static void netdev_work_proc(struct work_struct *work);
* - within the list entries (struct net_device fields):
* - work_node
* - work_tracker
+ * - work_pending
* - work_core_pending
*/
static LIST_HEAD(netdev_work_list);
static DEFINE_SPINLOCK(netdev_work_lock);
static DECLARE_WORK(netdev_work, netdev_work_proc);
-void __netdev_work_core_sched(struct net_device *dev, unsigned long event)
+static void netdev_work_enqueue(struct net_device *dev, unsigned long events,
+ unsigned long core)
{
+ if (!events && !core)
+ return;
+
spin_lock_bh(&netdev_work_lock);
if (list_empty(&dev->work_node)) {
list_add_tail(&dev->work_node, &netdev_work_list);
netdev_hold(dev, &dev->work_tracker, GFP_ATOMIC);
}
- dev->work_core_pending |= event;
+ dev->work_pending |= events;
+ dev->work_core_pending |= core;
spin_unlock_bh(&netdev_work_lock);
schedule_work(&netdev_work);
}
+static unsigned long
+netdev_work_dequeue(struct net_device *dev, unsigned long *pending,
+ unsigned long mask)
+{
+ unsigned long events;
+
+ spin_lock_bh(&netdev_work_lock);
+ events = *pending & mask;
+ *pending &= ~events;
+ if (!list_empty(&dev->work_node) &&
+ !dev->work_pending && !dev->work_core_pending) {
+ list_del_init(&dev->work_node);
+ netdev_put(dev, &dev->work_tracker);
+ }
+ spin_unlock_bh(&netdev_work_lock);
+
+ return events;
+}
+
+void netdev_work_sched(struct net_device *dev, unsigned long events)
+{
+ netdev_work_enqueue(dev, events, 0);
+}
+EXPORT_SYMBOL(netdev_work_sched);
+
/**
- * __netdev_work_core_cancel() - cancel selected core work for a netdev
+ * netdev_work_cancel() - cancel selected work for a netdev
* @dev: net_device
* @mask: events to cancel
*
* Clear @mask from the device's work pending mask. If no work is left pending
- * the device is dequeued.
+ * the device is dequeued and its ndo_work won't be called.
*
* No expectations on locking, but also no guarantees provided. If the caller
* wants to touch @dev afterwards (e.g. call the work that got canceled)
@@ -50,21 +82,33 @@ void __netdev_work_core_sched(struct net_device *dev, unsigned long event)
* Returns: the subset of @mask that was actually pending, so the caller can run
* those events inline.
*/
+unsigned long netdev_work_cancel(struct net_device *dev, unsigned long mask)
+{
+ return netdev_work_dequeue(dev, &dev->work_pending, mask);
+}
+EXPORT_SYMBOL(netdev_work_cancel);
+
+void __netdev_work_core_sched(struct net_device *dev, unsigned long events)
+{
+ netdev_work_enqueue(dev, 0, events);
+}
+
unsigned long
__netdev_work_core_cancel(struct net_device *dev, unsigned long mask)
{
- unsigned long event;
+ return netdev_work_dequeue(dev, &dev->work_core_pending, mask);
+}
- spin_lock_bh(&netdev_work_lock);
- event = dev->work_core_pending & mask;
- dev->work_core_pending &= ~mask;
- if (!list_empty(&dev->work_node) && !dev->work_core_pending) {
- list_del_init(&dev->work_node);
- netdev_put(dev, &dev->work_tracker);
- }
- spin_unlock_bh(&netdev_work_lock);
+static void netdev_work_run(struct net_device *dev, unsigned long events,
+ unsigned long core)
+{
+ if (!netif_device_present(dev))
+ return;
- return event;
+ if (core & NETDEV_WORK_RX_MODE)
+ netif_rx_mode_run(dev);
+ if (events && dev->netdev_ops->ndo_work)
+ dev->netdev_ops->ndo_work(dev, events);
}
static void netdev_work_proc(struct work_struct *work)
@@ -72,9 +116,9 @@ static void netdev_work_proc(struct work_struct *work)
rtnl_lock();
while (true) {
+ unsigned long events = 0, core = 0;
netdevice_tracker tracker;
struct net_device *dev;
- unsigned long core = 0;
spin_lock_bh(&netdev_work_lock);
if (list_empty(&netdev_work_list)) {
@@ -98,16 +142,17 @@ static void netdev_work_proc(struct work_struct *work)
list_del_init(&dev->work_node);
core = dev->work_core_pending;
dev->work_core_pending = 0;
+ events = dev->work_pending;
+ dev->work_pending = 0;
/* We took another ref above */
netdev_put(dev, &dev->work_tracker);
if (!dev_isalive(dev))
- core = 0;
+ core = events = 0;
}
spin_unlock_bh(&netdev_work_lock);
- if (core & NETDEV_WORK_RX_MODE)
- netif_rx_mode_run(dev);
+ netdev_work_run(dev, events, core);
netdev_unlock_ops(dev);
netdev_put(dev, &tracker);
--
2.54.0
^ permalink raw reply related
* [PATCH net 1/4] net: turn the rx_mode work into a generic netdev_work facility
From: Jakub Kicinski @ 2026-06-24 18:20 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, jv, sdf,
dongchenchen2, idosch, n05ec, yuantan098, kuniyu, nb,
aleksandr.loktionov, dtatulea, Jakub Kicinski
In-Reply-To: <20260624182018.2445732-1-kuba@kernel.org>
The rx_mode update runs from a workqueue: drivers have their
ndo_set_rx_mode_async() callback executed by a single global
work item under RTNL and ops lock. This is a useful pattern.
Support multiple "events" that need to be serviced and make RX_MODE
sync the first one. Call the events "core" because later on
we will let drivers define and schedule their own.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/core/Makefile | 2 +-
include/linux/netdevice.h | 10 ++--
net/core/dev.h | 11 +++-
net/core/dev.c | 1 +
net/core/dev_addr_lists.c | 77 +------------------------
net/core/netdev_work.c | 117 ++++++++++++++++++++++++++++++++++++++
6 files changed, 138 insertions(+), 80 deletions(-)
create mode 100644 net/core/netdev_work.c
diff --git a/net/core/Makefile b/net/core/Makefile
index dc17c5a61e9a..b3fdcb4e355f 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -13,7 +13,7 @@ obj-y += dev.o dev_api.o dev_addr_lists.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
fib_notifier.o xdp.o flow_offload.o gro.o \
- netdev-genl.o netdev-genl-gen.o gso.o
+ netdev-genl.o netdev-genl-gen.o netdev_work.o gso.o
obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b67a12541eac..732506787db3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1930,8 +1930,9 @@ enum netdev_reg_state {
* has been enabled due to the need to listen to
* additional unicast addresses in a device that
* does not implement ndo_set_rx_mode()
- * @rx_mode_node: List entry for rx_mode work processing
- * @rx_mode_tracker: Refcount tracker for rx_mode work
+ * @work_node: List entry for async netdev_work processing
+ * @work_tracker: Refcount tracker for async netdev_work
+ * @work_core_pending: Core-defined pending netdev_work (NETDEV_WORK_*)
* @rx_mode_addr_cache: Recycled snapshot entries for rx_mode work
* @rx_mode_retry_timer: Timer that re-queues rx_mode work after failure
* @rx_mode_retry_count: Number of consecutive retries already scheduled
@@ -2326,8 +2327,9 @@ struct net_device {
unsigned int promiscuity;
unsigned int allmulti;
bool uc_promisc;
- struct list_head rx_mode_node;
- netdevice_tracker rx_mode_tracker;
+ struct list_head work_node;
+ netdevice_tracker work_tracker;
+ unsigned long work_core_pending;
struct netdev_hw_addr_list rx_mode_addr_cache;
struct timer_list rx_mode_retry_timer;
unsigned int rx_mode_retry_count;
diff --git a/net/core/dev.h b/net/core/dev.h
index 4121c50e7c88..5d0b0305d3ba 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -167,10 +167,19 @@ int dev_change_carrier(struct net_device *dev, bool new_carrier);
void __dev_set_rx_mode(struct net_device *dev);
int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify);
void netif_rx_mode_init(struct net_device *dev);
-bool netif_rx_mode_clean(struct net_device *dev);
+void netif_rx_mode_run(struct net_device *dev);
void netif_rx_mode_sync(struct net_device *dev);
void netif_rx_mode_cancel_retry(struct net_device *dev);
+/* Events for the async netdev work, tracked in netdev->work_core_pending. */
+enum netdev_work_core {
+ NETDEV_WORK_RX_MODE = BIT(0), /* run the rx_mode update */
+};
+
+void __netdev_work_core_sched(struct net_device *dev, unsigned long event);
+unsigned long
+__netdev_work_core_cancel(struct net_device *dev, unsigned long mask);
+
void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
unsigned int gchanges, u32 portid,
const struct nlmsghdr *nlh);
diff --git a/net/core/dev.c b/net/core/dev.c
index 5c01dfaa6c44..e1d8af0ef6ab 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12093,6 +12093,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
INIT_LIST_HEAD(&dev->ptype_all);
INIT_LIST_HEAD(&dev->ptype_specific);
INIT_LIST_HEAD(&dev->net_notifier_list);
+ INIT_LIST_HEAD(&dev->work_node);
#ifdef CONFIG_NET_SCHED
hash_init(dev->qdisc_hash);
#endif
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index e17f64a65e17..08528ca0a8b3 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -12,17 +12,10 @@
#include <linux/export.h>
#include <linux/list.h>
#include <linux/spinlock.h>
-#include <linux/workqueue.h>
#include <kunit/visibility.h>
#include "dev.h"
-static void netdev_rx_mode_work(struct work_struct *work);
-
-static LIST_HEAD(rx_mode_list);
-static DEFINE_SPINLOCK(rx_mode_lock);
-static DECLARE_WORK(rx_mode_work, netdev_rx_mode_work);
-
/*
* General list handling functions
*/
@@ -1281,7 +1274,7 @@ void netif_rx_mode_cancel_retry(struct net_device *dev)
dev->rx_mode_retry_count = 0;
}
-static void netif_rx_mode_run(struct net_device *dev)
+void netif_rx_mode_run(struct net_device *dev)
{
struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref;
const struct net_device_ops *ops = dev->netdev_ops;
@@ -1339,49 +1332,9 @@ static void netif_rx_mode_run(struct net_device *dev)
}
}
-static void netdev_rx_mode_work(struct work_struct *work)
-{
- struct net_device *dev;
-
- rtnl_lock();
-
- while (true) {
- spin_lock_bh(&rx_mode_lock);
- if (list_empty(&rx_mode_list)) {
- spin_unlock_bh(&rx_mode_lock);
- break;
- }
- dev = list_first_entry(&rx_mode_list, struct net_device,
- rx_mode_node);
- list_del_init(&dev->rx_mode_node);
- /* We must free netdev tracker under
- * the spinlock protection.
- */
- netdev_tracker_free(dev, &dev->rx_mode_tracker);
- spin_unlock_bh(&rx_mode_lock);
-
- netdev_lock_ops(dev);
- netif_rx_mode_run(dev);
- netdev_unlock_ops(dev);
- /* Use __dev_put() because netdev_tracker_free() was already
- * called above. Must be after netdev_unlock_ops() to prevent
- * netdev_run_todo() from freeing the device while still in use.
- */
- __dev_put(dev);
- }
-
- rtnl_unlock();
-}
-
static void netif_rx_mode_queue(struct net_device *dev)
{
- spin_lock_bh(&rx_mode_lock);
- if (list_empty(&dev->rx_mode_node)) {
- list_add_tail(&dev->rx_mode_node, &rx_mode_list);
- netdev_hold(dev, &dev->rx_mode_tracker, GFP_ATOMIC);
- }
- spin_unlock_bh(&rx_mode_lock);
- schedule_work(&rx_mode_work);
+ __netdev_work_core_sched(dev, NETDEV_WORK_RX_MODE);
}
static void netif_rx_mode_retry(struct timer_list *t)
@@ -1394,7 +1347,6 @@ static void netif_rx_mode_retry(struct timer_list *t)
void netif_rx_mode_init(struct net_device *dev)
{
- INIT_LIST_HEAD(&dev->rx_mode_node);
__hw_addr_init(&dev->rx_mode_addr_cache);
timer_setup(&dev->rx_mode_retry_timer, netif_rx_mode_retry, 0);
}
@@ -1442,24 +1394,6 @@ void dev_set_rx_mode(struct net_device *dev)
netif_addr_unlock_bh(dev);
}
-bool netif_rx_mode_clean(struct net_device *dev)
-{
- bool clean = false;
-
- spin_lock_bh(&rx_mode_lock);
- if (!list_empty(&dev->rx_mode_node)) {
- list_del_init(&dev->rx_mode_node);
- clean = true;
- /* We must release netdev tracker under
- * the spinlock protection.
- */
- netdev_tracker_free(dev, &dev->rx_mode_tracker);
- }
- spin_unlock_bh(&rx_mode_lock);
-
- return clean;
-}
-
/**
* netif_rx_mode_sync() - sync rx mode inline
* @dev: network device
@@ -1473,11 +1407,6 @@ bool netif_rx_mode_clean(struct net_device *dev)
*/
void netif_rx_mode_sync(struct net_device *dev)
{
- if (netif_rx_mode_clean(dev)) {
+ if (__netdev_work_core_cancel(dev, NETDEV_WORK_RX_MODE))
netif_rx_mode_run(dev);
- /* Use __dev_put() because netdev_tracker_free() was already
- * called inside netif_rx_mode_clean().
- */
- __dev_put(dev);
- }
}
diff --git a/net/core/netdev_work.c b/net/core/netdev_work.c
new file mode 100644
index 000000000000..c121c24dc493
--- /dev/null
+++ b/net/core/netdev_work.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <net/netdev_lock.h>
+
+#include "dev.h"
+
+static void netdev_work_proc(struct work_struct *work);
+
+/* @netdev_work_lock protects:
+ * - @netdev_work_list
+ * - within the list entries (struct net_device fields):
+ * - work_node
+ * - work_tracker
+ * - work_core_pending
+ */
+static LIST_HEAD(netdev_work_list);
+static DEFINE_SPINLOCK(netdev_work_lock);
+static DECLARE_WORK(netdev_work, netdev_work_proc);
+
+void __netdev_work_core_sched(struct net_device *dev, unsigned long event)
+{
+ spin_lock_bh(&netdev_work_lock);
+ if (list_empty(&dev->work_node)) {
+ list_add_tail(&dev->work_node, &netdev_work_list);
+ netdev_hold(dev, &dev->work_tracker, GFP_ATOMIC);
+ }
+ dev->work_core_pending |= event;
+ spin_unlock_bh(&netdev_work_lock);
+
+ schedule_work(&netdev_work);
+}
+
+/**
+ * __netdev_work_core_cancel() - cancel selected core work for a netdev
+ * @dev: net_device
+ * @mask: events to cancel
+ *
+ * Clear @mask from the device's work pending mask. If no work is left pending
+ * the device is dequeued.
+ *
+ * No expectations on locking, but also no guarantees provided. If the caller
+ * wants to touch @dev afterwards (e.g. call the work that got canceled)
+ * they have to ensure @dev does not get freed.
+ *
+ * Returns: the subset of @mask that was actually pending, so the caller can run
+ * those events inline.
+ */
+unsigned long
+__netdev_work_core_cancel(struct net_device *dev, unsigned long mask)
+{
+ unsigned long event;
+
+ spin_lock_bh(&netdev_work_lock);
+ event = dev->work_core_pending & mask;
+ dev->work_core_pending &= ~mask;
+ if (!list_empty(&dev->work_node) && !dev->work_core_pending) {
+ list_del_init(&dev->work_node);
+ netdev_put(dev, &dev->work_tracker);
+ }
+ spin_unlock_bh(&netdev_work_lock);
+
+ return event;
+}
+
+static void netdev_work_proc(struct work_struct *work)
+{
+ rtnl_lock();
+
+ while (true) {
+ netdevice_tracker tracker;
+ struct net_device *dev;
+ unsigned long core = 0;
+
+ spin_lock_bh(&netdev_work_lock);
+ if (list_empty(&netdev_work_list)) {
+ spin_unlock_bh(&netdev_work_lock);
+ break;
+ }
+ dev = list_first_entry(&netdev_work_list, struct net_device,
+ work_node);
+ /* Take a temporary reference so @dev can't be freed while we
+ * drop the lock to grab its ops lock; the work reference is
+ * only released once we claim the work below.
+ * The re-locking dance is to ensure that ops lock is enough
+ * to ensure canceling work is not racy with dequeue.
+ */
+ netdev_hold(dev, &tracker, GFP_ATOMIC);
+ spin_unlock_bh(&netdev_work_lock);
+
+ netdev_lock_ops(dev);
+ spin_lock_bh(&netdev_work_lock);
+ if (!list_empty(&dev->work_node)) {
+ list_del_init(&dev->work_node);
+ core = dev->work_core_pending;
+ dev->work_core_pending = 0;
+ /* We took another ref above */
+ netdev_put(dev, &dev->work_tracker);
+
+ if (!dev_isalive(dev))
+ core = 0;
+ }
+ spin_unlock_bh(&netdev_work_lock);
+
+ if (core & NETDEV_WORK_RX_MODE)
+ netif_rx_mode_run(dev);
+ netdev_unlock_ops(dev);
+
+ netdev_put(dev, &tracker);
+ }
+
+ rtnl_unlock();
+}
--
2.54.0
^ permalink raw reply related
* [PATCH net 0/4] net: avoid nested UP notifier events
From: Jakub Kicinski @ 2026-06-24 18:20 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, jv, sdf,
dongchenchen2, idosch, n05ec, yuantan098, kuniyu, nb,
aleksandr.loktionov, dtatulea, Jakub Kicinski
syzbot reported that recent ethtool rework leads to deadlock
on stacked devices. VLANs create nested notifications, confusing
execution context. Bringing up dummy causes vlan to bring itself
up as well. Which in turn causes bond to ask for link state -
a call chain traveling in the opposite direction.
bond (3) bond_update_speed_duplex(vlan)
| ^ v
vlan (2) UP(vlan) (4) vlan_ethtool_get_link_ksettings()
| ^ v
dummy (1) UP(dummy) (5) __ethtool_get_link_ksettings()
We locked the instance lock of dummy at (1) and will will
try to lock it again at (5) - which of course deadlocks.
For non-nested notifications this is avoided because NETDEV_UP
is always run ops-locked (so that bond asks for link using the
netif_ API which assumes instance lock already held). The nesting,
however, makes this problematic, we cannot carry the state of
the whole chain back in the opposite direction.
AFAICT vlan is the only driver which causes such issues.
So let's try a localized fix of deferring vlan auto-open
to a workqueue.
Jakub Kicinski (4):
net: turn the rx_mode work into a generic netdev_work facility
net: add the driver-facing netdev_work scheduling API
vlan: defer real device state propagation to netdev_work
selftests: bonding: add a test for VLAN propagation over a bonded real
device
Documentation/networking/netdevices.rst | 2 +
net/core/Makefile | 2 +-
.../selftests/drivers/net/bonding/Makefile | 1 +
include/linux/netdevice.h | 21 +-
net/8021q/vlan.h | 11 ++
net/core/dev.h | 11 +-
net/8021q/vlan.c | 76 +-------
net/8021q/vlan_dev.c | 60 ++++++
net/core/dev.c | 2 +
net/core/dev_addr_lists.c | 77 +-------
net/core/netdev_work.c | 162 ++++++++++++++++
.../drivers/net/bonding/bond_vlan_real_dev.sh | 180 ++++++++++++++++++
12 files changed, 457 insertions(+), 148 deletions(-)
create mode 100644 net/core/netdev_work.c
create mode 100755 tools/testing/selftests/drivers/net/bonding/bond_vlan_real_dev.sh
--
2.54.0
^ permalink raw reply
* [PATCH v2] bpf: allow BPF_LOG_KERNEL from kernel space
From: Siddharth Nayyar @ 2026-06-24 18:19 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis
Cc: linux-kernel, bpf, Siddharth Nayyar, John Fastabend,
Giuliano Procida, Matthias Maennich, Tiffany Yang, Neill Kapron
When loading a BPF program or BTF from kernel space (e.g. using a
light skeleton generated loader module), the kernel module may want
to output verifier logs to dmesg by setting attr->log_level =
BPF_LOG_KERNEL (16).
Currently, any attempt to do this through the standard syscall path
(kern_sys_bpf -> bpf_vlog_init) fails with -EINVAL because
bpf_verifier_log_attr_valid() rejects any log_level bit outside
BPF_LOG_MASK. This prevents in-kernel loaders from successfully
using BPF_LOG_KERNEL, causing silent failures if the BPF object
is rejected by the verifier.
This patch modifies bpf_verifier_log_attr_valid() to accept
BPF_LOG_KERNEL unconditionally. To prevent userspace from exploiting
this to spam the kernel log, the patch enforces a strict privilege
check at the syscall boundary points (btf_parse, bpf_log_attr_init,
bpf_log_attr_create_vlog), ensuring BPF_LOG_KERNEL is only permitted
when uattr.is_kernel is true.
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
To: Alexei Starovoitov <ast@kernel.org>
To: Daniel Borkmann <daniel@iogearbox.net>
To: Andrii Nakryiko <andrii@kernel.org>
To: Eduard Zingerman <eddyz87@gmail.com>
To: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: Martin KaFai Lau <martin.lau@linux.dev>
To: Song Liu <song@kernel.org>
To: Yonghong Song <yonghong.song@linux.dev>
To: Jiri Olsa <jolsa@kernel.org>
To: Emil Tsalapatis <emil@etsalapatis.com>
To: John Fastabend <john.fastabend@gmail.com>
Cc: bpf@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: Giuliano Procida <gprocida@google.com>
Cc: Matthias Maennich <maennich@google.com>
Cc: Tiffany Yang <ynaffit@google.com>
Cc: Neill Kapron <nkapron@google.com>
Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
--- Changes in v2:
- Refactored BPF_LOG_KERNEL validation to check uattr.is_kernel at
syscall boundary points (btf_parse, bpf_log_attr_init, etc.) rather
than plumbing an is_kernel boolean through the verifier log
initialization functions.
- Link to v1:
https://lore.kernel.org/r/20260623-bpf-lskel-fixes-v1-1-90600b40e7cb@google.com
---
kernel/bpf/btf.c | 3 +++
kernel/bpf/log.c | 17 +++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 15ae7c43f594..4a0c18112ad3 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -5919,6 +5919,9 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr,
if (attr->btf_size > BTF_MAX_SIZE)
return ERR_PTR(-E2BIG);
+ if (attr_log->level == BPF_LOG_KERNEL && !uattr.is_kernel)
+ return ERR_PTR(-EINVAL);
+
env = kzalloc_obj(*env, GFP_KERNEL | __GFP_NOWARN);
if (!env)
return ERR_PTR(-ENOMEM);
diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c
index b740fa73ee26..25a9f8340980 100644
--- a/kernel/bpf/log.c
+++ b/kernel/bpf/log.c
@@ -21,6 +21,15 @@ static bool bpf_verifier_log_attr_valid(u32 log_level, char __user *log_buf, u32
/* log buf without log_level is meaningless */
if (log_buf && log_level == 0)
return false;
+
+ /* BPF_LOG_KERNEL is an exclusive internal mode, not a bit flag.
+ * It must be checked via strict equality to prevent it from being
+ * combined with userspace flags, which would cause the verifier
+ * to fallback to userspace logging and copy_to_user() failures.
+ */
+ if (log_level == BPF_LOG_KERNEL)
+ return true;
+
if (log_level & ~BPF_LOG_MASK)
return false;
if (log_size > UINT_MAX >> 2)
@@ -831,6 +840,11 @@ int bpf_log_attr_init(struct bpf_log_attr *log, u64 log_buf, u32 log_size, u32 l
char __user *ubuf_common = u64_to_user_ptr(common->log_buf);
char __user *ubuf = u64_to_user_ptr(log_buf);
+ if (common->log_level == BPF_LOG_KERNEL && !uattr_common.is_kernel)
+ return -EINVAL;
+ if (log_level == BPF_LOG_KERNEL && !uattr.is_kernel)
+ return -EINVAL;
+
if (!bpf_verifier_log_attr_valid(common->log_level, ubuf_common, common->log_size) ||
!bpf_verifier_log_attr_valid(log_level, ubuf, log_size))
return -EINVAL;
@@ -873,6 +887,9 @@ struct bpf_verifier_log *bpf_log_attr_create_vlog(struct bpf_log_attr *attr_log,
if (!size)
return NULL;
+ if (common->log_level == BPF_LOG_KERNEL && !uattr.is_kernel)
+ return ERR_PTR(-EINVAL);
+
log = kzalloc_obj(*log, GFP_KERNEL);
if (!log)
return ERR_PTR(-ENOMEM);
---
base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
change-id: 20260622-bpf-lskel-fixes-cafd1a83dec2
Best regards,
--
Siddharth Nayyar <sidnayyar@google.com>
^ permalink raw reply related
* Re: [PATCH 0/2] Convert env export and import to use getopt()
From: Tom Rini @ 2026-06-24 18:19 UTC (permalink / raw)
To: Quentin Schulz
Cc: Simon Glass, u-boot, Sean Anderson, Andrew Goodbody,
Christian Marangi, Heiko Schocher, Heinrich Schuchardt,
Ilias Apalodimas, Jerome Forissier, Kory Maincent (TI.com),
Marek Vasut, Mikhail Kshevetskiy
In-Reply-To: <e56cb70e-1a66-4ebf-8014-7fd6be9c69ef@cherry.de>
[-- Attachment #1: Type: text/plain, Size: 6478 bytes --]
On Wed, Jun 24, 2026 at 07:35:49PM +0200, Quentin Schulz wrote:
> On 5/22/26 7:03 PM, Tom Rini wrote:
> > On Wed, May 20, 2026 at 02:12:12PM -0600, Simon Glass wrote:
> >
> > > U-Boot has had a getopt() implementation for over five years but it is
> > > not used much; most commands hand-roll their own argv loops to spot
> > > -x style flags. The env export and env import sub-commands have the
> > > gnarliest of these parsers in nvedit.c
> > >
> > > Each one walks every -prefixed argv element by hand, opens an inner
> > > loop to split grouped flags and tracks a counter to catch a repeated
> > > format flag.
> > >
> > > This short series converts both sub-commands to getopt(). The mutex
> > > check for the format flags is done after the option loop, since it is
> > > a per-command rule rather than an option-parsing rule, and the trailing
> > > positional list is read straight out of argv from gs.index onwards.
> > >
> > > There is no functional change. getopt() stops at the first non-option,
> > > just as the hand-rolled loops did, so options still have to appear
> > > before the positional arguments.
> > >
> > > Each command gains a 'select GETOPT' so the parser is linked in on
> > > boards that do not already enable it.
> > >
> > > For firefly-rk3399:
> > >
> > > 03: cmd: nvedit: Use getopt() in env export
> > > aarch64: (for 1/1 boards) all -45.0 rodata +27.0 text -72.0
> > > 04: cmd: nvedit: Use getopt() in env import
> > > aarch64: (for 1/1 boards) all -27.0 rodata -55.0 text +28.0
> > >
> > >
> > > Simon Glass (2):
> > > cmd: nvedit: Use getopt() in env export
> > > cmd: nvedit: Use getopt() in env import
> > >
> > > cmd/Kconfig | 2 +
> > > cmd/nvedit.c | 186 +++++++++++++++++++++++----------------------------
> > > env/common.c | 2 +-
> > > 3 files changed, 85 insertions(+), 105 deletions(-)
> >
> > For the record, here's a link to v2:
> > https://lore.kernel.org/u-boot/20260519233207.2765755-1-sjg@chromium.org/
> > And here's the full size change for firefly-rk3399:
> > Summary of 3 commits for 1 boards (1 thread, 12 jobs per thread)
> > 01: arm: Fix typo in linker script
> > aarch64: w+ firefly-rk3399
> > +(firefly-rk3399) Image 'simple-bin' is missing external blobs and is non-functional: atf-bl31
> > +(firefly-rk3399)
> > +(firefly-rk3399) /binman/simple-bin/fit/images/@atf-SEQ/atf-bl31 (atf-bl31):
> > +(firefly-rk3399) See the documentation for your board. You may need to build ARM Trusted
> > +(firefly-rk3399) Firmware and build with BL31=/path/to/bl31.bin
> > +(firefly-rk3399) Image 'simple-bin' is missing optional external blobs but is still functional: tee-os
> > +(firefly-rk3399) /binman/simple-bin/fit/images/@tee-SEQ/tee-os (tee-os):
> > +(firefly-rk3399) See the documentation for your board. You may need to build Open Portable
> > +(firefly-rk3399) Trusted Execution Environment (OP-TEE) and build with TEE=/path/to/tee.bin
> > +(firefly-rk3399) Some images are invalid
> > 02: cmd: nvedit: Use getopt() in env export
> > aarch64: (for 1/1 boards) all +883.0 rodata +199.0 text +684.0
> > firefly-rk3399 : all +883 rodata +199 text +684
> > u-boot: add: 5/0, grow: 0/-2 bytes: 1184/-500 (684)
> > function old new delta
> > __getopt - 520 +520
> > static.bdinfo_print_all - 324 +324
> > print_eth - 236 +236
> > print_bi_dram - 92 +92
> > getopt_init_state - 12 +12
> > do_env_export 548 476 -72
> > do_bdinfo 588 160 -428
> > 03: cmd: nvedit: Use getopt() in env import
> > aarch64: (for 1/1 boards) all -27.0 rodata -55.0 text +28.0
> > firefly-rk3399 : all -27 rodata -55 text +28
> > u-boot: add: 0/0, grow: 1/0 bytes: 28/0 (28)
> > function old new delta
> > do_env_import 668 696 +28
> >
> > And so this is why I'm just deferring this until someone has the time to
> > pick up and address the underlying problems with this potential
> > migration that have been raised in the previous iterations.
> >
>
> Chiming in because I was put in Cc...
>
> Do I understand correctly that this only impacts U-Boot proper? If so, is a
> size increase in proper that much of a blocker? As opposed to xPL which
> usually resides in SRAM, I'm assuming U-Boot proper would run in RAM where I
> hope an additional ~700B shouldn't be too much to ask for? The issue however
> could be on the storage medium where U-Boot proper is located, maybe this
> gets the binary above the max space allowed for U-Boot proper to be stored
> (e.g. on some of my boards I'm (self-imposed) limited to 2000KiB) though I'm
> assuming it could be less than 700B if U-Boot proper is compressed for
> example. But I'm also lucky enough to have storage space and (D)RAM to spare
> on my boards.
>
> Out of the RFC, I see the strlower() part as being separate from the rest,
> maybe that's something we could revisit separately? Reading the cover
> letter, we should even spare 60B with that alone, with the added benefit of
> easier maintainability?
This was just impacting U-Boot proper. However, it showed I think two
sets of problems. The first of which is that there was an expectation
that switching the code should result in some sort of savings,
somewhere. And it didn't. And we do have boards where the space between
the end of U-Boot and the start of the environment is small and so
global changes that aren't just bug fixes need careful consideration
(and they've already turned off things that aren't needed for them such
as EFI loader). The second thing was that the code wasn't really easier
to read / follow. So I don't object to the concept but I think the
outcome of this series was that our getopt needs to be looked at in a
bit more detail, and figure out if it's really designed the way we need
it.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [yocto-patches] [layerindex-web][PATCH 1/1] layerindex: Use settings.DEFAULT_BRANCH instead of hardcoded branch name
From: Tim Orling @ 2026-06-24 18:18 UTC (permalink / raw)
To: Piotr Bulinski; +Cc: Sandeep Gundlupet Raju, yocto-patches, mark.hatle
In-Reply-To: <CAGjhzsKyprtbc53Ra2MiP31bygMhmmzg5NHhgo3b_snZNjj3YA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 22281 bytes --]
Hi Sandeep,
It would also be nice to include a use case in the git commit explaining
what is driving this change?
Also, see comments below regarding the opportunity to rename the
'master_branch' variable to 'default_branch' for better code consistency.
On Wed, Jun 24, 2026 at 11:08 AM Piotr Bulinski <piotr@qbee.io> wrote:
> Hi Sandeep,
>
> Thank you for the patch.
>
> In the layerindex/update_layer.py you are updating the default value of `--branch`
> to an empty string,
> which is inconsistent with the rest of the changes in this patch.
>
> In the same file, system settings are already imported at line 298, so
> perhaps that import should be moved above the parser logic
> to allow you to use `settings.DEFAULT_BRANCH` as a default value for the
> `--branch` option instead of an empty string.
>
> Best regards,
> Piotr Buliński
>
> On Fri, Jun 19, 2026 at 11:52 PM Sandeep Gundlupet Raju <
> sandeep.gundlupet-raju@amd.com> wrote:
>
>> Replace all hardcoded branch name references with settings.DEFAULT_BRANCH
>> so the default branch can be changed from a single location in settings.py
>> without modifying individual source files. DEFAULT_BRANCH defaults to
>> 'master'.
>>
>> - settings.py: add DEFAULT_BRANCH = 'master'
>> - docker/settings.py: add DEFAULT_BRANCH = 'master'
>> - layerindex/urls.py: use _DEFAULT_BRANCH from settings
>> - layerindex/views.py: use settings.DEFAULT_BRANCH (10 occurrences)
>> - layerindex/models.py: add import settings; use settings.DEFAULT_BRANCH
>> - layerindex/update.py: use settings.DEFAULT_BRANCH
>> - layerindex/update_layer.py: resolve branch from settings.DEFAULT_BRANCH
>> - layerindex/bulkchange.py: use settings.DEFAULT_BRANCH
>> - layerindex/tools/import_layer.py: use settings.DEFAULT_BRANCH
>> - layerindex/tools/import_wiki_layers.py: add import settings; use
>> DEFAULT_BRANCH
>> - layerindex/tools/import_classic_wiki.py: add import settings; use
>> DEFAULT_BRANCH
>> - layerindex/tools/update_classic_status.py: add import settings; use
>> DEFAULT_BRANCH
>> - rrs/tools/historytool.py: use settings.DEFAULT_BRANCH
>>
>> AI-Generated: GitHub Copilot (Claude Sonnet 4.6)
>>
>> Signed-off-by: Sandeep Gundlupet Raju <sandeep.gundlupet-raju@amd.com>
>> ---
>> docker/settings.py | 2 ++
>> layerindex/bulkchange.py | 2 +-
>> layerindex/models.py | 5 +++--
>> layerindex/tools/import_classic_wiki.py | 3 ++-
>> layerindex/tools/import_layer.py | 4 ++--
>> layerindex/tools/import_wiki_layers.py | 3 ++-
>> layerindex/tools/update_classic_status.py | 7 ++++---
>> layerindex/update.py | 2 +-
>> layerindex/update_layer.py | 4 +++-
>> layerindex/urls.py | 16 +++++++++-------
>> layerindex/views.py | 20 ++++++++++----------
>> rrs/tools/historytool.py | 4 ++--
>> settings.py | 3 +++
>> 13 files changed, 44 insertions(+), 31 deletions(-)
>>
>> diff --git a/docker/settings.py b/docker/settings.py
>> index e3ae0fd..85b7efd 100644
>> --- a/docker/settings.py
>> +++ b/docker/settings.py
>> @@ -315,3 +315,5 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO',
>> 'https')
>> SECURE_BROWSER_XSS_FILTER = True
>> SECURE_CONTENT_TYPE_NOSNIFF = True
>>
>> +# Default branch name used across the layer index
>> +DEFAULT_BRANCH = 'master'
>> diff --git a/layerindex/bulkchange.py b/layerindex/bulkchange.py
>> index 0ec4058..11cd7a6 100644
>> --- a/layerindex/bulkchange.py
>> +++ b/layerindex/bulkchange.py
>> @@ -98,7 +98,7 @@ def main():
>> utils.setup_django()
>> import settings
>>
>> - branch = utils.get_branch('master')
>> + branch = utils.get_branch(settings.DEFAULT_BRANCH)
>> fetchdir = settings.LAYER_FETCH_DIR
>>
>> import layerindex.models import LayerItem
>> diff --git a/layerindex/models.py b/layerindex/models.py
>> index 864264b..7a09962 100644
>> --- a/layerindex/models.py
>> +++ b/layerindex/models.py
>> @@ -18,6 +18,7 @@ import os.path
>> import re
>> import posixpath
>> import codecs
>> +import settings
>>
>> from . import utils
>>
>> @@ -190,7 +191,7 @@ class LayerItem(models.Model):
>> return fetch_dir
>>
>> def get_absolute_url(self):
>> - return reverse('layer_item', args=('master',self.name));
>> + return reverse('layer_item', args=(settings.DEFAULT_BRANCH,
>> self.name));
>>
>> def __str__(self):
>> return self.name
>> @@ -672,7 +673,7 @@ class ClassicRecipe(Recipe):
>> ('E', 'Equivalent functionality'),
>> ('D', 'Direct match'),
>> ]
>> - cover_layerbranch = models.ForeignKey(LayerBranch,
>> verbose_name='Covering layer', blank=True, null=True, limit_choices_to =
>> {'branch__name': 'master'}, on_delete=models.SET_NULL)
>> + cover_layerbranch = models.ForeignKey(LayerBranch,
>> verbose_name='Covering layer', blank=True, null=True, limit_choices_to =
>> {'branch__name': settings.DEFAULT_BRANCH}, on_delete=models.SET_NULL)
>> cover_pn = models.CharField('Covering recipe', max_length=100,
>> blank=True)
>> cover_status = models.CharField(max_length=1,
>> choices=COVER_STATUS_CHOICES, default='U')
>> cover_verified = models.BooleanField(default=False)
>> diff --git a/layerindex/tools/import_classic_wiki.py
>> b/layerindex/tools/import_classic_wiki.py
>> index bd7ab9a..e8c4c8c 100755
>> --- a/layerindex/tools/import_classic_wiki.py
>> +++ b/layerindex/tools/import_classic_wiki.py
>> @@ -84,6 +84,7 @@ def main():
>> options, args = parser.parse_args(sys.argv)
>>
>> utils.setup_django()
>> + import settings
>> from layerindex.models import LayerItem, LayerBranch, Recipe,
>> ClassicRecipe
>> from django.db import transaction
>>
>> @@ -178,7 +179,7 @@ def main():
>> res =
>> list(LayerItem.objects.filter(name=newlayer)[:1])
>> if res:
>> newlayeritem = res[0]
>> - recipe.cover_layerbranch =
>> newlayeritem.get_layerbranch('master')
>> + recipe.cover_layerbranch =
>> newlayeritem.get_layerbranch(settings.DEFAULT_BRANCH)
>> else:
>> logger.info('Replacement layer "%s" for
>> %s could not be found' % (newlayer, pn))
>> recipe.cover_pn = newpn
>> diff --git a/layerindex/tools/import_layer.py
>> b/layerindex/tools/import_layer.py
>> index 79c679e..cdbd40d 100755
>> --- a/layerindex/tools/import_layer.py
>> +++ b/layerindex/tools/import_layer.py
>> @@ -284,7 +284,7 @@ def main():
>> if not os.path.exists(fetchdir):
>> os.makedirs(fetchdir)
>>
>> - master_branch = utils.get_branch('master')
>> + master_branch = utils.get_branch(settings.DEFAULT_BRANCH)
>>
>
We have an opportunity here to rename master_branch variable to
default_branch to align better with the new direction.
> core_layer = None
>> try:
>> with transaction.atomic():
>> @@ -311,7 +311,7 @@ def main():
>> logger.error("Fetch failed: %s" % str(e))
>> sys.exit(1)
>>
>> - actual_branch = 'master'
>> + actual_branch = settings.DEFAULT_BRANCH
>> if (options.actual_branch):
>> actual_branch = options.actual_branch
>> try:
>> diff --git a/layerindex/tools/import_wiki_layers.py
>> b/layerindex/tools/import_wiki_layers.py
>> index 061f6df..f287bf6 100755
>> --- a/layerindex/tools/import_wiki_layers.py
>> +++ b/layerindex/tools/import_wiki_layers.py
>> @@ -35,6 +35,7 @@ def main():
>> options, args = parser.parse_args(sys.argv)
>>
>> utils.setup_django()
>> + import settings
>> from layerindex.models import LayerItem, LayerBranch, LayerDependency
>> from django.db import transaction
>>
>> @@ -49,7 +50,7 @@ def main():
>> nowiki_re = re.compile(r'</?nowiki>')
>> link_re = re.compile(r'\[(http.*) +link\]')
>> readme_re = re.compile(r';f=[a-zA-Z0-9/-]*README;')
>> - master_branch = utils.get_branch('master')
>> + master_branch = utils.get_branch(settings.DEFAULT_BRANCH)
>
>
Same comment here about 'master_branch' to 'default_branch' opportunity.
>
>
> core_layer = None
>> with transaction.atomic():
>> for line in data.splitlines():
>> diff --git a/layerindex/tools/update_classic_status.py
>> b/layerindex/tools/update_classic_status.py
>> index aa5d2ef..c8c373b 100755
>> --- a/layerindex/tools/update_classic_status.py
>> +++ b/layerindex/tools/update_classic_status.py
>> @@ -83,6 +83,7 @@ def main():
>> args = parser.parse_args()
>>
>> utils.setup_django()
>> + import settings
>> from layerindex.models import LayerItem, LayerBranch, Recipe,
>> ClassicRecipe, Update, ComparisonRecipeUpdate
>> from django.db import transaction
>>
>> @@ -121,7 +122,7 @@ def main():
>> try:
>> with transaction.atomic():
>> def recipe_pn_query(pn):
>> - return
>> Recipe.objects.filter(layerbranch__branch__name='master').filter(pn=pn).order_by('-layerbranch__layer__index_preference')
>> + return
>> Recipe.objects.filter(layerbranch__branch__name=settings.DEFAULT_BRANCH).filter(pn=pn).order_by('-layerbranch__layer__index_preference')
>>
>> if args.import_data:
>> recipequery =
>> ClassicRecipe.objects.filter(layerbranch=layerbranch)
>> @@ -141,9 +142,9 @@ def main():
>> orig_layerbranch = recipe.cover_layerbranch
>> recipe.cover_layerbranch =
>> layerbranches.get(cover_layer, None)
>> if recipe.cover_layerbranch is None:
>> - recipe.cover_layerbranch =
>> LayerBranch.objects.filter(branch__name='master',
>> layer__name=cover_layer).first()
>> + recipe.cover_layerbranch =
>> LayerBranch.objects.filter(branch__name=settings.DEFAULT_BRANCH,
>> layer__name=cover_layer).first()
>> if recipe.cover_layerbranch is None:
>> - logger.warning('Could not find cover
>> layer %s in master branch' % cover_layer)
>> + logger.warning('Could not find cover
>> layer %s in %s branch' % (cover_layer, settings.DEFAULT_BRANCH))
>> else:
>> layerbranches[cover_layer] =
>> recipe.cover_layerbranch
>> if orig_layerbranch != recipe.cover_layerbranch:
>> diff --git a/layerindex/update.py b/layerindex/update.py
>> index df3939f..788daee 100755
>> --- a/layerindex/update.py
>> +++ b/layerindex/update.py
>> @@ -333,7 +333,7 @@ def main():
>>
>> # Get a safe bitbake branch to call into from this script
>> (used later on)
>> safe_bitbake_branch = 'origin/master'
>> - master_branch = Branch.objects.filter(name='master').first()
>> + master_branch =
>> Branch.objects.filter(name=settings.DEFAULT_BRANCH).first()
>> if master_branch and master_branch.bitbake_branch:
>> safe_bitbake_branch = 'origin/' +
>> master_branch.bitbake_branch
>>
>
Same pattern here for 'master_branch' to 'default_branch' name change
opportunity.
>
>> diff --git a/layerindex/update_layer.py b/layerindex/update_layer.py
>> index 33c5cfb..6248f78 100644
>> --- a/layerindex/update_layer.py
>> +++ b/layerindex/update_layer.py
>> @@ -250,7 +250,7 @@ def main():
>>
>> parser.add_option("-b", "--branch",
>> help = "Specify branch to update",
>> - action="store", dest="branch", default='master')
>> + action="store", dest="branch", default='')
>> parser.add_option("-l", "--layer",
>> help = "Layer to update",
>> action="store", dest="layer")
>> @@ -304,6 +304,8 @@ def main():
>>
>> logger.setLevel(options.loglevel)
>>
>> + if not options.branch:
>> + options.branch = settings.DEFAULT_BRANCH
>> branch = utils.get_branch(options.branch)
>> if not branch:
>> logger.error("Specified branch %s is not valid" % options.branch)
>> diff --git a/layerindex/urls.py b/layerindex/urls.py
>> index 51a832d..e7b0531 100644
>> --- a/layerindex/urls.py
>> +++ b/layerindex/urls.py
>> @@ -20,6 +20,8 @@ from layerindex.views import LayerListView,
>> LayerReviewListView, LayerReviewDeta
>> from layerindex.models import LayerItem, Recipe, RecipeChangeset
>> from rest_framework import routers
>> from . import restviews
>> +import settings as _settings
>> +_DEFAULT_BRANCH = getattr(_settings, 'DEFAULT_BRANCH', 'master')
>>
>> router = routers.DefaultRouter()
>> router.register(r'branches', restviews.BranchViewSet)
>> @@ -39,23 +41,23 @@ router.register(r'incFiles', restviews.IncFileViewSet)
>>
>> urlpatterns = [
>> re_path(r'^$',
>> - RedirectView.as_view(url=reverse_lazy('layer_list',
>> args=('master',)), permanent=False),
>> + RedirectView.as_view(url=reverse_lazy('layer_list',
>> args=(_DEFAULT_BRANCH,)), permanent=False),
>> name='frontpage'),
>>
>> re_path(r'^api/', include(router.urls)),
>>
>> re_path(r'^layers/$',
>> - RedirectView.as_view(url=reverse_lazy('layer_list',
>> args=('master',)), permanent=False)),
>> + RedirectView.as_view(url=reverse_lazy('layer_list',
>> args=(_DEFAULT_BRANCH,)), permanent=False)),
>> re_path(r'^layer/(?P<slug>[-\.\w]+)/$',
>> - RedirectParamsView.as_view(permanent=False), {'redirect_name':
>> 'layer_item', 'branch': 'master'}),
>> + RedirectParamsView.as_view(permanent=False), {'redirect_name':
>> 'layer_item', 'branch': _DEFAULT_BRANCH}),
>> re_path(r'^recipes/$',
>> - RedirectView.as_view(url=reverse_lazy('recipe_search',
>> args=('master',)), permanent=False)),
>> + RedirectView.as_view(url=reverse_lazy('recipe_search',
>> args=(_DEFAULT_BRANCH,)), permanent=False)),
>> re_path(r'^machines/$',
>> - RedirectView.as_view(url=reverse_lazy('machine_search',
>> args=('master',)), permanent=False)),
>> + RedirectView.as_view(url=reverse_lazy('machine_search',
>> args=(_DEFAULT_BRANCH,)), permanent=False)),
>> re_path(r'^distros/$',
>> - RedirectView.as_view(url=reverse_lazy('distro_search',
>> args=('master',)), permanent=False)),
>> + RedirectView.as_view(url=reverse_lazy('distro_search',
>> args=(_DEFAULT_BRANCH,)), permanent=False)),
>> re_path(r'^classes/$',
>> - RedirectView.as_view(url=reverse_lazy('class_search',
>> args=('master',)), permanent=False)),
>> + RedirectView.as_view(url=reverse_lazy('class_search',
>> args=(_DEFAULT_BRANCH,)), permanent=False)),
>> re_path(r'^submit/$', edit_layer_view, {'template_name':
>> 'layerindex/submitlayer.html'}, name="submit_layer"),
>> re_path(r'^submit/thanks/$',
>> TemplateView.as_view(
>> diff --git a/layerindex/views.py b/layerindex/views.py
>> index 84750f7..d3d8181 100644
>> --- a/layerindex/views.py
>> +++ b/layerindex/views.py
>> @@ -114,7 +114,7 @@ def delete_layer_view(request, template_name, slug):
>> raise PermissionDenied
>> if request.method == 'POST':
>> layeritem.delete()
>> - return HttpResponseRedirect(reverse('layer_list',
>> args=('master',)))
>> + return HttpResponseRedirect(reverse('layer_list',
>> args=(settings.DEFAULT_BRANCH,)))
>> else:
>> return render(request, template_name, {
>> 'object': layeritem,
>> @@ -122,7 +122,7 @@ def delete_layer_view(request, template_name, slug):
>> 'cancel_url': layeritem.get_absolute_url()
>> })
>>
>> -def update_layer_view(request, template_name, branch='master',
>> slug=None):
>> +def update_layer_view(request, template_name,
>> branch=settings.DEFAULT_BRANCH, slug=None):
>> if not (request.user.is_authenticated and request.user.is_staff):
>> raise PermissionDenied
>> return_url = None
>> @@ -157,7 +157,7 @@ def update_layer_view(request, template_name,
>> branch='master', slug=None):
>>
>> return HttpResponseRedirect(reverse_lazy('task_status',
>> kwargs={'task_id': task_id}))
>>
>> -def edit_layer_view(request, template_name, branch='master', slug=None):
>> +def edit_layer_view(request, template_name,
>> branch=settings.DEFAULT_BRANCH, slug=None):
>> return_url = None
>> branchobj = Branch.objects.filter(name=branch)[:1].get()
>> if slug:
>> @@ -444,7 +444,7 @@ class LayerReviewListView(ListView):
>> return super(LayerReviewListView, self).dispatch(request, *args,
>> **kwargs)
>>
>> def get_queryset(self):
>> - return
>> LayerBranch.objects.filter(branch__name='master').filter(layer__status='N').order_by('layer__name')
>> + return
>> LayerBranch.objects.filter(branch__name=settings.DEFAULT_BRANCH).filter(layer__status='N').order_by('layer__name')
>>
>> class LayerDetailView(DetailView):
>> model = LayerItem
>> @@ -492,7 +492,7 @@ class LayerReviewDetailView(LayerDetailView):
>> return super(LayerReviewDetailView, self).dispatch(request,
>> *args, **kwargs)
>>
>> def get_context_data(self, **kwargs):
>> - self.kwargs['branch'] = 'master'
>> + self.kwargs['branch'] = settings.DEFAULT_BRANCH
>> context = super(LayerReviewDetailView,
>> self).get_context_data(**kwargs)
>> return context
>>
>> @@ -738,7 +738,7 @@ class AdvancedRecipeSearchView(ListView):
>> query = Q(**{"%s__icontains" % field: value})
>> else:
>> query = Q(**{"%s" % field: value})
>> - queryset =
>> Recipe.objects.filter(layerbranch__branch__name='master')
>> + queryset =
>> Recipe.objects.filter(layerbranch__branch__name=settings.DEFAULT_BRANCH)
>> layer = self.request.GET.get('layer', '')
>> if layer:
>> queryset = queryset.filter(layerbranch__layer=layer)
>> @@ -825,7 +825,7 @@ class BulkChangeSearchView(AdvancedRecipeSearchView):
>> def get_context_data(self, **kwargs):
>> context = super(BulkChangeSearchView,
>> self).get_context_data(**kwargs)
>> context['changeset'] = self.changeset
>> - context['current_branch'] = 'master'
>> + context['current_branch'] = settings.DEFAULT_BRANCH
>> return context
>>
>>
>> @@ -1341,7 +1341,7 @@ class ClassicRecipeSearchView(RecipeSearchView):
>> filtered = True
>> qs, filtered = self.search_recipe_query(init_qs, query_string,
>> preferred=False)
>> if qreversed:
>> - init_rqs =
>> Recipe.objects.filter(layerbranch__branch__name='master')
>> + init_rqs =
>> Recipe.objects.filter(layerbranch__branch__name=settings.DEFAULT_BRANCH)
>> if layer_ids:
>> init_rqs =
>> init_rqs.filter(layerbranch__layer__id__in=layer_ids)
>> excludeclasses_param =
>> self.request.GET.get('excludeclasses', '')
>> @@ -1735,7 +1735,7 @@ class
>> ComparisonRecipeSelectView(ClassicRecipeSearchView):
>> return True
>>
>> def get_context_data(self, **kwargs):
>> - self.kwargs['branch'] = 'master'
>> + self.kwargs['branch'] = settings.DEFAULT_BRANCH
>> context = super(ComparisonRecipeSelectView,
>> self).get_context_data(**kwargs)
>> recipe = get_object_or_404(ClassicRecipe, pk=self.kwargs['pk'])
>> context['select_for'] = recipe
>> @@ -1761,7 +1761,7 @@ class
>> ComparisonRecipeSelectView(ClassicRecipeSearchView):
>> layer_ids = [int(i) for i in selectedlayers_param.split(',')]
>> else:
>> layer_ids = []
>> - init_qs =
>> Recipe.objects.filter(layerbranch__branch__name='master')
>> + init_qs =
>> Recipe.objects.filter(layerbranch__branch__name=settings.DEFAULT_BRANCH)
>> if layer_ids:
>> init_qs = init_qs.filter(layerbranch__layer__in=layer_ids)
>> qs, _ = self.search_recipe_query(init_qs, query_string,
>> preferred=False)
>> diff --git a/rrs/tools/historytool.py b/rrs/tools/historytool.py
>> index 9f03ade..92e4b04 100755
>> --- a/rrs/tools/historytool.py
>> +++ b/rrs/tools/historytool.py
>> @@ -77,7 +77,7 @@ def rrs_import(args):
>> if not core_layer:
>> logger.error('Unable to find core layer %s' %
>> settings.CORE_LAYER_NAME)
>> return 1
>> - core_layerbranch = core_layer.get_layerbranch('master')
>> + core_layerbranch =
>> core_layer.get_layerbranch(settings.DEFAULT_BRANCH)
>> if not core_layerbranch:
>> logger.error('Unable to find branch master of layer %s' %
>> core_layerbranch.name)
>> return 1
>> @@ -130,7 +130,7 @@ def rrs_remove_duplicates(args):
>> if not core_layer:
>> logger.error('Unable to find core layer %s' %
>> settings.CORE_LAYER_NAME)
>> return 1
>> - core_layerbranch = core_layer.get_layerbranch('master')
>> + core_layerbranch =
>> core_layer.get_layerbranch(settings.DEFAULT_BRANCH)
>> if not core_layerbranch:
>> logger.error('Unable to find branch master of layer %s' %
>> core_layerbranch.name)
>> return 1
>> diff --git a/settings.py b/settings.py
>> index 94b3dd1..08004cb 100644
>> --- a/settings.py
>> +++ b/settings.py
>> @@ -299,3 +299,6 @@ TASK_LOG_DIR = "/tmp/layerindex-task-logs"
>>
>> # Full path to directory where rrs tools stores logs
>> TOOLS_LOG_DIR = ""
>> +
>> +# Default branch name used across the layer index
>> +DEFAULT_BRANCH = 'master'
>> --
>> 2.43.0
>>
>>
[-- Attachment #2: Type: text/html, Size: 28133 bytes --]
^ permalink raw reply
* Re: [PATCH v2] ASoC: dt-bindings: Convert cirrus,cs35l36 to DT schema
From: Rob Herring @ 2026-06-24 18:17 UTC (permalink / raw)
To: david
Cc: David Rhodes, Richard Fitzgerald, Liam Girdwood, Mark Brown,
Krzysztof Kozlowski, Conor Dooley, patches, Bjorn Helgaas,
linux-sound, devicetree, linux-kernel, phone-devel
In-Reply-To: <20260624-dt-cirrus-cs35l36-v2-1-74eccdbd8fe4@ixit.cz>
On Wed, Jun 24, 2026 at 11:02 AM David Heidelberg via B4 Relay
<devnull+david.ixit.cz@kernel.org> wrote:
>
> From: David Heidelberg <david@ixit.cz>
>
> Convert CS35L36 Speaker Amplifier to yaml.
>
> Changes:
> - maintainers email to the generic Cirrus email
> - Both the codec and downstream worked just fine without
> VP-supply provided. Align with datasheet for similar models.
> - add dai-common.yaml to cover for '#sound-dai-cells',
> 'sound-name-prefix'
>
> Reviewed-by: David Rhodes <David.Rhodes@cirrus.com>
If you are going to take stuff I haven't fixed:
Assisted-by: OpenAI:gpt-4
(I don't remember the exact flavor I used)
> Co-developed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: David Heidelberg <david@ixit.cz>
> ---
> Relevant for Pixel 3 / 3XL / 4.
> ---
> Changes in v2:
> - Rename the commit. (Mark)
> - Link to v1: https://lore.kernel.org/r/20260618-dt-cirrus-cs35l36-v1-1-1a43515666ad@ixit.cz
> ---
> .../devicetree/bindings/sound/cirrus,cs35l36.yaml | 224 +++++++++++++++++++++
> .../devicetree/bindings/sound/cs35l36.txt | 168 ----------------
> 2 files changed, 224 insertions(+), 168 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
> new file mode 100644
> index 0000000000000..af0acaaefb68e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
> @@ -0,0 +1,224 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/cirrus,cs35l36.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logic CS35L36 Speaker Amplifier
> +
> +maintainers:
> + - patches@opensource.cirrus.com
> + - Bjorn Helgaas <bhelgaas@google.com>
Bjorn is not correct. Generally we want a person, not a company list.
> +
> +description: |
Don't need '|'.
> + CS35L36 is a boosted mono Class D amplifier
> +
> +allOf:
> + - $ref: /schemas/sound/dai-common.yaml#
> +
> +properties:
> + compatible:
> + enum:
> + - cirrus,cs35l36
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + VA-supply:
> + description: Voltage regulator of analog internal section
> +
> + VP-supply:
> + description: Voltage regulator of boost converter
> +
> + reset-gpios:
> + maxItems: 1
> +
> + cirrus,boost-ctl-millivolt:
> + description: Boost converter output voltage in millivolts (step 50)
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 2550
> + maximum: 12000
> +
> + cirrus,boost-peak-milliamp:
> + description: Boost-converter peak current limit in mA (step 50)
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 4500
> + minimum: 1600
> + maximum: 4500
> +
> + cirrus,boost-ind-nanohenry:
> + description: Initial inductor estimation reference value in nanohenry (1000=1μH, 1200=1.2μH)
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 1000
> +
> + cirrus,multi-amp-mode:
> + description: Hi-Z ASP port when more than one amplifier in system.
> + type: boolean
> +
> + cirrus,boost-ctl-select:
> + description: Boost converter control source selection
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 0x01
> + enum:
> + - 0x00 # Control Port
> + - 0x01 # Class
> + - 0x10 # Sync
> +
> + cirrus,amp-pcm-inv:
> + description: Invert incoming PCM data when true.
> + type: boolean
> +
> + cirrus,imon-pol-inv:
> + description: Invert polarity of outbound IMON feedback when true.
> + type: boolean
> +
> + cirrus,vmon-pol-inv:
> + description: Invert polarity of outbound VMON feedback when true.
> + type: boolean
> +
> + cirrus,dcm-mode-enable:
> + description: Enable boost converter automatic Discontinuous Conduction Mode.
> + type: boolean
> +
> + cirrus,weak-fet-disable:
> + description: Reduce output driver strength in Weak-FET Drive Mode when true.
> + type: boolean
> +
> + cirrus,classh-wk-fet-delay:
> + description: Weak-FET entry delay in ms
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 100
How? Range is 0-7.
> + enum:
> + - 0 # 0
> + - 1 # 5
> + - 2 # 10
> + - 3 # 50
> + - 4 # 100
> + - 5 # 200
> + - 6 # 500
> + - 7 # 1000
> +
> + cirrus,classh-weak-fet-thld-millivolt:
> + description: Weak-FET drive threshold in mV
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700]
> +
> + cirrus,temp-warn-threshold:
> + description: Overtemperature warning threshold
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 2
> + enum:
> + - 0 # 105°C
> + - 1 # 115°C
> + - 2 # 125°C
> + - 3 # 135°C
> +
> + cirrus,irq-drive-select:
> + description: Interrupt output driver type
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 1
> + enum:
> + - 0 # open-drain
> + - 1 # push-pull
> +
> + cirrus,irq-gpio-select:
> + description: Programmable IRQ pin selection
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum:
> + - 0 # PDM_DATA/SWIRE_SD/INT
> + - 1 # GPIO
> +
> + cirrus,vpbr-config:
> + description: Brownout prevention configuration sub-node
> + type: object
> + additionalProperties: false
> +
> + properties:
> + cirrus,vpbr-en:
> + description: VBST brownout prevention enable
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 0
> + enum:
> + - 0 # disabled
> + - 1 # enabled
> +
> + cirrus,vpbr-thld:
> + description: Initial VPBR threshold voltage
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> + cirrus,vpbr-atk-rate:
> + description: Attenuation attack step rate
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> + cirrus,vpbr-atk-vol:
> + description: VP brownout prevention step size
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> + cirrus,vpbr-max-attn:
> + description: Maximum attenuation during VP brownout prevention
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> + cirrus,vpbr-wait:
> + description: Delay between brownout clearance and attenuation release
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> + cirrus,vpbr-rel-rate:
> + description: Attenuation release step rate
> + $ref: /schemas/types.yaml#/definitions/uint32
> +
> + cirrus,vpbr-mute-en:
> + description: Mute audio if maximum attenuation reached
> + $ref: /schemas/types.yaml#/definitions/uint32
Constraints on any of these?
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - VA-supply
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + codec@40 {
> + compatible = "cirrus,cs35l36";
> + reg = <0x40>;
> + VA-supply = <&dummy_vreg>;
> + VP-supply = <&dummy_vreg>;
> + reset-gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>;
> + interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
> +
> + cirrus,boost-ind-nanohenry = <1000>;
> + cirrus,boost-ctl-millivolt = <10000>;
> + cirrus,boost-peak-milliamp = <4500>;
> + cirrus,boost-ctl-select = <0x00>;
> + cirrus,weak-fet-delay = <4>;
> + cirrus,weak-fet-thld = <0x01>;
> + cirrus,temp-warn-threshold = <1>;
> + cirrus,multi-amp-mode;
> + cirrus,irq-drive-select = <1>;
> + cirrus,irq-gpio-select = <0x01>;
> +
> + cirrus,vpbr-config {
> + cirrus,vpbr-en = <0>;
> + cirrus,vpbr-thld = <0x05>;
> + cirrus,vpbr-atk-rate = <0x02>;
> + cirrus,vpbr-atk-vol = <0x01>;
> + cirrus,vpbr-max-attn = <0x09>;
> + cirrus,vpbr-wait = <0x01>;
> + cirrus,vpbr-rel-rate = <0x05>;
> + cirrus,vpbr-mute-en = <0x00>;
> + };
> + };
> + };
> +...
> diff --git a/Documentation/devicetree/bindings/sound/cs35l36.txt b/Documentation/devicetree/bindings/sound/cs35l36.txt
> deleted file mode 100644
> index d34117b8558e5..0000000000000
> --- a/Documentation/devicetree/bindings/sound/cs35l36.txt
> +++ /dev/null
> @@ -1,168 +0,0 @@
> -CS35L36 Speaker Amplifier
> -
> -Required properties:
> -
> - - compatible : "cirrus,cs35l36"
> -
> - - reg : the I2C address of the device for I2C
> -
> - - VA-supply, VP-supply : power supplies for the device,
> - as covered in
> - Documentation/devicetree/bindings/regulator/regulator.txt.
> -
> - - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost
> - converter's output voltage in mV. The range is from 2550mV to 12000mV with
> - increments of 50mV.
> - (Default) VP
> -
> - - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA.
> - Configures the peak current by monitoring the current through the boost FET.
> - Range starts at 1600mA and goes to a maximum of 4500mA with increments of
> - 50mA.
> - (Default) 4.50 Amps
> -
> - - cirrus,boost-ind-nanohenry : Inductor estimation LBST reference value.
> - Seeds the digital boost converter's inductor estimation block with the initial
> - inductance value to reference.
> -
> - 1000 = 1uH (Default)
> - 1200 = 1.2uH
> -
> -Optional properties:
> - - cirrus,multi-amp-mode : Boolean to determine if there are more than
> - one amplifier in the system. If more than one it is best to Hi-Z the ASP
> - port to prevent bus contention on the output signal
> -
> - - cirrus,boost-ctl-select : Boost converter control source selection.
> - Selects the source of the BST_CTL target VBST voltage for the boost
> - converter to generate.
> - 0x00 - Control Port Value
> - 0x01 - Class H Tracking (Default)
> - 0x10 - MultiDevice Sync Value
> -
> - - cirrus,amp-pcm-inv : Boolean to determine Amplifier will invert incoming
> - PCM data
> -
> - - cirrus,imon-pol-inv : Boolean to determine Amplifier will invert the
> - polarity of outbound IMON feedback data
> -
> - - cirrus,vmon-pol-inv : Boolean to determine Amplifier will invert the
> - polarity of outbound VMON feedback data
> -
> - - cirrus,dcm-mode-enable : Boost converter automatic DCM Mode enable.
> - This enables the digital boost converter to operate in a low power
> - (Discontinuous Conduction) mode during low loading conditions.
> -
> - - cirrus,weak-fet-disable : Boolean : The strength of the output drivers is
> - reduced when operating in a Weak-FET Drive Mode and must not be used to drive
> - a large load.
> -
> - - cirrus,classh-wk-fet-delay : Weak-FET entry delay. Controls the delay
> - (in ms) before the Class H algorithm switches to the weak-FET voltage
> - (after the audio falls and remains below the value specified in WKFET_AMP_THLD).
> -
> - 0 = 0ms
> - 1 = 5ms
> - 2 = 10ms
> - 3 = 50ms
> - 4 = 100ms (Default)
> - 5 = 200ms
> - 6 = 500ms
> - 7 = 1000ms
> -
> - - cirrus,classh-weak-fet-thld-millivolt : Weak-FET amplifier drive threshold.
> - Configures the signal threshold at which the PWM output stage enters
> - weak-FET operation. The range is 50mV to 700mV in 50mV increments.
> -
> - - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold.
> - Configures the threshold at which the overtemperature warning condition occurs.
> - When the threshold is met, the overtemperature warning attenuation is applied
> - and the TEMP_WARN_EINT interrupt status bit is set.
> - If TEMP_WARN_MASK = 0, INTb is asserted.
> -
> - 0 = 105C
> - 1 = 115C
> - 2 = 125C (Default)
> - 3 = 135C
> -
> - - cirrus,irq-drive-select : Selects the driver type of the selected interrupt
> - output.
> -
> - 0 = Open-drain
> - 1 = Push-pull (Default)
> -
> - - cirrus,irq-gpio-select : Selects the pin to serve as the programmable
> - interrupt output.
> -
> - 0 = PDM_DATA / SWIRE_SD / INT (Default)
> - 1 = GPIO
> -
> -Optional properties for the "cirrus,vpbr-config" Sub-node
> -
> - - cirrus,vpbr-en : VBST brownout prevention enable. Configures whether the
> - VBST brownout prevention algorithm is enabled or disabled.
> -
> - 0 = VBST brownout prevention disabled (default)
> - 1 = VBST brownout prevention enabled
> -
> - See Section 7.31.1 VPBR Config for configuration options & further details
> -
> - - cirrus,vpbr-thld : Initial VPBR threshold. Configures the VP brownout
> - threshold voltage
> -
> - - cirrus,cirrus,vpbr-atk-rate : Attenuation attack step rate. Configures the
> - amount delay between consecutive volume attenuation steps when a brownout
> - condition is present and the VP brownout condition is in an attacking state.
> -
> - - cirrus,vpbr-atk-vol : VP brownout prevention step size. Configures the VP
> - brownout prevention attacking attenuation step size when operating in either
> - digital volume or analog gain modes.
> -
> - - cirrus,vpbr-max-attn : Maximum attenuation that the VP brownout prevention
> - can apply to the audio signal.
> -
> - - cirrus,vpbr-wait : Configures the delay time between a brownout condition
> - no longer being present and the VP brownout prevention entering an attenuation
> - release state.
> -
> - - cirrus,vpbr-rel-rate : Attenuation release step rate. Configures the delay
> - between consecutive volume attenuation release steps when a brownout condition
> - is not longer present and the VP brownout is in an attenuation release state.
> -
> - - cirrus,vpbr-mute-en : During the attack state, if the vpbr-max-attn value
> - is reached, the error condition still remains, and this bit is set, the audio
> - is muted.
> -
> -Example:
> -
> -cs35l36: cs35l36@40 {
> - compatible = "cirrus,cs35l36";
> - reg = <0x40>;
> - VA-supply = <&dummy_vreg>;
> - VP-supply = <&dummy_vreg>;
> - reset-gpios = <&gpio0 54 0>;
> - interrupt-parent = <&gpio8>;
> - interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
> -
> - cirrus,boost-ind-nanohenry = <1000>;
> - cirrus,boost-ctl-millivolt = <10000>;
> - cirrus,boost-peak-milliamp = <4500>;
> - cirrus,boost-ctl-select = <0x00>;
> - cirrus,weak-fet-delay = <0x04>;
> - cirrus,weak-fet-thld = <0x01>;
> - cirrus,temp-warn-threshold = <0x01>;
> - cirrus,multi-amp-mode;
> - cirrus,irq-drive-select = <0x01>;
> - cirrus,irq-gpio-select = <0x01>;
> -
> - cirrus,vpbr-config {
> - cirrus,vpbr-en = <0x00>;
> - cirrus,vpbr-thld = <0x05>;
> - cirrus,vpbr-atk-rate = <0x02>;
> - cirrus,vpbr-atk-vol = <0x01>;
> - cirrus,vpbr-max-attn = <0x09>;
> - cirrus,vpbr-wait = <0x01>;
> - cirrus,vpbr-rel-rate = <0x05>;
> - cirrus,vpbr-mute-en = <0x00>;
> - };
> -};
>
> ---
> base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
> change-id: 20260618-dt-cirrus-cs35l36-99c466fb13fd
>
> Best regards,
> --
> David Heidelberg <david@ixit.cz>
>
>
>
^ permalink raw reply
* Re: [PATCH] cxl: fix mailbox return code description typo
From: Dave Jiang @ 2026-06-24 18:17 UTC (permalink / raw)
To: Yousef Alhouseen, Alison Schofield, Vishal Verma
Cc: Dan Williams, Ira Weiny, Jonathan Cameron, Davidlohr Bueso,
Li Ming, linux-cxl, linux-kernel
In-Reply-To: <20260624122835.5656-1-alhouseenyousef@gmail.com>
On 6/24/26 5:28 AM, Yousef Alhouseen wrote:
> Fix a typo in the CXL mailbox command return code description for the
> interrupted-command case.
>
> Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
> drivers/cxl/cxlmem.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index ed419d0c5..503ae2864 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -183,7 +183,7 @@ static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
> C(MBUNSUPPORTED, -ENXIO, "unsupported on the mailbox it was issued on"),\
> C(PAYLOADLEN, -ENXIO, "invalid payload length"), \
> C(LOG, -ENXIO, "invalid or unsupported log page"), \
> - C(INTERRUPTED, -ENXIO, "asynchronous event occured"), \
> + C(INTERRUPTED, -ENXIO, "asynchronous event occurred"), \
> C(FEATUREVERSION, -ENXIO, "unsupported feature version"), \
> C(FEATURESELVALUE, -ENXIO, "unsupported feature selection value"), \
> C(FEATURETRANSFERIP, -ENXIO, "feature transfer in progress"), \
^ permalink raw reply
* Re: [syzbot] [btrfs?] kernel BUG in btrfs_alloc_ordered_extent
From: syzbot @ 2026-06-24 18:17 UTC (permalink / raw)
To: clm, dsterba, linux-btrfs, linux-kernel, syzkaller-bugs
In-Reply-To: <6a39275b.5031c61f.34f2da.0001.GAE@google.com>
syzbot has found a reproducer for the following issue on:
HEAD commit: 840ef6c78e6a Merge tag 'nfs-for-7.2-1' of git://git.linux-..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=154b6591580000
kernel config: https://syzkaller.appspot.com/x/.config?x=4b70f7c595323ba2
dashboard link: https://syzkaller.appspot.com/bug?extid=ba2afde329fc27e3f22e
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=1005b21c580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=11e168dc580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/21afc0da735a/disk-840ef6c7.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/c89b2edbb4f6/vmlinux-840ef6c7.xz
kernel image: https://storage.googleapis.com/syzbot-assets/bef6a8464d41/bzImage-840ef6c7.xz
mounted in repro: https://storage.googleapis.com/syzbot-assets/33eb3874c00f/mount_0.gz
fsck result: failed (log: https://syzkaller.appspot.com/x/fsck.log?x=11009d0e580000)
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+ba2afde329fc27e3f22e@syzkaller.appspotmail.com
------------[ cut here ]------------
kernel BUG at fs/btrfs/ordered-data.c:264!
Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 1 UID: 0 PID: 6897 Comm: syz.4.79 Not tainted syzkaller #0 PREEMPT_{RT,(full)}
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026
RIP: 0010:insert_ordered_extent fs/btrfs/ordered-data.c:261 [inline]
RIP: 0010:btrfs_alloc_ordered_extent+0x943/0xad0 fs/btrfs/ordered-data.c:336
Code: 62 8d ba 08 01 00 00 b9 ef ff ff ff 49 c7 c0 20 15 97 8b 4d 89 f9 ff 75 00 41 54 41 55 41 56 53 e8 a2 54 37 fd 48 83 c4 28 90 <0f> 0b e8 c6 1d d2 fd 48 c7 c7 80 0c 97 8b 48 c7 c6 e0 0c 97 8b 48
RSP: 0018:ffffc90006e0e890 EFLAGS: 00010296
RAX: 45aae1616d386000 RBX: 0000000000069000 RCX: 1ffff92000dc1cf0
RDX: 0000000000000003 RSI: ffffffff8d89f46f RDI: ffff888028618000
RBP: ffff88806168cfe0 R08: 0000000000000000 R09: 0000000000000000
R10: dffffc0000000000 R11: fffff52000dc1c61 R12: 0000000000069000
R13: 0000000000004000 R14: 0000000000001089 R15: 0000000000004000
FS: 00007f50b1dee6c0(0000) GS:ffff88812621d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007efc8ea98d50 CR3: 0000000045856000 CR4: 00000000003526f0
Call Trace:
<TASK>
cow_one_range fs/btrfs/inode.c:1241 [inline]
cow_file_range+0x744/0x12a0 fs/btrfs/inode.c:1403
fallback_to_cow+0x5ea/0xa00 fs/btrfs/inode.c:1751
run_delalloc_nocow+0x110c/0x17a0 fs/btrfs/inode.c:2181
btrfs_run_delalloc_range+0xbe4/0x1c20 fs/btrfs/inode.c:2419
writepage_delalloc+0x104d/0x1ba0 fs/btrfs/extent_io.c:1558
extent_writepage fs/btrfs/extent_io.c:1930 [inline]
extent_write_cache_pages fs/btrfs/extent_io.c:2593 [inline]
btrfs_writepages+0x1667/0x28b0 fs/btrfs/extent_io.c:2725
do_writepages+0x338/0x560 mm/page-writeback.c:2571
filemap_writeback mm/filemap.c:387 [inline]
filemap_fdatawrite_range+0x1f2/0x300 mm/filemap.c:412
btrfs_fdatawrite_range+0x54/0xf0 fs/btrfs/file.c:3884
btrfs_direct_write+0x6a0/0xc30 fs/btrfs/direct-io.c:1038
btrfs_do_write_iter+0x329/0x790 fs/btrfs/file.c:1449
do_iter_readv_writev+0x624/0x8d0 fs/read_write.c:-1
vfs_writev+0x34c/0x990 fs/read_write.c:1058
do_pwritev fs/read_write.c:1154 [inline]
__do_sys_pwritev2 fs/read_write.c:1212 [inline]
__se_sys_pwritev2+0x17a/0x2a0 fs/read_write.c:1203
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f50b278ce59
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f50b1dee028 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
RAX: ffffffffffffffda RBX: 00007f50b2a05fa0 RCX: 00007f50b278ce59
RDX: 0000000000000020 RSI: 0000200000000240 RDI: 0000000000000004
RBP: 00007f50b2822e6f R08: 0000000000000000 R09: 0000000000000003
R10: 0000000000003000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f50b2a06038 R14: 00007f50b2a05fa0 R15: 00007ffce174b008
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:insert_ordered_extent fs/btrfs/ordered-data.c:261 [inline]
RIP: 0010:btrfs_alloc_ordered_extent+0x943/0xad0 fs/btrfs/ordered-data.c:336
Code: 62 8d ba 08 01 00 00 b9 ef ff ff ff 49 c7 c0 20 15 97 8b 4d 89 f9 ff 75 00 41 54 41 55 41 56 53 e8 a2 54 37 fd 48 83 c4 28 90 <0f> 0b e8 c6 1d d2 fd 48 c7 c7 80 0c 97 8b 48 c7 c6 e0 0c 97 8b 48
RSP: 0018:ffffc90006e0e890 EFLAGS: 00010296
RAX: 45aae1616d386000 RBX: 0000000000069000 RCX: 1ffff92000dc1cf0
RDX: 0000000000000003 RSI: ffffffff8d89f46f RDI: ffff888028618000
RBP: ffff88806168cfe0 R08: 0000000000000000 R09: 0000000000000000
R10: dffffc0000000000 R11: fffff52000dc1c61 R12: 0000000000069000
R13: 0000000000004000 R14: 0000000000001089 R15: 0000000000004000
FS: 00007f50b1dee6c0(0000) GS:ffff88812621d000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007efc8ea98d50 CR3: 0000000045856000 CR4: 00000000003526f0
---
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
^ permalink raw reply
* [PATCH 11/11] xfs_scrub: warn about difficult rtgroup repairs
From: Darrick J. Wong @ 2026-06-24 18:17 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Codex noticed that rtgroup metadata repairs can be difficult (e.g.
rtrmap) but we don't ever warn the user about that. Scrub does that for
per-AG and fs metadata, so do that here too.
Cc: <linux-xfs@vger.kernel.org> # v6.13.0
Fixes: 241d915d69d4ae ("xfs_scrub: scrub realtime allocation group metadata")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase2.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/scrub/phase2.c b/scrub/phase2.c
index 8de77429f05d60..f382c1367be474 100644
--- a/scrub/phase2.c
+++ b/scrub/phase2.c
@@ -251,6 +251,7 @@ scan_rtgroup_metadata(
struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
struct scan_ctl *sctl = arg;
char descr[DESCR_BUFSZ];
+ unsigned int difficulty;
bool defer_repairs;
int ret;
@@ -281,7 +282,14 @@ scan_rtgroup_metadata(
sctl->aborted = true;
return;
}
+ if (defer_repairs)
+ goto defer;
+ /* Complain about metadata corruptions that might not be fixable. */
+ difficulty = repair_item_difficulty(&sri);
+ warn_repair_difficulties(ctx, difficulty, descr);
+
+defer:
/* Everything else gets fixed during phase 4. */
ret = defer_fs_repair(ctx, &sri);
if (ret) {
^ permalink raw reply related
* [PATCH 10/11] xfs_scrub: don't leak the autofsck fsproperty handle
From: Darrick J. Wong @ 2026-06-24 18:17 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Codex notices that we leak the fsproperty handle if the filesystem
doesn't actually have the property set. Fix that by moving the free
call; it can handle a totally nulled out structure.
Cc: <linux-xfs@vger.kernel.org> # v6.10.0
Fixes: 9451b5ee0d0d2d ("xfs_scrub: allow sysadmin to control background scrubs")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase1.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/scrub/phase1.c b/scrub/phase1.c
index 6ac59264b50bb7..620a12393b3658 100644
--- a/scrub/phase1.c
+++ b/scrub/phase1.c
@@ -178,8 +178,6 @@ mode_from_autofsck(
break;
}
- fsprops_free_handle(&fph);
-
summarize:
switch (ctx->mode) {
case SCRUB_MODE_NONE:
@@ -200,6 +198,7 @@ mode_from_autofsck(
break;
}
+ fsprops_free_handle(&fph);
return;
no_property:
/*
^ permalink raw reply related
* Re: [PATCH] net: sparx5: unregister blocking notifier on init failure
From: Simon Horman @ 2026-06-24 18:16 UTC (permalink / raw)
To: Haoxiang Li
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, Steen.Hegelund,
daniel.machon, UNGLinuxDriver, kees, bjarni.jonasson,
lars.povlsen, netdev, linux-arm-kernel, linux-kernel, stable
In-Reply-To: <20260623115714.2192074-1-haoxiang_li2024@163.com>
On Tue, Jun 23, 2026 at 07:57:14PM +0800, Haoxiang Li wrote:
> sparx5_register_notifier_blocks() registers the switchdev blocking
> notifier before allocating the ordered workqueue. If the workqueue
> allocation fails, the error path unregisters the switchdev and netdevice
> notifiers, but leaves the blocking notifier registered.
>
> Add a separate error label for the workqueue allocation failure path and
> unregister the switchdev blocking notifier there.
>
> Fixes: d6fce5141929 ("net: sparx5: add switching support")
> Cc: stable@vger.kernel.org
> Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* [PATCH 09/11] xfs_scrub: account for reflinked realtime file data
From: Darrick J. Wong @ 2026-06-24 18:16 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
When we added reflink to the rt device, we forgot to account for
multiply owned space in the phase 7 accounting. Luckily, Codex noticed
for us.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase7.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/scrub/phase7.c b/scrub/phase7.c
index 4a25c521fa0c76..375ba0632c353b 100644
--- a/scrub/phase7.c
+++ b/scrub/phase7.c
@@ -27,7 +27,8 @@ struct summary_counts {
unsigned long long dbytes; /* data dev bytes */
unsigned long long rbytes; /* rt dev bytes */
unsigned long long lbytes; /* log dev bytes */
- unsigned long long next_phys; /* next phys bytes we see? */
+ unsigned long long next_dphys; /* next phys bytes we see on data dev? */
+ unsigned long long next_rphys; /* next phys bytes we see on rt dev? */
unsigned long long agbytes; /* freespace bytes */
/* Free space histogram, in fsb */
@@ -120,16 +121,21 @@ count_block_summary(
break;
case XFS_DEV_RT:
/* Count realtime extents. */
+ if (counts->next_rphys >= fsmap->fmr_physical + len)
+ return 0;
+ else if (counts->next_rphys > fsmap->fmr_physical)
+ len -= counts->next_rphys - fsmap->fmr_physical;
counts->rbytes += len;
+ counts->next_rphys = fsmap->fmr_physical + fsmap->fmr_length;
break;
case XFS_DEV_DATA:
/* Count datadev extents. */
- if (counts->next_phys >= fsmap->fmr_physical + len)
+ if (counts->next_dphys >= fsmap->fmr_physical + len)
return 0;
- else if (counts->next_phys > fsmap->fmr_physical)
- len -= counts->next_phys - fsmap->fmr_physical;
+ else if (counts->next_dphys > fsmap->fmr_physical)
+ len -= counts->next_dphys - fsmap->fmr_physical;
counts->dbytes += len;
- counts->next_phys = fsmap->fmr_physical + fsmap->fmr_length;
+ counts->next_dphys = fsmap->fmr_physical + fsmap->fmr_length;
break;
}
^ permalink raw reply related
* [PATCH 08/11] xfs_scrub: account only data extent tail after an overlap
From: Darrick J. Wong @ 2026-06-24 18:16 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Codex points out that the fsmap overlap handling in phase7 isn't quite
right -- if we already saw part of the current fsmapping, we should
*subtract* the overlap, not set the length to it! Fix that.
Cc: <linux-xfs@vger.kernel.org> # v4.15.0
Fixes: 698c6c7cb8ba75 ("xfs_scrub: check summary counters")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase7.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scrub/phase7.c b/scrub/phase7.c
index 3b765931a304a9..4a25c521fa0c76 100644
--- a/scrub/phase7.c
+++ b/scrub/phase7.c
@@ -127,7 +127,7 @@ count_block_summary(
if (counts->next_phys >= fsmap->fmr_physical + len)
return 0;
else if (counts->next_phys > fsmap->fmr_physical)
- len = counts->next_phys - fsmap->fmr_physical;
+ len -= counts->next_phys - fsmap->fmr_physical;
counts->dbytes += len;
counts->next_phys = fsmap->fmr_physical + fsmap->fmr_length;
break;
^ permalink raw reply related
* Re: [PATCH] sh: Use generic OHCI platform provider symbol
From: Geert Uytterhoeven @ 2026-06-24 18:16 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Yoshinori Sato, Rich Felker, John Paul Adrian Glaubitz, linux-sh,
linux-kernel
In-Reply-To: <20260624081926.12426-1-pengpeng@iscas.ac.cn>
On Wed, 24 Jun 2026 at 19:56, Pengpeng Hou <pengpeng@iscas.ac.cn> wrote:
> The old SuperH-specific `USB_OHCI_SH` provider symbol no longer carries
> an OHCI provider object. The current platform OHCI provider is
> `USB_OHCI_HCD_PLATFORM`, which builds ohci-platform.o.
>
> Several SH CPU subtypes still select `USB_OHCI_SH`, and the
> sh7757lcr defconfig still enables it directly. Switch both the subtype
> selects and the defconfig to `USB_OHCI_HCD_PLATFORM` so the intended OHCI
> provider remains reachable when `USB_OHCI_HCD` is enabled.
>
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Fixes: 4f6dfc2136fb2e8d ("usb: remove the dead USB_OHCI_SH option")
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
It's a pity people sometimes don't take into account review comments
before applying patches...
https://lore.kernel.org/CAMuHMdVM3BpvVD3c4gp1OidnwF5zFd4MJecij7zWBnahzNaSNw@mail.gmail.com/
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH 07/11] xfs_scrub: report external log space usage in phase 7
From: Darrick J. Wong @ 2026-06-24 18:16 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Let's report the external log space attached to a mounted filesystem so
that the user knows we found it.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase7.c | 73 +++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 25 deletions(-)
diff --git a/scrub/phase7.c b/scrub/phase7.c
index e16ca28aa28371..3b765931a304a9 100644
--- a/scrub/phase7.c
+++ b/scrub/phase7.c
@@ -26,6 +26,7 @@
struct summary_counts {
unsigned long long dbytes; /* data dev bytes */
unsigned long long rbytes; /* rt dev bytes */
+ unsigned long long lbytes; /* log dev bytes */
unsigned long long next_phys; /* next phys bytes we see? */
unsigned long long agbytes; /* freespace bytes */
@@ -68,21 +69,18 @@ count_block_summary(
void *arg)
{
struct summary_counts *counts;
- bool is_rt = false;
+ enum xfs_device dev;
unsigned long long len;
int ret;
- if (ctx->mnt.fsgeom.rtstart) {
- if (fsmap->fmr_device == XFS_DEV_LOG)
- return 0;
- if (fsmap->fmr_device == XFS_DEV_RT)
- is_rt = true;
- } else {
- if (fsmap->fmr_device == ctx->fsinfo.fs_logdev)
- return 0;
- if (fsmap->fmr_device == ctx->fsinfo.fs_rtdev)
- is_rt = true;
- }
+ if (ctx->mnt.fsgeom.rtstart)
+ dev = fsmap->fmr_device;
+ else if (fsmap->fmr_device == ctx->fsinfo.fs_logdev)
+ dev = XFS_DEV_LOG;
+ else if (fsmap->fmr_device == ctx->fsinfo.fs_rtdev)
+ dev = XFS_DEV_RT;
+ else
+ dev = XFS_DEV_DATA;
counts = ptvar_get((struct ptvar *)arg, &ret);
if (ret) {
@@ -95,10 +93,16 @@ count_block_summary(
uint64_t blocks;
blocks = cvt_b_to_off_fsbt(&ctx->mnt, fsmap->fmr_length);
- if (is_rt)
+ switch (dev) {
+ case XFS_DEV_RT:
hist_add(&counts->rtdev_hist, blocks);
- else
+ break;
+ case XFS_DEV_DATA:
hist_add(&counts->datadev_hist, blocks);
+ break;
+ case XFS_DEV_LOG:
+ break;
+ }
return 0;
}
@@ -109,10 +113,16 @@ count_block_summary(
fsmap->fmr_owner == XFS_FMR_OWN_AG)
counts->agbytes += fsmap->fmr_length;
- if (is_rt) {
+ switch (dev) {
+ case XFS_DEV_LOG:
+ /* Count external log */
+ counts->lbytes += len;
+ break;
+ case XFS_DEV_RT:
/* Count realtime extents. */
counts->rbytes += len;
- } else {
+ break;
+ case XFS_DEV_DATA:
/* Count datadev extents. */
if (counts->next_phys >= fsmap->fmr_physical + len)
return 0;
@@ -120,6 +130,7 @@ count_block_summary(
len = counts->next_phys - fsmap->fmr_physical;
counts->dbytes += len;
counts->next_phys = fsmap->fmr_physical + fsmap->fmr_length;
+ break;
}
return 0;
@@ -137,6 +148,7 @@ add_summaries(
total->dbytes += item->dbytes;
total->rbytes += item->rbytes;
+ total->lbytes += item->lbytes;
total->agbytes += item->agbytes;
hist_import(&total->datadev_hist, &item->datadev_hist);
@@ -162,8 +174,10 @@ phase7_func(
unsigned long long used_data;
unsigned long long used_rt;
unsigned long long used_files;
+ unsigned long long used_log;
unsigned long long stat_data;
unsigned long long stat_rt;
+ unsigned long long stat_log;
uint64_t counted_inodes = 0;
unsigned long long absdiff;
unsigned long long d_blocks;
@@ -241,8 +255,13 @@ phase7_func(
/* Report on what we found. */
used_data = cvt_off_fsb_to_b(&ctx->mnt, d_blocks - d_bfree);
used_rt = cvt_off_fsb_to_b(&ctx->mnt, r_blocks - r_bfree);
+ if (ctx->mnt.fsgeom.logstart == 0)
+ used_log = cvt_off_fsb_to_b(&ctx->mnt, l_blocks);
+ else
+ used_log = 0;
stat_data = totalcount.dbytes;
stat_rt = totalcount.rbytes;
+ stat_log = totalcount.lbytes;
/*
* Complain if the counts are off by more than 10% unless
@@ -252,28 +271,32 @@ phase7_func(
complain = verbose;
complain |= !within_range(ctx, stat_data, used_data, absdiff, 1, 10,
_("data blocks"));
+ complain |= !within_range(ctx, stat_log, used_log, absdiff, 1, 10,
+ _("external log blocks"));
complain |= !within_range(ctx, stat_rt, used_rt, absdiff, 1, 10,
_("realtime blocks"));
complain |= !within_range(ctx, counted_inodes, used_files, 100, 1, 10,
_("inodes"));
if (complain) {
- double d, r, i;
- char *du, *ru, *iu;
+ double d, r, i, l;
+ char *du, *ru, *iu, *lu;
- if (used_rt || stat_rt) {
+ if (used_rt || stat_rt || used_log) {
d = auto_space_units(used_data, &du);
r = auto_space_units(used_rt, &ru);
+ l = auto_space_units(used_log, &lu);
i = auto_units(used_files, &iu, &ip);
fprintf(stdout,
-_("%.1f%s data used; %.1f%s realtime data used; %.*f%s inodes used.\n"),
- d, du, r, ru, ip, i, iu);
+_("%.1f%s data used; %.1f%s realtime data used; %.1f%s external log used; %.*f%s inodes used.\n"),
+ d, du, r, ru, l, lu, ip, i, iu);
d = auto_space_units(stat_data, &du);
r = auto_space_units(stat_rt, &ru);
+ l = auto_space_units(stat_log, &lu);
i = auto_units(counted_inodes, &iu, &ip);
fprintf(stdout,
-_("%.1f%s data found; %.1f%s realtime data found; %.*f%s inodes found.\n"),
- d, du, r, ru, ip, i, iu);
+_("%.1f%s data found; %.1f%s realtime data found; %.1f%s external log found; %.*f%s inodes found.\n"),
+ d, du, r, ru, l, lu, ip, i, iu);
} else {
d = auto_space_units(used_data, &du);
i = auto_units(used_files, &iu, &ip);
@@ -314,13 +337,13 @@ _("%.*f%s inodes counted; %.*f%s inodes checked.\n"),
*/
if (ctx->bytes_checked &&
(verbose ||
- !within_range(ctx, used_data + used_rt,
+ !within_range(ctx, used_data + used_rt + used_log,
ctx->bytes_checked, absdiff, 1, 10,
_("verified blocks")))) {
double b1, b2;
char *b1u, *b2u;
- b1 = auto_space_units(used_data + used_rt, &b1u);
+ b1 = auto_space_units(used_data + used_rt + used_log, &b1u);
b2 = auto_space_units(ctx->bytes_checked, &b2u);
fprintf(stdout,
_("%.1f%s data counted; %.1f%s data verified.\n"),
^ permalink raw reply related
* [PATCH 06/11] xfs_scrub: warn about incomplete repairs if we never get to them
From: Darrick J. Wong @ 2026-06-24 18:16 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
If the final pass at repairs fails because the kernel says the
filesystem is busy, we should emit this error to the caller instead of
dropping it silently.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/repair.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/scrub/repair.c b/scrub/repair.c
index 5d821655877b80..fdefc2131aa453 100644
--- a/scrub/repair.c
+++ b/scrub/repair.c
@@ -110,7 +110,10 @@ repair_epilogue(
case EDEADLOCK:
case EBUSY:
/* Filesystem is busy, try again later. */
- if (debug || verbose)
+ if (repair_flags & XRM_FINAL_WARNING)
+ str_error(ctx, descr_render(dsc),
+_("Filesystem is busy, repair incomplete."));
+ else if (debug || verbose)
str_info(ctx, descr_render(dsc),
_("Filesystem is busy, deferring repair."));
return 0;
^ permalink raw reply related
* Re: [GSoC Patch v8 1/3] path: extract format_path() and use in rev-parse
From: Junio C Hamano @ 2026-06-24 18:15 UTC (permalink / raw)
To: K Jayatheerth
Cc: a3205153416, git, jltobler, kumarayushjha123, lucasseikioshiro,
phillip.wood, sandals
In-Reply-To: <20260624033748.108281-2-jayatheerthkulkarni2005@gmail.com>
K Jayatheerth <jayatheerthkulkarni2005@gmail.com> writes:
> +void format_path(struct strbuf *dest, const char *path,
> + const char *prefix, enum path_format format)
> +{
> + strbuf_reset(dest);
> +
> + switch (format) {
> + case PATH_FORMAT_UNMODIFIED:
> + strbuf_addstr(dest, path);
> + break;
> +
> + case PATH_FORMAT_RELATIVE: {
> ...
> + strbuf_addstr(dest, relative_path(path, prefix, &relative_buf));
> +
> + strbuf_release(&relative_buf);
> + strbuf_release(&real_path);
> + strbuf_release(&real_prefix);
> + free(cwd);
> + break;
> + }
> +
> + case PATH_FORMAT_RELATIVE_IF_SHARED: {
> ...
> + strbuf_addstr(dest, relative_path(path, prefix, &relative_buf));
> + strbuf_release(&relative_buf);
> + break;
> + }
> +
> + case PATH_FORMAT_CANONICAL:
> + /*
> + * strbuf_realpath_forgiving inherently resets the destination
> + * buffer, safely aligning with our replace semantics.
> + */
> + strbuf_realpath_forgiving(dest, path, 1);
> + break;
> +
> + default:
> + BUG("unknown path_format value %d", format);
> + }
> +}
Hmph.
I was hoping that we could lose even more strbuf, but since
relative_path() does not always leave its result in the strbuf that
is passed to it as its third parameter, we do need addstr() into
dest, which is a bit unsatisfying but not a fault of this patch at
all. At least, we lost extra copy in the canonical codepath ;-)
Looking good. Thanks.
^ permalink raw reply
* [PATCH 05/11] xfs_scrub: don't skip bulkstat batch when scrub_scan_user_files helper returns ESTALE
From: Darrick J. Wong @ 2026-06-24 18:15 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Codex complains that the ESTALE in the switch statement results in the
rest of the bulkstat batch being skipped, and that ECANCELED doesn't
actually abort the walk immediately. scrub_scan_user_files is only
called during phases 5 and 6, which is after we've verified all the file
metadata in the filesystem. Therefore, an ESTALE here means that the
file was deleted, so we skip it and move on to the next file. Fix both
issues.
Cc: <linux-xfs@vger.kernel.org> # v6.14.0
Fixes: 279b0d0e8d73f1 ("xfs_scrub: call bulkstat directly if we're only scanning user files")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/inodes.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/scrub/inodes.c b/scrub/inodes.c
index bf1cbdd6c7698b..7ce5f7ffeb62a1 100644
--- a/scrub/inodes.c
+++ b/scrub/inodes.c
@@ -360,6 +360,7 @@ bulkstat_for_inumbers(
enum abort_state {
RUNNING = 0,
ABORTED,
+ CANCELLED,
};
static inline int abort_state_ret(enum abort_state s)
@@ -544,8 +545,8 @@ _("Changed too many times during scan; giving up."));
goto out;
}
case ECANCELED:
- error = 0;
- fallthrough;
+ si->aborted = CANCELLED;
+ goto out;
default:
goto err;
}
@@ -761,9 +762,22 @@ scan_user_files(
case 0:
break;
case ESTALE:
- case ECANCELED:
+ /*
+ * scrub_scan_user_files is only called during phases
+ * 5 and 6, which is after we've verified all the file
+ * metadata in the filesystem. Therefore, an ESTALE
+ * here means that the file was deleted, so we skip it
+ * and move on to the next file.
+ */
error = 0;
- fallthrough;
+ break;
+ case ECANCELED:
+ /*
+ * Helper function wants us to stop iterating, so stop
+ * the walk immediately.
+ */
+ si->aborted = CANCELLED;
+ goto out;
default:
goto err;
}
^ permalink raw reply related
* [PATCH 04/11] xfs_scrub: track inode scan abort state with an enum
From: Darrick J. Wong @ 2026-06-24 18:15 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Change this from a boolean to an enum so that we can handle scan
cancellations correctly in the next patch.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/inodes.c | 44 +++++++++++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 17 deletions(-)
diff --git a/scrub/inodes.c b/scrub/inodes.c
index ab5cf393327f1a..bf1cbdd6c7698b 100644
--- a/scrub/inodes.c
+++ b/scrub/inodes.c
@@ -357,13 +357,23 @@ bulkstat_for_inumbers(
bulkstat_single_step(ctx, inumbers, seen_mask, breq);
}
+enum abort_state {
+ RUNNING = 0,
+ ABORTED,
+};
+
+static inline int abort_state_ret(enum abort_state s)
+{
+ return s == ABORTED ? -1 : 0;
+}
+
/* BULKSTAT wrapper routines. */
struct scan_inodes {
struct workqueue wq_bulkstat;
scrub_inode_iter_fn fn;
void *arg;
unsigned int nr_threads;
- bool aborted;
+ enum abort_state aborted;
};
/*
@@ -530,7 +540,7 @@ scan_ag_bulkstat(
}
str_info(ctx, descr_render(&dsc_bulkstat),
_("Changed too many times during scan; giving up."));
- si->aborted = true;
+ si->aborted = ABORTED;
goto out;
}
case ECANCELED:
@@ -540,7 +550,7 @@ _("Changed too many times during scan; giving up."));
goto err;
}
if (scrub_excessive_errors(ctx)) {
- si->aborted = true;
+ si->aborted = ABORTED;
goto out;
}
last_ino = scan_ino;
@@ -549,7 +559,7 @@ _("Changed too many times during scan; giving up."));
err:
if (error) {
str_liberror(ctx, error, descr_render(&dsc_bulkstat));
- si->aborted = true;
+ si->aborted = ABORTED;
}
out:
free(ichunk);
@@ -594,7 +604,7 @@ scan_ag_inumbers(
cvt_ino_to_agino(&ctx->mnt, nextino),
cvt_ino_to_agino(&ctx->mnt,
ireq->inumbers[0].xi_startino));
- si->aborted = true;
+ si->aborted = ABORTED;
break;
}
nextino = ireq->hdr.ino;
@@ -611,7 +621,7 @@ scan_ag_inumbers(
error = -workqueue_add(&si->wq_bulkstat,
scan_ag_bulkstat, agno, ichunk);
if (error) {
- si->aborted = true;
+ si->aborted = ABORTED;
str_liberror(ctx, error,
_("queueing bulkstat work"));
goto out;
@@ -641,7 +651,7 @@ scan_ag_inumbers(
err:
if (error) {
str_liberror(ctx, error, descr_render(&dsc));
- si->aborted = true;
+ si->aborted = ABORTED;
}
out:
if (ichunk)
@@ -687,14 +697,14 @@ scrub_scan_all_inodes(
si.nr_threads);
if (ret) {
str_liberror(ctx, ret, _("creating inumbers workqueue"));
- si.aborted = true;
+ si.aborted = ABORTED;
goto kill_bulkstat;
}
for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
ret = -workqueue_add(&wq_inumbers, scan_ag_inumbers, agno, &si);
if (ret) {
- si.aborted = true;
+ si.aborted = ABORTED;
str_liberror(ctx, ret, _("queueing inumbers work"));
break;
}
@@ -702,7 +712,7 @@ scrub_scan_all_inodes(
ret = -workqueue_terminate(&wq_inumbers);
if (ret) {
- si.aborted = true;
+ si.aborted = ABORTED;
str_liberror(ctx, ret, _("finishing inumbers work"));
}
workqueue_destroy(&wq_inumbers);
@@ -710,12 +720,12 @@ scrub_scan_all_inodes(
kill_bulkstat:
ret = -workqueue_terminate(&si.wq_bulkstat);
if (ret) {
- si.aborted = true;
+ si.aborted = ABORTED;
str_liberror(ctx, ret, _("finishing bulkstat work"));
}
workqueue_destroy(&si.wq_bulkstat);
- return si.aborted ? -1 : 0;
+ return abort_state_ret(si.aborted);
}
struct user_bulkstat {
@@ -758,7 +768,7 @@ scan_user_files(
goto err;
}
if (scrub_excessive_errors(ctx)) {
- si->aborted = true;
+ si->aborted = ABORTED;
goto out;
}
}
@@ -766,7 +776,7 @@ scan_user_files(
err:
if (error) {
str_liberror(ctx, error, descr_render(&dsc_bulkstat));
- si->aborted = true;
+ si->aborted = ABORTED;
}
out:
free(ureq);
@@ -824,7 +834,7 @@ scan_user_bulkstat(
err_ureq:
free(ureq);
err:
- si->aborted = true;
+ si->aborted = ABORTED;
str_liberror(ctx, ret, what);
return 0;
}
@@ -861,12 +871,12 @@ scrub_scan_user_files(
ret = -workqueue_terminate(&si.wq_bulkstat);
if (ret) {
- si.aborted = true;
+ si.aborted = ABORTED;
str_liberror(ctx, ret, _("finishing bulkstat work"));
}
workqueue_destroy(&si.wq_bulkstat);
- return si.aborted ? -1 : 0;
+ return abort_state_ret(si.aborted);
}
/* Open a file by handle, returning either the fd or -1 on error. */
^ permalink raw reply related
* [PATCH 03/11] xfs_scrub: handle media scans of internal rt devices correctly
From: Darrick J. Wong @ 2026-06-24 18:15 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Codex noticed media scans of internal rt devices don't work at all
correctly. First, we fail to allocate a ctx->verify_disks[XFS_DEV_RT]
for the internal rt section, and even if we did, phase 6 doesn't
allocate media_verify_state.rvp[XFS_DEV_RT] if there's a media error on
an internal rt volume, so we'll crash there too.
Fix both issues to make it work properly.
Cc: <linux-xfs@vger.kernel.org> # v6.15.0
Fixes: 37591ef3f4f14c ("xfs_scrub: support internal RT device")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase1.c | 7 +++++--
scrub/phase6.c | 4 ++--
scrub/spacemap.c | 2 +-
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/scrub/phase1.c b/scrub/phase1.c
index 34a2b3aec030eb..6ac59264b50bb7 100644
--- a/scrub/phase1.c
+++ b/scrub/phase1.c
@@ -101,7 +101,8 @@ scrub_cleanup(
disk_close(ctx->verify_disks[XFS_DEV_DATA]);
if (ctx->verify_disks[XFS_DEV_LOG])
disk_close(ctx->verify_disks[XFS_DEV_LOG]);
- if (ctx->verify_disks[XFS_DEV_RT])
+ if (ctx->verify_disks[XFS_DEV_RT] &&
+ ctx->verify_disks[XFS_DEV_RT] != ctx->verify_disks[XFS_DEV_DATA])
disk_close(ctx->verify_disks[XFS_DEV_RT]);
fshandle_destroy();
error = -xfd_close(&ctx->mnt);
@@ -232,7 +233,9 @@ configure_xfs_verify_fallback(
}
}
- if (ctx->fsinfo.fs_rt) {
+ if (ctx->mnt.fsgeom.rtstart) {
+ ctx->verify_disks[XFS_DEV_RT] = ctx->verify_disks[XFS_DEV_DATA];
+ } else if (ctx->fsinfo.fs_rt || ctx->mnt.fsgeom.rtstart) {
ctx->verify_disks[XFS_DEV_RT] = disk_open(ctx->fsinfo.fs_rt);
if (!ctx->verify_disks[XFS_DEV_RT]) {
str_error(ctx, ctx->mntpoint,
diff --git a/scrub/phase6.c b/scrub/phase6.c
index 2278ae5ad3dfd7..aef817add4157b 100644
--- a/scrub/phase6.c
+++ b/scrub/phase6.c
@@ -744,7 +744,7 @@ phase6_func(
goto out_datapool;
}
}
- if (ctx->fsinfo.fs_rt) {
+ if (ctx->fsinfo.fs_rt || ctx->mnt.fsgeom.rtstart) {
ret = alloc_pool(ctx, &vs, XFS_DEV_RT);
if (ret) {
str_liberror(ctx, ret,
@@ -843,7 +843,7 @@ phase6_estimate(
* nr_threads appropriately to handle that many threads.
*/
*nr_threads = read_verify_nproc(ctx);
- if (ctx->fsinfo.fs_rt)
+ if (ctx->fsinfo.fs_rt || ctx->mnt.fsgeom.rtstart)
*nr_threads += read_verify_nproc(ctx);
if (ctx->fsinfo.fs_log)
*nr_threads += read_verify_nproc(ctx);
diff --git a/scrub/spacemap.c b/scrub/spacemap.c
index 1ee4d1946d3db7..8f595ad94c5991 100644
--- a/scrub/spacemap.c
+++ b/scrub/spacemap.c
@@ -266,7 +266,7 @@ scrub_scan_all_spacemaps(
break;
}
}
- if (ctx->fsinfo.fs_rt) {
+ if (ctx->fsinfo.fs_rt || ctx->mnt.fsgeom.rtstart) {
for (agno = 0; agno < ctx->mnt.fsgeom.rgcount; agno++) {
ret = -workqueue_add(&wq, scan_rtg_rmaps, agno, &sbx);
if (ret) {
^ permalink raw reply related
* [PATCH 02/11] xfs_scrub: report bad file ranges correctly
From: Darrick J. Wong @ 2026-06-24 18:15 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Codex complains that the "media error at data offset..." message prints
the wrong information -- err_off is the offset into @map, not the file
offset; and the length should be constrained by the end of @map. Fix
both of these issues.
Cc: <linux-xfs@vger.kernel.org> # v4.15.0
Fixes: b364a9c008fc04 ("xfs_scrub: scrub file data blocks")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/phase6.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/scrub/phase6.c b/scrub/phase6.c
index cd9bb26bf88628..2278ae5ad3dfd7 100644
--- a/scrub/phase6.c
+++ b/scrub/phase6.c
@@ -408,6 +408,7 @@ report_ioerr_fsmap(
char buf[DESCR_BUFSZ];
struct ioerr_filerange *fr = arg;
uint64_t err_off;
+ uint64_t err_len;
int ret;
/* Don't care about unwritten extents. */
@@ -476,9 +477,12 @@ report_ioerr_fsmap(
return 0;
}
+ err_len = min(fr->physical + fr->length,
+ map->fmr_physical + map->fmr_length) -
+ max(fr->physical, map->fmr_physical);
str_unfixable_error(ctx, buf,
_("media error at data offset %llu length %llu."),
- err_off, fr->length);
+ map->fmr_offset + err_off, err_len);
return 0;
}
^ permalink raw reply related
* [PATCH 01/11] xfs_scrub: handle missing media verify ioctl failure return codes
From: Darrick J. Wong @ 2026-06-24 18:14 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
In-Reply-To: <178232484383.915780.8675173410074139317.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
Back when we reworked the read-verify code to use the kernel ioctl to
perform media scans, we forgot to teach read_verify_one callers to
handle the new error codes. Codex noticed this discrepancy, so let's
fix that.
Cc: <linux-xfs@vger.kernel.org> # v7.0.0
Fixes: 02760878dd86b9 ("xfs_scrub: use the verify media ioctl during phase 6 if possible")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
scrub/read_verify.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/scrub/read_verify.c b/scrub/read_verify.c
index 01e96f5bef40f6..efdf6d544858b8 100644
--- a/scrub/read_verify.c
+++ b/scrub/read_verify.c
@@ -383,7 +383,13 @@ read_verify(
read_error = errno;
/* Runtime error, bail out... */
- if (read_error != EIO && read_error != EILSEQ) {
+ switch (read_error) {
+ case EIO:
+ case EILSEQ:
+ case EREMOTEIO:
+ case ENODATA:
+ break;
+ default:
rvp->runtime_error = read_error;
return;
}
^ permalink raw reply related
* [PATCHSET] xfs_scrub: codex-inspired bug fixes, part 2
From: Darrick J. Wong @ 2026-06-24 18:14 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs, hch, linux-xfs
Hi all,
Here's a second batch of xfs_scrub fixes resulting from Codex reviews.
If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.
With a bit of luck, this should all go splendidly.
Comments and questions are, as always, welcome.
--D
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=scrub-codex-fixes2
---
Commits in this patchset:
* xfs_scrub: handle missing media verify ioctl failure return codes
* xfs_scrub: report bad file ranges correctly
* xfs_scrub: handle media scans of internal rt devices correctly
* xfs_scrub: track inode scan abort state with an enum
* xfs_scrub: don't skip bulkstat batch when scrub_scan_user_files helper returns ESTALE
* xfs_scrub: warn about incomplete repairs if we never get to them
* xfs_scrub: report external log space usage in phase 7
* xfs_scrub: account only data extent tail after an overlap
* xfs_scrub: account for reflinked realtime file data
* xfs_scrub: don't leak the autofsck fsproperty handle
* xfs_scrub: warn about difficult rtgroup repairs
---
scrub/inodes.c | 66 ++++++++++++++++++++++++++------------
scrub/phase1.c | 10 +++---
scrub/phase2.c | 8 +++++
scrub/phase6.c | 10 ++++--
scrub/phase7.c | 89 ++++++++++++++++++++++++++++++++++-----------------
scrub/read_verify.c | 8 ++++-
scrub/repair.c | 5 ++-
scrub/spacemap.c | 2 +
8 files changed, 137 insertions(+), 61 deletions(-)
^ permalink raw reply
* ✗ Fi.CI.BUILD: failure for Add support for a DRM backlight capability
From: Patchwork @ 2026-06-24 18:12 UTC (permalink / raw)
To: Mario Limonciello; +Cc: intel-gfx
In-Reply-To: <20260624165751.2014759-1-mario.limonciello@amd.com>
== Series Details ==
Series: Add support for a DRM backlight capability
URL : https://patchwork.freedesktop.org/series/169109/
State : failure
== Summary ==
Error: patch https://patchwork.freedesktop.org/api/1.0/series/169109/revisions/1/mbox/ not applied
Applying: Revert "backlight: Remove notifier"
Applying: backlight: add kernel-internal backlight API
Applying: drm: link connectors to backlight devices
Applying: DRM: Add support for client indicating support for luminance
error: sha1 information is lacking or useless (drivers/gpu/drm/drm_connector.c).
error: could not build fake ancestor
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0004 DRM: Add support for client indicating support for luminance
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Build failed, no error log produced
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.