mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Teresa Remmet <t.remmet@phytec.de>
To: barebox@lists.infradead.org
Subject: [PATCH 15/56] ubi: Rework Fastmap attach base code
Date: Wed, 29 Aug 2018 14:19:31 +0200	[thread overview]
Message-ID: <1535545212-18871-16-git-send-email-t.remmet@phytec.de> (raw)
In-Reply-To: <1535545212-18871-1-git-send-email-t.remmet@phytec.de>

From: Richard Weinberger <richard@nod.at>

Introduce a new list to the UBI attach information
object to be able to deal better with old and corrupted
Fastmap eraseblocks.
Also move more Fastmap specific code into fastmap.c.

Signed-off-by: Richard Weinberger <richard@nod.at>
[Fixed conflicts in attach and fastmap]
Signed-off-by: Teresa Remmet <t.remmet@phytec.de>
---
 drivers/mtd/ubi/attach.c  | 100 ++++++++++++++++++++++++++++++++--------------
 drivers/mtd/ubi/fastmap.c |  36 +++++++++++++++--
 drivers/mtd/ubi/ubi.h     |  28 ++++++++++++-
 drivers/mtd/ubi/wl.c      |  39 ++++++++++++++----
 4 files changed, 160 insertions(+), 43 deletions(-)

diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index 9cf9b2ae98e3..4869c6778b3d 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -169,6 +169,40 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
 }
 
 /**
+ * add_fastmap - add a Fastmap related physical eraseblock.
+ * @ai: attaching information
+ * @pnum: physical eraseblock number the VID header came from
+ * @vid_hdr: the volume identifier header
+ * @ec: erase counter of the physical eraseblock
+ *
+ * This function allocates a 'struct ubi_ainf_peb' object for a Fastamp
+ * physical eraseblock @pnum and adds it to the 'fastmap' list.
+ * Such blocks can be Fastmap super and data blocks from both the most
+ * recent Fastmap we're attaching from or from old Fastmaps which will
+ * be erased.
+ */
+static int add_fastmap(struct ubi_attach_info *ai, int pnum,
+		       struct ubi_vid_hdr *vid_hdr, int ec)
+{
+	struct ubi_ainf_peb *aeb;
+
+	aeb = kmalloc(sizeof(*aeb), GFP_KERNEL);
+	if (!aeb)
+		return -ENOMEM;
+
+	aeb->pnum = pnum;
+	aeb->vol_id = be32_to_cpu(vidh->vol_id);
+	aeb->sqnum = be64_to_cpu(vidh->sqnum);
+	aeb->ec = ec;
+	list_add(&aeb->u.list, &ai->fastmap);
+
+	dbg_bld("add to fastmap list: PEB %d, vol_id %d, sqnum: %llu", pnum,
+		aeb->vol_id, aeb->sqnum);
+
+	return 0;
+}
+
+/**
  * validate_vid_hdr - check volume identifier header.
  * @ubi: UBI device description object
  * @vid_hdr: the volume identifier header to check
@@ -811,18 +845,15 @@ static bool vol_ignored(int vol_id)
  * @ubi: UBI device description object
  * @ai: attaching information
  * @pnum: the physical eraseblock number
- * @vid: The volume ID of the found volume will be stored in this pointer
- * @sqnum: The sqnum of the found volume will be stored in this pointer
  *
  * This function reads UBI headers of PEB @pnum, checks them, and adds
  * information about this PEB to the corresponding list or RB-tree in the
  * "attaching info" structure. Returns zero if the physical eraseblock was
  * successfully handled and a negative error code in case of failure.
  */
-static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		    int pnum, int *vid, unsigned long long *sqnum)
+static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum)
 {
-	long long uninitialized_var(ec);
+	long long ec;
 	int err, bitflips = 0, vol_id = -1, ec_err = 0;
 
 	dbg_bld("scan PEB %d", pnum);
@@ -994,10 +1025,6 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 	}
 
 	vol_id = be32_to_cpu(vidh->vol_id);
-	if (vid)
-		*vid = vol_id;
-	if (sqnum)
-		*sqnum = be64_to_cpu(vidh->sqnum);
 	if (vol_id > UBI_MAX_VOLUMES && !vol_ignored(vol_id)) {
 		int lnum = be32_to_cpu(vidh->lnum);
 
@@ -1038,7 +1065,12 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 	if (ec_err)
 		ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
 			 pnum);
-	err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
+	if (ubi_is_fm_vol(vol_id))
+		err = add_fastmap(ai, pnum, vidh, ec);
+	else
+		err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
 	if (err)
 		return err;
 
@@ -1187,6 +1219,10 @@ static void destroy_ai(struct ubi_attach_info *ai)
 		list_del(&aeb->u.list);
 		kfree(aeb);
 	}
+	list_for_each_entry_safe(aeb, aeb_tmp, &ai->fastmap, u.list) {
+		list_del(&aeb->u.list);
+		kfree(aeb);
+	}
 
 	/* Destroy the volume RB-tree */
 	rb = ai->volumes.rb_node;
@@ -1243,7 +1279,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
 
 	for (pnum = start; pnum < ubi->peb_count; pnum++) {
 		dbg_gen("process PEB %d", pnum);
-		err = scan_peb(ubi, ai, pnum, NULL, NULL);
+		err = scan_peb(ubi, ai, pnum);
 		if (err < 0)
 			goto out_vidh;
 	}
@@ -1309,6 +1345,7 @@ static struct ubi_attach_info *alloc_ai(void)
 	INIT_LIST_HEAD(&ai->free);
 	INIT_LIST_HEAD(&ai->erase);
 	INIT_LIST_HEAD(&ai->alien);
+	INIT_LIST_HEAD(&ai->fastmap);
 	ai->volumes = RB_ROOT;
 
 	return ai;
@@ -1328,51 +1365,52 @@ static struct ubi_attach_info *alloc_ai(void)
  */
 static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai)
 {
-	int err, pnum, fm_anchor = -1;
-	unsigned long long max_sqnum = 0;
+	int err, pnum;
+	struct ubi_attach_info *scan_ai;
 
 	err = -ENOMEM;
 
+	scan_ai = alloc_ai();
+	if (!scan_ai)
+		goto out;
+
 	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
 	if (!ech)
-		goto out;
+		goto out_ai;
 
 	vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
 	if (!vidh)
 		goto out_ech;
 
 	for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
-		int vol_id = -1;
-		unsigned long long sqnum = -1;
-
 		dbg_gen("process PEB %d", pnum);
-		err = scan_peb(ubi, *ai, pnum, &vol_id, &sqnum);
+		err = scan_peb(ubi, scan_ai, pnum);
 		if (err < 0)
 			goto out_vidh;
-
-		if (vol_id == UBI_FM_SB_VOLUME_ID && sqnum > max_sqnum) {
-			max_sqnum = sqnum;
-			fm_anchor = pnum;
-		}
 	}
 
 	ubi_free_vid_hdr(ubi, vidh);
 	kfree(ech);
 
-	if (fm_anchor < 0)
-		return UBI_NO_FASTMAP;
-
-	destroy_ai(*ai);
-	*ai = alloc_ai();
-	if (!*ai)
-		return -ENOMEM;
+	err = ubi_scan_fastmap(ubi, *ai, scan_ai);
+	if (err) {
+		/*
+		 * Didn't attach via fastmap, do a full scan but reuse what
+		 * we've aready scanned.
+		 */
+		destroy_ai(*ai);
+		*ai = scan_ai;
+	} else
+		destroy_ai(scan_ai);
 
-	return ubi_scan_fastmap(ubi, *ai, fm_anchor);
+	return err;
 
 out_vidh:
 	ubi_free_vid_hdr(ubi, vidh);
 out_ech:
 	kfree(ech);
+out_ai:
+	destroy_ai(scan_ai);
 out:
 	return err;
 }
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index 205174495b0d..4a8de1db407a 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -784,27 +784,57 @@ fail:
 }
 
 /**
+ * find_fm_anchor - find the most recent Fastmap superblock (anchor)
+ * @ai: UBI attach info to be filled
+ */
+static int find_fm_anchor(struct ubi_attach_info *ai)
+{
+	int ret = -1;
+	struct ubi_ainf_peb *aeb;
+	unsigned long long max_sqnum = 0;
+
+	list_for_each_entry(aeb, &ai->fastmap, u.list) {
+		if (aeb->vol_id == UBI_FM_SB_VOLUME_ID && aeb->sqnum > max_sqnum) {
+			max_sqnum = aeb->sqnum;
+			ret = aeb->pnum;
+		}
+	}
+
+	return ret;
+}
+
+/**
  * ubi_scan_fastmap - scan the fastmap.
  * @ubi: UBI device object
  * @ai: UBI attach info to be filled
- * @fm_anchor: The fastmap starts at this PEB
+ * @scan_ai: UBI attach info from the first 64 PEBs,
+ *           used to find the most recent Fastmap data structure
  *
  * Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found,
  * UBI_BAD_FASTMAP if one was found but is not usable.
  * < 0 indicates an internal error.
  */
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		     int fm_anchor)
+		     struct ubi_attach_info *scan_ai)
 {
 	struct ubi_fm_sb *fmsb, *fmsb2;
 	struct ubi_vid_hdr *vh;
 	struct ubi_ec_hdr *ech;
 	struct ubi_fastmap_layout *fm;
-	int i, used_blocks, pnum, ret = 0;
+	struct ubi_ainf_peb *tmp_aeb, *aeb;
+	int i, used_blocks, pnum, fm_anchor, ret = 0;
 	size_t fm_size;
 	__be32 crc, tmp_crc;
 	unsigned long long sqnum = 0;
 
+	fm_anchor = find_fm_anchor(scan_ai);
+	if (fm_anchor < 0)
+		return UBI_NO_FASTMAP;
+
+	/* Move all (possible) fastmap blocks into our new attach structure. */
+	list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
+		list_move_tail(&aeb->u.list, &ai->fastmap);
+
 	memset(ubi->fm_buf, 0, ubi->fm_size);
 
 	fmsb = kmalloc(sizeof(*fmsb), GFP_KERNEL);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 5899ad7c92b8..2bd2d9e1ed88 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -639,6 +639,8 @@ struct ubi_ainf_volume {
  * @erase: list of physical eraseblocks which have to be erased
  * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
  *         those belonging to "preserve"-compatible internal volumes)
+ * @fastmap: list of physical eraseblocks which relate to fastmap (e.g.,
+ *           eraseblocks of the current and not yet erased old fastmap blocks)
  * @corr_peb_count: count of PEBs in the @corr list
  * @empty_peb_count: count of PEBs which are presumably empty (contain only
  *                   0xFF bytes)
@@ -667,6 +669,7 @@ struct ubi_attach_info {
 	struct list_head free;
 	struct list_head erase;
 	struct list_head alien;
+	struct list_head fastmap;
 	int corr_peb_count;
 	int empty_peb_count;
 	int alien_peb_count;
@@ -843,7 +846,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
 size_t ubi_calc_fm_size(struct ubi_device *ubi);
 int ubi_update_fastmap(struct ubi_device *ubi);
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		     int fm_anchor);
+		     struct ubi_attach_info *scan_ai);
 #else
 static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
 #endif
@@ -1033,4 +1036,27 @@ static inline bool ubi_is_fm_vol(int vol_id)
 	return false;
 }
 
+/**
+ * ubi_find_fm_block - check whether a PEB is part of the current Fastmap.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to look for
+ *
+ * This function returns a wear leveling object if @pnum relates to the current
+ * fastmap, @NULL otherwise.
+ */
+static inline struct ubi_wl_entry *ubi_find_fm_block(const struct ubi_device *ubi,
+						     int pnum)
+{
+	int i;
+
+	if (ubi->fm) {
+		for (i = 0; i < ubi->fm->used_blocks; i++) {
+			if (ubi->fm->e[i]->pnum == pnum)
+				return ubi->fm->e[i];
+		}
+	}
+
+	return NULL;
+}
+
 #endif /* !__UBI_UBI_H__ */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index eb1f24c74807..eef9c17c2d0f 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1457,19 +1457,42 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
 		}
 	}
 
-	dbg_wl("found %i PEBs", found_pebs);
+	list_for_each_entry(aeb, &ai->fastmap, u.list) {
+		e = ubi_find_fm_block(ubi, aeb->pnum);
+
+		if (e) {
+			ubi_assert(!ubi->lookuptbl[e->pnum]);
+			ubi->lookuptbl[e->pnum] = e;
+		} else {
+			/*
+			 * Usually old Fastmap PEBs are scheduled for erasure
+			 * and we don't have to care about them but if we face
+			 * an power cut before scheduling them we need to
+			 * take care of them here.
+			 */
+			if (ubi->lookuptbl[aeb->pnum])
+				continue;
 
-	if (ubi->fm) {
-		ubi_assert(ubi->good_peb_count ==
-			   found_pebs + ubi->fm->used_blocks);
+			e = kmalloc(sizeof(*e), GFP_KERNEL);
+			if (!e)
+				goto out_free;
 
-		for (i = 0; i < ubi->fm->used_blocks; i++) {
-			e = ubi->fm->e[i];
+			e->pnum = aeb->pnum;
+			e->ec = aeb->ec;
+			ubi_assert(!ubi->lookuptbl[e->pnum]);
 			ubi->lookuptbl[e->pnum] = e;
+			if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
+				wl_entry_destroy(ubi, e);
+				goto out_free;
+			}
 		}
+
+		found_pebs++;
 	}
-	else
-		ubi_assert(ubi->good_peb_count == found_pebs);
+
+	dbg_wl("found %i PEBs", found_pebs);
+
+	ubi_assert(ubi->good_peb_count == found_pebs);
 
 	reserved_pebs = WL_RESERVED_PEBS;
 	ubi_fastmap_init(ubi, &reserved_pebs);
-- 
2.7.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2018-08-29 12:20 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-29 12:19 [PATCH 00/56] Update Barebox UBI Teresa Remmet
2018-08-29 12:19 ` [PATCH 01/56] UBI: Fastmap: Fix memory leak while attaching Teresa Remmet
2018-08-29 12:19 ` [PATCH 02/56] UBI: Remove alloc_ai() slab name from parameter list Teresa Remmet
2018-08-29 12:19 ` [PATCH 03/56] UBI: Don't read back all data in ubi_eba_copy_leb() Teresa Remmet
2018-08-29 12:19 ` [PATCH 04/56] UBI: Modify wrong comment in ubi_leb_map function Teresa Remmet
2018-08-29 12:19 ` [PATCH 05/56] UBI: Clean up return in ubi_remove_volume() Teresa Remmet
2018-08-29 12:19 ` [PATCH 06/56] UBI: Set free_count to zero before walking through erase list Teresa Remmet
2018-08-29 12:19 ` [PATCH 07/56] UBI: Fix static volume checks when Fastmap is used Teresa Remmet
2018-08-29 12:19 ` [PATCH 08/56] ubi: Make recover_peb power cut aware Teresa Remmet
2018-08-29 12:19 ` [PATCH 09/56] ubi: Fix race condition between ubi device creation and udev Teresa Remmet
2018-08-29 12:19 ` [PATCH 10/56] ubi: Fix early logging Teresa Remmet
2018-08-29 12:19 ` [PATCH 11/56] ubi: Make volume resize power cut aware Teresa Remmet
2018-08-29 12:19 ` [PATCH 12/56] ubi: Fix scan_fast() comment Teresa Remmet
2018-08-29 12:19 ` [PATCH 13/56] ubi: Introduce vol_ignored() Teresa Remmet
2018-08-29 12:19 ` [PATCH 14/56] ubi: Fix whitespace issue in count_fastmap_pebs() Teresa Remmet
2018-08-29 12:19 ` Teresa Remmet [this message]
2018-08-29 12:19 ` [PATCH 16/56] ubi: Check whether the Fastmap anchor matches the super block Teresa Remmet
2018-08-29 12:19 ` [PATCH 17/56] ubi: Be more paranoid while seaching for the most recent Fastmap Teresa Remmet
2018-08-29 12:19 ` [PATCH 18/56] UBI: fastmap: use ubi_find_volume() instead of open coding it Teresa Remmet
2018-08-29 12:19 ` [PATCH 19/56] UBI: fix add_fastmap() to use the vid_hdr passed in argument Teresa Remmet
2018-08-29 12:19 ` [PATCH 20/56] UBI: fastmap: avoid multiple be32_to_cpu() when unneccesary Teresa Remmet
2018-08-29 12:19 ` [PATCH 21/56] UBI: fastmap: scrub PEB when bitflips are detected in a free PEB EC header Teresa Remmet
2018-08-29 12:19 ` [PATCH 22/56] UBI: factorize code used to manipulate volumes at attach time Teresa Remmet
2018-08-29 12:19 ` [PATCH 23/56] UBI: factorize destroy_av() and ubi_remove_av() code Teresa Remmet
2018-08-29 12:19 ` [PATCH 24/56] UBI: fastmap: use ubi_rb_for_each_entry() in unmap_peb() Teresa Remmet
2018-08-29 12:19 ` [PATCH 25/56] UBI: fastmap: use ubi_io_{read, write}_data() instead of ubi_io_{read, write}() Teresa Remmet
2018-08-29 12:19 ` [PATCH 26/56] UBI: provide helpers to allocate and free aeb elements Teresa Remmet
2018-08-29 12:19 ` [PATCH 27/56] UBI: move the global ech and vidh variables into struct ubi_attach_info Teresa Remmet
2018-08-29 12:19 ` [PATCH 28/56] UBI: simplify recover_peb() code Teresa Remmet
2018-08-29 12:19 ` [PATCH 29/56] UBI: simplify LEB write and atomic LEB change code Teresa Remmet
2018-08-29 12:19 ` [PATCH 30/56] UBI: add an helper to check lnum validity Teresa Remmet
2018-08-29 12:19 ` [PATCH 31/56] UBI: provide an helper to check whether a LEB is mapped or not Teresa Remmet
2018-08-29 12:19 ` [PATCH 32/56] UBI: provide an helper to query LEB information Teresa Remmet
2018-08-29 12:19 ` [PATCH 33/56] UBI: hide EBA internals Teresa Remmet
2018-08-29 12:19 ` [PATCH 34/56] UBI: introduce the VID buffer concept Teresa Remmet
2018-08-29 12:19 ` [PATCH 35/56] ubi: Deal with interrupted erasures in WL Teresa Remmet
2018-08-29 12:19 ` [PATCH 36/56] ubi: Fix races around ubi_refill_pools() Teresa Remmet
2018-08-29 12:19 ` [PATCH 37/56] ubi: Fix Fastmap's update_vol() Teresa Remmet
2018-08-29 12:19 ` [PATCH 38/56] ubi: fix swapped arguments to call to ubi_alloc_aeb Teresa Remmet
2018-08-29 12:19 ` [PATCH 39/56] UBI: Fix crash in try_recover_peb() Teresa Remmet
2018-08-29 12:19 ` [PATCH 40/56] ubi: fastmap: Fix add_vol() return value test in ubi_attach_fastmap() Teresa Remmet
2018-08-29 12:19 ` [PATCH 41/56] UBI: Fix typos Teresa Remmet
2018-08-29 12:19 ` [PATCH 42/56] ubi/upd: Always flush after prepared for an update Teresa Remmet
2018-08-29 12:19 ` [PATCH 43/56] ubi: fastmap: Fix slab corruption Teresa Remmet
2018-08-29 12:20 ` [PATCH 44/56] ubi: pr_err() strings should end with newlines Teresa Remmet
2018-08-29 12:20 ` [PATCH 45/56] ubi: fastmap: fix spelling mistake: "invalidiate" -> "invalidate" Teresa Remmet
2018-08-29 12:20 ` [PATCH 46/56] UBI: Fix two typos in comments Teresa Remmet
2018-08-29 12:20 ` [PATCH 47/56] ubi: fastmap: Clean up the initialization of pointer p Teresa Remmet
2018-08-29 12:20 ` [PATCH 48/56] ubi: fastmap: Erase outdated anchor PEBs during attach Teresa Remmet
2018-08-29 12:20 ` [PATCH 49/56] ubi: Fastmap: Fix typo Teresa Remmet
2018-08-29 12:20 ` [PATCH 50/56] ubi: Fix copy/paste error in function documentation Teresa Remmet
2018-08-29 12:20 ` [PATCH 51/56] mtd: ubi: wl: Fix error return code in ubi_wl_init() Teresa Remmet
2018-08-29 12:20 ` [PATCH 52/56] ubi: fastmap: Correctly handle interrupted erasures in EBA Teresa Remmet
2018-08-29 12:20 ` [PATCH 53/56] ubi: fastmap: Check each mapping only once Teresa Remmet
2018-08-29 12:20 ` [PATCH 54/56] ubi: fastmap: Detect EBA mismatches on-the-fly Teresa Remmet
2018-08-29 12:20 ` [PATCH 55/56] mtd: ubi: Update ubi-media.h to dual license Teresa Remmet
2018-08-29 12:20 ` [PATCH 56/56] ubi: Initialize Fastmap checkmapping correctly Teresa Remmet
2018-08-31  6:25 ` [PATCH 00/56] Update Barebox UBI Sascha Hauer

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=1535545212-18871-16-git-send-email-t.remmet@phytec.de \
    --to=t.remmet@phytec.de \
    --cc=barebox@lists.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox