diff mbox

xen/mm: Fix page_list_* helpers to evaluate all their arguments

Message ID 1457196754-6299-1-git-send-email-andrew.cooper3@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Cooper March 5, 2016, 4:52 p.m. UTC
If an architecture does not provide a custom page_list_entry, default
page_list_* helpers are provided, wrapping list_head as an underlying type for
page_list_head.

The two declarations of the page_list_* helpers differ between defines and
static inline functions, where the defines discard some of their parameters.

This causes a compilation failure if CONFIG_BIGMEM and debug=n in p2m-pod.c:

  p2m-pod.c: In function ‘p2m_pod_cache_add’:
  p2m-pod.c:72:20: error: unused variable ‘d’ [-Werror=unused-variable]
       struct domain *d = p2m->domain;
                      ^
  cc1: all warnings being treated as errors

because the use of d outside of the !NDEBUG section doesn't get evaluated as a
parameter by page_list_del().

Fix this by turning all #defines into static inline functions, so all
parameters are evaluated even if they are not used.

Doing this reveals that const-correctness of page_list_{next,prev}() is
suspect, taking a const pointer and returning a non-const one.  It is left
functioning as it did before, with an explicit typecast to remove constness.

While editing this area, correct the return type of page_list_empty from int
to bool_t.

Reported-by: Doug Goldstein <cardoe@cardoe.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Tim Deegan <tim@xen.org>
CC: George Dunlap <george.dunlap@eu.citrix.com>
---
 xen/include/xen/mm.h | 95 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 74 insertions(+), 21 deletions(-)

Comments

Douglas Goldstein March 5, 2016, 11:42 p.m. UTC | #1
On 3/5/16 10:52 AM, Andrew Cooper wrote:
> If an architecture does not provide a custom page_list_entry, default
> page_list_* helpers are provided, wrapping list_head as an underlying type for
> page_list_head.
> 
> The two declarations of the page_list_* helpers differ between defines and
> static inline functions, where the defines discard some of their parameters.
> 
> This causes a compilation failure if CONFIG_BIGMEM and debug=n in p2m-pod.c:
> 
>   p2m-pod.c: In function ‘p2m_pod_cache_add’:
>   p2m-pod.c:72:20: error: unused variable ‘d’ [-Werror=unused-variable]
>        struct domain *d = p2m->domain;
>                       ^
>   cc1: all warnings being treated as errors
> 
> because the use of d outside of the !NDEBUG section doesn't get evaluated as a
> parameter by page_list_del().
> 
> Fix this by turning all #defines into static inline functions, so all
> parameters are evaluated even if they are not used.
> 
> Doing this reveals that const-correctness of page_list_{next,prev}() is
> suspect, taking a const pointer and returning a non-const one.  It is left
> functioning as it did before, with an explicit typecast to remove constness.
> 
> While editing this area, correct the return type of page_list_empty from int
> to bool_t.
> 
> Reported-by: Doug Goldstein <cardoe@cardoe.com>
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Reviewed-by: Doug Goldstein <cardoe@cardoe.com>

I had planned on doing something similar but your commit message is much
better than what I would have come up with.

Not sure if people would like Identified-by: Travis CI but it actually
required a patch to be found.
http://lists.xen.org/archives/html/xen-devel/2016-03/msg00735.html which
is waiting to be merged.
Jan Beulich March 7, 2016, 1:15 p.m. UTC | #2
>>> On 05.03.16 at 17:52, <andrew.cooper3@citrix.com> wrote:
> Doing this reveals that const-correctness of page_list_{next,prev}() is
> suspect, taking a const pointer and returning a non-const one.  It is left
> functioning as it did before, with an explicit typecast to remove constness.

I don't see anything suspect here: Retrieving the next or prev list
element doesn't alter the current one, so the input pointer can
legitimately be const, while the output one obviously shouldn't be.
Or else why don't you similarly consider page_list_{first,last}()
bogus in that same respect?

> +static inline bool_t
> +page_list_empty(const struct page_list_head *head)
> +{
> +    return list_empty(head);
> +}

While I appreciate the conversion to bool_t, to be fully correct you
either need to use !! here, or switch list_empty() to bool_t too.

> +static inline struct page_info *
> +page_list_first(const struct page_list_head *head)
> +{
> +    return list_first_entry(head, struct page_info, list);
> +}
> +static inline struct page_info *
> +page_list_last(const struct page_list_head *head)
> +{
> +    return list_last_entry(head, struct page_info, list);
> +}
> +static inline struct page_info *
> +page_list_next(const struct page_info *page,
> +               const struct page_list_head *head)
> +{
> +    return list_next_entry((struct page_info *)page, list);
> +}
> +static inline struct page_info *
> +page_list_prev(const struct page_info *page,
> +               const struct page_list_head *head)
> +{
> +    return list_prev_entry((struct page_info *)page, list);
> +}

I'd suggest to avoid the explicit casts, by using
list_entry(page->list.next, struct page_info, list) and
list_entry(page->list.prev, struct page_info, list) respectively.

Jan
diff mbox

Patch

diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index a795dd6..38e12b7 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -220,7 +220,7 @@  struct page_list_head
 # define INIT_PAGE_LIST_HEAD(head) ((head)->tail = (head)->next = NULL)
 # define INIT_PAGE_LIST_ENTRY(ent) ((ent)->prev = (ent)->next = PAGE_LIST_NULL)
 
-static inline int
+static inline bool_t
 page_list_empty(const struct page_list_head *head)
 {
     return !head->next;
@@ -392,31 +392,84 @@  page_list_splice(struct page_list_head *list, struct page_list_head *head)
 # define PAGE_LIST_HEAD                  LIST_HEAD
 # define INIT_PAGE_LIST_HEAD             INIT_LIST_HEAD
 # define INIT_PAGE_LIST_ENTRY            INIT_LIST_HEAD
-# define page_list_empty                 list_empty
-# define page_list_first(hd)             \
-    list_first_entry(hd, struct page_info, list)
-# define page_list_last(hd)              \
-    list_last_entry(hd, struct page_info, list)
-# define page_list_next(pg, hd)          list_next_entry(pg, list)
-# define page_list_prev(pg, hd)          list_prev_entry(pg, list)
-# define page_list_add(pg, hd)           list_add(&(pg)->list, hd)
-# define page_list_add_tail(pg, hd)      list_add_tail(&(pg)->list, hd)
-# define page_list_del(pg, hd)           list_del(&(pg)->list)
-# define page_list_del2(pg, hd1, hd2)    list_del(&(pg)->list)
-# define page_list_remove_head(hd)       (!page_list_empty(hd) ? \
-    ({ \
-        struct page_info *__pg = page_list_first(hd); \
-        list_del(&__pg->list); \
-        __pg; \
-    }) : NULL)
-# define page_list_move(dst, src)        (!list_empty(src) ? \
-    list_replace_init(src, dst) : (void)0)
+
+static inline bool_t
+page_list_empty(const struct page_list_head *head)
+{
+    return list_empty(head);
+}
+static inline struct page_info *
+page_list_first(const struct page_list_head *head)
+{
+    return list_first_entry(head, struct page_info, list);
+}
+static inline struct page_info *
+page_list_last(const struct page_list_head *head)
+{
+    return list_last_entry(head, struct page_info, list);
+}
+static inline struct page_info *
+page_list_next(const struct page_info *page,
+               const struct page_list_head *head)
+{
+    return list_next_entry((struct page_info *)page, list);
+}
+static inline struct page_info *
+page_list_prev(const struct page_info *page,
+               const struct page_list_head *head)
+{
+    return list_prev_entry((struct page_info *)page, list);
+}
+static inline void
+page_list_add(struct page_info *page, struct page_list_head *head)
+{
+    list_add(&page->list, head);
+}
+static inline void
+page_list_add_tail(struct page_info *page, struct page_list_head *head)
+{
+    list_add_tail(&page->list, head);
+}
+static inline void
+page_list_del(struct page_info *page, struct page_list_head *head)
+{
+    list_del(&page->list);
+}
+static inline void
+page_list_del2(struct page_info *page, struct page_list_head *head1,
+               struct page_list_head *head2)
+{
+    list_del(&page->list);
+}
+static inline struct page_info *
+page_list_remove_head(struct page_list_head *head)
+{
+    struct page_info *pg;
+
+    if ( page_list_empty(head) )
+        return NULL;
+
+    pg = page_list_first(head);
+    list_del(&pg->list);
+    return pg;
+}
+static inline void
+page_list_move(struct page_list_head *dst, struct page_list_head *src)
+{
+    if ( !list_empty(src) )
+        list_replace_init(src, dst);
+}
+static inline void
+page_list_splice(struct page_list_head *list, struct page_list_head *head)
+{
+    list_splice(list, head);
+}
+
 # define page_list_for_each(pos, head)   list_for_each_entry(pos, head, list)
 # define page_list_for_each_safe(pos, tmp, head) \
     list_for_each_entry_safe(pos, tmp, head, list)
 # define page_list_for_each_safe_reverse(pos, tmp, head) \
     list_for_each_entry_safe_reverse(pos, tmp, head, list)
-# define page_list_splice(list, hd)        list_splice(list, hd)
 #endif
 
 static inline unsigned int get_order_from_bytes(paddr_t size)