18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci drbd_state.c 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This file is part of DRBD by Philipp Reisner and Lars Ellenberg. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. 88c2ecf20Sopenharmony_ci Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>. 98c2ecf20Sopenharmony_ci Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev 128c2ecf20Sopenharmony_ci from Logicworks, Inc. for making SDP replication support possible. 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/drbd_limits.h> 178c2ecf20Sopenharmony_ci#include "drbd_int.h" 188c2ecf20Sopenharmony_ci#include "drbd_protocol.h" 198c2ecf20Sopenharmony_ci#include "drbd_req.h" 208c2ecf20Sopenharmony_ci#include "drbd_state_change.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct after_state_chg_work { 238c2ecf20Sopenharmony_ci struct drbd_work w; 248c2ecf20Sopenharmony_ci struct drbd_device *device; 258c2ecf20Sopenharmony_ci union drbd_state os; 268c2ecf20Sopenharmony_ci union drbd_state ns; 278c2ecf20Sopenharmony_ci enum chg_state_flags flags; 288c2ecf20Sopenharmony_ci struct completion *done; 298c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cienum sanitize_state_warnings { 338c2ecf20Sopenharmony_ci NO_WARNING, 348c2ecf20Sopenharmony_ci ABORTED_ONLINE_VERIFY, 358c2ecf20Sopenharmony_ci ABORTED_RESYNC, 368c2ecf20Sopenharmony_ci CONNECTION_LOST_NEGOTIATING, 378c2ecf20Sopenharmony_ci IMPLICITLY_UPGRADED_DISK, 388c2ecf20Sopenharmony_ci IMPLICITLY_UPGRADED_PDSK, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void count_objects(struct drbd_resource *resource, 428c2ecf20Sopenharmony_ci unsigned int *n_devices, 438c2ecf20Sopenharmony_ci unsigned int *n_connections) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct drbd_device *device; 468c2ecf20Sopenharmony_ci struct drbd_connection *connection; 478c2ecf20Sopenharmony_ci int vnr; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci *n_devices = 0; 508c2ecf20Sopenharmony_ci *n_connections = 0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci idr_for_each_entry(&resource->devices, device, vnr) 538c2ecf20Sopenharmony_ci (*n_devices)++; 548c2ecf20Sopenharmony_ci for_each_connection(connection, resource) 558c2ecf20Sopenharmony_ci (*n_connections)++; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct drbd_state_change *alloc_state_change(unsigned int n_devices, unsigned int n_connections, gfp_t gfp) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 618c2ecf20Sopenharmony_ci unsigned int size, n; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci size = sizeof(struct drbd_state_change) + 648c2ecf20Sopenharmony_ci n_devices * sizeof(struct drbd_device_state_change) + 658c2ecf20Sopenharmony_ci n_connections * sizeof(struct drbd_connection_state_change) + 668c2ecf20Sopenharmony_ci n_devices * n_connections * sizeof(struct drbd_peer_device_state_change); 678c2ecf20Sopenharmony_ci state_change = kmalloc(size, gfp); 688c2ecf20Sopenharmony_ci if (!state_change) 698c2ecf20Sopenharmony_ci return NULL; 708c2ecf20Sopenharmony_ci state_change->n_devices = n_devices; 718c2ecf20Sopenharmony_ci state_change->n_connections = n_connections; 728c2ecf20Sopenharmony_ci state_change->devices = (void *)(state_change + 1); 738c2ecf20Sopenharmony_ci state_change->connections = (void *)&state_change->devices[n_devices]; 748c2ecf20Sopenharmony_ci state_change->peer_devices = (void *)&state_change->connections[n_connections]; 758c2ecf20Sopenharmony_ci state_change->resource->resource = NULL; 768c2ecf20Sopenharmony_ci for (n = 0; n < n_devices; n++) 778c2ecf20Sopenharmony_ci state_change->devices[n].device = NULL; 788c2ecf20Sopenharmony_ci for (n = 0; n < n_connections; n++) 798c2ecf20Sopenharmony_ci state_change->connections[n].connection = NULL; 808c2ecf20Sopenharmony_ci return state_change; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistruct drbd_state_change *remember_old_state(struct drbd_resource *resource, gfp_t gfp) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 868c2ecf20Sopenharmony_ci struct drbd_device *device; 878c2ecf20Sopenharmony_ci unsigned int n_devices; 888c2ecf20Sopenharmony_ci struct drbd_connection *connection; 898c2ecf20Sopenharmony_ci unsigned int n_connections; 908c2ecf20Sopenharmony_ci int vnr; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci struct drbd_device_state_change *device_state_change; 938c2ecf20Sopenharmony_ci struct drbd_peer_device_state_change *peer_device_state_change; 948c2ecf20Sopenharmony_ci struct drbd_connection_state_change *connection_state_change; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* Caller holds req_lock spinlock. 978c2ecf20Sopenharmony_ci * No state, no device IDR, no connections lists can change. */ 988c2ecf20Sopenharmony_ci count_objects(resource, &n_devices, &n_connections); 998c2ecf20Sopenharmony_ci state_change = alloc_state_change(n_devices, n_connections, gfp); 1008c2ecf20Sopenharmony_ci if (!state_change) 1018c2ecf20Sopenharmony_ci return NULL; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci kref_get(&resource->kref); 1048c2ecf20Sopenharmony_ci state_change->resource->resource = resource; 1058c2ecf20Sopenharmony_ci state_change->resource->role[OLD] = 1068c2ecf20Sopenharmony_ci conn_highest_role(first_connection(resource)); 1078c2ecf20Sopenharmony_ci state_change->resource->susp[OLD] = resource->susp; 1088c2ecf20Sopenharmony_ci state_change->resource->susp_nod[OLD] = resource->susp_nod; 1098c2ecf20Sopenharmony_ci state_change->resource->susp_fen[OLD] = resource->susp_fen; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci connection_state_change = state_change->connections; 1128c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 1138c2ecf20Sopenharmony_ci kref_get(&connection->kref); 1148c2ecf20Sopenharmony_ci connection_state_change->connection = connection; 1158c2ecf20Sopenharmony_ci connection_state_change->cstate[OLD] = 1168c2ecf20Sopenharmony_ci connection->cstate; 1178c2ecf20Sopenharmony_ci connection_state_change->peer_role[OLD] = 1188c2ecf20Sopenharmony_ci conn_highest_peer(connection); 1198c2ecf20Sopenharmony_ci connection_state_change++; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci device_state_change = state_change->devices; 1238c2ecf20Sopenharmony_ci peer_device_state_change = state_change->peer_devices; 1248c2ecf20Sopenharmony_ci idr_for_each_entry(&resource->devices, device, vnr) { 1258c2ecf20Sopenharmony_ci kref_get(&device->kref); 1268c2ecf20Sopenharmony_ci device_state_change->device = device; 1278c2ecf20Sopenharmony_ci device_state_change->disk_state[OLD] = device->state.disk; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* The peer_devices for each device have to be enumerated in 1308c2ecf20Sopenharmony_ci the order of the connections. We may not use for_each_peer_device() here. */ 1318c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 1328c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci peer_device = conn_peer_device(connection, device->vnr); 1358c2ecf20Sopenharmony_ci peer_device_state_change->peer_device = peer_device; 1368c2ecf20Sopenharmony_ci peer_device_state_change->disk_state[OLD] = 1378c2ecf20Sopenharmony_ci device->state.pdsk; 1388c2ecf20Sopenharmony_ci peer_device_state_change->repl_state[OLD] = 1398c2ecf20Sopenharmony_ci max_t(enum drbd_conns, 1408c2ecf20Sopenharmony_ci C_WF_REPORT_PARAMS, device->state.conn); 1418c2ecf20Sopenharmony_ci peer_device_state_change->resync_susp_user[OLD] = 1428c2ecf20Sopenharmony_ci device->state.user_isp; 1438c2ecf20Sopenharmony_ci peer_device_state_change->resync_susp_peer[OLD] = 1448c2ecf20Sopenharmony_ci device->state.peer_isp; 1458c2ecf20Sopenharmony_ci peer_device_state_change->resync_susp_dependency[OLD] = 1468c2ecf20Sopenharmony_ci device->state.aftr_isp; 1478c2ecf20Sopenharmony_ci peer_device_state_change++; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci device_state_change++; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return state_change; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void remember_new_state(struct drbd_state_change *state_change) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct drbd_resource_state_change *resource_state_change; 1588c2ecf20Sopenharmony_ci struct drbd_resource *resource; 1598c2ecf20Sopenharmony_ci unsigned int n; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (!state_change) 1628c2ecf20Sopenharmony_ci return; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci resource_state_change = &state_change->resource[0]; 1658c2ecf20Sopenharmony_ci resource = resource_state_change->resource; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci resource_state_change->role[NEW] = 1688c2ecf20Sopenharmony_ci conn_highest_role(first_connection(resource)); 1698c2ecf20Sopenharmony_ci resource_state_change->susp[NEW] = resource->susp; 1708c2ecf20Sopenharmony_ci resource_state_change->susp_nod[NEW] = resource->susp_nod; 1718c2ecf20Sopenharmony_ci resource_state_change->susp_fen[NEW] = resource->susp_fen; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci for (n = 0; n < state_change->n_devices; n++) { 1748c2ecf20Sopenharmony_ci struct drbd_device_state_change *device_state_change = 1758c2ecf20Sopenharmony_ci &state_change->devices[n]; 1768c2ecf20Sopenharmony_ci struct drbd_device *device = device_state_change->device; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci device_state_change->disk_state[NEW] = device->state.disk; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci for (n = 0; n < state_change->n_connections; n++) { 1828c2ecf20Sopenharmony_ci struct drbd_connection_state_change *connection_state_change = 1838c2ecf20Sopenharmony_ci &state_change->connections[n]; 1848c2ecf20Sopenharmony_ci struct drbd_connection *connection = 1858c2ecf20Sopenharmony_ci connection_state_change->connection; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci connection_state_change->cstate[NEW] = connection->cstate; 1888c2ecf20Sopenharmony_ci connection_state_change->peer_role[NEW] = 1898c2ecf20Sopenharmony_ci conn_highest_peer(connection); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci for (n = 0; n < state_change->n_devices * state_change->n_connections; n++) { 1938c2ecf20Sopenharmony_ci struct drbd_peer_device_state_change *peer_device_state_change = 1948c2ecf20Sopenharmony_ci &state_change->peer_devices[n]; 1958c2ecf20Sopenharmony_ci struct drbd_device *device = 1968c2ecf20Sopenharmony_ci peer_device_state_change->peer_device->device; 1978c2ecf20Sopenharmony_ci union drbd_dev_state state = device->state; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci peer_device_state_change->disk_state[NEW] = state.pdsk; 2008c2ecf20Sopenharmony_ci peer_device_state_change->repl_state[NEW] = 2018c2ecf20Sopenharmony_ci max_t(enum drbd_conns, C_WF_REPORT_PARAMS, state.conn); 2028c2ecf20Sopenharmony_ci peer_device_state_change->resync_susp_user[NEW] = 2038c2ecf20Sopenharmony_ci state.user_isp; 2048c2ecf20Sopenharmony_ci peer_device_state_change->resync_susp_peer[NEW] = 2058c2ecf20Sopenharmony_ci state.peer_isp; 2068c2ecf20Sopenharmony_ci peer_device_state_change->resync_susp_dependency[NEW] = 2078c2ecf20Sopenharmony_ci state.aftr_isp; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_civoid copy_old_to_new_state_change(struct drbd_state_change *state_change) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct drbd_resource_state_change *resource_state_change = &state_change->resource[0]; 2148c2ecf20Sopenharmony_ci unsigned int n_device, n_connection, n_peer_device, n_peer_devices; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#define OLD_TO_NEW(x) \ 2178c2ecf20Sopenharmony_ci (x[NEW] = x[OLD]) 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci OLD_TO_NEW(resource_state_change->role); 2208c2ecf20Sopenharmony_ci OLD_TO_NEW(resource_state_change->susp); 2218c2ecf20Sopenharmony_ci OLD_TO_NEW(resource_state_change->susp_nod); 2228c2ecf20Sopenharmony_ci OLD_TO_NEW(resource_state_change->susp_fen); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (n_connection = 0; n_connection < state_change->n_connections; n_connection++) { 2258c2ecf20Sopenharmony_ci struct drbd_connection_state_change *connection_state_change = 2268c2ecf20Sopenharmony_ci &state_change->connections[n_connection]; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci OLD_TO_NEW(connection_state_change->peer_role); 2298c2ecf20Sopenharmony_ci OLD_TO_NEW(connection_state_change->cstate); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (n_device = 0; n_device < state_change->n_devices; n_device++) { 2338c2ecf20Sopenharmony_ci struct drbd_device_state_change *device_state_change = 2348c2ecf20Sopenharmony_ci &state_change->devices[n_device]; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci OLD_TO_NEW(device_state_change->disk_state); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci n_peer_devices = state_change->n_devices * state_change->n_connections; 2408c2ecf20Sopenharmony_ci for (n_peer_device = 0; n_peer_device < n_peer_devices; n_peer_device++) { 2418c2ecf20Sopenharmony_ci struct drbd_peer_device_state_change *p = 2428c2ecf20Sopenharmony_ci &state_change->peer_devices[n_peer_device]; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci OLD_TO_NEW(p->disk_state); 2458c2ecf20Sopenharmony_ci OLD_TO_NEW(p->repl_state); 2468c2ecf20Sopenharmony_ci OLD_TO_NEW(p->resync_susp_user); 2478c2ecf20Sopenharmony_ci OLD_TO_NEW(p->resync_susp_peer); 2488c2ecf20Sopenharmony_ci OLD_TO_NEW(p->resync_susp_dependency); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#undef OLD_TO_NEW 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid forget_state_change(struct drbd_state_change *state_change) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci unsigned int n; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (!state_change) 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (state_change->resource->resource) 2628c2ecf20Sopenharmony_ci kref_put(&state_change->resource->resource->kref, drbd_destroy_resource); 2638c2ecf20Sopenharmony_ci for (n = 0; n < state_change->n_devices; n++) { 2648c2ecf20Sopenharmony_ci struct drbd_device *device = state_change->devices[n].device; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (device) 2678c2ecf20Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci for (n = 0; n < state_change->n_connections; n++) { 2708c2ecf20Sopenharmony_ci struct drbd_connection *connection = 2718c2ecf20Sopenharmony_ci state_change->connections[n].connection; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (connection) 2748c2ecf20Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci kfree(state_change); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int w_after_state_ch(struct drbd_work *w, int unused); 2808c2ecf20Sopenharmony_cistatic void after_state_ch(struct drbd_device *device, union drbd_state os, 2818c2ecf20Sopenharmony_ci union drbd_state ns, enum chg_state_flags flags, 2828c2ecf20Sopenharmony_ci struct drbd_state_change *); 2838c2ecf20Sopenharmony_cistatic enum drbd_state_rv is_valid_state(struct drbd_device *, union drbd_state); 2848c2ecf20Sopenharmony_cistatic enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_connection *); 2858c2ecf20Sopenharmony_cistatic enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); 2868c2ecf20Sopenharmony_cistatic union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os, 2878c2ecf20Sopenharmony_ci union drbd_state ns, enum sanitize_state_warnings *warn); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic inline bool is_susp(union drbd_state s) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci return s.susp || s.susp_nod || s.susp_fen; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cibool conn_all_vols_unconf(struct drbd_connection *connection) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 2978c2ecf20Sopenharmony_ci bool rv = true; 2988c2ecf20Sopenharmony_ci int vnr; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci rcu_read_lock(); 3018c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 3028c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 3038c2ecf20Sopenharmony_ci if (device->state.disk != D_DISKLESS || 3048c2ecf20Sopenharmony_ci device->state.conn != C_STANDALONE || 3058c2ecf20Sopenharmony_ci device->state.role != R_SECONDARY) { 3068c2ecf20Sopenharmony_ci rv = false; 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci rcu_read_unlock(); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return rv; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* Unfortunately the states where not correctly ordered, when 3168c2ecf20Sopenharmony_ci they where defined. therefore can not use max_t() here. */ 3178c2ecf20Sopenharmony_cistatic enum drbd_role max_role(enum drbd_role role1, enum drbd_role role2) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci if (role1 == R_PRIMARY || role2 == R_PRIMARY) 3208c2ecf20Sopenharmony_ci return R_PRIMARY; 3218c2ecf20Sopenharmony_ci if (role1 == R_SECONDARY || role2 == R_SECONDARY) 3228c2ecf20Sopenharmony_ci return R_SECONDARY; 3238c2ecf20Sopenharmony_ci return R_UNKNOWN; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci if (role1 == R_UNKNOWN || role2 == R_UNKNOWN) 3298c2ecf20Sopenharmony_ci return R_UNKNOWN; 3308c2ecf20Sopenharmony_ci if (role1 == R_SECONDARY || role2 == R_SECONDARY) 3318c2ecf20Sopenharmony_ci return R_SECONDARY; 3328c2ecf20Sopenharmony_ci return R_PRIMARY; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cienum drbd_role conn_highest_role(struct drbd_connection *connection) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci enum drbd_role role = R_SECONDARY; 3388c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 3398c2ecf20Sopenharmony_ci int vnr; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci rcu_read_lock(); 3428c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 3438c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 3448c2ecf20Sopenharmony_ci role = max_role(role, device->state.role); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci rcu_read_unlock(); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return role; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cienum drbd_role conn_highest_peer(struct drbd_connection *connection) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci enum drbd_role peer = R_UNKNOWN; 3548c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 3558c2ecf20Sopenharmony_ci int vnr; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci rcu_read_lock(); 3588c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 3598c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 3608c2ecf20Sopenharmony_ci peer = max_role(peer, device->state.peer); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci rcu_read_unlock(); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return peer; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cienum drbd_disk_state conn_highest_disk(struct drbd_connection *connection) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci enum drbd_disk_state disk_state = D_DISKLESS; 3708c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 3718c2ecf20Sopenharmony_ci int vnr; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci rcu_read_lock(); 3748c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 3758c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 3768c2ecf20Sopenharmony_ci disk_state = max_t(enum drbd_disk_state, disk_state, device->state.disk); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci rcu_read_unlock(); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return disk_state; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cienum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci enum drbd_disk_state disk_state = D_MASK; 3868c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 3878c2ecf20Sopenharmony_ci int vnr; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci rcu_read_lock(); 3908c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 3918c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 3928c2ecf20Sopenharmony_ci disk_state = min_t(enum drbd_disk_state, disk_state, device->state.disk); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci rcu_read_unlock(); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return disk_state; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cienum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci enum drbd_disk_state disk_state = D_DISKLESS; 4028c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 4038c2ecf20Sopenharmony_ci int vnr; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci rcu_read_lock(); 4068c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 4078c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 4088c2ecf20Sopenharmony_ci disk_state = max_t(enum drbd_disk_state, disk_state, device->state.pdsk); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci rcu_read_unlock(); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return disk_state; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cienum drbd_conns conn_lowest_conn(struct drbd_connection *connection) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci enum drbd_conns conn = C_MASK; 4188c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 4198c2ecf20Sopenharmony_ci int vnr; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci rcu_read_lock(); 4228c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 4238c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 4248c2ecf20Sopenharmony_ci conn = min_t(enum drbd_conns, conn, device->state.conn); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci rcu_read_unlock(); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return conn; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic bool no_peer_wf_report_params(struct drbd_connection *connection) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 4348c2ecf20Sopenharmony_ci int vnr; 4358c2ecf20Sopenharmony_ci bool rv = true; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci rcu_read_lock(); 4388c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 4398c2ecf20Sopenharmony_ci if (peer_device->device->state.conn == C_WF_REPORT_PARAMS) { 4408c2ecf20Sopenharmony_ci rv = false; 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci rcu_read_unlock(); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return rv; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void wake_up_all_devices(struct drbd_connection *connection) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 4518c2ecf20Sopenharmony_ci int vnr; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci rcu_read_lock(); 4548c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 4558c2ecf20Sopenharmony_ci wake_up(&peer_device->device->state_wait); 4568c2ecf20Sopenharmony_ci rcu_read_unlock(); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/** 4628c2ecf20Sopenharmony_ci * cl_wide_st_chg() - true if the state change is a cluster wide one 4638c2ecf20Sopenharmony_ci * @device: DRBD device. 4648c2ecf20Sopenharmony_ci * @os: old (current) state. 4658c2ecf20Sopenharmony_ci * @ns: new (wanted) state. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_cistatic int cl_wide_st_chg(struct drbd_device *device, 4688c2ecf20Sopenharmony_ci union drbd_state os, union drbd_state ns) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED && 4718c2ecf20Sopenharmony_ci ((os.role != R_PRIMARY && ns.role == R_PRIMARY) || 4728c2ecf20Sopenharmony_ci (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || 4738c2ecf20Sopenharmony_ci (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) || 4748c2ecf20Sopenharmony_ci (os.disk != D_FAILED && ns.disk == D_FAILED))) || 4758c2ecf20Sopenharmony_ci (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) || 4768c2ecf20Sopenharmony_ci (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S) || 4778c2ecf20Sopenharmony_ci (os.conn == C_CONNECTED && ns.conn == C_WF_REPORT_PARAMS); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic union drbd_state 4818c2ecf20Sopenharmony_ciapply_mask_val(union drbd_state os, union drbd_state mask, union drbd_state val) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci union drbd_state ns; 4848c2ecf20Sopenharmony_ci ns.i = (os.i & ~mask.i) | val.i; 4858c2ecf20Sopenharmony_ci return ns; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cienum drbd_state_rv 4898c2ecf20Sopenharmony_cidrbd_change_state(struct drbd_device *device, enum chg_state_flags f, 4908c2ecf20Sopenharmony_ci union drbd_state mask, union drbd_state val) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci unsigned long flags; 4938c2ecf20Sopenharmony_ci union drbd_state ns; 4948c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 4978c2ecf20Sopenharmony_ci ns = apply_mask_val(drbd_read_state(device), mask, val); 4988c2ecf20Sopenharmony_ci rv = _drbd_set_state(device, ns, f, NULL); 4998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return rv; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * drbd_force_state() - Impose a change which happens outside our control on our state 5068c2ecf20Sopenharmony_ci * @device: DRBD device. 5078c2ecf20Sopenharmony_ci * @mask: mask of state bits to change. 5088c2ecf20Sopenharmony_ci * @val: value of new state bits. 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_civoid drbd_force_state(struct drbd_device *device, 5118c2ecf20Sopenharmony_ci union drbd_state mask, union drbd_state val) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci drbd_change_state(device, CS_HARD, mask, val); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic enum drbd_state_rv 5178c2ecf20Sopenharmony_ci_req_st_cond(struct drbd_device *device, union drbd_state mask, 5188c2ecf20Sopenharmony_ci union drbd_state val) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci union drbd_state os, ns; 5218c2ecf20Sopenharmony_ci unsigned long flags; 5228c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &device->flags)) 5258c2ecf20Sopenharmony_ci return SS_CW_SUCCESS; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (test_and_clear_bit(CL_ST_CHG_FAIL, &device->flags)) 5288c2ecf20Sopenharmony_ci return SS_CW_FAILED_BY_PEER; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 5318c2ecf20Sopenharmony_ci os = drbd_read_state(device); 5328c2ecf20Sopenharmony_ci ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); 5338c2ecf20Sopenharmony_ci rv = is_valid_transition(os, ns); 5348c2ecf20Sopenharmony_ci if (rv >= SS_SUCCESS) 5358c2ecf20Sopenharmony_ci rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!cl_wide_st_chg(device, os, ns)) 5388c2ecf20Sopenharmony_ci rv = SS_CW_NO_NEED; 5398c2ecf20Sopenharmony_ci if (rv == SS_UNKNOWN_ERROR) { 5408c2ecf20Sopenharmony_ci rv = is_valid_state(device, ns); 5418c2ecf20Sopenharmony_ci if (rv >= SS_SUCCESS) { 5428c2ecf20Sopenharmony_ci rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection); 5438c2ecf20Sopenharmony_ci if (rv >= SS_SUCCESS) 5448c2ecf20Sopenharmony_ci rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return rv; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci/** 5538c2ecf20Sopenharmony_ci * drbd_req_state() - Perform an eventually cluster wide state change 5548c2ecf20Sopenharmony_ci * @device: DRBD device. 5558c2ecf20Sopenharmony_ci * @mask: mask of state bits to change. 5568c2ecf20Sopenharmony_ci * @val: value of new state bits. 5578c2ecf20Sopenharmony_ci * @f: flags 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Should not be called directly, use drbd_request_state() or 5608c2ecf20Sopenharmony_ci * _drbd_request_state(). 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_cistatic enum drbd_state_rv 5638c2ecf20Sopenharmony_cidrbd_req_state(struct drbd_device *device, union drbd_state mask, 5648c2ecf20Sopenharmony_ci union drbd_state val, enum chg_state_flags f) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct completion done; 5678c2ecf20Sopenharmony_ci unsigned long flags; 5688c2ecf20Sopenharmony_ci union drbd_state os, ns; 5698c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 5708c2ecf20Sopenharmony_ci void *buffer = NULL; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci init_completion(&done); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (f & CS_SERIALIZE) 5758c2ecf20Sopenharmony_ci mutex_lock(device->state_mutex); 5768c2ecf20Sopenharmony_ci if (f & CS_INHIBIT_MD_IO) 5778c2ecf20Sopenharmony_ci buffer = drbd_md_get_buffer(device, __func__); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 5808c2ecf20Sopenharmony_ci os = drbd_read_state(device); 5818c2ecf20Sopenharmony_ci ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); 5828c2ecf20Sopenharmony_ci rv = is_valid_transition(os, ns); 5838c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 5848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 5858c2ecf20Sopenharmony_ci goto abort; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (cl_wide_st_chg(device, os, ns)) { 5898c2ecf20Sopenharmony_ci rv = is_valid_state(device, ns); 5908c2ecf20Sopenharmony_ci if (rv == SS_SUCCESS) 5918c2ecf20Sopenharmony_ci rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection); 5928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 5958c2ecf20Sopenharmony_ci if (f & CS_VERBOSE) 5968c2ecf20Sopenharmony_ci print_st_err(device, os, ns, rv); 5978c2ecf20Sopenharmony_ci goto abort; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (drbd_send_state_req(first_peer_device(device), mask, val)) { 6018c2ecf20Sopenharmony_ci rv = SS_CW_FAILED_BY_PEER; 6028c2ecf20Sopenharmony_ci if (f & CS_VERBOSE) 6038c2ecf20Sopenharmony_ci print_st_err(device, os, ns, rv); 6048c2ecf20Sopenharmony_ci goto abort; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci wait_event(device->state_wait, 6088c2ecf20Sopenharmony_ci (rv = _req_st_cond(device, mask, val))); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 6118c2ecf20Sopenharmony_ci if (f & CS_VERBOSE) 6128c2ecf20Sopenharmony_ci print_st_err(device, os, ns, rv); 6138c2ecf20Sopenharmony_ci goto abort; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 6168c2ecf20Sopenharmony_ci ns = apply_mask_val(drbd_read_state(device), mask, val); 6178c2ecf20Sopenharmony_ci rv = _drbd_set_state(device, ns, f, &done); 6188c2ecf20Sopenharmony_ci } else { 6198c2ecf20Sopenharmony_ci rv = _drbd_set_state(device, ns, f, &done); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) { 6258c2ecf20Sopenharmony_ci D_ASSERT(device, current != first_peer_device(device)->connection->worker.task); 6268c2ecf20Sopenharmony_ci wait_for_completion(&done); 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ciabort: 6308c2ecf20Sopenharmony_ci if (buffer) 6318c2ecf20Sopenharmony_ci drbd_md_put_buffer(device); 6328c2ecf20Sopenharmony_ci if (f & CS_SERIALIZE) 6338c2ecf20Sopenharmony_ci mutex_unlock(device->state_mutex); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return rv; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci/** 6398c2ecf20Sopenharmony_ci * _drbd_request_state() - Request a state change (with flags) 6408c2ecf20Sopenharmony_ci * @device: DRBD device. 6418c2ecf20Sopenharmony_ci * @mask: mask of state bits to change. 6428c2ecf20Sopenharmony_ci * @val: value of new state bits. 6438c2ecf20Sopenharmony_ci * @f: flags 6448c2ecf20Sopenharmony_ci * 6458c2ecf20Sopenharmony_ci * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE 6468c2ecf20Sopenharmony_ci * flag, or when logging of failed state change requests is not desired. 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_cienum drbd_state_rv 6498c2ecf20Sopenharmony_ci_drbd_request_state(struct drbd_device *device, union drbd_state mask, 6508c2ecf20Sopenharmony_ci union drbd_state val, enum chg_state_flags f) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci wait_event(device->state_wait, 6558c2ecf20Sopenharmony_ci (rv = drbd_req_state(device, mask, val, f)) != SS_IN_TRANSIENT_STATE); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return rv; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* 6618c2ecf20Sopenharmony_ci * We grab drbd_md_get_buffer(), because we don't want to "fail" the disk while 6628c2ecf20Sopenharmony_ci * there is IO in-flight: the transition into D_FAILED for detach purposes 6638c2ecf20Sopenharmony_ci * may get misinterpreted as actual IO error in a confused endio function. 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * We wrap it all into wait_event(), to retry in case the drbd_req_state() 6668c2ecf20Sopenharmony_ci * returns SS_IN_TRANSIENT_STATE. 6678c2ecf20Sopenharmony_ci * 6688c2ecf20Sopenharmony_ci * To avoid potential deadlock with e.g. the receiver thread trying to grab 6698c2ecf20Sopenharmony_ci * drbd_md_get_buffer() while trying to get out of the "transient state", we 6708c2ecf20Sopenharmony_ci * need to grab and release the meta data buffer inside of that wait_event loop. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_cistatic enum drbd_state_rv 6738c2ecf20Sopenharmony_cirequest_detach(struct drbd_device *device) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci return drbd_req_state(device, NS(disk, D_FAILED), 6768c2ecf20Sopenharmony_ci CS_VERBOSE | CS_ORDERED | CS_INHIBIT_MD_IO); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ciint drbd_request_detach_interruptible(struct drbd_device *device) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci int ret, rv; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci drbd_suspend_io(device); /* so no-one is stuck in drbd_al_begin_io */ 6848c2ecf20Sopenharmony_ci wait_event_interruptible(device->state_wait, 6858c2ecf20Sopenharmony_ci (rv = request_detach(device)) != SS_IN_TRANSIENT_STATE); 6868c2ecf20Sopenharmony_ci drbd_resume_io(device); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci ret = wait_event_interruptible(device->misc_wait, 6898c2ecf20Sopenharmony_ci device->state.disk != D_FAILED); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (rv == SS_IS_DISKLESS) 6928c2ecf20Sopenharmony_ci rv = SS_NOTHING_TO_DO; 6938c2ecf20Sopenharmony_ci if (ret) 6948c2ecf20Sopenharmony_ci rv = ERR_INTR; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return rv; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cienum drbd_state_rv 7008c2ecf20Sopenharmony_ci_drbd_request_state_holding_state_mutex(struct drbd_device *device, union drbd_state mask, 7018c2ecf20Sopenharmony_ci union drbd_state val, enum chg_state_flags f) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci BUG_ON(f & CS_SERIALIZE); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci wait_event_cmd(device->state_wait, 7088c2ecf20Sopenharmony_ci (rv = drbd_req_state(device, mask, val, f)) != SS_IN_TRANSIENT_STATE, 7098c2ecf20Sopenharmony_ci mutex_unlock(device->state_mutex), 7108c2ecf20Sopenharmony_ci mutex_lock(device->state_mutex)); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return rv; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic void print_st(struct drbd_device *device, const char *name, union drbd_state ns) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci drbd_err(device, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n", 7188c2ecf20Sopenharmony_ci name, 7198c2ecf20Sopenharmony_ci drbd_conn_str(ns.conn), 7208c2ecf20Sopenharmony_ci drbd_role_str(ns.role), 7218c2ecf20Sopenharmony_ci drbd_role_str(ns.peer), 7228c2ecf20Sopenharmony_ci drbd_disk_str(ns.disk), 7238c2ecf20Sopenharmony_ci drbd_disk_str(ns.pdsk), 7248c2ecf20Sopenharmony_ci is_susp(ns) ? 's' : 'r', 7258c2ecf20Sopenharmony_ci ns.aftr_isp ? 'a' : '-', 7268c2ecf20Sopenharmony_ci ns.peer_isp ? 'p' : '-', 7278c2ecf20Sopenharmony_ci ns.user_isp ? 'u' : '-', 7288c2ecf20Sopenharmony_ci ns.susp_fen ? 'F' : '-', 7298c2ecf20Sopenharmony_ci ns.susp_nod ? 'N' : '-' 7308c2ecf20Sopenharmony_ci ); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_civoid print_st_err(struct drbd_device *device, union drbd_state os, 7348c2ecf20Sopenharmony_ci union drbd_state ns, enum drbd_state_rv err) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci if (err == SS_IN_TRANSIENT_STATE) 7378c2ecf20Sopenharmony_ci return; 7388c2ecf20Sopenharmony_ci drbd_err(device, "State change failed: %s\n", drbd_set_st_err_str(err)); 7398c2ecf20Sopenharmony_ci print_st(device, " state", os); 7408c2ecf20Sopenharmony_ci print_st(device, "wanted", ns); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic long print_state_change(char *pb, union drbd_state os, union drbd_state ns, 7448c2ecf20Sopenharmony_ci enum chg_state_flags flags) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci char *pbp; 7478c2ecf20Sopenharmony_ci pbp = pb; 7488c2ecf20Sopenharmony_ci *pbp = 0; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (ns.role != os.role && flags & CS_DC_ROLE) 7518c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "role( %s -> %s ) ", 7528c2ecf20Sopenharmony_ci drbd_role_str(os.role), 7538c2ecf20Sopenharmony_ci drbd_role_str(ns.role)); 7548c2ecf20Sopenharmony_ci if (ns.peer != os.peer && flags & CS_DC_PEER) 7558c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "peer( %s -> %s ) ", 7568c2ecf20Sopenharmony_ci drbd_role_str(os.peer), 7578c2ecf20Sopenharmony_ci drbd_role_str(ns.peer)); 7588c2ecf20Sopenharmony_ci if (ns.conn != os.conn && flags & CS_DC_CONN) 7598c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "conn( %s -> %s ) ", 7608c2ecf20Sopenharmony_ci drbd_conn_str(os.conn), 7618c2ecf20Sopenharmony_ci drbd_conn_str(ns.conn)); 7628c2ecf20Sopenharmony_ci if (ns.disk != os.disk && flags & CS_DC_DISK) 7638c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "disk( %s -> %s ) ", 7648c2ecf20Sopenharmony_ci drbd_disk_str(os.disk), 7658c2ecf20Sopenharmony_ci drbd_disk_str(ns.disk)); 7668c2ecf20Sopenharmony_ci if (ns.pdsk != os.pdsk && flags & CS_DC_PDSK) 7678c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "pdsk( %s -> %s ) ", 7688c2ecf20Sopenharmony_ci drbd_disk_str(os.pdsk), 7698c2ecf20Sopenharmony_ci drbd_disk_str(ns.pdsk)); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return pbp - pb; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic void drbd_pr_state_change(struct drbd_device *device, union drbd_state os, union drbd_state ns, 7758c2ecf20Sopenharmony_ci enum chg_state_flags flags) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci char pb[300]; 7788c2ecf20Sopenharmony_ci char *pbp = pb; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci pbp += print_state_change(pbp, os, ns, flags ^ CS_DC_MASK); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (ns.aftr_isp != os.aftr_isp) 7838c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", 7848c2ecf20Sopenharmony_ci os.aftr_isp, 7858c2ecf20Sopenharmony_ci ns.aftr_isp); 7868c2ecf20Sopenharmony_ci if (ns.peer_isp != os.peer_isp) 7878c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", 7888c2ecf20Sopenharmony_ci os.peer_isp, 7898c2ecf20Sopenharmony_ci ns.peer_isp); 7908c2ecf20Sopenharmony_ci if (ns.user_isp != os.user_isp) 7918c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "user_isp( %d -> %d ) ", 7928c2ecf20Sopenharmony_ci os.user_isp, 7938c2ecf20Sopenharmony_ci ns.user_isp); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (pbp != pb) 7968c2ecf20Sopenharmony_ci drbd_info(device, "%s\n", pb); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic void conn_pr_state_change(struct drbd_connection *connection, union drbd_state os, union drbd_state ns, 8008c2ecf20Sopenharmony_ci enum chg_state_flags flags) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci char pb[300]; 8038c2ecf20Sopenharmony_ci char *pbp = pb; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci pbp += print_state_change(pbp, os, ns, flags); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (is_susp(ns) != is_susp(os) && flags & CS_DC_SUSP) 8088c2ecf20Sopenharmony_ci pbp += sprintf(pbp, "susp( %d -> %d ) ", 8098c2ecf20Sopenharmony_ci is_susp(os), 8108c2ecf20Sopenharmony_ci is_susp(ns)); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (pbp != pb) 8138c2ecf20Sopenharmony_ci drbd_info(connection, "%s\n", pb); 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci/** 8188c2ecf20Sopenharmony_ci * is_valid_state() - Returns an SS_ error code if ns is not valid 8198c2ecf20Sopenharmony_ci * @device: DRBD device. 8208c2ecf20Sopenharmony_ci * @ns: State to consider. 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_cistatic enum drbd_state_rv 8238c2ecf20Sopenharmony_ciis_valid_state(struct drbd_device *device, union drbd_state ns) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci /* See drbd_state_sw_errors in drbd_strings.c */ 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci enum drbd_fencing_p fp; 8288c2ecf20Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 8298c2ecf20Sopenharmony_ci struct net_conf *nc; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci rcu_read_lock(); 8328c2ecf20Sopenharmony_ci fp = FP_DONT_CARE; 8338c2ecf20Sopenharmony_ci if (get_ldev(device)) { 8348c2ecf20Sopenharmony_ci fp = rcu_dereference(device->ldev->disk_conf)->fencing; 8358c2ecf20Sopenharmony_ci put_ldev(device); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci nc = rcu_dereference(first_peer_device(device)->connection->net_conf); 8398c2ecf20Sopenharmony_ci if (nc) { 8408c2ecf20Sopenharmony_ci if (!nc->two_primaries && ns.role == R_PRIMARY) { 8418c2ecf20Sopenharmony_ci if (ns.peer == R_PRIMARY) 8428c2ecf20Sopenharmony_ci rv = SS_TWO_PRIMARIES; 8438c2ecf20Sopenharmony_ci else if (conn_highest_peer(first_peer_device(device)->connection) == R_PRIMARY) 8448c2ecf20Sopenharmony_ci rv = SS_O_VOL_PEER_PRI; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (rv <= 0) 8498c2ecf20Sopenharmony_ci goto out; /* already found a reason to abort */ 8508c2ecf20Sopenharmony_ci else if (ns.role == R_SECONDARY && device->open_cnt) 8518c2ecf20Sopenharmony_ci rv = SS_DEVICE_IN_USE; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE) 8548c2ecf20Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci else if (fp >= FP_RESOURCE && 8578c2ecf20Sopenharmony_ci ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN) 8588c2ecf20Sopenharmony_ci rv = SS_PRIMARY_NOP; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT) 8618c2ecf20Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT) 8648c2ecf20Sopenharmony_ci rv = SS_NO_LOCAL_DISK; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT) 8678c2ecf20Sopenharmony_ci rv = SS_NO_REMOTE_DISK; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci else if (ns.conn > C_CONNECTED && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) 8708c2ecf20Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci else if ((ns.conn == C_CONNECTED || 8738c2ecf20Sopenharmony_ci ns.conn == C_WF_BITMAP_S || 8748c2ecf20Sopenharmony_ci ns.conn == C_SYNC_SOURCE || 8758c2ecf20Sopenharmony_ci ns.conn == C_PAUSED_SYNC_S) && 8768c2ecf20Sopenharmony_ci ns.disk == D_OUTDATED) 8778c2ecf20Sopenharmony_ci rv = SS_CONNECTED_OUTDATES; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && 8808c2ecf20Sopenharmony_ci (nc->verify_alg[0] == 0)) 8818c2ecf20Sopenharmony_ci rv = SS_NO_VERIFY_ALG; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && 8848c2ecf20Sopenharmony_ci first_peer_device(device)->connection->agreed_pro_version < 88) 8858c2ecf20Sopenharmony_ci rv = SS_NOT_SUPPORTED; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci else if (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) 8888c2ecf20Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci else if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) && 8918c2ecf20Sopenharmony_ci ns.pdsk == D_UNKNOWN) 8928c2ecf20Sopenharmony_ci rv = SS_NEED_CONNECTION; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN) 8958c2ecf20Sopenharmony_ci rv = SS_CONNECTED_OUTDATES; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ciout: 8988c2ecf20Sopenharmony_ci rcu_read_unlock(); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return rv; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci/** 9048c2ecf20Sopenharmony_ci * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible 9058c2ecf20Sopenharmony_ci * This function limits state transitions that may be declined by DRBD. I.e. 9068c2ecf20Sopenharmony_ci * user requests (aka soft transitions). 9078c2ecf20Sopenharmony_ci * @device: DRBD device. 9088c2ecf20Sopenharmony_ci * @ns: new state. 9098c2ecf20Sopenharmony_ci * @os: old state. 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic enum drbd_state_rv 9128c2ecf20Sopenharmony_ciis_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_connection *connection) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && 9178c2ecf20Sopenharmony_ci os.conn > C_CONNECTED) 9188c2ecf20Sopenharmony_ci rv = SS_RESYNC_RUNNING; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE) 9218c2ecf20Sopenharmony_ci rv = SS_ALREADY_STANDALONE; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS) 9248c2ecf20Sopenharmony_ci rv = SS_IS_DISKLESS; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED) 9278c2ecf20Sopenharmony_ci rv = SS_NO_NET_CONFIG; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING) 9308c2ecf20Sopenharmony_ci rv = SS_LOWER_THAN_OUTDATED; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED) 9338c2ecf20Sopenharmony_ci rv = SS_IN_TRANSIENT_STATE; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* While establishing a connection only allow cstate to change. 9368c2ecf20Sopenharmony_ci Delay/refuse role changes, detach attach etc... (they do not touch cstate) */ 9378c2ecf20Sopenharmony_ci if (test_bit(STATE_SENT, &connection->flags) && 9388c2ecf20Sopenharmony_ci !((ns.conn == C_WF_REPORT_PARAMS && os.conn == C_WF_CONNECTION) || 9398c2ecf20Sopenharmony_ci (ns.conn >= C_CONNECTED && os.conn == C_WF_REPORT_PARAMS))) 9408c2ecf20Sopenharmony_ci rv = SS_IN_TRANSIENT_STATE; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Do not promote during resync handshake triggered by "force primary". 9438c2ecf20Sopenharmony_ci * This is a hack. It should really be rejected by the peer during the 9448c2ecf20Sopenharmony_ci * cluster wide state change request. */ 9458c2ecf20Sopenharmony_ci if (os.role != R_PRIMARY && ns.role == R_PRIMARY 9468c2ecf20Sopenharmony_ci && ns.pdsk == D_UP_TO_DATE 9478c2ecf20Sopenharmony_ci && ns.disk != D_UP_TO_DATE && ns.disk != D_DISKLESS 9488c2ecf20Sopenharmony_ci && (ns.conn <= C_WF_SYNC_UUID || ns.conn != os.conn)) 9498c2ecf20Sopenharmony_ci rv = SS_IN_TRANSIENT_STATE; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) 9528c2ecf20Sopenharmony_ci rv = SS_NEED_CONNECTION; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && 9558c2ecf20Sopenharmony_ci ns.conn != os.conn && os.conn > C_CONNECTED) 9568c2ecf20Sopenharmony_ci rv = SS_RESYNC_RUNNING; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) && 9598c2ecf20Sopenharmony_ci os.conn < C_CONNECTED) 9608c2ecf20Sopenharmony_ci rv = SS_NEED_CONNECTION; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE) 9638c2ecf20Sopenharmony_ci && os.conn < C_WF_REPORT_PARAMS) 9648c2ecf20Sopenharmony_ci rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (ns.conn == C_DISCONNECTING && ns.pdsk == D_OUTDATED && 9678c2ecf20Sopenharmony_ci os.conn < C_CONNECTED && os.pdsk > D_OUTDATED) 9688c2ecf20Sopenharmony_ci rv = SS_OUTDATE_WO_CONN; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci return rv; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic enum drbd_state_rv 9748c2ecf20Sopenharmony_ciis_valid_conn_transition(enum drbd_conns oc, enum drbd_conns nc) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci /* no change -> nothing to do, at least for the connection part */ 9778c2ecf20Sopenharmony_ci if (oc == nc) 9788c2ecf20Sopenharmony_ci return SS_NOTHING_TO_DO; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* disconnect of an unconfigured connection does not make sense */ 9818c2ecf20Sopenharmony_ci if (oc == C_STANDALONE && nc == C_DISCONNECTING) 9828c2ecf20Sopenharmony_ci return SS_ALREADY_STANDALONE; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* from C_STANDALONE, we start with C_UNCONNECTED */ 9858c2ecf20Sopenharmony_ci if (oc == C_STANDALONE && nc != C_UNCONNECTED) 9868c2ecf20Sopenharmony_ci return SS_NEED_CONNECTION; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* When establishing a connection we need to go through WF_REPORT_PARAMS! 9898c2ecf20Sopenharmony_ci Necessary to do the right thing upon invalidate-remote on a disconnected resource */ 9908c2ecf20Sopenharmony_ci if (oc < C_WF_REPORT_PARAMS && nc >= C_CONNECTED) 9918c2ecf20Sopenharmony_ci return SS_NEED_CONNECTION; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */ 9948c2ecf20Sopenharmony_ci if (oc >= C_TIMEOUT && oc <= C_TEAR_DOWN && nc != C_UNCONNECTED && nc != C_DISCONNECTING) 9958c2ecf20Sopenharmony_ci return SS_IN_TRANSIENT_STATE; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* After C_DISCONNECTING only C_STANDALONE may follow */ 9988c2ecf20Sopenharmony_ci if (oc == C_DISCONNECTING && nc != C_STANDALONE) 9998c2ecf20Sopenharmony_ci return SS_IN_TRANSIENT_STATE; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return SS_SUCCESS; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/** 10068c2ecf20Sopenharmony_ci * is_valid_transition() - Returns an SS_ error code if the state transition is not possible 10078c2ecf20Sopenharmony_ci * This limits hard state transitions. Hard state transitions are facts there are 10088c2ecf20Sopenharmony_ci * imposed on DRBD by the environment. E.g. disk broke or network broke down. 10098c2ecf20Sopenharmony_ci * But those hard state transitions are still not allowed to do everything. 10108c2ecf20Sopenharmony_ci * @ns: new state. 10118c2ecf20Sopenharmony_ci * @os: old state. 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_cistatic enum drbd_state_rv 10148c2ecf20Sopenharmony_ciis_valid_transition(union drbd_state os, union drbd_state ns) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci rv = is_valid_conn_transition(os.conn, ns.conn); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* we cannot fail (again) if we already detached */ 10218c2ecf20Sopenharmony_ci if (ns.disk == D_FAILED && os.disk == D_DISKLESS) 10228c2ecf20Sopenharmony_ci rv = SS_IS_DISKLESS; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return rv; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic void print_sanitize_warnings(struct drbd_device *device, enum sanitize_state_warnings warn) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci static const char *msg_table[] = { 10308c2ecf20Sopenharmony_ci [NO_WARNING] = "", 10318c2ecf20Sopenharmony_ci [ABORTED_ONLINE_VERIFY] = "Online-verify aborted.", 10328c2ecf20Sopenharmony_ci [ABORTED_RESYNC] = "Resync aborted.", 10338c2ecf20Sopenharmony_ci [CONNECTION_LOST_NEGOTIATING] = "Connection lost while negotiating, no data!", 10348c2ecf20Sopenharmony_ci [IMPLICITLY_UPGRADED_DISK] = "Implicitly upgraded disk", 10358c2ecf20Sopenharmony_ci [IMPLICITLY_UPGRADED_PDSK] = "Implicitly upgraded pdsk", 10368c2ecf20Sopenharmony_ci }; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (warn != NO_WARNING) 10398c2ecf20Sopenharmony_ci drbd_warn(device, "%s\n", msg_table[warn]); 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci/** 10438c2ecf20Sopenharmony_ci * sanitize_state() - Resolves implicitly necessary additional changes to a state transition 10448c2ecf20Sopenharmony_ci * @device: DRBD device. 10458c2ecf20Sopenharmony_ci * @os: old state. 10468c2ecf20Sopenharmony_ci * @ns: new state. 10478c2ecf20Sopenharmony_ci * @warn_sync_abort: 10488c2ecf20Sopenharmony_ci * 10498c2ecf20Sopenharmony_ci * When we loose connection, we have to set the state of the peers disk (pdsk) 10508c2ecf20Sopenharmony_ci * to D_UNKNOWN. This rule and many more along those lines are in this function. 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_cistatic union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os, 10538c2ecf20Sopenharmony_ci union drbd_state ns, enum sanitize_state_warnings *warn) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci enum drbd_fencing_p fp; 10568c2ecf20Sopenharmony_ci enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (warn) 10598c2ecf20Sopenharmony_ci *warn = NO_WARNING; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci fp = FP_DONT_CARE; 10628c2ecf20Sopenharmony_ci if (get_ldev(device)) { 10638c2ecf20Sopenharmony_ci rcu_read_lock(); 10648c2ecf20Sopenharmony_ci fp = rcu_dereference(device->ldev->disk_conf)->fencing; 10658c2ecf20Sopenharmony_ci rcu_read_unlock(); 10668c2ecf20Sopenharmony_ci put_ldev(device); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Implications from connection to peer and peer_isp */ 10708c2ecf20Sopenharmony_ci if (ns.conn < C_CONNECTED) { 10718c2ecf20Sopenharmony_ci ns.peer_isp = 0; 10728c2ecf20Sopenharmony_ci ns.peer = R_UNKNOWN; 10738c2ecf20Sopenharmony_ci if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT) 10748c2ecf20Sopenharmony_ci ns.pdsk = D_UNKNOWN; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Clear the aftr_isp when becoming unconfigured */ 10788c2ecf20Sopenharmony_ci if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY) 10798c2ecf20Sopenharmony_ci ns.aftr_isp = 0; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* An implication of the disk states onto the connection state */ 10828c2ecf20Sopenharmony_ci /* Abort resync if a disk fails/detaches */ 10838c2ecf20Sopenharmony_ci if (ns.conn > C_CONNECTED && (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { 10848c2ecf20Sopenharmony_ci if (warn) 10858c2ecf20Sopenharmony_ci *warn = ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T ? 10868c2ecf20Sopenharmony_ci ABORTED_ONLINE_VERIFY : ABORTED_RESYNC; 10878c2ecf20Sopenharmony_ci ns.conn = C_CONNECTED; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* Connection breaks down before we finished "Negotiating" */ 10918c2ecf20Sopenharmony_ci if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && 10928c2ecf20Sopenharmony_ci get_ldev_if_state(device, D_NEGOTIATING)) { 10938c2ecf20Sopenharmony_ci if (device->ed_uuid == device->ldev->md.uuid[UI_CURRENT]) { 10948c2ecf20Sopenharmony_ci ns.disk = device->new_state_tmp.disk; 10958c2ecf20Sopenharmony_ci ns.pdsk = device->new_state_tmp.pdsk; 10968c2ecf20Sopenharmony_ci } else { 10978c2ecf20Sopenharmony_ci if (warn) 10988c2ecf20Sopenharmony_ci *warn = CONNECTION_LOST_NEGOTIATING; 10998c2ecf20Sopenharmony_ci ns.disk = D_DISKLESS; 11008c2ecf20Sopenharmony_ci ns.pdsk = D_UNKNOWN; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci put_ldev(device); 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* D_CONSISTENT and D_OUTDATED vanish when we get connected */ 11068c2ecf20Sopenharmony_ci if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) { 11078c2ecf20Sopenharmony_ci if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) 11088c2ecf20Sopenharmony_ci ns.disk = D_UP_TO_DATE; 11098c2ecf20Sopenharmony_ci if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED) 11108c2ecf20Sopenharmony_ci ns.pdsk = D_UP_TO_DATE; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* Implications of the connection state on the disk states */ 11148c2ecf20Sopenharmony_ci disk_min = D_DISKLESS; 11158c2ecf20Sopenharmony_ci disk_max = D_UP_TO_DATE; 11168c2ecf20Sopenharmony_ci pdsk_min = D_INCONSISTENT; 11178c2ecf20Sopenharmony_ci pdsk_max = D_UNKNOWN; 11188c2ecf20Sopenharmony_ci switch ((enum drbd_conns)ns.conn) { 11198c2ecf20Sopenharmony_ci case C_WF_BITMAP_T: 11208c2ecf20Sopenharmony_ci case C_PAUSED_SYNC_T: 11218c2ecf20Sopenharmony_ci case C_STARTING_SYNC_T: 11228c2ecf20Sopenharmony_ci case C_WF_SYNC_UUID: 11238c2ecf20Sopenharmony_ci case C_BEHIND: 11248c2ecf20Sopenharmony_ci disk_min = D_INCONSISTENT; 11258c2ecf20Sopenharmony_ci disk_max = D_OUTDATED; 11268c2ecf20Sopenharmony_ci pdsk_min = D_UP_TO_DATE; 11278c2ecf20Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci case C_VERIFY_S: 11308c2ecf20Sopenharmony_ci case C_VERIFY_T: 11318c2ecf20Sopenharmony_ci disk_min = D_UP_TO_DATE; 11328c2ecf20Sopenharmony_ci disk_max = D_UP_TO_DATE; 11338c2ecf20Sopenharmony_ci pdsk_min = D_UP_TO_DATE; 11348c2ecf20Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 11358c2ecf20Sopenharmony_ci break; 11368c2ecf20Sopenharmony_ci case C_CONNECTED: 11378c2ecf20Sopenharmony_ci disk_min = D_DISKLESS; 11388c2ecf20Sopenharmony_ci disk_max = D_UP_TO_DATE; 11398c2ecf20Sopenharmony_ci pdsk_min = D_DISKLESS; 11408c2ecf20Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci case C_WF_BITMAP_S: 11438c2ecf20Sopenharmony_ci case C_PAUSED_SYNC_S: 11448c2ecf20Sopenharmony_ci case C_STARTING_SYNC_S: 11458c2ecf20Sopenharmony_ci case C_AHEAD: 11468c2ecf20Sopenharmony_ci disk_min = D_UP_TO_DATE; 11478c2ecf20Sopenharmony_ci disk_max = D_UP_TO_DATE; 11488c2ecf20Sopenharmony_ci pdsk_min = D_INCONSISTENT; 11498c2ecf20Sopenharmony_ci pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/ 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci case C_SYNC_TARGET: 11528c2ecf20Sopenharmony_ci disk_min = D_INCONSISTENT; 11538c2ecf20Sopenharmony_ci disk_max = D_INCONSISTENT; 11548c2ecf20Sopenharmony_ci pdsk_min = D_UP_TO_DATE; 11558c2ecf20Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci case C_SYNC_SOURCE: 11588c2ecf20Sopenharmony_ci disk_min = D_UP_TO_DATE; 11598c2ecf20Sopenharmony_ci disk_max = D_UP_TO_DATE; 11608c2ecf20Sopenharmony_ci pdsk_min = D_INCONSISTENT; 11618c2ecf20Sopenharmony_ci pdsk_max = D_INCONSISTENT; 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci case C_STANDALONE: 11648c2ecf20Sopenharmony_ci case C_DISCONNECTING: 11658c2ecf20Sopenharmony_ci case C_UNCONNECTED: 11668c2ecf20Sopenharmony_ci case C_TIMEOUT: 11678c2ecf20Sopenharmony_ci case C_BROKEN_PIPE: 11688c2ecf20Sopenharmony_ci case C_NETWORK_FAILURE: 11698c2ecf20Sopenharmony_ci case C_PROTOCOL_ERROR: 11708c2ecf20Sopenharmony_ci case C_TEAR_DOWN: 11718c2ecf20Sopenharmony_ci case C_WF_CONNECTION: 11728c2ecf20Sopenharmony_ci case C_WF_REPORT_PARAMS: 11738c2ecf20Sopenharmony_ci case C_MASK: 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci if (ns.disk > disk_max) 11778c2ecf20Sopenharmony_ci ns.disk = disk_max; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (ns.disk < disk_min) { 11808c2ecf20Sopenharmony_ci if (warn) 11818c2ecf20Sopenharmony_ci *warn = IMPLICITLY_UPGRADED_DISK; 11828c2ecf20Sopenharmony_ci ns.disk = disk_min; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci if (ns.pdsk > pdsk_max) 11858c2ecf20Sopenharmony_ci ns.pdsk = pdsk_max; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (ns.pdsk < pdsk_min) { 11888c2ecf20Sopenharmony_ci if (warn) 11898c2ecf20Sopenharmony_ci *warn = IMPLICITLY_UPGRADED_PDSK; 11908c2ecf20Sopenharmony_ci ns.pdsk = pdsk_min; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (fp == FP_STONITH && 11948c2ecf20Sopenharmony_ci (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && 11958c2ecf20Sopenharmony_ci !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) 11968c2ecf20Sopenharmony_ci ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci if (device->resource->res_opts.on_no_data == OND_SUSPEND_IO && 11998c2ecf20Sopenharmony_ci (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && 12008c2ecf20Sopenharmony_ci !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) 12018c2ecf20Sopenharmony_ci ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { 12048c2ecf20Sopenharmony_ci if (ns.conn == C_SYNC_SOURCE) 12058c2ecf20Sopenharmony_ci ns.conn = C_PAUSED_SYNC_S; 12068c2ecf20Sopenharmony_ci if (ns.conn == C_SYNC_TARGET) 12078c2ecf20Sopenharmony_ci ns.conn = C_PAUSED_SYNC_T; 12088c2ecf20Sopenharmony_ci } else { 12098c2ecf20Sopenharmony_ci if (ns.conn == C_PAUSED_SYNC_S) 12108c2ecf20Sopenharmony_ci ns.conn = C_SYNC_SOURCE; 12118c2ecf20Sopenharmony_ci if (ns.conn == C_PAUSED_SYNC_T) 12128c2ecf20Sopenharmony_ci ns.conn = C_SYNC_TARGET; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci return ns; 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_civoid drbd_resume_al(struct drbd_device *device) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci if (test_and_clear_bit(AL_SUSPENDED, &device->flags)) 12218c2ecf20Sopenharmony_ci drbd_info(device, "Resumed AL updates\n"); 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/* helper for _drbd_set_state */ 12258c2ecf20Sopenharmony_cistatic void set_ov_position(struct drbd_device *device, enum drbd_conns cs) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci if (first_peer_device(device)->connection->agreed_pro_version < 90) 12288c2ecf20Sopenharmony_ci device->ov_start_sector = 0; 12298c2ecf20Sopenharmony_ci device->rs_total = drbd_bm_bits(device); 12308c2ecf20Sopenharmony_ci device->ov_position = 0; 12318c2ecf20Sopenharmony_ci if (cs == C_VERIFY_T) { 12328c2ecf20Sopenharmony_ci /* starting online verify from an arbitrary position 12338c2ecf20Sopenharmony_ci * does not fit well into the existing protocol. 12348c2ecf20Sopenharmony_ci * on C_VERIFY_T, we initialize ov_left and friends 12358c2ecf20Sopenharmony_ci * implicitly in receive_DataRequest once the 12368c2ecf20Sopenharmony_ci * first P_OV_REQUEST is received */ 12378c2ecf20Sopenharmony_ci device->ov_start_sector = ~(sector_t)0; 12388c2ecf20Sopenharmony_ci } else { 12398c2ecf20Sopenharmony_ci unsigned long bit = BM_SECT_TO_BIT(device->ov_start_sector); 12408c2ecf20Sopenharmony_ci if (bit >= device->rs_total) { 12418c2ecf20Sopenharmony_ci device->ov_start_sector = 12428c2ecf20Sopenharmony_ci BM_BIT_TO_SECT(device->rs_total - 1); 12438c2ecf20Sopenharmony_ci device->rs_total = 1; 12448c2ecf20Sopenharmony_ci } else 12458c2ecf20Sopenharmony_ci device->rs_total -= bit; 12468c2ecf20Sopenharmony_ci device->ov_position = device->ov_start_sector; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci device->ov_left = device->rs_total; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci/** 12528c2ecf20Sopenharmony_ci * _drbd_set_state() - Set a new DRBD state 12538c2ecf20Sopenharmony_ci * @device: DRBD device. 12548c2ecf20Sopenharmony_ci * @ns: new state. 12558c2ecf20Sopenharmony_ci * @flags: Flags 12568c2ecf20Sopenharmony_ci * @done: Optional completion, that will get completed after the after_state_ch() finished 12578c2ecf20Sopenharmony_ci * 12588c2ecf20Sopenharmony_ci * Caller needs to hold req_lock. Do not call directly. 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_cienum drbd_state_rv 12618c2ecf20Sopenharmony_ci_drbd_set_state(struct drbd_device *device, union drbd_state ns, 12628c2ecf20Sopenharmony_ci enum chg_state_flags flags, struct completion *done) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device = first_peer_device(device); 12658c2ecf20Sopenharmony_ci struct drbd_connection *connection = peer_device ? peer_device->connection : NULL; 12668c2ecf20Sopenharmony_ci union drbd_state os; 12678c2ecf20Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 12688c2ecf20Sopenharmony_ci enum sanitize_state_warnings ssw; 12698c2ecf20Sopenharmony_ci struct after_state_chg_work *ascw; 12708c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci os = drbd_read_state(device); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci ns = sanitize_state(device, os, ns, &ssw); 12758c2ecf20Sopenharmony_ci if (ns.i == os.i) 12768c2ecf20Sopenharmony_ci return SS_NOTHING_TO_DO; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci rv = is_valid_transition(os, ns); 12798c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 12808c2ecf20Sopenharmony_ci return rv; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (!(flags & CS_HARD)) { 12838c2ecf20Sopenharmony_ci /* pre-state-change checks ; only look at ns */ 12848c2ecf20Sopenharmony_ci /* See drbd_state_sw_errors in drbd_strings.c */ 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci rv = is_valid_state(device, ns); 12878c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 12888c2ecf20Sopenharmony_ci /* If the old state was illegal as well, then let 12898c2ecf20Sopenharmony_ci this happen...*/ 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (is_valid_state(device, os) == rv) 12928c2ecf20Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 12938c2ecf20Sopenharmony_ci } else 12948c2ecf20Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 12988c2ecf20Sopenharmony_ci if (flags & CS_VERBOSE) 12998c2ecf20Sopenharmony_ci print_st_err(device, os, ns, rv); 13008c2ecf20Sopenharmony_ci return rv; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci print_sanitize_warnings(device, ssw); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci drbd_pr_state_change(device, os, ns, flags); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* Display changes to the susp* flags that where caused by the call to 13088c2ecf20Sopenharmony_ci sanitize_state(). Only display it here if we where not called from 13098c2ecf20Sopenharmony_ci _conn_request_state() */ 13108c2ecf20Sopenharmony_ci if (!(flags & CS_DC_SUSP)) 13118c2ecf20Sopenharmony_ci conn_pr_state_change(connection, os, ns, 13128c2ecf20Sopenharmony_ci (flags & ~CS_DC_MASK) | CS_DC_SUSP); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference 13158c2ecf20Sopenharmony_ci * on the ldev here, to be sure the transition -> D_DISKLESS resp. 13168c2ecf20Sopenharmony_ci * drbd_ldev_destroy() won't happen before our corresponding 13178c2ecf20Sopenharmony_ci * after_state_ch works run, where we put_ldev again. */ 13188c2ecf20Sopenharmony_ci if ((os.disk != D_FAILED && ns.disk == D_FAILED) || 13198c2ecf20Sopenharmony_ci (os.disk != D_DISKLESS && ns.disk == D_DISKLESS)) 13208c2ecf20Sopenharmony_ci atomic_inc(&device->local_cnt); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (!is_sync_state(os.conn) && is_sync_state(ns.conn)) 13238c2ecf20Sopenharmony_ci clear_bit(RS_DONE, &device->flags); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* FIXME: Have any flags been set earlier in this function already? */ 13268c2ecf20Sopenharmony_ci state_change = remember_old_state(device->resource, GFP_ATOMIC); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* changes to local_cnt and device flags should be visible before 13298c2ecf20Sopenharmony_ci * changes to state, which again should be visible before anything else 13308c2ecf20Sopenharmony_ci * depending on that change happens. */ 13318c2ecf20Sopenharmony_ci smp_wmb(); 13328c2ecf20Sopenharmony_ci device->state.i = ns.i; 13338c2ecf20Sopenharmony_ci device->resource->susp = ns.susp; 13348c2ecf20Sopenharmony_ci device->resource->susp_nod = ns.susp_nod; 13358c2ecf20Sopenharmony_ci device->resource->susp_fen = ns.susp_fen; 13368c2ecf20Sopenharmony_ci smp_wmb(); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci remember_new_state(state_change); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* put replicated vs not-replicated requests in seperate epochs */ 13418c2ecf20Sopenharmony_ci if (drbd_should_do_remote((union drbd_dev_state)os.i) != 13428c2ecf20Sopenharmony_ci drbd_should_do_remote((union drbd_dev_state)ns.i)) 13438c2ecf20Sopenharmony_ci start_new_tl_epoch(connection); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) 13468c2ecf20Sopenharmony_ci drbd_print_uuids(device, "attached to UUIDs"); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* Wake up role changes, that were delayed because of connection establishing */ 13498c2ecf20Sopenharmony_ci if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS && 13508c2ecf20Sopenharmony_ci no_peer_wf_report_params(connection)) { 13518c2ecf20Sopenharmony_ci clear_bit(STATE_SENT, &connection->flags); 13528c2ecf20Sopenharmony_ci wake_up_all_devices(connection); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci wake_up(&device->misc_wait); 13568c2ecf20Sopenharmony_ci wake_up(&device->state_wait); 13578c2ecf20Sopenharmony_ci wake_up(&connection->ping_wait); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Aborted verify run, or we reached the stop sector. 13608c2ecf20Sopenharmony_ci * Log the last position, unless end-of-device. */ 13618c2ecf20Sopenharmony_ci if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && 13628c2ecf20Sopenharmony_ci ns.conn <= C_CONNECTED) { 13638c2ecf20Sopenharmony_ci device->ov_start_sector = 13648c2ecf20Sopenharmony_ci BM_BIT_TO_SECT(drbd_bm_bits(device) - device->ov_left); 13658c2ecf20Sopenharmony_ci if (device->ov_left) 13668c2ecf20Sopenharmony_ci drbd_info(device, "Online Verify reached sector %llu\n", 13678c2ecf20Sopenharmony_ci (unsigned long long)device->ov_start_sector); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) && 13718c2ecf20Sopenharmony_ci (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) { 13728c2ecf20Sopenharmony_ci drbd_info(device, "Syncer continues.\n"); 13738c2ecf20Sopenharmony_ci device->rs_paused += (long)jiffies 13748c2ecf20Sopenharmony_ci -(long)device->rs_mark_time[device->rs_last_mark]; 13758c2ecf20Sopenharmony_ci if (ns.conn == C_SYNC_TARGET) 13768c2ecf20Sopenharmony_ci mod_timer(&device->resync_timer, jiffies); 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) && 13808c2ecf20Sopenharmony_ci (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) { 13818c2ecf20Sopenharmony_ci drbd_info(device, "Resync suspended\n"); 13828c2ecf20Sopenharmony_ci device->rs_mark_time[device->rs_last_mark] = jiffies; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (os.conn == C_CONNECTED && 13868c2ecf20Sopenharmony_ci (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) { 13878c2ecf20Sopenharmony_ci unsigned long now = jiffies; 13888c2ecf20Sopenharmony_ci int i; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci set_ov_position(device, ns.conn); 13918c2ecf20Sopenharmony_ci device->rs_start = now; 13928c2ecf20Sopenharmony_ci device->rs_last_sect_ev = 0; 13938c2ecf20Sopenharmony_ci device->ov_last_oos_size = 0; 13948c2ecf20Sopenharmony_ci device->ov_last_oos_start = 0; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci for (i = 0; i < DRBD_SYNC_MARKS; i++) { 13978c2ecf20Sopenharmony_ci device->rs_mark_left[i] = device->ov_left; 13988c2ecf20Sopenharmony_ci device->rs_mark_time[i] = now; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci drbd_rs_controller_reset(device); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci if (ns.conn == C_VERIFY_S) { 14048c2ecf20Sopenharmony_ci drbd_info(device, "Starting Online Verify from sector %llu\n", 14058c2ecf20Sopenharmony_ci (unsigned long long)device->ov_position); 14068c2ecf20Sopenharmony_ci mod_timer(&device->resync_timer, jiffies); 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (get_ldev(device)) { 14118c2ecf20Sopenharmony_ci u32 mdf = device->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND| 14128c2ecf20Sopenharmony_ci MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE| 14138c2ecf20Sopenharmony_ci MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci mdf &= ~MDF_AL_CLEAN; 14168c2ecf20Sopenharmony_ci if (test_bit(CRASHED_PRIMARY, &device->flags)) 14178c2ecf20Sopenharmony_ci mdf |= MDF_CRASHED_PRIMARY; 14188c2ecf20Sopenharmony_ci if (device->state.role == R_PRIMARY || 14198c2ecf20Sopenharmony_ci (device->state.pdsk < D_INCONSISTENT && device->state.peer == R_PRIMARY)) 14208c2ecf20Sopenharmony_ci mdf |= MDF_PRIMARY_IND; 14218c2ecf20Sopenharmony_ci if (device->state.conn > C_WF_REPORT_PARAMS) 14228c2ecf20Sopenharmony_ci mdf |= MDF_CONNECTED_IND; 14238c2ecf20Sopenharmony_ci if (device->state.disk > D_INCONSISTENT) 14248c2ecf20Sopenharmony_ci mdf |= MDF_CONSISTENT; 14258c2ecf20Sopenharmony_ci if (device->state.disk > D_OUTDATED) 14268c2ecf20Sopenharmony_ci mdf |= MDF_WAS_UP_TO_DATE; 14278c2ecf20Sopenharmony_ci if (device->state.pdsk <= D_OUTDATED && device->state.pdsk >= D_INCONSISTENT) 14288c2ecf20Sopenharmony_ci mdf |= MDF_PEER_OUT_DATED; 14298c2ecf20Sopenharmony_ci if (mdf != device->ldev->md.flags) { 14308c2ecf20Sopenharmony_ci device->ldev->md.flags = mdf; 14318c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT) 14348c2ecf20Sopenharmony_ci drbd_set_ed_uuid(device, device->ldev->md.uuid[UI_CURRENT]); 14358c2ecf20Sopenharmony_ci put_ldev(device); 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */ 14398c2ecf20Sopenharmony_ci if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT && 14408c2ecf20Sopenharmony_ci os.peer == R_SECONDARY && ns.peer == R_PRIMARY) 14418c2ecf20Sopenharmony_ci set_bit(CONSIDER_RESYNC, &device->flags); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci /* Receiver should clean up itself */ 14448c2ecf20Sopenharmony_ci if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING) 14458c2ecf20Sopenharmony_ci drbd_thread_stop_nowait(&connection->receiver); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* Now the receiver finished cleaning up itself, it should die */ 14488c2ecf20Sopenharmony_ci if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE) 14498c2ecf20Sopenharmony_ci drbd_thread_stop_nowait(&connection->receiver); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* Upon network failure, we need to restart the receiver. */ 14528c2ecf20Sopenharmony_ci if (os.conn > C_WF_CONNECTION && 14538c2ecf20Sopenharmony_ci ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) 14548c2ecf20Sopenharmony_ci drbd_thread_restart_nowait(&connection->receiver); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* Resume AL writing if we get a connection */ 14578c2ecf20Sopenharmony_ci if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { 14588c2ecf20Sopenharmony_ci drbd_resume_al(device); 14598c2ecf20Sopenharmony_ci connection->connect_cnt++; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /* remember last attach time so request_timer_fn() won't 14638c2ecf20Sopenharmony_ci * kill newly established sessions while we are still trying to thaw 14648c2ecf20Sopenharmony_ci * previously frozen IO */ 14658c2ecf20Sopenharmony_ci if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) && 14668c2ecf20Sopenharmony_ci ns.disk > D_NEGOTIATING) 14678c2ecf20Sopenharmony_ci device->last_reattach_jif = jiffies; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); 14708c2ecf20Sopenharmony_ci if (ascw) { 14718c2ecf20Sopenharmony_ci ascw->os = os; 14728c2ecf20Sopenharmony_ci ascw->ns = ns; 14738c2ecf20Sopenharmony_ci ascw->flags = flags; 14748c2ecf20Sopenharmony_ci ascw->w.cb = w_after_state_ch; 14758c2ecf20Sopenharmony_ci ascw->device = device; 14768c2ecf20Sopenharmony_ci ascw->done = done; 14778c2ecf20Sopenharmony_ci ascw->state_change = state_change; 14788c2ecf20Sopenharmony_ci drbd_queue_work(&connection->sender_work, 14798c2ecf20Sopenharmony_ci &ascw->w); 14808c2ecf20Sopenharmony_ci } else { 14818c2ecf20Sopenharmony_ci drbd_err(device, "Could not kmalloc an ascw\n"); 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return rv; 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_cistatic int w_after_state_ch(struct drbd_work *w, int unused) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci struct after_state_chg_work *ascw = 14908c2ecf20Sopenharmony_ci container_of(w, struct after_state_chg_work, w); 14918c2ecf20Sopenharmony_ci struct drbd_device *device = ascw->device; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci after_state_ch(device, ascw->os, ascw->ns, ascw->flags, ascw->state_change); 14948c2ecf20Sopenharmony_ci forget_state_change(ascw->state_change); 14958c2ecf20Sopenharmony_ci if (ascw->flags & CS_WAIT_COMPLETE) 14968c2ecf20Sopenharmony_ci complete(ascw->done); 14978c2ecf20Sopenharmony_ci kfree(ascw); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return 0; 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cistatic void abw_start_sync(struct drbd_device *device, int rv) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci if (rv) { 15058c2ecf20Sopenharmony_ci drbd_err(device, "Writing the bitmap failed not starting resync.\n"); 15068c2ecf20Sopenharmony_ci _drbd_request_state(device, NS(conn, C_CONNECTED), CS_VERBOSE); 15078c2ecf20Sopenharmony_ci return; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci switch (device->state.conn) { 15118c2ecf20Sopenharmony_ci case C_STARTING_SYNC_T: 15128c2ecf20Sopenharmony_ci _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); 15138c2ecf20Sopenharmony_ci break; 15148c2ecf20Sopenharmony_ci case C_STARTING_SYNC_S: 15158c2ecf20Sopenharmony_ci drbd_start_resync(device, C_SYNC_SOURCE); 15168c2ecf20Sopenharmony_ci break; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ciint drbd_bitmap_io_from_worker(struct drbd_device *device, 15218c2ecf20Sopenharmony_ci int (*io_fn)(struct drbd_device *), 15228c2ecf20Sopenharmony_ci char *why, enum bm_flag flags) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci int rv; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci D_ASSERT(device, current == first_peer_device(device)->connection->worker.task); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* open coded non-blocking drbd_suspend_io(device); */ 15298c2ecf20Sopenharmony_ci atomic_inc(&device->suspend_cnt); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci drbd_bm_lock(device, why, flags); 15328c2ecf20Sopenharmony_ci rv = io_fn(device); 15338c2ecf20Sopenharmony_ci drbd_bm_unlock(device); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci drbd_resume_io(device); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci return rv; 15388c2ecf20Sopenharmony_ci} 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ciint notify_resource_state_change(struct sk_buff *skb, 15418c2ecf20Sopenharmony_ci unsigned int seq, 15428c2ecf20Sopenharmony_ci struct drbd_resource_state_change *resource_state_change, 15438c2ecf20Sopenharmony_ci enum drbd_notification_type type) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci struct drbd_resource *resource = resource_state_change->resource; 15468c2ecf20Sopenharmony_ci struct resource_info resource_info = { 15478c2ecf20Sopenharmony_ci .res_role = resource_state_change->role[NEW], 15488c2ecf20Sopenharmony_ci .res_susp = resource_state_change->susp[NEW], 15498c2ecf20Sopenharmony_ci .res_susp_nod = resource_state_change->susp_nod[NEW], 15508c2ecf20Sopenharmony_ci .res_susp_fen = resource_state_change->susp_fen[NEW], 15518c2ecf20Sopenharmony_ci }; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci return notify_resource_state(skb, seq, resource, &resource_info, type); 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ciint notify_connection_state_change(struct sk_buff *skb, 15578c2ecf20Sopenharmony_ci unsigned int seq, 15588c2ecf20Sopenharmony_ci struct drbd_connection_state_change *connection_state_change, 15598c2ecf20Sopenharmony_ci enum drbd_notification_type type) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci struct drbd_connection *connection = connection_state_change->connection; 15628c2ecf20Sopenharmony_ci struct connection_info connection_info = { 15638c2ecf20Sopenharmony_ci .conn_connection_state = connection_state_change->cstate[NEW], 15648c2ecf20Sopenharmony_ci .conn_role = connection_state_change->peer_role[NEW], 15658c2ecf20Sopenharmony_ci }; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci return notify_connection_state(skb, seq, connection, &connection_info, type); 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ciint notify_device_state_change(struct sk_buff *skb, 15718c2ecf20Sopenharmony_ci unsigned int seq, 15728c2ecf20Sopenharmony_ci struct drbd_device_state_change *device_state_change, 15738c2ecf20Sopenharmony_ci enum drbd_notification_type type) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci struct drbd_device *device = device_state_change->device; 15768c2ecf20Sopenharmony_ci struct device_info device_info = { 15778c2ecf20Sopenharmony_ci .dev_disk_state = device_state_change->disk_state[NEW], 15788c2ecf20Sopenharmony_ci }; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci return notify_device_state(skb, seq, device, &device_info, type); 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ciint notify_peer_device_state_change(struct sk_buff *skb, 15848c2ecf20Sopenharmony_ci unsigned int seq, 15858c2ecf20Sopenharmony_ci struct drbd_peer_device_state_change *p, 15868c2ecf20Sopenharmony_ci enum drbd_notification_type type) 15878c2ecf20Sopenharmony_ci{ 15888c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device = p->peer_device; 15898c2ecf20Sopenharmony_ci struct peer_device_info peer_device_info = { 15908c2ecf20Sopenharmony_ci .peer_repl_state = p->repl_state[NEW], 15918c2ecf20Sopenharmony_ci .peer_disk_state = p->disk_state[NEW], 15928c2ecf20Sopenharmony_ci .peer_resync_susp_user = p->resync_susp_user[NEW], 15938c2ecf20Sopenharmony_ci .peer_resync_susp_peer = p->resync_susp_peer[NEW], 15948c2ecf20Sopenharmony_ci .peer_resync_susp_dependency = p->resync_susp_dependency[NEW], 15958c2ecf20Sopenharmony_ci }; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type); 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic void broadcast_state_change(struct drbd_state_change *state_change) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct drbd_resource_state_change *resource_state_change = &state_change->resource[0]; 16038c2ecf20Sopenharmony_ci bool resource_state_has_changed; 16048c2ecf20Sopenharmony_ci unsigned int n_device, n_connection, n_peer_device, n_peer_devices; 16058c2ecf20Sopenharmony_ci int (*last_func)(struct sk_buff *, unsigned int, void *, 16068c2ecf20Sopenharmony_ci enum drbd_notification_type) = NULL; 16078c2ecf20Sopenharmony_ci void *last_arg = NULL; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci#define HAS_CHANGED(state) ((state)[OLD] != (state)[NEW]) 16108c2ecf20Sopenharmony_ci#define FINAL_STATE_CHANGE(type) \ 16118c2ecf20Sopenharmony_ci ({ if (last_func) \ 16128c2ecf20Sopenharmony_ci last_func(NULL, 0, last_arg, type); \ 16138c2ecf20Sopenharmony_ci }) 16148c2ecf20Sopenharmony_ci#define REMEMBER_STATE_CHANGE(func, arg, type) \ 16158c2ecf20Sopenharmony_ci ({ FINAL_STATE_CHANGE(type | NOTIFY_CONTINUES); \ 16168c2ecf20Sopenharmony_ci last_func = (typeof(last_func))func; \ 16178c2ecf20Sopenharmony_ci last_arg = arg; \ 16188c2ecf20Sopenharmony_ci }) 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci resource_state_has_changed = 16238c2ecf20Sopenharmony_ci HAS_CHANGED(resource_state_change->role) || 16248c2ecf20Sopenharmony_ci HAS_CHANGED(resource_state_change->susp) || 16258c2ecf20Sopenharmony_ci HAS_CHANGED(resource_state_change->susp_nod) || 16268c2ecf20Sopenharmony_ci HAS_CHANGED(resource_state_change->susp_fen); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (resource_state_has_changed) 16298c2ecf20Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_resource_state_change, 16308c2ecf20Sopenharmony_ci resource_state_change, NOTIFY_CHANGE); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci for (n_connection = 0; n_connection < state_change->n_connections; n_connection++) { 16338c2ecf20Sopenharmony_ci struct drbd_connection_state_change *connection_state_change = 16348c2ecf20Sopenharmony_ci &state_change->connections[n_connection]; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (HAS_CHANGED(connection_state_change->peer_role) || 16378c2ecf20Sopenharmony_ci HAS_CHANGED(connection_state_change->cstate)) 16388c2ecf20Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_connection_state_change, 16398c2ecf20Sopenharmony_ci connection_state_change, NOTIFY_CHANGE); 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci for (n_device = 0; n_device < state_change->n_devices; n_device++) { 16438c2ecf20Sopenharmony_ci struct drbd_device_state_change *device_state_change = 16448c2ecf20Sopenharmony_ci &state_change->devices[n_device]; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (HAS_CHANGED(device_state_change->disk_state)) 16478c2ecf20Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_device_state_change, 16488c2ecf20Sopenharmony_ci device_state_change, NOTIFY_CHANGE); 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci n_peer_devices = state_change->n_devices * state_change->n_connections; 16528c2ecf20Sopenharmony_ci for (n_peer_device = 0; n_peer_device < n_peer_devices; n_peer_device++) { 16538c2ecf20Sopenharmony_ci struct drbd_peer_device_state_change *p = 16548c2ecf20Sopenharmony_ci &state_change->peer_devices[n_peer_device]; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (HAS_CHANGED(p->disk_state) || 16578c2ecf20Sopenharmony_ci HAS_CHANGED(p->repl_state) || 16588c2ecf20Sopenharmony_ci HAS_CHANGED(p->resync_susp_user) || 16598c2ecf20Sopenharmony_ci HAS_CHANGED(p->resync_susp_peer) || 16608c2ecf20Sopenharmony_ci HAS_CHANGED(p->resync_susp_dependency)) 16618c2ecf20Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_peer_device_state_change, 16628c2ecf20Sopenharmony_ci p, NOTIFY_CHANGE); 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci FINAL_STATE_CHANGE(NOTIFY_CHANGE); 16668c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci#undef HAS_CHANGED 16698c2ecf20Sopenharmony_ci#undef FINAL_STATE_CHANGE 16708c2ecf20Sopenharmony_ci#undef REMEMBER_STATE_CHANGE 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci/* takes old and new peer disk state */ 16748c2ecf20Sopenharmony_cistatic bool lost_contact_to_peer_data(enum drbd_disk_state os, enum drbd_disk_state ns) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci if ((os >= D_INCONSISTENT && os != D_UNKNOWN && os != D_OUTDATED) 16778c2ecf20Sopenharmony_ci && (ns < D_INCONSISTENT || ns == D_UNKNOWN || ns == D_OUTDATED)) 16788c2ecf20Sopenharmony_ci return true; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* Scenario, starting with normal operation 16818c2ecf20Sopenharmony_ci * Connected Primary/Secondary UpToDate/UpToDate 16828c2ecf20Sopenharmony_ci * NetworkFailure Primary/Unknown UpToDate/DUnknown (frozen) 16838c2ecf20Sopenharmony_ci * ... 16848c2ecf20Sopenharmony_ci * Connected Primary/Secondary UpToDate/Diskless (resumed; needs to bump uuid!) 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_ci if (os == D_UNKNOWN 16878c2ecf20Sopenharmony_ci && (ns == D_DISKLESS || ns == D_FAILED || ns == D_OUTDATED)) 16888c2ecf20Sopenharmony_ci return true; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci return false; 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci/** 16948c2ecf20Sopenharmony_ci * after_state_ch() - Perform after state change actions that may sleep 16958c2ecf20Sopenharmony_ci * @device: DRBD device. 16968c2ecf20Sopenharmony_ci * @os: old state. 16978c2ecf20Sopenharmony_ci * @ns: new state. 16988c2ecf20Sopenharmony_ci * @flags: Flags 16998c2ecf20Sopenharmony_ci */ 17008c2ecf20Sopenharmony_cistatic void after_state_ch(struct drbd_device *device, union drbd_state os, 17018c2ecf20Sopenharmony_ci union drbd_state ns, enum chg_state_flags flags, 17028c2ecf20Sopenharmony_ci struct drbd_state_change *state_change) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci struct drbd_resource *resource = device->resource; 17058c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device = first_peer_device(device); 17068c2ecf20Sopenharmony_ci struct drbd_connection *connection = peer_device ? peer_device->connection : NULL; 17078c2ecf20Sopenharmony_ci struct sib_info sib; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci broadcast_state_change(state_change); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci sib.sib_reason = SIB_STATE_CHANGE; 17128c2ecf20Sopenharmony_ci sib.os = os; 17138c2ecf20Sopenharmony_ci sib.ns = ns; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if ((os.disk != D_UP_TO_DATE || os.pdsk != D_UP_TO_DATE) 17168c2ecf20Sopenharmony_ci && (ns.disk == D_UP_TO_DATE && ns.pdsk == D_UP_TO_DATE)) { 17178c2ecf20Sopenharmony_ci clear_bit(CRASHED_PRIMARY, &device->flags); 17188c2ecf20Sopenharmony_ci if (device->p_uuid) 17198c2ecf20Sopenharmony_ci device->p_uuid[UI_FLAGS] &= ~((u64)2); 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci /* Inform userspace about the change... */ 17238c2ecf20Sopenharmony_ci drbd_bcast_event(device, &sib); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) && 17268c2ecf20Sopenharmony_ci (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)) 17278c2ecf20Sopenharmony_ci drbd_khelper(device, "pri-on-incon-degr"); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci /* Here we have the actions that are performed after a 17308c2ecf20Sopenharmony_ci state change. This function might sleep */ 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci if (ns.susp_nod) { 17338c2ecf20Sopenharmony_ci enum drbd_req_event what = NOTHING; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 17368c2ecf20Sopenharmony_ci if (os.conn < C_CONNECTED && conn_lowest_conn(connection) >= C_CONNECTED) 17378c2ecf20Sopenharmony_ci what = RESEND; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) && 17408c2ecf20Sopenharmony_ci conn_lowest_disk(connection) == D_UP_TO_DATE) 17418c2ecf20Sopenharmony_ci what = RESTART_FROZEN_DISK_IO; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci if (resource->susp_nod && what != NOTHING) { 17448c2ecf20Sopenharmony_ci _tl_restart(connection, what); 17458c2ecf20Sopenharmony_ci _conn_request_state(connection, 17468c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_nod = 1 } }, 17478c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_nod = 0 } }, 17488c2ecf20Sopenharmony_ci CS_VERBOSE); 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci if (ns.susp_fen) { 17548c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 17558c2ecf20Sopenharmony_ci if (resource->susp_fen && conn_lowest_conn(connection) >= C_CONNECTED) { 17568c2ecf20Sopenharmony_ci /* case2: The connection was established again: */ 17578c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 17588c2ecf20Sopenharmony_ci int vnr; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci rcu_read_lock(); 17618c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 17628c2ecf20Sopenharmony_ci clear_bit(NEW_CUR_UUID, &peer_device->device->flags); 17638c2ecf20Sopenharmony_ci rcu_read_unlock(); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* We should actively create a new uuid, _before_ 17668c2ecf20Sopenharmony_ci * we resume/resent, if the peer is diskless 17678c2ecf20Sopenharmony_ci * (recovery from a multiple error scenario). 17688c2ecf20Sopenharmony_ci * Currently, this happens with a slight delay 17698c2ecf20Sopenharmony_ci * below when checking lost_contact_to_peer_data() ... 17708c2ecf20Sopenharmony_ci */ 17718c2ecf20Sopenharmony_ci _tl_restart(connection, RESEND); 17728c2ecf20Sopenharmony_ci _conn_request_state(connection, 17738c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_fen = 1 } }, 17748c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_fen = 0 } }, 17758c2ecf20Sopenharmony_ci CS_VERBOSE); 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci /* Became sync source. With protocol >= 96, we still need to send out 17818c2ecf20Sopenharmony_ci * the sync uuid now. Need to do that before any drbd_send_state, or 17828c2ecf20Sopenharmony_ci * the other side may go "paused sync" before receiving the sync uuids, 17838c2ecf20Sopenharmony_ci * which is unexpected. */ 17848c2ecf20Sopenharmony_ci if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && 17858c2ecf20Sopenharmony_ci (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && 17868c2ecf20Sopenharmony_ci connection->agreed_pro_version >= 96 && get_ldev(device)) { 17878c2ecf20Sopenharmony_ci drbd_gen_and_send_sync_uuid(peer_device); 17888c2ecf20Sopenharmony_ci put_ldev(device); 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci /* Do not change the order of the if above and the two below... */ 17928c2ecf20Sopenharmony_ci if (os.pdsk == D_DISKLESS && 17938c2ecf20Sopenharmony_ci ns.pdsk > D_DISKLESS && ns.pdsk != D_UNKNOWN) { /* attach on the peer */ 17948c2ecf20Sopenharmony_ci /* we probably will start a resync soon. 17958c2ecf20Sopenharmony_ci * make sure those things are properly reset. */ 17968c2ecf20Sopenharmony_ci device->rs_total = 0; 17978c2ecf20Sopenharmony_ci device->rs_failed = 0; 17988c2ecf20Sopenharmony_ci atomic_set(&device->rs_pending_cnt, 0); 17998c2ecf20Sopenharmony_ci drbd_rs_cancel_all(device); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci drbd_send_uuids(peer_device); 18028c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci /* No point in queuing send_bitmap if we don't have a connection 18058c2ecf20Sopenharmony_ci * anymore, so check also the _current_ state, not only the new state 18068c2ecf20Sopenharmony_ci * at the time this work was queued. */ 18078c2ecf20Sopenharmony_ci if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && 18088c2ecf20Sopenharmony_ci device->state.conn == C_WF_BITMAP_S) 18098c2ecf20Sopenharmony_ci drbd_queue_bitmap_io(device, &drbd_send_bitmap, NULL, 18108c2ecf20Sopenharmony_ci "send_bitmap (WFBitMapS)", 18118c2ecf20Sopenharmony_ci BM_LOCKED_TEST_ALLOWED); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci /* Lost contact to peer's copy of the data */ 18148c2ecf20Sopenharmony_ci if (lost_contact_to_peer_data(os.pdsk, ns.pdsk)) { 18158c2ecf20Sopenharmony_ci if (get_ldev(device)) { 18168c2ecf20Sopenharmony_ci if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && 18178c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { 18188c2ecf20Sopenharmony_ci if (drbd_suspended(device)) { 18198c2ecf20Sopenharmony_ci set_bit(NEW_CUR_UUID, &device->flags); 18208c2ecf20Sopenharmony_ci } else { 18218c2ecf20Sopenharmony_ci drbd_uuid_new_current(device); 18228c2ecf20Sopenharmony_ci drbd_send_uuids(peer_device); 18238c2ecf20Sopenharmony_ci } 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci put_ldev(device); 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (ns.pdsk < D_INCONSISTENT && get_ldev(device)) { 18308c2ecf20Sopenharmony_ci if (os.peer != R_PRIMARY && ns.peer == R_PRIMARY && 18318c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { 18328c2ecf20Sopenharmony_ci drbd_uuid_new_current(device); 18338c2ecf20Sopenharmony_ci drbd_send_uuids(peer_device); 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci /* D_DISKLESS Peer becomes secondary */ 18368c2ecf20Sopenharmony_ci if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) 18378c2ecf20Sopenharmony_ci /* We may still be Primary ourselves. 18388c2ecf20Sopenharmony_ci * No harm done if the bitmap still changes, 18398c2ecf20Sopenharmony_ci * redirtied pages will follow later. */ 18408c2ecf20Sopenharmony_ci drbd_bitmap_io_from_worker(device, &drbd_bm_write, 18418c2ecf20Sopenharmony_ci "demote diskless peer", BM_LOCKED_SET_ALLOWED); 18428c2ecf20Sopenharmony_ci put_ldev(device); 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci /* Write out all changed bits on demote. 18468c2ecf20Sopenharmony_ci * Though, no need to da that just yet 18478c2ecf20Sopenharmony_ci * if there is a resync going on still */ 18488c2ecf20Sopenharmony_ci if (os.role == R_PRIMARY && ns.role == R_SECONDARY && 18498c2ecf20Sopenharmony_ci device->state.conn <= C_CONNECTED && get_ldev(device)) { 18508c2ecf20Sopenharmony_ci /* No changes to the bitmap expected this time, so assert that, 18518c2ecf20Sopenharmony_ci * even though no harm was done if it did change. */ 18528c2ecf20Sopenharmony_ci drbd_bitmap_io_from_worker(device, &drbd_bm_write, 18538c2ecf20Sopenharmony_ci "demote", BM_LOCKED_TEST_ALLOWED); 18548c2ecf20Sopenharmony_ci put_ldev(device); 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci /* Last part of the attaching process ... */ 18588c2ecf20Sopenharmony_ci if (ns.conn >= C_CONNECTED && 18598c2ecf20Sopenharmony_ci os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) { 18608c2ecf20Sopenharmony_ci drbd_send_sizes(peer_device, 0, 0); /* to start sync... */ 18618c2ecf20Sopenharmony_ci drbd_send_uuids(peer_device); 18628c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci /* We want to pause/continue resync, tell peer. */ 18668c2ecf20Sopenharmony_ci if (ns.conn >= C_CONNECTED && 18678c2ecf20Sopenharmony_ci ((os.aftr_isp != ns.aftr_isp) || 18688c2ecf20Sopenharmony_ci (os.user_isp != ns.user_isp))) 18698c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci /* In case one of the isp bits got set, suspend other devices. */ 18728c2ecf20Sopenharmony_ci if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) && 18738c2ecf20Sopenharmony_ci (ns.aftr_isp || ns.peer_isp || ns.user_isp)) 18748c2ecf20Sopenharmony_ci suspend_other_sg(device); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci /* Make sure the peer gets informed about eventual state 18778c2ecf20Sopenharmony_ci changes (ISP bits) while we were in WFReportParams. */ 18788c2ecf20Sopenharmony_ci if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) 18798c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (os.conn != C_AHEAD && ns.conn == C_AHEAD) 18828c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* We are in the progress to start a full sync... */ 18858c2ecf20Sopenharmony_ci if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || 18868c2ecf20Sopenharmony_ci (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) 18878c2ecf20Sopenharmony_ci /* no other bitmap changes expected during this phase */ 18888c2ecf20Sopenharmony_ci drbd_queue_bitmap_io(device, 18898c2ecf20Sopenharmony_ci &drbd_bmio_set_n_write, &abw_start_sync, 18908c2ecf20Sopenharmony_ci "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci /* first half of local IO error, failure to attach, 18938c2ecf20Sopenharmony_ci * or administrative detach */ 18948c2ecf20Sopenharmony_ci if (os.disk != D_FAILED && ns.disk == D_FAILED) { 18958c2ecf20Sopenharmony_ci enum drbd_io_error_p eh = EP_PASS_ON; 18968c2ecf20Sopenharmony_ci int was_io_error = 0; 18978c2ecf20Sopenharmony_ci /* corresponding get_ldev was in _drbd_set_state, to serialize 18988c2ecf20Sopenharmony_ci * our cleanup here with the transition to D_DISKLESS. 18998c2ecf20Sopenharmony_ci * But is is still not save to dreference ldev here, since 19008c2ecf20Sopenharmony_ci * we might come from an failed Attach before ldev was set. */ 19018c2ecf20Sopenharmony_ci if (device->ldev) { 19028c2ecf20Sopenharmony_ci rcu_read_lock(); 19038c2ecf20Sopenharmony_ci eh = rcu_dereference(device->ldev->disk_conf)->on_io_error; 19048c2ecf20Sopenharmony_ci rcu_read_unlock(); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci was_io_error = test_and_clear_bit(WAS_IO_ERROR, &device->flags); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* Intentionally call this handler first, before drbd_send_state(). 19098c2ecf20Sopenharmony_ci * See: 2932204 drbd: call local-io-error handler early 19108c2ecf20Sopenharmony_ci * People may chose to hard-reset the box from this handler. 19118c2ecf20Sopenharmony_ci * It is useful if this looks like a "regular node crash". */ 19128c2ecf20Sopenharmony_ci if (was_io_error && eh == EP_CALL_HELPER) 19138c2ecf20Sopenharmony_ci drbd_khelper(device, "local-io-error"); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci /* Immediately allow completion of all application IO, 19168c2ecf20Sopenharmony_ci * that waits for completion from the local disk, 19178c2ecf20Sopenharmony_ci * if this was a force-detach due to disk_timeout 19188c2ecf20Sopenharmony_ci * or administrator request (drbdsetup detach --force). 19198c2ecf20Sopenharmony_ci * Do NOT abort otherwise. 19208c2ecf20Sopenharmony_ci * Aborting local requests may cause serious problems, 19218c2ecf20Sopenharmony_ci * if requests are completed to upper layers already, 19228c2ecf20Sopenharmony_ci * and then later the already submitted local bio completes. 19238c2ecf20Sopenharmony_ci * This can cause DMA into former bio pages that meanwhile 19248c2ecf20Sopenharmony_ci * have been re-used for other things. 19258c2ecf20Sopenharmony_ci * So aborting local requests may cause crashes, 19268c2ecf20Sopenharmony_ci * or even worse, silent data corruption. 19278c2ecf20Sopenharmony_ci */ 19288c2ecf20Sopenharmony_ci if (test_and_clear_bit(FORCE_DETACH, &device->flags)) 19298c2ecf20Sopenharmony_ci tl_abort_disk_io(device); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* current state still has to be D_FAILED, 19328c2ecf20Sopenharmony_ci * there is only one way out: to D_DISKLESS, 19338c2ecf20Sopenharmony_ci * and that may only happen after our put_ldev below. */ 19348c2ecf20Sopenharmony_ci if (device->state.disk != D_FAILED) 19358c2ecf20Sopenharmony_ci drbd_err(device, 19368c2ecf20Sopenharmony_ci "ASSERT FAILED: disk is %s during detach\n", 19378c2ecf20Sopenharmony_ci drbd_disk_str(device->state.disk)); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (ns.conn >= C_CONNECTED) 19408c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci drbd_rs_cancel_all(device); 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci /* In case we want to get something to stable storage still, 19458c2ecf20Sopenharmony_ci * this may be the last chance. 19468c2ecf20Sopenharmony_ci * Following put_ldev may transition to D_DISKLESS. */ 19478c2ecf20Sopenharmony_ci drbd_md_sync(device); 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci put_ldev(device); 19508c2ecf20Sopenharmony_ci } 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci /* second half of local IO error, failure to attach, 19538c2ecf20Sopenharmony_ci * or administrative detach, 19548c2ecf20Sopenharmony_ci * after local_cnt references have reached zero again */ 19558c2ecf20Sopenharmony_ci if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) { 19568c2ecf20Sopenharmony_ci /* We must still be diskless, 19578c2ecf20Sopenharmony_ci * re-attach has to be serialized with this! */ 19588c2ecf20Sopenharmony_ci if (device->state.disk != D_DISKLESS) 19598c2ecf20Sopenharmony_ci drbd_err(device, 19608c2ecf20Sopenharmony_ci "ASSERT FAILED: disk is %s while going diskless\n", 19618c2ecf20Sopenharmony_ci drbd_disk_str(device->state.disk)); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (ns.conn >= C_CONNECTED) 19648c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 19658c2ecf20Sopenharmony_ci /* corresponding get_ldev in __drbd_set_state 19668c2ecf20Sopenharmony_ci * this may finally trigger drbd_ldev_destroy. */ 19678c2ecf20Sopenharmony_ci put_ldev(device); 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci /* Notify peer that I had a local IO error, and did not detached.. */ 19718c2ecf20Sopenharmony_ci if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT && ns.conn >= C_CONNECTED) 19728c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* Disks got bigger while they were detached */ 19758c2ecf20Sopenharmony_ci if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING && 19768c2ecf20Sopenharmony_ci test_and_clear_bit(RESYNC_AFTER_NEG, &device->flags)) { 19778c2ecf20Sopenharmony_ci if (ns.conn == C_CONNECTED) 19788c2ecf20Sopenharmony_ci resync_after_online_grow(device); 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci /* A resync finished or aborted, wake paused devices... */ 19828c2ecf20Sopenharmony_ci if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) || 19838c2ecf20Sopenharmony_ci (os.peer_isp && !ns.peer_isp) || 19848c2ecf20Sopenharmony_ci (os.user_isp && !ns.user_isp)) 19858c2ecf20Sopenharmony_ci resume_next_sg(device); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci /* sync target done with resync. Explicitly notify peer, even though 19888c2ecf20Sopenharmony_ci * it should (at least for non-empty resyncs) already know itself. */ 19898c2ecf20Sopenharmony_ci if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) 19908c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci /* Verify finished, or reached stop sector. Peer did not know about 19938c2ecf20Sopenharmony_ci * the stop sector, and we may even have changed the stop sector during 19948c2ecf20Sopenharmony_ci * verify to interrupt/stop early. Send the new state. */ 19958c2ecf20Sopenharmony_ci if (os.conn == C_VERIFY_S && ns.conn == C_CONNECTED 19968c2ecf20Sopenharmony_ci && verify_can_do_stop_sector(device)) 19978c2ecf20Sopenharmony_ci drbd_send_state(peer_device, ns); 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* This triggers bitmap writeout of potentially still unwritten pages 20008c2ecf20Sopenharmony_ci * if the resync finished cleanly, or aborted because of peer disk 20018c2ecf20Sopenharmony_ci * failure, or on transition from resync back to AHEAD/BEHIND. 20028c2ecf20Sopenharmony_ci * 20038c2ecf20Sopenharmony_ci * Connection loss is handled in drbd_disconnected() by the receiver. 20048c2ecf20Sopenharmony_ci * 20058c2ecf20Sopenharmony_ci * For resync aborted because of local disk failure, we cannot do 20068c2ecf20Sopenharmony_ci * any bitmap writeout anymore. 20078c2ecf20Sopenharmony_ci * 20088c2ecf20Sopenharmony_ci * No harm done if some bits change during this phase. 20098c2ecf20Sopenharmony_ci */ 20108c2ecf20Sopenharmony_ci if ((os.conn > C_CONNECTED && os.conn < C_AHEAD) && 20118c2ecf20Sopenharmony_ci (ns.conn == C_CONNECTED || ns.conn >= C_AHEAD) && get_ldev(device)) { 20128c2ecf20Sopenharmony_ci drbd_queue_bitmap_io(device, &drbd_bm_write_copy_pages, NULL, 20138c2ecf20Sopenharmony_ci "write from resync_finished", BM_LOCKED_CHANGE_ALLOWED); 20148c2ecf20Sopenharmony_ci put_ldev(device); 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (ns.disk == D_DISKLESS && 20188c2ecf20Sopenharmony_ci ns.conn == C_STANDALONE && 20198c2ecf20Sopenharmony_ci ns.role == R_SECONDARY) { 20208c2ecf20Sopenharmony_ci if (os.aftr_isp != ns.aftr_isp) 20218c2ecf20Sopenharmony_ci resume_next_sg(device); 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci drbd_md_sync(device); 20258c2ecf20Sopenharmony_ci} 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_cistruct after_conn_state_chg_work { 20288c2ecf20Sopenharmony_ci struct drbd_work w; 20298c2ecf20Sopenharmony_ci enum drbd_conns oc; 20308c2ecf20Sopenharmony_ci union drbd_state ns_min; 20318c2ecf20Sopenharmony_ci union drbd_state ns_max; /* new, max state, over all devices */ 20328c2ecf20Sopenharmony_ci enum chg_state_flags flags; 20338c2ecf20Sopenharmony_ci struct drbd_connection *connection; 20348c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 20358c2ecf20Sopenharmony_ci}; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_cistatic int w_after_conn_state_ch(struct drbd_work *w, int unused) 20388c2ecf20Sopenharmony_ci{ 20398c2ecf20Sopenharmony_ci struct after_conn_state_chg_work *acscw = 20408c2ecf20Sopenharmony_ci container_of(w, struct after_conn_state_chg_work, w); 20418c2ecf20Sopenharmony_ci struct drbd_connection *connection = acscw->connection; 20428c2ecf20Sopenharmony_ci enum drbd_conns oc = acscw->oc; 20438c2ecf20Sopenharmony_ci union drbd_state ns_max = acscw->ns_max; 20448c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 20458c2ecf20Sopenharmony_ci int vnr; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci broadcast_state_change(acscw->state_change); 20488c2ecf20Sopenharmony_ci forget_state_change(acscw->state_change); 20498c2ecf20Sopenharmony_ci kfree(acscw); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* Upon network configuration, we need to start the receiver */ 20528c2ecf20Sopenharmony_ci if (oc == C_STANDALONE && ns_max.conn == C_UNCONNECTED) 20538c2ecf20Sopenharmony_ci drbd_thread_start(&connection->receiver); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if (oc == C_DISCONNECTING && ns_max.conn == C_STANDALONE) { 20568c2ecf20Sopenharmony_ci struct net_conf *old_conf; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci mutex_lock(¬ification_mutex); 20598c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 20608c2ecf20Sopenharmony_ci notify_peer_device_state(NULL, 0, peer_device, NULL, 20618c2ecf20Sopenharmony_ci NOTIFY_DESTROY | NOTIFY_CONTINUES); 20628c2ecf20Sopenharmony_ci notify_connection_state(NULL, 0, connection, NULL, NOTIFY_DESTROY); 20638c2ecf20Sopenharmony_ci mutex_unlock(¬ification_mutex); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci mutex_lock(&connection->resource->conf_update); 20668c2ecf20Sopenharmony_ci old_conf = connection->net_conf; 20678c2ecf20Sopenharmony_ci connection->my_addr_len = 0; 20688c2ecf20Sopenharmony_ci connection->peer_addr_len = 0; 20698c2ecf20Sopenharmony_ci RCU_INIT_POINTER(connection->net_conf, NULL); 20708c2ecf20Sopenharmony_ci conn_free_crypto(connection); 20718c2ecf20Sopenharmony_ci mutex_unlock(&connection->resource->conf_update); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci synchronize_rcu(); 20748c2ecf20Sopenharmony_ci kfree(old_conf); 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci if (ns_max.susp_fen) { 20788c2ecf20Sopenharmony_ci /* case1: The outdate peer handler is successful: */ 20798c2ecf20Sopenharmony_ci if (ns_max.pdsk <= D_OUTDATED) { 20808c2ecf20Sopenharmony_ci rcu_read_lock(); 20818c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 20828c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 20838c2ecf20Sopenharmony_ci if (test_bit(NEW_CUR_UUID, &device->flags)) { 20848c2ecf20Sopenharmony_ci drbd_uuid_new_current(device); 20858c2ecf20Sopenharmony_ci clear_bit(NEW_CUR_UUID, &device->flags); 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci rcu_read_unlock(); 20898c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 20908c2ecf20Sopenharmony_ci _tl_restart(connection, CONNECTION_LOST_WHILE_PENDING); 20918c2ecf20Sopenharmony_ci _conn_request_state(connection, 20928c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_fen = 1 } }, 20938c2ecf20Sopenharmony_ci (union drbd_state) { { .susp_fen = 0 } }, 20948c2ecf20Sopenharmony_ci CS_VERBOSE); 20958c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci conn_md_sync(connection); 20998c2ecf20Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci return 0; 21028c2ecf20Sopenharmony_ci} 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_cistatic void conn_old_common_state(struct drbd_connection *connection, union drbd_state *pcs, enum chg_state_flags *pf) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci enum chg_state_flags flags = ~0; 21078c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 21088c2ecf20Sopenharmony_ci int vnr, first_vol = 1; 21098c2ecf20Sopenharmony_ci union drbd_dev_state os, cs = { 21108c2ecf20Sopenharmony_ci { .role = R_SECONDARY, 21118c2ecf20Sopenharmony_ci .peer = R_UNKNOWN, 21128c2ecf20Sopenharmony_ci .conn = connection->cstate, 21138c2ecf20Sopenharmony_ci .disk = D_DISKLESS, 21148c2ecf20Sopenharmony_ci .pdsk = D_UNKNOWN, 21158c2ecf20Sopenharmony_ci } }; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci rcu_read_lock(); 21188c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 21198c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 21208c2ecf20Sopenharmony_ci os = device->state; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (first_vol) { 21238c2ecf20Sopenharmony_ci cs = os; 21248c2ecf20Sopenharmony_ci first_vol = 0; 21258c2ecf20Sopenharmony_ci continue; 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci if (cs.role != os.role) 21298c2ecf20Sopenharmony_ci flags &= ~CS_DC_ROLE; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci if (cs.peer != os.peer) 21328c2ecf20Sopenharmony_ci flags &= ~CS_DC_PEER; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (cs.conn != os.conn) 21358c2ecf20Sopenharmony_ci flags &= ~CS_DC_CONN; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (cs.disk != os.disk) 21388c2ecf20Sopenharmony_ci flags &= ~CS_DC_DISK; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (cs.pdsk != os.pdsk) 21418c2ecf20Sopenharmony_ci flags &= ~CS_DC_PDSK; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci rcu_read_unlock(); 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci *pf |= CS_DC_MASK; 21468c2ecf20Sopenharmony_ci *pf &= flags; 21478c2ecf20Sopenharmony_ci (*pcs).i = cs.i; 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_cistatic enum drbd_state_rv 21518c2ecf20Sopenharmony_ciconn_is_valid_transition(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 21528c2ecf20Sopenharmony_ci enum chg_state_flags flags) 21538c2ecf20Sopenharmony_ci{ 21548c2ecf20Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 21558c2ecf20Sopenharmony_ci union drbd_state ns, os; 21568c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 21578c2ecf20Sopenharmony_ci int vnr; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci rcu_read_lock(); 21608c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 21618c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 21628c2ecf20Sopenharmony_ci os = drbd_read_state(device); 21638c2ecf20Sopenharmony_ci ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED) 21668c2ecf20Sopenharmony_ci ns.disk = os.disk; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci if (ns.i == os.i) 21698c2ecf20Sopenharmony_ci continue; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci rv = is_valid_transition(os, ns); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci if (rv >= SS_SUCCESS && !(flags & CS_HARD)) { 21748c2ecf20Sopenharmony_ci rv = is_valid_state(device, ns); 21758c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 21768c2ecf20Sopenharmony_ci if (is_valid_state(device, os) == rv) 21778c2ecf20Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 21788c2ecf20Sopenharmony_ci } else 21798c2ecf20Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 21808c2ecf20Sopenharmony_ci } 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) { 21838c2ecf20Sopenharmony_ci if (flags & CS_VERBOSE) 21848c2ecf20Sopenharmony_ci print_st_err(device, os, ns, rv); 21858c2ecf20Sopenharmony_ci break; 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci } 21888c2ecf20Sopenharmony_ci rcu_read_unlock(); 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci return rv; 21918c2ecf20Sopenharmony_ci} 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_cistatic void 21948c2ecf20Sopenharmony_ciconn_set_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 21958c2ecf20Sopenharmony_ci union drbd_state *pns_min, union drbd_state *pns_max, enum chg_state_flags flags) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci union drbd_state ns, os, ns_max = { }; 21988c2ecf20Sopenharmony_ci union drbd_state ns_min = { 21998c2ecf20Sopenharmony_ci { .role = R_MASK, 22008c2ecf20Sopenharmony_ci .peer = R_MASK, 22018c2ecf20Sopenharmony_ci .conn = val.conn, 22028c2ecf20Sopenharmony_ci .disk = D_MASK, 22038c2ecf20Sopenharmony_ci .pdsk = D_MASK 22048c2ecf20Sopenharmony_ci } }; 22058c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 22068c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 22078c2ecf20Sopenharmony_ci int vnr, number_of_volumes = 0; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci if (mask.conn == C_MASK) { 22108c2ecf20Sopenharmony_ci /* remember last connect time so request_timer_fn() won't 22118c2ecf20Sopenharmony_ci * kill newly established sessions while we are still trying to thaw 22128c2ecf20Sopenharmony_ci * previously frozen IO */ 22138c2ecf20Sopenharmony_ci if (connection->cstate != C_WF_REPORT_PARAMS && val.conn == C_WF_REPORT_PARAMS) 22148c2ecf20Sopenharmony_ci connection->last_reconnect_jif = jiffies; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci connection->cstate = val.conn; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci rcu_read_lock(); 22208c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 22218c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 22228c2ecf20Sopenharmony_ci number_of_volumes++; 22238c2ecf20Sopenharmony_ci os = drbd_read_state(device); 22248c2ecf20Sopenharmony_ci ns = apply_mask_val(os, mask, val); 22258c2ecf20Sopenharmony_ci ns = sanitize_state(device, os, ns, NULL); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED) 22288c2ecf20Sopenharmony_ci ns.disk = os.disk; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci rv = _drbd_set_state(device, ns, flags, NULL); 22318c2ecf20Sopenharmony_ci BUG_ON(rv < SS_SUCCESS); 22328c2ecf20Sopenharmony_ci ns.i = device->state.i; 22338c2ecf20Sopenharmony_ci ns_max.role = max_role(ns.role, ns_max.role); 22348c2ecf20Sopenharmony_ci ns_max.peer = max_role(ns.peer, ns_max.peer); 22358c2ecf20Sopenharmony_ci ns_max.conn = max_t(enum drbd_conns, ns.conn, ns_max.conn); 22368c2ecf20Sopenharmony_ci ns_max.disk = max_t(enum drbd_disk_state, ns.disk, ns_max.disk); 22378c2ecf20Sopenharmony_ci ns_max.pdsk = max_t(enum drbd_disk_state, ns.pdsk, ns_max.pdsk); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci ns_min.role = min_role(ns.role, ns_min.role); 22408c2ecf20Sopenharmony_ci ns_min.peer = min_role(ns.peer, ns_min.peer); 22418c2ecf20Sopenharmony_ci ns_min.conn = min_t(enum drbd_conns, ns.conn, ns_min.conn); 22428c2ecf20Sopenharmony_ci ns_min.disk = min_t(enum drbd_disk_state, ns.disk, ns_min.disk); 22438c2ecf20Sopenharmony_ci ns_min.pdsk = min_t(enum drbd_disk_state, ns.pdsk, ns_min.pdsk); 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci rcu_read_unlock(); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci if (number_of_volumes == 0) { 22488c2ecf20Sopenharmony_ci ns_min = ns_max = (union drbd_state) { { 22498c2ecf20Sopenharmony_ci .role = R_SECONDARY, 22508c2ecf20Sopenharmony_ci .peer = R_UNKNOWN, 22518c2ecf20Sopenharmony_ci .conn = val.conn, 22528c2ecf20Sopenharmony_ci .disk = D_DISKLESS, 22538c2ecf20Sopenharmony_ci .pdsk = D_UNKNOWN 22548c2ecf20Sopenharmony_ci } }; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci ns_min.susp = ns_max.susp = connection->resource->susp; 22588c2ecf20Sopenharmony_ci ns_min.susp_nod = ns_max.susp_nod = connection->resource->susp_nod; 22598c2ecf20Sopenharmony_ci ns_min.susp_fen = ns_max.susp_fen = connection->resource->susp_fen; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci *pns_min = ns_min; 22628c2ecf20Sopenharmony_ci *pns_max = ns_max; 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_cistatic enum drbd_state_rv 22668c2ecf20Sopenharmony_ci_conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union drbd_state val) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci enum drbd_state_rv err, rv = SS_UNKNOWN_ERROR; /* continue waiting */; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &connection->flags)) 22718c2ecf20Sopenharmony_ci rv = SS_CW_SUCCESS; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &connection->flags)) 22748c2ecf20Sopenharmony_ci rv = SS_CW_FAILED_BY_PEER; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci err = conn_is_valid_transition(connection, mask, val, 0); 22778c2ecf20Sopenharmony_ci if (err == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS) 22788c2ecf20Sopenharmony_ci return rv; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci return err; 22818c2ecf20Sopenharmony_ci} 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_cienum drbd_state_rv 22848c2ecf20Sopenharmony_ci_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 22858c2ecf20Sopenharmony_ci enum chg_state_flags flags) 22868c2ecf20Sopenharmony_ci{ 22878c2ecf20Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 22888c2ecf20Sopenharmony_ci struct after_conn_state_chg_work *acscw; 22898c2ecf20Sopenharmony_ci enum drbd_conns oc = connection->cstate; 22908c2ecf20Sopenharmony_ci union drbd_state ns_max, ns_min, os; 22918c2ecf20Sopenharmony_ci bool have_mutex = false; 22928c2ecf20Sopenharmony_ci struct drbd_state_change *state_change; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (mask.conn) { 22958c2ecf20Sopenharmony_ci rv = is_valid_conn_transition(oc, val.conn); 22968c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 22978c2ecf20Sopenharmony_ci goto abort; 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci rv = conn_is_valid_transition(connection, mask, val, flags); 23018c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 23028c2ecf20Sopenharmony_ci goto abort; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING && 23058c2ecf20Sopenharmony_ci !(flags & (CS_LOCAL_ONLY | CS_HARD))) { 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci /* This will be a cluster-wide state change. 23088c2ecf20Sopenharmony_ci * Need to give up the spinlock, grab the mutex, 23098c2ecf20Sopenharmony_ci * then send the state change request, ... */ 23108c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 23118c2ecf20Sopenharmony_ci mutex_lock(&connection->cstate_mutex); 23128c2ecf20Sopenharmony_ci have_mutex = true; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci set_bit(CONN_WD_ST_CHG_REQ, &connection->flags); 23158c2ecf20Sopenharmony_ci if (conn_send_state_req(connection, mask, val)) { 23168c2ecf20Sopenharmony_ci /* sending failed. */ 23178c2ecf20Sopenharmony_ci clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags); 23188c2ecf20Sopenharmony_ci rv = SS_CW_FAILED_BY_PEER; 23198c2ecf20Sopenharmony_ci /* need to re-aquire the spin lock, though */ 23208c2ecf20Sopenharmony_ci goto abort_unlocked; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci if (val.conn == C_DISCONNECTING) 23248c2ecf20Sopenharmony_ci set_bit(DISCONNECT_SENT, &connection->flags); 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci /* ... and re-aquire the spinlock. 23278c2ecf20Sopenharmony_ci * If _conn_rq_cond() returned >= SS_SUCCESS, we must call 23288c2ecf20Sopenharmony_ci * conn_set_state() within the same spinlock. */ 23298c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 23308c2ecf20Sopenharmony_ci wait_event_lock_irq(connection->ping_wait, 23318c2ecf20Sopenharmony_ci (rv = _conn_rq_cond(connection, mask, val)), 23328c2ecf20Sopenharmony_ci connection->resource->req_lock); 23338c2ecf20Sopenharmony_ci clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags); 23348c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS) 23358c2ecf20Sopenharmony_ci goto abort; 23368c2ecf20Sopenharmony_ci } 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci state_change = remember_old_state(connection->resource, GFP_ATOMIC); 23398c2ecf20Sopenharmony_ci conn_old_common_state(connection, &os, &flags); 23408c2ecf20Sopenharmony_ci flags |= CS_DC_SUSP; 23418c2ecf20Sopenharmony_ci conn_set_state(connection, mask, val, &ns_min, &ns_max, flags); 23428c2ecf20Sopenharmony_ci conn_pr_state_change(connection, os, ns_max, flags); 23438c2ecf20Sopenharmony_ci remember_new_state(state_change); 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC); 23468c2ecf20Sopenharmony_ci if (acscw) { 23478c2ecf20Sopenharmony_ci acscw->oc = os.conn; 23488c2ecf20Sopenharmony_ci acscw->ns_min = ns_min; 23498c2ecf20Sopenharmony_ci acscw->ns_max = ns_max; 23508c2ecf20Sopenharmony_ci acscw->flags = flags; 23518c2ecf20Sopenharmony_ci acscw->w.cb = w_after_conn_state_ch; 23528c2ecf20Sopenharmony_ci kref_get(&connection->kref); 23538c2ecf20Sopenharmony_ci acscw->connection = connection; 23548c2ecf20Sopenharmony_ci acscw->state_change = state_change; 23558c2ecf20Sopenharmony_ci drbd_queue_work(&connection->sender_work, &acscw->w); 23568c2ecf20Sopenharmony_ci } else { 23578c2ecf20Sopenharmony_ci drbd_err(connection, "Could not kmalloc an acscw\n"); 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci abort: 23618c2ecf20Sopenharmony_ci if (have_mutex) { 23628c2ecf20Sopenharmony_ci /* mutex_unlock() "... must not be used in interrupt context.", 23638c2ecf20Sopenharmony_ci * so give up the spinlock, then re-aquire it */ 23648c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 23658c2ecf20Sopenharmony_ci abort_unlocked: 23668c2ecf20Sopenharmony_ci mutex_unlock(&connection->cstate_mutex); 23678c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci if (rv < SS_SUCCESS && flags & CS_VERBOSE) { 23708c2ecf20Sopenharmony_ci drbd_err(connection, "State change failed: %s\n", drbd_set_st_err_str(rv)); 23718c2ecf20Sopenharmony_ci drbd_err(connection, " mask = 0x%x val = 0x%x\n", mask.i, val.i); 23728c2ecf20Sopenharmony_ci drbd_err(connection, " old_conn:%s wanted_conn:%s\n", drbd_conn_str(oc), drbd_conn_str(val.conn)); 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci return rv; 23758c2ecf20Sopenharmony_ci} 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cienum drbd_state_rv 23788c2ecf20Sopenharmony_ciconn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 23798c2ecf20Sopenharmony_ci enum chg_state_flags flags) 23808c2ecf20Sopenharmony_ci{ 23818c2ecf20Sopenharmony_ci enum drbd_state_rv rv; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 23848c2ecf20Sopenharmony_ci rv = _conn_request_state(connection, mask, val, flags); 23858c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci return rv; 23888c2ecf20Sopenharmony_ci} 2389