+#define __JA_ALIGN_MASK(v, mask) (((v) + (mask)) & ~(mask))
+#define JA_ALIGN(v, align) __JA_ALIGN_MASK(v, (typeof(v)) (align) - 1)
+#define __JA_FLOOR_MASK(v, mask) ((v) & ~(mask))
+#define JA_FLOOR(v, align) __JA_FLOOR_MASK(v, (typeof(v)) (align) - 1)
+
+static
+char *align_ptr_size(char *ptr)
+{
+ return JA_ALIGN(ptr, sizeof(ptr));
+}
+
+static
+struct rcu_ja_node_flag *ja_linear_node_get_nth(const struct rcu_ja_type *type,
+ struct rcu_ja_node *node,
+ uint8_t n)
+{
+ uint8_t nr_child;
+ uint8_t *values;
+ struct rcu_ja_node_flag *pointers;
+ struct rcu_ja_node_flag *ptr;
+ unsigned int i;
+
+ assert(!type || type->type_class == RCU_JA_LINEAR);
+
+ nr_child = node->data[0];
+ cmm_smp_rmb(); /* read nr_child before values */
+ assert(!type || nr_child <= type->max_child);
+ assert(!type || nr_child >= type->min_child);
+
+ values = &node[1];
+ for (i = 0; i < nr_child; i++) {
+ if (values[i] == n)
+ break;
+ }
+ if (i >= nr_child)
+ return NULL;
+ cmm_smp_rmb(); /* read values before pointer */
+ pointers = align_ptr_size(&values[nr_child]);
+ ptr = pointers[i];
+ assert(ja_node_ptr(ptr) != NULL);
+ return ptr;
+}
+
+static
+struct rcu_ja_node_flag *ja_pool_node_get_nth(const struct rcu_ja_type *type,
+ struct rcu_ja_node *node,
+ uint8_t n)
+{
+ struct rcu_ja_node_flag *ptr;
+ struct rcu_ja_node *linear;
+
+ assert(type->type_class == RCU_JA_POOL);
+ linear = (struct rcu_ja_node *)
+ &node->data[((unsigned long) n >> (CHAR_BIT - type->nr_pool_order)) << type->pool_size_order];
+ return ja_linear_node_get_nth(NULL, linear, n);
+}
+
+static
+struct rcu_ja_node_flag *ja_pigeon_node_get_nth(const struct rcu_ja_type *type,
+ struct rcu_ja_node *node,
+ uint8_t n)
+{
+ assert(type->type_class == RCU_JA_PIGEON);
+ return ((struct rcu_ja_node_flag *) node->data)[n];
+}
+
+/* ja_node_get_nth: get nth item from a node */
+static
+struct rcu_ja_node_flag *ja_node_get_nth(struct rcu_ja_node_flag *node_flag,
+ uint8_t n)
+{
+ unsigned int type_index;
+ struct rcu_ja_node *node;
+ const struct rcu_ja_type *type;
+
+ node_flag = rcu_dereference(node_flag);
+ node = ja_node_ptr(node_flag);
+ assert(node != NULL);
+ type_index = ja_node_type(node_flag);
+ type = &ja_types[type_index];
+
+ switch (type->type_class) {
+ case RCU_JA_LINEAR:
+ return ja_linear_node_get_nth(type, node, n);
+ case RCU_JA_POOL:
+ return ja_pool_node_get_nth(type, node, n);
+ case RCU_JA_PIGEON:
+ return ja_pigeon_node_get_nth(type, node, n);
+ default:
+ assert(0);
+ return (void *) -1UL;
+ }
+}