On Fri, May 22, 2020 at 10:51 AM Kyle Evans <kev...@freebsd.org> wrote:
>
> On Fri, May 22, 2020 at 4:17 AM Wei Hu <w...@freebsd.org> wrote:
> >
> > Author: whu
> > Date: Fri May 22 09:17:07 2020
> > New Revision: 361360
> > URL: https://svnweb.freebsd.org/changeset/base/361360
> >
> > Log:
> >   Socket AF_HYPERV should return failure when it is not running on HyperV
> >
> > [... snip ...]
> > @@ -354,6 +354,9 @@ hvs_trans_attach(struct socket *so, int proto, struct
> >  {
> >         struct hvs_pcb *pcb = so2hvspcb(so);
> >
> > +       if (vm_guest != VM_GUEST_HV)
> > +               return (ESOCKTNOSUPPORT);
> > +
> >         HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
> >             "%s: HyperV Socket hvs_trans_attach called\n", __func__);
> >
>
> This one may be OK, but none of these other methods should be able to
> be invoked if the attach failed. See this comment at around
> ^/sys/kern/uipc_socket.c#50:
>
> 50 * pru_detach() disassociates protocol layer state from an attached socket,
> 51 * and will be called exactly once for sockets in which pru_attach() has
> 52 * been successfully called.  If pru_attach() returned an error,
> 53 * pru_detach() will not be called.  Socket layer private.
>
> That said, I wonder if VNET_DOMAIN_SET provides the correct semantics
> here at all. You can't fail domain_init, but I don't think there's any
> value in this domain actually getting registered on non-HyperV guests,
> a fact which presumably won't change at runtime.
>

I'm considering the patch below, which is almost certainly going to be
mangled by my mail client, for solving this style of problem. It gives
the domain a chance to probe the system and opt out, for cases like
hvsock where leaving the domain around and fully-initialized when
there's no way it can work is both wasteful and a bit of an accident
waiting to happen -- IMO it's much less error prone and more
comforting if we just reject it early on, since we can. The vm_guest
detection and hyperv's false-positive aversion stuff in hyperv_init
should run much earlier than this.

diff --git a/sys/dev/hyperv/hvsock/hv_sock.c b/sys/dev/hyperv/hvsock/hv_sock.c
index d212c2d8c2d..d3bc1ab0f2c 100644
--- a/sys/dev/hyperv/hvsock/hv_sock.c
+++ b/sys/dev/hyperv/hvsock/hv_sock.c
@@ -74,6 +74,8 @@ SYSCTL_INT(_net_hvsock, OID_AUTO, hvs_dbg_level,
CTLFLAG_RWTUN, &hvs_dbg_level,

 MALLOC_DEFINE(M_HVSOCK, "hyperv_socket", "hyperv socket control structures");

+static int hvs_dom_probe(void);
+
 /* The MTU is 16KB per host side's design */
 #define HVSOCK_MTU_SIZE                (1024 * 16)
 #define HVSOCK_SEND_BUF_SZ     (PAGE_SIZE - sizeof(struct vmpipe_proto_header))
@@ -124,6 +126,7 @@ static struct protosw               hv_socket_protosw[] = {
 static struct domain           hv_socket_domain = {
        .dom_family =           AF_HYPERV,
        .dom_name =             "hyperv",
+       .dom_probe =            hvs_dom_probe,
        .dom_protosw =          hv_socket_protosw,
        .dom_protoswNPROTOSW =  &hv_socket_protosw[nitems(hv_socket_protosw)]
 };
@@ -322,6 +325,16 @@ hvs_trans_unlock(void)
        sx_xunlock(&hvs_trans_socks_sx);
 }

+static int
+hvs_dom_probe(void)
+{
+
+       /* Don't even give us a chance to attach on non-HyperV. */
+       if (vm_guest != VM_GUEST_HV)
+               return (ENXIO);
+       return (0);
+}
+
 void
 hvs_trans_init(void)
 {
@@ -329,9 +342,6 @@ hvs_trans_init(void)
        if (!IS_DEFAULT_VNET(curvnet))
                return;

-       if (vm_guest != VM_GUEST_HV)
-               return;
-
        HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
            "%s: HyperV Socket hvs_trans_init called\n", __func__);

@@ -354,9 +364,6 @@ hvs_trans_attach(struct socket *so, int proto,
struct thread *td)
 {
        struct hvs_pcb *pcb = so2hvspcb(so);

-       if (vm_guest != VM_GUEST_HV)
-               return (ESOCKTNOSUPPORT);
-
        HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
            "%s: HyperV Socket hvs_trans_attach called\n", __func__);

@@ -383,9 +390,6 @@ hvs_trans_detach(struct socket *so)
 {
        struct hvs_pcb *pcb;

-       if (vm_guest != VM_GUEST_HV)
-               return;
-
        HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
            "%s: HyperV Socket hvs_trans_detach called\n", __func__);

@@ -595,9 +599,6 @@ hvs_trans_disconnect(struct socket *so)
 {
        struct hvs_pcb *pcb;

-       if (vm_guest != VM_GUEST_HV)
-               return (ESOCKTNOSUPPORT);
-
        HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
            "%s: HyperV Socket hvs_trans_disconnect called\n", __func__);

@@ -925,9 +926,6 @@ hvs_trans_close(struct socket *so)
 {
        struct hvs_pcb *pcb;

-       if (vm_guest != VM_GUEST_HV)
-               return;
-
        HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
            "%s: HyperV Socket hvs_trans_close called\n", __func__);

@@ -969,9 +967,6 @@ hvs_trans_abort(struct socket *so)
 {
        struct hvs_pcb *pcb = so2hvspcb(so);

-       if (vm_guest != VM_GUEST_HV)
-               return;
-
        HVSOCK_DBG(HVSOCK_DBG_VERBOSE,
            "%s: HyperV Socket hvs_trans_abort called\n", __func__);

diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index 60e30eb1ae0..63217566ba9 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -170,9 +170,13 @@ protosw_init(struct protosw *pr)
 void
 domain_init(void *arg)
 {
-       struct domain *dp = arg;
+       struct domain_set_args *dsa = arg;
+       struct domain *dp;
        struct protosw *pr;

+       if (!dsa->dsa_supported)
+               return;
+       dp = dsa->dsa_dp;
        if (dp->dom_init)
                (*dp->dom_init)();
        for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
@@ -198,8 +202,12 @@ vnet_domain_init(void *arg)
 void
 vnet_domain_uninit(void *arg)
 {
-       struct domain *dp = arg;
+       struct domain_set_args *dsa = arg;
+       struct domain *dp;

+       if (!dsa->dsa_supported)
+               return;
+       dp = dsa->dsa_dp;
        if (dp->dom_destroy)
                (*dp->dom_destroy)();
 }
@@ -213,9 +221,14 @@ vnet_domain_uninit(void *arg)
 void
 domain_add(void *data)
 {
+       struct domain_set_args *dsa;
        struct domain *dp;

-       dp = (struct domain *)data;
+       dsa = data;
+       dp = dsa->dsa_dp;
+       if (dp->dom_probe != NULL && (*dp->dom_probe)() != 0)
+               return;
+       dsa->dsa_supported = 1;
        mtx_lock(&dom_mtx);
        dp->dom_next = domains;
        domains = dp;
diff --git a/sys/sys/domain.h b/sys/sys/domain.h
index e83dd0f4afc..11211f072c2 100644
--- a/sys/sys/domain.h
+++ b/sys/sys/domain.h
@@ -49,6 +49,7 @@ struct        socket;
 struct domain {
        int     dom_family;             /* AF_xxx */
        char    *dom_name;
+       int     (*dom_probe)(void);     /* check for support (optional) */
        void    (*dom_init)             /* initialize domain data structures */
                (void);
        void    (*dom_destroy)          /* cleanup structures / state */
@@ -79,20 +80,36 @@ void                vnet_domain_init(void *);
 void           vnet_domain_uninit(void *);
 #endif

+struct domain_set_args {
+       struct domain   *dsa_dp;
+       int              dsa_supported;
+};
+
 #define        DOMAIN_SET(name)
         \
+       static struct domain_set_args name ## domain_set_args = {       \
+               .dsa_dp = & name ## domain,                             \
+       };                                                              \
        SYSINIT(domain_add_ ## name, SI_SUB_PROTO_DOMAIN,               \
-           SI_ORDER_FIRST, domain_add, & name ## domain);              \
+           SI_ORDER_FIRST, domain_add, &name ## domain_set_args);      \
        SYSINIT(domain_init_ ## name, SI_SUB_PROTO_DOMAIN,              \
-           SI_ORDER_SECOND, domain_init, & name ## domain);
+           SI_ORDER_SECOND, domain_init, &name ## domain_set_args);
 #ifdef VIMAGE
+/*
+ * There's no such thing as per-vnet domains, so domain_set_args don't really
+ * need to be virtualized at the moment.  Further consideration would be needed
+ * for such a concept to work at all.
+ */
 #define        VNET_DOMAIN_SET(name)
         \
+       static struct domain_set_args name ## domain_set_args = {       \
+               .dsa_dp = & name ## domain,                             \
+       };                                                              \
        SYSINIT(domain_add_ ## name, SI_SUB_PROTO_DOMAIN,               \
-           SI_ORDER_FIRST, domain_add, & name ## domain);              \
+           SI_ORDER_FIRST, domain_add, &name ## domain_set_args);      \
        VNET_SYSINIT(vnet_domain_init_ ## name, SI_SUB_PROTO_DOMAIN,    \
-           SI_ORDER_SECOND, vnet_domain_init, & name ## domain);       \
+           SI_ORDER_SECOND, vnet_domain_init, &name ## domain_set_args); \
        VNET_SYSUNINIT(vnet_domain_uninit_ ## name,                     \
            SI_SUB_PROTO_DOMAIN, SI_ORDER_SECOND, vnet_domain_uninit,   \
-           & name ## domain)
+           &name ## domain_set_args);
 #else /* !VIMAGE */
 #define        VNET_DOMAIN_SET(name)   DOMAIN_SET(name)
 #endif /* VIMAGE */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to