All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mike Snitzer <snitzer@kernel.org>
To: NeilBrown <neilb@suse.de>
Cc: Jeff Layton <jlayton@kernel.org>,
	linux-nfs@vger.kernel.org, Chuck Lever <chuck.lever@oracle.com>,
	Anna Schumaker <anna@kernel.org>,
	Trond Myklebust <trondmy@hammerspace.com>,
	linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH v14 15/25] nfs_common: introduce nfs_localio_ctx struct and interfaces
Date: Fri, 30 Aug 2024 01:08:52 -0400	[thread overview]
Message-ID: <ZtFT5LDW7BIkqKDf@kernel.org> (raw)
In-Reply-To: <ZtFSQz8YaD3A4r3Y@kernel.org>

On Fri, Aug 30, 2024 at 01:01:55AM -0400, Mike Snitzer wrote:
> On Fri, Aug 30, 2024 at 02:36:13PM +1000, NeilBrown wrote:
> > On Fri, 30 Aug 2024, Jeff Layton wrote:
> > > 
> > > Have a pointer to a struct nfsd_localio_ops or something in the
> > > nfs_common module. That's initially set to NULL. Then, have a static
> > > structure of that type in nfsd.ko, and have its __init routine set the
> > > pointer in nfs_common to point to the right structure. The __exit
> > > routine will later set it to NULL.
> > > 
> > > > I really don't want all calls in NFS client (or nfs_common) to have to
> > > > first check if nfs_common's 'nfs_to' ops structure is NULL or not.
> > > 
> > > Neil seems to think that's not necessary:
> > > 
> > > "If nfs/localio holds an auth_domain, then it implicitly holds a
> > > reference to the nfsd module and the functions cannot disappear."
> > 
> > On reflection that isn't quite right, but it is the sort of approach
> > that I think we need to take.
> > There are several things that the NFS client needs to hold one to.
> > 
> > 1/ It needs a reference to the nfsd module (or symbols in the module).
> >    I think this can be held long term but we need a clear mechanism for
> >    it to be dropped.
> > 2/ It needs a reference to the nfsd_serv which it gets through the
> >    'struct net' pointer.  I've posted patches to handle that better.
> > 3/ It needs a reference to an auth_domain.  This can safely be a long
> >    term reference.  It can already be invalidated and the code to free
> >    it is in sunrpc which nfs already pins.  Any delay in freeing it only
> >    wastes memory (not much), it doesn't impact anything else.
> > 4/ It needs a reference to the nfsd_file and/or file.  This is currently
> >    done only while the ref to the nfsd_serv is held, so I think there is
> >    no problem there.
> > 
> > So possibly we could take a reference to the nfsd module whenever we
> > store a net in nfs_uuid. and drop the ref whenever we clear that.
> > 
> > That means we cannot call nfsd_open_local_fh() without first getting a
> > ref on the nfsd_serv which my latest code doesn't do.  That is easily
> > fixed.  I'll send a patch for consideration...
> 
> I already implemented 2 different versions today, meant for v15.
> 
> First is a relaxed version of the v14 code (less code, only using
> symbol_request on nfsd_open_local_fh.

This is the corresponding code that is needed in fs/nfsd/localio.c

+static const struct nfsd_localio_operations nfsd_localio_ops = {
+       .nfsd_open_local_fh = nfsd_open_local_fh,
+       .nfsd_file_get = nfsd_file_get,
+       .nfsd_file_put = nfsd_file_put,
+       .nfsd_file_file = nfsd_file_file,
+       .nfsd_serv_put = nfsd_serv_put,
+};
+
+void init_nfs_to_nfsd_localio_ops(void)
+{
+       memcpy(&nfs_to, &nfsd_localio_ops, sizeof(nfsd_localio_ops));
+}
+EXPORT_SYMBOL_GPL(init_nfs_to_nfsd_localio_ops);

From: Mike Snitzer <snitzer@kernel.org>
Date: Wed, 28 Aug 2024 17:04:44 -0500
Subject: [PATCH v15.option1] nfs_common: introduce nfs_localio_ctx struct and interfaces

Introduce struct nfs_localio_ctx (which has nfsd_file and nfsd_net
members) and the interfaces nfs_localio_ctx_alloc() and
nfs_localio_ctx_free().  The next commit will introduce
nfsd_open_local_fh() which returns a nfs_localio_ctx structure.

Also, expose localio's required NFSD symbols to NFS client:
- Make nfsd_open_local_fh() symbol and other required NFSD symbols
  available to NFS in a global 'nfs_to' nfsd_localio_operations
  struct.  Add interfaces get_nfs_to_nfsd_localio_ops() and
  put_nfs_to_nfsd_localio_ops() to allow each NFS client to take a
  reference on NFSD (indirectly through nfs_common).

- Given the unique nature of NFS LOCALIO being an optional feature
  that when used requires NFS share access to NFSD memory: a unique
  bridging of NFSD resources to NFS (via nfs_common) is needed.  But
  that bridge must be dynamic, hence the use of symbol_request() and
  symbol_put() of the one init_nfs_to_nfsd_localio_ops() symbol which
  nfs_common's LOCALIO code uses as a bellwether for both if NFSD is
  available and supports LOCALIO.

- Use of a refcount_t (managed by {get,put}_nfs_to_nfsd_localio_ops)
  is required to ensure NFS doesn't become disjoint from NFSD's
  availability in the face of LOCALIO support being toggled on/off
  coupled with the NFSD module (possibly) being unloaded.

- Introduce nfsd_file_file() wrapper that provides access to
  nfsd_file's backing file.  Keeps nfsd_file structure opaque to NFS
  client (as suggested by Jeff Layton).

- The addition of nfsd_file_get, nfsd_file_put and nfsd_file_file
  symbols prepares for the NFS client to use nfsd_file for localio.

Suggested-by: Trond Myklebust <trond.myklebust@hammerspace.com> # nfs_to
Suggested-by: NeilBrown <neilb@suse.de> # nfsd_localio_operations
Suggested-by: Jeff Layton <jlayton@kernel.org> # nfsd_file_file
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
---
 fs/nfs_common/nfslocalio.c | 107 +++++++++++++++++++++++++++++++++++++
 fs/nfsd/filecache.c        |  16 ++++++
 fs/nfsd/filecache.h        |   1 +
 fs/nfsd/nfssvc.c           |   2 +
 include/linux/nfslocalio.h |  47 ++++++++++++++++
 5 files changed, 173 insertions(+)

diff --git a/fs/nfs_common/nfslocalio.c b/fs/nfs_common/nfslocalio.c
index 0b2e17c2068f..5f12610a877c 100644
--- a/fs/nfs_common/nfslocalio.c
+++ b/fs/nfs_common/nfslocalio.c
@@ -5,6 +5,7 @@
 
 #include <linux/module.h>
 #include <linux/rculist.h>
+#include <linux/refcount.h>
 #include <linux/nfslocalio.h>
 #include <net/netns/generic.h>
 
@@ -72,3 +73,109 @@ bool nfs_uuid_is_local(const uuid_t *uuid, struct net *net, struct auth_domain *
 	return is_local;
 }
 EXPORT_SYMBOL_GPL(nfs_uuid_is_local);
+
+/*
+ * The nfs localio code needs to call into nfsd using various symbols (below),
+ * but cannot be statically linked, because that will make the nfs module
+ * depend on the nfsd module.
+ *
+ * Instead, do dynamic linking to the nfsd module (via nfs_common module). The
+ * nfs_common module will only hold a reference on nfsd when localio is in use.
+ * This allows some sanity checking, like giving up on localio if nfsd isn't loaded.
+ */
+static DEFINE_SPINLOCK(nfs_to_nfsd_lock);
+static refcount_t nfs_to_ref;
+struct nfsd_localio_operations nfs_to;
+EXPORT_SYMBOL_GPL(nfs_to);
+
+bool get_nfs_to_nfsd_localio_ops(void)
+{
+	bool ret = false;
+	init_nfs_to_nfsd_localio_ops_t init_nfs_to;
+
+	spin_lock(&nfs_to_nfsd_lock);
+
+	/* Only get nfsd_localio_operations on first reference */
+	if (refcount_read(&nfs_to_ref) == 0)
+		refcount_set(&nfs_to_ref, 1);
+	else {
+		refcount_inc(&nfs_to_ref);
+		ret = true;
+		goto out;
+	}
+
+	/*
+	 * If NFSD isn't available LOCALIO isn't possible.
+	 * Use init_nfs_to_nfsd_ops symbol as the bellwether,
+	 * if available then nfs_common has NFSD module reference
+	 * on NFS's behalf and can initialize global 'nfs_to'.
+	 */
+	init_nfs_to = symbol_request(init_nfs_to_nfsd_localio_ops);
+	if (init_nfs_to) {
+		init_nfs_to();
+		if (WARN_ON_ONCE(!nfs_to.nfsd_open_local_fh)) {
+			symbol_put(init_nfs_to_nfsd_localio_ops);
+			goto out;
+		}
+		ret = true;
+	}
+out:
+	spin_unlock(&nfs_to_nfsd_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(get_nfs_to_nfsd_localio_ops);
+
+void put_nfs_to_nfsd_localio_ops(void)
+{
+	spin_lock(&nfs_to_nfsd_lock);
+
+	if (!refcount_dec_and_test(&nfs_to_ref))
+		goto out;
+
+	symbol_put(init_nfs_to_nfsd_localio_ops);
+	memset(&nfs_to, 0, sizeof(nfs_to));
+out:
+	spin_unlock(&nfs_to_nfsd_lock);
+}
+EXPORT_SYMBOL_GPL(put_nfs_to_nfsd_localio_ops);
+
+/*
+ * nfs_localio_ctx cache and alloc/free interfaces.
+ */
+static struct kmem_cache *nfs_localio_ctx_cache;
+
+struct nfs_localio_ctx *nfs_localio_ctx_alloc(void)
+{
+	return kmem_cache_alloc(nfs_localio_ctx_cache,
+				GFP_KERNEL | __GFP_ZERO);
+}
+EXPORT_SYMBOL_GPL(nfs_localio_ctx_alloc);
+
+void nfs_localio_ctx_free(struct nfs_localio_ctx *localio)
+{
+	if (localio->nf)
+		nfs_to.nfsd_file_put(localio->nf);
+	if (localio->nn)
+		nfs_to.nfsd_serv_put(localio->nn);
+	kmem_cache_free(nfs_localio_ctx_cache, localio);
+}
+EXPORT_SYMBOL_GPL(nfs_localio_ctx_free);
+
+static int __init nfslocalio_init(void)
+{
+	refcount_set(&nfs_to_ref, 0);
+
+	nfs_localio_ctx_cache = KMEM_CACHE(nfs_localio_ctx, 0);
+	if (!nfs_localio_ctx_cache)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void __exit nfslocalio_exit(void)
+{
+	kmem_cache_destroy(nfs_localio_ctx_cache);
+}
+
+module_init(nfslocalio_init);
+module_exit(nfslocalio_exit);
diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index 2dc72de31f61..1a26f5812578 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -39,6 +39,7 @@
 #include <linux/fsnotify.h>
 #include <linux/seq_file.h>
 #include <linux/rhashtable.h>
+#include <linux/nfslocalio.h>
 
 #include "vfs.h"
 #include "nfsd.h"
@@ -345,6 +346,7 @@ nfsd_file_get(struct nfsd_file *nf)
 		return nf;
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(nfsd_file_get);
 
 /**
  * nfsd_file_put - put the reference to a nfsd_file
@@ -389,6 +391,20 @@ nfsd_file_put(struct nfsd_file *nf)
 	if (refcount_dec_and_test(&nf->nf_ref))
 		nfsd_file_free(nf);
 }
+EXPORT_SYMBOL_GPL(nfsd_file_put);
+
+/**
+ * nfsd_file_file - get the backing file of an nfsd_file
+ * @nf: nfsd_file of which to access the backing file.
+ *
+ * Return backing file for @nf.
+ */
+struct file *
+nfsd_file_file(struct nfsd_file *nf)
+{
+	return nf->nf_file;
+}
+EXPORT_SYMBOL_GPL(nfsd_file_file);
 
 static void
 nfsd_file_dispose_list(struct list_head *dispose)
diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
index 26ada78b8c1e..6fbbb2e32e95 100644
--- a/fs/nfsd/filecache.h
+++ b/fs/nfsd/filecache.h
@@ -56,6 +56,7 @@ int nfsd_file_cache_start_net(struct net *net);
 void nfsd_file_cache_shutdown_net(struct net *net);
 void nfsd_file_put(struct nfsd_file *nf);
 struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
+struct file *nfsd_file_file(struct nfsd_file *nf);
 void nfsd_file_close_inode_sync(struct inode *inode);
 void nfsd_file_net_dispose(struct nfsd_net *nn);
 bool nfsd_file_is_cached(struct inode *inode);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index c639fbe4d8c2..7b9119b8dd1b 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -19,6 +19,7 @@
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/lockd/bind.h>
 #include <linux/nfsacl.h>
+#include <linux/nfslocalio.h>
 #include <linux/seq_file.h>
 #include <linux/inetdevice.h>
 #include <net/addrconf.h>
@@ -201,6 +202,7 @@ void nfsd_serv_put(struct nfsd_net *nn)
 {
 	percpu_ref_put(&nn->nfsd_serv_ref);
 }
+EXPORT_SYMBOL_GPL(nfsd_serv_put);
 
 static void nfsd_serv_done(struct percpu_ref *ref)
 {
diff --git a/include/linux/nfslocalio.h b/include/linux/nfslocalio.h
index 9735ae8d3e5e..6cc870122e2a 100644
--- a/include/linux/nfslocalio.h
+++ b/include/linux/nfslocalio.h
@@ -7,6 +7,7 @@
 
 #include <linux/list.h>
 #include <linux/uuid.h>
+#include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfs.h>
 #include <net/net_namespace.h>
@@ -28,4 +29,50 @@ void nfs_uuid_begin(nfs_uuid_t *);
 void nfs_uuid_end(nfs_uuid_t *);
 bool nfs_uuid_is_local(const uuid_t *, struct net *, struct auth_domain *);
 
+struct nfsd_file;
+struct nfsd_net;
+
+struct nfs_localio_ctx {
+	struct nfsd_file *nf;
+	struct nfsd_net *nn;
+};
+
+/* localio needs to map filehandle -> struct nfsd_file */
+typedef struct nfs_localio_ctx *
+(*nfs_to_nfsd_open_local_fh_t)(struct net *, struct auth_domain *,
+			       struct rpc_clnt *, const struct cred *,
+			       const struct nfs_fh *, const fmode_t);
+
+extern struct nfs_localio_ctx *
+nfsd_open_local_fh(struct net *, struct auth_domain *,
+		   struct rpc_clnt *, const struct cred *,
+		   const struct nfs_fh *, const fmode_t);
+
+/* localio needs to acquire an nfsd_file */
+typedef struct nfsd_file * (*nfs_to_nfsd_file_get_t)(struct nfsd_file *);
+/* localio needs to release an nfsd_file */
+typedef void (*nfs_to_nfsd_file_put_t)(struct nfsd_file *);
+/* localio needs to access the nf->nf_file */
+typedef struct file * (*nfs_to_nfsd_file_file_t)(struct nfsd_file *);
+/* localio needs to release nn->nfsd_serv */
+typedef void (*nfs_to_nfsd_serv_put_t)(struct nfsd_net *);
+
+struct nfsd_localio_operations {
+	nfs_to_nfsd_open_local_fh_t	nfsd_open_local_fh;
+	nfs_to_nfsd_file_get_t		nfsd_file_get;
+	nfs_to_nfsd_file_put_t		nfsd_file_put;
+	nfs_to_nfsd_file_file_t		nfsd_file_file;
+	nfs_to_nfsd_serv_put_t		nfsd_serv_put;
+} ____cacheline_aligned;
+
+extern struct nfsd_localio_operations nfs_to;
+
+typedef void (*init_nfs_to_nfsd_localio_ops_t)(void);
+extern void init_nfs_to_nfsd_localio_ops(void);
+bool get_nfs_to_nfsd_localio_ops(void);
+void put_nfs_to_nfsd_localio_ops(void);
+
+struct nfs_localio_ctx *nfs_localio_ctx_alloc(void);
+void nfs_localio_ctx_free(struct nfs_localio_ctx *);
+
 #endif  /* __LINUX_NFSLOCALIO_H */
-- 
2.44.0


  reply	other threads:[~2024-08-30  5:08 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-29  1:03 [PATCH v14 00/25] nfs/nfsd: add support for LOCALIO Mike Snitzer
2024-08-29  1:03 ` [PATCH v14 01/25] nfs_common: factor out nfs_errtbl and nfs_stat_to_errno Mike Snitzer
2024-08-29 14:17   ` Jeff Layton
2024-08-29  1:03 ` [PATCH v14 02/25] nfs_common: factor out nfs4_errtbl and nfs4_stat_to_errno Mike Snitzer
2024-08-29 14:17   ` Jeff Layton
2024-08-29  1:03 ` [PATCH v14 03/25] nfs: factor out {encode,decode}_opaque_fixed to nfs_xdr.h Mike Snitzer
2024-08-29 14:19   ` Jeff Layton
2024-08-29  1:03 ` [PATCH v14 04/25] NFSD: Handle @rqstp == NULL in check_nfsd_access() Mike Snitzer
2024-08-29 14:20   ` Jeff Layton
2024-08-29  1:04 ` [PATCH v14 05/25] NFSD: Refactor nfsd_setuser_and_check_port() Mike Snitzer
2024-08-29 14:23   ` Jeff Layton
2024-08-29  1:04 ` [PATCH v14 06/25] NFSD: Avoid using rqstp->rq_vers in nfsd_set_fh_dentry() Mike Snitzer
2024-08-29  1:45   ` [PATCH v14.5 " Mike Snitzer
2024-08-29 16:52     ` Jeff Layton
2024-08-29 14:28   ` [PATCH v14 " Jeff Layton
2024-08-29 15:28     ` Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 07/25] NFSD: Short-circuit fh_verify tracepoints for LOCALIO Mike Snitzer
2024-08-29 14:33   ` Jeff Layton
2024-08-29 14:35     ` Chuck Lever
2024-08-29  1:04 ` [PATCH v14 08/25] nfsd: factor out __fh_verify to allow NULL rqstp to be passed Mike Snitzer
2024-08-29 14:39   ` Jeff Layton
2024-08-29 15:35     ` Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 09/25] nfsd: add nfsd_file_acquire_local() Mike Snitzer
2024-08-29 14:49   ` Jeff Layton
2024-08-29 15:47   ` Chuck Lever
2024-08-29 15:59     ` Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 10/25] nfsd: add nfsd_serv_try_get and nfsd_serv_put Mike Snitzer
2024-08-29 15:49   ` Chuck Lever
2024-08-29 15:57   ` Jeff Layton
2024-08-29 16:01     ` Mike Snitzer
2024-08-29 16:04       ` Chuck Lever
2024-08-29  1:04 ` [PATCH v14 11/25] SUNRPC: remove call_allocate() BUG_ONs Mike Snitzer
2024-08-29 15:58   ` Jeff Layton
2024-08-29  1:04 ` [PATCH v14 12/25] SUNRPC: add svcauth_map_clnt_to_svc_cred_local Mike Snitzer
2024-08-29 15:50   ` Chuck Lever
2024-08-29 16:01   ` Jeff Layton
2024-08-29  1:04 ` [PATCH v14 13/25] SUNRPC: replace program list with program array Mike Snitzer
2024-08-29 16:02   ` Jeff Layton
2024-08-29  1:04 ` [PATCH v14 14/25] nfs_common: add NFS LOCALIO auxiliary protocol enablement Mike Snitzer
2024-08-29 16:07   ` Jeff Layton
2024-08-29 16:22     ` Mike Snitzer
2024-08-29 23:39   ` NeilBrown
2024-08-30  1:45     ` Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 15/25] nfs_common: introduce nfs_localio_ctx struct and interfaces Mike Snitzer
2024-08-29 16:40   ` Jeff Layton
2024-08-29 16:52     ` Mike Snitzer
2024-08-29 17:48       ` Jeff Layton
2024-08-30  4:36         ` NeilBrown
2024-08-30  5:01           ` Mike Snitzer
2024-08-30  5:08             ` Mike Snitzer [this message]
2024-08-30  5:12             ` Mike Snitzer
2024-08-30  5:34             ` NeilBrown
2024-08-30  6:02               ` Mike Snitzer
2024-08-30  5:46   ` NeilBrown
2024-08-30  5:56     ` Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 16/25] nfsd: add localio support Mike Snitzer
2024-08-29 16:01   ` Chuck Lever
2024-08-29 16:15     ` Mike Snitzer
2024-08-29 23:10     ` NeilBrown
2024-08-29 16:49   ` Jeff Layton
2024-08-29 16:59     ` Mike Snitzer
2024-08-29 17:18       ` Chuck Lever
2024-08-29  1:04 ` [PATCH v14 17/25] nfsd: implement server support for NFS_LOCALIO_PROGRAM Mike Snitzer
2024-08-29 16:50   ` Jeff Layton
2024-08-29  1:04 ` [PATCH v14 18/25] nfs: pass struct nfs_localio_ctx to nfs_init_pgio and nfs_init_commit Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 19/25] nfs: add localio support Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 20/25] nfs: enable localio for non-pNFS IO Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 21/25] pnfs/flexfiles: enable localio support Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 22/25] nfs/localio: use dedicated workqueues for filesystem read and write Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 23/25] nfs: implement client support for NFS_LOCALIO_PROGRAM Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 24/25] nfs: add Documentation/filesystems/nfs/localio.rst Mike Snitzer
2024-08-29  1:04 ` [PATCH v14 25/25] nfs: add FAQ section to Documentation/filesystems/nfs/localio.rst Mike Snitzer
2024-08-29  1:47   ` [PATCH v14.5 " Mike Snitzer
2024-08-29  1:42 ` [PATCH v14 00/25] nfs/nfsd: add support for LOCALIO Mike Snitzer
2024-08-29  1:50   ` Mike Snitzer

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=ZtFT5LDW7BIkqKDf@kernel.org \
    --to=snitzer@kernel.org \
    --cc=anna@kernel.org \
    --cc=chuck.lever@oracle.com \
    --cc=jlayton@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neilb@suse.de \
    --cc=trondmy@hammerspace.com \
    /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.