18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci******************************************************************************* 48c2ecf20Sopenharmony_ci** 58c2ecf20Sopenharmony_ci** Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci** 78c2ecf20Sopenharmony_ci** 88c2ecf20Sopenharmony_ci******************************************************************************* 98c2ecf20Sopenharmony_ci******************************************************************************/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "dlm_internal.h" 128c2ecf20Sopenharmony_ci#include "lockspace.h" 138c2ecf20Sopenharmony_ci#include "member.h" 148c2ecf20Sopenharmony_ci#include "recoverd.h" 158c2ecf20Sopenharmony_ci#include "recover.h" 168c2ecf20Sopenharmony_ci#include "rcom.h" 178c2ecf20Sopenharmony_ci#include "config.h" 188c2ecf20Sopenharmony_ci#include "lowcomms.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciint dlm_slots_version(struct dlm_header *h) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci if ((h->h_version & 0x0000FFFF) < DLM_HEADER_SLOTS) 238c2ecf20Sopenharmony_ci return 0; 248c2ecf20Sopenharmony_ci return 1; 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_civoid dlm_slot_save(struct dlm_ls *ls, struct dlm_rcom *rc, 288c2ecf20Sopenharmony_ci struct dlm_member *memb) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct rcom_config *rf = (struct rcom_config *)rc->rc_buf; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (!dlm_slots_version(&rc->rc_header)) 338c2ecf20Sopenharmony_ci return; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci memb->slot = le16_to_cpu(rf->rf_our_slot); 368c2ecf20Sopenharmony_ci memb->generation = le32_to_cpu(rf->rf_generation); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid dlm_slots_copy_out(struct dlm_ls *ls, struct dlm_rcom *rc) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct dlm_slot *slot; 428c2ecf20Sopenharmony_ci struct rcom_slot *ro; 438c2ecf20Sopenharmony_ci int i; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci ro = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* ls_slots array is sparse, but not rcom_slots */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci for (i = 0; i < ls->ls_slots_size; i++) { 508c2ecf20Sopenharmony_ci slot = &ls->ls_slots[i]; 518c2ecf20Sopenharmony_ci if (!slot->nodeid) 528c2ecf20Sopenharmony_ci continue; 538c2ecf20Sopenharmony_ci ro->ro_nodeid = cpu_to_le32(slot->nodeid); 548c2ecf20Sopenharmony_ci ro->ro_slot = cpu_to_le16(slot->slot); 558c2ecf20Sopenharmony_ci ro++; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define SLOT_DEBUG_LINE 128 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void log_slots(struct dlm_ls *ls, uint32_t gen, int num_slots, 628c2ecf20Sopenharmony_ci struct rcom_slot *ro0, struct dlm_slot *array, 638c2ecf20Sopenharmony_ci int array_size) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci char line[SLOT_DEBUG_LINE]; 668c2ecf20Sopenharmony_ci int len = SLOT_DEBUG_LINE - 1; 678c2ecf20Sopenharmony_ci int pos = 0; 688c2ecf20Sopenharmony_ci int ret, i; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci memset(line, 0, sizeof(line)); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (array) { 738c2ecf20Sopenharmony_ci for (i = 0; i < array_size; i++) { 748c2ecf20Sopenharmony_ci if (!array[i].nodeid) 758c2ecf20Sopenharmony_ci continue; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = snprintf(line + pos, len - pos, " %d:%d", 788c2ecf20Sopenharmony_ci array[i].slot, array[i].nodeid); 798c2ecf20Sopenharmony_ci if (ret >= len - pos) 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci pos += ret; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } else if (ro0) { 848c2ecf20Sopenharmony_ci for (i = 0; i < num_slots; i++) { 858c2ecf20Sopenharmony_ci ret = snprintf(line + pos, len - pos, " %d:%d", 868c2ecf20Sopenharmony_ci ro0[i].ro_slot, ro0[i].ro_nodeid); 878c2ecf20Sopenharmony_ci if (ret >= len - pos) 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci pos += ret; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci log_rinfo(ls, "generation %u slots %d%s", gen, num_slots, line); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint dlm_slots_copy_in(struct dlm_ls *ls) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct dlm_member *memb; 998c2ecf20Sopenharmony_ci struct dlm_rcom *rc = ls->ls_recover_buf; 1008c2ecf20Sopenharmony_ci struct rcom_config *rf = (struct rcom_config *)rc->rc_buf; 1018c2ecf20Sopenharmony_ci struct rcom_slot *ro0, *ro; 1028c2ecf20Sopenharmony_ci int our_nodeid = dlm_our_nodeid(); 1038c2ecf20Sopenharmony_ci int i, num_slots; 1048c2ecf20Sopenharmony_ci uint32_t gen; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (!dlm_slots_version(&rc->rc_header)) 1078c2ecf20Sopenharmony_ci return -1; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci gen = le32_to_cpu(rf->rf_generation); 1108c2ecf20Sopenharmony_ci if (gen <= ls->ls_generation) { 1118c2ecf20Sopenharmony_ci log_error(ls, "dlm_slots_copy_in gen %u old %u", 1128c2ecf20Sopenharmony_ci gen, ls->ls_generation); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci ls->ls_generation = gen; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci num_slots = le16_to_cpu(rf->rf_num_slots); 1178c2ecf20Sopenharmony_ci if (!num_slots) 1188c2ecf20Sopenharmony_ci return -1; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ro0 = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config)); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci for (i = 0, ro = ro0; i < num_slots; i++, ro++) { 1238c2ecf20Sopenharmony_ci ro->ro_nodeid = le32_to_cpu(ro->ro_nodeid); 1248c2ecf20Sopenharmony_ci ro->ro_slot = le16_to_cpu(ro->ro_slot); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci log_slots(ls, gen, num_slots, ro0, NULL, 0); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 1308c2ecf20Sopenharmony_ci for (i = 0, ro = ro0; i < num_slots; i++, ro++) { 1318c2ecf20Sopenharmony_ci if (ro->ro_nodeid != memb->nodeid) 1328c2ecf20Sopenharmony_ci continue; 1338c2ecf20Sopenharmony_ci memb->slot = ro->ro_slot; 1348c2ecf20Sopenharmony_ci memb->slot_prev = memb->slot; 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (memb->nodeid == our_nodeid) { 1398c2ecf20Sopenharmony_ci if (ls->ls_slot && ls->ls_slot != memb->slot) { 1408c2ecf20Sopenharmony_ci log_error(ls, "dlm_slots_copy_in our slot " 1418c2ecf20Sopenharmony_ci "changed %d %d", ls->ls_slot, 1428c2ecf20Sopenharmony_ci memb->slot); 1438c2ecf20Sopenharmony_ci return -1; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!ls->ls_slot) 1478c2ecf20Sopenharmony_ci ls->ls_slot = memb->slot; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (!memb->slot) { 1518c2ecf20Sopenharmony_ci log_error(ls, "dlm_slots_copy_in nodeid %d no slot", 1528c2ecf20Sopenharmony_ci memb->nodeid); 1538c2ecf20Sopenharmony_ci return -1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* for any nodes that do not support slots, we will not have set memb->slot 1618c2ecf20Sopenharmony_ci in wait_status_all(), so memb->slot will remain -1, and we will not 1628c2ecf20Sopenharmony_ci assign slots or set ls_num_slots here */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ciint dlm_slots_assign(struct dlm_ls *ls, int *num_slots, int *slots_size, 1658c2ecf20Sopenharmony_ci struct dlm_slot **slots_out, uint32_t *gen_out) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct dlm_member *memb; 1688c2ecf20Sopenharmony_ci struct dlm_slot *array; 1698c2ecf20Sopenharmony_ci int our_nodeid = dlm_our_nodeid(); 1708c2ecf20Sopenharmony_ci int array_size, max_slots, i; 1718c2ecf20Sopenharmony_ci int need = 0; 1728c2ecf20Sopenharmony_ci int max = 0; 1738c2ecf20Sopenharmony_ci int num = 0; 1748c2ecf20Sopenharmony_ci uint32_t gen = 0; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* our own memb struct will have slot -1 gen 0 */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 1798c2ecf20Sopenharmony_ci if (memb->nodeid == our_nodeid) { 1808c2ecf20Sopenharmony_ci memb->slot = ls->ls_slot; 1818c2ecf20Sopenharmony_ci memb->generation = ls->ls_generation; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 1878c2ecf20Sopenharmony_ci if (memb->generation > gen) 1888c2ecf20Sopenharmony_ci gen = memb->generation; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* node doesn't support slots */ 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (memb->slot == -1) 1938c2ecf20Sopenharmony_ci return -1; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* node needs a slot assigned */ 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!memb->slot) 1988c2ecf20Sopenharmony_ci need++; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* node has a slot assigned */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci num++; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (!max || max < memb->slot) 2058c2ecf20Sopenharmony_ci max = memb->slot; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* sanity check, once slot is assigned it shouldn't change */ 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (memb->slot_prev && memb->slot && memb->slot_prev != memb->slot) { 2108c2ecf20Sopenharmony_ci log_error(ls, "nodeid %d slot changed %d %d", 2118c2ecf20Sopenharmony_ci memb->nodeid, memb->slot_prev, memb->slot); 2128c2ecf20Sopenharmony_ci return -1; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci memb->slot_prev = memb->slot; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci array_size = max + need; 2188c2ecf20Sopenharmony_ci array = kcalloc(array_size, sizeof(*array), GFP_NOFS); 2198c2ecf20Sopenharmony_ci if (!array) 2208c2ecf20Sopenharmony_ci return -ENOMEM; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci num = 0; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* fill in slots (offsets) that are used */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 2278c2ecf20Sopenharmony_ci if (!memb->slot) 2288c2ecf20Sopenharmony_ci continue; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (memb->slot > array_size) { 2318c2ecf20Sopenharmony_ci log_error(ls, "invalid slot number %d", memb->slot); 2328c2ecf20Sopenharmony_ci kfree(array); 2338c2ecf20Sopenharmony_ci return -1; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci array[memb->slot - 1].nodeid = memb->nodeid; 2378c2ecf20Sopenharmony_ci array[memb->slot - 1].slot = memb->slot; 2388c2ecf20Sopenharmony_ci num++; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* assign new slots from unused offsets */ 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 2448c2ecf20Sopenharmony_ci if (memb->slot) 2458c2ecf20Sopenharmony_ci continue; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci for (i = 0; i < array_size; i++) { 2488c2ecf20Sopenharmony_ci if (array[i].nodeid) 2498c2ecf20Sopenharmony_ci continue; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci memb->slot = i + 1; 2528c2ecf20Sopenharmony_ci memb->slot_prev = memb->slot; 2538c2ecf20Sopenharmony_ci array[i].nodeid = memb->nodeid; 2548c2ecf20Sopenharmony_ci array[i].slot = memb->slot; 2558c2ecf20Sopenharmony_ci num++; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (!ls->ls_slot && memb->nodeid == our_nodeid) 2588c2ecf20Sopenharmony_ci ls->ls_slot = memb->slot; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!memb->slot) { 2638c2ecf20Sopenharmony_ci log_error(ls, "no free slot found"); 2648c2ecf20Sopenharmony_ci kfree(array); 2658c2ecf20Sopenharmony_ci return -1; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci gen++; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci log_slots(ls, gen, num, NULL, array, array_size); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci max_slots = (dlm_config.ci_buffer_size - sizeof(struct dlm_rcom) - 2748c2ecf20Sopenharmony_ci sizeof(struct rcom_config)) / sizeof(struct rcom_slot); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (num > max_slots) { 2778c2ecf20Sopenharmony_ci log_error(ls, "num_slots %d exceeds max_slots %d", 2788c2ecf20Sopenharmony_ci num, max_slots); 2798c2ecf20Sopenharmony_ci kfree(array); 2808c2ecf20Sopenharmony_ci return -1; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci *gen_out = gen; 2848c2ecf20Sopenharmony_ci *slots_out = array; 2858c2ecf20Sopenharmony_ci *slots_size = array_size; 2868c2ecf20Sopenharmony_ci *num_slots = num; 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct dlm_member *memb = NULL; 2938c2ecf20Sopenharmony_ci struct list_head *tmp; 2948c2ecf20Sopenharmony_ci struct list_head *newlist = &new->list; 2958c2ecf20Sopenharmony_ci struct list_head *head = &ls->ls_nodes; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci list_for_each(tmp, head) { 2988c2ecf20Sopenharmony_ci memb = list_entry(tmp, struct dlm_member, list); 2998c2ecf20Sopenharmony_ci if (new->nodeid < memb->nodeid) 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!memb) 3048c2ecf20Sopenharmony_ci list_add_tail(newlist, head); 3058c2ecf20Sopenharmony_ci else { 3068c2ecf20Sopenharmony_ci /* FIXME: can use list macro here */ 3078c2ecf20Sopenharmony_ci newlist->prev = tmp->prev; 3088c2ecf20Sopenharmony_ci newlist->next = tmp; 3098c2ecf20Sopenharmony_ci tmp->prev->next = newlist; 3108c2ecf20Sopenharmony_ci tmp->prev = newlist; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int dlm_add_member(struct dlm_ls *ls, struct dlm_config_node *node) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct dlm_member *memb; 3178c2ecf20Sopenharmony_ci int error; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci memb = kzalloc(sizeof(*memb), GFP_NOFS); 3208c2ecf20Sopenharmony_ci if (!memb) 3218c2ecf20Sopenharmony_ci return -ENOMEM; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci error = dlm_lowcomms_connect_node(node->nodeid); 3248c2ecf20Sopenharmony_ci if (error < 0) { 3258c2ecf20Sopenharmony_ci kfree(memb); 3268c2ecf20Sopenharmony_ci return error; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci memb->nodeid = node->nodeid; 3308c2ecf20Sopenharmony_ci memb->weight = node->weight; 3318c2ecf20Sopenharmony_ci memb->comm_seq = node->comm_seq; 3328c2ecf20Sopenharmony_ci add_ordered_member(ls, memb); 3338c2ecf20Sopenharmony_ci ls->ls_num_nodes++; 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic struct dlm_member *find_memb(struct list_head *head, int nodeid) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct dlm_member *memb; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci list_for_each_entry(memb, head, list) { 3428c2ecf20Sopenharmony_ci if (memb->nodeid == nodeid) 3438c2ecf20Sopenharmony_ci return memb; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci return NULL; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint dlm_is_member(struct dlm_ls *ls, int nodeid) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci if (find_memb(&ls->ls_nodes, nodeid)) 3518c2ecf20Sopenharmony_ci return 1; 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciint dlm_is_removed(struct dlm_ls *ls, int nodeid) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci if (find_memb(&ls->ls_nodes_gone, nodeid)) 3588c2ecf20Sopenharmony_ci return 1; 3598c2ecf20Sopenharmony_ci return 0; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic void clear_memb_list(struct list_head *head) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct dlm_member *memb; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci while (!list_empty(head)) { 3678c2ecf20Sopenharmony_ci memb = list_entry(head->next, struct dlm_member, list); 3688c2ecf20Sopenharmony_ci list_del(&memb->list); 3698c2ecf20Sopenharmony_ci kfree(memb); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_civoid dlm_clear_members(struct dlm_ls *ls) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci clear_memb_list(&ls->ls_nodes); 3768c2ecf20Sopenharmony_ci ls->ls_num_nodes = 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_civoid dlm_clear_members_gone(struct dlm_ls *ls) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci clear_memb_list(&ls->ls_nodes_gone); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void make_member_array(struct dlm_ls *ls) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct dlm_member *memb; 3878c2ecf20Sopenharmony_ci int i, w, x = 0, total = 0, all_zero = 0, *array; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci kfree(ls->ls_node_array); 3908c2ecf20Sopenharmony_ci ls->ls_node_array = NULL; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 3938c2ecf20Sopenharmony_ci if (memb->weight) 3948c2ecf20Sopenharmony_ci total += memb->weight; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* all nodes revert to weight of 1 if all have weight 0 */ 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (!total) { 4008c2ecf20Sopenharmony_ci total = ls->ls_num_nodes; 4018c2ecf20Sopenharmony_ci all_zero = 1; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ls->ls_total_weight = total; 4058c2ecf20Sopenharmony_ci array = kmalloc_array(total, sizeof(*array), GFP_NOFS); 4068c2ecf20Sopenharmony_ci if (!array) 4078c2ecf20Sopenharmony_ci return; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 4108c2ecf20Sopenharmony_ci if (!all_zero && !memb->weight) 4118c2ecf20Sopenharmony_ci continue; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (all_zero) 4148c2ecf20Sopenharmony_ci w = 1; 4158c2ecf20Sopenharmony_ci else 4168c2ecf20Sopenharmony_ci w = memb->weight; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci DLM_ASSERT(x < total, printk("total %d x %d\n", total, x);); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci for (i = 0; i < w; i++) 4218c2ecf20Sopenharmony_ci array[x++] = memb->nodeid; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ls->ls_node_array = array; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* send a status request to all members just to establish comms connections */ 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int ping_members(struct dlm_ls *ls) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct dlm_member *memb; 4328c2ecf20Sopenharmony_ci int error = 0; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 4358c2ecf20Sopenharmony_ci error = dlm_recovery_stopped(ls); 4368c2ecf20Sopenharmony_ci if (error) 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci error = dlm_rcom_status(ls, memb->nodeid, 0); 4398c2ecf20Sopenharmony_ci if (error) 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci if (error) 4438c2ecf20Sopenharmony_ci log_rinfo(ls, "ping_members aborted %d last nodeid %d", 4448c2ecf20Sopenharmony_ci error, ls->ls_recover_nodeid); 4458c2ecf20Sopenharmony_ci return error; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void dlm_lsop_recover_prep(struct dlm_ls *ls) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci if (!ls->ls_ops || !ls->ls_ops->recover_prep) 4518c2ecf20Sopenharmony_ci return; 4528c2ecf20Sopenharmony_ci ls->ls_ops->recover_prep(ls->ls_ops_arg); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct dlm_slot slot; 4588c2ecf20Sopenharmony_ci uint32_t seq; 4598c2ecf20Sopenharmony_ci int error; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!ls->ls_ops || !ls->ls_ops->recover_slot) 4628c2ecf20Sopenharmony_ci return; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* if there is no comms connection with this node 4658c2ecf20Sopenharmony_ci or the present comms connection is newer 4668c2ecf20Sopenharmony_ci than the one when this member was added, then 4678c2ecf20Sopenharmony_ci we consider the node to have failed (versus 4688c2ecf20Sopenharmony_ci being removed due to dlm_release_lockspace) */ 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci error = dlm_comm_seq(memb->nodeid, &seq); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (!error && seq == memb->comm_seq) 4738c2ecf20Sopenharmony_ci return; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci slot.nodeid = memb->nodeid; 4768c2ecf20Sopenharmony_ci slot.slot = memb->slot; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ls->ls_ops->recover_slot(ls->ls_ops_arg, &slot); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_civoid dlm_lsop_recover_done(struct dlm_ls *ls) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct dlm_member *memb; 4848c2ecf20Sopenharmony_ci struct dlm_slot *slots; 4858c2ecf20Sopenharmony_ci int i, num; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (!ls->ls_ops || !ls->ls_ops->recover_done) 4888c2ecf20Sopenharmony_ci return; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci num = ls->ls_num_nodes; 4918c2ecf20Sopenharmony_ci slots = kcalloc(num, sizeof(*slots), GFP_KERNEL); 4928c2ecf20Sopenharmony_ci if (!slots) 4938c2ecf20Sopenharmony_ci return; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci i = 0; 4968c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 4978c2ecf20Sopenharmony_ci if (i == num) { 4988c2ecf20Sopenharmony_ci log_error(ls, "dlm_lsop_recover_done bad num %d", num); 4998c2ecf20Sopenharmony_ci goto out; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci slots[i].nodeid = memb->nodeid; 5028c2ecf20Sopenharmony_ci slots[i].slot = memb->slot; 5038c2ecf20Sopenharmony_ci i++; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci ls->ls_ops->recover_done(ls->ls_ops_arg, slots, num, 5078c2ecf20Sopenharmony_ci ls->ls_slot, ls->ls_generation); 5088c2ecf20Sopenharmony_ci out: 5098c2ecf20Sopenharmony_ci kfree(slots); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic struct dlm_config_node *find_config_node(struct dlm_recover *rv, 5138c2ecf20Sopenharmony_ci int nodeid) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci int i; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci for (i = 0; i < rv->nodes_count; i++) { 5188c2ecf20Sopenharmony_ci if (rv->nodes[i].nodeid == nodeid) 5198c2ecf20Sopenharmony_ci return &rv->nodes[i]; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci return NULL; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciint dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct dlm_member *memb, *safe; 5278c2ecf20Sopenharmony_ci struct dlm_config_node *node; 5288c2ecf20Sopenharmony_ci int i, error, neg = 0, low = -1; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* previously removed members that we've not finished removing need to 5318c2ecf20Sopenharmony_ci count as a negative change so the "neg" recovery steps will happen */ 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes_gone, list) { 5348c2ecf20Sopenharmony_ci log_rinfo(ls, "prev removed member %d", memb->nodeid); 5358c2ecf20Sopenharmony_ci neg++; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* move departed members from ls_nodes to ls_nodes_gone */ 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) { 5418c2ecf20Sopenharmony_ci node = find_config_node(rv, memb->nodeid); 5428c2ecf20Sopenharmony_ci if (node && !node->new) 5438c2ecf20Sopenharmony_ci continue; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!node) { 5468c2ecf20Sopenharmony_ci log_rinfo(ls, "remove member %d", memb->nodeid); 5478c2ecf20Sopenharmony_ci } else { 5488c2ecf20Sopenharmony_ci /* removed and re-added */ 5498c2ecf20Sopenharmony_ci log_rinfo(ls, "remove member %d comm_seq %u %u", 5508c2ecf20Sopenharmony_ci memb->nodeid, memb->comm_seq, node->comm_seq); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci neg++; 5548c2ecf20Sopenharmony_ci list_move(&memb->list, &ls->ls_nodes_gone); 5558c2ecf20Sopenharmony_ci ls->ls_num_nodes--; 5568c2ecf20Sopenharmony_ci dlm_lsop_recover_slot(ls, memb); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* add new members to ls_nodes */ 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (i = 0; i < rv->nodes_count; i++) { 5628c2ecf20Sopenharmony_ci node = &rv->nodes[i]; 5638c2ecf20Sopenharmony_ci if (dlm_is_member(ls, node->nodeid)) 5648c2ecf20Sopenharmony_ci continue; 5658c2ecf20Sopenharmony_ci dlm_add_member(ls, node); 5668c2ecf20Sopenharmony_ci log_rinfo(ls, "add member %d", node->nodeid); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci list_for_each_entry(memb, &ls->ls_nodes, list) { 5708c2ecf20Sopenharmony_ci if (low == -1 || memb->nodeid < low) 5718c2ecf20Sopenharmony_ci low = memb->nodeid; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci ls->ls_low_nodeid = low; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci make_member_array(ls); 5768c2ecf20Sopenharmony_ci *neg_out = neg; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci error = ping_members(ls); 5798c2ecf20Sopenharmony_ci if (!error || error == -EPROTO) { 5808c2ecf20Sopenharmony_ci /* new_lockspace() may be waiting to know if the config 5818c2ecf20Sopenharmony_ci is good or bad */ 5828c2ecf20Sopenharmony_ci ls->ls_members_result = error; 5838c2ecf20Sopenharmony_ci complete(&ls->ls_members_done); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci log_rinfo(ls, "dlm_recover_members %d nodes", ls->ls_num_nodes); 5878c2ecf20Sopenharmony_ci return error; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before 5918c2ecf20Sopenharmony_ci dlm_ls_start() is called on any of them to start the new recovery. */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ciint dlm_ls_stop(struct dlm_ls *ls) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci int new; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* 5988c2ecf20Sopenharmony_ci * Prevent dlm_recv from being in the middle of something when we do 5998c2ecf20Sopenharmony_ci * the stop. This includes ensuring dlm_recv isn't processing a 6008c2ecf20Sopenharmony_ci * recovery message (rcom), while dlm_recoverd is aborting and 6018c2ecf20Sopenharmony_ci * resetting things from an in-progress recovery. i.e. we want 6028c2ecf20Sopenharmony_ci * dlm_recoverd to abort its recovery without worrying about dlm_recv 6038c2ecf20Sopenharmony_ci * processing an rcom at the same time. Stopping dlm_recv also makes 6048c2ecf20Sopenharmony_ci * it easy for dlm_receive_message() to check locking stopped and add a 6058c2ecf20Sopenharmony_ci * message to the requestqueue without races. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci down_write(&ls->ls_recv_active); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * Abort any recovery that's in progress (see RECOVER_STOP, 6128c2ecf20Sopenharmony_ci * dlm_recovery_stopped()) and tell any other threads running in the 6138c2ecf20Sopenharmony_ci * dlm to quit any processing (see RUNNING, dlm_locking_stopped()). 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci spin_lock(&ls->ls_recover_lock); 6178c2ecf20Sopenharmony_ci set_bit(LSFL_RECOVER_STOP, &ls->ls_flags); 6188c2ecf20Sopenharmony_ci new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags); 6198c2ecf20Sopenharmony_ci ls->ls_recover_seq++; 6208c2ecf20Sopenharmony_ci spin_unlock(&ls->ls_recover_lock); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* 6238c2ecf20Sopenharmony_ci * Let dlm_recv run again, now any normal messages will be saved on the 6248c2ecf20Sopenharmony_ci * requestqueue for later. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci up_write(&ls->ls_recv_active); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * This in_recovery lock does two things: 6318c2ecf20Sopenharmony_ci * 1) Keeps this function from returning until all threads are out 6328c2ecf20Sopenharmony_ci * of locking routines and locking is truly stopped. 6338c2ecf20Sopenharmony_ci * 2) Keeps any new requests from being processed until it's unlocked 6348c2ecf20Sopenharmony_ci * when recovery is complete. 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (new) { 6388c2ecf20Sopenharmony_ci set_bit(LSFL_RECOVER_DOWN, &ls->ls_flags); 6398c2ecf20Sopenharmony_ci wake_up_process(ls->ls_recoverd_task); 6408c2ecf20Sopenharmony_ci wait_event(ls->ls_recover_lock_wait, 6418c2ecf20Sopenharmony_ci test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags)); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* 6458c2ecf20Sopenharmony_ci * The recoverd suspend/resume makes sure that dlm_recoverd (if 6468c2ecf20Sopenharmony_ci * running) has noticed RECOVER_STOP above and quit processing the 6478c2ecf20Sopenharmony_ci * previous recovery. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci dlm_recoverd_suspend(ls); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci spin_lock(&ls->ls_recover_lock); 6538c2ecf20Sopenharmony_ci kfree(ls->ls_slots); 6548c2ecf20Sopenharmony_ci ls->ls_slots = NULL; 6558c2ecf20Sopenharmony_ci ls->ls_num_slots = 0; 6568c2ecf20Sopenharmony_ci ls->ls_slots_size = 0; 6578c2ecf20Sopenharmony_ci ls->ls_recover_status = 0; 6588c2ecf20Sopenharmony_ci spin_unlock(&ls->ls_recover_lock); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci dlm_recoverd_resume(ls); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (!ls->ls_recover_begin) 6638c2ecf20Sopenharmony_ci ls->ls_recover_begin = jiffies; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci dlm_lsop_recover_prep(ls); 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ciint dlm_ls_start(struct dlm_ls *ls) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct dlm_recover *rv, *rv_old; 6728c2ecf20Sopenharmony_ci struct dlm_config_node *nodes = NULL; 6738c2ecf20Sopenharmony_ci int error, count; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci rv = kzalloc(sizeof(*rv), GFP_NOFS); 6768c2ecf20Sopenharmony_ci if (!rv) 6778c2ecf20Sopenharmony_ci return -ENOMEM; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci error = dlm_config_nodes(ls->ls_name, &nodes, &count); 6808c2ecf20Sopenharmony_ci if (error < 0) 6818c2ecf20Sopenharmony_ci goto fail_rv; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci spin_lock(&ls->ls_recover_lock); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* the lockspace needs to be stopped before it can be started */ 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (!dlm_locking_stopped(ls)) { 6888c2ecf20Sopenharmony_ci spin_unlock(&ls->ls_recover_lock); 6898c2ecf20Sopenharmony_ci log_error(ls, "start ignored: lockspace running"); 6908c2ecf20Sopenharmony_ci error = -EINVAL; 6918c2ecf20Sopenharmony_ci goto fail; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci rv->nodes = nodes; 6958c2ecf20Sopenharmony_ci rv->nodes_count = count; 6968c2ecf20Sopenharmony_ci rv->seq = ++ls->ls_recover_seq; 6978c2ecf20Sopenharmony_ci rv_old = ls->ls_recover_args; 6988c2ecf20Sopenharmony_ci ls->ls_recover_args = rv; 6998c2ecf20Sopenharmony_ci spin_unlock(&ls->ls_recover_lock); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (rv_old) { 7028c2ecf20Sopenharmony_ci log_error(ls, "unused recovery %llx %d", 7038c2ecf20Sopenharmony_ci (unsigned long long)rv_old->seq, rv_old->nodes_count); 7048c2ecf20Sopenharmony_ci kfree(rv_old->nodes); 7058c2ecf20Sopenharmony_ci kfree(rv_old); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci set_bit(LSFL_RECOVER_WORK, &ls->ls_flags); 7098c2ecf20Sopenharmony_ci wake_up_process(ls->ls_recoverd_task); 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci fail: 7138c2ecf20Sopenharmony_ci kfree(nodes); 7148c2ecf20Sopenharmony_ci fail_rv: 7158c2ecf20Sopenharmony_ci kfree(rv); 7168c2ecf20Sopenharmony_ci return error; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 719