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