xref: /openbmc/linux/fs/ocfs2/cluster/nodemanager.c (revision 2309e9e0)
10c83ed8eSKurt Hackel /* -*- mode: c; c-basic-offset: 8; -*-
20c83ed8eSKurt Hackel  * vim: noexpandtab sw=8 ts=8 sts=0:
30c83ed8eSKurt Hackel  *
40c83ed8eSKurt Hackel  * Copyright (C) 2004, 2005 Oracle.  All rights reserved.
50c83ed8eSKurt Hackel  *
60c83ed8eSKurt Hackel  * This program is free software; you can redistribute it and/or
70c83ed8eSKurt Hackel  * modify it under the terms of the GNU General Public
80c83ed8eSKurt Hackel  * License as published by the Free Software Foundation; either
90c83ed8eSKurt Hackel  * version 2 of the License, or (at your option) any later version.
100c83ed8eSKurt Hackel  *
110c83ed8eSKurt Hackel  * This program is distributed in the hope that it will be useful,
120c83ed8eSKurt Hackel  * but WITHOUT ANY WARRANTY; without even the implied warranty of
130c83ed8eSKurt Hackel  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
140c83ed8eSKurt Hackel  * General Public License for more details.
150c83ed8eSKurt Hackel  *
160c83ed8eSKurt Hackel  * You should have received a copy of the GNU General Public
170c83ed8eSKurt Hackel  * License along with this program; if not, write to the
180c83ed8eSKurt Hackel  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
190c83ed8eSKurt Hackel  * Boston, MA 021110-1307, USA.
200c83ed8eSKurt Hackel  */
210c83ed8eSKurt Hackel 
220c83ed8eSKurt Hackel #include <linux/kernel.h>
230c83ed8eSKurt Hackel #include <linux/module.h>
240c83ed8eSKurt Hackel #include <linux/sysctl.h>
250c83ed8eSKurt Hackel #include <linux/configfs.h>
260c83ed8eSKurt Hackel 
270c83ed8eSKurt Hackel #include "tcp.h"
280c83ed8eSKurt Hackel #include "nodemanager.h"
290c83ed8eSKurt Hackel #include "heartbeat.h"
300c83ed8eSKurt Hackel #include "masklog.h"
310c83ed8eSKurt Hackel #include "sys.h"
320c83ed8eSKurt Hackel #include "ver.h"
330c83ed8eSKurt Hackel 
340c83ed8eSKurt Hackel /* for now we operate under the assertion that there can be only one
350c83ed8eSKurt Hackel  * cluster active at a time.  Changing this will require trickling
360c83ed8eSKurt Hackel  * cluster references throughout where nodes are looked up */
37296b75edSAndrew Beekhof struct o2nm_cluster *o2nm_single_cluster = NULL;
380c83ed8eSKurt Hackel 
390c83ed8eSKurt Hackel #define OCFS2_MAX_HB_CTL_PATH 256
400c83ed8eSKurt Hackel static char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl";
410c83ed8eSKurt Hackel 
420c83ed8eSKurt Hackel static ctl_table ocfs2_nm_table[] = {
430c83ed8eSKurt Hackel 	{
440c83ed8eSKurt Hackel 		.ctl_name	= 1,
450c83ed8eSKurt Hackel 		.procname	= "hb_ctl_path",
460c83ed8eSKurt Hackel 		.data		= ocfs2_hb_ctl_path,
470c83ed8eSKurt Hackel 		.maxlen		= OCFS2_MAX_HB_CTL_PATH,
480c83ed8eSKurt Hackel 		.mode		= 0644,
490c83ed8eSKurt Hackel 		.proc_handler	= &proc_dostring,
500c83ed8eSKurt Hackel 		.strategy	= &sysctl_string,
510c83ed8eSKurt Hackel 	},
520c83ed8eSKurt Hackel 	{ .ctl_name = 0 }
530c83ed8eSKurt Hackel };
540c83ed8eSKurt Hackel 
550c83ed8eSKurt Hackel static ctl_table ocfs2_mod_table[] = {
560c83ed8eSKurt Hackel 	{
570e03036cSEric W. Biederman 		.ctl_name	= FS_OCFS2_NM,
580c83ed8eSKurt Hackel 		.procname	= "nm",
590c83ed8eSKurt Hackel 		.data		= NULL,
600c83ed8eSKurt Hackel 		.maxlen		= 0,
610c83ed8eSKurt Hackel 		.mode		= 0555,
620c83ed8eSKurt Hackel 		.child		= ocfs2_nm_table
630c83ed8eSKurt Hackel 	},
640c83ed8eSKurt Hackel 	{ .ctl_name = 0}
650c83ed8eSKurt Hackel };
660c83ed8eSKurt Hackel 
670c83ed8eSKurt Hackel static ctl_table ocfs2_kern_table[] = {
680c83ed8eSKurt Hackel 	{
690e03036cSEric W. Biederman 		.ctl_name	= FS_OCFS2,
700c83ed8eSKurt Hackel 		.procname	= "ocfs2",
710c83ed8eSKurt Hackel 		.data		= NULL,
720c83ed8eSKurt Hackel 		.maxlen		= 0,
730c83ed8eSKurt Hackel 		.mode		= 0555,
740c83ed8eSKurt Hackel 		.child		= ocfs2_mod_table
750c83ed8eSKurt Hackel 	},
760c83ed8eSKurt Hackel 	{ .ctl_name = 0}
770c83ed8eSKurt Hackel };
780c83ed8eSKurt Hackel 
790c83ed8eSKurt Hackel static ctl_table ocfs2_root_table[] = {
800c83ed8eSKurt Hackel 	{
810c83ed8eSKurt Hackel 		.ctl_name	= CTL_FS,
820c83ed8eSKurt Hackel 		.procname	= "fs",
830c83ed8eSKurt Hackel 		.data		= NULL,
840c83ed8eSKurt Hackel 		.maxlen		= 0,
850c83ed8eSKurt Hackel 		.mode		= 0555,
860c83ed8eSKurt Hackel 		.child		= ocfs2_kern_table
870c83ed8eSKurt Hackel 	},
880c83ed8eSKurt Hackel 	{ .ctl_name = 0 }
890c83ed8eSKurt Hackel };
900c83ed8eSKurt Hackel 
910c83ed8eSKurt Hackel static struct ctl_table_header *ocfs2_table_header = NULL;
920c83ed8eSKurt Hackel 
930c83ed8eSKurt Hackel const char *o2nm_get_hb_ctl_path(void)
940c83ed8eSKurt Hackel {
950c83ed8eSKurt Hackel 	return ocfs2_hb_ctl_path;
960c83ed8eSKurt Hackel }
970c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_get_hb_ctl_path);
980c83ed8eSKurt Hackel 
990c83ed8eSKurt Hackel struct o2nm_node *o2nm_get_node_by_num(u8 node_num)
1000c83ed8eSKurt Hackel {
1010c83ed8eSKurt Hackel 	struct o2nm_node *node = NULL;
1020c83ed8eSKurt Hackel 
1030c83ed8eSKurt Hackel 	if (node_num >= O2NM_MAX_NODES || o2nm_single_cluster == NULL)
1040c83ed8eSKurt Hackel 		goto out;
1050c83ed8eSKurt Hackel 
1060c83ed8eSKurt Hackel 	read_lock(&o2nm_single_cluster->cl_nodes_lock);
1070c83ed8eSKurt Hackel 	node = o2nm_single_cluster->cl_nodes[node_num];
1080c83ed8eSKurt Hackel 	if (node)
1090c83ed8eSKurt Hackel 		config_item_get(&node->nd_item);
1100c83ed8eSKurt Hackel 	read_unlock(&o2nm_single_cluster->cl_nodes_lock);
1110c83ed8eSKurt Hackel out:
1120c83ed8eSKurt Hackel 	return node;
1130c83ed8eSKurt Hackel }
1140c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_get_node_by_num);
1150c83ed8eSKurt Hackel 
1160c83ed8eSKurt Hackel int o2nm_configured_node_map(unsigned long *map, unsigned bytes)
1170c83ed8eSKurt Hackel {
1180c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = o2nm_single_cluster;
1190c83ed8eSKurt Hackel 
1200c83ed8eSKurt Hackel 	BUG_ON(bytes < (sizeof(cluster->cl_nodes_bitmap)));
1210c83ed8eSKurt Hackel 
1220c83ed8eSKurt Hackel 	if (cluster == NULL)
1230c83ed8eSKurt Hackel 		return -EINVAL;
1240c83ed8eSKurt Hackel 
1250c83ed8eSKurt Hackel 	read_lock(&cluster->cl_nodes_lock);
1260c83ed8eSKurt Hackel 	memcpy(map, cluster->cl_nodes_bitmap, sizeof(cluster->cl_nodes_bitmap));
1270c83ed8eSKurt Hackel 	read_unlock(&cluster->cl_nodes_lock);
1280c83ed8eSKurt Hackel 
1290c83ed8eSKurt Hackel 	return 0;
1300c83ed8eSKurt Hackel }
1310c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_configured_node_map);
1320c83ed8eSKurt Hackel 
1330c83ed8eSKurt Hackel static struct o2nm_node *o2nm_node_ip_tree_lookup(struct o2nm_cluster *cluster,
1340c83ed8eSKurt Hackel 						  __be32 ip_needle,
1350c83ed8eSKurt Hackel 						  struct rb_node ***ret_p,
1360c83ed8eSKurt Hackel 						  struct rb_node **ret_parent)
1370c83ed8eSKurt Hackel {
1380c83ed8eSKurt Hackel 	struct rb_node **p = &cluster->cl_node_ip_tree.rb_node;
1390c83ed8eSKurt Hackel 	struct rb_node *parent = NULL;
1400c83ed8eSKurt Hackel 	struct o2nm_node *node, *ret = NULL;
1410c83ed8eSKurt Hackel 
1420c83ed8eSKurt Hackel 	while (*p) {
14379cd22d3SAkinobu Mita 		int cmp;
14479cd22d3SAkinobu Mita 
1450c83ed8eSKurt Hackel 		parent = *p;
1460c83ed8eSKurt Hackel 		node = rb_entry(parent, struct o2nm_node, nd_ip_node);
1470c83ed8eSKurt Hackel 
14879cd22d3SAkinobu Mita 		cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
14979cd22d3SAkinobu Mita 				sizeof(ip_needle));
15079cd22d3SAkinobu Mita 		if (cmp < 0)
1510c83ed8eSKurt Hackel 			p = &(*p)->rb_left;
15279cd22d3SAkinobu Mita 		else if (cmp > 0)
1530c83ed8eSKurt Hackel 			p = &(*p)->rb_right;
1540c83ed8eSKurt Hackel 		else {
1550c83ed8eSKurt Hackel 			ret = node;
1560c83ed8eSKurt Hackel 			break;
1570c83ed8eSKurt Hackel 		}
1580c83ed8eSKurt Hackel 	}
1590c83ed8eSKurt Hackel 
1600c83ed8eSKurt Hackel 	if (ret_p != NULL)
1610c83ed8eSKurt Hackel 		*ret_p = p;
1620c83ed8eSKurt Hackel 	if (ret_parent != NULL)
1630c83ed8eSKurt Hackel 		*ret_parent = parent;
1640c83ed8eSKurt Hackel 
1650c83ed8eSKurt Hackel 	return ret;
1660c83ed8eSKurt Hackel }
1670c83ed8eSKurt Hackel 
1680c83ed8eSKurt Hackel struct o2nm_node *o2nm_get_node_by_ip(__be32 addr)
1690c83ed8eSKurt Hackel {
1700c83ed8eSKurt Hackel 	struct o2nm_node *node = NULL;
1710c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = o2nm_single_cluster;
1720c83ed8eSKurt Hackel 
1730c83ed8eSKurt Hackel 	if (cluster == NULL)
1740c83ed8eSKurt Hackel 		goto out;
1750c83ed8eSKurt Hackel 
1760c83ed8eSKurt Hackel 	read_lock(&cluster->cl_nodes_lock);
1770c83ed8eSKurt Hackel 	node = o2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
1780c83ed8eSKurt Hackel 	if (node)
1790c83ed8eSKurt Hackel 		config_item_get(&node->nd_item);
1800c83ed8eSKurt Hackel 	read_unlock(&cluster->cl_nodes_lock);
1810c83ed8eSKurt Hackel 
1820c83ed8eSKurt Hackel out:
1830c83ed8eSKurt Hackel 	return node;
1840c83ed8eSKurt Hackel }
1850c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_get_node_by_ip);
1860c83ed8eSKurt Hackel 
1870c83ed8eSKurt Hackel void o2nm_node_put(struct o2nm_node *node)
1880c83ed8eSKurt Hackel {
1890c83ed8eSKurt Hackel 	config_item_put(&node->nd_item);
1900c83ed8eSKurt Hackel }
1910c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_node_put);
1920c83ed8eSKurt Hackel 
1930c83ed8eSKurt Hackel void o2nm_node_get(struct o2nm_node *node)
1940c83ed8eSKurt Hackel {
1950c83ed8eSKurt Hackel 	config_item_get(&node->nd_item);
1960c83ed8eSKurt Hackel }
1970c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_node_get);
1980c83ed8eSKurt Hackel 
1990c83ed8eSKurt Hackel u8 o2nm_this_node(void)
2000c83ed8eSKurt Hackel {
2010c83ed8eSKurt Hackel 	u8 node_num = O2NM_MAX_NODES;
2020c83ed8eSKurt Hackel 
2030c83ed8eSKurt Hackel 	if (o2nm_single_cluster && o2nm_single_cluster->cl_has_local)
2040c83ed8eSKurt Hackel 		node_num = o2nm_single_cluster->cl_local_node;
2050c83ed8eSKurt Hackel 
2060c83ed8eSKurt Hackel 	return node_num;
2070c83ed8eSKurt Hackel }
2080c83ed8eSKurt Hackel EXPORT_SYMBOL_GPL(o2nm_this_node);
2090c83ed8eSKurt Hackel 
2100c83ed8eSKurt Hackel /* node configfs bits */
2110c83ed8eSKurt Hackel 
2120c83ed8eSKurt Hackel static struct o2nm_cluster *to_o2nm_cluster(struct config_item *item)
2130c83ed8eSKurt Hackel {
2140c83ed8eSKurt Hackel 	return item ?
2150c83ed8eSKurt Hackel 		container_of(to_config_group(item), struct o2nm_cluster,
2160c83ed8eSKurt Hackel 			     cl_group)
2170c83ed8eSKurt Hackel 		: NULL;
2180c83ed8eSKurt Hackel }
2190c83ed8eSKurt Hackel 
2200c83ed8eSKurt Hackel static struct o2nm_node *to_o2nm_node(struct config_item *item)
2210c83ed8eSKurt Hackel {
2220c83ed8eSKurt Hackel 	return item ? container_of(item, struct o2nm_node, nd_item) : NULL;
2230c83ed8eSKurt Hackel }
2240c83ed8eSKurt Hackel 
2250c83ed8eSKurt Hackel static void o2nm_node_release(struct config_item *item)
2260c83ed8eSKurt Hackel {
2270c83ed8eSKurt Hackel 	struct o2nm_node *node = to_o2nm_node(item);
2280c83ed8eSKurt Hackel 	kfree(node);
2290c83ed8eSKurt Hackel }
2300c83ed8eSKurt Hackel 
2310c83ed8eSKurt Hackel static ssize_t o2nm_node_num_read(struct o2nm_node *node, char *page)
2320c83ed8eSKurt Hackel {
2330c83ed8eSKurt Hackel 	return sprintf(page, "%d\n", node->nd_num);
2340c83ed8eSKurt Hackel }
2350c83ed8eSKurt Hackel 
2360c83ed8eSKurt Hackel static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node)
2370c83ed8eSKurt Hackel {
2380c83ed8eSKurt Hackel 	/* through the first node_set .parent
2390c83ed8eSKurt Hackel 	 * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */
2400c83ed8eSKurt Hackel 	return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
2410c83ed8eSKurt Hackel }
2420c83ed8eSKurt Hackel 
2430c83ed8eSKurt Hackel enum {
2440c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_NUM = 0,
2450c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_PORT,
2460c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_ADDRESS,
2470c83ed8eSKurt Hackel 	O2NM_NODE_ATTR_LOCAL,
2480c83ed8eSKurt Hackel };
2490c83ed8eSKurt Hackel 
2500c83ed8eSKurt Hackel static ssize_t o2nm_node_num_write(struct o2nm_node *node, const char *page,
2510c83ed8eSKurt Hackel 				   size_t count)
2520c83ed8eSKurt Hackel {
2530c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
2540c83ed8eSKurt Hackel 	unsigned long tmp;
2550c83ed8eSKurt Hackel 	char *p = (char *)page;
2560c83ed8eSKurt Hackel 
2570c83ed8eSKurt Hackel 	tmp = simple_strtoul(p, &p, 0);
2580c83ed8eSKurt Hackel 	if (!p || (*p && (*p != '\n')))
2590c83ed8eSKurt Hackel 		return -EINVAL;
2600c83ed8eSKurt Hackel 
2610c83ed8eSKurt Hackel 	if (tmp >= O2NM_MAX_NODES)
2620c83ed8eSKurt Hackel 		return -ERANGE;
2630c83ed8eSKurt Hackel 
2640c83ed8eSKurt Hackel 	/* once we're in the cl_nodes tree networking can look us up by
2650c83ed8eSKurt Hackel 	 * node number and try to use our address and port attributes
2660c83ed8eSKurt Hackel 	 * to connect to this node.. make sure that they've been set
2670c83ed8eSKurt Hackel 	 * before writing the node attribute? */
2680c83ed8eSKurt Hackel 	if (!test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
2690c83ed8eSKurt Hackel 	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
2700c83ed8eSKurt Hackel 		return -EINVAL; /* XXX */
2710c83ed8eSKurt Hackel 
2720c83ed8eSKurt Hackel 	write_lock(&cluster->cl_nodes_lock);
2730c83ed8eSKurt Hackel 	if (cluster->cl_nodes[tmp])
2740c83ed8eSKurt Hackel 		p = NULL;
2750c83ed8eSKurt Hackel 	else  {
2760c83ed8eSKurt Hackel 		cluster->cl_nodes[tmp] = node;
2770c83ed8eSKurt Hackel 		node->nd_num = tmp;
2780c83ed8eSKurt Hackel 		set_bit(tmp, cluster->cl_nodes_bitmap);
2790c83ed8eSKurt Hackel 	}
2800c83ed8eSKurt Hackel 	write_unlock(&cluster->cl_nodes_lock);
2810c83ed8eSKurt Hackel 	if (p == NULL)
2820c83ed8eSKurt Hackel 		return -EEXIST;
2830c83ed8eSKurt Hackel 
2840c83ed8eSKurt Hackel 	return count;
2850c83ed8eSKurt Hackel }
2860c83ed8eSKurt Hackel static ssize_t o2nm_node_ipv4_port_read(struct o2nm_node *node, char *page)
2870c83ed8eSKurt Hackel {
2880c83ed8eSKurt Hackel 	return sprintf(page, "%u\n", ntohs(node->nd_ipv4_port));
2890c83ed8eSKurt Hackel }
2900c83ed8eSKurt Hackel 
2910c83ed8eSKurt Hackel static ssize_t o2nm_node_ipv4_port_write(struct o2nm_node *node,
2920c83ed8eSKurt Hackel 					 const char *page, size_t count)
2930c83ed8eSKurt Hackel {
2940c83ed8eSKurt Hackel 	unsigned long tmp;
2950c83ed8eSKurt Hackel 	char *p = (char *)page;
2960c83ed8eSKurt Hackel 
2970c83ed8eSKurt Hackel 	tmp = simple_strtoul(p, &p, 0);
2980c83ed8eSKurt Hackel 	if (!p || (*p && (*p != '\n')))
2990c83ed8eSKurt Hackel 		return -EINVAL;
3000c83ed8eSKurt Hackel 
3010c83ed8eSKurt Hackel 	if (tmp == 0)
3020c83ed8eSKurt Hackel 		return -EINVAL;
3030c83ed8eSKurt Hackel 	if (tmp >= (u16)-1)
3040c83ed8eSKurt Hackel 		return -ERANGE;
3050c83ed8eSKurt Hackel 
3060c83ed8eSKurt Hackel 	node->nd_ipv4_port = htons(tmp);
3070c83ed8eSKurt Hackel 
3080c83ed8eSKurt Hackel 	return count;
3090c83ed8eSKurt Hackel }
3100c83ed8eSKurt Hackel 
3110c83ed8eSKurt Hackel static ssize_t o2nm_node_ipv4_address_read(struct o2nm_node *node, char *page)
3120c83ed8eSKurt Hackel {
3130c83ed8eSKurt Hackel 	return sprintf(page, "%u.%u.%u.%u\n", NIPQUAD(node->nd_ipv4_address));
3140c83ed8eSKurt Hackel }
3150c83ed8eSKurt Hackel 
3160c83ed8eSKurt Hackel static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
3170c83ed8eSKurt Hackel 					    const char *page,
3180c83ed8eSKurt Hackel 					    size_t count)
3190c83ed8eSKurt Hackel {
3200c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
3210c83ed8eSKurt Hackel 	int ret, i;
3220c83ed8eSKurt Hackel 	struct rb_node **p, *parent;
3230c83ed8eSKurt Hackel 	unsigned int octets[4];
3240c83ed8eSKurt Hackel 	__be32 ipv4_addr = 0;
3250c83ed8eSKurt Hackel 
3260c83ed8eSKurt Hackel 	ret = sscanf(page, "%3u.%3u.%3u.%3u", &octets[3], &octets[2],
3270c83ed8eSKurt Hackel 		     &octets[1], &octets[0]);
3280c83ed8eSKurt Hackel 	if (ret != 4)
3290c83ed8eSKurt Hackel 		return -EINVAL;
3300c83ed8eSKurt Hackel 
3310c83ed8eSKurt Hackel 	for (i = 0; i < ARRAY_SIZE(octets); i++) {
3320c83ed8eSKurt Hackel 		if (octets[i] > 255)
3330c83ed8eSKurt Hackel 			return -ERANGE;
3340c83ed8eSKurt Hackel 		be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
3350c83ed8eSKurt Hackel 	}
3360c83ed8eSKurt Hackel 
3370c83ed8eSKurt Hackel 	ret = 0;
3380c83ed8eSKurt Hackel 	write_lock(&cluster->cl_nodes_lock);
3390c83ed8eSKurt Hackel 	if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
3400c83ed8eSKurt Hackel 		ret = -EEXIST;
3410c83ed8eSKurt Hackel 	else {
3420c83ed8eSKurt Hackel 		rb_link_node(&node->nd_ip_node, parent, p);
3430c83ed8eSKurt Hackel 		rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
3440c83ed8eSKurt Hackel 	}
3450c83ed8eSKurt Hackel 	write_unlock(&cluster->cl_nodes_lock);
3460c83ed8eSKurt Hackel 	if (ret)
3470c83ed8eSKurt Hackel 		return ret;
3480c83ed8eSKurt Hackel 
3490c83ed8eSKurt Hackel 	memcpy(&node->nd_ipv4_address, &ipv4_addr, sizeof(ipv4_addr));
3500c83ed8eSKurt Hackel 
3510c83ed8eSKurt Hackel 	return count;
3520c83ed8eSKurt Hackel }
3530c83ed8eSKurt Hackel 
3540c83ed8eSKurt Hackel static ssize_t o2nm_node_local_read(struct o2nm_node *node, char *page)
3550c83ed8eSKurt Hackel {
3560c83ed8eSKurt Hackel 	return sprintf(page, "%d\n", node->nd_local);
3570c83ed8eSKurt Hackel }
3580c83ed8eSKurt Hackel 
3590c83ed8eSKurt Hackel static ssize_t o2nm_node_local_write(struct o2nm_node *node, const char *page,
3600c83ed8eSKurt Hackel 				     size_t count)
3610c83ed8eSKurt Hackel {
3620c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
3630c83ed8eSKurt Hackel 	unsigned long tmp;
3640c83ed8eSKurt Hackel 	char *p = (char *)page;
3650c83ed8eSKurt Hackel 	ssize_t ret;
3660c83ed8eSKurt Hackel 
3670c83ed8eSKurt Hackel 	tmp = simple_strtoul(p, &p, 0);
3680c83ed8eSKurt Hackel 	if (!p || (*p && (*p != '\n')))
3690c83ed8eSKurt Hackel 		return -EINVAL;
3700c83ed8eSKurt Hackel 
3710c83ed8eSKurt Hackel 	tmp = !!tmp; /* boolean of whether this node wants to be local */
3720c83ed8eSKurt Hackel 
3730c83ed8eSKurt Hackel 	/* setting local turns on networking rx for now so we require having
3740c83ed8eSKurt Hackel 	 * set everything else first */
3750c83ed8eSKurt Hackel 	if (!test_bit(O2NM_NODE_ATTR_ADDRESS, &node->nd_set_attributes) ||
3760c83ed8eSKurt Hackel 	    !test_bit(O2NM_NODE_ATTR_NUM, &node->nd_set_attributes) ||
3770c83ed8eSKurt Hackel 	    !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
3780c83ed8eSKurt Hackel 		return -EINVAL; /* XXX */
3790c83ed8eSKurt Hackel 
3800c83ed8eSKurt Hackel 	/* the only failure case is trying to set a new local node
3810c83ed8eSKurt Hackel 	 * when a different one is already set */
3820c83ed8eSKurt Hackel 	if (tmp && tmp == cluster->cl_has_local &&
3830c83ed8eSKurt Hackel 	    cluster->cl_local_node != node->nd_num)
3840c83ed8eSKurt Hackel 		return -EBUSY;
3850c83ed8eSKurt Hackel 
3860c83ed8eSKurt Hackel 	/* bring up the rx thread if we're setting the new local node. */
3870c83ed8eSKurt Hackel 	if (tmp && !cluster->cl_has_local) {
3880c83ed8eSKurt Hackel 		ret = o2net_start_listening(node);
3890c83ed8eSKurt Hackel 		if (ret)
3900c83ed8eSKurt Hackel 			return ret;
3910c83ed8eSKurt Hackel 	}
3920c83ed8eSKurt Hackel 
3930c83ed8eSKurt Hackel 	if (!tmp && cluster->cl_has_local &&
3940c83ed8eSKurt Hackel 	    cluster->cl_local_node == node->nd_num) {
3950c83ed8eSKurt Hackel 		o2net_stop_listening(node);
3960c83ed8eSKurt Hackel 		cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
3970c83ed8eSKurt Hackel 	}
3980c83ed8eSKurt Hackel 
3990c83ed8eSKurt Hackel 	node->nd_local = tmp;
4000c83ed8eSKurt Hackel 	if (node->nd_local) {
4010c83ed8eSKurt Hackel 		cluster->cl_has_local = tmp;
4020c83ed8eSKurt Hackel 		cluster->cl_local_node = node->nd_num;
4030c83ed8eSKurt Hackel 	}
4040c83ed8eSKurt Hackel 
4050c83ed8eSKurt Hackel 	return count;
4060c83ed8eSKurt Hackel }
4070c83ed8eSKurt Hackel 
4080c83ed8eSKurt Hackel struct o2nm_node_attribute {
4090c83ed8eSKurt Hackel 	struct configfs_attribute attr;
4100c83ed8eSKurt Hackel 	ssize_t (*show)(struct o2nm_node *, char *);
4110c83ed8eSKurt Hackel 	ssize_t (*store)(struct o2nm_node *, const char *, size_t);
4120c83ed8eSKurt Hackel };
4130c83ed8eSKurt Hackel 
4140c83ed8eSKurt Hackel static struct o2nm_node_attribute o2nm_node_attr_num = {
4150c83ed8eSKurt Hackel 	.attr	= { .ca_owner = THIS_MODULE,
4160c83ed8eSKurt Hackel 		    .ca_name = "num",
4170c83ed8eSKurt Hackel 		    .ca_mode = S_IRUGO | S_IWUSR },
4180c83ed8eSKurt Hackel 	.show	= o2nm_node_num_read,
4190c83ed8eSKurt Hackel 	.store	= o2nm_node_num_write,
4200c83ed8eSKurt Hackel };
4210c83ed8eSKurt Hackel 
4220c83ed8eSKurt Hackel static struct o2nm_node_attribute o2nm_node_attr_ipv4_port = {
4230c83ed8eSKurt Hackel 	.attr	= { .ca_owner = THIS_MODULE,
4240c83ed8eSKurt Hackel 		    .ca_name = "ipv4_port",
4250c83ed8eSKurt Hackel 		    .ca_mode = S_IRUGO | S_IWUSR },
4260c83ed8eSKurt Hackel 	.show	= o2nm_node_ipv4_port_read,
4270c83ed8eSKurt Hackel 	.store	= o2nm_node_ipv4_port_write,
4280c83ed8eSKurt Hackel };
4290c83ed8eSKurt Hackel 
4300c83ed8eSKurt Hackel static struct o2nm_node_attribute o2nm_node_attr_ipv4_address = {
4310c83ed8eSKurt Hackel 	.attr	= { .ca_owner = THIS_MODULE,
4320c83ed8eSKurt Hackel 		    .ca_name = "ipv4_address",
4330c83ed8eSKurt Hackel 		    .ca_mode = S_IRUGO | S_IWUSR },
4340c83ed8eSKurt Hackel 	.show	= o2nm_node_ipv4_address_read,
4350c83ed8eSKurt Hackel 	.store	= o2nm_node_ipv4_address_write,
4360c83ed8eSKurt Hackel };
4370c83ed8eSKurt Hackel 
4380c83ed8eSKurt Hackel static struct o2nm_node_attribute o2nm_node_attr_local = {
4390c83ed8eSKurt Hackel 	.attr	= { .ca_owner = THIS_MODULE,
4400c83ed8eSKurt Hackel 		    .ca_name = "local",
4410c83ed8eSKurt Hackel 		    .ca_mode = S_IRUGO | S_IWUSR },
4420c83ed8eSKurt Hackel 	.show	= o2nm_node_local_read,
4430c83ed8eSKurt Hackel 	.store	= o2nm_node_local_write,
4440c83ed8eSKurt Hackel };
4450c83ed8eSKurt Hackel 
4460c83ed8eSKurt Hackel static struct configfs_attribute *o2nm_node_attrs[] = {
4470c83ed8eSKurt Hackel 	[O2NM_NODE_ATTR_NUM] = &o2nm_node_attr_num.attr,
4480c83ed8eSKurt Hackel 	[O2NM_NODE_ATTR_PORT] = &o2nm_node_attr_ipv4_port.attr,
4490c83ed8eSKurt Hackel 	[O2NM_NODE_ATTR_ADDRESS] = &o2nm_node_attr_ipv4_address.attr,
4500c83ed8eSKurt Hackel 	[O2NM_NODE_ATTR_LOCAL] = &o2nm_node_attr_local.attr,
4510c83ed8eSKurt Hackel 	NULL,
4520c83ed8eSKurt Hackel };
4530c83ed8eSKurt Hackel 
4540c83ed8eSKurt Hackel static int o2nm_attr_index(struct configfs_attribute *attr)
4550c83ed8eSKurt Hackel {
4560c83ed8eSKurt Hackel 	int i;
4570c83ed8eSKurt Hackel 	for (i = 0; i < ARRAY_SIZE(o2nm_node_attrs); i++) {
4580c83ed8eSKurt Hackel 		if (attr == o2nm_node_attrs[i])
4590c83ed8eSKurt Hackel 			return i;
4600c83ed8eSKurt Hackel 	}
4610c83ed8eSKurt Hackel 	BUG();
4620c83ed8eSKurt Hackel 	return 0;
4630c83ed8eSKurt Hackel }
4640c83ed8eSKurt Hackel 
4650c83ed8eSKurt Hackel static ssize_t o2nm_node_show(struct config_item *item,
4660c83ed8eSKurt Hackel 			      struct configfs_attribute *attr,
4670c83ed8eSKurt Hackel 			      char *page)
4680c83ed8eSKurt Hackel {
4690c83ed8eSKurt Hackel 	struct o2nm_node *node = to_o2nm_node(item);
4700c83ed8eSKurt Hackel 	struct o2nm_node_attribute *o2nm_node_attr =
4710c83ed8eSKurt Hackel 		container_of(attr, struct o2nm_node_attribute, attr);
4720c83ed8eSKurt Hackel 	ssize_t ret = 0;
4730c83ed8eSKurt Hackel 
4740c83ed8eSKurt Hackel 	if (o2nm_node_attr->show)
4750c83ed8eSKurt Hackel 		ret = o2nm_node_attr->show(node, page);
4760c83ed8eSKurt Hackel 	return ret;
4770c83ed8eSKurt Hackel }
4780c83ed8eSKurt Hackel 
4790c83ed8eSKurt Hackel static ssize_t o2nm_node_store(struct config_item *item,
4800c83ed8eSKurt Hackel 			       struct configfs_attribute *attr,
4810c83ed8eSKurt Hackel 			       const char *page, size_t count)
4820c83ed8eSKurt Hackel {
4830c83ed8eSKurt Hackel 	struct o2nm_node *node = to_o2nm_node(item);
4840c83ed8eSKurt Hackel 	struct o2nm_node_attribute *o2nm_node_attr =
4850c83ed8eSKurt Hackel 		container_of(attr, struct o2nm_node_attribute, attr);
4860c83ed8eSKurt Hackel 	ssize_t ret;
4870c83ed8eSKurt Hackel 	int attr_index = o2nm_attr_index(attr);
4880c83ed8eSKurt Hackel 
4890c83ed8eSKurt Hackel 	if (o2nm_node_attr->store == NULL) {
4900c83ed8eSKurt Hackel 		ret = -EINVAL;
4910c83ed8eSKurt Hackel 		goto out;
4920c83ed8eSKurt Hackel 	}
4930c83ed8eSKurt Hackel 
4940c83ed8eSKurt Hackel 	if (test_bit(attr_index, &node->nd_set_attributes))
4950c83ed8eSKurt Hackel 		return -EBUSY;
4960c83ed8eSKurt Hackel 
4970c83ed8eSKurt Hackel 	ret = o2nm_node_attr->store(node, page, count);
4980c83ed8eSKurt Hackel 	if (ret < count)
4990c83ed8eSKurt Hackel 		goto out;
5000c83ed8eSKurt Hackel 
5010c83ed8eSKurt Hackel 	set_bit(attr_index, &node->nd_set_attributes);
5020c83ed8eSKurt Hackel out:
5030c83ed8eSKurt Hackel 	return ret;
5040c83ed8eSKurt Hackel }
5050c83ed8eSKurt Hackel 
5060c83ed8eSKurt Hackel static struct configfs_item_operations o2nm_node_item_ops = {
5070c83ed8eSKurt Hackel 	.release		= o2nm_node_release,
5080c83ed8eSKurt Hackel 	.show_attribute		= o2nm_node_show,
5090c83ed8eSKurt Hackel 	.store_attribute	= o2nm_node_store,
5100c83ed8eSKurt Hackel };
5110c83ed8eSKurt Hackel 
5120c83ed8eSKurt Hackel static struct config_item_type o2nm_node_type = {
5130c83ed8eSKurt Hackel 	.ct_item_ops	= &o2nm_node_item_ops,
5140c83ed8eSKurt Hackel 	.ct_attrs	= o2nm_node_attrs,
5150c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
5160c83ed8eSKurt Hackel };
5170c83ed8eSKurt Hackel 
5180c83ed8eSKurt Hackel /* node set */
5190c83ed8eSKurt Hackel 
5200c83ed8eSKurt Hackel struct o2nm_node_group {
5210c83ed8eSKurt Hackel 	struct config_group ns_group;
5220c83ed8eSKurt Hackel 	/* some stuff? */
5230c83ed8eSKurt Hackel };
5240c83ed8eSKurt Hackel 
5250c83ed8eSKurt Hackel #if 0
5260c83ed8eSKurt Hackel static struct o2nm_node_group *to_o2nm_node_group(struct config_group *group)
5270c83ed8eSKurt Hackel {
5280c83ed8eSKurt Hackel 	return group ?
5290c83ed8eSKurt Hackel 		container_of(group, struct o2nm_node_group, ns_group)
5300c83ed8eSKurt Hackel 		: NULL;
5310c83ed8eSKurt Hackel }
5320c83ed8eSKurt Hackel #endif
5330c83ed8eSKurt Hackel 
534b5dd8030SJeff Mahoney struct o2nm_cluster_attribute {
535b5dd8030SJeff Mahoney 	struct configfs_attribute attr;
536b5dd8030SJeff Mahoney 	ssize_t (*show)(struct o2nm_cluster *, char *);
537b5dd8030SJeff Mahoney 	ssize_t (*store)(struct o2nm_cluster *, const char *, size_t);
538b5dd8030SJeff Mahoney };
539b5dd8030SJeff Mahoney 
540b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_write(const char *page, ssize_t count,
541b5dd8030SJeff Mahoney                                        unsigned int *val)
542b5dd8030SJeff Mahoney {
543b5dd8030SJeff Mahoney 	unsigned long tmp;
544b5dd8030SJeff Mahoney 	char *p = (char *)page;
545b5dd8030SJeff Mahoney 
546b5dd8030SJeff Mahoney 	tmp = simple_strtoul(p, &p, 0);
547b5dd8030SJeff Mahoney 	if (!p || (*p && (*p != '\n')))
548b5dd8030SJeff Mahoney 		return -EINVAL;
549b5dd8030SJeff Mahoney 
550b5dd8030SJeff Mahoney 	if (tmp == 0)
551b5dd8030SJeff Mahoney 		return -EINVAL;
552b5dd8030SJeff Mahoney 	if (tmp >= (u32)-1)
553b5dd8030SJeff Mahoney 		return -ERANGE;
554b5dd8030SJeff Mahoney 
555b5dd8030SJeff Mahoney 	*val = tmp;
556b5dd8030SJeff Mahoney 
557b5dd8030SJeff Mahoney 	return count;
558b5dd8030SJeff Mahoney }
559b5dd8030SJeff Mahoney 
560b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_idle_timeout_ms_read(
561b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster, char *page)
562b5dd8030SJeff Mahoney {
563b5dd8030SJeff Mahoney 	return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
564b5dd8030SJeff Mahoney }
565b5dd8030SJeff Mahoney 
566b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_idle_timeout_ms_write(
567b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster, const char *page, size_t count)
568b5dd8030SJeff Mahoney {
569b5dd8030SJeff Mahoney 	ssize_t ret;
570b5dd8030SJeff Mahoney 	unsigned int val;
571b5dd8030SJeff Mahoney 
572b5dd8030SJeff Mahoney 	ret =  o2nm_cluster_attr_write(page, count, &val);
573b5dd8030SJeff Mahoney 
574b5dd8030SJeff Mahoney 	if (ret > 0) {
575828ae6afSAndrew Beekhof 		if (cluster->cl_idle_timeout_ms != val
576828ae6afSAndrew Beekhof 			&& o2net_num_connected_peers()) {
577828ae6afSAndrew Beekhof 			mlog(ML_NOTICE,
578828ae6afSAndrew Beekhof 			     "o2net: cannot change idle timeout after "
579828ae6afSAndrew Beekhof 			     "the first peer has agreed to it."
580828ae6afSAndrew Beekhof 			     "  %d connected peers\n",
581828ae6afSAndrew Beekhof 			     o2net_num_connected_peers());
582828ae6afSAndrew Beekhof 			ret = -EINVAL;
583828ae6afSAndrew Beekhof 		} else if (val <= cluster->cl_keepalive_delay_ms) {
584b5dd8030SJeff Mahoney 			mlog(ML_NOTICE, "o2net: idle timeout must be larger "
585b5dd8030SJeff Mahoney 			     "than keepalive delay\n");
586828ae6afSAndrew Beekhof 			ret = -EINVAL;
587828ae6afSAndrew Beekhof 		} else {
588b5dd8030SJeff Mahoney 			cluster->cl_idle_timeout_ms = val;
589b5dd8030SJeff Mahoney 		}
590828ae6afSAndrew Beekhof 	}
591b5dd8030SJeff Mahoney 
592b5dd8030SJeff Mahoney 	return ret;
593b5dd8030SJeff Mahoney }
594b5dd8030SJeff Mahoney 
595b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_keepalive_delay_ms_read(
596b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster, char *page)
597b5dd8030SJeff Mahoney {
598b5dd8030SJeff Mahoney 	return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
599b5dd8030SJeff Mahoney }
600b5dd8030SJeff Mahoney 
601b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_keepalive_delay_ms_write(
602b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster, const char *page, size_t count)
603b5dd8030SJeff Mahoney {
604b5dd8030SJeff Mahoney 	ssize_t ret;
605b5dd8030SJeff Mahoney 	unsigned int val;
606b5dd8030SJeff Mahoney 
607b5dd8030SJeff Mahoney 	ret =  o2nm_cluster_attr_write(page, count, &val);
608b5dd8030SJeff Mahoney 
609b5dd8030SJeff Mahoney 	if (ret > 0) {
610828ae6afSAndrew Beekhof 		if (cluster->cl_keepalive_delay_ms != val
611828ae6afSAndrew Beekhof 		    && o2net_num_connected_peers()) {
612828ae6afSAndrew Beekhof 			mlog(ML_NOTICE,
613828ae6afSAndrew Beekhof 			     "o2net: cannot change keepalive delay after"
614828ae6afSAndrew Beekhof 			     " the first peer has agreed to it."
615828ae6afSAndrew Beekhof 			     "  %d connected peers\n",
616828ae6afSAndrew Beekhof 			     o2net_num_connected_peers());
617828ae6afSAndrew Beekhof 			ret = -EINVAL;
618828ae6afSAndrew Beekhof 		} else if (val >= cluster->cl_idle_timeout_ms) {
619b5dd8030SJeff Mahoney 			mlog(ML_NOTICE, "o2net: keepalive delay must be "
620b5dd8030SJeff Mahoney 			     "smaller than idle timeout\n");
621828ae6afSAndrew Beekhof 			ret = -EINVAL;
622828ae6afSAndrew Beekhof 		} else {
623b5dd8030SJeff Mahoney 			cluster->cl_keepalive_delay_ms = val;
624b5dd8030SJeff Mahoney 		}
625828ae6afSAndrew Beekhof 	}
626b5dd8030SJeff Mahoney 
627b5dd8030SJeff Mahoney 	return ret;
628b5dd8030SJeff Mahoney }
629b5dd8030SJeff Mahoney 
630b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_reconnect_delay_ms_read(
631b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster, char *page)
632b5dd8030SJeff Mahoney {
633b5dd8030SJeff Mahoney 	return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
634b5dd8030SJeff Mahoney }
635b5dd8030SJeff Mahoney 
636b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_attr_reconnect_delay_ms_write(
637b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster, const char *page, size_t count)
638b5dd8030SJeff Mahoney {
639b5dd8030SJeff Mahoney 	return o2nm_cluster_attr_write(page, count,
640b5dd8030SJeff Mahoney 	                               &cluster->cl_reconnect_delay_ms);
641b5dd8030SJeff Mahoney }
642b5dd8030SJeff Mahoney static struct o2nm_cluster_attribute o2nm_cluster_attr_idle_timeout_ms = {
643b5dd8030SJeff Mahoney 	.attr	= { .ca_owner = THIS_MODULE,
644b5dd8030SJeff Mahoney 		    .ca_name = "idle_timeout_ms",
645b5dd8030SJeff Mahoney 		    .ca_mode = S_IRUGO | S_IWUSR },
646b5dd8030SJeff Mahoney 	.show	= o2nm_cluster_attr_idle_timeout_ms_read,
647b5dd8030SJeff Mahoney 	.store	= o2nm_cluster_attr_idle_timeout_ms_write,
648b5dd8030SJeff Mahoney };
649b5dd8030SJeff Mahoney 
650b5dd8030SJeff Mahoney static struct o2nm_cluster_attribute o2nm_cluster_attr_keepalive_delay_ms = {
651b5dd8030SJeff Mahoney 	.attr	= { .ca_owner = THIS_MODULE,
652b5dd8030SJeff Mahoney 		    .ca_name = "keepalive_delay_ms",
653b5dd8030SJeff Mahoney 		    .ca_mode = S_IRUGO | S_IWUSR },
654b5dd8030SJeff Mahoney 	.show	= o2nm_cluster_attr_keepalive_delay_ms_read,
655b5dd8030SJeff Mahoney 	.store	= o2nm_cluster_attr_keepalive_delay_ms_write,
656b5dd8030SJeff Mahoney };
657b5dd8030SJeff Mahoney 
658b5dd8030SJeff Mahoney static struct o2nm_cluster_attribute o2nm_cluster_attr_reconnect_delay_ms = {
659b5dd8030SJeff Mahoney 	.attr	= { .ca_owner = THIS_MODULE,
660b5dd8030SJeff Mahoney 		    .ca_name = "reconnect_delay_ms",
661b5dd8030SJeff Mahoney 		    .ca_mode = S_IRUGO | S_IWUSR },
662b5dd8030SJeff Mahoney 	.show	= o2nm_cluster_attr_reconnect_delay_ms_read,
663b5dd8030SJeff Mahoney 	.store	= o2nm_cluster_attr_reconnect_delay_ms_write,
664b5dd8030SJeff Mahoney };
665b5dd8030SJeff Mahoney 
666b5dd8030SJeff Mahoney static struct configfs_attribute *o2nm_cluster_attrs[] = {
667b5dd8030SJeff Mahoney 	&o2nm_cluster_attr_idle_timeout_ms.attr,
668b5dd8030SJeff Mahoney 	&o2nm_cluster_attr_keepalive_delay_ms.attr,
669b5dd8030SJeff Mahoney 	&o2nm_cluster_attr_reconnect_delay_ms.attr,
670b5dd8030SJeff Mahoney 	NULL,
671b5dd8030SJeff Mahoney };
672b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_show(struct config_item *item,
673b5dd8030SJeff Mahoney                                  struct configfs_attribute *attr,
674b5dd8030SJeff Mahoney                                  char *page)
675b5dd8030SJeff Mahoney {
676b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
677b5dd8030SJeff Mahoney 	struct o2nm_cluster_attribute *o2nm_cluster_attr =
678b5dd8030SJeff Mahoney 		container_of(attr, struct o2nm_cluster_attribute, attr);
679b5dd8030SJeff Mahoney 	ssize_t ret = 0;
680b5dd8030SJeff Mahoney 
681b5dd8030SJeff Mahoney 	if (o2nm_cluster_attr->show)
682b5dd8030SJeff Mahoney 		ret = o2nm_cluster_attr->show(cluster, page);
683b5dd8030SJeff Mahoney 	return ret;
684b5dd8030SJeff Mahoney }
685b5dd8030SJeff Mahoney 
686b5dd8030SJeff Mahoney static ssize_t o2nm_cluster_store(struct config_item *item,
687b5dd8030SJeff Mahoney                                   struct configfs_attribute *attr,
688b5dd8030SJeff Mahoney                                   const char *page, size_t count)
689b5dd8030SJeff Mahoney {
690b5dd8030SJeff Mahoney 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
691b5dd8030SJeff Mahoney 	struct o2nm_cluster_attribute *o2nm_cluster_attr =
692b5dd8030SJeff Mahoney 		container_of(attr, struct o2nm_cluster_attribute, attr);
693b5dd8030SJeff Mahoney 	ssize_t ret;
694b5dd8030SJeff Mahoney 
695b5dd8030SJeff Mahoney 	if (o2nm_cluster_attr->store == NULL) {
696b5dd8030SJeff Mahoney 		ret = -EINVAL;
697b5dd8030SJeff Mahoney 		goto out;
698b5dd8030SJeff Mahoney 	}
699b5dd8030SJeff Mahoney 
700b5dd8030SJeff Mahoney 	ret = o2nm_cluster_attr->store(cluster, page, count);
701b5dd8030SJeff Mahoney 	if (ret < count)
702b5dd8030SJeff Mahoney 		goto out;
703b5dd8030SJeff Mahoney out:
704b5dd8030SJeff Mahoney 	return ret;
705b5dd8030SJeff Mahoney }
706b5dd8030SJeff Mahoney 
7070c83ed8eSKurt Hackel static struct config_item *o2nm_node_group_make_item(struct config_group *group,
7080c83ed8eSKurt Hackel 						     const char *name)
7090c83ed8eSKurt Hackel {
7100c83ed8eSKurt Hackel 	struct o2nm_node *node = NULL;
7110c83ed8eSKurt Hackel 	struct config_item *ret = NULL;
7120c83ed8eSKurt Hackel 
7130c83ed8eSKurt Hackel 	if (strlen(name) > O2NM_MAX_NAME_LEN)
7140c83ed8eSKurt Hackel 		goto out; /* ENAMETOOLONG */
7150c83ed8eSKurt Hackel 
716cd861280SRobert P. J. Day 	node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL);
7170c83ed8eSKurt Hackel 	if (node == NULL)
7180c83ed8eSKurt Hackel 		goto out; /* ENOMEM */
7190c83ed8eSKurt Hackel 
7200c83ed8eSKurt Hackel 	strcpy(node->nd_name, name); /* use item.ci_namebuf instead? */
7210c83ed8eSKurt Hackel 	config_item_init_type_name(&node->nd_item, name, &o2nm_node_type);
7220c83ed8eSKurt Hackel 	spin_lock_init(&node->nd_lock);
7230c83ed8eSKurt Hackel 
7240c83ed8eSKurt Hackel 	ret = &node->nd_item;
7250c83ed8eSKurt Hackel 
7260c83ed8eSKurt Hackel out:
7270c83ed8eSKurt Hackel 	if (ret == NULL)
7280c83ed8eSKurt Hackel 		kfree(node);
7290c83ed8eSKurt Hackel 
7300c83ed8eSKurt Hackel 	return ret;
7310c83ed8eSKurt Hackel }
7320c83ed8eSKurt Hackel 
7330c83ed8eSKurt Hackel static void o2nm_node_group_drop_item(struct config_group *group,
7340c83ed8eSKurt Hackel 				      struct config_item *item)
7350c83ed8eSKurt Hackel {
7360c83ed8eSKurt Hackel 	struct o2nm_node *node = to_o2nm_node(item);
7370c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster(group->cg_item.ci_parent);
7380c83ed8eSKurt Hackel 
7390c83ed8eSKurt Hackel 	o2net_disconnect_node(node);
7400c83ed8eSKurt Hackel 
7410c83ed8eSKurt Hackel 	if (cluster->cl_has_local &&
7420c83ed8eSKurt Hackel 	    (cluster->cl_local_node == node->nd_num)) {
7430c83ed8eSKurt Hackel 		cluster->cl_has_local = 0;
7440c83ed8eSKurt Hackel 		cluster->cl_local_node = O2NM_INVALID_NODE_NUM;
7450c83ed8eSKurt Hackel 		o2net_stop_listening(node);
7460c83ed8eSKurt Hackel 	}
7470c83ed8eSKurt Hackel 
7480c83ed8eSKurt Hackel 	/* XXX call into net to stop this node from trading messages */
7490c83ed8eSKurt Hackel 
7500c83ed8eSKurt Hackel 	write_lock(&cluster->cl_nodes_lock);
7510c83ed8eSKurt Hackel 
7520c83ed8eSKurt Hackel 	/* XXX sloppy */
7530c83ed8eSKurt Hackel 	if (node->nd_ipv4_address)
7540c83ed8eSKurt Hackel 		rb_erase(&node->nd_ip_node, &cluster->cl_node_ip_tree);
7550c83ed8eSKurt Hackel 
7560c83ed8eSKurt Hackel 	/* nd_num might be 0 if the node number hasn't been set.. */
7570c83ed8eSKurt Hackel 	if (cluster->cl_nodes[node->nd_num] == node) {
7580c83ed8eSKurt Hackel 		cluster->cl_nodes[node->nd_num] = NULL;
7590c83ed8eSKurt Hackel 		clear_bit(node->nd_num, cluster->cl_nodes_bitmap);
7600c83ed8eSKurt Hackel 	}
7610c83ed8eSKurt Hackel 	write_unlock(&cluster->cl_nodes_lock);
7620c83ed8eSKurt Hackel 
7630c83ed8eSKurt Hackel 	config_item_put(item);
7640c83ed8eSKurt Hackel }
7650c83ed8eSKurt Hackel 
7660c83ed8eSKurt Hackel static struct configfs_group_operations o2nm_node_group_group_ops = {
7670c83ed8eSKurt Hackel 	.make_item	= o2nm_node_group_make_item,
7680c83ed8eSKurt Hackel 	.drop_item	= o2nm_node_group_drop_item,
7690c83ed8eSKurt Hackel };
7700c83ed8eSKurt Hackel 
7710c83ed8eSKurt Hackel static struct config_item_type o2nm_node_group_type = {
7720c83ed8eSKurt Hackel 	.ct_group_ops	= &o2nm_node_group_group_ops,
7730c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
7740c83ed8eSKurt Hackel };
7750c83ed8eSKurt Hackel 
7760c83ed8eSKurt Hackel /* cluster */
7770c83ed8eSKurt Hackel 
7780c83ed8eSKurt Hackel static void o2nm_cluster_release(struct config_item *item)
7790c83ed8eSKurt Hackel {
7800c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
7810c83ed8eSKurt Hackel 
7820c83ed8eSKurt Hackel 	kfree(cluster->cl_group.default_groups);
7830c83ed8eSKurt Hackel 	kfree(cluster);
7840c83ed8eSKurt Hackel }
7850c83ed8eSKurt Hackel 
7860c83ed8eSKurt Hackel static struct configfs_item_operations o2nm_cluster_item_ops = {
7870c83ed8eSKurt Hackel 	.release	= o2nm_cluster_release,
788b5dd8030SJeff Mahoney 	.show_attribute		= o2nm_cluster_show,
789b5dd8030SJeff Mahoney 	.store_attribute	= o2nm_cluster_store,
7900c83ed8eSKurt Hackel };
7910c83ed8eSKurt Hackel 
7920c83ed8eSKurt Hackel static struct config_item_type o2nm_cluster_type = {
7930c83ed8eSKurt Hackel 	.ct_item_ops	= &o2nm_cluster_item_ops,
794b5dd8030SJeff Mahoney 	.ct_attrs	= o2nm_cluster_attrs,
7950c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
7960c83ed8eSKurt Hackel };
7970c83ed8eSKurt Hackel 
7980c83ed8eSKurt Hackel /* cluster set */
7990c83ed8eSKurt Hackel 
8000c83ed8eSKurt Hackel struct o2nm_cluster_group {
8010c83ed8eSKurt Hackel 	struct configfs_subsystem cs_subsys;
8020c83ed8eSKurt Hackel 	/* some stuff? */
8030c83ed8eSKurt Hackel };
8040c83ed8eSKurt Hackel 
8050c83ed8eSKurt Hackel #if 0
8060c83ed8eSKurt Hackel static struct o2nm_cluster_group *to_o2nm_cluster_group(struct config_group *group)
8070c83ed8eSKurt Hackel {
8080c83ed8eSKurt Hackel 	return group ?
8090c83ed8eSKurt Hackel 		container_of(to_configfs_subsystem(group), struct o2nm_cluster_group, cs_subsys)
8100c83ed8eSKurt Hackel 	       : NULL;
8110c83ed8eSKurt Hackel }
8120c83ed8eSKurt Hackel #endif
8130c83ed8eSKurt Hackel 
8140c83ed8eSKurt Hackel static struct config_group *o2nm_cluster_group_make_group(struct config_group *group,
8150c83ed8eSKurt Hackel 							  const char *name)
8160c83ed8eSKurt Hackel {
8170c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = NULL;
8180c83ed8eSKurt Hackel 	struct o2nm_node_group *ns = NULL;
8190c83ed8eSKurt Hackel 	struct config_group *o2hb_group = NULL, *ret = NULL;
8200c83ed8eSKurt Hackel 	void *defs = NULL;
8210c83ed8eSKurt Hackel 
8221b1dcc1bSJes Sorensen 	/* this runs under the parent dir's i_mutex; there can be only
8230c83ed8eSKurt Hackel 	 * one caller in here at a time */
8240c83ed8eSKurt Hackel 	if (o2nm_single_cluster)
8250c83ed8eSKurt Hackel 		goto out; /* ENOSPC */
8260c83ed8eSKurt Hackel 
827cd861280SRobert P. J. Day 	cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL);
828cd861280SRobert P. J. Day 	ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL);
8290c83ed8eSKurt Hackel 	defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
8300c83ed8eSKurt Hackel 	o2hb_group = o2hb_alloc_hb_set();
8310c83ed8eSKurt Hackel 	if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL)
8320c83ed8eSKurt Hackel 		goto out;
8330c83ed8eSKurt Hackel 
8340c83ed8eSKurt Hackel 	config_group_init_type_name(&cluster->cl_group, name,
8350c83ed8eSKurt Hackel 				    &o2nm_cluster_type);
8360c83ed8eSKurt Hackel 	config_group_init_type_name(&ns->ns_group, "node",
8370c83ed8eSKurt Hackel 				    &o2nm_node_group_type);
8380c83ed8eSKurt Hackel 
8390c83ed8eSKurt Hackel 	cluster->cl_group.default_groups = defs;
8400c83ed8eSKurt Hackel 	cluster->cl_group.default_groups[0] = &ns->ns_group;
8410c83ed8eSKurt Hackel 	cluster->cl_group.default_groups[1] = o2hb_group;
8420c83ed8eSKurt Hackel 	cluster->cl_group.default_groups[2] = NULL;
8430c83ed8eSKurt Hackel 	rwlock_init(&cluster->cl_nodes_lock);
8440c83ed8eSKurt Hackel 	cluster->cl_node_ip_tree = RB_ROOT;
845b5dd8030SJeff Mahoney 	cluster->cl_reconnect_delay_ms = O2NET_RECONNECT_DELAY_MS_DEFAULT;
846b5dd8030SJeff Mahoney 	cluster->cl_idle_timeout_ms    = O2NET_IDLE_TIMEOUT_MS_DEFAULT;
847b5dd8030SJeff Mahoney 	cluster->cl_keepalive_delay_ms = O2NET_KEEPALIVE_DELAY_MS_DEFAULT;
8480c83ed8eSKurt Hackel 
8490c83ed8eSKurt Hackel 	ret = &cluster->cl_group;
8500c83ed8eSKurt Hackel 	o2nm_single_cluster = cluster;
8510c83ed8eSKurt Hackel 
8520c83ed8eSKurt Hackel out:
8530c83ed8eSKurt Hackel 	if (ret == NULL) {
8540c83ed8eSKurt Hackel 		kfree(cluster);
8550c83ed8eSKurt Hackel 		kfree(ns);
8560c83ed8eSKurt Hackel 		o2hb_free_hb_set(o2hb_group);
8570c83ed8eSKurt Hackel 		kfree(defs);
8580c83ed8eSKurt Hackel 	}
8590c83ed8eSKurt Hackel 
8600c83ed8eSKurt Hackel 	return ret;
8610c83ed8eSKurt Hackel }
8620c83ed8eSKurt Hackel 
8630c83ed8eSKurt Hackel static void o2nm_cluster_group_drop_item(struct config_group *group, struct config_item *item)
8640c83ed8eSKurt Hackel {
8650c83ed8eSKurt Hackel 	struct o2nm_cluster *cluster = to_o2nm_cluster(item);
8660c83ed8eSKurt Hackel 	int i;
8670c83ed8eSKurt Hackel 	struct config_item *killme;
8680c83ed8eSKurt Hackel 
8690c83ed8eSKurt Hackel 	BUG_ON(o2nm_single_cluster != cluster);
8700c83ed8eSKurt Hackel 	o2nm_single_cluster = NULL;
8710c83ed8eSKurt Hackel 
8720c83ed8eSKurt Hackel 	for (i = 0; cluster->cl_group.default_groups[i]; i++) {
8730c83ed8eSKurt Hackel 		killme = &cluster->cl_group.default_groups[i]->cg_item;
8740c83ed8eSKurt Hackel 		cluster->cl_group.default_groups[i] = NULL;
8750c83ed8eSKurt Hackel 		config_item_put(killme);
8760c83ed8eSKurt Hackel 	}
8770c83ed8eSKurt Hackel 
8780c83ed8eSKurt Hackel 	config_item_put(item);
8790c83ed8eSKurt Hackel }
8800c83ed8eSKurt Hackel 
8810c83ed8eSKurt Hackel static struct configfs_group_operations o2nm_cluster_group_group_ops = {
8820c83ed8eSKurt Hackel 	.make_group	= o2nm_cluster_group_make_group,
8830c83ed8eSKurt Hackel 	.drop_item	= o2nm_cluster_group_drop_item,
8840c83ed8eSKurt Hackel };
8850c83ed8eSKurt Hackel 
8860c83ed8eSKurt Hackel static struct config_item_type o2nm_cluster_group_type = {
8870c83ed8eSKurt Hackel 	.ct_group_ops	= &o2nm_cluster_group_group_ops,
8880c83ed8eSKurt Hackel 	.ct_owner	= THIS_MODULE,
8890c83ed8eSKurt Hackel };
8900c83ed8eSKurt Hackel 
8910c83ed8eSKurt Hackel static struct o2nm_cluster_group o2nm_cluster_group = {
8920c83ed8eSKurt Hackel 	.cs_subsys = {
8930c83ed8eSKurt Hackel 		.su_group = {
8940c83ed8eSKurt Hackel 			.cg_item = {
8950c83ed8eSKurt Hackel 				.ci_namebuf = "cluster",
8960c83ed8eSKurt Hackel 				.ci_type = &o2nm_cluster_group_type,
8970c83ed8eSKurt Hackel 			},
8980c83ed8eSKurt Hackel 		},
8990c83ed8eSKurt Hackel 	},
9000c83ed8eSKurt Hackel };
9010c83ed8eSKurt Hackel 
90214829422SJoel Becker int o2nm_depend_item(struct config_item *item)
90314829422SJoel Becker {
90414829422SJoel Becker 	return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
90514829422SJoel Becker }
90614829422SJoel Becker 
90714829422SJoel Becker void o2nm_undepend_item(struct config_item *item)
90814829422SJoel Becker {
90914829422SJoel Becker 	configfs_undepend_item(&o2nm_cluster_group.cs_subsys, item);
91014829422SJoel Becker }
91114829422SJoel Becker 
91216c6a4f2SJoel Becker int o2nm_depend_this_node(void)
91316c6a4f2SJoel Becker {
91416c6a4f2SJoel Becker 	int ret = 0;
91516c6a4f2SJoel Becker 	struct o2nm_node *local_node;
91616c6a4f2SJoel Becker 
91716c6a4f2SJoel Becker 	local_node = o2nm_get_node_by_num(o2nm_this_node());
91816c6a4f2SJoel Becker 	if (!local_node) {
91916c6a4f2SJoel Becker 		ret = -EINVAL;
92016c6a4f2SJoel Becker 		goto out;
92116c6a4f2SJoel Becker 	}
92216c6a4f2SJoel Becker 
92316c6a4f2SJoel Becker 	ret = o2nm_depend_item(&local_node->nd_item);
92416c6a4f2SJoel Becker 	o2nm_node_put(local_node);
92516c6a4f2SJoel Becker 
92616c6a4f2SJoel Becker out:
92716c6a4f2SJoel Becker 	return ret;
92816c6a4f2SJoel Becker }
92916c6a4f2SJoel Becker 
93016c6a4f2SJoel Becker void o2nm_undepend_this_node(void)
93116c6a4f2SJoel Becker {
93216c6a4f2SJoel Becker 	struct o2nm_node *local_node;
93316c6a4f2SJoel Becker 
93416c6a4f2SJoel Becker 	local_node = o2nm_get_node_by_num(o2nm_this_node());
93516c6a4f2SJoel Becker 	BUG_ON(!local_node);
93616c6a4f2SJoel Becker 
93716c6a4f2SJoel Becker 	o2nm_undepend_item(&local_node->nd_item);
93816c6a4f2SJoel Becker 	o2nm_node_put(local_node);
93916c6a4f2SJoel Becker }
94016c6a4f2SJoel Becker 
94116c6a4f2SJoel Becker 
9420c83ed8eSKurt Hackel static void __exit exit_o2nm(void)
9430c83ed8eSKurt Hackel {
9440c83ed8eSKurt Hackel 	if (ocfs2_table_header)
9450c83ed8eSKurt Hackel 		unregister_sysctl_table(ocfs2_table_header);
9460c83ed8eSKurt Hackel 
9470c83ed8eSKurt Hackel 	/* XXX sync with hb callbacks and shut down hb? */
9480c83ed8eSKurt Hackel 	o2net_unregister_hb_callbacks();
9490c83ed8eSKurt Hackel 	configfs_unregister_subsystem(&o2nm_cluster_group.cs_subsys);
9500c83ed8eSKurt Hackel 	o2cb_sys_shutdown();
9510c83ed8eSKurt Hackel 
9520c83ed8eSKurt Hackel 	o2net_exit();
9530c83ed8eSKurt Hackel }
9540c83ed8eSKurt Hackel 
9550c83ed8eSKurt Hackel static int __init init_o2nm(void)
9560c83ed8eSKurt Hackel {
9570c83ed8eSKurt Hackel 	int ret = -1;
9580c83ed8eSKurt Hackel 
9590c83ed8eSKurt Hackel 	cluster_print_version();
9600c83ed8eSKurt Hackel 
9610c83ed8eSKurt Hackel 	o2hb_init();
9622309e9e0SSunil Mushran 
9632309e9e0SSunil Mushran 	ret = o2net_init();
9642309e9e0SSunil Mushran 	if (ret)
9652309e9e0SSunil Mushran 		goto out;
9660c83ed8eSKurt Hackel 
9670b4d4147SEric W. Biederman 	ocfs2_table_header = register_sysctl_table(ocfs2_root_table);
9680c83ed8eSKurt Hackel 	if (!ocfs2_table_header) {
9690c83ed8eSKurt Hackel 		printk(KERN_ERR "nodemanager: unable to register sysctl\n");
9700c83ed8eSKurt Hackel 		ret = -ENOMEM; /* or something. */
971895928b8SJeff Mahoney 		goto out_o2net;
9720c83ed8eSKurt Hackel 	}
9730c83ed8eSKurt Hackel 
9740c83ed8eSKurt Hackel 	ret = o2net_register_hb_callbacks();
9750c83ed8eSKurt Hackel 	if (ret)
9760c83ed8eSKurt Hackel 		goto out_sysctl;
9770c83ed8eSKurt Hackel 
9780c83ed8eSKurt Hackel 	config_group_init(&o2nm_cluster_group.cs_subsys.su_group);
979e6bd07aeSJoel Becker 	mutex_init(&o2nm_cluster_group.cs_subsys.su_mutex);
9800c83ed8eSKurt Hackel 	ret = configfs_register_subsystem(&o2nm_cluster_group.cs_subsys);
9810c83ed8eSKurt Hackel 	if (ret) {
9820c83ed8eSKurt Hackel 		printk(KERN_ERR "nodemanager: Registration returned %d\n", ret);
9830c83ed8eSKurt Hackel 		goto out_callbacks;
9840c83ed8eSKurt Hackel 	}
9850c83ed8eSKurt Hackel 
9860c83ed8eSKurt Hackel 	ret = o2cb_sys_init();
9870c83ed8eSKurt Hackel 	if (!ret)
9880c83ed8eSKurt Hackel 		goto out;
9890c83ed8eSKurt Hackel 
9900c83ed8eSKurt Hackel 	configfs_unregister_subsystem(&o2nm_cluster_group.cs_subsys);
9910c83ed8eSKurt Hackel out_callbacks:
9920c83ed8eSKurt Hackel 	o2net_unregister_hb_callbacks();
9930c83ed8eSKurt Hackel out_sysctl:
9940c83ed8eSKurt Hackel 	unregister_sysctl_table(ocfs2_table_header);
995895928b8SJeff Mahoney out_o2net:
996895928b8SJeff Mahoney 	o2net_exit();
9970c83ed8eSKurt Hackel out:
9980c83ed8eSKurt Hackel 	return ret;
9990c83ed8eSKurt Hackel }
10000c83ed8eSKurt Hackel 
10010c83ed8eSKurt Hackel MODULE_AUTHOR("Oracle");
10020c83ed8eSKurt Hackel MODULE_LICENSE("GPL");
10030c83ed8eSKurt Hackel 
10040c83ed8eSKurt Hackel module_init(init_o2nm)
10050c83ed8eSKurt Hackel module_exit(exit_o2nm)
1006