18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*-
38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0:
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * stack_o2cb.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Code which interfaces ocfs2 with the o2cb stack.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2007 Oracle.  All rights reserved.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/crc32.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Needed for AOP_TRUNCATED_PAGE in mlog_errno() */
188c2ecf20Sopenharmony_ci#include <linux/fs.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "cluster/masklog.h"
218c2ecf20Sopenharmony_ci#include "cluster/nodemanager.h"
228c2ecf20Sopenharmony_ci#include "cluster/heartbeat.h"
238c2ecf20Sopenharmony_ci#include "cluster/tcp.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "stackglue.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct o2dlm_private {
288c2ecf20Sopenharmony_ci	struct dlm_eviction_cb op_eviction_cb;
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic struct ocfs2_stack_plugin o2cb_stack;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* These should be identical */
348c2ecf20Sopenharmony_ci#if (DLM_LOCK_IV != LKM_IVMODE)
358c2ecf20Sopenharmony_ci# error Lock modes do not match
368c2ecf20Sopenharmony_ci#endif
378c2ecf20Sopenharmony_ci#if (DLM_LOCK_NL != LKM_NLMODE)
388c2ecf20Sopenharmony_ci# error Lock modes do not match
398c2ecf20Sopenharmony_ci#endif
408c2ecf20Sopenharmony_ci#if (DLM_LOCK_CR != LKM_CRMODE)
418c2ecf20Sopenharmony_ci# error Lock modes do not match
428c2ecf20Sopenharmony_ci#endif
438c2ecf20Sopenharmony_ci#if (DLM_LOCK_CW != LKM_CWMODE)
448c2ecf20Sopenharmony_ci# error Lock modes do not match
458c2ecf20Sopenharmony_ci#endif
468c2ecf20Sopenharmony_ci#if (DLM_LOCK_PR != LKM_PRMODE)
478c2ecf20Sopenharmony_ci# error Lock modes do not match
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci#if (DLM_LOCK_PW != LKM_PWMODE)
508c2ecf20Sopenharmony_ci# error Lock modes do not match
518c2ecf20Sopenharmony_ci#endif
528c2ecf20Sopenharmony_ci#if (DLM_LOCK_EX != LKM_EXMODE)
538c2ecf20Sopenharmony_ci# error Lock modes do not match
548c2ecf20Sopenharmony_ci#endif
558c2ecf20Sopenharmony_cistatic inline int mode_to_o2dlm(int mode)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	BUG_ON(mode > LKM_MAXMODE);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	return mode;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define map_flag(_generic, _o2dlm)		\
638c2ecf20Sopenharmony_ci	if (flags & (_generic)) {		\
648c2ecf20Sopenharmony_ci		flags &= ~(_generic);		\
658c2ecf20Sopenharmony_ci		o2dlm_flags |= (_o2dlm);	\
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_cistatic int flags_to_o2dlm(u32 flags)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	int o2dlm_flags = 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_NOQUEUE, LKM_NOQUEUE);
728c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_CANCEL, LKM_CANCEL);
738c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_CONVERT, LKM_CONVERT);
748c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_VALBLK, LKM_VALBLK);
758c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_IVVALBLK, LKM_INVVALBLK);
768c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_ORPHAN, LKM_ORPHAN);
778c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_FORCEUNLOCK, LKM_FORCE);
788c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_TIMEOUT, LKM_TIMEOUT);
798c2ecf20Sopenharmony_ci	map_flag(DLM_LKF_LOCAL, LKM_LOCAL);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* map_flag() should have cleared every flag passed in */
828c2ecf20Sopenharmony_ci	BUG_ON(flags != 0);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return o2dlm_flags;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci#undef map_flag
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * Map an o2dlm status to standard errno values.
908c2ecf20Sopenharmony_ci *
918c2ecf20Sopenharmony_ci * o2dlm only uses a handful of these, and returns even fewer to the
928c2ecf20Sopenharmony_ci * caller. Still, we try to assign sane values to each error.
938c2ecf20Sopenharmony_ci *
948c2ecf20Sopenharmony_ci * The following value pairs have special meanings to dlmglue, thus
958c2ecf20Sopenharmony_ci * the right hand side needs to stay unique - never duplicate the
968c2ecf20Sopenharmony_ci * mapping elsewhere in the table!
978c2ecf20Sopenharmony_ci *
988c2ecf20Sopenharmony_ci * DLM_NORMAL:		0
998c2ecf20Sopenharmony_ci * DLM_NOTQUEUED:	-EAGAIN
1008c2ecf20Sopenharmony_ci * DLM_CANCELGRANT:	-EBUSY
1018c2ecf20Sopenharmony_ci * DLM_CANCEL:		-DLM_ECANCEL
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_ci/* Keep in sync with dlmapi.h */
1048c2ecf20Sopenharmony_cistatic int status_map[] = {
1058c2ecf20Sopenharmony_ci	[DLM_NORMAL]			= 0,		/* Success */
1068c2ecf20Sopenharmony_ci	[DLM_GRANTED]			= -EINVAL,
1078c2ecf20Sopenharmony_ci	[DLM_DENIED]			= -EACCES,
1088c2ecf20Sopenharmony_ci	[DLM_DENIED_NOLOCKS]		= -EACCES,
1098c2ecf20Sopenharmony_ci	[DLM_WORKING]			= -EACCES,
1108c2ecf20Sopenharmony_ci	[DLM_BLOCKED]			= -EINVAL,
1118c2ecf20Sopenharmony_ci	[DLM_BLOCKED_ORPHAN]		= -EINVAL,
1128c2ecf20Sopenharmony_ci	[DLM_DENIED_GRACE_PERIOD]	= -EACCES,
1138c2ecf20Sopenharmony_ci	[DLM_SYSERR]			= -ENOMEM,	/* It is what it is */
1148c2ecf20Sopenharmony_ci	[DLM_NOSUPPORT]			= -EPROTO,
1158c2ecf20Sopenharmony_ci	[DLM_CANCELGRANT]		= -EBUSY,	/* Cancel after grant */
1168c2ecf20Sopenharmony_ci	[DLM_IVLOCKID]			= -EINVAL,
1178c2ecf20Sopenharmony_ci	[DLM_SYNC]			= -EINVAL,
1188c2ecf20Sopenharmony_ci	[DLM_BADTYPE]			= -EINVAL,
1198c2ecf20Sopenharmony_ci	[DLM_BADRESOURCE]		= -EINVAL,
1208c2ecf20Sopenharmony_ci	[DLM_MAXHANDLES]		= -ENOMEM,
1218c2ecf20Sopenharmony_ci	[DLM_NOCLINFO]			= -EINVAL,
1228c2ecf20Sopenharmony_ci	[DLM_NOLOCKMGR]			= -EINVAL,
1238c2ecf20Sopenharmony_ci	[DLM_NOPURGED]			= -EINVAL,
1248c2ecf20Sopenharmony_ci	[DLM_BADARGS]			= -EINVAL,
1258c2ecf20Sopenharmony_ci	[DLM_VOID]			= -EINVAL,
1268c2ecf20Sopenharmony_ci	[DLM_NOTQUEUED]			= -EAGAIN,	/* Trylock failed */
1278c2ecf20Sopenharmony_ci	[DLM_IVBUFLEN]			= -EINVAL,
1288c2ecf20Sopenharmony_ci	[DLM_CVTUNGRANT]		= -EPERM,
1298c2ecf20Sopenharmony_ci	[DLM_BADPARAM]			= -EINVAL,
1308c2ecf20Sopenharmony_ci	[DLM_VALNOTVALID]		= -EINVAL,
1318c2ecf20Sopenharmony_ci	[DLM_REJECTED]			= -EPERM,
1328c2ecf20Sopenharmony_ci	[DLM_ABORT]			= -EINVAL,
1338c2ecf20Sopenharmony_ci	[DLM_CANCEL]			= -DLM_ECANCEL,	/* Successful cancel */
1348c2ecf20Sopenharmony_ci	[DLM_IVRESHANDLE]		= -EINVAL,
1358c2ecf20Sopenharmony_ci	[DLM_DEADLOCK]			= -EDEADLK,
1368c2ecf20Sopenharmony_ci	[DLM_DENIED_NOASTS]		= -EINVAL,
1378c2ecf20Sopenharmony_ci	[DLM_FORWARD]			= -EINVAL,
1388c2ecf20Sopenharmony_ci	[DLM_TIMEOUT]			= -ETIMEDOUT,
1398c2ecf20Sopenharmony_ci	[DLM_IVGROUPID]			= -EINVAL,
1408c2ecf20Sopenharmony_ci	[DLM_VERS_CONFLICT]		= -EOPNOTSUPP,
1418c2ecf20Sopenharmony_ci	[DLM_BAD_DEVICE_PATH]		= -ENOENT,
1428c2ecf20Sopenharmony_ci	[DLM_NO_DEVICE_PERMISSION]	= -EPERM,
1438c2ecf20Sopenharmony_ci	[DLM_NO_CONTROL_DEVICE]		= -ENOENT,
1448c2ecf20Sopenharmony_ci	[DLM_RECOVERING]		= -ENOTCONN,
1458c2ecf20Sopenharmony_ci	[DLM_MIGRATING]			= -ERESTART,
1468c2ecf20Sopenharmony_ci	[DLM_MAXSTATS]			= -EINVAL,
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int dlm_status_to_errno(enum dlm_status status)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	BUG_ON(status < 0 || status >= ARRAY_SIZE(status_map));
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return status_map[status];
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic void o2dlm_lock_ast_wrapper(void *astarg)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct ocfs2_dlm_lksb *lksb = astarg;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	lksb->lksb_conn->cc_proto->lp_lock_ast(lksb);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void o2dlm_blocking_ast_wrapper(void *astarg, int level)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct ocfs2_dlm_lksb *lksb = astarg;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	lksb->lksb_conn->cc_proto->lp_blocking_ast(lksb, level);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void o2dlm_unlock_ast_wrapper(void *astarg, enum dlm_status status)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct ocfs2_dlm_lksb *lksb = astarg;
1738c2ecf20Sopenharmony_ci	int error = dlm_status_to_errno(status);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/*
1768c2ecf20Sopenharmony_ci	 * In o2dlm, you can get both the lock_ast() for the lock being
1778c2ecf20Sopenharmony_ci	 * granted and the unlock_ast() for the CANCEL failing.  A
1788c2ecf20Sopenharmony_ci	 * successful cancel sends DLM_NORMAL here.  If the
1798c2ecf20Sopenharmony_ci	 * lock grant happened before the cancel arrived, you get
1808c2ecf20Sopenharmony_ci	 * DLM_CANCELGRANT.
1818c2ecf20Sopenharmony_ci	 *
1828c2ecf20Sopenharmony_ci	 * There's no need for the double-ast.  If we see DLM_CANCELGRANT,
1838c2ecf20Sopenharmony_ci	 * we just ignore it.  We expect the lock_ast() to handle the
1848c2ecf20Sopenharmony_ci	 * granted lock.
1858c2ecf20Sopenharmony_ci	 */
1868c2ecf20Sopenharmony_ci	if (status == DLM_CANCELGRANT)
1878c2ecf20Sopenharmony_ci		return;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	lksb->lksb_conn->cc_proto->lp_unlock_ast(lksb, error);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int o2cb_dlm_lock(struct ocfs2_cluster_connection *conn,
1938c2ecf20Sopenharmony_ci			 int mode,
1948c2ecf20Sopenharmony_ci			 struct ocfs2_dlm_lksb *lksb,
1958c2ecf20Sopenharmony_ci			 u32 flags,
1968c2ecf20Sopenharmony_ci			 void *name,
1978c2ecf20Sopenharmony_ci			 unsigned int namelen)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	enum dlm_status status;
2008c2ecf20Sopenharmony_ci	int o2dlm_mode = mode_to_o2dlm(mode);
2018c2ecf20Sopenharmony_ci	int o2dlm_flags = flags_to_o2dlm(flags);
2028c2ecf20Sopenharmony_ci	int ret;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	status = dlmlock(conn->cc_lockspace, o2dlm_mode, &lksb->lksb_o2dlm,
2058c2ecf20Sopenharmony_ci			 o2dlm_flags, name, namelen,
2068c2ecf20Sopenharmony_ci			 o2dlm_lock_ast_wrapper, lksb,
2078c2ecf20Sopenharmony_ci			 o2dlm_blocking_ast_wrapper);
2088c2ecf20Sopenharmony_ci	ret = dlm_status_to_errno(status);
2098c2ecf20Sopenharmony_ci	return ret;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic int o2cb_dlm_unlock(struct ocfs2_cluster_connection *conn,
2138c2ecf20Sopenharmony_ci			   struct ocfs2_dlm_lksb *lksb,
2148c2ecf20Sopenharmony_ci			   u32 flags)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	enum dlm_status status;
2178c2ecf20Sopenharmony_ci	int o2dlm_flags = flags_to_o2dlm(flags);
2188c2ecf20Sopenharmony_ci	int ret;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	status = dlmunlock(conn->cc_lockspace, &lksb->lksb_o2dlm,
2218c2ecf20Sopenharmony_ci			   o2dlm_flags, o2dlm_unlock_ast_wrapper, lksb);
2228c2ecf20Sopenharmony_ci	ret = dlm_status_to_errno(status);
2238c2ecf20Sopenharmony_ci	return ret;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic int o2cb_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	return dlm_status_to_errno(lksb->lksb_o2dlm.status);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/*
2328c2ecf20Sopenharmony_ci * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB
2338c2ecf20Sopenharmony_ci * contents, it will zero out the LVB.  Thus the caller can always trust
2348c2ecf20Sopenharmony_ci * the contents.
2358c2ecf20Sopenharmony_ci */
2368c2ecf20Sopenharmony_cistatic int o2cb_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	return 1;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic void *o2cb_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	return (void *)(lksb->lksb_o2dlm.lvb);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void o2cb_dump_lksb(struct ocfs2_dlm_lksb *lksb)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	dlm_print_one_lock(lksb->lksb_o2dlm.lockid);
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/*
2528c2ecf20Sopenharmony_ci * Check if this node is heartbeating and is connected to all other
2538c2ecf20Sopenharmony_ci * heartbeating nodes.
2548c2ecf20Sopenharmony_ci */
2558c2ecf20Sopenharmony_cistatic int o2cb_cluster_check(void)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	u8 node_num;
2588c2ecf20Sopenharmony_ci	int i;
2598c2ecf20Sopenharmony_ci	unsigned long hbmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
2608c2ecf20Sopenharmony_ci	unsigned long netmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	node_num = o2nm_this_node();
2638c2ecf20Sopenharmony_ci	if (node_num == O2NM_MAX_NODES) {
2648c2ecf20Sopenharmony_ci		printk(KERN_ERR "o2cb: This node has not been configured.\n");
2658c2ecf20Sopenharmony_ci		return -EINVAL;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/*
2698c2ecf20Sopenharmony_ci	 * o2dlm expects o2net sockets to be created. If not, then
2708c2ecf20Sopenharmony_ci	 * dlm_join_domain() fails with a stack of errors which are both cryptic
2718c2ecf20Sopenharmony_ci	 * and incomplete. The idea here is to detect upfront whether we have
2728c2ecf20Sopenharmony_ci	 * managed to connect to all nodes or not. If not, then list the nodes
2738c2ecf20Sopenharmony_ci	 * to allow the user to check the configuration (incorrect IP, firewall,
2748c2ecf20Sopenharmony_ci	 * etc.) Yes, this is racy. But its not the end of the world.
2758c2ecf20Sopenharmony_ci	 */
2768c2ecf20Sopenharmony_ci#define	O2CB_MAP_STABILIZE_COUNT	60
2778c2ecf20Sopenharmony_ci	for (i = 0; i < O2CB_MAP_STABILIZE_COUNT; ++i) {
2788c2ecf20Sopenharmony_ci		o2hb_fill_node_map(hbmap, sizeof(hbmap));
2798c2ecf20Sopenharmony_ci		if (!test_bit(node_num, hbmap)) {
2808c2ecf20Sopenharmony_ci			printk(KERN_ERR "o2cb: %s heartbeat has not been "
2818c2ecf20Sopenharmony_ci			       "started.\n", (o2hb_global_heartbeat_active() ?
2828c2ecf20Sopenharmony_ci					      "Global" : "Local"));
2838c2ecf20Sopenharmony_ci			return -EINVAL;
2848c2ecf20Sopenharmony_ci		}
2858c2ecf20Sopenharmony_ci		o2net_fill_node_map(netmap, sizeof(netmap));
2868c2ecf20Sopenharmony_ci		/* Force set the current node to allow easy compare */
2878c2ecf20Sopenharmony_ci		set_bit(node_num, netmap);
2888c2ecf20Sopenharmony_ci		if (!memcmp(hbmap, netmap, sizeof(hbmap)))
2898c2ecf20Sopenharmony_ci			return 0;
2908c2ecf20Sopenharmony_ci		if (i < O2CB_MAP_STABILIZE_COUNT - 1)
2918c2ecf20Sopenharmony_ci			msleep(1000);
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	printk(KERN_ERR "o2cb: This node could not connect to nodes:");
2958c2ecf20Sopenharmony_ci	i = -1;
2968c2ecf20Sopenharmony_ci	while ((i = find_next_bit(hbmap, O2NM_MAX_NODES,
2978c2ecf20Sopenharmony_ci				  i + 1)) < O2NM_MAX_NODES) {
2988c2ecf20Sopenharmony_ci		if (!test_bit(i, netmap))
2998c2ecf20Sopenharmony_ci			printk(" %u", i);
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci	printk(".\n");
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return -ENOTCONN;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/*
3078c2ecf20Sopenharmony_ci * Called from the dlm when it's about to evict a node. This is how the
3088c2ecf20Sopenharmony_ci * classic stack signals node death.
3098c2ecf20Sopenharmony_ci */
3108c2ecf20Sopenharmony_cistatic void o2dlm_eviction_cb(int node_num, void *data)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct ocfs2_cluster_connection *conn = data;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	printk(KERN_NOTICE "o2cb: o2dlm has evicted node %d from domain %.*s\n",
3158c2ecf20Sopenharmony_ci	       node_num, conn->cc_namelen, conn->cc_name);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	conn->cc_recovery_handler(node_num, conn->cc_recovery_data);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	int rc = 0;
3238c2ecf20Sopenharmony_ci	u32 dlm_key;
3248c2ecf20Sopenharmony_ci	struct dlm_ctxt *dlm;
3258c2ecf20Sopenharmony_ci	struct o2dlm_private *priv;
3268c2ecf20Sopenharmony_ci	struct dlm_protocol_version fs_version;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	BUG_ON(conn == NULL);
3298c2ecf20Sopenharmony_ci	BUG_ON(conn->cc_proto == NULL);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* Ensure cluster stack is up and all nodes are connected */
3328c2ecf20Sopenharmony_ci	rc = o2cb_cluster_check();
3338c2ecf20Sopenharmony_ci	if (rc) {
3348c2ecf20Sopenharmony_ci		printk(KERN_ERR "o2cb: Cluster check failed. Fix errors "
3358c2ecf20Sopenharmony_ci		       "before retrying.\n");
3368c2ecf20Sopenharmony_ci		goto out;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	priv = kzalloc(sizeof(struct o2dlm_private), GFP_KERNEL);
3408c2ecf20Sopenharmony_ci	if (!priv) {
3418c2ecf20Sopenharmony_ci		rc = -ENOMEM;
3428c2ecf20Sopenharmony_ci		goto out_free;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* This just fills the structure in.  It is safe to pass conn. */
3468c2ecf20Sopenharmony_ci	dlm_setup_eviction_cb(&priv->op_eviction_cb, o2dlm_eviction_cb,
3478c2ecf20Sopenharmony_ci			      conn);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	conn->cc_private = priv;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* used by the dlm code to make message headers unique, each
3528c2ecf20Sopenharmony_ci	 * node in this domain must agree on this. */
3538c2ecf20Sopenharmony_ci	dlm_key = crc32_le(0, conn->cc_name, conn->cc_namelen);
3548c2ecf20Sopenharmony_ci	fs_version.pv_major = conn->cc_version.pv_major;
3558c2ecf20Sopenharmony_ci	fs_version.pv_minor = conn->cc_version.pv_minor;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	dlm = dlm_register_domain(conn->cc_name, dlm_key, &fs_version);
3588c2ecf20Sopenharmony_ci	if (IS_ERR(dlm)) {
3598c2ecf20Sopenharmony_ci		rc = PTR_ERR(dlm);
3608c2ecf20Sopenharmony_ci		mlog_errno(rc);
3618c2ecf20Sopenharmony_ci		goto out_free;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	conn->cc_version.pv_major = fs_version.pv_major;
3658c2ecf20Sopenharmony_ci	conn->cc_version.pv_minor = fs_version.pv_minor;
3668c2ecf20Sopenharmony_ci	conn->cc_lockspace = dlm;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	dlm_register_eviction_cb(dlm, &priv->op_eviction_cb);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciout_free:
3718c2ecf20Sopenharmony_ci	if (rc)
3728c2ecf20Sopenharmony_ci		kfree(conn->cc_private);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ciout:
3758c2ecf20Sopenharmony_ci	return rc;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int o2cb_cluster_disconnect(struct ocfs2_cluster_connection *conn)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct dlm_ctxt *dlm = conn->cc_lockspace;
3818c2ecf20Sopenharmony_ci	struct o2dlm_private *priv = conn->cc_private;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	dlm_unregister_eviction_cb(&priv->op_eviction_cb);
3848c2ecf20Sopenharmony_ci	conn->cc_private = NULL;
3858c2ecf20Sopenharmony_ci	kfree(priv);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	dlm_unregister_domain(dlm);
3888c2ecf20Sopenharmony_ci	conn->cc_lockspace = NULL;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	return 0;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int o2cb_cluster_this_node(struct ocfs2_cluster_connection *conn,
3948c2ecf20Sopenharmony_ci				  unsigned int *node)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int node_num;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	node_num = o2nm_this_node();
3998c2ecf20Sopenharmony_ci	if (node_num == O2NM_INVALID_NODE_NUM)
4008c2ecf20Sopenharmony_ci		return -ENOENT;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (node_num >= O2NM_MAX_NODES)
4038c2ecf20Sopenharmony_ci		return -EOVERFLOW;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	*node = node_num;
4068c2ecf20Sopenharmony_ci	return 0;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic struct ocfs2_stack_operations o2cb_stack_ops = {
4108c2ecf20Sopenharmony_ci	.connect	= o2cb_cluster_connect,
4118c2ecf20Sopenharmony_ci	.disconnect	= o2cb_cluster_disconnect,
4128c2ecf20Sopenharmony_ci	.this_node	= o2cb_cluster_this_node,
4138c2ecf20Sopenharmony_ci	.dlm_lock	= o2cb_dlm_lock,
4148c2ecf20Sopenharmony_ci	.dlm_unlock	= o2cb_dlm_unlock,
4158c2ecf20Sopenharmony_ci	.lock_status	= o2cb_dlm_lock_status,
4168c2ecf20Sopenharmony_ci	.lvb_valid	= o2cb_dlm_lvb_valid,
4178c2ecf20Sopenharmony_ci	.lock_lvb	= o2cb_dlm_lvb,
4188c2ecf20Sopenharmony_ci	.dump_lksb	= o2cb_dump_lksb,
4198c2ecf20Sopenharmony_ci};
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic struct ocfs2_stack_plugin o2cb_stack = {
4228c2ecf20Sopenharmony_ci	.sp_name	= "o2cb",
4238c2ecf20Sopenharmony_ci	.sp_ops		= &o2cb_stack_ops,
4248c2ecf20Sopenharmony_ci	.sp_owner	= THIS_MODULE,
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int __init o2cb_stack_init(void)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	return ocfs2_stack_glue_register(&o2cb_stack);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic void __exit o2cb_stack_exit(void)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	ocfs2_stack_glue_unregister(&o2cb_stack);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Oracle");
4388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ocfs2 driver for the classic o2cb stack");
4398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4408c2ecf20Sopenharmony_cimodule_init(o2cb_stack_init);
4418c2ecf20Sopenharmony_cimodule_exit(o2cb_stack_exit);
442