All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] KVM: x86: pvclock fixes and cleanups
@ 2025-01-18  0:55 Sean Christopherson
  2025-01-18  0:55 ` [PATCH 01/10] KVM: x86: Don't take kvm->lock when iterating over vCPUs in suspend notifier Sean Christopherson
                   ` (9 more replies)
  0 siblings, 10 replies; 32+ messages in thread
From: Sean Christopherson @ 2025-01-18  0:55 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, David Woodhouse, Paul Durrant
  Cc: kvm, linux-kernel, syzbot+352e553a86e0d75f5120, Paul Durrant,
	David Woodhouse, Vitaly Kuznetsov

Fix a lockdep splat in KVM's suspend notifier by simply removing a
spurious kvm->lock acquisition related to kvmclock, and then try to
wrangle KVM's pvclock handling into something approaching sanity (I
made the mistake of looking at how KVM handled PVCLOCK_GUEST_STOPPED).

David,

I didn't look too closely to see how this interacts with your overhaul of
the pvclock madness[*].  When I first started poking at this, I didn't
realize vcpu->arch.hv_lock had tendrils in so many places.  Please holler
if you want me to drop the vcpu->arch.hv_lock changes and/or tweak
something to make it play nice with your series.

The Xen changes are *very* lightly tested, so I definitely won't apply
the potentially problematic changes, i.e. anything past "Don't bleed
PVCLOCK_GUEST_STOPPED across PV clocks", until I get a thumbs up from
you and/or Paul.

[*] https://lore.kernel.org/all/20240522001817.619072-1-dwmw2@infradead.org

Sean Christopherson (10):
  KVM: x86: Don't take kvm->lock when iterating over vCPUs in suspend
    notifier
  KVM: x86: Eliminate "handling" of impossible errors during SUSPEND
  KVM: x86: Drop local pvclock_flags variable in kvm_guest_time_update()
  KVM: x86: Set PVCLOCK_GUEST_STOPPED only for kvmclock, not for Xen PV
    clock
  KVM: x86: Don't bleed PVCLOCK_GUEST_STOPPED across PV clocks
  KVM: x86/xen: Use guest's copy of pvclock when starting timer
  KVM: x86: Pass reference pvclock as a param to
    kvm_setup_guest_pvclock()
  KVM: x86: Remove per-vCPU "cache" of its reference pvclock
  KVM: x86: Setup Hyper-V TSC page before Xen PV clocks (during clock
    update)
  KVM: x86: Override TSC_STABLE flag for Xen PV clocks in
    kvm_guest_time_update()

 arch/x86/include/asm/kvm_host.h |   3 +-
 arch/x86/kvm/x86.c              | 115 ++++++++++++++++----------------
 arch/x86/kvm/xen.c              |  62 +++++++++++++++--
 3 files changed, 114 insertions(+), 66 deletions(-)


base-commit: eb723766b1030a23c38adf2348b7c3d1409d11f0
-- 
2.48.0.rc2.279.g1de40edade-goog


^ permalink raw reply	[flat|nested] 32+ messages in thread
* Re: [PATCH 06/10] KVM: x86/xen: Use guest's copy of pvclock when starting timer
@ 2025-01-22 15:05 kernel test robot
  0 siblings, 0 replies; 32+ messages in thread
From: kernel test robot @ 2025-01-22 15:05 UTC (permalink / raw)
  To: oe-kbuild; +Cc: lkp, Dan Carpenter

BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20250118005552.2626804-7-seanjc@google.com>
References: <20250118005552.2626804-7-seanjc@google.com>
TO: Sean Christopherson <seanjc@google.com>

Hi Sean,

kernel test robot noticed the following build warnings:

[auto build test WARNING on eb723766b1030a23c38adf2348b7c3d1409d11f0]

url:    https://github.com/intel-lab-lkp/linux/commits/Sean-Christopherson/KVM-x86-Don-t-take-kvm-lock-when-iterating-over-vCPUs-in-suspend-notifier/20250118-085939
base:   eb723766b1030a23c38adf2348b7c3d1409d11f0
patch link:    https://lore.kernel.org/r/20250118005552.2626804-7-seanjc%40google.com
patch subject: [PATCH 06/10] KVM: x86/xen: Use guest's copy of pvclock when starting timer
:::::: branch date: 5 days ago
:::::: commit date: 5 days ago
config: i386-randconfig-141-20250122 (https://download.01.org/0day-ci/archive/20250122/202501222250.KDXKa8hj-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
| Closes: https://lore.kernel.org/r/202501222250.KDXKa8hj-lkp@intel.com/

New smatch warnings:
arch/x86/kvm/xen.c:173 xen_get_guest_pvclock() error: uninitialized symbol 'guest_hv_clock'.
arch/x86/kvm/xen.c:219 kvm_xen_start_timer() error: uninitialized symbol 'xen'.

Old smatch warnings:
include/linux/kvm_host.h:998 kvm_get_vcpu_by_id() warn: iterator 'i' not incremented

vim +/guest_hv_clock +173 arch/x86/kvm/xen.c

536395260582be Joao Martins        2022-03-03  152  
4d6163d65c0021 Sean Christopherson 2025-01-17  153  static int xen_get_guest_pvclock(struct kvm_vcpu *vcpu,
4d6163d65c0021 Sean Christopherson 2025-01-17  154  				 struct pvclock_vcpu_time_info *hv_clock,
4d6163d65c0021 Sean Christopherson 2025-01-17  155  				 struct gfn_to_pfn_cache *gpc,
4d6163d65c0021 Sean Christopherson 2025-01-17  156  				 unsigned int offset)
4d6163d65c0021 Sean Christopherson 2025-01-17  157  {
4d6163d65c0021 Sean Christopherson 2025-01-17  158  	struct pvclock_vcpu_time_info *guest_hv_clock;
4d6163d65c0021 Sean Christopherson 2025-01-17  159  	unsigned long flags;
4d6163d65c0021 Sean Christopherson 2025-01-17  160  	int r;
4d6163d65c0021 Sean Christopherson 2025-01-17  161  
4d6163d65c0021 Sean Christopherson 2025-01-17  162  	read_lock_irqsave(&gpc->lock, flags);
4d6163d65c0021 Sean Christopherson 2025-01-17  163  	while (!kvm_gpc_check(gpc, offset + sizeof(*guest_hv_clock))) {
4d6163d65c0021 Sean Christopherson 2025-01-17  164  		read_unlock_irqrestore(&gpc->lock, flags);
4d6163d65c0021 Sean Christopherson 2025-01-17  165  
4d6163d65c0021 Sean Christopherson 2025-01-17  166  		r = kvm_gpc_refresh(gpc, offset + sizeof(*guest_hv_clock));
4d6163d65c0021 Sean Christopherson 2025-01-17  167  		if (r)
4d6163d65c0021 Sean Christopherson 2025-01-17  168  			return r;
4d6163d65c0021 Sean Christopherson 2025-01-17  169  
4d6163d65c0021 Sean Christopherson 2025-01-17  170  		read_lock_irqsave(&gpc->lock, flags);
4d6163d65c0021 Sean Christopherson 2025-01-17  171  	}
4d6163d65c0021 Sean Christopherson 2025-01-17  172  
4d6163d65c0021 Sean Christopherson 2025-01-17 @173  	memcpy(hv_clock, guest_hv_clock, sizeof(*hv_clock));
4d6163d65c0021 Sean Christopherson 2025-01-17  174  	read_unlock_irqrestore(&gpc->lock, flags);
4d6163d65c0021 Sean Christopherson 2025-01-17  175  
4d6163d65c0021 Sean Christopherson 2025-01-17  176  	/*
4d6163d65c0021 Sean Christopherson 2025-01-17  177  	 * Sanity check TSC shift+multiplier to verify the guest's view of time
4d6163d65c0021 Sean Christopherson 2025-01-17  178  	 * is more or less consistent.
4d6163d65c0021 Sean Christopherson 2025-01-17  179  	 */
4d6163d65c0021 Sean Christopherson 2025-01-17  180  	if (hv_clock->tsc_shift != vcpu->arch.hv_clock.tsc_shift ||
4d6163d65c0021 Sean Christopherson 2025-01-17  181  	    hv_clock->tsc_to_system_mul != vcpu->arch.hv_clock.tsc_to_system_mul)
4d6163d65c0021 Sean Christopherson 2025-01-17  182  		return -EINVAL;
4d6163d65c0021 Sean Christopherson 2025-01-17  183  	return 0;
4d6163d65c0021 Sean Christopherson 2025-01-17  184  }
4d6163d65c0021 Sean Christopherson 2025-01-17  185  
451a707813aee2 David Woodhouse     2024-02-27  186  static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
451a707813aee2 David Woodhouse     2024-02-27  187  				bool linux_wa)
536395260582be Joao Martins        2022-03-03  188  {
4d6163d65c0021 Sean Christopherson 2025-01-17  189  	struct kvm_vcpu_xen *xen;
451a707813aee2 David Woodhouse     2024-02-27  190  	int64_t kernel_now, delta;
451a707813aee2 David Woodhouse     2024-02-27  191  	uint64_t guest_now;
4d6163d65c0021 Sean Christopherson 2025-01-17  192  	int r = -EOPNOTSUPP;
451a707813aee2 David Woodhouse     2024-02-27  193  
451a707813aee2 David Woodhouse     2024-02-27  194  	/*
451a707813aee2 David Woodhouse     2024-02-27  195  	 * The guest provides the requested timeout in absolute nanoseconds
451a707813aee2 David Woodhouse     2024-02-27  196  	 * of the KVM clock — as *it* sees it, based on the scaled TSC and
451a707813aee2 David Woodhouse     2024-02-27  197  	 * the pvclock information provided by KVM.
451a707813aee2 David Woodhouse     2024-02-27  198  	 *
451a707813aee2 David Woodhouse     2024-02-27  199  	 * The kernel doesn't support hrtimers based on CLOCK_MONOTONIC_RAW
451a707813aee2 David Woodhouse     2024-02-27  200  	 * so use CLOCK_MONOTONIC. In the timescales covered by timers, the
451a707813aee2 David Woodhouse     2024-02-27  201  	 * difference won't matter much as there is no cumulative effect.
451a707813aee2 David Woodhouse     2024-02-27  202  	 *
451a707813aee2 David Woodhouse     2024-02-27  203  	 * Calculate the time for some arbitrary point in time around "now"
451a707813aee2 David Woodhouse     2024-02-27  204  	 * in terms of both kvmclock and CLOCK_MONOTONIC. Calculate the
451a707813aee2 David Woodhouse     2024-02-27  205  	 * delta between the kvmclock "now" value and the guest's requested
451a707813aee2 David Woodhouse     2024-02-27  206  	 * timeout, apply the "Linux workaround" described below, and add
451a707813aee2 David Woodhouse     2024-02-27  207  	 * the resulting delta to the CLOCK_MONOTONIC "now" value, to get
451a707813aee2 David Woodhouse     2024-02-27  208  	 * the absolute CLOCK_MONOTONIC time at which the timer should
451a707813aee2 David Woodhouse     2024-02-27  209  	 * fire.
451a707813aee2 David Woodhouse     2024-02-27  210  	 */
4d6163d65c0021 Sean Christopherson 2025-01-17  211  	do {
4d6163d65c0021 Sean Christopherson 2025-01-17  212  		struct pvclock_vcpu_time_info hv_clock;
451a707813aee2 David Woodhouse     2024-02-27  213  		uint64_t host_tsc, guest_tsc;
451a707813aee2 David Woodhouse     2024-02-27  214  
4d6163d65c0021 Sean Christopherson 2025-01-17  215  		if (!static_cpu_has(X86_FEATURE_CONSTANT_TSC) ||
4d6163d65c0021 Sean Christopherson 2025-01-17  216  		    !vcpu->kvm->arch.use_master_clock)
4d6163d65c0021 Sean Christopherson 2025-01-17  217  			break;
4d6163d65c0021 Sean Christopherson 2025-01-17  218  
4d6163d65c0021 Sean Christopherson 2025-01-17 @219  		if (xen->vcpu_info_cache.active)
4d6163d65c0021 Sean Christopherson 2025-01-17  220  			r = xen_get_guest_pvclock(vcpu, &hv_clock, &xen->vcpu_info_cache,
4d6163d65c0021 Sean Christopherson 2025-01-17  221  						offsetof(struct compat_vcpu_info, time));
4d6163d65c0021 Sean Christopherson 2025-01-17  222  		else if (xen->vcpu_time_info_cache.active)
4d6163d65c0021 Sean Christopherson 2025-01-17  223  			r = xen_get_guest_pvclock(vcpu, &hv_clock, &xen->vcpu_time_info_cache, 0);
4d6163d65c0021 Sean Christopherson 2025-01-17  224  		if (r)
4d6163d65c0021 Sean Christopherson 2025-01-17  225  			break;
4d6163d65c0021 Sean Christopherson 2025-01-17  226  
451a707813aee2 David Woodhouse     2024-02-27  227  		if (!IS_ENABLED(CONFIG_64BIT) ||
451a707813aee2 David Woodhouse     2024-02-27  228  		    !kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc)) {
451a707813aee2 David Woodhouse     2024-02-27  229  			/*
451a707813aee2 David Woodhouse     2024-02-27  230  			 * Don't fall back to get_kvmclock_ns() because it's
451a707813aee2 David Woodhouse     2024-02-27  231  			 * broken; it has a systemic error in its results
451a707813aee2 David Woodhouse     2024-02-27  232  			 * because it scales directly from host TSC to
451a707813aee2 David Woodhouse     2024-02-27  233  			 * nanoseconds, and doesn't scale first to guest TSC
451a707813aee2 David Woodhouse     2024-02-27  234  			 * and *then* to nanoseconds as the guest does.
451a707813aee2 David Woodhouse     2024-02-27  235  			 *
451a707813aee2 David Woodhouse     2024-02-27  236  			 * There is a small error introduced here because time
451a707813aee2 David Woodhouse     2024-02-27  237  			 * continues to elapse between the ktime_get() and the
451a707813aee2 David Woodhouse     2024-02-27  238  			 * subsequent rdtsc(). But not the systemic drift due
451a707813aee2 David Woodhouse     2024-02-27  239  			 * to get_kvmclock_ns().
451a707813aee2 David Woodhouse     2024-02-27  240  			 */
451a707813aee2 David Woodhouse     2024-02-27  241  			kernel_now = ktime_get(); /* This is CLOCK_MONOTONIC */
451a707813aee2 David Woodhouse     2024-02-27  242  			host_tsc = rdtsc();
451a707813aee2 David Woodhouse     2024-02-27  243  		}
451a707813aee2 David Woodhouse     2024-02-27  244  
451a707813aee2 David Woodhouse     2024-02-27  245  		/* Calculate the guest kvmclock as the guest would do it. */
451a707813aee2 David Woodhouse     2024-02-27  246  		guest_tsc = kvm_read_l1_tsc(vcpu, host_tsc);
4d6163d65c0021 Sean Christopherson 2025-01-17  247  		guest_now = __pvclock_read_cycles(&hv_clock, guest_tsc);
4d6163d65c0021 Sean Christopherson 2025-01-17  248  	} while (0);
4d6163d65c0021 Sean Christopherson 2025-01-17  249  
4d6163d65c0021 Sean Christopherson 2025-01-17  250  	if (r) {
451a707813aee2 David Woodhouse     2024-02-27  251  		/*
451a707813aee2 David Woodhouse     2024-02-27  252  		 * Without CONSTANT_TSC, get_kvmclock_ns() is the only option.
451a707813aee2 David Woodhouse     2024-02-27  253  		 *
451a707813aee2 David Woodhouse     2024-02-27  254  		 * Also if the guest PV clock hasn't been set up yet, as is
451a707813aee2 David Woodhouse     2024-02-27  255  		 * likely to be the case during migration when the vCPU has
451a707813aee2 David Woodhouse     2024-02-27  256  		 * not been run yet. It would be possible to calculate the
451a707813aee2 David Woodhouse     2024-02-27  257  		 * scaling factors properly in that case but there's not much
451a707813aee2 David Woodhouse     2024-02-27  258  		 * point in doing so. The get_kvmclock_ns() drift accumulates
451a707813aee2 David Woodhouse     2024-02-27  259  		 * over time, so it's OK to use it at startup. Besides, on
451a707813aee2 David Woodhouse     2024-02-27  260  		 * migration there's going to be a little bit of skew in the
451a707813aee2 David Woodhouse     2024-02-27  261  		 * precise moment at which timers fire anyway. Often they'll
451a707813aee2 David Woodhouse     2024-02-27  262  		 * be in the "past" by the time the VM is running again after
451a707813aee2 David Woodhouse     2024-02-27  263  		 * migration.
451a707813aee2 David Woodhouse     2024-02-27  264  		 */
451a707813aee2 David Woodhouse     2024-02-27  265  		guest_now = get_kvmclock_ns(vcpu->kvm);
451a707813aee2 David Woodhouse     2024-02-27  266  		kernel_now = ktime_get();
451a707813aee2 David Woodhouse     2024-02-27  267  	}
451a707813aee2 David Woodhouse     2024-02-27  268  
451a707813aee2 David Woodhouse     2024-02-27  269  	delta = guest_abs - guest_now;
451a707813aee2 David Woodhouse     2024-02-27  270  
451a707813aee2 David Woodhouse     2024-02-27  271  	/*
451a707813aee2 David Woodhouse     2024-02-27  272  	 * Xen has a 'Linux workaround' in do_set_timer_op() which checks for
451a707813aee2 David Woodhouse     2024-02-27  273  	 * negative absolute timeout values (caused by integer overflow), and
451a707813aee2 David Woodhouse     2024-02-27  274  	 * for values about 13 days in the future (2^50ns) which would be
451a707813aee2 David Woodhouse     2024-02-27  275  	 * caused by jiffies overflow. For those cases, Xen sets the timeout
451a707813aee2 David Woodhouse     2024-02-27  276  	 * 100ms in the future (not *too* soon, since if a guest really did
451a707813aee2 David Woodhouse     2024-02-27  277  	 * set a long timeout on purpose we don't want to keep churning CPU
451a707813aee2 David Woodhouse     2024-02-27  278  	 * time by waking it up).  Emulate Xen's workaround when starting the
451a707813aee2 David Woodhouse     2024-02-27  279  	 * timer in response to __HYPERVISOR_set_timer_op.
451a707813aee2 David Woodhouse     2024-02-27  280  	 */
451a707813aee2 David Woodhouse     2024-02-27  281  	if (linux_wa &&
451a707813aee2 David Woodhouse     2024-02-27  282  	    unlikely((int64_t)guest_abs < 0 ||
451a707813aee2 David Woodhouse     2024-02-27  283  		     (delta > 0 && (uint32_t) (delta >> 50) != 0))) {
451a707813aee2 David Woodhouse     2024-02-27  284  		delta = 100 * NSEC_PER_MSEC;
451a707813aee2 David Woodhouse     2024-02-27  285  		guest_abs = guest_now + delta;
451a707813aee2 David Woodhouse     2024-02-27  286  	}
451a707813aee2 David Woodhouse     2024-02-27  287  
77c9b9dea4fb3e David Woodhouse     2023-09-30  288  	/*
77c9b9dea4fb3e David Woodhouse     2023-09-30  289  	 * Avoid races with the old timer firing. Checking timer_expires
77c9b9dea4fb3e David Woodhouse     2023-09-30  290  	 * to avoid calling hrtimer_cancel() will only have false positives
77c9b9dea4fb3e David Woodhouse     2023-09-30  291  	 * so is fine.
77c9b9dea4fb3e David Woodhouse     2023-09-30  292  	 */
77c9b9dea4fb3e David Woodhouse     2023-09-30  293  	if (vcpu->arch.xen.timer_expires)
77c9b9dea4fb3e David Woodhouse     2023-09-30  294  		hrtimer_cancel(&vcpu->arch.xen.timer);
77c9b9dea4fb3e David Woodhouse     2023-09-30  295  
536395260582be Joao Martins        2022-03-03  296  	atomic_set(&vcpu->arch.xen.timer_pending, 0);
536395260582be Joao Martins        2022-03-03  297  	vcpu->arch.xen.timer_expires = guest_abs;
536395260582be Joao Martins        2022-03-03  298  
451a707813aee2 David Woodhouse     2024-02-27  299  	if (delta <= 0)
536395260582be Joao Martins        2022-03-03  300  		xen_timer_callback(&vcpu->arch.xen.timer);
451a707813aee2 David Woodhouse     2024-02-27  301  	else
536395260582be Joao Martins        2022-03-03  302  		hrtimer_start(&vcpu->arch.xen.timer,
451a707813aee2 David Woodhouse     2024-02-27  303  			      ktime_add_ns(kernel_now, delta),
536395260582be Joao Martins        2022-03-03  304  			      HRTIMER_MODE_ABS_HARD);
536395260582be Joao Martins        2022-03-03  305  }
536395260582be Joao Martins        2022-03-03  306  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2025-01-22 15:07 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-18  0:55 [PATCH 00/10] KVM: x86: pvclock fixes and cleanups Sean Christopherson
2025-01-18  0:55 ` [PATCH 01/10] KVM: x86: Don't take kvm->lock when iterating over vCPUs in suspend notifier Sean Christopherson
2025-01-21 16:01   ` Paul Durrant
2025-01-18  0:55 ` [PATCH 02/10] KVM: x86: Eliminate "handling" of impossible errors during SUSPEND Sean Christopherson
2025-01-21 16:03   ` Paul Durrant
2025-01-18  0:55 ` [PATCH 03/10] KVM: x86: Drop local pvclock_flags variable in kvm_guest_time_update() Sean Christopherson
2025-01-21 16:05   ` Paul Durrant
2025-01-18  0:55 ` [PATCH 04/10] KVM: x86: Set PVCLOCK_GUEST_STOPPED only for kvmclock, not for Xen PV clock Sean Christopherson
2025-01-21 16:42   ` Paul Durrant
2025-01-21 17:09     ` Sean Christopherson
2025-01-21 17:15       ` Paul Durrant
2025-01-21 18:32         ` Sean Christopherson
2025-01-18  0:55 ` [PATCH 05/10] KVM: x86: Don't bleed PVCLOCK_GUEST_STOPPED across PV clocks Sean Christopherson
2025-01-21 16:54   ` Paul Durrant
2025-01-21 17:11     ` Sean Christopherson
2025-01-18  0:55 ` [PATCH 06/10] KVM: x86/xen: Use guest's copy of pvclock when starting timer Sean Christopherson
2025-01-19  3:00   ` kernel test robot
2025-01-21 16:58   ` Paul Durrant
2025-01-21 18:45     ` Sean Christopherson
2025-01-18  0:55 ` [PATCH 07/10] KVM: x86: Pass reference pvclock as a param to kvm_setup_guest_pvclock() Sean Christopherson
2025-01-21 17:00   ` Paul Durrant
2025-01-18  0:55 ` [PATCH 08/10] KVM: x86: Remove per-vCPU "cache" of its reference pvclock Sean Christopherson
2025-01-21 17:03   ` Paul Durrant
2025-01-18  0:55 ` [PATCH 09/10] KVM: x86: Setup Hyper-V TSC page before Xen PV clocks (during clock update) Sean Christopherson
2025-01-20 14:49   ` Vitaly Kuznetsov
2025-01-21 15:44     ` Sean Christopherson
2025-01-21 15:59       ` Paul Durrant
2025-01-21 17:16         ` David Woodhouse
2025-01-21 17:30           ` Paul Durrant
2025-01-18  0:55 ` [PATCH 10/10] KVM: x86: Override TSC_STABLE flag for Xen PV clocks in kvm_guest_time_update() Sean Christopherson
2025-01-21 17:05   ` Paul Durrant
  -- strict thread matches above, loose matches on Subject: below --
2025-01-22 15:05 [PATCH 06/10] KVM: x86/xen: Use guest's copy of pvclock when starting timer kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.