]> xenbits.xensource.com Git - xen.git/commitdiff
xen/sched: Improvements to the {alloc,free}_domdata() interfaces
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 27 Feb 2018 16:48:19 +0000 (16:48 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 7 Mar 2018 16:00:37 +0000 (16:00 +0000)
The main purpose of this change is for the subsequent cleanup it enables, but
it stands on its own merits.

In principle, these hooks are optional, but the SCHED_OP() default aliases a
memory allocation failure, which causes arinc653 to play the dangerous game of
passing its priv pointer back, and remembering not to actually free it.

Redefine alloc_domdata to use ERR_PTR() for errors, NULL for nothing, and
non-NULL for a real allocation, which allows the hook to become properly
optional.  Redefine free_domdata to be idempotent.

For arinc653, this means the dummy hooks can be dropped entirely.  For the
other schedulers, this means returning ERR_PTR(-ENOMEM) instead of NULL for
memory allocation failures, and modifying the free hooks to cope with a NULL
pointer.  While making the alterations, drop some spurious casts to void *.

Introduce and use proper wrappers for sched_{alloc,free}_domdata().  These are
strictly better than SCHED_OP(), as the source code is visible to
grep/cscope/tags, the generated code is better, and there can be proper
per-hook defaults and checks.

Callers of the alloc hooks are switched to using IS_ERR(), rather than
checking for NULL.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
Acked-by: Meng Xu <mengxu@cis.upenn.edu>
Reviewed-by: Dario Faggioli <dfaggioli@suse.com>
xen/common/sched_arinc653.c
xen/common/sched_credit.c
xen/common/sched_credit2.c
xen/common/sched_null.c
xen/common/sched_rt.c
xen/common/schedule.c
xen/include/xen/sched-if.h

index 982845b550f94dd5bc0868097222f6f5509af583..17e765d2cb677c2381847be2612e24c28c7c74b9 100644 (file)
@@ -454,34 +454,6 @@ a653sched_free_vdata(const struct scheduler *ops, void *priv)
     update_schedule_vcpus(ops);
 }
 
-/**
- * This function allocates scheduler-specific data for a domain
- *
- * We do not actually make use of any per-domain data but the hypervisor
- * expects a non-NULL return value
- *
- * @param ops       Pointer to this instance of the scheduler structure
- *
- * @return          Pointer to the allocated data
- */
-static void *
-a653sched_alloc_domdata(const struct scheduler *ops, struct domain *dom)
-{
-    /* return a non-NULL value to keep schedule.c happy */
-    return SCHED_PRIV(ops);
-}
-
-/**
- * This function frees scheduler-specific data for a domain
- *
- * @param ops       Pointer to this instance of the scheduler structure
- */
-static void
-a653sched_free_domdata(const struct scheduler *ops, void *data)
-{
-    /* nop */
-}
-
 /**
  * Xen scheduler callback function to sleep a VCPU
  *
@@ -740,9 +712,6 @@ static const struct scheduler sched_arinc653_def = {
     .free_vdata     = a653sched_free_vdata,
     .alloc_vdata    = a653sched_alloc_vdata,
 
-    .free_domdata   = a653sched_free_domdata,
-    .alloc_domdata  = a653sched_alloc_domdata,
-
     .init_domain    = NULL,
     .destroy_domain = NULL,
 
index a2c5d43e335ce4ca7d645bbee8a0247dbb6abf41..d9ae23dee3e329a9d21fcb6a8e7c6c9369c52636 100644 (file)
@@ -1281,7 +1281,7 @@ csched_alloc_domdata(const struct scheduler *ops, struct domain *dom)
 
     sdom = xzalloc(struct csched_dom);
     if ( sdom == NULL )
-        return NULL;
+        return ERR_PTR(-ENOMEM);
 
     /* Initialize credit and weight */
     INIT_LIST_HEAD(&sdom->active_vcpu);
@@ -1289,7 +1289,7 @@ csched_alloc_domdata(const struct scheduler *ops, struct domain *dom)
     sdom->dom = dom;
     sdom->weight = CSCHED_DEFAULT_WEIGHT;
 
-    return (void *)sdom;
+    return sdom;
 }
 
 static int
@@ -1301,8 +1301,8 @@ csched_dom_init(const struct scheduler *ops, struct domain *dom)
         return 0;
 
     sdom = csched_alloc_domdata(ops, dom);
-    if ( sdom == NULL )
-        return -ENOMEM;
+    if ( IS_ERR(sdom) )
+        return PTR_ERR(sdom);
 
     dom->sched_priv = sdom;
 
index b094b3c2bee474f5198c433fcdbd492305b96164..29a24d6cb60b17b5eae3aac3a10580f2b1aa7d8c 100644 (file)
@@ -3012,7 +3012,7 @@ csched2_alloc_domdata(const struct scheduler *ops, struct domain *dom)
 
     sdom = xzalloc(struct csched2_dom);
     if ( sdom == NULL )
-        return NULL;
+        return ERR_PTR(-ENOMEM);
 
     /* Initialize credit, cap and weight */
     INIT_LIST_HEAD(&sdom->sdom_elem);
@@ -3032,7 +3032,7 @@ csched2_alloc_domdata(const struct scheduler *ops, struct domain *dom)
 
     write_unlock_irqrestore(&prv->lock, flags);
 
-    return (void *)sdom;
+    return sdom;
 }
 
 static int
@@ -3044,8 +3044,8 @@ csched2_dom_init(const struct scheduler *ops, struct domain *dom)
         return 0;
 
     sdom = csched2_alloc_domdata(ops, dom);
-    if ( sdom == NULL )
-        return -ENOMEM;
+    if ( IS_ERR(sdom) )
+        return PTR_ERR(sdom);
 
     dom->sched_priv = sdom;
 
@@ -3055,19 +3055,21 @@ csched2_dom_init(const struct scheduler *ops, struct domain *dom)
 static void
 csched2_free_domdata(const struct scheduler *ops, void *data)
 {
-    unsigned long flags;
     struct csched2_dom *sdom = data;
     struct csched2_private *prv = csched2_priv(ops);
 
-    kill_timer(&sdom->repl_timer);
-
-    write_lock_irqsave(&prv->lock, flags);
+    if ( sdom )
+    {
+        unsigned long flags;
 
-    list_del_init(&sdom->sdom_elem);
+        kill_timer(&sdom->repl_timer);
 
-    write_unlock_irqrestore(&prv->lock, flags);
+        write_lock_irqsave(&prv->lock, flags);
+        list_del_init(&sdom->sdom_elem);
+        write_unlock_irqrestore(&prv->lock, flags);
 
-    xfree(data);
+        xfree(sdom);
+    }
 }
 
 static void
index b4a24baf8e62c3d37a731f65a87939b54e32b762..4dd405b2e5c3d540062d8925b58c9c70c89b4f0d 100644 (file)
@@ -231,7 +231,7 @@ static void * null_alloc_domdata(const struct scheduler *ops,
 
     ndom = xzalloc(struct null_dom);
     if ( ndom == NULL )
-        return NULL;
+        return ERR_PTR(-ENOMEM);
 
     ndom->dom = d;
 
@@ -239,20 +239,24 @@ static void * null_alloc_domdata(const struct scheduler *ops,
     list_add_tail(&ndom->ndom_elem, &null_priv(ops)->ndom);
     spin_unlock_irqrestore(&prv->lock, flags);
 
-    return (void*)ndom;
+    return ndom;
 }
 
 static void null_free_domdata(const struct scheduler *ops, void *data)
 {
-    unsigned long flags;
     struct null_dom *ndom = data;
     struct null_private *prv = null_priv(ops);
 
-    spin_lock_irqsave(&prv->lock, flags);
-    list_del_init(&ndom->ndom_elem);
-    spin_unlock_irqrestore(&prv->lock, flags);
+    if ( ndom )
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave(&prv->lock, flags);
+        list_del_init(&ndom->ndom_elem);
+        spin_unlock_irqrestore(&prv->lock, flags);
 
-    xfree(data);
+        xfree(ndom);
+    }
 }
 
 static int null_dom_init(const struct scheduler *ops, struct domain *d)
@@ -263,8 +267,8 @@ static int null_dom_init(const struct scheduler *ops, struct domain *d)
         return 0;
 
     ndom = null_alloc_domdata(ops, d);
-    if ( ndom == NULL )
-        return -ENOMEM;
+    if ( IS_ERR(ndom) )
+        return PTR_ERR(ndom);
 
     d->sched_priv = ndom;
 
index a20280235edb2a522539dee003acba942a3bb0ea..e4ff5c19c979e16fb229dec53afcc64ce4b1b03c 100644 (file)
@@ -820,7 +820,7 @@ rt_alloc_domdata(const struct scheduler *ops, struct domain *dom)
 
     sdom = xzalloc(struct rt_dom);
     if ( sdom == NULL )
-        return NULL;
+        return ERR_PTR(-ENOMEM);
 
     INIT_LIST_HEAD(&sdom->sdom_elem);
     sdom->dom = dom;
@@ -836,14 +836,19 @@ rt_alloc_domdata(const struct scheduler *ops, struct domain *dom)
 static void
 rt_free_domdata(const struct scheduler *ops, void *data)
 {
-    unsigned long flags;
     struct rt_dom *sdom = data;
     struct rt_private *prv = rt_priv(ops);
 
-    spin_lock_irqsave(&prv->lock, flags);
-    list_del_init(&sdom->sdom_elem);
-    spin_unlock_irqrestore(&prv->lock, flags);
-    xfree(data);
+    if ( sdom )
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave(&prv->lock, flags);
+        list_del_init(&sdom->sdom_elem);
+        spin_unlock_irqrestore(&prv->lock, flags);
+
+        xfree(sdom);
+    }
 }
 
 static int
@@ -856,8 +861,8 @@ rt_dom_init(const struct scheduler *ops, struct domain *dom)
         return 0;
 
     sdom = rt_alloc_domdata(ops, dom);
-    if ( sdom == NULL )
-        return -ENOMEM;
+    if ( IS_ERR(sdom) )
+        return PTR_ERR(sdom);
 
     dom->sched_priv = sdom;
 
index b7884263f258c0b1030c8bdd0eadf576ee3c3065..08a31b69de7b30c1b316462d7fd7fe9823cee266 100644 (file)
@@ -318,14 +318,14 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
             return -EBUSY;
     }
 
-    domdata = SCHED_OP(c->sched, alloc_domdata, d);
-    if ( domdata == NULL )
-        return -ENOMEM;
+    domdata = sched_alloc_domdata(c->sched, d);
+    if ( IS_ERR(domdata) )
+        return PTR_ERR(domdata);
 
     vcpu_priv = xzalloc_array(void *, d->max_vcpus);
     if ( vcpu_priv == NULL )
     {
-        SCHED_OP(c->sched, free_domdata, domdata);
+        sched_free_domdata(c->sched, domdata);
         return -ENOMEM;
     }
 
@@ -337,7 +337,7 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
             for_each_vcpu ( d, v )
                 xfree(vcpu_priv[v->vcpu_id]);
             xfree(vcpu_priv);
-            SCHED_OP(c->sched, free_domdata, domdata);
+            sched_free_domdata(c->sched, domdata);
             return -ENOMEM;
         }
     }
@@ -393,7 +393,7 @@ int sched_move_domain(struct domain *d, struct cpupool *c)
 
     domain_unpause(d);
 
-    SCHED_OP(old_ops, free_domdata, old_domdata);
+    sched_free_domdata(old_ops, old_domdata);
 
     xfree(vcpu_priv);
 
index c4a493587a4b9ec443f68c9a6d71b1b0dc6cb31d..56e7d0c2b2116cccb0196bcc7e48666e8005eafa 100644 (file)
@@ -146,8 +146,11 @@ struct scheduler {
     void *       (*alloc_pdata)    (const struct scheduler *, int);
     void         (*init_pdata)     (const struct scheduler *, void *, int);
     void         (*deinit_pdata)   (const struct scheduler *, void *, int);
-    void         (*free_domdata)   (const struct scheduler *, void *);
+
+    /* Returns ERR_PTR(-err) for error, NULL for 'nothing needed'. */
     void *       (*alloc_domdata)  (const struct scheduler *, struct domain *);
+    /* Idempotent. */
+    void         (*free_domdata)   (const struct scheduler *, void *);
 
     void         (*switch_sched)   (struct scheduler *, unsigned int,
                                     void *, void *);
@@ -181,6 +184,28 @@ struct scheduler {
     void         (*tick_resume)     (const struct scheduler *, unsigned int);
 };
 
+static inline void *sched_alloc_domdata(const struct scheduler *s,
+                                        struct domain *d)
+{
+    if ( s->alloc_domdata )
+        return s->alloc_domdata(s, d);
+    else
+        return NULL;
+}
+
+static inline void sched_free_domdata(const struct scheduler *s,
+                                      void *data)
+{
+    if ( s->free_domdata )
+        s->free_domdata(s, data);
+    else
+        /*
+         * Check that if there isn't a free_domdata hook, we haven't got any
+         * data we're expected to deal with.
+         */
+        ASSERT(!data);
+}
+
 #define REGISTER_SCHEDULER(x) static const struct scheduler *x##_entry \
   __used_section(".data.schedulers") = &x;