From: Chao Yu <chao@kernel.org>
To: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: kernel-team@android.com, Daeho Jeong <daehojeong@google.com>,
Daniel Rosenberg <drosen@google.com>,
linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH v4 1/2] dump.f2fs: Add ability to dump folders
Date: Fri, 31 May 2024 09:13:24 +0800 [thread overview]
Message-ID: <fed5c9ec-4ebb-4580-9843-bf408f7ab0a2@kernel.org> (raw)
In-Reply-To: <ZlkOmapurmR-yJk3@google.com>
On 2024/5/31 7:41, Jaegeuk Kim wrote:
> On 05/29, Chao Yu wrote:
>> On 2024/5/24 6:46, Daniel Rosenberg wrote:
>>> This adds the ability to dump folders as well as files. Folders are
>>> dumped recursively. Additionally, dumped files/folders may be directed
>>> to a folder specified by -o [path] instead of ./lost_found. The -r flag
>>> will dump the entire fs from the root inode. -f or -y will skip the
>>> prompt before dumping, and -P will preserve the mode/owner info for the
>>> created file/folder.
>>>
>>> Signed-off-by: Daniel Rosenberg <drosen@google.com>
>>> Reviewed-by: Daeho Jeong <daehojeong@google.com>
>>> ---
>>> fsck/dump.c | 178 ++++++++++++++++++++++++++++++++++++++----------
>>> fsck/fsck.c | 4 +-
>>> fsck/fsck.h | 4 +-
>>> fsck/main.c | 29 +++++++-
>>> man/dump.f2fs.8 | 17 ++++-
>>> 5 files changed, 190 insertions(+), 42 deletions(-)
>>>
>>> diff --git a/fsck/dump.c b/fsck/dump.c
>>> index b2e990b..fa68456 100644
>>> --- a/fsck/dump.c
>>> +++ b/fsck/dump.c
>>> @@ -247,7 +247,26 @@ out:
>>> printf("\n");
>>> }
>>> -static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
>>> +static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap,
>>> + struct f2fs_dir_entry *dentry,
>>> + __u8 (*filenames)[F2FS_SLOT_LEN], int max)
>>> +{
>>> + int i;
>>> + int name_len;
>>> +
>>> + for (i = 0; i < max; i++) {
>>> + if (test_bit_le(i, bitmap) == 0)
>>> + continue;
>>> + name_len = le16_to_cpu(dentry[i].name_len);
>>> + if (name_len == 1 && filenames[i][0] == '.')
>>> + continue;
>>> + if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
>>> + continue;
>>> + dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1);
>>> + }
>>> +}
>>> +
>>> +static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, bool is_folder)
>>> {
>>> char buf[F2FS_BLKSIZE];
>>> @@ -288,12 +307,19 @@ static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
>>> ASSERT(ret >= 0);
>>> }
>>> - /* write blkaddr */
>>> - dev_write_dump(buf, offset, F2FS_BLKSIZE);
>>> + if (is_folder) {
>>> + struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
>>> +
>>> + dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
>>> + F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
>>> + } else {
>>> + /* write blkaddr */
>>> + dev_write_dump(buf, offset, F2FS_BLKSIZE);
>>> + }
>>> }
>>> static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
>>> - u32 nid, u32 addr_per_block, u64 *ofs)
>>> + u32 nid, u32 addr_per_block, u64 *ofs, int is_dir)
>>> {
>>> struct node_info ni;
>>> struct f2fs_node *node_blk;
>>> @@ -330,20 +356,20 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
>>> switch (ntype) {
>>> case TYPE_DIRECT_NODE:
>>> dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
>>> - le32_to_cpu(node_blk->dn.addr[i]));
>>> + le32_to_cpu(node_blk->dn.addr[i]), is_dir);
>>> (*ofs)++;
>>> break;
>>> case TYPE_INDIRECT_NODE:
>>> dump_node_blk(sbi, TYPE_DIRECT_NODE,
>>> le32_to_cpu(node_blk->in.nid[i]),
>>> addr_per_block,
>>> - ofs);
>>> + ofs, is_dir);
>>> break;
>>> case TYPE_DOUBLE_INDIRECT_NODE:
>>> dump_node_blk(sbi, TYPE_INDIRECT_NODE,
>>> le32_to_cpu(node_blk->in.nid[i]),
>>> addr_per_block,
>>> - ofs);
>>> + ofs, is_dir);
>>> break;
>>> }
>>> }
>>> @@ -435,8 +461,9 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
>>> u32 i = 0;
>>> u64 ofs = 0;
>>> u32 addr_per_block;
>>> + bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
>>> - if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
>>> + if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
>>> DBG(3, "ino[0x%x] has inline data!\n", nid);
>>> /* recover from inline data */
>>> dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
>>> @@ -444,13 +471,25 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
>>> return -1;
>>> }
>>> + if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
>>> + void *inline_dentry = inline_data_addr(node_blk);
>>> + struct f2fs_dentry_ptr d;
>>> +
>>> + make_dentry_ptr(&d, node_blk, inline_dentry, 2);
>>> +
>>> + DBG(3, "ino[0x%x] has inline dentries!\n", nid);
>>> + /* recover from inline dentry */
>>> + dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
>>> + return -1;
>>> + }
>>> +
>>> c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
>>> addr_per_block = ADDRS_PER_BLOCK(&node_blk->i);
>>> /* check data blocks in inode */
>>> for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
>>> dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
>>> - node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
>>> + node_blk->i.i_addr[get_extra_isize(node_blk) + i]), is_dir);
>>> /* check node blocks in inode */
>>> for (i = 0; i < 5; i++) {
>>> @@ -458,17 +497,20 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
>>> dump_node_blk(sbi, TYPE_DIRECT_NODE,
>>> le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
>>> addr_per_block,
>>> - &ofs);
>>> + &ofs,
>>> + is_dir);
>>> else if (i == 2 || i == 3)
>>> dump_node_blk(sbi, TYPE_INDIRECT_NODE,
>>> le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
>>> addr_per_block,
>>> - &ofs);
>>> + &ofs,
>>> + is_dir);
>>> else if (i == 4)
>>> dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
>>> le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
>>> addr_per_block,
>>> - &ofs);
>>> + &ofs,
>>> + is_dir);
>>> else
>>> ASSERT(0);
>>> }
>>> @@ -479,8 +521,51 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
>>> return 0;
>>> }
>>> -static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> - struct f2fs_node *node_blk, int force)
>>> +static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> + struct f2fs_node *node_blk, char *path)
>>> +{
>>> + struct f2fs_inode *inode = &node_blk->i;
>>> + int ret;
>>> +
>>> + c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
>>> + ASSERT(c.dump_fd >= 0);
>>> +
>>> + /* dump file's data */
>>> + dump_inode_blk(sbi, ni->ino, node_blk);
>>> +
>>> + /* adjust file size */
>>> + ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
>>> + ASSERT(ret >= 0);
>>> +
>>> + close(c.dump_fd);
>>> +}
>>> +
>>> +static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> + struct f2fs_node *node_blk, char *path, int is_root)
>>> +{
>>> + if (!is_root) {
>>> +#if defined(__MINGW32__)
>>> + if (mkdir(path) < 0 && errno != EEXIST) {
>>> + MSG(0, "Failed to create directory %s\n", path);
>>> + return;
>>> + }
>>> +#else
>>> + if (mkdir(path, 0777) < 0 && errno != EEXIST) {
>>> + MSG(0, "Failed to create directory %s\n", path);
>>> + return;
>>> + }
>>> +#endif
>>> + ASSERT(chdir(path) == 0);
>>> + }
>>> + /* dump folder data */
>>> + dump_inode_blk(sbi, ni->ino, node_blk);
>>> + if (!is_root)
>>> + ASSERT(chdir("..") == 0);
>>> +}
>>> +
>>> +static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> + struct f2fs_node *node_blk, int force, char *base_path,
>>> + bool is_base, bool allow_folder)
>>> {
>>> struct f2fs_inode *inode = &node_blk->i;
>>> u32 imode = le16_to_cpu(inode->i_mode);
>>> @@ -489,6 +574,7 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> char path[1024] = {0};
>>> char ans[255] = {0};
>>> int is_encrypted = file_is_encrypt(inode);
>>> + int is_root = sbi->root_ino_num == ni->nid;
>>> int ret;
>>> if (is_encrypted) {
>>> @@ -496,11 +582,15 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> return -1;
>>> }
>>> - if ((!S_ISREG(imode) && !S_ISLNK(imode)) ||
>>> - namelen == 0 || namelen > F2FS_NAME_LEN) {
>>> - MSG(force, "Not a regular file or wrong name info\n\n");
>>> + if ((!S_ISREG(imode) && !S_ISLNK(imode) && !(S_ISDIR(imode) && allow_folder))) {
>>> + MSG(force, "Not a valid file type\n\n");
>>> + return -1;
>>> + }
>>> + if (!is_root && (namelen == 0 || namelen > F2FS_NAME_LEN)) {
>>> + MSG(force, "Wrong name info\n\n");
>>> return -1;
>>> }
>>> + base_path = base_path ?: "./lost_found";
>>> if (force)
>>> goto dump;
>>> @@ -508,31 +598,49 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
>>> if (c.show_file_map)
>>> return dump_inode_blk(sbi, ni->ino, node_blk);
>>> - printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
>>> + printf("Do you want to dump this %s into %s/? [Y/N] ",
>>> + S_ISREG(imode) || S_ISLNK(imode) ? "file" : "folder",
>>> + base_path);
>>> ret = scanf("%s", ans);
>>> ASSERT(ret >= 0);
>>> if (!strcasecmp(ans, "y")) {
>>> dump:
>>> - ret = system("mkdir -p ./lost_found");
>>> - ASSERT(ret >= 0);
>>> -
>>> - /* make a file */
>>> - strncpy(name, (const char *)inode->i_name, namelen);
>>> - name[namelen] = 0;
>>> - sprintf(path, "./lost_found/%s", name);
>>> + if (is_base) {
>>> + ASSERT(getcwd(path, sizeof(path)) != NULL);
>>> +#if defined(__MINGW32__)
>>> + ret = mkdir(base_path);
>>> +#else
>>> + ret = mkdir(base_path, 0777);
>>> +#endif
>>> - c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
>>> - ASSERT(c.dump_fd >= 0);
>>> + ASSERT(ret == 0 || errno == EEXIST);
>>> + ASSERT(chdir(base_path) == 0);
>>> + }
>>> - /* dump file's data */
>>> - dump_inode_blk(sbi, ni->ino, node_blk);
>>> + /* make a file */
>>> + if (!is_root) {
>>> + strncpy(name, (const char *)inode->i_name, namelen);
>>> + name[namelen] = 0;
>>> + }
>>> - /* adjust file size */
>>> - ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
>>> - ASSERT(ret >= 0);
>>> + if (S_ISREG(imode) || S_ISLNK(imode)) {
>>> + dump_file(sbi, ni, node_blk, name);
>>> + } else {
>>> + dump_folder(sbi, ni, node_blk, name, is_root);
>>> + }
>>> - close(c.dump_fd);
>>> +#if !defined(__MINGW32__)
>>> + /* fix up mode/owner */
>>> + if (c.preserve_perms) {
>>> + if (is_root)
>>> + strncpy(name, ".", 2);
>>> + ASSERT(chmod(name, imode) == 0);
>>> + ASSERT(chown(name, inode->i_uid, inode->i_gid) == 0);
>>> + }
>>> +#endif
>>> + if (is_base)
>>> + ASSERT(chdir(path) == 0);
>>> }
>>> return 0;
>>> }
>>> @@ -582,7 +690,7 @@ void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid)
>>> free(node_blk);
>>> }
>>> -int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
>>> +int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder)
>>> {
>>> struct node_info ni;
>>> struct f2fs_node *node_blk;
>>> @@ -617,7 +725,7 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
>>> print_node_info(sbi, node_blk, force);
>>> if (ni.ino == ni.nid)
>>> - ret = dump_file(sbi, &ni, node_blk, force);
>>> + ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder);
>>> } else {
>>> print_node_info(sbi, node_blk, force);
>>> MSG(force, "Invalid (i)node block\n\n");
>>> diff --git a/fsck/fsck.c b/fsck/fsck.c
>>> index 5d345d0..7400dcf 100644
>>> --- a/fsck/fsck.c
>>> +++ b/fsck/fsck.c
>>> @@ -1651,7 +1651,7 @@ static void print_dentry(struct f2fs_sb_info *sbi, __u8 *name,
>>> d = d->next;
>>> }
>>> printf("/%s", new);
>>> - if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0))
>>> + if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0, NULL, 0, 0))
>>> printf("\33[2K\r");
>>> } else {
>>> for (i = 1; i < depth; i++)
>>> @@ -3632,7 +3632,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
>>> if (!strcasecmp(ans, "y")) {
>>> for (i = 0; i < fsck->nr_nat_entries; i++) {
>>> if (f2fs_test_bit(i, fsck->nat_area_bitmap))
>>> - dump_node(sbi, i, 1);
>>> + dump_node(sbi, i, 1, NULL, 1, 0);
>>> }
>>> }
>>> }
>>> diff --git a/fsck/fsck.h b/fsck/fsck.h
>>> index f5282e2..6cac926 100644
>>> --- a/fsck/fsck.h
>>> +++ b/fsck/fsck.h
>>> @@ -270,12 +270,14 @@ struct dump_option {
>>> int end_ssa;
>>> int32_t blk_addr;
>>> nid_t scan_nid;
>>> + int use_root_nid;
>>> + char *base_path;
>>> };
>>> extern void nat_dump(struct f2fs_sb_info *, nid_t, nid_t);
>>> extern void sit_dump(struct f2fs_sb_info *, unsigned int, unsigned int);
>>> extern void ssa_dump(struct f2fs_sb_info *, int, int);
>>> -extern int dump_node(struct f2fs_sb_info *, nid_t, int);
>>> +extern int dump_node(struct f2fs_sb_info *, nid_t, int, char *, int, int);
>>> extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32);
>>> extern unsigned int start_bidx_of_node(unsigned int, struct f2fs_node *);
>>> extern void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid);
>>> diff --git a/fsck/main.c b/fsck/main.c
>>> index c4d0956..6edc902 100644
>>> --- a/fsck/main.c
>>> +++ b/fsck/main.c
>>> @@ -34,7 +34,7 @@ struct f2fs_fsck gfsck;
>>> INIT_FEATURE_TABLE;
>>> -#ifdef WITH_SLOAD
>>> +#if defined(WITH_SLOAD) || defined(WITH_DUMP)
>>> static char *absolute_path(const char *file)
>>> {
>>> char *ret;
>>> @@ -384,7 +384,7 @@ void f2fs_parse_options(int argc, char *argv[])
>>> }
>>> } else if (!strcmp("dump.f2fs", prog)) {
>>> #ifdef WITH_DUMP
>>> - const char *option_string = "d:i:I:n:Ms:Sa:b:V";
>>> + const char *option_string = "d:fi:I:n:Mo:Prs:Sa:b:Vy";
>>> static struct dump_option dump_opt = {
>>> .nid = 0, /* default root ino */
>>> .start_nat = -1,
>>> @@ -395,6 +395,8 @@ void f2fs_parse_options(int argc, char *argv[])
>>> .end_ssa = -1,
>>> .blk_addr = -1,
>>> .scan_nid = 0,
>>> + .use_root_nid = 0,
>>> + .base_path = NULL,
>>> };
>>> c.func = DUMP;
>>> @@ -456,6 +458,24 @@ void f2fs_parse_options(int argc, char *argv[])
>>> ret = sscanf(optarg, "%x",
>>> &dump_opt.blk_addr);
>>> break;
>>> + case 'y':
>>> + case 'f':
>>> + c.force = 1;
>>> + break;
>>> + case 'r':
>>> + dump_opt.use_root_nid = 1;
>>> + break;
>>> + case 'o':
>>> + dump_opt.base_path = absolute_path(optarg);
>>> + break;
>>> + case 'P':
>>> +#if defined(__MINGW32__)
>>> + MSG(0, "-P not supported for Windows\n");
>>> + err = EWRONG_OPT;
>>> +#else
>>> + c.preserve_perms = 1;
>>> +#endif
>>> + break;
>>> case 'V':
>>> show_version(prog);
>>> exit(0);
>>> @@ -914,6 +934,9 @@ static void do_dump(struct f2fs_sb_info *sbi)
>>> struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
>>> u32 flag = le32_to_cpu(ckpt->ckpt_flags);
>>> + if (opt->use_root_nid)
>>> + opt->nid = sbi->root_ino_num;
>>> +
>>> if (opt->end_nat == -1)
>>> opt->end_nat = NM_I(sbi)->max_nid;
>>> if (opt->end_sit == -1)
>>> @@ -929,7 +952,7 @@ static void do_dump(struct f2fs_sb_info *sbi)
>>> if (opt->blk_addr != -1)
>>> dump_info_from_blkaddr(sbi, opt->blk_addr);
>>> if (opt->nid)
>>> - dump_node(sbi, opt->nid, 0);
>>> + dump_node(sbi, opt->nid, c.force, opt->base_path, 1, 1);
>>> if (opt->scan_nid)
>>> dump_node_scan_disk(sbi, opt->scan_nid);
>>> diff --git a/man/dump.f2fs.8 b/man/dump.f2fs.8
>>> index 94bf5f3..60d6783 100644
>>> --- a/man/dump.f2fs.8
>>> +++ b/man/dump.f2fs.8
>>> @@ -44,7 +44,8 @@ is used to retrieve f2fs metadata (usually in a disk partition).
>>> \fIdevice\fP is the special file corresponding to the device (e.g.
>>> \fI/dev/sdXX\fP).
>>> -Currently, it can retrieve 1) a file given its inode number, 2) NAT
>>> +Currently, it can retrieve 1) a file or folder given its inode number
>>> +(folders are dumped recursively), 2) NAT
>>> entries into a file, 3) SIT entries into a file, 4) SSA entries into
>>> a file, 5) reverse information from the given block address.
>>> .PP
>>> @@ -56,6 +57,20 @@ is 0 on success and -1 on failure.
>>> .BI \-i " inode number"
>>> Specify an inode number to dump out.
>>> .TP
>>> +.BI \-r
>>> +Dump out from the root inode.
>>> +.TP
>>> +.BI \-f
>>> +Do not prompt before dumping
>>> +.TP
>>> +.BI \-y
>>> +Alias for \-f
>>> +.TP
>>> +.BI \-o " path"
>>> +Dump inodes to the given path
>>> +.BI \-P
>>> +Preserve mode/owner/group for dumped inode
>>> +.TP
>>
>> It needs to update dump_usage() as well.
>>
>> Seems f2fs mailing list is out-of-response previously, so I resend it.
>
> Chao, can I ask for your help to write a patch for this?
Jaegeuk, no problem.
Thanks,
>
> Thanks,
>
>>
>> Thanks,
>>
>>> .BI \-I " inode number"
>>> Specify an inode number and scan full disk to dump out, include history inode block
>>> .TP
>>>
>>> base-commit: 5da4e5241503b385e4a7e75b1b2bb3367b38be96
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
prev parent reply other threads:[~2024-05-31 1:13 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-23 22:46 [f2fs-dev] [PATCH v4 1/2] dump.f2fs: Add ability to dump folders Daniel Rosenberg via Linux-f2fs-devel
2024-05-23 22:47 ` [f2fs-dev] [PATCH v4 2/2] dump.f2fs: Fix xattr dumping Daniel Rosenberg via Linux-f2fs-devel
2024-05-23 23:34 ` Daeho Jeong
2024-05-29 6:41 ` Chao Yu
2024-05-23 23:33 ` [f2fs-dev] [PATCH v4 1/2] dump.f2fs: Add ability to dump folders Daeho Jeong
2024-05-29 6:39 ` Chao Yu
2024-05-30 23:41 ` Jaegeuk Kim
2024-05-31 1:13 ` Chao Yu [this message]
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=fed5c9ec-4ebb-4580-9843-bf408f7ab0a2@kernel.org \
--to=chao@kernel.org \
--cc=daehojeong@google.com \
--cc=drosen@google.com \
--cc=jaegeuk@kernel.org \
--cc=kernel-team@android.com \
--cc=linux-f2fs-devel@lists.sourceforge.net \
/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).