From: Chao Yu <chao@kernel.org>
To: Sheng Yong <shengyong1@huawei.com>,
jaegeuk@kernel.org, yuchao0@huawei.com
Cc: miaoxie@huawei.com, heyunlei@huawei.com,
linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [RFC PATCH 4/5] mkfs.f2fs: create lost+found directory
Date: Thu, 8 Feb 2018 23:08:12 +0800 [thread overview]
Message-ID: <dfbb59fc-d2c7-09d6-960c-8f3fc8163081@kernel.org> (raw)
In-Reply-To: <20180206043125.134191-5-shengyong1@huawei.com>
On 2018/2/6 12:31, Sheng Yong wrote:
> This patch introduces a new feature F2FS_FEATURE_LOST_FOUND. It can be
> switched on by indicating a new option `lost+found' with -O. If
Not sure, do we need to change this option to 'lost_found' to follow other
generic -O options?
> F2FS_FEATUER_LOST_FOUND is enabled, an empty directory lost+found is
> created during mkfs.
>
> This is a preparation for fsck. During fsck, the directory is used to
> save unreachable files, which have no parent directory or their parent
> directory is removed by fsck. Encrypted files are also allowed to be
> saved here.
>
> Signed-off-by: Sheng Yong <shengyong1@huawei.com>
> ---
> fsck/mount.c | 3 +
> include/f2fs_fs.h | 6 ++
> mkfs/f2fs_format.c | 223 +++++++++++++++++++++++++++++++++++++++++++++---
> mkfs/f2fs_format_main.c | 2 +
> 4 files changed, 222 insertions(+), 12 deletions(-)
>
> diff --git a/fsck/mount.c b/fsck/mount.c
> index 46cb571..df53c48 100644
> --- a/fsck/mount.c
> +++ b/fsck/mount.c
> @@ -460,6 +460,9 @@ void print_sb_state(struct f2fs_super_block *sb)
> if (f & cpu_to_le32(F2FS_FEATURE_INODE_CRTIME)) {
> MSG(0, "%s", " inode_crtime");
> }
> + if (f & cpu_to_le32(F2FS_FEATURE_LOST_FOUND)) {
> + MSG(0, "%s", " lost+found");
> + }
> MSG(0, "\n");
> MSG(0, "Info: superblock encrypt level = %d, salt = ",
> sb->encryption_level);
> diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
> index ca4522d..093c402 100644
> --- a/include/f2fs_fs.h
> +++ b/include/f2fs_fs.h
> @@ -291,6 +291,8 @@ static inline uint64_t bswap_64(uint64_t val)
>
> #define VERSION_LEN 256
>
> +#define LPF "lost+found"
> +
> enum f2fs_config_func {
> MKFS,
> FSCK,
> @@ -369,6 +371,9 @@ struct f2fs_configuration {
> u_int32_t next_free_nid;
> u_int32_t quota_inum;
> u_int32_t quota_dnum;
> + u_int32_t lpf_inum;
> + u_int32_t lpf_dnum;
> + u_int32_t lpf_ino;
>
> /* defragmentation parameters */
> int defrag_shrink;
> @@ -557,6 +562,7 @@ enum {
> #define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040
> #define F2FS_FEATURE_QUOTA_INO 0x0080
> #define F2FS_FEATURE_INODE_CRTIME 0x0100
> +#define F2FS_FEATURE_LOST_FOUND 0x0200
>
> #define MAX_VOLUME_NAME 512
>
> diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
> index bda3c9d..33dd98c 100644
> --- a/mkfs/f2fs_format.c
> +++ b/mkfs/f2fs_format.c
> @@ -426,6 +426,9 @@ static int f2fs_prepare_super_block(void)
> qtype, c.next_free_nid - 1);
> }
>
> + if (c.feature & cpu_to_le32(F2FS_FEATURE_LOST_FOUND))
> + c.lpf_ino = c.next_free_nid++;
> +
> if (total_zones <= 6) {
> MSG(1, "\tError: %d zones: Need more zones "
> "by shrinking zone size\n", total_zones);
> @@ -608,9 +611,10 @@ static int f2fs_write_check_point_pack(void)
> set_cp(cur_data_segno[i], 0xffffffff);
> }
>
> - set_cp(cur_node_blkoff[0], 1 + c.quota_inum);
> - set_cp(cur_data_blkoff[0], 1 + c.quota_dnum);
> - set_cp(valid_block_count, 2 + c.quota_inum + c.quota_dnum);
> + set_cp(cur_node_blkoff[0], 1 + c.quota_inum + c.lpf_inum);
> + set_cp(cur_data_blkoff[0], 1 + c.quota_dnum + c.lpf_dnum);
> + set_cp(valid_block_count, 2 + c.quota_inum + c.quota_dnum +
> + c.lpf_inum + c.lpf_dnum);
> set_cp(rsvd_segment_count, c.reserved_segments);
> set_cp(overprov_segment_count, (get_sb(segment_count_main) -
> get_cp(rsvd_segment_count)) *
> @@ -642,8 +646,8 @@ static int f2fs_write_check_point_pack(void)
>
> set_cp(ckpt_flags, flags);
> set_cp(cp_pack_start_sum, 1 + get_sb(cp_payload));
> - set_cp(valid_node_count, 1 + c.quota_inum);
> - set_cp(valid_inode_count, 1 + c.quota_inum);
> + set_cp(valid_node_count, 1 + c.quota_inum + c.lpf_inum);
> + set_cp(valid_inode_count, 1 + c.quota_inum + c.lpf_inum);
> set_cp(next_free_nid, c.next_free_nid);
> set_cp(sit_ver_bitmap_bytesize, ((get_sb(segment_count_sit) / 2) <<
> get_sb(log_blocks_per_seg)) / 8);
> @@ -702,7 +706,7 @@ static int f2fs_write_check_point_pack(void)
> SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
>
> journal = &sum->journal;
> - journal->n_nats = cpu_to_le16(1 + c.quota_inum);
> + journal->n_nats = cpu_to_le16(1 + c.quota_inum + c.lpf_inum);
> journal->nat_j.entries[0].nid = sb->root_ino;
> journal->nat_j.entries[0].ne.version = 0;
> journal->nat_j.entries[0].ne.ino = sb->root_ino;
> @@ -723,6 +727,16 @@ static int f2fs_write_check_point_pack(void)
> i++;
> }
>
> + if (c.lpf_inum) {
> + journal->nat_j.entries[i].nid = cpu_to_le32(c.lpf_ino);
> + journal->nat_j.entries[i].ne.version = 0;
> + journal->nat_j.entries[i].ne.ino = cpu_to_le32(c.lpf_ino);
> + journal->nat_j.entries[i].ne.block_addr = cpu_to_le32(
> + get_sb(main_blkaddr) +
> + get_cp(cur_node_segno[0]) *
> + c.blks_per_seg + i);
> + }
> +
> memcpy(sum_compact_p, &journal->n_nats, SUM_JOURNAL_SIZE);
> sum_compact_p += SUM_JOURNAL_SIZE;
>
> @@ -732,10 +746,13 @@ static int f2fs_write_check_point_pack(void)
> journal->sit_j.entries[0].segno = cp->cur_node_segno[0];
> journal->sit_j.entries[0].se.vblocks =
> cpu_to_le16((CURSEG_HOT_NODE << 10) |
> - (1 + c.quota_inum));
> + (1 + c.quota_inum + c.lpf_inum));
> f2fs_set_bit(0, (char *)journal->sit_j.entries[0].se.valid_map);
> for (i = 1; i <= c.quota_inum; i++)
> f2fs_set_bit(i, (char *)journal->sit_j.entries[0].se.valid_map);
> + if (c.lpf_inum)
> + f2fs_set_bit(i, (char *)journal->sit_j.entries[0].se.valid_map);
> +
> journal->sit_j.entries[1].segno = cp->cur_node_segno[1];
> journal->sit_j.entries[1].se.vblocks =
> cpu_to_le16((CURSEG_WARM_NODE << 10));
> @@ -747,10 +764,12 @@ static int f2fs_write_check_point_pack(void)
> journal->sit_j.entries[3].segno = cp->cur_data_segno[0];
> journal->sit_j.entries[3].se.vblocks =
> cpu_to_le16((CURSEG_HOT_DATA << 10) |
> - (1 + c.quota_dnum));
> + (1 + c.quota_dnum + c.lpf_dnum));
> f2fs_set_bit(0, (char *)journal->sit_j.entries[3].se.valid_map);
> for (i = 1; i <= c.quota_dnum; i++)
> f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map);
> + if (c.lpf_dnum)
> + f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map);
>
> journal->sit_j.entries[4].segno = cp->cur_data_segno[1];
> journal->sit_j.entries[4].se.vblocks =
> @@ -780,6 +799,11 @@ static int f2fs_write_check_point_pack(void)
> off += QUOTA_DATA(qtype);
> }
>
> + if (c.lpf_dnum) {
> + (sum_entry + off)->nid = cpu_to_le32(c.lpf_ino);
> + (sum_entry + off)->ofs_in_node = 0;
> + }
> +
> /* warm data summary, nothing to do */
> /* cold data summary, nothing to do */
>
> @@ -804,6 +828,11 @@ static int f2fs_write_check_point_pack(void)
> sum->entries[1 + i].ofs_in_node = 0;
> i++;
> }
> + if (c.lpf_inum) {
> + i++;
> + sum->entries[i].nid = cpu_to_le32(c.lpf_ino);
> + sum->entries[i].ofs_in_node = 0;
> + }
>
> cp_seg_blk++;
> DBG(1, "\tWriting Segment summary for HOT_NODE, at offset 0x%08"PRIx64"\n",
> @@ -952,7 +981,7 @@ static int discard_obsolete_dnode(struct f2fs_node *raw_node, u_int64_t offset)
>
> /* only root inode was written before truncating dnodes */
> last_inode_pos = start_inode_pos +
> - c.cur_seg[CURSEG_HOT_NODE] * c.blks_per_seg + c.quota_inum;
> + c.cur_seg[CURSEG_HOT_NODE] * c.blks_per_seg + c.quota_inum + c.lpf_inum;
>
> if (c.zoned_mode)
> return 0;
> @@ -1004,7 +1033,10 @@ static int f2fs_write_root_inode(void)
> c.blks_per_seg + 1);
>
> raw_node->i.i_mode = cpu_to_le16(0x41ed);
> - raw_node->i.i_links = cpu_to_le32(2);
> + if (c.lpf_ino)
> + raw_node->i.i_links = cpu_to_le32(3);
> + else
> + raw_node->i.i_links = cpu_to_le32(2);
> raw_node->i.i_uid = cpu_to_le32(getuid());
> raw_node->i.i_gid = cpu_to_le32(getgid());
>
> @@ -1121,10 +1153,16 @@ static int f2fs_write_default_quota(int qtype, unsigned int blkaddr,
> dqblk.dqb_pad = cpu_to_le32(0);
> dqblk.dqb_ihardlimit = cpu_to_le64(0);
> dqblk.dqb_isoftlimit = cpu_to_le64(0);
> - dqblk.dqb_curinodes = cpu_to_le64(1);
> + if (c.lpf_ino)
> + dqblk.dqb_curinodes = cpu_to_le64(2);
> + else
> + dqblk.dqb_curinodes = cpu_to_le64(1);
> dqblk.dqb_bhardlimit = cpu_to_le64(0);
> dqblk.dqb_bsoftlimit = cpu_to_le64(0);
> - dqblk.dqb_curspace = cpu_to_le64(4096);
> + if (c.lpf_ino)
> + dqblk.dqb_curspace = cpu_to_le64(8192);
> + else
> + dqblk.dqb_curspace = cpu_to_le64(4096);
> dqblk.dqb_btime = cpu_to_le64(0);
> dqblk.dqb_itime = cpu_to_le64(0);
>
> @@ -1299,6 +1337,137 @@ static int f2fs_update_nat_root(void)
> return 0;
> }
>
> +static u_int64_t f2fs_add_default_dentry_lpf(void)
> +{
> + struct f2fs_dentry_block *dent_blk;
> + u_int64_t data_blk_offset = 0;
> +
> + dent_blk = calloc(F2FS_BLKSIZE, 1);
> + if (dent_blk == NULL) {
> + MSG(1, "\tError: Calloc Failed for dent_blk!!!\n");
> + return -1;
> + }
> +
> + dent_blk->dentry[0].hash_code = 0;
> + dent_blk->dentry[0].ino = cpu_to_le32(c.lpf_ino);
> + dent_blk->dentry[0].name_len = cpu_to_le16(1);
> + dent_blk->dentry[0].file_type = F2FS_FT_DIR;
> + memcpy(dent_blk->filename[0], ".", 1);
> +
> + dent_blk->dentry[1].hash_code = 0;
> + dent_blk->dentry[1].ino = sb->root_ino;
> + dent_blk->dentry[1].name_len = cpu_to_le16(2);
> + dent_blk->dentry[1].file_type = F2FS_FT_DIR;
> + memcpy(dent_blk->filename[1], "..", 2);
> +
> + test_and_set_bit_le(0, dent_blk->dentry_bitmap);
> + test_and_set_bit_le(1, dent_blk->dentry_bitmap);
> +
> + data_blk_offset = get_sb(main_blkaddr);
> + data_blk_offset += c.cur_seg[CURSEG_HOT_DATA] * c.blks_per_seg +
> + 1 + c.quota_dnum;
> +
> + DBG(1, "\tWriting default dentry lost+found, at offset 0x%08"PRIx64"\n",
> + data_blk_offset);
> + if (dev_write_block(dent_blk, data_blk_offset)) {
> + MSG(1, "\tError While writing the dentry_blk to disk!!!\n");
> + free(dent_blk);
> + return -1;
> + }
> +
> + free(dent_blk);
> + c.lpf_dnum++;
> + return data_blk_offset;
> +}
> +
> +static int f2fs_write_lpf_inode(void)
> +{
> + struct f2fs_node *raw_node;
> + u_int64_t blk_size_bytes, data_blk_nor;
> + u_int64_t main_area_node_seg_blk_offset;
> + int err = 0;
> +
> + ASSERT(c.lpf_ino);
> +
> + raw_node = calloc(F2FS_BLKSIZE, 1);
> + if (raw_node == NULL) {
> + MSG(1, "\tError: Calloc Failed for raw_node!!!\n");
> + return -1;
> + }
> +
> + raw_node->footer.nid = cpu_to_le32(c.lpf_ino);
> + raw_node->footer.ino = raw_node->footer.nid;
> + raw_node->footer.cp_ver = cpu_to_le64(1);
> + raw_node->footer.next_blkaddr = cpu_to_le32(
> + get_sb(main_blkaddr) +
> + c.cur_seg[CURSEG_HOT_NODE] * c.blks_per_seg +
> + 1 + c.quota_inum + 1);
> +
> + raw_node->i.i_mode = cpu_to_le16(0x41c0); /* 0700 */
> + raw_node->i.i_links = cpu_to_le32(2);
> + raw_node->i.i_uid = cpu_to_le32(getuid());
> + raw_node->i.i_gid = cpu_to_le32(getgid());
> +
> + blk_size_bytes = 1 << get_sb(log_blocksize);
> + raw_node->i.i_size = cpu_to_le64(1 * blk_size_bytes); /* dentry */
> + raw_node->i.i_blocks = cpu_to_le64(2);
> +
> + raw_node->i.i_atime = cpu_to_le32(time(NULL));
> + raw_node->i.i_atime_nsec = 0;
> + raw_node->i.i_ctime = cpu_to_le32(time(NULL));
> + raw_node->i.i_ctime_nsec = 0;
> + raw_node->i.i_mtime = cpu_to_le32(time(NULL));
> + raw_node->i.i_mtime_nsec = 0;
> + raw_node->i.i_generation = 0;
> + raw_node->i.i_xattr_nid = 0;
> + raw_node->i.i_flags = 0;
> + raw_node->i.i_pino = le32_to_cpu(sb->root_ino);
> + raw_node->i.i_namelen = le32_to_cpu(strlen(LPF));
> + memcpy(raw_node->i.i_name, LPF, strlen(LPF));
> + raw_node->i.i_current_depth = cpu_to_le32(1);
> + raw_node->i.i_dir_level = DEF_DIR_LEVEL;
> +
> + if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
> + raw_node->i.i_inline = F2FS_EXTRA_ATTR;
> + raw_node->i.i_extra_isize =
> + cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
> + }
> +
> + if (c.feature & cpu_to_le32(F2FS_FEATURE_PRJQUOTA))
> + raw_node->i.i_projid = cpu_to_le32(F2FS_DEF_PROJID);
Need to handle inode_crtime case?
> +
> + data_blk_nor = f2fs_add_default_dentry_lpf();
> + if (data_blk_nor < 0) {
> + MSG(1, "\tError: Failed to add default dentries for lost+found!!!\n");
> + err = -1;
> + goto exit;
> + }
> + raw_node->i.i_addr[get_extra_isize(raw_node)] = cpu_to_le32(data_blk_nor);
> +
> + if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
> + raw_node->i.i_inode_checksum =
> + cpu_to_le32(f2fs_inode_chksum(raw_node));
> +
> + main_area_node_seg_blk_offset = get_sb(main_blkaddr);
> + main_area_node_seg_blk_offset += c.cur_seg[CURSEG_HOT_NODE] *
> + c.blks_per_seg + c.quota_inum + 1;
> +
> + DBG(1, "\tWriting lost+found inode (hot node), %x %x %x at offset 0x%08"PRIu64"\n",
> + get_sb(main_blkaddr),
> + c.cur_seg[CURSEG_HOT_NODE],
> + c.blks_per_seg, main_area_node_seg_blk_offset);
> + if (dev_write_block(raw_node, main_area_node_seg_blk_offset)) {
> + MSG(1, "\tError: While writing the raw_node to disk!!!\n");
> + err = -1;
> + goto exit;
> + }
> +
> + c.lpf_inum++;
> +exit:
> + free(raw_node);
> + return err;
> +}
> +
> static int f2fs_add_default_dentry_root(void)
> {
> struct f2fs_dentry_block *dent_blk = NULL;
> @@ -1326,6 +1495,27 @@ static int f2fs_add_default_dentry_root(void)
> test_and_set_bit_le(0, dent_blk->dentry_bitmap);
> test_and_set_bit_le(1, dent_blk->dentry_bitmap);
>
> + if (c.lpf_ino) {
> + int len = strlen(LPF);
> + f2fs_hash_t hash = f2fs_dentry_hash((unsigned char *)LPF, len);
> +
> + dent_blk->dentry[2].hash_code = cpu_to_le32(hash);
> + dent_blk->dentry[2].ino = cpu_to_le32(c.lpf_ino);
> + dent_blk->dentry[2].name_len = strlen(LPF);
cpu_to_le16(strlen(LPF))
> + dent_blk->dentry[2].file_type = F2FS_FT_DIR;
> + memcpy(dent_blk->filename[2], LPF, F2FS_SLOT_LEN);
> +
> + dent_blk->dentry[3].hash_code = cpu_to_le32(hash);
> + dent_blk->dentry[3].ino = cpu_to_le32(c.lpf_ino);
> + dent_blk->dentry[3].name_len = strlen(LPF);
> + dent_blk->dentry[3].file_type = F2FS_FT_DIR;
Do not need to update this whole slot?
> + memcpy(dent_blk->filename[3], LPF + F2FS_SLOT_LEN,
> + len - F2FS_SLOT_LEN);
> +
> + test_and_set_bit_le(2, dent_blk->dentry_bitmap);
> + test_and_set_bit_le(3, dent_blk->dentry_bitmap);
> + }
> +
> data_blk_offset = get_sb(main_blkaddr);
> data_blk_offset += c.cur_seg[CURSEG_HOT_DATA] *
> c.blks_per_seg;
> @@ -1363,6 +1553,14 @@ static int f2fs_create_root_dir(void)
> }
> }
>
> + if (c.feature & cpu_to_le32(F2FS_FEATURE_LOST_FOUND)) {
> + err = f2fs_write_lpf_inode();
> + if (err < 0) {
> + MSG(1, "\tError: Failed to write lost+found inode!!!\n");
> + goto exit;
> + }
> + }
> +
> err = f2fs_update_nat_root();
> if (err < 0) {
> MSG(1, "\tError: Failed to update NAT for root!!!\n");
> @@ -1428,6 +1626,7 @@ int f2fs_format_device(void)
> MSG(0, "\tError: Failed to write the Super Block!!!\n");
> goto exit;
> }
> +
Meaningless blank?
Thanks,
> exit:
> if (err)
> MSG(0, "\tError: Could not format the device!!!\n");
> diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c
> index 120eeba..6382e71 100644
> --- a/mkfs/f2fs_format_main.c
> +++ b/mkfs/f2fs_format_main.c
> @@ -95,6 +95,8 @@ static void parse_feature(const char *features)
> c.feature |= cpu_to_le32(F2FS_FEATURE_QUOTA_INO);
> } else if (!strcmp(features, "inode_crtime")) {
> c.feature |= cpu_to_le32(F2FS_FEATURE_INODE_CRTIME);
> + } else if (!strcmp(features, "lost+found")) {
> + c.feature |= cpu_to_le32(F2FS_FEATURE_LOST_FOUND);
> } else {
> MSG(0, "Error: Wrong features\n");
> mkfs_usage();
>
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
next prev parent reply other threads:[~2018-02-08 15:08 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-06 4:31 [RFC PATCH 0/5] f2fs-tools: introduce lost+found feature Sheng Yong
2018-02-06 4:31 ` [RFC PATCH 1/5] mkfs.f2fs: introduce mkfs parameters in f2fs_configuration Sheng Yong
2018-02-08 13:30 ` Chao Yu
2018-02-09 3:21 ` Sheng Yong
2018-02-09 12:59 ` Chao Yu
2018-02-06 4:31 ` [RFC PATCH 2/5] f2fs-tools: init f2fs_configuration as 0 Sheng Yong
2018-02-08 13:32 ` Chao Yu
2018-02-10 2:49 ` Jaegeuk Kim
2018-02-06 4:31 ` [RFC PATCH 3/5] fsck.f2fs: integrate sanity_check_inode to __check_inode_mode Sheng Yong
2018-02-08 13:44 ` Chao Yu
2018-02-06 4:31 ` [RFC PATCH 4/5] mkfs.f2fs: create lost+found directory Sheng Yong
2018-02-08 15:08 ` Chao Yu [this message]
2018-02-09 3:21 ` Sheng Yong
2018-02-09 13:13 ` Chao Yu
2018-02-06 4:31 ` [RFC PATCH 5/5] fsck.f2fs: reconnect unreachable files to lost+found Sheng Yong
2018-02-07 10:01 ` Sheng Yong
2018-02-07 10:04 ` Sheng Yong
2018-02-13 14:22 ` Chao Yu
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=dfbb59fc-d2c7-09d6-960c-8f3fc8163081@kernel.org \
--to=chao@kernel.org \
--cc=heyunlei@huawei.com \
--cc=jaegeuk@kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=miaoxie@huawei.com \
--cc=shengyong1@huawei.com \
--cc=yuchao0@huawei.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 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).