From: Dave Jiang <dave.jiang@intel.com>
To: John Groves <john@jagalactic.com>, John Groves <John@Groves.net>,
Miklos Szeredi <miklos@szeredi.hu>,
Dan Williams <dan.j.williams@intel.com>,
Bernd Schubert <bschubert@ddn.com>,
Alison Schofield <alison.schofield@intel.com>
Cc: John Groves <jgroves@micron.com>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Vishal Verma <vishal.l.verma@intel.com>,
Matthew Wilcox <willy@infradead.org>, Jan Kara <jack@suse.cz>,
Alexander Viro <viro@zeniv.linux.org.uk>,
David Hildenbrand <david@kernel.org>,
Christian Brauner <brauner@kernel.org>,
"Darrick J . Wong" <djwong@kernel.org>,
Randy Dunlap <rdunlap@infradead.org>,
Jeff Layton <jlayton@kernel.org>,
Amir Goldstein <amir73il@gmail.com>,
Jonathan Cameron <Jonathan.Cameron@huawei.com>,
Stefan Hajnoczi <shajnocz@redhat.com>,
Joanne Koong <joannelkoong@gmail.com>,
Josef Bacik <josef@toxicpanda.com>,
Bagas Sanjaya <bagasdotme@gmail.com>,
Chen Linxuan <chenlinxuan@uniontech.com>,
James Morse <james.morse@arm.com>, Fuad Tabba <tabba@google.com>,
Sean Christopherson <seanjc@google.com>,
Shivank Garg <shivankg@amd.com>,
Ackerley Tng <ackerleytng@google.com>,
Gregory Price <gourry@gourry.net>,
Aravind Ramesh <arramesh@micron.com>,
Ajay Joshi <ajayjoshi@micron.com>,
"venkataravis@micron.com" <venkataravis@micron.com>,
"linux-doc@vger.kernel.org" <linux-doc@vger.kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"nvdimm@lists.linux.dev" <nvdimm@lists.linux.dev>,
"linux-cxl@vger.kernel.org" <linux-cxl@vger.kernel.org>,
"linux-fsdevel@vger.kernel.org" <linux-fsdevel@vger.kernel.org>
Subject: Re: [PATCH V9 3/8] dax: add fsdev.c driver for fs-dax on character dax
Date: Tue, 24 Mar 2026 08:19:24 -0700 [thread overview]
Message-ID: <e0421e4f-0436-47f5-9d45-11adfbecdc3c@intel.com> (raw)
In-Reply-To: <0100019d1d476420-6b0bf60e-3b3a-4868-8f5f-484cd55d4709-000000@email.amazonses.com>
On 3/23/26 5:38 PM, John Groves wrote:
> From: John Groves <john@groves.net>
>
> The new fsdev driver provides pages/folios initialized compatibly with
> fsdax - normal rather than devdax-style refcounting, and starting out
> with order-0 folios.
>
> When fsdev binds to a daxdev, it is usually (always?) switching from the
> devdax mode (device.c), which pre-initializes compound folios according
> to its alignment. Fsdev uses fsdev_clear_folio_state() to switch the
> folios into a fsdax-compatible state.
>
> A side effect of this is that raw mmap doesn't (can't?) work on an fsdev
> dax instance. Accordingly, The fsdev driver does not provide raw mmap -
> devices must be put in 'devdax' mode (drivers/dax/device.c) to get raw
> mmap capability.
>
> In this commit is just the framework, which remaps pages/folios compatibly
> with fsdax.
>
> Enabling dax changes:
>
> - bus.h: add DAXDRV_FSDEV_TYPE driver type
> - bus.c: allow DAXDRV_FSDEV_TYPE drivers to bind to daxdevs
> - dax.h: prototype inode_dax(), which fsdev needs
>
> Suggested-by: Dan Williams <dan.j.williams@intel.com>
> Suggested-by: Gregory Price <gourry@gourry.net>
> Signed-off-by: John Groves <john@groves.net>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
> MAINTAINERS | 8 ++
> drivers/dax/Kconfig | 11 ++
> drivers/dax/Makefile | 2 +
> drivers/dax/bus.c | 4 +
> drivers/dax/bus.h | 1 +
> drivers/dax/fsdev.c | 245 +++++++++++++++++++++++++++++++++++++++++++
> fs/dax.c | 1 +
> 7 files changed, 272 insertions(+)
> create mode 100644 drivers/dax/fsdev.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7d10988cbc62..eedf4cce56ed 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7298,6 +7298,14 @@ L: linux-cxl@vger.kernel.org
> S: Supported
> F: drivers/dax/
>
> +DEVICE DIRECT ACCESS (DAX) [fsdev_dax]
> +M: John Groves <jgroves@micron.com>
> +M: John Groves <John@Groves.net>
> +L: nvdimm@lists.linux.dev
> +L: linux-cxl@vger.kernel.org
> +S: Supported
> +F: drivers/dax/fsdev.c
> +
> DEVICE FREQUENCY (DEVFREQ)
> M: MyungJoo Ham <myungjoo.ham@samsung.com>
> M: Kyungmin Park <kyungmin.park@samsung.com>
> diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig
> index d656e4c0eb84..7051b70980d5 100644
> --- a/drivers/dax/Kconfig
> +++ b/drivers/dax/Kconfig
> @@ -61,6 +61,17 @@ config DEV_DAX_HMEM_DEVICES
> depends on DEV_DAX_HMEM && DAX
> def_bool y
>
> +config DEV_DAX_FSDEV
> + tristate "FSDEV DAX: fs-dax compatible devdax driver"
> + depends on DEV_DAX && FS_DAX
> + help
> + Support fs-dax access to DAX devices via a character device
> + interface. Unlike device_dax (which pre-initializes compound folios
> + based on device alignment), this driver leaves folios at order-0 so
> + that fs-dax filesystems can manage folio order dynamically.
> +
> + Say M if unsure.
> +
> config DEV_DAX_KMEM
> tristate "KMEM DAX: map dax-devices as System-RAM"
> default DEV_DAX
> diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile
> index 5ed5c39857c8..ba35bda7abef 100644
> --- a/drivers/dax/Makefile
> +++ b/drivers/dax/Makefile
> @@ -4,11 +4,13 @@ obj-$(CONFIG_DEV_DAX) += device_dax.o
> obj-$(CONFIG_DEV_DAX_KMEM) += kmem.o
> obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
> obj-$(CONFIG_DEV_DAX_CXL) += dax_cxl.o
> +obj-$(CONFIG_DEV_DAX_FSDEV) += fsdev_dax.o
>
> dax-y := super.o
> dax-y += bus.o
> device_dax-y := device.o
> dax_pmem-y := pmem.o
> dax_cxl-y := cxl.o
> +fsdev_dax-y := fsdev.o
>
> obj-y += hmem/
> diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
> index e4bd5c9f006c..562e2b06f61a 100644
> --- a/drivers/dax/bus.c
> +++ b/drivers/dax/bus.c
> @@ -81,6 +81,10 @@ static int dax_match_type(const struct dax_device_driver *dax_drv, struct device
> !IS_ENABLED(CONFIG_DEV_DAX_KMEM))
> return 1;
>
> + /* fsdev driver can also bind to device-type dax devices */
> + if (dax_drv->type == DAXDRV_FSDEV_TYPE && type == DAXDRV_DEVICE_TYPE)
> + return 1;
> +
> return 0;
> }
>
> diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h
> index cbbf64443098..880bdf7e72d7 100644
> --- a/drivers/dax/bus.h
> +++ b/drivers/dax/bus.h
> @@ -31,6 +31,7 @@ struct dev_dax *devm_create_dev_dax(struct dev_dax_data *data);
> enum dax_driver_type {
> DAXDRV_KMEM_TYPE,
> DAXDRV_DEVICE_TYPE,
> + DAXDRV_FSDEV_TYPE,
> };
>
> struct dax_device_driver {
> diff --git a/drivers/dax/fsdev.c b/drivers/dax/fsdev.c
> new file mode 100644
> index 000000000000..8b5c6976ad17
> --- /dev/null
> +++ b/drivers/dax/fsdev.c
> @@ -0,0 +1,245 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright(c) 2026 Micron Technology, Inc. */
> +#include <linux/memremap.h>
> +#include <linux/pagemap.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/cdev.h>
> +#include <linux/slab.h>
> +#include <linux/dax.h>
> +#include <linux/uio.h>
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include "dax-private.h"
> +#include "bus.h"
> +
> +/*
> + * FS-DAX compatible devdax driver
> + *
> + * Unlike drivers/dax/device.c which pre-initializes compound folios based
> + * on device alignment (via vmemmap_shift), this driver leaves folios
> + * uninitialized similar to pmem. This allows fs-dax filesystems like famfs
> + * to work without needing special handling for pre-initialized folios.
> + *
> + * Key differences from device.c:
> + * - pgmap type is MEMORY_DEVICE_FS_DAX (not MEMORY_DEVICE_GENERIC)
> + * - vmemmap_shift is NOT set (folios remain order-0)
> + * - fs-dax can dynamically create compound folios as needed
> + * - No mmap support - all access is through fs-dax/iomap
> + */
> +
> +static void fsdev_cdev_del(void *cdev)
> +{
> + cdev_del(cdev);
> +}
> +
> +static void fsdev_kill(void *dev_dax)
> +{
> + kill_dev_dax(dev_dax);
> +}
> +
> +/*
> + * Page map operations for FS-DAX mode
> + * Similar to fsdax_pagemap_ops in drivers/nvdimm/pmem.c
> + *
> + * Note: folio_free callback is not needed for MEMORY_DEVICE_FS_DAX.
> + * The core mm code in free_zone_device_folio() handles the wake_up_var()
> + * directly for this memory type.
> + */
> +static int fsdev_pagemap_memory_failure(struct dev_pagemap *pgmap,
> + unsigned long pfn, unsigned long nr_pages, int mf_flags)
> +{
> + struct dev_dax *dev_dax = pgmap->owner;
> + u64 offset = PFN_PHYS(pfn) - dev_dax->ranges[0].range.start;
> + u64 len = nr_pages << PAGE_SHIFT;
> +
> + return dax_holder_notify_failure(dev_dax->dax_dev, offset,
> + len, mf_flags);
> +}
> +
> +static const struct dev_pagemap_ops fsdev_pagemap_ops = {
> + .memory_failure = fsdev_pagemap_memory_failure,
> +};
> +
> +/*
> + * Clear any stale folio state from pages in the given range.
> + * This is necessary because device_dax pre-initializes compound folios
> + * based on vmemmap_shift, and that state may persist after driver unbind.
> + * Since fsdev_dax uses MEMORY_DEVICE_FS_DAX without vmemmap_shift, fs-dax
> + * expects to find clean order-0 folios that it can build into compound
> + * folios on demand.
> + *
> + * At probe time, no filesystem should be mounted yet, so all mappings
> + * are stale and must be cleared along with compound state.
> + */
> +static void fsdev_clear_folio_state(struct dev_dax *dev_dax)
> +{
> + for (int i = 0; i < dev_dax->nr_range; i++) {
> + struct range *range = &dev_dax->ranges[i].range;
> + unsigned long pfn = PHYS_PFN(range->start);
> + unsigned long end_pfn = PHYS_PFN(range->end) + 1;
> +
> + while (pfn < end_pfn) {
> + struct folio *folio = pfn_folio(pfn);
> + int order = dax_folio_reset_order(folio);
> +
> + pfn += 1UL << order;
> + }
> + }
> +}
> +
> +static void fsdev_clear_folio_state_action(void *data)
> +{
> + fsdev_clear_folio_state(data);
> +}
> +
> +static int fsdev_open(struct inode *inode, struct file *filp)
> +{
> + struct dax_device *dax_dev = inode_dax(inode);
> + struct dev_dax *dev_dax = dax_get_private(dax_dev);
> +
> + filp->private_data = dev_dax;
> +
> + return 0;
> +}
> +
> +static int fsdev_release(struct inode *inode, struct file *filp)
> +{
> + return 0;
> +}
> +
> +static const struct file_operations fsdev_fops = {
> + .llseek = noop_llseek,
> + .owner = THIS_MODULE,
> + .open = fsdev_open,
> + .release = fsdev_release,
> +};
> +
> +static int fsdev_dax_probe(struct dev_dax *dev_dax)
> +{
> + struct dax_device *dax_dev = dev_dax->dax_dev;
> + struct device *dev = &dev_dax->dev;
> + struct dev_pagemap *pgmap;
> + struct inode *inode;
> + struct cdev *cdev;
> + void *addr;
> + int rc, i;
> +
> + if (static_dev_dax(dev_dax)) {
> + if (dev_dax->nr_range > 1) {
> + dev_warn(dev, "static pgmap / multi-range device conflict\n");
> + return -EINVAL;
> + }
> +
> + pgmap = dev_dax->pgmap;
> + } else {
> + size_t pgmap_size;
> +
> + if (dev_dax->pgmap) {
> + dev_warn(dev, "dynamic-dax with pre-populated page map\n");
> + return -EINVAL;
> + }
> +
> + pgmap_size = struct_size(pgmap, ranges, dev_dax->nr_range - 1);
> + pgmap = devm_kzalloc(dev, pgmap_size, GFP_KERNEL);
> + if (!pgmap)
> + return -ENOMEM;
> +
> + pgmap->nr_range = dev_dax->nr_range;
> + dev_dax->pgmap = pgmap;
> +
> + for (i = 0; i < dev_dax->nr_range; i++) {
> + struct range *range = &dev_dax->ranges[i].range;
> +
> + pgmap->ranges[i] = *range;
> + }
> + }
> +
> + for (i = 0; i < dev_dax->nr_range; i++) {
> + struct range *range = &dev_dax->ranges[i].range;
> +
> + if (!devm_request_mem_region(dev, range->start,
> + range_len(range), dev_name(dev))) {
> + dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve range\n",
> + i, range->start, range->end);
> + return -EBUSY;
> + }
> + }
> +
> + /*
> + * Use MEMORY_DEVICE_FS_DAX without setting vmemmap_shift, leaving
> + * folios at order-0. Unlike device.c (MEMORY_DEVICE_GENERIC), this
> + * lets fs-dax dynamically build compound folios as needed, similar
> + * to pmem behavior.
> + */
> + pgmap->type = MEMORY_DEVICE_FS_DAX;
> + pgmap->ops = &fsdev_pagemap_ops;
> + pgmap->owner = dev_dax;
> +
> + addr = devm_memremap_pages(dev, pgmap);
> + if (IS_ERR(addr))
> + return PTR_ERR(addr);
> +
> + /*
> + * Clear any stale compound folio state left over from a previous
> + * driver (e.g., device_dax with vmemmap_shift). Also register this
> + * as a devm action so folio state is cleared on unbind, ensuring
> + * clean pages for subsequent drivers (e.g., kmem for system-ram).
> + */
> + fsdev_clear_folio_state(dev_dax);
> + rc = devm_add_action_or_reset(dev, fsdev_clear_folio_state_action,
> + dev_dax);
> + if (rc)
> + return rc;
> +
> + /* Detect whether the data is at a non-zero offset into the memory */
> + if (pgmap->range.start != dev_dax->ranges[0].range.start) {
> + u64 phys = dev_dax->ranges[0].range.start;
> + u64 pgmap_phys = dev_dax->pgmap[0].range.start;
> + u64 data_offset = 0;
> +
> + if (!WARN_ON(pgmap_phys > phys))
> + data_offset = phys - pgmap_phys;
> +
> + pr_debug("%s: offset detected phys=%llx pgmap_phys=%llx offset=%llx\n",
> + __func__, phys, pgmap_phys, data_offset);
> + }
> +
> + inode = dax_inode(dax_dev);
> + cdev = inode->i_cdev;
> + cdev_init(cdev, &fsdev_fops);
> + cdev->owner = dev->driver->owner;
> + cdev_set_parent(cdev, &dev->kobj);
> + rc = cdev_add(cdev, dev->devt, 1);
> + if (rc)
> + return rc;
> +
> + rc = devm_add_action_or_reset(dev, fsdev_cdev_del, cdev);
> + if (rc)
> + return rc;
> +
> + run_dax(dax_dev);
> + return devm_add_action_or_reset(dev, fsdev_kill, dev_dax);
> +}
> +
> +static struct dax_device_driver fsdev_dax_driver = {
> + .probe = fsdev_dax_probe,
> + .type = DAXDRV_FSDEV_TYPE,
> +};
> +
> +static int __init dax_init(void)
> +{
> + return dax_driver_register(&fsdev_dax_driver);
> +}
> +
> +static void __exit dax_exit(void)
> +{
> + dax_driver_unregister(&fsdev_dax_driver);
> +}
> +
> +MODULE_AUTHOR("John Groves");
> +MODULE_DESCRIPTION("FS-DAX Device: fs-dax compatible devdax driver");
> +MODULE_LICENSE("GPL");
> +module_init(dax_init);
> +module_exit(dax_exit);
> +MODULE_ALIAS_DAX_DEVICE(0);
> diff --git a/fs/dax.c b/fs/dax.c
> index eba86802a7a7..b91a2535149a 100644
> --- a/fs/dax.c
> +++ b/fs/dax.c
> @@ -430,6 +430,7 @@ int dax_folio_reset_order(struct folio *folio)
>
> return order;
> }
> +EXPORT_SYMBOL_GPL(dax_folio_reset_order);
>
> static inline unsigned long dax_folio_put(struct folio *folio)
> {
next prev parent reply other threads:[~2026-03-24 15:19 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260324003630.4930-1-john@jagalactic.com>
2026-03-24 0:36 ` [PATCH BUNDLE v9] famfs: Fabric-Attached Memory File System John Groves
2026-03-24 0:37 ` [PATCH V9 0/8] dax: prepare for famfs John Groves
2026-03-24 0:37 ` [PATCH V9 1/8] dax: move dax_pgoff_to_phys from [drivers/dax/] device.c to bus.c John Groves
2026-03-24 14:18 ` Jonathan Cameron
2026-03-24 23:44 ` Ira Weiny
2026-03-25 11:55 ` Jonathan Cameron
2026-03-24 0:38 ` [PATCH V9 2/8] dax: Factor out dax_folio_reset_order() helper John Groves
2026-03-24 14:23 ` Jonathan Cameron
2026-03-24 0:38 ` [PATCH V9 3/8] dax: add fsdev.c driver for fs-dax on character dax John Groves
2026-03-24 14:39 ` Jonathan Cameron
2026-03-25 12:43 ` John Groves
2026-03-25 16:04 ` Ira Weiny
2026-03-26 14:33 ` John Groves
2026-03-26 22:46 ` Ira Weiny
2026-03-27 0:56 ` John Groves
2026-03-27 16:40 ` Ira Weiny
2026-03-24 15:19 ` Dave Jiang [this message]
2026-03-25 4:48 ` Ira Weiny
2026-03-24 0:38 ` [PATCH V9 4/8] dax: Save the kva from memremap John Groves
2026-03-24 14:40 ` Jonathan Cameron
2026-03-24 0:39 ` [PATCH V9 5/8] dax: Add dax_operations for use by fs-dax on fsdev dax John Groves
2026-03-24 14:51 ` Jonathan Cameron
2026-03-24 15:23 ` Dave Jiang
2026-03-25 21:28 ` Dave Jiang
2026-03-27 14:06 ` John Groves
2026-03-25 22:40 ` Dave Jiang
2026-03-27 14:14 ` John Groves
2026-03-24 0:39 ` [PATCH V9 6/8] dax: Add dax_set_ops() for setting dax_operations at bind time John Groves
2026-03-24 14:53 ` Jonathan Cameron
2026-03-24 0:39 ` [PATCH V9 7/8] dax: Add fs_dax_get() func to prepare dax for fs-dax usage John Groves
2026-03-24 15:05 ` Jonathan Cameron
2026-03-27 14:45 ` John Groves
2026-03-24 15:25 ` Dave Jiang
2026-03-24 0:39 ` [PATCH V9 8/8] dax: export dax_dev_get() John Groves
2026-03-24 15:06 ` Jonathan Cameron
2026-03-24 0:39 ` [PATCH V9 00/10] famfs: port into fuse John Groves
2026-03-24 0:40 ` [PATCH V9 01/10] famfs_fuse: Update macro s/FUSE_IS_DAX/FUSE_IS_VIRTIO_DAX/ John Groves
2026-03-24 15:12 ` Jonathan Cameron
2026-03-27 14:52 ` John Groves
2026-03-24 0:40 ` [PATCH V9 02/10] famfs_fuse: Basic fuse kernel ABI enablement for famfs John Groves
2026-03-24 0:40 ` [PATCH V9 03/10] famfs_fuse: Plumb the GET_FMAP message/response John Groves
2026-03-24 0:41 ` [PATCH V9 04/10] famfs_fuse: Create files with famfs fmaps John Groves
2026-03-24 0:41 ` [PATCH V9 05/10] famfs_fuse: GET_DAXDEV message and daxdev_table John Groves
2026-03-24 0:41 ` [PATCH V9 06/10] famfs_fuse: Plumb dax iomap and fuse read/write/mmap John Groves
2026-03-24 0:41 ` [PATCH V9 07/10] famfs_fuse: Add holder_operations for dax notify_failure() John Groves
2026-03-24 0:41 ` [PATCH V9 08/10] famfs_fuse: Add DAX address_space_operations with noop_dirty_folio John Groves
2026-03-24 0:42 ` [PATCH V9 09/10] famfs_fuse: Add famfs fmap metadata documentation John Groves
2026-03-24 0:42 ` [PATCH V9 10/10] famfs_fuse: Add documentation John Groves
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=e0421e4f-0436-47f5-9d45-11adfbecdc3c@intel.com \
--to=dave.jiang@intel.com \
--cc=John@Groves.net \
--cc=Jonathan.Cameron@huawei.com \
--cc=ackerleytng@google.com \
--cc=ajayjoshi@micron.com \
--cc=alison.schofield@intel.com \
--cc=amir73il@gmail.com \
--cc=arramesh@micron.com \
--cc=bagasdotme@gmail.com \
--cc=brauner@kernel.org \
--cc=bschubert@ddn.com \
--cc=chenlinxuan@uniontech.com \
--cc=corbet@lwn.net \
--cc=dan.j.williams@intel.com \
--cc=david@kernel.org \
--cc=djwong@kernel.org \
--cc=gourry@gourry.net \
--cc=jack@suse.cz \
--cc=james.morse@arm.com \
--cc=jgroves@micron.com \
--cc=jlayton@kernel.org \
--cc=joannelkoong@gmail.com \
--cc=john@jagalactic.com \
--cc=josef@toxicpanda.com \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=nvdimm@lists.linux.dev \
--cc=rdunlap@infradead.org \
--cc=seanjc@google.com \
--cc=shajnocz@redhat.com \
--cc=shivankg@amd.com \
--cc=skhan@linuxfoundation.org \
--cc=tabba@google.com \
--cc=venkataravis@micron.com \
--cc=viro@zeniv.linux.org.uk \
--cc=vishal.l.verma@intel.com \
--cc=willy@infradead.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.