18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*-
38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0:
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * dlmast.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * AST and BAST functionality for local and remote nodes
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2004 Oracle.  All rights reserved.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/fs.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci#include <linux/highmem.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/sysctl.h>
198c2ecf20Sopenharmony_ci#include <linux/random.h>
208c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
218c2ecf20Sopenharmony_ci#include <linux/socket.h>
228c2ecf20Sopenharmony_ci#include <linux/inet.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "../cluster/heartbeat.h"
278c2ecf20Sopenharmony_ci#include "../cluster/nodemanager.h"
288c2ecf20Sopenharmony_ci#include "../cluster/tcp.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "dlmapi.h"
318c2ecf20Sopenharmony_ci#include "dlmcommon.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define MLOG_MASK_PREFIX ML_DLM
348c2ecf20Sopenharmony_ci#include "../cluster/masklog.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void dlm_update_lvb(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
378c2ecf20Sopenharmony_ci			   struct dlm_lock *lock);
388c2ecf20Sopenharmony_cistatic int dlm_should_cancel_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Should be called as an ast gets queued to see if the new
418c2ecf20Sopenharmony_ci * lock level will obsolete a pending bast.
428c2ecf20Sopenharmony_ci * For example, if dlm_thread queued a bast for an EX lock that
438c2ecf20Sopenharmony_ci * was blocking another EX, but before sending the bast the
448c2ecf20Sopenharmony_ci * lock owner downconverted to NL, the bast is now obsolete.
458c2ecf20Sopenharmony_ci * Only the ast should be sent.
468c2ecf20Sopenharmony_ci * This is needed because the lock and convert paths can queue
478c2ecf20Sopenharmony_ci * asts out-of-band (not waiting for dlm_thread) in order to
488c2ecf20Sopenharmony_ci * allow for LKM_NOQUEUE to get immediate responses. */
498c2ecf20Sopenharmony_cistatic int dlm_should_cancel_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	assert_spin_locked(&dlm->ast_lock);
528c2ecf20Sopenharmony_ci	assert_spin_locked(&lock->spinlock);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (lock->ml.highest_blocked == LKM_IVMODE)
558c2ecf20Sopenharmony_ci		return 0;
568c2ecf20Sopenharmony_ci	BUG_ON(lock->ml.highest_blocked == LKM_NLMODE);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (lock->bast_pending &&
598c2ecf20Sopenharmony_ci	    list_empty(&lock->bast_list))
608c2ecf20Sopenharmony_ci		/* old bast already sent, ok */
618c2ecf20Sopenharmony_ci		return 0;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (lock->ml.type == LKM_EXMODE)
648c2ecf20Sopenharmony_ci		/* EX blocks anything left, any bast still valid */
658c2ecf20Sopenharmony_ci		return 0;
668c2ecf20Sopenharmony_ci	else if (lock->ml.type == LKM_NLMODE)
678c2ecf20Sopenharmony_ci		/* NL blocks nothing, no reason to send any bast, cancel it */
688c2ecf20Sopenharmony_ci		return 1;
698c2ecf20Sopenharmony_ci	else if (lock->ml.highest_blocked != LKM_EXMODE)
708c2ecf20Sopenharmony_ci		/* PR only blocks EX */
718c2ecf20Sopenharmony_ci		return 1;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_civoid __dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct dlm_lock_resource *res;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	BUG_ON(!dlm);
818c2ecf20Sopenharmony_ci	BUG_ON(!lock);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	res = lock->lockres;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	assert_spin_locked(&dlm->ast_lock);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (!list_empty(&lock->ast_list)) {
888c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "%s: res %.*s, lock %u:%llu, "
898c2ecf20Sopenharmony_ci		     "AST list not empty, pending %d, newlevel %d\n",
908c2ecf20Sopenharmony_ci		     dlm->name, res->lockname.len, res->lockname.name,
918c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
928c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
938c2ecf20Sopenharmony_ci		     lock->ast_pending, lock->ml.type);
948c2ecf20Sopenharmony_ci		BUG();
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	if (lock->ast_pending)
978c2ecf20Sopenharmony_ci		mlog(0, "%s: res %.*s, lock %u:%llu, AST getting flushed\n",
988c2ecf20Sopenharmony_ci		     dlm->name, res->lockname.len, res->lockname.name,
998c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
1008c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)));
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* putting lock on list, add a ref */
1038c2ecf20Sopenharmony_ci	dlm_lock_get(lock);
1048c2ecf20Sopenharmony_ci	spin_lock(&lock->spinlock);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* check to see if this ast obsoletes the bast */
1078c2ecf20Sopenharmony_ci	if (dlm_should_cancel_bast(dlm, lock)) {
1088c2ecf20Sopenharmony_ci		mlog(0, "%s: res %.*s, lock %u:%llu, Cancelling BAST\n",
1098c2ecf20Sopenharmony_ci		     dlm->name, res->lockname.len, res->lockname.name,
1108c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
1118c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)));
1128c2ecf20Sopenharmony_ci		lock->bast_pending = 0;
1138c2ecf20Sopenharmony_ci		list_del_init(&lock->bast_list);
1148c2ecf20Sopenharmony_ci		lock->ml.highest_blocked = LKM_IVMODE;
1158c2ecf20Sopenharmony_ci		/* removing lock from list, remove a ref.  guaranteed
1168c2ecf20Sopenharmony_ci		 * this won't be the last ref because of the get above,
1178c2ecf20Sopenharmony_ci		 * so res->spinlock will not be taken here */
1188c2ecf20Sopenharmony_ci		dlm_lock_put(lock);
1198c2ecf20Sopenharmony_ci		/* free up the reserved bast that we are cancelling.
1208c2ecf20Sopenharmony_ci		 * guaranteed that this will not be the last reserved
1218c2ecf20Sopenharmony_ci		 * ast because *both* an ast and a bast were reserved
1228c2ecf20Sopenharmony_ci		 * to get to this point.  the res->spinlock will not be
1238c2ecf20Sopenharmony_ci		 * taken here */
1248c2ecf20Sopenharmony_ci		dlm_lockres_release_ast(dlm, res);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci	list_add_tail(&lock->ast_list, &dlm->pending_asts);
1278c2ecf20Sopenharmony_ci	lock->ast_pending = 1;
1288c2ecf20Sopenharmony_ci	spin_unlock(&lock->spinlock);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_civoid dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	BUG_ON(!dlm);
1348c2ecf20Sopenharmony_ci	BUG_ON(!lock);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	spin_lock(&dlm->ast_lock);
1378c2ecf20Sopenharmony_ci	__dlm_queue_ast(dlm, lock);
1388c2ecf20Sopenharmony_ci	spin_unlock(&dlm->ast_lock);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_civoid __dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct dlm_lock_resource *res;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	BUG_ON(!dlm);
1478c2ecf20Sopenharmony_ci	BUG_ON(!lock);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	assert_spin_locked(&dlm->ast_lock);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	res = lock->lockres;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&lock->bast_list));
1548c2ecf20Sopenharmony_ci	if (lock->bast_pending)
1558c2ecf20Sopenharmony_ci		mlog(0, "%s: res %.*s, lock %u:%llu, BAST getting flushed\n",
1568c2ecf20Sopenharmony_ci		     dlm->name, res->lockname.len, res->lockname.name,
1578c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
1588c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)));
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* putting lock on list, add a ref */
1618c2ecf20Sopenharmony_ci	dlm_lock_get(lock);
1628c2ecf20Sopenharmony_ci	spin_lock(&lock->spinlock);
1638c2ecf20Sopenharmony_ci	list_add_tail(&lock->bast_list, &dlm->pending_basts);
1648c2ecf20Sopenharmony_ci	lock->bast_pending = 1;
1658c2ecf20Sopenharmony_ci	spin_unlock(&lock->spinlock);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_civoid dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	BUG_ON(!dlm);
1718c2ecf20Sopenharmony_ci	BUG_ON(!lock);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	spin_lock(&dlm->ast_lock);
1748c2ecf20Sopenharmony_ci	__dlm_queue_bast(dlm, lock);
1758c2ecf20Sopenharmony_ci	spin_unlock(&dlm->ast_lock);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void dlm_update_lvb(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
1798c2ecf20Sopenharmony_ci			   struct dlm_lock *lock)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct dlm_lockstatus *lksb = lock->lksb;
1828c2ecf20Sopenharmony_ci	BUG_ON(!lksb);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* only updates if this node masters the lockres */
1858c2ecf20Sopenharmony_ci	spin_lock(&res->spinlock);
1868c2ecf20Sopenharmony_ci	if (res->owner == dlm->node_num) {
1878c2ecf20Sopenharmony_ci		/* check the lksb flags for the direction */
1888c2ecf20Sopenharmony_ci		if (lksb->flags & DLM_LKSB_GET_LVB) {
1898c2ecf20Sopenharmony_ci			mlog(0, "getting lvb from lockres for %s node\n",
1908c2ecf20Sopenharmony_ci				  lock->ml.node == dlm->node_num ? "master" :
1918c2ecf20Sopenharmony_ci				  "remote");
1928c2ecf20Sopenharmony_ci			memcpy(lksb->lvb, res->lvb, DLM_LVB_LEN);
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci		/* Do nothing for lvb put requests - they should be done in
1958c2ecf20Sopenharmony_ci 		 * place when the lock is downconverted - otherwise we risk
1968c2ecf20Sopenharmony_ci 		 * racing gets and puts which could result in old lvb data
1978c2ecf20Sopenharmony_ci 		 * being propagated. We leave the put flag set and clear it
1988c2ecf20Sopenharmony_ci 		 * here. In the future we might want to clear it at the time
1998c2ecf20Sopenharmony_ci 		 * the put is actually done.
2008c2ecf20Sopenharmony_ci		 */
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	spin_unlock(&res->spinlock);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* reset any lvb flags on the lksb */
2058c2ecf20Sopenharmony_ci	lksb->flags &= ~(DLM_LKSB_PUT_LVB|DLM_LKSB_GET_LVB);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_civoid dlm_do_local_ast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
2098c2ecf20Sopenharmony_ci		      struct dlm_lock *lock)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	dlm_astlockfunc_t *fn;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	mlog(0, "%s: res %.*s, lock %u:%llu, Local AST\n", dlm->name,
2148c2ecf20Sopenharmony_ci	     res->lockname.len, res->lockname.name,
2158c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
2168c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)));
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	fn = lock->ast;
2198c2ecf20Sopenharmony_ci	BUG_ON(lock->ml.node != dlm->node_num);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	dlm_update_lvb(dlm, res, lock);
2228c2ecf20Sopenharmony_ci	(*fn)(lock->astdata);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ciint dlm_do_remote_ast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
2278c2ecf20Sopenharmony_ci		      struct dlm_lock *lock)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	int ret;
2308c2ecf20Sopenharmony_ci	struct dlm_lockstatus *lksb;
2318c2ecf20Sopenharmony_ci	int lksbflags;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	mlog(0, "%s: res %.*s, lock %u:%llu, Remote AST\n", dlm->name,
2348c2ecf20Sopenharmony_ci	     res->lockname.len, res->lockname.name,
2358c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
2368c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)));
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	lksb = lock->lksb;
2398c2ecf20Sopenharmony_ci	BUG_ON(lock->ml.node == dlm->node_num);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	lksbflags = lksb->flags;
2428c2ecf20Sopenharmony_ci	dlm_update_lvb(dlm, res, lock);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* lock request came from another node
2458c2ecf20Sopenharmony_ci	 * go do the ast over there */
2468c2ecf20Sopenharmony_ci	ret = dlm_send_proxy_ast(dlm, res, lock, lksbflags);
2478c2ecf20Sopenharmony_ci	return ret;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_civoid dlm_do_local_bast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
2518c2ecf20Sopenharmony_ci		       struct dlm_lock *lock, int blocked_type)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	dlm_bastlockfunc_t *fn = lock->bast;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	BUG_ON(lock->ml.node != dlm->node_num);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	mlog(0, "%s: res %.*s, lock %u:%llu, Local BAST, blocked %d\n",
2588c2ecf20Sopenharmony_ci	     dlm->name, res->lockname.len, res->lockname.name,
2598c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
2608c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
2618c2ecf20Sopenharmony_ci	     blocked_type);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	(*fn)(lock->astdata, blocked_type);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ciint dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
2698c2ecf20Sopenharmony_ci			  void **ret_data)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	int ret;
2728c2ecf20Sopenharmony_ci	unsigned int locklen;
2738c2ecf20Sopenharmony_ci	struct dlm_ctxt *dlm = data;
2748c2ecf20Sopenharmony_ci	struct dlm_lock_resource *res = NULL;
2758c2ecf20Sopenharmony_ci	struct dlm_lock *lock = NULL;
2768c2ecf20Sopenharmony_ci	struct dlm_proxy_ast *past = (struct dlm_proxy_ast *) msg->buf;
2778c2ecf20Sopenharmony_ci	char *name;
2788c2ecf20Sopenharmony_ci	struct list_head *head = NULL;
2798c2ecf20Sopenharmony_ci	__be64 cookie;
2808c2ecf20Sopenharmony_ci	u32 flags;
2818c2ecf20Sopenharmony_ci	u8 node;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (!dlm_grab(dlm)) {
2848c2ecf20Sopenharmony_ci		dlm_error(DLM_REJECTED);
2858c2ecf20Sopenharmony_ci		return DLM_REJECTED;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	mlog_bug_on_msg(!dlm_domain_fully_joined(dlm),
2898c2ecf20Sopenharmony_ci			"Domain %s not fully joined!\n", dlm->name);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	name = past->name;
2928c2ecf20Sopenharmony_ci	locklen = past->namelen;
2938c2ecf20Sopenharmony_ci	cookie = past->cookie;
2948c2ecf20Sopenharmony_ci	flags = be32_to_cpu(past->flags);
2958c2ecf20Sopenharmony_ci	node = past->node_idx;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (locklen > DLM_LOCKID_NAME_MAX) {
2988c2ecf20Sopenharmony_ci		ret = DLM_IVBUFLEN;
2998c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "Invalid name length (%d) in proxy ast "
3008c2ecf20Sopenharmony_ci		     "handler!\n", locklen);
3018c2ecf20Sopenharmony_ci		goto leave;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if ((flags & (LKM_PUT_LVB|LKM_GET_LVB)) ==
3058c2ecf20Sopenharmony_ci	     (LKM_PUT_LVB|LKM_GET_LVB)) {
3068c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "Both PUT and GET lvb specified, (0x%x)\n",
3078c2ecf20Sopenharmony_ci		     flags);
3088c2ecf20Sopenharmony_ci		ret = DLM_BADARGS;
3098c2ecf20Sopenharmony_ci		goto leave;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	mlog(0, "lvb: %s\n", flags & LKM_PUT_LVB ? "put lvb" :
3138c2ecf20Sopenharmony_ci		  (flags & LKM_GET_LVB ? "get lvb" : "none"));
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	mlog(0, "type=%d, blocked_type=%d\n", past->type, past->blocked_type);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (past->type != DLM_AST &&
3188c2ecf20Sopenharmony_ci	    past->type != DLM_BAST) {
3198c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu"
3208c2ecf20Sopenharmony_ci		     "name=%.*s, node=%u\n", past->type,
3218c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
3228c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
3238c2ecf20Sopenharmony_ci		     locklen, name, node);
3248c2ecf20Sopenharmony_ci		ret = DLM_IVLOCKID;
3258c2ecf20Sopenharmony_ci		goto leave;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	res = dlm_lookup_lockres(dlm, name, locklen);
3298c2ecf20Sopenharmony_ci	if (!res) {
3308c2ecf20Sopenharmony_ci		mlog(0, "Got %sast for unknown lockres! cookie=%u:%llu, "
3318c2ecf20Sopenharmony_ci		     "name=%.*s, node=%u\n", (past->type == DLM_AST ? "" : "b"),
3328c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
3338c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
3348c2ecf20Sopenharmony_ci		     locklen, name, node);
3358c2ecf20Sopenharmony_ci		ret = DLM_IVLOCKID;
3368c2ecf20Sopenharmony_ci		goto leave;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* cannot get a proxy ast message if this node owns it */
3408c2ecf20Sopenharmony_ci	BUG_ON(res->owner == dlm->node_num);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	mlog(0, "%s: res %.*s\n", dlm->name, res->lockname.len,
3438c2ecf20Sopenharmony_ci	     res->lockname.name);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	spin_lock(&res->spinlock);
3468c2ecf20Sopenharmony_ci	if (res->state & DLM_LOCK_RES_RECOVERING) {
3478c2ecf20Sopenharmony_ci		mlog(0, "Responding with DLM_RECOVERING!\n");
3488c2ecf20Sopenharmony_ci		ret = DLM_RECOVERING;
3498c2ecf20Sopenharmony_ci		goto unlock_out;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci	if (res->state & DLM_LOCK_RES_MIGRATING) {
3528c2ecf20Sopenharmony_ci		mlog(0, "Responding with DLM_MIGRATING!\n");
3538c2ecf20Sopenharmony_ci		ret = DLM_MIGRATING;
3548c2ecf20Sopenharmony_ci		goto unlock_out;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci	/* try convert queue for both ast/bast */
3578c2ecf20Sopenharmony_ci	head = &res->converting;
3588c2ecf20Sopenharmony_ci	lock = NULL;
3598c2ecf20Sopenharmony_ci	list_for_each_entry(lock, head, list) {
3608c2ecf20Sopenharmony_ci		if (lock->ml.cookie == cookie)
3618c2ecf20Sopenharmony_ci			goto do_ast;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* if not on convert, try blocked for ast, granted for bast */
3658c2ecf20Sopenharmony_ci	if (past->type == DLM_AST)
3668c2ecf20Sopenharmony_ci		head = &res->blocked;
3678c2ecf20Sopenharmony_ci	else
3688c2ecf20Sopenharmony_ci		head = &res->granted;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	list_for_each_entry(lock, head, list) {
3718c2ecf20Sopenharmony_ci		/* if lock is found but unlock is pending ignore the bast */
3728c2ecf20Sopenharmony_ci		if (lock->ml.cookie == cookie) {
3738c2ecf20Sopenharmony_ci			if (lock->unlock_pending)
3748c2ecf20Sopenharmony_ci				break;
3758c2ecf20Sopenharmony_ci			goto do_ast;
3768c2ecf20Sopenharmony_ci		}
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	mlog(0, "Got %sast for unknown lock! cookie=%u:%llu, name=%.*s, "
3808c2ecf20Sopenharmony_ci	     "node=%u\n", past->type == DLM_AST ? "" : "b",
3818c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
3828c2ecf20Sopenharmony_ci	     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
3838c2ecf20Sopenharmony_ci	     locklen, name, node);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	ret = DLM_NORMAL;
3868c2ecf20Sopenharmony_ciunlock_out:
3878c2ecf20Sopenharmony_ci	spin_unlock(&res->spinlock);
3888c2ecf20Sopenharmony_ci	goto leave;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cido_ast:
3918c2ecf20Sopenharmony_ci	ret = DLM_NORMAL;
3928c2ecf20Sopenharmony_ci	if (past->type == DLM_AST) {
3938c2ecf20Sopenharmony_ci		/* do not alter lock refcount.  switching lists. */
3948c2ecf20Sopenharmony_ci		list_move_tail(&lock->list, &res->granted);
3958c2ecf20Sopenharmony_ci		mlog(0, "%s: res %.*s, lock %u:%llu, Granted type %d => %d\n",
3968c2ecf20Sopenharmony_ci		     dlm->name, res->lockname.len, res->lockname.name,
3978c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
3988c2ecf20Sopenharmony_ci		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
3998c2ecf20Sopenharmony_ci		     lock->ml.type, lock->ml.convert_type);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		if (lock->ml.convert_type != LKM_IVMODE) {
4028c2ecf20Sopenharmony_ci			lock->ml.type = lock->ml.convert_type;
4038c2ecf20Sopenharmony_ci			lock->ml.convert_type = LKM_IVMODE;
4048c2ecf20Sopenharmony_ci		} else {
4058c2ecf20Sopenharmony_ci			// should already be there....
4068c2ecf20Sopenharmony_ci		}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		lock->lksb->status = DLM_NORMAL;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci		/* if we requested the lvb, fetch it into our lksb now */
4118c2ecf20Sopenharmony_ci		if (flags & LKM_GET_LVB) {
4128c2ecf20Sopenharmony_ci			BUG_ON(!(lock->lksb->flags & DLM_LKSB_GET_LVB));
4138c2ecf20Sopenharmony_ci			memcpy(lock->lksb->lvb, past->lvb, DLM_LVB_LEN);
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	spin_unlock(&res->spinlock);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (past->type == DLM_AST)
4198c2ecf20Sopenharmony_ci		dlm_do_local_ast(dlm, res, lock);
4208c2ecf20Sopenharmony_ci	else
4218c2ecf20Sopenharmony_ci		dlm_do_local_bast(dlm, res, lock, past->blocked_type);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cileave:
4248c2ecf20Sopenharmony_ci	if (res)
4258c2ecf20Sopenharmony_ci		dlm_lockres_put(res);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	dlm_put(dlm);
4288c2ecf20Sopenharmony_ci	return ret;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ciint dlm_send_proxy_ast_msg(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
4348c2ecf20Sopenharmony_ci			   struct dlm_lock *lock, int msg_type,
4358c2ecf20Sopenharmony_ci			   int blocked_type, int flags)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	int ret = 0;
4388c2ecf20Sopenharmony_ci	struct dlm_proxy_ast past;
4398c2ecf20Sopenharmony_ci	struct kvec vec[2];
4408c2ecf20Sopenharmony_ci	size_t veclen = 1;
4418c2ecf20Sopenharmony_ci	int status;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	mlog(0, "%s: res %.*s, to %u, type %d, blocked_type %d\n", dlm->name,
4448c2ecf20Sopenharmony_ci	     res->lockname.len, res->lockname.name, lock->ml.node, msg_type,
4458c2ecf20Sopenharmony_ci	     blocked_type);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	memset(&past, 0, sizeof(struct dlm_proxy_ast));
4488c2ecf20Sopenharmony_ci	past.node_idx = dlm->node_num;
4498c2ecf20Sopenharmony_ci	past.type = msg_type;
4508c2ecf20Sopenharmony_ci	past.blocked_type = blocked_type;
4518c2ecf20Sopenharmony_ci	past.namelen = res->lockname.len;
4528c2ecf20Sopenharmony_ci	memcpy(past.name, res->lockname.name, past.namelen);
4538c2ecf20Sopenharmony_ci	past.cookie = lock->ml.cookie;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	vec[0].iov_len = sizeof(struct dlm_proxy_ast);
4568c2ecf20Sopenharmony_ci	vec[0].iov_base = &past;
4578c2ecf20Sopenharmony_ci	if (flags & DLM_LKSB_GET_LVB) {
4588c2ecf20Sopenharmony_ci		be32_add_cpu(&past.flags, LKM_GET_LVB);
4598c2ecf20Sopenharmony_ci		vec[1].iov_len = DLM_LVB_LEN;
4608c2ecf20Sopenharmony_ci		vec[1].iov_base = lock->lksb->lvb;
4618c2ecf20Sopenharmony_ci		veclen++;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	ret = o2net_send_message_vec(DLM_PROXY_AST_MSG, dlm->key, vec, veclen,
4658c2ecf20Sopenharmony_ci				     lock->ml.node, &status);
4668c2ecf20Sopenharmony_ci	if (ret < 0)
4678c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "%s: res %.*s, error %d send AST to node %u\n",
4688c2ecf20Sopenharmony_ci		     dlm->name, res->lockname.len, res->lockname.name, ret,
4698c2ecf20Sopenharmony_ci		     lock->ml.node);
4708c2ecf20Sopenharmony_ci	else {
4718c2ecf20Sopenharmony_ci		if (status == DLM_RECOVERING) {
4728c2ecf20Sopenharmony_ci			mlog(ML_ERROR, "sent AST to node %u, it thinks this "
4738c2ecf20Sopenharmony_ci			     "node is dead!\n", lock->ml.node);
4748c2ecf20Sopenharmony_ci			BUG();
4758c2ecf20Sopenharmony_ci		} else if (status == DLM_MIGRATING) {
4768c2ecf20Sopenharmony_ci			mlog(ML_ERROR, "sent AST to node %u, it returned "
4778c2ecf20Sopenharmony_ci			     "DLM_MIGRATING!\n", lock->ml.node);
4788c2ecf20Sopenharmony_ci			BUG();
4798c2ecf20Sopenharmony_ci		} else if (status != DLM_NORMAL && status != DLM_IVLOCKID) {
4808c2ecf20Sopenharmony_ci			mlog(ML_ERROR, "AST to node %u returned %d!\n",
4818c2ecf20Sopenharmony_ci			     lock->ml.node, status);
4828c2ecf20Sopenharmony_ci			/* ignore it */
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci		ret = 0;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci	return ret;
4878c2ecf20Sopenharmony_ci}
488