kern/145385: commit references a PR

dfilter service dfilter at FreeBSD.ORG
Fri Oct 1 10:40:04 UTC 2010


The following reply was made to PR kern/145385; it has been noted by GNATS.

From: dfilter at FreeBSD.ORG (dfilter service)
To: bug-followup at FreeBSD.org
Cc:  
Subject: Re: kern/145385: commit references a PR
Date: Fri,  1 Oct 2010 10:33:00 +0000 (UTC)

 Author: avg
 Date: Fri Oct  1 10:32:54 2010
 New Revision: 213323
 URL: http://svn.freebsd.org/changeset/base/213323
 
 Log:
   i386 and amd64 mp_machdep: improve topology detection for Intel CPUs
   
   This patch is significantly based on previous work by jkim.
   List of changes:
   - added comments that describe topology uniformity assumption
   - added reference to Intel Processor Topology Enumeration article
   - documented a few global variables that describe topology
   - retired weirdly set and used logical_cpus variable
   - changed fallback code for mp_ncpus > 0 case, so that CPUs are treated
     as being different packages rather than cores in a single package
   - moved AMD-specific code to topo_probe_amd [jkim]
   - in topo_probe_0x4() follow Intel-prescribed procedure of deriving SMT
     and core masks and match APIC IDs against those masks [started by
     jkim]
   - in topo_probe_0x4() drop code for double-checking topology parameters
     by looking at L1 cache properties [jkim]
   - in topo_probe_0xb() add fallback path to topo_probe_0x4() as
     prescribed by Intel [jkim]
   
   Still to do:
   - prepare for upcoming AMD CPUs by using new mechanism of uniform
     topology description [pointed by jkim]
   - probe cache topology in addition to CPU topology and probably use that
     for scheduler affinity topology; e.g. Core2 Duo and Athlon II X2 have
     the same CPU topology, but Athlon cores do not share L2 cache while
     Core2's do (no L3 cache in both cases)
   - think of supporting non-uniform topologies if they are ever
     implemented for platforms in question
   - think how to better described old HTT vs new HTT distinction, HTT vs
     SMT can be confusing as SMT is a generic term
   - more robust code for marking CPUs as "logical" and/or "hyperthreaded",
     use HTT mask instead of modulo operation
   - correct support for halting logical and/or hyperthreaded CPUs, let
     scheduler know that it shouldn't schedule any threads on those CPUs
   
   PR:			kern/145385 (related)
   In collaboration with:	jkim
   Tested by:		Sergey Kandaurov <pluknet at gmail.com>,
   			Jeremy Chadwick <freebsd at jdc.parodius.com>,
   			Chip Camden <sterling at camdensoftware.com>,
   			Steve Wills <steve at mouf.net>,
   			Olivier Smedts <olivier at gid0.org>,
   			Florian Smeets <flo at smeets.im>
   MFC after:		1 month
 
 Modified:
   head/sys/amd64/amd64/mp_machdep.c
   head/sys/i386/i386/mp_machdep.c
 
 Modified: head/sys/amd64/amd64/mp_machdep.c
 ==============================================================================
 --- head/sys/amd64/amd64/mp_machdep.c	Fri Oct  1 09:34:41 2010	(r213322)
 +++ head/sys/amd64/amd64/mp_machdep.c	Fri Oct  1 10:32:54 2010	(r213323)
 @@ -126,7 +126,6 @@ extern inthand_t IDTVEC(fast_syscall), I
   * Local data and functions.
   */
  
 -static u_int logical_cpus;
  static volatile cpumask_t ipi_nmi_pending;
  
  /* used to hold the AP's until we are ready to release them */
 @@ -152,8 +151,8 @@ int apic_cpuids[MAX_APIC_ID + 1];
  static volatile u_int cpu_ipi_pending[MAXCPU];
  
  static u_int boot_address;
 -static int cpu_logical;
 -static int cpu_cores;
 +static int cpu_logical;			/* logical cpus per core */
 +static int cpu_cores;			/* cores per package */
  
  static void	assign_cpu_ids(void);
  static void	set_interrupt_apic_ids(void);
 @@ -162,7 +161,7 @@ static int	start_ap(int apic_id);
  static void	release_aps(void *dummy);
  
  static int	hlt_logical_cpus;
 -static u_int	hyperthreading_cpus;
 +static u_int	hyperthreading_cpus;	/* logical cpus sharing L1 cache */
  static cpumask_t	hyperthreading_cpus_mask;
  static int	hyperthreading_allowed = 1;
  static struct	sysctl_ctx_list logical_cpu_clist;
 @@ -176,24 +175,105 @@ mem_range_AP_init(void)
  }
  
  static void
 +topo_probe_amd(void)
 +{
 +
 +	/* AMD processors do not support HTT. */
 +	cpu_cores = (amd_feature2 & AMDID2_CMP) != 0 ?
 +	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
 +	cpu_logical = 1;
 +}
 +
 +/*
 + * Round up to the next power of two, if necessary, and then
 + * take log2.
 + * Returns -1 if argument is zero.
 + */
 +static __inline int
 +mask_width(u_int x)
 +{
 +
 +	return (fls(x << (1 - powerof2(x))) - 1);
 +}
 +
 +static void
 +topo_probe_0x4(void)
 +{
 +	u_int p[4];
 +	int pkg_id_bits;
 +	int core_id_bits;
 +	int max_cores;
 +	int max_logical;
 +	int id;
 +
 +	/* Both zero and one here mean one logical processor per package. */
 +	max_logical = (cpu_feature & CPUID_HTT) != 0 ?
 +	    (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1;
 +	if (max_logical <= 1)
 +		return;
 +
 +	/*
 +	 * Because of uniformity assumption we examine only
 +	 * those logical processors that belong to the same
 +	 * package as BSP.  Further, we count number of
 +	 * logical processors that belong to the same core
 +	 * as BSP thus deducing number of threads per core.
 +	 */
 +	cpuid_count(0x04, 0, p);
 +	max_cores = ((p[0] >> 26) & 0x3f) + 1;
 +	core_id_bits = mask_width(max_logical/max_cores);
 +	if (core_id_bits < 0)
 +		return;
 +	pkg_id_bits = core_id_bits + mask_width(max_cores);
 +
 +	for (id = 0; id <= MAX_APIC_ID; id++) {
 +		/* Check logical CPU availability. */
 +		if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
 +			continue;
 +		/* Check if logical CPU has the same package ID. */
 +		if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits))
 +			continue;
 +		cpu_cores++;
 +		/* Check if logical CPU has the same package and core IDs. */
 +		if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits))
 +			cpu_logical++;
 +	}
 +
 +	cpu_cores /= cpu_logical;
 +	hyperthreading_cpus = cpu_logical;
 +}
 +
 +static void
  topo_probe_0xb(void)
  {
 -	int logical;
 -	int p[4];
 +	u_int p[4];
  	int bits;
 -	int type;
  	int cnt;
  	int i;
 +	int logical;
 +	int type;
  	int x;
  
 -	/* We only support two levels for now. */
 +	/* We only support three levels for now. */
  	for (i = 0; i < 3; i++) {
 -		cpuid_count(0x0B, i, p);
 +		cpuid_count(0x0b, i, p);
 +
 +		/* Fall back if CPU leaf 11 doesn't really exist. */
 +		if (i == 0 && p[1] == 0) {
 +			topo_probe_0x4();
 +			return;
 +		}
 +
  		bits = p[0] & 0x1f;
  		logical = p[1] &= 0xffff;
  		type = (p[2] >> 8) & 0xff;
  		if (type == 0 || logical == 0)
  			break;
 +		/*
 +		 * Because of uniformity assumption we examine only
 +		 * those logical processors that belong to the same
 +		 * package as BSP.
 +		 */
  		for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
  			if (!cpu_info[x].cpu_present ||
  			    cpu_info[x].cpu_disabled)
 @@ -211,76 +291,16 @@ topo_probe_0xb(void)
  	cpu_cores /= cpu_logical;
  }
  
 -static void
 -topo_probe_0x4(void)
 -{
 -	u_int threads_per_cache, p[4];
 -	u_int htt, cmp;
 -	int i;
 -
 -	htt = cmp = 1;
 -	/*
 -	 * If this CPU supports HTT or CMP then mention the
 -	 * number of physical/logical cores it contains.
 -	 */
 -	if (cpu_feature & CPUID_HTT)
 -		htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
 -	if (cpu_vendor_id == CPU_VENDOR_AMD && (amd_feature2 & AMDID2_CMP))
 -		cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1;
 -	else if (cpu_vendor_id == CPU_VENDOR_INTEL && (cpu_high >= 4)) {
 -		cpuid_count(4, 0, p);
 -		if ((p[0] & 0x1f) != 0)
 -			cmp = ((p[0] >> 26) & 0x3f) + 1;
 -	}
 -	cpu_cores = cmp;
 -	cpu_logical = htt / cmp;
 -
 -	/* Setup the initial logical CPUs info. */
 -	if (cpu_feature & CPUID_HTT)
 -		logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
 -
 -	/*
 -	 * Work out if hyperthreading is *really* enabled.  This
 -	 * is made really ugly by the fact that processors lie: Dual
 -	 * core processors claim to be hyperthreaded even when they're
 -	 * not, presumably because they want to be treated the same
 -	 * way as HTT with respect to per-cpu software licensing.
 -	 * At the time of writing (May 12, 2005) the only hyperthreaded
 -	 * cpus are from Intel, and Intel's dual-core processors can be
 -	 * identified via the "deterministic cache parameters" cpuid
 -	 * calls.
 -	 */
 -	/*
 -	 * First determine if this is an Intel processor which claims
 -	 * to have hyperthreading support.
 -	 */
 -	if ((cpu_feature & CPUID_HTT) && cpu_vendor_id == CPU_VENDOR_INTEL) {
 -		/*
 -		 * If the "deterministic cache parameters" cpuid calls
 -		 * are available, use them.
 -		 */
 -		if (cpu_high >= 4) {
 -			/* Ask the processor about the L1 cache. */
 -			for (i = 0; i < 1; i++) {
 -				cpuid_count(4, i, p);
 -				threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1;
 -				if (hyperthreading_cpus < threads_per_cache)
 -					hyperthreading_cpus = threads_per_cache;
 -				if ((p[0] & 0x1f) == 0)
 -					break;
 -			}
 -		}
 -
 -		/*
 -		 * If the deterministic cache parameters are not
 -		 * available, or if no caches were reported to exist,
 -		 * just accept what the HTT flag indicated.
 -		 */
 -		if (hyperthreading_cpus == 0)
 -			hyperthreading_cpus = logical_cpus;
 -	}
 -}
 -
 +/*
 + * Both topology discovery code and code that consumes topology
 + * information assume top-down uniformity of the topology.
 + * That is, all physical packages must be identical and each
 + * core in a package must have the same number of threads.
 + * Topology information is queried only on BSP, on which this
 + * code runs and for which it can query CPUID information.
 + * Then topology is extrapolated on all packages using the
 + * uniformity assumption.
 + */
  static void
  topo_probe(void)
  {
 @@ -289,13 +309,31 @@ topo_probe(void)
  	if (cpu_topo_probed)
  		return;
  
 -	logical_cpus = logical_cpus_mask = 0;
 -	if (cpu_high >= 0xb)
 -		topo_probe_0xb();
 -	else if (cpu_high)
 -		topo_probe_0x4();
 +	logical_cpus_mask = 0;
 +	if (cpu_vendor_id == CPU_VENDOR_AMD)
 +		topo_probe_amd();
 +	else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
 +		/*
 +		 * See Intel(R) 64 Architecture Processor
 +		 * Topology Enumeration article for details.
 +		 *
 +		 * Note that 0x1 <= cpu_high < 4 case should be
 +		 * compatible with topo_probe_0x4() logic when
 +		 * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
 +		 * or it should trigger the fallback otherwise.
 +		 */
 +		if (cpu_high >= 0xb)
 +			topo_probe_0xb();
 +		else if (cpu_high >= 0x1)
 +			topo_probe_0x4();
 +	}
 +
 +	/*
 +	 * Fallback: assume each logical CPU is in separate
 +	 * physical package.  That is, no multi-core, no SMT.
 +	 */
  	if (cpu_cores == 0)
 -		cpu_cores = mp_ncpus > 0 ? mp_ncpus : 1;
 +		cpu_cores = 1;
  	if (cpu_logical == 0)
  		cpu_logical = 1;
  	cpu_topo_probed = 1;
 @@ -675,7 +713,8 @@ init_secondary(void)
  	printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid));
  
  	/* Determine if we are a logical CPU. */
 -	if (logical_cpus > 1 && PCPU_GET(apic_id) % logical_cpus != 0)
 +	/* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */
 +	if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0)
  		logical_cpus_mask |= PCPU_GET(cpumask);
  	
  	/* Determine if we are a hyperthread. */
 
 Modified: head/sys/i386/i386/mp_machdep.c
 ==============================================================================
 --- head/sys/i386/i386/mp_machdep.c	Fri Oct  1 09:34:41 2010	(r213322)
 +++ head/sys/i386/i386/mp_machdep.c	Fri Oct  1 10:32:54 2010	(r213323)
 @@ -173,7 +173,6 @@ static u_long *ipi_hardclock_counts[MAXC
   * Local data and functions.
   */
  
 -static u_int logical_cpus;
  static volatile cpumask_t ipi_nmi_pending;
  
  /* used to hold the AP's until we are ready to release them */
 @@ -199,8 +198,8 @@ int apic_cpuids[MAX_APIC_ID + 1];
  static volatile u_int cpu_ipi_pending[MAXCPU];
  
  static u_int boot_address;
 -static int cpu_logical;
 -static int cpu_cores;
 +static int cpu_logical;			/* logical cpus per core */
 +static int cpu_cores;			/* cores per package */
  
  static void	assign_cpu_ids(void);
  static void	install_ap_tramp(void);
 @@ -210,7 +209,7 @@ static int	start_ap(int apic_id);
  static void	release_aps(void *dummy);
  
  static int	hlt_logical_cpus;
 -static u_int	hyperthreading_cpus;
 +static u_int	hyperthreading_cpus;	/* logical cpus sharing L1 cache */
  static cpumask_t	hyperthreading_cpus_mask;
  static int	hyperthreading_allowed = 1;
  static struct	sysctl_ctx_list logical_cpu_clist;
 @@ -223,24 +222,105 @@ mem_range_AP_init(void)
  }
  
  static void
 +topo_probe_amd(void)
 +{
 +
 +	/* AMD processors do not support HTT. */
 +	cpu_cores = (amd_feature2 & AMDID2_CMP) != 0 ?
 +	    (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1;
 +	cpu_logical = 1;
 +}
 +
 +/*
 + * Round up to the next power of two, if necessary, and then
 + * take log2.
 + * Returns -1 if argument is zero.
 + */
 +static __inline int
 +mask_width(u_int x)
 +{
 +
 +	return (fls(x << (1 - powerof2(x))) - 1);
 +}
 +
 +static void
 +topo_probe_0x4(void)
 +{
 +	u_int p[4];
 +	int pkg_id_bits;
 +	int core_id_bits;
 +	int max_cores;
 +	int max_logical;
 +	int id;
 +
 +	/* Both zero and one here mean one logical processor per package. */
 +	max_logical = (cpu_feature & CPUID_HTT) != 0 ?
 +	    (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1;
 +	if (max_logical <= 1)
 +		return;
 +
 +	/*
 +	 * Because of uniformity assumption we examine only
 +	 * those logical processors that belong to the same
 +	 * package as BSP.  Further, we count number of
 +	 * logical processors that belong to the same core
 +	 * as BSP thus deducing number of threads per core.
 +	 */
 +	cpuid_count(0x04, 0, p);
 +	max_cores = ((p[0] >> 26) & 0x3f) + 1;
 +	core_id_bits = mask_width(max_logical/max_cores);
 +	if (core_id_bits < 0)
 +		return;
 +	pkg_id_bits = core_id_bits + mask_width(max_cores);
 +
 +	for (id = 0; id <= MAX_APIC_ID; id++) {
 +		/* Check logical CPU availability. */
 +		if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
 +			continue;
 +		/* Check if logical CPU has the same package ID. */
 +		if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits))
 +			continue;
 +		cpu_cores++;
 +		/* Check if logical CPU has the same package and core IDs. */
 +		if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits))
 +			cpu_logical++;
 +	}
 +
 +	cpu_cores /= cpu_logical;
 +	hyperthreading_cpus = cpu_logical;
 +}
 +
 +static void
  topo_probe_0xb(void)
  {
 -	int logical;
 -	int p[4];
 +	u_int p[4];
  	int bits;
 -	int type;
  	int cnt;
  	int i;
 +	int logical;
 +	int type;
  	int x;
  
 -	/* We only support two levels for now. */
 +	/* We only support three levels for now. */
  	for (i = 0; i < 3; i++) {
 -		cpuid_count(0x0B, i, p);
 +		cpuid_count(0x0b, i, p);
 +
 +		/* Fall back if CPU leaf 11 doesn't really exist. */
 +		if (i == 0 && p[1] == 0) {
 +			topo_probe_0x4();
 +			return;
 +		}
 +
  		bits = p[0] & 0x1f;
  		logical = p[1] &= 0xffff;
  		type = (p[2] >> 8) & 0xff;
  		if (type == 0 || logical == 0)
  			break;
 +		/*
 +		 * Because of uniformity assumption we examine only
 +		 * those logical processors that belong to the same
 +		 * package as BSP.
 +		 */
  		for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
  			if (!cpu_info[x].cpu_present ||
  			    cpu_info[x].cpu_disabled)
 @@ -258,76 +338,16 @@ topo_probe_0xb(void)
  	cpu_cores /= cpu_logical;
  }
  
 -static void
 -topo_probe_0x4(void)
 -{
 -	u_int threads_per_cache, p[4];
 -	u_int htt, cmp;
 -	int i;
 -
 -	htt = cmp = 1;
 -	/*
 -	 * If this CPU supports HTT or CMP then mention the
 -	 * number of physical/logical cores it contains.
 -	 */
 -	if (cpu_feature & CPUID_HTT)
 -		htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
 -	if (cpu_vendor_id == CPU_VENDOR_AMD && (amd_feature2 & AMDID2_CMP))
 -		cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1;
 -	else if (cpu_vendor_id == CPU_VENDOR_INTEL && (cpu_high >= 4)) {
 -		cpuid_count(4, 0, p);
 -		if ((p[0] & 0x1f) != 0)
 -			cmp = ((p[0] >> 26) & 0x3f) + 1;
 -	}
 -	cpu_cores = cmp;
 -	cpu_logical = htt / cmp;
 -
 -	/* Setup the initial logical CPUs info. */
 -	if (cpu_feature & CPUID_HTT)
 -		logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16;
 -
 -	/*
 -	 * Work out if hyperthreading is *really* enabled.  This
 -	 * is made really ugly by the fact that processors lie: Dual
 -	 * core processors claim to be hyperthreaded even when they're
 -	 * not, presumably because they want to be treated the same
 -	 * way as HTT with respect to per-cpu software licensing.
 -	 * At the time of writing (May 12, 2005) the only hyperthreaded
 -	 * cpus are from Intel, and Intel's dual-core processors can be
 -	 * identified via the "deterministic cache parameters" cpuid
 -	 * calls.
 -	 */
 -	/*
 -	 * First determine if this is an Intel processor which claims
 -	 * to have hyperthreading support.
 -	 */
 -	if ((cpu_feature & CPUID_HTT) && cpu_vendor_id == CPU_VENDOR_INTEL) {
 -		/*
 -		 * If the "deterministic cache parameters" cpuid calls
 -		 * are available, use them.
 -		 */
 -		if (cpu_high >= 4) {
 -			/* Ask the processor about the L1 cache. */
 -			for (i = 0; i < 1; i++) {
 -				cpuid_count(4, i, p);
 -				threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1;
 -				if (hyperthreading_cpus < threads_per_cache)
 -					hyperthreading_cpus = threads_per_cache;
 -				if ((p[0] & 0x1f) == 0)
 -					break;
 -			}
 -		}
 -
 -		/*
 -		 * If the deterministic cache parameters are not
 -		 * available, or if no caches were reported to exist,
 -		 * just accept what the HTT flag indicated.
 -		 */
 -		if (hyperthreading_cpus == 0)
 -			hyperthreading_cpus = logical_cpus;
 -	}
 -}
 -
 +/*
 + * Both topology discovery code and code that consumes topology
 + * information assume top-down uniformity of the topology.
 + * That is, all physical packages must be identical and each
 + * core in a package must have the same number of threads.
 + * Topology information is queried only on BSP, on which this
 + * code runs and for which it can query CPUID information.
 + * Then topology is extrapolated on all packages using the
 + * uniformity assumption.
 + */
  static void
  topo_probe(void)
  {
 @@ -336,13 +356,31 @@ topo_probe(void)
  	if (cpu_topo_probed)
  		return;
  
 -	logical_cpus = logical_cpus_mask = 0;
 -	if (cpu_high >= 0xb)
 -		topo_probe_0xb();
 -	else if (cpu_high)
 -		topo_probe_0x4();
 +	logical_cpus_mask = 0;
 +	if (cpu_vendor_id == CPU_VENDOR_AMD)
 +		topo_probe_amd();
 +	else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
 +		/*
 +		 * See Intel(R) 64 Architecture Processor
 +		 * Topology Enumeration article for details.
 +		 *
 +		 * Note that 0x1 <= cpu_high < 4 case should be
 +		 * compatible with topo_probe_0x4() logic when
 +		 * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
 +		 * or it should trigger the fallback otherwise.
 +		 */
 +		if (cpu_high >= 0xb)
 +			topo_probe_0xb();
 +		else if (cpu_high >= 0x1)
 +			topo_probe_0x4();
 +	}
 +
 +	/*
 +	 * Fallback: assume each logical CPU is in separate
 +	 * physical package.  That is, no multi-core, no SMT.
 +	 */
  	if (cpu_cores == 0)
 -		cpu_cores = mp_ncpus > 0 ? mp_ncpus : 1;
 +		cpu_cores = 1;
  	if (cpu_logical == 0)
  		cpu_logical = 1;
  	cpu_topo_probed = 1;
 @@ -706,7 +744,8 @@ init_secondary(void)
  	printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid));
  
  	/* Determine if we are a logical CPU. */
 -	if (logical_cpus > 1 && PCPU_GET(apic_id) % logical_cpus != 0)
 +	/* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */
 +	if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0)
  		logical_cpus_mask |= PCPU_GET(cpumask);
  	
  	/* Determine if we are a hyperthread. */
 _______________________________________________
 svn-src-all at freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
 


More information about the freebsd-bugs mailing list