xref: /kernel/linux/linux-5.10/fs/ocfs2/dlmfs/userdlm.c (revision 8c2ecf20)
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 * userdlm.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Code which implements the kernel side of a minimal userspace
88c2ecf20Sopenharmony_ci * interface to our DLM.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Many of the functions here are pared down versions of dlmglue.c
118c2ecf20Sopenharmony_ci * functions.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Copyright (C) 2003, 2004 Oracle.  All rights reserved.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/signal.h>
178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/fs.h>
218c2ecf20Sopenharmony_ci#include <linux/types.h>
228c2ecf20Sopenharmony_ci#include <linux/crc32.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "../ocfs2_lockingver.h"
258c2ecf20Sopenharmony_ci#include "../stackglue.h"
268c2ecf20Sopenharmony_ci#include "userdlm.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define MLOG_MASK_PREFIX ML_DLMFS
298c2ecf20Sopenharmony_ci#include "../cluster/masklog.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline struct user_lock_res *user_lksb_to_lock_res(struct ocfs2_dlm_lksb *lksb)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	return container_of(lksb, struct user_lock_res, l_lksb);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline int user_check_wait_flag(struct user_lock_res *lockres,
388c2ecf20Sopenharmony_ci				       int flag)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	int ret;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
438c2ecf20Sopenharmony_ci	ret = lockres->l_flags & flag;
448c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return ret;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline void user_wait_on_busy_lock(struct user_lock_res *lockres)
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	wait_event(lockres->l_event,
538c2ecf20Sopenharmony_ci		   !user_check_wait_flag(lockres, USER_LOCK_BUSY));
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic inline void user_wait_on_blocked_lock(struct user_lock_res *lockres)
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	wait_event(lockres->l_event,
608c2ecf20Sopenharmony_ci		   !user_check_wait_flag(lockres, USER_LOCK_BLOCKED));
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* I heart container_of... */
648c2ecf20Sopenharmony_cistatic inline struct ocfs2_cluster_connection *
658c2ecf20Sopenharmony_cicluster_connection_from_user_lockres(struct user_lock_res *lockres)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct dlmfs_inode_private *ip;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	ip = container_of(lockres,
708c2ecf20Sopenharmony_ci			  struct dlmfs_inode_private,
718c2ecf20Sopenharmony_ci			  ip_lockres);
728c2ecf20Sopenharmony_ci	return ip->ip_conn;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic struct inode *
768c2ecf20Sopenharmony_ciuser_dlm_inode_from_user_lockres(struct user_lock_res *lockres)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct dlmfs_inode_private *ip;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	ip = container_of(lockres,
818c2ecf20Sopenharmony_ci			  struct dlmfs_inode_private,
828c2ecf20Sopenharmony_ci			  ip_lockres);
838c2ecf20Sopenharmony_ci	return &ip->ip_vfs_inode;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline void user_recover_from_dlm_error(struct user_lock_res *lockres)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
898c2ecf20Sopenharmony_ci	lockres->l_flags &= ~USER_LOCK_BUSY;
908c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define user_log_dlm_error(_func, _stat, _lockres) do {			\
948c2ecf20Sopenharmony_ci	mlog(ML_ERROR, "Dlm error %d while calling %s on "		\
958c2ecf20Sopenharmony_ci		"resource %.*s\n", _stat, _func,			\
968c2ecf20Sopenharmony_ci		_lockres->l_namelen, _lockres->l_name); 		\
978c2ecf20Sopenharmony_ci} while (0)
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* WARNING: This function lives in a world where the only three lock
1008c2ecf20Sopenharmony_ci * levels are EX, PR, and NL. It *will* have to be adjusted when more
1018c2ecf20Sopenharmony_ci * lock types are added. */
1028c2ecf20Sopenharmony_cistatic inline int user_highest_compat_lock_level(int level)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	int new_level = DLM_LOCK_EX;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (level == DLM_LOCK_EX)
1078c2ecf20Sopenharmony_ci		new_level = DLM_LOCK_NL;
1088c2ecf20Sopenharmony_ci	else if (level == DLM_LOCK_PR)
1098c2ecf20Sopenharmony_ci		new_level = DLM_LOCK_PR;
1108c2ecf20Sopenharmony_ci	return new_level;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void user_ast(struct ocfs2_dlm_lksb *lksb)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct user_lock_res *lockres = user_lksb_to_lock_res(lksb);
1168c2ecf20Sopenharmony_ci	int status;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	mlog(ML_BASTS, "AST fired for lockres %.*s, level %d => %d\n",
1198c2ecf20Sopenharmony_ci	     lockres->l_namelen, lockres->l_name, lockres->l_level,
1208c2ecf20Sopenharmony_ci	     lockres->l_requested);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	status = ocfs2_dlm_lock_status(&lockres->l_lksb);
1258c2ecf20Sopenharmony_ci	if (status) {
1268c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "lksb status value of %u on lockres %.*s\n",
1278c2ecf20Sopenharmony_ci		     status, lockres->l_namelen, lockres->l_name);
1288c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
1298c2ecf20Sopenharmony_ci		return;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	mlog_bug_on_msg(lockres->l_requested == DLM_LOCK_IV,
1338c2ecf20Sopenharmony_ci			"Lockres %.*s, requested ivmode. flags 0x%x\n",
1348c2ecf20Sopenharmony_ci			lockres->l_namelen, lockres->l_name, lockres->l_flags);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* we're downconverting. */
1378c2ecf20Sopenharmony_ci	if (lockres->l_requested < lockres->l_level) {
1388c2ecf20Sopenharmony_ci		if (lockres->l_requested <=
1398c2ecf20Sopenharmony_ci		    user_highest_compat_lock_level(lockres->l_blocking)) {
1408c2ecf20Sopenharmony_ci			lockres->l_blocking = DLM_LOCK_NL;
1418c2ecf20Sopenharmony_ci			lockres->l_flags &= ~USER_LOCK_BLOCKED;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	lockres->l_level = lockres->l_requested;
1468c2ecf20Sopenharmony_ci	lockres->l_requested = DLM_LOCK_IV;
1478c2ecf20Sopenharmony_ci	lockres->l_flags |= USER_LOCK_ATTACHED;
1488c2ecf20Sopenharmony_ci	lockres->l_flags &= ~USER_LOCK_BUSY;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	wake_up(&lockres->l_event);
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic inline void user_dlm_grab_inode_ref(struct user_lock_res *lockres)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct inode *inode;
1588c2ecf20Sopenharmony_ci	inode = user_dlm_inode_from_user_lockres(lockres);
1598c2ecf20Sopenharmony_ci	if (!igrab(inode))
1608c2ecf20Sopenharmony_ci		BUG();
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void user_dlm_unblock_lock(struct work_struct *work);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void __user_dlm_queue_lockres(struct user_lock_res *lockres)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	if (!(lockres->l_flags & USER_LOCK_QUEUED)) {
1688c2ecf20Sopenharmony_ci		user_dlm_grab_inode_ref(lockres);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		INIT_WORK(&lockres->l_work, user_dlm_unblock_lock);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci		queue_work(user_dlm_worker, &lockres->l_work);
1738c2ecf20Sopenharmony_ci		lockres->l_flags |= USER_LOCK_QUEUED;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic void __user_dlm_cond_queue_lockres(struct user_lock_res *lockres)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int queue = 0;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (!(lockres->l_flags & USER_LOCK_BLOCKED))
1828c2ecf20Sopenharmony_ci		return;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	switch (lockres->l_blocking) {
1858c2ecf20Sopenharmony_ci	case DLM_LOCK_EX:
1868c2ecf20Sopenharmony_ci		if (!lockres->l_ex_holders && !lockres->l_ro_holders)
1878c2ecf20Sopenharmony_ci			queue = 1;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	case DLM_LOCK_PR:
1908c2ecf20Sopenharmony_ci		if (!lockres->l_ex_holders)
1918c2ecf20Sopenharmony_ci			queue = 1;
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci	default:
1948c2ecf20Sopenharmony_ci		BUG();
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (queue)
1988c2ecf20Sopenharmony_ci		__user_dlm_queue_lockres(lockres);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void user_bast(struct ocfs2_dlm_lksb *lksb, int level)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct user_lock_res *lockres = user_lksb_to_lock_res(lksb);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	mlog(ML_BASTS, "BAST fired for lockres %.*s, blocking %d, level %d\n",
2068c2ecf20Sopenharmony_ci	     lockres->l_namelen, lockres->l_name, level, lockres->l_level);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
2098c2ecf20Sopenharmony_ci	lockres->l_flags |= USER_LOCK_BLOCKED;
2108c2ecf20Sopenharmony_ci	if (level > lockres->l_blocking)
2118c2ecf20Sopenharmony_ci		lockres->l_blocking = level;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	__user_dlm_queue_lockres(lockres);
2148c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	wake_up(&lockres->l_event);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void user_unlock_ast(struct ocfs2_dlm_lksb *lksb, int status)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct user_lock_res *lockres = user_lksb_to_lock_res(lksb);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	mlog(ML_BASTS, "UNLOCK AST fired for lockres %.*s, flags 0x%x\n",
2248c2ecf20Sopenharmony_ci	     lockres->l_namelen, lockres->l_name, lockres->l_flags);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (status)
2278c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "dlm returns status %d\n", status);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
2308c2ecf20Sopenharmony_ci	/* The teardown flag gets set early during the unlock process,
2318c2ecf20Sopenharmony_ci	 * so test the cancel flag to make sure that this ast isn't
2328c2ecf20Sopenharmony_ci	 * for a concurrent cancel. */
2338c2ecf20Sopenharmony_ci	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN
2348c2ecf20Sopenharmony_ci	    && !(lockres->l_flags & USER_LOCK_IN_CANCEL)) {
2358c2ecf20Sopenharmony_ci		lockres->l_level = DLM_LOCK_IV;
2368c2ecf20Sopenharmony_ci	} else if (status == DLM_CANCELGRANT) {
2378c2ecf20Sopenharmony_ci		/* We tried to cancel a convert request, but it was
2388c2ecf20Sopenharmony_ci		 * already granted. Don't clear the busy flag - the
2398c2ecf20Sopenharmony_ci		 * ast should've done this already. */
2408c2ecf20Sopenharmony_ci		BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
2418c2ecf20Sopenharmony_ci		lockres->l_flags &= ~USER_LOCK_IN_CANCEL;
2428c2ecf20Sopenharmony_ci		goto out_noclear;
2438c2ecf20Sopenharmony_ci	} else {
2448c2ecf20Sopenharmony_ci		BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
2458c2ecf20Sopenharmony_ci		/* Cancel succeeded, we want to re-queue */
2468c2ecf20Sopenharmony_ci		lockres->l_requested = DLM_LOCK_IV; /* cancel an
2478c2ecf20Sopenharmony_ci						    * upconvert
2488c2ecf20Sopenharmony_ci						    * request. */
2498c2ecf20Sopenharmony_ci		lockres->l_flags &= ~USER_LOCK_IN_CANCEL;
2508c2ecf20Sopenharmony_ci		/* we want the unblock thread to look at it again
2518c2ecf20Sopenharmony_ci		 * now. */
2528c2ecf20Sopenharmony_ci		if (lockres->l_flags & USER_LOCK_BLOCKED)
2538c2ecf20Sopenharmony_ci			__user_dlm_queue_lockres(lockres);
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	lockres->l_flags &= ~USER_LOCK_BUSY;
2578c2ecf20Sopenharmony_ciout_noclear:
2588c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	wake_up(&lockres->l_event);
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/*
2648c2ecf20Sopenharmony_ci * This is the userdlmfs locking protocol version.
2658c2ecf20Sopenharmony_ci *
2668c2ecf20Sopenharmony_ci * See fs/ocfs2/dlmglue.c for more details on locking versions.
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistatic struct ocfs2_locking_protocol user_dlm_lproto = {
2698c2ecf20Sopenharmony_ci	.lp_max_version = {
2708c2ecf20Sopenharmony_ci		.pv_major = OCFS2_LOCKING_PROTOCOL_MAJOR,
2718c2ecf20Sopenharmony_ci		.pv_minor = OCFS2_LOCKING_PROTOCOL_MINOR,
2728c2ecf20Sopenharmony_ci	},
2738c2ecf20Sopenharmony_ci	.lp_lock_ast		= user_ast,
2748c2ecf20Sopenharmony_ci	.lp_blocking_ast	= user_bast,
2758c2ecf20Sopenharmony_ci	.lp_unlock_ast		= user_unlock_ast,
2768c2ecf20Sopenharmony_ci};
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic inline void user_dlm_drop_inode_ref(struct user_lock_res *lockres)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct inode *inode;
2818c2ecf20Sopenharmony_ci	inode = user_dlm_inode_from_user_lockres(lockres);
2828c2ecf20Sopenharmony_ci	iput(inode);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic void user_dlm_unblock_lock(struct work_struct *work)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	int new_level, status;
2888c2ecf20Sopenharmony_ci	struct user_lock_res *lockres =
2898c2ecf20Sopenharmony_ci		container_of(work, struct user_lock_res, l_work);
2908c2ecf20Sopenharmony_ci	struct ocfs2_cluster_connection *conn =
2918c2ecf20Sopenharmony_ci		cluster_connection_from_user_lockres(lockres);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	mlog(0, "lockres %.*s\n", lockres->l_namelen, lockres->l_name);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	mlog_bug_on_msg(!(lockres->l_flags & USER_LOCK_QUEUED),
2988c2ecf20Sopenharmony_ci			"Lockres %.*s, flags 0x%x\n",
2998c2ecf20Sopenharmony_ci			lockres->l_namelen, lockres->l_name, lockres->l_flags);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* notice that we don't clear USER_LOCK_BLOCKED here. If it's
3028c2ecf20Sopenharmony_ci	 * set, we want user_ast clear it. */
3038c2ecf20Sopenharmony_ci	lockres->l_flags &= ~USER_LOCK_QUEUED;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* It's valid to get here and no longer be blocked - if we get
3068c2ecf20Sopenharmony_ci	 * several basts in a row, we might be queued by the first
3078c2ecf20Sopenharmony_ci	 * one, the unblock thread might run and clear the queued
3088c2ecf20Sopenharmony_ci	 * flag, and finally we might get another bast which re-queues
3098c2ecf20Sopenharmony_ci	 * us before our ast for the downconvert is called. */
3108c2ecf20Sopenharmony_ci	if (!(lockres->l_flags & USER_LOCK_BLOCKED)) {
3118c2ecf20Sopenharmony_ci		mlog(ML_BASTS, "lockres %.*s USER_LOCK_BLOCKED\n",
3128c2ecf20Sopenharmony_ci		     lockres->l_namelen, lockres->l_name);
3138c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
3148c2ecf20Sopenharmony_ci		goto drop_ref;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
3188c2ecf20Sopenharmony_ci		mlog(ML_BASTS, "lockres %.*s USER_LOCK_IN_TEARDOWN\n",
3198c2ecf20Sopenharmony_ci		     lockres->l_namelen, lockres->l_name);
3208c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
3218c2ecf20Sopenharmony_ci		goto drop_ref;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (lockres->l_flags & USER_LOCK_BUSY) {
3258c2ecf20Sopenharmony_ci		if (lockres->l_flags & USER_LOCK_IN_CANCEL) {
3268c2ecf20Sopenharmony_ci			mlog(ML_BASTS, "lockres %.*s USER_LOCK_IN_CANCEL\n",
3278c2ecf20Sopenharmony_ci			     lockres->l_namelen, lockres->l_name);
3288c2ecf20Sopenharmony_ci			spin_unlock(&lockres->l_lock);
3298c2ecf20Sopenharmony_ci			goto drop_ref;
3308c2ecf20Sopenharmony_ci		}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		lockres->l_flags |= USER_LOCK_IN_CANCEL;
3338c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci		status = ocfs2_dlm_unlock(conn, &lockres->l_lksb,
3368c2ecf20Sopenharmony_ci					  DLM_LKF_CANCEL);
3378c2ecf20Sopenharmony_ci		if (status)
3388c2ecf20Sopenharmony_ci			user_log_dlm_error("ocfs2_dlm_unlock", status, lockres);
3398c2ecf20Sopenharmony_ci		goto drop_ref;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* If there are still incompat holders, we can exit safely
3438c2ecf20Sopenharmony_ci	 * without worrying about re-queueing this lock as that will
3448c2ecf20Sopenharmony_ci	 * happen on the last call to user_cluster_unlock. */
3458c2ecf20Sopenharmony_ci	if ((lockres->l_blocking == DLM_LOCK_EX)
3468c2ecf20Sopenharmony_ci	    && (lockres->l_ex_holders || lockres->l_ro_holders)) {
3478c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
3488c2ecf20Sopenharmony_ci		mlog(ML_BASTS, "lockres %.*s, EX/PR Holders %u,%u\n",
3498c2ecf20Sopenharmony_ci		     lockres->l_namelen, lockres->l_name,
3508c2ecf20Sopenharmony_ci		     lockres->l_ex_holders, lockres->l_ro_holders);
3518c2ecf20Sopenharmony_ci		goto drop_ref;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if ((lockres->l_blocking == DLM_LOCK_PR)
3558c2ecf20Sopenharmony_ci	    && lockres->l_ex_holders) {
3568c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
3578c2ecf20Sopenharmony_ci		mlog(ML_BASTS, "lockres %.*s, EX Holders %u\n",
3588c2ecf20Sopenharmony_ci		     lockres->l_namelen, lockres->l_name,
3598c2ecf20Sopenharmony_ci		     lockres->l_ex_holders);
3608c2ecf20Sopenharmony_ci		goto drop_ref;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* yay, we can downconvert now. */
3648c2ecf20Sopenharmony_ci	new_level = user_highest_compat_lock_level(lockres->l_blocking);
3658c2ecf20Sopenharmony_ci	lockres->l_requested = new_level;
3668c2ecf20Sopenharmony_ci	lockres->l_flags |= USER_LOCK_BUSY;
3678c2ecf20Sopenharmony_ci	mlog(ML_BASTS, "lockres %.*s, downconvert %d => %d\n",
3688c2ecf20Sopenharmony_ci	     lockres->l_namelen, lockres->l_name, lockres->l_level, new_level);
3698c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* need lock downconvert request now... */
3728c2ecf20Sopenharmony_ci	status = ocfs2_dlm_lock(conn, new_level, &lockres->l_lksb,
3738c2ecf20Sopenharmony_ci				DLM_LKF_CONVERT|DLM_LKF_VALBLK,
3748c2ecf20Sopenharmony_ci				lockres->l_name,
3758c2ecf20Sopenharmony_ci				lockres->l_namelen);
3768c2ecf20Sopenharmony_ci	if (status) {
3778c2ecf20Sopenharmony_ci		user_log_dlm_error("ocfs2_dlm_lock", status, lockres);
3788c2ecf20Sopenharmony_ci		user_recover_from_dlm_error(lockres);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cidrop_ref:
3828c2ecf20Sopenharmony_ci	user_dlm_drop_inode_ref(lockres);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic inline void user_dlm_inc_holders(struct user_lock_res *lockres,
3868c2ecf20Sopenharmony_ci					int level)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	switch(level) {
3898c2ecf20Sopenharmony_ci	case DLM_LOCK_EX:
3908c2ecf20Sopenharmony_ci		lockres->l_ex_holders++;
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci	case DLM_LOCK_PR:
3938c2ecf20Sopenharmony_ci		lockres->l_ro_holders++;
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	default:
3968c2ecf20Sopenharmony_ci		BUG();
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/* predict what lock level we'll be dropping down to on behalf
4018c2ecf20Sopenharmony_ci * of another node, and return true if the currently wanted
4028c2ecf20Sopenharmony_ci * level will be compatible with it. */
4038c2ecf20Sopenharmony_cistatic inline int
4048c2ecf20Sopenharmony_ciuser_may_continue_on_blocked_lock(struct user_lock_res *lockres,
4058c2ecf20Sopenharmony_ci				  int wanted)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	BUG_ON(!(lockres->l_flags & USER_LOCK_BLOCKED));
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return wanted <= user_highest_compat_lock_level(lockres->l_blocking);
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ciint user_dlm_cluster_lock(struct user_lock_res *lockres,
4138c2ecf20Sopenharmony_ci			  int level,
4148c2ecf20Sopenharmony_ci			  int lkm_flags)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	int status, local_flags;
4178c2ecf20Sopenharmony_ci	struct ocfs2_cluster_connection *conn =
4188c2ecf20Sopenharmony_ci		cluster_connection_from_user_lockres(lockres);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (level != DLM_LOCK_EX &&
4218c2ecf20Sopenharmony_ci	    level != DLM_LOCK_PR) {
4228c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
4238c2ecf20Sopenharmony_ci		     lockres->l_namelen, lockres->l_name);
4248c2ecf20Sopenharmony_ci		status = -EINVAL;
4258c2ecf20Sopenharmony_ci		goto bail;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	mlog(ML_BASTS, "lockres %.*s, level %d, flags = 0x%x\n",
4298c2ecf20Sopenharmony_ci	     lockres->l_namelen, lockres->l_name, level, lkm_flags);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciagain:
4328c2ecf20Sopenharmony_ci	if (signal_pending(current)) {
4338c2ecf20Sopenharmony_ci		status = -ERESTARTSYS;
4348c2ecf20Sopenharmony_ci		goto bail;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
4388c2ecf20Sopenharmony_ci	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
4398c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
4408c2ecf20Sopenharmony_ci		status = -EAGAIN;
4418c2ecf20Sopenharmony_ci		goto bail;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* We only compare against the currently granted level
4458c2ecf20Sopenharmony_ci	 * here. If the lock is blocked waiting on a downconvert,
4468c2ecf20Sopenharmony_ci	 * we'll get caught below. */
4478c2ecf20Sopenharmony_ci	if ((lockres->l_flags & USER_LOCK_BUSY) &&
4488c2ecf20Sopenharmony_ci	    (level > lockres->l_level)) {
4498c2ecf20Sopenharmony_ci		/* is someone sitting in dlm_lock? If so, wait on
4508c2ecf20Sopenharmony_ci		 * them. */
4518c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		user_wait_on_busy_lock(lockres);
4548c2ecf20Sopenharmony_ci		goto again;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if ((lockres->l_flags & USER_LOCK_BLOCKED) &&
4588c2ecf20Sopenharmony_ci	    (!user_may_continue_on_blocked_lock(lockres, level))) {
4598c2ecf20Sopenharmony_ci		/* is the lock is currently blocked on behalf of
4608c2ecf20Sopenharmony_ci		 * another node */
4618c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		user_wait_on_blocked_lock(lockres);
4648c2ecf20Sopenharmony_ci		goto again;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	if (level > lockres->l_level) {
4688c2ecf20Sopenharmony_ci		local_flags = lkm_flags | DLM_LKF_VALBLK;
4698c2ecf20Sopenharmony_ci		if (lockres->l_level != DLM_LOCK_IV)
4708c2ecf20Sopenharmony_ci			local_flags |= DLM_LKF_CONVERT;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci		lockres->l_requested = level;
4738c2ecf20Sopenharmony_ci		lockres->l_flags |= USER_LOCK_BUSY;
4748c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		BUG_ON(level == DLM_LOCK_IV);
4778c2ecf20Sopenharmony_ci		BUG_ON(level == DLM_LOCK_NL);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		/* call dlm_lock to upgrade lock now */
4808c2ecf20Sopenharmony_ci		status = ocfs2_dlm_lock(conn, level, &lockres->l_lksb,
4818c2ecf20Sopenharmony_ci					local_flags, lockres->l_name,
4828c2ecf20Sopenharmony_ci					lockres->l_namelen);
4838c2ecf20Sopenharmony_ci		if (status) {
4848c2ecf20Sopenharmony_ci			if ((lkm_flags & DLM_LKF_NOQUEUE) &&
4858c2ecf20Sopenharmony_ci			    (status != -EAGAIN))
4868c2ecf20Sopenharmony_ci				user_log_dlm_error("ocfs2_dlm_lock",
4878c2ecf20Sopenharmony_ci						   status, lockres);
4888c2ecf20Sopenharmony_ci			user_recover_from_dlm_error(lockres);
4898c2ecf20Sopenharmony_ci			goto bail;
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		user_wait_on_busy_lock(lockres);
4938c2ecf20Sopenharmony_ci		goto again;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	user_dlm_inc_holders(lockres, level);
4978c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	status = 0;
5008c2ecf20Sopenharmony_cibail:
5018c2ecf20Sopenharmony_ci	return status;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic inline void user_dlm_dec_holders(struct user_lock_res *lockres,
5058c2ecf20Sopenharmony_ci					int level)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	switch(level) {
5088c2ecf20Sopenharmony_ci	case DLM_LOCK_EX:
5098c2ecf20Sopenharmony_ci		BUG_ON(!lockres->l_ex_holders);
5108c2ecf20Sopenharmony_ci		lockres->l_ex_holders--;
5118c2ecf20Sopenharmony_ci		break;
5128c2ecf20Sopenharmony_ci	case DLM_LOCK_PR:
5138c2ecf20Sopenharmony_ci		BUG_ON(!lockres->l_ro_holders);
5148c2ecf20Sopenharmony_ci		lockres->l_ro_holders--;
5158c2ecf20Sopenharmony_ci		break;
5168c2ecf20Sopenharmony_ci	default:
5178c2ecf20Sopenharmony_ci		BUG();
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_civoid user_dlm_cluster_unlock(struct user_lock_res *lockres,
5228c2ecf20Sopenharmony_ci			     int level)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	if (level != DLM_LOCK_EX &&
5258c2ecf20Sopenharmony_ci	    level != DLM_LOCK_PR) {
5268c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
5278c2ecf20Sopenharmony_ci		     lockres->l_namelen, lockres->l_name);
5288c2ecf20Sopenharmony_ci		return;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
5328c2ecf20Sopenharmony_ci	user_dlm_dec_holders(lockres, level);
5338c2ecf20Sopenharmony_ci	__user_dlm_cond_queue_lockres(lockres);
5348c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_civoid user_dlm_write_lvb(struct inode *inode,
5388c2ecf20Sopenharmony_ci			const char *val,
5398c2ecf20Sopenharmony_ci			unsigned int len)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	struct user_lock_res *lockres = &DLMFS_I(inode)->ip_lockres;
5428c2ecf20Sopenharmony_ci	char *lvb;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	BUG_ON(len > DLM_LVB_LEN);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	BUG_ON(lockres->l_level < DLM_LOCK_EX);
5498c2ecf20Sopenharmony_ci	lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
5508c2ecf20Sopenharmony_ci	memcpy(lvb, val, len);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cibool user_dlm_read_lvb(struct inode *inode, char *val)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct user_lock_res *lockres = &DLMFS_I(inode)->ip_lockres;
5588c2ecf20Sopenharmony_ci	char *lvb;
5598c2ecf20Sopenharmony_ci	bool ret = true;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	BUG_ON(lockres->l_level < DLM_LOCK_PR);
5648c2ecf20Sopenharmony_ci	if (ocfs2_dlm_lvb_valid(&lockres->l_lksb)) {
5658c2ecf20Sopenharmony_ci		lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
5668c2ecf20Sopenharmony_ci		memcpy(val, lvb, DLM_LVB_LEN);
5678c2ecf20Sopenharmony_ci	} else
5688c2ecf20Sopenharmony_ci		ret = false;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
5718c2ecf20Sopenharmony_ci	return ret;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_civoid user_dlm_lock_res_init(struct user_lock_res *lockres,
5758c2ecf20Sopenharmony_ci			    struct dentry *dentry)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	memset(lockres, 0, sizeof(*lockres));
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	spin_lock_init(&lockres->l_lock);
5808c2ecf20Sopenharmony_ci	init_waitqueue_head(&lockres->l_event);
5818c2ecf20Sopenharmony_ci	lockres->l_level = DLM_LOCK_IV;
5828c2ecf20Sopenharmony_ci	lockres->l_requested = DLM_LOCK_IV;
5838c2ecf20Sopenharmony_ci	lockres->l_blocking = DLM_LOCK_IV;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* should have been checked before getting here. */
5868c2ecf20Sopenharmony_ci	BUG_ON(dentry->d_name.len >= USER_DLM_LOCK_ID_MAX_LEN);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	memcpy(lockres->l_name,
5898c2ecf20Sopenharmony_ci	       dentry->d_name.name,
5908c2ecf20Sopenharmony_ci	       dentry->d_name.len);
5918c2ecf20Sopenharmony_ci	lockres->l_namelen = dentry->d_name.len;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ciint user_dlm_destroy_lock(struct user_lock_res *lockres)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	int status = -EBUSY;
5978c2ecf20Sopenharmony_ci	struct ocfs2_cluster_connection *conn =
5988c2ecf20Sopenharmony_ci		cluster_connection_from_user_lockres(lockres);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	mlog(ML_BASTS, "lockres %.*s\n", lockres->l_namelen, lockres->l_name);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	spin_lock(&lockres->l_lock);
6038c2ecf20Sopenharmony_ci	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
6048c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
6058c2ecf20Sopenharmony_ci		goto bail;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	lockres->l_flags |= USER_LOCK_IN_TEARDOWN;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	while (lockres->l_flags & USER_LOCK_BUSY) {
6118c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci		user_wait_on_busy_lock(lockres);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		spin_lock(&lockres->l_lock);
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (lockres->l_ro_holders || lockres->l_ex_holders) {
6198c2ecf20Sopenharmony_ci		lockres->l_flags &= ~USER_LOCK_IN_TEARDOWN;
6208c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
6218c2ecf20Sopenharmony_ci		goto bail;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	status = 0;
6258c2ecf20Sopenharmony_ci	if (!(lockres->l_flags & USER_LOCK_ATTACHED)) {
6268c2ecf20Sopenharmony_ci		/*
6278c2ecf20Sopenharmony_ci		 * lock is never requested, leave USER_LOCK_IN_TEARDOWN set
6288c2ecf20Sopenharmony_ci		 * to avoid new lock request coming in.
6298c2ecf20Sopenharmony_ci		 */
6308c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
6318c2ecf20Sopenharmony_ci		goto bail;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	lockres->l_flags &= ~USER_LOCK_ATTACHED;
6358c2ecf20Sopenharmony_ci	lockres->l_flags |= USER_LOCK_BUSY;
6368c2ecf20Sopenharmony_ci	spin_unlock(&lockres->l_lock);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	status = ocfs2_dlm_unlock(conn, &lockres->l_lksb, DLM_LKF_VALBLK);
6398c2ecf20Sopenharmony_ci	if (status) {
6408c2ecf20Sopenharmony_ci		spin_lock(&lockres->l_lock);
6418c2ecf20Sopenharmony_ci		lockres->l_flags &= ~USER_LOCK_IN_TEARDOWN;
6428c2ecf20Sopenharmony_ci		lockres->l_flags &= ~USER_LOCK_BUSY;
6438c2ecf20Sopenharmony_ci		spin_unlock(&lockres->l_lock);
6448c2ecf20Sopenharmony_ci		user_log_dlm_error("ocfs2_dlm_unlock", status, lockres);
6458c2ecf20Sopenharmony_ci		goto bail;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	user_wait_on_busy_lock(lockres);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	status = 0;
6518c2ecf20Sopenharmony_cibail:
6528c2ecf20Sopenharmony_ci	return status;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic void user_dlm_recovery_handler_noop(int node_num,
6568c2ecf20Sopenharmony_ci					   void *recovery_data)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	/* We ignore recovery events */
6598c2ecf20Sopenharmony_ci	return;
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_civoid user_dlm_set_locking_protocol(void)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	ocfs2_stack_glue_set_max_proto_version(&user_dlm_lproto.lp_max_version);
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistruct ocfs2_cluster_connection *user_dlm_register(const struct qstr *name)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	int rc;
6708c2ecf20Sopenharmony_ci	struct ocfs2_cluster_connection *conn;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	rc = ocfs2_cluster_connect_agnostic(name->name, name->len,
6738c2ecf20Sopenharmony_ci					    &user_dlm_lproto,
6748c2ecf20Sopenharmony_ci					    user_dlm_recovery_handler_noop,
6758c2ecf20Sopenharmony_ci					    NULL, &conn);
6768c2ecf20Sopenharmony_ci	if (rc)
6778c2ecf20Sopenharmony_ci		mlog_errno(rc);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return rc ? ERR_PTR(rc) : conn;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_civoid user_dlm_unregister(struct ocfs2_cluster_connection *conn)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	ocfs2_cluster_disconnect(conn, 0);
6858c2ecf20Sopenharmony_ci}
686