162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * dlmlock.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * underlying calls for lock creation
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2004 Oracle.  All rights reserved.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/fs.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/highmem.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/sysctl.h>
1862306a36Sopenharmony_ci#include <linux/random.h>
1962306a36Sopenharmony_ci#include <linux/blkdev.h>
2062306a36Sopenharmony_ci#include <linux/socket.h>
2162306a36Sopenharmony_ci#include <linux/inet.h>
2262306a36Sopenharmony_ci#include <linux/spinlock.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "../cluster/heartbeat.h"
2762306a36Sopenharmony_ci#include "../cluster/nodemanager.h"
2862306a36Sopenharmony_ci#include "../cluster/tcp.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "dlmapi.h"
3162306a36Sopenharmony_ci#include "dlmcommon.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "dlmconvert.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define MLOG_MASK_PREFIX ML_DLM
3662306a36Sopenharmony_ci#include "../cluster/masklog.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic struct kmem_cache *dlm_lock_cache;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(dlm_cookie_lock);
4162306a36Sopenharmony_cistatic u64 dlm_next_cookie = 1;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic enum dlm_status dlm_send_remote_lock_request(struct dlm_ctxt *dlm,
4462306a36Sopenharmony_ci					       struct dlm_lock_resource *res,
4562306a36Sopenharmony_ci					       struct dlm_lock *lock, int flags);
4662306a36Sopenharmony_cistatic void dlm_init_lock(struct dlm_lock *newlock, int type,
4762306a36Sopenharmony_ci			  u8 node, u64 cookie);
4862306a36Sopenharmony_cistatic void dlm_lock_release(struct kref *kref);
4962306a36Sopenharmony_cistatic void dlm_lock_detach_lockres(struct dlm_lock *lock);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciint dlm_init_lock_cache(void)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	dlm_lock_cache = kmem_cache_create("o2dlm_lock",
5462306a36Sopenharmony_ci					   sizeof(struct dlm_lock),
5562306a36Sopenharmony_ci					   0, SLAB_HWCACHE_ALIGN, NULL);
5662306a36Sopenharmony_ci	if (dlm_lock_cache == NULL)
5762306a36Sopenharmony_ci		return -ENOMEM;
5862306a36Sopenharmony_ci	return 0;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_civoid dlm_destroy_lock_cache(void)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	kmem_cache_destroy(dlm_lock_cache);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Tell us whether we can grant a new lock request.
6762306a36Sopenharmony_ci * locking:
6862306a36Sopenharmony_ci *   caller needs:  res->spinlock
6962306a36Sopenharmony_ci *   taken:         none
7062306a36Sopenharmony_ci *   held on exit:  none
7162306a36Sopenharmony_ci * returns: 1 if the lock can be granted, 0 otherwise.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic int dlm_can_grant_new_lock(struct dlm_lock_resource *res,
7462306a36Sopenharmony_ci				  struct dlm_lock *lock)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct dlm_lock *tmplock;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	list_for_each_entry(tmplock, &res->granted, list) {
7962306a36Sopenharmony_ci		if (!dlm_lock_compatible(tmplock->ml.type, lock->ml.type))
8062306a36Sopenharmony_ci			return 0;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	list_for_each_entry(tmplock, &res->converting, list) {
8462306a36Sopenharmony_ci		if (!dlm_lock_compatible(tmplock->ml.type, lock->ml.type))
8562306a36Sopenharmony_ci			return 0;
8662306a36Sopenharmony_ci		if (!dlm_lock_compatible(tmplock->ml.convert_type,
8762306a36Sopenharmony_ci					 lock->ml.type))
8862306a36Sopenharmony_ci			return 0;
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return 1;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* performs lock creation at the lockres master site
9562306a36Sopenharmony_ci * locking:
9662306a36Sopenharmony_ci *   caller needs:  none
9762306a36Sopenharmony_ci *   taken:         takes and drops res->spinlock
9862306a36Sopenharmony_ci *   held on exit:  none
9962306a36Sopenharmony_ci * returns: DLM_NORMAL, DLM_NOTQUEUED
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_cistatic enum dlm_status dlmlock_master(struct dlm_ctxt *dlm,
10262306a36Sopenharmony_ci				      struct dlm_lock_resource *res,
10362306a36Sopenharmony_ci				      struct dlm_lock *lock, int flags)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	int call_ast = 0, kick_thread = 0;
10662306a36Sopenharmony_ci	enum dlm_status status = DLM_NORMAL;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	mlog(0, "type=%d\n", lock->ml.type);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	spin_lock(&res->spinlock);
11162306a36Sopenharmony_ci	/* if called from dlm_create_lock_handler, need to
11262306a36Sopenharmony_ci	 * ensure it will not sleep in dlm_wait_on_lockres */
11362306a36Sopenharmony_ci	status = __dlm_lockres_state_to_status(res);
11462306a36Sopenharmony_ci	if (status != DLM_NORMAL &&
11562306a36Sopenharmony_ci	    lock->ml.node != dlm->node_num) {
11662306a36Sopenharmony_ci		/* erf.  state changed after lock was dropped. */
11762306a36Sopenharmony_ci		spin_unlock(&res->spinlock);
11862306a36Sopenharmony_ci		dlm_error(status);
11962306a36Sopenharmony_ci		return status;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci	__dlm_wait_on_lockres(res);
12262306a36Sopenharmony_ci	__dlm_lockres_reserve_ast(res);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (dlm_can_grant_new_lock(res, lock)) {
12562306a36Sopenharmony_ci		mlog(0, "I can grant this lock right away\n");
12662306a36Sopenharmony_ci		/* got it right away */
12762306a36Sopenharmony_ci		lock->lksb->status = DLM_NORMAL;
12862306a36Sopenharmony_ci		status = DLM_NORMAL;
12962306a36Sopenharmony_ci		dlm_lock_get(lock);
13062306a36Sopenharmony_ci		list_add_tail(&lock->list, &res->granted);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		/* for the recovery lock, we can't allow the ast
13362306a36Sopenharmony_ci		 * to be queued since the dlmthread is already
13462306a36Sopenharmony_ci		 * frozen.  but the recovery lock is always locked
13562306a36Sopenharmony_ci		 * with LKM_NOQUEUE so we do not need the ast in
13662306a36Sopenharmony_ci		 * this special case */
13762306a36Sopenharmony_ci		if (!dlm_is_recovery_lock(res->lockname.name,
13862306a36Sopenharmony_ci					  res->lockname.len)) {
13962306a36Sopenharmony_ci			kick_thread = 1;
14062306a36Sopenharmony_ci			call_ast = 1;
14162306a36Sopenharmony_ci		} else {
14262306a36Sopenharmony_ci			mlog(0, "%s: returning DLM_NORMAL to "
14362306a36Sopenharmony_ci			     "node %u for reco lock\n", dlm->name,
14462306a36Sopenharmony_ci			     lock->ml.node);
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci	} else {
14762306a36Sopenharmony_ci		/* for NOQUEUE request, unless we get the
14862306a36Sopenharmony_ci		 * lock right away, return DLM_NOTQUEUED */
14962306a36Sopenharmony_ci		if (flags & LKM_NOQUEUE) {
15062306a36Sopenharmony_ci			status = DLM_NOTQUEUED;
15162306a36Sopenharmony_ci			if (dlm_is_recovery_lock(res->lockname.name,
15262306a36Sopenharmony_ci						 res->lockname.len)) {
15362306a36Sopenharmony_ci				mlog(0, "%s: returning NOTQUEUED to "
15462306a36Sopenharmony_ci				     "node %u for reco lock\n", dlm->name,
15562306a36Sopenharmony_ci				     lock->ml.node);
15662306a36Sopenharmony_ci			}
15762306a36Sopenharmony_ci		} else {
15862306a36Sopenharmony_ci			status = DLM_NORMAL;
15962306a36Sopenharmony_ci			dlm_lock_get(lock);
16062306a36Sopenharmony_ci			list_add_tail(&lock->list, &res->blocked);
16162306a36Sopenharmony_ci			kick_thread = 1;
16262306a36Sopenharmony_ci		}
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	spin_unlock(&res->spinlock);
16662306a36Sopenharmony_ci	wake_up(&res->wq);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* either queue the ast or release it */
16962306a36Sopenharmony_ci	if (call_ast)
17062306a36Sopenharmony_ci		dlm_queue_ast(dlm, lock);
17162306a36Sopenharmony_ci	else
17262306a36Sopenharmony_ci		dlm_lockres_release_ast(dlm, res);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	dlm_lockres_calc_usage(dlm, res);
17562306a36Sopenharmony_ci	if (kick_thread)
17662306a36Sopenharmony_ci		dlm_kick_thread(dlm, res);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return status;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_civoid dlm_revert_pending_lock(struct dlm_lock_resource *res,
18262306a36Sopenharmony_ci			     struct dlm_lock *lock)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	/* remove from local queue if it failed */
18562306a36Sopenharmony_ci	list_del_init(&lock->list);
18662306a36Sopenharmony_ci	lock->lksb->flags &= ~DLM_LKSB_GET_LVB;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/*
19162306a36Sopenharmony_ci * locking:
19262306a36Sopenharmony_ci *   caller needs:  none
19362306a36Sopenharmony_ci *   taken:         takes and drops res->spinlock
19462306a36Sopenharmony_ci *   held on exit:  none
19562306a36Sopenharmony_ci * returns: DLM_DENIED, DLM_RECOVERING, or net status
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_cistatic enum dlm_status dlmlock_remote(struct dlm_ctxt *dlm,
19862306a36Sopenharmony_ci				      struct dlm_lock_resource *res,
19962306a36Sopenharmony_ci				      struct dlm_lock *lock, int flags)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	enum dlm_status status = DLM_DENIED;
20262306a36Sopenharmony_ci	int lockres_changed = 1;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	mlog(0, "type=%d, lockres %.*s, flags = 0x%x\n",
20562306a36Sopenharmony_ci	     lock->ml.type, res->lockname.len,
20662306a36Sopenharmony_ci	     res->lockname.name, flags);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/*
20962306a36Sopenharmony_ci	 * Wait if resource is getting recovered, remastered, etc.
21062306a36Sopenharmony_ci	 * If the resource was remastered and new owner is self, then exit.
21162306a36Sopenharmony_ci	 */
21262306a36Sopenharmony_ci	spin_lock(&res->spinlock);
21362306a36Sopenharmony_ci	__dlm_wait_on_lockres(res);
21462306a36Sopenharmony_ci	if (res->owner == dlm->node_num) {
21562306a36Sopenharmony_ci		spin_unlock(&res->spinlock);
21662306a36Sopenharmony_ci		return DLM_RECOVERING;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci	res->state |= DLM_LOCK_RES_IN_PROGRESS;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* add lock to local (secondary) queue */
22162306a36Sopenharmony_ci	dlm_lock_get(lock);
22262306a36Sopenharmony_ci	list_add_tail(&lock->list, &res->blocked);
22362306a36Sopenharmony_ci	lock->lock_pending = 1;
22462306a36Sopenharmony_ci	spin_unlock(&res->spinlock);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* spec seems to say that you will get DLM_NORMAL when the lock
22762306a36Sopenharmony_ci	 * has been queued, meaning we need to wait for a reply here. */
22862306a36Sopenharmony_ci	status = dlm_send_remote_lock_request(dlm, res, lock, flags);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	spin_lock(&res->spinlock);
23162306a36Sopenharmony_ci	res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
23262306a36Sopenharmony_ci	lock->lock_pending = 0;
23362306a36Sopenharmony_ci	if (status != DLM_NORMAL) {
23462306a36Sopenharmony_ci		if (status == DLM_RECOVERING &&
23562306a36Sopenharmony_ci		    dlm_is_recovery_lock(res->lockname.name,
23662306a36Sopenharmony_ci					 res->lockname.len)) {
23762306a36Sopenharmony_ci			/* recovery lock was mastered by dead node.
23862306a36Sopenharmony_ci			 * we need to have calc_usage shoot down this
23962306a36Sopenharmony_ci			 * lockres and completely remaster it. */
24062306a36Sopenharmony_ci			mlog(0, "%s: recovery lock was owned by "
24162306a36Sopenharmony_ci			     "dead node %u, remaster it now.\n",
24262306a36Sopenharmony_ci			     dlm->name, res->owner);
24362306a36Sopenharmony_ci		} else if (status != DLM_NOTQUEUED) {
24462306a36Sopenharmony_ci			/*
24562306a36Sopenharmony_ci			 * DO NOT call calc_usage, as this would unhash
24662306a36Sopenharmony_ci			 * the remote lockres before we ever get to use
24762306a36Sopenharmony_ci			 * it.  treat as if we never made any change to
24862306a36Sopenharmony_ci			 * the lockres.
24962306a36Sopenharmony_ci			 */
25062306a36Sopenharmony_ci			lockres_changed = 0;
25162306a36Sopenharmony_ci			dlm_error(status);
25262306a36Sopenharmony_ci		}
25362306a36Sopenharmony_ci		dlm_revert_pending_lock(res, lock);
25462306a36Sopenharmony_ci		dlm_lock_put(lock);
25562306a36Sopenharmony_ci	} else if (dlm_is_recovery_lock(res->lockname.name,
25662306a36Sopenharmony_ci					res->lockname.len)) {
25762306a36Sopenharmony_ci		/* special case for the $RECOVERY lock.
25862306a36Sopenharmony_ci		 * there will never be an AST delivered to put
25962306a36Sopenharmony_ci		 * this lock on the proper secondary queue
26062306a36Sopenharmony_ci		 * (granted), so do it manually. */
26162306a36Sopenharmony_ci		mlog(0, "%s: $RECOVERY lock for this node (%u) is "
26262306a36Sopenharmony_ci		     "mastered by %u; got lock, manually granting (no ast)\n",
26362306a36Sopenharmony_ci		     dlm->name, dlm->node_num, res->owner);
26462306a36Sopenharmony_ci		list_move_tail(&lock->list, &res->granted);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci	spin_unlock(&res->spinlock);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (lockres_changed)
26962306a36Sopenharmony_ci		dlm_lockres_calc_usage(dlm, res);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	wake_up(&res->wq);
27262306a36Sopenharmony_ci	return status;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/* for remote lock creation.
27762306a36Sopenharmony_ci * locking:
27862306a36Sopenharmony_ci *   caller needs:  none, but need res->state & DLM_LOCK_RES_IN_PROGRESS
27962306a36Sopenharmony_ci *   taken:         none
28062306a36Sopenharmony_ci *   held on exit:  none
28162306a36Sopenharmony_ci * returns: DLM_NOLOCKMGR, or net status
28262306a36Sopenharmony_ci */
28362306a36Sopenharmony_cistatic enum dlm_status dlm_send_remote_lock_request(struct dlm_ctxt *dlm,
28462306a36Sopenharmony_ci					       struct dlm_lock_resource *res,
28562306a36Sopenharmony_ci					       struct dlm_lock *lock, int flags)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct dlm_create_lock create;
28862306a36Sopenharmony_ci	int tmpret, status = 0;
28962306a36Sopenharmony_ci	enum dlm_status ret;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	memset(&create, 0, sizeof(create));
29262306a36Sopenharmony_ci	create.node_idx = dlm->node_num;
29362306a36Sopenharmony_ci	create.requested_type = lock->ml.type;
29462306a36Sopenharmony_ci	create.cookie = lock->ml.cookie;
29562306a36Sopenharmony_ci	create.namelen = res->lockname.len;
29662306a36Sopenharmony_ci	create.flags = cpu_to_be32(flags);
29762306a36Sopenharmony_ci	memcpy(create.name, res->lockname.name, create.namelen);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	tmpret = o2net_send_message(DLM_CREATE_LOCK_MSG, dlm->key, &create,
30062306a36Sopenharmony_ci				    sizeof(create), res->owner, &status);
30162306a36Sopenharmony_ci	if (tmpret >= 0) {
30262306a36Sopenharmony_ci		ret = status;
30362306a36Sopenharmony_ci		if (ret == DLM_REJECTED) {
30462306a36Sopenharmony_ci			mlog(ML_ERROR, "%s: res %.*s, Stale lockres no longer "
30562306a36Sopenharmony_ci			     "owned by node %u. That node is coming back up "
30662306a36Sopenharmony_ci			     "currently.\n", dlm->name, create.namelen,
30762306a36Sopenharmony_ci			     create.name, res->owner);
30862306a36Sopenharmony_ci			dlm_print_one_lock_resource(res);
30962306a36Sopenharmony_ci			BUG();
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci	} else {
31262306a36Sopenharmony_ci		mlog(ML_ERROR, "%s: res %.*s, Error %d send CREATE LOCK to "
31362306a36Sopenharmony_ci		     "node %u\n", dlm->name, create.namelen, create.name,
31462306a36Sopenharmony_ci		     tmpret, res->owner);
31562306a36Sopenharmony_ci		if (dlm_is_host_down(tmpret))
31662306a36Sopenharmony_ci			ret = DLM_RECOVERING;
31762306a36Sopenharmony_ci		else
31862306a36Sopenharmony_ci			ret = dlm_err_to_dlm_status(tmpret);
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return ret;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_civoid dlm_lock_get(struct dlm_lock *lock)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	kref_get(&lock->lock_refs);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_civoid dlm_lock_put(struct dlm_lock *lock)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	kref_put(&lock->lock_refs, dlm_lock_release);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void dlm_lock_release(struct kref *kref)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct dlm_lock *lock;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	lock = container_of(kref, struct dlm_lock, lock_refs);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	BUG_ON(!list_empty(&lock->list));
34162306a36Sopenharmony_ci	BUG_ON(!list_empty(&lock->ast_list));
34262306a36Sopenharmony_ci	BUG_ON(!list_empty(&lock->bast_list));
34362306a36Sopenharmony_ci	BUG_ON(lock->ast_pending);
34462306a36Sopenharmony_ci	BUG_ON(lock->bast_pending);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	dlm_lock_detach_lockres(lock);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (lock->lksb_kernel_allocated) {
34962306a36Sopenharmony_ci		mlog(0, "freeing kernel-allocated lksb\n");
35062306a36Sopenharmony_ci		kfree(lock->lksb);
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci	kmem_cache_free(dlm_lock_cache, lock);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci/* associate a lock with it's lockres, getting a ref on the lockres */
35662306a36Sopenharmony_civoid dlm_lock_attach_lockres(struct dlm_lock *lock,
35762306a36Sopenharmony_ci			     struct dlm_lock_resource *res)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	dlm_lockres_get(res);
36062306a36Sopenharmony_ci	lock->lockres = res;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/* drop ref on lockres, if there is still one associated with lock */
36462306a36Sopenharmony_cistatic void dlm_lock_detach_lockres(struct dlm_lock *lock)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct dlm_lock_resource *res;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	res = lock->lockres;
36962306a36Sopenharmony_ci	if (res) {
37062306a36Sopenharmony_ci		lock->lockres = NULL;
37162306a36Sopenharmony_ci		mlog(0, "removing lock's lockres reference\n");
37262306a36Sopenharmony_ci		dlm_lockres_put(res);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic void dlm_init_lock(struct dlm_lock *newlock, int type,
37762306a36Sopenharmony_ci			  u8 node, u64 cookie)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	INIT_LIST_HEAD(&newlock->list);
38062306a36Sopenharmony_ci	INIT_LIST_HEAD(&newlock->ast_list);
38162306a36Sopenharmony_ci	INIT_LIST_HEAD(&newlock->bast_list);
38262306a36Sopenharmony_ci	spin_lock_init(&newlock->spinlock);
38362306a36Sopenharmony_ci	newlock->ml.type = type;
38462306a36Sopenharmony_ci	newlock->ml.convert_type = LKM_IVMODE;
38562306a36Sopenharmony_ci	newlock->ml.highest_blocked = LKM_IVMODE;
38662306a36Sopenharmony_ci	newlock->ml.node = node;
38762306a36Sopenharmony_ci	newlock->ml.pad1 = 0;
38862306a36Sopenharmony_ci	newlock->ml.list = 0;
38962306a36Sopenharmony_ci	newlock->ml.flags = 0;
39062306a36Sopenharmony_ci	newlock->ast = NULL;
39162306a36Sopenharmony_ci	newlock->bast = NULL;
39262306a36Sopenharmony_ci	newlock->astdata = NULL;
39362306a36Sopenharmony_ci	newlock->ml.cookie = cpu_to_be64(cookie);
39462306a36Sopenharmony_ci	newlock->ast_pending = 0;
39562306a36Sopenharmony_ci	newlock->bast_pending = 0;
39662306a36Sopenharmony_ci	newlock->convert_pending = 0;
39762306a36Sopenharmony_ci	newlock->lock_pending = 0;
39862306a36Sopenharmony_ci	newlock->unlock_pending = 0;
39962306a36Sopenharmony_ci	newlock->cancel_pending = 0;
40062306a36Sopenharmony_ci	newlock->lksb_kernel_allocated = 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	kref_init(&newlock->lock_refs);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistruct dlm_lock * dlm_new_lock(int type, u8 node, u64 cookie,
40662306a36Sopenharmony_ci			       struct dlm_lockstatus *lksb)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct dlm_lock *lock;
40962306a36Sopenharmony_ci	int kernel_allocated = 0;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	lock = kmem_cache_zalloc(dlm_lock_cache, GFP_NOFS);
41262306a36Sopenharmony_ci	if (!lock)
41362306a36Sopenharmony_ci		return NULL;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (!lksb) {
41662306a36Sopenharmony_ci		/* zero memory only if kernel-allocated */
41762306a36Sopenharmony_ci		lksb = kzalloc(sizeof(*lksb), GFP_NOFS);
41862306a36Sopenharmony_ci		if (!lksb) {
41962306a36Sopenharmony_ci			kmem_cache_free(dlm_lock_cache, lock);
42062306a36Sopenharmony_ci			return NULL;
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci		kernel_allocated = 1;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	dlm_init_lock(lock, type, node, cookie);
42662306a36Sopenharmony_ci	if (kernel_allocated)
42762306a36Sopenharmony_ci		lock->lksb_kernel_allocated = 1;
42862306a36Sopenharmony_ci	lock->lksb = lksb;
42962306a36Sopenharmony_ci	lksb->lockid = lock;
43062306a36Sopenharmony_ci	return lock;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/* handler for lock creation net message
43462306a36Sopenharmony_ci * locking:
43562306a36Sopenharmony_ci *   caller needs:  none
43662306a36Sopenharmony_ci *   taken:         takes and drops res->spinlock
43762306a36Sopenharmony_ci *   held on exit:  none
43862306a36Sopenharmony_ci * returns: DLM_NORMAL, DLM_SYSERR, DLM_IVLOCKID, DLM_NOTQUEUED
43962306a36Sopenharmony_ci */
44062306a36Sopenharmony_ciint dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data,
44162306a36Sopenharmony_ci			    void **ret_data)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct dlm_ctxt *dlm = data;
44462306a36Sopenharmony_ci	struct dlm_create_lock *create = (struct dlm_create_lock *)msg->buf;
44562306a36Sopenharmony_ci	struct dlm_lock_resource *res = NULL;
44662306a36Sopenharmony_ci	struct dlm_lock *newlock = NULL;
44762306a36Sopenharmony_ci	struct dlm_lockstatus *lksb = NULL;
44862306a36Sopenharmony_ci	enum dlm_status status = DLM_NORMAL;
44962306a36Sopenharmony_ci	char *name;
45062306a36Sopenharmony_ci	unsigned int namelen;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	BUG_ON(!dlm);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (!dlm_grab(dlm))
45562306a36Sopenharmony_ci		return DLM_REJECTED;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	name = create->name;
45862306a36Sopenharmony_ci	namelen = create->namelen;
45962306a36Sopenharmony_ci	status = DLM_REJECTED;
46062306a36Sopenharmony_ci	if (!dlm_domain_fully_joined(dlm)) {
46162306a36Sopenharmony_ci		mlog(ML_ERROR, "Domain %s not fully joined, but node %u is "
46262306a36Sopenharmony_ci		     "sending a create_lock message for lock %.*s!\n",
46362306a36Sopenharmony_ci		     dlm->name, create->node_idx, namelen, name);
46462306a36Sopenharmony_ci		dlm_error(status);
46562306a36Sopenharmony_ci		goto leave;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	status = DLM_IVBUFLEN;
46962306a36Sopenharmony_ci	if (namelen > DLM_LOCKID_NAME_MAX) {
47062306a36Sopenharmony_ci		dlm_error(status);
47162306a36Sopenharmony_ci		goto leave;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	status = DLM_SYSERR;
47562306a36Sopenharmony_ci	newlock = dlm_new_lock(create->requested_type,
47662306a36Sopenharmony_ci			       create->node_idx,
47762306a36Sopenharmony_ci			       be64_to_cpu(create->cookie), NULL);
47862306a36Sopenharmony_ci	if (!newlock) {
47962306a36Sopenharmony_ci		dlm_error(status);
48062306a36Sopenharmony_ci		goto leave;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	lksb = newlock->lksb;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (be32_to_cpu(create->flags) & LKM_GET_LVB) {
48662306a36Sopenharmony_ci		lksb->flags |= DLM_LKSB_GET_LVB;
48762306a36Sopenharmony_ci		mlog(0, "set DLM_LKSB_GET_LVB flag\n");
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	status = DLM_IVLOCKID;
49162306a36Sopenharmony_ci	res = dlm_lookup_lockres(dlm, name, namelen);
49262306a36Sopenharmony_ci	if (!res) {
49362306a36Sopenharmony_ci		dlm_error(status);
49462306a36Sopenharmony_ci		goto leave;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	spin_lock(&res->spinlock);
49862306a36Sopenharmony_ci	status = __dlm_lockres_state_to_status(res);
49962306a36Sopenharmony_ci	spin_unlock(&res->spinlock);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (status != DLM_NORMAL) {
50262306a36Sopenharmony_ci		mlog(0, "lockres recovering/migrating/in-progress\n");
50362306a36Sopenharmony_ci		goto leave;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	dlm_lock_attach_lockres(newlock, res);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	status = dlmlock_master(dlm, res, newlock, be32_to_cpu(create->flags));
50962306a36Sopenharmony_cileave:
51062306a36Sopenharmony_ci	if (status != DLM_NORMAL)
51162306a36Sopenharmony_ci		if (newlock)
51262306a36Sopenharmony_ci			dlm_lock_put(newlock);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (res)
51562306a36Sopenharmony_ci		dlm_lockres_put(res);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	dlm_put(dlm);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return status;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci/* fetch next node-local (u8 nodenum + u56 cookie) into u64 */
52462306a36Sopenharmony_cistatic inline void dlm_get_next_cookie(u8 node_num, u64 *cookie)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	u64 tmpnode = node_num;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/* shift single byte of node num into top 8 bits */
52962306a36Sopenharmony_ci	tmpnode <<= 56;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	spin_lock(&dlm_cookie_lock);
53262306a36Sopenharmony_ci	*cookie = (dlm_next_cookie | tmpnode);
53362306a36Sopenharmony_ci	if (++dlm_next_cookie & 0xff00000000000000ull) {
53462306a36Sopenharmony_ci		mlog(0, "This node's cookie will now wrap!\n");
53562306a36Sopenharmony_ci		dlm_next_cookie = 1;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci	spin_unlock(&dlm_cookie_lock);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cienum dlm_status dlmlock(struct dlm_ctxt *dlm, int mode,
54162306a36Sopenharmony_ci			struct dlm_lockstatus *lksb, int flags,
54262306a36Sopenharmony_ci			const char *name, int namelen, dlm_astlockfunc_t *ast,
54362306a36Sopenharmony_ci			void *data, dlm_bastlockfunc_t *bast)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	enum dlm_status status;
54662306a36Sopenharmony_ci	struct dlm_lock_resource *res = NULL;
54762306a36Sopenharmony_ci	struct dlm_lock *lock = NULL;
54862306a36Sopenharmony_ci	int convert = 0, recovery = 0;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* yes this function is a mess.
55162306a36Sopenharmony_ci	 * TODO: clean this up.  lots of common code in the
55262306a36Sopenharmony_ci	 *       lock and convert paths, especially in the retry blocks */
55362306a36Sopenharmony_ci	if (!lksb) {
55462306a36Sopenharmony_ci		dlm_error(DLM_BADARGS);
55562306a36Sopenharmony_ci		return DLM_BADARGS;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	status = DLM_BADPARAM;
55962306a36Sopenharmony_ci	if (mode != LKM_EXMODE && mode != LKM_PRMODE && mode != LKM_NLMODE) {
56062306a36Sopenharmony_ci		dlm_error(status);
56162306a36Sopenharmony_ci		goto error;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (flags & ~LKM_VALID_FLAGS) {
56562306a36Sopenharmony_ci		dlm_error(status);
56662306a36Sopenharmony_ci		goto error;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	convert = (flags & LKM_CONVERT);
57062306a36Sopenharmony_ci	recovery = (flags & LKM_RECOVERY);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (recovery &&
57362306a36Sopenharmony_ci	    (!dlm_is_recovery_lock(name, namelen) || convert) ) {
57462306a36Sopenharmony_ci		dlm_error(status);
57562306a36Sopenharmony_ci		goto error;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	if (convert && (flags & LKM_LOCAL)) {
57862306a36Sopenharmony_ci		mlog(ML_ERROR, "strange LOCAL convert request!\n");
57962306a36Sopenharmony_ci		goto error;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (convert) {
58362306a36Sopenharmony_ci		/* CONVERT request */
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		/* if converting, must pass in a valid dlm_lock */
58662306a36Sopenharmony_ci		lock = lksb->lockid;
58762306a36Sopenharmony_ci		if (!lock) {
58862306a36Sopenharmony_ci			mlog(ML_ERROR, "NULL lock pointer in convert "
58962306a36Sopenharmony_ci			     "request\n");
59062306a36Sopenharmony_ci			goto error;
59162306a36Sopenharmony_ci		}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		res = lock->lockres;
59462306a36Sopenharmony_ci		if (!res) {
59562306a36Sopenharmony_ci			mlog(ML_ERROR, "NULL lockres pointer in convert "
59662306a36Sopenharmony_ci			     "request\n");
59762306a36Sopenharmony_ci			goto error;
59862306a36Sopenharmony_ci		}
59962306a36Sopenharmony_ci		dlm_lockres_get(res);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		/* XXX: for ocfs2 purposes, the ast/bast/astdata/lksb are
60262306a36Sopenharmony_ci	 	 * static after the original lock call.  convert requests will
60362306a36Sopenharmony_ci		 * ensure that everything is the same, or return DLM_BADARGS.
60462306a36Sopenharmony_ci	 	 * this means that DLM_DENIED_NOASTS will never be returned.
60562306a36Sopenharmony_ci	 	 */
60662306a36Sopenharmony_ci		if (lock->lksb != lksb || lock->ast != ast ||
60762306a36Sopenharmony_ci		    lock->bast != bast || lock->astdata != data) {
60862306a36Sopenharmony_ci			status = DLM_BADARGS;
60962306a36Sopenharmony_ci			mlog(ML_ERROR, "new args:  lksb=%p, ast=%p, bast=%p, "
61062306a36Sopenharmony_ci			     "astdata=%p\n", lksb, ast, bast, data);
61162306a36Sopenharmony_ci			mlog(ML_ERROR, "orig args: lksb=%p, ast=%p, bast=%p, "
61262306a36Sopenharmony_ci			     "astdata=%p\n", lock->lksb, lock->ast,
61362306a36Sopenharmony_ci			     lock->bast, lock->astdata);
61462306a36Sopenharmony_ci			goto error;
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ciretry_convert:
61762306a36Sopenharmony_ci		dlm_wait_for_recovery(dlm);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		if (res->owner == dlm->node_num)
62062306a36Sopenharmony_ci			status = dlmconvert_master(dlm, res, lock, flags, mode);
62162306a36Sopenharmony_ci		else
62262306a36Sopenharmony_ci			status = dlmconvert_remote(dlm, res, lock, flags, mode);
62362306a36Sopenharmony_ci		if (status == DLM_RECOVERING || status == DLM_MIGRATING ||
62462306a36Sopenharmony_ci		    status == DLM_FORWARD) {
62562306a36Sopenharmony_ci			/* for now, see how this works without sleeping
62662306a36Sopenharmony_ci			 * and just retry right away.  I suspect the reco
62762306a36Sopenharmony_ci			 * or migration will complete fast enough that
62862306a36Sopenharmony_ci			 * no waiting will be necessary */
62962306a36Sopenharmony_ci			mlog(0, "retrying convert with migration/recovery/"
63062306a36Sopenharmony_ci			     "in-progress\n");
63162306a36Sopenharmony_ci			msleep(100);
63262306a36Sopenharmony_ci			goto retry_convert;
63362306a36Sopenharmony_ci		}
63462306a36Sopenharmony_ci	} else {
63562306a36Sopenharmony_ci		u64 tmpcookie;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		/* LOCK request */
63862306a36Sopenharmony_ci		status = DLM_BADARGS;
63962306a36Sopenharmony_ci		if (!name) {
64062306a36Sopenharmony_ci			dlm_error(status);
64162306a36Sopenharmony_ci			goto error;
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci		status = DLM_IVBUFLEN;
64562306a36Sopenharmony_ci		if (namelen > DLM_LOCKID_NAME_MAX || namelen < 1) {
64662306a36Sopenharmony_ci			dlm_error(status);
64762306a36Sopenharmony_ci			goto error;
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		dlm_get_next_cookie(dlm->node_num, &tmpcookie);
65162306a36Sopenharmony_ci		lock = dlm_new_lock(mode, dlm->node_num, tmpcookie, lksb);
65262306a36Sopenharmony_ci		if (!lock) {
65362306a36Sopenharmony_ci			dlm_error(status);
65462306a36Sopenharmony_ci			goto error;
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		if (!recovery)
65862306a36Sopenharmony_ci			dlm_wait_for_recovery(dlm);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		/* find or create the lock resource */
66162306a36Sopenharmony_ci		res = dlm_get_lock_resource(dlm, name, namelen, flags);
66262306a36Sopenharmony_ci		if (!res) {
66362306a36Sopenharmony_ci			status = DLM_IVLOCKID;
66462306a36Sopenharmony_ci			dlm_error(status);
66562306a36Sopenharmony_ci			goto error;
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		mlog(0, "type=%d, flags = 0x%x\n", mode, flags);
66962306a36Sopenharmony_ci		mlog(0, "creating lock: lock=%p res=%p\n", lock, res);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		dlm_lock_attach_lockres(lock, res);
67262306a36Sopenharmony_ci		lock->ast = ast;
67362306a36Sopenharmony_ci		lock->bast = bast;
67462306a36Sopenharmony_ci		lock->astdata = data;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciretry_lock:
67762306a36Sopenharmony_ci		if (flags & LKM_VALBLK) {
67862306a36Sopenharmony_ci			mlog(0, "LKM_VALBLK passed by caller\n");
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci			/* LVB requests for non PR, PW or EX locks are
68162306a36Sopenharmony_ci			 * ignored. */
68262306a36Sopenharmony_ci			if (mode < LKM_PRMODE)
68362306a36Sopenharmony_ci				flags &= ~LKM_VALBLK;
68462306a36Sopenharmony_ci			else {
68562306a36Sopenharmony_ci				flags |= LKM_GET_LVB;
68662306a36Sopenharmony_ci				lock->lksb->flags |= DLM_LKSB_GET_LVB;
68762306a36Sopenharmony_ci			}
68862306a36Sopenharmony_ci		}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		if (res->owner == dlm->node_num)
69162306a36Sopenharmony_ci			status = dlmlock_master(dlm, res, lock, flags);
69262306a36Sopenharmony_ci		else
69362306a36Sopenharmony_ci			status = dlmlock_remote(dlm, res, lock, flags);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		if (status == DLM_RECOVERING || status == DLM_MIGRATING ||
69662306a36Sopenharmony_ci		    status == DLM_FORWARD) {
69762306a36Sopenharmony_ci			msleep(100);
69862306a36Sopenharmony_ci			if (recovery) {
69962306a36Sopenharmony_ci				if (status != DLM_RECOVERING)
70062306a36Sopenharmony_ci					goto retry_lock;
70162306a36Sopenharmony_ci				/* wait to see the node go down, then
70262306a36Sopenharmony_ci				 * drop down and allow the lockres to
70362306a36Sopenharmony_ci				 * get cleaned up.  need to remaster. */
70462306a36Sopenharmony_ci				dlm_wait_for_node_death(dlm, res->owner,
70562306a36Sopenharmony_ci						DLM_NODE_DEATH_WAIT_MAX);
70662306a36Sopenharmony_ci			} else {
70762306a36Sopenharmony_ci				dlm_wait_for_recovery(dlm);
70862306a36Sopenharmony_ci				goto retry_lock;
70962306a36Sopenharmony_ci			}
71062306a36Sopenharmony_ci		}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci		/* Inflight taken in dlm_get_lock_resource() is dropped here */
71362306a36Sopenharmony_ci		spin_lock(&res->spinlock);
71462306a36Sopenharmony_ci		dlm_lockres_drop_inflight_ref(dlm, res);
71562306a36Sopenharmony_ci		spin_unlock(&res->spinlock);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		dlm_lockres_calc_usage(dlm, res);
71862306a36Sopenharmony_ci		dlm_kick_thread(dlm, res);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		if (status != DLM_NORMAL) {
72162306a36Sopenharmony_ci			lock->lksb->flags &= ~DLM_LKSB_GET_LVB;
72262306a36Sopenharmony_ci			if (status != DLM_NOTQUEUED)
72362306a36Sopenharmony_ci				dlm_error(status);
72462306a36Sopenharmony_ci			goto error;
72562306a36Sopenharmony_ci		}
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cierror:
72962306a36Sopenharmony_ci	if (status != DLM_NORMAL) {
73062306a36Sopenharmony_ci		if (lock && !convert)
73162306a36Sopenharmony_ci			dlm_lock_put(lock);
73262306a36Sopenharmony_ci		// this is kind of unnecessary
73362306a36Sopenharmony_ci		lksb->status = status;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* put lockres ref from the convert path
73762306a36Sopenharmony_ci	 * or from dlm_get_lock_resource */
73862306a36Sopenharmony_ci	if (res)
73962306a36Sopenharmony_ci		dlm_lockres_put(res);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	return status;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dlmlock);
744