userdlm.c revision ea5b3a187e2724fa9d08b2fbd3898c149ed95c6b
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
378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "cluster/nodemanager.h"
398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "cluster/heartbeat.h"
408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "cluster/tcp.h"
418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "dlmapi.h"
438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "userdlm.h"
458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#define MLOG_MASK_PREFIX ML_DLMFS
478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh#include "cluster/masklog.h"
488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline int user_check_wait_flag(struct user_lock_res *lockres,
508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				       int flag)
518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int ret;
538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	ret = lockres->l_flags & flag;
568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return ret;
598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_wait_on_busy_lock(struct user_lock_res *lockres)
628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wait_event(lockres->l_event,
658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		   !user_check_wait_flag(lockres, USER_LOCK_BUSY));
668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_wait_on_blocked_lock(struct user_lock_res *lockres)
698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wait_event(lockres->l_event,
728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		   !user_check_wait_flag(lockres, USER_LOCK_BLOCKED));
738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* I heart container_of... */
768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline struct dlm_ctxt *
778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehdlm_ctxt_from_user_lockres(struct user_lock_res *lockres)
788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlmfs_inode_private *ip;
808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	ip = container_of(lockres,
828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  struct dlmfs_inode_private,
838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  ip_lockres);
848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return ip->ip_dlm;
858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic struct inode *
888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehuser_dlm_inode_from_user_lockres(struct user_lock_res *lockres)
898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlmfs_inode_private *ip;
918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	ip = container_of(lockres,
938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  struct dlmfs_inode_private,
948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  ip_lockres);
958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return &ip->ip_vfs_inode;
968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_recover_from_dlm_error(struct user_lock_res *lockres)
998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
1018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_BUSY;
1028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
1038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
105ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh#define user_log_dlm_error(_func, _stat, _lockres) do {			\
106ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(ML_ERROR, "Dlm error \"%s\" while calling %s on "		\
107ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		"resource %.*s: %s\n", dlm_errname(_stat), _func,	\
108ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		_lockres->l_namelen, _lockres->l_name, dlm_errmsg(_stat)); \
1098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh} while (0)
1108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* WARNING: This function lives in a world where the only three lock
1128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * levels are EX, PR, and NL. It *will* have to be adjusted when more
1138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * lock types are added. */
1148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline int user_highest_compat_lock_level(int level)
1158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int new_level = LKM_EXMODE;
1178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level == LKM_EXMODE)
1198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		new_level = LKM_NLMODE;
1208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	else if (level == LKM_PRMODE)
1218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		new_level = LKM_PRMODE;
1228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return new_level;
1238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void user_ast(void *opaque)
1268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = opaque;
1288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlm_lockstatus *lksb;
1298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
130ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(0, "AST fired for lockres %.*s\n", lockres->l_namelen,
131ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     lockres->l_name);
1328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
1348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lksb = &(lockres->l_lksb);
1368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lksb->status != DLM_NORMAL) {
137ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		mlog(ML_ERROR, "lksb status value of %u on lockres %.*s\n",
138ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		     lksb->status, lockres->l_namelen, lockres->l_name);
1398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
1408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return;
1418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
1428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
143cc6eb725955efb026007e1d7da8fe5383981afd2Mark Fasheh	mlog_bug_on_msg(lockres->l_requested == LKM_IVMODE,
144ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			"Lockres %.*s, requested ivmode. flags 0x%x\n",
145ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			lockres->l_namelen, lockres->l_name, lockres->l_flags);
146cc6eb725955efb026007e1d7da8fe5383981afd2Mark Fasheh
1478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* we're downconverting. */
1488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_requested < lockres->l_level) {
1498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (lockres->l_requested <=
1508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		    user_highest_compat_lock_level(lockres->l_blocking)) {
1518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			lockres->l_blocking = LKM_NLMODE;
1528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			lockres->l_flags &= ~USER_LOCK_BLOCKED;
1538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		}
1548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
1558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_level = lockres->l_requested;
1578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_requested = LKM_IVMODE;
1588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_ATTACHED;
1598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_BUSY;
1608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
1628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wake_up(&lockres->l_event);
1648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_grab_inode_ref(struct user_lock_res *lockres)
1678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct inode *inode;
1698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	inode = user_dlm_inode_from_user_lockres(lockres);
1708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!igrab(inode))
1718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
1728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void user_dlm_unblock_lock(void *opaque);
1758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void __user_dlm_queue_lockres(struct user_lock_res *lockres)
1778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_QUEUED)) {
1798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_dlm_grab_inode_ref(lockres);
1808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		INIT_WORK(&lockres->l_work, user_dlm_unblock_lock,
1828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  lockres);
1838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		queue_work(user_dlm_worker, &lockres->l_work);
1858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags |= USER_LOCK_QUEUED;
1868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
1878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
1888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void __user_dlm_cond_queue_lockres(struct user_lock_res *lockres)
1908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
1918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int queue = 0;
1928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_BLOCKED))
1948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return;
1958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
1968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	switch (lockres->l_blocking) {
1978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	case LKM_EXMODE:
1988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (!lockres->l_ex_holders && !lockres->l_ro_holders)
1998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			queue = 1;
2008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
2018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	case LKM_PRMODE:
2028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (!lockres->l_ex_holders)
2038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			queue = 1;
2048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
2058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	default:
2068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
2078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
2088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (queue)
2108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		__user_dlm_queue_lockres(lockres);
2118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void user_bast(void *opaque, int level)
2148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = opaque;
2168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
217ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(0, "Blocking AST fired for lockres %.*s. Blocking level %d\n",
218ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     lockres->l_namelen, lockres->l_name, level);
2198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
2218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_BLOCKED;
2228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level > lockres->l_blocking)
2238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_blocking = level;
2248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	__user_dlm_queue_lockres(lockres);
2268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
2278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wake_up(&lockres->l_event);
2298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void user_unlock_ast(void *opaque, enum dlm_status status)
2328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = opaque;
2348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
235ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(0, "UNLOCK AST called on lock %.*s\n", lockres->l_namelen,
236ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     lockres->l_name);
2378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
238f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh	if (status != DLM_NORMAL && status != DLM_CANCELGRANT)
2398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		mlog(ML_ERROR, "Dlm returns status %d\n", status);
2408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
2422cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	/* The teardown flag gets set early during the unlock process,
2432cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	 * so test the cancel flag to make sure that this ast isn't
2442cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	 * for a concurrent cancel. */
2452cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN
2462cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	    && !(lockres->l_flags & USER_LOCK_IN_CANCEL)) {
2478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_level = LKM_IVMODE;
2482cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	} else if (status == DLM_CANCELGRANT) {
249f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		/* We tried to cancel a convert request, but it was
250f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		 * already granted. Don't clear the busy flag - the
251f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		 * ast should've done this already. */
252f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
253f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		lockres->l_flags &= ~USER_LOCK_IN_CANCEL;
254f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		goto out_noclear;
255f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh	} else {
256f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		BUG_ON(!(lockres->l_flags & USER_LOCK_IN_CANCEL));
257f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		/* Cancel succeeded, we want to re-queue */
2588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_requested = LKM_IVMODE; /* cancel an
2598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh						    * upconvert
2608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh						    * request. */
2618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags &= ~USER_LOCK_IN_CANCEL;
2628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* we want the unblock thread to look at it again
2638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		 * now. */
264f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		if (lockres->l_flags & USER_LOCK_BLOCKED)
265f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh			__user_dlm_queue_lockres(lockres);
2668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
2678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_BUSY;
269f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fashehout_noclear:
2708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
2718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	wake_up(&lockres->l_event);
2738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_drop_inode_ref(struct user_lock_res *lockres)
2768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct inode *inode;
2788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	inode = user_dlm_inode_from_user_lockres(lockres);
2798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	iput(inode);
2808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
2818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic void user_dlm_unblock_lock(void *opaque)
2838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
2848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int new_level, status;
2858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = (struct user_lock_res *) opaque;
2868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres);
2878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
288ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(0, "processing lockres %.*s\n", lockres->l_namelen,
289ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     lockres->l_name);
2908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
2928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2931f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	mlog_bug_on_msg(!(lockres->l_flags & USER_LOCK_QUEUED),
294ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			"Lockres %.*s, flags 0x%x\n",
295ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			lockres->l_namelen, lockres->l_name, lockres->l_flags);
2968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
2971f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	/* notice that we don't clear USER_LOCK_BLOCKED here. If it's
2981f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * set, we want user_ast clear it. */
2998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_QUEUED;
3008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3011f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	/* It's valid to get here and no longer be blocked - if we get
3021f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * several basts in a row, we might be queued by the first
3031f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * one, the unblock thread might run and clear the queued
3041f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * flag, and finally we might get another bast which re-queues
3051f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	 * us before our ast for the downconvert is called. */
3061f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_BLOCKED)) {
3071f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh		spin_unlock(&lockres->l_lock);
3081f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh		goto drop_ref;
3091f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh	}
3101f7bc828e30fe3e23ea0968b9595ad20e2785978Mark Fasheh
3118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
3128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_flags & USER_LOCK_BUSY) {
3178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (lockres->l_flags & USER_LOCK_IN_CANCEL) {
3188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			spin_unlock(&lockres->l_lock);
3198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			goto drop_ref;
3208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		}
3218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags |= USER_LOCK_IN_CANCEL;
3238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = dlmunlock(dlm,
3268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				   &lockres->l_lksb,
3278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				   LKM_CANCEL,
3288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				   user_unlock_ast,
3298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				   lockres);
330f43e6918c0e3906fd4483316f6a1a07bba615908Mark Fasheh		if (status != DLM_NORMAL)
3318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			user_log_dlm_error("dlmunlock", status, lockres);
3328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* If there are still incompat holders, we can exit safely
3368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * without worrying about re-queueing this lock as that will
3378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * happen on the last call to user_cluster_unlock. */
3388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if ((lockres->l_blocking == LKM_EXMODE)
3398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    && (lockres->l_ex_holders || lockres->l_ro_holders)) {
3408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		mlog(0, "can't downconvert for ex: ro = %u, ex = %u\n",
3428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			lockres->l_ro_holders, lockres->l_ex_holders);
3438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if ((lockres->l_blocking == LKM_PRMODE)
3478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    && lockres->l_ex_holders) {
3488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
3498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		mlog(0, "can't downconvert for pr: ex = %u\n",
3508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			lockres->l_ex_holders);
3518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto drop_ref;
3528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* yay, we can downconvert now. */
3558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	new_level = user_highest_compat_lock_level(lockres->l_blocking);
3568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_requested = new_level;
3578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_BUSY;
3588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	mlog(0, "Downconvert lock from %d to %d\n",
3598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_level, new_level);
3608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
3618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* need lock downconvert request now... */
3638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = dlmlock(dlm,
3648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 new_level,
3658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 &lockres->l_lksb,
3668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 LKM_CONVERT|LKM_VALBLK,
3678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 lockres->l_name,
368ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh			 lockres->l_namelen,
3698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 user_ast,
3708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 lockres,
3718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			 user_bast);
3728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (status != DLM_NORMAL) {
3738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_log_dlm_error("dlmlock", status, lockres);
3748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_recover_from_dlm_error(lockres);
3758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehdrop_ref:
3788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_dlm_drop_inode_ref(lockres);
3798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
3808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_inc_holders(struct user_lock_res *lockres,
3828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh					int level)
3838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
3848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	switch(level) {
3858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	case LKM_EXMODE:
3868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ex_holders++;
3878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
3888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	case LKM_PRMODE:
3898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ro_holders++;
3908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
3918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	default:
3928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
3938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
3948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
3958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
3968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh/* predict what lock level we'll be dropping down to on behalf
3978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * of another node, and return true if the currently wanted
3988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh * level will be compatible with it. */
3998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline int
4008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehuser_may_continue_on_blocked_lock(struct user_lock_res *lockres,
4018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				  int wanted)
4028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
4038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(!(lockres->l_flags & USER_LOCK_BLOCKED));
4048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return wanted <= user_highest_compat_lock_level(lockres->l_blocking);
4068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
4078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehint user_dlm_cluster_lock(struct user_lock_res *lockres,
4098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  int level,
4108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			  int lkm_flags)
4118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
4128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int status, local_flags;
4138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres);
4148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level != LKM_EXMODE &&
4168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    level != LKM_PRMODE) {
417ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
418ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		     lockres->l_namelen, lockres->l_name);
4198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = -EINVAL;
4208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
4218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
423ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(0, "lockres %.*s: asking for %s lock, passed flags = 0x%x\n",
424ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     lockres->l_namelen, lockres->l_name,
425ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     (level == LKM_EXMODE) ? "LKM_EXMODE" : "LKM_PRMODE",
426ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	     lkm_flags);
4278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehagain:
4298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (signal_pending(current)) {
4308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = -ERESTARTSYS;
4318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
4328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
4358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* We only compare against the currently granted level
4378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * here. If the lock is blocked waiting on a downconvert,
4388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	 * we'll get caught below. */
4398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if ((lockres->l_flags & USER_LOCK_BUSY) &&
4408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    (level > lockres->l_level)) {
4418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* is someone sitting in dlm_lock? If so, wait on
4428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		 * them. */
4438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
4448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_busy_lock(lockres);
4468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto again;
4478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if ((lockres->l_flags & USER_LOCK_BLOCKED) &&
4508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    (!user_may_continue_on_blocked_lock(lockres, level))) {
4518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* is the lock is currently blocked on behalf of
4528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		 * another node */
4538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
4548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_blocked_lock(lockres);
4568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto again;
4578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level > lockres->l_level) {
4608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		local_flags = lkm_flags | LKM_VALBLK;
4618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (lockres->l_level != LKM_IVMODE)
4628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			local_flags |= LKM_CONVERT;
4638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_requested = level;
4658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_flags |= USER_LOCK_BUSY;
4668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
4678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG_ON(level == LKM_IVMODE);
4698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG_ON(level == LKM_NLMODE);
4708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		/* call dlm_lock to upgrade lock now */
4728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = dlmlock(dlm,
4738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 level,
4748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 &lockres->l_lksb,
4758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 local_flags,
4768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 lockres->l_name,
477ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh				 lockres->l_namelen,
4788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 user_ast,
4798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 lockres,
4808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				 user_bast);
4818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		if (status != DLM_NORMAL) {
4828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			if ((lkm_flags & LKM_NOQUEUE) &&
4838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			    (status == DLM_NOTQUEUED))
4848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				status = -EAGAIN;
4858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			else {
4868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				user_log_dlm_error("dlmlock", status, lockres);
4878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh				status = -EINVAL;
4888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			}
4898df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			user_recover_from_dlm_error(lockres);
4908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			goto bail;
4918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		}
4928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_busy_lock(lockres);
4948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto again;
4958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
4968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
4978df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_dlm_inc_holders(lockres, level);
4988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
4998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5008df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = 0;
5018df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehbail:
5028df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return status;
5038df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5048df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5058df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstatic inline void user_dlm_dec_holders(struct user_lock_res *lockres,
5068df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh					int level)
5078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	switch(level) {
5098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	case LKM_EXMODE:
5108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG_ON(!lockres->l_ex_holders);
5118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ex_holders--;
5128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
5138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	case LKM_PRMODE:
5148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG_ON(!lockres->l_ro_holders);
5158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		lockres->l_ro_holders--;
5168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		break;
5178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	default:
5188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		BUG();
5198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
5208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_cluster_unlock(struct user_lock_res *lockres,
5238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			     int level)
5248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (level != LKM_EXMODE &&
5268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	    level != LKM_PRMODE) {
527ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		mlog(ML_ERROR, "lockres %.*s: invalid request!\n",
528ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh		     lockres->l_namelen, lockres->l_name);
5298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return;
5308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
5318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
5338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_dlm_dec_holders(lockres, level);
5348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	__user_dlm_cond_queue_lockres(lockres);
5358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_write_lvb(struct inode *inode,
5398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			const char *val,
5408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			unsigned int len)
5418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = &DLMFS_I(inode)->ip_lockres;
5438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	char *lvb = lockres->l_lksb.lvb;
5448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(len > DLM_LVB_LEN);
5468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
5488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(lockres->l_level < LKM_EXMODE);
5508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memcpy(lvb, val, len);
5518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5548df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_read_lvb(struct inode *inode,
5568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		       char *val,
5578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		       unsigned int len)
5588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct user_lock_res *lockres = &DLMFS_I(inode)->ip_lockres;
5608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	char *lvb = lockres->l_lksb.lvb;
5618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(len > DLM_LVB_LEN);
5638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
5658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(lockres->l_level < LKM_PRMODE);
5678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memcpy(val, lvb, len);
5688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
5708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_lock_res_init(struct user_lock_res *lockres,
5738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			    struct dentry *dentry)
5748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memset(lockres, 0, sizeof(*lockres));
5768df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5778df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock_init(&lockres->l_lock);
5788df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	init_waitqueue_head(&lockres->l_event);
5798df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_level = LKM_IVMODE;
5808df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_requested = LKM_IVMODE;
5818df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_blocking = LKM_IVMODE;
5828df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5838df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	/* should have been checked before getting here. */
5848df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	BUG_ON(dentry->d_name.len >= USER_DLM_LOCK_ID_MAX_LEN);
5858df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5868df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	memcpy(lockres->l_name,
5878df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	       dentry->d_name.name,
5888df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	       dentry->d_name.len);
589ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	lockres->l_namelen = dentry->d_name.len;
5908df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
5918df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5928df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehint user_dlm_destroy_lock(struct user_lock_res *lockres)
5938df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
5948df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	int status = -EBUSY;
5958df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlm_ctxt *dlm = dlm_ctxt_from_user_lockres(lockres);
5968df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
597ea5b3a187e2724fa9d08b2fbd3898c149ed95c6bMark Fasheh	mlog(0, "asked to destroy %.*s\n", lockres->l_namelen, lockres->l_name);
5988df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
5998df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_lock(&lockres->l_lock);
6002cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	if (lockres->l_flags & USER_LOCK_IN_TEARDOWN) {
6012cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh		spin_unlock(&lockres->l_lock);
6022cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh		return 0;
6032cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	}
6042cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh
6052cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh	lockres->l_flags |= USER_LOCK_IN_TEARDOWN;
6062cd9888590c52ac7592e3607d0a3174ccd57ef86Mark Fasheh
6078df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	while (lockres->l_flags & USER_LOCK_BUSY) {
6088df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
6098df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6108df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_wait_on_busy_lock(lockres);
6118df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6128df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_lock(&lockres->l_lock);
6138df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6148df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6158df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (lockres->l_ro_holders || lockres->l_ex_holders) {
6168df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
6178df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
6188df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6198df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6208df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = 0;
6218df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!(lockres->l_flags & USER_LOCK_ATTACHED)) {
6228df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		spin_unlock(&lockres->l_lock);
6238df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
6248df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6258df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6268df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags &= ~USER_LOCK_ATTACHED;
6278df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	lockres->l_flags |= USER_LOCK_BUSY;
6288df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	spin_unlock(&lockres->l_lock);
6298df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6308df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = dlmunlock(dlm,
6318df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			   &lockres->l_lksb,
6328df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			   LKM_VALBLK,
6338df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			   user_unlock_ast,
6348df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh			   lockres);
6358df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (status != DLM_NORMAL) {
6368df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		user_log_dlm_error("dlmunlock", status, lockres);
6378df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		status = -EINVAL;
6388df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		goto bail;
6398df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6408df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6418df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	user_wait_on_busy_lock(lockres);
6428df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6438df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	status = 0;
6448df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehbail:
6458df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return status;
6468df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
6478df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6488df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehstruct dlm_ctxt *user_dlm_register_context(struct qstr *name)
6498df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
6508df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	struct dlm_ctxt *dlm;
6518df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	u32 dlm_key;
6528df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	char *domain;
6538df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
654ad8100e0d20e0123def9f83c040b68c96c8638f0Kurt Hackel	domain = kmalloc(name->len + 1, GFP_NOFS);
6558df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (!domain) {
6568df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		mlog_errno(-ENOMEM);
6578df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		return ERR_PTR(-ENOMEM);
6588df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	}
6598df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6608df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	dlm_key = crc32_le(0, name->name, name->len);
6618df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6628df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	snprintf(domain, name->len + 1, "%.*s", name->len, name->name);
6638df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6648df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	dlm = dlm_register_domain(domain, dlm_key);
6658df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	if (IS_ERR(dlm))
6668df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh		mlog_errno(PTR_ERR(dlm));
6678df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6688df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	kfree(domain);
6698df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	return dlm;
6708df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
6718df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh
6728df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fashehvoid user_dlm_unregister_context(struct dlm_ctxt *dlm)
6738df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh{
6748df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh	dlm_unregister_domain(dlm);
6758df08c89c668e1bd922a053fdb5ba1fadbecbb38Mark Fasheh}
676