xref: /openbmc/linux/fs/ocfs2/cluster/nodemanager.c (revision 328970de)
1328970deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20c83ed8eSKurt Hackel /* -*- mode: c; c-basic-offset: 8; -*-
30c83ed8eSKurt Hackel  * vim: noexpandtab sw=8 ts=8 sts=0:
40c83ed8eSKurt Hackel  *
50c83ed8eSKurt Hackel  * Copyright (C) 2004, 2005 Oracle.  All rights reserved.
60c83ed8eSKurt Hackel  */
70c83ed8eSKurt Hackel 
85a0e3ad6STejun Heo #include <linux/slab.h>
90c83ed8eSKurt Hackel #include <linux/kernel.h>
100c83ed8eSKurt Hackel #include <linux/module.h>
110c83ed8eSKurt Hackel #include <linux/configfs.h>
120c83ed8eSKurt Hackel 
130c83ed8eSKurt Hackel #include "tcp.h"
140c83ed8eSKurt Hackel #include "nodemanager.h"
150c83ed8eSKurt Hackel #include "heartbeat.h"
160c83ed8eSKurt Hackel #include "masklog.h"
170c83ed8eSKurt Hackel #include "sys.h"
180c83ed8eSKurt Hackel 
190c83ed8eSKurt Hackel /* for now we operate under the assertion that there can be only one
200c83ed8eSKurt Hackel  * cluster active at a time.  Changing this will require trickling
210c83ed8eSKurt Hackel  * cluster references throughout where nodes are looked up */
22296b75edSAndrew Beekhof struct o2nm_cluster *o2nm_single_cluster = NULL;
230c83ed8eSKurt Hackel 
24480bd564SColin Ian King static const char *o2nm_fence_method_desc[O2NM_FENCE_METHODS] = {
25f6656d26SSunil Mushran 	"reset",	/* O2NM_FENCE_RESET */
26f6656d26SSunil Mushran 	"panic",	/* O2NM_FENCE_PANIC */
27f6656d26SSunil Mushran };
280c83ed8eSKurt Hackel 
29853bc26aSalex chen static inline void o2nm_lock_subsystem(void);
30853bc26aSalex chen static inline void o2nm_unlock_subsystem(void);
31853bc26aSalex chen 
320c83ed8eSKurt Hackel struct o2nm_node *o2nm_get_node_by_num(u8 node_num)
330c83ed8eSKurt Hackel {
340c83ed8eSKurt Hackel 	struct o2nm_node *node = NULL;
350c83ed8eSKurt Hackel 
360c83ed8eSKurt Hackel 	if (node_num >= O2NM_MAX_NODES || o2nm_single_cluster == NULL)
370c83ed8eSKurt Hackel 		goto out;
380c83ed8eSKurt Hackel 
390c83ed8eSKurt Hackel 	read_lock(&o2nm_single_cluster->cl_nodes_lock);
400c83ed8eSKurt Hackel 	node = o2nm_single_cluster->cl_nodes[node_num];
410c83ed8eSKurt Hackel 	if (node)
420c83ed8eSKurt Hackel 		config_item_get(&node->nd_item);
430c83ed8eSKurt Hackel 	read_unlock(&o2nm_single_cluster->cl_nodes_lock);
440c83ed8eSKurt Hackel out:
450c83ed8eSKurt Hackel 	return node;
460c83ed8eSKurt Hackel }
470c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_get_node_by_num);
480c83ed8eSKurt Hackel 
490c83ed8eSKurt Hackel int o2nm_configured_node_map(unsigned long *map, unsigned bytes)
500c83ed8eSKurt Hackel {
510c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = o2nm_single_cluster;
520c83ed8eSKurt Hackel 
530c83ed8eSKurt Hackel 	BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
540c83ed8eSKurt Hackel 
550c83ed8eSKurt Hackel 	if (cluster == NULL)
560c83ed8eSKurt Hackel 		return -EINVAL;
570c83ed8eSKurt Hackel 
580c83ed8eSKurt Hackel 	read_lock(&cluster->cl_nodes_lock);
590c83ed8eSKurt Hackel 	memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
600c83ed8eSKurt Hackel 	read_unlock(&cluster->cl_nodes_lock);
610c83ed8eSKurt Hackel 
620c83ed8eSKurt Hackel 	return 0;
630c83ed8eSKurt Hackel }
640c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_configured_node_map);
650c83ed8eSKurt Hackel 
660c83ed8eSKurt Hackel static struct o2nm_node *o2nm_node_ip_tree_lookup(struct o2nm_cluster *cluster,
670c83ed8eSKurt Hackel 						  __be32 ip_needle,
680c83ed8eSKurt Hackel 						  struct rb_node ***ret_p,
690c83ed8eSKurt Hackel 						  struct rb_node **ret_parent)
700c83ed8eSKurt Hackel {
710c83ed8eSKurt Hackel 	struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
720c83ed8eSKurt Hackel 	struct rb_node *parent = NULL;
730c83ed8eSKurt Hackel 	struct o2nm_node *node, *ret = NULL;
740c83ed8eSKurt Hackel 
750c83ed8eSKurt Hackel 	while (*p) {
7679cd22d3SAkinobu Mita 		int cmp;
7779cd22d3SAkinobu Mita 
780c83ed8eSKurt Hackel 		parent = *p;
790c83ed8eSKurt Hackel 		node = rb_entry(parent, struct o2nm_node, nd_ip_node);
800c83ed8eSKurt Hackel 
8179cd22d3SAkinobu Mita 		cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
8279cd22d3SAkinobu Mita 				sizeof(ip_needle));
8379cd22d3SAkinobu Mita 		if (cmp < 0)
840c83ed8eSKurt Hackel 			p = &(*p)->rb_left;
8579cd22d3SAkinobu Mita 		else if (cmp > 0)
860c83ed8eSKurt Hackel 			p = &(*p)->rb_right;
870c83ed8eSKurt Hackel 		else {
880c83ed8eSKurt Hackel 			ret = node;
890c83ed8eSKurt Hackel 			break;
900c83ed8eSKurt Hackel 		}
910c83ed8eSKurt Hackel 	}
920c83ed8eSKurt Hackel 
930c83ed8eSKurt Hackel 	if (ret_p != NULL)
940c83ed8eSKurt Hackel 		*ret_p = p;
950c83ed8eSKurt Hackel 	if (ret_parent != NULL)
960c83ed8eSKurt Hackel 		*ret_parent = parent;
970c83ed8eSKurt Hackel 
980c83ed8eSKurt Hackel 	return ret;
990c83ed8eSKurt Hackel }
1000c83ed8eSKurt Hackel 
1010c83ed8eSKurt Hackel struct o2nm_node *o2nm_get_node_by_ip(__be32 addr)
1020c83ed8eSKurt Hackel {
1030c83ed8eSKurt Hackel 	struct o2nm_node *node = NULL;
1040c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = o2nm_single_cluster;
1050c83ed8eSKurt Hackel 
1060c83ed8eSKurt Hackel 	if (cluster == NULL)
1070c83ed8eSKurt Hackel 		goto out;
1080c83ed8eSKurt Hackel 
1090c83ed8eSKurt Hackel 	read_lock(&cluster->cl_nodes_lock);
1100c83ed8eSKurt Hackel 	node = o2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
1110c83ed8eSKurt Hackel 	if (node)
1120c83ed8eSKurt Hackel 		config_item_get(&node->nd_item);
1130c83ed8eSKurt Hackel 	read_unlock(&cluster->cl_nodes_lock);
1140c83ed8eSKurt Hackel 
1150c83ed8eSKurt Hackel out:
1160c83ed8eSKurt Hackel 	return node;
1170c83ed8eSKurt Hackel }
1180c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_get_node_by_ip);
1190c83ed8eSKurt Hackel 
1200c83ed8eSKurt Hackel void o2nm_node_put(struct o2nm_node *node)
1210c83ed8eSKurt Hackel {
1220c83ed8eSKurt Hackel 	config_item_put(&node->nd_item);
1230c83ed8eSKurt Hackel }
1240c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_node_put);
1250c83ed8eSKurt Hackel 
1260c83ed8eSKurt Hackel void o2nm_node_get(struct o2nm_node *node)
1270c83ed8eSKurt Hackel {
1280c83ed8eSKurt Hackel 	config_item_get(&node->nd_item);
1290c83ed8eSKurt Hackel }
1300c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_node_get);
1310c83ed8eSKurt Hackel 
1320c83ed8eSKurt Hackel u8 o2nm_this_node(void)
1330c83ed8eSKurt Hackel {
1340c83ed8eSKurt Hackel 	u8 node_num = O2NM_MAX_NODES;
1350c83ed8eSKurt Hackel 
1360c83ed8eSKurt Hackel 	if (o2nm_single_cluster && o2nm_single_cluster->cl_has_local)
1370c83ed8eSKurt Hackel 		node_num = o2nm_single_cluster->cl_local_node;
1380c83ed8eSKurt Hackel 
1390c83ed8eSKurt Hackel 	return node_num;
1400c83ed8eSKurt Hackel }
1410c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_this_node);
1420c83ed8eSKurt Hackel 
1430c83ed8eSKurt Hackel /* node configfs bits */
1440c83ed8eSKurt Hackel 
1450c83ed8eSKurt Hackel static struct o2nm_cluster *to_o2nm_cluster(struct config_item *item)
1460c83ed8eSKurt Hackel {
1470c83ed8eSKurt Hackel 	return item ?
1480c83ed8eSKurt Hackel 		container_of(to_config_group(item), struct o2nm_cluster,
1490c83ed8eSKurt Hackel 			     cl_group)
1500c83ed8eSKurt Hackel 		: NULL;
1510c83ed8eSKurt Hackel }
1520c83ed8eSKurt Hackel 
1530c83ed8eSKurt Hackel static struct o2nm_node *to_o2nm_node(struct config_item *item)
1540c83ed8eSKurt Hackel {
1550c83ed8eSKurt Hackel 	return item ? container_of(item, struct o2nm_node, nd_item) : NULL;
1560c83ed8eSKurt Hackel }
1570c83ed8eSKurt Hackel 
1580c83ed8eSKurt Hackel static void o2nm_node_release(struct config_item *item)
1590c83ed8eSKurt Hackel {
1600c83ed8eSKurt Hackel 	struct o2nm_node *node = to_o2nm_node(item);
1610c83ed8eSKurt Hackel 	kfree(node);
1620c83ed8eSKurt Hackel }
1630c83ed8eSKurt Hackel 
16445b99773SChristoph Hellwig static ssize_t o2nm_node_num_show(struct config_item *item, char *page)
1650c83ed8eSKurt Hackel {
16645b99773SChristoph Hellwig 	return sprintf(page, "%d\n", to_o2nm_node(item)->nd_num);
1670c83ed8eSKurt Hackel }
1680c83ed8eSKurt Hackel 
1690c83ed8eSKurt Hackel static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node)
1700c83ed8eSKurt Hackel {
1710c83ed8eSKurt Hackel 	/* through the first node_set .parent
1720c83ed8eSKurt Hackel 	 * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */
173853bc26aSalex chen 	if (node->nd_item.ci_parent)
1740c83ed8eSKurt Hackel 		return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
175853bc26aSalex chen 	else
176853bc26aSalex chen 		return NULL;
1770c83ed8eSKurt Hackel }
1780c83ed8eSKurt Hackel 
1790c83ed8eSKurt Hackel enum {
1800c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_NUM = 0,
1810c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_PORT,
1820c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_ADDRESS,
1830c83ed8eSKurt Hackel };
1840c83ed8eSKurt Hackel 
18545b99773SChristoph Hellwig static ssize_t o2nm_node_num_store(struct config_item *item, const char *page,
1860c83ed8eSKurt Hackel 				   size_t count)
1870c83ed8eSKurt Hackel {
18845b99773SChristoph Hellwig 	struct o2nm_node *node = to_o2nm_node(item);
189853bc26aSalex chen 	struct o2nm_cluster *cluster;
1900c83ed8eSKurt Hackel 	unsigned long tmp;
1910c83ed8eSKurt Hackel 	char *p = (char *)page;
19213a83fc9SChristoph Hellwig 	int ret = 0;
1930c83ed8eSKurt Hackel 
1940c83ed8eSKurt Hackel 	tmp = simple_strtoul(p, &p, 0);
1950c83ed8eSKurt Hackel 	if (!p || (*p && (*p != '\n')))
1960c83ed8eSKurt Hackel 		return -EINVAL;
1970c83ed8eSKurt Hackel 
1980c83ed8eSKurt Hackel 	if (tmp >= O2NM_MAX_NODES)
1990c83ed8eSKurt Hackel 		return -ERANGE;
2000c83ed8eSKurt Hackel 
2010c83ed8eSKurt Hackel 	/* once we're in the cl_nodes tree networking can look us up by
2020c83ed8eSKurt Hackel 	 * node number and try to use our address and port attributes
2030c83ed8eSKurt Hackel 	 * to connect to this node.. make sure that they've been set
2040c83ed8eSKurt Hackel 	 * before writing the node attribute? */
2050c83ed8eSKurt Hackel 	if (!test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
2060c83ed8eSKurt Hackel 	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
2070c83ed8eSKurt Hackel 		return -EINVAL; /* XXX */
2080c83ed8eSKurt Hackel 
209853bc26aSalex chen 	o2nm_lock_subsystem();
210853bc26aSalex chen 	cluster = to_o2nm_cluster_from_node(node);
211853bc26aSalex chen 	if (!cluster) {
212853bc26aSalex chen 		o2nm_unlock_subsystem();
213853bc26aSalex chen 		return -EINVAL;
214853bc26aSalex chen 	}
215853bc26aSalex chen 
2160c83ed8eSKurt Hackel 	write_lock(&cluster->cl_nodes_lock);
2170c83ed8eSKurt Hackel 	if (cluster->cl_nodes[tmp])
21813a83fc9SChristoph Hellwig 		ret = -EEXIST;
21913a83fc9SChristoph Hellwig 	else if (test_and_set_bit(O2NM_NODE_ATTR_NUM,
22013a83fc9SChristoph Hellwig 			&node->nd_set_attributes))
22113a83fc9SChristoph Hellwig 		ret = -EBUSY;
2220c83ed8eSKurt Hackel 	else  {
2230c83ed8eSKurt Hackel 		cluster->cl_nodes[tmp] = node;
2240c83ed8eSKurt Hackel 		node->nd_num = tmp;
2250c83ed8eSKurt Hackel 		set_bit(tmp, cluster->cl_nodes_bitmap);
2260c83ed8eSKurt Hackel 	}
2270c83ed8eSKurt Hackel 	write_unlock(&cluster->cl_nodes_lock);
228853bc26aSalex chen 	o2nm_unlock_subsystem();
229853bc26aSalex chen 
23013a83fc9SChristoph Hellwig 	if (ret)
23113a83fc9SChristoph Hellwig 		return ret;
2320c83ed8eSKurt Hackel 
2330c83ed8eSKurt Hackel 	return count;
2340c83ed8eSKurt Hackel }
23545b99773SChristoph Hellwig static ssize_t o2nm_node_ipv4_port_show(struct config_item *item, char *page)
2360c83ed8eSKurt Hackel {
23745b99773SChristoph Hellwig 	return sprintf(page, "%u\n", ntohs(to_o2nm_node(item)->nd_ipv4_port));
2380c83ed8eSKurt Hackel }
2390c83ed8eSKurt Hackel 
24045b99773SChristoph Hellwig static ssize_t o2nm_node_ipv4_port_store(struct config_item *item,
2410c83ed8eSKurt Hackel 					 const char *page, size_t count)
2420c83ed8eSKurt Hackel {
24345b99773SChristoph Hellwig 	struct o2nm_node *node = to_o2nm_node(item);
2440c83ed8eSKurt Hackel 	unsigned long tmp;
2450c83ed8eSKurt Hackel 	char *p = (char *)page;
2460c83ed8eSKurt Hackel 
2470c83ed8eSKurt Hackel 	tmp = simple_strtoul(p, &p, 0);
2480c83ed8eSKurt Hackel 	if (!p || (*p && (*p != '\n')))
2490c83ed8eSKurt Hackel 		return -EINVAL;
2500c83ed8eSKurt Hackel 
2510c83ed8eSKurt Hackel 	if (tmp == 0)
2520c83ed8eSKurt Hackel 		return -EINVAL;
2530c83ed8eSKurt Hackel 	if (tmp >= (u16)-1)
2540c83ed8eSKurt Hackel 		return -ERANGE;
2550c83ed8eSKurt Hackel 
25613a83fc9SChristoph Hellwig 	if (test_and_set_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
25713a83fc9SChristoph Hellwig 		return -EBUSY;
2580c83ed8eSKurt Hackel 	node->nd_ipv4_port = htons(tmp);
2590c83ed8eSKurt Hackel 
2600c83ed8eSKurt Hackel 	return count;
2610c83ed8eSKurt Hackel }
2620c83ed8eSKurt Hackel 
26345b99773SChristoph Hellwig static ssize_t o2nm_node_ipv4_address_show(struct config_item *item, char *page)
2640c83ed8eSKurt Hackel {
26545b99773SChristoph Hellwig 	return sprintf(page, "%pI4\n", &to_o2nm_node(item)->nd_ipv4_address);
2660c83ed8eSKurt Hackel }
2670c83ed8eSKurt Hackel 
26845b99773SChristoph Hellwig static ssize_t o2nm_node_ipv4_address_store(struct config_item *item,
2690c83ed8eSKurt Hackel 					    const char *page,
2700c83ed8eSKurt Hackel 					    size_t count)
2710c83ed8eSKurt Hackel {
27245b99773SChristoph Hellwig 	struct o2nm_node *node = to_o2nm_node(item);
273853bc26aSalex chen 	struct o2nm_cluster *cluster;
2740c83ed8eSKurt Hackel 	int ret, i;
2750c83ed8eSKurt Hackel 	struct rb_node **p, *parent;
2760c83ed8eSKurt Hackel 	unsigned int octets[4];
2770c83ed8eSKurt Hackel 	__be32 ipv4_addr = 0;
2780c83ed8eSKurt Hackel 
2790c83ed8eSKurt Hackel 	ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
2800c83ed8eSKurt Hackel 		     &octets[1], &octets[0]);
2810c83ed8eSKurt Hackel 	if (ret != 4)
2820c83ed8eSKurt Hackel 		return -EINVAL;
2830c83ed8eSKurt Hackel 
2840c83ed8eSKurt Hackel 	for (i = 0; i < ARRAY_SIZE(octets); i++) {
2850c83ed8eSKurt Hackel 		if (octets[i] > 255)
2860c83ed8eSKurt Hackel 			return -ERANGE;
2870c83ed8eSKurt Hackel 		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
2880c83ed8eSKurt Hackel 	}
2890c83ed8eSKurt Hackel 
290853bc26aSalex chen 	o2nm_lock_subsystem();
291853bc26aSalex chen 	cluster = to_o2nm_cluster_from_node(node);
292853bc26aSalex chen 	if (!cluster) {
293853bc26aSalex chen 		o2nm_unlock_subsystem();
294853bc26aSalex chen 		return -EINVAL;
295853bc26aSalex chen 	}
296853bc26aSalex chen 
2970c83ed8eSKurt Hackel 	ret = 0;
2980c83ed8eSKurt Hackel 	write_lock(&cluster->cl_nodes_lock);
2990c83ed8eSKurt Hackel 	if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
3000c83ed8eSKurt Hackel 		ret = -EEXIST;
30113a83fc9SChristoph Hellwig 	else if (test_and_set_bit(O2NM_NODE_ATTR_ADDRESS,
30213a83fc9SChristoph Hellwig 			&node->nd_set_attributes))
30313a83fc9SChristoph Hellwig 		ret = -EBUSY;
3040c83ed8eSKurt Hackel 	else {
3050c83ed8eSKurt Hackel 		rb_link_node(&node->nd_ip_node, parent, p);
3060c83ed8eSKurt Hackel 		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
3070c83ed8eSKurt Hackel 	}
3080c83ed8eSKurt Hackel 	write_unlock(&cluster->cl_nodes_lock);
309853bc26aSalex chen 	o2nm_unlock_subsystem();
310853bc26aSalex chen 
3110c83ed8eSKurt Hackel 	if (ret)
3120c83ed8eSKurt Hackel 		return ret;
3130c83ed8eSKurt Hackel 
3140c83ed8eSKurt Hackel 	memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
3150c83ed8eSKurt Hackel 
3160c83ed8eSKurt Hackel 	return count;
3170c83ed8eSKurt Hackel }
3180c83ed8eSKurt Hackel 
31945b99773SChristoph Hellwig static ssize_t o2nm_node_local_show(struct config_item *item, char *page)
3200c83ed8eSKurt Hackel {
32145b99773SChristoph Hellwig 	return sprintf(page, "%d\n", to_o2nm_node(item)->nd_local);
3220c83ed8eSKurt Hackel }
3230c83ed8eSKurt Hackel 
32445b99773SChristoph Hellwig static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,
3250c83ed8eSKurt Hackel 				     size_t count)
3260c83ed8eSKurt Hackel {
32745b99773SChristoph Hellwig 	struct o2nm_node *node = to_o2nm_node(item);
328853bc26aSalex chen 	struct o2nm_cluster *cluster;
3290c83ed8eSKurt Hackel 	unsigned long tmp;
3300c83ed8eSKurt Hackel 	char *p = (char *)page;
3310c83ed8eSKurt Hackel 	ssize_t ret;
3320c83ed8eSKurt Hackel 
3330c83ed8eSKurt Hackel 	tmp = simple_strtoul(p, &p, 0);
3340c83ed8eSKurt Hackel 	if (!p || (*p && (*p != '\n')))
3350c83ed8eSKurt Hackel 		return -EINVAL;
3360c83ed8eSKurt Hackel 
3370c83ed8eSKurt Hackel 	tmp = !!tmp; /* boolean of whether this node wants to be local */
3380c83ed8eSKurt Hackel 
3390c83ed8eSKurt Hackel 	/* setting local turns on networking rx for now so we require having
3400c83ed8eSKurt Hackel 	 * set everything else first */
3410c83ed8eSKurt Hackel 	if (!test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
3420c83ed8eSKurt Hackel 	    !test_bit(O2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
3430c83ed8eSKurt Hackel 	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
3440c83ed8eSKurt Hackel 		return -EINVAL; /* XXX */
3450c83ed8eSKurt Hackel 
346853bc26aSalex chen 	o2nm_lock_subsystem();
347853bc26aSalex chen 	cluster = to_o2nm_cluster_from_node(node);
348853bc26aSalex chen 	if (!cluster) {
349853bc26aSalex chen 		ret = -EINVAL;
350853bc26aSalex chen 		goto out;
351853bc26aSalex chen 	}
352853bc26aSalex chen 
3530c83ed8eSKurt Hackel 	/* the only failure case is trying to set a new local node
3540c83ed8eSKurt Hackel 	 * when a different one is already set */
3550c83ed8eSKurt Hackel 	if (tmp && tmp == cluster->cl_has_local &&
356853bc26aSalex chen 	    cluster->cl_local_node != node->nd_num) {
357853bc26aSalex chen 		ret = -EBUSY;
358853bc26aSalex chen 		goto out;
359853bc26aSalex chen 	}
3600c83ed8eSKurt Hackel 
3610c83ed8eSKurt Hackel 	/* bring up the rx thread if we're setting the new local node. */
3620c83ed8eSKurt Hackel 	if (tmp && !cluster->cl_has_local) {
3630c83ed8eSKurt Hackel 		ret = o2net_start_listening(node);
3640c83ed8eSKurt Hackel 		if (ret)
365853bc26aSalex chen 			goto out;
3660c83ed8eSKurt Hackel 	}
3670c83ed8eSKurt Hackel 
3680c83ed8eSKurt Hackel 	if (!tmp && cluster->cl_has_local &&
3690c83ed8eSKurt Hackel 	    cluster->cl_local_node == node->nd_num) {
3700c83ed8eSKurt Hackel 		o2net_stop_listening(node);
3710c83ed8eSKurt Hackel 		cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
3720c83ed8eSKurt Hackel 	}
3730c83ed8eSKurt Hackel 
3740c83ed8eSKurt Hackel 	node->nd_local = tmp;
3750c83ed8eSKurt Hackel 	if (node->nd_local) {
3760c83ed8eSKurt Hackel 		cluster->cl_has_local = tmp;
3770c83ed8eSKurt Hackel 		cluster->cl_local_node = node->nd_num;
3780c83ed8eSKurt Hackel 	}
3790c83ed8eSKurt Hackel 
380853bc26aSalex chen 	ret = count;
381853bc26aSalex chen 
382853bc26aSalex chen out:
383853bc26aSalex chen 	o2nm_unlock_subsystem();
384853bc26aSalex chen 	return ret;
3850c83ed8eSKurt Hackel }
3860c83ed8eSKurt Hackel 
38745b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_node_, num);
38845b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_node_, ipv4_port);
38945b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_node_, ipv4_address);
39045b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_node_, local);
3910c83ed8eSKurt Hackel 
3920c83ed8eSKurt Hackel static struct configfs_attribute *o2nm_node_attrs[] = {
39345b99773SChristoph Hellwig 	&o2nm_node_attr_num,
39445b99773SChristoph Hellwig 	&o2nm_node_attr_ipv4_port,
39545b99773SChristoph Hellwig 	&o2nm_node_attr_ipv4_address,
39645b99773SChristoph Hellwig 	&o2nm_node_attr_local,
3970c83ed8eSKurt Hackel 	NULL,
3980c83ed8eSKurt Hackel };
3990c83ed8eSKurt Hackel 
4000c83ed8eSKurt Hackel static struct configfs_item_operations o2nm_node_item_ops = {
4010c83ed8eSKurt Hackel 	.release		= o2nm_node_release,
4020c83ed8eSKurt Hackel };
4030c83ed8eSKurt Hackel 
4044843afe4SBhumika Goyal static const struct config_item_type o2nm_node_type = {
4050c83ed8eSKurt Hackel 	.ct_item_ops	= &o2nm_node_item_ops,
4060c83ed8eSKurt Hackel 	.ct_attrs	= o2nm_node_attrs,
4070c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
4080c83ed8eSKurt Hackel };
4090c83ed8eSKurt Hackel 
4100c83ed8eSKurt Hackel /* node set */
4110c83ed8eSKurt Hackel 
4120c83ed8eSKurt Hackel struct o2nm_node_group {
4130c83ed8eSKurt Hackel 	struct config_group ns_group;
4140c83ed8eSKurt Hackel 	/* some stuff? */
4150c83ed8eSKurt Hackel };
4160c83ed8eSKurt Hackel 
4170c83ed8eSKurt Hackel #if 0
4180c83ed8eSKurt Hackel static struct o2nm_node_group *to_o2nm_node_group(struct config_group *group)
4190c83ed8eSKurt Hackel {
4200c83ed8eSKurt Hackel 	return group ?
4210c83ed8eSKurt Hackel 		container_of(group, struct o2nm_node_group, ns_group)
4220c83ed8eSKurt Hackel 		: NULL;
4230c83ed8eSKurt Hackel }
4240c83ed8eSKurt Hackel #endif
4250c83ed8eSKurt Hackel 
426b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_write(const char *page, ssize_t count,
427b5dd8030SJeff Mahoney                                        unsigned int *val)
428b5dd8030SJeff Mahoney {
429b5dd8030SJeff Mahoney 	unsigned long tmp;
430b5dd8030SJeff Mahoney 	char *p = (char *)page;
431b5dd8030SJeff Mahoney 
432b5dd8030SJeff Mahoney 	tmp = simple_strtoul(p, &p, 0);
433b5dd8030SJeff Mahoney 	if (!p || (*p && (*p != '\n')))
434b5dd8030SJeff Mahoney 		return -EINVAL;
435b5dd8030SJeff Mahoney 
436b5dd8030SJeff Mahoney 	if (tmp == 0)
437b5dd8030SJeff Mahoney 		return -EINVAL;
438b5dd8030SJeff Mahoney 	if (tmp >= (u32)-1)
439b5dd8030SJeff Mahoney 		return -ERANGE;
440b5dd8030SJeff Mahoney 
441b5dd8030SJeff Mahoney 	*val = tmp;
442b5dd8030SJeff Mahoney 
443b5dd8030SJeff Mahoney 	return count;
444b5dd8030SJeff Mahoney }
445b5dd8030SJeff Mahoney 
44645b99773SChristoph Hellwig static ssize_t o2nm_cluster_idle_timeout_ms_show(struct config_item *item,
44745b99773SChristoph Hellwig 	char *page)
448b5dd8030SJeff Mahoney {
44945b99773SChristoph Hellwig 	return sprintf(page, "%u\n", to_o2nm_cluster(item)->cl_idle_timeout_ms);
450b5dd8030SJeff Mahoney }
451b5dd8030SJeff Mahoney 
45245b99773SChristoph Hellwig static ssize_t o2nm_cluster_idle_timeout_ms_store(struct config_item *item,
45345b99773SChristoph Hellwig 	const char *page, size_t count)
454b5dd8030SJeff Mahoney {
45545b99773SChristoph Hellwig 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
456b5dd8030SJeff Mahoney 	ssize_t ret;
457b5dd8030SJeff Mahoney 	unsigned int val;
458b5dd8030SJeff Mahoney 
459b5dd8030SJeff Mahoney 	ret =  o2nm_cluster_attr_write(page, count, &val);
460b5dd8030SJeff Mahoney 
461b5dd8030SJeff Mahoney 	if (ret > 0) {
462828ae6afSAndrew Beekhof 		if (cluster->cl_idle_timeout_ms != val
463828ae6afSAndrew Beekhof 			&& o2net_num_connected_peers()) {
464828ae6afSAndrew Beekhof 			mlog(ML_NOTICE,
465828ae6afSAndrew Beekhof 			     "o2net: cannot change idle timeout after "
466828ae6afSAndrew Beekhof 			     "the first peer has agreed to it."
467828ae6afSAndrew Beekhof 			     "  %d connected peers\n",
468828ae6afSAndrew Beekhof 			     o2net_num_connected_peers());
469828ae6afSAndrew Beekhof 			ret = -EINVAL;
470828ae6afSAndrew Beekhof 		} else if (val <= cluster->cl_keepalive_delay_ms) {
471b5dd8030SJeff Mahoney 			mlog(ML_NOTICE, "o2net: idle timeout must be larger "
472b5dd8030SJeff Mahoney 			     "than keepalive delay\n");
473828ae6afSAndrew Beekhof 			ret = -EINVAL;
474828ae6afSAndrew Beekhof 		} else {
475b5dd8030SJeff Mahoney 			cluster->cl_idle_timeout_ms = val;
476b5dd8030SJeff Mahoney 		}
477828ae6afSAndrew Beekhof 	}
478b5dd8030SJeff Mahoney 
479b5dd8030SJeff Mahoney 	return ret;
480b5dd8030SJeff Mahoney }
481b5dd8030SJeff Mahoney 
48245b99773SChristoph Hellwig static ssize_t o2nm_cluster_keepalive_delay_ms_show(
48345b99773SChristoph Hellwig 	struct config_item *item, char *page)
484b5dd8030SJeff Mahoney {
48545b99773SChristoph Hellwig 	return sprintf(page, "%u\n",
48645b99773SChristoph Hellwig 			to_o2nm_cluster(item)->cl_keepalive_delay_ms);
487b5dd8030SJeff Mahoney }
488b5dd8030SJeff Mahoney 
48945b99773SChristoph Hellwig static ssize_t o2nm_cluster_keepalive_delay_ms_store(
49045b99773SChristoph Hellwig 	struct config_item *item, const char *page, size_t count)
491b5dd8030SJeff Mahoney {
49245b99773SChristoph Hellwig 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
493b5dd8030SJeff Mahoney 	ssize_t ret;
494b5dd8030SJeff Mahoney 	unsigned int val;
495b5dd8030SJeff Mahoney 
496b5dd8030SJeff Mahoney 	ret =  o2nm_cluster_attr_write(page, count, &val);
497b5dd8030SJeff Mahoney 
498b5dd8030SJeff Mahoney 	if (ret > 0) {
499828ae6afSAndrew Beekhof 		if (cluster->cl_keepalive_delay_ms != val
500828ae6afSAndrew Beekhof 		    && o2net_num_connected_peers()) {
501828ae6afSAndrew Beekhof 			mlog(ML_NOTICE,
502828ae6afSAndrew Beekhof 			     "o2net: cannot change keepalive delay after"
503828ae6afSAndrew Beekhof 			     " the first peer has agreed to it."
504828ae6afSAndrew Beekhof 			     "  %d connected peers\n",
505828ae6afSAndrew Beekhof 			     o2net_num_connected_peers());
506828ae6afSAndrew Beekhof 			ret = -EINVAL;
507828ae6afSAndrew Beekhof 		} else if (val >= cluster->cl_idle_timeout_ms) {
508b5dd8030SJeff Mahoney 			mlog(ML_NOTICE, "o2net: keepalive delay must be "
509b5dd8030SJeff Mahoney 			     "smaller than idle timeout\n");
510828ae6afSAndrew Beekhof 			ret = -EINVAL;
511828ae6afSAndrew Beekhof 		} else {
512b5dd8030SJeff Mahoney 			cluster->cl_keepalive_delay_ms = val;
513b5dd8030SJeff Mahoney 		}
514828ae6afSAndrew Beekhof 	}
515b5dd8030SJeff Mahoney 
516b5dd8030SJeff Mahoney 	return ret;
517b5dd8030SJeff Mahoney }
518b5dd8030SJeff Mahoney 
51945b99773SChristoph Hellwig static ssize_t o2nm_cluster_reconnect_delay_ms_show(
52045b99773SChristoph Hellwig 	struct config_item *item, char *page)
521b5dd8030SJeff Mahoney {
52245b99773SChristoph Hellwig 	return sprintf(page, "%u\n",
52345b99773SChristoph Hellwig 			to_o2nm_cluster(item)->cl_reconnect_delay_ms);
524b5dd8030SJeff Mahoney }
525b5dd8030SJeff Mahoney 
52645b99773SChristoph Hellwig static ssize_t o2nm_cluster_reconnect_delay_ms_store(
52745b99773SChristoph Hellwig 	struct config_item *item, const char *page, size_t count)
528b5dd8030SJeff Mahoney {
529b5dd8030SJeff Mahoney 	return o2nm_cluster_attr_write(page, count,
53045b99773SChristoph Hellwig                                &to_o2nm_cluster(item)->cl_reconnect_delay_ms);
531b5dd8030SJeff Mahoney }
532f6656d26SSunil Mushran 
53345b99773SChristoph Hellwig static ssize_t o2nm_cluster_fence_method_show(
53445b99773SChristoph Hellwig 	struct config_item *item, char *page)
535f6656d26SSunil Mushran {
53645b99773SChristoph Hellwig 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
537f6656d26SSunil Mushran 	ssize_t ret = 0;
538f6656d26SSunil Mushran 
539f6656d26SSunil Mushran 	if (cluster)
540f6656d26SSunil Mushran 		ret = sprintf(page, "%s\n",
541f6656d26SSunil Mushran 			      o2nm_fence_method_desc[cluster->cl_fence_method]);
542f6656d26SSunil Mushran 	return ret;
543f6656d26SSunil Mushran }
544f6656d26SSunil Mushran 
54545b99773SChristoph Hellwig static ssize_t o2nm_cluster_fence_method_store(
54645b99773SChristoph Hellwig 	struct config_item *item, const char *page, size_t count)
547f6656d26SSunil Mushran {
548f6656d26SSunil Mushran 	unsigned int i;
549f6656d26SSunil Mushran 
550f6656d26SSunil Mushran 	if (page[count - 1] != '\n')
551f6656d26SSunil Mushran 		goto bail;
552f6656d26SSunil Mushran 
553f6656d26SSunil Mushran 	for (i = 0; i < O2NM_FENCE_METHODS; ++i) {
554f6656d26SSunil Mushran 		if (count != strlen(o2nm_fence_method_desc[i]) + 1)
555f6656d26SSunil Mushran 			continue;
556f6656d26SSunil Mushran 		if (strncasecmp(page, o2nm_fence_method_desc[i], count - 1))
557f6656d26SSunil Mushran 			continue;
55845b99773SChristoph Hellwig 		if (to_o2nm_cluster(item)->cl_fence_method != i) {
559f6656d26SSunil Mushran 			printk(KERN_INFO "ocfs2: Changing fence method to %s\n",
560f6656d26SSunil Mushran 			       o2nm_fence_method_desc[i]);
56145b99773SChristoph Hellwig 			to_o2nm_cluster(item)->cl_fence_method = i;
562f6656d26SSunil Mushran 		}
563f6656d26SSunil Mushran 		return count;
564f6656d26SSunil Mushran 	}
565f6656d26SSunil Mushran 
566f6656d26SSunil Mushran bail:
567f6656d26SSunil Mushran 	return -EINVAL;
568f6656d26SSunil Mushran }
569f6656d26SSunil Mushran 
57045b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_cluster_, idle_timeout_ms);
57145b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_cluster_, keepalive_delay_ms);
57245b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_cluster_, reconnect_delay_ms);
57345b99773SChristoph Hellwig CONFIGFS_ATTR(o2nm_cluster_, fence_method);
574f6656d26SSunil Mushran 
575b5dd8030SJeff Mahoney static struct configfs_attribute *o2nm_cluster_attrs[] = {
57645b99773SChristoph Hellwig 	&o2nm_cluster_attr_idle_timeout_ms,
57745b99773SChristoph Hellwig 	&o2nm_cluster_attr_keepalive_delay_ms,
57845b99773SChristoph Hellwig 	&o2nm_cluster_attr_reconnect_delay_ms,
57945b99773SChristoph Hellwig 	&o2nm_cluster_attr_fence_method,
580b5dd8030SJeff Mahoney 	NULL,
581b5dd8030SJeff Mahoney };
582b5dd8030SJeff Mahoney 
583f89ab861SJoel Becker static struct config_item *o2nm_node_group_make_item(struct config_group *group,
584f89ab861SJoel Becker 						     const char *name)
5850c83ed8eSKurt Hackel {
5860c83ed8eSKurt Hackel 	struct o2nm_node *node = NULL;
5870c83ed8eSKurt Hackel 
588f89ab861SJoel Becker 	if (strlen(name) > O2NM_MAX_NAME_LEN)
589a6795e9eSJoel Becker 		return ERR_PTR(-ENAMETOOLONG);
5900c83ed8eSKurt Hackel 
591cd861280SRobert P. J. Day 	node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL);
592f89ab861SJoel Becker 	if (node == NULL)
593a6795e9eSJoel Becker 		return ERR_PTR(-ENOMEM);
5940c83ed8eSKurt Hackel 
5950c83ed8eSKurt Hackel 	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
5960c83ed8eSKurt Hackel 	config_item_init_type_name(&node->nd_item, name, &o2nm_node_type);
5970c83ed8eSKurt Hackel 	spin_lock_init(&node->nd_lock);
5980c83ed8eSKurt Hackel 
59939a29856SSunil Mushran 	mlog(ML_CLUSTER, "o2nm: Registering node %s\n", name);
60039a29856SSunil Mushran 
601a6795e9eSJoel Becker 	return &node->nd_item;
6020c83ed8eSKurt Hackel }
6030c83ed8eSKurt Hackel 
6040c83ed8eSKurt Hackel static void o2nm_node_group_drop_item(struct config_group *group,
6050c83ed8eSKurt Hackel 				      struct config_item *item)
6060c83ed8eSKurt Hackel {
6070c83ed8eSKurt Hackel 	struct o2nm_node *node = to_o2nm_node(item);
6080c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster(group->cg_item.ci_parent);
6090c83ed8eSKurt Hackel 
610cc725ef3SJia Guo 	if (cluster->cl_nodes[node->nd_num] == node) {
6110c83ed8eSKurt Hackel 		o2net_disconnect_node(node);
6120c83ed8eSKurt Hackel 
6130c83ed8eSKurt Hackel 		if (cluster->cl_has_local &&
6140c83ed8eSKurt Hackel 		    (cluster->cl_local_node == node->nd_num)) {
6150c83ed8eSKurt Hackel 			cluster->cl_has_local = 0;
6160c83ed8eSKurt Hackel 			cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
6170c83ed8eSKurt Hackel 			o2net_stop_listening(node);
6180c83ed8eSKurt Hackel 		}
619cc725ef3SJia Guo 	}
6200c83ed8eSKurt Hackel 
6210c83ed8eSKurt Hackel 	/* XXX call into net to stop this node from trading messages */
6220c83ed8eSKurt Hackel 
6230c83ed8eSKurt Hackel 	write_lock(&cluster->cl_nodes_lock);
6240c83ed8eSKurt Hackel 
6250c83ed8eSKurt Hackel 	/* XXX sloppy */
6260c83ed8eSKurt Hackel 	if (node->nd_ipv4_address)
6270c83ed8eSKurt Hackel 		rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
6280c83ed8eSKurt Hackel 
6290c83ed8eSKurt Hackel 	/* nd_num might be 0 if the node number hasn't been set.. */
6300c83ed8eSKurt Hackel 	if (cluster->cl_nodes[node->nd_num] == node) {
6310c83ed8eSKurt Hackel 		cluster->cl_nodes[node->nd_num] = NULL;
6320c83ed8eSKurt Hackel 		clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
6330c83ed8eSKurt Hackel 	}
6340c83ed8eSKurt Hackel 	write_unlock(&cluster->cl_nodes_lock);
6350c83ed8eSKurt Hackel 
63639a29856SSunil Mushran 	mlog(ML_CLUSTER, "o2nm: Unregistered node %s\n",
63739a29856SSunil Mushran 	     config_item_name(&node->nd_item));
63839a29856SSunil Mushran 
6390c83ed8eSKurt Hackel 	config_item_put(item);
6400c83ed8eSKurt Hackel }
6410c83ed8eSKurt Hackel 
6420c83ed8eSKurt Hackel static struct configfs_group_operations o2nm_node_group_group_ops = {
6430c83ed8eSKurt Hackel 	.make_item	= o2nm_node_group_make_item,
6440c83ed8eSKurt Hackel 	.drop_item	= o2nm_node_group_drop_item,
6450c83ed8eSKurt Hackel };
6460c83ed8eSKurt Hackel 
6474843afe4SBhumika Goyal static const struct config_item_type o2nm_node_group_type = {
6480c83ed8eSKurt Hackel 	.ct_group_ops	= &o2nm_node_group_group_ops,
6490c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
6500c83ed8eSKurt Hackel };
6510c83ed8eSKurt Hackel 
6520c83ed8eSKurt Hackel /* cluster */
6530c83ed8eSKurt Hackel 
6540c83ed8eSKurt Hackel static void o2nm_cluster_release(struct config_item *item)
6550c83ed8eSKurt Hackel {
6560c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
6570c83ed8eSKurt Hackel 
6580c83ed8eSKurt Hackel 	kfree(cluster);
6590c83ed8eSKurt Hackel }
6600c83ed8eSKurt Hackel 
6610c83ed8eSKurt Hackel static struct configfs_item_operations o2nm_cluster_item_ops = {
6620c83ed8eSKurt Hackel 	.release	= o2nm_cluster_release,
6630c83ed8eSKurt Hackel };
6640c83ed8eSKurt Hackel 
6654843afe4SBhumika Goyal static const struct config_item_type o2nm_cluster_type = {
6660c83ed8eSKurt Hackel 	.ct_item_ops	= &o2nm_cluster_item_ops,
667b5dd8030SJeff Mahoney 	.ct_attrs	= o2nm_cluster_attrs,
6680c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
6690c83ed8eSKurt Hackel };
6700c83ed8eSKurt Hackel 
6710c83ed8eSKurt Hackel /* cluster set */
6720c83ed8eSKurt Hackel 
6730c83ed8eSKurt Hackel struct o2nm_cluster_group {
6740c83ed8eSKurt Hackel 	struct configfs_subsystem cs_subsys;
6750c83ed8eSKurt Hackel 	/* some stuff? */
6760c83ed8eSKurt Hackel };
6770c83ed8eSKurt Hackel 
6780c83ed8eSKurt Hackel #if 0
6790c83ed8eSKurt Hackel static struct o2nm_cluster_group *to_o2nm_cluster_group(struct config_group *group)
6800c83ed8eSKurt Hackel {
6810c83ed8eSKurt Hackel 	return group ?
6820c83ed8eSKurt Hackel 		container_of(to_configfs_subsystem(group), struct o2nm_cluster_group, cs_subsys)
6830c83ed8eSKurt Hackel 	       : NULL;
6840c83ed8eSKurt Hackel }
6850c83ed8eSKurt Hackel #endif
6860c83ed8eSKurt Hackel 
687f89ab861SJoel Becker static struct config_group *o2nm_cluster_group_make_group(struct config_group *group,
688f89ab861SJoel Becker 							  const char *name)
6890c83ed8eSKurt Hackel {
6900c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = NULL;
6910c83ed8eSKurt Hackel 	struct o2nm_node_group *ns = NULL;
692f89ab861SJoel Becker 	struct config_group *o2hb_group = NULL, *ret = NULL;
6930c83ed8eSKurt Hackel 
6941b1dcc1bSJes Sorensen 	/* this runs under the parent dir's i_mutex; there can be only
6950c83ed8eSKurt Hackel 	 * one caller in here at a time */
696f89ab861SJoel Becker 	if (o2nm_single_cluster)
697a6795e9eSJoel Becker 		return ERR_PTR(-ENOSPC);
6980c83ed8eSKurt Hackel 
699cd861280SRobert P. J. Day 	cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
700cd861280SRobert P. J. Day 	ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
7010c83ed8eSKurt Hackel 	o2hb_group = o2hb_alloc_hb_set();
7021ae1602dSChristoph Hellwig 	if (cluster == NULL || ns == NULL || o2hb_group == NULL)
7030c83ed8eSKurt Hackel 		goto out;
7040c83ed8eSKurt Hackel 
7050c83ed8eSKurt Hackel 	config_group_init_type_name(&cluster->cl_group, name,
7060c83ed8eSKurt Hackel 				    &o2nm_cluster_type);
7071ae1602dSChristoph Hellwig 	configfs_add_default_group(&ns->ns_group, &cluster->cl_group);
7081ae1602dSChristoph Hellwig 
7090c83ed8eSKurt Hackel 	config_group_init_type_name(&ns->ns_group, "node",
7100c83ed8eSKurt Hackel 				    &o2nm_node_group_type);
7111ae1602dSChristoph Hellwig 	configfs_add_default_group(o2hb_group, &cluster->cl_group);
7120c83ed8eSKurt Hackel 
7130c83ed8eSKurt Hackel 	rwlock_init(&cluster->cl_nodes_lock);
7140c83ed8eSKurt Hackel 	cluster->cl_node_ip_tree = RB_ROOT;
715b5dd8030SJeff Mahoney 	cluster->cl_reconnect_delay_ms = O2NET_RECONNECT_DELAY_MS_DEFAULT;
716b5dd8030SJeff Mahoney 	cluster->cl_idle_timeout_ms    = O2NET_IDLE_TIMEOUT_MS_DEFAULT;
717b5dd8030SJeff Mahoney 	cluster->cl_keepalive_delay_ms = O2NET_KEEPALIVE_DELAY_MS_DEFAULT;
718f6656d26SSunil Mushran 	cluster->cl_fence_method       = O2NM_FENCE_RESET;
7190c83ed8eSKurt Hackel 
720f89ab861SJoel Becker 	ret = &cluster->cl_group;
7210c83ed8eSKurt Hackel 	o2nm_single_cluster = cluster;
7220c83ed8eSKurt Hackel 
7230c83ed8eSKurt Hackel out:
724f89ab861SJoel Becker 	if (ret == NULL) {
7250c83ed8eSKurt Hackel 		kfree(cluster);
7260c83ed8eSKurt Hackel 		kfree(ns);
7270c83ed8eSKurt Hackel 		o2hb_free_hb_set(o2hb_group);
728a6795e9eSJoel Becker 		ret = ERR_PTR(-ENOMEM);
7290c83ed8eSKurt Hackel 	}
7300c83ed8eSKurt Hackel 
7310c83ed8eSKurt Hackel 	return ret;
7320c83ed8eSKurt Hackel }
7330c83ed8eSKurt Hackel 
7340c83ed8eSKurt Hackel static void o2nm_cluster_group_drop_item(struct config_group *group, struct config_item *item)
7350c83ed8eSKurt Hackel {
7360c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
7370c83ed8eSKurt Hackel 
7380c83ed8eSKurt Hackel 	BUG_ON(o2nm_single_cluster != cluster);
7390c83ed8eSKurt Hackel 	o2nm_single_cluster = NULL;
7400c83ed8eSKurt Hackel 
7411ae1602dSChristoph Hellwig 	configfs_remove_default_groups(&cluster->cl_group);
7420c83ed8eSKurt Hackel 	config_item_put(item);
7430c83ed8eSKurt Hackel }
7440c83ed8eSKurt Hackel 
7450c83ed8eSKurt Hackel static struct configfs_group_operations o2nm_cluster_group_group_ops = {
7460c83ed8eSKurt Hackel 	.make_group	= o2nm_cluster_group_make_group,
7470c83ed8eSKurt Hackel 	.drop_item	= o2nm_cluster_group_drop_item,
7480c83ed8eSKurt Hackel };
7490c83ed8eSKurt Hackel 
7504843afe4SBhumika Goyal static const struct config_item_type o2nm_cluster_group_type = {
7510c83ed8eSKurt Hackel 	.ct_group_ops	= &o2nm_cluster_group_group_ops,
7520c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
7530c83ed8eSKurt Hackel };
7540c83ed8eSKurt Hackel 
7550c83ed8eSKurt Hackel static struct o2nm_cluster_group o2nm_cluster_group = {
7560c83ed8eSKurt Hackel 	.cs_subsys = {
7570c83ed8eSKurt Hackel 		.su_group = {
7580c83ed8eSKurt Hackel 			.cg_item = {
7590c83ed8eSKurt Hackel 				.ci_namebuf = "cluster",
7600c83ed8eSKurt Hackel 				.ci_type = &o2nm_cluster_group_type,
7610c83ed8eSKurt Hackel 			},
7620c83ed8eSKurt Hackel 		},
7630c83ed8eSKurt Hackel 	},
7640c83ed8eSKurt Hackel };
7650c83ed8eSKurt Hackel 
766853bc26aSalex chen static inline void o2nm_lock_subsystem(void)
767853bc26aSalex chen {
768853bc26aSalex chen 	mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex);
769853bc26aSalex chen }
770853bc26aSalex chen 
771853bc26aSalex chen static inline void o2nm_unlock_subsystem(void)
772853bc26aSalex chen {
773853bc26aSalex chen 	mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex);
774853bc26aSalex chen }
775853bc26aSalex chen 
77614829422SJoel Becker int o2nm_depend_item(struct config_item *item)
77714829422SJoel Becker {
77814829422SJoel Becker 	return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
77914829422SJoel Becker }
78014829422SJoel Becker 
78114829422SJoel Becker void o2nm_undepend_item(struct config_item *item)
78214829422SJoel Becker {
7839a9e3415SKrzysztof Opasiak 	configfs_undepend_item(item);
78414829422SJoel Becker }
78514829422SJoel Becker 
78616c6a4f2SJoel Becker int o2nm_depend_this_node(void)
78716c6a4f2SJoel Becker {
78816c6a4f2SJoel Becker 	int ret = 0;
78916c6a4f2SJoel Becker 	struct o2nm_node *local_node;
79016c6a4f2SJoel Becker 
79116c6a4f2SJoel Becker 	local_node = o2nm_get_node_by_num(o2nm_this_node());
79216c6a4f2SJoel Becker 	if (!local_node) {
79316c6a4f2SJoel Becker 		ret = -EINVAL;
79416c6a4f2SJoel Becker 		goto out;
79516c6a4f2SJoel Becker 	}
79616c6a4f2SJoel Becker 
79716c6a4f2SJoel Becker 	ret = o2nm_depend_item(&local_node->nd_item);
79816c6a4f2SJoel Becker 	o2nm_node_put(local_node);
79916c6a4f2SJoel Becker 
80016c6a4f2SJoel Becker out:
80116c6a4f2SJoel Becker 	return ret;
80216c6a4f2SJoel Becker }
80316c6a4f2SJoel Becker 
80416c6a4f2SJoel Becker void o2nm_undepend_this_node(void)
80516c6a4f2SJoel Becker {
80616c6a4f2SJoel Becker 	struct o2nm_node *local_node;
80716c6a4f2SJoel Becker 
80816c6a4f2SJoel Becker 	local_node = o2nm_get_node_by_num(o2nm_this_node());
80916c6a4f2SJoel Becker 	BUG_ON(!local_node);
81016c6a4f2SJoel Becker 
81116c6a4f2SJoel Becker 	o2nm_undepend_item(&local_node->nd_item);
81216c6a4f2SJoel Becker 	o2nm_node_put(local_node);
81316c6a4f2SJoel Becker }
81416c6a4f2SJoel Becker 
81516c6a4f2SJoel Becker 
8160c83ed8eSKurt Hackel static void __exit exit_o2nm(void)
8170c83ed8eSKurt Hackel {
8180c83ed8eSKurt Hackel 	/* XXX sync with hb callbacks and shut down hb? */
8190c83ed8eSKurt Hackel 	o2net_unregister_hb_callbacks();
8200c83ed8eSKurt Hackel 	configfs_unregister_subsystem(&o2nm_cluster_group.cs_subsys);
8210c83ed8eSKurt Hackel 	o2cb_sys_shutdown();
8220c83ed8eSKurt Hackel 
8230c83ed8eSKurt Hackel 	o2net_exit();
82487d3d3f3SSunil Mushran 	o2hb_exit();
8250c83ed8eSKurt Hackel }
8260c83ed8eSKurt Hackel 
8270c83ed8eSKurt Hackel static int __init init_o2nm(void)
8280c83ed8eSKurt Hackel {
8290c83ed8eSKurt Hackel 	int ret = -1;
8300c83ed8eSKurt Hackel 
83187d3d3f3SSunil Mushran 	ret = o2hb_init();
83287d3d3f3SSunil Mushran 	if (ret)
83387d3d3f3SSunil Mushran 		goto out;
8342309e9e0SSunil Mushran 
8352309e9e0SSunil Mushran 	ret = o2net_init();
8362309e9e0SSunil Mushran 	if (ret)
83787d3d3f3SSunil Mushran 		goto out_o2hb;
8380c83ed8eSKurt Hackel 
8390c83ed8eSKurt Hackel 	ret = o2net_register_hb_callbacks();
8400c83ed8eSKurt Hackel 	if (ret)
8413878f110SJoel Becker 		goto out_o2net;
8420c83ed8eSKurt Hackel 
8430c83ed8eSKurt Hackel 	config_group_init(&o2nm_cluster_group.cs_subsys.su_group);
844e6bd07aeSJoel Becker 	mutex_init(&o2nm_cluster_group.cs_subsys.su_mutex);
8450c83ed8eSKurt Hackel 	ret = configfs_register_subsystem(&o2nm_cluster_group.cs_subsys);
8460c83ed8eSKurt Hackel 	if (ret) {
8470c83ed8eSKurt Hackel 		printk(KERN_ERR "nodemanager: Registration returned %d\n", ret);
8480c83ed8eSKurt Hackel 		goto out_callbacks;
8490c83ed8eSKurt Hackel 	}
8500c83ed8eSKurt Hackel 
8510c83ed8eSKurt Hackel 	ret = o2cb_sys_init();
8520c83ed8eSKurt Hackel 	if (!ret)
8530c83ed8eSKurt Hackel 		goto out;
8540c83ed8eSKurt Hackel 
8550c83ed8eSKurt Hackel 	configfs_unregister_subsystem(&o2nm_cluster_group.cs_subsys);
8560c83ed8eSKurt Hackel out_callbacks:
8570c83ed8eSKurt Hackel 	o2net_unregister_hb_callbacks();
858895928b8SJeff Mahoney out_o2net:
859895928b8SJeff Mahoney 	o2net_exit();
86087d3d3f3SSunil Mushran out_o2hb:
86187d3d3f3SSunil Mushran 	o2hb_exit();
8620c83ed8eSKurt Hackel out:
8630c83ed8eSKurt Hackel 	return ret;
8640c83ed8eSKurt Hackel }
8650c83ed8eSKurt Hackel 
8660c83ed8eSKurt Hackel MODULE_AUTHOR("Oracle");
8670c83ed8eSKurt Hackel MODULE_LICENSE("GPL");
868ff8fb335SGoldwyn Rodrigues MODULE_DESCRIPTION("OCFS2 cluster management");
8690c83ed8eSKurt Hackel 
8700c83ed8eSKurt Hackel module_init(init_o2nm)
8710c83ed8eSKurt Hackel module_exit(exit_o2nm)
872