diff options
Diffstat (limited to 'include/linux/list.h')
| -rw-r--r-- | include/linux/list.h | 136 | 
1 files changed, 112 insertions, 24 deletions
diff --git a/include/linux/list.h b/include/linux/list.h index 85c92555e31f..4f3b7f71bdfd 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -23,6 +23,13 @@  #define LIST_HEAD(name) \  	struct list_head name = LIST_HEAD_INIT(name) +/** + * INIT_LIST_HEAD - Initialize a list_head structure + * @list: list_head structure to be initialized. + * + * Initializes the list_head to point to itself.  If it is a list header, + * the result is an empty list. + */  static inline void INIT_LIST_HEAD(struct list_head *list)  {  	WRITE_ONCE(list->next, list); @@ -120,12 +127,6 @@ static inline void __list_del_clearprev(struct list_head *entry)  	entry->prev = NULL;  } -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */  static inline void __list_del_entry(struct list_head *entry)  {  	if (!__list_del_entry_valid(entry)) @@ -134,6 +135,12 @@ static inline void __list_del_entry(struct list_head *entry)  	__list_del(entry->prev, entry->next);  } +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */  static inline void list_del(struct list_head *entry)  {  	__list_del_entry(entry); @@ -157,8 +164,15 @@ static inline void list_replace(struct list_head *old,  	new->prev->next = new;  } +/** + * list_replace_init - replace old entry by new one and initialize the old one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */  static inline void list_replace_init(struct list_head *old, -					struct list_head *new) +				     struct list_head *new)  {  	list_replace(old, new);  	INIT_LIST_HEAD(old); @@ -744,11 +758,36 @@ static inline void INIT_HLIST_NODE(struct hlist_node *h)  	h->pprev = NULL;  } +/** + * hlist_unhashed - Has node been removed from list and reinitialized? + * @h: Node to be checked + * + * Not that not all removal functions will leave a node in unhashed + * state.  For example, hlist_nulls_del_init_rcu() does leave the + * node in unhashed state, but hlist_nulls_del() does not. + */  static inline int hlist_unhashed(const struct hlist_node *h)  {  	return !h->pprev;  } +/** + * hlist_unhashed_lockless - Version of hlist_unhashed for lockless use + * @h: Node to be checked + * + * This variant of hlist_unhashed() must be used in lockless contexts + * to avoid potential load-tearing.  The READ_ONCE() is paired with the + * various WRITE_ONCE() in hlist helpers that are defined below. + */ +static inline int hlist_unhashed_lockless(const struct hlist_node *h) +{ +	return !READ_ONCE(h->pprev); +} + +/** + * hlist_empty - Is the specified hlist_head structure an empty hlist? + * @h: Structure to check. + */  static inline int hlist_empty(const struct hlist_head *h)  {  	return !READ_ONCE(h->first); @@ -761,9 +800,16 @@ static inline void __hlist_del(struct hlist_node *n)  	WRITE_ONCE(*pprev, next);  	if (next) -		next->pprev = pprev; +		WRITE_ONCE(next->pprev, pprev);  } +/** + * hlist_del - Delete the specified hlist_node from its list + * @n: Node to delete. + * + * Note that this function leaves the node in hashed state.  Use + * hlist_del_init() or similar instead to unhash @n. + */  static inline void hlist_del(struct hlist_node *n)  {  	__hlist_del(n); @@ -771,6 +817,12 @@ static inline void hlist_del(struct hlist_node *n)  	n->pprev = LIST_POISON2;  } +/** + * hlist_del_init - Delete the specified hlist_node from its list and initialize + * @n: Node to delete. + * + * Note that this function leaves the node in unhashed state. + */  static inline void hlist_del_init(struct hlist_node *n)  {  	if (!hlist_unhashed(n)) { @@ -779,51 +831,83 @@ static inline void hlist_del_init(struct hlist_node *n)  	}  } +/** + * hlist_add_head - add a new entry at the beginning of the hlist + * @n: new entry to be added + * @h: hlist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */  static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)  {  	struct hlist_node *first = h->first; -	n->next = first; +	WRITE_ONCE(n->next, first);  	if (first) -		first->pprev = &n->next; +		WRITE_ONCE(first->pprev, &n->next);  	WRITE_ONCE(h->first, n); -	n->pprev = &h->first; +	WRITE_ONCE(n->pprev, &h->first);  } -/* next must be != NULL */ +/** + * hlist_add_before - add a new entry before the one specified + * @n: new entry to be added + * @next: hlist node to add it before, which must be non-NULL + */  static inline void hlist_add_before(struct hlist_node *n, -					struct hlist_node *next) +				    struct hlist_node *next)  { -	n->pprev = next->pprev; -	n->next = next; -	next->pprev = &n->next; +	WRITE_ONCE(n->pprev, next->pprev); +	WRITE_ONCE(n->next, next); +	WRITE_ONCE(next->pprev, &n->next);  	WRITE_ONCE(*(n->pprev), n);  } +/** + * hlist_add_behing - add a new entry after the one specified + * @n: new entry to be added + * @prev: hlist node to add it after, which must be non-NULL + */  static inline void hlist_add_behind(struct hlist_node *n,  				    struct hlist_node *prev)  { -	n->next = prev->next; -	prev->next = n; -	n->pprev = &prev->next; +	WRITE_ONCE(n->next, prev->next); +	WRITE_ONCE(prev->next, n); +	WRITE_ONCE(n->pprev, &prev->next);  	if (n->next) -		n->next->pprev  = &n->next; +		WRITE_ONCE(n->next->pprev, &n->next);  } -/* after that we'll appear to be on some hlist and hlist_del will work */ +/** + * hlist_add_fake - create a fake hlist consisting of a single headless node + * @n: Node to make a fake list out of + * + * This makes @n appear to be its own predecessor on a headless hlist. + * The point of this is to allow things like hlist_del() to work correctly + * in cases where there is no list. + */  static inline void hlist_add_fake(struct hlist_node *n)  {  	n->pprev = &n->next;  } +/** + * hlist_fake: Is this node a fake hlist? + * @h: Node to check for being a self-referential fake hlist. + */  static inline bool hlist_fake(struct hlist_node *h)  {  	return h->pprev == &h->next;  } -/* +/** + * hlist_is_singular_node - is node the only element of the specified hlist? + * @n: Node to check for singularity. + * @h: Header for potentially singular list. + *   * Check whether the node is the only node of the head without - * accessing head: + * accessing head, thus avoiding unnecessary cache misses.   */  static inline bool  hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) @@ -831,7 +915,11 @@ hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)  	return !n->next && n->pprev == &h->first;  } -/* +/** + * hlist_move_list - Move an hlist + * @old: hlist_head for old list. + * @new: hlist_head for new list. + *   * Move a list from one list head to another. Fixup the pprev   * reference of the first entry if it exists.   */  |