162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2004, 2005 Oracle.  All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/configfs.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "tcp.h"
1262306a36Sopenharmony_ci#include "nodemanager.h"
1362306a36Sopenharmony_ci#include "heartbeat.h"
1462306a36Sopenharmony_ci#include "masklog.h"
1562306a36Sopenharmony_ci#include "sys.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* for now we operate under the assertion that there can be only one
1862306a36Sopenharmony_ci * cluster active at a time.  Changing this will require trickling
1962306a36Sopenharmony_ci * cluster references throughout where nodes are looked up */
2062306a36Sopenharmony_cistruct o2nm_cluster *o2nm_single_cluster = NULL;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const char *o2nm_fence_method_desc[O2NM_FENCE_METHODS] = {
2362306a36Sopenharmony_ci	"reset",	/* O2NM_FENCE_RESET */
2462306a36Sopenharmony_ci	"panic",	/* O2NM_FENCE_PANIC */
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic inline void o2nm_lock_subsystem(void);
2862306a36Sopenharmony_cistatic inline void o2nm_unlock_subsystem(void);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct o2nm_node *o2nm_get_node_by_num(u8 node_num)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct o2nm_node *node = NULL;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (node_num >= O2NM_MAX_NODES || o2nm_single_cluster == NULL)
3562306a36Sopenharmony_ci		goto out;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	read_lock(&o2nm_single_cluster->cl_nodes_lock);
3862306a36Sopenharmony_ci	node = o2nm_single_cluster->cl_nodes[node_num];
3962306a36Sopenharmony_ci	if (node)
4062306a36Sopenharmony_ci		config_item_get(&node->nd_item);
4162306a36Sopenharmony_ci	read_unlock(&o2nm_single_cluster->cl_nodes_lock);
4262306a36Sopenharmony_ciout:
4362306a36Sopenharmony_ci	return node;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2nm_get_node_by_num);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ciint o2nm_configured_node_map(unsigned long *map, unsigned bytes)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct o2nm_cluster *cluster = o2nm_single_cluster;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (cluster == NULL)
5462306a36Sopenharmony_ci		return -EINVAL;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	read_lock(&cluster->cl_nodes_lock);
5762306a36Sopenharmony_ci	bitmap_copy(map, cluster->cl_nodes_bitmap, O2NM_MAX_NODES);
5862306a36Sopenharmony_ci	read_unlock(&cluster->cl_nodes_lock);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2nm_configured_node_map);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic struct o2nm_node *o2nm_node_ip_tree_lookup(struct o2nm_cluster *cluster,
6562306a36Sopenharmony_ci						  __be32 ip_needle,
6662306a36Sopenharmony_ci						  struct rb_node ***ret_p,
6762306a36Sopenharmony_ci						  struct rb_node **ret_parent)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
7062306a36Sopenharmony_ci	struct rb_node *parent = NULL;
7162306a36Sopenharmony_ci	struct o2nm_node *node, *ret = NULL;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	while (*p) {
7462306a36Sopenharmony_ci		int cmp;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		parent = *p;
7762306a36Sopenharmony_ci		node = rb_entry(parent, struct o2nm_node, nd_ip_node);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
8062306a36Sopenharmony_ci				sizeof(ip_needle));
8162306a36Sopenharmony_ci		if (cmp < 0)
8262306a36Sopenharmony_ci			p = &(*p)->rb_left;
8362306a36Sopenharmony_ci		else if (cmp > 0)
8462306a36Sopenharmony_ci			p = &(*p)->rb_right;
8562306a36Sopenharmony_ci		else {
8662306a36Sopenharmony_ci			ret = node;
8762306a36Sopenharmony_ci			break;
8862306a36Sopenharmony_ci		}
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (ret_p != NULL)
9262306a36Sopenharmony_ci		*ret_p = p;
9362306a36Sopenharmony_ci	if (ret_parent != NULL)
9462306a36Sopenharmony_ci		*ret_parent = parent;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return ret;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistruct o2nm_node *o2nm_get_node_by_ip(__be32 addr)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct o2nm_node *node = NULL;
10262306a36Sopenharmony_ci	struct o2nm_cluster *cluster = o2nm_single_cluster;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (cluster == NULL)
10562306a36Sopenharmony_ci		goto out;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	read_lock(&cluster->cl_nodes_lock);
10862306a36Sopenharmony_ci	node = o2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
10962306a36Sopenharmony_ci	if (node)
11062306a36Sopenharmony_ci		config_item_get(&node->nd_item);
11162306a36Sopenharmony_ci	read_unlock(&cluster->cl_nodes_lock);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciout:
11462306a36Sopenharmony_ci	return node;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2nm_get_node_by_ip);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_civoid o2nm_node_put(struct o2nm_node *node)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	config_item_put(&node->nd_item);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2nm_node_put);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_civoid o2nm_node_get(struct o2nm_node *node)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	config_item_get(&node->nd_item);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2nm_node_get);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciu8 o2nm_this_node(void)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	u8 node_num = O2NM_MAX_NODES;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (o2nm_single_cluster && o2nm_single_cluster->cl_has_local)
13562306a36Sopenharmony_ci		node_num = o2nm_single_cluster->cl_local_node;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	return node_num;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(o2nm_this_node);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* node configfs bits */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic struct o2nm_cluster *to_o2nm_cluster(struct config_item *item)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	return item ?
14662306a36Sopenharmony_ci		container_of(to_config_group(item), struct o2nm_cluster,
14762306a36Sopenharmony_ci			     cl_group)
14862306a36Sopenharmony_ci		: NULL;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic struct o2nm_node *to_o2nm_node(struct config_item *item)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	return item ? container_of(item, struct o2nm_node, nd_item) : NULL;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void o2nm_node_release(struct config_item *item)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct o2nm_node *node = to_o2nm_node(item);
15962306a36Sopenharmony_ci	kfree(node);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic ssize_t o2nm_node_num_show(struct config_item *item, char *page)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	return sprintf(page, "%d\n", to_o2nm_node(item)->nd_num);
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	/* through the first node_set .parent
17062306a36Sopenharmony_ci	 * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */
17162306a36Sopenharmony_ci	if (node->nd_item.ci_parent)
17262306a36Sopenharmony_ci		return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
17362306a36Sopenharmony_ci	else
17462306a36Sopenharmony_ci		return NULL;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cienum {
17862306a36Sopenharmony_ci	O2NM_NODE_ATTR_NUM = 0,
17962306a36Sopenharmony_ci	O2NM_NODE_ATTR_PORT,
18062306a36Sopenharmony_ci	O2NM_NODE_ATTR_ADDRESS,
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic ssize_t o2nm_node_num_store(struct config_item *item, const char *page,
18462306a36Sopenharmony_ci				   size_t count)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct o2nm_node *node = to_o2nm_node(item);
18762306a36Sopenharmony_ci	struct o2nm_cluster *cluster;
18862306a36Sopenharmony_ci	unsigned long tmp;
18962306a36Sopenharmony_ci	char *p = (char *)page;
19062306a36Sopenharmony_ci	int ret = 0;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	tmp = simple_strtoul(p, &p, 0);
19362306a36Sopenharmony_ci	if (!p || (*p && (*p != '\n')))
19462306a36Sopenharmony_ci		return -EINVAL;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (tmp >= O2NM_MAX_NODES)
19762306a36Sopenharmony_ci		return -ERANGE;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* once we're in the cl_nodes tree networking can look us up by
20062306a36Sopenharmony_ci	 * node number and try to use our address and port attributes
20162306a36Sopenharmony_ci	 * to connect to this node.. make sure that they've been set
20262306a36Sopenharmony_ci	 * before writing the node attribute? */
20362306a36Sopenharmony_ci	if (!test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
20462306a36Sopenharmony_ci	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
20562306a36Sopenharmony_ci		return -EINVAL; /* XXX */
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	o2nm_lock_subsystem();
20862306a36Sopenharmony_ci	cluster = to_o2nm_cluster_from_node(node);
20962306a36Sopenharmony_ci	if (!cluster) {
21062306a36Sopenharmony_ci		o2nm_unlock_subsystem();
21162306a36Sopenharmony_ci		return -EINVAL;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	write_lock(&cluster->cl_nodes_lock);
21562306a36Sopenharmony_ci	if (cluster->cl_nodes[tmp])
21662306a36Sopenharmony_ci		ret = -EEXIST;
21762306a36Sopenharmony_ci	else if (test_and_set_bit(O2NM_NODE_ATTR_NUM,
21862306a36Sopenharmony_ci			&node->nd_set_attributes))
21962306a36Sopenharmony_ci		ret = -EBUSY;
22062306a36Sopenharmony_ci	else  {
22162306a36Sopenharmony_ci		cluster->cl_nodes[tmp] = node;
22262306a36Sopenharmony_ci		node->nd_num = tmp;
22362306a36Sopenharmony_ci		set_bit(tmp, cluster->cl_nodes_bitmap);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	write_unlock(&cluster->cl_nodes_lock);
22662306a36Sopenharmony_ci	o2nm_unlock_subsystem();
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (ret)
22962306a36Sopenharmony_ci		return ret;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return count;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_cistatic ssize_t o2nm_node_ipv4_port_show(struct config_item *item, char *page)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	return sprintf(page, "%u\n", ntohs(to_o2nm_node(item)->nd_ipv4_port));
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic ssize_t o2nm_node_ipv4_port_store(struct config_item *item,
23962306a36Sopenharmony_ci					 const char *page, size_t count)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct o2nm_node *node = to_o2nm_node(item);
24262306a36Sopenharmony_ci	unsigned long tmp;
24362306a36Sopenharmony_ci	char *p = (char *)page;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	tmp = simple_strtoul(p, &p, 0);
24662306a36Sopenharmony_ci	if (!p || (*p && (*p != '\n')))
24762306a36Sopenharmony_ci		return -EINVAL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (tmp == 0)
25062306a36Sopenharmony_ci		return -EINVAL;
25162306a36Sopenharmony_ci	if (tmp >= (u16)-1)
25262306a36Sopenharmony_ci		return -ERANGE;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (test_and_set_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
25562306a36Sopenharmony_ci		return -EBUSY;
25662306a36Sopenharmony_ci	node->nd_ipv4_port = htons(tmp);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return count;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic ssize_t o2nm_node_ipv4_address_show(struct config_item *item, char *page)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	return sprintf(page, "%pI4\n", &to_o2nm_node(item)->nd_ipv4_address);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic ssize_t o2nm_node_ipv4_address_store(struct config_item *item,
26762306a36Sopenharmony_ci					    const char *page,
26862306a36Sopenharmony_ci					    size_t count)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct o2nm_node *node = to_o2nm_node(item);
27162306a36Sopenharmony_ci	struct o2nm_cluster *cluster;
27262306a36Sopenharmony_ci	int ret, i;
27362306a36Sopenharmony_ci	struct rb_node **p, *parent;
27462306a36Sopenharmony_ci	unsigned int octets[4];
27562306a36Sopenharmony_ci	__be32 ipv4_addr = 0;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
27862306a36Sopenharmony_ci		     &octets[1], &octets[0]);
27962306a36Sopenharmony_ci	if (ret != 4)
28062306a36Sopenharmony_ci		return -EINVAL;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(octets); i++) {
28362306a36Sopenharmony_ci		if (octets[i] > 255)
28462306a36Sopenharmony_ci			return -ERANGE;
28562306a36Sopenharmony_ci		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	o2nm_lock_subsystem();
28962306a36Sopenharmony_ci	cluster = to_o2nm_cluster_from_node(node);
29062306a36Sopenharmony_ci	if (!cluster) {
29162306a36Sopenharmony_ci		o2nm_unlock_subsystem();
29262306a36Sopenharmony_ci		return -EINVAL;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	ret = 0;
29662306a36Sopenharmony_ci	write_lock(&cluster->cl_nodes_lock);
29762306a36Sopenharmony_ci	if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
29862306a36Sopenharmony_ci		ret = -EEXIST;
29962306a36Sopenharmony_ci	else if (test_and_set_bit(O2NM_NODE_ATTR_ADDRESS,
30062306a36Sopenharmony_ci			&node->nd_set_attributes))
30162306a36Sopenharmony_ci		ret = -EBUSY;
30262306a36Sopenharmony_ci	else {
30362306a36Sopenharmony_ci		rb_link_node(&node->nd_ip_node, parent, p);
30462306a36Sopenharmony_ci		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	write_unlock(&cluster->cl_nodes_lock);
30762306a36Sopenharmony_ci	o2nm_unlock_subsystem();
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (ret)
31062306a36Sopenharmony_ci		return ret;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return count;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic ssize_t o2nm_node_local_show(struct config_item *item, char *page)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	return sprintf(page, "%d\n", to_o2nm_node(item)->nd_local);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic ssize_t o2nm_node_local_store(struct config_item *item, const char *page,
32362306a36Sopenharmony_ci				     size_t count)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct o2nm_node *node = to_o2nm_node(item);
32662306a36Sopenharmony_ci	struct o2nm_cluster *cluster;
32762306a36Sopenharmony_ci	unsigned long tmp;
32862306a36Sopenharmony_ci	char *p = (char *)page;
32962306a36Sopenharmony_ci	ssize_t ret;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	tmp = simple_strtoul(p, &p, 0);
33262306a36Sopenharmony_ci	if (!p || (*p && (*p != '\n')))
33362306a36Sopenharmony_ci		return -EINVAL;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	tmp = !!tmp; /* boolean of whether this node wants to be local */
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* setting local turns on networking rx for now so we require having
33862306a36Sopenharmony_ci	 * set everything else first */
33962306a36Sopenharmony_ci	if (!test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
34062306a36Sopenharmony_ci	    !test_bit(O2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
34162306a36Sopenharmony_ci	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
34262306a36Sopenharmony_ci		return -EINVAL; /* XXX */
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	o2nm_lock_subsystem();
34562306a36Sopenharmony_ci	cluster = to_o2nm_cluster_from_node(node);
34662306a36Sopenharmony_ci	if (!cluster) {
34762306a36Sopenharmony_ci		ret = -EINVAL;
34862306a36Sopenharmony_ci		goto out;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* the only failure case is trying to set a new local node
35262306a36Sopenharmony_ci	 * when a different one is already set */
35362306a36Sopenharmony_ci	if (tmp && tmp == cluster->cl_has_local &&
35462306a36Sopenharmony_ci	    cluster->cl_local_node != node->nd_num) {
35562306a36Sopenharmony_ci		ret = -EBUSY;
35662306a36Sopenharmony_ci		goto out;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* bring up the rx thread if we're setting the new local node. */
36062306a36Sopenharmony_ci	if (tmp && !cluster->cl_has_local) {
36162306a36Sopenharmony_ci		ret = o2net_start_listening(node);
36262306a36Sopenharmony_ci		if (ret)
36362306a36Sopenharmony_ci			goto out;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (!tmp && cluster->cl_has_local &&
36762306a36Sopenharmony_ci	    cluster->cl_local_node == node->nd_num) {
36862306a36Sopenharmony_ci		o2net_stop_listening(node);
36962306a36Sopenharmony_ci		cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	node->nd_local = tmp;
37362306a36Sopenharmony_ci	if (node->nd_local) {
37462306a36Sopenharmony_ci		cluster->cl_has_local = tmp;
37562306a36Sopenharmony_ci		cluster->cl_local_node = node->nd_num;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	ret = count;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciout:
38162306a36Sopenharmony_ci	o2nm_unlock_subsystem();
38262306a36Sopenharmony_ci	return ret;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_node_, num);
38662306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_node_, ipv4_port);
38762306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_node_, ipv4_address);
38862306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_node_, local);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic struct configfs_attribute *o2nm_node_attrs[] = {
39162306a36Sopenharmony_ci	&o2nm_node_attr_num,
39262306a36Sopenharmony_ci	&o2nm_node_attr_ipv4_port,
39362306a36Sopenharmony_ci	&o2nm_node_attr_ipv4_address,
39462306a36Sopenharmony_ci	&o2nm_node_attr_local,
39562306a36Sopenharmony_ci	NULL,
39662306a36Sopenharmony_ci};
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic struct configfs_item_operations o2nm_node_item_ops = {
39962306a36Sopenharmony_ci	.release		= o2nm_node_release,
40062306a36Sopenharmony_ci};
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic const struct config_item_type o2nm_node_type = {
40362306a36Sopenharmony_ci	.ct_item_ops	= &o2nm_node_item_ops,
40462306a36Sopenharmony_ci	.ct_attrs	= o2nm_node_attrs,
40562306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
40662306a36Sopenharmony_ci};
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci/* node set */
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistruct o2nm_node_group {
41162306a36Sopenharmony_ci	struct config_group ns_group;
41262306a36Sopenharmony_ci	/* some stuff? */
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci#if 0
41662306a36Sopenharmony_cistatic struct o2nm_node_group *to_o2nm_node_group(struct config_group *group)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	return group ?
41962306a36Sopenharmony_ci		container_of(group, struct o2nm_node_group, ns_group)
42062306a36Sopenharmony_ci		: NULL;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci#endif
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic ssize_t o2nm_cluster_attr_write(const char *page, ssize_t count,
42562306a36Sopenharmony_ci                                       unsigned int *val)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	unsigned long tmp;
42862306a36Sopenharmony_ci	char *p = (char *)page;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	tmp = simple_strtoul(p, &p, 0);
43162306a36Sopenharmony_ci	if (!p || (*p && (*p != '\n')))
43262306a36Sopenharmony_ci		return -EINVAL;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (tmp == 0)
43562306a36Sopenharmony_ci		return -EINVAL;
43662306a36Sopenharmony_ci	if (tmp >= (u32)-1)
43762306a36Sopenharmony_ci		return -ERANGE;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	*val = tmp;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return count;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic ssize_t o2nm_cluster_idle_timeout_ms_show(struct config_item *item,
44562306a36Sopenharmony_ci	char *page)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	return sprintf(page, "%u\n", to_o2nm_cluster(item)->cl_idle_timeout_ms);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic ssize_t o2nm_cluster_idle_timeout_ms_store(struct config_item *item,
45162306a36Sopenharmony_ci	const char *page, size_t count)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
45462306a36Sopenharmony_ci	ssize_t ret;
45562306a36Sopenharmony_ci	unsigned int val;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	ret =  o2nm_cluster_attr_write(page, count, &val);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (ret > 0) {
46062306a36Sopenharmony_ci		if (cluster->cl_idle_timeout_ms != val
46162306a36Sopenharmony_ci			&& o2net_num_connected_peers()) {
46262306a36Sopenharmony_ci			mlog(ML_NOTICE,
46362306a36Sopenharmony_ci			     "o2net: cannot change idle timeout after "
46462306a36Sopenharmony_ci			     "the first peer has agreed to it."
46562306a36Sopenharmony_ci			     "  %d connected peers\n",
46662306a36Sopenharmony_ci			     o2net_num_connected_peers());
46762306a36Sopenharmony_ci			ret = -EINVAL;
46862306a36Sopenharmony_ci		} else if (val <= cluster->cl_keepalive_delay_ms) {
46962306a36Sopenharmony_ci			mlog(ML_NOTICE, "o2net: idle timeout must be larger "
47062306a36Sopenharmony_ci			     "than keepalive delay\n");
47162306a36Sopenharmony_ci			ret = -EINVAL;
47262306a36Sopenharmony_ci		} else {
47362306a36Sopenharmony_ci			cluster->cl_idle_timeout_ms = val;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return ret;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic ssize_t o2nm_cluster_keepalive_delay_ms_show(
48162306a36Sopenharmony_ci	struct config_item *item, char *page)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	return sprintf(page, "%u\n",
48462306a36Sopenharmony_ci			to_o2nm_cluster(item)->cl_keepalive_delay_ms);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic ssize_t o2nm_cluster_keepalive_delay_ms_store(
48862306a36Sopenharmony_ci	struct config_item *item, const char *page, size_t count)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
49162306a36Sopenharmony_ci	ssize_t ret;
49262306a36Sopenharmony_ci	unsigned int val;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	ret =  o2nm_cluster_attr_write(page, count, &val);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (ret > 0) {
49762306a36Sopenharmony_ci		if (cluster->cl_keepalive_delay_ms != val
49862306a36Sopenharmony_ci		    && o2net_num_connected_peers()) {
49962306a36Sopenharmony_ci			mlog(ML_NOTICE,
50062306a36Sopenharmony_ci			     "o2net: cannot change keepalive delay after"
50162306a36Sopenharmony_ci			     " the first peer has agreed to it."
50262306a36Sopenharmony_ci			     "  %d connected peers\n",
50362306a36Sopenharmony_ci			     o2net_num_connected_peers());
50462306a36Sopenharmony_ci			ret = -EINVAL;
50562306a36Sopenharmony_ci		} else if (val >= cluster->cl_idle_timeout_ms) {
50662306a36Sopenharmony_ci			mlog(ML_NOTICE, "o2net: keepalive delay must be "
50762306a36Sopenharmony_ci			     "smaller than idle timeout\n");
50862306a36Sopenharmony_ci			ret = -EINVAL;
50962306a36Sopenharmony_ci		} else {
51062306a36Sopenharmony_ci			cluster->cl_keepalive_delay_ms = val;
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return ret;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic ssize_t o2nm_cluster_reconnect_delay_ms_show(
51862306a36Sopenharmony_ci	struct config_item *item, char *page)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	return sprintf(page, "%u\n",
52162306a36Sopenharmony_ci			to_o2nm_cluster(item)->cl_reconnect_delay_ms);
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic ssize_t o2nm_cluster_reconnect_delay_ms_store(
52562306a36Sopenharmony_ci	struct config_item *item, const char *page, size_t count)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	return o2nm_cluster_attr_write(page, count,
52862306a36Sopenharmony_ci                               &to_o2nm_cluster(item)->cl_reconnect_delay_ms);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic ssize_t o2nm_cluster_fence_method_show(
53262306a36Sopenharmony_ci	struct config_item *item, char *page)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
53562306a36Sopenharmony_ci	ssize_t ret = 0;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (cluster)
53862306a36Sopenharmony_ci		ret = sprintf(page, "%s\n",
53962306a36Sopenharmony_ci			      o2nm_fence_method_desc[cluster->cl_fence_method]);
54062306a36Sopenharmony_ci	return ret;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic ssize_t o2nm_cluster_fence_method_store(
54462306a36Sopenharmony_ci	struct config_item *item, const char *page, size_t count)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	unsigned int i;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (page[count - 1] != '\n')
54962306a36Sopenharmony_ci		goto bail;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	for (i = 0; i < O2NM_FENCE_METHODS; ++i) {
55262306a36Sopenharmony_ci		if (count != strlen(o2nm_fence_method_desc[i]) + 1)
55362306a36Sopenharmony_ci			continue;
55462306a36Sopenharmony_ci		if (strncasecmp(page, o2nm_fence_method_desc[i], count - 1))
55562306a36Sopenharmony_ci			continue;
55662306a36Sopenharmony_ci		if (to_o2nm_cluster(item)->cl_fence_method != i) {
55762306a36Sopenharmony_ci			printk(KERN_INFO "ocfs2: Changing fence method to %s\n",
55862306a36Sopenharmony_ci			       o2nm_fence_method_desc[i]);
55962306a36Sopenharmony_ci			to_o2nm_cluster(item)->cl_fence_method = i;
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci		return count;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cibail:
56562306a36Sopenharmony_ci	return -EINVAL;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_cluster_, idle_timeout_ms);
56962306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_cluster_, keepalive_delay_ms);
57062306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_cluster_, reconnect_delay_ms);
57162306a36Sopenharmony_ciCONFIGFS_ATTR(o2nm_cluster_, fence_method);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic struct configfs_attribute *o2nm_cluster_attrs[] = {
57462306a36Sopenharmony_ci	&o2nm_cluster_attr_idle_timeout_ms,
57562306a36Sopenharmony_ci	&o2nm_cluster_attr_keepalive_delay_ms,
57662306a36Sopenharmony_ci	&o2nm_cluster_attr_reconnect_delay_ms,
57762306a36Sopenharmony_ci	&o2nm_cluster_attr_fence_method,
57862306a36Sopenharmony_ci	NULL,
57962306a36Sopenharmony_ci};
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic struct config_item *o2nm_node_group_make_item(struct config_group *group,
58262306a36Sopenharmony_ci						     const char *name)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct o2nm_node *node = NULL;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (strlen(name) > O2NM_MAX_NAME_LEN)
58762306a36Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL);
59062306a36Sopenharmony_ci	if (node == NULL)
59162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
59462306a36Sopenharmony_ci	config_item_init_type_name(&node->nd_item, name, &o2nm_node_type);
59562306a36Sopenharmony_ci	spin_lock_init(&node->nd_lock);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	mlog(ML_CLUSTER, "o2nm: Registering node %s\n", name);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return &node->nd_item;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic void o2nm_node_group_drop_item(struct config_group *group,
60362306a36Sopenharmony_ci				      struct config_item *item)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct o2nm_node *node = to_o2nm_node(item);
60662306a36Sopenharmony_ci	struct o2nm_cluster *cluster = to_o2nm_cluster(group->cg_item.ci_parent);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (cluster->cl_nodes[node->nd_num] == node) {
60962306a36Sopenharmony_ci		o2net_disconnect_node(node);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		if (cluster->cl_has_local &&
61262306a36Sopenharmony_ci		    (cluster->cl_local_node == node->nd_num)) {
61362306a36Sopenharmony_ci			cluster->cl_has_local = 0;
61462306a36Sopenharmony_ci			cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
61562306a36Sopenharmony_ci			o2net_stop_listening(node);
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* XXX call into net to stop this node from trading messages */
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	write_lock(&cluster->cl_nodes_lock);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/* XXX sloppy */
62462306a36Sopenharmony_ci	if (node->nd_ipv4_address)
62562306a36Sopenharmony_ci		rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* nd_num might be 0 if the node number hasn't been set.. */
62862306a36Sopenharmony_ci	if (cluster->cl_nodes[node->nd_num] == node) {
62962306a36Sopenharmony_ci		cluster->cl_nodes[node->nd_num] = NULL;
63062306a36Sopenharmony_ci		clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci	write_unlock(&cluster->cl_nodes_lock);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	mlog(ML_CLUSTER, "o2nm: Unregistered node %s\n",
63562306a36Sopenharmony_ci	     config_item_name(&node->nd_item));
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	config_item_put(item);
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic struct configfs_group_operations o2nm_node_group_group_ops = {
64162306a36Sopenharmony_ci	.make_item	= o2nm_node_group_make_item,
64262306a36Sopenharmony_ci	.drop_item	= o2nm_node_group_drop_item,
64362306a36Sopenharmony_ci};
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic const struct config_item_type o2nm_node_group_type = {
64662306a36Sopenharmony_ci	.ct_group_ops	= &o2nm_node_group_group_ops,
64762306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
64862306a36Sopenharmony_ci};
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci/* cluster */
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void o2nm_cluster_release(struct config_item *item)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	kfree(cluster);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic struct configfs_item_operations o2nm_cluster_item_ops = {
66062306a36Sopenharmony_ci	.release	= o2nm_cluster_release,
66162306a36Sopenharmony_ci};
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic const struct config_item_type o2nm_cluster_type = {
66462306a36Sopenharmony_ci	.ct_item_ops	= &o2nm_cluster_item_ops,
66562306a36Sopenharmony_ci	.ct_attrs	= o2nm_cluster_attrs,
66662306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
66762306a36Sopenharmony_ci};
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci/* cluster set */
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistruct o2nm_cluster_group {
67262306a36Sopenharmony_ci	struct configfs_subsystem cs_subsys;
67362306a36Sopenharmony_ci	/* some stuff? */
67462306a36Sopenharmony_ci};
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci#if 0
67762306a36Sopenharmony_cistatic struct o2nm_cluster_group *to_o2nm_cluster_group(struct config_group *group)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	return group ?
68062306a36Sopenharmony_ci		container_of(to_configfs_subsystem(group), struct o2nm_cluster_group, cs_subsys)
68162306a36Sopenharmony_ci	       : NULL;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci#endif
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic struct config_group *o2nm_cluster_group_make_group(struct config_group *group,
68662306a36Sopenharmony_ci							  const char *name)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct o2nm_cluster *cluster = NULL;
68962306a36Sopenharmony_ci	struct o2nm_node_group *ns = NULL;
69062306a36Sopenharmony_ci	struct config_group *o2hb_group = NULL, *ret = NULL;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* this runs under the parent dir's i_rwsem; there can be only
69362306a36Sopenharmony_ci	 * one caller in here at a time */
69462306a36Sopenharmony_ci	if (o2nm_single_cluster)
69562306a36Sopenharmony_ci		return ERR_PTR(-ENOSPC);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
69862306a36Sopenharmony_ci	ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
69962306a36Sopenharmony_ci	o2hb_group = o2hb_alloc_hb_set();
70062306a36Sopenharmony_ci	if (cluster == NULL || ns == NULL || o2hb_group == NULL)
70162306a36Sopenharmony_ci		goto out;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	config_group_init_type_name(&cluster->cl_group, name,
70462306a36Sopenharmony_ci				    &o2nm_cluster_type);
70562306a36Sopenharmony_ci	configfs_add_default_group(&ns->ns_group, &cluster->cl_group);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	config_group_init_type_name(&ns->ns_group, "node",
70862306a36Sopenharmony_ci				    &o2nm_node_group_type);
70962306a36Sopenharmony_ci	configfs_add_default_group(o2hb_group, &cluster->cl_group);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	rwlock_init(&cluster->cl_nodes_lock);
71262306a36Sopenharmony_ci	cluster->cl_node_ip_tree = RB_ROOT;
71362306a36Sopenharmony_ci	cluster->cl_reconnect_delay_ms = O2NET_RECONNECT_DELAY_MS_DEFAULT;
71462306a36Sopenharmony_ci	cluster->cl_idle_timeout_ms    = O2NET_IDLE_TIMEOUT_MS_DEFAULT;
71562306a36Sopenharmony_ci	cluster->cl_keepalive_delay_ms = O2NET_KEEPALIVE_DELAY_MS_DEFAULT;
71662306a36Sopenharmony_ci	cluster->cl_fence_method       = O2NM_FENCE_RESET;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	ret = &cluster->cl_group;
71962306a36Sopenharmony_ci	o2nm_single_cluster = cluster;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ciout:
72262306a36Sopenharmony_ci	if (ret == NULL) {
72362306a36Sopenharmony_ci		kfree(cluster);
72462306a36Sopenharmony_ci		kfree(ns);
72562306a36Sopenharmony_ci		o2hb_free_hb_set(o2hb_group);
72662306a36Sopenharmony_ci		ret = ERR_PTR(-ENOMEM);
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return ret;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic void o2nm_cluster_group_drop_item(struct config_group *group, struct config_item *item)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	BUG_ON(o2nm_single_cluster != cluster);
73762306a36Sopenharmony_ci	o2nm_single_cluster = NULL;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	configfs_remove_default_groups(&cluster->cl_group);
74062306a36Sopenharmony_ci	config_item_put(item);
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic struct configfs_group_operations o2nm_cluster_group_group_ops = {
74462306a36Sopenharmony_ci	.make_group	= o2nm_cluster_group_make_group,
74562306a36Sopenharmony_ci	.drop_item	= o2nm_cluster_group_drop_item,
74662306a36Sopenharmony_ci};
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic const struct config_item_type o2nm_cluster_group_type = {
74962306a36Sopenharmony_ci	.ct_group_ops	= &o2nm_cluster_group_group_ops,
75062306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
75162306a36Sopenharmony_ci};
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic struct o2nm_cluster_group o2nm_cluster_group = {
75462306a36Sopenharmony_ci	.cs_subsys = {
75562306a36Sopenharmony_ci		.su_group = {
75662306a36Sopenharmony_ci			.cg_item = {
75762306a36Sopenharmony_ci				.ci_namebuf = "cluster",
75862306a36Sopenharmony_ci				.ci_type = &o2nm_cluster_group_type,
75962306a36Sopenharmony_ci			},
76062306a36Sopenharmony_ci		},
76162306a36Sopenharmony_ci	},
76262306a36Sopenharmony_ci};
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic inline void o2nm_lock_subsystem(void)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex);
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic inline void o2nm_unlock_subsystem(void)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ciint o2nm_depend_item(struct config_item *item)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_civoid o2nm_undepend_item(struct config_item *item)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	configfs_undepend_item(item);
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ciint o2nm_depend_this_node(void)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	int ret = 0;
78762306a36Sopenharmony_ci	struct o2nm_node *local_node;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	local_node = o2nm_get_node_by_num(o2nm_this_node());
79062306a36Sopenharmony_ci	if (!local_node) {
79162306a36Sopenharmony_ci		ret = -EINVAL;
79262306a36Sopenharmony_ci		goto out;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ret = o2nm_depend_item(&local_node->nd_item);
79662306a36Sopenharmony_ci	o2nm_node_put(local_node);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ciout:
79962306a36Sopenharmony_ci	return ret;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_civoid o2nm_undepend_this_node(void)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	struct o2nm_node *local_node;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	local_node = o2nm_get_node_by_num(o2nm_this_node());
80762306a36Sopenharmony_ci	BUG_ON(!local_node);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	o2nm_undepend_item(&local_node->nd_item);
81062306a36Sopenharmony_ci	o2nm_node_put(local_node);
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void __exit exit_o2nm(void)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	/* XXX sync with hb callbacks and shut down hb? */
81762306a36Sopenharmony_ci	o2net_unregister_hb_callbacks();
81862306a36Sopenharmony_ci	configfs_unregister_subsystem(&o2nm_cluster_group.cs_subsys);
81962306a36Sopenharmony_ci	o2cb_sys_shutdown();
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	o2net_exit();
82262306a36Sopenharmony_ci	o2hb_exit();
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int __init init_o2nm(void)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	int ret;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	o2hb_init();
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	ret = o2net_init();
83262306a36Sopenharmony_ci	if (ret)
83362306a36Sopenharmony_ci		goto out_o2hb;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	ret = o2net_register_hb_callbacks();
83662306a36Sopenharmony_ci	if (ret)
83762306a36Sopenharmony_ci		goto out_o2net;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	config_group_init(&o2nm_cluster_group.cs_subsys.su_group);
84062306a36Sopenharmony_ci	mutex_init(&o2nm_cluster_group.cs_subsys.su_mutex);
84162306a36Sopenharmony_ci	ret = configfs_register_subsystem(&o2nm_cluster_group.cs_subsys);
84262306a36Sopenharmony_ci	if (ret) {
84362306a36Sopenharmony_ci		printk(KERN_ERR "nodemanager: Registration returned %d\n", ret);
84462306a36Sopenharmony_ci		goto out_callbacks;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	ret = o2cb_sys_init();
84862306a36Sopenharmony_ci	if (!ret)
84962306a36Sopenharmony_ci		goto out;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	configfs_unregister_subsystem(&o2nm_cluster_group.cs_subsys);
85262306a36Sopenharmony_ciout_callbacks:
85362306a36Sopenharmony_ci	o2net_unregister_hb_callbacks();
85462306a36Sopenharmony_ciout_o2net:
85562306a36Sopenharmony_ci	o2net_exit();
85662306a36Sopenharmony_ciout_o2hb:
85762306a36Sopenharmony_ci	o2hb_exit();
85862306a36Sopenharmony_ciout:
85962306a36Sopenharmony_ci	return ret;
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ciMODULE_AUTHOR("Oracle");
86362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
86462306a36Sopenharmony_ciMODULE_DESCRIPTION("OCFS2 cluster management");
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cimodule_init(init_o2nm)
86762306a36Sopenharmony_cimodule_exit(exit_o2nm)
868