162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * stackglue.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Code which implements an OCFS2 specific interface to underlying
662306a36Sopenharmony_ci * cluster stacks.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2007, 2009 Oracle.  All rights reserved.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/list.h>
1262306a36Sopenharmony_ci#include <linux/spinlock.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/kmod.h>
1662306a36Sopenharmony_ci#include <linux/fs.h>
1762306a36Sopenharmony_ci#include <linux/kobject.h>
1862306a36Sopenharmony_ci#include <linux/sysfs.h>
1962306a36Sopenharmony_ci#include <linux/sysctl.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "ocfs2_fs.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "stackglue.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define OCFS2_STACK_PLUGIN_O2CB		"o2cb"
2662306a36Sopenharmony_ci#define OCFS2_STACK_PLUGIN_USER		"user"
2762306a36Sopenharmony_ci#define OCFS2_MAX_HB_CTL_PATH		256
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic struct ocfs2_protocol_version locking_max_version;
3062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ocfs2_stack_lock);
3162306a36Sopenharmony_cistatic LIST_HEAD(ocfs2_stack_list);
3262306a36Sopenharmony_cistatic char cluster_stack_name[OCFS2_STACK_LABEL_LEN + 1];
3362306a36Sopenharmony_cistatic char ocfs2_hb_ctl_path[OCFS2_MAX_HB_CTL_PATH] = "/sbin/ocfs2_hb_ctl";
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * The stack currently in use.  If not null, active_stack->sp_count > 0,
3762306a36Sopenharmony_ci * the module is pinned, and the locking protocol cannot be changed.
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic struct ocfs2_stack_plugin *active_stack;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct ocfs2_stack_plugin *p;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	assert_spin_locked(&ocfs2_stack_lock);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
4862306a36Sopenharmony_ci		if (!strcmp(p->sp_name, name))
4962306a36Sopenharmony_ci			return p;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return NULL;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int ocfs2_stack_driver_request(const char *stack_name,
5662306a36Sopenharmony_ci				      const char *plugin_name)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	int rc;
5962306a36Sopenharmony_ci	struct ocfs2_stack_plugin *p;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/*
6462306a36Sopenharmony_ci	 * If the stack passed by the filesystem isn't the selected one,
6562306a36Sopenharmony_ci	 * we can't continue.
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	if (strcmp(stack_name, cluster_stack_name)) {
6862306a36Sopenharmony_ci		rc = -EBUSY;
6962306a36Sopenharmony_ci		goto out;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (active_stack) {
7362306a36Sopenharmony_ci		/*
7462306a36Sopenharmony_ci		 * If the active stack isn't the one we want, it cannot
7562306a36Sopenharmony_ci		 * be selected right now.
7662306a36Sopenharmony_ci		 */
7762306a36Sopenharmony_ci		if (!strcmp(active_stack->sp_name, plugin_name))
7862306a36Sopenharmony_ci			rc = 0;
7962306a36Sopenharmony_ci		else
8062306a36Sopenharmony_ci			rc = -EBUSY;
8162306a36Sopenharmony_ci		goto out;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	p = ocfs2_stack_lookup(plugin_name);
8562306a36Sopenharmony_ci	if (!p || !try_module_get(p->sp_owner)) {
8662306a36Sopenharmony_ci		rc = -ENOENT;
8762306a36Sopenharmony_ci		goto out;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	active_stack = p;
9162306a36Sopenharmony_ci	rc = 0;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciout:
9462306a36Sopenharmony_ci	/* If we found it, pin it */
9562306a36Sopenharmony_ci	if (!rc)
9662306a36Sopenharmony_ci		active_stack->sp_count++;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
9962306a36Sopenharmony_ci	return rc;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/*
10362306a36Sopenharmony_ci * This function looks up the appropriate stack and makes it active.  If
10462306a36Sopenharmony_ci * there is no stack, it tries to load it.  It will fail if the stack still
10562306a36Sopenharmony_ci * cannot be found.  It will also fail if a different stack is in use.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_cistatic int ocfs2_stack_driver_get(const char *stack_name)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int rc;
11062306a36Sopenharmony_ci	char *plugin_name = OCFS2_STACK_PLUGIN_O2CB;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/*
11362306a36Sopenharmony_ci	 * Classic stack does not pass in a stack name.  This is
11462306a36Sopenharmony_ci	 * compatible with older tools as well.
11562306a36Sopenharmony_ci	 */
11662306a36Sopenharmony_ci	if (!stack_name || !*stack_name)
11762306a36Sopenharmony_ci		stack_name = OCFS2_STACK_PLUGIN_O2CB;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (strlen(stack_name) != OCFS2_STACK_LABEL_LEN) {
12062306a36Sopenharmony_ci		printk(KERN_ERR
12162306a36Sopenharmony_ci		       "ocfs2 passed an invalid cluster stack label: \"%s\"\n",
12262306a36Sopenharmony_ci		       stack_name);
12362306a36Sopenharmony_ci		return -EINVAL;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Anything that isn't the classic stack is a user stack */
12762306a36Sopenharmony_ci	if (strcmp(stack_name, OCFS2_STACK_PLUGIN_O2CB))
12862306a36Sopenharmony_ci		plugin_name = OCFS2_STACK_PLUGIN_USER;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	rc = ocfs2_stack_driver_request(stack_name, plugin_name);
13162306a36Sopenharmony_ci	if (rc == -ENOENT) {
13262306a36Sopenharmony_ci		request_module("ocfs2_stack_%s", plugin_name);
13362306a36Sopenharmony_ci		rc = ocfs2_stack_driver_request(stack_name, plugin_name);
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (rc == -ENOENT) {
13762306a36Sopenharmony_ci		printk(KERN_ERR
13862306a36Sopenharmony_ci		       "ocfs2: Cluster stack driver \"%s\" cannot be found\n",
13962306a36Sopenharmony_ci		       plugin_name);
14062306a36Sopenharmony_ci	} else if (rc == -EBUSY) {
14162306a36Sopenharmony_ci		printk(KERN_ERR
14262306a36Sopenharmony_ci		       "ocfs2: A different cluster stack is in use\n");
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return rc;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void ocfs2_stack_driver_put(void)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
15162306a36Sopenharmony_ci	BUG_ON(active_stack == NULL);
15262306a36Sopenharmony_ci	BUG_ON(active_stack->sp_count == 0);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	active_stack->sp_count--;
15562306a36Sopenharmony_ci	if (!active_stack->sp_count) {
15662306a36Sopenharmony_ci		module_put(active_stack->sp_owner);
15762306a36Sopenharmony_ci		active_stack = NULL;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciint ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int rc;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
16762306a36Sopenharmony_ci	if (!ocfs2_stack_lookup(plugin->sp_name)) {
16862306a36Sopenharmony_ci		plugin->sp_count = 0;
16962306a36Sopenharmony_ci		plugin->sp_max_proto = locking_max_version;
17062306a36Sopenharmony_ci		list_add(&plugin->sp_list, &ocfs2_stack_list);
17162306a36Sopenharmony_ci		printk(KERN_INFO "ocfs2: Registered cluster interface %s\n",
17262306a36Sopenharmony_ci		       plugin->sp_name);
17362306a36Sopenharmony_ci		rc = 0;
17462306a36Sopenharmony_ci	} else {
17562306a36Sopenharmony_ci		printk(KERN_ERR "ocfs2: Stack \"%s\" already registered\n",
17662306a36Sopenharmony_ci		       plugin->sp_name);
17762306a36Sopenharmony_ci		rc = -EEXIST;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return rc;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_stack_glue_register);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_civoid ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct ocfs2_stack_plugin *p;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
19062306a36Sopenharmony_ci	p = ocfs2_stack_lookup(plugin->sp_name);
19162306a36Sopenharmony_ci	if (p) {
19262306a36Sopenharmony_ci		BUG_ON(p != plugin);
19362306a36Sopenharmony_ci		BUG_ON(plugin == active_stack);
19462306a36Sopenharmony_ci		BUG_ON(plugin->sp_count != 0);
19562306a36Sopenharmony_ci		list_del_init(&plugin->sp_list);
19662306a36Sopenharmony_ci		printk(KERN_INFO "ocfs2: Unregistered cluster interface %s\n",
19762306a36Sopenharmony_ci		       plugin->sp_name);
19862306a36Sopenharmony_ci	} else {
19962306a36Sopenharmony_ci		printk(KERN_ERR "Stack \"%s\" is not registered\n",
20062306a36Sopenharmony_ci		       plugin->sp_name);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_stack_glue_unregister);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_civoid ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_proto)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct ocfs2_stack_plugin *p;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
21162306a36Sopenharmony_ci	if (memcmp(max_proto, &locking_max_version,
21262306a36Sopenharmony_ci		   sizeof(struct ocfs2_protocol_version))) {
21362306a36Sopenharmony_ci		BUG_ON(locking_max_version.pv_major != 0);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		locking_max_version = *max_proto;
21662306a36Sopenharmony_ci		list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
21762306a36Sopenharmony_ci			p->sp_max_proto = locking_max_version;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_stack_glue_set_max_proto_version);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/*
22662306a36Sopenharmony_ci * The ocfs2_dlm_lock() and ocfs2_dlm_unlock() functions take no argument
22762306a36Sopenharmony_ci * for the ast and bast functions.  They will pass the lksb to the ast
22862306a36Sopenharmony_ci * and bast.  The caller can wrap the lksb with their own structure to
22962306a36Sopenharmony_ci * get more information.
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_ciint ocfs2_dlm_lock(struct ocfs2_cluster_connection *conn,
23262306a36Sopenharmony_ci		   int mode,
23362306a36Sopenharmony_ci		   struct ocfs2_dlm_lksb *lksb,
23462306a36Sopenharmony_ci		   u32 flags,
23562306a36Sopenharmony_ci		   void *name,
23662306a36Sopenharmony_ci		   unsigned int namelen)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	if (!lksb->lksb_conn)
23962306a36Sopenharmony_ci		lksb->lksb_conn = conn;
24062306a36Sopenharmony_ci	else
24162306a36Sopenharmony_ci		BUG_ON(lksb->lksb_conn != conn);
24262306a36Sopenharmony_ci	return active_stack->sp_ops->dlm_lock(conn, mode, lksb, flags,
24362306a36Sopenharmony_ci					      name, namelen);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_dlm_lock);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ciint ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn,
24862306a36Sopenharmony_ci		     struct ocfs2_dlm_lksb *lksb,
24962306a36Sopenharmony_ci		     u32 flags)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	BUG_ON(lksb->lksb_conn == NULL);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return active_stack->sp_ops->dlm_unlock(conn, lksb, flags);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_dlm_unlock);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ciint ocfs2_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	return active_stack->sp_ops->lock_status(lksb);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ciint ocfs2_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	return active_stack->sp_ops->lvb_valid(lksb);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_civoid *ocfs2_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	return active_stack->sp_ops->lock_lvb(lksb);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_dlm_lvb);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_civoid ocfs2_dlm_dump_lksb(struct ocfs2_dlm_lksb *lksb)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	active_stack->sp_ops->dump_lksb(lksb);
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ciint ocfs2_stack_supports_plocks(void)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	return active_stack && active_stack->sp_ops->plock;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/*
28862306a36Sopenharmony_ci * ocfs2_plock() can only be safely called if
28962306a36Sopenharmony_ci * ocfs2_stack_supports_plocks() returned true
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_ciint ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
29262306a36Sopenharmony_ci		struct file *file, int cmd, struct file_lock *fl)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	WARN_ON_ONCE(active_stack->sp_ops->plock == NULL);
29562306a36Sopenharmony_ci	if (active_stack->sp_ops->plock)
29662306a36Sopenharmony_ci		return active_stack->sp_ops->plock(conn, ino, file, cmd, fl);
29762306a36Sopenharmony_ci	return -EOPNOTSUPP;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_plock);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciint ocfs2_cluster_connect(const char *stack_name,
30262306a36Sopenharmony_ci			  const char *cluster_name,
30362306a36Sopenharmony_ci			  int cluster_name_len,
30462306a36Sopenharmony_ci			  const char *group,
30562306a36Sopenharmony_ci			  int grouplen,
30662306a36Sopenharmony_ci			  struct ocfs2_locking_protocol *lproto,
30762306a36Sopenharmony_ci			  void (*recovery_handler)(int node_num,
30862306a36Sopenharmony_ci						   void *recovery_data),
30962306a36Sopenharmony_ci			  void *recovery_data,
31062306a36Sopenharmony_ci			  struct ocfs2_cluster_connection **conn)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int rc = 0;
31362306a36Sopenharmony_ci	struct ocfs2_cluster_connection *new_conn;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	BUG_ON(group == NULL);
31662306a36Sopenharmony_ci	BUG_ON(conn == NULL);
31762306a36Sopenharmony_ci	BUG_ON(recovery_handler == NULL);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (grouplen > GROUP_NAME_MAX) {
32062306a36Sopenharmony_ci		rc = -EINVAL;
32162306a36Sopenharmony_ci		goto out;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (memcmp(&lproto->lp_max_version, &locking_max_version,
32562306a36Sopenharmony_ci		   sizeof(struct ocfs2_protocol_version))) {
32662306a36Sopenharmony_ci		rc = -EINVAL;
32762306a36Sopenharmony_ci		goto out;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	new_conn = kzalloc(sizeof(struct ocfs2_cluster_connection),
33162306a36Sopenharmony_ci			   GFP_KERNEL);
33262306a36Sopenharmony_ci	if (!new_conn) {
33362306a36Sopenharmony_ci		rc = -ENOMEM;
33462306a36Sopenharmony_ci		goto out;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	strscpy(new_conn->cc_name, group, GROUP_NAME_MAX + 1);
33862306a36Sopenharmony_ci	new_conn->cc_namelen = grouplen;
33962306a36Sopenharmony_ci	if (cluster_name_len)
34062306a36Sopenharmony_ci		strscpy(new_conn->cc_cluster_name, cluster_name,
34162306a36Sopenharmony_ci			CLUSTER_NAME_MAX + 1);
34262306a36Sopenharmony_ci	new_conn->cc_cluster_name_len = cluster_name_len;
34362306a36Sopenharmony_ci	new_conn->cc_recovery_handler = recovery_handler;
34462306a36Sopenharmony_ci	new_conn->cc_recovery_data = recovery_data;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	new_conn->cc_proto = lproto;
34762306a36Sopenharmony_ci	/* Start the new connection at our maximum compatibility level */
34862306a36Sopenharmony_ci	new_conn->cc_version = lproto->lp_max_version;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* This will pin the stack driver if successful */
35162306a36Sopenharmony_ci	rc = ocfs2_stack_driver_get(stack_name);
35262306a36Sopenharmony_ci	if (rc)
35362306a36Sopenharmony_ci		goto out_free;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	rc = active_stack->sp_ops->connect(new_conn);
35662306a36Sopenharmony_ci	if (rc) {
35762306a36Sopenharmony_ci		ocfs2_stack_driver_put();
35862306a36Sopenharmony_ci		goto out_free;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	*conn = new_conn;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ciout_free:
36462306a36Sopenharmony_ci	if (rc)
36562306a36Sopenharmony_ci		kfree(new_conn);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ciout:
36862306a36Sopenharmony_ci	return rc;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_cluster_connect);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/* The caller will ensure all nodes have the same cluster stack */
37362306a36Sopenharmony_ciint ocfs2_cluster_connect_agnostic(const char *group,
37462306a36Sopenharmony_ci				   int grouplen,
37562306a36Sopenharmony_ci				   struct ocfs2_locking_protocol *lproto,
37662306a36Sopenharmony_ci				   void (*recovery_handler)(int node_num,
37762306a36Sopenharmony_ci							    void *recovery_data),
37862306a36Sopenharmony_ci				   void *recovery_data,
37962306a36Sopenharmony_ci				   struct ocfs2_cluster_connection **conn)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	char *stack_name = NULL;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (cluster_stack_name[0])
38462306a36Sopenharmony_ci		stack_name = cluster_stack_name;
38562306a36Sopenharmony_ci	return ocfs2_cluster_connect(stack_name, NULL, 0, group, grouplen,
38662306a36Sopenharmony_ci				     lproto, recovery_handler, recovery_data,
38762306a36Sopenharmony_ci				     conn);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_cluster_connect_agnostic);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/* If hangup_pending is 0, the stack driver will be dropped */
39262306a36Sopenharmony_ciint ocfs2_cluster_disconnect(struct ocfs2_cluster_connection *conn,
39362306a36Sopenharmony_ci			     int hangup_pending)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	int ret;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	BUG_ON(conn == NULL);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	ret = active_stack->sp_ops->disconnect(conn);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* XXX Should we free it anyway? */
40262306a36Sopenharmony_ci	if (!ret) {
40362306a36Sopenharmony_ci		kfree(conn);
40462306a36Sopenharmony_ci		if (!hangup_pending)
40562306a36Sopenharmony_ci			ocfs2_stack_driver_put();
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return ret;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_cluster_disconnect);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/*
41362306a36Sopenharmony_ci * Leave the group for this filesystem.  This is executed by a userspace
41462306a36Sopenharmony_ci * program (stored in ocfs2_hb_ctl_path).
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic void ocfs2_leave_group(const char *group)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	int ret;
41962306a36Sopenharmony_ci	char *argv[5], *envp[3];
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	argv[0] = ocfs2_hb_ctl_path;
42262306a36Sopenharmony_ci	argv[1] = "-K";
42362306a36Sopenharmony_ci	argv[2] = "-u";
42462306a36Sopenharmony_ci	argv[3] = (char *)group;
42562306a36Sopenharmony_ci	argv[4] = NULL;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* minimal command environment taken from cpu_run_sbin_hotplug */
42862306a36Sopenharmony_ci	envp[0] = "HOME=/";
42962306a36Sopenharmony_ci	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
43062306a36Sopenharmony_ci	envp[2] = NULL;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
43362306a36Sopenharmony_ci	if (ret < 0) {
43462306a36Sopenharmony_ci		printk(KERN_ERR
43562306a36Sopenharmony_ci		       "ocfs2: Error %d running user helper "
43662306a36Sopenharmony_ci		       "\"%s %s %s %s\"\n",
43762306a36Sopenharmony_ci		       ret, argv[0], argv[1], argv[2], argv[3]);
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/*
44262306a36Sopenharmony_ci * Hangup is a required post-umount.  ocfs2-tools software expects the
44362306a36Sopenharmony_ci * filesystem to call "ocfs2_hb_ctl" during unmount.  This happens
44462306a36Sopenharmony_ci * regardless of whether the DLM got started, so we can't do it
44562306a36Sopenharmony_ci * in ocfs2_cluster_disconnect().  The ocfs2_leave_group() function does
44662306a36Sopenharmony_ci * the actual work.
44762306a36Sopenharmony_ci */
44862306a36Sopenharmony_civoid ocfs2_cluster_hangup(const char *group, int grouplen)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	BUG_ON(group == NULL);
45162306a36Sopenharmony_ci	BUG_ON(group[grouplen] != '\0');
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	ocfs2_leave_group(group);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* cluster_disconnect() was called with hangup_pending==1 */
45662306a36Sopenharmony_ci	ocfs2_stack_driver_put();
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_cluster_hangup);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ciint ocfs2_cluster_this_node(struct ocfs2_cluster_connection *conn,
46162306a36Sopenharmony_ci			    unsigned int *node)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	return active_stack->sp_ops->this_node(conn, node);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_cluster_this_node);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci/*
46962306a36Sopenharmony_ci * Sysfs bits
47062306a36Sopenharmony_ci */
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic ssize_t ocfs2_max_locking_protocol_show(struct kobject *kobj,
47362306a36Sopenharmony_ci					       struct kobj_attribute *attr,
47462306a36Sopenharmony_ci					       char *buf)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	ssize_t ret = 0;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
47962306a36Sopenharmony_ci	if (locking_max_version.pv_major)
48062306a36Sopenharmony_ci		ret = snprintf(buf, PAGE_SIZE, "%u.%u\n",
48162306a36Sopenharmony_ci			       locking_max_version.pv_major,
48262306a36Sopenharmony_ci			       locking_max_version.pv_minor);
48362306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	return ret;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic struct kobj_attribute ocfs2_attr_max_locking_protocol =
48962306a36Sopenharmony_ci	__ATTR(max_locking_protocol, S_IRUGO,
49062306a36Sopenharmony_ci	       ocfs2_max_locking_protocol_show, NULL);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic ssize_t ocfs2_loaded_cluster_plugins_show(struct kobject *kobj,
49362306a36Sopenharmony_ci						 struct kobj_attribute *attr,
49462306a36Sopenharmony_ci						 char *buf)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
49762306a36Sopenharmony_ci	struct ocfs2_stack_plugin *p;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
50062306a36Sopenharmony_ci	list_for_each_entry(p, &ocfs2_stack_list, sp_list) {
50162306a36Sopenharmony_ci		ret = snprintf(buf, remain, "%s\n",
50262306a36Sopenharmony_ci			       p->sp_name);
50362306a36Sopenharmony_ci		if (ret >= remain) {
50462306a36Sopenharmony_ci			/* snprintf() didn't fit */
50562306a36Sopenharmony_ci			total = -E2BIG;
50662306a36Sopenharmony_ci			break;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci		total += ret;
50962306a36Sopenharmony_ci		remain -= ret;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return total;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic struct kobj_attribute ocfs2_attr_loaded_cluster_plugins =
51762306a36Sopenharmony_ci	__ATTR(loaded_cluster_plugins, S_IRUGO,
51862306a36Sopenharmony_ci	       ocfs2_loaded_cluster_plugins_show, NULL);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic ssize_t ocfs2_active_cluster_plugin_show(struct kobject *kobj,
52162306a36Sopenharmony_ci						struct kobj_attribute *attr,
52262306a36Sopenharmony_ci						char *buf)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	ssize_t ret = 0;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
52762306a36Sopenharmony_ci	if (active_stack) {
52862306a36Sopenharmony_ci		ret = snprintf(buf, PAGE_SIZE, "%s\n",
52962306a36Sopenharmony_ci			       active_stack->sp_name);
53062306a36Sopenharmony_ci		if (ret >= PAGE_SIZE)
53162306a36Sopenharmony_ci			ret = -E2BIG;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return ret;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic struct kobj_attribute ocfs2_attr_active_cluster_plugin =
53962306a36Sopenharmony_ci	__ATTR(active_cluster_plugin, S_IRUGO,
54062306a36Sopenharmony_ci	       ocfs2_active_cluster_plugin_show, NULL);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic ssize_t ocfs2_cluster_stack_show(struct kobject *kobj,
54362306a36Sopenharmony_ci					struct kobj_attribute *attr,
54462306a36Sopenharmony_ci					char *buf)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	ssize_t ret;
54762306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
54862306a36Sopenharmony_ci	ret = snprintf(buf, PAGE_SIZE, "%s\n", cluster_stack_name);
54962306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return ret;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic ssize_t ocfs2_cluster_stack_store(struct kobject *kobj,
55562306a36Sopenharmony_ci					 struct kobj_attribute *attr,
55662306a36Sopenharmony_ci					 const char *buf, size_t count)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	size_t len = count;
55962306a36Sopenharmony_ci	ssize_t ret;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (len == 0)
56262306a36Sopenharmony_ci		return len;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (buf[len - 1] == '\n')
56562306a36Sopenharmony_ci		len--;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if ((len != OCFS2_STACK_LABEL_LEN) ||
56862306a36Sopenharmony_ci	    (strnlen(buf, len) != len))
56962306a36Sopenharmony_ci		return -EINVAL;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	spin_lock(&ocfs2_stack_lock);
57262306a36Sopenharmony_ci	if (active_stack) {
57362306a36Sopenharmony_ci		if (!strncmp(buf, cluster_stack_name, len))
57462306a36Sopenharmony_ci			ret = count;
57562306a36Sopenharmony_ci		else
57662306a36Sopenharmony_ci			ret = -EBUSY;
57762306a36Sopenharmony_ci	} else {
57862306a36Sopenharmony_ci		memcpy(cluster_stack_name, buf, len);
57962306a36Sopenharmony_ci		ret = count;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci	spin_unlock(&ocfs2_stack_lock);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return ret;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic struct kobj_attribute ocfs2_attr_cluster_stack =
58862306a36Sopenharmony_ci	__ATTR(cluster_stack, S_IRUGO | S_IWUSR,
58962306a36Sopenharmony_ci	       ocfs2_cluster_stack_show,
59062306a36Sopenharmony_ci	       ocfs2_cluster_stack_store);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic ssize_t ocfs2_dlm_recover_show(struct kobject *kobj,
59562306a36Sopenharmony_ci					struct kobj_attribute *attr,
59662306a36Sopenharmony_ci					char *buf)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "1\n");
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic struct kobj_attribute ocfs2_attr_dlm_recover_support =
60262306a36Sopenharmony_ci	__ATTR(dlm_recover_callback_support, S_IRUGO,
60362306a36Sopenharmony_ci	       ocfs2_dlm_recover_show, NULL);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic struct attribute *ocfs2_attrs[] = {
60662306a36Sopenharmony_ci	&ocfs2_attr_max_locking_protocol.attr,
60762306a36Sopenharmony_ci	&ocfs2_attr_loaded_cluster_plugins.attr,
60862306a36Sopenharmony_ci	&ocfs2_attr_active_cluster_plugin.attr,
60962306a36Sopenharmony_ci	&ocfs2_attr_cluster_stack.attr,
61062306a36Sopenharmony_ci	&ocfs2_attr_dlm_recover_support.attr,
61162306a36Sopenharmony_ci	NULL,
61262306a36Sopenharmony_ci};
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic const struct attribute_group ocfs2_attr_group = {
61562306a36Sopenharmony_ci	.attrs = ocfs2_attrs,
61662306a36Sopenharmony_ci};
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistruct kset *ocfs2_kset;
61962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocfs2_kset);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void ocfs2_sysfs_exit(void)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	kset_unregister(ocfs2_kset);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int ocfs2_sysfs_init(void)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	int ret;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	ocfs2_kset = kset_create_and_add("ocfs2", NULL, fs_kobj);
63162306a36Sopenharmony_ci	if (!ocfs2_kset)
63262306a36Sopenharmony_ci		return -ENOMEM;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	ret = sysfs_create_group(&ocfs2_kset->kobj, &ocfs2_attr_group);
63562306a36Sopenharmony_ci	if (ret)
63662306a36Sopenharmony_ci		goto error;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	return 0;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cierror:
64162306a36Sopenharmony_ci	kset_unregister(ocfs2_kset);
64262306a36Sopenharmony_ci	return ret;
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci/*
64662306a36Sopenharmony_ci * Sysctl bits
64762306a36Sopenharmony_ci *
64862306a36Sopenharmony_ci * The sysctl lives at /proc/sys/fs/ocfs2/nm/hb_ctl_path.  The 'nm' doesn't
64962306a36Sopenharmony_ci * make as much sense in a multiple cluster stack world, but it's safer
65062306a36Sopenharmony_ci * and easier to preserve the name.
65162306a36Sopenharmony_ci */
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic struct ctl_table ocfs2_nm_table[] = {
65462306a36Sopenharmony_ci	{
65562306a36Sopenharmony_ci		.procname	= "hb_ctl_path",
65662306a36Sopenharmony_ci		.data		= ocfs2_hb_ctl_path,
65762306a36Sopenharmony_ci		.maxlen		= OCFS2_MAX_HB_CTL_PATH,
65862306a36Sopenharmony_ci		.mode		= 0644,
65962306a36Sopenharmony_ci		.proc_handler	= proc_dostring,
66062306a36Sopenharmony_ci	},
66162306a36Sopenharmony_ci	{ }
66262306a36Sopenharmony_ci};
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic struct ctl_table_header *ocfs2_table_header;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci/*
66762306a36Sopenharmony_ci * Initialization
66862306a36Sopenharmony_ci */
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int __init ocfs2_stack_glue_init(void)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	int ret;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	ocfs2_table_header = register_sysctl("fs/ocfs2/nm", ocfs2_nm_table);
67762306a36Sopenharmony_ci	if (!ocfs2_table_header) {
67862306a36Sopenharmony_ci		printk(KERN_ERR
67962306a36Sopenharmony_ci		       "ocfs2 stack glue: unable to register sysctl\n");
68062306a36Sopenharmony_ci		return -ENOMEM; /* or something. */
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	ret = ocfs2_sysfs_init();
68462306a36Sopenharmony_ci	if (ret)
68562306a36Sopenharmony_ci		unregister_sysctl_table(ocfs2_table_header);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	return ret;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic void __exit ocfs2_stack_glue_exit(void)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	memset(&locking_max_version, 0,
69362306a36Sopenharmony_ci	       sizeof(struct ocfs2_protocol_version));
69462306a36Sopenharmony_ci	ocfs2_sysfs_exit();
69562306a36Sopenharmony_ci	if (ocfs2_table_header)
69662306a36Sopenharmony_ci		unregister_sysctl_table(ocfs2_table_header);
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ciMODULE_AUTHOR("Oracle");
70062306a36Sopenharmony_ciMODULE_DESCRIPTION("ocfs2 cluster stack glue layer");
70162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
70262306a36Sopenharmony_cimodule_init(ocfs2_stack_glue_init);
70362306a36Sopenharmony_cimodule_exit(ocfs2_stack_glue_exit);
704