16714d8e8SKurt Hackel /* -*- mode: c; c-basic-offset: 8; -*- 26714d8e8SKurt Hackel * vim: noexpandtab sw=8 ts=8 sts=0: 36714d8e8SKurt Hackel * 46714d8e8SKurt Hackel * dlmdomain.c 56714d8e8SKurt Hackel * 66714d8e8SKurt Hackel * defines domain join / leave apis 76714d8e8SKurt Hackel * 86714d8e8SKurt Hackel * Copyright (C) 2004 Oracle. All rights reserved. 96714d8e8SKurt Hackel * 106714d8e8SKurt Hackel * This program is free software; you can redistribute it and/or 116714d8e8SKurt Hackel * modify it under the terms of the GNU General Public 126714d8e8SKurt Hackel * License as published by the Free Software Foundation; either 136714d8e8SKurt Hackel * version 2 of the License, or (at your option) any later version. 146714d8e8SKurt Hackel * 156714d8e8SKurt Hackel * This program is distributed in the hope that it will be useful, 166714d8e8SKurt Hackel * but WITHOUT ANY WARRANTY; without even the implied warranty of 176714d8e8SKurt Hackel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 186714d8e8SKurt Hackel * General Public License for more details. 196714d8e8SKurt Hackel * 206714d8e8SKurt Hackel * You should have received a copy of the GNU General Public 216714d8e8SKurt Hackel * License along with this program; if not, write to the 226714d8e8SKurt Hackel * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 236714d8e8SKurt Hackel * Boston, MA 021110-1307, USA. 246714d8e8SKurt Hackel * 256714d8e8SKurt Hackel */ 266714d8e8SKurt Hackel 276714d8e8SKurt Hackel #include <linux/module.h> 286714d8e8SKurt Hackel #include <linux/types.h> 296714d8e8SKurt Hackel #include <linux/slab.h> 306714d8e8SKurt Hackel #include <linux/highmem.h> 316714d8e8SKurt Hackel #include <linux/utsname.h> 326714d8e8SKurt Hackel #include <linux/init.h> 336714d8e8SKurt Hackel #include <linux/spinlock.h> 346714d8e8SKurt Hackel #include <linux/delay.h> 356714d8e8SKurt Hackel #include <linux/err.h> 366325b4a2SSunil Mushran #include <linux/debugfs.h> 376714d8e8SKurt Hackel 386714d8e8SKurt Hackel #include "cluster/heartbeat.h" 396714d8e8SKurt Hackel #include "cluster/nodemanager.h" 406714d8e8SKurt Hackel #include "cluster/tcp.h" 416714d8e8SKurt Hackel 426714d8e8SKurt Hackel #include "dlmapi.h" 436714d8e8SKurt Hackel #include "dlmcommon.h" 446714d8e8SKurt Hackel #include "dlmdomain.h" 456325b4a2SSunil Mushran #include "dlmdebug.h" 466714d8e8SKurt Hackel 476714d8e8SKurt Hackel #include "dlmver.h" 486714d8e8SKurt Hackel 496714d8e8SKurt Hackel #define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_DOMAIN) 506714d8e8SKurt Hackel #include "cluster/masklog.h" 516714d8e8SKurt Hackel 521faf2894SSrinivas Eeda /* 531faf2894SSrinivas Eeda * ocfs2 node maps are array of long int, which limits to send them freely 541faf2894SSrinivas Eeda * across the wire due to endianness issues. To workaround this, we convert 551faf2894SSrinivas Eeda * long ints to byte arrays. Following 3 routines are helper functions to 561faf2894SSrinivas Eeda * set/test/copy bits within those array of bytes 571faf2894SSrinivas Eeda */ 581faf2894SSrinivas Eeda static inline void byte_set_bit(u8 nr, u8 map[]) 591faf2894SSrinivas Eeda { 601faf2894SSrinivas Eeda map[nr >> 3] |= (1UL << (nr & 7)); 611faf2894SSrinivas Eeda } 621faf2894SSrinivas Eeda 631faf2894SSrinivas Eeda static inline int byte_test_bit(u8 nr, u8 map[]) 641faf2894SSrinivas Eeda { 651faf2894SSrinivas Eeda return ((1UL << (nr & 7)) & (map[nr >> 3])) != 0; 661faf2894SSrinivas Eeda } 671faf2894SSrinivas Eeda 681faf2894SSrinivas Eeda static inline void byte_copymap(u8 dmap[], unsigned long smap[], 691faf2894SSrinivas Eeda unsigned int sz) 701faf2894SSrinivas Eeda { 711faf2894SSrinivas Eeda unsigned int nn; 721faf2894SSrinivas Eeda 731faf2894SSrinivas Eeda if (!sz) 741faf2894SSrinivas Eeda return; 751faf2894SSrinivas Eeda 761faf2894SSrinivas Eeda memset(dmap, 0, ((sz + 7) >> 3)); 771faf2894SSrinivas Eeda for (nn = 0 ; nn < sz; nn++) 781faf2894SSrinivas Eeda if (test_bit(nn, smap)) 791faf2894SSrinivas Eeda byte_set_bit(nn, dmap); 801faf2894SSrinivas Eeda } 811faf2894SSrinivas Eeda 8203d864c0SDaniel Phillips static void dlm_free_pagevec(void **vec, int pages) 8303d864c0SDaniel Phillips { 8403d864c0SDaniel Phillips while (pages--) 8503d864c0SDaniel Phillips free_page((unsigned long)vec[pages]); 8603d864c0SDaniel Phillips kfree(vec); 8703d864c0SDaniel Phillips } 8803d864c0SDaniel Phillips 8903d864c0SDaniel Phillips static void **dlm_alloc_pagevec(int pages) 9003d864c0SDaniel Phillips { 9103d864c0SDaniel Phillips void **vec = kmalloc(pages * sizeof(void *), GFP_KERNEL); 9203d864c0SDaniel Phillips int i; 9303d864c0SDaniel Phillips 9403d864c0SDaniel Phillips if (!vec) 9503d864c0SDaniel Phillips return NULL; 9603d864c0SDaniel Phillips 9703d864c0SDaniel Phillips for (i = 0; i < pages; i++) 9803d864c0SDaniel Phillips if (!(vec[i] = (void *)__get_free_page(GFP_KERNEL))) 9903d864c0SDaniel Phillips goto out_free; 100c8f33b6eSJoel Becker 101685f1adbSMark Fasheh mlog(0, "Allocated DLM hash pagevec; %d pages (%lu expected), %lu buckets per page\n", 102f5a923d1SMark Fasheh pages, (unsigned long)DLM_HASH_PAGES, 103f5a923d1SMark Fasheh (unsigned long)DLM_BUCKETS_PER_PAGE); 10403d864c0SDaniel Phillips return vec; 10503d864c0SDaniel Phillips out_free: 10603d864c0SDaniel Phillips dlm_free_pagevec(vec, i); 10703d864c0SDaniel Phillips return NULL; 10803d864c0SDaniel Phillips } 10903d864c0SDaniel Phillips 1106714d8e8SKurt Hackel /* 1116714d8e8SKurt Hackel * 1126714d8e8SKurt Hackel * spinlock lock ordering: if multiple locks are needed, obey this ordering: 1136714d8e8SKurt Hackel * dlm_domain_lock 1146714d8e8SKurt Hackel * struct dlm_ctxt->spinlock 1156714d8e8SKurt Hackel * struct dlm_lock_resource->spinlock 1166714d8e8SKurt Hackel * struct dlm_ctxt->master_lock 1176714d8e8SKurt Hackel * struct dlm_ctxt->ast_lock 1186714d8e8SKurt Hackel * dlm_master_list_entry->spinlock 1196714d8e8SKurt Hackel * dlm_lock->spinlock 1206714d8e8SKurt Hackel * 1216714d8e8SKurt Hackel */ 1226714d8e8SKurt Hackel 12334af946aSIngo Molnar DEFINE_SPINLOCK(dlm_domain_lock); 1246714d8e8SKurt Hackel LIST_HEAD(dlm_domains); 1256714d8e8SKurt Hackel static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); 1266714d8e8SKurt Hackel 127d24fbcdaSJoel Becker /* 128d24fbcdaSJoel Becker * The supported protocol version for DLM communication. Running domains 129d24fbcdaSJoel Becker * will have a negotiated version with the same major number and a minor 130d24fbcdaSJoel Becker * number equal or smaller. The dlm_ctxt->dlm_locking_proto field should 131d24fbcdaSJoel Becker * be used to determine what a running domain is actually using. 132d24fbcdaSJoel Becker */ 133d24fbcdaSJoel Becker static const struct dlm_protocol_version dlm_protocol = { 134d24fbcdaSJoel Becker .pv_major = 1, 135d24fbcdaSJoel Becker .pv_minor = 0, 136d24fbcdaSJoel Becker }; 137d24fbcdaSJoel Becker 1386714d8e8SKurt Hackel #define DLM_DOMAIN_BACKOFF_MS 200 1396714d8e8SKurt Hackel 140d74c9803SKurt Hackel static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, 141d74c9803SKurt Hackel void **ret_data); 142d74c9803SKurt Hackel static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, 143d74c9803SKurt Hackel void **ret_data); 144d74c9803SKurt Hackel static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, 145d74c9803SKurt Hackel void **ret_data); 146d74c9803SKurt Hackel static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, 147d74c9803SKurt Hackel void **ret_data); 148d24fbcdaSJoel Becker static int dlm_protocol_compare(struct dlm_protocol_version *existing, 149d24fbcdaSJoel Becker struct dlm_protocol_version *request); 1506714d8e8SKurt Hackel 1516714d8e8SKurt Hackel static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); 1526714d8e8SKurt Hackel 1536714d8e8SKurt Hackel void __dlm_unhash_lockres(struct dlm_lock_resource *lockres) 1546714d8e8SKurt Hackel { 15578062cb2SSunil Mushran if (!hlist_unhashed(&lockres->hash_node)) { 15681f2094aSMark Fasheh hlist_del_init(&lockres->hash_node); 1576714d8e8SKurt Hackel dlm_lockres_put(lockres); 1586714d8e8SKurt Hackel } 15978062cb2SSunil Mushran } 1606714d8e8SKurt Hackel 1616714d8e8SKurt Hackel void __dlm_insert_lockres(struct dlm_ctxt *dlm, 1626714d8e8SKurt Hackel struct dlm_lock_resource *res) 1636714d8e8SKurt Hackel { 16481f2094aSMark Fasheh struct hlist_head *bucket; 1656714d8e8SKurt Hackel struct qstr *q; 1666714d8e8SKurt Hackel 1676714d8e8SKurt Hackel assert_spin_locked(&dlm->spinlock); 1686714d8e8SKurt Hackel 1696714d8e8SKurt Hackel q = &res->lockname; 17003d864c0SDaniel Phillips bucket = dlm_lockres_hash(dlm, q->hash); 1716714d8e8SKurt Hackel 1726714d8e8SKurt Hackel /* get a reference for our hashtable */ 1736714d8e8SKurt Hackel dlm_lockres_get(res); 1746714d8e8SKurt Hackel 17581f2094aSMark Fasheh hlist_add_head(&res->hash_node, bucket); 1766714d8e8SKurt Hackel } 1776714d8e8SKurt Hackel 178ba2bf218SKurt Hackel struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm, 1796714d8e8SKurt Hackel const char *name, 180a3d33291SMark Fasheh unsigned int len, 181a3d33291SMark Fasheh unsigned int hash) 1826714d8e8SKurt Hackel { 18381f2094aSMark Fasheh struct hlist_head *bucket; 1844198985fSDaniel Phillips struct hlist_node *list; 1856714d8e8SKurt Hackel 1866714d8e8SKurt Hackel mlog_entry("%.*s\n", len, name); 1876714d8e8SKurt Hackel 1886714d8e8SKurt Hackel assert_spin_locked(&dlm->spinlock); 1896714d8e8SKurt Hackel 19003d864c0SDaniel Phillips bucket = dlm_lockres_hash(dlm, hash); 19103d864c0SDaniel Phillips 1924198985fSDaniel Phillips hlist_for_each(list, bucket) { 1934198985fSDaniel Phillips struct dlm_lock_resource *res = hlist_entry(list, 1944198985fSDaniel Phillips struct dlm_lock_resource, hash_node); 1954198985fSDaniel Phillips if (res->lockname.name[0] != name[0]) 1964198985fSDaniel Phillips continue; 1974198985fSDaniel Phillips if (unlikely(res->lockname.len != len)) 1984198985fSDaniel Phillips continue; 1994198985fSDaniel Phillips if (memcmp(res->lockname.name + 1, name + 1, len - 1)) 2004198985fSDaniel Phillips continue; 2014198985fSDaniel Phillips dlm_lockres_get(res); 2024198985fSDaniel Phillips return res; 2036714d8e8SKurt Hackel } 2044198985fSDaniel Phillips return NULL; 2056714d8e8SKurt Hackel } 2066714d8e8SKurt Hackel 207ba2bf218SKurt Hackel /* intended to be called by functions which do not care about lock 208ba2bf218SKurt Hackel * resources which are being purged (most net _handler functions). 209ba2bf218SKurt Hackel * this will return NULL for any lock resource which is found but 210ba2bf218SKurt Hackel * currently in the process of dropping its mastery reference. 211ba2bf218SKurt Hackel * use __dlm_lookup_lockres_full when you need the lock resource 212ba2bf218SKurt Hackel * regardless (e.g. dlm_get_lock_resource) */ 213ba2bf218SKurt Hackel struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, 214ba2bf218SKurt Hackel const char *name, 215ba2bf218SKurt Hackel unsigned int len, 216ba2bf218SKurt Hackel unsigned int hash) 217ba2bf218SKurt Hackel { 218ba2bf218SKurt Hackel struct dlm_lock_resource *res = NULL; 219ba2bf218SKurt Hackel 220ba2bf218SKurt Hackel mlog_entry("%.*s\n", len, name); 221ba2bf218SKurt Hackel 222ba2bf218SKurt Hackel assert_spin_locked(&dlm->spinlock); 223ba2bf218SKurt Hackel 224ba2bf218SKurt Hackel res = __dlm_lookup_lockres_full(dlm, name, len, hash); 225ba2bf218SKurt Hackel if (res) { 226ba2bf218SKurt Hackel spin_lock(&res->spinlock); 227ba2bf218SKurt Hackel if (res->state & DLM_LOCK_RES_DROPPING_REF) { 228ba2bf218SKurt Hackel spin_unlock(&res->spinlock); 229ba2bf218SKurt Hackel dlm_lockres_put(res); 230ba2bf218SKurt Hackel return NULL; 231ba2bf218SKurt Hackel } 232ba2bf218SKurt Hackel spin_unlock(&res->spinlock); 233ba2bf218SKurt Hackel } 234ba2bf218SKurt Hackel 235ba2bf218SKurt Hackel return res; 236ba2bf218SKurt Hackel } 237ba2bf218SKurt Hackel 2386714d8e8SKurt Hackel struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm, 2396714d8e8SKurt Hackel const char *name, 2406714d8e8SKurt Hackel unsigned int len) 2416714d8e8SKurt Hackel { 2426714d8e8SKurt Hackel struct dlm_lock_resource *res; 243a3d33291SMark Fasheh unsigned int hash = dlm_lockid_hash(name, len); 2446714d8e8SKurt Hackel 2456714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 246a3d33291SMark Fasheh res = __dlm_lookup_lockres(dlm, name, len, hash); 2476714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 2486714d8e8SKurt Hackel return res; 2496714d8e8SKurt Hackel } 2506714d8e8SKurt Hackel 2516714d8e8SKurt Hackel static struct dlm_ctxt * __dlm_lookup_domain_full(const char *domain, int len) 2526714d8e8SKurt Hackel { 2536714d8e8SKurt Hackel struct dlm_ctxt *tmp = NULL; 2546714d8e8SKurt Hackel struct list_head *iter; 2556714d8e8SKurt Hackel 2566714d8e8SKurt Hackel assert_spin_locked(&dlm_domain_lock); 2576714d8e8SKurt Hackel 2586714d8e8SKurt Hackel /* tmp->name here is always NULL terminated, 2596714d8e8SKurt Hackel * but domain may not be! */ 2606714d8e8SKurt Hackel list_for_each(iter, &dlm_domains) { 2616714d8e8SKurt Hackel tmp = list_entry (iter, struct dlm_ctxt, list); 2626714d8e8SKurt Hackel if (strlen(tmp->name) == len && 2636714d8e8SKurt Hackel memcmp(tmp->name, domain, len)==0) 2646714d8e8SKurt Hackel break; 2656714d8e8SKurt Hackel tmp = NULL; 2666714d8e8SKurt Hackel } 2676714d8e8SKurt Hackel 2686714d8e8SKurt Hackel return tmp; 2696714d8e8SKurt Hackel } 2706714d8e8SKurt Hackel 2716714d8e8SKurt Hackel /* For null terminated domain strings ONLY */ 2726714d8e8SKurt Hackel static struct dlm_ctxt * __dlm_lookup_domain(const char *domain) 2736714d8e8SKurt Hackel { 2746714d8e8SKurt Hackel assert_spin_locked(&dlm_domain_lock); 2756714d8e8SKurt Hackel 2766714d8e8SKurt Hackel return __dlm_lookup_domain_full(domain, strlen(domain)); 2776714d8e8SKurt Hackel } 2786714d8e8SKurt Hackel 2796714d8e8SKurt Hackel 2806714d8e8SKurt Hackel /* returns true on one of two conditions: 2816714d8e8SKurt Hackel * 1) the domain does not exist 2826714d8e8SKurt Hackel * 2) the domain exists and it's state is "joined" */ 2836714d8e8SKurt Hackel static int dlm_wait_on_domain_helper(const char *domain) 2846714d8e8SKurt Hackel { 2856714d8e8SKurt Hackel int ret = 0; 2866714d8e8SKurt Hackel struct dlm_ctxt *tmp = NULL; 2876714d8e8SKurt Hackel 2886714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 2896714d8e8SKurt Hackel 2906714d8e8SKurt Hackel tmp = __dlm_lookup_domain(domain); 2916714d8e8SKurt Hackel if (!tmp) 2926714d8e8SKurt Hackel ret = 1; 2936714d8e8SKurt Hackel else if (tmp->dlm_state == DLM_CTXT_JOINED) 2946714d8e8SKurt Hackel ret = 1; 2956714d8e8SKurt Hackel 2966714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 2976714d8e8SKurt Hackel return ret; 2986714d8e8SKurt Hackel } 2996714d8e8SKurt Hackel 3006714d8e8SKurt Hackel static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm) 3016714d8e8SKurt Hackel { 3026325b4a2SSunil Mushran dlm_destroy_debugfs_subroot(dlm); 3036325b4a2SSunil Mushran 30481f2094aSMark Fasheh if (dlm->lockres_hash) 30503d864c0SDaniel Phillips dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); 3066714d8e8SKurt Hackel 307e2b66ddcSSunil Mushran if (dlm->master_hash) 308e2b66ddcSSunil Mushran dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES); 309e2b66ddcSSunil Mushran 3106714d8e8SKurt Hackel if (dlm->name) 3116714d8e8SKurt Hackel kfree(dlm->name); 3126714d8e8SKurt Hackel 3136714d8e8SKurt Hackel kfree(dlm); 3146714d8e8SKurt Hackel } 3156714d8e8SKurt Hackel 3166714d8e8SKurt Hackel /* A little strange - this function will be called while holding 3176714d8e8SKurt Hackel * dlm_domain_lock and is expected to be holding it on the way out. We 3186714d8e8SKurt Hackel * will however drop and reacquire it multiple times */ 3196714d8e8SKurt Hackel static void dlm_ctxt_release(struct kref *kref) 3206714d8e8SKurt Hackel { 3216714d8e8SKurt Hackel struct dlm_ctxt *dlm; 3226714d8e8SKurt Hackel 3236714d8e8SKurt Hackel dlm = container_of(kref, struct dlm_ctxt, dlm_refs); 3246714d8e8SKurt Hackel 3256714d8e8SKurt Hackel BUG_ON(dlm->num_joins); 3266714d8e8SKurt Hackel BUG_ON(dlm->dlm_state == DLM_CTXT_JOINED); 3276714d8e8SKurt Hackel 3286714d8e8SKurt Hackel /* we may still be in the list if we hit an error during join. */ 3296714d8e8SKurt Hackel list_del_init(&dlm->list); 3306714d8e8SKurt Hackel 3316714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 3326714d8e8SKurt Hackel 3336714d8e8SKurt Hackel mlog(0, "freeing memory from domain %s\n", dlm->name); 3346714d8e8SKurt Hackel 3356714d8e8SKurt Hackel wake_up(&dlm_domain_events); 3366714d8e8SKurt Hackel 3376714d8e8SKurt Hackel dlm_free_ctxt_mem(dlm); 3386714d8e8SKurt Hackel 3396714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 3406714d8e8SKurt Hackel } 3416714d8e8SKurt Hackel 3426714d8e8SKurt Hackel void dlm_put(struct dlm_ctxt *dlm) 3436714d8e8SKurt Hackel { 3446714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 3456714d8e8SKurt Hackel kref_put(&dlm->dlm_refs, dlm_ctxt_release); 3466714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 3476714d8e8SKurt Hackel } 3486714d8e8SKurt Hackel 3496714d8e8SKurt Hackel static void __dlm_get(struct dlm_ctxt *dlm) 3506714d8e8SKurt Hackel { 3516714d8e8SKurt Hackel kref_get(&dlm->dlm_refs); 3526714d8e8SKurt Hackel } 3536714d8e8SKurt Hackel 3546714d8e8SKurt Hackel /* given a questionable reference to a dlm object, gets a reference if 3556714d8e8SKurt Hackel * it can find it in the list, otherwise returns NULL in which case 3566714d8e8SKurt Hackel * you shouldn't trust your pointer. */ 3576714d8e8SKurt Hackel struct dlm_ctxt *dlm_grab(struct dlm_ctxt *dlm) 3586714d8e8SKurt Hackel { 3596714d8e8SKurt Hackel struct list_head *iter; 3606714d8e8SKurt Hackel struct dlm_ctxt *target = NULL; 3616714d8e8SKurt Hackel 3626714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 3636714d8e8SKurt Hackel 3646714d8e8SKurt Hackel list_for_each(iter, &dlm_domains) { 3656714d8e8SKurt Hackel target = list_entry (iter, struct dlm_ctxt, list); 3666714d8e8SKurt Hackel 3676714d8e8SKurt Hackel if (target == dlm) { 3686714d8e8SKurt Hackel __dlm_get(target); 3696714d8e8SKurt Hackel break; 3706714d8e8SKurt Hackel } 3716714d8e8SKurt Hackel 3726714d8e8SKurt Hackel target = NULL; 3736714d8e8SKurt Hackel } 3746714d8e8SKurt Hackel 3756714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 3766714d8e8SKurt Hackel 3776714d8e8SKurt Hackel return target; 3786714d8e8SKurt Hackel } 3796714d8e8SKurt Hackel 3806714d8e8SKurt Hackel int dlm_domain_fully_joined(struct dlm_ctxt *dlm) 3816714d8e8SKurt Hackel { 3826714d8e8SKurt Hackel int ret; 3836714d8e8SKurt Hackel 3846714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 3856714d8e8SKurt Hackel ret = (dlm->dlm_state == DLM_CTXT_JOINED) || 3866714d8e8SKurt Hackel (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN); 3876714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 3886714d8e8SKurt Hackel 3896714d8e8SKurt Hackel return ret; 3906714d8e8SKurt Hackel } 3916714d8e8SKurt Hackel 3923156d267SKurt Hackel static void dlm_destroy_dlm_worker(struct dlm_ctxt *dlm) 3933156d267SKurt Hackel { 3943156d267SKurt Hackel if (dlm->dlm_worker) { 3953156d267SKurt Hackel flush_workqueue(dlm->dlm_worker); 3963156d267SKurt Hackel destroy_workqueue(dlm->dlm_worker); 3973156d267SKurt Hackel dlm->dlm_worker = NULL; 3983156d267SKurt Hackel } 3993156d267SKurt Hackel } 4003156d267SKurt Hackel 4016714d8e8SKurt Hackel static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm) 4026714d8e8SKurt Hackel { 4036714d8e8SKurt Hackel dlm_unregister_domain_handlers(dlm); 404007dce53SSunil Mushran dlm_debug_shutdown(dlm); 4056714d8e8SKurt Hackel dlm_complete_thread(dlm); 4066714d8e8SKurt Hackel dlm_complete_recovery_thread(dlm); 4073156d267SKurt Hackel dlm_destroy_dlm_worker(dlm); 4086714d8e8SKurt Hackel 4096714d8e8SKurt Hackel /* We've left the domain. Now we can take ourselves out of the 4106714d8e8SKurt Hackel * list and allow the kref stuff to help us free the 4116714d8e8SKurt Hackel * memory. */ 4126714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 4136714d8e8SKurt Hackel list_del_init(&dlm->list); 4146714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 4156714d8e8SKurt Hackel 4166714d8e8SKurt Hackel /* Wake up anyone waiting for us to remove this domain */ 4176714d8e8SKurt Hackel wake_up(&dlm_domain_events); 4186714d8e8SKurt Hackel } 4196714d8e8SKurt Hackel 420ba2bf218SKurt Hackel static int dlm_migrate_all_locks(struct dlm_ctxt *dlm) 4216714d8e8SKurt Hackel { 422ba2bf218SKurt Hackel int i, num, n, ret = 0; 4236714d8e8SKurt Hackel struct dlm_lock_resource *res; 424ba2bf218SKurt Hackel struct hlist_node *iter; 425ba2bf218SKurt Hackel struct hlist_head *bucket; 426ba2bf218SKurt Hackel int dropped; 4276714d8e8SKurt Hackel 4286714d8e8SKurt Hackel mlog(0, "Migrating locks from domain %s\n", dlm->name); 429ba2bf218SKurt Hackel 430ba2bf218SKurt Hackel num = 0; 4316714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 43281f2094aSMark Fasheh for (i = 0; i < DLM_HASH_BUCKETS; i++) { 433ba2bf218SKurt Hackel redo_bucket: 434ba2bf218SKurt Hackel n = 0; 435ba2bf218SKurt Hackel bucket = dlm_lockres_hash(dlm, i); 436ba2bf218SKurt Hackel iter = bucket->first; 437ba2bf218SKurt Hackel while (iter) { 438ba2bf218SKurt Hackel n++; 439ba2bf218SKurt Hackel res = hlist_entry(iter, struct dlm_lock_resource, 440ba2bf218SKurt Hackel hash_node); 4416714d8e8SKurt Hackel dlm_lockres_get(res); 442ba2bf218SKurt Hackel /* migrate, if necessary. this will drop the dlm 443ba2bf218SKurt Hackel * spinlock and retake it if it does migration. */ 444ba2bf218SKurt Hackel dropped = dlm_empty_lockres(dlm, res); 4456714d8e8SKurt Hackel 446ba2bf218SKurt Hackel spin_lock(&res->spinlock); 447ba2bf218SKurt Hackel __dlm_lockres_calc_usage(dlm, res); 448ba2bf218SKurt Hackel iter = res->hash_node.next; 449ba2bf218SKurt Hackel spin_unlock(&res->spinlock); 450ba2bf218SKurt Hackel 4516714d8e8SKurt Hackel dlm_lockres_put(res); 452ba2bf218SKurt Hackel 453ba2bf218SKurt Hackel if (dropped) 454ba2bf218SKurt Hackel goto redo_bucket; 4556714d8e8SKurt Hackel } 4560d01af6eSSunil Mushran cond_resched_lock(&dlm->spinlock); 457ba2bf218SKurt Hackel num += n; 458ba2bf218SKurt Hackel mlog(0, "%s: touched %d lockreses in bucket %d " 459ba2bf218SKurt Hackel "(tot=%d)\n", dlm->name, n, i, num); 4606714d8e8SKurt Hackel } 4616714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 462ba2bf218SKurt Hackel wake_up(&dlm->dlm_thread_wq); 4636714d8e8SKurt Hackel 464ba2bf218SKurt Hackel /* let the dlm thread take care of purging, keep scanning until 465ba2bf218SKurt Hackel * nothing remains in the hash */ 466ba2bf218SKurt Hackel if (num) { 467ba2bf218SKurt Hackel mlog(0, "%s: %d lock resources in hash last pass\n", 468ba2bf218SKurt Hackel dlm->name, num); 469ba2bf218SKurt Hackel ret = -EAGAIN; 470ba2bf218SKurt Hackel } 4716714d8e8SKurt Hackel mlog(0, "DONE Migrating locks from domain %s\n", dlm->name); 472ba2bf218SKurt Hackel return ret; 4736714d8e8SKurt Hackel } 4746714d8e8SKurt Hackel 4756714d8e8SKurt Hackel static int dlm_no_joining_node(struct dlm_ctxt *dlm) 4766714d8e8SKurt Hackel { 4776714d8e8SKurt Hackel int ret; 4786714d8e8SKurt Hackel 4796714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 4806714d8e8SKurt Hackel ret = dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN; 4816714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 4826714d8e8SKurt Hackel 4836714d8e8SKurt Hackel return ret; 4846714d8e8SKurt Hackel } 4856714d8e8SKurt Hackel 4866714d8e8SKurt Hackel static void dlm_mark_domain_leaving(struct dlm_ctxt *dlm) 4876714d8e8SKurt Hackel { 4886714d8e8SKurt Hackel /* Yikes, a double spinlock! I need domain_lock for the dlm 4896714d8e8SKurt Hackel * state and the dlm spinlock for join state... Sorry! */ 4906714d8e8SKurt Hackel again: 4916714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 4926714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 4936714d8e8SKurt Hackel 4946714d8e8SKurt Hackel if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { 4956714d8e8SKurt Hackel mlog(0, "Node %d is joining, we wait on it.\n", 4966714d8e8SKurt Hackel dlm->joining_node); 4976714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 4986714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 4996714d8e8SKurt Hackel 5006714d8e8SKurt Hackel wait_event(dlm->dlm_join_events, dlm_no_joining_node(dlm)); 5016714d8e8SKurt Hackel goto again; 5026714d8e8SKurt Hackel } 5036714d8e8SKurt Hackel 5046714d8e8SKurt Hackel dlm->dlm_state = DLM_CTXT_LEAVING; 5056714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 5066714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 5076714d8e8SKurt Hackel } 5086714d8e8SKurt Hackel 5096714d8e8SKurt Hackel static void __dlm_print_nodes(struct dlm_ctxt *dlm) 5106714d8e8SKurt Hackel { 5116714d8e8SKurt Hackel int node = -1; 5126714d8e8SKurt Hackel 5136714d8e8SKurt Hackel assert_spin_locked(&dlm->spinlock); 5146714d8e8SKurt Hackel 515781ee3e2SSunil Mushran printk(KERN_INFO "ocfs2_dlm: Nodes in domain (\"%s\"): ", dlm->name); 5166714d8e8SKurt Hackel 5176714d8e8SKurt Hackel while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 5186714d8e8SKurt Hackel node + 1)) < O2NM_MAX_NODES) { 519781ee3e2SSunil Mushran printk("%d ", node); 5206714d8e8SKurt Hackel } 521781ee3e2SSunil Mushran printk("\n"); 5226714d8e8SKurt Hackel } 5236714d8e8SKurt Hackel 524d74c9803SKurt Hackel static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, 525d74c9803SKurt Hackel void **ret_data) 5266714d8e8SKurt Hackel { 5276714d8e8SKurt Hackel struct dlm_ctxt *dlm = data; 5286714d8e8SKurt Hackel unsigned int node; 5296714d8e8SKurt Hackel struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf; 5306714d8e8SKurt Hackel 5316714d8e8SKurt Hackel mlog_entry("%p %u %p", msg, len, data); 5326714d8e8SKurt Hackel 5336714d8e8SKurt Hackel if (!dlm_grab(dlm)) 5346714d8e8SKurt Hackel return 0; 5356714d8e8SKurt Hackel 5366714d8e8SKurt Hackel node = exit_msg->node_idx; 5376714d8e8SKurt Hackel 538781ee3e2SSunil Mushran printk(KERN_INFO "ocfs2_dlm: Node %u leaves domain %s\n", node, dlm->name); 5396714d8e8SKurt Hackel 5406714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 5416714d8e8SKurt Hackel clear_bit(node, dlm->domain_map); 5426714d8e8SKurt Hackel __dlm_print_nodes(dlm); 5436714d8e8SKurt Hackel 5446714d8e8SKurt Hackel /* notify anything attached to the heartbeat events */ 5456714d8e8SKurt Hackel dlm_hb_event_notify_attached(dlm, node, 0); 5466714d8e8SKurt Hackel 5476714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 5486714d8e8SKurt Hackel 5496714d8e8SKurt Hackel dlm_put(dlm); 5506714d8e8SKurt Hackel 5516714d8e8SKurt Hackel return 0; 5526714d8e8SKurt Hackel } 5536714d8e8SKurt Hackel 5546714d8e8SKurt Hackel static int dlm_send_one_domain_exit(struct dlm_ctxt *dlm, 5556714d8e8SKurt Hackel unsigned int node) 5566714d8e8SKurt Hackel { 5576714d8e8SKurt Hackel int status; 5586714d8e8SKurt Hackel struct dlm_exit_domain leave_msg; 5596714d8e8SKurt Hackel 5606714d8e8SKurt Hackel mlog(0, "Asking node %u if we can leave the domain %s me = %u\n", 5616714d8e8SKurt Hackel node, dlm->name, dlm->node_num); 5626714d8e8SKurt Hackel 5636714d8e8SKurt Hackel memset(&leave_msg, 0, sizeof(leave_msg)); 5646714d8e8SKurt Hackel leave_msg.node_idx = dlm->node_num; 5656714d8e8SKurt Hackel 5666714d8e8SKurt Hackel status = o2net_send_message(DLM_EXIT_DOMAIN_MSG, dlm->key, 5676714d8e8SKurt Hackel &leave_msg, sizeof(leave_msg), node, 5686714d8e8SKurt Hackel NULL); 5696714d8e8SKurt Hackel 5706714d8e8SKurt Hackel mlog(0, "status return %d from o2net_send_message\n", status); 5716714d8e8SKurt Hackel 5726714d8e8SKurt Hackel return status; 5736714d8e8SKurt Hackel } 5746714d8e8SKurt Hackel 5756714d8e8SKurt Hackel 5766714d8e8SKurt Hackel static void dlm_leave_domain(struct dlm_ctxt *dlm) 5776714d8e8SKurt Hackel { 5786714d8e8SKurt Hackel int node, clear_node, status; 5796714d8e8SKurt Hackel 5806714d8e8SKurt Hackel /* At this point we've migrated away all our locks and won't 5816714d8e8SKurt Hackel * accept mastership of new ones. The dlm is responsible for 5826714d8e8SKurt Hackel * almost nothing now. We make sure not to confuse any joining 5836714d8e8SKurt Hackel * nodes and then commence shutdown procedure. */ 5846714d8e8SKurt Hackel 5856714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 5866714d8e8SKurt Hackel /* Clear ourselves from the domain map */ 5876714d8e8SKurt Hackel clear_bit(dlm->node_num, dlm->domain_map); 5886714d8e8SKurt Hackel while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 5896714d8e8SKurt Hackel 0)) < O2NM_MAX_NODES) { 5906714d8e8SKurt Hackel /* Drop the dlm spinlock. This is safe wrt the domain_map. 5916714d8e8SKurt Hackel * -nodes cannot be added now as the 5926714d8e8SKurt Hackel * query_join_handlers knows to respond with OK_NO_MAP 5936714d8e8SKurt Hackel * -we catch the right network errors if a node is 5946714d8e8SKurt Hackel * removed from the map while we're sending him the 5956714d8e8SKurt Hackel * exit message. */ 5966714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 5976714d8e8SKurt Hackel 5986714d8e8SKurt Hackel clear_node = 1; 5996714d8e8SKurt Hackel 6006714d8e8SKurt Hackel status = dlm_send_one_domain_exit(dlm, node); 6016714d8e8SKurt Hackel if (status < 0 && 6026714d8e8SKurt Hackel status != -ENOPROTOOPT && 6036714d8e8SKurt Hackel status != -ENOTCONN) { 6046714d8e8SKurt Hackel mlog(ML_NOTICE, "Error %d sending domain exit message " 6056714d8e8SKurt Hackel "to node %d\n", status, node); 6066714d8e8SKurt Hackel 6076714d8e8SKurt Hackel /* Not sure what to do here but lets sleep for 6086714d8e8SKurt Hackel * a bit in case this was a transient 6096714d8e8SKurt Hackel * error... */ 6106714d8e8SKurt Hackel msleep(DLM_DOMAIN_BACKOFF_MS); 6116714d8e8SKurt Hackel clear_node = 0; 6126714d8e8SKurt Hackel } 6136714d8e8SKurt Hackel 6146714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 6156714d8e8SKurt Hackel /* If we're not clearing the node bit then we intend 6166714d8e8SKurt Hackel * to loop back around to try again. */ 6176714d8e8SKurt Hackel if (clear_node) 6186714d8e8SKurt Hackel clear_bit(node, dlm->domain_map); 6196714d8e8SKurt Hackel } 6206714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 6216714d8e8SKurt Hackel } 6226714d8e8SKurt Hackel 6236714d8e8SKurt Hackel int dlm_joined(struct dlm_ctxt *dlm) 6246714d8e8SKurt Hackel { 6256714d8e8SKurt Hackel int ret = 0; 6266714d8e8SKurt Hackel 6276714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 6286714d8e8SKurt Hackel 6296714d8e8SKurt Hackel if (dlm->dlm_state == DLM_CTXT_JOINED) 6306714d8e8SKurt Hackel ret = 1; 6316714d8e8SKurt Hackel 6326714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 6336714d8e8SKurt Hackel 6346714d8e8SKurt Hackel return ret; 6356714d8e8SKurt Hackel } 6366714d8e8SKurt Hackel 6376714d8e8SKurt Hackel int dlm_shutting_down(struct dlm_ctxt *dlm) 6386714d8e8SKurt Hackel { 6396714d8e8SKurt Hackel int ret = 0; 6406714d8e8SKurt Hackel 6416714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 6426714d8e8SKurt Hackel 6436714d8e8SKurt Hackel if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN) 6446714d8e8SKurt Hackel ret = 1; 6456714d8e8SKurt Hackel 6466714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 6476714d8e8SKurt Hackel 6486714d8e8SKurt Hackel return ret; 6496714d8e8SKurt Hackel } 6506714d8e8SKurt Hackel 6516714d8e8SKurt Hackel void dlm_unregister_domain(struct dlm_ctxt *dlm) 6526714d8e8SKurt Hackel { 6536714d8e8SKurt Hackel int leave = 0; 65429576f8bSSunil Mushran struct dlm_lock_resource *res; 6556714d8e8SKurt Hackel 6566714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 6576714d8e8SKurt Hackel BUG_ON(dlm->dlm_state != DLM_CTXT_JOINED); 6586714d8e8SKurt Hackel BUG_ON(!dlm->num_joins); 6596714d8e8SKurt Hackel 6606714d8e8SKurt Hackel dlm->num_joins--; 6616714d8e8SKurt Hackel if (!dlm->num_joins) { 6626714d8e8SKurt Hackel /* We mark it "in shutdown" now so new register 6636714d8e8SKurt Hackel * requests wait until we've completely left the 6646714d8e8SKurt Hackel * domain. Don't use DLM_CTXT_LEAVING yet as we still 6656714d8e8SKurt Hackel * want new domain joins to communicate with us at 6666714d8e8SKurt Hackel * least until we've completed migration of our 6676714d8e8SKurt Hackel * resources. */ 6686714d8e8SKurt Hackel dlm->dlm_state = DLM_CTXT_IN_SHUTDOWN; 6696714d8e8SKurt Hackel leave = 1; 6706714d8e8SKurt Hackel } 6716714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 6726714d8e8SKurt Hackel 6736714d8e8SKurt Hackel if (leave) { 6746714d8e8SKurt Hackel mlog(0, "shutting down domain %s\n", dlm->name); 6756714d8e8SKurt Hackel 6766714d8e8SKurt Hackel /* We changed dlm state, notify the thread */ 6776714d8e8SKurt Hackel dlm_kick_thread(dlm, NULL); 6786714d8e8SKurt Hackel 679ba2bf218SKurt Hackel while (dlm_migrate_all_locks(dlm)) { 6802f5bf1f2SSunil Mushran /* Give dlm_thread time to purge the lockres' */ 6812f5bf1f2SSunil Mushran msleep(500); 682ba2bf218SKurt Hackel mlog(0, "%s: more migration to do\n", dlm->name); 683ba2bf218SKurt Hackel } 68429576f8bSSunil Mushran 68529576f8bSSunil Mushran /* This list should be empty. If not, print remaining lockres */ 68629576f8bSSunil Mushran if (!list_empty(&dlm->tracking_list)) { 68729576f8bSSunil Mushran mlog(ML_ERROR, "Following lockres' are still on the " 68829576f8bSSunil Mushran "tracking list:\n"); 68929576f8bSSunil Mushran list_for_each_entry(res, &dlm->tracking_list, tracking) 69029576f8bSSunil Mushran dlm_print_one_lock_resource(res); 69129576f8bSSunil Mushran } 69229576f8bSSunil Mushran 6936714d8e8SKurt Hackel dlm_mark_domain_leaving(dlm); 6946714d8e8SKurt Hackel dlm_leave_domain(dlm); 6956714d8e8SKurt Hackel dlm_complete_dlm_shutdown(dlm); 6966714d8e8SKurt Hackel } 6976714d8e8SKurt Hackel dlm_put(dlm); 6986714d8e8SKurt Hackel } 6996714d8e8SKurt Hackel EXPORT_SYMBOL_GPL(dlm_unregister_domain); 7006714d8e8SKurt Hackel 701d24fbcdaSJoel Becker static int dlm_query_join_proto_check(char *proto_type, int node, 702d24fbcdaSJoel Becker struct dlm_protocol_version *ours, 703d24fbcdaSJoel Becker struct dlm_protocol_version *request) 704d24fbcdaSJoel Becker { 705d24fbcdaSJoel Becker int rc; 706d24fbcdaSJoel Becker struct dlm_protocol_version proto = *request; 707d24fbcdaSJoel Becker 708d24fbcdaSJoel Becker if (!dlm_protocol_compare(ours, &proto)) { 709d24fbcdaSJoel Becker mlog(0, 710d24fbcdaSJoel Becker "node %u wanted to join with %s locking protocol " 711d24fbcdaSJoel Becker "%u.%u, we respond with %u.%u\n", 712d24fbcdaSJoel Becker node, proto_type, 713d24fbcdaSJoel Becker request->pv_major, 714d24fbcdaSJoel Becker request->pv_minor, 715d24fbcdaSJoel Becker proto.pv_major, proto.pv_minor); 716d24fbcdaSJoel Becker request->pv_minor = proto.pv_minor; 717d24fbcdaSJoel Becker rc = 0; 718d24fbcdaSJoel Becker } else { 719d24fbcdaSJoel Becker mlog(ML_NOTICE, 720d24fbcdaSJoel Becker "Node %u wanted to join with %s locking " 721d24fbcdaSJoel Becker "protocol %u.%u, but we have %u.%u, disallowing\n", 722d24fbcdaSJoel Becker node, proto_type, 723d24fbcdaSJoel Becker request->pv_major, 724d24fbcdaSJoel Becker request->pv_minor, 725d24fbcdaSJoel Becker ours->pv_major, 726d24fbcdaSJoel Becker ours->pv_minor); 727d24fbcdaSJoel Becker rc = 1; 728d24fbcdaSJoel Becker } 729d24fbcdaSJoel Becker 730d24fbcdaSJoel Becker return rc; 731d24fbcdaSJoel Becker } 732d24fbcdaSJoel Becker 7330f71b7b4SJoel Becker /* 7340f71b7b4SJoel Becker * struct dlm_query_join_packet is made up of four one-byte fields. They 7350f71b7b4SJoel Becker * are effectively in big-endian order already. However, little-endian 7360f71b7b4SJoel Becker * machines swap them before putting the packet on the wire (because 7370f71b7b4SJoel Becker * query_join's response is a status, and that status is treated as a u32 7380f71b7b4SJoel Becker * on the wire). Thus, a big-endian and little-endian machines will treat 7390f71b7b4SJoel Becker * this structure differently. 7400f71b7b4SJoel Becker * 7410f71b7b4SJoel Becker * The solution is to have little-endian machines swap the structure when 7420f71b7b4SJoel Becker * converting from the structure to the u32 representation. This will 7430f71b7b4SJoel Becker * result in the structure having the correct format on the wire no matter 7440f71b7b4SJoel Becker * the host endian format. 7450f71b7b4SJoel Becker */ 7460f71b7b4SJoel Becker static void dlm_query_join_packet_to_wire(struct dlm_query_join_packet *packet, 7470f71b7b4SJoel Becker u32 *wire) 7480f71b7b4SJoel Becker { 7490f71b7b4SJoel Becker union dlm_query_join_response response; 7500f71b7b4SJoel Becker 7510f71b7b4SJoel Becker response.packet = *packet; 7520f71b7b4SJoel Becker *wire = cpu_to_be32(response.intval); 7530f71b7b4SJoel Becker } 7540f71b7b4SJoel Becker 7550f71b7b4SJoel Becker static void dlm_query_join_wire_to_packet(u32 wire, 7560f71b7b4SJoel Becker struct dlm_query_join_packet *packet) 7570f71b7b4SJoel Becker { 7580f71b7b4SJoel Becker union dlm_query_join_response response; 7590f71b7b4SJoel Becker 7600f71b7b4SJoel Becker response.intval = cpu_to_be32(wire); 7610f71b7b4SJoel Becker *packet = response.packet; 7620f71b7b4SJoel Becker } 7630f71b7b4SJoel Becker 764d74c9803SKurt Hackel static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, 765d74c9803SKurt Hackel void **ret_data) 7666714d8e8SKurt Hackel { 7676714d8e8SKurt Hackel struct dlm_query_join_request *query; 7680f71b7b4SJoel Becker struct dlm_query_join_packet packet = { 7690f71b7b4SJoel Becker .code = JOIN_DISALLOW, 770d24fbcdaSJoel Becker }; 7716714d8e8SKurt Hackel struct dlm_ctxt *dlm = NULL; 7720f71b7b4SJoel Becker u32 response; 7731faf2894SSrinivas Eeda u8 nodenum; 7746714d8e8SKurt Hackel 7756714d8e8SKurt Hackel query = (struct dlm_query_join_request *) msg->buf; 7766714d8e8SKurt Hackel 7776714d8e8SKurt Hackel mlog(0, "node %u wants to join domain %s\n", query->node_idx, 7786714d8e8SKurt Hackel query->domain); 7796714d8e8SKurt Hackel 7806714d8e8SKurt Hackel /* 7816714d8e8SKurt Hackel * If heartbeat doesn't consider the node live, tell it 7826714d8e8SKurt Hackel * to back off and try again. This gives heartbeat a chance 7836714d8e8SKurt Hackel * to catch up. 7846714d8e8SKurt Hackel */ 7856714d8e8SKurt Hackel if (!o2hb_check_node_heartbeating(query->node_idx)) { 7866714d8e8SKurt Hackel mlog(0, "node %u is not in our live map yet\n", 7876714d8e8SKurt Hackel query->node_idx); 7886714d8e8SKurt Hackel 7890f71b7b4SJoel Becker packet.code = JOIN_DISALLOW; 7906714d8e8SKurt Hackel goto respond; 7916714d8e8SKurt Hackel } 7926714d8e8SKurt Hackel 7930f71b7b4SJoel Becker packet.code = JOIN_OK_NO_MAP; 7946714d8e8SKurt Hackel 7956714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 7966714d8e8SKurt Hackel dlm = __dlm_lookup_domain_full(query->domain, query->name_len); 7971faf2894SSrinivas Eeda if (!dlm) 7981faf2894SSrinivas Eeda goto unlock_respond; 7991faf2894SSrinivas Eeda 8001faf2894SSrinivas Eeda /* 8011faf2894SSrinivas Eeda * There is a small window where the joining node may not see the 8021faf2894SSrinivas Eeda * node(s) that just left but still part of the cluster. DISALLOW 8031faf2894SSrinivas Eeda * join request if joining node has different node map. 8041faf2894SSrinivas Eeda */ 8051faf2894SSrinivas Eeda nodenum=0; 8061faf2894SSrinivas Eeda while (nodenum < O2NM_MAX_NODES) { 8071faf2894SSrinivas Eeda if (test_bit(nodenum, dlm->domain_map)) { 8081faf2894SSrinivas Eeda if (!byte_test_bit(nodenum, query->node_map)) { 809e4968476SSunil Mushran mlog(0, "disallow join as node %u does not " 810e4968476SSunil Mushran "have node %u in its nodemap\n", 811e4968476SSunil Mushran query->node_idx, nodenum); 8120f71b7b4SJoel Becker packet.code = JOIN_DISALLOW; 8131faf2894SSrinivas Eeda goto unlock_respond; 8141faf2894SSrinivas Eeda } 8151faf2894SSrinivas Eeda } 8161faf2894SSrinivas Eeda nodenum++; 8171faf2894SSrinivas Eeda } 8181faf2894SSrinivas Eeda 8196714d8e8SKurt Hackel /* Once the dlm ctxt is marked as leaving then we don't want 820e2faea4cSKurt Hackel * to be put in someone's domain map. 821e2faea4cSKurt Hackel * Also, explicitly disallow joining at certain troublesome 822e2faea4cSKurt Hackel * times (ie. during recovery). */ 8236714d8e8SKurt Hackel if (dlm && dlm->dlm_state != DLM_CTXT_LEAVING) { 824e2faea4cSKurt Hackel int bit = query->node_idx; 8256714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 8266714d8e8SKurt Hackel 8276714d8e8SKurt Hackel if (dlm->dlm_state == DLM_CTXT_NEW && 8286714d8e8SKurt Hackel dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN) { 8296714d8e8SKurt Hackel /*If this is a brand new context and we 8306714d8e8SKurt Hackel * haven't started our join process yet, then 8316714d8e8SKurt Hackel * the other node won the race. */ 8320f71b7b4SJoel Becker packet.code = JOIN_OK_NO_MAP; 8336714d8e8SKurt Hackel } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { 8346714d8e8SKurt Hackel /* Disallow parallel joins. */ 8350f71b7b4SJoel Becker packet.code = JOIN_DISALLOW; 836e2faea4cSKurt Hackel } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { 837e4968476SSunil Mushran mlog(0, "node %u trying to join, but recovery " 838e2faea4cSKurt Hackel "is ongoing.\n", bit); 8390f71b7b4SJoel Becker packet.code = JOIN_DISALLOW; 840e2faea4cSKurt Hackel } else if (test_bit(bit, dlm->recovery_map)) { 841e4968476SSunil Mushran mlog(0, "node %u trying to join, but it " 842e2faea4cSKurt Hackel "still needs recovery.\n", bit); 8430f71b7b4SJoel Becker packet.code = JOIN_DISALLOW; 844e2faea4cSKurt Hackel } else if (test_bit(bit, dlm->domain_map)) { 845e4968476SSunil Mushran mlog(0, "node %u trying to join, but it " 846e2faea4cSKurt Hackel "is still in the domain! needs recovery?\n", 847e2faea4cSKurt Hackel bit); 8480f71b7b4SJoel Becker packet.code = JOIN_DISALLOW; 8496714d8e8SKurt Hackel } else { 8506714d8e8SKurt Hackel /* Alright we're fully a part of this domain 8516714d8e8SKurt Hackel * so we keep some state as to who's joining 8526714d8e8SKurt Hackel * and indicate to him that needs to be fixed 8536714d8e8SKurt Hackel * up. */ 854d24fbcdaSJoel Becker 855d24fbcdaSJoel Becker /* Make sure we speak compatible locking protocols. */ 856d24fbcdaSJoel Becker if (dlm_query_join_proto_check("DLM", bit, 857d24fbcdaSJoel Becker &dlm->dlm_locking_proto, 858d24fbcdaSJoel Becker &query->dlm_proto)) { 8590f71b7b4SJoel Becker packet.code = JOIN_PROTOCOL_MISMATCH; 860d24fbcdaSJoel Becker } else if (dlm_query_join_proto_check("fs", bit, 861d24fbcdaSJoel Becker &dlm->fs_locking_proto, 862d24fbcdaSJoel Becker &query->fs_proto)) { 8630f71b7b4SJoel Becker packet.code = JOIN_PROTOCOL_MISMATCH; 864d24fbcdaSJoel Becker } else { 8650f71b7b4SJoel Becker packet.dlm_minor = query->dlm_proto.pv_minor; 8660f71b7b4SJoel Becker packet.fs_minor = query->fs_proto.pv_minor; 8670f71b7b4SJoel Becker packet.code = JOIN_OK; 8686714d8e8SKurt Hackel __dlm_set_joining_node(dlm, query->node_idx); 8696714d8e8SKurt Hackel } 870d24fbcdaSJoel Becker } 8716714d8e8SKurt Hackel 8726714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 8736714d8e8SKurt Hackel } 8741faf2894SSrinivas Eeda unlock_respond: 8756714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 8766714d8e8SKurt Hackel 8776714d8e8SKurt Hackel respond: 8780f71b7b4SJoel Becker mlog(0, "We respond with %u\n", packet.code); 8796714d8e8SKurt Hackel 8800f71b7b4SJoel Becker dlm_query_join_packet_to_wire(&packet, &response); 8810f71b7b4SJoel Becker return response; 8826714d8e8SKurt Hackel } 8836714d8e8SKurt Hackel 884d74c9803SKurt Hackel static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, 885d74c9803SKurt Hackel void **ret_data) 8866714d8e8SKurt Hackel { 8876714d8e8SKurt Hackel struct dlm_assert_joined *assert; 8886714d8e8SKurt Hackel struct dlm_ctxt *dlm = NULL; 8896714d8e8SKurt Hackel 8906714d8e8SKurt Hackel assert = (struct dlm_assert_joined *) msg->buf; 8916714d8e8SKurt Hackel 8926714d8e8SKurt Hackel mlog(0, "node %u asserts join on domain %s\n", assert->node_idx, 8936714d8e8SKurt Hackel assert->domain); 8946714d8e8SKurt Hackel 8956714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 8966714d8e8SKurt Hackel dlm = __dlm_lookup_domain_full(assert->domain, assert->name_len); 8976714d8e8SKurt Hackel /* XXX should we consider no dlm ctxt an error? */ 8986714d8e8SKurt Hackel if (dlm) { 8996714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 9006714d8e8SKurt Hackel 9016714d8e8SKurt Hackel /* Alright, this node has officially joined our 9026714d8e8SKurt Hackel * domain. Set him in the map and clean up our 9036714d8e8SKurt Hackel * leftover join state. */ 9046714d8e8SKurt Hackel BUG_ON(dlm->joining_node != assert->node_idx); 9056714d8e8SKurt Hackel set_bit(assert->node_idx, dlm->domain_map); 9066714d8e8SKurt Hackel __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); 9076714d8e8SKurt Hackel 908781ee3e2SSunil Mushran printk(KERN_INFO "ocfs2_dlm: Node %u joins domain %s\n", 909781ee3e2SSunil Mushran assert->node_idx, dlm->name); 9106714d8e8SKurt Hackel __dlm_print_nodes(dlm); 9116714d8e8SKurt Hackel 9126714d8e8SKurt Hackel /* notify anything attached to the heartbeat events */ 9136714d8e8SKurt Hackel dlm_hb_event_notify_attached(dlm, assert->node_idx, 1); 9146714d8e8SKurt Hackel 9156714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 9166714d8e8SKurt Hackel } 9176714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 9186714d8e8SKurt Hackel 9196714d8e8SKurt Hackel return 0; 9206714d8e8SKurt Hackel } 9216714d8e8SKurt Hackel 922d74c9803SKurt Hackel static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, 923d74c9803SKurt Hackel void **ret_data) 9246714d8e8SKurt Hackel { 9256714d8e8SKurt Hackel struct dlm_cancel_join *cancel; 9266714d8e8SKurt Hackel struct dlm_ctxt *dlm = NULL; 9276714d8e8SKurt Hackel 9286714d8e8SKurt Hackel cancel = (struct dlm_cancel_join *) msg->buf; 9296714d8e8SKurt Hackel 9306714d8e8SKurt Hackel mlog(0, "node %u cancels join on domain %s\n", cancel->node_idx, 9316714d8e8SKurt Hackel cancel->domain); 9326714d8e8SKurt Hackel 9336714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 9346714d8e8SKurt Hackel dlm = __dlm_lookup_domain_full(cancel->domain, cancel->name_len); 9356714d8e8SKurt Hackel 9366714d8e8SKurt Hackel if (dlm) { 9376714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 9386714d8e8SKurt Hackel 9396714d8e8SKurt Hackel /* Yikes, this guy wants to cancel his join. No 9406714d8e8SKurt Hackel * problem, we simply cleanup our join state. */ 9416714d8e8SKurt Hackel BUG_ON(dlm->joining_node != cancel->node_idx); 9426714d8e8SKurt Hackel __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); 9436714d8e8SKurt Hackel 9446714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 9456714d8e8SKurt Hackel } 9466714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 9476714d8e8SKurt Hackel 9486714d8e8SKurt Hackel return 0; 9496714d8e8SKurt Hackel } 9506714d8e8SKurt Hackel 9516714d8e8SKurt Hackel static int dlm_send_one_join_cancel(struct dlm_ctxt *dlm, 9526714d8e8SKurt Hackel unsigned int node) 9536714d8e8SKurt Hackel { 9546714d8e8SKurt Hackel int status; 9556714d8e8SKurt Hackel struct dlm_cancel_join cancel_msg; 9566714d8e8SKurt Hackel 9576714d8e8SKurt Hackel memset(&cancel_msg, 0, sizeof(cancel_msg)); 9586714d8e8SKurt Hackel cancel_msg.node_idx = dlm->node_num; 9596714d8e8SKurt Hackel cancel_msg.name_len = strlen(dlm->name); 9606714d8e8SKurt Hackel memcpy(cancel_msg.domain, dlm->name, cancel_msg.name_len); 9616714d8e8SKurt Hackel 9626714d8e8SKurt Hackel status = o2net_send_message(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY, 9636714d8e8SKurt Hackel &cancel_msg, sizeof(cancel_msg), node, 9646714d8e8SKurt Hackel NULL); 9656714d8e8SKurt Hackel if (status < 0) { 9666714d8e8SKurt Hackel mlog_errno(status); 9676714d8e8SKurt Hackel goto bail; 9686714d8e8SKurt Hackel } 9696714d8e8SKurt Hackel 9706714d8e8SKurt Hackel bail: 9716714d8e8SKurt Hackel return status; 9726714d8e8SKurt Hackel } 9736714d8e8SKurt Hackel 9746714d8e8SKurt Hackel /* map_size should be in bytes. */ 9756714d8e8SKurt Hackel static int dlm_send_join_cancels(struct dlm_ctxt *dlm, 9766714d8e8SKurt Hackel unsigned long *node_map, 9776714d8e8SKurt Hackel unsigned int map_size) 9786714d8e8SKurt Hackel { 9796714d8e8SKurt Hackel int status, tmpstat; 9806714d8e8SKurt Hackel unsigned int node; 9816714d8e8SKurt Hackel 9826714d8e8SKurt Hackel if (map_size != (BITS_TO_LONGS(O2NM_MAX_NODES) * 9836714d8e8SKurt Hackel sizeof(unsigned long))) { 9846714d8e8SKurt Hackel mlog(ML_ERROR, 9856714d8e8SKurt Hackel "map_size %u != BITS_TO_LONGS(O2NM_MAX_NODES) %u\n", 9863a4780a8SAndrew Morton map_size, (unsigned)BITS_TO_LONGS(O2NM_MAX_NODES)); 9876714d8e8SKurt Hackel return -EINVAL; 9886714d8e8SKurt Hackel } 9896714d8e8SKurt Hackel 9906714d8e8SKurt Hackel status = 0; 9916714d8e8SKurt Hackel node = -1; 9926714d8e8SKurt Hackel while ((node = find_next_bit(node_map, O2NM_MAX_NODES, 9936714d8e8SKurt Hackel node + 1)) < O2NM_MAX_NODES) { 9946714d8e8SKurt Hackel if (node == dlm->node_num) 9956714d8e8SKurt Hackel continue; 9966714d8e8SKurt Hackel 9976714d8e8SKurt Hackel tmpstat = dlm_send_one_join_cancel(dlm, node); 9986714d8e8SKurt Hackel if (tmpstat) { 9996714d8e8SKurt Hackel mlog(ML_ERROR, "Error return %d cancelling join on " 10006714d8e8SKurt Hackel "node %d\n", tmpstat, node); 10016714d8e8SKurt Hackel if (!status) 10026714d8e8SKurt Hackel status = tmpstat; 10036714d8e8SKurt Hackel } 10046714d8e8SKurt Hackel } 10056714d8e8SKurt Hackel 10066714d8e8SKurt Hackel if (status) 10076714d8e8SKurt Hackel mlog_errno(status); 10086714d8e8SKurt Hackel return status; 10096714d8e8SKurt Hackel } 10106714d8e8SKurt Hackel 10116714d8e8SKurt Hackel static int dlm_request_join(struct dlm_ctxt *dlm, 10126714d8e8SKurt Hackel int node, 1013d24fbcdaSJoel Becker enum dlm_query_join_response_code *response) 10146714d8e8SKurt Hackel { 1015d24fbcdaSJoel Becker int status; 10166714d8e8SKurt Hackel struct dlm_query_join_request join_msg; 10170f71b7b4SJoel Becker struct dlm_query_join_packet packet; 10180f71b7b4SJoel Becker u32 join_resp; 10196714d8e8SKurt Hackel 10206714d8e8SKurt Hackel mlog(0, "querying node %d\n", node); 10216714d8e8SKurt Hackel 10226714d8e8SKurt Hackel memset(&join_msg, 0, sizeof(join_msg)); 10236714d8e8SKurt Hackel join_msg.node_idx = dlm->node_num; 10246714d8e8SKurt Hackel join_msg.name_len = strlen(dlm->name); 10256714d8e8SKurt Hackel memcpy(join_msg.domain, dlm->name, join_msg.name_len); 1026d24fbcdaSJoel Becker join_msg.dlm_proto = dlm->dlm_locking_proto; 1027d24fbcdaSJoel Becker join_msg.fs_proto = dlm->fs_locking_proto; 10286714d8e8SKurt Hackel 10291faf2894SSrinivas Eeda /* copy live node map to join message */ 10301faf2894SSrinivas Eeda byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES); 10311faf2894SSrinivas Eeda 10326714d8e8SKurt Hackel status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, 1033d24fbcdaSJoel Becker sizeof(join_msg), node, 10340f71b7b4SJoel Becker &join_resp); 10356714d8e8SKurt Hackel if (status < 0 && status != -ENOPROTOOPT) { 10366714d8e8SKurt Hackel mlog_errno(status); 10376714d8e8SKurt Hackel goto bail; 10386714d8e8SKurt Hackel } 10390f71b7b4SJoel Becker dlm_query_join_wire_to_packet(join_resp, &packet); 10406714d8e8SKurt Hackel 10416714d8e8SKurt Hackel /* -ENOPROTOOPT from the net code means the other side isn't 10426714d8e8SKurt Hackel listening for our message type -- that's fine, it means 10436714d8e8SKurt Hackel his dlm isn't up, so we can consider him a 'yes' but not 10446714d8e8SKurt Hackel joined into the domain. */ 10456714d8e8SKurt Hackel if (status == -ENOPROTOOPT) { 10466714d8e8SKurt Hackel status = 0; 10476714d8e8SKurt Hackel *response = JOIN_OK_NO_MAP; 10480f71b7b4SJoel Becker } else if (packet.code == JOIN_DISALLOW || 10490f71b7b4SJoel Becker packet.code == JOIN_OK_NO_MAP) { 10500f71b7b4SJoel Becker *response = packet.code; 10510f71b7b4SJoel Becker } else if (packet.code == JOIN_PROTOCOL_MISMATCH) { 1052d24fbcdaSJoel Becker mlog(ML_NOTICE, 1053d24fbcdaSJoel Becker "This node requested DLM locking protocol %u.%u and " 1054d24fbcdaSJoel Becker "filesystem locking protocol %u.%u. At least one of " 1055d24fbcdaSJoel Becker "the protocol versions on node %d is not compatible, " 1056d24fbcdaSJoel Becker "disconnecting\n", 1057d24fbcdaSJoel Becker dlm->dlm_locking_proto.pv_major, 1058d24fbcdaSJoel Becker dlm->dlm_locking_proto.pv_minor, 1059d24fbcdaSJoel Becker dlm->fs_locking_proto.pv_major, 1060d24fbcdaSJoel Becker dlm->fs_locking_proto.pv_minor, 1061d24fbcdaSJoel Becker node); 1062d24fbcdaSJoel Becker status = -EPROTO; 10630f71b7b4SJoel Becker *response = packet.code; 10640f71b7b4SJoel Becker } else if (packet.code == JOIN_OK) { 10650f71b7b4SJoel Becker *response = packet.code; 1066d24fbcdaSJoel Becker /* Use the same locking protocol as the remote node */ 10670f71b7b4SJoel Becker dlm->dlm_locking_proto.pv_minor = packet.dlm_minor; 10680f71b7b4SJoel Becker dlm->fs_locking_proto.pv_minor = packet.fs_minor; 1069d24fbcdaSJoel Becker mlog(0, 1070d24fbcdaSJoel Becker "Node %d responds JOIN_OK with DLM locking protocol " 1071d24fbcdaSJoel Becker "%u.%u and fs locking protocol %u.%u\n", 1072d24fbcdaSJoel Becker node, 1073d24fbcdaSJoel Becker dlm->dlm_locking_proto.pv_major, 1074d24fbcdaSJoel Becker dlm->dlm_locking_proto.pv_minor, 1075d24fbcdaSJoel Becker dlm->fs_locking_proto.pv_major, 1076d24fbcdaSJoel Becker dlm->fs_locking_proto.pv_minor); 10776714d8e8SKurt Hackel } else { 10786714d8e8SKurt Hackel status = -EINVAL; 1079d24fbcdaSJoel Becker mlog(ML_ERROR, "invalid response %d from node %u\n", 10800f71b7b4SJoel Becker packet.code, node); 10816714d8e8SKurt Hackel } 10826714d8e8SKurt Hackel 10836714d8e8SKurt Hackel mlog(0, "status %d, node %d response is %d\n", status, node, 10846714d8e8SKurt Hackel *response); 10856714d8e8SKurt Hackel 10866714d8e8SKurt Hackel bail: 10876714d8e8SKurt Hackel return status; 10886714d8e8SKurt Hackel } 10896714d8e8SKurt Hackel 10906714d8e8SKurt Hackel static int dlm_send_one_join_assert(struct dlm_ctxt *dlm, 10916714d8e8SKurt Hackel unsigned int node) 10926714d8e8SKurt Hackel { 10936714d8e8SKurt Hackel int status; 10946714d8e8SKurt Hackel struct dlm_assert_joined assert_msg; 10956714d8e8SKurt Hackel 10966714d8e8SKurt Hackel mlog(0, "Sending join assert to node %u\n", node); 10976714d8e8SKurt Hackel 10986714d8e8SKurt Hackel memset(&assert_msg, 0, sizeof(assert_msg)); 10996714d8e8SKurt Hackel assert_msg.node_idx = dlm->node_num; 11006714d8e8SKurt Hackel assert_msg.name_len = strlen(dlm->name); 11016714d8e8SKurt Hackel memcpy(assert_msg.domain, dlm->name, assert_msg.name_len); 11026714d8e8SKurt Hackel 11036714d8e8SKurt Hackel status = o2net_send_message(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY, 11046714d8e8SKurt Hackel &assert_msg, sizeof(assert_msg), node, 11056714d8e8SKurt Hackel NULL); 11066714d8e8SKurt Hackel if (status < 0) 11076714d8e8SKurt Hackel mlog_errno(status); 11086714d8e8SKurt Hackel 11096714d8e8SKurt Hackel return status; 11106714d8e8SKurt Hackel } 11116714d8e8SKurt Hackel 11126714d8e8SKurt Hackel static void dlm_send_join_asserts(struct dlm_ctxt *dlm, 11136714d8e8SKurt Hackel unsigned long *node_map) 11146714d8e8SKurt Hackel { 11156714d8e8SKurt Hackel int status, node, live; 11166714d8e8SKurt Hackel 11176714d8e8SKurt Hackel status = 0; 11186714d8e8SKurt Hackel node = -1; 11196714d8e8SKurt Hackel while ((node = find_next_bit(node_map, O2NM_MAX_NODES, 11206714d8e8SKurt Hackel node + 1)) < O2NM_MAX_NODES) { 11216714d8e8SKurt Hackel if (node == dlm->node_num) 11226714d8e8SKurt Hackel continue; 11236714d8e8SKurt Hackel 11246714d8e8SKurt Hackel do { 11256714d8e8SKurt Hackel /* It is very important that this message be 11266714d8e8SKurt Hackel * received so we spin until either the node 11276714d8e8SKurt Hackel * has died or it gets the message. */ 11286714d8e8SKurt Hackel status = dlm_send_one_join_assert(dlm, node); 11296714d8e8SKurt Hackel 11306714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 11316714d8e8SKurt Hackel live = test_bit(node, dlm->live_nodes_map); 11326714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 11336714d8e8SKurt Hackel 11346714d8e8SKurt Hackel if (status) { 11356714d8e8SKurt Hackel mlog(ML_ERROR, "Error return %d asserting " 11366714d8e8SKurt Hackel "join on node %d\n", status, node); 11376714d8e8SKurt Hackel 11386714d8e8SKurt Hackel /* give us some time between errors... */ 11396714d8e8SKurt Hackel if (live) 11406714d8e8SKurt Hackel msleep(DLM_DOMAIN_BACKOFF_MS); 11416714d8e8SKurt Hackel } 11426714d8e8SKurt Hackel } while (status && live); 11436714d8e8SKurt Hackel } 11446714d8e8SKurt Hackel } 11456714d8e8SKurt Hackel 11466714d8e8SKurt Hackel struct domain_join_ctxt { 11476714d8e8SKurt Hackel unsigned long live_map[BITS_TO_LONGS(O2NM_MAX_NODES)]; 11486714d8e8SKurt Hackel unsigned long yes_resp_map[BITS_TO_LONGS(O2NM_MAX_NODES)]; 11496714d8e8SKurt Hackel }; 11506714d8e8SKurt Hackel 11516714d8e8SKurt Hackel static int dlm_should_restart_join(struct dlm_ctxt *dlm, 11526714d8e8SKurt Hackel struct domain_join_ctxt *ctxt, 1153d24fbcdaSJoel Becker enum dlm_query_join_response_code response) 11546714d8e8SKurt Hackel { 11556714d8e8SKurt Hackel int ret; 11566714d8e8SKurt Hackel 11576714d8e8SKurt Hackel if (response == JOIN_DISALLOW) { 11586714d8e8SKurt Hackel mlog(0, "Latest response of disallow -- should restart\n"); 11596714d8e8SKurt Hackel return 1; 11606714d8e8SKurt Hackel } 11616714d8e8SKurt Hackel 11626714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 11636714d8e8SKurt Hackel /* For now, we restart the process if the node maps have 11646714d8e8SKurt Hackel * changed at all */ 11656714d8e8SKurt Hackel ret = memcmp(ctxt->live_map, dlm->live_nodes_map, 11666714d8e8SKurt Hackel sizeof(dlm->live_nodes_map)); 11676714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 11686714d8e8SKurt Hackel 11696714d8e8SKurt Hackel if (ret) 11706714d8e8SKurt Hackel mlog(0, "Node maps changed -- should restart\n"); 11716714d8e8SKurt Hackel 11726714d8e8SKurt Hackel return ret; 11736714d8e8SKurt Hackel } 11746714d8e8SKurt Hackel 11756714d8e8SKurt Hackel static int dlm_try_to_join_domain(struct dlm_ctxt *dlm) 11766714d8e8SKurt Hackel { 11776714d8e8SKurt Hackel int status = 0, tmpstat, node; 11786714d8e8SKurt Hackel struct domain_join_ctxt *ctxt; 1179d24fbcdaSJoel Becker enum dlm_query_join_response_code response = JOIN_DISALLOW; 11806714d8e8SKurt Hackel 11816714d8e8SKurt Hackel mlog_entry("%p", dlm); 11826714d8e8SKurt Hackel 1183cd861280SRobert P. J. Day ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 11846714d8e8SKurt Hackel if (!ctxt) { 11856714d8e8SKurt Hackel status = -ENOMEM; 11866714d8e8SKurt Hackel mlog_errno(status); 11876714d8e8SKurt Hackel goto bail; 11886714d8e8SKurt Hackel } 11896714d8e8SKurt Hackel 11906714d8e8SKurt Hackel /* group sem locking should work for us here -- we're already 11916714d8e8SKurt Hackel * registered for heartbeat events so filling this should be 11926714d8e8SKurt Hackel * atomic wrt getting those handlers called. */ 11936714d8e8SKurt Hackel o2hb_fill_node_map(dlm->live_nodes_map, sizeof(dlm->live_nodes_map)); 11946714d8e8SKurt Hackel 11956714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 11966714d8e8SKurt Hackel memcpy(ctxt->live_map, dlm->live_nodes_map, sizeof(ctxt->live_map)); 11976714d8e8SKurt Hackel 11986714d8e8SKurt Hackel __dlm_set_joining_node(dlm, dlm->node_num); 11996714d8e8SKurt Hackel 12006714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 12016714d8e8SKurt Hackel 12026714d8e8SKurt Hackel node = -1; 12036714d8e8SKurt Hackel while ((node = find_next_bit(ctxt->live_map, O2NM_MAX_NODES, 12046714d8e8SKurt Hackel node + 1)) < O2NM_MAX_NODES) { 12056714d8e8SKurt Hackel if (node == dlm->node_num) 12066714d8e8SKurt Hackel continue; 12076714d8e8SKurt Hackel 12086714d8e8SKurt Hackel status = dlm_request_join(dlm, node, &response); 12096714d8e8SKurt Hackel if (status < 0) { 12106714d8e8SKurt Hackel mlog_errno(status); 12116714d8e8SKurt Hackel goto bail; 12126714d8e8SKurt Hackel } 12136714d8e8SKurt Hackel 12146714d8e8SKurt Hackel /* Ok, either we got a response or the node doesn't have a 12156714d8e8SKurt Hackel * dlm up. */ 12166714d8e8SKurt Hackel if (response == JOIN_OK) 12176714d8e8SKurt Hackel set_bit(node, ctxt->yes_resp_map); 12186714d8e8SKurt Hackel 12196714d8e8SKurt Hackel if (dlm_should_restart_join(dlm, ctxt, response)) { 12206714d8e8SKurt Hackel status = -EAGAIN; 12216714d8e8SKurt Hackel goto bail; 12226714d8e8SKurt Hackel } 12236714d8e8SKurt Hackel } 12246714d8e8SKurt Hackel 12256714d8e8SKurt Hackel mlog(0, "Yay, done querying nodes!\n"); 12266714d8e8SKurt Hackel 12276714d8e8SKurt Hackel /* Yay, everyone agree's we can join the domain. My domain is 12286714d8e8SKurt Hackel * comprised of all nodes who were put in the 12296714d8e8SKurt Hackel * yes_resp_map. Copy that into our domain map and send a join 12306714d8e8SKurt Hackel * assert message to clean up everyone elses state. */ 12316714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 12326714d8e8SKurt Hackel memcpy(dlm->domain_map, ctxt->yes_resp_map, 12336714d8e8SKurt Hackel sizeof(ctxt->yes_resp_map)); 12346714d8e8SKurt Hackel set_bit(dlm->node_num, dlm->domain_map); 12356714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 12366714d8e8SKurt Hackel 12376714d8e8SKurt Hackel dlm_send_join_asserts(dlm, ctxt->yes_resp_map); 12386714d8e8SKurt Hackel 12396714d8e8SKurt Hackel /* Joined state *must* be set before the joining node 12406714d8e8SKurt Hackel * information, otherwise the query_join handler may read no 12416714d8e8SKurt Hackel * current joiner but a state of NEW and tell joining nodes 12426714d8e8SKurt Hackel * we're not in the domain. */ 12436714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 12446714d8e8SKurt Hackel dlm->dlm_state = DLM_CTXT_JOINED; 12456714d8e8SKurt Hackel dlm->num_joins++; 12466714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 12476714d8e8SKurt Hackel 12486714d8e8SKurt Hackel bail: 12496714d8e8SKurt Hackel spin_lock(&dlm->spinlock); 12506714d8e8SKurt Hackel __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); 12516714d8e8SKurt Hackel if (!status) 12526714d8e8SKurt Hackel __dlm_print_nodes(dlm); 12536714d8e8SKurt Hackel spin_unlock(&dlm->spinlock); 12546714d8e8SKurt Hackel 12556714d8e8SKurt Hackel if (ctxt) { 12566714d8e8SKurt Hackel /* Do we need to send a cancel message to any nodes? */ 12576714d8e8SKurt Hackel if (status < 0) { 12586714d8e8SKurt Hackel tmpstat = dlm_send_join_cancels(dlm, 12596714d8e8SKurt Hackel ctxt->yes_resp_map, 12606714d8e8SKurt Hackel sizeof(ctxt->yes_resp_map)); 12616714d8e8SKurt Hackel if (tmpstat < 0) 12626714d8e8SKurt Hackel mlog_errno(tmpstat); 12636714d8e8SKurt Hackel } 12646714d8e8SKurt Hackel kfree(ctxt); 12656714d8e8SKurt Hackel } 12666714d8e8SKurt Hackel 12676714d8e8SKurt Hackel mlog(0, "returning %d\n", status); 12686714d8e8SKurt Hackel return status; 12696714d8e8SKurt Hackel } 12706714d8e8SKurt Hackel 12716714d8e8SKurt Hackel static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm) 12726714d8e8SKurt Hackel { 127314829422SJoel Becker o2hb_unregister_callback(NULL, &dlm->dlm_hb_up); 127414829422SJoel Becker o2hb_unregister_callback(NULL, &dlm->dlm_hb_down); 12756714d8e8SKurt Hackel o2net_unregister_handler_list(&dlm->dlm_domain_handlers); 12766714d8e8SKurt Hackel } 12776714d8e8SKurt Hackel 12786714d8e8SKurt Hackel static int dlm_register_domain_handlers(struct dlm_ctxt *dlm) 12796714d8e8SKurt Hackel { 12806714d8e8SKurt Hackel int status; 12816714d8e8SKurt Hackel 12826714d8e8SKurt Hackel mlog(0, "registering handlers.\n"); 12836714d8e8SKurt Hackel 12846714d8e8SKurt Hackel o2hb_setup_callback(&dlm->dlm_hb_down, O2HB_NODE_DOWN_CB, 12856714d8e8SKurt Hackel dlm_hb_node_down_cb, dlm, DLM_HB_NODE_DOWN_PRI); 128614829422SJoel Becker status = o2hb_register_callback(NULL, &dlm->dlm_hb_down); 12876714d8e8SKurt Hackel if (status) 12886714d8e8SKurt Hackel goto bail; 12896714d8e8SKurt Hackel 12906714d8e8SKurt Hackel o2hb_setup_callback(&dlm->dlm_hb_up, O2HB_NODE_UP_CB, 12916714d8e8SKurt Hackel dlm_hb_node_up_cb, dlm, DLM_HB_NODE_UP_PRI); 129214829422SJoel Becker status = o2hb_register_callback(NULL, &dlm->dlm_hb_up); 12936714d8e8SKurt Hackel if (status) 12946714d8e8SKurt Hackel goto bail; 12956714d8e8SKurt Hackel 12966714d8e8SKurt Hackel status = o2net_register_handler(DLM_MASTER_REQUEST_MSG, dlm->key, 12976714d8e8SKurt Hackel sizeof(struct dlm_master_request), 12986714d8e8SKurt Hackel dlm_master_request_handler, 1299d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13006714d8e8SKurt Hackel if (status) 13016714d8e8SKurt Hackel goto bail; 13026714d8e8SKurt Hackel 13036714d8e8SKurt Hackel status = o2net_register_handler(DLM_ASSERT_MASTER_MSG, dlm->key, 13046714d8e8SKurt Hackel sizeof(struct dlm_assert_master), 13056714d8e8SKurt Hackel dlm_assert_master_handler, 13063b8118cfSKurt Hackel dlm, dlm_assert_master_post_handler, 13073b8118cfSKurt Hackel &dlm->dlm_domain_handlers); 13086714d8e8SKurt Hackel if (status) 13096714d8e8SKurt Hackel goto bail; 13106714d8e8SKurt Hackel 13116714d8e8SKurt Hackel status = o2net_register_handler(DLM_CREATE_LOCK_MSG, dlm->key, 13126714d8e8SKurt Hackel sizeof(struct dlm_create_lock), 13136714d8e8SKurt Hackel dlm_create_lock_handler, 1314d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13156714d8e8SKurt Hackel if (status) 13166714d8e8SKurt Hackel goto bail; 13176714d8e8SKurt Hackel 13186714d8e8SKurt Hackel status = o2net_register_handler(DLM_CONVERT_LOCK_MSG, dlm->key, 13196714d8e8SKurt Hackel DLM_CONVERT_LOCK_MAX_LEN, 13206714d8e8SKurt Hackel dlm_convert_lock_handler, 1321d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13226714d8e8SKurt Hackel if (status) 13236714d8e8SKurt Hackel goto bail; 13246714d8e8SKurt Hackel 13256714d8e8SKurt Hackel status = o2net_register_handler(DLM_UNLOCK_LOCK_MSG, dlm->key, 13266714d8e8SKurt Hackel DLM_UNLOCK_LOCK_MAX_LEN, 13276714d8e8SKurt Hackel dlm_unlock_lock_handler, 1328d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13296714d8e8SKurt Hackel if (status) 13306714d8e8SKurt Hackel goto bail; 13316714d8e8SKurt Hackel 13326714d8e8SKurt Hackel status = o2net_register_handler(DLM_PROXY_AST_MSG, dlm->key, 13336714d8e8SKurt Hackel DLM_PROXY_AST_MAX_LEN, 13346714d8e8SKurt Hackel dlm_proxy_ast_handler, 1335d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13366714d8e8SKurt Hackel if (status) 13376714d8e8SKurt Hackel goto bail; 13386714d8e8SKurt Hackel 13396714d8e8SKurt Hackel status = o2net_register_handler(DLM_EXIT_DOMAIN_MSG, dlm->key, 13406714d8e8SKurt Hackel sizeof(struct dlm_exit_domain), 13416714d8e8SKurt Hackel dlm_exit_domain_handler, 1342d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13436714d8e8SKurt Hackel if (status) 13446714d8e8SKurt Hackel goto bail; 13456714d8e8SKurt Hackel 1346ba2bf218SKurt Hackel status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key, 1347ba2bf218SKurt Hackel sizeof(struct dlm_deref_lockres), 1348ba2bf218SKurt Hackel dlm_deref_lockres_handler, 1349d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 1350ba2bf218SKurt Hackel if (status) 1351ba2bf218SKurt Hackel goto bail; 1352ba2bf218SKurt Hackel 13536714d8e8SKurt Hackel status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key, 13546714d8e8SKurt Hackel sizeof(struct dlm_migrate_request), 13556714d8e8SKurt Hackel dlm_migrate_request_handler, 1356d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13576714d8e8SKurt Hackel if (status) 13586714d8e8SKurt Hackel goto bail; 13596714d8e8SKurt Hackel 13606714d8e8SKurt Hackel status = o2net_register_handler(DLM_MIG_LOCKRES_MSG, dlm->key, 13616714d8e8SKurt Hackel DLM_MIG_LOCKRES_MAX_LEN, 13626714d8e8SKurt Hackel dlm_mig_lockres_handler, 1363d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13646714d8e8SKurt Hackel if (status) 13656714d8e8SKurt Hackel goto bail; 13666714d8e8SKurt Hackel 13676714d8e8SKurt Hackel status = o2net_register_handler(DLM_MASTER_REQUERY_MSG, dlm->key, 13686714d8e8SKurt Hackel sizeof(struct dlm_master_requery), 13696714d8e8SKurt Hackel dlm_master_requery_handler, 1370d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13716714d8e8SKurt Hackel if (status) 13726714d8e8SKurt Hackel goto bail; 13736714d8e8SKurt Hackel 13746714d8e8SKurt Hackel status = o2net_register_handler(DLM_LOCK_REQUEST_MSG, dlm->key, 13756714d8e8SKurt Hackel sizeof(struct dlm_lock_request), 13766714d8e8SKurt Hackel dlm_request_all_locks_handler, 1377d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13786714d8e8SKurt Hackel if (status) 13796714d8e8SKurt Hackel goto bail; 13806714d8e8SKurt Hackel 13816714d8e8SKurt Hackel status = o2net_register_handler(DLM_RECO_DATA_DONE_MSG, dlm->key, 13826714d8e8SKurt Hackel sizeof(struct dlm_reco_data_done), 13836714d8e8SKurt Hackel dlm_reco_data_done_handler, 1384d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13856714d8e8SKurt Hackel if (status) 13866714d8e8SKurt Hackel goto bail; 13876714d8e8SKurt Hackel 13886714d8e8SKurt Hackel status = o2net_register_handler(DLM_BEGIN_RECO_MSG, dlm->key, 13896714d8e8SKurt Hackel sizeof(struct dlm_begin_reco), 13906714d8e8SKurt Hackel dlm_begin_reco_handler, 1391d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13926714d8e8SKurt Hackel if (status) 13936714d8e8SKurt Hackel goto bail; 13946714d8e8SKurt Hackel 13956714d8e8SKurt Hackel status = o2net_register_handler(DLM_FINALIZE_RECO_MSG, dlm->key, 13966714d8e8SKurt Hackel sizeof(struct dlm_finalize_reco), 13976714d8e8SKurt Hackel dlm_finalize_reco_handler, 1398d74c9803SKurt Hackel dlm, NULL, &dlm->dlm_domain_handlers); 13996714d8e8SKurt Hackel if (status) 14006714d8e8SKurt Hackel goto bail; 14016714d8e8SKurt Hackel 14026714d8e8SKurt Hackel bail: 14036714d8e8SKurt Hackel if (status) 14046714d8e8SKurt Hackel dlm_unregister_domain_handlers(dlm); 14056714d8e8SKurt Hackel 14066714d8e8SKurt Hackel return status; 14076714d8e8SKurt Hackel } 14086714d8e8SKurt Hackel 14096714d8e8SKurt Hackel static int dlm_join_domain(struct dlm_ctxt *dlm) 14106714d8e8SKurt Hackel { 14116714d8e8SKurt Hackel int status; 14120dd82141SSunil Mushran unsigned int backoff; 14130dd82141SSunil Mushran unsigned int total_backoff = 0; 14146714d8e8SKurt Hackel 14156714d8e8SKurt Hackel BUG_ON(!dlm); 14166714d8e8SKurt Hackel 14176714d8e8SKurt Hackel mlog(0, "Join domain %s\n", dlm->name); 14186714d8e8SKurt Hackel 14196714d8e8SKurt Hackel status = dlm_register_domain_handlers(dlm); 14206714d8e8SKurt Hackel if (status) { 14216714d8e8SKurt Hackel mlog_errno(status); 14226714d8e8SKurt Hackel goto bail; 14236714d8e8SKurt Hackel } 14246714d8e8SKurt Hackel 1425007dce53SSunil Mushran status = dlm_debug_init(dlm); 1426007dce53SSunil Mushran if (status < 0) { 1427007dce53SSunil Mushran mlog_errno(status); 1428007dce53SSunil Mushran goto bail; 1429007dce53SSunil Mushran } 1430007dce53SSunil Mushran 14316714d8e8SKurt Hackel status = dlm_launch_thread(dlm); 14326714d8e8SKurt Hackel if (status < 0) { 14336714d8e8SKurt Hackel mlog_errno(status); 14346714d8e8SKurt Hackel goto bail; 14356714d8e8SKurt Hackel } 14366714d8e8SKurt Hackel 14376714d8e8SKurt Hackel status = dlm_launch_recovery_thread(dlm); 14386714d8e8SKurt Hackel if (status < 0) { 14396714d8e8SKurt Hackel mlog_errno(status); 14406714d8e8SKurt Hackel goto bail; 14416714d8e8SKurt Hackel } 14426714d8e8SKurt Hackel 14433156d267SKurt Hackel dlm->dlm_worker = create_singlethread_workqueue("dlm_wq"); 14443156d267SKurt Hackel if (!dlm->dlm_worker) { 14453156d267SKurt Hackel status = -ENOMEM; 14463156d267SKurt Hackel mlog_errno(status); 14473156d267SKurt Hackel goto bail; 14483156d267SKurt Hackel } 14493156d267SKurt Hackel 14506714d8e8SKurt Hackel do { 14516714d8e8SKurt Hackel status = dlm_try_to_join_domain(dlm); 14526714d8e8SKurt Hackel 14536714d8e8SKurt Hackel /* If we're racing another node to the join, then we 14546714d8e8SKurt Hackel * need to back off temporarily and let them 14556714d8e8SKurt Hackel * complete. */ 14560dd82141SSunil Mushran #define DLM_JOIN_TIMEOUT_MSECS 90000 14576714d8e8SKurt Hackel if (status == -EAGAIN) { 14586714d8e8SKurt Hackel if (signal_pending(current)) { 14596714d8e8SKurt Hackel status = -ERESTARTSYS; 14606714d8e8SKurt Hackel goto bail; 14616714d8e8SKurt Hackel } 14626714d8e8SKurt Hackel 14630dd82141SSunil Mushran if (total_backoff > 14640dd82141SSunil Mushran msecs_to_jiffies(DLM_JOIN_TIMEOUT_MSECS)) { 14650dd82141SSunil Mushran status = -ERESTARTSYS; 14660dd82141SSunil Mushran mlog(ML_NOTICE, "Timed out joining dlm domain " 14670dd82141SSunil Mushran "%s after %u msecs\n", dlm->name, 14680dd82141SSunil Mushran jiffies_to_msecs(total_backoff)); 14690dd82141SSunil Mushran goto bail; 14700dd82141SSunil Mushran } 14710dd82141SSunil Mushran 14726714d8e8SKurt Hackel /* 14736714d8e8SKurt Hackel * <chip> After you! 14746714d8e8SKurt Hackel * <dale> No, after you! 14756714d8e8SKurt Hackel * <chip> I insist! 14766714d8e8SKurt Hackel * <dale> But you first! 14776714d8e8SKurt Hackel * ... 14786714d8e8SKurt Hackel */ 14796714d8e8SKurt Hackel backoff = (unsigned int)(jiffies & 0x3); 14806714d8e8SKurt Hackel backoff *= DLM_DOMAIN_BACKOFF_MS; 14810dd82141SSunil Mushran total_backoff += backoff; 14826714d8e8SKurt Hackel mlog(0, "backoff %d\n", backoff); 14836714d8e8SKurt Hackel msleep(backoff); 14846714d8e8SKurt Hackel } 14856714d8e8SKurt Hackel } while (status == -EAGAIN); 14866714d8e8SKurt Hackel 14876714d8e8SKurt Hackel if (status < 0) { 14886714d8e8SKurt Hackel mlog_errno(status); 14896714d8e8SKurt Hackel goto bail; 14906714d8e8SKurt Hackel } 14916714d8e8SKurt Hackel 14926714d8e8SKurt Hackel status = 0; 14936714d8e8SKurt Hackel bail: 14946714d8e8SKurt Hackel wake_up(&dlm_domain_events); 14956714d8e8SKurt Hackel 14966714d8e8SKurt Hackel if (status) { 14976714d8e8SKurt Hackel dlm_unregister_domain_handlers(dlm); 1498007dce53SSunil Mushran dlm_debug_shutdown(dlm); 14996714d8e8SKurt Hackel dlm_complete_thread(dlm); 15006714d8e8SKurt Hackel dlm_complete_recovery_thread(dlm); 15013156d267SKurt Hackel dlm_destroy_dlm_worker(dlm); 15026714d8e8SKurt Hackel } 15036714d8e8SKurt Hackel 15046714d8e8SKurt Hackel return status; 15056714d8e8SKurt Hackel } 15066714d8e8SKurt Hackel 15076714d8e8SKurt Hackel static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, 15086714d8e8SKurt Hackel u32 key) 15096714d8e8SKurt Hackel { 15106714d8e8SKurt Hackel int i; 15116325b4a2SSunil Mushran int ret; 15126714d8e8SKurt Hackel struct dlm_ctxt *dlm = NULL; 15136714d8e8SKurt Hackel 1514cd861280SRobert P. J. Day dlm = kzalloc(sizeof(*dlm), GFP_KERNEL); 15156714d8e8SKurt Hackel if (!dlm) { 15166714d8e8SKurt Hackel mlog_errno(-ENOMEM); 15176714d8e8SKurt Hackel goto leave; 15186714d8e8SKurt Hackel } 15196714d8e8SKurt Hackel 15206714d8e8SKurt Hackel dlm->name = kmalloc(strlen(domain) + 1, GFP_KERNEL); 15216714d8e8SKurt Hackel if (dlm->name == NULL) { 15226714d8e8SKurt Hackel mlog_errno(-ENOMEM); 15236714d8e8SKurt Hackel kfree(dlm); 15246714d8e8SKurt Hackel dlm = NULL; 15256714d8e8SKurt Hackel goto leave; 15266714d8e8SKurt Hackel } 15276714d8e8SKurt Hackel 152803d864c0SDaniel Phillips dlm->lockres_hash = (struct hlist_head **)dlm_alloc_pagevec(DLM_HASH_PAGES); 152981f2094aSMark Fasheh if (!dlm->lockres_hash) { 15306714d8e8SKurt Hackel mlog_errno(-ENOMEM); 15316714d8e8SKurt Hackel kfree(dlm->name); 15326714d8e8SKurt Hackel kfree(dlm); 15336714d8e8SKurt Hackel dlm = NULL; 15346714d8e8SKurt Hackel goto leave; 15356714d8e8SKurt Hackel } 15366714d8e8SKurt Hackel 153781f2094aSMark Fasheh for (i = 0; i < DLM_HASH_BUCKETS; i++) 153803d864c0SDaniel Phillips INIT_HLIST_HEAD(dlm_lockres_hash(dlm, i)); 15396714d8e8SKurt Hackel 1540e2b66ddcSSunil Mushran dlm->master_hash = (struct hlist_head **) 1541e2b66ddcSSunil Mushran dlm_alloc_pagevec(DLM_HASH_PAGES); 1542e2b66ddcSSunil Mushran if (!dlm->master_hash) { 1543e2b66ddcSSunil Mushran mlog_errno(-ENOMEM); 1544e2b66ddcSSunil Mushran dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); 1545e2b66ddcSSunil Mushran kfree(dlm->name); 1546e2b66ddcSSunil Mushran kfree(dlm); 1547e2b66ddcSSunil Mushran dlm = NULL; 1548e2b66ddcSSunil Mushran goto leave; 1549e2b66ddcSSunil Mushran } 1550e2b66ddcSSunil Mushran 1551e2b66ddcSSunil Mushran for (i = 0; i < DLM_HASH_BUCKETS; i++) 1552e2b66ddcSSunil Mushran INIT_HLIST_HEAD(dlm_master_hash(dlm, i)); 1553e2b66ddcSSunil Mushran 15546714d8e8SKurt Hackel strcpy(dlm->name, domain); 15556714d8e8SKurt Hackel dlm->key = key; 15566714d8e8SKurt Hackel dlm->node_num = o2nm_this_node(); 15576714d8e8SKurt Hackel 15586325b4a2SSunil Mushran ret = dlm_create_debugfs_subroot(dlm); 15596325b4a2SSunil Mushran if (ret < 0) { 1560e2b66ddcSSunil Mushran dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES); 15616325b4a2SSunil Mushran dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); 15626325b4a2SSunil Mushran kfree(dlm->name); 15636325b4a2SSunil Mushran kfree(dlm); 15646325b4a2SSunil Mushran dlm = NULL; 15656325b4a2SSunil Mushran goto leave; 15666325b4a2SSunil Mushran } 15676325b4a2SSunil Mushran 15686714d8e8SKurt Hackel spin_lock_init(&dlm->spinlock); 15696714d8e8SKurt Hackel spin_lock_init(&dlm->master_lock); 15706714d8e8SKurt Hackel spin_lock_init(&dlm->ast_lock); 1571b0d4f817SSunil Mushran spin_lock_init(&dlm->track_lock); 15726714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->list); 15736714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->dirty_list); 15746714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->reco.resources); 15756714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->reco.received); 15766714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->reco.node_data); 15776714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->purge_list); 15786714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->dlm_domain_handlers); 157929576f8bSSunil Mushran INIT_LIST_HEAD(&dlm->tracking_list); 15806714d8e8SKurt Hackel dlm->reco.state = 0; 15816714d8e8SKurt Hackel 15826714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->pending_asts); 15836714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->pending_basts); 15846714d8e8SKurt Hackel 15856714d8e8SKurt Hackel mlog(0, "dlm->recovery_map=%p, &(dlm->recovery_map[0])=%p\n", 15866714d8e8SKurt Hackel dlm->recovery_map, &(dlm->recovery_map[0])); 15876714d8e8SKurt Hackel 15886714d8e8SKurt Hackel memset(dlm->recovery_map, 0, sizeof(dlm->recovery_map)); 15896714d8e8SKurt Hackel memset(dlm->live_nodes_map, 0, sizeof(dlm->live_nodes_map)); 15906714d8e8SKurt Hackel memset(dlm->domain_map, 0, sizeof(dlm->domain_map)); 15916714d8e8SKurt Hackel 15926714d8e8SKurt Hackel dlm->dlm_thread_task = NULL; 15936714d8e8SKurt Hackel dlm->dlm_reco_thread_task = NULL; 15943156d267SKurt Hackel dlm->dlm_worker = NULL; 15956714d8e8SKurt Hackel init_waitqueue_head(&dlm->dlm_thread_wq); 15966714d8e8SKurt Hackel init_waitqueue_head(&dlm->dlm_reco_thread_wq); 15976714d8e8SKurt Hackel init_waitqueue_head(&dlm->reco.event); 15986714d8e8SKurt Hackel init_waitqueue_head(&dlm->ast_wq); 15996714d8e8SKurt Hackel init_waitqueue_head(&dlm->migration_wq); 16006714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->master_list); 16016714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->mle_hb_events); 16026714d8e8SKurt Hackel 16036714d8e8SKurt Hackel dlm->joining_node = DLM_LOCK_RES_OWNER_UNKNOWN; 16046714d8e8SKurt Hackel init_waitqueue_head(&dlm->dlm_join_events); 16056714d8e8SKurt Hackel 16066714d8e8SKurt Hackel dlm->reco.new_master = O2NM_INVALID_NODE_NUM; 16076714d8e8SKurt Hackel dlm->reco.dead_node = O2NM_INVALID_NODE_NUM; 16086714d8e8SKurt Hackel atomic_set(&dlm->local_resources, 0); 16096714d8e8SKurt Hackel atomic_set(&dlm->remote_resources, 0); 16106714d8e8SKurt Hackel atomic_set(&dlm->unknown_resources, 0); 16116714d8e8SKurt Hackel 16126714d8e8SKurt Hackel spin_lock_init(&dlm->work_lock); 16136714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->work_list); 1614c4028958SDavid Howells INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work); 16156714d8e8SKurt Hackel 16166714d8e8SKurt Hackel kref_init(&dlm->dlm_refs); 16176714d8e8SKurt Hackel dlm->dlm_state = DLM_CTXT_NEW; 16186714d8e8SKurt Hackel 16196714d8e8SKurt Hackel INIT_LIST_HEAD(&dlm->dlm_eviction_callbacks); 16206714d8e8SKurt Hackel 16216714d8e8SKurt Hackel mlog(0, "context init: refcount %u\n", 16226714d8e8SKurt Hackel atomic_read(&dlm->dlm_refs.refcount)); 16236714d8e8SKurt Hackel 16246714d8e8SKurt Hackel leave: 16256714d8e8SKurt Hackel return dlm; 16266714d8e8SKurt Hackel } 16276714d8e8SKurt Hackel 16286714d8e8SKurt Hackel /* 1629d24fbcdaSJoel Becker * Compare a requested locking protocol version against the current one. 1630d24fbcdaSJoel Becker * 1631d24fbcdaSJoel Becker * If the major numbers are different, they are incompatible. 1632d24fbcdaSJoel Becker * If the current minor is greater than the request, they are incompatible. 1633d24fbcdaSJoel Becker * If the current minor is less than or equal to the request, they are 1634d24fbcdaSJoel Becker * compatible, and the requester should run at the current minor version. 1635d24fbcdaSJoel Becker */ 1636d24fbcdaSJoel Becker static int dlm_protocol_compare(struct dlm_protocol_version *existing, 1637d24fbcdaSJoel Becker struct dlm_protocol_version *request) 1638d24fbcdaSJoel Becker { 1639d24fbcdaSJoel Becker if (existing->pv_major != request->pv_major) 1640d24fbcdaSJoel Becker return 1; 1641d24fbcdaSJoel Becker 1642d24fbcdaSJoel Becker if (existing->pv_minor > request->pv_minor) 1643d24fbcdaSJoel Becker return 1; 1644d24fbcdaSJoel Becker 1645d24fbcdaSJoel Becker if (existing->pv_minor < request->pv_minor) 1646d24fbcdaSJoel Becker request->pv_minor = existing->pv_minor; 1647d24fbcdaSJoel Becker 1648d24fbcdaSJoel Becker return 0; 1649d24fbcdaSJoel Becker } 1650d24fbcdaSJoel Becker 1651d24fbcdaSJoel Becker /* 1652d24fbcdaSJoel Becker * dlm_register_domain: one-time setup per "domain". 1653d24fbcdaSJoel Becker * 1654d24fbcdaSJoel Becker * The filesystem passes in the requested locking version via proto. 1655d24fbcdaSJoel Becker * If registration was successful, proto will contain the negotiated 1656d24fbcdaSJoel Becker * locking protocol. 16576714d8e8SKurt Hackel */ 16586714d8e8SKurt Hackel struct dlm_ctxt * dlm_register_domain(const char *domain, 1659d24fbcdaSJoel Becker u32 key, 1660d24fbcdaSJoel Becker struct dlm_protocol_version *fs_proto) 16616714d8e8SKurt Hackel { 16626714d8e8SKurt Hackel int ret; 16636714d8e8SKurt Hackel struct dlm_ctxt *dlm = NULL; 16646714d8e8SKurt Hackel struct dlm_ctxt *new_ctxt = NULL; 16656714d8e8SKurt Hackel 16666714d8e8SKurt Hackel if (strlen(domain) > O2NM_MAX_NAME_LEN) { 16676714d8e8SKurt Hackel ret = -ENAMETOOLONG; 16686714d8e8SKurt Hackel mlog(ML_ERROR, "domain name length too long\n"); 16696714d8e8SKurt Hackel goto leave; 16706714d8e8SKurt Hackel } 16716714d8e8SKurt Hackel 16726714d8e8SKurt Hackel if (!o2hb_check_local_node_heartbeating()) { 16736714d8e8SKurt Hackel mlog(ML_ERROR, "the local node has not been configured, or is " 16746714d8e8SKurt Hackel "not heartbeating\n"); 16756714d8e8SKurt Hackel ret = -EPROTO; 16766714d8e8SKurt Hackel goto leave; 16776714d8e8SKurt Hackel } 16786714d8e8SKurt Hackel 16796714d8e8SKurt Hackel mlog(0, "register called for domain \"%s\"\n", domain); 16806714d8e8SKurt Hackel 16816714d8e8SKurt Hackel retry: 16826714d8e8SKurt Hackel dlm = NULL; 16836714d8e8SKurt Hackel if (signal_pending(current)) { 16846714d8e8SKurt Hackel ret = -ERESTARTSYS; 16856714d8e8SKurt Hackel mlog_errno(ret); 16866714d8e8SKurt Hackel goto leave; 16876714d8e8SKurt Hackel } 16886714d8e8SKurt Hackel 16896714d8e8SKurt Hackel spin_lock(&dlm_domain_lock); 16906714d8e8SKurt Hackel 16916714d8e8SKurt Hackel dlm = __dlm_lookup_domain(domain); 16926714d8e8SKurt Hackel if (dlm) { 16936714d8e8SKurt Hackel if (dlm->dlm_state != DLM_CTXT_JOINED) { 16946714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 16956714d8e8SKurt Hackel 16966714d8e8SKurt Hackel mlog(0, "This ctxt is not joined yet!\n"); 16976714d8e8SKurt Hackel wait_event_interruptible(dlm_domain_events, 16986714d8e8SKurt Hackel dlm_wait_on_domain_helper( 16996714d8e8SKurt Hackel domain)); 17006714d8e8SKurt Hackel goto retry; 17016714d8e8SKurt Hackel } 17026714d8e8SKurt Hackel 1703d24fbcdaSJoel Becker if (dlm_protocol_compare(&dlm->fs_locking_proto, fs_proto)) { 1704d24fbcdaSJoel Becker mlog(ML_ERROR, 1705d24fbcdaSJoel Becker "Requested locking protocol version is not " 1706d24fbcdaSJoel Becker "compatible with already registered domain " 1707d24fbcdaSJoel Becker "\"%s\"\n", domain); 1708d24fbcdaSJoel Becker ret = -EPROTO; 1709d24fbcdaSJoel Becker goto leave; 1710d24fbcdaSJoel Becker } 1711d24fbcdaSJoel Becker 17126714d8e8SKurt Hackel __dlm_get(dlm); 17136714d8e8SKurt Hackel dlm->num_joins++; 17146714d8e8SKurt Hackel 17156714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 17166714d8e8SKurt Hackel 17176714d8e8SKurt Hackel ret = 0; 17186714d8e8SKurt Hackel goto leave; 17196714d8e8SKurt Hackel } 17206714d8e8SKurt Hackel 17216714d8e8SKurt Hackel /* doesn't exist */ 17226714d8e8SKurt Hackel if (!new_ctxt) { 17236714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 17246714d8e8SKurt Hackel 17256714d8e8SKurt Hackel new_ctxt = dlm_alloc_ctxt(domain, key); 17266714d8e8SKurt Hackel if (new_ctxt) 17276714d8e8SKurt Hackel goto retry; 17286714d8e8SKurt Hackel 17296714d8e8SKurt Hackel ret = -ENOMEM; 17306714d8e8SKurt Hackel mlog_errno(ret); 17316714d8e8SKurt Hackel goto leave; 17326714d8e8SKurt Hackel } 17336714d8e8SKurt Hackel 17346714d8e8SKurt Hackel /* a little variable switch-a-roo here... */ 17356714d8e8SKurt Hackel dlm = new_ctxt; 17366714d8e8SKurt Hackel new_ctxt = NULL; 17376714d8e8SKurt Hackel 17386714d8e8SKurt Hackel /* add the new domain */ 17396714d8e8SKurt Hackel list_add_tail(&dlm->list, &dlm_domains); 17406714d8e8SKurt Hackel spin_unlock(&dlm_domain_lock); 17416714d8e8SKurt Hackel 1742d24fbcdaSJoel Becker /* 1743d24fbcdaSJoel Becker * Pass the locking protocol version into the join. If the join 1744d24fbcdaSJoel Becker * succeeds, it will have the negotiated protocol set. 1745d24fbcdaSJoel Becker */ 1746d24fbcdaSJoel Becker dlm->dlm_locking_proto = dlm_protocol; 1747d24fbcdaSJoel Becker dlm->fs_locking_proto = *fs_proto; 1748d24fbcdaSJoel Becker 17496714d8e8SKurt Hackel ret = dlm_join_domain(dlm); 17506714d8e8SKurt Hackel if (ret) { 17516714d8e8SKurt Hackel mlog_errno(ret); 17526714d8e8SKurt Hackel dlm_put(dlm); 17536714d8e8SKurt Hackel goto leave; 17546714d8e8SKurt Hackel } 17556714d8e8SKurt Hackel 1756d24fbcdaSJoel Becker /* Tell the caller what locking protocol we negotiated */ 1757d24fbcdaSJoel Becker *fs_proto = dlm->fs_locking_proto; 1758d24fbcdaSJoel Becker 17596714d8e8SKurt Hackel ret = 0; 17606714d8e8SKurt Hackel leave: 17616714d8e8SKurt Hackel if (new_ctxt) 17626714d8e8SKurt Hackel dlm_free_ctxt_mem(new_ctxt); 17636714d8e8SKurt Hackel 17646714d8e8SKurt Hackel if (ret < 0) 17656714d8e8SKurt Hackel dlm = ERR_PTR(ret); 17666714d8e8SKurt Hackel 17676714d8e8SKurt Hackel return dlm; 17686714d8e8SKurt Hackel } 17696714d8e8SKurt Hackel EXPORT_SYMBOL_GPL(dlm_register_domain); 17706714d8e8SKurt Hackel 17716714d8e8SKurt Hackel static LIST_HEAD(dlm_join_handlers); 17726714d8e8SKurt Hackel 17736714d8e8SKurt Hackel static void dlm_unregister_net_handlers(void) 17746714d8e8SKurt Hackel { 17756714d8e8SKurt Hackel o2net_unregister_handler_list(&dlm_join_handlers); 17766714d8e8SKurt Hackel } 17776714d8e8SKurt Hackel 17786714d8e8SKurt Hackel static int dlm_register_net_handlers(void) 17796714d8e8SKurt Hackel { 17806714d8e8SKurt Hackel int status = 0; 17816714d8e8SKurt Hackel 17826714d8e8SKurt Hackel status = o2net_register_handler(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, 17836714d8e8SKurt Hackel sizeof(struct dlm_query_join_request), 17846714d8e8SKurt Hackel dlm_query_join_handler, 1785d74c9803SKurt Hackel NULL, NULL, &dlm_join_handlers); 17866714d8e8SKurt Hackel if (status) 17876714d8e8SKurt Hackel goto bail; 17886714d8e8SKurt Hackel 17896714d8e8SKurt Hackel status = o2net_register_handler(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY, 17906714d8e8SKurt Hackel sizeof(struct dlm_assert_joined), 17916714d8e8SKurt Hackel dlm_assert_joined_handler, 1792d74c9803SKurt Hackel NULL, NULL, &dlm_join_handlers); 17936714d8e8SKurt Hackel if (status) 17946714d8e8SKurt Hackel goto bail; 17956714d8e8SKurt Hackel 17966714d8e8SKurt Hackel status = o2net_register_handler(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY, 17976714d8e8SKurt Hackel sizeof(struct dlm_cancel_join), 17986714d8e8SKurt Hackel dlm_cancel_join_handler, 1799d74c9803SKurt Hackel NULL, NULL, &dlm_join_handlers); 18006714d8e8SKurt Hackel 18016714d8e8SKurt Hackel bail: 18026714d8e8SKurt Hackel if (status < 0) 18036714d8e8SKurt Hackel dlm_unregister_net_handlers(); 18046714d8e8SKurt Hackel 18056714d8e8SKurt Hackel return status; 18066714d8e8SKurt Hackel } 18076714d8e8SKurt Hackel 18086714d8e8SKurt Hackel /* Domain eviction callback handling. 18096714d8e8SKurt Hackel * 18106714d8e8SKurt Hackel * The file system requires notification of node death *before* the 18116714d8e8SKurt Hackel * dlm completes it's recovery work, otherwise it may be able to 18126714d8e8SKurt Hackel * acquire locks on resources requiring recovery. Since the dlm can 18136714d8e8SKurt Hackel * evict a node from it's domain *before* heartbeat fires, a similar 18146714d8e8SKurt Hackel * mechanism is required. */ 18156714d8e8SKurt Hackel 18166714d8e8SKurt Hackel /* Eviction is not expected to happen often, so a per-domain lock is 18176714d8e8SKurt Hackel * not necessary. Eviction callbacks are allowed to sleep for short 18186714d8e8SKurt Hackel * periods of time. */ 18196714d8e8SKurt Hackel static DECLARE_RWSEM(dlm_callback_sem); 18206714d8e8SKurt Hackel 18216714d8e8SKurt Hackel void dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm, 18226714d8e8SKurt Hackel int node_num) 18236714d8e8SKurt Hackel { 18246714d8e8SKurt Hackel struct list_head *iter; 18256714d8e8SKurt Hackel struct dlm_eviction_cb *cb; 18266714d8e8SKurt Hackel 18276714d8e8SKurt Hackel down_read(&dlm_callback_sem); 18286714d8e8SKurt Hackel list_for_each(iter, &dlm->dlm_eviction_callbacks) { 18296714d8e8SKurt Hackel cb = list_entry(iter, struct dlm_eviction_cb, ec_item); 18306714d8e8SKurt Hackel 18316714d8e8SKurt Hackel cb->ec_func(node_num, cb->ec_data); 18326714d8e8SKurt Hackel } 18336714d8e8SKurt Hackel up_read(&dlm_callback_sem); 18346714d8e8SKurt Hackel } 18356714d8e8SKurt Hackel 18366714d8e8SKurt Hackel void dlm_setup_eviction_cb(struct dlm_eviction_cb *cb, 18376714d8e8SKurt Hackel dlm_eviction_func *f, 18386714d8e8SKurt Hackel void *data) 18396714d8e8SKurt Hackel { 18406714d8e8SKurt Hackel INIT_LIST_HEAD(&cb->ec_item); 18416714d8e8SKurt Hackel cb->ec_func = f; 18426714d8e8SKurt Hackel cb->ec_data = data; 18436714d8e8SKurt Hackel } 18446714d8e8SKurt Hackel EXPORT_SYMBOL_GPL(dlm_setup_eviction_cb); 18456714d8e8SKurt Hackel 18466714d8e8SKurt Hackel void dlm_register_eviction_cb(struct dlm_ctxt *dlm, 18476714d8e8SKurt Hackel struct dlm_eviction_cb *cb) 18486714d8e8SKurt Hackel { 18496714d8e8SKurt Hackel down_write(&dlm_callback_sem); 18506714d8e8SKurt Hackel list_add_tail(&cb->ec_item, &dlm->dlm_eviction_callbacks); 18516714d8e8SKurt Hackel up_write(&dlm_callback_sem); 18526714d8e8SKurt Hackel } 18536714d8e8SKurt Hackel EXPORT_SYMBOL_GPL(dlm_register_eviction_cb); 18546714d8e8SKurt Hackel 18556714d8e8SKurt Hackel void dlm_unregister_eviction_cb(struct dlm_eviction_cb *cb) 18566714d8e8SKurt Hackel { 18576714d8e8SKurt Hackel down_write(&dlm_callback_sem); 18586714d8e8SKurt Hackel list_del_init(&cb->ec_item); 18596714d8e8SKurt Hackel up_write(&dlm_callback_sem); 18606714d8e8SKurt Hackel } 18616714d8e8SKurt Hackel EXPORT_SYMBOL_GPL(dlm_unregister_eviction_cb); 18626714d8e8SKurt Hackel 18636714d8e8SKurt Hackel static int __init dlm_init(void) 18646714d8e8SKurt Hackel { 18656714d8e8SKurt Hackel int status; 18666714d8e8SKurt Hackel 18676714d8e8SKurt Hackel dlm_print_version(); 18686714d8e8SKurt Hackel 18696714d8e8SKurt Hackel status = dlm_init_mle_cache(); 187012eb0035SSunil Mushran if (status) { 187112eb0035SSunil Mushran mlog(ML_ERROR, "Could not create o2dlm_mle slabcache\n"); 1872724bdca9SSunil Mushran goto error; 1873724bdca9SSunil Mushran } 1874724bdca9SSunil Mushran 1875724bdca9SSunil Mushran status = dlm_init_master_caches(); 1876724bdca9SSunil Mushran if (status) { 1877724bdca9SSunil Mushran mlog(ML_ERROR, "Could not create o2dlm_lockres and " 1878724bdca9SSunil Mushran "o2dlm_lockname slabcaches\n"); 1879724bdca9SSunil Mushran goto error; 1880724bdca9SSunil Mushran } 1881724bdca9SSunil Mushran 1882724bdca9SSunil Mushran status = dlm_init_lock_cache(); 1883724bdca9SSunil Mushran if (status) { 1884724bdca9SSunil Mushran mlog(ML_ERROR, "Count not create o2dlm_lock slabcache\n"); 1885724bdca9SSunil Mushran goto error; 188612eb0035SSunil Mushran } 18876714d8e8SKurt Hackel 18886714d8e8SKurt Hackel status = dlm_register_net_handlers(); 18896714d8e8SKurt Hackel if (status) { 1890724bdca9SSunil Mushran mlog(ML_ERROR, "Unable to register network handlers\n"); 1891724bdca9SSunil Mushran goto error; 18926714d8e8SKurt Hackel } 18936714d8e8SKurt Hackel 18946325b4a2SSunil Mushran status = dlm_create_debugfs_root(); 18956325b4a2SSunil Mushran if (status) 18966325b4a2SSunil Mushran goto error; 18976325b4a2SSunil Mushran 18986714d8e8SKurt Hackel return 0; 1899724bdca9SSunil Mushran error: 19006325b4a2SSunil Mushran dlm_unregister_net_handlers(); 1901724bdca9SSunil Mushran dlm_destroy_lock_cache(); 1902724bdca9SSunil Mushran dlm_destroy_master_caches(); 1903724bdca9SSunil Mushran dlm_destroy_mle_cache(); 1904724bdca9SSunil Mushran return -1; 19056714d8e8SKurt Hackel } 19066714d8e8SKurt Hackel 19076714d8e8SKurt Hackel static void __exit dlm_exit (void) 19086714d8e8SKurt Hackel { 19096325b4a2SSunil Mushran dlm_destroy_debugfs_root(); 19106714d8e8SKurt Hackel dlm_unregister_net_handlers(); 1911724bdca9SSunil Mushran dlm_destroy_lock_cache(); 1912724bdca9SSunil Mushran dlm_destroy_master_caches(); 19136714d8e8SKurt Hackel dlm_destroy_mle_cache(); 19146714d8e8SKurt Hackel } 19156714d8e8SKurt Hackel 19166714d8e8SKurt Hackel MODULE_AUTHOR("Oracle"); 19176714d8e8SKurt Hackel MODULE_LICENSE("GPL"); 19186714d8e8SKurt Hackel 19196714d8e8SKurt Hackel module_init(dlm_init); 19206714d8e8SKurt Hackel module_exit(dlm_exit); 1921