Linux Audio

Check our new training course

Loading...
v4.6
 
  1/******************************************************************************
  2*******************************************************************************
  3**
  4**  Copyright (C) 2005-2011 Red Hat, Inc.  All rights reserved.
  5**
  6**  This copyrighted material is made available to anyone wishing to use,
  7**  modify, copy, or redistribute it subject to the terms and conditions
  8**  of the GNU General Public License v.2.
  9**
 10*******************************************************************************
 11******************************************************************************/
 12
 13#include "dlm_internal.h"
 14#include "lockspace.h"
 15#include "member.h"
 16#include "recoverd.h"
 17#include "recover.h"
 18#include "rcom.h"
 19#include "config.h"
 
 20#include "lowcomms.h"
 21
 22int dlm_slots_version(struct dlm_header *h)
 23{
 24	if ((h->h_version & 0x0000FFFF) < DLM_HEADER_SLOTS)
 25		return 0;
 26	return 1;
 27}
 28
 29void dlm_slot_save(struct dlm_ls *ls, struct dlm_rcom *rc,
 30		   struct dlm_member *memb)
 31{
 32	struct rcom_config *rf = (struct rcom_config *)rc->rc_buf;
 33
 34	if (!dlm_slots_version(&rc->rc_header))
 35		return;
 36
 37	memb->slot = le16_to_cpu(rf->rf_our_slot);
 38	memb->generation = le32_to_cpu(rf->rf_generation);
 39}
 40
 41void dlm_slots_copy_out(struct dlm_ls *ls, struct dlm_rcom *rc)
 42{
 43	struct dlm_slot *slot;
 44	struct rcom_slot *ro;
 45	int i;
 46
 47	ro = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config));
 48
 49	/* ls_slots array is sparse, but not rcom_slots */
 50
 51	for (i = 0; i < ls->ls_slots_size; i++) {
 52		slot = &ls->ls_slots[i];
 53		if (!slot->nodeid)
 54			continue;
 55		ro->ro_nodeid = cpu_to_le32(slot->nodeid);
 56		ro->ro_slot = cpu_to_le16(slot->slot);
 57		ro++;
 58	}
 59}
 60
 61#define SLOT_DEBUG_LINE 128
 62
 63static void log_slots(struct dlm_ls *ls, uint32_t gen, int num_slots,
 64		      struct rcom_slot *ro0, struct dlm_slot *array,
 65		      int array_size)
 66{
 67	char line[SLOT_DEBUG_LINE];
 68	int len = SLOT_DEBUG_LINE - 1;
 69	int pos = 0;
 70	int ret, i;
 71
 72	memset(line, 0, sizeof(line));
 73
 74	if (array) {
 75		for (i = 0; i < array_size; i++) {
 76			if (!array[i].nodeid)
 77				continue;
 78
 79			ret = snprintf(line + pos, len - pos, " %d:%d",
 80				       array[i].slot, array[i].nodeid);
 81			if (ret >= len - pos)
 82				break;
 83			pos += ret;
 84		}
 85	} else if (ro0) {
 86		for (i = 0; i < num_slots; i++) {
 87			ret = snprintf(line + pos, len - pos, " %d:%d",
 88				       ro0[i].ro_slot, ro0[i].ro_nodeid);
 89			if (ret >= len - pos)
 90				break;
 91			pos += ret;
 92		}
 93	}
 94
 95	log_rinfo(ls, "generation %u slots %d%s", gen, num_slots, line);
 96}
 97
 98int dlm_slots_copy_in(struct dlm_ls *ls)
 99{
100	struct dlm_member *memb;
101	struct dlm_rcom *rc = ls->ls_recover_buf;
102	struct rcom_config *rf = (struct rcom_config *)rc->rc_buf;
103	struct rcom_slot *ro0, *ro;
104	int our_nodeid = dlm_our_nodeid();
105	int i, num_slots;
106	uint32_t gen;
107
108	if (!dlm_slots_version(&rc->rc_header))
109		return -1;
110
111	gen = le32_to_cpu(rf->rf_generation);
112	if (gen <= ls->ls_generation) {
113		log_error(ls, "dlm_slots_copy_in gen %u old %u",
114			  gen, ls->ls_generation);
115	}
116	ls->ls_generation = gen;
117
118	num_slots = le16_to_cpu(rf->rf_num_slots);
119	if (!num_slots)
120		return -1;
121
122	ro0 = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config));
123
124	for (i = 0, ro = ro0; i < num_slots; i++, ro++) {
125		ro->ro_nodeid = le32_to_cpu(ro->ro_nodeid);
126		ro->ro_slot = le16_to_cpu(ro->ro_slot);
127	}
128
129	log_slots(ls, gen, num_slots, ro0, NULL, 0);
130
131	list_for_each_entry(memb, &ls->ls_nodes, list) {
132		for (i = 0, ro = ro0; i < num_slots; i++, ro++) {
133			if (ro->ro_nodeid != memb->nodeid)
134				continue;
135			memb->slot = ro->ro_slot;
136			memb->slot_prev = memb->slot;
137			break;
138		}
139
140		if (memb->nodeid == our_nodeid) {
141			if (ls->ls_slot && ls->ls_slot != memb->slot) {
142				log_error(ls, "dlm_slots_copy_in our slot "
143					  "changed %d %d", ls->ls_slot,
144					  memb->slot);
145				return -1;
146			}
147
148			if (!ls->ls_slot)
149				ls->ls_slot = memb->slot;
150		}
151
152		if (!memb->slot) {
153			log_error(ls, "dlm_slots_copy_in nodeid %d no slot",
154				   memb->nodeid);
155			return -1;
156		}
157	}
158
159	return 0;
160}
161
162/* for any nodes that do not support slots, we will not have set memb->slot
163   in wait_status_all(), so memb->slot will remain -1, and we will not
164   assign slots or set ls_num_slots here */
165
166int dlm_slots_assign(struct dlm_ls *ls, int *num_slots, int *slots_size,
167		     struct dlm_slot **slots_out, uint32_t *gen_out)
168{
169	struct dlm_member *memb;
170	struct dlm_slot *array;
171	int our_nodeid = dlm_our_nodeid();
172	int array_size, max_slots, i;
173	int need = 0;
174	int max = 0;
175	int num = 0;
176	uint32_t gen = 0;
177
178	/* our own memb struct will have slot -1 gen 0 */
179
180	list_for_each_entry(memb, &ls->ls_nodes, list) {
181		if (memb->nodeid == our_nodeid) {
182			memb->slot = ls->ls_slot;
183			memb->generation = ls->ls_generation;
184			break;
185		}
186	}
187
188	list_for_each_entry(memb, &ls->ls_nodes, list) {
189		if (memb->generation > gen)
190			gen = memb->generation;
191
192		/* node doesn't support slots */
193
194		if (memb->slot == -1)
195			return -1;
196
197		/* node needs a slot assigned */
198
199		if (!memb->slot)
200			need++;
201
202		/* node has a slot assigned */
203
204		num++;
205
206		if (!max || max < memb->slot)
207			max = memb->slot;
208
209		/* sanity check, once slot is assigned it shouldn't change */
210
211		if (memb->slot_prev && memb->slot && memb->slot_prev != memb->slot) {
212			log_error(ls, "nodeid %d slot changed %d %d",
213				  memb->nodeid, memb->slot_prev, memb->slot);
214			return -1;
215		}
216		memb->slot_prev = memb->slot;
217	}
218
219	array_size = max + need;
220
221	array = kzalloc(array_size * sizeof(struct dlm_slot), GFP_NOFS);
222	if (!array)
223		return -ENOMEM;
224
225	num = 0;
226
227	/* fill in slots (offsets) that are used */
228
229	list_for_each_entry(memb, &ls->ls_nodes, list) {
230		if (!memb->slot)
231			continue;
232
233		if (memb->slot > array_size) {
234			log_error(ls, "invalid slot number %d", memb->slot);
235			kfree(array);
236			return -1;
237		}
238
239		array[memb->slot - 1].nodeid = memb->nodeid;
240		array[memb->slot - 1].slot = memb->slot;
241		num++;
242	}
243
244	/* assign new slots from unused offsets */
245
246	list_for_each_entry(memb, &ls->ls_nodes, list) {
247		if (memb->slot)
248			continue;
249
250		for (i = 0; i < array_size; i++) {
251			if (array[i].nodeid)
252				continue;
253
254			memb->slot = i + 1;
255			memb->slot_prev = memb->slot;
256			array[i].nodeid = memb->nodeid;
257			array[i].slot = memb->slot;
258			num++;
259
260			if (!ls->ls_slot && memb->nodeid == our_nodeid)
261				ls->ls_slot = memb->slot;
262			break;
263		}
264
265		if (!memb->slot) {
266			log_error(ls, "no free slot found");
267			kfree(array);
268			return -1;
269		}
270	}
271
272	gen++;
273
274	log_slots(ls, gen, num, NULL, array, array_size);
275
276	max_slots = (dlm_config.ci_buffer_size - sizeof(struct dlm_rcom) -
277		     sizeof(struct rcom_config)) / sizeof(struct rcom_slot);
278
279	if (num > max_slots) {
280		log_error(ls, "num_slots %d exceeds max_slots %d",
281			  num, max_slots);
282		kfree(array);
283		return -1;
284	}
285
286	*gen_out = gen;
287	*slots_out = array;
288	*slots_size = array_size;
289	*num_slots = num;
290	return 0;
291}
292
293static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
294{
295	struct dlm_member *memb = NULL;
296	struct list_head *tmp;
297	struct list_head *newlist = &new->list;
298	struct list_head *head = &ls->ls_nodes;
299
300	list_for_each(tmp, head) {
301		memb = list_entry(tmp, struct dlm_member, list);
302		if (new->nodeid < memb->nodeid)
303			break;
304	}
305
306	if (!memb)
307		list_add_tail(newlist, head);
308	else {
309		/* FIXME: can use list macro here */
310		newlist->prev = tmp->prev;
311		newlist->next = tmp;
312		tmp->prev->next = newlist;
313		tmp->prev = newlist;
314	}
315}
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317static int dlm_add_member(struct dlm_ls *ls, struct dlm_config_node *node)
318{
319	struct dlm_member *memb;
320	int error;
321
322	memb = kzalloc(sizeof(struct dlm_member), GFP_NOFS);
323	if (!memb)
324		return -ENOMEM;
325
326	error = dlm_lowcomms_connect_node(node->nodeid);
 
 
 
 
327	if (error < 0) {
328		kfree(memb);
329		return error;
330	}
331
332	memb->nodeid = node->nodeid;
333	memb->weight = node->weight;
334	memb->comm_seq = node->comm_seq;
335	add_ordered_member(ls, memb);
336	ls->ls_num_nodes++;
337	return 0;
338}
339
340static struct dlm_member *find_memb(struct list_head *head, int nodeid)
341{
342	struct dlm_member *memb;
343
344	list_for_each_entry(memb, head, list) {
345		if (memb->nodeid == nodeid)
346			return memb;
347	}
348	return NULL;
349}
350
351int dlm_is_member(struct dlm_ls *ls, int nodeid)
352{
353	if (find_memb(&ls->ls_nodes, nodeid))
354		return 1;
355	return 0;
356}
357
358int dlm_is_removed(struct dlm_ls *ls, int nodeid)
359{
 
 
360	if (find_memb(&ls->ls_nodes_gone, nodeid))
361		return 1;
362	return 0;
363}
364
365static void clear_memb_list(struct list_head *head)
 
366{
367	struct dlm_member *memb;
368
369	while (!list_empty(head)) {
370		memb = list_entry(head->next, struct dlm_member, list);
371		list_del(&memb->list);
 
 
372		kfree(memb);
373	}
374}
375
 
 
 
 
 
 
 
 
376void dlm_clear_members(struct dlm_ls *ls)
377{
378	clear_memb_list(&ls->ls_nodes);
379	ls->ls_num_nodes = 0;
380}
381
382void dlm_clear_members_gone(struct dlm_ls *ls)
383{
384	clear_memb_list(&ls->ls_nodes_gone);
385}
386
387static void make_member_array(struct dlm_ls *ls)
388{
389	struct dlm_member *memb;
390	int i, w, x = 0, total = 0, all_zero = 0, *array;
391
392	kfree(ls->ls_node_array);
393	ls->ls_node_array = NULL;
394
395	list_for_each_entry(memb, &ls->ls_nodes, list) {
396		if (memb->weight)
397			total += memb->weight;
398	}
399
400	/* all nodes revert to weight of 1 if all have weight 0 */
401
402	if (!total) {
403		total = ls->ls_num_nodes;
404		all_zero = 1;
405	}
406
407	ls->ls_total_weight = total;
408
409	array = kmalloc(sizeof(int) * total, GFP_NOFS);
410	if (!array)
411		return;
412
413	list_for_each_entry(memb, &ls->ls_nodes, list) {
414		if (!all_zero && !memb->weight)
415			continue;
416
417		if (all_zero)
418			w = 1;
419		else
420			w = memb->weight;
421
422		DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););
423
424		for (i = 0; i < w; i++)
425			array[x++] = memb->nodeid;
426	}
427
428	ls->ls_node_array = array;
429}
430
431/* send a status request to all members just to establish comms connections */
432
433static int ping_members(struct dlm_ls *ls)
434{
435	struct dlm_member *memb;
436	int error = 0;
437
438	list_for_each_entry(memb, &ls->ls_nodes, list) {
439		error = dlm_recovery_stopped(ls);
440		if (error)
441			break;
442		error = dlm_rcom_status(ls, memb->nodeid, 0);
 
443		if (error)
444			break;
445	}
446	if (error)
447		log_rinfo(ls, "ping_members aborted %d last nodeid %d",
448			  error, ls->ls_recover_nodeid);
449	return error;
450}
451
452static void dlm_lsop_recover_prep(struct dlm_ls *ls)
453{
454	if (!ls->ls_ops || !ls->ls_ops->recover_prep)
455		return;
456	ls->ls_ops->recover_prep(ls->ls_ops_arg);
457}
458
459static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb)
460{
461	struct dlm_slot slot;
462	uint32_t seq;
463	int error;
464
465	if (!ls->ls_ops || !ls->ls_ops->recover_slot)
466		return;
467
468	/* if there is no comms connection with this node
469	   or the present comms connection is newer
470	   than the one when this member was added, then
471	   we consider the node to have failed (versus
472	   being removed due to dlm_release_lockspace) */
473
474	error = dlm_comm_seq(memb->nodeid, &seq);
475
476	if (!error && seq == memb->comm_seq)
477		return;
478
479	slot.nodeid = memb->nodeid;
480	slot.slot = memb->slot;
481
482	ls->ls_ops->recover_slot(ls->ls_ops_arg, &slot);
483}
484
485void dlm_lsop_recover_done(struct dlm_ls *ls)
486{
487	struct dlm_member *memb;
488	struct dlm_slot *slots;
489	int i, num;
490
491	if (!ls->ls_ops || !ls->ls_ops->recover_done)
492		return;
493
494	num = ls->ls_num_nodes;
495
496	slots = kzalloc(num * sizeof(struct dlm_slot), GFP_KERNEL);
497	if (!slots)
498		return;
499
500	i = 0;
501	list_for_each_entry(memb, &ls->ls_nodes, list) {
502		if (i == num) {
503			log_error(ls, "dlm_lsop_recover_done bad num %d", num);
504			goto out;
505		}
506		slots[i].nodeid = memb->nodeid;
507		slots[i].slot = memb->slot;
508		i++;
509	}
510
511	ls->ls_ops->recover_done(ls->ls_ops_arg, slots, num,
512				 ls->ls_slot, ls->ls_generation);
513 out:
514	kfree(slots);
515}
516
517static struct dlm_config_node *find_config_node(struct dlm_recover *rv,
518						int nodeid)
519{
520	int i;
521
522	for (i = 0; i < rv->nodes_count; i++) {
523		if (rv->nodes[i].nodeid == nodeid)
524			return &rv->nodes[i];
525	}
526	return NULL;
527}
528
529int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
530{
531	struct dlm_member *memb, *safe;
532	struct dlm_config_node *node;
533	int i, error, neg = 0, low = -1;
534
535	/* previously removed members that we've not finished removing need to
536	   count as a negative change so the "neg" recovery steps will happen */
 
 
 
 
537
538	list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
539		log_rinfo(ls, "prev removed member %d", memb->nodeid);
540		neg++;
541	}
542
543	/* move departed members from ls_nodes to ls_nodes_gone */
544
545	list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
546		node = find_config_node(rv, memb->nodeid);
547		if (node && !node->new)
548			continue;
549
550		if (!node) {
551			log_rinfo(ls, "remove member %d", memb->nodeid);
552		} else {
553			/* removed and re-added */
554			log_rinfo(ls, "remove member %d comm_seq %u %u",
555				  memb->nodeid, memb->comm_seq, node->comm_seq);
556		}
557
558		neg++;
559		list_move(&memb->list, &ls->ls_nodes_gone);
 
560		ls->ls_num_nodes--;
561		dlm_lsop_recover_slot(ls, memb);
562	}
563
564	/* add new members to ls_nodes */
565
566	for (i = 0; i < rv->nodes_count; i++) {
567		node = &rv->nodes[i];
568		if (dlm_is_member(ls, node->nodeid))
569			continue;
570		dlm_add_member(ls, node);
 
 
 
571		log_rinfo(ls, "add member %d", node->nodeid);
572	}
573
574	list_for_each_entry(memb, &ls->ls_nodes, list) {
575		if (low == -1 || memb->nodeid < low)
576			low = memb->nodeid;
577	}
578	ls->ls_low_nodeid = low;
579
580	make_member_array(ls);
581	*neg_out = neg;
582
583	error = ping_members(ls);
584	if (!error || error == -EPROTO) {
585		/* new_lockspace() may be waiting to know if the config
586		   is good or bad */
587		ls->ls_members_result = error;
588		complete(&ls->ls_members_done);
589	}
590
591	log_rinfo(ls, "dlm_recover_members %d nodes", ls->ls_num_nodes);
592	return error;
593}
594
595/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before
596   dlm_ls_start() is called on any of them to start the new recovery. */
597
598int dlm_ls_stop(struct dlm_ls *ls)
599{
600	int new;
601
602	/*
603	 * Prevent dlm_recv from being in the middle of something when we do
604	 * the stop.  This includes ensuring dlm_recv isn't processing a
605	 * recovery message (rcom), while dlm_recoverd is aborting and
606	 * resetting things from an in-progress recovery.  i.e. we want
607	 * dlm_recoverd to abort its recovery without worrying about dlm_recv
608	 * processing an rcom at the same time.  Stopping dlm_recv also makes
609	 * it easy for dlm_receive_message() to check locking stopped and add a
610	 * message to the requestqueue without races.
611	 */
612
613	down_write(&ls->ls_recv_active);
614
615	/*
616	 * Abort any recovery that's in progress (see RECOVER_STOP,
617	 * dlm_recovery_stopped()) and tell any other threads running in the
618	 * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
619	 */
620
621	spin_lock(&ls->ls_recover_lock);
622	set_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
623	new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
 
 
624	ls->ls_recover_seq++;
625	spin_unlock(&ls->ls_recover_lock);
 
 
 
 
 
626
627	/*
628	 * Let dlm_recv run again, now any normal messages will be saved on the
629	 * requestqueue for later.
630	 */
631
632	up_write(&ls->ls_recv_active);
633
634	/*
635	 * This in_recovery lock does two things:
636	 * 1) Keeps this function from returning until all threads are out
637	 *    of locking routines and locking is truly stopped.
638	 * 2) Keeps any new requests from being processed until it's unlocked
639	 *    when recovery is complete.
640	 */
641
642	if (new) {
643		set_bit(LSFL_RECOVER_DOWN, &ls->ls_flags);
644		wake_up_process(ls->ls_recoverd_task);
645		wait_event(ls->ls_recover_lock_wait,
646			   test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
647	}
648
649	/*
650	 * The recoverd suspend/resume makes sure that dlm_recoverd (if
651	 * running) has noticed RECOVER_STOP above and quit processing the
652	 * previous recovery.
653	 */
654
655	dlm_recoverd_suspend(ls);
656
657	spin_lock(&ls->ls_recover_lock);
658	kfree(ls->ls_slots);
659	ls->ls_slots = NULL;
660	ls->ls_num_slots = 0;
661	ls->ls_slots_size = 0;
662	ls->ls_recover_status = 0;
663	spin_unlock(&ls->ls_recover_lock);
664
665	dlm_recoverd_resume(ls);
666
667	if (!ls->ls_recover_begin)
668		ls->ls_recover_begin = jiffies;
669
670	dlm_lsop_recover_prep(ls);
 
 
 
 
 
 
 
 
 
671	return 0;
672}
673
674int dlm_ls_start(struct dlm_ls *ls)
675{
676	struct dlm_recover *rv = NULL, *rv_old;
677	struct dlm_config_node *nodes;
678	int error, count;
679
680	rv = kzalloc(sizeof(struct dlm_recover), GFP_NOFS);
681	if (!rv)
682		return -ENOMEM;
683
684	error = dlm_config_nodes(ls->ls_name, &nodes, &count);
685	if (error < 0)
686		goto fail;
687
688	spin_lock(&ls->ls_recover_lock);
689
690	/* the lockspace needs to be stopped before it can be started */
691
692	if (!dlm_locking_stopped(ls)) {
693		spin_unlock(&ls->ls_recover_lock);
694		log_error(ls, "start ignored: lockspace running");
695		error = -EINVAL;
696		goto fail;
697	}
698
699	rv->nodes = nodes;
700	rv->nodes_count = count;
701	rv->seq = ++ls->ls_recover_seq;
702	rv_old = ls->ls_recover_args;
703	ls->ls_recover_args = rv;
704	spin_unlock(&ls->ls_recover_lock);
705
706	if (rv_old) {
707		log_error(ls, "unused recovery %llx %d",
708			  (unsigned long long)rv_old->seq, rv_old->nodes_count);
709		kfree(rv_old->nodes);
710		kfree(rv_old);
711	}
712
713	set_bit(LSFL_RECOVER_WORK, &ls->ls_flags);
714	wake_up_process(ls->ls_recoverd_task);
715	return 0;
716
717 fail:
718	kfree(rv);
719	kfree(nodes);
 
 
720	return error;
721}
722
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/******************************************************************************
  3*******************************************************************************
  4**
  5**  Copyright (C) 2005-2011 Red Hat, Inc.  All rights reserved.
  6**
 
 
 
  7**
  8*******************************************************************************
  9******************************************************************************/
 10
 11#include "dlm_internal.h"
 12#include "lockspace.h"
 13#include "member.h"
 14#include "recoverd.h"
 15#include "recover.h"
 16#include "rcom.h"
 17#include "config.h"
 18#include "midcomms.h"
 19#include "lowcomms.h"
 20
 21int dlm_slots_version(const struct dlm_header *h)
 22{
 23	if ((le32_to_cpu(h->h_version) & 0x0000FFFF) < DLM_HEADER_SLOTS)
 24		return 0;
 25	return 1;
 26}
 27
 28void dlm_slot_save(struct dlm_ls *ls, struct dlm_rcom *rc,
 29		   struct dlm_member *memb)
 30{
 31	struct rcom_config *rf = (struct rcom_config *)rc->rc_buf;
 32
 33	if (!dlm_slots_version(&rc->rc_header))
 34		return;
 35
 36	memb->slot = le16_to_cpu(rf->rf_our_slot);
 37	memb->generation = le32_to_cpu(rf->rf_generation);
 38}
 39
 40void dlm_slots_copy_out(struct dlm_ls *ls, struct dlm_rcom *rc)
 41{
 42	struct dlm_slot *slot;
 43	struct rcom_slot *ro;
 44	int i;
 45
 46	ro = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config));
 47
 48	/* ls_slots array is sparse, but not rcom_slots */
 49
 50	for (i = 0; i < ls->ls_slots_size; i++) {
 51		slot = &ls->ls_slots[i];
 52		if (!slot->nodeid)
 53			continue;
 54		ro->ro_nodeid = cpu_to_le32(slot->nodeid);
 55		ro->ro_slot = cpu_to_le16(slot->slot);
 56		ro++;
 57	}
 58}
 59
 60#define SLOT_DEBUG_LINE 128
 61
 62static void log_slots(struct dlm_ls *ls, uint32_t gen, int num_slots,
 63		      struct rcom_slot *ro0, struct dlm_slot *array,
 64		      int array_size)
 65{
 66	char line[SLOT_DEBUG_LINE];
 67	int len = SLOT_DEBUG_LINE - 1;
 68	int pos = 0;
 69	int ret, i;
 70
 71	memset(line, 0, sizeof(line));
 72
 73	if (array) {
 74		for (i = 0; i < array_size; i++) {
 75			if (!array[i].nodeid)
 76				continue;
 77
 78			ret = snprintf(line + pos, len - pos, " %d:%d",
 79				       array[i].slot, array[i].nodeid);
 80			if (ret >= len - pos)
 81				break;
 82			pos += ret;
 83		}
 84	} else if (ro0) {
 85		for (i = 0; i < num_slots; i++) {
 86			ret = snprintf(line + pos, len - pos, " %d:%d",
 87				       ro0[i].ro_slot, ro0[i].ro_nodeid);
 88			if (ret >= len - pos)
 89				break;
 90			pos += ret;
 91		}
 92	}
 93
 94	log_rinfo(ls, "generation %u slots %d%s", gen, num_slots, line);
 95}
 96
 97int dlm_slots_copy_in(struct dlm_ls *ls)
 98{
 99	struct dlm_member *memb;
100	struct dlm_rcom *rc = ls->ls_recover_buf;
101	struct rcom_config *rf = (struct rcom_config *)rc->rc_buf;
102	struct rcom_slot *ro0, *ro;
103	int our_nodeid = dlm_our_nodeid();
104	int i, num_slots;
105	uint32_t gen;
106
107	if (!dlm_slots_version(&rc->rc_header))
108		return -1;
109
110	gen = le32_to_cpu(rf->rf_generation);
111	if (gen <= ls->ls_generation) {
112		log_error(ls, "dlm_slots_copy_in gen %u old %u",
113			  gen, ls->ls_generation);
114	}
115	ls->ls_generation = gen;
116
117	num_slots = le16_to_cpu(rf->rf_num_slots);
118	if (!num_slots)
119		return -1;
120
121	ro0 = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config));
122
 
 
 
 
 
123	log_slots(ls, gen, num_slots, ro0, NULL, 0);
124
125	list_for_each_entry(memb, &ls->ls_nodes, list) {
126		for (i = 0, ro = ro0; i < num_slots; i++, ro++) {
127			if (le32_to_cpu(ro->ro_nodeid) != memb->nodeid)
128				continue;
129			memb->slot = le16_to_cpu(ro->ro_slot);
130			memb->slot_prev = memb->slot;
131			break;
132		}
133
134		if (memb->nodeid == our_nodeid) {
135			if (ls->ls_slot && ls->ls_slot != memb->slot) {
136				log_error(ls, "dlm_slots_copy_in our slot "
137					  "changed %d %d", ls->ls_slot,
138					  memb->slot);
139				return -1;
140			}
141
142			if (!ls->ls_slot)
143				ls->ls_slot = memb->slot;
144		}
145
146		if (!memb->slot) {
147			log_error(ls, "dlm_slots_copy_in nodeid %d no slot",
148				   memb->nodeid);
149			return -1;
150		}
151	}
152
153	return 0;
154}
155
156/* for any nodes that do not support slots, we will not have set memb->slot
157   in wait_status_all(), so memb->slot will remain -1, and we will not
158   assign slots or set ls_num_slots here */
159
160int dlm_slots_assign(struct dlm_ls *ls, int *num_slots, int *slots_size,
161		     struct dlm_slot **slots_out, uint32_t *gen_out)
162{
163	struct dlm_member *memb;
164	struct dlm_slot *array;
165	int our_nodeid = dlm_our_nodeid();
166	int array_size, max_slots, i;
167	int need = 0;
168	int max = 0;
169	int num = 0;
170	uint32_t gen = 0;
171
172	/* our own memb struct will have slot -1 gen 0 */
173
174	list_for_each_entry(memb, &ls->ls_nodes, list) {
175		if (memb->nodeid == our_nodeid) {
176			memb->slot = ls->ls_slot;
177			memb->generation = ls->ls_generation;
178			break;
179		}
180	}
181
182	list_for_each_entry(memb, &ls->ls_nodes, list) {
183		if (memb->generation > gen)
184			gen = memb->generation;
185
186		/* node doesn't support slots */
187
188		if (memb->slot == -1)
189			return -1;
190
191		/* node needs a slot assigned */
192
193		if (!memb->slot)
194			need++;
195
196		/* node has a slot assigned */
197
198		num++;
199
200		if (!max || max < memb->slot)
201			max = memb->slot;
202
203		/* sanity check, once slot is assigned it shouldn't change */
204
205		if (memb->slot_prev && memb->slot && memb->slot_prev != memb->slot) {
206			log_error(ls, "nodeid %d slot changed %d %d",
207				  memb->nodeid, memb->slot_prev, memb->slot);
208			return -1;
209		}
210		memb->slot_prev = memb->slot;
211	}
212
213	array_size = max + need;
214	array = kcalloc(array_size, sizeof(*array), GFP_NOFS);
 
215	if (!array)
216		return -ENOMEM;
217
218	num = 0;
219
220	/* fill in slots (offsets) that are used */
221
222	list_for_each_entry(memb, &ls->ls_nodes, list) {
223		if (!memb->slot)
224			continue;
225
226		if (memb->slot > array_size) {
227			log_error(ls, "invalid slot number %d", memb->slot);
228			kfree(array);
229			return -1;
230		}
231
232		array[memb->slot - 1].nodeid = memb->nodeid;
233		array[memb->slot - 1].slot = memb->slot;
234		num++;
235	}
236
237	/* assign new slots from unused offsets */
238
239	list_for_each_entry(memb, &ls->ls_nodes, list) {
240		if (memb->slot)
241			continue;
242
243		for (i = 0; i < array_size; i++) {
244			if (array[i].nodeid)
245				continue;
246
247			memb->slot = i + 1;
248			memb->slot_prev = memb->slot;
249			array[i].nodeid = memb->nodeid;
250			array[i].slot = memb->slot;
251			num++;
252
253			if (!ls->ls_slot && memb->nodeid == our_nodeid)
254				ls->ls_slot = memb->slot;
255			break;
256		}
257
258		if (!memb->slot) {
259			log_error(ls, "no free slot found");
260			kfree(array);
261			return -1;
262		}
263	}
264
265	gen++;
266
267	log_slots(ls, gen, num, NULL, array, array_size);
268
269	max_slots = (DLM_MAX_APP_BUFSIZE - sizeof(struct dlm_rcom) -
270		     sizeof(struct rcom_config)) / sizeof(struct rcom_slot);
271
272	if (num > max_slots) {
273		log_error(ls, "num_slots %d exceeds max_slots %d",
274			  num, max_slots);
275		kfree(array);
276		return -1;
277	}
278
279	*gen_out = gen;
280	*slots_out = array;
281	*slots_size = array_size;
282	*num_slots = num;
283	return 0;
284}
285
286static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
287{
288	struct dlm_member *memb = NULL;
289	struct list_head *tmp;
290	struct list_head *newlist = &new->list;
291	struct list_head *head = &ls->ls_nodes;
292
293	list_for_each(tmp, head) {
294		memb = list_entry(tmp, struct dlm_member, list);
295		if (new->nodeid < memb->nodeid)
296			break;
297	}
298
299	if (!memb)
300		list_add_tail(newlist, head);
301	else {
302		/* FIXME: can use list macro here */
303		newlist->prev = tmp->prev;
304		newlist->next = tmp;
305		tmp->prev->next = newlist;
306		tmp->prev = newlist;
307	}
308}
309
310static int add_remote_member(int nodeid)
311{
312	int error;
313
314	if (nodeid == dlm_our_nodeid())
315		return 0;
316
317	error = dlm_lowcomms_connect_node(nodeid);
318	if (error < 0)
319		return error;
320
321	dlm_midcomms_add_member(nodeid);
322	return 0;
323}
324
325static int dlm_add_member(struct dlm_ls *ls, struct dlm_config_node *node)
326{
327	struct dlm_member *memb;
328	int error;
329
330	memb = kzalloc(sizeof(*memb), GFP_NOFS);
331	if (!memb)
332		return -ENOMEM;
333
334	memb->nodeid = node->nodeid;
335	memb->weight = node->weight;
336	memb->comm_seq = node->comm_seq;
337
338	error = add_remote_member(node->nodeid);
339	if (error < 0) {
340		kfree(memb);
341		return error;
342	}
343
 
 
 
344	add_ordered_member(ls, memb);
345	ls->ls_num_nodes++;
346	return 0;
347}
348
349static struct dlm_member *find_memb(struct list_head *head, int nodeid)
350{
351	struct dlm_member *memb;
352
353	list_for_each_entry(memb, head, list) {
354		if (memb->nodeid == nodeid)
355			return memb;
356	}
357	return NULL;
358}
359
360int dlm_is_member(struct dlm_ls *ls, int nodeid)
361{
362	if (find_memb(&ls->ls_nodes, nodeid))
363		return 1;
364	return 0;
365}
366
367int dlm_is_removed(struct dlm_ls *ls, int nodeid)
368{
369	WARN_ON_ONCE(!nodeid || nodeid == -1);
370
371	if (find_memb(&ls->ls_nodes_gone, nodeid))
372		return 1;
373	return 0;
374}
375
376static void clear_memb_list(struct list_head *head,
377			    void (*after_del)(int nodeid))
378{
379	struct dlm_member *memb;
380
381	while (!list_empty(head)) {
382		memb = list_entry(head->next, struct dlm_member, list);
383		list_del(&memb->list);
384		if (after_del)
385			after_del(memb->nodeid);
386		kfree(memb);
387	}
388}
389
390static void remove_remote_member(int nodeid)
391{
392	if (nodeid == dlm_our_nodeid())
393		return;
394
395	dlm_midcomms_remove_member(nodeid);
396}
397
398void dlm_clear_members(struct dlm_ls *ls)
399{
400	clear_memb_list(&ls->ls_nodes, remove_remote_member);
401	ls->ls_num_nodes = 0;
402}
403
404void dlm_clear_members_gone(struct dlm_ls *ls)
405{
406	clear_memb_list(&ls->ls_nodes_gone, NULL);
407}
408
409static void make_member_array(struct dlm_ls *ls)
410{
411	struct dlm_member *memb;
412	int i, w, x = 0, total = 0, all_zero = 0, *array;
413
414	kfree(ls->ls_node_array);
415	ls->ls_node_array = NULL;
416
417	list_for_each_entry(memb, &ls->ls_nodes, list) {
418		if (memb->weight)
419			total += memb->weight;
420	}
421
422	/* all nodes revert to weight of 1 if all have weight 0 */
423
424	if (!total) {
425		total = ls->ls_num_nodes;
426		all_zero = 1;
427	}
428
429	ls->ls_total_weight = total;
430	array = kmalloc_array(total, sizeof(*array), GFP_NOFS);
 
431	if (!array)
432		return;
433
434	list_for_each_entry(memb, &ls->ls_nodes, list) {
435		if (!all_zero && !memb->weight)
436			continue;
437
438		if (all_zero)
439			w = 1;
440		else
441			w = memb->weight;
442
443		DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););
444
445		for (i = 0; i < w; i++)
446			array[x++] = memb->nodeid;
447	}
448
449	ls->ls_node_array = array;
450}
451
452/* send a status request to all members just to establish comms connections */
453
454static int ping_members(struct dlm_ls *ls, uint64_t seq)
455{
456	struct dlm_member *memb;
457	int error = 0;
458
459	list_for_each_entry(memb, &ls->ls_nodes, list) {
460		if (dlm_recovery_stopped(ls)) {
461			error = -EINTR;
462			break;
463		}
464		error = dlm_rcom_status(ls, memb->nodeid, 0, seq);
465		if (error)
466			break;
467	}
468	if (error)
469		log_rinfo(ls, "ping_members aborted %d last nodeid %d",
470			  error, ls->ls_recover_nodeid);
471	return error;
472}
473
474static void dlm_lsop_recover_prep(struct dlm_ls *ls)
475{
476	if (!ls->ls_ops || !ls->ls_ops->recover_prep)
477		return;
478	ls->ls_ops->recover_prep(ls->ls_ops_arg);
479}
480
481static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb)
482{
483	struct dlm_slot slot;
484	uint32_t seq;
485	int error;
486
487	if (!ls->ls_ops || !ls->ls_ops->recover_slot)
488		return;
489
490	/* if there is no comms connection with this node
491	   or the present comms connection is newer
492	   than the one when this member was added, then
493	   we consider the node to have failed (versus
494	   being removed due to dlm_release_lockspace) */
495
496	error = dlm_comm_seq(memb->nodeid, &seq, false);
497
498	if (!error && seq == memb->comm_seq)
499		return;
500
501	slot.nodeid = memb->nodeid;
502	slot.slot = memb->slot;
503
504	ls->ls_ops->recover_slot(ls->ls_ops_arg, &slot);
505}
506
507void dlm_lsop_recover_done(struct dlm_ls *ls)
508{
509	struct dlm_member *memb;
510	struct dlm_slot *slots;
511	int i, num;
512
513	if (!ls->ls_ops || !ls->ls_ops->recover_done)
514		return;
515
516	num = ls->ls_num_nodes;
517	slots = kcalloc(num, sizeof(*slots), GFP_KERNEL);
 
518	if (!slots)
519		return;
520
521	i = 0;
522	list_for_each_entry(memb, &ls->ls_nodes, list) {
523		if (i == num) {
524			log_error(ls, "dlm_lsop_recover_done bad num %d", num);
525			goto out;
526		}
527		slots[i].nodeid = memb->nodeid;
528		slots[i].slot = memb->slot;
529		i++;
530	}
531
532	ls->ls_ops->recover_done(ls->ls_ops_arg, slots, num,
533				 ls->ls_slot, ls->ls_generation);
534 out:
535	kfree(slots);
536}
537
538static struct dlm_config_node *find_config_node(struct dlm_recover *rv,
539						int nodeid)
540{
541	int i;
542
543	for (i = 0; i < rv->nodes_count; i++) {
544		if (rv->nodes[i].nodeid == nodeid)
545			return &rv->nodes[i];
546	}
547	return NULL;
548}
549
550int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
551{
552	struct dlm_member *memb, *safe;
553	struct dlm_config_node *node;
554	int i, error, neg = 0, low = -1;
555
556	/* previously removed members that we've not finished removing need to
557	 * count as a negative change so the "neg" recovery steps will happen
558	 *
559	 * This functionality must report all member changes to lsops or
560	 * midcomms layer and must never return before.
561	 */
562
563	list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
564		log_rinfo(ls, "prev removed member %d", memb->nodeid);
565		neg++;
566	}
567
568	/* move departed members from ls_nodes to ls_nodes_gone */
569
570	list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
571		node = find_config_node(rv, memb->nodeid);
572		if (node && !node->new)
573			continue;
574
575		if (!node) {
576			log_rinfo(ls, "remove member %d", memb->nodeid);
577		} else {
578			/* removed and re-added */
579			log_rinfo(ls, "remove member %d comm_seq %u %u",
580				  memb->nodeid, memb->comm_seq, node->comm_seq);
581		}
582
583		neg++;
584		list_move(&memb->list, &ls->ls_nodes_gone);
585		remove_remote_member(memb->nodeid);
586		ls->ls_num_nodes--;
587		dlm_lsop_recover_slot(ls, memb);
588	}
589
590	/* add new members to ls_nodes */
591
592	for (i = 0; i < rv->nodes_count; i++) {
593		node = &rv->nodes[i];
594		if (dlm_is_member(ls, node->nodeid))
595			continue;
596		error = dlm_add_member(ls, node);
597		if (error)
598			return error;
599
600		log_rinfo(ls, "add member %d", node->nodeid);
601	}
602
603	list_for_each_entry(memb, &ls->ls_nodes, list) {
604		if (low == -1 || memb->nodeid < low)
605			low = memb->nodeid;
606	}
607	ls->ls_low_nodeid = low;
608
609	make_member_array(ls);
610	*neg_out = neg;
611
612	error = ping_members(ls, rv->seq);
 
 
 
 
 
 
 
613	log_rinfo(ls, "dlm_recover_members %d nodes", ls->ls_num_nodes);
614	return error;
615}
616
617/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before
618   dlm_ls_start() is called on any of them to start the new recovery. */
619
620int dlm_ls_stop(struct dlm_ls *ls)
621{
622	int new;
623
624	/*
625	 * Prevent dlm_recv from being in the middle of something when we do
626	 * the stop.  This includes ensuring dlm_recv isn't processing a
627	 * recovery message (rcom), while dlm_recoverd is aborting and
628	 * resetting things from an in-progress recovery.  i.e. we want
629	 * dlm_recoverd to abort its recovery without worrying about dlm_recv
630	 * processing an rcom at the same time.  Stopping dlm_recv also makes
631	 * it easy for dlm_receive_message() to check locking stopped and add a
632	 * message to the requestqueue without races.
633	 */
634
635	write_lock_bh(&ls->ls_recv_active);
636
637	/*
638	 * Abort any recovery that's in progress (see RECOVER_STOP,
639	 * dlm_recovery_stopped()) and tell any other threads running in the
640	 * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
641	 */
642
643	spin_lock_bh(&ls->ls_recover_lock);
644	set_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
645	new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
646	if (new)
647		timer_delete_sync(&ls->ls_scan_timer);
648	ls->ls_recover_seq++;
649
650	/* activate requestqueue and stop processing */
651	write_lock_bh(&ls->ls_requestqueue_lock);
652	set_bit(LSFL_RECV_MSG_BLOCKED, &ls->ls_flags);
653	write_unlock_bh(&ls->ls_requestqueue_lock);
654	spin_unlock_bh(&ls->ls_recover_lock);
655
656	/*
657	 * Let dlm_recv run again, now any normal messages will be saved on the
658	 * requestqueue for later.
659	 */
660
661	write_unlock_bh(&ls->ls_recv_active);
662
663	/*
664	 * This in_recovery lock does two things:
665	 * 1) Keeps this function from returning until all threads are out
666	 *    of locking routines and locking is truly stopped.
667	 * 2) Keeps any new requests from being processed until it's unlocked
668	 *    when recovery is complete.
669	 */
670
671	if (new) {
672		set_bit(LSFL_RECOVER_DOWN, &ls->ls_flags);
673		wake_up_process(ls->ls_recoverd_task);
674		wait_event(ls->ls_recover_lock_wait,
675			   test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
676	}
677
678	/*
679	 * The recoverd suspend/resume makes sure that dlm_recoverd (if
680	 * running) has noticed RECOVER_STOP above and quit processing the
681	 * previous recovery.
682	 */
683
684	dlm_recoverd_suspend(ls);
685
686	spin_lock_bh(&ls->ls_recover_lock);
687	kfree(ls->ls_slots);
688	ls->ls_slots = NULL;
689	ls->ls_num_slots = 0;
690	ls->ls_slots_size = 0;
691	ls->ls_recover_status = 0;
692	spin_unlock_bh(&ls->ls_recover_lock);
693
694	dlm_recoverd_resume(ls);
695
696	if (!ls->ls_recover_begin)
697		ls->ls_recover_begin = jiffies;
698
699	/* call recover_prep ops only once and not multiple times
700	 * for each possible dlm_ls_stop() when recovery is already
701	 * stopped.
702	 *
703	 * If we successful was able to clear LSFL_RUNNING bit and
704	 * it was set we know it is the first dlm_ls_stop() call.
705	 */
706	if (new)
707		dlm_lsop_recover_prep(ls);
708
709	return 0;
710}
711
712int dlm_ls_start(struct dlm_ls *ls)
713{
714	struct dlm_recover *rv, *rv_old;
715	struct dlm_config_node *nodes = NULL;
716	int error, count;
717
718	rv = kzalloc(sizeof(*rv), GFP_NOFS);
719	if (!rv)
720		return -ENOMEM;
721
722	error = dlm_config_nodes(ls->ls_name, &nodes, &count);
723	if (error < 0)
724		goto fail_rv;
725
726	spin_lock_bh(&ls->ls_recover_lock);
727
728	/* the lockspace needs to be stopped before it can be started */
729
730	if (!dlm_locking_stopped(ls)) {
731		spin_unlock_bh(&ls->ls_recover_lock);
732		log_error(ls, "start ignored: lockspace running");
733		error = -EINVAL;
734		goto fail;
735	}
736
737	rv->nodes = nodes;
738	rv->nodes_count = count;
739	rv->seq = ++ls->ls_recover_seq;
740	rv_old = ls->ls_recover_args;
741	ls->ls_recover_args = rv;
742	spin_unlock_bh(&ls->ls_recover_lock);
743
744	if (rv_old) {
745		log_error(ls, "unused recovery %llx %d",
746			  (unsigned long long)rv_old->seq, rv_old->nodes_count);
747		kfree(rv_old->nodes);
748		kfree(rv_old);
749	}
750
751	set_bit(LSFL_RECOVER_WORK, &ls->ls_flags);
752	wake_up_process(ls->ls_recoverd_task);
753	return 0;
754
755 fail:
 
756	kfree(nodes);
757 fail_rv:
758	kfree(rv);
759	return error;
760}
761