162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * stack_o2cb.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Code which interfaces ocfs2 with the o2cb stack.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2007 Oracle.  All rights reserved.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/crc32.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Needed for AOP_TRUNCATED_PAGE in mlog_errno() */
1662306a36Sopenharmony_ci#include <linux/fs.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "cluster/masklog.h"
1962306a36Sopenharmony_ci#include "cluster/nodemanager.h"
2062306a36Sopenharmony_ci#include "cluster/heartbeat.h"
2162306a36Sopenharmony_ci#include "cluster/tcp.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "stackglue.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct o2dlm_private {
2662306a36Sopenharmony_ci	struct dlm_eviction_cb op_eviction_cb;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic struct ocfs2_stack_plugin o2cb_stack;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* These should be identical */
3262306a36Sopenharmony_ci#if (DLM_LOCK_IV != LKM_IVMODE)
3362306a36Sopenharmony_ci# error Lock modes do not match
3462306a36Sopenharmony_ci#endif
3562306a36Sopenharmony_ci#if (DLM_LOCK_NL != LKM_NLMODE)
3662306a36Sopenharmony_ci# error Lock modes do not match
3762306a36Sopenharmony_ci#endif
3862306a36Sopenharmony_ci#if (DLM_LOCK_CR != LKM_CRMODE)
3962306a36Sopenharmony_ci# error Lock modes do not match
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci#if (DLM_LOCK_CW != LKM_CWMODE)
4262306a36Sopenharmony_ci# error Lock modes do not match
4362306a36Sopenharmony_ci#endif
4462306a36Sopenharmony_ci#if (DLM_LOCK_PR != LKM_PRMODE)
4562306a36Sopenharmony_ci# error Lock modes do not match
4662306a36Sopenharmony_ci#endif
4762306a36Sopenharmony_ci#if (DLM_LOCK_PW != LKM_PWMODE)
4862306a36Sopenharmony_ci# error Lock modes do not match
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci#if (DLM_LOCK_EX != LKM_EXMODE)
5162306a36Sopenharmony_ci# error Lock modes do not match
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_cistatic inline int mode_to_o2dlm(int mode)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	BUG_ON(mode > LKM_MAXMODE);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return mode;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int flags_to_o2dlm(u32 flags)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	int o2dlm_flags = 0;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (flags & DLM_LKF_NOQUEUE)
6562306a36Sopenharmony_ci		o2dlm_flags |= LKM_NOQUEUE;
6662306a36Sopenharmony_ci	if (flags & DLM_LKF_CANCEL)
6762306a36Sopenharmony_ci		o2dlm_flags |= LKM_CANCEL;
6862306a36Sopenharmony_ci	if (flags & DLM_LKF_CONVERT)
6962306a36Sopenharmony_ci		o2dlm_flags |= LKM_CONVERT;
7062306a36Sopenharmony_ci	if (flags & DLM_LKF_VALBLK)
7162306a36Sopenharmony_ci		o2dlm_flags |= LKM_VALBLK;
7262306a36Sopenharmony_ci	if (flags & DLM_LKF_IVVALBLK)
7362306a36Sopenharmony_ci		o2dlm_flags |= LKM_INVVALBLK;
7462306a36Sopenharmony_ci	if (flags & DLM_LKF_ORPHAN)
7562306a36Sopenharmony_ci		o2dlm_flags |= LKM_ORPHAN;
7662306a36Sopenharmony_ci	if (flags & DLM_LKF_FORCEUNLOCK)
7762306a36Sopenharmony_ci		o2dlm_flags |= LKM_FORCE;
7862306a36Sopenharmony_ci	if (flags & DLM_LKF_TIMEOUT)
7962306a36Sopenharmony_ci		o2dlm_flags |= LKM_TIMEOUT;
8062306a36Sopenharmony_ci	if (flags & DLM_LKF_LOCAL)
8162306a36Sopenharmony_ci		o2dlm_flags |= LKM_LOCAL;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return o2dlm_flags;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/*
8762306a36Sopenharmony_ci * Map an o2dlm status to standard errno values.
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * o2dlm only uses a handful of these, and returns even fewer to the
9062306a36Sopenharmony_ci * caller. Still, we try to assign sane values to each error.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * The following value pairs have special meanings to dlmglue, thus
9362306a36Sopenharmony_ci * the right hand side needs to stay unique - never duplicate the
9462306a36Sopenharmony_ci * mapping elsewhere in the table!
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * DLM_NORMAL:		0
9762306a36Sopenharmony_ci * DLM_NOTQUEUED:	-EAGAIN
9862306a36Sopenharmony_ci * DLM_CANCELGRANT:	-EBUSY
9962306a36Sopenharmony_ci * DLM_CANCEL:		-DLM_ECANCEL
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_ci/* Keep in sync with dlmapi.h */
10262306a36Sopenharmony_cistatic int status_map[] = {
10362306a36Sopenharmony_ci	[DLM_NORMAL]			= 0,		/* Success */
10462306a36Sopenharmony_ci	[DLM_GRANTED]			= -EINVAL,
10562306a36Sopenharmony_ci	[DLM_DENIED]			= -EACCES,
10662306a36Sopenharmony_ci	[DLM_DENIED_NOLOCKS]		= -EACCES,
10762306a36Sopenharmony_ci	[DLM_WORKING]			= -EACCES,
10862306a36Sopenharmony_ci	[DLM_BLOCKED]			= -EINVAL,
10962306a36Sopenharmony_ci	[DLM_BLOCKED_ORPHAN]		= -EINVAL,
11062306a36Sopenharmony_ci	[DLM_DENIED_GRACE_PERIOD]	= -EACCES,
11162306a36Sopenharmony_ci	[DLM_SYSERR]			= -ENOMEM,	/* It is what it is */
11262306a36Sopenharmony_ci	[DLM_NOSUPPORT]			= -EPROTO,
11362306a36Sopenharmony_ci	[DLM_CANCELGRANT]		= -EBUSY,	/* Cancel after grant */
11462306a36Sopenharmony_ci	[DLM_IVLOCKID]			= -EINVAL,
11562306a36Sopenharmony_ci	[DLM_SYNC]			= -EINVAL,
11662306a36Sopenharmony_ci	[DLM_BADTYPE]			= -EINVAL,
11762306a36Sopenharmony_ci	[DLM_BADRESOURCE]		= -EINVAL,
11862306a36Sopenharmony_ci	[DLM_MAXHANDLES]		= -ENOMEM,
11962306a36Sopenharmony_ci	[DLM_NOCLINFO]			= -EINVAL,
12062306a36Sopenharmony_ci	[DLM_NOLOCKMGR]			= -EINVAL,
12162306a36Sopenharmony_ci	[DLM_NOPURGED]			= -EINVAL,
12262306a36Sopenharmony_ci	[DLM_BADARGS]			= -EINVAL,
12362306a36Sopenharmony_ci	[DLM_VOID]			= -EINVAL,
12462306a36Sopenharmony_ci	[DLM_NOTQUEUED]			= -EAGAIN,	/* Trylock failed */
12562306a36Sopenharmony_ci	[DLM_IVBUFLEN]			= -EINVAL,
12662306a36Sopenharmony_ci	[DLM_CVTUNGRANT]		= -EPERM,
12762306a36Sopenharmony_ci	[DLM_BADPARAM]			= -EINVAL,
12862306a36Sopenharmony_ci	[DLM_VALNOTVALID]		= -EINVAL,
12962306a36Sopenharmony_ci	[DLM_REJECTED]			= -EPERM,
13062306a36Sopenharmony_ci	[DLM_ABORT]			= -EINVAL,
13162306a36Sopenharmony_ci	[DLM_CANCEL]			= -DLM_ECANCEL,	/* Successful cancel */
13262306a36Sopenharmony_ci	[DLM_IVRESHANDLE]		= -EINVAL,
13362306a36Sopenharmony_ci	[DLM_DEADLOCK]			= -EDEADLK,
13462306a36Sopenharmony_ci	[DLM_DENIED_NOASTS]		= -EINVAL,
13562306a36Sopenharmony_ci	[DLM_FORWARD]			= -EINVAL,
13662306a36Sopenharmony_ci	[DLM_TIMEOUT]			= -ETIMEDOUT,
13762306a36Sopenharmony_ci	[DLM_IVGROUPID]			= -EINVAL,
13862306a36Sopenharmony_ci	[DLM_VERS_CONFLICT]		= -EOPNOTSUPP,
13962306a36Sopenharmony_ci	[DLM_BAD_DEVICE_PATH]		= -ENOENT,
14062306a36Sopenharmony_ci	[DLM_NO_DEVICE_PERMISSION]	= -EPERM,
14162306a36Sopenharmony_ci	[DLM_NO_CONTROL_DEVICE]		= -ENOENT,
14262306a36Sopenharmony_ci	[DLM_RECOVERING]		= -ENOTCONN,
14362306a36Sopenharmony_ci	[DLM_MIGRATING]			= -ERESTART,
14462306a36Sopenharmony_ci	[DLM_MAXSTATS]			= -EINVAL,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int dlm_status_to_errno(enum dlm_status status)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	BUG_ON(status < 0 || status >= ARRAY_SIZE(status_map));
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return status_map[status];
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void o2dlm_lock_ast_wrapper(void *astarg)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct ocfs2_dlm_lksb *lksb = astarg;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	lksb->lksb_conn->cc_proto->lp_lock_ast(lksb);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void o2dlm_blocking_ast_wrapper(void *astarg, int level)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct ocfs2_dlm_lksb *lksb = astarg;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	lksb->lksb_conn->cc_proto->lp_blocking_ast(lksb, level);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic void o2dlm_unlock_ast_wrapper(void *astarg, enum dlm_status status)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct ocfs2_dlm_lksb *lksb = astarg;
17162306a36Sopenharmony_ci	int error = dlm_status_to_errno(status);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/*
17462306a36Sopenharmony_ci	 * In o2dlm, you can get both the lock_ast() for the lock being
17562306a36Sopenharmony_ci	 * granted and the unlock_ast() for the CANCEL failing.  A
17662306a36Sopenharmony_ci	 * successful cancel sends DLM_NORMAL here.  If the
17762306a36Sopenharmony_ci	 * lock grant happened before the cancel arrived, you get
17862306a36Sopenharmony_ci	 * DLM_CANCELGRANT.
17962306a36Sopenharmony_ci	 *
18062306a36Sopenharmony_ci	 * There's no need for the double-ast.  If we see DLM_CANCELGRANT,
18162306a36Sopenharmony_ci	 * we just ignore it.  We expect the lock_ast() to handle the
18262306a36Sopenharmony_ci	 * granted lock.
18362306a36Sopenharmony_ci	 */
18462306a36Sopenharmony_ci	if (status == DLM_CANCELGRANT)
18562306a36Sopenharmony_ci		return;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	lksb->lksb_conn->cc_proto->lp_unlock_ast(lksb, error);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int o2cb_dlm_lock(struct ocfs2_cluster_connection *conn,
19162306a36Sopenharmony_ci			 int mode,
19262306a36Sopenharmony_ci			 struct ocfs2_dlm_lksb *lksb,
19362306a36Sopenharmony_ci			 u32 flags,
19462306a36Sopenharmony_ci			 void *name,
19562306a36Sopenharmony_ci			 unsigned int namelen)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	enum dlm_status status;
19862306a36Sopenharmony_ci	int o2dlm_mode = mode_to_o2dlm(mode);
19962306a36Sopenharmony_ci	int o2dlm_flags = flags_to_o2dlm(flags);
20062306a36Sopenharmony_ci	int ret;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	status = dlmlock(conn->cc_lockspace, o2dlm_mode, &lksb->lksb_o2dlm,
20362306a36Sopenharmony_ci			 o2dlm_flags, name, namelen,
20462306a36Sopenharmony_ci			 o2dlm_lock_ast_wrapper, lksb,
20562306a36Sopenharmony_ci			 o2dlm_blocking_ast_wrapper);
20662306a36Sopenharmony_ci	ret = dlm_status_to_errno(status);
20762306a36Sopenharmony_ci	return ret;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int o2cb_dlm_unlock(struct ocfs2_cluster_connection *conn,
21162306a36Sopenharmony_ci			   struct ocfs2_dlm_lksb *lksb,
21262306a36Sopenharmony_ci			   u32 flags)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	enum dlm_status status;
21562306a36Sopenharmony_ci	int o2dlm_flags = flags_to_o2dlm(flags);
21662306a36Sopenharmony_ci	int ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	status = dlmunlock(conn->cc_lockspace, &lksb->lksb_o2dlm,
21962306a36Sopenharmony_ci			   o2dlm_flags, o2dlm_unlock_ast_wrapper, lksb);
22062306a36Sopenharmony_ci	ret = dlm_status_to_errno(status);
22162306a36Sopenharmony_ci	return ret;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int o2cb_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return dlm_status_to_errno(lksb->lksb_o2dlm.status);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/*
23062306a36Sopenharmony_ci * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB
23162306a36Sopenharmony_ci * contents, it will zero out the LVB.  Thus the caller can always trust
23262306a36Sopenharmony_ci * the contents.
23362306a36Sopenharmony_ci */
23462306a36Sopenharmony_cistatic int o2cb_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	return 1;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void *o2cb_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	return (void *)(lksb->lksb_o2dlm.lvb);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic void o2cb_dump_lksb(struct ocfs2_dlm_lksb *lksb)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	dlm_print_one_lock(lksb->lksb_o2dlm.lockid);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*
25062306a36Sopenharmony_ci * Check if this node is heartbeating and is connected to all other
25162306a36Sopenharmony_ci * heartbeating nodes.
25262306a36Sopenharmony_ci */
25362306a36Sopenharmony_cistatic int o2cb_cluster_check(void)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	u8 node_num;
25662306a36Sopenharmony_ci	int i;
25762306a36Sopenharmony_ci	unsigned long hbmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
25862306a36Sopenharmony_ci	unsigned long netmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	node_num = o2nm_this_node();
26162306a36Sopenharmony_ci	if (node_num == O2NM_MAX_NODES) {
26262306a36Sopenharmony_ci		printk(KERN_ERR "o2cb: This node has not been configured.\n");
26362306a36Sopenharmony_ci		return -EINVAL;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/*
26762306a36Sopenharmony_ci	 * o2dlm expects o2net sockets to be created. If not, then
26862306a36Sopenharmony_ci	 * dlm_join_domain() fails with a stack of errors which are both cryptic
26962306a36Sopenharmony_ci	 * and incomplete. The idea here is to detect upfront whether we have
27062306a36Sopenharmony_ci	 * managed to connect to all nodes or not. If not, then list the nodes
27162306a36Sopenharmony_ci	 * to allow the user to check the configuration (incorrect IP, firewall,
27262306a36Sopenharmony_ci	 * etc.) Yes, this is racy. But its not the end of the world.
27362306a36Sopenharmony_ci	 */
27462306a36Sopenharmony_ci#define	O2CB_MAP_STABILIZE_COUNT	60
27562306a36Sopenharmony_ci	for (i = 0; i < O2CB_MAP_STABILIZE_COUNT; ++i) {
27662306a36Sopenharmony_ci		o2hb_fill_node_map(hbmap, O2NM_MAX_NODES);
27762306a36Sopenharmony_ci		if (!test_bit(node_num, hbmap)) {
27862306a36Sopenharmony_ci			printk(KERN_ERR "o2cb: %s heartbeat has not been "
27962306a36Sopenharmony_ci			       "started.\n", (o2hb_global_heartbeat_active() ?
28062306a36Sopenharmony_ci					      "Global" : "Local"));
28162306a36Sopenharmony_ci			return -EINVAL;
28262306a36Sopenharmony_ci		}
28362306a36Sopenharmony_ci		o2net_fill_node_map(netmap, O2NM_MAX_NODES);
28462306a36Sopenharmony_ci		/* Force set the current node to allow easy compare */
28562306a36Sopenharmony_ci		set_bit(node_num, netmap);
28662306a36Sopenharmony_ci		if (bitmap_equal(hbmap, netmap, O2NM_MAX_NODES))
28762306a36Sopenharmony_ci			return 0;
28862306a36Sopenharmony_ci		if (i < O2CB_MAP_STABILIZE_COUNT - 1)
28962306a36Sopenharmony_ci			msleep(1000);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	printk(KERN_ERR "o2cb: This node could not connect to nodes:");
29362306a36Sopenharmony_ci	i = -1;
29462306a36Sopenharmony_ci	while ((i = find_next_bit(hbmap, O2NM_MAX_NODES,
29562306a36Sopenharmony_ci				  i + 1)) < O2NM_MAX_NODES) {
29662306a36Sopenharmony_ci		if (!test_bit(i, netmap))
29762306a36Sopenharmony_ci			printk(" %u", i);
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci	printk(".\n");
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return -ENOTCONN;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/*
30562306a36Sopenharmony_ci * Called from the dlm when it's about to evict a node. This is how the
30662306a36Sopenharmony_ci * classic stack signals node death.
30762306a36Sopenharmony_ci */
30862306a36Sopenharmony_cistatic void o2dlm_eviction_cb(int node_num, void *data)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct ocfs2_cluster_connection *conn = data;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	printk(KERN_NOTICE "o2cb: o2dlm has evicted node %d from domain %.*s\n",
31362306a36Sopenharmony_ci	       node_num, conn->cc_namelen, conn->cc_name);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	conn->cc_recovery_handler(node_num, conn->cc_recovery_data);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	int rc = 0;
32162306a36Sopenharmony_ci	u32 dlm_key;
32262306a36Sopenharmony_ci	struct dlm_ctxt *dlm;
32362306a36Sopenharmony_ci	struct o2dlm_private *priv;
32462306a36Sopenharmony_ci	struct dlm_protocol_version fs_version;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	BUG_ON(conn == NULL);
32762306a36Sopenharmony_ci	BUG_ON(conn->cc_proto == NULL);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* Ensure cluster stack is up and all nodes are connected */
33062306a36Sopenharmony_ci	rc = o2cb_cluster_check();
33162306a36Sopenharmony_ci	if (rc) {
33262306a36Sopenharmony_ci		printk(KERN_ERR "o2cb: Cluster check failed. Fix errors "
33362306a36Sopenharmony_ci		       "before retrying.\n");
33462306a36Sopenharmony_ci		goto out;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	priv = kzalloc(sizeof(struct o2dlm_private), GFP_KERNEL);
33862306a36Sopenharmony_ci	if (!priv) {
33962306a36Sopenharmony_ci		rc = -ENOMEM;
34062306a36Sopenharmony_ci		goto out_free;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* This just fills the structure in.  It is safe to pass conn. */
34462306a36Sopenharmony_ci	dlm_setup_eviction_cb(&priv->op_eviction_cb, o2dlm_eviction_cb,
34562306a36Sopenharmony_ci			      conn);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	conn->cc_private = priv;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* used by the dlm code to make message headers unique, each
35062306a36Sopenharmony_ci	 * node in this domain must agree on this. */
35162306a36Sopenharmony_ci	dlm_key = crc32_le(0, conn->cc_name, conn->cc_namelen);
35262306a36Sopenharmony_ci	fs_version.pv_major = conn->cc_version.pv_major;
35362306a36Sopenharmony_ci	fs_version.pv_minor = conn->cc_version.pv_minor;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	dlm = dlm_register_domain(conn->cc_name, dlm_key, &fs_version);
35662306a36Sopenharmony_ci	if (IS_ERR(dlm)) {
35762306a36Sopenharmony_ci		rc = PTR_ERR(dlm);
35862306a36Sopenharmony_ci		mlog_errno(rc);
35962306a36Sopenharmony_ci		goto out_free;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	conn->cc_version.pv_major = fs_version.pv_major;
36362306a36Sopenharmony_ci	conn->cc_version.pv_minor = fs_version.pv_minor;
36462306a36Sopenharmony_ci	conn->cc_lockspace = dlm;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	dlm_register_eviction_cb(dlm, &priv->op_eviction_cb);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ciout_free:
36962306a36Sopenharmony_ci	if (rc)
37062306a36Sopenharmony_ci		kfree(conn->cc_private);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ciout:
37362306a36Sopenharmony_ci	return rc;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int o2cb_cluster_disconnect(struct ocfs2_cluster_connection *conn)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct dlm_ctxt *dlm = conn->cc_lockspace;
37962306a36Sopenharmony_ci	struct o2dlm_private *priv = conn->cc_private;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	dlm_unregister_eviction_cb(&priv->op_eviction_cb);
38262306a36Sopenharmony_ci	conn->cc_private = NULL;
38362306a36Sopenharmony_ci	kfree(priv);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	dlm_unregister_domain(dlm);
38662306a36Sopenharmony_ci	conn->cc_lockspace = NULL;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return 0;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic int o2cb_cluster_this_node(struct ocfs2_cluster_connection *conn,
39262306a36Sopenharmony_ci				  unsigned int *node)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int node_num;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	node_num = o2nm_this_node();
39762306a36Sopenharmony_ci	if (node_num == O2NM_INVALID_NODE_NUM)
39862306a36Sopenharmony_ci		return -ENOENT;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (node_num >= O2NM_MAX_NODES)
40162306a36Sopenharmony_ci		return -EOVERFLOW;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	*node = node_num;
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic struct ocfs2_stack_operations o2cb_stack_ops = {
40862306a36Sopenharmony_ci	.connect	= o2cb_cluster_connect,
40962306a36Sopenharmony_ci	.disconnect	= o2cb_cluster_disconnect,
41062306a36Sopenharmony_ci	.this_node	= o2cb_cluster_this_node,
41162306a36Sopenharmony_ci	.dlm_lock	= o2cb_dlm_lock,
41262306a36Sopenharmony_ci	.dlm_unlock	= o2cb_dlm_unlock,
41362306a36Sopenharmony_ci	.lock_status	= o2cb_dlm_lock_status,
41462306a36Sopenharmony_ci	.lvb_valid	= o2cb_dlm_lvb_valid,
41562306a36Sopenharmony_ci	.lock_lvb	= o2cb_dlm_lvb,
41662306a36Sopenharmony_ci	.dump_lksb	= o2cb_dump_lksb,
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic struct ocfs2_stack_plugin o2cb_stack = {
42062306a36Sopenharmony_ci	.sp_name	= "o2cb",
42162306a36Sopenharmony_ci	.sp_ops		= &o2cb_stack_ops,
42262306a36Sopenharmony_ci	.sp_owner	= THIS_MODULE,
42362306a36Sopenharmony_ci};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic int __init o2cb_stack_init(void)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	return ocfs2_stack_glue_register(&o2cb_stack);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void __exit o2cb_stack_exit(void)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	ocfs2_stack_glue_unregister(&o2cb_stack);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ciMODULE_AUTHOR("Oracle");
43662306a36Sopenharmony_ciMODULE_DESCRIPTION("ocfs2 driver for the classic o2cb stack");
43762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
43862306a36Sopenharmony_cimodule_init(o2cb_stack_init);
43962306a36Sopenharmony_cimodule_exit(o2cb_stack_exit);
440