From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: Andrii Nakryiko <andrii@kernel.org>
Cc: linux-trace-kernel@vger.kernel.org, rostedt@goodmis.org,
oleg@redhat.com, peterz@infradead.org, mingo@redhat.com,
bpf@vger.kernel.org, jolsa@kernel.org, paulmck@kernel.org,
clm@meta.com
Subject: Re: [PATCH 05/12] uprobes: move offset and ref_ctr_offset into uprobe_consumer
Date: Thu, 27 Jun 2024 12:06:23 +0900 [thread overview]
Message-ID: <20240627120623.8e946a9c3856fa28f068437a@kernel.org> (raw)
In-Reply-To: <20240625002144.3485799-6-andrii@kernel.org>
On Mon, 24 Jun 2024 17:21:37 -0700
Andrii Nakryiko <andrii@kernel.org> wrote:
> Simplify uprobe registration/unregistration interfaces by making offset
> and ref_ctr_offset part of uprobe_consumer "interface". In practice, all
> existing users already store these fields somewhere in uprobe_consumer's
> containing structure, so this doesn't pose any problem. We just move
> some fields around.
>
> On the other hand, this simplifies uprobe_register() and
> uprobe_unregister() API by having only struct uprobe_consumer as one
> thing representing attachment/detachment entity. This makes batched
> versions of uprobe_register() and uprobe_unregister() simpler.
>
> This also makes uprobe_register_refctr() unnecessary, so remove it and
> simplify consumers.
>
> No functional changes intended.
>
Looks good to me.
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Thanks!
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
> ---
> include/linux/uprobes.h | 18 +++----
> kernel/events/uprobes.c | 19 ++-----
> kernel/trace/bpf_trace.c | 21 +++-----
> kernel/trace/trace_uprobe.c | 53 ++++++++-----------
> .../selftests/bpf/bpf_testmod/bpf_testmod.c | 23 ++++----
> 5 files changed, 55 insertions(+), 79 deletions(-)
>
> diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
> index b503fafb7fb3..a75ba37ce3c8 100644
> --- a/include/linux/uprobes.h
> +++ b/include/linux/uprobes.h
> @@ -42,6 +42,11 @@ struct uprobe_consumer {
> enum uprobe_filter_ctx ctx,
> struct mm_struct *mm);
>
> + /* associated file offset of this probe */
> + loff_t offset;
> + /* associated refctr file offset of this probe, or zero */
> + loff_t ref_ctr_offset;
> + /* for internal uprobe infra use, consumers shouldn't touch fields below */
> struct uprobe_consumer *next;
> };
>
> @@ -110,10 +115,9 @@ extern bool is_trap_insn(uprobe_opcode_t *insn);
> extern unsigned long uprobe_get_swbp_addr(struct pt_regs *regs);
> extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs);
> extern int uprobe_write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t);
> -extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
> -extern int uprobe_register_refctr(struct inode *inode, loff_t offset, loff_t ref_ctr_offset, struct uprobe_consumer *uc);
> +extern int uprobe_register(struct inode *inode, struct uprobe_consumer *uc);
> extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
> -extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
> +extern void uprobe_unregister(struct inode *inode, struct uprobe_consumer *uc);
> extern int uprobe_mmap(struct vm_area_struct *vma);
> extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
> extern void uprobe_start_dup_mmap(void);
> @@ -152,11 +156,7 @@ static inline void uprobes_init(void)
> #define uprobe_get_trap_addr(regs) instruction_pointer(regs)
>
> static inline int
> -uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
> -{
> - return -ENOSYS;
> -}
> -static inline int uprobe_register_refctr(struct inode *inode, loff_t offset, loff_t ref_ctr_offset, struct uprobe_consumer *uc)
> +uprobe_register(struct inode *inode, struct uprobe_consumer *uc)
> {
> return -ENOSYS;
> }
> @@ -166,7 +166,7 @@ uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, boo
> return -ENOSYS;
> }
> static inline void
> -uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
> +uprobe_unregister(struct inode *inode, struct uprobe_consumer *uc)
> {
> }
> static inline int uprobe_mmap(struct vm_area_struct *vma)
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index 8ce669bc6474..2544e8b79bad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -1197,14 +1197,13 @@ __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *uc)
> /*
> * uprobe_unregister - unregister an already registered probe.
> * @inode: the file in which the probe has to be removed.
> - * @offset: offset from the start of the file.
> - * @uc: identify which probe if multiple probes are colocated.
> + * @uc: identify which probe consumer to unregister.
> */
> -void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
> +void uprobe_unregister(struct inode *inode, struct uprobe_consumer *uc)
> {
> struct uprobe *uprobe;
>
> - uprobe = find_uprobe(inode, offset);
> + uprobe = find_uprobe(inode, uc->offset);
> if (WARN_ON(!uprobe))
> return;
>
> @@ -1277,20 +1276,12 @@ static int __uprobe_register(struct inode *inode, loff_t offset,
> return ret;
> }
>
> -int uprobe_register(struct inode *inode, loff_t offset,
> - struct uprobe_consumer *uc)
> +int uprobe_register(struct inode *inode, struct uprobe_consumer *uc)
> {
> - return __uprobe_register(inode, offset, 0, uc);
> + return __uprobe_register(inode, uc->offset, uc->ref_ctr_offset, uc);
> }
> EXPORT_SYMBOL_GPL(uprobe_register);
>
> -int uprobe_register_refctr(struct inode *inode, loff_t offset,
> - loff_t ref_ctr_offset, struct uprobe_consumer *uc)
> -{
> - return __uprobe_register(inode, offset, ref_ctr_offset, uc);
> -}
> -EXPORT_SYMBOL_GPL(uprobe_register_refctr);
> -
> /*
> * uprobe_apply - unregister an already registered probe.
> * @inode: the file in which the probe has to be removed.
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index d1daeab1bbc1..ba62baec3152 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -3154,8 +3154,6 @@ struct bpf_uprobe_multi_link;
>
> struct bpf_uprobe {
> struct bpf_uprobe_multi_link *link;
> - loff_t offset;
> - unsigned long ref_ctr_offset;
> u64 cookie;
> struct uprobe_consumer consumer;
> };
> @@ -3181,8 +3179,7 @@ static void bpf_uprobe_unregister(struct path *path, struct bpf_uprobe *uprobes,
> u32 i;
>
> for (i = 0; i < cnt; i++) {
> - uprobe_unregister(d_real_inode(path->dentry), uprobes[i].offset,
> - &uprobes[i].consumer);
> + uprobe_unregister(d_real_inode(path->dentry), &uprobes[i].consumer);
> }
> }
>
> @@ -3262,10 +3259,10 @@ static int bpf_uprobe_multi_link_fill_link_info(const struct bpf_link *link,
>
> for (i = 0; i < ucount; i++) {
> if (uoffsets &&
> - put_user(umulti_link->uprobes[i].offset, uoffsets + i))
> + put_user(umulti_link->uprobes[i].consumer.offset, uoffsets + i))
> return -EFAULT;
> if (uref_ctr_offsets &&
> - put_user(umulti_link->uprobes[i].ref_ctr_offset, uref_ctr_offsets + i))
> + put_user(umulti_link->uprobes[i].consumer.ref_ctr_offset, uref_ctr_offsets + i))
> return -EFAULT;
> if (ucookies &&
> put_user(umulti_link->uprobes[i].cookie, ucookies + i))
> @@ -3439,15 +3436,16 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
> goto error_free;
>
> for (i = 0; i < cnt; i++) {
> - if (__get_user(uprobes[i].offset, uoffsets + i)) {
> + if (__get_user(uprobes[i].consumer.offset, uoffsets + i)) {
> err = -EFAULT;
> goto error_free;
> }
> - if (uprobes[i].offset < 0) {
> + if (uprobes[i].consumer.offset < 0) {
> err = -EINVAL;
> goto error_free;
> }
> - if (uref_ctr_offsets && __get_user(uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) {
> + if (uref_ctr_offsets &&
> + __get_user(uprobes[i].consumer.ref_ctr_offset, uref_ctr_offsets + i)) {
> err = -EFAULT;
> goto error_free;
> }
> @@ -3477,10 +3475,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
> &bpf_uprobe_multi_link_lops, prog);
>
> for (i = 0; i < cnt; i++) {
> - err = uprobe_register_refctr(d_real_inode(link->path.dentry),
> - uprobes[i].offset,
> - uprobes[i].ref_ctr_offset,
> - &uprobes[i].consumer);
> + err = uprobe_register(d_real_inode(link->path.dentry), &uprobes[i].consumer);
> if (err) {
> bpf_uprobe_unregister(&path, uprobes, i);
> goto error_free;
> diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
> index c98e3b3386ba..d786f99114be 100644
> --- a/kernel/trace/trace_uprobe.c
> +++ b/kernel/trace/trace_uprobe.c
> @@ -60,8 +60,6 @@ struct trace_uprobe {
> struct path path;
> struct inode *inode;
> char *filename;
> - unsigned long offset;
> - unsigned long ref_ctr_offset;
> unsigned long nhit;
> struct trace_probe tp;
> };
> @@ -205,7 +203,7 @@ static unsigned long translate_user_vaddr(unsigned long file_offset)
>
> udd = (void *) current->utask->vaddr;
>
> - base_addr = udd->bp_addr - udd->tu->offset;
> + base_addr = udd->bp_addr - udd->tu->consumer.offset;
> return base_addr + file_offset;
> }
>
> @@ -286,13 +284,13 @@ static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
> if (strncmp(tu->filename, argv[0], len) || argv[0][len] != ':')
> return false;
>
> - if (tu->ref_ctr_offset == 0)
> - snprintf(buf, sizeof(buf), "0x%0*lx",
> - (int)(sizeof(void *) * 2), tu->offset);
> + if (tu->consumer.ref_ctr_offset == 0)
> + snprintf(buf, sizeof(buf), "0x%0*llx",
> + (int)(sizeof(void *) * 2), tu->consumer.offset);
> else
> - snprintf(buf, sizeof(buf), "0x%0*lx(0x%lx)",
> - (int)(sizeof(void *) * 2), tu->offset,
> - tu->ref_ctr_offset);
> + snprintf(buf, sizeof(buf), "0x%0*llx(0x%llx)",
> + (int)(sizeof(void *) * 2), tu->consumer.offset,
> + tu->consumer.ref_ctr_offset);
> if (strcmp(buf, &argv[0][len + 1]))
> return false;
>
> @@ -410,7 +408,7 @@ static bool trace_uprobe_has_same_uprobe(struct trace_uprobe *orig,
>
> list_for_each_entry(orig, &tpe->probes, tp.list) {
> if (comp_inode != d_real_inode(orig->path.dentry) ||
> - comp->offset != orig->offset)
> + comp->consumer.offset != orig->consumer.offset)
> continue;
>
> /*
> @@ -472,8 +470,8 @@ static int validate_ref_ctr_offset(struct trace_uprobe *new)
>
> for_each_trace_uprobe(tmp, pos) {
> if (new_inode == d_real_inode(tmp->path.dentry) &&
> - new->offset == tmp->offset &&
> - new->ref_ctr_offset != tmp->ref_ctr_offset) {
> + new->consumer.offset == tmp->consumer.offset &&
> + new->consumer.ref_ctr_offset != tmp->consumer.ref_ctr_offset) {
> pr_warn("Reference counter offset mismatch.");
> return -EINVAL;
> }
> @@ -675,8 +673,8 @@ static int __trace_uprobe_create(int argc, const char **argv)
> WARN_ON_ONCE(ret != -ENOMEM);
> goto fail_address_parse;
> }
> - tu->offset = offset;
> - tu->ref_ctr_offset = ref_ctr_offset;
> + tu->consumer.offset = offset;
> + tu->consumer.ref_ctr_offset = ref_ctr_offset;
> tu->path = path;
> tu->filename = filename;
>
> @@ -746,12 +744,12 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
> char c = is_ret_probe(tu) ? 'r' : 'p';
> int i;
>
> - seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, trace_probe_group_name(&tu->tp),
> + seq_printf(m, "%c:%s/%s %s:0x%0*llx", c, trace_probe_group_name(&tu->tp),
> trace_probe_name(&tu->tp), tu->filename,
> - (int)(sizeof(void *) * 2), tu->offset);
> + (int)(sizeof(void *) * 2), tu->consumer.offset);
>
> - if (tu->ref_ctr_offset)
> - seq_printf(m, "(0x%lx)", tu->ref_ctr_offset);
> + if (tu->consumer.ref_ctr_offset)
> + seq_printf(m, "(0x%llx)", tu->consumer.ref_ctr_offset);
>
> for (i = 0; i < tu->tp.nr_args; i++)
> seq_printf(m, " %s=%s", tu->tp.args[i].name, tu->tp.args[i].comm);
> @@ -1089,12 +1087,7 @@ static int trace_uprobe_enable(struct trace_uprobe *tu, filter_func_t filter)
> tu->consumer.filter = filter;
> tu->inode = d_real_inode(tu->path.dentry);
>
> - if (tu->ref_ctr_offset)
> - ret = uprobe_register_refctr(tu->inode, tu->offset,
> - tu->ref_ctr_offset, &tu->consumer);
> - else
> - ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
> -
> + ret = uprobe_register(tu->inode, &tu->consumer);
> if (ret)
> tu->inode = NULL;
>
> @@ -1112,7 +1105,7 @@ static void __probe_event_disable(struct trace_probe *tp)
> if (!tu->inode)
> continue;
>
> - uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
> + uprobe_unregister(tu->inode, &tu->consumer);
> tu->inode = NULL;
> }
> }
> @@ -1310,7 +1303,7 @@ static int uprobe_perf_close(struct trace_event_call *call,
> return 0;
>
> list_for_each_entry(tu, trace_probe_probe_list(tp), tp.list) {
> - ret = uprobe_apply(tu->inode, tu->offset, &tu->consumer, false);
> + ret = uprobe_apply(tu->inode, tu->consumer.offset, &tu->consumer, false);
> if (ret)
> break;
> }
> @@ -1334,7 +1327,7 @@ static int uprobe_perf_open(struct trace_event_call *call,
> return 0;
>
> list_for_each_entry(tu, trace_probe_probe_list(tp), tp.list) {
> - err = uprobe_apply(tu->inode, tu->offset, &tu->consumer, true);
> + err = uprobe_apply(tu->inode, tu->consumer.offset, &tu->consumer, true);
> if (err) {
> uprobe_perf_close(call, event);
> break;
> @@ -1464,7 +1457,7 @@ int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type,
> *fd_type = is_ret_probe(tu) ? BPF_FD_TYPE_URETPROBE
> : BPF_FD_TYPE_UPROBE;
> *filename = tu->filename;
> - *probe_offset = tu->offset;
> + *probe_offset = tu->consumer.offset;
> *probe_addr = 0;
> return 0;
> }
> @@ -1627,9 +1620,9 @@ create_local_trace_uprobe(char *name, unsigned long offs,
> return ERR_CAST(tu);
> }
>
> - tu->offset = offs;
> + tu->consumer.offset = offs;
> tu->path = path;
> - tu->ref_ctr_offset = ref_ctr_offset;
> + tu->consumer.ref_ctr_offset = ref_ctr_offset;
> tu->filename = kstrdup(name, GFP_KERNEL);
> if (!tu->filename) {
> ret = -ENOMEM;
> diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
> index b0132a342bb5..9ae2a3c64daa 100644
> --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
> +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
> @@ -377,7 +377,6 @@ uprobe_ret_handler(struct uprobe_consumer *self, unsigned long func,
>
> struct testmod_uprobe {
> struct path path;
> - loff_t offset;
> struct uprobe_consumer consumer;
> };
>
> @@ -391,25 +390,24 @@ static int testmod_register_uprobe(loff_t offset)
> {
> int err = -EBUSY;
>
> - if (uprobe.offset)
> + if (uprobe.consumer.offset)
> return -EBUSY;
>
> mutex_lock(&testmod_uprobe_mutex);
>
> - if (uprobe.offset)
> + if (uprobe.consumer.offset)
> goto out;
>
> err = kern_path("/proc/self/exe", LOOKUP_FOLLOW, &uprobe.path);
> if (err)
> goto out;
>
> - err = uprobe_register_refctr(d_real_inode(uprobe.path.dentry),
> - offset, 0, &uprobe.consumer);
> - if (err)
> + uprobe.consumer.offset = offset;
> + err = uprobe_register(d_real_inode(uprobe.path.dentry), &uprobe.consumer);
> + if (err) {
> path_put(&uprobe.path);
> - else
> - uprobe.offset = offset;
> -
> + uprobe.consumer.offset = 0;
> + }
> out:
> mutex_unlock(&testmod_uprobe_mutex);
> return err;
> @@ -419,10 +417,9 @@ static void testmod_unregister_uprobe(void)
> {
> mutex_lock(&testmod_uprobe_mutex);
>
> - if (uprobe.offset) {
> - uprobe_unregister(d_real_inode(uprobe.path.dentry),
> - uprobe.offset, &uprobe.consumer);
> - uprobe.offset = 0;
> + if (uprobe.consumer.offset) {
> + uprobe_unregister(d_real_inode(uprobe.path.dentry), &uprobe.consumer);
> + uprobe.consumer.offset = 0;
> }
>
> mutex_unlock(&testmod_uprobe_mutex);
> --
> 2.43.0
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
next prev parent reply other threads:[~2024-06-27 3:06 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-25 0:21 [PATCH 00/12] uprobes: add batched register/unregister APIs and per-CPU RW semaphore Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 01/12] uprobes: update outdated comment Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 02/12] uprobes: grab write mmap lock in unapply_uprobe() Andrii Nakryiko
2024-06-25 1:29 ` Masami Hiramatsu
2024-06-25 14:49 ` Oleg Nesterov
2024-06-25 17:37 ` Andrii Nakryiko
2024-06-25 19:07 ` Oleg Nesterov
2024-06-26 16:38 ` Andrii Nakryiko
2024-06-25 10:50 ` Oleg Nesterov
2024-06-25 0:21 ` [PATCH 03/12] uprobes: simplify error handling for alloc_uprobe() Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 04/12] uprobes: revamp uprobe refcounting and lifetime management Andrii Nakryiko
2024-06-25 14:44 ` Oleg Nesterov
2024-06-25 17:30 ` Andrii Nakryiko
2024-06-26 6:02 ` kernel test robot
2024-06-26 16:39 ` Andrii Nakryiko
2024-06-27 2:29 ` Masami Hiramatsu
2024-06-27 16:43 ` Andrii Nakryiko
2024-07-01 21:59 ` Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 05/12] uprobes: move offset and ref_ctr_offset into uprobe_consumer Andrii Nakryiko
2024-06-27 3:06 ` Masami Hiramatsu [this message]
2024-06-25 0:21 ` [PATCH 06/12] uprobes: add batch uprobe register/unregister APIs Andrii Nakryiko
2024-06-26 11:27 ` Jiri Olsa
2024-06-26 16:44 ` Andrii Nakryiko
2024-06-27 13:04 ` Masami Hiramatsu
2024-06-27 16:47 ` Andrii Nakryiko
2024-06-28 6:28 ` Masami Hiramatsu
2024-06-28 16:34 ` Andrii Nakryiko
2024-06-29 23:30 ` Masami Hiramatsu
2024-07-01 17:55 ` Andrii Nakryiko
2024-07-01 22:15 ` Andrii Nakryiko
2024-07-02 1:01 ` Masami Hiramatsu
2024-07-02 1:34 ` Andrii Nakryiko
2024-07-02 15:19 ` Masami Hiramatsu
2024-07-02 16:53 ` Steven Rostedt
2024-07-02 21:23 ` Andrii Nakryiko
2024-07-02 23:16 ` Masami Hiramatsu
2024-06-25 0:21 ` [PATCH 07/12] uprobes: inline alloc_uprobe() logic into __uprobe_register() Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 08/12] uprobes: split uprobe allocation and uprobes_tree insertion steps Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 09/12] uprobes: batch uprobes_treelock during registration Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 10/12] uprobes: improve lock batching for uprobe_unregister_batch Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 11/12] uprobes,bpf: switch to batch uprobe APIs for BPF multi-uprobes Andrii Nakryiko
2024-06-25 0:21 ` [PATCH 12/12] uprobes: switch uprobes_treelock to per-CPU RW semaphore Andrii Nakryiko
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=20240627120623.8e946a9c3856fa28f068437a@kernel.org \
--to=mhiramat@kernel.org \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=clm@meta.com \
--cc=jolsa@kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=oleg@redhat.com \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.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).