[sheepdog] [RFC PATCH 3/3] make list more typesafe

MORITA Kazutaka morita.kazutaka at gmail.com
Wed Sep 25 20:12:11 CEST 2013


From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>

This patch adds more strict type checking to list functions and
forbids inserting invalid list nodes into the list head.

Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
 dog/trace.c                   |   7 +-
 dog/treeview.c                |  27 ++++---
 include/list.h                | 167 +++++++++++++++++++++++++++---------------
 include/work.h                |   4 +-
 lib/logger.c                  |  11 +--
 lib/util.c                    |  10 +--
 lib/work.c                    |  28 +++----
 sheep/cluster.h               |   7 +-
 sheep/cluster/corosync.c      |  32 ++++----
 sheep/cluster/shepherd.c      |  22 +++---
 sheep/cluster/zookeeper.c     |  17 +++--
 sheep/group.c                 |  42 +++++------
 sheep/object_cache.c          |  28 +++----
 sheep/ops.c                   |   2 +-
 sheep/request.c               |  41 ++++++-----
 sheep/sheep.c                 |   2 +-
 sheep/sheep_priv.h            |  41 ++++++-----
 sheep/store.c                 |   2 +-
 sheep/trace/trace.c           |  17 +++--
 sheep/vdi.c                   |  12 +--
 shepherd/shepherd.c           |  35 ++++-----
 tests/unit/sheep/mock_sheep.c |   2 +-
 22 files changed, 308 insertions(+), 248 deletions(-)

diff --git a/dog/trace.c b/dog/trace.c
index 9346849..302ee34 100644
--- a/dog/trace.c
+++ b/dog/trace.c
@@ -252,7 +252,8 @@ struct graph_stat_entry {
 	uint16_t nr_calls;
 };
 
-static LIST_HEAD(stat_list);
+static LIST_HEAD(list_stat_head, struct graph_stat_entry, list) stat_list =
+	LIST_HEAD_INITIALIZER(stat_list);
 
 static int graph_stat_cmp(const struct graph_stat_entry *a,
 			  const struct graph_stat_entry *b)
@@ -290,14 +291,14 @@ static void prepare_stat_tree(struct trace_graph_item *item)
 		free(new);
 		return;
 	}
-	list_add(&new->list, &stat_list);
+	list_add(new, &stat_list);
 }
 
 static void stat_list_print(void)
 {
 	struct graph_stat_entry *entry;
 
-	list_for_each_entry(entry, &stat_list, list) {
+	list_for_each_entry(entry, &stat_list) {
 		float total = (float)entry->duration / 1000000000;
 		float per = (float)entry->duration / entry->nr_calls / 1000000;
 
diff --git a/dog/treeview.c b/dog/treeview.c
index c407f2d..68a2917 100644
--- a/dog/treeview.c
+++ b/dog/treeview.c
@@ -26,10 +26,12 @@ struct vdi_tree {
 	uint32_t vid;
 	uint32_t pvid;
 	bool highlight;
-	struct list_head children;
+	struct list_tree_head *children;
 	struct list_node siblings;
 };
 
+LIST_HEAD(list_tree_head, struct vdi_tree, siblings);
+
 static int *width, *more;
 static struct vdi_tree *root;
 
@@ -38,7 +40,7 @@ static struct vdi_tree *find_vdi(struct vdi_tree *parent, uint32_t vid,
 {
 	struct vdi_tree *vdi, *ret;
 
-	list_for_each_entry(vdi, &parent->children, siblings) {
+	list_for_each_entry(vdi, parent->children) {
 		if (vdi->vid == vid && !strcmp(vdi->name, name))
 			return vdi;
 
@@ -60,7 +62,8 @@ static struct vdi_tree *new_vdi(const char *name, const char *label,
 	vdi->vid = vid;
 	vdi->pvid = pvid;
 	vdi->highlight = highlight;
-	INIT_LIST_HEAD(&vdi->children);
+	vdi->children = xmalloc(sizeof(*vdi->children));
+	INIT_LIST_HEAD(vdi->children);
 	return vdi;
 }
 
@@ -82,17 +85,17 @@ void add_vdi_tree(const char *name, const char *label, uint32_t vid,
 	if (!parent)
 		parent = root;
 
-	list_add_tail(&vdi->siblings, &parent->children);
+	list_add_tail(vdi, parent->children);
 }
 
 static void compaction(struct vdi_tree *parent)
 {
 	struct vdi_tree *vdi, *new_parent;
 
-	list_for_each_entry(vdi, &parent->children, siblings) {
+	list_for_each_entry(vdi, parent->children) {
 		new_parent = find_vdi(root, vdi->pvid, vdi->name);
 		if (new_parent && parent != new_parent)
-			list_move_tail(&vdi->siblings, &new_parent->children);
+			list_move_tail(vdi, new_parent->children);
 
 		compaction(vdi);
 	}
@@ -103,7 +106,7 @@ static int get_depth(struct vdi_tree *parent)
 	struct vdi_tree *vdi;
 	int max_depth = 0, depth;
 
-	list_for_each_entry(vdi, &parent->children, siblings) {
+	list_for_each_entry(vdi, parent->children) {
 		depth = get_depth(vdi);
 		if (max_depth < depth)
 			max_depth = depth;
@@ -148,7 +151,7 @@ static void _dump_tree(struct vdi_tree *current, int level, bool first, bool las
 	if (current->highlight)
 		printf(TEXT_NORMAL);
 
-	if (list_empty(&current->children)) {
+	if (list_empty(current->children)) {
 		putchar('\n');
 		return;
 	}
@@ -156,10 +159,10 @@ static void _dump_tree(struct vdi_tree *current, int level, bool first, bool las
 	more[level] = !last;
 	width[level] = strlen(current->label);
 
-	list_for_each_entry(vdi, &current->children, siblings) {
+	list_for_each_entry(vdi, current->children) {
 		_dump_tree(vdi, level + 1,
-			   &vdi->siblings == current->children.n.next,
-			   vdi->siblings.next == &current->children.n);
+			   &vdi->siblings == current->children->h.n.next,
+			   vdi->siblings.next == &current->children->h.n);
 	}
 }
 
@@ -179,7 +182,7 @@ void dump_tree(void)
 		return;
 	}
 
-	list_for_each_entry(vdi, &root->children, siblings) {
+	list_for_each_entry(vdi, root->children) {
 		printf("%s", vdi->name);
 		more[0] = 0;
 		width[0] = strlen(vdi->name);
diff --git a/include/list.h b/include/list.h
index 03250ae..fd58627 100644
--- a/include/list.h
+++ b/include/list.h
@@ -12,60 +12,75 @@ struct list_node {
 	struct list_node *prev;
 };
 
-struct list_head {
+struct __list_head {
 	struct list_node n;
 };
 
-#define LIST_HEAD_INIT(name) { { &(name.n), &(name.n) } }
-#define LIST_NODE_INIT { NULL, NULL }
+#define LIST_HEAD_INITIALIZER(name) { .h.n = { &((name).h.n), &((name).h.n) } }
+#define LIST_NODE_INITIALIZER { NULL, NULL }
 
-#define LIST_HEAD(name) \
-	struct list_head name = LIST_HEAD_INIT(name)
-#define LIST_NODE(name) \
-	struct list_node name = LIST_NODE_INIT
+#define LIST_HEAD(name, type, member)				\
+struct name {							\
+	struct __list_head h;					\
+								\
+	/* The below fields are used only at compile time */	\
+	type *t;						\
+	char o[offsetof(type, member)];				\
+}
 
-static inline void INIT_LIST_HEAD(struct list_head *list)
+static inline void __INIT_LIST_HEAD(struct __list_head *list)
 {
 	list->n.next = &list->n;
 	list->n.prev = &list->n;
 }
 
+#define INIT_LIST_HEAD(head) __INIT_LIST_HEAD(&(head)->h)
+
 static inline void INIT_LIST_NODE(struct list_node *list)
 {
 	list->next = NULL;
 	list->prev = NULL;
 }
 
-#define list_first_entry(head, type, member) \
-	list_entry((head)->n.next, type, member)
+#define list_first_entry(head) \
+	list_entry((head)->h.n.next, head)
+
+#define list_next_entry(node, head) \
+	list_entry(list_node_of(node, head)->next, head)
 
-static inline bool list_empty(const struct list_head *head)
+static inline bool __list_empty(struct __list_head *head)
 {
 	return head->n.next == &head->n;
 }
 
-#define list_entry(ptr, type, member) \
-	container_of(ptr, type, member)
+#define list_empty(head) __list_empty(&(head)->h)
+
+#define list_type_check(entry, head) (void) ((entry) == (head)->t)
+
+#define list_entry(node, head) \
+	offset_container_of(node, typeof(*(head)->t), sizeof((head)->o))
+
+#define list_node_of(entry, head)					\
+({									\
+	list_type_check(entry, head);					\
+	offset_member_of(entry, struct list_node, sizeof((head)->o));	\
+})
 
 #define list_for_each(pos, head)					\
-	for (typeof(pos) LOCAL(n) = (pos = (head)->n.next, pos->next);	\
+	for (struct list_node *LOCAL(n) = (pos = (head)->n.next,	\
+					   pos->next);			\
 	     pos != &(head)->n;						\
 	     pos = LOCAL(n), LOCAL(n) = pos->next)
 
-#define list_for_each_entry(pos, head, member)				\
-	for (typeof(pos) LOCAL(n) = (pos = list_entry((head)->n.next,	\
-						      typeof(*pos),	\
-						      member),		\
-				     list_entry(pos->member.next,	\
-						typeof(*pos),		\
-						member));		\
-	     &pos->member != &(head)->n;				\
-	     pos = LOCAL(n), LOCAL(n) = list_entry(LOCAL(n)->member.next, \
-						   typeof(*LOCAL(n)),	\
-						   member))
+#define list_for_each_entry(pos, head)					\
+	for (typeof(pos) LOCAL(n) = (pos = list_entry((head)->h.n.next, \
+						      head),		\
+				     list_next_entry(pos, head));	\
+	     list_node_of(pos, head) != &(head)->h.n;			\
+	     pos = LOCAL(n), LOCAL(n) = list_next_entry(LOCAL(n), head))
 
-static inline bool __list_linked(const struct list_node *node,
-				 const struct list_head *head)
+static inline bool ____list_linked(const struct list_node *node,
+				   const struct __list_head *head)
 {
 	struct list_node *pos;
 
@@ -77,19 +92,22 @@ static inline bool __list_linked(const struct list_node *node,
 	return false;
 }
 
-static inline bool list_linked(const struct list_node *node,
-			       const struct list_head *head)
+static inline bool __list_linked(const struct list_node *node,
+			       const struct __list_head *head)
 {
 	bool ret = (node->next != NULL);
 
-	assert(ret == __list_linked(node, head));
+	assert(ret == ____list_linked(node, head));
 
 	return ret;
 }
 
-static inline void __list_add(struct list_node *new,
-			      struct list_node *prev,
-			      struct list_node *next)
+#define list_linked(entry, head) \
+	__list_linked(list_node_of(entry, head), &(head)->h)
+
+static inline void ____list_add(struct list_node *new,
+				struct list_node *prev,
+				struct list_node *next)
 {
 	next->prev = new;
 	new->next = next;
@@ -97,17 +115,24 @@ static inline void __list_add(struct list_node *new,
 	prev->next = new;
 }
 
-static inline void list_add(struct list_node *new, struct list_head *head)
+static inline void __list_add(struct list_node *new, struct __list_head *head)
 {
-	__list_add(new, &head->n, head->n.next);
+	____list_add(new, &head->n, head->n.next);
 }
 
-static inline void list_add_tail(struct list_node *new, struct list_head *head)
+#define list_add(new, head) \
+	__list_add(list_node_of(new, head), &(head)->h)
+
+static inline void __list_add_tail(struct list_node *new,
+				   struct __list_head *head)
 {
-	__list_add(new, head->n.prev, &head->n);
+	____list_add(new, head->n.prev, &head->n);
 }
 
-static inline void __list_del(struct list_node *prev, struct list_node *next)
+#define list_add_tail(new, head) \
+	__list_add_tail(list_node_of(new, head), &(head)->h)
+
+static inline void ____list_del(struct list_node *prev, struct list_node *next)
 {
 	next->prev = prev;
 	prev->next = next;
@@ -115,31 +140,40 @@ static inline void __list_del(struct list_node *prev, struct list_node *next)
 
 static inline void __list_del_entry(struct list_node *entry)
 {
-	__list_del(entry->prev, entry->next);
+	____list_del(entry->prev, entry->next);
 }
 
-static inline void list_del(struct list_node *entry,
-			    const struct list_head *head)
+static inline void __list_del(struct list_node *entry,
+			      const struct __list_head *head)
 {
 	assert(__list_linked(entry, head));
-	__list_del(entry->prev, entry->next);
+	____list_del(entry->prev, entry->next);
 	entry->next = entry->prev = NULL;
 }
 
-static inline void list_move(struct list_node *list, struct list_head *head)
+#define list_del(entry, head) \
+	__list_del(list_node_of(entry, head), &(head)->h)
+
+static inline void __list_move(struct list_node *list, struct __list_head *head)
 {
 	__list_del_entry(list);
-	list_add(list, head);
+	__list_add(list, head);
 }
 
-static inline void list_move_tail(struct list_node *list,
-				  struct list_head *head)
+#define list_move(entry, head) \
+	__list_move(list_node_of(entry, head), &(head)->h)
+
+static inline void __list_move_tail(struct list_node *list,
+				  struct __list_head *head)
 {
 	__list_del_entry(list);
-	list_add_tail(list, head);
+	__list_add_tail(list, head);
 }
 
-static inline void __list_splice(const struct list_head *list,
+#define list_move_tail(entry, head) \
+	__list_move_tail(list_node_of(entry, head), &(head)->h)
+
+static inline void __list_splice(const struct __list_head *list,
 				 struct list_node *prev,
 				 struct list_node *next)
 {
@@ -153,24 +187,36 @@ static inline void __list_splice(const struct list_head *list,
 	next->prev = last;
 }
 
-static inline void list_splice_init(struct list_head *list,
-				    struct list_head *head)
+static inline void __list_splice_init(struct __list_head *list,
+				      struct __list_head *head)
 {
-	if (!list_empty(list)) {
+	if (!__list_empty(list)) {
 		__list_splice(list, &head->n, head->n.next);
-		INIT_LIST_HEAD(list);
+		__INIT_LIST_HEAD(list);
 	}
 }
 
-static inline void list_splice_tail_init(struct list_head *list,
-					 struct list_head *head)
+#define list_splice_init(list, head)			\
+({							\
+	(void) ((list) == (head));			\
+	__list_splice_init(&(list)->h, &(head)->h);	\
+})
+
+static inline void __list_splice_tail_init(struct __list_head *list,
+					   struct __list_head *head)
 {
-	if (!list_empty(list)) {
+	if (!__list_empty(list)) {
 		__list_splice(list, head->n.prev, &head->n);
-		INIT_LIST_HEAD(list);
+		__INIT_LIST_HEAD(list);
 	}
 }
 
+#define list_splice_tail_init(list, head)			\
+({								\
+	(void) ((list) == (head));				\
+	__list_splice_tail_init(&(list)->h, &(head)->h);	\
+})
+
 /* hlist, mostly useful for hash tables */
 
 #define LIST_POISON1 ((void *) 0x00100100)
@@ -270,7 +316,10 @@ static inline void hlist_add_after(struct hlist_node *n,
 		     (tpos = hlist_entry(pos, typeof(*tpos), member), 1); \
 	     pos = LOCAL(n))
 
-void list_sort(void *priv, struct list_head *head,
-	       int (*cmp)(void *priv, struct list_node *a,
-			  struct list_node *b));
+void __list_sort(void *priv, struct __list_head *head,
+		 int (*cmp)(void *priv, struct list_node *a,
+			    struct list_node *b));
+
+#define list_sort(priv, head, cmp) __list_sort(priv, &(head)->h, cmp)
+
 #endif	/* __LIST_H__ */
diff --git a/include/work.h b/include/work.h
index 322b930..5595d2b 100644
--- a/include/work.h
+++ b/include/work.h
@@ -16,9 +16,11 @@ struct work {
 	work_func_t done;
 };
 
+LIST_HEAD(list_work_head, struct work, w_list);
+
 struct work_queue {
 	int wq_state;
-	struct list_head pending_list;
+	struct list_work_head pending_list;
 };
 
 enum wq_thread_control {
diff --git a/lib/logger.c b/lib/logger.c
index 5a75498..92f4bc8 100644
--- a/lib/logger.c
+++ b/lib/logger.c
@@ -104,7 +104,8 @@ struct log_format {
 	struct list_node list;
 };
 
-static LIST_HEAD(log_formats);
+static LIST_HEAD(, struct log_format, list) log_formats =
+	LIST_HEAD_INITIALIZER(log_formats);
 static struct log_format *format;
 
 static int log_fd = -1;
@@ -225,7 +226,7 @@ static void log_format_register(const char *name, formatter_fn formatter)
 
 	f->name = name;
 	f->formatter = formatter;
-	list_add(&f->list, &log_formats);
+	list_add(f, &log_formats);
 }
 
 /*
@@ -241,7 +242,7 @@ init_log_formatter(void)
 	log_format_register("server", server_log_formatter);
 	log_format_register("default", default_log_formatter);
 
-	list_for_each_entry(f, &log_formats, list) {
+	list_for_each_entry(f, &log_formats) {
 		if (!strcmp(f->name, "default")) {
 			format = f;
 			return;
@@ -580,7 +581,7 @@ void early_log_init(const char *format_name, struct logger_user_info *user_info)
 
 	logger_user_info = user_info;
 
-	list_for_each_entry(f, &log_formats, list) {
+	list_for_each_entry(f, &log_formats) {
 		if (!strcmp(f->name, format_name)) {
 			format = f;
 			return;
@@ -589,7 +590,7 @@ void early_log_init(const char *format_name, struct logger_user_info *user_info)
 
 	sd_err("invalid log format: %s", format_name);
 	sd_err("valid options are:");
-	list_for_each_entry(f, &log_formats, list) {
+	list_for_each_entry(f, &log_formats) {
 		sd_err("\t%s", f->name);
 	}
 
diff --git a/lib/util.c b/lib/util.c
index bde6833..1d50a50 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -659,7 +659,7 @@ static void
 merge_and_restore_back_links(void *priv,
 			     int (*cmp)(void *priv, struct list_node *a,
 					struct list_node *b),
-			     struct list_head *head,
+			     struct __list_head *head,
 			     struct list_node *a, struct list_node *b)
 {
 	struct list_node *tail = &head->n;
@@ -710,9 +710,9 @@ merge_and_restore_back_links(void *priv,
  * @b. If @a and @b are equivalent, and their original relative
  * ordering is to be preserved, @cmp must return 0.
  */
-void list_sort(void *priv, struct list_head *head,
-	       int (*cmp)(void *priv, struct list_node *a,
-			  struct list_node *b))
+void __list_sort(void *priv, struct __list_head *head,
+		 int (*cmp)(void *priv, struct list_node *a,
+			    struct list_node *b))
 {
 	/* sorted partial lists -- last slot is a sentinel */
 #define MAX_LIST_LENGTH_BITS 20
@@ -721,7 +721,7 @@ void list_sort(void *priv, struct list_head *head,
 	int max_lev = 0;
 	struct list_node *list;
 
-	if (list_empty(head))
+	if (__list_empty(head))
 		return;
 
 	memset(part, 0, sizeof(part));
diff --git a/lib/work.c b/lib/work.c
index f88056e..941b3cd 100644
--- a/lib/work.c
+++ b/lib/work.c
@@ -51,7 +51,7 @@ static void (*suspend_callback)(void);
 struct worker_info {
 	const char *name;
 
-	struct list_head finished_list;
+	struct list_work_head finished_list;
 	struct list_node worker_info_siblings;
 
 	pthread_mutex_t finished_lock;
@@ -74,7 +74,8 @@ struct worker_info {
 };
 
 static int efd;
-static LIST_HEAD(worker_info_list);
+static LIST_HEAD(, struct worker_info, worker_info_siblings) worker_info_list =
+	LIST_HEAD_INITIALIZER(worker_info_list);
 static size_t nr_nodes = 1;
 static size_t (*wq_get_nr_nodes)(void);
 
@@ -161,7 +162,7 @@ void suspend_worker_threads(void)
 	struct worker_info *wi;
 	int tid;
 
-	list_for_each_entry(wi, &worker_info_list, worker_info_siblings) {
+	list_for_each_entry(wi, &worker_info_list) {
 		pthread_mutex_lock(&wi->pending_lock);
 	}
 
@@ -199,7 +200,7 @@ void resume_worker_threads(void)
 	for (int i = 0; i < nr_threads; i++)
 		eventfd_xread(ack_efd);
 
-	list_for_each_entry(wi, &worker_info_list, worker_info_siblings) {
+	list_for_each_entry(wi, &worker_info_list) {
 		pthread_mutex_unlock(&wi->pending_lock);
 	}
 }
@@ -225,7 +226,7 @@ void queue_work(struct work_queue *q, struct work *work)
 		/* double the thread pool size */
 		create_worker_threads(wi, wi->nr_threads * 2);
 
-	list_add_tail(&work->w_list, &wi->q.pending_list);
+	list_add_tail(work, &wi->q.pending_list);
 	pthread_mutex_unlock(&wi->pending_lock);
 
 	pthread_cond_signal(&wi->pending_cond);
@@ -235,21 +236,21 @@ static void worker_thread_request_done(int fd, int events, void *data)
 {
 	struct worker_info *wi;
 	struct work *work;
-	LIST_HEAD(list);
+	struct list_work_head list = LIST_HEAD_INITIALIZER(list);
 
 	if (wq_get_nr_nodes)
 		nr_nodes = wq_get_nr_nodes();
 
 	eventfd_xread(fd);
 
-	list_for_each_entry(wi, &worker_info_list, worker_info_siblings) {
+	list_for_each_entry(wi, &worker_info_list) {
 		pthread_mutex_lock(&wi->finished_lock);
 		list_splice_init(&wi->finished_list, &list);
 		pthread_mutex_unlock(&wi->finished_lock);
 
 		while (!list_empty(&list)) {
-			work = list_first_entry(&list, struct work, w_list);
-			list_del(&work->w_list, &list);
+			work = list_first_entry(&list);
+			list_del(work, &list);
 
 			work->done(work);
 			uatomic_dec(&wi->nr_workers);
@@ -300,17 +301,16 @@ retest:
 			goto retest;
 		}
 
-		work = list_first_entry(&wi->q.pending_list,
-				       struct work, w_list);
+		work = list_first_entry(&wi->q.pending_list);
 
-		list_del(&work->w_list, &wi->q.pending_list);
+		list_del(work, &wi->q.pending_list);
 		pthread_mutex_unlock(&wi->pending_lock);
 
 		if (work->fn)
 			work->fn(work);
 
 		pthread_mutex_lock(&wi->finished_lock);
-		list_add_tail(&work->w_list, &wi->finished_list);
+		list_add_tail(work, &wi->finished_list);
 		pthread_mutex_unlock(&wi->finished_lock);
 
 		eventfd_xwrite(efd, 1);
@@ -403,7 +403,7 @@ struct work_queue *create_work_queue(const char *name,
 	if (ret < 0)
 		goto destroy_threads;
 
-	list_add(&wi->worker_info_siblings, &worker_info_list);
+	list_add(wi, &worker_info_list);
 
 	return &wi->q;
 destroy_threads:
diff --git a/sheep/cluster.h b/sheep/cluster.h
index 6a60033..b2019fa 100644
--- a/sheep/cluster.h
+++ b/sheep/cluster.h
@@ -115,7 +115,8 @@ struct cluster_driver {
 	struct list_node list;
 };
 
-extern struct list_head cluster_drivers;
+LIST_HEAD(list_cdrv_head, struct cluster_driver, list);
+extern struct list_cdrv_head cluster_drivers;
 
 #ifdef HAVE_COROSYNC
 #define DEFAULT_CLUSTER_DRIVER "corosync"
@@ -128,11 +129,11 @@ static void __attribute__((constructor)) regist_ ## driver(void)	\
 {									\
 	if (!driver.init || !driver.join || !driver.leave || !driver.notify) \
 		panic("the driver '%s' is incomplete", driver.name);	\
-	list_add(&driver.list, &cluster_drivers);			\
+	list_add(&driver, &cluster_drivers);			\
 }
 
 #define FOR_EACH_CLUSTER_DRIVER(driver) \
-	list_for_each_entry(driver, &cluster_drivers, list)
+	list_for_each_entry(driver, &cluster_drivers)
 
 static inline struct cluster_driver *find_cdrv(const char *name)
 {
diff --git a/sheep/cluster/corosync.c b/sheep/cluster/corosync.c
index 7898c73..55657d7 100644
--- a/sheep/cluster/corosync.c
+++ b/sheep/cluster/corosync.c
@@ -34,9 +34,6 @@ static struct cpg_name cpg_group = { 8, "sheepdog" };
 static corosync_cfg_handle_t cfg_handle;
 static struct cpg_node this_node;
 
-static LIST_HEAD(corosync_block_event_list);
-static LIST_HEAD(corosync_nonblock_event_list);
-
 static struct cpg_node cpg_nodes[COROSYNC_MAX_NODES];
 static size_t nr_cpg_nodes;
 static bool self_elect;
@@ -80,6 +77,11 @@ struct corosync_event {
 	struct list_node list;
 };
 
+static LIST_HEAD(, struct corosync_event, list) corosync_block_event_list =
+	LIST_HEAD_INITIALIZER(corosync_block_event_list);
+static LIST_HEAD(, struct corosync_event, list) corosync_nonblock_event_list =
+	LIST_HEAD_INITIALIZER(corosync_nonblock_event_list);
+
 struct corosync_message {
 	struct cpg_node sender;
 	enum corosync_message_type type:16;
@@ -206,7 +208,7 @@ find_block_event(enum corosync_event_type type, struct cpg_node *sender)
 {
 	struct corosync_event *cevent;
 
-	list_for_each_entry(cevent, &corosync_block_event_list, list) {
+	list_for_each_entry(cevent, &corosync_block_event_list) {
 		if (cevent->type == type &&
 		    cpg_node_equal(&cevent->sender, sender))
 			return cevent;
@@ -220,7 +222,7 @@ find_nonblock_event(enum corosync_event_type type, struct cpg_node *sender)
 {
 	struct corosync_event *cevent;
 
-	list_for_each_entry(cevent, &corosync_nonblock_event_list, list) {
+	list_for_each_entry(cevent, &corosync_nonblock_event_list) {
 		if (cevent->type == type &&
 		    cpg_node_equal(&cevent->sender, sender))
 			return cevent;
@@ -378,12 +380,10 @@ static void __corosync_dispatch(void)
 	       !list_empty(&corosync_nonblock_event_list)) {
 		bool block;
 		if (!list_empty(&corosync_nonblock_event_list)) {
-			cevent = list_first_entry(&corosync_nonblock_event_list,
-						  typeof(*cevent), list);
+			cevent = list_first_entry(&corosync_nonblock_event_list);
 			block = false;
 		} else {
-			cevent = list_first_entry(&corosync_block_event_list,
-						  typeof(*cevent), list);
+			cevent = list_first_entry(&corosync_block_event_list);
 			block = true;
 		}
 
@@ -403,9 +403,9 @@ static void __corosync_dispatch(void)
 		}
 
 		if (block)
-			list_del(&cevent->list, &corosync_block_event_list);
+			list_del(cevent, &corosync_block_event_list);
 		else
-			list_del(&cevent->list, &corosync_nonblock_event_list);
+			list_del(cevent, &corosync_nonblock_event_list);
 		free(cevent->msg);
 		free(cevent);
 	}
@@ -439,9 +439,9 @@ update_event(enum corosync_event_type type, struct cpg_node *sender, void *msg,
 static void queue_event(struct corosync_event *cevent)
 {
 	if (cevent->type == COROSYNC_EVENT_TYPE_BLOCK)
-		list_add_tail(&cevent->list, &corosync_block_event_list);
+		list_add_tail(cevent, &corosync_block_event_list);
 	else
-		list_add_tail(&cevent->list, &corosync_nonblock_event_list);
+		list_add_tail(cevent, &corosync_nonblock_event_list);
 }
 
 static void cdrv_cpg_deliver(cpg_handle_t handle,
@@ -468,7 +468,7 @@ static void cdrv_cpg_deliver(cpg_handle_t handle,
 		cevent = update_event(COROSYNC_EVENT_TYPE_BLOCK, &cmsg->sender,
 				      cmsg->msg, cmsg->msg_len);
 		if (cevent) {
-			list_del(&cevent->list, &corosync_block_event_list);
+			list_del(cevent, &corosync_block_event_list);
 			free(cevent->msg);
 			free(cevent);
 		}
@@ -588,7 +588,7 @@ static void cdrv_cpg_confchg(cpg_handle_t handle,
 		cevent = find_event(COROSYNC_EVENT_TYPE_JOIN, left_sheep + i);
 		if (cevent) {
 			/* the node left before joining */
-			list_del(&cevent->list, &corosync_nonblock_event_list);
+			list_del(cevent, &corosync_nonblock_event_list);
 			free(cevent->msg);
 			free(cevent);
 			continue;
@@ -597,7 +597,7 @@ static void cdrv_cpg_confchg(cpg_handle_t handle,
 		cevent = find_event(COROSYNC_EVENT_TYPE_BLOCK, left_sheep + i);
 		if (cevent) {
 			/* the node left before sending UNBLOCK */
-			list_del(&cevent->list, &corosync_block_event_list);
+			list_del(cevent, &corosync_block_event_list);
 			free(cevent->msg);
 			free(cevent);
 		}
diff --git a/sheep/cluster/shepherd.c b/sheep/cluster/shepherd.c
index 494af01..e6bb9df 100644
--- a/sheep/cluster/shepherd.c
+++ b/sheep/cluster/shepherd.c
@@ -174,8 +174,10 @@ struct sph_event {
 	struct list_node event_list;
 };
 
-static LIST_HEAD(nonblocked_event_list);
-static LIST_HEAD(blocked_event_list);
+static LIST_HEAD(, struct sph_event, event_list) nonblocked_event_list =
+	LIST_HEAD_INITIALIZER(nonblocked_event_list);
+static LIST_HEAD(, struct sph_event, event_list) blocked_event_list =
+	LIST_HEAD_INITIALIZER(blocked_event_list);
 
 static int sph_event_fd;
 
@@ -185,12 +187,10 @@ static bool sph_process_event(void)
 	bool nonblock;
 
 	if (!list_empty(&nonblocked_event_list)) {
-		ev = list_first_entry(&nonblocked_event_list,
-				struct sph_event, event_list);
+		ev = list_first_entry(&nonblocked_event_list);
 		nonblock = true;
 	} else if (!list_empty(&blocked_event_list)) {
-		ev = list_first_entry(&blocked_event_list,
-				struct sph_event, event_list);
+		ev = list_first_entry(&blocked_event_list);
 		nonblock = false;
 	} else
 		return false;
@@ -214,9 +214,9 @@ static bool sph_process_event(void)
 
 remove:
 	if (nonblock)
-		list_del(&ev->event_list, &nonblocked_event_list);
+		list_del(ev, &nonblocked_event_list);
 	else
-		list_del(&ev->event_list, &blocked_event_list);
+		list_del(ev, &blocked_event_list);
 	free(ev->msg);
 	free(ev);
 
@@ -244,9 +244,9 @@ static void push_sph_event(bool nonblock, struct sd_node *sender,
 	ev->callbacked = false;
 
 	if (nonblock)
-		list_add_tail(&ev->event_list, &nonblocked_event_list);
+		list_add_tail(ev, &nonblocked_event_list);
 	else
-		list_add_tail(&ev->event_list, &blocked_event_list);
+		list_add_tail(ev, &blocked_event_list);
 
 	eventfd_xwrite(sph_event_fd, 1);
 }
@@ -260,7 +260,7 @@ static void remove_one_block_event(void)
 		/* FIXME: should I treat this case as an error? */
 		return;
 
-	list_for_each_entry(ev, &blocked_event_list, event_list) {
+	list_for_each_entry(ev, &blocked_event_list) {
 		if (ev->removed)
 			continue;
 
diff --git a/sheep/cluster/zookeeper.c b/sheep/cluster/zookeeper.c
index 18c7ef4..e221c6e 100644
--- a/sheep/cluster/zookeeper.c
+++ b/sheep/cluster/zookeeper.c
@@ -73,7 +73,8 @@ static struct rb_node_root sd_node_root = RB_ROOT_INITIALIZER(node_cmp);
 static size_t nr_sd_nodes;
 static struct sd_lock zk_tree_lock = SD_LOCK_INITIALIZER;
 static struct sd_lock zk_compete_master_lock = SD_LOCK_INITIALIZER;
-static LIST_HEAD(zk_block_list);
+static LIST_HEAD(, struct zk_node, list) zk_block_list =
+	LIST_HEAD_INITIALIZER(zk_block_list);
 static uatomic_bool is_master;
 static uatomic_bool stop;
 static bool joined;
@@ -891,7 +892,7 @@ static void kick_block_event(void)
 
 	if (list_empty(&zk_block_list))
 		return;
-	block = list_first_entry(&zk_block_list, typeof(*block), list);
+	block = list_first_entry(&zk_block_list);
 	if (!block->callbacked)
 		block->callbacked = sd_block_handler(&block->node);
 }
@@ -900,9 +901,9 @@ static void block_event_list_del(struct zk_node *n)
 {
 	struct zk_node *ev;
 
-	list_for_each_entry(ev, &zk_block_list, list) {
+	list_for_each_entry(ev, &zk_block_list) {
 		if (node_eq(&ev->node, &n->node)) {
-			list_del(&ev->list, &zk_block_list);
+			list_del(ev, &zk_block_list);
 			free(ev);
 		}
 	}
@@ -929,8 +930,8 @@ static void zk_handle_block(struct zk_event *ev)
 
 	sd_debug("BLOCK");
 	block->node = ev->sender.node;
-	list_add_tail(&block->list, &zk_block_list);
-	block = list_first_entry(&zk_block_list, typeof(*block), list);
+	list_add_tail(block, &zk_block_list);
+	block = list_first_entry(&zk_block_list);
 	if (!block->callbacked)
 		block->callbacked = sd_block_handler(&block->node);
 }
@@ -942,10 +943,10 @@ static void zk_handle_unblock(struct zk_event *ev)
 	sd_debug("UNBLOCK");
 	if (list_empty(&zk_block_list))
 		return;
-	block = list_first_entry(&zk_block_list, typeof(*block), list);
+	block = list_first_entry(&zk_block_list);
 	sd_notify_handler(&ev->sender.node, ev->buf, ev->buf_len);
 
-	list_del(&block->list, &zk_block_list);
+	list_del(block, &zk_block_list);
 	free(block);
 }
 
diff --git a/sheep/group.c b/sheep/group.c
index 88afc45..5fdd220 100644
--- a/sheep/group.c
+++ b/sheep/group.c
@@ -27,9 +27,11 @@ static pthread_mutex_t wait_vdis_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t wait_vdis_cond = PTHREAD_COND_INITIALIZER;
 static refcnt_t nr_get_vdis_works;
 
+LIST_HEAD(list_pending_head, struct request, pending_list);
+
 static main_thread(struct vnode_info *) current_vnode_info;
-static main_thread(struct list_head *) pending_block_list;
-static main_thread(struct list_head *) pending_notify_list;
+static main_thread(struct list_pending_head *) pending_block_list;
+static main_thread(struct list_pending_head *) pending_notify_list;
 
 static int get_zones_nr_from(struct rb_node_root *nroot)
 {
@@ -248,7 +250,7 @@ static void cluster_op_done(struct work *work)
 	req->status = REQUEST_DONE;
 	return;
 drop:
-	list_del(&req->pending_list, main_thread_get(pending_block_list));
+	list_del(req, main_thread_get(pending_block_list));
 	req->rp.result = SD_RES_CLUSTER_ERROR;
 	put_request(req);
 	cluster_op_running = false;
@@ -275,8 +277,7 @@ main_fn bool sd_block_handler(const struct sd_node *sender)
 
 	cluster_op_running = true;
 
-	req = list_first_entry(main_thread_get(pending_block_list),
-				struct request, pending_list);
+	req = list_first_entry(main_thread_get(pending_block_list));
 	req->work.fn = do_process_work;
 	req->work.done = cluster_op_done;
 
@@ -304,8 +305,7 @@ main_fn void queue_cluster_request(struct request *req)
 			       sd_strerror(ret));
 			goto error;
 		}
-		list_add_tail(&req->pending_list,
-			      main_thread_get(pending_block_list));
+		list_add_tail(req, main_thread_get(pending_block_list));
 	} else {
 		struct vdi_op_message *msg;
 		size_t size;
@@ -320,8 +320,7 @@ main_fn void queue_cluster_request(struct request *req)
 			goto error;
 		}
 
-		list_add_tail(&req->pending_list,
-			      main_thread_get(pending_notify_list));
+		list_add_tail(req, main_thread_get(pending_notify_list));
 
 		free(msg);
 	}
@@ -701,16 +700,12 @@ main_fn void sd_notify_handler(const struct sd_node *sender, void *data,
 	if (node_is_local(sender)) {
 		if (has_process_work(op)) {
 			req = list_first_entry(
-				main_thread_get(pending_block_list),
-				struct request, pending_list);
-			list_del(&req->pending_list,
-				 main_thread_get(pending_block_list));
+				main_thread_get(pending_block_list));
+			list_del(req, main_thread_get(pending_block_list));
 		} else {
 			req = list_first_entry(
-				main_thread_get(pending_notify_list),
-				struct request, pending_list);
-			list_del(&req->pending_list,
-				 main_thread_get(pending_notify_list));
+				main_thread_get(pending_notify_list));
+			list_del(req, main_thread_get(pending_notify_list));
 		}
 	}
 
@@ -790,8 +785,7 @@ static void requeue_cluster_request(void)
 	struct vdi_op_message *msg;
 	size_t size;
 
-	list_for_each_entry(req, main_thread_get(pending_notify_list),
-			    pending_list) {
+	list_for_each_entry(req, main_thread_get(pending_notify_list)) {
 		/*
 		 * ->notify() was called and succeeded but after that
 		 * this node session-timeouted and sd_notify_handler
@@ -806,15 +800,13 @@ static void requeue_cluster_request(void)
 		free(msg);
 	}
 
-	list_for_each_entry(req, main_thread_get(pending_block_list),
-			    pending_list) {
+	list_for_each_entry(req, main_thread_get(pending_block_list)) {
 		switch (req->status) {
 		case REQUEST_INIT:
 			/* this request has never been executed, re-queue it */
 			sd_debug("requeue a block request, op: %s",
 				 op_name(req->op));
-			list_del(&req->pending_list,
-				 main_thread_get(pending_block_list));
+			list_del(req, main_thread_get(pending_block_list));
 			queue_cluster_request(req);
 			break;
 		case REQUEST_QUEUED:
@@ -1024,10 +1016,10 @@ int create_cluster(int port, int64_t zone, int nr_vnodes,
 	sys->cinfo.status = SD_STATUS_WAIT;
 
 	main_thread_set(pending_block_list,
-			  xzalloc(sizeof(struct list_head)));
+			xzalloc(sizeof(struct list_pending_head)));
 	INIT_LIST_HEAD(main_thread_get(pending_block_list));
 	main_thread_set(pending_notify_list,
-			  xzalloc(sizeof(struct list_head)));
+			xzalloc(sizeof(struct list_pending_head)));
 	INIT_LIST_HEAD(main_thread_get(pending_notify_list));
 
 	INIT_LIST_HEAD(&sys->local_req_queue);
diff --git a/sheep/object_cache.c b/sheep/object_cache.c
index 07ce50b..f1b1d6f 100644
--- a/sheep/object_cache.c
+++ b/sheep/object_cache.c
@@ -58,8 +58,10 @@ struct object_cache {
 	struct hlist_node hash; /* VDI is linked to the global hash lists */
 	/* For faster object search */
 	RB_ROOT(rb_lru_root, struct object_cache_entry, node) lru_tree;
-	struct list_head lru_head; /* Per VDI LRU list for reclaimer */
-	struct list_head dirty_head; /* Dirty objects linked to this list */
+	/* Per VDI LRU list for reclaimer */
+	LIST_HEAD(, struct object_cache_entry, lru_list) lru_head;
+	/* Dirty objects linked to this list */
+	LIST_HEAD(, struct object_cache_entry, dirty_list) dirty_head;
 	int push_efd; /* Used to synchronize between pusher and push threads */
 	uatomic_bool in_push; /* Whether if pusher is running */
 
@@ -250,7 +252,7 @@ static void del_from_dirty_list(struct object_cache_entry *entry)
 {
 	struct object_cache *oc = entry->oc;
 
-	list_del(&entry->dirty_list, &oc->dirty_head);
+	list_del(entry, &oc->dirty_head);
 	uatomic_dec(&oc->dirty_count);
 }
 
@@ -258,7 +260,7 @@ static void add_to_dirty_list(struct object_cache_entry *entry)
 {
 	struct object_cache *oc = entry->oc;
 
-	list_add_tail(&entry->dirty_list, &oc->dirty_head);
+	list_add_tail(entry, &oc->dirty_head);
 	/* FIXME read sys->status atomically */
 	if (uatomic_add_return(&oc->dirty_count, 1) > MAX_DIRTY_OBJECT_COUNT
 	    && !uatomic_is_true(&oc->in_push)
@@ -272,9 +274,9 @@ free_cache_entry(struct object_cache_entry *entry)
 	struct object_cache *oc = entry->oc;
 
 	rb_erase(entry, &oc->lru_tree);
-	list_del(&entry->lru_list, &oc->lru_head);
+	list_del(entry, &oc->lru_head);
 	oc->total_count--;
-	if (list_linked(&entry->dirty_list, &oc->dirty_head))
+	if (list_linked(entry, &oc->dirty_head))
 		del_from_dirty_list(entry);
 	sd_destroy_lock(&entry->lock);
 	free(entry);
@@ -391,7 +393,7 @@ static int read_cache_object(struct object_cache_entry *entry, void *buf,
 
 	if (ret == SD_RES_SUCCESS) {
 		write_lock_cache(oc);
-		list_move_tail(&entry->lru_list, &oc->lru_head);
+		list_move_tail(entry, &oc->lru_head);
 		unlock_cache(oc);
 	}
 	return ret;
@@ -417,10 +419,10 @@ static int write_cache_object(struct object_cache_entry *entry, void *buf,
 	write_lock_cache(oc);
 	if (writeback) {
 		entry->bmap |= calc_object_bmap(oid, count, offset);
-		if (!list_linked(&entry->dirty_list, &oc->dirty_head))
+		if (!list_linked(entry, &oc->dirty_head))
 			add_to_dirty_list(entry);
 	}
-	list_move_tail(&entry->lru_list, &oc->lru_head);
+	list_move_tail(entry, &oc->lru_head);
 	unlock_cache(oc);
 
 	unlock_entry(entry);
@@ -517,7 +519,7 @@ static void do_reclaim_object(struct object_cache *oc)
 	uint32_t cap;
 
 	write_lock_cache(oc);
-	list_for_each_entry(entry, &oc->lru_head, lru_list) {
+	list_for_each_entry(entry, &oc->lru_head) {
 		oid = idx_to_oid(oc->vid, entry_idx(entry));
 		if (entry_in_use(entry)) {
 			sd_debug("%"PRIx64" is in use, skip...", oid);
@@ -688,7 +690,7 @@ static void add_to_lru_cache(struct object_cache *oc, uint32_t idx, bool create)
 	if (unlikely(lru_tree_insert(&oc->lru_tree, entry)))
 		panic("the object already exist");
 	uatomic_add(&gcache.capacity, CACHE_OBJECT_SIZE);
-	list_add_tail(&entry->lru_list, &oc->lru_head);
+	list_add_tail(entry, &oc->lru_head);
 	oc->total_count++;
 	if (create) {
 		/* Cache lock assure it is not raced with pusher */
@@ -910,7 +912,7 @@ static int object_cache_push(struct object_cache *oc)
 	}
 
 	uatomic_set(&oc->push_count, uatomic_read(&oc->dirty_count));
-	list_for_each_entry(entry, &oc->dirty_head, dirty_list) {
+	list_for_each_entry(entry, &oc->dirty_head) {
 		struct push_work *pw;
 
 		get_cache_entry(entry);
@@ -959,7 +961,7 @@ void object_cache_delete(uint32_t vid)
 	sd_unlock(&hashtable_lock[h]);
 
 	write_lock_cache(cache);
-	list_for_each_entry(entry, &cache->lru_head, lru_list) {
+	list_for_each_entry(entry, &cache->lru_head) {
 		free_cache_entry(entry);
 		uatomic_sub(&gcache.capacity, CACHE_OBJECT_SIZE);
 	}
diff --git a/sheep/ops.c b/sheep/ops.c
index 05ba009..b4fc77d 100644
--- a/sheep/ops.c
+++ b/sheep/ops.c
@@ -366,7 +366,7 @@ static int local_get_store_list(struct request *req)
 	struct strbuf buf = STRBUF_INIT;
 	struct store_driver *driver;
 
-	list_for_each_entry(driver, &store_drivers, list) {
+	list_for_each_entry(driver, &store_drivers) {
 		strbuf_addf(&buf, "%s ", driver->name);
 	}
 	req->rp.data_length = strbuf_copyout(&buf, req->data, req->data_length);
diff --git a/sheep/request.c b/sheep/request.c
index 863b9a5..28781ad 100644
--- a/sheep/request.c
+++ b/sheep/request.c
@@ -15,9 +15,9 @@
 
 static void requeue_request(struct request *req);
 
-static void del_requeue_request(struct request *req, struct list_head *head)
+static void del_requeue_request(struct request *req, struct list_request_head *head)
 {
-	list_del(&req->request_list, head);
+	list_del(req, head);
 	requeue_request(req);
 }
 
@@ -84,7 +84,7 @@ static void io_op_done(struct work *work)
  */
 static inline void sleep_on_wait_queue(struct request *req)
 {
-	list_add_tail(&req->request_list, &sys->req_wait_queue);
+	list_add_tail(req, &sys->req_wait_queue);
 }
 
 static void gateway_op_done(struct work *work)
@@ -203,11 +203,12 @@ static bool request_in_recovery(struct request *req)
 void wakeup_requests_on_epoch(void)
 {
 	struct request *req;
-	LIST_HEAD(pending_list);
+	struct list_request_head pending_list =
+		LIST_HEAD_INITIALIZER(pending_list);
 
 	list_splice_init(&sys->req_wait_queue, &pending_list);
 
-	list_for_each_entry(req, &pending_list, request_list) {
+	list_for_each_entry(req, &pending_list) {
 		switch (req->rp.result) {
 		case SD_RES_OLD_NODE_VER:
 			/*
@@ -240,11 +241,12 @@ void wakeup_requests_on_epoch(void)
 void wakeup_requests_on_oid(uint64_t oid)
 {
 	struct request *req;
-	LIST_HEAD(pending_list);
+	struct list_request_head pending_list =
+		LIST_HEAD_INITIALIZER(pending_list);
 
 	list_splice_init(&sys->req_wait_queue, &pending_list);
 
-	list_for_each_entry(req, &pending_list, request_list) {
+	list_for_each_entry(req, &pending_list) {
 		if (req->local_oid != oid)
 			continue;
 		sd_debug("retry %" PRIx64, req->local_oid);
@@ -256,11 +258,12 @@ void wakeup_requests_on_oid(uint64_t oid)
 void wakeup_all_requests(void)
 {
 	struct request *req;
-	LIST_HEAD(pending_list);
+	struct list_request_head pending_list =
+		LIST_HEAD_INITIALIZER(pending_list);
 
 	list_splice_init(&sys->req_wait_queue, &pending_list);
 
-	list_for_each_entry(req, &pending_list, request_list) {
+	list_for_each_entry(req, &pending_list) {
 		sd_debug("%"PRIx64, req->rq.obj.oid);
 		del_requeue_request(req, &pending_list);
 	}
@@ -492,7 +495,7 @@ worker_fn int exec_local_req(struct sd_req *rq, void *data)
 	}
 
 	pthread_mutex_lock(&sys->local_req_lock);
-	list_add_tail(&req->request_list, &sys->local_req_queue);
+	list_add_tail(req, &sys->local_req_queue);
 	pthread_mutex_unlock(&sys->local_req_lock);
 
 	eventfd_xwrite(sys->local_req_efd, 1);
@@ -560,7 +563,7 @@ main_fn void put_request(struct request *req)
 			clear_client_info(ci);
 			free_request(req);
 		} else {
-			list_add_tail(&req->request_list, &ci->done_reqs);
+			list_add_tail(req, &ci->done_reqs);
 
 			if (ci->tx_req == NULL)
 				/* There is no request being sent. */
@@ -690,8 +693,8 @@ static void clear_client_info(struct client_info *ci)
 
 	sd_debug("connection seems to be dead");
 
-	list_for_each_entry(req, &ci->done_reqs, request_list) {
-		list_del(&req->request_list, &ci->done_reqs);
+	list_for_each_entry(req, &ci->done_reqs) {
+		list_del(req, &ci->done_reqs);
 		free_request(req);
 	}
 
@@ -769,9 +772,8 @@ static void client_handler(int fd, int events, void *data)
 			return;
 
 		assert(ci->tx_req == NULL);
-		ci->tx_req = list_first_entry(&ci->done_reqs, struct request,
-					      request_list);
-		list_del(&ci->tx_req->request_list, &ci->done_reqs);
+		ci->tx_req = list_first_entry(&ci->done_reqs);
+		list_del(ci->tx_req, &ci->done_reqs);
 
 		/*
 		 * Increment refcnt so that the client_info isn't freed while
@@ -856,7 +858,8 @@ int init_unix_domain_socket(const char *dir)
 static void local_req_handler(int listen_fd, int events, void *data)
 {
 	struct request *req;
-	LIST_HEAD(pending_list);
+	struct list_request_head pending_list =
+		LIST_HEAD_INITIALIZER(pending_list);
 
 	if (events & EPOLLERR)
 		sd_err("request handler error");
@@ -867,8 +870,8 @@ static void local_req_handler(int listen_fd, int events, void *data)
 	list_splice_init(&sys->local_req_queue, &pending_list);
 	pthread_mutex_unlock(&sys->local_req_lock);
 
-	list_for_each_entry(req, &pending_list, request_list) {
-		list_del(&req->request_list, &pending_list);
+	list_for_each_entry(req, &pending_list) {
+		list_del(req, &pending_list);
 		queue_request(req);
 	}
 }
diff --git a/sheep/sheep.c b/sheep/sheep.c
index 7d4cd85..84d99a8 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -20,7 +20,7 @@
 #define DEFAULT_OBJECT_DIR "/tmp"
 #define LOG_FILE_NAME "sheep.log"
 
-LIST_HEAD(cluster_drivers);
+struct list_cdrv_head cluster_drivers = LIST_HEAD_INITIALIZER(cluster_drivers);
 static const char program_name[] = "sheep";
 
 static const char bind_help[] =
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index 5a178ce..83415cb 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -62,20 +62,6 @@
 #define worker_fn
 #endif
 
-struct client_info {
-	struct connection conn;
-
-	struct request *rx_req;
-	struct work rx_work;
-
-	struct request *tx_req;
-	struct work tx_work;
-
-	struct list_head done_reqs;
-
-	refcnt_t refcnt;
-};
-
 enum REQUST_STATUS {
 	REQUEST_INIT,
 	REQUEST_QUEUED,
@@ -109,6 +95,22 @@ struct request {
 	bool stat; /* true if this request is during stat */
 };
 
+LIST_HEAD(list_request_head, struct request, request_list);
+
+struct client_info {
+	struct connection conn;
+
+	struct request *rx_req;
+	struct work rx_work;
+
+	struct request *tx_req;
+	struct work tx_work;
+
+	struct list_request_head done_reqs;
+
+	refcnt_t refcnt;
+};
+
 struct system_info {
 	struct cluster_driver *cdrv;
 	const char *cdrv_option;
@@ -124,8 +126,8 @@ struct system_info {
 	int local_req_efd;
 
 	pthread_mutex_t local_req_lock;
-	struct list_head local_req_queue;
-	struct list_head req_wait_queue;
+	struct list_request_head local_req_queue;
+	struct list_request_head req_wait_queue;
 	int nr_outstanding_reqs;
 
 	bool gateway_only;
@@ -231,18 +233,19 @@ int for_each_object_in_stale(int (*func)(uint64_t oid, const char *path,
 			     void *arg);
 int for_each_obj_path(int (*func)(const char *path));
 
-extern struct list_head store_drivers;
+LIST_HEAD(list_sdrv_head, struct store_driver, list);
+extern struct list_sdrv_head store_drivers;
 #define add_store_driver(driver)				\
 static void __attribute__((constructor)) add_ ## driver(void)	\
 {								\
-	list_add(&driver.list, &store_drivers);			\
+	list_add(&driver, &store_drivers);			\
 }
 
 static inline struct store_driver *find_store_driver(const char *name)
 {
 	struct store_driver *driver;
 
-	list_for_each_entry(driver, &store_drivers, list) {
+	list_for_each_entry(driver, &store_drivers) {
 		if (strcmp(driver->name, name) == 0)
 			return driver;
 	}
diff --git a/sheep/store.c b/sheep/store.c
index b0af526..d88d2a3 100644
--- a/sheep/store.c
+++ b/sheep/store.c
@@ -15,7 +15,7 @@ char *obj_path;
 char *epoch_path;
 
 struct store_driver *sd_store;
-LIST_HEAD(store_drivers);
+struct list_sdrv_head store_drivers = LIST_HEAD_INITIALIZER(store_drivers);
 
 int update_epoch_log(uint32_t epoch, struct sd_node *nodes, size_t nr_nodes)
 {
diff --git a/sheep/trace/trace.c b/sheep/trace/trace.c
index 5fdb580..94dacd0 100644
--- a/sheep/trace/trace.c
+++ b/sheep/trace/trace.c
@@ -18,7 +18,8 @@
 /* Intel recommended one for 5 bytes nops (nopl 0x0(%rax,%rax,1)) */
 static const unsigned char NOP5[INSN_SIZE] = {0x0f, 0x1f, 0x44, 0x00, 0x00};
 
-static LIST_HEAD(tracers);
+static LIST_HEAD(, struct tracer, list) tracers =
+	LIST_HEAD_INITIALIZER(tracers);
 static __thread int ret_stack_index;
 static __thread struct {
 	const struct caller *caller;
@@ -84,7 +85,7 @@ static struct caller *trace_lookup_ip(unsigned long ip)
 
 void regist_tracer(struct tracer *tracer)
 {
-	list_add_tail(&tracer->list, &tracers);
+	list_add_tail(tracer, &tracers);
 }
 
 static void patch_all_sites(unsigned long addr)
@@ -115,7 +116,7 @@ void trace_function_enter(unsigned long ip, unsigned long *ret_addr)
 
 	caller = trace_lookup_ip(ip);
 
-	list_for_each_entry(tracer, &tracers, list) {
+	list_for_each_entry(tracer, &tracers) {
 		if (tracer->enter && uatomic_is_true(&tracer->enabled)) {
 			tracer->stack_depth++;
 			tracer->enter(caller, ret_stack_index);
@@ -142,7 +143,7 @@ unsigned long trace_function_exit(void)
 
 	ret_stack_index--;
 
-	list_for_each_entry(tracer, &tracers, list) {
+	list_for_each_entry(tracer, &tracers) {
 		if (tracer->exit && uatomic_is_true(&tracer->enabled)) {
 			if (tracer->stack_depth == 0)
 				/*
@@ -166,7 +167,7 @@ static size_t count_enabled_tracers(void)
 	size_t nr = 0;
 	struct tracer *t;
 
-	list_for_each_entry(t, &tracers, list) {
+	list_for_each_entry(t, &tracers) {
 		if (uatomic_is_true(&t->enabled))
 			nr++;
 	}
@@ -178,7 +179,7 @@ static struct tracer *find_tracer(const char *name)
 {
 	struct tracer *t;
 
-	list_for_each_entry(t, &tracers, list) {
+	list_for_each_entry(t, &tracers) {
 		if (strcmp(t->name, name) == 0)
 			return t;
 	}
@@ -242,7 +243,7 @@ size_t trace_status(char *buf)
 	struct tracer *t;
 	char *p = buf;
 
-	list_for_each_entry(t, &tracers, list) {
+	list_for_each_entry(t, &tracers) {
 		strcpy(p, t->name);
 		p += strlen(p);
 
@@ -450,7 +451,7 @@ void trace_cleanup(void)
 {
 	struct tracer *t;
 
-	list_for_each_entry(t, &tracers, list)
+	list_for_each_entry(t, &tracers)
 		trace_disable(t->name);
 
 	call_on_worker_threads(__trace_cleanup);
diff --git a/sheep/vdi.c b/sheep/vdi.c
index 490f69e..31215c0 100644
--- a/sheep/vdi.c
+++ b/sheep/vdi.c
@@ -735,7 +735,8 @@ struct deletion_work {
 	uint32_t *buf;
 };
 
-static LIST_HEAD(deletion_work_list);
+static LIST_HEAD(, struct deletion_work, list) deletion_work_list =
+	LIST_HEAD_INITIALIZER(deletion_work_list);
 
 static int delete_inode(struct deletion_work *dw)
 {
@@ -855,7 +856,7 @@ static void delete_one_done(struct work *work)
 		return;
 	}
 
-	list_del(&dw->list, &deletion_work_list);
+	list_del(dw, &deletion_work_list);
 
 	put_request(req);
 
@@ -863,8 +864,7 @@ static void delete_one_done(struct work *work)
 	free(dw);
 
 	if (!list_empty(&deletion_work_list)) {
-		dw = list_first_entry(&deletion_work_list,
-				      struct deletion_work, list);
+		dw = list_first_entry(&deletion_work_list);
 
 		queue_work(sys->deletion_wqueue, &dw->work);
 	}
@@ -1005,10 +1005,10 @@ static int start_deletion(struct request *req, uint32_t vid)
 	refcount_inc(&req->refcnt);
 
 	if (list_empty(&deletion_work_list)) {
-		list_add_tail(&dw->list, &deletion_work_list);
+		list_add_tail(dw, &deletion_work_list);
 		queue_work(sys->deletion_wqueue, &dw->work);
 	} else
-		list_add_tail(&dw->list, &deletion_work_list);
+		list_add_tail(dw, &deletion_work_list);
 out:
 	return SD_RES_SUCCESS;
 err:
diff --git a/shepherd/shepherd.c b/shepherd/shepherd.c
index 449da0f..2e26aae 100644
--- a/shepherd/shepherd.c
+++ b/shepherd/shepherd.c
@@ -60,7 +60,8 @@ struct sheep {
 	struct list_node join_wait_list;
 };
 
-static LIST_HEAD(sheep_list_head);
+static LIST_HEAD(, struct sheep, sheep_list) sheep_list_head =
+	LIST_HEAD_INITIALIZER(sheep_list_head);
 
 static bool running;
 static const char *progname;
@@ -77,7 +78,7 @@ static int build_node_array(struct sd_node *nodes)
 	struct sheep *s;
 
 	i = 0;
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		if (s->state != SHEEP_STATE_JOINED)
 			continue;
 
@@ -91,7 +92,7 @@ static struct sheep *find_sheep_by_nid(struct node_id *id)
 {
 	struct sheep *s;
 
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		if (!node_id_cmp(&s->node.nid, id))
 			return s;
 	}
@@ -121,7 +122,7 @@ static int notify_remove_sheep(struct sheep *leaving)
 	snd.type = SPH_SRV_MSG_REMOVE;
 	snd.body_len = sizeof(struct sd_node);
 
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		if (s->state != SHEEP_STATE_JOINED)
 			continue;
 
@@ -139,7 +140,8 @@ static int notify_remove_sheep(struct sheep *leaving)
 	return failed;
 }
 
-static LIST_HEAD(join_wait_queue);
+static LIST_HEAD(, struct sheep, join_wait_list) join_wait_queue =
+	LIST_HEAD_INITIALIZER(join_wait_queue);
 
 static void remove_handler(int fd, int events, void *data)
 {
@@ -150,7 +152,7 @@ static void remove_handler(int fd, int events, void *data)
 
 	sd_debug("removed sheeps");
 remove:
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		if (s->state != SHEEP_STATE_LEAVING)
 			continue;
 
@@ -181,8 +183,8 @@ del:
 	unregister_event(s->fd);
 	close(s->fd);
 
-	list_del(&s->sheep_list, &sheep_list_head);
-	list_del(&s->join_wait_list, &join_wait_queue);
+	list_del(s, &sheep_list_head);
+	list_del(s, &join_wait_queue);
 	free(s);
 
 	if (--nr_removed)
@@ -203,9 +205,8 @@ retry:
 	if (list_empty(&join_wait_queue))
 		return nr_failed;
 
-	waiting = list_first_entry(&join_wait_queue,
-				struct sheep, join_wait_list);
-	list_del(&waiting->join_wait_list, &join_wait_queue);
+	waiting = list_first_entry(&join_wait_queue);
+	list_del(waiting, &join_wait_queue);
 
 	memset(&snd, 0, sizeof(snd));
 	snd.type = SPH_SRV_MSG_JOIN_RETRY;
@@ -244,7 +245,7 @@ static void sph_handle_join(struct sph_msg *msg, struct sheep *sheep)
 		}
 		free(buf);
 
-		list_add(&sheep->join_wait_list, &join_wait_queue);
+		list_add(sheep, &join_wait_queue);
 
 		sd_debug("there is already a joining sheep");
 		return;
@@ -357,7 +358,7 @@ static void sph_handle_accept(struct sph_msg *msg, struct sheep *sheep)
 	join_node_finish->nodes[join_node_finish->nr_nodes++] =
 		joining_sheep->node;
 
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		if (s->state != SHEEP_STATE_JOINED)
 			continue;
 
@@ -420,7 +421,7 @@ static void sph_handle_notify(struct sph_msg *msg, struct sheep *sheep)
 
 	notify_forward->from_node = sheep->node;
 
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		if (s->state != SHEEP_STATE_JOINED)
 			continue;
 
@@ -454,7 +455,7 @@ static void sph_handle_block(struct sph_msg *msg, struct sheep *sheep)
 	snd.type = SPH_SRV_MSG_BLOCK_FORWARD;
 	snd.body_len = sizeof(struct sd_node);
 
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		ssize_t wbytes;
 
 		if (s->state != SHEEP_STATE_JOINED)
@@ -488,7 +489,7 @@ static void sph_handle_leave(struct sph_msg *msg, struct sheep *sheep)
 	snd.type = SPH_SRV_MSG_LEAVE_FORWARD;
 	snd.body_len = sizeof(struct sd_node);
 
-	list_for_each_entry(s, &sheep_list_head, sheep_list) {
+	list_for_each_entry(s, &sheep_list_head) {
 		ssize_t wbytes;
 
 		if (s->state != SHEEP_STATE_JOINED)
@@ -584,7 +585,7 @@ static void sheep_accept_handler(int fd, int events, void *data)
 		goto clean;
 	}
 
-	list_add_tail(&new_sheep->sheep_list, &sheep_list_head);
+	list_add_tail(new_sheep, &sheep_list_head);
 	new_sheep->state = SHEEP_STATE_CONNECTED;
 
 	sd_info("accepted new sheep connection");
diff --git a/tests/unit/sheep/mock_sheep.c b/tests/unit/sheep/mock_sheep.c
index 5454735..6f2eda3 100644
--- a/tests/unit/sheep/mock_sheep.c
+++ b/tests/unit/sheep/mock_sheep.c
@@ -14,4 +14,4 @@
 #include "sheep_priv.h"
 
 struct system_info *sys;
-LIST_HEAD(cluster_drivers);
+struct list_cdrv_head cluster_drivers = LIST_HEAD_INITIALIZER(cluster_drivers);
-- 
1.8.1.2




More information about the sheepdog mailing list