lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20100224201509.GB21067@Krystal>
Date:	Wed, 24 Feb 2010 15:15:09 -0500
From:	Mathieu Desnoyers <mathieu.desnoyers@...icios.com>
To:	Arnd Bergmann <arnd@...db.de>
Cc:	paulmck@...ux.vnet.ibm.com, linux-kernel@...r.kernel.org,
	mingo@...e.hu, laijs@...fujitsu.com, dipankar@...ibm.com,
	akpm@...ux-foundation.org, josh@...htriplett.org,
	dvhltc@...ibm.com, niv@...ibm.com, tglx@...utronix.de,
	peterz@...radead.org, rostedt@...dmis.org, Valdis.Kletnieks@...edu,
	dhowells@...hat.com
Subject: Re: [PATCH 02/10] rcu: annotated list rcu code

* Arnd Bergmann (arnd@...db.de) wrote:
> The listrcu implementation now defines new rcu_list_head,
> rcu_hlist_head and rcu_hlist_entry structures that are
> annotated with __rcu. Only these can now be passed into
> rcu_list_for_each and related interfaces.
> 
> When not running sparse, the types are defined to the
> original list_head etc in order to not break working
> setups that are lacking annotation.

Hrm, wait.. dumb question: how can an annotation break compilation ? If there is
any way out of this, I would prefer if we can do without a #ifdef __CHECKER__ if
possible. It calls for bugs and implementation mismatch.

Thanks,

Mathieu

> 
> Signed-off-by: Arnd Bergmann <arnd@...db.de>
> ---
>  include/linux/rculist.h |  152 ++++++++++++++++++++++++++++++++++------------
>  1 files changed, 112 insertions(+), 40 deletions(-)
> 
> diff --git a/include/linux/rculist.h b/include/linux/rculist.h
> index 1bf0f70..dfbc6ea 100644
> --- a/include/linux/rculist.h
> +++ b/include/linux/rculist.h
> @@ -9,16 +9,67 @@
>  #include <linux/list.h>
>  #include <linux/rcupdate.h>
>  
> +#ifdef __CHECKER__
> +struct rcu_list_head {
> +	struct rcu_list_head __rcu *next;
> +	struct rcu_list_head *prev;
> +};
> +#define LIST_HEAD_INIT_RCU(name) { (struct rcu_list_head __force __rcu *)&(name), &(name) }
> +
> +#define LIST_HEAD_RCU(name) \
> +	struct rcu_list_head name = LIST_HEAD_INIT_RCU(name)
> +
> +static inline void INIT_LIST_HEAD_RCU(struct rcu_list_head *list)
> +{
> +	__rcu_assign_pointer(list->next, list);
> +	list->prev = list;
> +}
> +
> +struct rcu_hlist_head {
> +	struct rcu_hlist_node __rcu *first;
> +};
> +
> +struct rcu_hlist_node {
> +	struct rcu_hlist_node __rcu *next, **pprev;
> +};
> +
> +#define HLIST_HEAD_INIT_RCU { .first = (void __rcu __force *)NULL }
> +#define HLIST_HEAD_RCU(name) struct rcu_hlist_head name = \
> +		{  .first = (void __rcu __force *)NULL }
> +#define INIT_HLIST_HEAD_RCU(ptr) ((ptr)->first = (void __rcu __force *)NULL)
> +static inline void INIT_HLIST_NODE_RCU(struct rcu_hlist_node *h)
> +{
> +	__rcu_assign_pointer(h->next, NULL);
> +	h->pprev = NULL;
> +}
> +
> +#else /* !__CHECKER__ */
> +
> +#define rcu_list_head list_head
> +#define LIST_HEAD_INIT_RCU LIST_HEAD_INIT
> +#define LIST_HEAD_RCU LIST_HEAD
> +#define INIT_LIST_HEAD_RCU INIT_LIST_HEAD
> +
> +#define rcu_hlist_head hlist_head
> +#define rcu_hlist_node hlist_node
> +#define HLIST_HEAD_INIT_RCU HLIST_HEAD_INIT
> +#define HLIST_HEAD_RCU HLIST_HEAD
> +#define INIT_HLIST_HEAD_RCU INIT_HLIST_HEAD
> +#define INIT_HLIST_NODE_RCU INIT_HLIST_NODE
> +
> +#endif /* !__CHECKER__ */
> +
> +
>  /*
>   * Insert a new entry between two known consecutive entries.
>   *
>   * This is only for internal list manipulation where we know
>   * the prev/next entries already!
>   */
> -static inline void __list_add_rcu(struct list_head *new,
> -		struct list_head *prev, struct list_head *next)
> +static inline void __list_add_rcu(struct rcu_list_head *new,
> +		struct rcu_list_head *prev, struct rcu_list_head *next)
>  {
> -	new->next = next;
> +	__rcu_assign_pointer(new->next, next);
>  	new->prev = prev;
>  	rcu_assign_pointer(prev->next, new);
>  	next->prev = new;
> @@ -40,9 +91,9 @@ static inline void __list_add_rcu(struct list_head *new,
>   * the _rcu list-traversal primitives, such as
>   * list_for_each_entry_rcu().
>   */
> -static inline void list_add_rcu(struct list_head *new, struct list_head *head)
> +static inline void list_add_rcu(struct rcu_list_head *new, struct rcu_list_head *head)
>  {
> -	__list_add_rcu(new, head, head->next);
> +	__list_add_rcu(new, head, __rcu_dereference(head->next));
>  }
>  
>  /**
> @@ -61,8 +112,8 @@ static inline void list_add_rcu(struct list_head *new, struct list_head *head)
>   * the _rcu list-traversal primitives, such as
>   * list_for_each_entry_rcu().
>   */
> -static inline void list_add_tail_rcu(struct list_head *new,
> -					struct list_head *head)
> +static inline void list_add_tail_rcu(struct rcu_list_head *new,
> +					struct rcu_list_head *head)
>  {
>  	__list_add_rcu(new, head->prev, head);
>  }
> @@ -91,13 +142,29 @@ static inline void list_add_tail_rcu(struct list_head *new,
>   * or call_rcu() must be used to defer freeing until an RCU
>   * grace period has elapsed.
>   */
> -static inline void list_del_rcu(struct list_head *entry)
> +static inline void __list_del_rcu(struct rcu_list_head *prev, struct rcu_list_head *next)
>  {
> -	__list_del(entry->prev, entry->next);
> +	next->prev = prev;
> +	__rcu_assign_pointer(prev->next, next);
> +}
> +
> +static inline void list_del_rcu(struct rcu_list_head *entry)
> +{
> +	__list_del_rcu(entry->prev, __rcu_dereference(entry->next));
>  	entry->prev = LIST_POISON2;
>  }
>  
>  /**
> + * list_empty - tests whether a list is empty
> + * @head: the list to test.
> + */
> +static inline int list_empty_rcu(const struct rcu_list_head *head)
> +{
> +	return rcu_dereference(head->next) == head;
> +}
> +
> +
> +/**
>   * hlist_del_init_rcu - deletes entry from hash list with re-initialization
>   * @n: the element to delete from the hash list.
>   *
> @@ -117,7 +184,7 @@ static inline void list_del_rcu(struct list_head *entry)
>   * perfectly legal to run concurrently with the _rcu list-traversal
>   * primitives, such as hlist_for_each_entry_rcu().
>   */
> -static inline void hlist_del_init_rcu(struct hlist_node *n)
> +static inline void hlist_del_init_rcu(struct rcu_hlist_node *n)
>  {
>  	if (!hlist_unhashed(n)) {
>  		__hlist_del(n);
> @@ -133,13 +200,13 @@ static inline void hlist_del_init_rcu(struct hlist_node *n)
>   * The @old entry will be replaced with the @new entry atomically.
>   * Note: @old should not be empty.
>   */
> -static inline void list_replace_rcu(struct list_head *old,
> -				struct list_head *new)
> +static inline void list_replace_rcu(struct rcu_list_head *old,
> +				struct rcu_list_head *new)
>  {
>  	new->next = old->next;
>  	new->prev = old->prev;
> -	rcu_assign_pointer(new->prev->next, new);
> -	new->next->prev = new;
> +	__rcu_assign_pointer(new->prev->next, new);
> +	rcu_dereference(new->next)->prev = new;
>  	old->prev = LIST_POISON2;
>  }
>  
> @@ -160,13 +227,13 @@ static inline void list_replace_rcu(struct list_head *old,
>   *	based on call_rcu() could be created.  But only if -really-
>   *	needed -- there is no shortage of RCU API members.
>   */
> -static inline void list_splice_init_rcu(struct list_head *list,
> -					struct list_head *head,
> +static inline void list_splice_init_rcu(struct rcu_list_head *list,
> +					struct rcu_list_head *head,
>  					void (*sync)(void))
>  {
> -	struct list_head *first = list->next;
> -	struct list_head *last = list->prev;
> -	struct list_head *at = head->next;
> +	struct rcu_list_head *first = __rcu_dereference(list->next);
> +	struct rcu_list_head *last = list->prev;
> +	struct rcu_list_head *at = __rcu_dereference(head->next);
>  
>  	if (list_empty(head))
>  		return;
> @@ -192,7 +259,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
>  	 * this function.
>  	 */
>  
> -	last->next = at;
> +	__rcu_assign_pointer(last->next,at);
>  	rcu_assign_pointer(head->next, first);
>  	first->prev = head;
>  	at->prev = last;
> @@ -200,7 +267,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
>  
>  /**
>   * list_entry_rcu - get the struct for this entry
> - * @ptr:        the &struct list_head pointer.
> + * @ptr:        the &struct rcu_list_head pointer.
>   * @type:       the type of the struct this is embedded in.
>   * @member:     the name of the list_struct within the struct.
>   *
> @@ -241,13 +308,13 @@ static inline void list_splice_init_rcu(struct list_head *list,
>   */
>  #define list_for_each_entry_rcu(pos, head, member) \
>  	for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
> -		prefetch(pos->member.next), &pos->member != (head); \
> +		prefetch(__rcu_dereference(pos->member.next)), &pos->member != (head); \
>  		pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
>  
>  
>  /**
>   * list_for_each_continue_rcu
> - * @pos:	the &struct list_head to use as a loop cursor.
> + * @pos:	the &struct rcu_list_head to use as a loop cursor.
>   * @head:	the head for your list.
>   *
>   * Iterate over an rcu-protected list, continuing after current point.
> @@ -294,9 +361,9 @@ static inline void list_splice_init_rcu(struct list_head *list,
>   * the _rcu list-traversal primitives, such as
>   * hlist_for_each_entry().
>   */
> -static inline void hlist_del_rcu(struct hlist_node *n)
> +static inline void hlist_del_rcu(struct rcu_hlist_node *n)
>  {
> -	__hlist_del(n);
> +	__hlist_del((struct hlist_node *)n);
>  	n->pprev = LIST_POISON2;
>  }
>  
> @@ -307,16 +374,16 @@ static inline void hlist_del_rcu(struct hlist_node *n)
>   *
>   * The @old entry will be replaced with the @new entry atomically.
>   */
> -static inline void hlist_replace_rcu(struct hlist_node *old,
> -					struct hlist_node *new)
> +static inline void hlist_replace_rcu(struct rcu_hlist_node *old,
> +					struct rcu_hlist_node *new)
>  {
> -	struct hlist_node *next = old->next;
> +	struct rcu_hlist_node __rcu *next = old->next;
>  
>  	new->next = next;
>  	new->pprev = old->pprev;
>  	rcu_assign_pointer(*new->pprev, new);
>  	if (next)
> -		new->next->pprev = &new->next;
> +		__rcu_dereference(new->next)->pprev = &new->next;
>  	old->pprev = LIST_POISON2;
>  }
>  
> @@ -339,12 +406,12 @@ static inline void hlist_replace_rcu(struct hlist_node *old,
>   * problems on Alpha CPUs.  Regardless of the type of CPU, the
>   * list-traversal primitive must be guarded by rcu_read_lock().
>   */
> -static inline void hlist_add_head_rcu(struct hlist_node *n,
> -					struct hlist_head *h)
> +static inline void hlist_add_head_rcu(struct rcu_hlist_node *n,
> +					struct rcu_hlist_head *h)
>  {
> -	struct hlist_node *first = h->first;
> +	struct rcu_hlist_node *first = __rcu_dereference(h->first);
>  
> -	n->next = first;
> +	__rcu_assign_pointer(n->next, first);
>  	n->pprev = &h->first;
>  	rcu_assign_pointer(h->first, n);
>  	if (first)
> @@ -369,8 +436,8 @@ static inline void hlist_add_head_rcu(struct hlist_node *n,
>   * hlist_for_each_entry_rcu(), used to prevent memory-consistency
>   * problems on Alpha CPUs.
>   */
> -static inline void hlist_add_before_rcu(struct hlist_node *n,
> -					struct hlist_node *next)
> +static inline void hlist_add_before_rcu(struct rcu_hlist_node *n,
> +					struct rcu_hlist_node *next)
>  {
>  	n->pprev = next->pprev;
>  	n->next = next;
> @@ -396,8 +463,8 @@ static inline void hlist_add_before_rcu(struct hlist_node *n,
>   * hlist_for_each_entry_rcu(), used to prevent memory-consistency
>   * problems on Alpha CPUs.
>   */
> -static inline void hlist_add_after_rcu(struct hlist_node *prev,
> -				       struct hlist_node *n)
> +static inline void hlist_add_after_rcu(struct rcu_hlist_node *prev,
> +				       struct rcu_hlist_node *n)
>  {
>  	n->next = prev->next;
>  	n->pprev = &prev->next;
> @@ -406,12 +473,17 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
>  		n->next->pprev = &n->next;
>  }
>  
> +static inline int hlist_empty_rcu(const struct rcu_hlist_head *h)
> +{
> +	return !__rcu_dereference(h->first);
> +}
> +
>  /**
>   * hlist_for_each_entry_rcu - iterate over rcu list of given type
>   * @tpos:	the type * to use as a loop cursor.
> - * @pos:	the &struct hlist_node to use as a loop cursor.
> + * @pos:	the &struct rcu_hlist_node to use as a loop cursor.
>   * @head:	the head for your list.
> - * @member:	the name of the hlist_node within the struct.
> + * @member:	the name of the rcu_hlist_node within the struct.
>   *
>   * This list-traversal primitive may safely run concurrently with
>   * the _rcu list-mutation primitives such as hlist_add_head_rcu()
> @@ -419,7 +491,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
>   */
>  #define hlist_for_each_entry_rcu(tpos, pos, head, member)		 \
>  	for (pos = rcu_dereference((head)->first);			 \
> -		pos && ({ prefetch(pos->next); 1; }) &&			 \
> +		pos && ({ prefetch(__rcu_dereference(pos->next)); 1; }) &&			 \
>  		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
>  		pos = rcu_dereference(pos->next))
>  
> -- 
> 1.6.3.3
> 

-- 
Mathieu Desnoyers
Operating System Efficiency Consultant
EfficiOS Inc.
http://www.efficios.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ