18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*- 38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * dlmdomain.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * defines domain join / leave apis 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2004 Oracle. All rights reserved. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/highmem.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 218c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "../cluster/heartbeat.h" 248c2ecf20Sopenharmony_ci#include "../cluster/nodemanager.h" 258c2ecf20Sopenharmony_ci#include "../cluster/tcp.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "dlmapi.h" 288c2ecf20Sopenharmony_ci#include "dlmcommon.h" 298c2ecf20Sopenharmony_ci#include "dlmdomain.h" 308c2ecf20Sopenharmony_ci#include "dlmdebug.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_DOMAIN) 338c2ecf20Sopenharmony_ci#include "../cluster/masklog.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * ocfs2 node maps are array of long int, which limits to send them freely 378c2ecf20Sopenharmony_ci * across the wire due to endianness issues. To workaround this, we convert 388c2ecf20Sopenharmony_ci * long ints to byte arrays. Following 3 routines are helper functions to 398c2ecf20Sopenharmony_ci * set/test/copy bits within those array of bytes 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic inline void byte_set_bit(u8 nr, u8 map[]) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci map[nr >> 3] |= (1UL << (nr & 7)); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline int byte_test_bit(u8 nr, u8 map[]) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci return ((1UL << (nr & 7)) & (map[nr >> 3])) != 0; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic inline void byte_copymap(u8 dmap[], unsigned long smap[], 528c2ecf20Sopenharmony_ci unsigned int sz) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned int nn; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (!sz) 578c2ecf20Sopenharmony_ci return; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci memset(dmap, 0, ((sz + 7) >> 3)); 608c2ecf20Sopenharmony_ci for (nn = 0 ; nn < sz; nn++) 618c2ecf20Sopenharmony_ci if (test_bit(nn, smap)) 628c2ecf20Sopenharmony_ci byte_set_bit(nn, dmap); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void dlm_free_pagevec(void **vec, int pages) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci while (pages--) 688c2ecf20Sopenharmony_ci free_page((unsigned long)vec[pages]); 698c2ecf20Sopenharmony_ci kfree(vec); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void **dlm_alloc_pagevec(int pages) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci void **vec = kmalloc_array(pages, sizeof(void *), GFP_KERNEL); 758c2ecf20Sopenharmony_ci int i; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (!vec) 788c2ecf20Sopenharmony_ci return NULL; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; i < pages; i++) 818c2ecf20Sopenharmony_ci if (!(vec[i] = (void *)__get_free_page(GFP_KERNEL))) 828c2ecf20Sopenharmony_ci goto out_free; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci mlog(0, "Allocated DLM hash pagevec; %d pages (%lu expected), %lu buckets per page\n", 858c2ecf20Sopenharmony_ci pages, (unsigned long)DLM_HASH_PAGES, 868c2ecf20Sopenharmony_ci (unsigned long)DLM_BUCKETS_PER_PAGE); 878c2ecf20Sopenharmony_ci return vec; 888c2ecf20Sopenharmony_ciout_free: 898c2ecf20Sopenharmony_ci dlm_free_pagevec(vec, i); 908c2ecf20Sopenharmony_ci return NULL; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * spinlock lock ordering: if multiple locks are needed, obey this ordering: 968c2ecf20Sopenharmony_ci * dlm_domain_lock 978c2ecf20Sopenharmony_ci * struct dlm_ctxt->spinlock 988c2ecf20Sopenharmony_ci * struct dlm_lock_resource->spinlock 998c2ecf20Sopenharmony_ci * struct dlm_ctxt->master_lock 1008c2ecf20Sopenharmony_ci * struct dlm_ctxt->ast_lock 1018c2ecf20Sopenharmony_ci * dlm_master_list_entry->spinlock 1028c2ecf20Sopenharmony_ci * dlm_lock->spinlock 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(dlm_domain_lock); 1078c2ecf20Sopenharmony_ciLIST_HEAD(dlm_domains); 1088c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * The supported protocol version for DLM communication. Running domains 1128c2ecf20Sopenharmony_ci * will have a negotiated version with the same major number and a minor 1138c2ecf20Sopenharmony_ci * number equal or smaller. The dlm_ctxt->dlm_locking_proto field should 1148c2ecf20Sopenharmony_ci * be used to determine what a running domain is actually using. 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * New in version 1.1: 1178c2ecf20Sopenharmony_ci * - Message DLM_QUERY_REGION added to support global heartbeat 1188c2ecf20Sopenharmony_ci * - Message DLM_QUERY_NODEINFO added to allow online node removes 1198c2ecf20Sopenharmony_ci * New in version 1.2: 1208c2ecf20Sopenharmony_ci * - Message DLM_BEGIN_EXIT_DOMAIN_MSG added to mark start of exit domain 1218c2ecf20Sopenharmony_ci * New in version 1.3: 1228c2ecf20Sopenharmony_ci * - Message DLM_DEREF_LOCKRES_DONE added to inform non-master that the 1238c2ecf20Sopenharmony_ci * refmap is cleared 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic const struct dlm_protocol_version dlm_protocol = { 1268c2ecf20Sopenharmony_ci .pv_major = 1, 1278c2ecf20Sopenharmony_ci .pv_minor = 3, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define DLM_DOMAIN_BACKOFF_MS 200 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, 1338c2ecf20Sopenharmony_ci void **ret_data); 1348c2ecf20Sopenharmony_cistatic int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, 1358c2ecf20Sopenharmony_ci void **ret_data); 1368c2ecf20Sopenharmony_cistatic int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, 1378c2ecf20Sopenharmony_ci void **ret_data); 1388c2ecf20Sopenharmony_cistatic int dlm_query_region_handler(struct o2net_msg *msg, u32 len, 1398c2ecf20Sopenharmony_ci void *data, void **ret_data); 1408c2ecf20Sopenharmony_cistatic int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, 1418c2ecf20Sopenharmony_ci void **ret_data); 1428c2ecf20Sopenharmony_cistatic int dlm_protocol_compare(struct dlm_protocol_version *existing, 1438c2ecf20Sopenharmony_ci struct dlm_protocol_version *request); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid __dlm_unhash_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci if (hlist_unhashed(&res->hash_node)) 1508c2ecf20Sopenharmony_ci return; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci mlog(0, "%s: Unhash res %.*s\n", dlm->name, res->lockname.len, 1538c2ecf20Sopenharmony_ci res->lockname.name); 1548c2ecf20Sopenharmony_ci hlist_del_init(&res->hash_node); 1558c2ecf20Sopenharmony_ci dlm_lockres_put(res); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_civoid __dlm_insert_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct hlist_head *bucket; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci assert_spin_locked(&dlm->spinlock); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci bucket = dlm_lockres_hash(dlm, res->lockname.hash); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* get a reference for our hashtable */ 1678c2ecf20Sopenharmony_ci dlm_lockres_get(res); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci hlist_add_head(&res->hash_node, bucket); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci mlog(0, "%s: Hash res %.*s\n", dlm->name, res->lockname.len, 1728c2ecf20Sopenharmony_ci res->lockname.name); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistruct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm, 1768c2ecf20Sopenharmony_ci const char *name, 1778c2ecf20Sopenharmony_ci unsigned int len, 1788c2ecf20Sopenharmony_ci unsigned int hash) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct hlist_head *bucket; 1818c2ecf20Sopenharmony_ci struct dlm_lock_resource *res; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci mlog(0, "%.*s\n", len, name); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci assert_spin_locked(&dlm->spinlock); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci bucket = dlm_lockres_hash(dlm, hash); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci hlist_for_each_entry(res, bucket, hash_node) { 1908c2ecf20Sopenharmony_ci if (res->lockname.name[0] != name[0]) 1918c2ecf20Sopenharmony_ci continue; 1928c2ecf20Sopenharmony_ci if (unlikely(res->lockname.len != len)) 1938c2ecf20Sopenharmony_ci continue; 1948c2ecf20Sopenharmony_ci if (memcmp(res->lockname.name + 1, name + 1, len - 1)) 1958c2ecf20Sopenharmony_ci continue; 1968c2ecf20Sopenharmony_ci dlm_lockres_get(res); 1978c2ecf20Sopenharmony_ci return res; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci return NULL; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* intended to be called by functions which do not care about lock 2038c2ecf20Sopenharmony_ci * resources which are being purged (most net _handler functions). 2048c2ecf20Sopenharmony_ci * this will return NULL for any lock resource which is found but 2058c2ecf20Sopenharmony_ci * currently in the process of dropping its mastery reference. 2068c2ecf20Sopenharmony_ci * use __dlm_lookup_lockres_full when you need the lock resource 2078c2ecf20Sopenharmony_ci * regardless (e.g. dlm_get_lock_resource) */ 2088c2ecf20Sopenharmony_cistruct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, 2098c2ecf20Sopenharmony_ci const char *name, 2108c2ecf20Sopenharmony_ci unsigned int len, 2118c2ecf20Sopenharmony_ci unsigned int hash) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct dlm_lock_resource *res = NULL; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci mlog(0, "%.*s\n", len, name); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci assert_spin_locked(&dlm->spinlock); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci res = __dlm_lookup_lockres_full(dlm, name, len, hash); 2208c2ecf20Sopenharmony_ci if (res) { 2218c2ecf20Sopenharmony_ci spin_lock(&res->spinlock); 2228c2ecf20Sopenharmony_ci if (res->state & DLM_LOCK_RES_DROPPING_REF) { 2238c2ecf20Sopenharmony_ci spin_unlock(&res->spinlock); 2248c2ecf20Sopenharmony_ci dlm_lockres_put(res); 2258c2ecf20Sopenharmony_ci return NULL; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci spin_unlock(&res->spinlock); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return res; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistruct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm, 2348c2ecf20Sopenharmony_ci const char *name, 2358c2ecf20Sopenharmony_ci unsigned int len) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct dlm_lock_resource *res; 2388c2ecf20Sopenharmony_ci unsigned int hash = dlm_lockid_hash(name, len); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 2418c2ecf20Sopenharmony_ci res = __dlm_lookup_lockres(dlm, name, len, hash); 2428c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 2438c2ecf20Sopenharmony_ci return res; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct dlm_ctxt * __dlm_lookup_domain_full(const char *domain, int len) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct dlm_ctxt *tmp; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci assert_spin_locked(&dlm_domain_lock); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* tmp->name here is always NULL terminated, 2538c2ecf20Sopenharmony_ci * but domain may not be! */ 2548c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &dlm_domains, list) { 2558c2ecf20Sopenharmony_ci if (strlen(tmp->name) == len && 2568c2ecf20Sopenharmony_ci memcmp(tmp->name, domain, len)==0) 2578c2ecf20Sopenharmony_ci return tmp; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return NULL; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* For null terminated domain strings ONLY */ 2648c2ecf20Sopenharmony_cistatic struct dlm_ctxt * __dlm_lookup_domain(const char *domain) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci assert_spin_locked(&dlm_domain_lock); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return __dlm_lookup_domain_full(domain, strlen(domain)); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* returns true on one of two conditions: 2738c2ecf20Sopenharmony_ci * 1) the domain does not exist 2748c2ecf20Sopenharmony_ci * 2) the domain exists and it's state is "joined" */ 2758c2ecf20Sopenharmony_cistatic int dlm_wait_on_domain_helper(const char *domain) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int ret = 0; 2788c2ecf20Sopenharmony_ci struct dlm_ctxt *tmp = NULL; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci tmp = __dlm_lookup_domain(domain); 2838c2ecf20Sopenharmony_ci if (!tmp) 2848c2ecf20Sopenharmony_ci ret = 1; 2858c2ecf20Sopenharmony_ci else if (tmp->dlm_state == DLM_CTXT_JOINED) 2868c2ecf20Sopenharmony_ci ret = 1; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void dlm_free_ctxt_mem(struct dlm_ctxt *dlm) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci dlm_destroy_debugfs_subroot(dlm); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (dlm->lockres_hash) 2978c2ecf20Sopenharmony_ci dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (dlm->master_hash) 3008c2ecf20Sopenharmony_ci dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci kfree(dlm->name); 3038c2ecf20Sopenharmony_ci kfree(dlm); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* A little strange - this function will be called while holding 3078c2ecf20Sopenharmony_ci * dlm_domain_lock and is expected to be holding it on the way out. We 3088c2ecf20Sopenharmony_ci * will however drop and reacquire it multiple times */ 3098c2ecf20Sopenharmony_cistatic void dlm_ctxt_release(struct kref *kref) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci dlm = container_of(kref, struct dlm_ctxt, dlm_refs); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci BUG_ON(dlm->num_joins); 3168c2ecf20Sopenharmony_ci BUG_ON(dlm->dlm_state == DLM_CTXT_JOINED); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* we may still be in the list if we hit an error during join. */ 3198c2ecf20Sopenharmony_ci list_del_init(&dlm->list); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci mlog(0, "freeing memory from domain %s\n", dlm->name); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci wake_up(&dlm_domain_events); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci dlm_free_ctxt_mem(dlm); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_civoid dlm_put(struct dlm_ctxt *dlm) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 3358c2ecf20Sopenharmony_ci kref_put(&dlm->dlm_refs, dlm_ctxt_release); 3368c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void __dlm_get(struct dlm_ctxt *dlm) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci kref_get(&dlm->dlm_refs); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* given a questionable reference to a dlm object, gets a reference if 3458c2ecf20Sopenharmony_ci * it can find it in the list, otherwise returns NULL in which case 3468c2ecf20Sopenharmony_ci * you shouldn't trust your pointer. */ 3478c2ecf20Sopenharmony_cistruct dlm_ctxt *dlm_grab(struct dlm_ctxt *dlm) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct dlm_ctxt *target; 3508c2ecf20Sopenharmony_ci struct dlm_ctxt *ret = NULL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci list_for_each_entry(target, &dlm_domains, list) { 3558c2ecf20Sopenharmony_ci if (target == dlm) { 3568c2ecf20Sopenharmony_ci __dlm_get(target); 3578c2ecf20Sopenharmony_ci ret = target; 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return ret; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciint dlm_domain_fully_joined(struct dlm_ctxt *dlm) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 3728c2ecf20Sopenharmony_ci ret = (dlm->dlm_state == DLM_CTXT_JOINED) || 3738c2ecf20Sopenharmony_ci (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN); 3748c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return ret; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void dlm_destroy_dlm_worker(struct dlm_ctxt *dlm) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci if (dlm->dlm_worker) { 3828c2ecf20Sopenharmony_ci destroy_workqueue(dlm->dlm_worker); 3838c2ecf20Sopenharmony_ci dlm->dlm_worker = NULL; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci dlm_unregister_domain_handlers(dlm); 3908c2ecf20Sopenharmony_ci dlm_complete_thread(dlm); 3918c2ecf20Sopenharmony_ci dlm_complete_recovery_thread(dlm); 3928c2ecf20Sopenharmony_ci dlm_destroy_dlm_worker(dlm); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* We've left the domain. Now we can take ourselves out of the 3958c2ecf20Sopenharmony_ci * list and allow the kref stuff to help us free the 3968c2ecf20Sopenharmony_ci * memory. */ 3978c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 3988c2ecf20Sopenharmony_ci list_del_init(&dlm->list); 3998c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Wake up anyone waiting for us to remove this domain */ 4028c2ecf20Sopenharmony_ci wake_up(&dlm_domain_events); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int dlm_migrate_all_locks(struct dlm_ctxt *dlm) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci int i, num, n, ret = 0; 4088c2ecf20Sopenharmony_ci struct dlm_lock_resource *res; 4098c2ecf20Sopenharmony_ci struct hlist_node *iter; 4108c2ecf20Sopenharmony_ci struct hlist_head *bucket; 4118c2ecf20Sopenharmony_ci int dropped; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci mlog(0, "Migrating locks from domain %s\n", dlm->name); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci num = 0; 4168c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 4178c2ecf20Sopenharmony_ci for (i = 0; i < DLM_HASH_BUCKETS; i++) { 4188c2ecf20Sopenharmony_ciredo_bucket: 4198c2ecf20Sopenharmony_ci n = 0; 4208c2ecf20Sopenharmony_ci bucket = dlm_lockres_hash(dlm, i); 4218c2ecf20Sopenharmony_ci iter = bucket->first; 4228c2ecf20Sopenharmony_ci while (iter) { 4238c2ecf20Sopenharmony_ci n++; 4248c2ecf20Sopenharmony_ci res = hlist_entry(iter, struct dlm_lock_resource, 4258c2ecf20Sopenharmony_ci hash_node); 4268c2ecf20Sopenharmony_ci dlm_lockres_get(res); 4278c2ecf20Sopenharmony_ci /* migrate, if necessary. this will drop the dlm 4288c2ecf20Sopenharmony_ci * spinlock and retake it if it does migration. */ 4298c2ecf20Sopenharmony_ci dropped = dlm_empty_lockres(dlm, res); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci spin_lock(&res->spinlock); 4328c2ecf20Sopenharmony_ci if (dropped) 4338c2ecf20Sopenharmony_ci __dlm_lockres_calc_usage(dlm, res); 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci iter = res->hash_node.next; 4368c2ecf20Sopenharmony_ci spin_unlock(&res->spinlock); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci dlm_lockres_put(res); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (dropped) { 4418c2ecf20Sopenharmony_ci cond_resched_lock(&dlm->spinlock); 4428c2ecf20Sopenharmony_ci goto redo_bucket; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci cond_resched_lock(&dlm->spinlock); 4468c2ecf20Sopenharmony_ci num += n; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (!num) { 4508c2ecf20Sopenharmony_ci if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { 4518c2ecf20Sopenharmony_ci mlog(0, "%s: perhaps there are more lock resources " 4528c2ecf20Sopenharmony_ci "need to be migrated after dlm recovery\n", dlm->name); 4538c2ecf20Sopenharmony_ci ret = -EAGAIN; 4548c2ecf20Sopenharmony_ci } else { 4558c2ecf20Sopenharmony_ci mlog(0, "%s: we won't do dlm recovery after migrating " 4568c2ecf20Sopenharmony_ci "all lock resources\n", dlm->name); 4578c2ecf20Sopenharmony_ci dlm->migrate_done = 1; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 4628c2ecf20Sopenharmony_ci wake_up(&dlm->dlm_thread_wq); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* let the dlm thread take care of purging, keep scanning until 4658c2ecf20Sopenharmony_ci * nothing remains in the hash */ 4668c2ecf20Sopenharmony_ci if (num) { 4678c2ecf20Sopenharmony_ci mlog(0, "%s: %d lock resources in hash last pass\n", 4688c2ecf20Sopenharmony_ci dlm->name, num); 4698c2ecf20Sopenharmony_ci ret = -EAGAIN; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci mlog(0, "DONE Migrating locks from domain %s\n", dlm->name); 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int dlm_no_joining_node(struct dlm_ctxt *dlm) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci int ret; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 4808c2ecf20Sopenharmony_ci ret = dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN; 4818c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return ret; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int dlm_begin_exit_domain_handler(struct o2net_msg *msg, u32 len, 4878c2ecf20Sopenharmony_ci void *data, void **ret_data) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = data; 4908c2ecf20Sopenharmony_ci unsigned int node; 4918c2ecf20Sopenharmony_ci struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (!dlm_grab(dlm)) 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci node = exit_msg->node_idx; 4978c2ecf20Sopenharmony_ci mlog(0, "%s: Node %u sent a begin exit domain message\n", dlm->name, node); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 5008c2ecf20Sopenharmony_ci set_bit(node, dlm->exit_domain_map); 5018c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci dlm_put(dlm); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic void dlm_mark_domain_leaving(struct dlm_ctxt *dlm) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci /* Yikes, a double spinlock! I need domain_lock for the dlm 5118c2ecf20Sopenharmony_ci * state and the dlm spinlock for join state... Sorry! */ 5128c2ecf20Sopenharmony_ciagain: 5138c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 5148c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { 5178c2ecf20Sopenharmony_ci mlog(0, "Node %d is joining, we wait on it.\n", 5188c2ecf20Sopenharmony_ci dlm->joining_node); 5198c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 5208c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci wait_event(dlm->dlm_join_events, dlm_no_joining_node(dlm)); 5238c2ecf20Sopenharmony_ci goto again; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci dlm->dlm_state = DLM_CTXT_LEAVING; 5278c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 5288c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic void __dlm_print_nodes(struct dlm_ctxt *dlm) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci int node = -1, num = 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci assert_spin_locked(&dlm->spinlock); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci printk("( "); 5388c2ecf20Sopenharmony_ci while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 5398c2ecf20Sopenharmony_ci node + 1)) < O2NM_MAX_NODES) { 5408c2ecf20Sopenharmony_ci printk("%d ", node); 5418c2ecf20Sopenharmony_ci ++num; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci printk(") %u nodes\n", num); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, 5478c2ecf20Sopenharmony_ci void **ret_data) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = data; 5508c2ecf20Sopenharmony_ci unsigned int node; 5518c2ecf20Sopenharmony_ci struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci mlog(0, "%p %u %p", msg, len, data); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (!dlm_grab(dlm)) 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci node = exit_msg->node_idx; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 5618c2ecf20Sopenharmony_ci clear_bit(node, dlm->domain_map); 5628c2ecf20Sopenharmony_ci clear_bit(node, dlm->exit_domain_map); 5638c2ecf20Sopenharmony_ci printk(KERN_NOTICE "o2dlm: Node %u leaves domain %s ", node, dlm->name); 5648c2ecf20Sopenharmony_ci __dlm_print_nodes(dlm); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* notify anything attached to the heartbeat events */ 5678c2ecf20Sopenharmony_ci dlm_hb_event_notify_attached(dlm, node, 0); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci dlm_put(dlm); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int dlm_send_one_domain_exit(struct dlm_ctxt *dlm, u32 msg_type, 5778c2ecf20Sopenharmony_ci unsigned int node) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci int status; 5808c2ecf20Sopenharmony_ci struct dlm_exit_domain leave_msg; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci mlog(0, "%s: Sending domain exit message %u to node %u\n", dlm->name, 5838c2ecf20Sopenharmony_ci msg_type, node); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci memset(&leave_msg, 0, sizeof(leave_msg)); 5868c2ecf20Sopenharmony_ci leave_msg.node_idx = dlm->node_num; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci status = o2net_send_message(msg_type, dlm->key, &leave_msg, 5898c2ecf20Sopenharmony_ci sizeof(leave_msg), node, NULL); 5908c2ecf20Sopenharmony_ci if (status < 0) 5918c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Error %d sending domain exit message %u " 5928c2ecf20Sopenharmony_ci "to node %u on domain %s\n", status, msg_type, node, 5938c2ecf20Sopenharmony_ci dlm->name); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return status; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic void dlm_begin_exit_domain(struct dlm_ctxt *dlm) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci int node = -1; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Support for begin exit domain was added in 1.2 */ 6038c2ecf20Sopenharmony_ci if (dlm->dlm_locking_proto.pv_major == 1 && 6048c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor < 2) 6058c2ecf20Sopenharmony_ci return; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* 6088c2ecf20Sopenharmony_ci * Unlike DLM_EXIT_DOMAIN_MSG, DLM_BEGIN_EXIT_DOMAIN_MSG is purely 6098c2ecf20Sopenharmony_ci * informational. Meaning if a node does not receive the message, 6108c2ecf20Sopenharmony_ci * so be it. 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 6138c2ecf20Sopenharmony_ci while (1) { 6148c2ecf20Sopenharmony_ci node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, node + 1); 6158c2ecf20Sopenharmony_ci if (node >= O2NM_MAX_NODES) 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci if (node == dlm->node_num) 6188c2ecf20Sopenharmony_ci continue; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 6218c2ecf20Sopenharmony_ci dlm_send_one_domain_exit(dlm, DLM_BEGIN_EXIT_DOMAIN_MSG, node); 6228c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic void dlm_leave_domain(struct dlm_ctxt *dlm) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci int node, clear_node, status; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* At this point we've migrated away all our locks and won't 6328c2ecf20Sopenharmony_ci * accept mastership of new ones. The dlm is responsible for 6338c2ecf20Sopenharmony_ci * almost nothing now. We make sure not to confuse any joining 6348c2ecf20Sopenharmony_ci * nodes and then commence shutdown procedure. */ 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 6378c2ecf20Sopenharmony_ci /* Clear ourselves from the domain map */ 6388c2ecf20Sopenharmony_ci clear_bit(dlm->node_num, dlm->domain_map); 6398c2ecf20Sopenharmony_ci while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 6408c2ecf20Sopenharmony_ci 0)) < O2NM_MAX_NODES) { 6418c2ecf20Sopenharmony_ci /* Drop the dlm spinlock. This is safe wrt the domain_map. 6428c2ecf20Sopenharmony_ci * -nodes cannot be added now as the 6438c2ecf20Sopenharmony_ci * query_join_handlers knows to respond with OK_NO_MAP 6448c2ecf20Sopenharmony_ci * -we catch the right network errors if a node is 6458c2ecf20Sopenharmony_ci * removed from the map while we're sending him the 6468c2ecf20Sopenharmony_ci * exit message. */ 6478c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci clear_node = 1; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci status = dlm_send_one_domain_exit(dlm, DLM_EXIT_DOMAIN_MSG, 6528c2ecf20Sopenharmony_ci node); 6538c2ecf20Sopenharmony_ci if (status < 0 && 6548c2ecf20Sopenharmony_ci status != -ENOPROTOOPT && 6558c2ecf20Sopenharmony_ci status != -ENOTCONN) { 6568c2ecf20Sopenharmony_ci mlog(ML_NOTICE, "Error %d sending domain exit message " 6578c2ecf20Sopenharmony_ci "to node %d\n", status, node); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Not sure what to do here but lets sleep for 6608c2ecf20Sopenharmony_ci * a bit in case this was a transient 6618c2ecf20Sopenharmony_ci * error... */ 6628c2ecf20Sopenharmony_ci msleep(DLM_DOMAIN_BACKOFF_MS); 6638c2ecf20Sopenharmony_ci clear_node = 0; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 6678c2ecf20Sopenharmony_ci /* If we're not clearing the node bit then we intend 6688c2ecf20Sopenharmony_ci * to loop back around to try again. */ 6698c2ecf20Sopenharmony_ci if (clear_node) 6708c2ecf20Sopenharmony_ci clear_bit(node, dlm->domain_map); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_civoid dlm_unregister_domain(struct dlm_ctxt *dlm) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci int leave = 0; 6788c2ecf20Sopenharmony_ci struct dlm_lock_resource *res; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 6818c2ecf20Sopenharmony_ci BUG_ON(dlm->dlm_state != DLM_CTXT_JOINED); 6828c2ecf20Sopenharmony_ci BUG_ON(!dlm->num_joins); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci dlm->num_joins--; 6858c2ecf20Sopenharmony_ci if (!dlm->num_joins) { 6868c2ecf20Sopenharmony_ci /* We mark it "in shutdown" now so new register 6878c2ecf20Sopenharmony_ci * requests wait until we've completely left the 6888c2ecf20Sopenharmony_ci * domain. Don't use DLM_CTXT_LEAVING yet as we still 6898c2ecf20Sopenharmony_ci * want new domain joins to communicate with us at 6908c2ecf20Sopenharmony_ci * least until we've completed migration of our 6918c2ecf20Sopenharmony_ci * resources. */ 6928c2ecf20Sopenharmony_ci dlm->dlm_state = DLM_CTXT_IN_SHUTDOWN; 6938c2ecf20Sopenharmony_ci leave = 1; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (leave) { 6988c2ecf20Sopenharmony_ci mlog(0, "shutting down domain %s\n", dlm->name); 6998c2ecf20Sopenharmony_ci dlm_begin_exit_domain(dlm); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* We changed dlm state, notify the thread */ 7028c2ecf20Sopenharmony_ci dlm_kick_thread(dlm, NULL); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci while (dlm_migrate_all_locks(dlm)) { 7058c2ecf20Sopenharmony_ci /* Give dlm_thread time to purge the lockres' */ 7068c2ecf20Sopenharmony_ci msleep(500); 7078c2ecf20Sopenharmony_ci mlog(0, "%s: more migration to do\n", dlm->name); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* This list should be empty. If not, print remaining lockres */ 7118c2ecf20Sopenharmony_ci if (!list_empty(&dlm->tracking_list)) { 7128c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Following lockres' are still on the " 7138c2ecf20Sopenharmony_ci "tracking list:\n"); 7148c2ecf20Sopenharmony_ci list_for_each_entry(res, &dlm->tracking_list, tracking) 7158c2ecf20Sopenharmony_ci dlm_print_one_lock_resource(res); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci dlm_mark_domain_leaving(dlm); 7198c2ecf20Sopenharmony_ci dlm_leave_domain(dlm); 7208c2ecf20Sopenharmony_ci printk(KERN_NOTICE "o2dlm: Leaving domain %s\n", dlm->name); 7218c2ecf20Sopenharmony_ci dlm_force_free_mles(dlm); 7228c2ecf20Sopenharmony_ci dlm_complete_dlm_shutdown(dlm); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci dlm_put(dlm); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dlm_unregister_domain); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int dlm_query_join_proto_check(char *proto_type, int node, 7298c2ecf20Sopenharmony_ci struct dlm_protocol_version *ours, 7308c2ecf20Sopenharmony_ci struct dlm_protocol_version *request) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci int rc; 7338c2ecf20Sopenharmony_ci struct dlm_protocol_version proto = *request; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (!dlm_protocol_compare(ours, &proto)) { 7368c2ecf20Sopenharmony_ci mlog(0, 7378c2ecf20Sopenharmony_ci "node %u wanted to join with %s locking protocol " 7388c2ecf20Sopenharmony_ci "%u.%u, we respond with %u.%u\n", 7398c2ecf20Sopenharmony_ci node, proto_type, 7408c2ecf20Sopenharmony_ci request->pv_major, 7418c2ecf20Sopenharmony_ci request->pv_minor, 7428c2ecf20Sopenharmony_ci proto.pv_major, proto.pv_minor); 7438c2ecf20Sopenharmony_ci request->pv_minor = proto.pv_minor; 7448c2ecf20Sopenharmony_ci rc = 0; 7458c2ecf20Sopenharmony_ci } else { 7468c2ecf20Sopenharmony_ci mlog(ML_NOTICE, 7478c2ecf20Sopenharmony_ci "Node %u wanted to join with %s locking " 7488c2ecf20Sopenharmony_ci "protocol %u.%u, but we have %u.%u, disallowing\n", 7498c2ecf20Sopenharmony_ci node, proto_type, 7508c2ecf20Sopenharmony_ci request->pv_major, 7518c2ecf20Sopenharmony_ci request->pv_minor, 7528c2ecf20Sopenharmony_ci ours->pv_major, 7538c2ecf20Sopenharmony_ci ours->pv_minor); 7548c2ecf20Sopenharmony_ci rc = 1; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci return rc; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci/* 7618c2ecf20Sopenharmony_ci * struct dlm_query_join_packet is made up of four one-byte fields. They 7628c2ecf20Sopenharmony_ci * are effectively in big-endian order already. However, little-endian 7638c2ecf20Sopenharmony_ci * machines swap them before putting the packet on the wire (because 7648c2ecf20Sopenharmony_ci * query_join's response is a status, and that status is treated as a u32 7658c2ecf20Sopenharmony_ci * on the wire). Thus, a big-endian and little-endian machines will treat 7668c2ecf20Sopenharmony_ci * this structure differently. 7678c2ecf20Sopenharmony_ci * 7688c2ecf20Sopenharmony_ci * The solution is to have little-endian machines swap the structure when 7698c2ecf20Sopenharmony_ci * converting from the structure to the u32 representation. This will 7708c2ecf20Sopenharmony_ci * result in the structure having the correct format on the wire no matter 7718c2ecf20Sopenharmony_ci * the host endian format. 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_cistatic void dlm_query_join_packet_to_wire(struct dlm_query_join_packet *packet, 7748c2ecf20Sopenharmony_ci u32 *wire) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci union dlm_query_join_response response; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci response.packet = *packet; 7798c2ecf20Sopenharmony_ci *wire = be32_to_cpu(response.intval); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic void dlm_query_join_wire_to_packet(u32 wire, 7838c2ecf20Sopenharmony_ci struct dlm_query_join_packet *packet) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci union dlm_query_join_response response; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci response.intval = cpu_to_be32(wire); 7888c2ecf20Sopenharmony_ci *packet = response.packet; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, 7928c2ecf20Sopenharmony_ci void **ret_data) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct dlm_query_join_request *query; 7958c2ecf20Sopenharmony_ci struct dlm_query_join_packet packet = { 7968c2ecf20Sopenharmony_ci .code = JOIN_DISALLOW, 7978c2ecf20Sopenharmony_ci }; 7988c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 7998c2ecf20Sopenharmony_ci u32 response; 8008c2ecf20Sopenharmony_ci u8 nodenum; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci query = (struct dlm_query_join_request *) msg->buf; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci mlog(0, "node %u wants to join domain %s\n", query->node_idx, 8058c2ecf20Sopenharmony_ci query->domain); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* 8088c2ecf20Sopenharmony_ci * If heartbeat doesn't consider the node live, tell it 8098c2ecf20Sopenharmony_ci * to back off and try again. This gives heartbeat a chance 8108c2ecf20Sopenharmony_ci * to catch up. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci if (!o2hb_check_node_heartbeating_no_sem(query->node_idx)) { 8138c2ecf20Sopenharmony_ci mlog(0, "node %u is not in our live map yet\n", 8148c2ecf20Sopenharmony_ci query->node_idx); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci packet.code = JOIN_DISALLOW; 8178c2ecf20Sopenharmony_ci goto respond; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci packet.code = JOIN_OK_NO_MAP; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 8238c2ecf20Sopenharmony_ci dlm = __dlm_lookup_domain_full(query->domain, query->name_len); 8248c2ecf20Sopenharmony_ci if (!dlm) 8258c2ecf20Sopenharmony_ci goto unlock_respond; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* 8288c2ecf20Sopenharmony_ci * There is a small window where the joining node may not see the 8298c2ecf20Sopenharmony_ci * node(s) that just left but still part of the cluster. DISALLOW 8308c2ecf20Sopenharmony_ci * join request if joining node has different node map. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_ci nodenum=0; 8338c2ecf20Sopenharmony_ci while (nodenum < O2NM_MAX_NODES) { 8348c2ecf20Sopenharmony_ci if (test_bit(nodenum, dlm->domain_map)) { 8358c2ecf20Sopenharmony_ci if (!byte_test_bit(nodenum, query->node_map)) { 8368c2ecf20Sopenharmony_ci mlog(0, "disallow join as node %u does not " 8378c2ecf20Sopenharmony_ci "have node %u in its nodemap\n", 8388c2ecf20Sopenharmony_ci query->node_idx, nodenum); 8398c2ecf20Sopenharmony_ci packet.code = JOIN_DISALLOW; 8408c2ecf20Sopenharmony_ci goto unlock_respond; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci nodenum++; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* Once the dlm ctxt is marked as leaving then we don't want 8478c2ecf20Sopenharmony_ci * to be put in someone's domain map. 8488c2ecf20Sopenharmony_ci * Also, explicitly disallow joining at certain troublesome 8498c2ecf20Sopenharmony_ci * times (ie. during recovery). */ 8508c2ecf20Sopenharmony_ci if (dlm->dlm_state != DLM_CTXT_LEAVING) { 8518c2ecf20Sopenharmony_ci int bit = query->node_idx; 8528c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (dlm->dlm_state == DLM_CTXT_NEW && 8558c2ecf20Sopenharmony_ci dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN) { 8568c2ecf20Sopenharmony_ci /*If this is a brand new context and we 8578c2ecf20Sopenharmony_ci * haven't started our join process yet, then 8588c2ecf20Sopenharmony_ci * the other node won the race. */ 8598c2ecf20Sopenharmony_ci packet.code = JOIN_OK_NO_MAP; 8608c2ecf20Sopenharmony_ci } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { 8618c2ecf20Sopenharmony_ci /* Disallow parallel joins. */ 8628c2ecf20Sopenharmony_ci packet.code = JOIN_DISALLOW; 8638c2ecf20Sopenharmony_ci } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { 8648c2ecf20Sopenharmony_ci mlog(0, "node %u trying to join, but recovery " 8658c2ecf20Sopenharmony_ci "is ongoing.\n", bit); 8668c2ecf20Sopenharmony_ci packet.code = JOIN_DISALLOW; 8678c2ecf20Sopenharmony_ci } else if (test_bit(bit, dlm->recovery_map)) { 8688c2ecf20Sopenharmony_ci mlog(0, "node %u trying to join, but it " 8698c2ecf20Sopenharmony_ci "still needs recovery.\n", bit); 8708c2ecf20Sopenharmony_ci packet.code = JOIN_DISALLOW; 8718c2ecf20Sopenharmony_ci } else if (test_bit(bit, dlm->domain_map)) { 8728c2ecf20Sopenharmony_ci mlog(0, "node %u trying to join, but it " 8738c2ecf20Sopenharmony_ci "is still in the domain! needs recovery?\n", 8748c2ecf20Sopenharmony_ci bit); 8758c2ecf20Sopenharmony_ci packet.code = JOIN_DISALLOW; 8768c2ecf20Sopenharmony_ci } else { 8778c2ecf20Sopenharmony_ci /* Alright we're fully a part of this domain 8788c2ecf20Sopenharmony_ci * so we keep some state as to who's joining 8798c2ecf20Sopenharmony_ci * and indicate to him that needs to be fixed 8808c2ecf20Sopenharmony_ci * up. */ 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Make sure we speak compatible locking protocols. */ 8838c2ecf20Sopenharmony_ci if (dlm_query_join_proto_check("DLM", bit, 8848c2ecf20Sopenharmony_ci &dlm->dlm_locking_proto, 8858c2ecf20Sopenharmony_ci &query->dlm_proto)) { 8868c2ecf20Sopenharmony_ci packet.code = JOIN_PROTOCOL_MISMATCH; 8878c2ecf20Sopenharmony_ci } else if (dlm_query_join_proto_check("fs", bit, 8888c2ecf20Sopenharmony_ci &dlm->fs_locking_proto, 8898c2ecf20Sopenharmony_ci &query->fs_proto)) { 8908c2ecf20Sopenharmony_ci packet.code = JOIN_PROTOCOL_MISMATCH; 8918c2ecf20Sopenharmony_ci } else { 8928c2ecf20Sopenharmony_ci packet.dlm_minor = query->dlm_proto.pv_minor; 8938c2ecf20Sopenharmony_ci packet.fs_minor = query->fs_proto.pv_minor; 8948c2ecf20Sopenharmony_ci packet.code = JOIN_OK; 8958c2ecf20Sopenharmony_ci __dlm_set_joining_node(dlm, query->node_idx); 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ciunlock_respond: 9028c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cirespond: 9058c2ecf20Sopenharmony_ci mlog(0, "We respond with %u\n", packet.code); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci dlm_query_join_packet_to_wire(&packet, &response); 9088c2ecf20Sopenharmony_ci return response; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, 9128c2ecf20Sopenharmony_ci void **ret_data) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci struct dlm_assert_joined *assert; 9158c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci assert = (struct dlm_assert_joined *) msg->buf; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci mlog(0, "node %u asserts join on domain %s\n", assert->node_idx, 9208c2ecf20Sopenharmony_ci assert->domain); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 9238c2ecf20Sopenharmony_ci dlm = __dlm_lookup_domain_full(assert->domain, assert->name_len); 9248c2ecf20Sopenharmony_ci /* XXX should we consider no dlm ctxt an error? */ 9258c2ecf20Sopenharmony_ci if (dlm) { 9268c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* Alright, this node has officially joined our 9298c2ecf20Sopenharmony_ci * domain. Set him in the map and clean up our 9308c2ecf20Sopenharmony_ci * leftover join state. */ 9318c2ecf20Sopenharmony_ci BUG_ON(dlm->joining_node != assert->node_idx); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { 9348c2ecf20Sopenharmony_ci mlog(0, "dlm recovery is ongoing, disallow join\n"); 9358c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 9368c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 9378c2ecf20Sopenharmony_ci return -EAGAIN; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci set_bit(assert->node_idx, dlm->domain_map); 9418c2ecf20Sopenharmony_ci clear_bit(assert->node_idx, dlm->exit_domain_map); 9428c2ecf20Sopenharmony_ci __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci printk(KERN_NOTICE "o2dlm: Node %u joins domain %s ", 9458c2ecf20Sopenharmony_ci assert->node_idx, dlm->name); 9468c2ecf20Sopenharmony_ci __dlm_print_nodes(dlm); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* notify anything attached to the heartbeat events */ 9498c2ecf20Sopenharmony_ci dlm_hb_event_notify_attached(dlm, assert->node_idx, 1); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int dlm_match_regions(struct dlm_ctxt *dlm, 9598c2ecf20Sopenharmony_ci struct dlm_query_region *qr, 9608c2ecf20Sopenharmony_ci char *local, int locallen) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci char *remote = qr->qr_regions; 9638c2ecf20Sopenharmony_ci char *l, *r; 9648c2ecf20Sopenharmony_ci int localnr, i, j, foundit; 9658c2ecf20Sopenharmony_ci int status = 0; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (!o2hb_global_heartbeat_active()) { 9688c2ecf20Sopenharmony_ci if (qr->qr_numregions) { 9698c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Domain %s: Joining node %d has global " 9708c2ecf20Sopenharmony_ci "heartbeat enabled but local node %d does not\n", 9718c2ecf20Sopenharmony_ci qr->qr_domain, qr->qr_node, dlm->node_num); 9728c2ecf20Sopenharmony_ci status = -EINVAL; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci goto bail; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (o2hb_global_heartbeat_active() && !qr->qr_numregions) { 9788c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Domain %s: Local node %d has global " 9798c2ecf20Sopenharmony_ci "heartbeat enabled but joining node %d does not\n", 9808c2ecf20Sopenharmony_ci qr->qr_domain, dlm->node_num, qr->qr_node); 9818c2ecf20Sopenharmony_ci status = -EINVAL; 9828c2ecf20Sopenharmony_ci goto bail; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci r = remote; 9868c2ecf20Sopenharmony_ci for (i = 0; i < qr->qr_numregions; ++i) { 9878c2ecf20Sopenharmony_ci mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); 9888c2ecf20Sopenharmony_ci r += O2HB_MAX_REGION_NAME_LEN; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci localnr = min(O2NM_MAX_REGIONS, locallen/O2HB_MAX_REGION_NAME_LEN); 9928c2ecf20Sopenharmony_ci localnr = o2hb_get_all_regions(local, (u8)localnr); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* compare local regions with remote */ 9958c2ecf20Sopenharmony_ci l = local; 9968c2ecf20Sopenharmony_ci for (i = 0; i < localnr; ++i) { 9978c2ecf20Sopenharmony_ci foundit = 0; 9988c2ecf20Sopenharmony_ci r = remote; 9998c2ecf20Sopenharmony_ci for (j = 0; j <= qr->qr_numregions; ++j) { 10008c2ecf20Sopenharmony_ci if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { 10018c2ecf20Sopenharmony_ci foundit = 1; 10028c2ecf20Sopenharmony_ci break; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci r += O2HB_MAX_REGION_NAME_LEN; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci if (!foundit) { 10078c2ecf20Sopenharmony_ci status = -EINVAL; 10088c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Domain %s: Region '%.*s' registered " 10098c2ecf20Sopenharmony_ci "in local node %d but not in joining node %d\n", 10108c2ecf20Sopenharmony_ci qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, l, 10118c2ecf20Sopenharmony_ci dlm->node_num, qr->qr_node); 10128c2ecf20Sopenharmony_ci goto bail; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci l += O2HB_MAX_REGION_NAME_LEN; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* compare remote with local regions */ 10188c2ecf20Sopenharmony_ci r = remote; 10198c2ecf20Sopenharmony_ci for (i = 0; i < qr->qr_numregions; ++i) { 10208c2ecf20Sopenharmony_ci foundit = 0; 10218c2ecf20Sopenharmony_ci l = local; 10228c2ecf20Sopenharmony_ci for (j = 0; j < localnr; ++j) { 10238c2ecf20Sopenharmony_ci if (!memcmp(r, l, O2HB_MAX_REGION_NAME_LEN)) { 10248c2ecf20Sopenharmony_ci foundit = 1; 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci l += O2HB_MAX_REGION_NAME_LEN; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci if (!foundit) { 10308c2ecf20Sopenharmony_ci status = -EINVAL; 10318c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Domain %s: Region '%.*s' registered " 10328c2ecf20Sopenharmony_ci "in joining node %d but not in local node %d\n", 10338c2ecf20Sopenharmony_ci qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, r, 10348c2ecf20Sopenharmony_ci qr->qr_node, dlm->node_num); 10358c2ecf20Sopenharmony_ci goto bail; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci r += O2HB_MAX_REGION_NAME_LEN; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cibail: 10418c2ecf20Sopenharmony_ci return status; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic int dlm_send_regions(struct dlm_ctxt *dlm, unsigned long *node_map) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct dlm_query_region *qr = NULL; 10478c2ecf20Sopenharmony_ci int status, ret = 0, i; 10488c2ecf20Sopenharmony_ci char *p; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES) 10518c2ecf20Sopenharmony_ci goto bail; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci qr = kzalloc(sizeof(struct dlm_query_region), GFP_KERNEL); 10548c2ecf20Sopenharmony_ci if (!qr) { 10558c2ecf20Sopenharmony_ci ret = -ENOMEM; 10568c2ecf20Sopenharmony_ci mlog_errno(ret); 10578c2ecf20Sopenharmony_ci goto bail; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci qr->qr_node = dlm->node_num; 10618c2ecf20Sopenharmony_ci qr->qr_namelen = strlen(dlm->name); 10628c2ecf20Sopenharmony_ci memcpy(qr->qr_domain, dlm->name, qr->qr_namelen); 10638c2ecf20Sopenharmony_ci /* if local hb, the numregions will be zero */ 10648c2ecf20Sopenharmony_ci if (o2hb_global_heartbeat_active()) 10658c2ecf20Sopenharmony_ci qr->qr_numregions = o2hb_get_all_regions(qr->qr_regions, 10668c2ecf20Sopenharmony_ci O2NM_MAX_REGIONS); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci p = qr->qr_regions; 10698c2ecf20Sopenharmony_ci for (i = 0; i < qr->qr_numregions; ++i, p += O2HB_MAX_REGION_NAME_LEN) 10708c2ecf20Sopenharmony_ci mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, p); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci i = -1; 10738c2ecf20Sopenharmony_ci while ((i = find_next_bit(node_map, O2NM_MAX_NODES, 10748c2ecf20Sopenharmony_ci i + 1)) < O2NM_MAX_NODES) { 10758c2ecf20Sopenharmony_ci if (i == dlm->node_num) 10768c2ecf20Sopenharmony_ci continue; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci mlog(0, "Sending regions to node %d\n", i); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci ret = o2net_send_message(DLM_QUERY_REGION, DLM_MOD_KEY, qr, 10818c2ecf20Sopenharmony_ci sizeof(struct dlm_query_region), 10828c2ecf20Sopenharmony_ci i, &status); 10838c2ecf20Sopenharmony_ci if (ret >= 0) 10848c2ecf20Sopenharmony_ci ret = status; 10858c2ecf20Sopenharmony_ci if (ret) { 10868c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Region mismatch %d, node %d\n", 10878c2ecf20Sopenharmony_ci ret, i); 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cibail: 10938c2ecf20Sopenharmony_ci kfree(qr); 10948c2ecf20Sopenharmony_ci return ret; 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic int dlm_query_region_handler(struct o2net_msg *msg, u32 len, 10988c2ecf20Sopenharmony_ci void *data, void **ret_data) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct dlm_query_region *qr; 11018c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 11028c2ecf20Sopenharmony_ci char *local = NULL; 11038c2ecf20Sopenharmony_ci int status = 0; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci qr = (struct dlm_query_region *) msg->buf; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci mlog(0, "Node %u queries hb regions on domain %s\n", qr->qr_node, 11088c2ecf20Sopenharmony_ci qr->qr_domain); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* buffer used in dlm_mast_regions() */ 11118c2ecf20Sopenharmony_ci local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL); 11128c2ecf20Sopenharmony_ci if (!local) 11138c2ecf20Sopenharmony_ci return -ENOMEM; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci status = -EINVAL; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 11188c2ecf20Sopenharmony_ci dlm = __dlm_lookup_domain_full(qr->qr_domain, qr->qr_namelen); 11198c2ecf20Sopenharmony_ci if (!dlm) { 11208c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Node %d queried hb regions on domain %s " 11218c2ecf20Sopenharmony_ci "before join domain\n", qr->qr_node, qr->qr_domain); 11228c2ecf20Sopenharmony_ci goto out_domain_lock; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 11268c2ecf20Sopenharmony_ci if (dlm->joining_node != qr->qr_node) { 11278c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Node %d queried hb regions on domain %s " 11288c2ecf20Sopenharmony_ci "but joining node is %d\n", qr->qr_node, qr->qr_domain, 11298c2ecf20Sopenharmony_ci dlm->joining_node); 11308c2ecf20Sopenharmony_ci goto out_dlm_lock; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* Support for global heartbeat was added in 1.1 */ 11348c2ecf20Sopenharmony_ci if (dlm->dlm_locking_proto.pv_major == 1 && 11358c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor == 0) { 11368c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Node %d queried hb regions on domain %s " 11378c2ecf20Sopenharmony_ci "but active dlm protocol is %d.%d\n", qr->qr_node, 11388c2ecf20Sopenharmony_ci qr->qr_domain, dlm->dlm_locking_proto.pv_major, 11398c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor); 11408c2ecf20Sopenharmony_ci goto out_dlm_lock; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci status = dlm_match_regions(dlm, qr, local, sizeof(qr->qr_regions)); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ciout_dlm_lock: 11468c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ciout_domain_lock: 11498c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci kfree(local); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return status; 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic int dlm_match_nodes(struct dlm_ctxt *dlm, struct dlm_query_nodeinfo *qn) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct o2nm_node *local; 11598c2ecf20Sopenharmony_ci struct dlm_node_info *remote; 11608c2ecf20Sopenharmony_ci int i, j; 11618c2ecf20Sopenharmony_ci int status = 0; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci for (j = 0; j < qn->qn_numnodes; ++j) 11648c2ecf20Sopenharmony_ci mlog(0, "Node %3d, %pI4:%u\n", qn->qn_nodes[j].ni_nodenum, 11658c2ecf20Sopenharmony_ci &(qn->qn_nodes[j].ni_ipv4_address), 11668c2ecf20Sopenharmony_ci ntohs(qn->qn_nodes[j].ni_ipv4_port)); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci for (i = 0; i < O2NM_MAX_NODES && !status; ++i) { 11698c2ecf20Sopenharmony_ci local = o2nm_get_node_by_num(i); 11708c2ecf20Sopenharmony_ci remote = NULL; 11718c2ecf20Sopenharmony_ci for (j = 0; j < qn->qn_numnodes; ++j) { 11728c2ecf20Sopenharmony_ci if (qn->qn_nodes[j].ni_nodenum == i) { 11738c2ecf20Sopenharmony_ci remote = &(qn->qn_nodes[j]); 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (!local && !remote) 11798c2ecf20Sopenharmony_ci continue; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if ((local && !remote) || (!local && remote)) 11828c2ecf20Sopenharmony_ci status = -EINVAL; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (!status && 11858c2ecf20Sopenharmony_ci ((remote->ni_nodenum != local->nd_num) || 11868c2ecf20Sopenharmony_ci (remote->ni_ipv4_port != local->nd_ipv4_port) || 11878c2ecf20Sopenharmony_ci (remote->ni_ipv4_address != local->nd_ipv4_address))) 11888c2ecf20Sopenharmony_ci status = -EINVAL; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (status) { 11918c2ecf20Sopenharmony_ci if (remote && !local) 11928c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) " 11938c2ecf20Sopenharmony_ci "registered in joining node %d but not in " 11948c2ecf20Sopenharmony_ci "local node %d\n", qn->qn_domain, 11958c2ecf20Sopenharmony_ci remote->ni_nodenum, 11968c2ecf20Sopenharmony_ci &(remote->ni_ipv4_address), 11978c2ecf20Sopenharmony_ci ntohs(remote->ni_ipv4_port), 11988c2ecf20Sopenharmony_ci qn->qn_nodenum, dlm->node_num); 11998c2ecf20Sopenharmony_ci if (local && !remote) 12008c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) " 12018c2ecf20Sopenharmony_ci "registered in local node %d but not in " 12028c2ecf20Sopenharmony_ci "joining node %d\n", qn->qn_domain, 12038c2ecf20Sopenharmony_ci local->nd_num, &(local->nd_ipv4_address), 12048c2ecf20Sopenharmony_ci ntohs(local->nd_ipv4_port), 12058c2ecf20Sopenharmony_ci dlm->node_num, qn->qn_nodenum); 12068c2ecf20Sopenharmony_ci BUG_ON((!local && !remote)); 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (local) 12108c2ecf20Sopenharmony_ci o2nm_node_put(local); 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return status; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic int dlm_send_nodeinfo(struct dlm_ctxt *dlm, unsigned long *node_map) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct dlm_query_nodeinfo *qn = NULL; 12198c2ecf20Sopenharmony_ci struct o2nm_node *node; 12208c2ecf20Sopenharmony_ci int ret = 0, status, count, i; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES) 12238c2ecf20Sopenharmony_ci goto bail; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci qn = kzalloc(sizeof(struct dlm_query_nodeinfo), GFP_KERNEL); 12268c2ecf20Sopenharmony_ci if (!qn) { 12278c2ecf20Sopenharmony_ci ret = -ENOMEM; 12288c2ecf20Sopenharmony_ci mlog_errno(ret); 12298c2ecf20Sopenharmony_ci goto bail; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci for (i = 0, count = 0; i < O2NM_MAX_NODES; ++i) { 12338c2ecf20Sopenharmony_ci node = o2nm_get_node_by_num(i); 12348c2ecf20Sopenharmony_ci if (!node) 12358c2ecf20Sopenharmony_ci continue; 12368c2ecf20Sopenharmony_ci qn->qn_nodes[count].ni_nodenum = node->nd_num; 12378c2ecf20Sopenharmony_ci qn->qn_nodes[count].ni_ipv4_port = node->nd_ipv4_port; 12388c2ecf20Sopenharmony_ci qn->qn_nodes[count].ni_ipv4_address = node->nd_ipv4_address; 12398c2ecf20Sopenharmony_ci mlog(0, "Node %3d, %pI4:%u\n", node->nd_num, 12408c2ecf20Sopenharmony_ci &(node->nd_ipv4_address), ntohs(node->nd_ipv4_port)); 12418c2ecf20Sopenharmony_ci ++count; 12428c2ecf20Sopenharmony_ci o2nm_node_put(node); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci qn->qn_nodenum = dlm->node_num; 12468c2ecf20Sopenharmony_ci qn->qn_numnodes = count; 12478c2ecf20Sopenharmony_ci qn->qn_namelen = strlen(dlm->name); 12488c2ecf20Sopenharmony_ci memcpy(qn->qn_domain, dlm->name, qn->qn_namelen); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci i = -1; 12518c2ecf20Sopenharmony_ci while ((i = find_next_bit(node_map, O2NM_MAX_NODES, 12528c2ecf20Sopenharmony_ci i + 1)) < O2NM_MAX_NODES) { 12538c2ecf20Sopenharmony_ci if (i == dlm->node_num) 12548c2ecf20Sopenharmony_ci continue; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci mlog(0, "Sending nodeinfo to node %d\n", i); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci ret = o2net_send_message(DLM_QUERY_NODEINFO, DLM_MOD_KEY, 12598c2ecf20Sopenharmony_ci qn, sizeof(struct dlm_query_nodeinfo), 12608c2ecf20Sopenharmony_ci i, &status); 12618c2ecf20Sopenharmony_ci if (ret >= 0) 12628c2ecf20Sopenharmony_ci ret = status; 12638c2ecf20Sopenharmony_ci if (ret) { 12648c2ecf20Sopenharmony_ci mlog(ML_ERROR, "node mismatch %d, node %d\n", ret, i); 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cibail: 12708c2ecf20Sopenharmony_ci kfree(qn); 12718c2ecf20Sopenharmony_ci return ret; 12728c2ecf20Sopenharmony_ci} 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_cistatic int dlm_query_nodeinfo_handler(struct o2net_msg *msg, u32 len, 12758c2ecf20Sopenharmony_ci void *data, void **ret_data) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci struct dlm_query_nodeinfo *qn; 12788c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 12798c2ecf20Sopenharmony_ci int locked = 0, status = -EINVAL; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci qn = (struct dlm_query_nodeinfo *) msg->buf; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci mlog(0, "Node %u queries nodes on domain %s\n", qn->qn_nodenum, 12848c2ecf20Sopenharmony_ci qn->qn_domain); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 12878c2ecf20Sopenharmony_ci dlm = __dlm_lookup_domain_full(qn->qn_domain, qn->qn_namelen); 12888c2ecf20Sopenharmony_ci if (!dlm) { 12898c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Node %d queried nodes on domain %s before " 12908c2ecf20Sopenharmony_ci "join domain\n", qn->qn_nodenum, qn->qn_domain); 12918c2ecf20Sopenharmony_ci goto bail; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 12958c2ecf20Sopenharmony_ci locked = 1; 12968c2ecf20Sopenharmony_ci if (dlm->joining_node != qn->qn_nodenum) { 12978c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Node %d queried nodes on domain %s but " 12988c2ecf20Sopenharmony_ci "joining node is %d\n", qn->qn_nodenum, qn->qn_domain, 12998c2ecf20Sopenharmony_ci dlm->joining_node); 13008c2ecf20Sopenharmony_ci goto bail; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Support for node query was added in 1.1 */ 13048c2ecf20Sopenharmony_ci if (dlm->dlm_locking_proto.pv_major == 1 && 13058c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor == 0) { 13068c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Node %d queried nodes on domain %s " 13078c2ecf20Sopenharmony_ci "but active dlm protocol is %d.%d\n", qn->qn_nodenum, 13088c2ecf20Sopenharmony_ci qn->qn_domain, dlm->dlm_locking_proto.pv_major, 13098c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor); 13108c2ecf20Sopenharmony_ci goto bail; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci status = dlm_match_nodes(dlm, qn); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cibail: 13168c2ecf20Sopenharmony_ci if (locked) 13178c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 13188c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci return status; 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, 13248c2ecf20Sopenharmony_ci void **ret_data) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct dlm_cancel_join *cancel; 13278c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci cancel = (struct dlm_cancel_join *) msg->buf; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci mlog(0, "node %u cancels join on domain %s\n", cancel->node_idx, 13328c2ecf20Sopenharmony_ci cancel->domain); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 13358c2ecf20Sopenharmony_ci dlm = __dlm_lookup_domain_full(cancel->domain, cancel->name_len); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci if (dlm) { 13388c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* Yikes, this guy wants to cancel his join. No 13418c2ecf20Sopenharmony_ci * problem, we simply cleanup our join state. */ 13428c2ecf20Sopenharmony_ci BUG_ON(dlm->joining_node != cancel->node_idx); 13438c2ecf20Sopenharmony_ci __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci return 0; 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cistatic int dlm_send_one_join_cancel(struct dlm_ctxt *dlm, 13538c2ecf20Sopenharmony_ci unsigned int node) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci int status; 13568c2ecf20Sopenharmony_ci struct dlm_cancel_join cancel_msg; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci memset(&cancel_msg, 0, sizeof(cancel_msg)); 13598c2ecf20Sopenharmony_ci cancel_msg.node_idx = dlm->node_num; 13608c2ecf20Sopenharmony_ci cancel_msg.name_len = strlen(dlm->name); 13618c2ecf20Sopenharmony_ci memcpy(cancel_msg.domain, dlm->name, cancel_msg.name_len); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci status = o2net_send_message(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY, 13648c2ecf20Sopenharmony_ci &cancel_msg, sizeof(cancel_msg), node, 13658c2ecf20Sopenharmony_ci NULL); 13668c2ecf20Sopenharmony_ci if (status < 0) { 13678c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to " 13688c2ecf20Sopenharmony_ci "node %u\n", status, DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY, 13698c2ecf20Sopenharmony_ci node); 13708c2ecf20Sopenharmony_ci goto bail; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cibail: 13748c2ecf20Sopenharmony_ci return status; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci/* map_size should be in bytes. */ 13788c2ecf20Sopenharmony_cistatic int dlm_send_join_cancels(struct dlm_ctxt *dlm, 13798c2ecf20Sopenharmony_ci unsigned long *node_map, 13808c2ecf20Sopenharmony_ci unsigned int map_size) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci int status, tmpstat; 13838c2ecf20Sopenharmony_ci int node; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (map_size != (BITS_TO_LONGS(O2NM_MAX_NODES) * 13868c2ecf20Sopenharmony_ci sizeof(unsigned long))) { 13878c2ecf20Sopenharmony_ci mlog(ML_ERROR, 13888c2ecf20Sopenharmony_ci "map_size %u != BITS_TO_LONGS(O2NM_MAX_NODES) %u\n", 13898c2ecf20Sopenharmony_ci map_size, (unsigned)BITS_TO_LONGS(O2NM_MAX_NODES)); 13908c2ecf20Sopenharmony_ci return -EINVAL; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci status = 0; 13948c2ecf20Sopenharmony_ci node = -1; 13958c2ecf20Sopenharmony_ci while ((node = find_next_bit(node_map, O2NM_MAX_NODES, 13968c2ecf20Sopenharmony_ci node + 1)) < O2NM_MAX_NODES) { 13978c2ecf20Sopenharmony_ci if (node == dlm->node_num) 13988c2ecf20Sopenharmony_ci continue; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci tmpstat = dlm_send_one_join_cancel(dlm, node); 14018c2ecf20Sopenharmony_ci if (tmpstat) { 14028c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Error return %d cancelling join on " 14038c2ecf20Sopenharmony_ci "node %d\n", tmpstat, node); 14048c2ecf20Sopenharmony_ci if (!status) 14058c2ecf20Sopenharmony_ci status = tmpstat; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (status) 14108c2ecf20Sopenharmony_ci mlog_errno(status); 14118c2ecf20Sopenharmony_ci return status; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_cistatic int dlm_request_join(struct dlm_ctxt *dlm, 14158c2ecf20Sopenharmony_ci int node, 14168c2ecf20Sopenharmony_ci enum dlm_query_join_response_code *response) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci int status; 14198c2ecf20Sopenharmony_ci struct dlm_query_join_request join_msg; 14208c2ecf20Sopenharmony_ci struct dlm_query_join_packet packet; 14218c2ecf20Sopenharmony_ci u32 join_resp; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci mlog(0, "querying node %d\n", node); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci memset(&join_msg, 0, sizeof(join_msg)); 14268c2ecf20Sopenharmony_ci join_msg.node_idx = dlm->node_num; 14278c2ecf20Sopenharmony_ci join_msg.name_len = strlen(dlm->name); 14288c2ecf20Sopenharmony_ci memcpy(join_msg.domain, dlm->name, join_msg.name_len); 14298c2ecf20Sopenharmony_ci join_msg.dlm_proto = dlm->dlm_locking_proto; 14308c2ecf20Sopenharmony_ci join_msg.fs_proto = dlm->fs_locking_proto; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci /* copy live node map to join message */ 14338c2ecf20Sopenharmony_ci byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, 14368c2ecf20Sopenharmony_ci sizeof(join_msg), node, &join_resp); 14378c2ecf20Sopenharmony_ci if (status < 0 && status != -ENOPROTOOPT) { 14388c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to " 14398c2ecf20Sopenharmony_ci "node %u\n", status, DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, 14408c2ecf20Sopenharmony_ci node); 14418c2ecf20Sopenharmony_ci goto bail; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci dlm_query_join_wire_to_packet(join_resp, &packet); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci /* -ENOPROTOOPT from the net code means the other side isn't 14468c2ecf20Sopenharmony_ci listening for our message type -- that's fine, it means 14478c2ecf20Sopenharmony_ci his dlm isn't up, so we can consider him a 'yes' but not 14488c2ecf20Sopenharmony_ci joined into the domain. */ 14498c2ecf20Sopenharmony_ci if (status == -ENOPROTOOPT) { 14508c2ecf20Sopenharmony_ci status = 0; 14518c2ecf20Sopenharmony_ci *response = JOIN_OK_NO_MAP; 14528c2ecf20Sopenharmony_ci } else { 14538c2ecf20Sopenharmony_ci *response = packet.code; 14548c2ecf20Sopenharmony_ci switch (packet.code) { 14558c2ecf20Sopenharmony_ci case JOIN_DISALLOW: 14568c2ecf20Sopenharmony_ci case JOIN_OK_NO_MAP: 14578c2ecf20Sopenharmony_ci break; 14588c2ecf20Sopenharmony_ci case JOIN_PROTOCOL_MISMATCH: 14598c2ecf20Sopenharmony_ci mlog(ML_NOTICE, 14608c2ecf20Sopenharmony_ci "This node requested DLM locking protocol %u.%u and " 14618c2ecf20Sopenharmony_ci "filesystem locking protocol %u.%u. At least one of " 14628c2ecf20Sopenharmony_ci "the protocol versions on node %d is not compatible, " 14638c2ecf20Sopenharmony_ci "disconnecting\n", 14648c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_major, 14658c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor, 14668c2ecf20Sopenharmony_ci dlm->fs_locking_proto.pv_major, 14678c2ecf20Sopenharmony_ci dlm->fs_locking_proto.pv_minor, 14688c2ecf20Sopenharmony_ci node); 14698c2ecf20Sopenharmony_ci status = -EPROTO; 14708c2ecf20Sopenharmony_ci break; 14718c2ecf20Sopenharmony_ci case JOIN_OK: 14728c2ecf20Sopenharmony_ci /* Use the same locking protocol as the remote node */ 14738c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor = packet.dlm_minor; 14748c2ecf20Sopenharmony_ci dlm->fs_locking_proto.pv_minor = packet.fs_minor; 14758c2ecf20Sopenharmony_ci mlog(0, 14768c2ecf20Sopenharmony_ci "Node %d responds JOIN_OK with DLM locking protocol " 14778c2ecf20Sopenharmony_ci "%u.%u and fs locking protocol %u.%u\n", 14788c2ecf20Sopenharmony_ci node, 14798c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_major, 14808c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor, 14818c2ecf20Sopenharmony_ci dlm->fs_locking_proto.pv_major, 14828c2ecf20Sopenharmony_ci dlm->fs_locking_proto.pv_minor); 14838c2ecf20Sopenharmony_ci break; 14848c2ecf20Sopenharmony_ci default: 14858c2ecf20Sopenharmony_ci status = -EINVAL; 14868c2ecf20Sopenharmony_ci mlog(ML_ERROR, "invalid response %d from node %u\n", 14878c2ecf20Sopenharmony_ci packet.code, node); 14888c2ecf20Sopenharmony_ci /* Reset response to JOIN_DISALLOW */ 14898c2ecf20Sopenharmony_ci *response = JOIN_DISALLOW; 14908c2ecf20Sopenharmony_ci break; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci mlog(0, "status %d, node %d response is %d\n", status, node, 14958c2ecf20Sopenharmony_ci *response); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_cibail: 14988c2ecf20Sopenharmony_ci return status; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic int dlm_send_one_join_assert(struct dlm_ctxt *dlm, 15028c2ecf20Sopenharmony_ci unsigned int node) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci int status; 15058c2ecf20Sopenharmony_ci int ret; 15068c2ecf20Sopenharmony_ci struct dlm_assert_joined assert_msg; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci mlog(0, "Sending join assert to node %u\n", node); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci memset(&assert_msg, 0, sizeof(assert_msg)); 15118c2ecf20Sopenharmony_ci assert_msg.node_idx = dlm->node_num; 15128c2ecf20Sopenharmony_ci assert_msg.name_len = strlen(dlm->name); 15138c2ecf20Sopenharmony_ci memcpy(assert_msg.domain, dlm->name, assert_msg.name_len); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci status = o2net_send_message(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY, 15168c2ecf20Sopenharmony_ci &assert_msg, sizeof(assert_msg), node, 15178c2ecf20Sopenharmony_ci &ret); 15188c2ecf20Sopenharmony_ci if (status < 0) 15198c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to " 15208c2ecf20Sopenharmony_ci "node %u\n", status, DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY, 15218c2ecf20Sopenharmony_ci node); 15228c2ecf20Sopenharmony_ci else 15238c2ecf20Sopenharmony_ci status = ret; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci return status; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic void dlm_send_join_asserts(struct dlm_ctxt *dlm, 15298c2ecf20Sopenharmony_ci unsigned long *node_map) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci int status, node, live; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci status = 0; 15348c2ecf20Sopenharmony_ci node = -1; 15358c2ecf20Sopenharmony_ci while ((node = find_next_bit(node_map, O2NM_MAX_NODES, 15368c2ecf20Sopenharmony_ci node + 1)) < O2NM_MAX_NODES) { 15378c2ecf20Sopenharmony_ci if (node == dlm->node_num) 15388c2ecf20Sopenharmony_ci continue; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci do { 15418c2ecf20Sopenharmony_ci /* It is very important that this message be 15428c2ecf20Sopenharmony_ci * received so we spin until either the node 15438c2ecf20Sopenharmony_ci * has died or it gets the message. */ 15448c2ecf20Sopenharmony_ci status = dlm_send_one_join_assert(dlm, node); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 15478c2ecf20Sopenharmony_ci live = test_bit(node, dlm->live_nodes_map); 15488c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (status) { 15518c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Error return %d asserting " 15528c2ecf20Sopenharmony_ci "join on node %d\n", status, node); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* give us some time between errors... */ 15558c2ecf20Sopenharmony_ci if (live) 15568c2ecf20Sopenharmony_ci msleep(DLM_DOMAIN_BACKOFF_MS); 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci } while (status && live); 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistruct domain_join_ctxt { 15638c2ecf20Sopenharmony_ci unsigned long live_map[BITS_TO_LONGS(O2NM_MAX_NODES)]; 15648c2ecf20Sopenharmony_ci unsigned long yes_resp_map[BITS_TO_LONGS(O2NM_MAX_NODES)]; 15658c2ecf20Sopenharmony_ci}; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic int dlm_should_restart_join(struct dlm_ctxt *dlm, 15688c2ecf20Sopenharmony_ci struct domain_join_ctxt *ctxt, 15698c2ecf20Sopenharmony_ci enum dlm_query_join_response_code response) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci int ret; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (response == JOIN_DISALLOW) { 15748c2ecf20Sopenharmony_ci mlog(0, "Latest response of disallow -- should restart\n"); 15758c2ecf20Sopenharmony_ci return 1; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 15798c2ecf20Sopenharmony_ci /* For now, we restart the process if the node maps have 15808c2ecf20Sopenharmony_ci * changed at all */ 15818c2ecf20Sopenharmony_ci ret = memcmp(ctxt->live_map, dlm->live_nodes_map, 15828c2ecf20Sopenharmony_ci sizeof(dlm->live_nodes_map)); 15838c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (ret) 15868c2ecf20Sopenharmony_ci mlog(0, "Node maps changed -- should restart\n"); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci return ret; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int dlm_try_to_join_domain(struct dlm_ctxt *dlm) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci int status = 0, tmpstat, node; 15948c2ecf20Sopenharmony_ci struct domain_join_ctxt *ctxt; 15958c2ecf20Sopenharmony_ci enum dlm_query_join_response_code response = JOIN_DISALLOW; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci mlog(0, "%p", dlm); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 16008c2ecf20Sopenharmony_ci if (!ctxt) { 16018c2ecf20Sopenharmony_ci status = -ENOMEM; 16028c2ecf20Sopenharmony_ci mlog_errno(status); 16038c2ecf20Sopenharmony_ci goto bail; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* group sem locking should work for us here -- we're already 16078c2ecf20Sopenharmony_ci * registered for heartbeat events so filling this should be 16088c2ecf20Sopenharmony_ci * atomic wrt getting those handlers called. */ 16098c2ecf20Sopenharmony_ci o2hb_fill_node_map(dlm->live_nodes_map, sizeof(dlm->live_nodes_map)); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 16128c2ecf20Sopenharmony_ci memcpy(ctxt->live_map, dlm->live_nodes_map, sizeof(ctxt->live_map)); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci __dlm_set_joining_node(dlm, dlm->node_num); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci node = -1; 16198c2ecf20Sopenharmony_ci while ((node = find_next_bit(ctxt->live_map, O2NM_MAX_NODES, 16208c2ecf20Sopenharmony_ci node + 1)) < O2NM_MAX_NODES) { 16218c2ecf20Sopenharmony_ci if (node == dlm->node_num) 16228c2ecf20Sopenharmony_ci continue; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci status = dlm_request_join(dlm, node, &response); 16258c2ecf20Sopenharmony_ci if (status < 0) { 16268c2ecf20Sopenharmony_ci mlog_errno(status); 16278c2ecf20Sopenharmony_ci goto bail; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* Ok, either we got a response or the node doesn't have a 16318c2ecf20Sopenharmony_ci * dlm up. */ 16328c2ecf20Sopenharmony_ci if (response == JOIN_OK) 16338c2ecf20Sopenharmony_ci set_bit(node, ctxt->yes_resp_map); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (dlm_should_restart_join(dlm, ctxt, response)) { 16368c2ecf20Sopenharmony_ci status = -EAGAIN; 16378c2ecf20Sopenharmony_ci goto bail; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci mlog(0, "Yay, done querying nodes!\n"); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci /* Yay, everyone agree's we can join the domain. My domain is 16448c2ecf20Sopenharmony_ci * comprised of all nodes who were put in the 16458c2ecf20Sopenharmony_ci * yes_resp_map. Copy that into our domain map and send a join 16468c2ecf20Sopenharmony_ci * assert message to clean up everyone elses state. */ 16478c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 16488c2ecf20Sopenharmony_ci memcpy(dlm->domain_map, ctxt->yes_resp_map, 16498c2ecf20Sopenharmony_ci sizeof(ctxt->yes_resp_map)); 16508c2ecf20Sopenharmony_ci set_bit(dlm->node_num, dlm->domain_map); 16518c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci /* Support for global heartbeat and node info was added in 1.1 */ 16548c2ecf20Sopenharmony_ci if (dlm->dlm_locking_proto.pv_major > 1 || 16558c2ecf20Sopenharmony_ci dlm->dlm_locking_proto.pv_minor > 0) { 16568c2ecf20Sopenharmony_ci status = dlm_send_nodeinfo(dlm, ctxt->yes_resp_map); 16578c2ecf20Sopenharmony_ci if (status) { 16588c2ecf20Sopenharmony_ci mlog_errno(status); 16598c2ecf20Sopenharmony_ci goto bail; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci status = dlm_send_regions(dlm, ctxt->yes_resp_map); 16628c2ecf20Sopenharmony_ci if (status) { 16638c2ecf20Sopenharmony_ci mlog_errno(status); 16648c2ecf20Sopenharmony_ci goto bail; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci dlm_send_join_asserts(dlm, ctxt->yes_resp_map); 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci /* Joined state *must* be set before the joining node 16718c2ecf20Sopenharmony_ci * information, otherwise the query_join handler may read no 16728c2ecf20Sopenharmony_ci * current joiner but a state of NEW and tell joining nodes 16738c2ecf20Sopenharmony_ci * we're not in the domain. */ 16748c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 16758c2ecf20Sopenharmony_ci dlm->dlm_state = DLM_CTXT_JOINED; 16768c2ecf20Sopenharmony_ci dlm->num_joins++; 16778c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_cibail: 16808c2ecf20Sopenharmony_ci spin_lock(&dlm->spinlock); 16818c2ecf20Sopenharmony_ci __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); 16828c2ecf20Sopenharmony_ci if (!status) { 16838c2ecf20Sopenharmony_ci printk(KERN_NOTICE "o2dlm: Joining domain %s ", dlm->name); 16848c2ecf20Sopenharmony_ci __dlm_print_nodes(dlm); 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci spin_unlock(&dlm->spinlock); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (ctxt) { 16898c2ecf20Sopenharmony_ci /* Do we need to send a cancel message to any nodes? */ 16908c2ecf20Sopenharmony_ci if (status < 0) { 16918c2ecf20Sopenharmony_ci tmpstat = dlm_send_join_cancels(dlm, 16928c2ecf20Sopenharmony_ci ctxt->yes_resp_map, 16938c2ecf20Sopenharmony_ci sizeof(ctxt->yes_resp_map)); 16948c2ecf20Sopenharmony_ci if (tmpstat < 0) 16958c2ecf20Sopenharmony_ci mlog_errno(tmpstat); 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci kfree(ctxt); 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci mlog(0, "returning %d\n", status); 17018c2ecf20Sopenharmony_ci return status; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cistatic void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci o2hb_unregister_callback(dlm->name, &dlm->dlm_hb_up); 17078c2ecf20Sopenharmony_ci o2hb_unregister_callback(dlm->name, &dlm->dlm_hb_down); 17088c2ecf20Sopenharmony_ci o2net_unregister_handler_list(&dlm->dlm_domain_handlers); 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic int dlm_register_domain_handlers(struct dlm_ctxt *dlm) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci int status; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci mlog(0, "registering handlers.\n"); 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci o2hb_setup_callback(&dlm->dlm_hb_down, O2HB_NODE_DOWN_CB, 17188c2ecf20Sopenharmony_ci dlm_hb_node_down_cb, dlm, DLM_HB_NODE_DOWN_PRI); 17198c2ecf20Sopenharmony_ci o2hb_setup_callback(&dlm->dlm_hb_up, O2HB_NODE_UP_CB, 17208c2ecf20Sopenharmony_ci dlm_hb_node_up_cb, dlm, DLM_HB_NODE_UP_PRI); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci status = o2hb_register_callback(dlm->name, &dlm->dlm_hb_down); 17238c2ecf20Sopenharmony_ci if (status) 17248c2ecf20Sopenharmony_ci goto bail; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci status = o2hb_register_callback(dlm->name, &dlm->dlm_hb_up); 17278c2ecf20Sopenharmony_ci if (status) 17288c2ecf20Sopenharmony_ci goto bail; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_MASTER_REQUEST_MSG, dlm->key, 17318c2ecf20Sopenharmony_ci sizeof(struct dlm_master_request), 17328c2ecf20Sopenharmony_ci dlm_master_request_handler, 17338c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17348c2ecf20Sopenharmony_ci if (status) 17358c2ecf20Sopenharmony_ci goto bail; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_ASSERT_MASTER_MSG, dlm->key, 17388c2ecf20Sopenharmony_ci sizeof(struct dlm_assert_master), 17398c2ecf20Sopenharmony_ci dlm_assert_master_handler, 17408c2ecf20Sopenharmony_ci dlm, dlm_assert_master_post_handler, 17418c2ecf20Sopenharmony_ci &dlm->dlm_domain_handlers); 17428c2ecf20Sopenharmony_ci if (status) 17438c2ecf20Sopenharmony_ci goto bail; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_CREATE_LOCK_MSG, dlm->key, 17468c2ecf20Sopenharmony_ci sizeof(struct dlm_create_lock), 17478c2ecf20Sopenharmony_ci dlm_create_lock_handler, 17488c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17498c2ecf20Sopenharmony_ci if (status) 17508c2ecf20Sopenharmony_ci goto bail; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_CONVERT_LOCK_MSG, dlm->key, 17538c2ecf20Sopenharmony_ci DLM_CONVERT_LOCK_MAX_LEN, 17548c2ecf20Sopenharmony_ci dlm_convert_lock_handler, 17558c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17568c2ecf20Sopenharmony_ci if (status) 17578c2ecf20Sopenharmony_ci goto bail; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_UNLOCK_LOCK_MSG, dlm->key, 17608c2ecf20Sopenharmony_ci DLM_UNLOCK_LOCK_MAX_LEN, 17618c2ecf20Sopenharmony_ci dlm_unlock_lock_handler, 17628c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17638c2ecf20Sopenharmony_ci if (status) 17648c2ecf20Sopenharmony_ci goto bail; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_PROXY_AST_MSG, dlm->key, 17678c2ecf20Sopenharmony_ci DLM_PROXY_AST_MAX_LEN, 17688c2ecf20Sopenharmony_ci dlm_proxy_ast_handler, 17698c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17708c2ecf20Sopenharmony_ci if (status) 17718c2ecf20Sopenharmony_ci goto bail; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_EXIT_DOMAIN_MSG, dlm->key, 17748c2ecf20Sopenharmony_ci sizeof(struct dlm_exit_domain), 17758c2ecf20Sopenharmony_ci dlm_exit_domain_handler, 17768c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17778c2ecf20Sopenharmony_ci if (status) 17788c2ecf20Sopenharmony_ci goto bail; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key, 17818c2ecf20Sopenharmony_ci sizeof(struct dlm_deref_lockres), 17828c2ecf20Sopenharmony_ci dlm_deref_lockres_handler, 17838c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17848c2ecf20Sopenharmony_ci if (status) 17858c2ecf20Sopenharmony_ci goto bail; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key, 17888c2ecf20Sopenharmony_ci sizeof(struct dlm_migrate_request), 17898c2ecf20Sopenharmony_ci dlm_migrate_request_handler, 17908c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17918c2ecf20Sopenharmony_ci if (status) 17928c2ecf20Sopenharmony_ci goto bail; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_MIG_LOCKRES_MSG, dlm->key, 17958c2ecf20Sopenharmony_ci DLM_MIG_LOCKRES_MAX_LEN, 17968c2ecf20Sopenharmony_ci dlm_mig_lockres_handler, 17978c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 17988c2ecf20Sopenharmony_ci if (status) 17998c2ecf20Sopenharmony_ci goto bail; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_MASTER_REQUERY_MSG, dlm->key, 18028c2ecf20Sopenharmony_ci sizeof(struct dlm_master_requery), 18038c2ecf20Sopenharmony_ci dlm_master_requery_handler, 18048c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18058c2ecf20Sopenharmony_ci if (status) 18068c2ecf20Sopenharmony_ci goto bail; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_LOCK_REQUEST_MSG, dlm->key, 18098c2ecf20Sopenharmony_ci sizeof(struct dlm_lock_request), 18108c2ecf20Sopenharmony_ci dlm_request_all_locks_handler, 18118c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18128c2ecf20Sopenharmony_ci if (status) 18138c2ecf20Sopenharmony_ci goto bail; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_RECO_DATA_DONE_MSG, dlm->key, 18168c2ecf20Sopenharmony_ci sizeof(struct dlm_reco_data_done), 18178c2ecf20Sopenharmony_ci dlm_reco_data_done_handler, 18188c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18198c2ecf20Sopenharmony_ci if (status) 18208c2ecf20Sopenharmony_ci goto bail; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_BEGIN_RECO_MSG, dlm->key, 18238c2ecf20Sopenharmony_ci sizeof(struct dlm_begin_reco), 18248c2ecf20Sopenharmony_ci dlm_begin_reco_handler, 18258c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18268c2ecf20Sopenharmony_ci if (status) 18278c2ecf20Sopenharmony_ci goto bail; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_FINALIZE_RECO_MSG, dlm->key, 18308c2ecf20Sopenharmony_ci sizeof(struct dlm_finalize_reco), 18318c2ecf20Sopenharmony_ci dlm_finalize_reco_handler, 18328c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18338c2ecf20Sopenharmony_ci if (status) 18348c2ecf20Sopenharmony_ci goto bail; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_BEGIN_EXIT_DOMAIN_MSG, dlm->key, 18378c2ecf20Sopenharmony_ci sizeof(struct dlm_exit_domain), 18388c2ecf20Sopenharmony_ci dlm_begin_exit_domain_handler, 18398c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18408c2ecf20Sopenharmony_ci if (status) 18418c2ecf20Sopenharmony_ci goto bail; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_DEREF_LOCKRES_DONE, dlm->key, 18448c2ecf20Sopenharmony_ci sizeof(struct dlm_deref_lockres_done), 18458c2ecf20Sopenharmony_ci dlm_deref_lockres_done_handler, 18468c2ecf20Sopenharmony_ci dlm, NULL, &dlm->dlm_domain_handlers); 18478c2ecf20Sopenharmony_cibail: 18488c2ecf20Sopenharmony_ci if (status) 18498c2ecf20Sopenharmony_ci dlm_unregister_domain_handlers(dlm); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci return status; 18528c2ecf20Sopenharmony_ci} 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_cistatic int dlm_join_domain(struct dlm_ctxt *dlm) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci int status; 18578c2ecf20Sopenharmony_ci unsigned int backoff; 18588c2ecf20Sopenharmony_ci unsigned int total_backoff = 0; 18598c2ecf20Sopenharmony_ci char wq_name[O2NM_MAX_NAME_LEN]; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci BUG_ON(!dlm); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci mlog(0, "Join domain %s\n", dlm->name); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci status = dlm_register_domain_handlers(dlm); 18668c2ecf20Sopenharmony_ci if (status) { 18678c2ecf20Sopenharmony_ci mlog_errno(status); 18688c2ecf20Sopenharmony_ci goto bail; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci status = dlm_launch_thread(dlm); 18728c2ecf20Sopenharmony_ci if (status < 0) { 18738c2ecf20Sopenharmony_ci mlog_errno(status); 18748c2ecf20Sopenharmony_ci goto bail; 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci status = dlm_launch_recovery_thread(dlm); 18788c2ecf20Sopenharmony_ci if (status < 0) { 18798c2ecf20Sopenharmony_ci mlog_errno(status); 18808c2ecf20Sopenharmony_ci goto bail; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci dlm_debug_init(dlm); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci snprintf(wq_name, O2NM_MAX_NAME_LEN, "dlm_wq-%s", dlm->name); 18868c2ecf20Sopenharmony_ci dlm->dlm_worker = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 0); 18878c2ecf20Sopenharmony_ci if (!dlm->dlm_worker) { 18888c2ecf20Sopenharmony_ci status = -ENOMEM; 18898c2ecf20Sopenharmony_ci mlog_errno(status); 18908c2ecf20Sopenharmony_ci goto bail; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci do { 18948c2ecf20Sopenharmony_ci status = dlm_try_to_join_domain(dlm); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci /* If we're racing another node to the join, then we 18978c2ecf20Sopenharmony_ci * need to back off temporarily and let them 18988c2ecf20Sopenharmony_ci * complete. */ 18998c2ecf20Sopenharmony_ci#define DLM_JOIN_TIMEOUT_MSECS 90000 19008c2ecf20Sopenharmony_ci if (status == -EAGAIN) { 19018c2ecf20Sopenharmony_ci if (signal_pending(current)) { 19028c2ecf20Sopenharmony_ci status = -ERESTARTSYS; 19038c2ecf20Sopenharmony_ci goto bail; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (total_backoff > DLM_JOIN_TIMEOUT_MSECS) { 19078c2ecf20Sopenharmony_ci status = -ERESTARTSYS; 19088c2ecf20Sopenharmony_ci mlog(ML_NOTICE, "Timed out joining dlm domain " 19098c2ecf20Sopenharmony_ci "%s after %u msecs\n", dlm->name, 19108c2ecf20Sopenharmony_ci total_backoff); 19118c2ecf20Sopenharmony_ci goto bail; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* 19158c2ecf20Sopenharmony_ci * <chip> After you! 19168c2ecf20Sopenharmony_ci * <dale> No, after you! 19178c2ecf20Sopenharmony_ci * <chip> I insist! 19188c2ecf20Sopenharmony_ci * <dale> But you first! 19198c2ecf20Sopenharmony_ci * ... 19208c2ecf20Sopenharmony_ci */ 19218c2ecf20Sopenharmony_ci backoff = (unsigned int)(jiffies & 0x3); 19228c2ecf20Sopenharmony_ci backoff *= DLM_DOMAIN_BACKOFF_MS; 19238c2ecf20Sopenharmony_ci total_backoff += backoff; 19248c2ecf20Sopenharmony_ci mlog(0, "backoff %d\n", backoff); 19258c2ecf20Sopenharmony_ci msleep(backoff); 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci } while (status == -EAGAIN); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci if (status < 0) { 19308c2ecf20Sopenharmony_ci mlog_errno(status); 19318c2ecf20Sopenharmony_ci goto bail; 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci status = 0; 19358c2ecf20Sopenharmony_cibail: 19368c2ecf20Sopenharmony_ci wake_up(&dlm_domain_events); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci if (status) { 19398c2ecf20Sopenharmony_ci dlm_unregister_domain_handlers(dlm); 19408c2ecf20Sopenharmony_ci dlm_complete_thread(dlm); 19418c2ecf20Sopenharmony_ci dlm_complete_recovery_thread(dlm); 19428c2ecf20Sopenharmony_ci dlm_destroy_dlm_worker(dlm); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci return status; 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_cistatic struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, 19498c2ecf20Sopenharmony_ci u32 key) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci int i; 19528c2ecf20Sopenharmony_ci int ret; 19538c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci dlm = kzalloc(sizeof(*dlm), GFP_KERNEL); 19568c2ecf20Sopenharmony_ci if (!dlm) { 19578c2ecf20Sopenharmony_ci ret = -ENOMEM; 19588c2ecf20Sopenharmony_ci mlog_errno(ret); 19598c2ecf20Sopenharmony_ci goto leave; 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci dlm->name = kstrdup(domain, GFP_KERNEL); 19638c2ecf20Sopenharmony_ci if (dlm->name == NULL) { 19648c2ecf20Sopenharmony_ci ret = -ENOMEM; 19658c2ecf20Sopenharmony_ci mlog_errno(ret); 19668c2ecf20Sopenharmony_ci goto leave; 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci dlm->lockres_hash = (struct hlist_head **)dlm_alloc_pagevec(DLM_HASH_PAGES); 19708c2ecf20Sopenharmony_ci if (!dlm->lockres_hash) { 19718c2ecf20Sopenharmony_ci ret = -ENOMEM; 19728c2ecf20Sopenharmony_ci mlog_errno(ret); 19738c2ecf20Sopenharmony_ci goto leave; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci for (i = 0; i < DLM_HASH_BUCKETS; i++) 19778c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(dlm_lockres_hash(dlm, i)); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci dlm->master_hash = (struct hlist_head **) 19808c2ecf20Sopenharmony_ci dlm_alloc_pagevec(DLM_HASH_PAGES); 19818c2ecf20Sopenharmony_ci if (!dlm->master_hash) { 19828c2ecf20Sopenharmony_ci ret = -ENOMEM; 19838c2ecf20Sopenharmony_ci mlog_errno(ret); 19848c2ecf20Sopenharmony_ci goto leave; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci for (i = 0; i < DLM_HASH_BUCKETS; i++) 19888c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(dlm_master_hash(dlm, i)); 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci dlm->key = key; 19918c2ecf20Sopenharmony_ci dlm->node_num = o2nm_this_node(); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci dlm_create_debugfs_subroot(dlm); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci spin_lock_init(&dlm->spinlock); 19968c2ecf20Sopenharmony_ci spin_lock_init(&dlm->master_lock); 19978c2ecf20Sopenharmony_ci spin_lock_init(&dlm->ast_lock); 19988c2ecf20Sopenharmony_ci spin_lock_init(&dlm->track_lock); 19998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->list); 20008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->dirty_list); 20018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->reco.resources); 20028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->reco.node_data); 20038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->purge_list); 20048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->dlm_domain_handlers); 20058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->tracking_list); 20068c2ecf20Sopenharmony_ci dlm->reco.state = 0; 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->pending_asts); 20098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->pending_basts); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci mlog(0, "dlm->recovery_map=%p, &(dlm->recovery_map[0])=%p\n", 20128c2ecf20Sopenharmony_ci dlm->recovery_map, &(dlm->recovery_map[0])); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci memset(dlm->recovery_map, 0, sizeof(dlm->recovery_map)); 20158c2ecf20Sopenharmony_ci memset(dlm->live_nodes_map, 0, sizeof(dlm->live_nodes_map)); 20168c2ecf20Sopenharmony_ci memset(dlm->domain_map, 0, sizeof(dlm->domain_map)); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci dlm->dlm_thread_task = NULL; 20198c2ecf20Sopenharmony_ci dlm->dlm_reco_thread_task = NULL; 20208c2ecf20Sopenharmony_ci dlm->dlm_worker = NULL; 20218c2ecf20Sopenharmony_ci init_waitqueue_head(&dlm->dlm_thread_wq); 20228c2ecf20Sopenharmony_ci init_waitqueue_head(&dlm->dlm_reco_thread_wq); 20238c2ecf20Sopenharmony_ci init_waitqueue_head(&dlm->reco.event); 20248c2ecf20Sopenharmony_ci init_waitqueue_head(&dlm->ast_wq); 20258c2ecf20Sopenharmony_ci init_waitqueue_head(&dlm->migration_wq); 20268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->mle_hb_events); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci dlm->joining_node = DLM_LOCK_RES_OWNER_UNKNOWN; 20298c2ecf20Sopenharmony_ci init_waitqueue_head(&dlm->dlm_join_events); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci dlm->migrate_done = 0; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci dlm->reco.new_master = O2NM_INVALID_NODE_NUM; 20348c2ecf20Sopenharmony_ci dlm->reco.dead_node = O2NM_INVALID_NODE_NUM; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci atomic_set(&dlm->res_tot_count, 0); 20378c2ecf20Sopenharmony_ci atomic_set(&dlm->res_cur_count, 0); 20388c2ecf20Sopenharmony_ci for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) { 20398c2ecf20Sopenharmony_ci atomic_set(&dlm->mle_tot_count[i], 0); 20408c2ecf20Sopenharmony_ci atomic_set(&dlm->mle_cur_count[i], 0); 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci spin_lock_init(&dlm->work_lock); 20448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->work_list); 20458c2ecf20Sopenharmony_ci INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci kref_init(&dlm->dlm_refs); 20488c2ecf20Sopenharmony_ci dlm->dlm_state = DLM_CTXT_NEW; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dlm->dlm_eviction_callbacks); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci mlog(0, "context init: refcount %u\n", 20538c2ecf20Sopenharmony_ci kref_read(&dlm->dlm_refs)); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci ret = 0; 20568c2ecf20Sopenharmony_cileave: 20578c2ecf20Sopenharmony_ci if (ret < 0 && dlm) { 20588c2ecf20Sopenharmony_ci if (dlm->master_hash) 20598c2ecf20Sopenharmony_ci dlm_free_pagevec((void **)dlm->master_hash, 20608c2ecf20Sopenharmony_ci DLM_HASH_PAGES); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (dlm->lockres_hash) 20638c2ecf20Sopenharmony_ci dlm_free_pagevec((void **)dlm->lockres_hash, 20648c2ecf20Sopenharmony_ci DLM_HASH_PAGES); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci kfree(dlm->name); 20678c2ecf20Sopenharmony_ci kfree(dlm); 20688c2ecf20Sopenharmony_ci dlm = NULL; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci return dlm; 20718c2ecf20Sopenharmony_ci} 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci/* 20748c2ecf20Sopenharmony_ci * Compare a requested locking protocol version against the current one. 20758c2ecf20Sopenharmony_ci * 20768c2ecf20Sopenharmony_ci * If the major numbers are different, they are incompatible. 20778c2ecf20Sopenharmony_ci * If the current minor is greater than the request, they are incompatible. 20788c2ecf20Sopenharmony_ci * If the current minor is less than or equal to the request, they are 20798c2ecf20Sopenharmony_ci * compatible, and the requester should run at the current minor version. 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_cistatic int dlm_protocol_compare(struct dlm_protocol_version *existing, 20828c2ecf20Sopenharmony_ci struct dlm_protocol_version *request) 20838c2ecf20Sopenharmony_ci{ 20848c2ecf20Sopenharmony_ci if (existing->pv_major != request->pv_major) 20858c2ecf20Sopenharmony_ci return 1; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci if (existing->pv_minor > request->pv_minor) 20888c2ecf20Sopenharmony_ci return 1; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci if (existing->pv_minor < request->pv_minor) 20918c2ecf20Sopenharmony_ci request->pv_minor = existing->pv_minor; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci return 0; 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci/* 20978c2ecf20Sopenharmony_ci * dlm_register_domain: one-time setup per "domain". 20988c2ecf20Sopenharmony_ci * 20998c2ecf20Sopenharmony_ci * The filesystem passes in the requested locking version via proto. 21008c2ecf20Sopenharmony_ci * If registration was successful, proto will contain the negotiated 21018c2ecf20Sopenharmony_ci * locking protocol. 21028c2ecf20Sopenharmony_ci */ 21038c2ecf20Sopenharmony_cistruct dlm_ctxt * dlm_register_domain(const char *domain, 21048c2ecf20Sopenharmony_ci u32 key, 21058c2ecf20Sopenharmony_ci struct dlm_protocol_version *fs_proto) 21068c2ecf20Sopenharmony_ci{ 21078c2ecf20Sopenharmony_ci int ret; 21088c2ecf20Sopenharmony_ci struct dlm_ctxt *dlm = NULL; 21098c2ecf20Sopenharmony_ci struct dlm_ctxt *new_ctxt = NULL; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (strlen(domain) >= O2NM_MAX_NAME_LEN) { 21128c2ecf20Sopenharmony_ci ret = -ENAMETOOLONG; 21138c2ecf20Sopenharmony_ci mlog(ML_ERROR, "domain name length too long\n"); 21148c2ecf20Sopenharmony_ci goto leave; 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci mlog(0, "register called for domain \"%s\"\n", domain); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ciretry: 21208c2ecf20Sopenharmony_ci dlm = NULL; 21218c2ecf20Sopenharmony_ci if (signal_pending(current)) { 21228c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 21238c2ecf20Sopenharmony_ci mlog_errno(ret); 21248c2ecf20Sopenharmony_ci goto leave; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci spin_lock(&dlm_domain_lock); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci dlm = __dlm_lookup_domain(domain); 21308c2ecf20Sopenharmony_ci if (dlm) { 21318c2ecf20Sopenharmony_ci if (dlm->dlm_state != DLM_CTXT_JOINED) { 21328c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci mlog(0, "This ctxt is not joined yet!\n"); 21358c2ecf20Sopenharmony_ci wait_event_interruptible(dlm_domain_events, 21368c2ecf20Sopenharmony_ci dlm_wait_on_domain_helper( 21378c2ecf20Sopenharmony_ci domain)); 21388c2ecf20Sopenharmony_ci goto retry; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci if (dlm_protocol_compare(&dlm->fs_locking_proto, fs_proto)) { 21428c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 21438c2ecf20Sopenharmony_ci mlog(ML_ERROR, 21448c2ecf20Sopenharmony_ci "Requested locking protocol version is not " 21458c2ecf20Sopenharmony_ci "compatible with already registered domain " 21468c2ecf20Sopenharmony_ci "\"%s\"\n", domain); 21478c2ecf20Sopenharmony_ci ret = -EPROTO; 21488c2ecf20Sopenharmony_ci goto leave; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci __dlm_get(dlm); 21528c2ecf20Sopenharmony_ci dlm->num_joins++; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci ret = 0; 21578c2ecf20Sopenharmony_ci goto leave; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* doesn't exist */ 21618c2ecf20Sopenharmony_ci if (!new_ctxt) { 21628c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci new_ctxt = dlm_alloc_ctxt(domain, key); 21658c2ecf20Sopenharmony_ci if (new_ctxt) 21668c2ecf20Sopenharmony_ci goto retry; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci ret = -ENOMEM; 21698c2ecf20Sopenharmony_ci mlog_errno(ret); 21708c2ecf20Sopenharmony_ci goto leave; 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci /* a little variable switch-a-roo here... */ 21748c2ecf20Sopenharmony_ci dlm = new_ctxt; 21758c2ecf20Sopenharmony_ci new_ctxt = NULL; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci /* add the new domain */ 21788c2ecf20Sopenharmony_ci list_add_tail(&dlm->list, &dlm_domains); 21798c2ecf20Sopenharmony_ci spin_unlock(&dlm_domain_lock); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci /* 21828c2ecf20Sopenharmony_ci * Pass the locking protocol version into the join. If the join 21838c2ecf20Sopenharmony_ci * succeeds, it will have the negotiated protocol set. 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_ci dlm->dlm_locking_proto = dlm_protocol; 21868c2ecf20Sopenharmony_ci dlm->fs_locking_proto = *fs_proto; 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci ret = dlm_join_domain(dlm); 21898c2ecf20Sopenharmony_ci if (ret) { 21908c2ecf20Sopenharmony_ci mlog_errno(ret); 21918c2ecf20Sopenharmony_ci dlm_put(dlm); 21928c2ecf20Sopenharmony_ci goto leave; 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci /* Tell the caller what locking protocol we negotiated */ 21968c2ecf20Sopenharmony_ci *fs_proto = dlm->fs_locking_proto; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci ret = 0; 21998c2ecf20Sopenharmony_cileave: 22008c2ecf20Sopenharmony_ci if (new_ctxt) 22018c2ecf20Sopenharmony_ci dlm_free_ctxt_mem(new_ctxt); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (ret < 0) 22048c2ecf20Sopenharmony_ci dlm = ERR_PTR(ret); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci return dlm; 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dlm_register_domain); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_cistatic LIST_HEAD(dlm_join_handlers); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cistatic void dlm_unregister_net_handlers(void) 22138c2ecf20Sopenharmony_ci{ 22148c2ecf20Sopenharmony_ci o2net_unregister_handler_list(&dlm_join_handlers); 22158c2ecf20Sopenharmony_ci} 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_cistatic int dlm_register_net_handlers(void) 22188c2ecf20Sopenharmony_ci{ 22198c2ecf20Sopenharmony_ci int status = 0; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, 22228c2ecf20Sopenharmony_ci sizeof(struct dlm_query_join_request), 22238c2ecf20Sopenharmony_ci dlm_query_join_handler, 22248c2ecf20Sopenharmony_ci NULL, NULL, &dlm_join_handlers); 22258c2ecf20Sopenharmony_ci if (status) 22268c2ecf20Sopenharmony_ci goto bail; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY, 22298c2ecf20Sopenharmony_ci sizeof(struct dlm_assert_joined), 22308c2ecf20Sopenharmony_ci dlm_assert_joined_handler, 22318c2ecf20Sopenharmony_ci NULL, NULL, &dlm_join_handlers); 22328c2ecf20Sopenharmony_ci if (status) 22338c2ecf20Sopenharmony_ci goto bail; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY, 22368c2ecf20Sopenharmony_ci sizeof(struct dlm_cancel_join), 22378c2ecf20Sopenharmony_ci dlm_cancel_join_handler, 22388c2ecf20Sopenharmony_ci NULL, NULL, &dlm_join_handlers); 22398c2ecf20Sopenharmony_ci if (status) 22408c2ecf20Sopenharmony_ci goto bail; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_QUERY_REGION, DLM_MOD_KEY, 22438c2ecf20Sopenharmony_ci sizeof(struct dlm_query_region), 22448c2ecf20Sopenharmony_ci dlm_query_region_handler, 22458c2ecf20Sopenharmony_ci NULL, NULL, &dlm_join_handlers); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci if (status) 22488c2ecf20Sopenharmony_ci goto bail; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci status = o2net_register_handler(DLM_QUERY_NODEINFO, DLM_MOD_KEY, 22518c2ecf20Sopenharmony_ci sizeof(struct dlm_query_nodeinfo), 22528c2ecf20Sopenharmony_ci dlm_query_nodeinfo_handler, 22538c2ecf20Sopenharmony_ci NULL, NULL, &dlm_join_handlers); 22548c2ecf20Sopenharmony_cibail: 22558c2ecf20Sopenharmony_ci if (status < 0) 22568c2ecf20Sopenharmony_ci dlm_unregister_net_handlers(); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci return status; 22598c2ecf20Sopenharmony_ci} 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci/* Domain eviction callback handling. 22628c2ecf20Sopenharmony_ci * 22638c2ecf20Sopenharmony_ci * The file system requires notification of node death *before* the 22648c2ecf20Sopenharmony_ci * dlm completes it's recovery work, otherwise it may be able to 22658c2ecf20Sopenharmony_ci * acquire locks on resources requiring recovery. Since the dlm can 22668c2ecf20Sopenharmony_ci * evict a node from it's domain *before* heartbeat fires, a similar 22678c2ecf20Sopenharmony_ci * mechanism is required. */ 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci/* Eviction is not expected to happen often, so a per-domain lock is 22708c2ecf20Sopenharmony_ci * not necessary. Eviction callbacks are allowed to sleep for short 22718c2ecf20Sopenharmony_ci * periods of time. */ 22728c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(dlm_callback_sem); 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_civoid dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm, 22758c2ecf20Sopenharmony_ci int node_num) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci struct dlm_eviction_cb *cb; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci down_read(&dlm_callback_sem); 22808c2ecf20Sopenharmony_ci list_for_each_entry(cb, &dlm->dlm_eviction_callbacks, ec_item) { 22818c2ecf20Sopenharmony_ci cb->ec_func(node_num, cb->ec_data); 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci up_read(&dlm_callback_sem); 22848c2ecf20Sopenharmony_ci} 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_civoid dlm_setup_eviction_cb(struct dlm_eviction_cb *cb, 22878c2ecf20Sopenharmony_ci dlm_eviction_func *f, 22888c2ecf20Sopenharmony_ci void *data) 22898c2ecf20Sopenharmony_ci{ 22908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cb->ec_item); 22918c2ecf20Sopenharmony_ci cb->ec_func = f; 22928c2ecf20Sopenharmony_ci cb->ec_data = data; 22938c2ecf20Sopenharmony_ci} 22948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dlm_setup_eviction_cb); 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_civoid dlm_register_eviction_cb(struct dlm_ctxt *dlm, 22978c2ecf20Sopenharmony_ci struct dlm_eviction_cb *cb) 22988c2ecf20Sopenharmony_ci{ 22998c2ecf20Sopenharmony_ci down_write(&dlm_callback_sem); 23008c2ecf20Sopenharmony_ci list_add_tail(&cb->ec_item, &dlm->dlm_eviction_callbacks); 23018c2ecf20Sopenharmony_ci up_write(&dlm_callback_sem); 23028c2ecf20Sopenharmony_ci} 23038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dlm_register_eviction_cb); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_civoid dlm_unregister_eviction_cb(struct dlm_eviction_cb *cb) 23068c2ecf20Sopenharmony_ci{ 23078c2ecf20Sopenharmony_ci down_write(&dlm_callback_sem); 23088c2ecf20Sopenharmony_ci list_del_init(&cb->ec_item); 23098c2ecf20Sopenharmony_ci up_write(&dlm_callback_sem); 23108c2ecf20Sopenharmony_ci} 23118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dlm_unregister_eviction_cb); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_cistatic int __init dlm_init(void) 23148c2ecf20Sopenharmony_ci{ 23158c2ecf20Sopenharmony_ci int status; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci status = dlm_init_mle_cache(); 23188c2ecf20Sopenharmony_ci if (status) { 23198c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Could not create o2dlm_mle slabcache\n"); 23208c2ecf20Sopenharmony_ci goto error; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci status = dlm_init_master_caches(); 23248c2ecf20Sopenharmony_ci if (status) { 23258c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Could not create o2dlm_lockres and " 23268c2ecf20Sopenharmony_ci "o2dlm_lockname slabcaches\n"); 23278c2ecf20Sopenharmony_ci goto error; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci status = dlm_init_lock_cache(); 23318c2ecf20Sopenharmony_ci if (status) { 23328c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Count not create o2dlm_lock slabcache\n"); 23338c2ecf20Sopenharmony_ci goto error; 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci status = dlm_register_net_handlers(); 23378c2ecf20Sopenharmony_ci if (status) { 23388c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Unable to register network handlers\n"); 23398c2ecf20Sopenharmony_ci goto error; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci dlm_create_debugfs_root(); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci return 0; 23458c2ecf20Sopenharmony_cierror: 23468c2ecf20Sopenharmony_ci dlm_unregister_net_handlers(); 23478c2ecf20Sopenharmony_ci dlm_destroy_lock_cache(); 23488c2ecf20Sopenharmony_ci dlm_destroy_master_caches(); 23498c2ecf20Sopenharmony_ci dlm_destroy_mle_cache(); 23508c2ecf20Sopenharmony_ci return -1; 23518c2ecf20Sopenharmony_ci} 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_cistatic void __exit dlm_exit (void) 23548c2ecf20Sopenharmony_ci{ 23558c2ecf20Sopenharmony_ci dlm_destroy_debugfs_root(); 23568c2ecf20Sopenharmony_ci dlm_unregister_net_handlers(); 23578c2ecf20Sopenharmony_ci dlm_destroy_lock_cache(); 23588c2ecf20Sopenharmony_ci dlm_destroy_master_caches(); 23598c2ecf20Sopenharmony_ci dlm_destroy_mle_cache(); 23608c2ecf20Sopenharmony_ci} 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Oracle"); 23638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 23648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OCFS2 Distributed Lock Management"); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_cimodule_init(dlm_init); 23678c2ecf20Sopenharmony_cimodule_exit(dlm_exit); 2368