12522fe45SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2e7fd4179SDavid Teigland /****************************************************************************** 3e7fd4179SDavid Teigland ******************************************************************************* 4e7fd4179SDavid Teigland ** 5e7fd4179SDavid Teigland ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 6dbcfc347SDavid Teigland ** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. 7e7fd4179SDavid Teigland ** 8e7fd4179SDavid Teigland ** 9e7fd4179SDavid Teigland ******************************************************************************* 10e7fd4179SDavid Teigland ******************************************************************************/ 11e7fd4179SDavid Teigland 12e7fd4179SDavid Teigland #include "dlm_internal.h" 13e7fd4179SDavid Teigland #include "lockspace.h" 14e7fd4179SDavid Teigland #include "member.h" 15e7fd4179SDavid Teigland #include "lowcomms.h" 16e7fd4179SDavid Teigland #include "midcomms.h" 17e7fd4179SDavid Teigland #include "rcom.h" 18e7fd4179SDavid Teigland #include "recover.h" 19e7fd4179SDavid Teigland #include "dir.h" 20e7fd4179SDavid Teigland #include "config.h" 21e7fd4179SDavid Teigland #include "memory.h" 22e7fd4179SDavid Teigland #include "lock.h" 23e7fd4179SDavid Teigland #include "util.h" 24e7fd4179SDavid Teigland 25e7fd4179SDavid Teigland static int rcom_response(struct dlm_ls *ls) 26e7fd4179SDavid Teigland { 27e7fd4179SDavid Teigland return test_bit(LSFL_RCOM_READY, &ls->ls_flags); 28e7fd4179SDavid Teigland } 29e7fd4179SDavid Teigland 30*a070a91cSAlexander Aring static void _create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len, 31*a070a91cSAlexander Aring struct dlm_rcom **rc_ret, char *mb, int mb_len) 32e7fd4179SDavid Teigland { 33e7fd4179SDavid Teigland struct dlm_rcom *rc; 34e7fd4179SDavid Teigland 35e7fd4179SDavid Teigland rc = (struct dlm_rcom *) mb; 36e7fd4179SDavid Teigland 37e7fd4179SDavid Teigland rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR); 38e7fd4179SDavid Teigland rc->rc_header.h_lockspace = ls->ls_global_id; 39e7fd4179SDavid Teigland rc->rc_header.h_nodeid = dlm_our_nodeid(); 40e7fd4179SDavid Teigland rc->rc_header.h_length = mb_len; 41e7fd4179SDavid Teigland rc->rc_header.h_cmd = DLM_RCOM; 42e7fd4179SDavid Teigland 43e7fd4179SDavid Teigland rc->rc_type = type; 44e7fd4179SDavid Teigland 4538aa8b0cSDavid Teigland spin_lock(&ls->ls_recover_lock); 4638aa8b0cSDavid Teigland rc->rc_seq = ls->ls_recover_seq; 4738aa8b0cSDavid Teigland spin_unlock(&ls->ls_recover_lock); 4838aa8b0cSDavid Teigland 49e7fd4179SDavid Teigland *rc_ret = rc; 50*a070a91cSAlexander Aring } 51*a070a91cSAlexander Aring 52*a070a91cSAlexander Aring static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len, 53*a070a91cSAlexander Aring struct dlm_rcom **rc_ret, struct dlm_mhandle **mh_ret) 54*a070a91cSAlexander Aring { 55*a070a91cSAlexander Aring int mb_len = sizeof(struct dlm_rcom) + len; 56*a070a91cSAlexander Aring struct dlm_mhandle *mh; 57*a070a91cSAlexander Aring char *mb; 58*a070a91cSAlexander Aring 59*a070a91cSAlexander Aring mh = dlm_midcomms_get_mhandle(to_nodeid, mb_len, GFP_NOFS, &mb); 60*a070a91cSAlexander Aring if (!mh) { 61*a070a91cSAlexander Aring log_print("%s to %d type %d len %d ENOBUFS", 62*a070a91cSAlexander Aring __func__, to_nodeid, type, len); 63*a070a91cSAlexander Aring return -ENOBUFS; 64*a070a91cSAlexander Aring } 65*a070a91cSAlexander Aring 66*a070a91cSAlexander Aring _create_rcom(ls, to_nodeid, type, len, rc_ret, mb, mb_len); 67*a070a91cSAlexander Aring *mh_ret = mh; 68e7fd4179SDavid Teigland return 0; 69e7fd4179SDavid Teigland } 70e7fd4179SDavid Teigland 71*a070a91cSAlexander Aring static int create_rcom_stateless(struct dlm_ls *ls, int to_nodeid, int type, 72*a070a91cSAlexander Aring int len, struct dlm_rcom **rc_ret, 73*a070a91cSAlexander Aring void **mh_ret) 74*a070a91cSAlexander Aring { 75*a070a91cSAlexander Aring int mb_len = sizeof(struct dlm_rcom) + len; 76*a070a91cSAlexander Aring void *mh; 77*a070a91cSAlexander Aring char *mb; 78*a070a91cSAlexander Aring 79*a070a91cSAlexander Aring mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_NOFS, &mb); 80*a070a91cSAlexander Aring if (!mh) { 81*a070a91cSAlexander Aring log_print("create_rcom to %d type %d len %d ENOBUFS", 82*a070a91cSAlexander Aring to_nodeid, type, len); 83*a070a91cSAlexander Aring return -ENOBUFS; 84*a070a91cSAlexander Aring } 85*a070a91cSAlexander Aring 86*a070a91cSAlexander Aring _create_rcom(ls, to_nodeid, type, len, rc_ret, mb, mb_len); 87*a070a91cSAlexander Aring *mh_ret = mh; 88*a070a91cSAlexander Aring return 0; 89*a070a91cSAlexander Aring } 90*a070a91cSAlexander Aring 91*a070a91cSAlexander Aring static void _send_rcom(struct dlm_ls *ls, struct dlm_rcom *rc) 92*a070a91cSAlexander Aring { 93*a070a91cSAlexander Aring dlm_rcom_out(rc); 94*a070a91cSAlexander Aring } 95*a070a91cSAlexander Aring 96e7fd4179SDavid Teigland static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh, 97e7fd4179SDavid Teigland struct dlm_rcom *rc) 98e7fd4179SDavid Teigland { 99*a070a91cSAlexander Aring _send_rcom(ls, rc); 100*a070a91cSAlexander Aring dlm_midcomms_commit_mhandle(mh); 101*a070a91cSAlexander Aring } 102*a070a91cSAlexander Aring 103*a070a91cSAlexander Aring static void send_rcom_stateless(struct dlm_ls *ls, void *mh, 104*a070a91cSAlexander Aring struct dlm_rcom *rc) 105*a070a91cSAlexander Aring { 106*a070a91cSAlexander Aring _send_rcom(ls, rc); 107e7fd4179SDavid Teigland dlm_lowcomms_commit_buffer(mh); 108e7fd4179SDavid Teigland } 109e7fd4179SDavid Teigland 110757a4271SDavid Teigland static void set_rcom_status(struct dlm_ls *ls, struct rcom_status *rs, 111757a4271SDavid Teigland uint32_t flags) 112757a4271SDavid Teigland { 113757a4271SDavid Teigland rs->rs_flags = cpu_to_le32(flags); 114757a4271SDavid Teigland } 115757a4271SDavid Teigland 116e7fd4179SDavid Teigland /* When replying to a status request, a node also sends back its 117e7fd4179SDavid Teigland configuration values. The requesting node then checks that the remote 118e7fd4179SDavid Teigland node is configured the same way as itself. */ 119e7fd4179SDavid Teigland 120757a4271SDavid Teigland static void set_rcom_config(struct dlm_ls *ls, struct rcom_config *rf, 121757a4271SDavid Teigland uint32_t num_slots) 122e7fd4179SDavid Teigland { 12393ff2971SAl Viro rf->rf_lvblen = cpu_to_le32(ls->ls_lvblen); 12493ff2971SAl Viro rf->rf_lsflags = cpu_to_le32(ls->ls_exflags); 125757a4271SDavid Teigland 126757a4271SDavid Teigland rf->rf_our_slot = cpu_to_le16(ls->ls_slot); 127757a4271SDavid Teigland rf->rf_num_slots = cpu_to_le16(num_slots); 128757a4271SDavid Teigland rf->rf_generation = cpu_to_le32(ls->ls_generation); 129e7fd4179SDavid Teigland } 130e7fd4179SDavid Teigland 131757a4271SDavid Teigland static int check_rcom_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) 132e7fd4179SDavid Teigland { 1339e971b71SDavid Teigland struct rcom_config *rf = (struct rcom_config *) rc->rc_buf; 1349e971b71SDavid Teigland 1359e971b71SDavid Teigland if ((rc->rc_header.h_version & 0xFFFF0000) != DLM_HEADER_MAJOR) { 1369e971b71SDavid Teigland log_error(ls, "version mismatch: %x nodeid %d: %x", 1379e971b71SDavid Teigland DLM_HEADER_MAJOR | DLM_HEADER_MINOR, nodeid, 1389e971b71SDavid Teigland rc->rc_header.h_version); 1398b0e7b2cSDavid Teigland return -EPROTO; 1409e971b71SDavid Teigland } 1419e971b71SDavid Teigland 14293ff2971SAl Viro if (le32_to_cpu(rf->rf_lvblen) != ls->ls_lvblen || 14393ff2971SAl Viro le32_to_cpu(rf->rf_lsflags) != ls->ls_exflags) { 144e7fd4179SDavid Teigland log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x", 14593ff2971SAl Viro ls->ls_lvblen, ls->ls_exflags, nodeid, 14693ff2971SAl Viro le32_to_cpu(rf->rf_lvblen), 14793ff2971SAl Viro le32_to_cpu(rf->rf_lsflags)); 1488b0e7b2cSDavid Teigland return -EPROTO; 149e7fd4179SDavid Teigland } 150e7fd4179SDavid Teigland return 0; 151e7fd4179SDavid Teigland } 152e7fd4179SDavid Teigland 15398f176fbSDavid Teigland static void allow_sync_reply(struct dlm_ls *ls, uint64_t *new_seq) 15498f176fbSDavid Teigland { 15598f176fbSDavid Teigland spin_lock(&ls->ls_rcom_spin); 15698f176fbSDavid Teigland *new_seq = ++ls->ls_rcom_seq; 15798f176fbSDavid Teigland set_bit(LSFL_RCOM_WAIT, &ls->ls_flags); 15898f176fbSDavid Teigland spin_unlock(&ls->ls_rcom_spin); 15998f176fbSDavid Teigland } 16098f176fbSDavid Teigland 16198f176fbSDavid Teigland static void disallow_sync_reply(struct dlm_ls *ls) 16298f176fbSDavid Teigland { 16398f176fbSDavid Teigland spin_lock(&ls->ls_rcom_spin); 16498f176fbSDavid Teigland clear_bit(LSFL_RCOM_WAIT, &ls->ls_flags); 16598f176fbSDavid Teigland clear_bit(LSFL_RCOM_READY, &ls->ls_flags); 16698f176fbSDavid Teigland spin_unlock(&ls->ls_rcom_spin); 16798f176fbSDavid Teigland } 16898f176fbSDavid Teigland 169757a4271SDavid Teigland /* 170757a4271SDavid Teigland * low nodeid gathers one slot value at a time from each node. 171757a4271SDavid Teigland * it sets need_slots=0, and saves rf_our_slot returned from each 172757a4271SDavid Teigland * rcom_config. 173757a4271SDavid Teigland * 174757a4271SDavid Teigland * other nodes gather all slot values at once from the low nodeid. 175757a4271SDavid Teigland * they set need_slots=1, and ignore the rf_our_slot returned from each 176757a4271SDavid Teigland * rcom_config. they use the rf_num_slots returned from the low 177757a4271SDavid Teigland * node's rcom_config. 178757a4271SDavid Teigland */ 179757a4271SDavid Teigland 180757a4271SDavid Teigland int dlm_rcom_status(struct dlm_ls *ls, int nodeid, uint32_t status_flags) 181e7fd4179SDavid Teigland { 182e7fd4179SDavid Teigland struct dlm_rcom *rc; 183e7fd4179SDavid Teigland int error = 0; 184*a070a91cSAlexander Aring void *mh; 185e7fd4179SDavid Teigland 186faa0f267SDavid Teigland ls->ls_recover_nodeid = nodeid; 187e7fd4179SDavid Teigland 188e7fd4179SDavid Teigland if (nodeid == dlm_our_nodeid()) { 1894007685cSAl Viro rc = ls->ls_recover_buf; 190e7fd4179SDavid Teigland rc->rc_result = dlm_recover_status(ls); 191e7fd4179SDavid Teigland goto out; 192e7fd4179SDavid Teigland } 193e7fd4179SDavid Teigland 19459661212Stsutomu.owa@toshiba.co.jp retry: 195*a070a91cSAlexander Aring error = create_rcom_stateless(ls, nodeid, DLM_RCOM_STATUS, 196757a4271SDavid Teigland sizeof(struct rcom_status), &rc, &mh); 197e7fd4179SDavid Teigland if (error) 198e7fd4179SDavid Teigland goto out; 19998f176fbSDavid Teigland 200757a4271SDavid Teigland set_rcom_status(ls, (struct rcom_status *)rc->rc_buf, status_flags); 201757a4271SDavid Teigland 20298f176fbSDavid Teigland allow_sync_reply(ls, &rc->rc_id); 2039f8f9c77SAlexander Aring memset(ls->ls_recover_buf, 0, LOWCOMMS_MAX_TX_BUFFER_LEN); 204e7fd4179SDavid Teigland 205*a070a91cSAlexander Aring send_rcom_stateless(ls, mh, rc); 206e7fd4179SDavid Teigland 207e7fd4179SDavid Teigland error = dlm_wait_function(ls, &rcom_response); 20898f176fbSDavid Teigland disallow_sync_reply(ls); 20959661212Stsutomu.owa@toshiba.co.jp if (error == -ETIMEDOUT) 21059661212Stsutomu.owa@toshiba.co.jp goto retry; 211e7fd4179SDavid Teigland if (error) 212e7fd4179SDavid Teigland goto out; 213e7fd4179SDavid Teigland 2144007685cSAl Viro rc = ls->ls_recover_buf; 215e7fd4179SDavid Teigland 216e7fd4179SDavid Teigland if (rc->rc_result == -ESRCH) { 217e7fd4179SDavid Teigland /* we pretend the remote lockspace exists with 0 status */ 218e7fd4179SDavid Teigland log_debug(ls, "remote node %d not ready", nodeid); 219e7fd4179SDavid Teigland rc->rc_result = 0; 220757a4271SDavid Teigland error = 0; 221757a4271SDavid Teigland } else { 222757a4271SDavid Teigland error = check_rcom_config(ls, rc, nodeid); 223757a4271SDavid Teigland } 224757a4271SDavid Teigland 225e7fd4179SDavid Teigland /* the caller looks at rc_result for the remote recovery status */ 226e7fd4179SDavid Teigland out: 227e7fd4179SDavid Teigland return error; 228e7fd4179SDavid Teigland } 229e7fd4179SDavid Teigland 230e7fd4179SDavid Teigland static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in) 231e7fd4179SDavid Teigland { 232e7fd4179SDavid Teigland struct dlm_rcom *rc; 233757a4271SDavid Teigland struct rcom_status *rs; 234757a4271SDavid Teigland uint32_t status; 235757a4271SDavid Teigland int nodeid = rc_in->rc_header.h_nodeid; 236757a4271SDavid Teigland int len = sizeof(struct rcom_config); 237757a4271SDavid Teigland int num_slots = 0; 238757a4271SDavid Teigland int error; 239*a070a91cSAlexander Aring void *mh; 240e7fd4179SDavid Teigland 241757a4271SDavid Teigland if (!dlm_slots_version(&rc_in->rc_header)) { 242757a4271SDavid Teigland status = dlm_recover_status(ls); 243757a4271SDavid Teigland goto do_create; 244757a4271SDavid Teigland } 245757a4271SDavid Teigland 246757a4271SDavid Teigland rs = (struct rcom_status *)rc_in->rc_buf; 247757a4271SDavid Teigland 248c07127b4SNeale Ferguson if (!(le32_to_cpu(rs->rs_flags) & DLM_RSF_NEED_SLOTS)) { 249757a4271SDavid Teigland status = dlm_recover_status(ls); 250757a4271SDavid Teigland goto do_create; 251757a4271SDavid Teigland } 252757a4271SDavid Teigland 253757a4271SDavid Teigland spin_lock(&ls->ls_recover_lock); 254757a4271SDavid Teigland status = ls->ls_recover_status; 255757a4271SDavid Teigland num_slots = ls->ls_num_slots; 256757a4271SDavid Teigland spin_unlock(&ls->ls_recover_lock); 257757a4271SDavid Teigland len += num_slots * sizeof(struct rcom_slot); 258757a4271SDavid Teigland 259757a4271SDavid Teigland do_create: 260*a070a91cSAlexander Aring error = create_rcom_stateless(ls, nodeid, DLM_RCOM_STATUS_REPLY, 261757a4271SDavid Teigland len, &rc, &mh); 262e7fd4179SDavid Teigland if (error) 263e7fd4179SDavid Teigland return; 264757a4271SDavid Teigland 2654a99c3d9SDavid Teigland rc->rc_id = rc_in->rc_id; 26638aa8b0cSDavid Teigland rc->rc_seq_reply = rc_in->rc_seq; 267757a4271SDavid Teigland rc->rc_result = status; 268e7fd4179SDavid Teigland 269757a4271SDavid Teigland set_rcom_config(ls, (struct rcom_config *)rc->rc_buf, num_slots); 270757a4271SDavid Teigland 271757a4271SDavid Teigland if (!num_slots) 272757a4271SDavid Teigland goto do_send; 273757a4271SDavid Teigland 274757a4271SDavid Teigland spin_lock(&ls->ls_recover_lock); 275757a4271SDavid Teigland if (ls->ls_num_slots != num_slots) { 276757a4271SDavid Teigland spin_unlock(&ls->ls_recover_lock); 277757a4271SDavid Teigland log_debug(ls, "receive_rcom_status num_slots %d to %d", 278757a4271SDavid Teigland num_slots, ls->ls_num_slots); 279757a4271SDavid Teigland rc->rc_result = 0; 280757a4271SDavid Teigland set_rcom_config(ls, (struct rcom_config *)rc->rc_buf, 0); 281757a4271SDavid Teigland goto do_send; 282757a4271SDavid Teigland } 283757a4271SDavid Teigland 284757a4271SDavid Teigland dlm_slots_copy_out(ls, rc); 285757a4271SDavid Teigland spin_unlock(&ls->ls_recover_lock); 286757a4271SDavid Teigland 287757a4271SDavid Teigland do_send: 288*a070a91cSAlexander Aring send_rcom_stateless(ls, mh, rc); 289e7fd4179SDavid Teigland } 290e7fd4179SDavid Teigland 2914a99c3d9SDavid Teigland static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) 292e7fd4179SDavid Teigland { 29398f176fbSDavid Teigland spin_lock(&ls->ls_rcom_spin); 29498f176fbSDavid Teigland if (!test_bit(LSFL_RCOM_WAIT, &ls->ls_flags) || 29598f176fbSDavid Teigland rc_in->rc_id != ls->ls_rcom_seq) { 29698f176fbSDavid Teigland log_debug(ls, "reject reply %d from %d seq %llx expect %llx", 29798f176fbSDavid Teigland rc_in->rc_type, rc_in->rc_header.h_nodeid, 29857adf7eeSRyusuke Konishi (unsigned long long)rc_in->rc_id, 29957adf7eeSRyusuke Konishi (unsigned long long)ls->ls_rcom_seq); 30098f176fbSDavid Teigland goto out; 3014a99c3d9SDavid Teigland } 302e7fd4179SDavid Teigland memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length); 303e7fd4179SDavid Teigland set_bit(LSFL_RCOM_READY, &ls->ls_flags); 30498f176fbSDavid Teigland clear_bit(LSFL_RCOM_WAIT, &ls->ls_flags); 305e7fd4179SDavid Teigland wake_up(&ls->ls_wait_general); 30698f176fbSDavid Teigland out: 30798f176fbSDavid Teigland spin_unlock(&ls->ls_rcom_spin); 308e7fd4179SDavid Teigland } 309e7fd4179SDavid Teigland 310e7fd4179SDavid Teigland int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) 311e7fd4179SDavid Teigland { 312e7fd4179SDavid Teigland struct dlm_rcom *rc; 3134007685cSAl Viro int error = 0; 314*a070a91cSAlexander Aring void *mh; 315e7fd4179SDavid Teigland 316faa0f267SDavid Teigland ls->ls_recover_nodeid = nodeid; 317e7fd4179SDavid Teigland 31859661212Stsutomu.owa@toshiba.co.jp retry: 319*a070a91cSAlexander Aring error = create_rcom_stateless(ls, nodeid, DLM_RCOM_NAMES, last_len, 320*a070a91cSAlexander Aring &rc, &mh); 321e7fd4179SDavid Teigland if (error) 322e7fd4179SDavid Teigland goto out; 323e7fd4179SDavid Teigland memcpy(rc->rc_buf, last_name, last_len); 32498f176fbSDavid Teigland 32598f176fbSDavid Teigland allow_sync_reply(ls, &rc->rc_id); 3269f8f9c77SAlexander Aring memset(ls->ls_recover_buf, 0, LOWCOMMS_MAX_TX_BUFFER_LEN); 327e7fd4179SDavid Teigland 328*a070a91cSAlexander Aring send_rcom_stateless(ls, mh, rc); 329e7fd4179SDavid Teigland 330e7fd4179SDavid Teigland error = dlm_wait_function(ls, &rcom_response); 33198f176fbSDavid Teigland disallow_sync_reply(ls); 33259661212Stsutomu.owa@toshiba.co.jp if (error == -ETIMEDOUT) 33359661212Stsutomu.owa@toshiba.co.jp goto retry; 334e7fd4179SDavid Teigland out: 335e7fd4179SDavid Teigland return error; 336e7fd4179SDavid Teigland } 337e7fd4179SDavid Teigland 338e7fd4179SDavid Teigland static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) 339e7fd4179SDavid Teigland { 340e7fd4179SDavid Teigland struct dlm_rcom *rc; 34138aa8b0cSDavid Teigland int error, inlen, outlen, nodeid; 342*a070a91cSAlexander Aring void *mh; 343e7fd4179SDavid Teigland 344e7fd4179SDavid Teigland nodeid = rc_in->rc_header.h_nodeid; 345e7fd4179SDavid Teigland inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom); 3469f8f9c77SAlexander Aring outlen = LOWCOMMS_MAX_TX_BUFFER_LEN - sizeof(struct dlm_rcom); 347e7fd4179SDavid Teigland 348*a070a91cSAlexander Aring error = create_rcom_stateless(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, 349*a070a91cSAlexander Aring &rc, &mh); 350e7fd4179SDavid Teigland if (error) 351e7fd4179SDavid Teigland return; 3524a99c3d9SDavid Teigland rc->rc_id = rc_in->rc_id; 35338aa8b0cSDavid Teigland rc->rc_seq_reply = rc_in->rc_seq; 354e7fd4179SDavid Teigland 355e7fd4179SDavid Teigland dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen, 356e7fd4179SDavid Teigland nodeid); 357*a070a91cSAlexander Aring send_rcom_stateless(ls, mh, rc); 358e7fd4179SDavid Teigland } 359e7fd4179SDavid Teigland 360e7fd4179SDavid Teigland int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid) 361e7fd4179SDavid Teigland { 362e7fd4179SDavid Teigland struct dlm_rcom *rc; 363e7fd4179SDavid Teigland struct dlm_mhandle *mh; 364e7fd4179SDavid Teigland struct dlm_ls *ls = r->res_ls; 365e7fd4179SDavid Teigland int error; 366e7fd4179SDavid Teigland 367e7fd4179SDavid Teigland error = create_rcom(ls, dir_nodeid, DLM_RCOM_LOOKUP, r->res_length, 368e7fd4179SDavid Teigland &rc, &mh); 369e7fd4179SDavid Teigland if (error) 370e7fd4179SDavid Teigland goto out; 371e7fd4179SDavid Teigland memcpy(rc->rc_buf, r->res_name, r->res_length); 3721d7c484eSDavid Teigland rc->rc_id = (unsigned long) r->res_id; 373e7fd4179SDavid Teigland 374e7fd4179SDavid Teigland send_rcom(ls, mh, rc); 375e7fd4179SDavid Teigland out: 376e7fd4179SDavid Teigland return error; 377e7fd4179SDavid Teigland } 378e7fd4179SDavid Teigland 379e7fd4179SDavid Teigland static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in) 380e7fd4179SDavid Teigland { 381e7fd4179SDavid Teigland struct dlm_rcom *rc; 382e7fd4179SDavid Teigland struct dlm_mhandle *mh; 383e7fd4179SDavid Teigland int error, ret_nodeid, nodeid = rc_in->rc_header.h_nodeid; 384e7fd4179SDavid Teigland int len = rc_in->rc_header.h_length - sizeof(struct dlm_rcom); 385e7fd4179SDavid Teigland 386e7fd4179SDavid Teigland error = create_rcom(ls, nodeid, DLM_RCOM_LOOKUP_REPLY, 0, &rc, &mh); 387e7fd4179SDavid Teigland if (error) 388e7fd4179SDavid Teigland return; 389e7fd4179SDavid Teigland 3909250e523SDavid Teigland /* Old code would send this special id to trigger a debug dump. */ 391c04fecb4SDavid Teigland if (rc_in->rc_id == 0xFFFFFFFF) { 392c04fecb4SDavid Teigland log_error(ls, "receive_rcom_lookup dump from %d", nodeid); 393c04fecb4SDavid Teigland dlm_dump_rsb_name(ls, rc_in->rc_buf, len); 394c04fecb4SDavid Teigland return; 395c04fecb4SDavid Teigland } 396c04fecb4SDavid Teigland 397c04fecb4SDavid Teigland error = dlm_master_lookup(ls, nodeid, rc_in->rc_buf, len, 398c04fecb4SDavid Teigland DLM_LU_RECOVER_MASTER, &ret_nodeid, NULL); 399e7fd4179SDavid Teigland if (error) 400e7fd4179SDavid Teigland ret_nodeid = error; 401e7fd4179SDavid Teigland rc->rc_result = ret_nodeid; 402e7fd4179SDavid Teigland rc->rc_id = rc_in->rc_id; 40338aa8b0cSDavid Teigland rc->rc_seq_reply = rc_in->rc_seq; 404e7fd4179SDavid Teigland 405e7fd4179SDavid Teigland send_rcom(ls, mh, rc); 406e7fd4179SDavid Teigland } 407e7fd4179SDavid Teigland 408e7fd4179SDavid Teigland static void receive_rcom_lookup_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) 409e7fd4179SDavid Teigland { 410e7fd4179SDavid Teigland dlm_recover_master_reply(ls, rc_in); 411e7fd4179SDavid Teigland } 412e7fd4179SDavid Teigland 413e7fd4179SDavid Teigland static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb, 414e7fd4179SDavid Teigland struct rcom_lock *rl) 415e7fd4179SDavid Teigland { 416e7fd4179SDavid Teigland memset(rl, 0, sizeof(*rl)); 417e7fd4179SDavid Teigland 418163a1859SAl Viro rl->rl_ownpid = cpu_to_le32(lkb->lkb_ownpid); 419163a1859SAl Viro rl->rl_lkid = cpu_to_le32(lkb->lkb_id); 420163a1859SAl Viro rl->rl_exflags = cpu_to_le32(lkb->lkb_exflags); 421163a1859SAl Viro rl->rl_flags = cpu_to_le32(lkb->lkb_flags); 422163a1859SAl Viro rl->rl_lvbseq = cpu_to_le32(lkb->lkb_lvbseq); 423e7fd4179SDavid Teigland rl->rl_rqmode = lkb->lkb_rqmode; 424e7fd4179SDavid Teigland rl->rl_grmode = lkb->lkb_grmode; 425e7fd4179SDavid Teigland rl->rl_status = lkb->lkb_status; 426163a1859SAl Viro rl->rl_wait_type = cpu_to_le16(lkb->lkb_wait_type); 427e7fd4179SDavid Teigland 428e5dae548SDavid Teigland if (lkb->lkb_bastfn) 4298304d6f2SDavid Teigland rl->rl_asts |= DLM_CB_BAST; 430e5dae548SDavid Teigland if (lkb->lkb_astfn) 4318304d6f2SDavid Teigland rl->rl_asts |= DLM_CB_CAST; 432e7fd4179SDavid Teigland 433163a1859SAl Viro rl->rl_namelen = cpu_to_le16(r->res_length); 434e7fd4179SDavid Teigland memcpy(rl->rl_name, r->res_name, r->res_length); 435e7fd4179SDavid Teigland 436e7fd4179SDavid Teigland /* FIXME: might we have an lvb without DLM_LKF_VALBLK set ? 437e7fd4179SDavid Teigland If so, receive_rcom_lock_args() won't take this copy. */ 438e7fd4179SDavid Teigland 439e7fd4179SDavid Teigland if (lkb->lkb_lvbptr) 440e7fd4179SDavid Teigland memcpy(rl->rl_lvb, lkb->lkb_lvbptr, r->res_ls->ls_lvblen); 441e7fd4179SDavid Teigland } 442e7fd4179SDavid Teigland 443e7fd4179SDavid Teigland int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb) 444e7fd4179SDavid Teigland { 445e7fd4179SDavid Teigland struct dlm_ls *ls = r->res_ls; 446e7fd4179SDavid Teigland struct dlm_rcom *rc; 447e7fd4179SDavid Teigland struct dlm_mhandle *mh; 448e7fd4179SDavid Teigland struct rcom_lock *rl; 449e7fd4179SDavid Teigland int error, len = sizeof(struct rcom_lock); 450e7fd4179SDavid Teigland 451e7fd4179SDavid Teigland if (lkb->lkb_lvbptr) 452e7fd4179SDavid Teigland len += ls->ls_lvblen; 453e7fd4179SDavid Teigland 454e7fd4179SDavid Teigland error = create_rcom(ls, r->res_nodeid, DLM_RCOM_LOCK, len, &rc, &mh); 455e7fd4179SDavid Teigland if (error) 456e7fd4179SDavid Teigland goto out; 457e7fd4179SDavid Teigland 458e7fd4179SDavid Teigland rl = (struct rcom_lock *) rc->rc_buf; 459e7fd4179SDavid Teigland pack_rcom_lock(r, lkb, rl); 460e7fd4179SDavid Teigland rc->rc_id = (unsigned long) r; 461e7fd4179SDavid Teigland 462e7fd4179SDavid Teigland send_rcom(ls, mh, rc); 463e7fd4179SDavid Teigland out: 464e7fd4179SDavid Teigland return error; 465e7fd4179SDavid Teigland } 466e7fd4179SDavid Teigland 467ae773d0bSAl Viro /* needs at least dlm_rcom + rcom_lock */ 468e7fd4179SDavid Teigland static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in) 469e7fd4179SDavid Teigland { 470e7fd4179SDavid Teigland struct dlm_rcom *rc; 471e7fd4179SDavid Teigland struct dlm_mhandle *mh; 472e7fd4179SDavid Teigland int error, nodeid = rc_in->rc_header.h_nodeid; 473e7fd4179SDavid Teigland 474e7fd4179SDavid Teigland dlm_recover_master_copy(ls, rc_in); 475e7fd4179SDavid Teigland 476e7fd4179SDavid Teigland error = create_rcom(ls, nodeid, DLM_RCOM_LOCK_REPLY, 477e7fd4179SDavid Teigland sizeof(struct rcom_lock), &rc, &mh); 478e7fd4179SDavid Teigland if (error) 479e7fd4179SDavid Teigland return; 480e7fd4179SDavid Teigland 481e7fd4179SDavid Teigland /* We send back the same rcom_lock struct we received, but 482e7fd4179SDavid Teigland dlm_recover_master_copy() has filled in rl_remid and rl_result */ 483e7fd4179SDavid Teigland 484e7fd4179SDavid Teigland memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock)); 485e7fd4179SDavid Teigland rc->rc_id = rc_in->rc_id; 48638aa8b0cSDavid Teigland rc->rc_seq_reply = rc_in->rc_seq; 487e7fd4179SDavid Teigland 488e7fd4179SDavid Teigland send_rcom(ls, mh, rc); 489e7fd4179SDavid Teigland } 490e7fd4179SDavid Teigland 491c36258b5SDavid Teigland /* If the lockspace doesn't exist then still send a status message 492c36258b5SDavid Teigland back; it's possible that it just doesn't have its global_id yet. */ 493c36258b5SDavid Teigland 494c36258b5SDavid Teigland int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) 495e7fd4179SDavid Teigland { 496e7fd4179SDavid Teigland struct dlm_rcom *rc; 4971babdb45SDavid Teigland struct rcom_config *rf; 498e7fd4179SDavid Teigland struct dlm_mhandle *mh; 499e7fd4179SDavid Teigland char *mb; 5001babdb45SDavid Teigland int mb_len = sizeof(struct dlm_rcom) + sizeof(struct rcom_config); 501e7fd4179SDavid Teigland 502*a070a91cSAlexander Aring mh = dlm_midcomms_get_mhandle(nodeid, mb_len, GFP_NOFS, &mb); 503e7fd4179SDavid Teigland if (!mh) 504e7fd4179SDavid Teigland return -ENOBUFS; 505e7fd4179SDavid Teigland 506e7fd4179SDavid Teigland rc = (struct dlm_rcom *) mb; 507e7fd4179SDavid Teigland 508e7fd4179SDavid Teigland rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR); 509e7fd4179SDavid Teigland rc->rc_header.h_lockspace = rc_in->rc_header.h_lockspace; 510e7fd4179SDavid Teigland rc->rc_header.h_nodeid = dlm_our_nodeid(); 511e7fd4179SDavid Teigland rc->rc_header.h_length = mb_len; 512e7fd4179SDavid Teigland rc->rc_header.h_cmd = DLM_RCOM; 513e7fd4179SDavid Teigland 514e7fd4179SDavid Teigland rc->rc_type = DLM_RCOM_STATUS_REPLY; 515f5888750SDavid Teigland rc->rc_id = rc_in->rc_id; 51638aa8b0cSDavid Teigland rc->rc_seq_reply = rc_in->rc_seq; 517e7fd4179SDavid Teigland rc->rc_result = -ESRCH; 518e7fd4179SDavid Teigland 5191babdb45SDavid Teigland rf = (struct rcom_config *) rc->rc_buf; 52093ff2971SAl Viro rf->rf_lvblen = cpu_to_le32(~0U); 5211babdb45SDavid Teigland 522e7fd4179SDavid Teigland dlm_rcom_out(rc); 523*a070a91cSAlexander Aring dlm_midcomms_commit_mhandle(mh); 524e7fd4179SDavid Teigland 525e7fd4179SDavid Teigland return 0; 526e7fd4179SDavid Teigland } 527e7fd4179SDavid Teigland 528c04fecb4SDavid Teigland /* 529c04fecb4SDavid Teigland * Ignore messages for stage Y before we set 530c04fecb4SDavid Teigland * recover_status bit for stage X: 531c04fecb4SDavid Teigland * 532c04fecb4SDavid Teigland * recover_status = 0 533c04fecb4SDavid Teigland * 534c04fecb4SDavid Teigland * dlm_recover_members() 535c04fecb4SDavid Teigland * - send nothing 536c04fecb4SDavid Teigland * - recv nothing 537c04fecb4SDavid Teigland * - ignore NAMES, NAMES_REPLY 538c04fecb4SDavid Teigland * - ignore LOOKUP, LOOKUP_REPLY 539c04fecb4SDavid Teigland * - ignore LOCK, LOCK_REPLY 540c04fecb4SDavid Teigland * 541c04fecb4SDavid Teigland * recover_status |= NODES 542c04fecb4SDavid Teigland * 543c04fecb4SDavid Teigland * dlm_recover_members_wait() 544c04fecb4SDavid Teigland * 545c04fecb4SDavid Teigland * dlm_recover_directory() 546c04fecb4SDavid Teigland * - send NAMES 547c04fecb4SDavid Teigland * - recv NAMES_REPLY 548c04fecb4SDavid Teigland * - ignore LOOKUP, LOOKUP_REPLY 549c04fecb4SDavid Teigland * - ignore LOCK, LOCK_REPLY 550c04fecb4SDavid Teigland * 551c04fecb4SDavid Teigland * recover_status |= DIR 552c04fecb4SDavid Teigland * 553c04fecb4SDavid Teigland * dlm_recover_directory_wait() 554c04fecb4SDavid Teigland * 555c04fecb4SDavid Teigland * dlm_recover_masters() 556c04fecb4SDavid Teigland * - send LOOKUP 557c04fecb4SDavid Teigland * - recv LOOKUP_REPLY 558c04fecb4SDavid Teigland * 559c04fecb4SDavid Teigland * dlm_recover_locks() 560c04fecb4SDavid Teigland * - send LOCKS 561c04fecb4SDavid Teigland * - recv LOCKS_REPLY 562c04fecb4SDavid Teigland * 563c04fecb4SDavid Teigland * recover_status |= LOCKS 564c04fecb4SDavid Teigland * 565c04fecb4SDavid Teigland * dlm_recover_locks_wait() 566c04fecb4SDavid Teigland * 567c04fecb4SDavid Teigland * recover_status |= DONE 568c04fecb4SDavid Teigland */ 569c04fecb4SDavid Teigland 570c36258b5SDavid Teigland /* Called by dlm_recv; corresponds to dlm_receive_message() but special 571e7fd4179SDavid Teigland recovery-only comms are sent through here. */ 572e7fd4179SDavid Teigland 573c36258b5SDavid Teigland void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) 574e7fd4179SDavid Teigland { 575ae773d0bSAl Viro int lock_size = sizeof(struct dlm_rcom) + sizeof(struct rcom_lock); 576c04fecb4SDavid Teigland int stop, reply = 0, names = 0, lookup = 0, lock = 0; 5774875647aSDavid Teigland uint32_t status; 578d6e24788SDavid Teigland uint64_t seq; 579ae773d0bSAl Viro 580d6e24788SDavid Teigland switch (rc->rc_type) { 581c04fecb4SDavid Teigland case DLM_RCOM_STATUS_REPLY: 582c04fecb4SDavid Teigland reply = 1; 583c04fecb4SDavid Teigland break; 584c04fecb4SDavid Teigland case DLM_RCOM_NAMES: 585c04fecb4SDavid Teigland names = 1; 586c04fecb4SDavid Teigland break; 587c04fecb4SDavid Teigland case DLM_RCOM_NAMES_REPLY: 588c04fecb4SDavid Teigland names = 1; 589c04fecb4SDavid Teigland reply = 1; 590c04fecb4SDavid Teigland break; 591c04fecb4SDavid Teigland case DLM_RCOM_LOOKUP: 592c04fecb4SDavid Teigland lookup = 1; 593c04fecb4SDavid Teigland break; 594c04fecb4SDavid Teigland case DLM_RCOM_LOOKUP_REPLY: 595c04fecb4SDavid Teigland lookup = 1; 596c04fecb4SDavid Teigland reply = 1; 597c04fecb4SDavid Teigland break; 5984875647aSDavid Teigland case DLM_RCOM_LOCK: 5994875647aSDavid Teigland lock = 1; 6004875647aSDavid Teigland break; 6014875647aSDavid Teigland case DLM_RCOM_LOCK_REPLY: 6024875647aSDavid Teigland lock = 1; 6034875647aSDavid Teigland reply = 1; 6044875647aSDavid Teigland break; 60590db4f8bSWu Bo } 606d6e24788SDavid Teigland 607d6e24788SDavid Teigland spin_lock(&ls->ls_recover_lock); 6084875647aSDavid Teigland status = ls->ls_recover_status; 609475f230cSDavid Teigland stop = test_bit(LSFL_RECOVER_STOP, &ls->ls_flags); 610d6e24788SDavid Teigland seq = ls->ls_recover_seq; 611d6e24788SDavid Teigland spin_unlock(&ls->ls_recover_lock); 612d6e24788SDavid Teigland 613c04fecb4SDavid Teigland if (stop && (rc->rc_type != DLM_RCOM_STATUS)) 614c04fecb4SDavid Teigland goto ignore; 615c04fecb4SDavid Teigland 616c04fecb4SDavid Teigland if (reply && (rc->rc_seq_reply != seq)) 617c04fecb4SDavid Teigland goto ignore; 618c04fecb4SDavid Teigland 619c04fecb4SDavid Teigland if (!(status & DLM_RS_NODES) && (names || lookup || lock)) 620c04fecb4SDavid Teigland goto ignore; 621c04fecb4SDavid Teigland 622c04fecb4SDavid Teigland if (!(status & DLM_RS_DIR) && (lookup || lock)) 623c04fecb4SDavid Teigland goto ignore; 624e7fd4179SDavid Teigland 625e7fd4179SDavid Teigland switch (rc->rc_type) { 626e7fd4179SDavid Teigland case DLM_RCOM_STATUS: 627e7fd4179SDavid Teigland receive_rcom_status(ls, rc); 628e7fd4179SDavid Teigland break; 629e7fd4179SDavid Teigland 630e7fd4179SDavid Teigland case DLM_RCOM_NAMES: 631e7fd4179SDavid Teigland receive_rcom_names(ls, rc); 632e7fd4179SDavid Teigland break; 633e7fd4179SDavid Teigland 634e7fd4179SDavid Teigland case DLM_RCOM_LOOKUP: 635e7fd4179SDavid Teigland receive_rcom_lookup(ls, rc); 636e7fd4179SDavid Teigland break; 637e7fd4179SDavid Teigland 638e7fd4179SDavid Teigland case DLM_RCOM_LOCK: 639ae773d0bSAl Viro if (rc->rc_header.h_length < lock_size) 640ae773d0bSAl Viro goto Eshort; 641e7fd4179SDavid Teigland receive_rcom_lock(ls, rc); 642e7fd4179SDavid Teigland break; 643e7fd4179SDavid Teigland 644e7fd4179SDavid Teigland case DLM_RCOM_STATUS_REPLY: 645dbcfc347SDavid Teigland receive_sync_reply(ls, rc); 646e7fd4179SDavid Teigland break; 647e7fd4179SDavid Teigland 648e7fd4179SDavid Teigland case DLM_RCOM_NAMES_REPLY: 649dbcfc347SDavid Teigland receive_sync_reply(ls, rc); 650e7fd4179SDavid Teigland break; 651e7fd4179SDavid Teigland 652e7fd4179SDavid Teigland case DLM_RCOM_LOOKUP_REPLY: 653e7fd4179SDavid Teigland receive_rcom_lookup_reply(ls, rc); 654e7fd4179SDavid Teigland break; 655e7fd4179SDavid Teigland 656e7fd4179SDavid Teigland case DLM_RCOM_LOCK_REPLY: 657ae773d0bSAl Viro if (rc->rc_header.h_length < lock_size) 658ae773d0bSAl Viro goto Eshort; 659dbcfc347SDavid Teigland dlm_recover_process_copy(ls, rc); 660e7fd4179SDavid Teigland break; 661e7fd4179SDavid Teigland 662e7fd4179SDavid Teigland default: 663dbcfc347SDavid Teigland log_error(ls, "receive_rcom bad type %d", rc->rc_type); 664e7fd4179SDavid Teigland } 665c04fecb4SDavid Teigland return; 666c04fecb4SDavid Teigland 667c04fecb4SDavid Teigland ignore: 668c04fecb4SDavid Teigland log_limit(ls, "dlm_receive_rcom ignore msg %d " 669c04fecb4SDavid Teigland "from %d %llu %llu recover seq %llu sts %x gen %u", 670c04fecb4SDavid Teigland rc->rc_type, 671c04fecb4SDavid Teigland nodeid, 672c04fecb4SDavid Teigland (unsigned long long)rc->rc_seq, 673c04fecb4SDavid Teigland (unsigned long long)rc->rc_seq_reply, 674c04fecb4SDavid Teigland (unsigned long long)seq, 675c04fecb4SDavid Teigland status, ls->ls_generation); 676c36258b5SDavid Teigland return; 677ae773d0bSAl Viro Eshort: 678c04fecb4SDavid Teigland log_error(ls, "recovery message %d from %d is too short", 679ae773d0bSAl Viro rc->rc_type, nodeid); 680e7fd4179SDavid Teigland } 681e7fd4179SDavid Teigland 682