18df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* -*- mode: c; c-basic-offset: 8; -*-
28df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * vim: noexpandtab sw=8 ts=8 sts=0:
38df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
48df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * userdlm.c
58df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
68df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * Code which implements the kernel side of a minimal userspace
78df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * interface to our DLM.
88df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
98df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * Many of the functions here are pared down versions of dlmglue.c
108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * functions.
118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * Copyright (C) 2003, 2004 Oracle.  All rights reserved.
138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * This program is free software; you can redistribute it and/or
158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * modify it under the terms of the GNU General Public
168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * License as published by the Free Software Foundation; either
178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * version 2 of the License, or (at your option) any later version.
188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * This program is distributed in the hope that it will be useful,
208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * but WITHOUT ANY WARRANTY; without even the implied warranty of
218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * General Public License for more details.
238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh *
248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * You should have received a copy of the GNU General Public
258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * License along with this program; if not, write to the
268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * Boston, MA 021110-1307, USA.
288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh */
298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
30aee93ac4b7ad461255939248d0d51566cff77e05Jeff Mahoney#include <linux/signal.h>
318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include <linux/module.h>
338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include <linux/fs.h>
348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include <linux/types.h>
358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include <linux/crc32.h>
368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
370016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker#include "ocfs2_lockingver.h"
380016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker#include "stackglue.h"
398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "userdlm.h"
408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#define MLOG_MASK_PREFIX ML_DLMFS
428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "cluster/masklog.h"
438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
440016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker
450016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic inline struct user_lock_res *user_lksb_to_lock_res(struct ocfs2_dlm_lksb *lksb)
460016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker{
470016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	return container_of(lksb, struct user_lock_res, l_lksb);
480016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker}
490016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker
508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline int user_check_wait_flag(struct user_lock_res *lockres,
518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				       int flag)
528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int ret;
548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	ret = lockres->l_flags & flag;
578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return ret;
608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_wait_on_busy_lock(struct user_lock_res *lockres)
638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wait_event(lockres->l_event,
668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		   !user_check_wait_flag(lockres, USER_LOCK_BUSY));
678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_wait_on_blocked_lock(struct user_lock_res *lockres)
708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wait_event(lockres->l_event,
738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		   !user_check_wait_flag(lockres, USER_LOCK_BLOCKED));
748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* I heart container_of... */
770016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic inline struct ocfs2_cluster_connection *
780016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckercluster_connection_from_user_lockres(struct user_lock_res *lockres)
798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlmfs_inode_private *ip;
818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	ip = container_of(lockres,
838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  struct dlmfs_inode_private,
848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  ip_lockres);
850016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	return ip->ip_conn;
868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic struct inode *
898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehuser_dlm_inode_from_user_lockres(struct user_lock_res *lockres)
908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlmfs_inode_private *ip;
928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	ip = container_of(lockres,
948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  struct dlmfs_inode_private,
958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  ip_lockres);
968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return &ip->ip_vfs_inode;
978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_recover_from_dlm_error(struct user_lock_res *lockres)
1008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
1028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_BUSY;
1038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
1048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
106ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh#define user_log_dlm_error(_func, _stat, _lockres) do {			\
1070016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	mlog(ML_ERROR, "Dlm error %d while calling %s on "		\
1080016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		"resource %.*s\n", _stat, _func,			\
1090016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		_lockres->l_namelen, _lockres->l_name); 		\
1108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh} while (0)
1118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* WARNING: This function lives in a world where the only three lock
1138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * levels are EX, PR, and NL. It *will* have to be adjusted when more
1148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * lock types are added. */
1158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline int user_highest_compat_lock_level(int level)
1168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1170016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	int new_level = DLM_LOCK_EX;
1188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1190016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (level == DLM_LOCK_EX)
1200016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		new_level = DLM_LOCK_NL;
1210016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	else if (level == DLM_LOCK_PR)
1220016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		new_level = DLM_LOCK_PR;
1238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return new_level;
1248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1260016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic void user_ast(struct ocfs2_dlm_lksb *lksb)
1278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1280016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct user_lock_res *lockres = user_lksb_to_lock_res(lksb);
1290016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	int status;
1308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1316fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(ML_BASTS, "AST fired for lockres %.*s, level %d => %d\n",
1326fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	     lockres->l_namelen, lockres->l_name, lockres->l_level,
1336fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	     lockres->l_requested);
1348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
1368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1370016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	status = ocfs2_dlm_lock_status(&lockres->l_lksb);
1380016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (status) {
139ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		mlog(ML_ERROR, "lksb status value of %u on lockres %.*s\n",
1400016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		     status, lockres->l_namelen, lockres->l_name);
1418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
1428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return;
1438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
1448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1450016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	mlog_bug_on_msg(lockres->l_requested == DLM_LOCK_IV,
146ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			"Lockres %.*s, requested ivmode. flags 0x%x\n",
147ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			lockres->l_namelen, lockres->l_name, lockres->l_flags);
148cc6eb725955efb026007e1d7da8fe5383981afd2Mark Fasheh
1498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* we're downconverting. */
1508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_requested < lockres->l_level) {
1518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (lockres->l_requested <=
1528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		    user_highest_compat_lock_level(lockres->l_blocking)) {
1530016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			lockres->l_blocking = DLM_LOCK_NL;
1548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			lockres->l_flags &= ~USER_LOCK_BLOCKED;
1558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		}
1568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
1578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_level = lockres->l_requested;
1590016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	lockres->l_requested = DLM_LOCK_IV;
1608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_ATTACHED;
1618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_BUSY;
1628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
1648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wake_up(&lockres->l_event);
1668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_grab_inode_ref(struct user_lock_res *lockres)
1698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct inode *inode;
1718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	inode = user_dlm_inode_from_user_lockres(lockres);
1728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!igrab(inode))
1738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
1748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
176c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void user_dlm_unblock_lock(struct work_struct *work);
1778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void __user_dlm_queue_lockres(struct user_lock_res *lockres)
1798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_QUEUED)) {
1818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_dlm_grab_inode_ref(lockres);
1828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
183c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		INIT_WORK(&lockres->l_work, user_dlm_unblock_lock);
1848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		queue_work(user_dlm_worker, &lockres->l_work);
1868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags |= USER_LOCK_QUEUED;
1878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
1888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void __user_dlm_cond_queue_lockres(struct user_lock_res *lockres)
1918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int queue = 0;
1938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_BLOCKED))
1958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return;
1968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	switch (lockres->l_blocking) {
1980016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	case DLM_LOCK_EX:
1998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (!lockres->l_ex_holders && !lockres->l_ro_holders)
2008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			queue = 1;
2018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
2020016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	case DLM_LOCK_PR:
2038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (!lockres->l_ex_holders)
2048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			queue = 1;
2058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
2068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	default:
2078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
2088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
2098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (queue)
2118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		__user_dlm_queue_lockres(lockres);
2128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2140016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic void user_bast(struct ocfs2_dlm_lksb *lksb, int level)
2158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2160016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct user_lock_res *lockres = user_lksb_to_lock_res(lksb);
2178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2186fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(ML_BASTS, "BAST fired for lockres %.*s, blocking %d, level %d\n",
2196fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	     lockres->l_namelen, lockres->l_name, level, lockres->l_level);
2208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
2228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_BLOCKED;
2238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level > lockres->l_blocking)
2248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_blocking = level;
2258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	__user_dlm_queue_lockres(lockres);
2278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
2288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wake_up(&lockres->l_event);
2308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2320016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic void user_unlock_ast(struct ocfs2_dlm_lksb *lksb, int status)
2338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2340016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct user_lock_res *lockres = user_lksb_to_lock_res(lksb);
2358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2366fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(ML_BASTS, "UNLOCK AST fired for lockres %.*s, flags 0x%x\n",
2376fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	     lockres->l_namelen, lockres->l_name, lockres->l_flags);
2388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2390016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (status)
2400016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		mlog(ML_ERROR, "dlm returns status %d\n", status);
2418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
2432cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	/* The teardown flag gets set early during the unlock process,
2442cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	 * so test the cancel flag to make sure that this ast isn't
2452cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	 * for a concurrent cancel. */
2462cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN
2472cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	    && !(lockres->l_flags & USER_LOCK_IN_CANCEL)) {
2480016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		lockres->l_level = DLM_LOCK_IV;
2492cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	} else if (status == DLM_CANCELGRANT) {
250f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		/* We tried to cancel a convert request, but it was
251f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		 * already granted. Don't clear the busy flag - the
252f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		 * ast should've done this already. */
253f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
254f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		lockres->l_flags &= ~USER_LOCK_IN_CANCEL;
255f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		goto out_noclear;
256f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh	} else {
257f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
258f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		/* Cancel succeeded, we want to re-queue */
2590016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		lockres->l_requested = DLM_LOCK_IV; /* cancel an
2608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh						    * upconvert
2618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh						    * request. */
2628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags &= ~USER_LOCK_IN_CANCEL;
2638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* we want the unblock thread to look at it again
2648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		 * now. */
265f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		if (lockres->l_flags & USER_LOCK_BLOCKED)
266f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh			__user_dlm_queue_lockres(lockres);
2678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
2688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_BUSY;
270f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fashehout_noclear:
2718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
2728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wake_up(&lockres->l_event);
2748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2760016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker/*
2770016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker * This is the userdlmfs locking protocol version.
2780016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker *
2790016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker * See fs/ocfs2/dlmglue.c for more details on locking versions.
2800016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker */
2810016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic struct ocfs2_locking_protocol user_dlm_lproto = {
2820016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	.lp_max_version = {
2830016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		.pv_major = OCFS2_LOCKING_PROTOCOL_MAJOR,
2840016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		.pv_minor = OCFS2_LOCKING_PROTOCOL_MINOR,
2850016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	},
2860016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	.lp_lock_ast		= user_ast,
2870016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	.lp_blocking_ast	= user_bast,
2880016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	.lp_unlock_ast		= user_unlock_ast,
2890016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker};
2900016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker
2918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_drop_inode_ref(struct user_lock_res *lockres)
2928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct inode *inode;
2948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	inode = user_dlm_inode_from_user_lockres(lockres);
2958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	iput(inode);
2968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
298c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void user_dlm_unblock_lock(struct work_struct *work)
2998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
3008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int new_level, status;
301c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct user_lock_res *lockres =
302c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct user_lock_res, l_work);
3030016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct ocfs2_cluster_connection *conn =
3040016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		cluster_connection_from_user_lockres(lockres);
3058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3066fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(0, "lockres %.*s\n", lockres->l_namelen, lockres->l_name);
3078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
3098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3101f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	mlog_bug_on_msg(!(lockres->l_flags & USER_LOCK_QUEUED),
311ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			"Lockres %.*s, flags 0x%x\n",
312ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			lockres->l_namelen, lockres->l_name, lockres->l_flags);
3138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3141f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	/* notice that we don't clear USER_LOCK_BLOCKED here. If it's
3151f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * set, we want user_ast clear it. */
3168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_QUEUED;
3178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3181f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	/* It's valid to get here and no longer be blocked - if we get
3191f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * several basts in a row, we might be queued by the first
3201f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * one, the unblock thread might run and clear the queued
3211f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * flag, and finally we might get another bast which re-queues
3221f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * us before our ast for the downconvert is called. */
3231f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_BLOCKED)) {
3246fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		mlog(ML_BASTS, "lockres %.*s USER_LOCK_BLOCKED\n",
3256fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		     lockres->l_namelen, lockres->l_name);
3261f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh		spin_unlock(&lockres->l_lock);
3271f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh		goto drop_ref;
3281f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	}
3291f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh
3308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
3316fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		mlog(ML_BASTS, "lockres %.*s USER_LOCK_IN_TEARDOWN\n",
3326fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		     lockres->l_namelen, lockres->l_name);
3338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_flags & USER_LOCK_BUSY) {
3388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (lockres->l_flags & USER_LOCK_IN_CANCEL) {
3396fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran			mlog(ML_BASTS, "lockres %.*s USER_LOCK_IN_CANCEL\n",
3406fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran			     lockres->l_namelen, lockres->l_name);
3418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			spin_unlock(&lockres->l_lock);
3428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			goto drop_ref;
3438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		}
3448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags |= USER_LOCK_IN_CANCEL;
3468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3480016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		status = ocfs2_dlm_unlock(conn, &lockres->l_lksb,
3490016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker					  DLM_LKF_CANCEL);
3500016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		if (status)
3510016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			user_log_dlm_error("ocfs2_dlm_unlock", status, lockres);
3528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* If there are still incompat holders, we can exit safely
3568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * without worrying about re-queueing this lock as that will
3578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * happen on the last call to user_cluster_unlock. */
3580016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if ((lockres->l_blocking == DLM_LOCK_EX)
3598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    && (lockres->l_ex_holders || lockres->l_ro_holders)) {
3608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3616fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		mlog(ML_BASTS, "lockres %.*s, EX/PR Holders %u,%u\n",
3626fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		     lockres->l_namelen, lockres->l_name,
3636fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		     lockres->l_ex_holders, lockres->l_ro_holders);
3648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3670016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if ((lockres->l_blocking == DLM_LOCK_PR)
3688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    && lockres->l_ex_holders) {
3698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3706fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		mlog(ML_BASTS, "lockres %.*s, EX Holders %u\n",
3716fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		     lockres->l_namelen, lockres->l_name,
3726fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran		     lockres->l_ex_holders);
3738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* yay, we can downconvert now. */
3778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	new_level = user_highest_compat_lock_level(lockres->l_blocking);
3788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_requested = new_level;
3798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_BUSY;
3806fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(ML_BASTS, "lockres %.*s, downconvert %d => %d\n",
3816fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	     lockres->l_namelen, lockres->l_name, lockres->l_level, new_level);
3828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
3838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* need lock downconvert request now... */
3850016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	status = ocfs2_dlm_lock(conn, new_level, &lockres->l_lksb,
3860016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker				DLM_LKF_CONVERT|DLM_LKF_VALBLK,
3870016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker				lockres->l_name,
3880016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker				lockres->l_namelen);
3890016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (status) {
3900016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		user_log_dlm_error("ocfs2_dlm_lock", status, lockres);
3918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_recover_from_dlm_error(lockres);
3928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehdrop_ref:
3958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_dlm_drop_inode_ref(lockres);
3968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
3978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_inc_holders(struct user_lock_res *lockres,
3998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh					int level)
4008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
4018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	switch(level) {
4020016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	case DLM_LOCK_EX:
4038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ex_holders++;
4048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
4050016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	case DLM_LOCK_PR:
4068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ro_holders++;
4078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
4088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	default:
4098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
4108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
4128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* predict what lock level we'll be dropping down to on behalf
4148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * of another node, and return true if the currently wanted
4158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * level will be compatible with it. */
4168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline int
4178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehuser_may_continue_on_blocked_lock(struct user_lock_res *lockres,
4188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				  int wanted)
4198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
4208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(!(lockres->l_flags & USER_LOCK_BLOCKED));
4218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return wanted <= user_highest_compat_lock_level(lockres->l_blocking);
4238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
4248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehint user_dlm_cluster_lock(struct user_lock_res *lockres,
4268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  int level,
4278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  int lkm_flags)
4288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
4298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int status, local_flags;
4300016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct ocfs2_cluster_connection *conn =
4310016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		cluster_connection_from_user_lockres(lockres);
4328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4330016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (level != DLM_LOCK_EX &&
4340016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	    level != DLM_LOCK_PR) {
435ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
436ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		     lockres->l_namelen, lockres->l_name);
4378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = -EINVAL;
4388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
4398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4416fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(ML_BASTS, "lockres %.*s, level %d, flags = 0x%x\n",
4426fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	     lockres->l_namelen, lockres->l_name, level, lkm_flags);
4438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehagain:
4458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (signal_pending(current)) {
4468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = -ERESTARTSYS;
4478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
4488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
4518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* We only compare against the currently granted level
4538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * here. If the lock is blocked waiting on a downconvert,
4548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * we'll get caught below. */
4558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if ((lockres->l_flags & USER_LOCK_BUSY) &&
4568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    (level > lockres->l_level)) {
4578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* is someone sitting in dlm_lock? If so, wait on
4588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		 * them. */
4598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
4608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_busy_lock(lockres);
4628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto again;
4638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if ((lockres->l_flags & USER_LOCK_BLOCKED) &&
4668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    (!user_may_continue_on_blocked_lock(lockres, level))) {
4678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* is the lock is currently blocked on behalf of
4688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		 * another node */
4698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
4708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_blocked_lock(lockres);
4728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto again;
4738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level > lockres->l_level) {
4760016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		local_flags = lkm_flags | DLM_LKF_VALBLK;
4770016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		if (lockres->l_level != DLM_LOCK_IV)
4780016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			local_flags |= DLM_LKF_CONVERT;
4798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_requested = level;
4818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags |= USER_LOCK_BUSY;
4828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
4838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4840016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		BUG_ON(level == DLM_LOCK_IV);
4850016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		BUG_ON(level == DLM_LOCK_NL);
4868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* call dlm_lock to upgrade lock now */
4880016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		status = ocfs2_dlm_lock(conn, level, &lockres->l_lksb,
4890016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker					local_flags, lockres->l_name,
4900016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker					lockres->l_namelen);
4910016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		if (status) {
4920016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			if ((lkm_flags & DLM_LKF_NOQUEUE) &&
4930016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			    (status != -EAGAIN))
4940016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker				user_log_dlm_error("ocfs2_dlm_lock",
4950016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker						   status, lockres);
4968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			user_recover_from_dlm_error(lockres);
4978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			goto bail;
4988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		}
4998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_busy_lock(lockres);
5018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto again;
5028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
5038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_dlm_inc_holders(lockres, level);
5058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = 0;
5088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehbail:
5098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return status;
5108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_dec_holders(struct user_lock_res *lockres,
5138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh					int level)
5148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	switch(level) {
5160016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	case DLM_LOCK_EX:
5178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG_ON(!lockres->l_ex_holders);
5188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ex_holders--;
5198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
5200016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	case DLM_LOCK_PR:
5218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG_ON(!lockres->l_ro_holders);
5228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ro_holders--;
5238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
5248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	default:
5258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
5268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
5278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_cluster_unlock(struct user_lock_res *lockres,
5308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			     int level)
5318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5320016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (level != DLM_LOCK_EX &&
5330016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	    level != DLM_LOCK_PR) {
534ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
535ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		     lockres->l_namelen, lockres->l_name);
5368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return;
5378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
5388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
5408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_dlm_dec_holders(lockres, level);
5418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	__user_dlm_cond_queue_lockres(lockres);
5428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_write_lvb(struct inode *inode,
5468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			const char *val,
5478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			unsigned int len)
5488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = &DLMFS_I(inode)->ip_lockres;
5500016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	char *lvb;
5518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(len > DLM_LVB_LEN);
5538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
5558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5560016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	BUG_ON(lockres->l_level < DLM_LOCK_EX);
5570016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
5588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memcpy(lvb, val, len);
5598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5630016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerssize_t user_dlm_read_lvb(struct inode *inode,
5640016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			  char *val,
5650016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker			  unsigned int len)
5668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = &DLMFS_I(inode)->ip_lockres;
5680016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	char *lvb;
5690016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	ssize_t ret = len;
5708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(len > DLM_LVB_LEN);
5728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
5748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5750016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	BUG_ON(lockres->l_level < DLM_LOCK_PR);
5760016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (ocfs2_dlm_lvb_valid(&lockres->l_lksb)) {
5770016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
5780016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		memcpy(val, lvb, len);
5790016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	} else
5800016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		ret = 0;
5818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5830016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	return ret;
5848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_lock_res_init(struct user_lock_res *lockres,
5878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			    struct dentry *dentry)
5888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memset(lockres, 0, sizeof(*lockres));
5908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock_init(&lockres->l_lock);
5928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	init_waitqueue_head(&lockres->l_event);
5930016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	lockres->l_level = DLM_LOCK_IV;
5940016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	lockres->l_requested = DLM_LOCK_IV;
5950016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	lockres->l_blocking = DLM_LOCK_IV;
5968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* should have been checked before getting here. */
5988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(dentry->d_name.len >= USER_DLM_LOCK_ID_MAX_LEN);
5998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memcpy(lockres->l_name,
6018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	       dentry->d_name.name,
6028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	       dentry->d_name.len);
603ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	lockres->l_namelen = dentry->d_name.len;
6048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
6058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehint user_dlm_destroy_lock(struct user_lock_res *lockres)
6078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
6088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int status = -EBUSY;
6090016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct ocfs2_cluster_connection *conn =
6100016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		cluster_connection_from_user_lockres(lockres);
6118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6126fcef3f04a1a0f8d7a086147d2f2e650c8cc2754Sunil Mushran	mlog(ML_BASTS, "lockres %.*s\n", lockres->l_namelen, lockres->l_name);
6138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
6152cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
6162cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh		spin_unlock(&lockres->l_lock);
6172cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh		return 0;
6182cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	}
6192cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh
6202cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	lockres->l_flags |= USER_LOCK_IN_TEARDOWN;
6212cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh
6228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	while (lockres->l_flags & USER_LOCK_BUSY) {
6238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
6248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_busy_lock(lockres);
6268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_lock(&lockres->l_lock);
6288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_ro_holders || lockres->l_ex_holders) {
6318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
6328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
6338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = 0;
6368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_ATTACHED)) {
6378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
6388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
6398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_ATTACHED;
6428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_BUSY;
6438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
6448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6450016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	status = ocfs2_dlm_unlock(conn, &lockres->l_lksb, DLM_LKF_VALBLK);
6460016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (status) {
6470016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		user_log_dlm_error("ocfs2_dlm_unlock", status, lockres);
6488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
6498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_wait_on_busy_lock(lockres);
6528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = 0;
6548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehbail:
6558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return status;
6568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
6578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6580016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstatic void user_dlm_recovery_handler_noop(int node_num,
6590016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker					   void *recovery_data)
6608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
6610016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	/* We ignore recovery events */
6620016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	return;
6630016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker}
6648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6650016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckervoid user_dlm_set_locking_protocol(void)
6660016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker{
6670016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	ocfs2_stack_glue_set_max_proto_version(&user_dlm_lproto.lp_max_version);
6680016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker}
6698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6700016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckerstruct ocfs2_cluster_connection *user_dlm_register(struct qstr *name)
6710016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker{
6720016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	int rc;
6730016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	struct ocfs2_cluster_connection *conn;
6748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
675cbe0e331fdbdb256943499358c75bc098a2134c1Joel Becker	rc = ocfs2_cluster_connect_agnostic(name->name, name->len,
676cbe0e331fdbdb256943499358c75bc098a2134c1Joel Becker					    &user_dlm_lproto,
677cbe0e331fdbdb256943499358c75bc098a2134c1Joel Becker					    user_dlm_recovery_handler_noop,
678cbe0e331fdbdb256943499358c75bc098a2134c1Joel Becker					    NULL, &conn);
6790016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	if (rc)
6800016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker		mlog_errno(rc);
6818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6820016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	return rc ? ERR_PTR(rc) : conn;
6838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
6848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6850016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Beckervoid user_dlm_unregister(struct ocfs2_cluster_connection *conn)
6868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
6870016eedc4185a3cd7e578b027a6e69001b85d6c4Joel Becker	ocfs2_cluster_disconnect(conn, 0);
6888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
689