[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v2 1/3] x86/viridian: Re-purpose the HVM parameter to be a feature mask



On 04/08/14 14:12, Paul Durrant wrote:
> The following commits introduced the time reference counter MSR and
> TSC/APIC frequency MSRs into the viridian feature set respectively:
>
> e36cd2cdc9674a7a4855d21fb7b3e6e17c4bb33b
> 84657efd9116f40924aa13c9d5a349e007da716f
>
> The time reference counter MSR feature was then reverted by commit
>
> 1cd4fab14ce25859efa4a2af13475e6650a5506c
>
> because a flaw in the implementation meant the counter was reset on
> migration.
>
> All of these changes were made without any addtional options being
> added to the VM configuration, or any compatibility checks being made
> in the domain save/restore code. Hence setting the single boolean
> 'viridian' option in the VM configuration yields a different set of
> features depending on which version of Xen the VM is started on, and the
> feature set can change across migration (so new MSRs can magically appear).
>
> This patch grandfathers in the current viridian features set and calls them
> the 'base' plus 'freq' feature set. HVM_PARAM_VIRIDIAN is re-purposed as
> a feature mask. It has only ever been legally set to 0 or 1, so the presence
> of the base set and freq set are indicated by setting bit 0. The 'freq' set
> can then be turned off by setting bit 1, thus restoring the pre-Xen-4.4
> 'base' set. Newly implemented viridian features can be optionally enabled
> in future by setting further bits.
>
> The viridian option in xl.cfg(5) has also been changed to a string list so
> that the sets can be individually sepcified. For compatibility, if the
> option is specified as a boolean, then a true (1) value will be translated
> to a string list containing "base" and "freq".
>
> This patch also alters the allowed write accesses to HVM_PARAM_VIRIDIAN.
> Currently there is nothing to stop the guest writing this value (which,
> while harmless to anything else, should not happen) and nothing to
> stop a toolstack from setting the value back to zero whilst the guest is
> running, causing CPUID leaves to disappear and MSR accesses to start
> causing GPFs in the guest. Both of these possibilities are now disallowed:
> Once the parameter is set to a non-zero value it may not be cleared, and
> guests no longer have any write access.
>
> Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
> Cc: Keir Fraser <keir@xxxxxxx>
> Cc: Jan Beulich <jbeulich@xxxxxxxx>
> Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
> Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> Cc: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
> ---
>  docs/man/xl.cfg.pod.5           |   53 
> ++++++++++++++++++++++++++++++---------
>  tools/libxc/xc_domain_restore.c |    4 +--
>  tools/libxl/libxl.h             |    6 +++++
>  tools/libxl/libxl_create.c      |    1 -
>  tools/libxl/libxl_dom.c         |   46 ++++++++++++++++++++++++++-------
>  tools/libxl/libxl_types.idl     |    2 +-
>  tools/libxl/xl_cmdimpl.c        |   24 +++++++++++++++++-
>  tools/libxl/xl_sxp.c            |    8 ++++--
>  xen/arch/x86/hvm/hvm.c          |   18 +++++++++++--
>  xen/arch/x86/hvm/viridian.c     |   21 ++++++++++++++--
>  xen/include/asm-x86/hvm/hvm.h   |    7 ++++--
>  xen/include/public/hvm/params.h |   33 +++++++++++++++++++++++-
>  12 files changed, 188 insertions(+), 35 deletions(-)
>
> diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
> index ff9ea77..a05e831 100644
> --- a/docs/man/xl.cfg.pod.5
> +++ b/docs/man/xl.cfg.pod.5
> @@ -1084,18 +1084,47 @@ Windows L<http://wiki.xen.org/wiki/XenWindowsGplPv>.
>  Setting B<xen_platform_pci=0> with the default device_model "qemu-xen"
>  requires at least QEMU 1.6.
>  
> -=item B<viridian=BOOLEAN>
> -
> -Turns on or off the exposure of MicroSoft Hyper-V (AKA viridian)
> -compatible enlightenments to the guest.  These can improve performance
> -of Microsoft Windows guests from Windows Vista and Windows 2008
> -onwards and setting this option for such guests is strongly
> -recommended. This option should be harmless for other versions of
> -Windows (although it will not give any benefit) and the majority of
> -other non-Windows OSes. However it is known to be incompatible with
> -some other Operating Systems and in some circumstance can prevent
> -Xen's own paravirtualisation interfaces for HVM guests from being
> -used.
> +=item B<viridian=[ "SET", "SET", ...]>
> +
> +The sets of Microsoft Hyper-V (AKA viridian) compatible enlightenments
> +exposed to the guest. The following sets of enlightenments may be
> +specified:
> +
> +=over 4
> +
> +=item B<base>
> +
> +This set incorporates the Hypercall MSRs, Virtual processor index MSR,
> +and APIC access MSRs. This set is a pre-requisite for all other sets.
> +If it is not specified then all enlightenments will be disabled.
> +
> +These enlightenments can improve performance of Windows Vista and Windows
> +Server 2008 onwards and setting this option for such guests is strongly
> +recommended.
> +
> +=item B<freq>
> +
> +This set incorporates the TSC and APIC frequency MSRs.
> +
> +This enlightenment can improve performance of Windows 7 and Windows
> +Server 2008 R2 onwards.
> +
> +=back
> + 
> +See the latest version of Microsoft's Hypervisor Top-Level Functional
> +Specification for more details.
> +
> +The enlightenments should be harmless for other versions of Windows
> +(although they will not give any benefit) and the majority of other
> +non-Windows OSes.
> +However it is known that they are incompatible with some other Operating
> +Systems and in some circumstance can prevent Xen's own paravirtualisation
> +interfaces for HVM guests from being used.
> +
> +Specifying the viridian option as a boolean is deprecated. However, for
> +backwards compatibility, if it is specified as a boolean a value of
> +true (1) will cause both the 'base' and 'freq' sets to be exposed to
> +the guest, and a value of false (0) will disable all enlightenments.
>  
>  =back
>  
> diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c
> index e73e0a2..5e7e62d 100644
> --- a/tools/libxc/xc_domain_restore.c
> +++ b/tools/libxc/xc_domain_restore.c
> @@ -922,7 +922,7 @@ static int pagebuf_get_one(xc_interface *xch, struct 
> restore_ctx *ctx,
>          if ( RDEXACT(fd, &buf->viridian, sizeof(uint32_t)) ||
>               RDEXACT(fd, &buf->viridian, sizeof(uint64_t)) )
>          {
> -            PERROR("error read the viridian flag");
> +            PERROR("error read the viridian flags");
>              return -1;
>          }
>          return pagebuf_get_one(xch, ctx, buf, fd, dom);
> @@ -1733,7 +1733,7 @@ int xc_domain_restore(xc_interface *xch, int io_fd, 
> uint32_t dom,
>      }
>  
>      if (pagebuf.viridian != 0)
> -        xc_hvm_param_set(xch, dom, HVM_PARAM_VIRIDIAN, 1);
> +        xc_hvm_param_set(xch, dom, HVM_PARAM_VIRIDIAN, pagebuf.viridian);
>  
>      /*
>       * If we are migrating in from a host that does not support
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index 5ae6532..b985f49 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -128,6 +128,12 @@
>  #define LIBXL_HAVE_LIBXL_DEVICE_DISK_DISCARD_ENABLE 1
>  
>  /*
> + * The libxl_domain_build_info u.hvm.viridian field is a string list
> + */
> +#define LIBXL_HAVE_BUILDINFO_HVM_VIRIDIAN_STRING_LIST 1
> +
> +
> +/*
>   * libxl ABI compatibility
>   *
>   * The only guarantee which libxl makes regarding ABI compatibility
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index 0686f96..ee19fc8 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -273,7 +273,6 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
>          libxl_defbool_setdefault(&b_info->u.hvm.acpi_s3,            true);
>          libxl_defbool_setdefault(&b_info->u.hvm.acpi_s4,            true);
>          libxl_defbool_setdefault(&b_info->u.hvm.nx,                 true);
> -        libxl_defbool_setdefault(&b_info->u.hvm.viridian,           false);
>          libxl_defbool_setdefault(&b_info->u.hvm.hpet,               true);
>          libxl_defbool_setdefault(&b_info->u.hvm.vpt_align,          true);
>          libxl_defbool_setdefault(&b_info->u.hvm.nested_hvm,         false);
> diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
> index 83eb29a..a15c185 100644
> --- a/tools/libxl/libxl_dom.c
> +++ b/tools/libxl/libxl_dom.c
> @@ -209,21 +209,49 @@ static unsigned long timer_mode(const 
> libxl_domain_build_info *info)
>      return ((unsigned long)mode);
>  }
>  
> -static void hvm_set_conf_params(xc_interface *handle, uint32_t domid,
> +#if defined(__i386__) || defined(__x86_64__)
> +static void hvm_set_viridian_features(libxl__gc *gc, uint32_t domid,
> +                                      libxl_domain_build_info *const info)
> +{
> +    uint64_t feature_mask = HVMPV_no_freq;
> +
> +    char **p = info->u.hvm.viridian;
> +    while (*p) {       
> +        LOG(DETAIL, "+%s", *p);
> +        if (strcmp(*p, "base") == 0)
> +            feature_mask |= HVMPV_base_freq;
> +        else if (strcmp(*p, "freq") == 0)
> +            feature_mask &= ~HVMPV_no_freq;
> +        p++;
> +    }
> +
> +    if (xc_hvm_param_set(CTX->xch,
> +                         domid,
> +                         HVM_PARAM_VIRIDIAN,
> +                         feature_mask) != 0)
> +        LIBXL__LOG_ERRNO(CTX, LIBXL__LOG_WARNING,
> +                         "Couldn't set viridian feature mask (0x%lx)",

PRIx64, or this will break 32bit builds.

> +                         feature_mask);
> +}
> +#endif
> +
> +static void hvm_set_conf_params(libxl__gc *gc, uint32_t domid,
>                                  libxl_domain_build_info *const info)

const libxl_domain_build_info *info ?

>  {
> -    xc_hvm_param_set(handle, domid, HVM_PARAM_PAE_ENABLED,
> +    xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_PAE_ENABLED,
>                      libxl_defbool_val(info->u.hvm.pae));
>  #if defined(__i386__) || defined(__x86_64__)
> -    xc_hvm_param_set(handle, domid, HVM_PARAM_VIRIDIAN,
> -                    libxl_defbool_val(info->u.hvm.viridian));
> -    xc_hvm_param_set(handle, domid, HVM_PARAM_HPET_ENABLED,
> +    if (libxl_string_list_length(&info->u.hvm.viridian) != 0)
> +        hvm_set_viridian_features(gc, domid, info);
> +
> +    xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_HPET_ENABLED,
>                      libxl_defbool_val(info->u.hvm.hpet));
>  #endif
> -    xc_hvm_param_set(handle, domid, HVM_PARAM_TIMER_MODE, timer_mode(info));
> -    xc_hvm_param_set(handle, domid, HVM_PARAM_VPT_ALIGN,
> +    xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_TIMER_MODE,
> +                     timer_mode(info));
> +    xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_VPT_ALIGN,
>                      libxl_defbool_val(info->u.hvm.vpt_align));
> -    xc_hvm_param_set(handle, domid, HVM_PARAM_NESTEDHVM,
> +    xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_NESTEDHVM,
>                      libxl_defbool_val(info->u.hvm.nested_hvm));
>  }
>  
> @@ -306,7 +334,7 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
>      state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 
> state->console_domid);
>  
>      if (info->type == LIBXL_DOMAIN_TYPE_HVM)
> -        hvm_set_conf_params(ctx->xch, domid, info);
> +        hvm_set_conf_params(gc, domid, info);
>  
>      rc = libxl__arch_domain_create(gc, d_config, domid);
>  
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index a412f9c..6c5d7e0 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -363,7 +363,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
>                                         ("acpi_s3",          libxl_defbool),
>                                         ("acpi_s4",          libxl_defbool),
>                                         ("nx",               libxl_defbool),
> -                                       ("viridian",         libxl_defbool),
> +                                       ("viridian",         
> libxl_string_list),
>                                         ("timeoffset",       string),
>                                         ("hpet",             libxl_defbool),
>                                         ("vpt_align",        libxl_defbool),
> diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
> index 01bce2f..960f626 100644
> --- a/tools/libxl/xl_cmdimpl.c
> +++ b/tools/libxl/xl_cmdimpl.c
> @@ -951,10 +951,32 @@ static void parse_config_data(const char *config_source,
>          xlu_cfg_get_defbool(config, "acpi_s3", &b_info->u.hvm.acpi_s3, 0);
>          xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0);
>          xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0);
> -        xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 0);
>          xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0);
>          xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 
> 0);
>  
> +        switch (xlu_cfg_get_list_as_string_list(config, "viridian",
> +                                                &b_info->u.hvm.viridian, 1))
> +        {
> +        case 0: break; /* Success */
> +        case ESRCH: break; /* Option not present */
> +        case EINVAL: {
> +            libxl_defbool b;
> +
> +            xlu_cfg_get_defbool(config, "viridian", &b, 1);
> +            if (libxl_defbool_val(b)) {
> +                fprintf(stderr, "WARNING: Specifying \"viridian\""
> +                        " as a boolean is deprecated. "
> +                        "Please use a list of features.\n");
> +                split_string_into_string_list("base freq", " \n",
> +                                              &b_info->u.hvm.viridian);
> +            }
> +            break;
> +        }
> +        default:
> +            fprintf(stderr,"xl: Unable to parse bootloader_args.\n");
> +            exit(-ERROR_FAIL);
> +        }
> +
>          if (!xlu_cfg_get_long(config, "timer_mode", &l, 1)) {
>              const char *s = libxl_timer_mode_to_string(l);
>              fprintf(stderr, "WARNING: specifying \"timer_mode\" as an 
> integer is deprecated. "
> diff --git a/tools/libxl/xl_sxp.c b/tools/libxl/xl_sxp.c
> index 48eb608..347526f 100644
> --- a/tools/libxl/xl_sxp.c
> +++ b/tools/libxl/xl_sxp.c
> @@ -97,8 +97,12 @@ void printf_info_sexp(int domid, libxl_domain_config 
> *d_config)
>          printf("\t\t\t(acpi %s)\n",
>                 libxl_defbool_to_string(b_info->u.hvm.acpi));
>          printf("\t\t\t(nx %s)\n", libxl_defbool_to_string(b_info->u.hvm.nx));
> -        printf("\t\t\t(viridian %s)\n",
> -               libxl_defbool_to_string(b_info->u.hvm.viridian));
> +        if (b_info->u.hvm.viridian) {
> +            printf("\t\t\t(viridian");
> +            for (i=0; b_info->u.hvm.viridian[i]; i++)
> +                printf(" %s", b_info->u.hvm.viridian[i]);
> +            printf(")\n");
> +        }
>          printf("\t\t\t(hpet %s)\n",
>                 libxl_defbool_to_string(b_info->u.hvm.hpet));
>          printf("\t\t\t(vpt_align %s)\n",
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index fba13e0..04d43d0 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -5533,8 +5533,22 @@ long do_hvm_op(unsigned long op, 
> XEN_GUEST_HANDLE_PARAM(void) arg)
>                      rc = -EINVAL;
>                  break;
>              case HVM_PARAM_VIRIDIAN:
> -                if ( a.value > 1 )
> -                    rc = -EINVAL;
> +                /* This should only ever be set once by the tools and read 
> by the guest. */
> +                rc = -EPERM;
> +                if ( curr_d == d )
> +                    break;
> +
> +                rc = -EPERM;
> +                if ( d->arch.hvm_domain.params[a.index] &&
> +                     a.value != d->arch.hvm_domain.params[a.index] )
> +                    break;

Setting it twice should be an error, even if it is set to the same value
again.  Also, EEXIST would be a better error.

> +                
> +                rc = -EINVAL;
> +                if ( a.value & ~HVMPV_feature_mask ||
> +                     !(a.value & HVMPV_base_freq) )
> +                    break;
> +
> +                rc = 0;

To save bloating the code here if/when new combinations are introduced,
would it be better to have a "rc = viridian_initialise(d, a.value);"
which validates the featureset and sets it if necessary.  The above
EEXISTs check could be included as well.

>                  break;
>              case HVM_PARAM_IDENT_PT:
>                  /* Not reflexive, as we must domain_pause(). */
> diff --git a/xen/arch/x86/hvm/viridian.c b/xen/arch/x86/hvm/viridian.c
> index 0fcbfd8..31c9656 100644
> --- a/xen/arch/x86/hvm/viridian.c
> +++ b/xen/arch/x86/hvm/viridian.c
> @@ -90,8 +90,9 @@ int cpuid_viridian_leaves(unsigned int leaf, unsigned int 
> *eax,
>          /* Which hypervisor MSRs are available to the guest */
>          *eax = (CPUID3A_MSR_APIC_ACCESS |
>                  CPUID3A_MSR_HYPERCALL   |
> -                CPUID3A_MSR_VP_INDEX    |
> -                CPUID3A_MSR_FREQ);
> +                CPUID3A_MSR_VP_INDEX);
> +        if ( !(viridian_feature_mask(d) & HVMPV_no_freq) )
> +            *eax |= CPUID3A_MSR_FREQ;
>          break;
>      case 4:
>          /* Recommended hypercall usage. */
> @@ -312,11 +313,17 @@ int rdmsr_viridian_regs(uint32_t idx, uint64_t *val)
>          break;
>  
>      case VIRIDIAN_MSR_TSC_FREQUENCY:
> +        if ( viridian_feature_mask(d) & HVMPV_no_freq )
> +            return 0;
> +
>          perfc_incr(mshv_rdmsr_tsc_frequency);
>          *val = (uint64_t)d->arch.tsc_khz * 1000ull;
>          break;
>  
>      case VIRIDIAN_MSR_APIC_FREQUENCY:
> +        if ( viridian_feature_mask(d) & HVMPV_no_freq )
> +            return 0;
> +
>          perfc_incr(mshv_rdmsr_apic_frequency);
>          *val = 1000000000ull / APIC_BUS_CYCLE_NS;
>          break;
> @@ -489,3 +496,13 @@ static int viridian_load_vcpu_ctxt(struct domain *d, 
> hvm_domain_context_t *h)
>  
>  HVM_REGISTER_SAVE_RESTORE(VIRIDIAN_VCPU, viridian_save_vcpu_ctxt,
>                            viridian_load_vcpu_ctxt, 1, HVMSR_PER_VCPU);
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
> index 0ebd478..24e513b 100644
> --- a/xen/include/asm-x86/hvm/hvm.h
> +++ b/xen/include/asm-x86/hvm/hvm.h
> @@ -344,8 +344,11 @@ static inline unsigned long 
> hvm_get_shadow_gs_base(struct vcpu *v)
>      return hvm_funcs.get_shadow_gs_base(v);
>  }
>  
> -#define is_viridian_domain(_d)                                             \
> - (is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN]))
> +#define viridian_feature_mask(d) \
> +    ((d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN])
> +
> +#define is_viridian_domain(d) \
> +    (is_hvm_domain(d) && (viridian_feature_mask(d) & HVMPV_base_freq))
>  
>  void hvm_hypervisor_cpuid_leaf(uint32_t sub_idx,
>                                 uint32_t *eax, uint32_t *ebx,
> diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
> index 614ff5f..68d26fd 100644
> --- a/xen/include/public/hvm/params.h
> +++ b/xen/include/public/hvm/params.h
> @@ -56,9 +56,40 @@
>  
>  #if defined(__i386__) || defined(__x86_64__)
>  
> -/* Expose Viridian interfaces to this HVM guest? */
> +/*
> + * Viridian enlightenments
> + *
> + * (See 
> http://download.microsoft.com/download/A/B/4/AB43A34E-BDD0-4FA6-BDEF-79EEF16E880B/Hypervisor%20Top%20Level%20Functional%20Specification%20v4.0.docx)
> + *
> + * To expose viridian enlightenments to the guest set this parameter
> + * to the desired feature mask. The base feature set must be present
> + * in any valid feature mask.
> + */
>  #define HVM_PARAM_VIRIDIAN     9
>  
> +/* Base+Freq viridian feature sets:
> + *
> + * - Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL)
> + * - APIC access MSRs (HV_X64_MSR_EOI, HV_X64_MSR_ICR and HV_X64_MSR_TPR)
> + * - Virtual Processor index MSR (HV_X64_MSR_VP_INDEX)
> + * - Timer frequency MSRs (HV_X64_MSR_TSC_FREQUENCY and
> + *   HV_X64_MSR_APIC_FREQUENCY)
> + */
> +#define _HVMPV_base_freq 0
> +#define HVMPV_base_freq  (1 << _HVMPV_base_freq)
> +
> +/* Feature set modifications */
> +
> +/* Disable timer frequency MSRs (HV_X64_MSR_TSC_FREQUENCY and
> + * HV_X64_MSR_APIC_FREQUENCY).
> + * This modification restores the viridian feature set to the
> + * original 'base' set exposed in releases prior to Xen 4.4.
> + */
> +#define _HVMPV_no_freq 1
> +#define HVMPV_no_freq  (1 << _HVMPV_no_freq)
> +
> +#define HVMPV_feature_mask (HVMPV_base_freq|HVMPV_no_freq)

Please could we avoid introducing new negated-sense booleans, especially
when their predominant use is "if ( !$FOO_no_BAR )"

~Andrew

> +
>  #endif
>  
>  /*


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.