All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Bristot de Oliveira <bristot@kernel.org>
To: Guenter Roeck <linux@roeck-us.net>, Steven Rostedt <rostedt@goodmis.org>
Cc: Wim Van Sebroeck <wim@linux-watchdog.org>,
	Jonathan Corbet <corbet@lwn.net>, Ingo Molnar <mingo@redhat.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Peter Zijlstra <peterz@infradead.org>,
	Will Deacon <will@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Marco Elver <elver@google.com>,
	Dmitry Vyukov <dvyukov@google.com>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Gabriele Paoloni <gpaoloni@redhat.com>,
	Juri Lelli <juri.lelli@redhat.com>,
	Clark Williams <williams@redhat.com>,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-trace-devel@vger.kernel.org
Subject: Re: [PATCH V4 17/20] watchdog/dev: Add tracepoints
Date: Thu, 16 Jun 2022 17:47:15 +0200	[thread overview]
Message-ID: <4d8c53a1-7b94-fb0e-29e5-ed13b72093f1@kernel.org> (raw)
In-Reply-To: <a141e63a-c62c-8094-fedf-7f22f9090b0f@roeck-us.net>

On 6/16/22 15:44, Guenter Roeck wrote:
> On 6/16/22 01:44, Daniel Bristot de Oliveira wrote:
>> Add a set of tracepoints, enabling the observability of the watchdog
>> device interactions with user-space.
>>
>> The events are:
>>     watchdog:watchdog_open
>>     watchdog:watchdog_close
>>     watchdog:watchdog_start
>>     watchdog:watchdog_stop
>>     watchdog:watchdog_set_timeout
>>     watchdog:watchdog_ping
>>     watchdog:watchdog_nowayout
>>     watchdog:watchdog_set_keep_alive
>>     watchdog:watchdog_keep_alive
>>     watchdog:watchdog_set_pretimeout
>>     watchdog:watchdog_pretimeout
>>
>> Cc: Wim Van Sebroeck <wim@linux-watchdog.org>
>> Cc: Guenter Roeck <linux@roeck-us.net>
>> Cc: Jonathan Corbet <corbet@lwn.net>
>> Cc: Steven Rostedt <rostedt@goodmis.org>
>> Cc: Ingo Molnar <mingo@redhat.com>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> Cc: Peter Zijlstra <peterz@infradead.org>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Marco Elver <elver@google.com>
>> Cc: Dmitry Vyukov <dvyukov@google.com>
>> Cc: "Paul E. McKenney" <paulmck@kernel.org>
>> Cc: Shuah Khan <skhan@linuxfoundation.org>
>> Cc: Gabriele Paoloni <gpaoloni@redhat.com>
>> Cc: Juri Lelli <juri.lelli@redhat.com>
>> Cc: Clark Williams <williams@redhat.com>
>> Cc: linux-doc@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org
>> Cc: linux-trace-devel@vger.kernel.org
>> Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
>> ---
>>   drivers/watchdog/watchdog_dev.c        |  43 ++++++++++-
>>   drivers/watchdog/watchdog_pretimeout.c |   2 +
>>   include/linux/watchdog.h               |   7 +-
>>   include/trace/events/watchdog.h        | 101 +++++++++++++++++++++++++
>>   4 files changed, 143 insertions(+), 10 deletions(-)
>>   create mode 100644 include/trace/events/watchdog.h
>>
>> diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
>> index 54903f3c851e..2f28dc5ab763 100644
>> --- a/drivers/watchdog/watchdog_dev.c
>> +++ b/drivers/watchdog/watchdog_dev.c
>> @@ -44,6 +44,9 @@
>>   #include <linux/watchdog.h>    /* For watchdog specific items */
>>   #include <linux/uaccess.h>    /* For copy_to_user/put_user/... */
>>   +#define CREATE_TRACE_POINTS
>> +#include <trace/events/watchdog.h>
>> +
>>   #include "watchdog_core.h"
>>   #include "watchdog_pretimeout.h"
>>   @@ -130,9 +133,11 @@ static inline void watchdog_update_worker(struct
>> watchdog_device *wdd)
>>       if (watchdog_need_worker(wdd)) {
>>           ktime_t t = watchdog_next_keepalive(wdd);
>>   -        if (t > 0)
>> +        if (t > 0) {
>>               hrtimer_start(&wd_data->timer, t,
>>                         HRTIMER_MODE_REL_HARD);
>> +            trace_watchdog_set_keep_alive(wdd, ktime_to_ms(t));
>> +        }
>>       } else {
>>           hrtimer_cancel(&wd_data->timer);
>>       }
>> @@ -141,7 +146,7 @@ static inline void watchdog_update_worker(struct
>> watchdog_device *wdd)
>>   static int __watchdog_ping(struct watchdog_device *wdd)
>>   {
>>       struct watchdog_core_data *wd_data = wdd->wd_data;
>> -    ktime_t earliest_keepalive, now;
>> +    ktime_t earliest_keepalive, now, next_keepalive;
>>       int err;
>>         earliest_keepalive = ktime_add(wd_data->last_hw_keepalive,
>> @@ -149,14 +154,16 @@ static int __watchdog_ping(struct watchdog_device *wdd)
>>       now = ktime_get();
>>         if (ktime_after(earliest_keepalive, now)) {
>> -        hrtimer_start(&wd_data->timer,
>> -                  ktime_sub(earliest_keepalive, now),
>> +        next_keepalive = ktime_sub(earliest_keepalive, now);
>> +        hrtimer_start(&wd_data->timer, next_keepalive,
>>                     HRTIMER_MODE_REL_HARD);
>> +        trace_watchdog_set_keep_alive(wdd, ktime_to_ms(next_keepalive));
>>           return 0;
>>       }
>>         wd_data->last_hw_keepalive = now;
>>   +    trace_watchdog_ping(wdd);
>>       if (wdd->ops->ping)
>>           err = wdd->ops->ping(wdd);  /* ping the watchdog */
>>       else
>> @@ -215,6 +222,7 @@ static void watchdog_ping_work(struct kthread_work *work)
>>       wd_data = container_of(work, struct watchdog_core_data, work);
>>         mutex_lock(&wd_data->lock);
>> +    trace_watchdog_keep_alive(wd_data->wdd);
>>       if (watchdog_worker_should_ping(wd_data))
>>           __watchdog_ping(wd_data->wdd);
>>       mutex_unlock(&wd_data->lock);
>> @@ -250,6 +258,8 @@ static int watchdog_start(struct watchdog_device *wdd)
>>         set_bit(_WDOG_KEEPALIVE, &wd_data->status);
>>   +    trace_watchdog_start(wdd);
>> +
>>       started_at = ktime_get();
>>       if (watchdog_hw_running(wdd) && wdd->ops->ping) {
>>           err = __watchdog_ping(wdd);
>> @@ -294,6 +304,7 @@ static int watchdog_stop(struct watchdog_device *wdd)
>>           return -EBUSY;
>>       }
>>   +    trace_watchdog_stop(wdd);
>>       if (wdd->ops->stop) {
>>           clear_bit(WDOG_HW_RUNNING, &wdd->status);
>>           err = wdd->ops->stop(wdd);
>> @@ -367,6 +378,7 @@ static int watchdog_set_timeout(struct watchdog_device *wdd,
>>       if (watchdog_timeout_invalid(wdd, timeout))
>>           return -EINVAL;
>>   +    trace_watchdog_set_timeout(wdd, timeout);
> 
> The driver has no obligation to set the timeout to the
> requested value. It might be more valuable to report both
> the requested and the actual values.
> 
>

Ack! how do I get the actual value?

>>       if (wdd->ops->set_timeout) {
>>           err = wdd->ops->set_timeout(wdd, timeout);
>>       } else {
>> @@ -399,6 +411,8 @@ static int watchdog_set_pretimeout(struct watchdog_device
>> *wdd,
>>       if (watchdog_pretimeout_invalid(wdd, timeout))
>>           return -EINVAL;
>>   +    trace_watchdog_set_pretimeout(wdd, timeout);
>> +
> 
> Again, the driver has no obligation to set the timeout to the
> requested value.

/me takes note.

> 
>>       if (wdd->ops->set_pretimeout && (wdd->info->options & WDIOF_PRETIMEOUT))
>>           err = wdd->ops->set_pretimeout(wdd, timeout);
>>       else
>> @@ -430,6 +444,23 @@ static int watchdog_get_timeleft(struct watchdog_device
>> *wdd,
>>       return 0;
>>   }
>>   +/**
>> + * watchdog_set_nowayout - set nowaout bit
>> + * @wdd:    The watchdog device to set nowayoutbit
>> + * @nowayout    A boolean on/off switcher
>> + *
>> + * If nowayout boolean is true, the nowayout option is set. No action is
>> + * taken if nowayout is false.
>> + */
>> +void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
>> +{
>> +    if (nowayout) {
>> +        set_bit(WDOG_NO_WAY_OUT, &wdd->status);
>> +        trace_watchdog_nowayout(wdd);
>> +    }
>> +}
>> +EXPORT_SYMBOL(watchdog_set_nowayout);
>> +
>>   #ifdef CONFIG_WATCHDOG_SYSFS
>>   static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
>>                   char *buf)
>> @@ -861,6 +892,8 @@ static int watchdog_open(struct inode *inode, struct file
>> *file)
>>           goto out_clear;
>>       }
>>   +    trace_watchdog_open(wdd);
>> +
>>       err = watchdog_start(wdd);
>>       if (err < 0)
>>           goto out_mod;
>> @@ -883,6 +916,7 @@ static int watchdog_open(struct inode *inode, struct file
>> *file)
>>       return stream_open(inode, file);
>>     out_mod:
>> +    trace_watchdog_close(wdd);
>>       module_put(wd_data->wdd->ops->owner);
>>   out_clear:
>>       clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
>> @@ -944,6 +978,7 @@ static int watchdog_release(struct inode *inode, struct
>> file *file)
>>       /* make sure that /dev/watchdog can be re-opened */
>>       clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
>>   +    trace_watchdog_close(wdd);
>>   done:
>>       running = wdd && watchdog_hw_running(wdd);
>>       mutex_unlock(&wd_data->lock);
>> diff --git a/drivers/watchdog/watchdog_pretimeout.c
>> b/drivers/watchdog/watchdog_pretimeout.c
>> index 376a495ab80c..58c391ed2205 100644
>> --- a/drivers/watchdog/watchdog_pretimeout.c
>> +++ b/drivers/watchdog/watchdog_pretimeout.c
>> @@ -8,6 +8,7 @@
>>   #include <linux/spinlock.h>
>>   #include <linux/string.h>
>>   #include <linux/watchdog.h>
>> +#include <trace/events/watchdog.h>
>>     #include "watchdog_core.h"
>>   #include "watchdog_pretimeout.h"
>> @@ -107,6 +108,7 @@ void watchdog_notify_pretimeout(struct watchdog_device *wdd)
>>           return;
>>       }
>>   +    trace_watchdog_pretimeout(wdd);
>>       wdd->gov->pretimeout(wdd);
>>       spin_unlock_irqrestore(&pretimeout_lock, flags);
>>   }
>> diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
>> index 99660197a36c..11d93407e492 100644
>> --- a/include/linux/watchdog.h
>> +++ b/include/linux/watchdog.h
>> @@ -139,12 +139,7 @@ static inline bool watchdog_hw_running(struct
>> watchdog_device *wdd)
>>       return test_bit(WDOG_HW_RUNNING, &wdd->status);
>>   }
>>   -/* Use the following function to set the nowayout feature */
>> -static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool
>> nowayout)
>> -{
>> -    if (nowayout)
>> -        set_bit(WDOG_NO_WAY_OUT, &wdd->status);
>> -}
>> +void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout);
>>     /* Use the following function to stop the watchdog on reboot */
>>   static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd)
>> diff --git a/include/trace/events/watchdog.h b/include/trace/events/watchdog.h
>> new file mode 100644
>> index 000000000000..145cd6cfaa02
>> --- /dev/null
>> +++ b/include/trace/events/watchdog.h
>> @@ -0,0 +1,101 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +#undef TRACE_SYSTEM
>> +#define TRACE_SYSTEM watchdog
>> +
>> +#if !defined(_TRACE_WATCHDOG_H) || defined(TRACE_HEADER_MULTI_READ)
>> +#define _TRACE_WATCHDOG_H
>> +
>> +#include <linux/tracepoint.h>
>> +
>> +/*
>> + * These are all events whose sole argument is the watchdog id.
>> + */
>> +DECLARE_EVENT_CLASS(dev_operations_template,
>> +
>> +    TP_PROTO(struct watchdog_device *wdd),
>> +
>> +    TP_ARGS(wdd),
>> +
>> +    TP_STRUCT__entry(
>> +        __field(__u32, id)
>> +    ),
>> +
>> +    TP_fast_assign(
>> +        __entry->id = wdd->id;
>> +    ),
>> +
>> +    TP_printk("id=%d",
>> +          __entry->id)
>> +);
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_open,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_close,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_start,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_stop,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_ping,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_nowayout,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_keep_alive,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +DEFINE_EVENT(dev_operations_template, watchdog_pretimeout,
>> +         TP_PROTO(struct watchdog_device *wdd),
>> +         TP_ARGS(wdd));
>> +
>> +/*
>> + * These are all events with a device ID and a given timeout.
>> + */
>> +DECLARE_EVENT_CLASS(watchdog_timeout_template,
>> +
>> +    TP_PROTO(struct watchdog_device *wdd, u64 timeout),
>> +
>> +    TP_ARGS(wdd, timeout),
>> +
>> +    TP_STRUCT__entry(
>> +        __field(__u32, id)
>> +        __field(__u64, timeout)
> 
> 
> Why u64 ? timeout is unsigned long.

ack! I will change it. (I am seeing unsigned int, am I missing something?).

Thanks!
-- Daniel

  reply	other threads:[~2022-06-16 15:47 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-16  8:44 [PATCH V4 00/20] The Runtime Verification (RV) interface Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 01/20] rv: Add " Daniel Bristot de Oliveira
2022-06-23 17:21   ` Punit Agrawal
2022-07-01 13:24     ` Daniel Bristot de Oliveira
2022-06-23 20:26   ` Steven Rostedt
2022-07-04 19:49     ` Daniel Bristot de Oliveira
2022-07-06 17:49   ` Tao Zhou
2022-07-06 17:53     ` Matthew Wilcox
2022-07-08 15:36       ` Tao Zhou
2022-07-08 15:55         ` Matthew Wilcox
2022-07-08 14:39     ` Daniel Bristot de Oliveira
2022-07-10 15:11       ` Tao Zhou
2022-07-10 15:42         ` Steven Rostedt
2022-07-10 22:28           ` Tao Zhou
2022-06-16  8:44 ` [PATCH V4 02/20] rv: Add runtime reactors interface Daniel Bristot de Oliveira
2022-06-23 20:40   ` Steven Rostedt
2022-06-16  8:44 ` [PATCH V4 03/20] rv/include: Add helper functions for deterministic automata Daniel Bristot de Oliveira
2022-06-28 17:48   ` Steven Rostedt
2022-07-06 18:35   ` Tao Zhou
2022-07-13 18:38     ` Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 04/20] rv/include: Add deterministic automata monitor definition via C macros Daniel Bristot de Oliveira
2022-07-06 18:56   ` Tao Zhou
2022-07-13 18:39     ` Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 05/20] rv/include: Add instrumentation helper functions Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 06/20] tools/rv: Add dot2c Daniel Bristot de Oliveira
2022-06-28 18:10   ` Steven Rostedt
2022-06-28 18:16   ` Steven Rostedt
2022-07-13 18:41     ` Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 07/20] tools/rv: Add dot2k Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 08/20] rv/monitor: Add the wip monitor skeleton created by dot2k Daniel Bristot de Oliveira
2022-06-28 19:02   ` Steven Rostedt
2022-06-16  8:44 ` [PATCH V4 09/20] rv/monitor: wip instrumentation and Makefile/Kconfig entries Daniel Bristot de Oliveira
2022-06-16 11:21   ` kernel test robot
2022-06-16 21:00   ` Randy Dunlap
2022-06-17 16:07     ` Daniel Bristot de Oliveira
2022-06-28 19:02     ` Steven Rostedt
2022-06-16  8:44 ` [PATCH V4 10/20] rv/monitor: Add the wwnr monitor skeleton created by dot2k Daniel Bristot de Oliveira
2022-07-06 20:08   ` Tao Zhou
2022-06-16  8:44 ` [PATCH V4 11/20] rv/monitor: wwnr instrumentation and Makefile/Kconfig entries Daniel Bristot de Oliveira
2022-06-16 13:47   ` kernel test robot
2022-06-28 19:05   ` Steven Rostedt
2022-06-16  8:44 ` [PATCH V4 12/20] rv/reactor: Add the printk reactor Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 13/20] rv/reactor: Add the panic reactor Daniel Bristot de Oliveira
2022-06-16 15:20   ` kernel test robot
2022-06-16 21:03   ` Randy Dunlap
2022-06-17 16:09     ` Daniel Bristot de Oliveira
2022-07-13 18:47     ` Daniel Bristot de Oliveira
2022-06-28 19:06   ` Steven Rostedt
2022-06-16  8:44 ` [PATCH V4 14/20] Documentation/rv: Add a basic documentation Daniel Bristot de Oliveira
2022-06-29  3:35   ` Bagas Sanjaya
2022-07-13 19:30     ` Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 15/20] Documentation/rv: Add deterministic automata monitor synthesis documentation Daniel Bristot de Oliveira
2022-06-28 19:09   ` Steven Rostedt
2022-06-16  8:44 ` [PATCH V4 16/20] Documentation/rv: Add deterministic automata instrumentation documentation Daniel Bristot de Oliveira
2022-06-16  8:44 ` [PATCH V4 17/20] watchdog/dev: Add tracepoints Daniel Bristot de Oliveira
2022-06-16 13:44   ` Guenter Roeck
2022-06-16 15:47     ` Daniel Bristot de Oliveira [this message]
2022-06-16 23:55       ` Guenter Roeck
2022-06-17 16:16         ` Daniel Bristot de Oliveira
2022-07-13 18:49         ` Daniel Bristot de Oliveira
2022-06-16  8:45 ` [PATCH V4 18/20] rv/monitor: Add safe watchdog monitor Daniel Bristot de Oliveira
2022-06-16 13:36   ` Guenter Roeck
2022-06-16 15:29     ` Daniel Bristot de Oliveira
     [not found]       ` <CA+wEVJbvcMZbCroO2_rdVxLvYkUo-ePxCwsp5vbDpoqys4HGWQ@mail.gmail.com>
2022-06-16 23:53         ` Guenter Roeck
2022-06-17 17:06           ` Daniel Bristot de Oliveira
2022-06-28 19:32           ` Steven Rostedt
2022-07-01 14:45             ` Guenter Roeck
2022-07-01 15:38               ` Steven Rostedt
2022-07-04 12:41                 ` Daniel Bristot de Oliveira
2022-06-16 20:57   ` Randy Dunlap
2022-06-17 16:17     ` Daniel Bristot de Oliveira
2022-07-13 19:13   ` Daniel Bristot de Oliveira
2022-06-16  8:45 ` [PATCH V4 19/20] rv/safety_app: Add a safety_app sample Daniel Bristot de Oliveira
2022-06-16  8:45 ` [PATCH V4 20/20] Documentation/rv: Add watchdog-monitor documentation Daniel Bristot de Oliveira
2022-07-07 12:41   ` Tao Zhou
2022-07-13 18:51     ` Daniel Bristot de Oliveira
2022-06-22  7:24 ` [PATCH V4 00/20] The Runtime Verification (RV) interface Song Liu
2022-06-23 16:41   ` Daniel Bristot de Oliveira
2022-06-23 17:52     ` Song Liu
2022-06-23 20:29       ` Daniel Bristot de Oliveira
2022-06-23 21:10         ` Song Liu
2022-07-06 16:18 ` Tao Zhou

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=4d8c53a1-7b94-fb0e-29e5-ed13b72093f1@kernel.org \
    --to=bristot@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=corbet@lwn.net \
    --cc=dvyukov@google.com \
    --cc=elver@google.com \
    --cc=gpaoloni@redhat.com \
    --cc=juri.lelli@redhat.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=mingo@redhat.com \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=skhan@linuxfoundation.org \
    --cc=tglx@linutronix.de \
    --cc=will@kernel.org \
    --cc=williams@redhat.com \
    --cc=wim@linux-watchdog.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.