From: George Stark <gnstark@salutedevices.com>
To: "Marek Behún" <marek.behun@nic.cz>, "Waiman Long" <longman@redhat.com>
Cc: <andy.shevchenko@gmail.com>, <pavel@ucw.cz>, <lee@kernel.org>,
<vadimp@nvidia.com>, <mpe@ellerman.id.au>, <npiggin@gmail.com>,
<christophe.leroy@csgroup.eu>, <hdegoede@redhat.com>,
<mazziesaccount@gmail.com>, <peterz@infradead.org>,
<mingo@redhat.com>, <will@kernel.org>, <boqun.feng@gmail.com>,
<nikitos.tr@gmail.com>, <kabel@kernel.org>,
<linux-leds@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<linuxppc-dev@lists.ozlabs.org>, <kernel@salutedevices.com>
Subject: Re: [PATCH v5 02/10] locking/mutex: introduce devm_mutex_init
Date: Tue, 12 Mar 2024 02:47:10 +0300 [thread overview]
Message-ID: <cfceef12-883e-4593-9dca-50768acb1aa9@salutedevices.com> (raw)
In-Reply-To: <20240307174414.4059d7ee@dellmb>
Hello Waiman, Marek
Thanks for the review.
I've never used lockdep for debug but it seems preferable to
keep that feature working. It could be look like this:
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index f7611c092db7..574f6de6084d 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -22,6 +22,8 @@
#include <linux/cleanup.h>
#include <linux/mutex_types.h>
+struct device;
+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
, .dep_map = { \
@@ -115,10 +117,31 @@ do { \
#ifdef CONFIG_DEBUG_MUTEXES
+int debug_devm_mutex_init(struct device *dev, struct mutex *lock);
+
+#define devm_mutex_init(dev, mutex) \
+({ \
+ int ret; \
+ mutex_init(mutex); \
+ ret = debug_devm_mutex_init(dev, mutex); \
+ ret; \
+})
+
void mutex_destroy(struct mutex *lock);
#else
+/*
+* When CONFIG_DEBUG_MUTEXES is off mutex_destroy is just a nop so
+* there's no really need to register it in devm subsystem.
+*/
+#define devm_mutex_init(dev, mutex) \
+({ \
+ typecheck(struct device *, dev); \
+ mutex_init(mutex); \
+ 0; \
+})
+
static inline void mutex_destroy(struct mutex *lock) {}
#endif
diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
index bc8abb8549d2..967a5367c79a 100644
--- a/kernel/locking/mutex-debug.c
+++ b/kernel/locking/mutex-debug.c
@@ -19,6 +19,7 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
+#include <linux/device.h>
#include "mutex.h"
@@ -89,6 +90,16 @@ void debug_mutex_init(struct mutex *lock, const char
*name,
lock->magic = lock;
}
+static void devm_mutex_release(void *res)
+{
+ mutex_destroy(res);
+}
+
+int debug_devm_mutex_init(struct device *dev, struct mutex *lock)
+{
+ return devm_add_action_or_reset(dev, devm_mutex_release, lock);
+}
+
/***
* mutex_destroy - mark a mutex unusable
* @lock: the mutex to be destroyed
--
2.25.1
And now I would drop the the refactoring patch with moving down
mutex_destroy. devm block is big enough to be declared standalone.
On 3/7/24 19:44, Marek Behún wrote:
> On Thu, 7 Mar 2024 08:39:46 -0500
> Waiman Long <longman@redhat.com> wrote:
>
>> On 3/7/24 04:56, Marek Behún wrote:
>>> On Thu, Mar 07, 2024 at 05:40:26AM +0300, George Stark wrote:
>>>> Using of devm API leads to a certain order of releasing resources.
>>>> So all dependent resources which are not devm-wrapped should be deleted
>>>> with respect to devm-release order. Mutex is one of such objects that
>>>> often is bound to other resources and has no own devm wrapping.
>>>> Since mutex_destroy() actually does nothing in non-debug builds
>>>> frequently calling mutex_destroy() is just ignored which is safe for now
>>>> but wrong formally and can lead to a problem if mutex_destroy() will be
>>>> extended so introduce devm_mutex_init()
>>>>
>>>> Signed-off-by: George Stark <gnstark@salutedevices.com>
>>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>>> ---
>>>> Hello Christophe. Hope you don't mind I put you SoB tag because you helped alot
>>>> to make this patch happen.
>>>>
>>>> include/linux/mutex.h | 13 +++++++++++++
>>>> kernel/locking/mutex-debug.c | 22 ++++++++++++++++++++++
>>>> 2 files changed, 35 insertions(+)
>>>>
>>>> diff --git a/include/linux/mutex.h b/include/linux/mutex.h
>>>> index f7611c092db7..9bcf72cb941a 100644
>>>> --- a/include/linux/mutex.h
>>>> +++ b/include/linux/mutex.h
>>>> @@ -22,6 +22,8 @@
>>>> #include <linux/cleanup.h>
>>>> #include <linux/mutex_types.h>
>>>>
>>>> +struct device;
>>>> +
>>>> #ifdef CONFIG_DEBUG_LOCK_ALLOC
>>>> # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
>>>> , .dep_map = { \
>>>> @@ -115,10 +117,21 @@ do { \
>>>>
>>>> #ifdef CONFIG_DEBUG_MUTEXES
>>>>
>>>> +int devm_mutex_init(struct device *dev, struct mutex *lock);
>>>> void mutex_destroy(struct mutex *lock);
>>>>
>>>> #else
>>>>
>>>> +static inline int devm_mutex_init(struct device *dev, struct mutex *lock)
>>>> +{
>>>> + /*
>>>> + * since mutex_destroy is nop actually there's no need to register it
>>>> + * in devm subsystem.
>>>> + */
>>>> + mutex_init(lock);
>>>> + return 0;
>>>> +}
>>>> +
>>>> static inline void mutex_destroy(struct mutex *lock) {}
>>>>
>>>> #endif
>>>> diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
>>>> index bc8abb8549d2..c9efab1a8026 100644
>>>> --- a/kernel/locking/mutex-debug.c
>>>> +++ b/kernel/locking/mutex-debug.c
>>>> @@ -19,6 +19,7 @@
>>>> #include <linux/kallsyms.h>
>>>> #include <linux/interrupt.h>
>>>> #include <linux/debug_locks.h>
>>>> +#include <linux/device.h>
>>>>
>>>> #include "mutex.h"
>>>>
>>>> @@ -104,3 +105,24 @@ void mutex_destroy(struct mutex *lock)
>>>> }
>>>>
>>>> EXPORT_SYMBOL_GPL(mutex_destroy);
>>>> +
>>>> +static void devm_mutex_release(void *res)
>>>> +{
>>>> + mutex_destroy(res);
>>>> +}
>>>> +
>>>> +/**
>>>> + * devm_mutex_init - Resource-managed mutex initialization
>>>> + * @dev: Device which lifetime mutex is bound to
>>>> + * @lock: Pointer to a mutex
>>>> + *
>>>> + * Initialize mutex which is automatically destroyed when the driver is detached.
>>>> + *
>>>> + * Returns: 0 on success or a negative error code on failure.
>>>> + */
>>>> +int devm_mutex_init(struct device *dev, struct mutex *lock)
>>>> +{
>>>> + mutex_init(lock);
>>>> + return devm_add_action_or_reset(dev, devm_mutex_release, lock);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(devm_mutex_init);
>>> Hi George,
>>>
>>> look at
>>> https://lore.kernel.org/lkml/7013bf9e-2663-4613-ae61-61872e81355b@redhat.com/
>>> where Matthew and Hans explain that devm_mutex_init needs to be a macro
>>> because of the static lockdep key.
>>>
>>> so this should be something like:
>>>
>>> static inline int __devm_mutex_init(struct device *dev, struct mutex *mutex,
>>> const char *name,
>>> struct lock_class_key *key)
>>> {
>>> __mutex_init(mutex, name, key);
>>> return devm_add_action_or_reset(dev, devm_mutex_release, mutex);
>>> }
>>>
>>> #define devm_mutex_init(dev, mutex) \
>>> do { \
>>> static struct lock_class_key __key; \
>>> \
>>> __devm_mutex_init(dev, (mutex), #mutex, &__key); \
>>> } while (0);
>>>
>>>
>>> Marek
>>
>> Making devm_mutex_init() a function will make all the devm_mutex share
>> the same lockdep key. Making it a macro will make each caller of
>> devm_mutex_init() have a distinct lockdep key. It all depends on whether
>> all the devm_mutexes have the same lock usage pattern or not and whether
>> it is possible for one devm_mutex to be nested inside another. So either
>> way can be fine depending on the mutex usage pattern. My suggestion is
>> to use a function, if possible, unless it will cause a false positive
>> lockdep splat as there is a limit on the maximum # of lockdep keys that
>> can be used.
>
> devm_mutex_init() should behave like other similar function
> initializing stuff with resource management. I.e. it should behave like
> mutex_init(), but with resource management.
>
> mutex_init() is a macro generating static lockdep key for each instance,
> so devm_mutex_init() should also generate static lockdep key for each
> instance.
>
> Marek
--
Best regards
George
WARNING: multiple messages have this Message-ID (diff)
From: George Stark <gnstark@salutedevices.com>
To: "Marek Behún" <marek.behun@nic.cz>, "Waiman Long" <longman@redhat.com>
Cc: kabel@kernel.org, linuxppc-dev@lists.ozlabs.org,
vadimp@nvidia.com, mazziesaccount@gmail.com,
peterz@infradead.org, boqun.feng@gmail.com, lee@kernel.org,
kernel@salutedevices.com, linux-kernel@vger.kernel.org,
npiggin@gmail.com, hdegoede@redhat.com,
andy.shevchenko@gmail.com, mingo@redhat.com, pavel@ucw.cz,
nikitos.tr@gmail.com, will@kernel.org,
linux-leds@vger.kernel.org
Subject: Re: [PATCH v5 02/10] locking/mutex: introduce devm_mutex_init
Date: Tue, 12 Mar 2024 02:47:10 +0300 [thread overview]
Message-ID: <cfceef12-883e-4593-9dca-50768acb1aa9@salutedevices.com> (raw)
In-Reply-To: <20240307174414.4059d7ee@dellmb>
Hello Waiman, Marek
Thanks for the review.
I've never used lockdep for debug but it seems preferable to
keep that feature working. It could be look like this:
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index f7611c092db7..574f6de6084d 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -22,6 +22,8 @@
#include <linux/cleanup.h>
#include <linux/mutex_types.h>
+struct device;
+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
, .dep_map = { \
@@ -115,10 +117,31 @@ do { \
#ifdef CONFIG_DEBUG_MUTEXES
+int debug_devm_mutex_init(struct device *dev, struct mutex *lock);
+
+#define devm_mutex_init(dev, mutex) \
+({ \
+ int ret; \
+ mutex_init(mutex); \
+ ret = debug_devm_mutex_init(dev, mutex); \
+ ret; \
+})
+
void mutex_destroy(struct mutex *lock);
#else
+/*
+* When CONFIG_DEBUG_MUTEXES is off mutex_destroy is just a nop so
+* there's no really need to register it in devm subsystem.
+*/
+#define devm_mutex_init(dev, mutex) \
+({ \
+ typecheck(struct device *, dev); \
+ mutex_init(mutex); \
+ 0; \
+})
+
static inline void mutex_destroy(struct mutex *lock) {}
#endif
diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
index bc8abb8549d2..967a5367c79a 100644
--- a/kernel/locking/mutex-debug.c
+++ b/kernel/locking/mutex-debug.c
@@ -19,6 +19,7 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
+#include <linux/device.h>
#include "mutex.h"
@@ -89,6 +90,16 @@ void debug_mutex_init(struct mutex *lock, const char
*name,
lock->magic = lock;
}
+static void devm_mutex_release(void *res)
+{
+ mutex_destroy(res);
+}
+
+int debug_devm_mutex_init(struct device *dev, struct mutex *lock)
+{
+ return devm_add_action_or_reset(dev, devm_mutex_release, lock);
+}
+
/***
* mutex_destroy - mark a mutex unusable
* @lock: the mutex to be destroyed
--
2.25.1
And now I would drop the the refactoring patch with moving down
mutex_destroy. devm block is big enough to be declared standalone.
On 3/7/24 19:44, Marek Behún wrote:
> On Thu, 7 Mar 2024 08:39:46 -0500
> Waiman Long <longman@redhat.com> wrote:
>
>> On 3/7/24 04:56, Marek Behún wrote:
>>> On Thu, Mar 07, 2024 at 05:40:26AM +0300, George Stark wrote:
>>>> Using of devm API leads to a certain order of releasing resources.
>>>> So all dependent resources which are not devm-wrapped should be deleted
>>>> with respect to devm-release order. Mutex is one of such objects that
>>>> often is bound to other resources and has no own devm wrapping.
>>>> Since mutex_destroy() actually does nothing in non-debug builds
>>>> frequently calling mutex_destroy() is just ignored which is safe for now
>>>> but wrong formally and can lead to a problem if mutex_destroy() will be
>>>> extended so introduce devm_mutex_init()
>>>>
>>>> Signed-off-by: George Stark <gnstark@salutedevices.com>
>>>> Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>>>> ---
>>>> Hello Christophe. Hope you don't mind I put you SoB tag because you helped alot
>>>> to make this patch happen.
>>>>
>>>> include/linux/mutex.h | 13 +++++++++++++
>>>> kernel/locking/mutex-debug.c | 22 ++++++++++++++++++++++
>>>> 2 files changed, 35 insertions(+)
>>>>
>>>> diff --git a/include/linux/mutex.h b/include/linux/mutex.h
>>>> index f7611c092db7..9bcf72cb941a 100644
>>>> --- a/include/linux/mutex.h
>>>> +++ b/include/linux/mutex.h
>>>> @@ -22,6 +22,8 @@
>>>> #include <linux/cleanup.h>
>>>> #include <linux/mutex_types.h>
>>>>
>>>> +struct device;
>>>> +
>>>> #ifdef CONFIG_DEBUG_LOCK_ALLOC
>>>> # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
>>>> , .dep_map = { \
>>>> @@ -115,10 +117,21 @@ do { \
>>>>
>>>> #ifdef CONFIG_DEBUG_MUTEXES
>>>>
>>>> +int devm_mutex_init(struct device *dev, struct mutex *lock);
>>>> void mutex_destroy(struct mutex *lock);
>>>>
>>>> #else
>>>>
>>>> +static inline int devm_mutex_init(struct device *dev, struct mutex *lock)
>>>> +{
>>>> + /*
>>>> + * since mutex_destroy is nop actually there's no need to register it
>>>> + * in devm subsystem.
>>>> + */
>>>> + mutex_init(lock);
>>>> + return 0;
>>>> +}
>>>> +
>>>> static inline void mutex_destroy(struct mutex *lock) {}
>>>>
>>>> #endif
>>>> diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
>>>> index bc8abb8549d2..c9efab1a8026 100644
>>>> --- a/kernel/locking/mutex-debug.c
>>>> +++ b/kernel/locking/mutex-debug.c
>>>> @@ -19,6 +19,7 @@
>>>> #include <linux/kallsyms.h>
>>>> #include <linux/interrupt.h>
>>>> #include <linux/debug_locks.h>
>>>> +#include <linux/device.h>
>>>>
>>>> #include "mutex.h"
>>>>
>>>> @@ -104,3 +105,24 @@ void mutex_destroy(struct mutex *lock)
>>>> }
>>>>
>>>> EXPORT_SYMBOL_GPL(mutex_destroy);
>>>> +
>>>> +static void devm_mutex_release(void *res)
>>>> +{
>>>> + mutex_destroy(res);
>>>> +}
>>>> +
>>>> +/**
>>>> + * devm_mutex_init - Resource-managed mutex initialization
>>>> + * @dev: Device which lifetime mutex is bound to
>>>> + * @lock: Pointer to a mutex
>>>> + *
>>>> + * Initialize mutex which is automatically destroyed when the driver is detached.
>>>> + *
>>>> + * Returns: 0 on success or a negative error code on failure.
>>>> + */
>>>> +int devm_mutex_init(struct device *dev, struct mutex *lock)
>>>> +{
>>>> + mutex_init(lock);
>>>> + return devm_add_action_or_reset(dev, devm_mutex_release, lock);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(devm_mutex_init);
>>> Hi George,
>>>
>>> look at
>>> https://lore.kernel.org/lkml/7013bf9e-2663-4613-ae61-61872e81355b@redhat.com/
>>> where Matthew and Hans explain that devm_mutex_init needs to be a macro
>>> because of the static lockdep key.
>>>
>>> so this should be something like:
>>>
>>> static inline int __devm_mutex_init(struct device *dev, struct mutex *mutex,
>>> const char *name,
>>> struct lock_class_key *key)
>>> {
>>> __mutex_init(mutex, name, key);
>>> return devm_add_action_or_reset(dev, devm_mutex_release, mutex);
>>> }
>>>
>>> #define devm_mutex_init(dev, mutex) \
>>> do { \
>>> static struct lock_class_key __key; \
>>> \
>>> __devm_mutex_init(dev, (mutex), #mutex, &__key); \
>>> } while (0);
>>>
>>>
>>> Marek
>>
>> Making devm_mutex_init() a function will make all the devm_mutex share
>> the same lockdep key. Making it a macro will make each caller of
>> devm_mutex_init() have a distinct lockdep key. It all depends on whether
>> all the devm_mutexes have the same lock usage pattern or not and whether
>> it is possible for one devm_mutex to be nested inside another. So either
>> way can be fine depending on the mutex usage pattern. My suggestion is
>> to use a function, if possible, unless it will cause a false positive
>> lockdep splat as there is a limit on the maximum # of lockdep keys that
>> can be used.
>
> devm_mutex_init() should behave like other similar function
> initializing stuff with resource management. I.e. it should behave like
> mutex_init(), but with resource management.
>
> mutex_init() is a macro generating static lockdep key for each instance,
> so devm_mutex_init() should also generate static lockdep key for each
> instance.
>
> Marek
--
Best regards
George
next prev parent reply other threads:[~2024-03-11 23:47 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-07 2:40 [PATCH v5 00/10] devm_led_classdev_register() usage problem George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 01/10] locking/mutex: move mutex_destroy() definition lower George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 02/10] locking/mutex: introduce devm_mutex_init George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 9:56 ` Marek Behún
2024-03-07 9:56 ` Marek Behún
2024-03-07 13:39 ` Waiman Long
2024-03-07 13:39 ` Waiman Long
2024-03-07 16:44 ` Marek Behún
2024-03-07 16:44 ` Marek Behún
2024-03-11 23:47 ` George Stark [this message]
2024-03-11 23:47 ` George Stark
2024-03-12 1:10 ` Waiman Long
2024-03-12 1:10 ` Waiman Long
2024-03-12 5:44 ` Christophe Leroy
2024-03-12 5:44 ` Christophe Leroy
2024-03-12 6:04 ` Christophe Leroy
2024-03-12 6:04 ` Christophe Leroy
2024-03-12 11:39 ` George Stark
2024-03-12 11:39 ` George Stark
2024-03-12 11:51 ` Christophe Leroy
2024-03-12 11:51 ` Christophe Leroy
2024-03-12 15:30 ` George Stark
2024-03-12 15:30 ` George Stark
2024-03-12 18:17 ` Christophe Leroy
2024-03-12 18:17 ` Christophe Leroy
2024-03-07 10:34 ` Andy Shevchenko
2024-03-07 10:34 ` Andy Shevchenko
2024-03-12 0:01 ` George Stark
2024-03-12 0:01 ` George Stark
2024-03-12 5:41 ` Christophe Leroy
2024-03-12 5:41 ` Christophe Leroy
2024-03-12 8:58 ` Andy Shevchenko
2024-03-12 8:58 ` Andy Shevchenko
2024-03-07 13:50 ` Christophe Leroy
2024-03-07 13:50 ` Christophe Leroy
2024-03-11 23:31 ` George Stark
2024-03-11 23:31 ` George Stark
2024-03-07 2:40 ` [PATCH v5 03/10] leds: aw2013: use devm API to cleanup module's resources George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 04/10] leds: aw200xx: " George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 05/10] leds: lp3952: " George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 06/10] leds: lm3532: " George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 07/10] leds: nic78bx: " George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 08/10] leds: mlxreg: use devm_mutex_init for mutex initializtion George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 09/10] leds: an30259a: use devm_mutext_init for mutext initialization George Stark
2024-03-07 2:40 ` George Stark
2024-03-07 2:40 ` [PATCH v5 10/10] leds: powernv: use LED_RETAIN_AT_SHUTDOWN flag for leds George Stark
2024-03-07 2:40 ` George Stark
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cfceef12-883e-4593-9dca-50768acb1aa9@salutedevices.com \
--to=gnstark@salutedevices.com \
--cc=andy.shevchenko@gmail.com \
--cc=boqun.feng@gmail.com \
--cc=christophe.leroy@csgroup.eu \
--cc=hdegoede@redhat.com \
--cc=kabel@kernel.org \
--cc=kernel@salutedevices.com \
--cc=lee@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=longman@redhat.com \
--cc=marek.behun@nic.cz \
--cc=mazziesaccount@gmail.com \
--cc=mingo@redhat.com \
--cc=mpe@ellerman.id.au \
--cc=nikitos.tr@gmail.com \
--cc=npiggin@gmail.com \
--cc=pavel@ucw.cz \
--cc=peterz@infradead.org \
--cc=vadimp@nvidia.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.