* [PATCH v4 1/2] remoteproc: Move coredump configuration to sysfs
2020-09-17 18:56 [PATCH v4 0/3] Move recovery/coredump configuration to sysfs Rishabh Bhatnagar
@ 2020-09-17 18:56 ` Rishabh Bhatnagar
2020-09-17 18:56 ` [PATCH v4 2/2] remoteproc: Move recovery " Rishabh Bhatnagar
2020-09-17 23:40 ` [PATCH v4 0/3] Move recovery/coredump " Randy Dunlap
2 siblings, 0 replies; 5+ messages in thread
From: Rishabh Bhatnagar @ 2020-09-17 18:56 UTC (permalink / raw)
To: bjorn.andersson, ohad
Cc: linux-remoteproc, linux-kernel, tsoni, psodagud, sidgup,
Rishabh Bhatnagar
Move coredump configuration from debugfs to sysfs. This will
allow usage of this configuration feature in production
devices where access to debugfs might be limited.
Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
---
Documentation/ABI/testing/sysfs-class-remoteproc | 24 +++++++
drivers/remoteproc/remoteproc_debugfs.c | 90 ------------------------
drivers/remoteproc/remoteproc_sysfs.c | 64 +++++++++++++++++
3 files changed, 88 insertions(+), 90 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc
index 36094fb..f6c44fa 100644
--- a/Documentation/ABI/testing/sysfs-class-remoteproc
+++ b/Documentation/ABI/testing/sysfs-class-remoteproc
@@ -58,3 +58,27 @@ Description: Remote processor name
Reports the name of the remote processor. This can be used by
userspace in exactly identifying a remote processor and ease
up the usage in modifying the 'firmware' or 'state' files.
+
+What: /sys/class/remoteproc/.../coredump
+Date: July 2020
+Contact: Bjorn Andersson <bjorn.andersson@linaro.org>, Ohad Ben-Cohen <ohad@wizery.com>
+Description: Remote processor coredump configuration
+
+ Reports the coredump configuration of the remote processor,
+ which will be one of:
+
+ "default"
+ "inline"
+ "disabled"
+
+ "default" means when the remote processor's coredump is
+ collected it will be copied to a separate buffer and that
+ buffer is exposed to userspace.
+
+ "inline" means when the remote processor's coredump is
+ collected userspace will directly read from the remote
+ processor's device memory. Extra buffer will not be used to
+ copy the dump. Also recovery process will not proceed until
+ all data is read by usersapce.
+
+ "disabled" means no dump will be collected.
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 2e3b3e2..732770e 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -28,94 +28,6 @@
static struct dentry *rproc_dbg;
/*
- * A coredump-configuration-to-string lookup table, for exposing a
- * human readable configuration via debugfs. Always keep in sync with
- * enum rproc_coredump_mechanism
- */
-static const char * const rproc_coredump_str[] = {
- [RPROC_COREDUMP_DEFAULT] = "default",
- [RPROC_COREDUMP_INLINE] = "inline",
- [RPROC_COREDUMP_DISABLED] = "disabled",
-};
-
-/* Expose the current coredump configuration via debugfs */
-static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct rproc *rproc = filp->private_data;
- char buf[20];
- int len;
-
- len = scnprintf(buf, sizeof(buf), "%s\n",
- rproc_coredump_str[rproc->dump_conf]);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, len);
-}
-
-/*
- * By writing to the 'coredump' debugfs entry, we control the behavior of the
- * coredump mechanism dynamically. The default value of this entry is "default".
- *
- * The 'coredump' debugfs entry supports these commands:
- *
- * default: This is the default coredump mechanism. When the remoteproc
- * crashes the entire coredump will be copied to a separate buffer
- * and exposed to userspace.
- *
- * inline: The coredump will not be copied to a separate buffer and the
- * recovery process will have to wait until data is read by
- * userspace. But this avoid usage of extra memory.
- *
- * disabled: This will disable coredump. Recovery will proceed without
- * collecting any dump.
- */
-static ssize_t rproc_coredump_write(struct file *filp,
- const char __user *user_buf, size_t count,
- loff_t *ppos)
-{
- struct rproc *rproc = filp->private_data;
- int ret, err = 0;
- char buf[20];
-
- if (count > sizeof(buf))
- return -EINVAL;
-
- ret = copy_from_user(buf, user_buf, count);
- if (ret)
- return -EFAULT;
-
- /* remove end of line */
- if (buf[count - 1] == '\n')
- buf[count - 1] = '\0';
-
- if (rproc->state == RPROC_CRASHED) {
- dev_err(&rproc->dev, "can't change coredump configuration\n");
- err = -EBUSY;
- goto out;
- }
-
- if (!strncmp(buf, "disable", count)) {
- rproc->dump_conf = RPROC_COREDUMP_DISABLED;
- } else if (!strncmp(buf, "inline", count)) {
- rproc->dump_conf = RPROC_COREDUMP_INLINE;
- } else if (!strncmp(buf, "default", count)) {
- rproc->dump_conf = RPROC_COREDUMP_DEFAULT;
- } else {
- dev_err(&rproc->dev, "Invalid coredump configuration\n");
- err = -EINVAL;
- }
-out:
- return err ? err : count;
-}
-
-static const struct file_operations rproc_coredump_fops = {
- .read = rproc_coredump_read,
- .write = rproc_coredump_write,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
-/*
* Some remote processors may support dumping trace logs into a shared
* memory buffer. We expose this trace buffer using debugfs, so users
* can easily tell what's going on remotely.
@@ -425,8 +337,6 @@ void rproc_create_debug_dir(struct rproc *rproc)
rproc, &rproc_rsc_table_fops);
debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
rproc, &rproc_carveouts_fops);
- debugfs_create_file("coredump", 0600, rproc->dbg_dir,
- rproc, &rproc_coredump_fops);
}
void __init rproc_init_debugfs(void)
diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index eea514c..40949a0 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -10,6 +10,69 @@
#define to_rproc(d) container_of(d, struct rproc, dev)
+/*
+ * A coredump-configuration-to-string lookup table, for exposing a
+ * human readable configuration via sysfs. Always keep in sync with
+ * enum rproc_coredump_mechanism
+ */
+static const char * const rproc_coredump_str[] = {
+ [RPROC_COREDUMP_DEFAULT] = "default",
+ [RPROC_COREDUMP_INLINE] = "inline",
+ [RPROC_COREDUMP_DISABLED] = "disabled",
+};
+
+/* Expose the current coredump configuration via debugfs */
+static ssize_t coredump_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rproc *rproc = to_rproc(dev);
+
+ return sprintf(buf, "%s\n", rproc_coredump_str[rproc->dump_conf]);
+}
+
+/*
+ * By writing to the 'coredump' sysfs entry, we control the behavior of the
+ * coredump mechanism dynamically. The default value of this entry is "default".
+ *
+ * The 'coredump' sysfs entry supports these commands:
+ *
+ * default: This is the default coredump mechanism. When the remoteproc
+ * crashes the entire coredump will be copied to a separate buffer
+ * and exposed to userspace.
+ *
+ * inline: The coredump will not be copied to a separate buffer and the
+ * recovery process will have to wait until data is read by
+ * userspace. But this avoid usage of extra memory.
+ *
+ * disabled: This will disable coredump. Recovery will proceed without
+ * collecting any dump.
+ */
+static ssize_t coredump_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rproc *rproc = to_rproc(dev);
+
+ if (rproc->state == RPROC_CRASHED) {
+ dev_err(&rproc->dev, "can't change coredump configuration\n");
+ return -EBUSY;
+ }
+
+ if (sysfs_streq(buf, "disable")) {
+ rproc->dump_conf = RPROC_COREDUMP_DISABLED;
+ } else if (sysfs_streq(buf, "inline")) {
+ rproc->dump_conf = RPROC_COREDUMP_INLINE;
+ } else if (sysfs_streq(buf, "default")) {
+ rproc->dump_conf = RPROC_COREDUMP_DEFAULT;
+ } else {
+ dev_err(&rproc->dev, "Invalid coredump configuration\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RW(coredump);
+
/* Expose the loaded / running firmware name via sysfs */
static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -138,6 +201,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(name);
static struct attribute *rproc_attrs[] = {
+ &dev_attr_coredump.attr,
&dev_attr_firmware.attr,
&dev_attr_state.attr,
&dev_attr_name.attr,
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 2/2] remoteproc: Move recovery configuration to sysfs
2020-09-17 18:56 [PATCH v4 0/3] Move recovery/coredump configuration to sysfs Rishabh Bhatnagar
2020-09-17 18:56 ` [PATCH v4 1/2] remoteproc: Move coredump " Rishabh Bhatnagar
@ 2020-09-17 18:56 ` Rishabh Bhatnagar
2020-09-17 23:40 ` [PATCH v4 0/3] Move recovery/coredump " Randy Dunlap
2 siblings, 0 replies; 5+ messages in thread
From: Rishabh Bhatnagar @ 2020-09-17 18:56 UTC (permalink / raw)
To: bjorn.andersson, ohad
Cc: linux-remoteproc, linux-kernel, tsoni, psodagud, sidgup,
Rishabh Bhatnagar
Move recovery configuration from debugfs to sysfs. This will
allow usage of this configuration feature in production
devices where access to debugfs might be limited.
Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
---
Documentation/ABI/testing/sysfs-class-remoteproc | 20 ++++++
drivers/remoteproc/remoteproc_debugfs.c | 78 ------------------------
drivers/remoteproc/remoteproc_sysfs.c | 56 +++++++++++++++++
3 files changed, 76 insertions(+), 78 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-remoteproc b/Documentation/ABI/testing/sysfs-class-remoteproc
index f6c44fa..7368b50 100644
--- a/Documentation/ABI/testing/sysfs-class-remoteproc
+++ b/Documentation/ABI/testing/sysfs-class-remoteproc
@@ -82,3 +82,23 @@ Description: Remote processor coredump configuration
all data is read by usersapce.
"disabled" means no dump will be collected.
+
+What: /sys/class/remoteproc/.../recovery
+Date: July 2020
+Contact: Bjorn Andersson <bjorn.andersson@linaro.org>, Ohad Ben-Cohen <ohad@wizery.com>
+Description: Remote processor recovery mechanism
+
+ Reports the recovery mechanism of the remote processor,
+ which will be one of:
+
+ "enabled"
+ "disabled"
+
+ "enabled" means, the remote processor will be automatically
+ recovered whenever it crashes. Moreover, if the remote
+ processor crashes while recovery is disabled, it will
+ be automatically recovered too as soon as recovery is enabled.
+
+ "disabled" means, a remote processor will remain in a crashed
+ state if it crashes. This is useful for debugging purposes;
+ without it, debugging a crash is substantially harder.
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 732770e..c505f0e 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -84,82 +84,6 @@ static const struct file_operations rproc_name_ops = {
.llseek = generic_file_llseek,
};
-/* expose recovery flag via debugfs */
-static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct rproc *rproc = filp->private_data;
- char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n";
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-}
-
-/*
- * By writing to the 'recovery' debugfs entry, we control the behavior of the
- * recovery mechanism dynamically. The default value of this entry is "enabled".
- *
- * The 'recovery' debugfs entry supports these commands:
- *
- * enabled: When enabled, the remote processor will be automatically
- * recovered whenever it crashes. Moreover, if the remote
- * processor crashes while recovery is disabled, it will
- * be automatically recovered too as soon as recovery is enabled.
- *
- * disabled: When disabled, a remote processor will remain in a crashed
- * state if it crashes. This is useful for debugging purposes;
- * without it, debugging a crash is substantially harder.
- *
- * recover: This function will trigger an immediate recovery if the
- * remote processor is in a crashed state, without changing
- * or checking the recovery state (enabled/disabled).
- * This is useful during debugging sessions, when one expects
- * additional crashes to happen after enabling recovery. In this
- * case, enabling recovery will make it hard to debug subsequent
- * crashes, so it's recommended to keep recovery disabled, and
- * instead use the "recover" command as needed.
- */
-static ssize_t
-rproc_recovery_write(struct file *filp, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct rproc *rproc = filp->private_data;
- char buf[10];
- int ret;
-
- if (count < 1 || count > sizeof(buf))
- return -EINVAL;
-
- ret = copy_from_user(buf, user_buf, count);
- if (ret)
- return -EFAULT;
-
- /* remove end of line */
- if (buf[count - 1] == '\n')
- buf[count - 1] = '\0';
-
- if (!strncmp(buf, "enabled", count)) {
- /* change the flag and begin the recovery process if needed */
- rproc->recovery_disabled = false;
- rproc_trigger_recovery(rproc);
- } else if (!strncmp(buf, "disabled", count)) {
- rproc->recovery_disabled = true;
- } else if (!strncmp(buf, "recover", count)) {
- /* begin the recovery process without changing the flag */
- rproc_trigger_recovery(rproc);
- } else {
- return -EINVAL;
- }
-
- return count;
-}
-
-static const struct file_operations rproc_recovery_ops = {
- .read = rproc_recovery_read,
- .write = rproc_recovery_write,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
/* expose the crash trigger via debugfs */
static ssize_t
rproc_crash_write(struct file *filp, const char __user *user_buf,
@@ -329,8 +253,6 @@ void rproc_create_debug_dir(struct rproc *rproc)
debugfs_create_file("name", 0400, rproc->dbg_dir,
rproc, &rproc_name_ops);
- debugfs_create_file("recovery", 0600, rproc->dbg_dir,
- rproc, &rproc_recovery_ops);
debugfs_create_file("crash", 0200, rproc->dbg_dir,
rproc, &rproc_crash_ops);
debugfs_create_file("resource_table", 0400, rproc->dbg_dir,
diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c
index 40949a0..2508eca 100644
--- a/drivers/remoteproc/remoteproc_sysfs.c
+++ b/drivers/remoteproc/remoteproc_sysfs.c
@@ -10,6 +10,61 @@
#define to_rproc(d) container_of(d, struct rproc, dev)
+static ssize_t recovery_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rproc *rproc = to_rproc(dev);
+
+ return sprintf(buf, "%s", rproc->recovery_disabled ? "disabled\n" : "enabled\n");
+}
+
+/*
+ * By writing to the 'recovery' sysfs entry, we control the behavior of the
+ * recovery mechanism dynamically. The default value of this entry is "enabled".
+ *
+ * The 'recovery' sysfs entry supports these commands:
+ *
+ * enabled: When enabled, the remote processor will be automatically
+ * recovered whenever it crashes. Moreover, if the remote
+ * processor crashes while recovery is disabled, it will
+ * be automatically recovered too as soon as recovery is enabled.
+ *
+ * disabled: When disabled, a remote processor will remain in a crashed
+ * state if it crashes. This is useful for debugging purposes;
+ * without it, debugging a crash is substantially harder.
+ *
+ * recover: This function will trigger an immediate recovery if the
+ * remote processor is in a crashed state, without changing
+ * or checking the recovery state (enabled/disabled).
+ * This is useful during debugging sessions, when one expects
+ * additional crashes to happen after enabling recovery. In this
+ * case, enabling recovery will make it hard to debug subsequent
+ * crashes, so it's recommended to keep recovery disabled, and
+ * instead use the "recover" command as needed.
+ */
+static ssize_t recovery_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rproc *rproc = to_rproc(dev);
+
+ if (sysfs_streq(buf, "enabled")) {
+ /* change the flag and begin the recovery process if needed */
+ rproc->recovery_disabled = false;
+ rproc_trigger_recovery(rproc);
+ } else if (sysfs_streq(buf, "disabled")) {
+ rproc->recovery_disabled = true;
+ } else if (sysfs_streq(buf, "recover")) {
+ /* begin the recovery process without changing the flag */
+ rproc_trigger_recovery(rproc);
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RW(recovery);
+
/*
* A coredump-configuration-to-string lookup table, for exposing a
* human readable configuration via sysfs. Always keep in sync with
@@ -202,6 +257,7 @@ static DEVICE_ATTR_RO(name);
static struct attribute *rproc_attrs[] = {
&dev_attr_coredump.attr,
+ &dev_attr_recovery.attr,
&dev_attr_firmware.attr,
&dev_attr_state.attr,
&dev_attr_name.attr,
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v4 0/3] Move recovery/coredump configuration to sysfs
2020-09-17 18:56 [PATCH v4 0/3] Move recovery/coredump configuration to sysfs Rishabh Bhatnagar
2020-09-17 18:56 ` [PATCH v4 1/2] remoteproc: Move coredump " Rishabh Bhatnagar
2020-09-17 18:56 ` [PATCH v4 2/2] remoteproc: Move recovery " Rishabh Bhatnagar
@ 2020-09-17 23:40 ` Randy Dunlap
2020-09-18 17:15 ` rishabhb
2 siblings, 1 reply; 5+ messages in thread
From: Randy Dunlap @ 2020-09-17 23:40 UTC (permalink / raw)
To: Rishabh Bhatnagar, bjorn.andersson, ohad
Cc: linux-remoteproc, linux-kernel, tsoni, psodagud, sidgup
On 9/17/20 11:56 AM, Rishabh Bhatnagar wrote:
> From Android R onwards Google has restricted access to debugfs in user
> and user-debug builds. This restricts access to most of the features
> exposed through debugfs. This patch series removes the recovery/coredump
> entries from debugfs and moves them to sysfs.
> 'Coredump' and 'Recovery' are critical interfaces that are required
> for remoteproc to work on Qualcomm Chipsets. Coredump configuration
> needs to be set to "inline" in debug/test build and "disabled" in
> production builds. Whereas recovery needs to be "disabled" for
> debugging purposes and "enabled" on production builds.
>
> Changelog:
>
> v4 -> v3:
> - Remove the feature flag to expose recovery/coredump
>
> v3 -> v2:
> - Remove the coredump/recovery entries from debugfs
> - Expose recovery/coredump from sysfs under a feature flag
>
> v1 -> v2:
> - Correct the contact name in the sysfs documentation.
> - Remove the redundant write documentation for coredump/recovery sysfs
> - Add a feature flag to make this interface switch configurable.
>
> Rishabh Bhatnagar (3):
> remoteproc: Expose remoteproc configuration through sysfs
> remoteproc: Add coredump configuration to sysfs
> remoteproc: Add recovery configuration to sysfs
>
> Documentation/ABI/testing/sysfs-class-remoteproc | 44 ++++++++
> drivers/remoteproc/Kconfig | 12 +++
> drivers/remoteproc/remoteproc_debugfs.c | 10 +-
> drivers/remoteproc/remoteproc_sysfs.c | 126 +++++++++++++++++++++++
> 4 files changed, 190 insertions(+), 2 deletions(-)
>
Hi,
Is there a patch 3/3?
This email (reply) is patch 0/3, then I see
patch 1/2
patch 2/2
so I'm confused. However, the diffstat above references a Kconfig file
and neither patch 1/2 nor patch 2/2 contains any Kconfig changes.
thanks.
--
~Randy
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v4 0/3] Move recovery/coredump configuration to sysfs
2020-09-17 23:40 ` [PATCH v4 0/3] Move recovery/coredump " Randy Dunlap
@ 2020-09-18 17:15 ` rishabhb
0 siblings, 0 replies; 5+ messages in thread
From: rishabhb @ 2020-09-18 17:15 UTC (permalink / raw)
To: Randy Dunlap
Cc: bjorn.andersson, ohad, linux-remoteproc, linux-kernel, tsoni,
psodagud, sidgup
On 2020-09-17 16:40, Randy Dunlap wrote:
> On 9/17/20 11:56 AM, Rishabh Bhatnagar wrote:
>> From Android R onwards Google has restricted access to debugfs in user
>> and user-debug builds. This restricts access to most of the features
>> exposed through debugfs. This patch series removes the
>> recovery/coredump
>> entries from debugfs and moves them to sysfs.
>> 'Coredump' and 'Recovery' are critical interfaces that are required
>> for remoteproc to work on Qualcomm Chipsets. Coredump configuration
>> needs to be set to "inline" in debug/test build and "disabled" in
>> production builds. Whereas recovery needs to be "disabled" for
>> debugging purposes and "enabled" on production builds.
>>
>> Changelog:
>>
>> v4 -> v3:
>> - Remove the feature flag to expose recovery/coredump
>>
>> v3 -> v2:
>> - Remove the coredump/recovery entries from debugfs
>> - Expose recovery/coredump from sysfs under a feature flag
>>
>> v1 -> v2:
>> - Correct the contact name in the sysfs documentation.
>> - Remove the redundant write documentation for coredump/recovery sysfs
>> - Add a feature flag to make this interface switch configurable.
>>
>> Rishabh Bhatnagar (3):
>> remoteproc: Expose remoteproc configuration through sysfs
>> remoteproc: Add coredump configuration to sysfs
>> remoteproc: Add recovery configuration to sysfs
>>
>> Documentation/ABI/testing/sysfs-class-remoteproc | 44 ++++++++
>> drivers/remoteproc/Kconfig | 12 +++
>> drivers/remoteproc/remoteproc_debugfs.c | 10 +-
>> drivers/remoteproc/remoteproc_sysfs.c | 126
>> +++++++++++++++++++++++
>> 4 files changed, 190 insertions(+), 2 deletions(-)
>>
>
> Hi,
>
> Is there a patch 3/3?
> This email (reply) is patch 0/3, then I see
> patch 1/2
> patch 2/2
> so I'm confused. However, the diffstat above references a Kconfig file
> and neither patch 1/2 nor patch 2/2 contains any Kconfig changes.
>
> thanks.
Hi Randy,
The cover letter got messed up. There are only 2 patches now whereas in
the
earlier versions there were 3 patches. I'll be sending out v5 soon.
Please review that.
^ permalink raw reply [flat|nested] 5+ messages in thread