blob: 3aff23feefdc74f837bc4e3d81669b2639902a2d [file] [log] [blame]
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * dlmdomain.c
5 *
6 * defines domain join / leave apis
7 *
8 * Copyright (C) 2004 Oracle. All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public
21 * License along with this program; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 021110-1307, USA.
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/types.h>
29#include <linux/slab.h>
30#include <linux/highmem.h>
Kurt Hackel6714d8e2005-12-15 14:31:23 -080031#include <linux/init.h>
32#include <linux/spinlock.h>
33#include <linux/delay.h>
34#include <linux/err.h>
Sunil Mushran6325b4a2008-03-10 15:16:22 -070035#include <linux/debugfs.h>
Kurt Hackel6714d8e2005-12-15 14:31:23 -080036
37#include "cluster/heartbeat.h"
38#include "cluster/nodemanager.h"
39#include "cluster/tcp.h"
40
41#include "dlmapi.h"
42#include "dlmcommon.h"
Kurt Hackel6714d8e2005-12-15 14:31:23 -080043#include "dlmdomain.h"
Sunil Mushran6325b4a2008-03-10 15:16:22 -070044#include "dlmdebug.h"
Kurt Hackel6714d8e2005-12-15 14:31:23 -080045
46#include "dlmver.h"
47
48#define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_DOMAIN)
49#include "cluster/masklog.h"
50
Srinivas Eeda1faf2892007-01-29 15:31:35 -080051/*
52 * ocfs2 node maps are array of long int, which limits to send them freely
53 * across the wire due to endianness issues. To workaround this, we convert
54 * long ints to byte arrays. Following 3 routines are helper functions to
55 * set/test/copy bits within those array of bytes
56 */
57static inline void byte_set_bit(u8 nr, u8 map[])
58{
59 map[nr >> 3] |= (1UL << (nr & 7));
60}
61
62static inline int byte_test_bit(u8 nr, u8 map[])
63{
64 return ((1UL << (nr & 7)) & (map[nr >> 3])) != 0;
65}
66
67static inline void byte_copymap(u8 dmap[], unsigned long smap[],
68 unsigned int sz)
69{
70 unsigned int nn;
71
72 if (!sz)
73 return;
74
75 memset(dmap, 0, ((sz + 7) >> 3));
76 for (nn = 0 ; nn < sz; nn++)
77 if (test_bit(nn, smap))
78 byte_set_bit(nn, dmap);
79}
80
Daniel Phillips03d864c2006-03-10 18:08:16 -080081static void dlm_free_pagevec(void **vec, int pages)
82{
83 while (pages--)
84 free_page((unsigned long)vec[pages]);
85 kfree(vec);
86}
87
88static void **dlm_alloc_pagevec(int pages)
89{
90 void **vec = kmalloc(pages * sizeof(void *), GFP_KERNEL);
91 int i;
92
93 if (!vec)
94 return NULL;
95
96 for (i = 0; i < pages; i++)
97 if (!(vec[i] = (void *)__get_free_page(GFP_KERNEL)))
98 goto out_free;
Joel Beckerc8f33b62006-03-16 17:40:37 -080099
Mark Fasheh685f1ad2006-03-23 11:23:29 -0800100 mlog(0, "Allocated DLM hash pagevec; %d pages (%lu expected), %lu buckets per page\n",
Mark Fashehf5a923d2006-11-28 15:13:18 -0800101 pages, (unsigned long)DLM_HASH_PAGES,
102 (unsigned long)DLM_BUCKETS_PER_PAGE);
Daniel Phillips03d864c2006-03-10 18:08:16 -0800103 return vec;
104out_free:
105 dlm_free_pagevec(vec, i);
106 return NULL;
107}
108
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800109/*
110 *
111 * spinlock lock ordering: if multiple locks are needed, obey this ordering:
112 * dlm_domain_lock
113 * struct dlm_ctxt->spinlock
114 * struct dlm_lock_resource->spinlock
115 * struct dlm_ctxt->master_lock
116 * struct dlm_ctxt->ast_lock
117 * dlm_master_list_entry->spinlock
118 * dlm_lock->spinlock
119 *
120 */
121
Ingo Molnar34af9462006-06-27 02:53:55 -0700122DEFINE_SPINLOCK(dlm_domain_lock);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800123LIST_HEAD(dlm_domains);
124static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events);
125
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800126/*
127 * The supported protocol version for DLM communication. Running domains
128 * will have a negotiated version with the same major number and a minor
129 * number equal or smaller. The dlm_ctxt->dlm_locking_proto field should
130 * be used to determine what a running domain is actually using.
Sunil Mushranea203442010-10-09 10:26:23 -0700131 *
132 * New in version 1.1:
133 * - Message DLM_QUERY_REGION added to support global heartbeat
Sunil Mushran18cfdf12010-10-07 16:47:03 -0700134 * - Message DLM_QUERY_NODEINFO added to allow online node removes
Sunil Mushranbddefde2011-05-19 14:34:11 -0700135 * New in version 1.2:
136 * - Message DLM_BEGIN_EXIT_DOMAIN_MSG added to mark start of exit domain
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800137 */
138static const struct dlm_protocol_version dlm_protocol = {
139 .pv_major = 1,
Sunil Mushranbddefde2011-05-19 14:34:11 -0700140 .pv_minor = 2,
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800141};
142
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800143#define DLM_DOMAIN_BACKOFF_MS 200
144
Kurt Hackeld74c9802007-01-17 17:04:25 -0800145static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
146 void **ret_data);
147static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
148 void **ret_data);
149static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
150 void **ret_data);
Sunil Mushranea203442010-10-09 10:26:23 -0700151static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
152 void *data, void **ret_data);
Kurt Hackeld74c9802007-01-17 17:04:25 -0800153static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
154 void **ret_data);
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800155static int dlm_protocol_compare(struct dlm_protocol_version *existing,
156 struct dlm_protocol_version *request);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800157
158static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm);
159
160void __dlm_unhash_lockres(struct dlm_lock_resource *lockres)
161{
Sunil Mushran78062cb2007-03-22 17:01:07 -0700162 if (!hlist_unhashed(&lockres->hash_node)) {
163 hlist_del_init(&lockres->hash_node);
164 dlm_lockres_put(lockres);
165 }
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800166}
167
168void __dlm_insert_lockres(struct dlm_ctxt *dlm,
169 struct dlm_lock_resource *res)
170{
Mark Fasheh81f20942006-02-28 17:31:22 -0800171 struct hlist_head *bucket;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800172 struct qstr *q;
173
174 assert_spin_locked(&dlm->spinlock);
175
176 q = &res->lockname;
Daniel Phillips03d864c2006-03-10 18:08:16 -0800177 bucket = dlm_lockres_hash(dlm, q->hash);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800178
179 /* get a reference for our hashtable */
180 dlm_lockres_get(res);
181
Mark Fasheh81f20942006-02-28 17:31:22 -0800182 hlist_add_head(&res->hash_node, bucket);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800183}
184
Kurt Hackelba2bf212006-12-01 14:47:20 -0800185struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
186 const char *name,
187 unsigned int len,
188 unsigned int hash)
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800189{
Mark Fasheh81f20942006-02-28 17:31:22 -0800190 struct hlist_head *bucket;
Daniel Phillips41989852006-03-10 13:31:47 -0800191 struct hlist_node *list;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800192
Tao Maef6b6892011-02-21 11:10:44 +0800193 mlog(0, "%.*s\n", len, name);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800194
195 assert_spin_locked(&dlm->spinlock);
196
Daniel Phillips03d864c2006-03-10 18:08:16 -0800197 bucket = dlm_lockres_hash(dlm, hash);
198
Daniel Phillips41989852006-03-10 13:31:47 -0800199 hlist_for_each(list, bucket) {
200 struct dlm_lock_resource *res = hlist_entry(list,
201 struct dlm_lock_resource, hash_node);
202 if (res->lockname.name[0] != name[0])
203 continue;
204 if (unlikely(res->lockname.len != len))
205 continue;
206 if (memcmp(res->lockname.name + 1, name + 1, len - 1))
207 continue;
208 dlm_lockres_get(res);
209 return res;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800210 }
Daniel Phillips41989852006-03-10 13:31:47 -0800211 return NULL;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800212}
213
Kurt Hackelba2bf212006-12-01 14:47:20 -0800214/* intended to be called by functions which do not care about lock
215 * resources which are being purged (most net _handler functions).
216 * this will return NULL for any lock resource which is found but
217 * currently in the process of dropping its mastery reference.
218 * use __dlm_lookup_lockres_full when you need the lock resource
219 * regardless (e.g. dlm_get_lock_resource) */
220struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
221 const char *name,
222 unsigned int len,
223 unsigned int hash)
224{
225 struct dlm_lock_resource *res = NULL;
226
Tao Maef6b6892011-02-21 11:10:44 +0800227 mlog(0, "%.*s\n", len, name);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800228
229 assert_spin_locked(&dlm->spinlock);
230
231 res = __dlm_lookup_lockres_full(dlm, name, len, hash);
232 if (res) {
233 spin_lock(&res->spinlock);
234 if (res->state & DLM_LOCK_RES_DROPPING_REF) {
235 spin_unlock(&res->spinlock);
236 dlm_lockres_put(res);
237 return NULL;
238 }
239 spin_unlock(&res->spinlock);
240 }
241
242 return res;
243}
244
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800245struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm,
246 const char *name,
247 unsigned int len)
248{
249 struct dlm_lock_resource *res;
Mark Fasheha3d33292006-03-09 17:55:56 -0800250 unsigned int hash = dlm_lockid_hash(name, len);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800251
252 spin_lock(&dlm->spinlock);
Mark Fasheha3d33292006-03-09 17:55:56 -0800253 res = __dlm_lookup_lockres(dlm, name, len, hash);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800254 spin_unlock(&dlm->spinlock);
255 return res;
256}
257
258static struct dlm_ctxt * __dlm_lookup_domain_full(const char *domain, int len)
259{
260 struct dlm_ctxt *tmp = NULL;
261 struct list_head *iter;
262
263 assert_spin_locked(&dlm_domain_lock);
264
265 /* tmp->name here is always NULL terminated,
266 * but domain may not be! */
267 list_for_each(iter, &dlm_domains) {
268 tmp = list_entry (iter, struct dlm_ctxt, list);
269 if (strlen(tmp->name) == len &&
270 memcmp(tmp->name, domain, len)==0)
271 break;
272 tmp = NULL;
273 }
274
275 return tmp;
276}
277
278/* For null terminated domain strings ONLY */
279static struct dlm_ctxt * __dlm_lookup_domain(const char *domain)
280{
281 assert_spin_locked(&dlm_domain_lock);
282
283 return __dlm_lookup_domain_full(domain, strlen(domain));
284}
285
286
287/* returns true on one of two conditions:
288 * 1) the domain does not exist
289 * 2) the domain exists and it's state is "joined" */
290static int dlm_wait_on_domain_helper(const char *domain)
291{
292 int ret = 0;
293 struct dlm_ctxt *tmp = NULL;
294
295 spin_lock(&dlm_domain_lock);
296
297 tmp = __dlm_lookup_domain(domain);
298 if (!tmp)
299 ret = 1;
300 else if (tmp->dlm_state == DLM_CTXT_JOINED)
301 ret = 1;
302
303 spin_unlock(&dlm_domain_lock);
304 return ret;
305}
306
307static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm)
308{
Sunil Mushran6325b4a2008-03-10 15:16:22 -0700309 dlm_destroy_debugfs_subroot(dlm);
310
Mark Fasheh81f20942006-02-28 17:31:22 -0800311 if (dlm->lockres_hash)
Daniel Phillips03d864c2006-03-10 18:08:16 -0800312 dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800313
Sunil Mushrane2b66dd2009-02-26 15:00:40 -0800314 if (dlm->master_hash)
315 dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES);
316
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800317 if (dlm->name)
318 kfree(dlm->name);
319
320 kfree(dlm);
321}
322
323/* A little strange - this function will be called while holding
324 * dlm_domain_lock and is expected to be holding it on the way out. We
325 * will however drop and reacquire it multiple times */
326static void dlm_ctxt_release(struct kref *kref)
327{
328 struct dlm_ctxt *dlm;
329
330 dlm = container_of(kref, struct dlm_ctxt, dlm_refs);
331
332 BUG_ON(dlm->num_joins);
333 BUG_ON(dlm->dlm_state == DLM_CTXT_JOINED);
334
335 /* we may still be in the list if we hit an error during join. */
336 list_del_init(&dlm->list);
337
338 spin_unlock(&dlm_domain_lock);
339
340 mlog(0, "freeing memory from domain %s\n", dlm->name);
341
342 wake_up(&dlm_domain_events);
343
344 dlm_free_ctxt_mem(dlm);
345
346 spin_lock(&dlm_domain_lock);
347}
348
349void dlm_put(struct dlm_ctxt *dlm)
350{
351 spin_lock(&dlm_domain_lock);
352 kref_put(&dlm->dlm_refs, dlm_ctxt_release);
353 spin_unlock(&dlm_domain_lock);
354}
355
356static void __dlm_get(struct dlm_ctxt *dlm)
357{
358 kref_get(&dlm->dlm_refs);
359}
360
361/* given a questionable reference to a dlm object, gets a reference if
362 * it can find it in the list, otherwise returns NULL in which case
363 * you shouldn't trust your pointer. */
364struct dlm_ctxt *dlm_grab(struct dlm_ctxt *dlm)
365{
366 struct list_head *iter;
367 struct dlm_ctxt *target = NULL;
368
369 spin_lock(&dlm_domain_lock);
370
371 list_for_each(iter, &dlm_domains) {
372 target = list_entry (iter, struct dlm_ctxt, list);
373
374 if (target == dlm) {
375 __dlm_get(target);
376 break;
377 }
378
379 target = NULL;
380 }
381
382 spin_unlock(&dlm_domain_lock);
383
384 return target;
385}
386
387int dlm_domain_fully_joined(struct dlm_ctxt *dlm)
388{
389 int ret;
390
391 spin_lock(&dlm_domain_lock);
392 ret = (dlm->dlm_state == DLM_CTXT_JOINED) ||
393 (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN);
394 spin_unlock(&dlm_domain_lock);
395
396 return ret;
397}
398
Kurt Hackel3156d262006-05-01 14:39:29 -0700399static void dlm_destroy_dlm_worker(struct dlm_ctxt *dlm)
400{
401 if (dlm->dlm_worker) {
402 flush_workqueue(dlm->dlm_worker);
403 destroy_workqueue(dlm->dlm_worker);
404 dlm->dlm_worker = NULL;
405 }
406}
407
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800408static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm)
409{
410 dlm_unregister_domain_handlers(dlm);
Sunil Mushran007dce52008-03-10 15:16:23 -0700411 dlm_debug_shutdown(dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800412 dlm_complete_thread(dlm);
413 dlm_complete_recovery_thread(dlm);
Kurt Hackel3156d262006-05-01 14:39:29 -0700414 dlm_destroy_dlm_worker(dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800415
416 /* We've left the domain. Now we can take ourselves out of the
417 * list and allow the kref stuff to help us free the
418 * memory. */
419 spin_lock(&dlm_domain_lock);
420 list_del_init(&dlm->list);
421 spin_unlock(&dlm_domain_lock);
422
423 /* Wake up anyone waiting for us to remove this domain */
424 wake_up(&dlm_domain_events);
425}
426
Kurt Hackelba2bf212006-12-01 14:47:20 -0800427static int dlm_migrate_all_locks(struct dlm_ctxt *dlm)
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800428{
Kurt Hackelba2bf212006-12-01 14:47:20 -0800429 int i, num, n, ret = 0;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800430 struct dlm_lock_resource *res;
Kurt Hackelba2bf212006-12-01 14:47:20 -0800431 struct hlist_node *iter;
432 struct hlist_head *bucket;
433 int dropped;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800434
435 mlog(0, "Migrating locks from domain %s\n", dlm->name);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800436
437 num = 0;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800438 spin_lock(&dlm->spinlock);
Mark Fasheh81f20942006-02-28 17:31:22 -0800439 for (i = 0; i < DLM_HASH_BUCKETS; i++) {
Kurt Hackelba2bf212006-12-01 14:47:20 -0800440redo_bucket:
441 n = 0;
442 bucket = dlm_lockres_hash(dlm, i);
443 iter = bucket->first;
444 while (iter) {
445 n++;
446 res = hlist_entry(iter, struct dlm_lock_resource,
447 hash_node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800448 dlm_lockres_get(res);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800449 /* migrate, if necessary. this will drop the dlm
450 * spinlock and retake it if it does migration. */
451 dropped = dlm_empty_lockres(dlm, res);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800452
Kurt Hackelba2bf212006-12-01 14:47:20 -0800453 spin_lock(&res->spinlock);
454 __dlm_lockres_calc_usage(dlm, res);
455 iter = res->hash_node.next;
456 spin_unlock(&res->spinlock);
457
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800458 dlm_lockres_put(res);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800459
Kurt Hackelba2bf212006-12-01 14:47:20 -0800460 if (dropped)
461 goto redo_bucket;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800462 }
Sunil Mushran0d01af62007-04-17 13:32:20 -0700463 cond_resched_lock(&dlm->spinlock);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800464 num += n;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800465 }
466 spin_unlock(&dlm->spinlock);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800467 wake_up(&dlm->dlm_thread_wq);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800468
Kurt Hackelba2bf212006-12-01 14:47:20 -0800469 /* let the dlm thread take care of purging, keep scanning until
470 * nothing remains in the hash */
471 if (num) {
472 mlog(0, "%s: %d lock resources in hash last pass\n",
473 dlm->name, num);
474 ret = -EAGAIN;
475 }
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800476 mlog(0, "DONE Migrating locks from domain %s\n", dlm->name);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800477 return ret;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800478}
479
480static int dlm_no_joining_node(struct dlm_ctxt *dlm)
481{
482 int ret;
483
484 spin_lock(&dlm->spinlock);
485 ret = dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN;
486 spin_unlock(&dlm->spinlock);
487
488 return ret;
489}
490
Sunil Mushranbddefde2011-05-19 14:34:11 -0700491static int dlm_begin_exit_domain_handler(struct o2net_msg *msg, u32 len,
492 void *data, void **ret_data)
493{
494 struct dlm_ctxt *dlm = data;
495 unsigned int node;
496 struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf;
497
498 if (!dlm_grab(dlm))
499 return 0;
500
501 node = exit_msg->node_idx;
502 mlog(0, "%s: Node %u sent a begin exit domain message\n", dlm->name, node);
503
504 spin_lock(&dlm->spinlock);
505 set_bit(node, dlm->exit_domain_map);
506 spin_unlock(&dlm->spinlock);
507
508 dlm_put(dlm);
509
510 return 0;
511}
512
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800513static void dlm_mark_domain_leaving(struct dlm_ctxt *dlm)
514{
515 /* Yikes, a double spinlock! I need domain_lock for the dlm
516 * state and the dlm spinlock for join state... Sorry! */
517again:
518 spin_lock(&dlm_domain_lock);
519 spin_lock(&dlm->spinlock);
520
521 if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) {
522 mlog(0, "Node %d is joining, we wait on it.\n",
523 dlm->joining_node);
524 spin_unlock(&dlm->spinlock);
525 spin_unlock(&dlm_domain_lock);
526
527 wait_event(dlm->dlm_join_events, dlm_no_joining_node(dlm));
528 goto again;
529 }
530
531 dlm->dlm_state = DLM_CTXT_LEAVING;
532 spin_unlock(&dlm->spinlock);
533 spin_unlock(&dlm_domain_lock);
534}
535
536static void __dlm_print_nodes(struct dlm_ctxt *dlm)
537{
538 int node = -1;
539
540 assert_spin_locked(&dlm->spinlock);
541
Sunil Mushran5c80d4c2010-04-13 18:00:30 -0700542 printk(KERN_NOTICE "o2dlm: Nodes in domain %s: ", dlm->name);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800543
544 while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES,
545 node + 1)) < O2NM_MAX_NODES) {
Sunil Mushran781ee3e2006-04-27 16:41:31 -0700546 printk("%d ", node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800547 }
Sunil Mushran781ee3e2006-04-27 16:41:31 -0700548 printk("\n");
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800549}
550
Kurt Hackeld74c9802007-01-17 17:04:25 -0800551static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
552 void **ret_data)
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800553{
554 struct dlm_ctxt *dlm = data;
555 unsigned int node;
556 struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf;
557
Tao Maef6b6892011-02-21 11:10:44 +0800558 mlog(0, "%p %u %p", msg, len, data);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800559
560 if (!dlm_grab(dlm))
561 return 0;
562
563 node = exit_msg->node_idx;
564
Sunil Mushran5c80d4c2010-04-13 18:00:30 -0700565 printk(KERN_NOTICE "o2dlm: Node %u leaves domain %s\n", node, dlm->name);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800566
567 spin_lock(&dlm->spinlock);
568 clear_bit(node, dlm->domain_map);
Sunil Mushranbddefde2011-05-19 14:34:11 -0700569 clear_bit(node, dlm->exit_domain_map);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800570 __dlm_print_nodes(dlm);
571
572 /* notify anything attached to the heartbeat events */
573 dlm_hb_event_notify_attached(dlm, node, 0);
574
575 spin_unlock(&dlm->spinlock);
576
577 dlm_put(dlm);
578
579 return 0;
580}
581
Sunil Mushranbddefde2011-05-19 14:34:11 -0700582static int dlm_send_one_domain_exit(struct dlm_ctxt *dlm, u32 msg_type,
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800583 unsigned int node)
584{
585 int status;
586 struct dlm_exit_domain leave_msg;
587
Sunil Mushranbddefde2011-05-19 14:34:11 -0700588 mlog(0, "%s: Sending domain exit message %u to node %u\n", dlm->name,
589 msg_type, node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800590
591 memset(&leave_msg, 0, sizeof(leave_msg));
592 leave_msg.node_idx = dlm->node_num;
593
Sunil Mushranbddefde2011-05-19 14:34:11 -0700594 status = o2net_send_message(msg_type, dlm->key, &leave_msg,
595 sizeof(leave_msg), node, NULL);
Wengang Wanga5196ec2010-03-30 12:09:22 +0800596 if (status < 0)
Sunil Mushranbddefde2011-05-19 14:34:11 -0700597 mlog(ML_ERROR, "Error %d sending domain exit message %u "
598 "to node %u on domain %s\n", status, msg_type, node,
599 dlm->name);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800600
601 return status;
602}
603
Sunil Mushranbddefde2011-05-19 14:34:11 -0700604static void dlm_begin_exit_domain(struct dlm_ctxt *dlm)
605{
606 int node = -1;
607
608 /* Support for begin exit domain was added in 1.2 */
609 if (dlm->dlm_locking_proto.pv_major == 1 &&
610 dlm->dlm_locking_proto.pv_minor < 2)
611 return;
612
613 /*
614 * Unlike DLM_EXIT_DOMAIN_MSG, DLM_BEGIN_EXIT_DOMAIN_MSG is purely
615 * informational. Meaning if a node does not receive the message,
616 * so be it.
617 */
618 spin_lock(&dlm->spinlock);
619 while (1) {
620 node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, node + 1);
621 if (node >= O2NM_MAX_NODES)
622 break;
623 if (node == dlm->node_num)
624 continue;
625
626 spin_unlock(&dlm->spinlock);
627 dlm_send_one_domain_exit(dlm, DLM_BEGIN_EXIT_DOMAIN_MSG, node);
628 spin_lock(&dlm->spinlock);
629 }
630 spin_unlock(&dlm->spinlock);
631}
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800632
633static void dlm_leave_domain(struct dlm_ctxt *dlm)
634{
635 int node, clear_node, status;
636
637 /* At this point we've migrated away all our locks and won't
638 * accept mastership of new ones. The dlm is responsible for
639 * almost nothing now. We make sure not to confuse any joining
640 * nodes and then commence shutdown procedure. */
641
642 spin_lock(&dlm->spinlock);
643 /* Clear ourselves from the domain map */
644 clear_bit(dlm->node_num, dlm->domain_map);
645 while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES,
646 0)) < O2NM_MAX_NODES) {
647 /* Drop the dlm spinlock. This is safe wrt the domain_map.
648 * -nodes cannot be added now as the
649 * query_join_handlers knows to respond with OK_NO_MAP
650 * -we catch the right network errors if a node is
651 * removed from the map while we're sending him the
652 * exit message. */
653 spin_unlock(&dlm->spinlock);
654
655 clear_node = 1;
656
Sunil Mushranbddefde2011-05-19 14:34:11 -0700657 status = dlm_send_one_domain_exit(dlm, DLM_EXIT_DOMAIN_MSG,
658 node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800659 if (status < 0 &&
660 status != -ENOPROTOOPT &&
661 status != -ENOTCONN) {
662 mlog(ML_NOTICE, "Error %d sending domain exit message "
663 "to node %d\n", status, node);
664
665 /* Not sure what to do here but lets sleep for
666 * a bit in case this was a transient
667 * error... */
668 msleep(DLM_DOMAIN_BACKOFF_MS);
669 clear_node = 0;
670 }
671
672 spin_lock(&dlm->spinlock);
673 /* If we're not clearing the node bit then we intend
674 * to loop back around to try again. */
675 if (clear_node)
676 clear_bit(node, dlm->domain_map);
677 }
678 spin_unlock(&dlm->spinlock);
679}
680
681int dlm_joined(struct dlm_ctxt *dlm)
682{
683 int ret = 0;
684
685 spin_lock(&dlm_domain_lock);
686
687 if (dlm->dlm_state == DLM_CTXT_JOINED)
688 ret = 1;
689
690 spin_unlock(&dlm_domain_lock);
691
692 return ret;
693}
694
695int dlm_shutting_down(struct dlm_ctxt *dlm)
696{
697 int ret = 0;
698
699 spin_lock(&dlm_domain_lock);
700
701 if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN)
702 ret = 1;
703
704 spin_unlock(&dlm_domain_lock);
705
706 return ret;
707}
708
709void dlm_unregister_domain(struct dlm_ctxt *dlm)
710{
711 int leave = 0;
Sunil Mushran29576f82008-03-10 15:16:21 -0700712 struct dlm_lock_resource *res;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800713
714 spin_lock(&dlm_domain_lock);
715 BUG_ON(dlm->dlm_state != DLM_CTXT_JOINED);
716 BUG_ON(!dlm->num_joins);
717
718 dlm->num_joins--;
719 if (!dlm->num_joins) {
720 /* We mark it "in shutdown" now so new register
721 * requests wait until we've completely left the
722 * domain. Don't use DLM_CTXT_LEAVING yet as we still
723 * want new domain joins to communicate with us at
724 * least until we've completed migration of our
725 * resources. */
726 dlm->dlm_state = DLM_CTXT_IN_SHUTDOWN;
727 leave = 1;
728 }
729 spin_unlock(&dlm_domain_lock);
730
731 if (leave) {
732 mlog(0, "shutting down domain %s\n", dlm->name);
Sunil Mushranbddefde2011-05-19 14:34:11 -0700733 dlm_begin_exit_domain(dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800734
735 /* We changed dlm state, notify the thread */
736 dlm_kick_thread(dlm, NULL);
737
Kurt Hackelba2bf212006-12-01 14:47:20 -0800738 while (dlm_migrate_all_locks(dlm)) {
Sunil Mushran2f5bf1f2007-03-22 17:08:32 -0700739 /* Give dlm_thread time to purge the lockres' */
740 msleep(500);
Kurt Hackelba2bf212006-12-01 14:47:20 -0800741 mlog(0, "%s: more migration to do\n", dlm->name);
742 }
Sunil Mushran29576f82008-03-10 15:16:21 -0700743
744 /* This list should be empty. If not, print remaining lockres */
745 if (!list_empty(&dlm->tracking_list)) {
746 mlog(ML_ERROR, "Following lockres' are still on the "
747 "tracking list:\n");
748 list_for_each_entry(res, &dlm->tracking_list, tracking)
749 dlm_print_one_lock_resource(res);
750 }
751
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800752 dlm_mark_domain_leaving(dlm);
753 dlm_leave_domain(dlm);
Srinivas Eeda5dad6c32010-09-21 16:27:26 -0700754 dlm_force_free_mles(dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800755 dlm_complete_dlm_shutdown(dlm);
756 }
757 dlm_put(dlm);
758}
759EXPORT_SYMBOL_GPL(dlm_unregister_domain);
760
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800761static int dlm_query_join_proto_check(char *proto_type, int node,
762 struct dlm_protocol_version *ours,
763 struct dlm_protocol_version *request)
764{
765 int rc;
766 struct dlm_protocol_version proto = *request;
767
768 if (!dlm_protocol_compare(ours, &proto)) {
769 mlog(0,
770 "node %u wanted to join with %s locking protocol "
771 "%u.%u, we respond with %u.%u\n",
772 node, proto_type,
773 request->pv_major,
774 request->pv_minor,
775 proto.pv_major, proto.pv_minor);
776 request->pv_minor = proto.pv_minor;
777 rc = 0;
778 } else {
779 mlog(ML_NOTICE,
780 "Node %u wanted to join with %s locking "
781 "protocol %u.%u, but we have %u.%u, disallowing\n",
782 node, proto_type,
783 request->pv_major,
784 request->pv_minor,
785 ours->pv_major,
786 ours->pv_minor);
787 rc = 1;
788 }
789
790 return rc;
791}
792
Joel Becker0f71b7b2008-02-12 14:56:25 -0800793/*
794 * struct dlm_query_join_packet is made up of four one-byte fields. They
795 * are effectively in big-endian order already. However, little-endian
796 * machines swap them before putting the packet on the wire (because
797 * query_join's response is a status, and that status is treated as a u32
798 * on the wire). Thus, a big-endian and little-endian machines will treat
799 * this structure differently.
800 *
801 * The solution is to have little-endian machines swap the structure when
802 * converting from the structure to the u32 representation. This will
803 * result in the structure having the correct format on the wire no matter
804 * the host endian format.
805 */
806static void dlm_query_join_packet_to_wire(struct dlm_query_join_packet *packet,
807 u32 *wire)
808{
809 union dlm_query_join_response response;
810
811 response.packet = *packet;
812 *wire = cpu_to_be32(response.intval);
813}
814
815static void dlm_query_join_wire_to_packet(u32 wire,
816 struct dlm_query_join_packet *packet)
817{
818 union dlm_query_join_response response;
819
820 response.intval = cpu_to_be32(wire);
821 *packet = response.packet;
822}
823
Kurt Hackeld74c9802007-01-17 17:04:25 -0800824static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
825 void **ret_data)
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800826{
827 struct dlm_query_join_request *query;
Joel Becker0f71b7b2008-02-12 14:56:25 -0800828 struct dlm_query_join_packet packet = {
829 .code = JOIN_DISALLOW,
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800830 };
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800831 struct dlm_ctxt *dlm = NULL;
Joel Becker0f71b7b2008-02-12 14:56:25 -0800832 u32 response;
Srinivas Eeda1faf2892007-01-29 15:31:35 -0800833 u8 nodenum;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800834
835 query = (struct dlm_query_join_request *) msg->buf;
836
837 mlog(0, "node %u wants to join domain %s\n", query->node_idx,
838 query->domain);
839
840 /*
841 * If heartbeat doesn't consider the node live, tell it
842 * to back off and try again. This gives heartbeat a chance
843 * to catch up.
844 */
845 if (!o2hb_check_node_heartbeating(query->node_idx)) {
846 mlog(0, "node %u is not in our live map yet\n",
847 query->node_idx);
848
Joel Becker0f71b7b2008-02-12 14:56:25 -0800849 packet.code = JOIN_DISALLOW;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800850 goto respond;
851 }
852
Joel Becker0f71b7b2008-02-12 14:56:25 -0800853 packet.code = JOIN_OK_NO_MAP;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800854
855 spin_lock(&dlm_domain_lock);
856 dlm = __dlm_lookup_domain_full(query->domain, query->name_len);
Srinivas Eeda1faf2892007-01-29 15:31:35 -0800857 if (!dlm)
858 goto unlock_respond;
859
860 /*
861 * There is a small window where the joining node may not see the
862 * node(s) that just left but still part of the cluster. DISALLOW
863 * join request if joining node has different node map.
864 */
865 nodenum=0;
866 while (nodenum < O2NM_MAX_NODES) {
867 if (test_bit(nodenum, dlm->domain_map)) {
868 if (!byte_test_bit(nodenum, query->node_map)) {
Sunil Mushrane4968472007-01-29 15:37:02 -0800869 mlog(0, "disallow join as node %u does not "
870 "have node %u in its nodemap\n",
871 query->node_idx, nodenum);
Joel Becker0f71b7b2008-02-12 14:56:25 -0800872 packet.code = JOIN_DISALLOW;
Srinivas Eeda1faf2892007-01-29 15:31:35 -0800873 goto unlock_respond;
874 }
875 }
876 nodenum++;
877 }
878
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800879 /* Once the dlm ctxt is marked as leaving then we don't want
Sunil Mushran2bd63212010-01-25 16:57:38 -0800880 * to be put in someone's domain map.
Kurt Hackele2faea42006-01-12 14:24:55 -0800881 * Also, explicitly disallow joining at certain troublesome
882 * times (ie. during recovery). */
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800883 if (dlm && dlm->dlm_state != DLM_CTXT_LEAVING) {
Kurt Hackele2faea42006-01-12 14:24:55 -0800884 int bit = query->node_idx;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800885 spin_lock(&dlm->spinlock);
886
887 if (dlm->dlm_state == DLM_CTXT_NEW &&
888 dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN) {
889 /*If this is a brand new context and we
890 * haven't started our join process yet, then
891 * the other node won the race. */
Joel Becker0f71b7b2008-02-12 14:56:25 -0800892 packet.code = JOIN_OK_NO_MAP;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800893 } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) {
894 /* Disallow parallel joins. */
Joel Becker0f71b7b2008-02-12 14:56:25 -0800895 packet.code = JOIN_DISALLOW;
Kurt Hackele2faea42006-01-12 14:24:55 -0800896 } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) {
Sunil Mushrane4968472007-01-29 15:37:02 -0800897 mlog(0, "node %u trying to join, but recovery "
Kurt Hackele2faea42006-01-12 14:24:55 -0800898 "is ongoing.\n", bit);
Joel Becker0f71b7b2008-02-12 14:56:25 -0800899 packet.code = JOIN_DISALLOW;
Kurt Hackele2faea42006-01-12 14:24:55 -0800900 } else if (test_bit(bit, dlm->recovery_map)) {
Sunil Mushrane4968472007-01-29 15:37:02 -0800901 mlog(0, "node %u trying to join, but it "
Kurt Hackele2faea42006-01-12 14:24:55 -0800902 "still needs recovery.\n", bit);
Joel Becker0f71b7b2008-02-12 14:56:25 -0800903 packet.code = JOIN_DISALLOW;
Kurt Hackele2faea42006-01-12 14:24:55 -0800904 } else if (test_bit(bit, dlm->domain_map)) {
Sunil Mushrane4968472007-01-29 15:37:02 -0800905 mlog(0, "node %u trying to join, but it "
Kurt Hackele2faea42006-01-12 14:24:55 -0800906 "is still in the domain! needs recovery?\n",
907 bit);
Joel Becker0f71b7b2008-02-12 14:56:25 -0800908 packet.code = JOIN_DISALLOW;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800909 } else {
910 /* Alright we're fully a part of this domain
911 * so we keep some state as to who's joining
912 * and indicate to him that needs to be fixed
913 * up. */
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800914
915 /* Make sure we speak compatible locking protocols. */
916 if (dlm_query_join_proto_check("DLM", bit,
917 &dlm->dlm_locking_proto,
918 &query->dlm_proto)) {
Joel Becker0f71b7b2008-02-12 14:56:25 -0800919 packet.code = JOIN_PROTOCOL_MISMATCH;
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800920 } else if (dlm_query_join_proto_check("fs", bit,
921 &dlm->fs_locking_proto,
922 &query->fs_proto)) {
Joel Becker0f71b7b2008-02-12 14:56:25 -0800923 packet.code = JOIN_PROTOCOL_MISMATCH;
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800924 } else {
Joel Becker0f71b7b2008-02-12 14:56:25 -0800925 packet.dlm_minor = query->dlm_proto.pv_minor;
926 packet.fs_minor = query->fs_proto.pv_minor;
927 packet.code = JOIN_OK;
Joel Beckerd24fbcd2008-01-25 17:02:21 -0800928 __dlm_set_joining_node(dlm, query->node_idx);
929 }
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800930 }
931
932 spin_unlock(&dlm->spinlock);
933 }
Srinivas Eeda1faf2892007-01-29 15:31:35 -0800934unlock_respond:
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800935 spin_unlock(&dlm_domain_lock);
936
937respond:
Joel Becker0f71b7b2008-02-12 14:56:25 -0800938 mlog(0, "We respond with %u\n", packet.code);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800939
Joel Becker0f71b7b2008-02-12 14:56:25 -0800940 dlm_query_join_packet_to_wire(&packet, &response);
941 return response;
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800942}
943
Kurt Hackeld74c9802007-01-17 17:04:25 -0800944static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
945 void **ret_data)
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800946{
947 struct dlm_assert_joined *assert;
948 struct dlm_ctxt *dlm = NULL;
949
950 assert = (struct dlm_assert_joined *) msg->buf;
951
952 mlog(0, "node %u asserts join on domain %s\n", assert->node_idx,
953 assert->domain);
954
955 spin_lock(&dlm_domain_lock);
956 dlm = __dlm_lookup_domain_full(assert->domain, assert->name_len);
957 /* XXX should we consider no dlm ctxt an error? */
958 if (dlm) {
959 spin_lock(&dlm->spinlock);
960
961 /* Alright, this node has officially joined our
962 * domain. Set him in the map and clean up our
963 * leftover join state. */
964 BUG_ON(dlm->joining_node != assert->node_idx);
965 set_bit(assert->node_idx, dlm->domain_map);
Sunil Mushranbddefde2011-05-19 14:34:11 -0700966 clear_bit(assert->node_idx, dlm->exit_domain_map);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800967 __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
968
Sunil Mushran5c80d4c2010-04-13 18:00:30 -0700969 printk(KERN_NOTICE "o2dlm: Node %u joins domain %s\n",
Sunil Mushran781ee3e2006-04-27 16:41:31 -0700970 assert->node_idx, dlm->name);
Kurt Hackel6714d8e2005-12-15 14:31:23 -0800971 __dlm_print_nodes(dlm);
972
973 /* notify anything attached to the heartbeat events */
974 dlm_hb_event_notify_attached(dlm, assert->node_idx, 1);
975
976 spin_unlock(&dlm->spinlock);
977 }
978 spin_unlock(&dlm_domain_lock);
979
980 return 0;
981}
982
Sunil Mushranea203442010-10-09 10:26:23 -0700983static int dlm_match_regions(struct dlm_ctxt *dlm,
Sunil Mushran770c4d82011-02-21 14:25:25 -0800984 struct dlm_query_region *qr,
985 char *local, int locallen)
Sunil Mushranea203442010-10-09 10:26:23 -0700986{
Sunil Mushran770c4d82011-02-21 14:25:25 -0800987 char *remote = qr->qr_regions;
Sunil Mushranea203442010-10-09 10:26:23 -0700988 char *l, *r;
989 int localnr, i, j, foundit;
990 int status = 0;
991
992 if (!o2hb_global_heartbeat_active()) {
993 if (qr->qr_numregions) {
994 mlog(ML_ERROR, "Domain %s: Joining node %d has global "
995 "heartbeat enabled but local node %d does not\n",
996 qr->qr_domain, qr->qr_node, dlm->node_num);
997 status = -EINVAL;
998 }
999 goto bail;
1000 }
1001
1002 if (o2hb_global_heartbeat_active() && !qr->qr_numregions) {
1003 mlog(ML_ERROR, "Domain %s: Local node %d has global "
1004 "heartbeat enabled but joining node %d does not\n",
1005 qr->qr_domain, dlm->node_num, qr->qr_node);
1006 status = -EINVAL;
1007 goto bail;
1008 }
1009
1010 r = remote;
1011 for (i = 0; i < qr->qr_numregions; ++i) {
1012 mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r);
1013 r += O2HB_MAX_REGION_NAME_LEN;
1014 }
1015
Sunil Mushran770c4d82011-02-21 14:25:25 -08001016 localnr = min(O2NM_MAX_REGIONS, locallen/O2HB_MAX_REGION_NAME_LEN);
1017 localnr = o2hb_get_all_regions(local, (u8)localnr);
Sunil Mushranea203442010-10-09 10:26:23 -07001018
1019 /* compare local regions with remote */
1020 l = local;
1021 for (i = 0; i < localnr; ++i) {
1022 foundit = 0;
1023 r = remote;
1024 for (j = 0; j <= qr->qr_numregions; ++j) {
1025 if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) {
1026 foundit = 1;
1027 break;
1028 }
1029 r += O2HB_MAX_REGION_NAME_LEN;
1030 }
1031 if (!foundit) {
1032 status = -EINVAL;
1033 mlog(ML_ERROR, "Domain %s: Region '%.*s' registered "
1034 "in local node %d but not in joining node %d\n",
1035 qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, l,
1036 dlm->node_num, qr->qr_node);
1037 goto bail;
1038 }
1039 l += O2HB_MAX_REGION_NAME_LEN;
1040 }
1041
1042 /* compare remote with local regions */
1043 r = remote;
1044 for (i = 0; i < qr->qr_numregions; ++i) {
1045 foundit = 0;
1046 l = local;
1047 for (j = 0; j < localnr; ++j) {
1048 if (!memcmp(r, l, O2HB_MAX_REGION_NAME_LEN)) {
1049 foundit = 1;
1050 break;
1051 }
1052 l += O2HB_MAX_REGION_NAME_LEN;
1053 }
1054 if (!foundit) {
1055 status = -EINVAL;
1056 mlog(ML_ERROR, "Domain %s: Region '%.*s' registered "
1057 "in joining node %d but not in local node %d\n",
1058 qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, r,
1059 qr->qr_node, dlm->node_num);
1060 goto bail;
1061 }
1062 r += O2HB_MAX_REGION_NAME_LEN;
1063 }
1064
1065bail:
Sunil Mushranea203442010-10-09 10:26:23 -07001066 return status;
1067}
1068
1069static int dlm_send_regions(struct dlm_ctxt *dlm, unsigned long *node_map)
1070{
1071 struct dlm_query_region *qr = NULL;
1072 int status, ret = 0, i;
1073 char *p;
1074
1075 if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES)
1076 goto bail;
1077
1078 qr = kzalloc(sizeof(struct dlm_query_region), GFP_KERNEL);
1079 if (!qr) {
1080 ret = -ENOMEM;
1081 mlog_errno(ret);
1082 goto bail;
1083 }
1084
1085 qr->qr_node = dlm->node_num;
1086 qr->qr_namelen = strlen(dlm->name);
1087 memcpy(qr->qr_domain, dlm->name, qr->qr_namelen);
1088 /* if local hb, the numregions will be zero */
1089 if (o2hb_global_heartbeat_active())
1090 qr->qr_numregions = o2hb_get_all_regions(qr->qr_regions,
1091 O2NM_MAX_REGIONS);
1092
1093 p = qr->qr_regions;
1094 for (i = 0; i < qr->qr_numregions; ++i, p += O2HB_MAX_REGION_NAME_LEN)
1095 mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, p);
1096
1097 i = -1;
1098 while ((i = find_next_bit(node_map, O2NM_MAX_NODES,
1099 i + 1)) < O2NM_MAX_NODES) {
1100 if (i == dlm->node_num)
1101 continue;
1102
1103 mlog(0, "Sending regions to node %d\n", i);
1104
1105 ret = o2net_send_message(DLM_QUERY_REGION, DLM_MOD_KEY, qr,
1106 sizeof(struct dlm_query_region),
1107 i, &status);
1108 if (ret >= 0)
1109 ret = status;
1110 if (ret) {
1111 mlog(ML_ERROR, "Region mismatch %d, node %d\n",
1112 ret, i);
1113 break;
1114 }
1115 }
1116
1117bail:
1118 kfree(qr);
1119 return ret;
1120}
1121
1122static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
1123 void *data, void **ret_data)
1124{
1125 struct dlm_query_region *qr;
1126 struct dlm_ctxt *dlm = NULL;
Sunil Mushran770c4d82011-02-21 14:25:25 -08001127 char *local = NULL;
Sunil Mushranea203442010-10-09 10:26:23 -07001128 int status = 0;
1129 int locked = 0;
1130
1131 qr = (struct dlm_query_region *) msg->buf;
1132
1133 mlog(0, "Node %u queries hb regions on domain %s\n", qr->qr_node,
1134 qr->qr_domain);
1135
Sunil Mushran770c4d82011-02-21 14:25:25 -08001136 /* buffer used in dlm_mast_regions() */
1137 local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL);
1138 if (!local) {
1139 status = -ENOMEM;
1140 goto bail;
1141 }
1142
Sunil Mushranea203442010-10-09 10:26:23 -07001143 status = -EINVAL;
1144
1145 spin_lock(&dlm_domain_lock);
1146 dlm = __dlm_lookup_domain_full(qr->qr_domain, qr->qr_namelen);
1147 if (!dlm) {
1148 mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
1149 "before join domain\n", qr->qr_node, qr->qr_domain);
1150 goto bail;
1151 }
1152
1153 spin_lock(&dlm->spinlock);
1154 locked = 1;
1155 if (dlm->joining_node != qr->qr_node) {
1156 mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
1157 "but joining node is %d\n", qr->qr_node, qr->qr_domain,
1158 dlm->joining_node);
1159 goto bail;
1160 }
1161
1162 /* Support for global heartbeat was added in 1.1 */
1163 if (dlm->dlm_locking_proto.pv_major == 1 &&
1164 dlm->dlm_locking_proto.pv_minor == 0) {
1165 mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
1166 "but active dlm protocol is %d.%d\n", qr->qr_node,
1167 qr->qr_domain, dlm->dlm_locking_proto.pv_major,
1168 dlm->dlm_locking_proto.pv_minor);
1169 goto bail;
1170 }
1171
Sunil Mushran770c4d82011-02-21 14:25:25 -08001172 status = dlm_match_regions(dlm, qr, local, sizeof(qr->qr_regions));
Sunil Mushranea203442010-10-09 10:26:23 -07001173
1174bail:
1175 if (locked)
1176 spin_unlock(&dlm->spinlock);
1177 spin_unlock(&dlm_domain_lock);
1178
Sunil Mushran770c4d82011-02-21 14:25:25 -08001179 kfree(local);
1180
Sunil Mushranea203442010-10-09 10:26:23 -07001181 return status;
1182}
1183
Sunil Mushran18cfdf12010-10-07 16:47:03 -07001184static int dlm_match_nodes(struct dlm_ctxt *dlm, struct dlm_query_nodeinfo *qn)
1185{
1186 struct o2nm_node *local;
1187 struct dlm_node_info *remote;
1188 int i, j;
1189 int status = 0;
1190
1191 for (j = 0; j < qn->qn_numnodes; ++j)
1192 mlog(0, "Node %3d, %pI4:%u\n", qn->qn_nodes[j].ni_nodenum,
1193 &(qn->qn_nodes[j].ni_ipv4_address),
1194 ntohs(qn->qn_nodes[j].ni_ipv4_port));
1195
1196 for (i = 0; i < O2NM_MAX_NODES && !status; ++i) {
1197 local = o2nm_get_node_by_num(i);
1198 remote = NULL;
1199 for (j = 0; j < qn->qn_numnodes; ++j) {
1200 if (qn->qn_nodes[j].ni_nodenum == i) {
1201 remote = &(qn->qn_nodes[j]);
1202 break;
1203 }
1204 }
1205
1206 if (!local && !remote)
1207 continue;
1208
1209 if ((local && !remote) || (!local && remote))
1210 status = -EINVAL;
1211
1212 if (!status &&
1213 ((remote->ni_nodenum != local->nd_num) ||
1214 (remote->ni_ipv4_port != local->nd_ipv4_port) ||
1215 (remote->ni_ipv4_address != local->nd_ipv4_address)))
1216 status = -EINVAL;
1217
1218 if (status) {
1219 if (remote && !local)
1220 mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) "
1221 "registered in joining node %d but not in "
1222 "local node %d\n", qn->qn_domain,
1223 remote->ni_nodenum,
1224 &(remote->ni_ipv4_address),
1225 ntohs(remote->ni_ipv4_port),
1226 qn->qn_nodenum, dlm->node_num);
1227 if (local && !remote)
1228 mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) "
1229 "registered in local node %d but not in "
1230 "joining node %d\n", qn->qn_domain,
1231 local->nd_num, &(local->nd_ipv4_address),
1232 ntohs(local->nd_ipv4_port),
1233 dlm->node_num, qn->qn_nodenum);
1234 BUG_ON((!local && !remote));
1235 }
1236
1237 if (local)
1238 o2nm_node_put(local);
1239 }
1240
1241 return status;
1242}
1243
1244static int dlm_send_nodeinfo(struct dlm_ctxt *dlm, unsigned long *node_map)
1245{
1246 struct dlm_query_nodeinfo *qn = NULL;
1247 struct o2nm_node *node;
1248 int ret = 0, status, count, i;
1249
1250 if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES)
1251 goto bail;
1252
1253 qn = kzalloc(sizeof(struct dlm_query_nodeinfo), GFP_KERNEL);
1254 if (!qn) {
1255 ret = -ENOMEM;
1256 mlog_errno(ret);
1257 goto bail;
1258 }
1259
1260 for (i = 0, count = 0; i < O2NM_MAX_NODES; ++i) {
1261 node = o2nm_get_node_by_num(i);
1262 if (!node)
1263 continue;
1264 qn->qn_nodes[count].ni_nodenum = node->nd_num;
1265 qn->qn_nodes[count].ni_ipv4_port = node->nd_ipv4_port;
1266 qn->qn_nodes[count].ni_ipv4_address = node->nd_ipv4_address;
1267 mlog(0, "Node %3d, %pI4:%u\n", node->nd_num,
1268 &(node->nd_ipv4_address), ntohs(node->nd_ipv4_port));
1269 ++count;
1270 o2nm_node_put(node);
1271 }
1272
1273 qn->qn_nodenum = dlm->node_num;
1274 qn->qn_numnodes = count;
1275 qn->qn_namelen = strlen(dlm->name);
1276 memcpy(qn->qn_domain, dlm->name, qn->qn_namelen);
1277
1278 i = -1;
1279 while ((i = find_next_bit(node_map, O2NM_MAX_NODES,
1280 i + 1)) < O2NM_MAX_NODES) {
1281 if (i == dlm->node_num)
1282 continue;
1283
1284 mlog(0, "Sending nodeinfo to node %d\n", i);
1285
1286 ret = o2net_send_message(DLM_QUERY_NODEINFO, DLM_MOD_KEY,
1287 qn, sizeof(struct dlm_query_nodeinfo),
1288 i, &status);
1289 if (ret >= 0)
1290 ret = status;
1291 if (ret) {
1292 mlog(ML_ERROR, "node mismatch %d, node %d\n", ret, i);
1293 break;
1294 }
1295 }
1296
1297bail:
1298 kfree(qn);
1299 return ret;
1300}
1301
1302static int dlm_query_nodeinfo_handler(struct o2net_msg *msg, u32 len,
1303 void *data, void **ret_data)
1304{
1305 struct dlm_query_nodeinfo *qn;
1306 struct dlm_ctxt *dlm = NULL;
1307 int locked = 0, status = -EINVAL;
1308
1309 qn = (struct dlm_query_nodeinfo *) msg->buf;
1310
1311 mlog(0, "Node %u queries nodes on domain %s\n", qn->qn_nodenum,
1312 qn->qn_domain);
1313
1314 spin_lock(&dlm_domain_lock);
1315 dlm = __dlm_lookup_domain_full(qn->qn_domain, qn->qn_namelen);
1316 if (!dlm) {
1317 mlog(ML_ERROR, "Node %d queried nodes on domain %s before "
1318 "join domain\n", qn->qn_nodenum, qn->qn_domain);
1319 goto bail;
1320 }
1321
1322 spin_lock(&dlm->spinlock);
1323 locked = 1;
1324 if (dlm->joining_node != qn->qn_nodenum) {
1325 mlog(ML_ERROR, "Node %d queried nodes on domain %s but "
1326 "joining node is %d\n", qn->qn_nodenum, qn->qn_domain,
1327 dlm->joining_node);
1328 goto bail;
1329 }
1330
1331 /* Support for node query was added in 1.1 */
1332 if (dlm->dlm_locking_proto.pv_major == 1 &&
1333 dlm->dlm_locking_proto.pv_minor == 0) {
1334 mlog(ML_ERROR, "Node %d queried nodes on domain %s "
1335 "but active dlm protocol is %d.%d\n", qn->qn_nodenum,
1336 qn->qn_domain, dlm->dlm_locking_proto.pv_major,
1337 dlm->dlm_locking_proto.pv_minor);
1338 goto bail;
1339 }
1340
1341 status = dlm_match_nodes(dlm, qn);
1342
1343bail:
1344 if (locked)
1345 spin_unlock(&dlm->spinlock);
1346 spin_unlock(&dlm_domain_lock);
1347
1348 return status;
1349}
1350
Kurt Hackeld74c9802007-01-17 17:04:25 -08001351static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
1352 void **ret_data)
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001353{
1354 struct dlm_cancel_join *cancel;
1355 struct dlm_ctxt *dlm = NULL;
1356
1357 cancel = (struct dlm_cancel_join *) msg->buf;
1358
1359 mlog(0, "node %u cancels join on domain %s\n", cancel->node_idx,
1360 cancel->domain);
1361
1362 spin_lock(&dlm_domain_lock);
1363 dlm = __dlm_lookup_domain_full(cancel->domain, cancel->name_len);
1364
1365 if (dlm) {
1366 spin_lock(&dlm->spinlock);
1367
1368 /* Yikes, this guy wants to cancel his join. No
1369 * problem, we simply cleanup our join state. */
1370 BUG_ON(dlm->joining_node != cancel->node_idx);
1371 __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
1372
1373 spin_unlock(&dlm->spinlock);
1374 }
1375 spin_unlock(&dlm_domain_lock);
1376
1377 return 0;
1378}
1379
1380static int dlm_send_one_join_cancel(struct dlm_ctxt *dlm,
1381 unsigned int node)
1382{
1383 int status;
1384 struct dlm_cancel_join cancel_msg;
1385
1386 memset(&cancel_msg, 0, sizeof(cancel_msg));
1387 cancel_msg.node_idx = dlm->node_num;
1388 cancel_msg.name_len = strlen(dlm->name);
1389 memcpy(cancel_msg.domain, dlm->name, cancel_msg.name_len);
1390
1391 status = o2net_send_message(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY,
1392 &cancel_msg, sizeof(cancel_msg), node,
1393 NULL);
1394 if (status < 0) {
Wengang Wanga5196ec2010-03-30 12:09:22 +08001395 mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to "
1396 "node %u\n", status, DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY,
1397 node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001398 goto bail;
1399 }
1400
1401bail:
1402 return status;
1403}
1404
1405/* map_size should be in bytes. */
1406static int dlm_send_join_cancels(struct dlm_ctxt *dlm,
1407 unsigned long *node_map,
1408 unsigned int map_size)
1409{
1410 int status, tmpstat;
1411 unsigned int node;
1412
1413 if (map_size != (BITS_TO_LONGS(O2NM_MAX_NODES) *
1414 sizeof(unsigned long))) {
1415 mlog(ML_ERROR,
1416 "map_size %u != BITS_TO_LONGS(O2NM_MAX_NODES) %u\n",
Andrew Morton3a4780a2008-02-29 01:56:06 -08001417 map_size, (unsigned)BITS_TO_LONGS(O2NM_MAX_NODES));
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001418 return -EINVAL;
1419 }
1420
1421 status = 0;
1422 node = -1;
1423 while ((node = find_next_bit(node_map, O2NM_MAX_NODES,
1424 node + 1)) < O2NM_MAX_NODES) {
1425 if (node == dlm->node_num)
1426 continue;
1427
1428 tmpstat = dlm_send_one_join_cancel(dlm, node);
1429 if (tmpstat) {
1430 mlog(ML_ERROR, "Error return %d cancelling join on "
1431 "node %d\n", tmpstat, node);
1432 if (!status)
1433 status = tmpstat;
1434 }
1435 }
1436
1437 if (status)
1438 mlog_errno(status);
1439 return status;
1440}
1441
1442static int dlm_request_join(struct dlm_ctxt *dlm,
1443 int node,
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001444 enum dlm_query_join_response_code *response)
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001445{
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001446 int status;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001447 struct dlm_query_join_request join_msg;
Joel Becker0f71b7b2008-02-12 14:56:25 -08001448 struct dlm_query_join_packet packet;
1449 u32 join_resp;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001450
1451 mlog(0, "querying node %d\n", node);
1452
1453 memset(&join_msg, 0, sizeof(join_msg));
1454 join_msg.node_idx = dlm->node_num;
1455 join_msg.name_len = strlen(dlm->name);
1456 memcpy(join_msg.domain, dlm->name, join_msg.name_len);
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001457 join_msg.dlm_proto = dlm->dlm_locking_proto;
1458 join_msg.fs_proto = dlm->fs_locking_proto;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001459
Srinivas Eeda1faf2892007-01-29 15:31:35 -08001460 /* copy live node map to join message */
1461 byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES);
1462
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001463 status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg,
Wengang Wanga5196ec2010-03-30 12:09:22 +08001464 sizeof(join_msg), node, &join_resp);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001465 if (status < 0 && status != -ENOPROTOOPT) {
Wengang Wanga5196ec2010-03-30 12:09:22 +08001466 mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to "
1467 "node %u\n", status, DLM_QUERY_JOIN_MSG, DLM_MOD_KEY,
1468 node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001469 goto bail;
1470 }
Joel Becker0f71b7b2008-02-12 14:56:25 -08001471 dlm_query_join_wire_to_packet(join_resp, &packet);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001472
1473 /* -ENOPROTOOPT from the net code means the other side isn't
1474 listening for our message type -- that's fine, it means
1475 his dlm isn't up, so we can consider him a 'yes' but not
1476 joined into the domain. */
1477 if (status == -ENOPROTOOPT) {
1478 status = 0;
1479 *response = JOIN_OK_NO_MAP;
Joel Becker0f71b7b2008-02-12 14:56:25 -08001480 } else if (packet.code == JOIN_DISALLOW ||
1481 packet.code == JOIN_OK_NO_MAP) {
1482 *response = packet.code;
1483 } else if (packet.code == JOIN_PROTOCOL_MISMATCH) {
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001484 mlog(ML_NOTICE,
1485 "This node requested DLM locking protocol %u.%u and "
1486 "filesystem locking protocol %u.%u. At least one of "
1487 "the protocol versions on node %d is not compatible, "
1488 "disconnecting\n",
1489 dlm->dlm_locking_proto.pv_major,
1490 dlm->dlm_locking_proto.pv_minor,
1491 dlm->fs_locking_proto.pv_major,
1492 dlm->fs_locking_proto.pv_minor,
1493 node);
1494 status = -EPROTO;
Joel Becker0f71b7b2008-02-12 14:56:25 -08001495 *response = packet.code;
1496 } else if (packet.code == JOIN_OK) {
1497 *response = packet.code;
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001498 /* Use the same locking protocol as the remote node */
Joel Becker0f71b7b2008-02-12 14:56:25 -08001499 dlm->dlm_locking_proto.pv_minor = packet.dlm_minor;
1500 dlm->fs_locking_proto.pv_minor = packet.fs_minor;
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001501 mlog(0,
1502 "Node %d responds JOIN_OK with DLM locking protocol "
1503 "%u.%u and fs locking protocol %u.%u\n",
1504 node,
1505 dlm->dlm_locking_proto.pv_major,
1506 dlm->dlm_locking_proto.pv_minor,
1507 dlm->fs_locking_proto.pv_major,
1508 dlm->fs_locking_proto.pv_minor);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001509 } else {
1510 status = -EINVAL;
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001511 mlog(ML_ERROR, "invalid response %d from node %u\n",
Joel Becker0f71b7b2008-02-12 14:56:25 -08001512 packet.code, node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001513 }
1514
1515 mlog(0, "status %d, node %d response is %d\n", status, node,
Joel Becker0f71b7b2008-02-12 14:56:25 -08001516 *response);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001517
1518bail:
1519 return status;
1520}
1521
1522static int dlm_send_one_join_assert(struct dlm_ctxt *dlm,
1523 unsigned int node)
1524{
1525 int status;
1526 struct dlm_assert_joined assert_msg;
1527
1528 mlog(0, "Sending join assert to node %u\n", node);
1529
1530 memset(&assert_msg, 0, sizeof(assert_msg));
1531 assert_msg.node_idx = dlm->node_num;
1532 assert_msg.name_len = strlen(dlm->name);
1533 memcpy(assert_msg.domain, dlm->name, assert_msg.name_len);
1534
1535 status = o2net_send_message(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY,
1536 &assert_msg, sizeof(assert_msg), node,
1537 NULL);
1538 if (status < 0)
Wengang Wanga5196ec2010-03-30 12:09:22 +08001539 mlog(ML_ERROR, "Error %d when sending message %u (key 0x%x) to "
1540 "node %u\n", status, DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY,
1541 node);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001542
1543 return status;
1544}
1545
1546static void dlm_send_join_asserts(struct dlm_ctxt *dlm,
1547 unsigned long *node_map)
1548{
1549 int status, node, live;
1550
1551 status = 0;
1552 node = -1;
1553 while ((node = find_next_bit(node_map, O2NM_MAX_NODES,
1554 node + 1)) < O2NM_MAX_NODES) {
1555 if (node == dlm->node_num)
1556 continue;
1557
1558 do {
1559 /* It is very important that this message be
1560 * received so we spin until either the node
1561 * has died or it gets the message. */
1562 status = dlm_send_one_join_assert(dlm, node);
1563
1564 spin_lock(&dlm->spinlock);
1565 live = test_bit(node, dlm->live_nodes_map);
1566 spin_unlock(&dlm->spinlock);
1567
1568 if (status) {
1569 mlog(ML_ERROR, "Error return %d asserting "
1570 "join on node %d\n", status, node);
1571
1572 /* give us some time between errors... */
1573 if (live)
1574 msleep(DLM_DOMAIN_BACKOFF_MS);
1575 }
1576 } while (status && live);
1577 }
1578}
1579
1580struct domain_join_ctxt {
1581 unsigned long live_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
1582 unsigned long yes_resp_map[BITS_TO_LONGS(O2NM_MAX_NODES)];
1583};
1584
1585static int dlm_should_restart_join(struct dlm_ctxt *dlm,
1586 struct domain_join_ctxt *ctxt,
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001587 enum dlm_query_join_response_code response)
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001588{
1589 int ret;
1590
1591 if (response == JOIN_DISALLOW) {
1592 mlog(0, "Latest response of disallow -- should restart\n");
1593 return 1;
1594 }
1595
1596 spin_lock(&dlm->spinlock);
1597 /* For now, we restart the process if the node maps have
1598 * changed at all */
1599 ret = memcmp(ctxt->live_map, dlm->live_nodes_map,
1600 sizeof(dlm->live_nodes_map));
1601 spin_unlock(&dlm->spinlock);
1602
1603 if (ret)
1604 mlog(0, "Node maps changed -- should restart\n");
1605
1606 return ret;
1607}
1608
1609static int dlm_try_to_join_domain(struct dlm_ctxt *dlm)
1610{
1611 int status = 0, tmpstat, node;
1612 struct domain_join_ctxt *ctxt;
Joel Beckerd24fbcd2008-01-25 17:02:21 -08001613 enum dlm_query_join_response_code response = JOIN_DISALLOW;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001614
Tao Maef6b6892011-02-21 11:10:44 +08001615 mlog(0, "%p", dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001616
Robert P. J. Daycd861282006-12-13 00:34:52 -08001617 ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001618 if (!ctxt) {
1619 status = -ENOMEM;
1620 mlog_errno(status);
1621 goto bail;
1622 }
1623
1624 /* group sem locking should work for us here -- we're already
1625 * registered for heartbeat events so filling this should be
1626 * atomic wrt getting those handlers called. */
1627 o2hb_fill_node_map(dlm->live_nodes_map, sizeof(dlm->live_nodes_map));
1628
1629 spin_lock(&dlm->spinlock);
1630 memcpy(ctxt->live_map, dlm->live_nodes_map, sizeof(ctxt->live_map));
1631
1632 __dlm_set_joining_node(dlm, dlm->node_num);
1633
1634 spin_unlock(&dlm->spinlock);
1635
1636 node = -1;
1637 while ((node = find_next_bit(ctxt->live_map, O2NM_MAX_NODES,
1638 node + 1)) < O2NM_MAX_NODES) {
1639 if (node == dlm->node_num)
1640 continue;
1641
1642 status = dlm_request_join(dlm, node, &response);
1643 if (status < 0) {
1644 mlog_errno(status);
1645 goto bail;
1646 }
1647
1648 /* Ok, either we got a response or the node doesn't have a
1649 * dlm up. */
1650 if (response == JOIN_OK)
1651 set_bit(node, ctxt->yes_resp_map);
1652
1653 if (dlm_should_restart_join(dlm, ctxt, response)) {
1654 status = -EAGAIN;
1655 goto bail;
1656 }
1657 }
1658
1659 mlog(0, "Yay, done querying nodes!\n");
1660
1661 /* Yay, everyone agree's we can join the domain. My domain is
1662 * comprised of all nodes who were put in the
1663 * yes_resp_map. Copy that into our domain map and send a join
1664 * assert message to clean up everyone elses state. */
1665 spin_lock(&dlm->spinlock);
1666 memcpy(dlm->domain_map, ctxt->yes_resp_map,
1667 sizeof(ctxt->yes_resp_map));
1668 set_bit(dlm->node_num, dlm->domain_map);
1669 spin_unlock(&dlm->spinlock);
1670
Sunil Mushran18cfdf12010-10-07 16:47:03 -07001671 /* Support for global heartbeat and node info was added in 1.1 */
Sunil Mushran4da6dc22011-05-04 10:27:10 -07001672 if (dlm->dlm_locking_proto.pv_major > 1 ||
1673 dlm->dlm_locking_proto.pv_minor > 0) {
Sunil Mushran18cfdf12010-10-07 16:47:03 -07001674 status = dlm_send_nodeinfo(dlm, ctxt->yes_resp_map);
1675 if (status) {
1676 mlog_errno(status);
1677 goto bail;
1678 }
Sunil Mushranea203442010-10-09 10:26:23 -07001679 status = dlm_send_regions(dlm, ctxt->yes_resp_map);
1680 if (status) {
1681 mlog_errno(status);
1682 goto bail;
1683 }
1684 }
1685
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001686 dlm_send_join_asserts(dlm, ctxt->yes_resp_map);
1687
1688 /* Joined state *must* be set before the joining node
1689 * information, otherwise the query_join handler may read no
1690 * current joiner but a state of NEW and tell joining nodes
1691 * we're not in the domain. */
1692 spin_lock(&dlm_domain_lock);
1693 dlm->dlm_state = DLM_CTXT_JOINED;
1694 dlm->num_joins++;
1695 spin_unlock(&dlm_domain_lock);
1696
1697bail:
1698 spin_lock(&dlm->spinlock);
1699 __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN);
1700 if (!status)
1701 __dlm_print_nodes(dlm);
1702 spin_unlock(&dlm->spinlock);
1703
1704 if (ctxt) {
1705 /* Do we need to send a cancel message to any nodes? */
1706 if (status < 0) {
1707 tmpstat = dlm_send_join_cancels(dlm,
1708 ctxt->yes_resp_map,
1709 sizeof(ctxt->yes_resp_map));
1710 if (tmpstat < 0)
1711 mlog_errno(tmpstat);
1712 }
1713 kfree(ctxt);
1714 }
1715
1716 mlog(0, "returning %d\n", status);
1717 return status;
1718}
1719
1720static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm)
1721{
Sunil Mushran58a31582010-12-14 14:14:29 -08001722 o2hb_unregister_callback(dlm->name, &dlm->dlm_hb_up);
1723 o2hb_unregister_callback(dlm->name, &dlm->dlm_hb_down);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001724 o2net_unregister_handler_list(&dlm->dlm_domain_handlers);
1725}
1726
1727static int dlm_register_domain_handlers(struct dlm_ctxt *dlm)
1728{
1729 int status;
1730
1731 mlog(0, "registering handlers.\n");
1732
1733 o2hb_setup_callback(&dlm->dlm_hb_down, O2HB_NODE_DOWN_CB,
1734 dlm_hb_node_down_cb, dlm, DLM_HB_NODE_DOWN_PRI);
Sunil Mushran58a31582010-12-14 14:14:29 -08001735 status = o2hb_register_callback(dlm->name, &dlm->dlm_hb_down);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001736 if (status)
1737 goto bail;
1738
1739 o2hb_setup_callback(&dlm->dlm_hb_up, O2HB_NODE_UP_CB,
1740 dlm_hb_node_up_cb, dlm, DLM_HB_NODE_UP_PRI);
Sunil Mushran58a31582010-12-14 14:14:29 -08001741 status = o2hb_register_callback(dlm->name, &dlm->dlm_hb_up);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001742 if (status)
1743 goto bail;
1744
1745 status = o2net_register_handler(DLM_MASTER_REQUEST_MSG, dlm->key,
1746 sizeof(struct dlm_master_request),
1747 dlm_master_request_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001748 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001749 if (status)
1750 goto bail;
1751
1752 status = o2net_register_handler(DLM_ASSERT_MASTER_MSG, dlm->key,
1753 sizeof(struct dlm_assert_master),
1754 dlm_assert_master_handler,
Kurt Hackel3b8118c2007-01-17 17:05:53 -08001755 dlm, dlm_assert_master_post_handler,
1756 &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001757 if (status)
1758 goto bail;
1759
1760 status = o2net_register_handler(DLM_CREATE_LOCK_MSG, dlm->key,
1761 sizeof(struct dlm_create_lock),
1762 dlm_create_lock_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001763 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001764 if (status)
1765 goto bail;
1766
1767 status = o2net_register_handler(DLM_CONVERT_LOCK_MSG, dlm->key,
1768 DLM_CONVERT_LOCK_MAX_LEN,
1769 dlm_convert_lock_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001770 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001771 if (status)
1772 goto bail;
1773
1774 status = o2net_register_handler(DLM_UNLOCK_LOCK_MSG, dlm->key,
1775 DLM_UNLOCK_LOCK_MAX_LEN,
1776 dlm_unlock_lock_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001777 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001778 if (status)
1779 goto bail;
1780
1781 status = o2net_register_handler(DLM_PROXY_AST_MSG, dlm->key,
1782 DLM_PROXY_AST_MAX_LEN,
1783 dlm_proxy_ast_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001784 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001785 if (status)
1786 goto bail;
1787
1788 status = o2net_register_handler(DLM_EXIT_DOMAIN_MSG, dlm->key,
1789 sizeof(struct dlm_exit_domain),
1790 dlm_exit_domain_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001791 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001792 if (status)
1793 goto bail;
1794
Kurt Hackelba2bf212006-12-01 14:47:20 -08001795 status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key,
1796 sizeof(struct dlm_deref_lockres),
1797 dlm_deref_lockres_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001798 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackelba2bf212006-12-01 14:47:20 -08001799 if (status)
1800 goto bail;
1801
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001802 status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key,
1803 sizeof(struct dlm_migrate_request),
1804 dlm_migrate_request_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001805 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001806 if (status)
1807 goto bail;
1808
1809 status = o2net_register_handler(DLM_MIG_LOCKRES_MSG, dlm->key,
1810 DLM_MIG_LOCKRES_MAX_LEN,
1811 dlm_mig_lockres_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001812 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001813 if (status)
1814 goto bail;
1815
1816 status = o2net_register_handler(DLM_MASTER_REQUERY_MSG, dlm->key,
1817 sizeof(struct dlm_master_requery),
1818 dlm_master_requery_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001819 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001820 if (status)
1821 goto bail;
1822
1823 status = o2net_register_handler(DLM_LOCK_REQUEST_MSG, dlm->key,
1824 sizeof(struct dlm_lock_request),
1825 dlm_request_all_locks_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001826 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001827 if (status)
1828 goto bail;
1829
1830 status = o2net_register_handler(DLM_RECO_DATA_DONE_MSG, dlm->key,
1831 sizeof(struct dlm_reco_data_done),
1832 dlm_reco_data_done_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001833 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001834 if (status)
1835 goto bail;
1836
1837 status = o2net_register_handler(DLM_BEGIN_RECO_MSG, dlm->key,
1838 sizeof(struct dlm_begin_reco),
1839 dlm_begin_reco_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001840 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001841 if (status)
1842 goto bail;
1843
1844 status = o2net_register_handler(DLM_FINALIZE_RECO_MSG, dlm->key,
1845 sizeof(struct dlm_finalize_reco),
1846 dlm_finalize_reco_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08001847 dlm, NULL, &dlm->dlm_domain_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001848 if (status)
1849 goto bail;
1850
Sunil Mushranbddefde2011-05-19 14:34:11 -07001851 status = o2net_register_handler(DLM_BEGIN_EXIT_DOMAIN_MSG, dlm->key,
1852 sizeof(struct dlm_exit_domain),
1853 dlm_begin_exit_domain_handler,
1854 dlm, NULL, &dlm->dlm_domain_handlers);
1855 if (status)
1856 goto bail;
1857
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001858bail:
1859 if (status)
1860 dlm_unregister_domain_handlers(dlm);
1861
1862 return status;
1863}
1864
1865static int dlm_join_domain(struct dlm_ctxt *dlm)
1866{
1867 int status;
Sunil Mushran0dd82142007-01-29 15:44:27 -08001868 unsigned int backoff;
1869 unsigned int total_backoff = 0;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001870
1871 BUG_ON(!dlm);
1872
1873 mlog(0, "Join domain %s\n", dlm->name);
1874
1875 status = dlm_register_domain_handlers(dlm);
1876 if (status) {
1877 mlog_errno(status);
1878 goto bail;
1879 }
1880
Sunil Mushran007dce52008-03-10 15:16:23 -07001881 status = dlm_debug_init(dlm);
1882 if (status < 0) {
1883 mlog_errno(status);
1884 goto bail;
1885 }
1886
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001887 status = dlm_launch_thread(dlm);
1888 if (status < 0) {
1889 mlog_errno(status);
1890 goto bail;
1891 }
1892
1893 status = dlm_launch_recovery_thread(dlm);
1894 if (status < 0) {
1895 mlog_errno(status);
1896 goto bail;
1897 }
1898
Kurt Hackel3156d262006-05-01 14:39:29 -07001899 dlm->dlm_worker = create_singlethread_workqueue("dlm_wq");
1900 if (!dlm->dlm_worker) {
1901 status = -ENOMEM;
1902 mlog_errno(status);
1903 goto bail;
1904 }
1905
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001906 do {
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001907 status = dlm_try_to_join_domain(dlm);
1908
1909 /* If we're racing another node to the join, then we
1910 * need to back off temporarily and let them
1911 * complete. */
Sunil Mushran0dd82142007-01-29 15:44:27 -08001912#define DLM_JOIN_TIMEOUT_MSECS 90000
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001913 if (status == -EAGAIN) {
1914 if (signal_pending(current)) {
1915 status = -ERESTARTSYS;
1916 goto bail;
1917 }
1918
Sunil Mushran0dd82142007-01-29 15:44:27 -08001919 if (total_backoff >
1920 msecs_to_jiffies(DLM_JOIN_TIMEOUT_MSECS)) {
1921 status = -ERESTARTSYS;
1922 mlog(ML_NOTICE, "Timed out joining dlm domain "
1923 "%s after %u msecs\n", dlm->name,
1924 jiffies_to_msecs(total_backoff));
1925 goto bail;
1926 }
1927
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001928 /*
1929 * <chip> After you!
1930 * <dale> No, after you!
1931 * <chip> I insist!
1932 * <dale> But you first!
1933 * ...
1934 */
1935 backoff = (unsigned int)(jiffies & 0x3);
1936 backoff *= DLM_DOMAIN_BACKOFF_MS;
Sunil Mushran0dd82142007-01-29 15:44:27 -08001937 total_backoff += backoff;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001938 mlog(0, "backoff %d\n", backoff);
1939 msleep(backoff);
1940 }
1941 } while (status == -EAGAIN);
1942
1943 if (status < 0) {
1944 mlog_errno(status);
1945 goto bail;
1946 }
1947
1948 status = 0;
1949bail:
1950 wake_up(&dlm_domain_events);
1951
1952 if (status) {
1953 dlm_unregister_domain_handlers(dlm);
Sunil Mushran007dce52008-03-10 15:16:23 -07001954 dlm_debug_shutdown(dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001955 dlm_complete_thread(dlm);
1956 dlm_complete_recovery_thread(dlm);
Kurt Hackel3156d262006-05-01 14:39:29 -07001957 dlm_destroy_dlm_worker(dlm);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001958 }
1959
1960 return status;
1961}
1962
1963static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
1964 u32 key)
1965{
1966 int i;
Sunil Mushran6325b4a2008-03-10 15:16:22 -07001967 int ret;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001968 struct dlm_ctxt *dlm = NULL;
1969
Robert P. J. Daycd861282006-12-13 00:34:52 -08001970 dlm = kzalloc(sizeof(*dlm), GFP_KERNEL);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001971 if (!dlm) {
1972 mlog_errno(-ENOMEM);
1973 goto leave;
1974 }
1975
Julia Lawall316ce2b2010-05-14 21:30:48 +02001976 dlm->name = kstrdup(domain, GFP_KERNEL);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001977 if (dlm->name == NULL) {
1978 mlog_errno(-ENOMEM);
1979 kfree(dlm);
1980 dlm = NULL;
1981 goto leave;
1982 }
1983
Daniel Phillips03d864c2006-03-10 18:08:16 -08001984 dlm->lockres_hash = (struct hlist_head **)dlm_alloc_pagevec(DLM_HASH_PAGES);
Mark Fasheh81f20942006-02-28 17:31:22 -08001985 if (!dlm->lockres_hash) {
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001986 mlog_errno(-ENOMEM);
1987 kfree(dlm->name);
1988 kfree(dlm);
1989 dlm = NULL;
1990 goto leave;
1991 }
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001992
Daniel Phillips03d864c2006-03-10 18:08:16 -08001993 for (i = 0; i < DLM_HASH_BUCKETS; i++)
1994 INIT_HLIST_HEAD(dlm_lockres_hash(dlm, i));
Kurt Hackel6714d8e2005-12-15 14:31:23 -08001995
Sunil Mushrane2b66dd2009-02-26 15:00:40 -08001996 dlm->master_hash = (struct hlist_head **)
1997 dlm_alloc_pagevec(DLM_HASH_PAGES);
1998 if (!dlm->master_hash) {
1999 mlog_errno(-ENOMEM);
2000 dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES);
2001 kfree(dlm->name);
2002 kfree(dlm);
2003 dlm = NULL;
2004 goto leave;
2005 }
2006
2007 for (i = 0; i < DLM_HASH_BUCKETS; i++)
2008 INIT_HLIST_HEAD(dlm_master_hash(dlm, i));
2009
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002010 dlm->key = key;
2011 dlm->node_num = o2nm_this_node();
2012
Sunil Mushran6325b4a2008-03-10 15:16:22 -07002013 ret = dlm_create_debugfs_subroot(dlm);
2014 if (ret < 0) {
Sunil Mushrane2b66dd2009-02-26 15:00:40 -08002015 dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES);
Sunil Mushran6325b4a2008-03-10 15:16:22 -07002016 dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES);
2017 kfree(dlm->name);
2018 kfree(dlm);
2019 dlm = NULL;
2020 goto leave;
2021 }
2022
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002023 spin_lock_init(&dlm->spinlock);
2024 spin_lock_init(&dlm->master_lock);
2025 spin_lock_init(&dlm->ast_lock);
Sunil Mushranb0d4f8172008-12-16 15:49:22 -08002026 spin_lock_init(&dlm->track_lock);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002027 INIT_LIST_HEAD(&dlm->list);
2028 INIT_LIST_HEAD(&dlm->dirty_list);
2029 INIT_LIST_HEAD(&dlm->reco.resources);
2030 INIT_LIST_HEAD(&dlm->reco.received);
2031 INIT_LIST_HEAD(&dlm->reco.node_data);
2032 INIT_LIST_HEAD(&dlm->purge_list);
2033 INIT_LIST_HEAD(&dlm->dlm_domain_handlers);
Sunil Mushran29576f82008-03-10 15:16:21 -07002034 INIT_LIST_HEAD(&dlm->tracking_list);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002035 dlm->reco.state = 0;
2036
2037 INIT_LIST_HEAD(&dlm->pending_asts);
2038 INIT_LIST_HEAD(&dlm->pending_basts);
2039
2040 mlog(0, "dlm->recovery_map=%p, &(dlm->recovery_map[0])=%p\n",
2041 dlm->recovery_map, &(dlm->recovery_map[0]));
2042
2043 memset(dlm->recovery_map, 0, sizeof(dlm->recovery_map));
2044 memset(dlm->live_nodes_map, 0, sizeof(dlm->live_nodes_map));
2045 memset(dlm->domain_map, 0, sizeof(dlm->domain_map));
2046
2047 dlm->dlm_thread_task = NULL;
2048 dlm->dlm_reco_thread_task = NULL;
Kurt Hackel3156d262006-05-01 14:39:29 -07002049 dlm->dlm_worker = NULL;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002050 init_waitqueue_head(&dlm->dlm_thread_wq);
2051 init_waitqueue_head(&dlm->dlm_reco_thread_wq);
2052 init_waitqueue_head(&dlm->reco.event);
2053 init_waitqueue_head(&dlm->ast_wq);
2054 init_waitqueue_head(&dlm->migration_wq);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002055 INIT_LIST_HEAD(&dlm->mle_hb_events);
2056
2057 dlm->joining_node = DLM_LOCK_RES_OWNER_UNKNOWN;
2058 init_waitqueue_head(&dlm->dlm_join_events);
2059
2060 dlm->reco.new_master = O2NM_INVALID_NODE_NUM;
2061 dlm->reco.dead_node = O2NM_INVALID_NODE_NUM;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002062
Sunil Mushran68007912009-02-26 15:00:44 -08002063 atomic_set(&dlm->res_tot_count, 0);
2064 atomic_set(&dlm->res_cur_count, 0);
Sunil Mushran2041d8f2009-02-26 15:00:43 -08002065 for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) {
2066 atomic_set(&dlm->mle_tot_count[i], 0);
2067 atomic_set(&dlm->mle_cur_count[i], 0);
2068 }
2069
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002070 spin_lock_init(&dlm->work_lock);
2071 INIT_LIST_HEAD(&dlm->work_list);
David Howellsc4028952006-11-22 14:57:56 +00002072 INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002073
2074 kref_init(&dlm->dlm_refs);
2075 dlm->dlm_state = DLM_CTXT_NEW;
2076
2077 INIT_LIST_HEAD(&dlm->dlm_eviction_callbacks);
2078
2079 mlog(0, "context init: refcount %u\n",
2080 atomic_read(&dlm->dlm_refs.refcount));
2081
2082leave:
2083 return dlm;
2084}
2085
2086/*
Joel Beckerd24fbcd2008-01-25 17:02:21 -08002087 * Compare a requested locking protocol version against the current one.
2088 *
2089 * If the major numbers are different, they are incompatible.
2090 * If the current minor is greater than the request, they are incompatible.
2091 * If the current minor is less than or equal to the request, they are
2092 * compatible, and the requester should run at the current minor version.
2093 */
2094static int dlm_protocol_compare(struct dlm_protocol_version *existing,
2095 struct dlm_protocol_version *request)
2096{
2097 if (existing->pv_major != request->pv_major)
2098 return 1;
2099
2100 if (existing->pv_minor > request->pv_minor)
2101 return 1;
2102
2103 if (existing->pv_minor < request->pv_minor)
2104 request->pv_minor = existing->pv_minor;
2105
2106 return 0;
2107}
2108
2109/*
2110 * dlm_register_domain: one-time setup per "domain".
2111 *
2112 * The filesystem passes in the requested locking version via proto.
2113 * If registration was successful, proto will contain the negotiated
2114 * locking protocol.
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002115 */
2116struct dlm_ctxt * dlm_register_domain(const char *domain,
Joel Beckerd24fbcd2008-01-25 17:02:21 -08002117 u32 key,
2118 struct dlm_protocol_version *fs_proto)
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002119{
2120 int ret;
2121 struct dlm_ctxt *dlm = NULL;
2122 struct dlm_ctxt *new_ctxt = NULL;
2123
Dan Carpentere3723572010-07-10 16:33:36 +02002124 if (strlen(domain) >= O2NM_MAX_NAME_LEN) {
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002125 ret = -ENAMETOOLONG;
2126 mlog(ML_ERROR, "domain name length too long\n");
2127 goto leave;
2128 }
2129
2130 if (!o2hb_check_local_node_heartbeating()) {
2131 mlog(ML_ERROR, "the local node has not been configured, or is "
2132 "not heartbeating\n");
2133 ret = -EPROTO;
2134 goto leave;
2135 }
2136
2137 mlog(0, "register called for domain \"%s\"\n", domain);
2138
2139retry:
2140 dlm = NULL;
2141 if (signal_pending(current)) {
2142 ret = -ERESTARTSYS;
2143 mlog_errno(ret);
2144 goto leave;
2145 }
2146
2147 spin_lock(&dlm_domain_lock);
2148
2149 dlm = __dlm_lookup_domain(domain);
2150 if (dlm) {
2151 if (dlm->dlm_state != DLM_CTXT_JOINED) {
2152 spin_unlock(&dlm_domain_lock);
2153
2154 mlog(0, "This ctxt is not joined yet!\n");
2155 wait_event_interruptible(dlm_domain_events,
2156 dlm_wait_on_domain_helper(
2157 domain));
2158 goto retry;
2159 }
2160
Joel Beckerd24fbcd2008-01-25 17:02:21 -08002161 if (dlm_protocol_compare(&dlm->fs_locking_proto, fs_proto)) {
Julia Lawall64692722010-05-26 17:58:53 +02002162 spin_unlock(&dlm_domain_lock);
Joel Beckerd24fbcd2008-01-25 17:02:21 -08002163 mlog(ML_ERROR,
2164 "Requested locking protocol version is not "
2165 "compatible with already registered domain "
2166 "\"%s\"\n", domain);
2167 ret = -EPROTO;
2168 goto leave;
2169 }
2170
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002171 __dlm_get(dlm);
2172 dlm->num_joins++;
2173
2174 spin_unlock(&dlm_domain_lock);
2175
2176 ret = 0;
2177 goto leave;
2178 }
2179
2180 /* doesn't exist */
2181 if (!new_ctxt) {
2182 spin_unlock(&dlm_domain_lock);
2183
2184 new_ctxt = dlm_alloc_ctxt(domain, key);
2185 if (new_ctxt)
2186 goto retry;
2187
2188 ret = -ENOMEM;
2189 mlog_errno(ret);
2190 goto leave;
2191 }
2192
2193 /* a little variable switch-a-roo here... */
2194 dlm = new_ctxt;
2195 new_ctxt = NULL;
2196
2197 /* add the new domain */
2198 list_add_tail(&dlm->list, &dlm_domains);
2199 spin_unlock(&dlm_domain_lock);
2200
Joel Beckerd24fbcd2008-01-25 17:02:21 -08002201 /*
2202 * Pass the locking protocol version into the join. If the join
2203 * succeeds, it will have the negotiated protocol set.
2204 */
2205 dlm->dlm_locking_proto = dlm_protocol;
2206 dlm->fs_locking_proto = *fs_proto;
2207
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002208 ret = dlm_join_domain(dlm);
2209 if (ret) {
2210 mlog_errno(ret);
2211 dlm_put(dlm);
2212 goto leave;
2213 }
2214
Joel Beckerd24fbcd2008-01-25 17:02:21 -08002215 /* Tell the caller what locking protocol we negotiated */
2216 *fs_proto = dlm->fs_locking_proto;
2217
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002218 ret = 0;
2219leave:
2220 if (new_ctxt)
2221 dlm_free_ctxt_mem(new_ctxt);
2222
2223 if (ret < 0)
2224 dlm = ERR_PTR(ret);
2225
2226 return dlm;
2227}
2228EXPORT_SYMBOL_GPL(dlm_register_domain);
2229
2230static LIST_HEAD(dlm_join_handlers);
2231
2232static void dlm_unregister_net_handlers(void)
2233{
2234 o2net_unregister_handler_list(&dlm_join_handlers);
2235}
2236
2237static int dlm_register_net_handlers(void)
2238{
2239 int status = 0;
2240
2241 status = o2net_register_handler(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY,
2242 sizeof(struct dlm_query_join_request),
2243 dlm_query_join_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08002244 NULL, NULL, &dlm_join_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002245 if (status)
2246 goto bail;
2247
2248 status = o2net_register_handler(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY,
2249 sizeof(struct dlm_assert_joined),
2250 dlm_assert_joined_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08002251 NULL, NULL, &dlm_join_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002252 if (status)
2253 goto bail;
2254
2255 status = o2net_register_handler(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY,
2256 sizeof(struct dlm_cancel_join),
2257 dlm_cancel_join_handler,
Kurt Hackeld74c9802007-01-17 17:04:25 -08002258 NULL, NULL, &dlm_join_handlers);
Sunil Mushranea203442010-10-09 10:26:23 -07002259 if (status)
2260 goto bail;
2261
2262 status = o2net_register_handler(DLM_QUERY_REGION, DLM_MOD_KEY,
2263 sizeof(struct dlm_query_region),
2264 dlm_query_region_handler,
2265 NULL, NULL, &dlm_join_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002266
Sunil Mushran18cfdf12010-10-07 16:47:03 -07002267 if (status)
2268 goto bail;
2269
2270 status = o2net_register_handler(DLM_QUERY_NODEINFO, DLM_MOD_KEY,
2271 sizeof(struct dlm_query_nodeinfo),
2272 dlm_query_nodeinfo_handler,
2273 NULL, NULL, &dlm_join_handlers);
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002274bail:
2275 if (status < 0)
2276 dlm_unregister_net_handlers();
2277
2278 return status;
2279}
2280
2281/* Domain eviction callback handling.
2282 *
2283 * The file system requires notification of node death *before* the
2284 * dlm completes it's recovery work, otherwise it may be able to
2285 * acquire locks on resources requiring recovery. Since the dlm can
2286 * evict a node from it's domain *before* heartbeat fires, a similar
2287 * mechanism is required. */
2288
2289/* Eviction is not expected to happen often, so a per-domain lock is
2290 * not necessary. Eviction callbacks are allowed to sleep for short
2291 * periods of time. */
2292static DECLARE_RWSEM(dlm_callback_sem);
2293
2294void dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm,
2295 int node_num)
2296{
2297 struct list_head *iter;
2298 struct dlm_eviction_cb *cb;
2299
2300 down_read(&dlm_callback_sem);
2301 list_for_each(iter, &dlm->dlm_eviction_callbacks) {
2302 cb = list_entry(iter, struct dlm_eviction_cb, ec_item);
2303
2304 cb->ec_func(node_num, cb->ec_data);
2305 }
2306 up_read(&dlm_callback_sem);
2307}
2308
2309void dlm_setup_eviction_cb(struct dlm_eviction_cb *cb,
2310 dlm_eviction_func *f,
2311 void *data)
2312{
2313 INIT_LIST_HEAD(&cb->ec_item);
2314 cb->ec_func = f;
2315 cb->ec_data = data;
2316}
2317EXPORT_SYMBOL_GPL(dlm_setup_eviction_cb);
2318
2319void dlm_register_eviction_cb(struct dlm_ctxt *dlm,
2320 struct dlm_eviction_cb *cb)
2321{
2322 down_write(&dlm_callback_sem);
2323 list_add_tail(&cb->ec_item, &dlm->dlm_eviction_callbacks);
2324 up_write(&dlm_callback_sem);
2325}
2326EXPORT_SYMBOL_GPL(dlm_register_eviction_cb);
2327
2328void dlm_unregister_eviction_cb(struct dlm_eviction_cb *cb)
2329{
2330 down_write(&dlm_callback_sem);
2331 list_del_init(&cb->ec_item);
2332 up_write(&dlm_callback_sem);
2333}
2334EXPORT_SYMBOL_GPL(dlm_unregister_eviction_cb);
2335
2336static int __init dlm_init(void)
2337{
2338 int status;
2339
2340 dlm_print_version();
2341
2342 status = dlm_init_mle_cache();
Sunil Mushran12eb0032008-03-10 15:16:19 -07002343 if (status) {
2344 mlog(ML_ERROR, "Could not create o2dlm_mle slabcache\n");
Sunil Mushran724bdca2008-03-10 15:16:20 -07002345 goto error;
2346 }
2347
2348 status = dlm_init_master_caches();
2349 if (status) {
2350 mlog(ML_ERROR, "Could not create o2dlm_lockres and "
2351 "o2dlm_lockname slabcaches\n");
2352 goto error;
2353 }
2354
2355 status = dlm_init_lock_cache();
2356 if (status) {
2357 mlog(ML_ERROR, "Count not create o2dlm_lock slabcache\n");
2358 goto error;
Sunil Mushran12eb0032008-03-10 15:16:19 -07002359 }
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002360
2361 status = dlm_register_net_handlers();
2362 if (status) {
Sunil Mushran724bdca2008-03-10 15:16:20 -07002363 mlog(ML_ERROR, "Unable to register network handlers\n");
2364 goto error;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002365 }
2366
Sunil Mushran6325b4a2008-03-10 15:16:22 -07002367 status = dlm_create_debugfs_root();
2368 if (status)
2369 goto error;
2370
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002371 return 0;
Sunil Mushran724bdca2008-03-10 15:16:20 -07002372error:
Sunil Mushran6325b4a2008-03-10 15:16:22 -07002373 dlm_unregister_net_handlers();
Sunil Mushran724bdca2008-03-10 15:16:20 -07002374 dlm_destroy_lock_cache();
2375 dlm_destroy_master_caches();
2376 dlm_destroy_mle_cache();
2377 return -1;
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002378}
2379
2380static void __exit dlm_exit (void)
2381{
Sunil Mushran6325b4a2008-03-10 15:16:22 -07002382 dlm_destroy_debugfs_root();
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002383 dlm_unregister_net_handlers();
Sunil Mushran724bdca2008-03-10 15:16:20 -07002384 dlm_destroy_lock_cache();
2385 dlm_destroy_master_caches();
Kurt Hackel6714d8e2005-12-15 14:31:23 -08002386 dlm_destroy_mle_cache();
2387}
2388
2389MODULE_AUTHOR("Oracle");
2390MODULE_LICENSE("GPL");
2391
2392module_init(dlm_init);
2393module_exit(dlm_exit);