From: Andreas Rohner <andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
To: Ryusuke Konishi
<konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
Cc: linux-nilfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH 1/9] nilfs2: refactor nilfs_sufile_updatev()
Date: Tue, 10 Mar 2015 21:40:43 +0100 [thread overview]
Message-ID: <54FF56CB.4060907@gmx.net> (raw)
In-Reply-To: <20150311.005220.1374468405510151934.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
On 2015-03-10 16:52, Ryusuke Konishi wrote:
> On Tue, 24 Feb 2015 20:01:36 +0100, Andreas Rohner wrote:
>> This patch refactors nilfs_sufile_updatev() to take an array of
>> arbitrary data structures instead of an array of segment numbers as
>> input parameter. With this change it is reusable for cases, where
>> it is necessary to pass extra data to the update function. The only
>> requirement for the data structures passed as input is, that they
>> contain the segment number within the structure. By passing the
>> offset to the segment number as another input parameter,
>> nilfs_sufile_updatev() can be oblivious to the actual type of the
>> input structures in the array.
>>
>> Signed-off-by: Andreas Rohner <andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
>> ---
>> fs/nilfs2/sufile.c | 79 ++++++++++++++++++++++++++++++++----------------------
>> fs/nilfs2/sufile.h | 39 ++++++++++++++-------------
>> 2 files changed, 68 insertions(+), 50 deletions(-)
>>
>> diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
>> index 2a869c3..1e8cac6 100644
>> --- a/fs/nilfs2/sufile.c
>> +++ b/fs/nilfs2/sufile.c
>> @@ -138,14 +138,18 @@ unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
>> /**
>> * nilfs_sufile_updatev - modify multiple segment usages at a time
>> * @sufile: inode of segment usage file
>> - * @segnumv: array of segment numbers
>> - * @nsegs: size of @segnumv array
>> + * @datav: array of segment numbers
>> + * @datasz: size of elements in @datav
>> + * @segoff: offset to segnum within the elements of @datav
>> + * @ndata: size of @datav array
>> * @create: creation flag
>> * @ndone: place to store number of modified segments on @segnumv
>> * @dofunc: primitive operation for the update
>> *
>> * Description: nilfs_sufile_updatev() repeatedly calls @dofunc
>> - * against the given array of segments. The @dofunc is called with
>> + * against the given array of data elements. Every data element has
>> + * to contain a valid segment number and @segoff should be the offset
>> + * to that within the data structure. The @dofunc is called with
>> * buffers of a header block and the sufile block in which the target
>> * segment usage entry is contained. If @ndone is given, the number
>> * of successfully modified segments from the head is stored in the
>> @@ -163,50 +167,55 @@ unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile)
>> *
>> * %-EINVAL - Invalid segment usage number
>> */
>> -int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
>> - int create, size_t *ndone,
>> - void (*dofunc)(struct inode *, __u64,
>> +int nilfs_sufile_updatev(struct inode *sufile, void *datav, size_t datasz,
>> + size_t segoff, size_t ndata, int create,
>> + size_t *ndone,
>> + void (*dofunc)(struct inode *, void *,
>> struct buffer_head *,
>> struct buffer_head *))
>
> Using offset byte of the data like segoff is nasty.
>
> Please consider defining a template structure and its variation:
>
> struct nilfs_sufile_update_data {
> __u64 segnum;
> /* Optional data comes after segnum */
> };
>
> /**
> * struct nilfs_sufile_update_count - data type of nilfs_sufile_do_xxx
> * @segnum: segment number
> * @nadd: additional value to a counter
> * Description: This structure derives from nilfs_sufile_update_data
> * struct.
> */
> struct nilfs_sufile_update_count {
> __u64 segnum;
> __u64 nadd;
> };
>
> int nilfs_sufile_updatev(struct inode *sufile,
> struct nilfs_sufile_update_data *datav,
> size_t datasz,
> size_t ndata, int create, size_t *ndone,
> void (*dofunc)(struct inode *,
> struct nilfs_sufile_update_data *,
> struct buffer_head *,
> struct buffer_head *))
> {
> ...
> }
I agree this is a much better solution. I'll change it.
Regards,
Andreas Rohner
> If you need define segnum in the middle of structure, you can use
> container_of():
>
> Example:
>
> struct nilfs_sufile_update_xxx {
> __u32 item_a;
> __u32 item_b;
> struct nilfs_sufile_update_data u_data;
> };
>
> static inline struct nilfs_sufile_update_xxx *
> NILFS_SU_UPDATE_XXX(struct nilfs_sufile_update_data *data)
> {
> return container_of(data, struct nilfs_sufile_update_xxx, u_data);
> }
>
> void nilfs_sufile_do_xxx(...)
> {
> struct nilfs_sufile_update_xxx *xxx;
>
> xxx = NILFS_SU_UPDATA_XXX(data);
> ...
> }
>
> I believe the former technique is enough in your case. (you can
> suppose that segnum is always the first member of data, right ?).
>
>
>> {
>> struct buffer_head *header_bh, *bh;
>> unsigned long blkoff, prev_blkoff;
>> __u64 *seg;
>> - size_t nerr = 0, n = 0;
>> + void *data, *dataend = datav + ndata * datasz;
>> + size_t n = 0;
>> int ret = 0;
>>
>> - if (unlikely(nsegs == 0))
>> + if (unlikely(ndata == 0))
>> goto out;
>>
>> - down_write(&NILFS_MDT(sufile)->mi_sem);
>> - for (seg = segnumv; seg < segnumv + nsegs; seg++) {
>> +
>> + for (data = datav; data < dataend; data += datasz) {
>> + seg = data + segoff;
>> if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
>> printk(KERN_WARNING
>> "%s: invalid segment number: %llu\n", __func__,
>> (unsigned long long)*seg);
>> - nerr++;
>> + ret = -EINVAL;
>> + goto out;
>> }
>> }
>> - if (nerr > 0) {
>> - ret = -EINVAL;
>> - goto out_sem;
>> - }
>>
>> + down_write(&NILFS_MDT(sufile)->mi_sem);
>> ret = nilfs_sufile_get_header_block(sufile, &header_bh);
>> if (ret < 0)
>> goto out_sem;
>>
>> - seg = segnumv;
>> + data = datav;
>> + seg = data + segoff;
>> blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
>> ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
>> if (ret < 0)
>> goto out_header;
>>
>> for (;;) {
>> - dofunc(sufile, *seg, header_bh, bh);
>> + dofunc(sufile, data, header_bh, bh);
>>
>> - if (++seg >= segnumv + nsegs)
>> + ++n;
>> + data += datasz;
>> + if (data >= dataend)
>> break;
>> + seg = data + segoff;
>> prev_blkoff = blkoff;
>> blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
>> if (blkoff == prev_blkoff)
>> @@ -220,28 +229,30 @@ int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
>> }
>> brelse(bh);
>>
>> - out_header:
>> - n = seg - segnumv;
>> +out_header:
>> brelse(header_bh);
>> - out_sem:
>> +out_sem:
>> up_write(&NILFS_MDT(sufile)->mi_sem);
>> - out:
>> +out:
>> if (ndone)
>> *ndone = n;
>> return ret;
>> }
>>
>> -int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
>> - void (*dofunc)(struct inode *, __u64,
>> +int nilfs_sufile_update(struct inode *sufile, void *data, size_t segoff,
>> + int create,
>> + void (*dofunc)(struct inode *, void *,
>> struct buffer_head *,
>> struct buffer_head *))
>
> ditto.
>
>> {
>> struct buffer_head *header_bh, *bh;
>> + __u64 *seg;
>> int ret;
>>
>> - if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
>> + seg = data + segoff;
>> + if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
>> printk(KERN_WARNING "%s: invalid segment number: %llu\n",
>> - __func__, (unsigned long long)segnum);
>> + __func__, (unsigned long long)*seg);
>> return -EINVAL;
>> }
>
> You can remove these nasty changes.
>
>> down_write(&NILFS_MDT(sufile)->mi_sem);
>> @@ -250,9 +261,9 @@ int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
>> if (ret < 0)
>> goto out_sem;
>>
>> - ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh);
>> + ret = nilfs_sufile_get_segment_usage_block(sufile, *seg, create, &bh);
>
> ditto.
>
>> if (!ret) {
>> - dofunc(sufile, segnum, header_bh, bh);
>> + dofunc(sufile, data, header_bh, bh);
>> brelse(bh);
>> }
>> brelse(header_bh);
>> @@ -406,12 +417,13 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump)
>> return ret;
>> }
>>
>> -void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
>> +void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 *data,
>> struct buffer_head *header_bh,
>> struct buffer_head *su_bh)
>> {
>> struct nilfs_segment_usage *su;
>> void *kaddr;
>> + __u64 segnum = *data;
>>
>> kaddr = kmap_atomic(su_bh->b_page);
>> su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
>> @@ -431,13 +443,14 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
>> nilfs_mdt_mark_dirty(sufile);
>> }
>>
>> -void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
>> +void nilfs_sufile_do_scrap(struct inode *sufile, __u64 *data,
>> struct buffer_head *header_bh,
>> struct buffer_head *su_bh)
>> {
>> struct nilfs_segment_usage *su;
>> void *kaddr;
>> int clean, dirty;
>> + __u64 segnum = *data;
>
> This can be converted to as follows:
>
> __u64 segnum = data->segnum;
>
>>
>> kaddr = kmap_atomic(su_bh->b_page);
>> su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
>> @@ -462,13 +475,14 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
>> nilfs_mdt_mark_dirty(sufile);
>> }
>>
>> -void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
>> +void nilfs_sufile_do_free(struct inode *sufile, __u64 *data,
>> struct buffer_head *header_bh,
>> struct buffer_head *su_bh)
>> {
>> struct nilfs_segment_usage *su;
>> void *kaddr;
>> int sudirty;
>> + __u64 segnum = *data;
>>
>> kaddr = kmap_atomic(su_bh->b_page);
>> su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
>> @@ -596,13 +610,14 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat)
>> return ret;
>> }
>>
>> -void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
>> +void nilfs_sufile_do_set_error(struct inode *sufile, __u64 *data,
>> struct buffer_head *header_bh,
>> struct buffer_head *su_bh)
>> {
>> struct nilfs_segment_usage *su;
>> void *kaddr;
>> int suclean;
>> + __u64 segnum = *data;
>>
>> kaddr = kmap_atomic(su_bh->b_page);
>> su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
>> diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h
>> index b8afd72..2df6c71 100644
>> --- a/fs/nilfs2/sufile.h
>> +++ b/fs/nilfs2/sufile.h
>> @@ -46,21 +46,21 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
>> size_t);
>> ssize_t nilfs_sufile_set_suinfo(struct inode *, void *, unsigned , size_t);
>>
>> -int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
>> - void (*dofunc)(struct inode *, __u64,
>> - struct buffer_head *,
>> - struct buffer_head *));
>> -int nilfs_sufile_update(struct inode *, __u64, int,
>> - void (*dofunc)(struct inode *, __u64,
>> +int nilfs_sufile_updatev(struct inode *, void *, size_t, size_t, size_t, int,
>> + size_t *, void (*dofunc)(struct inode *, void *,
>> + struct buffer_head *,
>> + struct buffer_head *));
>> +int nilfs_sufile_update(struct inode *, void *, size_t, int,
>> + void (*dofunc)(struct inode *, void *,
>> struct buffer_head *,
>> struct buffer_head *));
>
>> -void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *,
>> +void nilfs_sufile_do_scrap(struct inode *, __u64 *, struct buffer_head *,
>> struct buffer_head *);
>> -void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *,
>> +void nilfs_sufile_do_free(struct inode *, __u64 *, struct buffer_head *,
>> struct buffer_head *);
>> -void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *,
>> +void nilfs_sufile_do_cancel_free(struct inode *, __u64 *, struct buffer_head *,
>> struct buffer_head *);
>> -void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *,
>> +void nilfs_sufile_do_set_error(struct inode *, __u64 *, struct buffer_head *,
>> struct buffer_head *);
>
> Please, use "struct nilfs_sufile_update_data *" type for the second
> argument of these declaration.
>
>>
>> int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs);
>> @@ -75,7 +75,8 @@ int nilfs_sufile_trim_fs(struct inode *sufile, struct fstrim_range *range);
>> */
>> static inline int nilfs_sufile_scrap(struct inode *sufile, __u64 segnum)
>> {
>> - return nilfs_sufile_update(sufile, segnum, 1, nilfs_sufile_do_scrap);
>> + return nilfs_sufile_update(sufile, &segnum, 0, 1,
>> + (void *)nilfs_sufile_do_scrap);
>> }
>
> Then you can avoid this nasty (void *) cast to the callback function.
>
>>
>> /**
>> @@ -85,7 +86,8 @@ static inline int nilfs_sufile_scrap(struct inode *sufile, __u64 segnum)
>> */
>> static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum)
>> {
>> - return nilfs_sufile_update(sufile, segnum, 0, nilfs_sufile_do_free);
>> + return nilfs_sufile_update(sufile, &segnum, 0, 0,
>> + (void *)nilfs_sufile_do_free);
>> }
>
> ditto
>
>> /**
>> @@ -98,8 +100,8 @@ static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum)
>> static inline int nilfs_sufile_freev(struct inode *sufile, __u64 *segnumv,
>> size_t nsegs, size_t *ndone)
>> {
>> - return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone,
>> - nilfs_sufile_do_free);
>> + return nilfs_sufile_updatev(sufile, segnumv, sizeof(__u64), 0, nsegs,
>> + 0, ndone, (void *)nilfs_sufile_do_free);
>> }
>
> ditto
>
>> /**
>> @@ -116,8 +118,9 @@ static inline int nilfs_sufile_cancel_freev(struct inode *sufile,
>> __u64 *segnumv, size_t nsegs,
>> size_t *ndone)
>> {
>> - return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone,
>> - nilfs_sufile_do_cancel_free);
>> + return nilfs_sufile_updatev(sufile, segnumv, sizeof(__u64), 0, nsegs,
>> + 0, ndone,
>> + (void *)nilfs_sufile_do_cancel_free);
>> }
>
> ditto
>
>> /**
>> @@ -139,8 +142,8 @@ static inline int nilfs_sufile_cancel_freev(struct inode *sufile,
>> */
>> static inline int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum)
>> {
>> - return nilfs_sufile_update(sufile, segnum, 0,
>> - nilfs_sufile_do_set_error);
>> + return nilfs_sufile_update(sufile, &segnum, 0, 0,
>> + (void *)nilfs_sufile_do_set_error);
>> }
>>
>> #endif /* _NILFS_SUFILE_H */
>
> ditto
>
>
> Regards,
> Ryusuke Konishi
>
>> --
>> 2.3.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2015-03-10 20:40 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-24 19:01 [PATCH 0/9] nilfs2: implementation of cost-benefit GC policy Andreas Rohner
[not found] ` <1424804504-10914-1-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-02-24 19:01 ` [PATCH 1/9] nilfs2: refactor nilfs_sufile_updatev() Andreas Rohner
[not found] ` <1424804504-10914-2-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-10 15:52 ` Ryusuke Konishi
[not found] ` <20150311.005220.1374468405510151934.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
2015-03-10 20:40 ` Andreas Rohner [this message]
2015-02-24 19:01 ` [PATCH 2/9] nilfs2: add simple cache for modifications to SUFILE Andreas Rohner
[not found] ` <1424804504-10914-3-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 0:45 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 3/9] nilfs2: extend SUFILE on-disk format to enable counting of live blocks Andreas Rohner
[not found] ` <1424804504-10914-4-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 4:05 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 4/9] nilfs2: add function to modify su_nlive_blks Andreas Rohner
[not found] ` <1424804504-10914-5-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 4:57 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 5/9] nilfs2: add simple tracking of block deletions and updates Andreas Rohner
[not found] ` <1424804504-10914-6-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 3:46 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 6/9] nilfs2: use modification cache to improve performance Andreas Rohner
[not found] ` <1424804504-10914-7-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 1:04 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 7/9] nilfs2: add additional flags for nilfs_vdesc Andreas Rohner
[not found] ` <1424804504-10914-8-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 3:21 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 8/9] nilfs2: improve accuracy and correct for invalid GC values Andreas Rohner
[not found] ` <1424804504-10914-9-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 2:50 ` Ryusuke Konishi
2015-02-24 19:01 ` [PATCH 9/9] nilfs2: prevent starvation of segments protected by snapshots Andreas Rohner
[not found] ` <1424804504-10914-10-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 3:51 ` Ryusuke Konishi
[not found] ` <20150314.125109.1017248837083480553.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
2015-03-14 12:36 ` Andreas Rohner
[not found] ` <55042B53.5000101-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 12:49 ` Ryusuke Konishi
2015-03-14 14:32 ` Ryusuke Konishi
2015-02-24 19:04 ` [PATCH 1/6] nilfs-utils: extend SUFILE on-disk format to enable track live blocks Andreas Rohner
[not found] ` <1424804659-10986-1-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-02-24 19:04 ` [PATCH 2/6] nilfs-utils: add additional flags for nilfs_vdesc Andreas Rohner
2015-02-24 19:04 ` [PATCH 3/6] nilfs-utils: add support for tracking live blocks Andreas Rohner
[not found] ` <1424804659-10986-3-git-send-email-andreas.rohner-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 5:52 ` Ryusuke Konishi
2015-02-24 19:04 ` [PATCH 4/6] nilfs-utils: implement the tracking of live blocks for set_suinfo Andreas Rohner
2015-02-24 19:04 ` [PATCH 5/6] nilfs-utils: add support for greedy/cost-benefit policies Andreas Rohner
2015-02-24 19:04 ` [PATCH 6/6] nilfs-utils: add su_nsnapshot_blks field to indicate starvation Andreas Rohner
2015-02-25 0:18 ` [PATCH 0/9] nilfs2: implementation of cost-benefit GC policy Ryusuke Konishi
[not found] ` <20150225.091804.1850885506186316087.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
2015-03-10 5:21 ` Ryusuke Konishi
[not found] ` <20150310.142119.813265940569588216.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
2015-03-10 20:37 ` Andreas Rohner
[not found] ` <54FF561E.7030409-hi6Y0CQ0nG0@public.gmane.org>
2015-03-12 12:54 ` Ryusuke Konishi
[not found] ` <20150312.215431.324210374799651841.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org>
2015-03-14 12:24 ` Andreas Rohner
[not found] ` <55042879.90701-hi6Y0CQ0nG0@public.gmane.org>
2015-03-14 15:40 ` Ryusuke Konishi
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=54FF56CB.4060907@gmx.net \
--to=andreas.rohner-hi6y0cq0ng0@public.gmane.org \
--cc=konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org \
--cc=linux-nilfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.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;
as well as URLs for NNTP newsgroup(s).