162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci drbd_state.c 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci This file is part of DRBD by Philipp Reisner and Lars Ellenberg. 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. 862306a36Sopenharmony_ci Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>. 962306a36Sopenharmony_ci Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev 1262306a36Sopenharmony_ci from Logicworks, Inc. for making SDP replication support possible. 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/drbd_limits.h> 1762306a36Sopenharmony_ci#include "drbd_int.h" 1862306a36Sopenharmony_ci#include "drbd_protocol.h" 1962306a36Sopenharmony_ci#include "drbd_req.h" 2062306a36Sopenharmony_ci#include "drbd_state_change.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct after_state_chg_work { 2362306a36Sopenharmony_ci struct drbd_work w; 2462306a36Sopenharmony_ci struct drbd_device *device; 2562306a36Sopenharmony_ci union drbd_state os; 2662306a36Sopenharmony_ci union drbd_state ns; 2762306a36Sopenharmony_ci enum chg_state_flags flags; 2862306a36Sopenharmony_ci struct completion *done; 2962306a36Sopenharmony_ci struct drbd_state_change *state_change; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cienum sanitize_state_warnings { 3362306a36Sopenharmony_ci NO_WARNING, 3462306a36Sopenharmony_ci ABORTED_ONLINE_VERIFY, 3562306a36Sopenharmony_ci ABORTED_RESYNC, 3662306a36Sopenharmony_ci CONNECTION_LOST_NEGOTIATING, 3762306a36Sopenharmony_ci IMPLICITLY_UPGRADED_DISK, 3862306a36Sopenharmony_ci IMPLICITLY_UPGRADED_PDSK, 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void count_objects(struct drbd_resource *resource, 4262306a36Sopenharmony_ci unsigned int *n_devices, 4362306a36Sopenharmony_ci unsigned int *n_connections) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct drbd_device *device; 4662306a36Sopenharmony_ci struct drbd_connection *connection; 4762306a36Sopenharmony_ci int vnr; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci *n_devices = 0; 5062306a36Sopenharmony_ci *n_connections = 0; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci idr_for_each_entry(&resource->devices, device, vnr) 5362306a36Sopenharmony_ci (*n_devices)++; 5462306a36Sopenharmony_ci for_each_connection(connection, resource) 5562306a36Sopenharmony_ci (*n_connections)++; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic struct drbd_state_change *alloc_state_change(unsigned int n_devices, unsigned int n_connections, gfp_t gfp) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct drbd_state_change *state_change; 6162306a36Sopenharmony_ci unsigned int size, n; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci size = sizeof(struct drbd_state_change) + 6462306a36Sopenharmony_ci n_devices * sizeof(struct drbd_device_state_change) + 6562306a36Sopenharmony_ci n_connections * sizeof(struct drbd_connection_state_change) + 6662306a36Sopenharmony_ci n_devices * n_connections * sizeof(struct drbd_peer_device_state_change); 6762306a36Sopenharmony_ci state_change = kmalloc(size, gfp); 6862306a36Sopenharmony_ci if (!state_change) 6962306a36Sopenharmony_ci return NULL; 7062306a36Sopenharmony_ci state_change->n_devices = n_devices; 7162306a36Sopenharmony_ci state_change->n_connections = n_connections; 7262306a36Sopenharmony_ci state_change->devices = (void *)(state_change + 1); 7362306a36Sopenharmony_ci state_change->connections = (void *)&state_change->devices[n_devices]; 7462306a36Sopenharmony_ci state_change->peer_devices = (void *)&state_change->connections[n_connections]; 7562306a36Sopenharmony_ci state_change->resource->resource = NULL; 7662306a36Sopenharmony_ci for (n = 0; n < n_devices; n++) 7762306a36Sopenharmony_ci state_change->devices[n].device = NULL; 7862306a36Sopenharmony_ci for (n = 0; n < n_connections; n++) 7962306a36Sopenharmony_ci state_change->connections[n].connection = NULL; 8062306a36Sopenharmony_ci return state_change; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct drbd_state_change *remember_old_state(struct drbd_resource *resource, gfp_t gfp) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct drbd_state_change *state_change; 8662306a36Sopenharmony_ci struct drbd_device *device; 8762306a36Sopenharmony_ci unsigned int n_devices; 8862306a36Sopenharmony_ci struct drbd_connection *connection; 8962306a36Sopenharmony_ci unsigned int n_connections; 9062306a36Sopenharmony_ci int vnr; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci struct drbd_device_state_change *device_state_change; 9362306a36Sopenharmony_ci struct drbd_peer_device_state_change *peer_device_state_change; 9462306a36Sopenharmony_ci struct drbd_connection_state_change *connection_state_change; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* Caller holds req_lock spinlock. 9762306a36Sopenharmony_ci * No state, no device IDR, no connections lists can change. */ 9862306a36Sopenharmony_ci count_objects(resource, &n_devices, &n_connections); 9962306a36Sopenharmony_ci state_change = alloc_state_change(n_devices, n_connections, gfp); 10062306a36Sopenharmony_ci if (!state_change) 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci kref_get(&resource->kref); 10462306a36Sopenharmony_ci state_change->resource->resource = resource; 10562306a36Sopenharmony_ci state_change->resource->role[OLD] = 10662306a36Sopenharmony_ci conn_highest_role(first_connection(resource)); 10762306a36Sopenharmony_ci state_change->resource->susp[OLD] = resource->susp; 10862306a36Sopenharmony_ci state_change->resource->susp_nod[OLD] = resource->susp_nod; 10962306a36Sopenharmony_ci state_change->resource->susp_fen[OLD] = resource->susp_fen; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci connection_state_change = state_change->connections; 11262306a36Sopenharmony_ci for_each_connection(connection, resource) { 11362306a36Sopenharmony_ci kref_get(&connection->kref); 11462306a36Sopenharmony_ci connection_state_change->connection = connection; 11562306a36Sopenharmony_ci connection_state_change->cstate[OLD] = 11662306a36Sopenharmony_ci connection->cstate; 11762306a36Sopenharmony_ci connection_state_change->peer_role[OLD] = 11862306a36Sopenharmony_ci conn_highest_peer(connection); 11962306a36Sopenharmony_ci connection_state_change++; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci device_state_change = state_change->devices; 12362306a36Sopenharmony_ci peer_device_state_change = state_change->peer_devices; 12462306a36Sopenharmony_ci idr_for_each_entry(&resource->devices, device, vnr) { 12562306a36Sopenharmony_ci kref_get(&device->kref); 12662306a36Sopenharmony_ci device_state_change->device = device; 12762306a36Sopenharmony_ci device_state_change->disk_state[OLD] = device->state.disk; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* The peer_devices for each device have to be enumerated in 13062306a36Sopenharmony_ci the order of the connections. We may not use for_each_peer_device() here. */ 13162306a36Sopenharmony_ci for_each_connection(connection, resource) { 13262306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci peer_device = conn_peer_device(connection, device->vnr); 13562306a36Sopenharmony_ci peer_device_state_change->peer_device = peer_device; 13662306a36Sopenharmony_ci peer_device_state_change->disk_state[OLD] = 13762306a36Sopenharmony_ci device->state.pdsk; 13862306a36Sopenharmony_ci peer_device_state_change->repl_state[OLD] = 13962306a36Sopenharmony_ci max_t(enum drbd_conns, 14062306a36Sopenharmony_ci C_WF_REPORT_PARAMS, device->state.conn); 14162306a36Sopenharmony_ci peer_device_state_change->resync_susp_user[OLD] = 14262306a36Sopenharmony_ci device->state.user_isp; 14362306a36Sopenharmony_ci peer_device_state_change->resync_susp_peer[OLD] = 14462306a36Sopenharmony_ci device->state.peer_isp; 14562306a36Sopenharmony_ci peer_device_state_change->resync_susp_dependency[OLD] = 14662306a36Sopenharmony_ci device->state.aftr_isp; 14762306a36Sopenharmony_ci peer_device_state_change++; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci device_state_change++; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return state_change; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void remember_new_state(struct drbd_state_change *state_change) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct drbd_resource_state_change *resource_state_change; 15862306a36Sopenharmony_ci struct drbd_resource *resource; 15962306a36Sopenharmony_ci unsigned int n; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!state_change) 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci resource_state_change = &state_change->resource[0]; 16562306a36Sopenharmony_ci resource = resource_state_change->resource; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci resource_state_change->role[NEW] = 16862306a36Sopenharmony_ci conn_highest_role(first_connection(resource)); 16962306a36Sopenharmony_ci resource_state_change->susp[NEW] = resource->susp; 17062306a36Sopenharmony_ci resource_state_change->susp_nod[NEW] = resource->susp_nod; 17162306a36Sopenharmony_ci resource_state_change->susp_fen[NEW] = resource->susp_fen; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci for (n = 0; n < state_change->n_devices; n++) { 17462306a36Sopenharmony_ci struct drbd_device_state_change *device_state_change = 17562306a36Sopenharmony_ci &state_change->devices[n]; 17662306a36Sopenharmony_ci struct drbd_device *device = device_state_change->device; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci device_state_change->disk_state[NEW] = device->state.disk; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci for (n = 0; n < state_change->n_connections; n++) { 18262306a36Sopenharmony_ci struct drbd_connection_state_change *connection_state_change = 18362306a36Sopenharmony_ci &state_change->connections[n]; 18462306a36Sopenharmony_ci struct drbd_connection *connection = 18562306a36Sopenharmony_ci connection_state_change->connection; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci connection_state_change->cstate[NEW] = connection->cstate; 18862306a36Sopenharmony_ci connection_state_change->peer_role[NEW] = 18962306a36Sopenharmony_ci conn_highest_peer(connection); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (n = 0; n < state_change->n_devices * state_change->n_connections; n++) { 19362306a36Sopenharmony_ci struct drbd_peer_device_state_change *peer_device_state_change = 19462306a36Sopenharmony_ci &state_change->peer_devices[n]; 19562306a36Sopenharmony_ci struct drbd_device *device = 19662306a36Sopenharmony_ci peer_device_state_change->peer_device->device; 19762306a36Sopenharmony_ci union drbd_dev_state state = device->state; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci peer_device_state_change->disk_state[NEW] = state.pdsk; 20062306a36Sopenharmony_ci peer_device_state_change->repl_state[NEW] = 20162306a36Sopenharmony_ci max_t(enum drbd_conns, C_WF_REPORT_PARAMS, state.conn); 20262306a36Sopenharmony_ci peer_device_state_change->resync_susp_user[NEW] = 20362306a36Sopenharmony_ci state.user_isp; 20462306a36Sopenharmony_ci peer_device_state_change->resync_susp_peer[NEW] = 20562306a36Sopenharmony_ci state.peer_isp; 20662306a36Sopenharmony_ci peer_device_state_change->resync_susp_dependency[NEW] = 20762306a36Sopenharmony_ci state.aftr_isp; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_civoid copy_old_to_new_state_change(struct drbd_state_change *state_change) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct drbd_resource_state_change *resource_state_change = &state_change->resource[0]; 21462306a36Sopenharmony_ci unsigned int n_device, n_connection, n_peer_device, n_peer_devices; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci#define OLD_TO_NEW(x) \ 21762306a36Sopenharmony_ci (x[NEW] = x[OLD]) 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci OLD_TO_NEW(resource_state_change->role); 22062306a36Sopenharmony_ci OLD_TO_NEW(resource_state_change->susp); 22162306a36Sopenharmony_ci OLD_TO_NEW(resource_state_change->susp_nod); 22262306a36Sopenharmony_ci OLD_TO_NEW(resource_state_change->susp_fen); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (n_connection = 0; n_connection < state_change->n_connections; n_connection++) { 22562306a36Sopenharmony_ci struct drbd_connection_state_change *connection_state_change = 22662306a36Sopenharmony_ci &state_change->connections[n_connection]; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci OLD_TO_NEW(connection_state_change->peer_role); 22962306a36Sopenharmony_ci OLD_TO_NEW(connection_state_change->cstate); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci for (n_device = 0; n_device < state_change->n_devices; n_device++) { 23362306a36Sopenharmony_ci struct drbd_device_state_change *device_state_change = 23462306a36Sopenharmony_ci &state_change->devices[n_device]; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci OLD_TO_NEW(device_state_change->disk_state); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci n_peer_devices = state_change->n_devices * state_change->n_connections; 24062306a36Sopenharmony_ci for (n_peer_device = 0; n_peer_device < n_peer_devices; n_peer_device++) { 24162306a36Sopenharmony_ci struct drbd_peer_device_state_change *p = 24262306a36Sopenharmony_ci &state_change->peer_devices[n_peer_device]; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci OLD_TO_NEW(p->disk_state); 24562306a36Sopenharmony_ci OLD_TO_NEW(p->repl_state); 24662306a36Sopenharmony_ci OLD_TO_NEW(p->resync_susp_user); 24762306a36Sopenharmony_ci OLD_TO_NEW(p->resync_susp_peer); 24862306a36Sopenharmony_ci OLD_TO_NEW(p->resync_susp_dependency); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#undef OLD_TO_NEW 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_civoid forget_state_change(struct drbd_state_change *state_change) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci unsigned int n; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!state_change) 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (state_change->resource->resource) 26262306a36Sopenharmony_ci kref_put(&state_change->resource->resource->kref, drbd_destroy_resource); 26362306a36Sopenharmony_ci for (n = 0; n < state_change->n_devices; n++) { 26462306a36Sopenharmony_ci struct drbd_device *device = state_change->devices[n].device; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (device) 26762306a36Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci for (n = 0; n < state_change->n_connections; n++) { 27062306a36Sopenharmony_ci struct drbd_connection *connection = 27162306a36Sopenharmony_ci state_change->connections[n].connection; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (connection) 27462306a36Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci kfree(state_change); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int w_after_state_ch(struct drbd_work *w, int unused); 28062306a36Sopenharmony_cistatic void after_state_ch(struct drbd_device *device, union drbd_state os, 28162306a36Sopenharmony_ci union drbd_state ns, enum chg_state_flags flags, 28262306a36Sopenharmony_ci struct drbd_state_change *); 28362306a36Sopenharmony_cistatic enum drbd_state_rv is_valid_state(struct drbd_device *, union drbd_state); 28462306a36Sopenharmony_cistatic enum drbd_state_rv is_valid_soft_transition(union drbd_state, union drbd_state, struct drbd_connection *); 28562306a36Sopenharmony_cistatic enum drbd_state_rv is_valid_transition(union drbd_state os, union drbd_state ns); 28662306a36Sopenharmony_cistatic union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os, 28762306a36Sopenharmony_ci union drbd_state ns, enum sanitize_state_warnings *warn); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic inline bool is_susp(union drbd_state s) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci return s.susp || s.susp_nod || s.susp_fen; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cibool conn_all_vols_unconf(struct drbd_connection *connection) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 29762306a36Sopenharmony_ci bool rv = true; 29862306a36Sopenharmony_ci int vnr; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci rcu_read_lock(); 30162306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 30262306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 30362306a36Sopenharmony_ci if (device->state.disk != D_DISKLESS || 30462306a36Sopenharmony_ci device->state.conn != C_STANDALONE || 30562306a36Sopenharmony_ci device->state.role != R_SECONDARY) { 30662306a36Sopenharmony_ci rv = false; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci rcu_read_unlock(); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return rv; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/* Unfortunately the states where not correctly ordered, when 31662306a36Sopenharmony_ci they where defined. therefore can not use max_t() here. */ 31762306a36Sopenharmony_cistatic enum drbd_role max_role(enum drbd_role role1, enum drbd_role role2) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci if (role1 == R_PRIMARY || role2 == R_PRIMARY) 32062306a36Sopenharmony_ci return R_PRIMARY; 32162306a36Sopenharmony_ci if (role1 == R_SECONDARY || role2 == R_SECONDARY) 32262306a36Sopenharmony_ci return R_SECONDARY; 32362306a36Sopenharmony_ci return R_UNKNOWN; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci if (role1 == R_UNKNOWN || role2 == R_UNKNOWN) 32962306a36Sopenharmony_ci return R_UNKNOWN; 33062306a36Sopenharmony_ci if (role1 == R_SECONDARY || role2 == R_SECONDARY) 33162306a36Sopenharmony_ci return R_SECONDARY; 33262306a36Sopenharmony_ci return R_PRIMARY; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cienum drbd_role conn_highest_role(struct drbd_connection *connection) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci enum drbd_role role = R_SECONDARY; 33862306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 33962306a36Sopenharmony_ci int vnr; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci rcu_read_lock(); 34262306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 34362306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 34462306a36Sopenharmony_ci role = max_role(role, device->state.role); 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci rcu_read_unlock(); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return role; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cienum drbd_role conn_highest_peer(struct drbd_connection *connection) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci enum drbd_role peer = R_UNKNOWN; 35462306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 35562306a36Sopenharmony_ci int vnr; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci rcu_read_lock(); 35862306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 35962306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 36062306a36Sopenharmony_ci peer = max_role(peer, device->state.peer); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci rcu_read_unlock(); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return peer; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cienum drbd_disk_state conn_highest_disk(struct drbd_connection *connection) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci enum drbd_disk_state disk_state = D_DISKLESS; 37062306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 37162306a36Sopenharmony_ci int vnr; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rcu_read_lock(); 37462306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 37562306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 37662306a36Sopenharmony_ci disk_state = max_t(enum drbd_disk_state, disk_state, device->state.disk); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci rcu_read_unlock(); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return disk_state; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cienum drbd_disk_state conn_lowest_disk(struct drbd_connection *connection) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci enum drbd_disk_state disk_state = D_MASK; 38662306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 38762306a36Sopenharmony_ci int vnr; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci rcu_read_lock(); 39062306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 39162306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 39262306a36Sopenharmony_ci disk_state = min_t(enum drbd_disk_state, disk_state, device->state.disk); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci rcu_read_unlock(); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return disk_state; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cienum drbd_disk_state conn_highest_pdsk(struct drbd_connection *connection) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci enum drbd_disk_state disk_state = D_DISKLESS; 40262306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 40362306a36Sopenharmony_ci int vnr; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci rcu_read_lock(); 40662306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 40762306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 40862306a36Sopenharmony_ci disk_state = max_t(enum drbd_disk_state, disk_state, device->state.pdsk); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci rcu_read_unlock(); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return disk_state; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cienum drbd_conns conn_lowest_conn(struct drbd_connection *connection) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci enum drbd_conns conn = C_MASK; 41862306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 41962306a36Sopenharmony_ci int vnr; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci rcu_read_lock(); 42262306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 42362306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 42462306a36Sopenharmony_ci conn = min_t(enum drbd_conns, conn, device->state.conn); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci rcu_read_unlock(); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return conn; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic bool no_peer_wf_report_params(struct drbd_connection *connection) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 43462306a36Sopenharmony_ci int vnr; 43562306a36Sopenharmony_ci bool rv = true; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci rcu_read_lock(); 43862306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 43962306a36Sopenharmony_ci if (peer_device->device->state.conn == C_WF_REPORT_PARAMS) { 44062306a36Sopenharmony_ci rv = false; 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci rcu_read_unlock(); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return rv; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void wake_up_all_devices(struct drbd_connection *connection) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 45162306a36Sopenharmony_ci int vnr; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci rcu_read_lock(); 45462306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 45562306a36Sopenharmony_ci wake_up(&peer_device->device->state_wait); 45662306a36Sopenharmony_ci rcu_read_unlock(); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/** 46262306a36Sopenharmony_ci * cl_wide_st_chg() - true if the state change is a cluster wide one 46362306a36Sopenharmony_ci * @device: DRBD device. 46462306a36Sopenharmony_ci * @os: old (current) state. 46562306a36Sopenharmony_ci * @ns: new (wanted) state. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_cistatic int cl_wide_st_chg(struct drbd_device *device, 46862306a36Sopenharmony_ci union drbd_state os, union drbd_state ns) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED && 47162306a36Sopenharmony_ci ((os.role != R_PRIMARY && ns.role == R_PRIMARY) || 47262306a36Sopenharmony_ci (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || 47362306a36Sopenharmony_ci (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) || 47462306a36Sopenharmony_ci (os.disk != D_FAILED && ns.disk == D_FAILED))) || 47562306a36Sopenharmony_ci (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) || 47662306a36Sopenharmony_ci (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S) || 47762306a36Sopenharmony_ci (os.conn == C_CONNECTED && ns.conn == C_WF_REPORT_PARAMS); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic union drbd_state 48162306a36Sopenharmony_ciapply_mask_val(union drbd_state os, union drbd_state mask, union drbd_state val) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci union drbd_state ns; 48462306a36Sopenharmony_ci ns.i = (os.i & ~mask.i) | val.i; 48562306a36Sopenharmony_ci return ns; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cienum drbd_state_rv 48962306a36Sopenharmony_cidrbd_change_state(struct drbd_device *device, enum chg_state_flags f, 49062306a36Sopenharmony_ci union drbd_state mask, union drbd_state val) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci unsigned long flags; 49362306a36Sopenharmony_ci union drbd_state ns; 49462306a36Sopenharmony_ci enum drbd_state_rv rv; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 49762306a36Sopenharmony_ci ns = apply_mask_val(drbd_read_state(device), mask, val); 49862306a36Sopenharmony_ci rv = _drbd_set_state(device, ns, f, NULL); 49962306a36Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return rv; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/** 50562306a36Sopenharmony_ci * drbd_force_state() - Impose a change which happens outside our control on our state 50662306a36Sopenharmony_ci * @device: DRBD device. 50762306a36Sopenharmony_ci * @mask: mask of state bits to change. 50862306a36Sopenharmony_ci * @val: value of new state bits. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_civoid drbd_force_state(struct drbd_device *device, 51162306a36Sopenharmony_ci union drbd_state mask, union drbd_state val) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci drbd_change_state(device, CS_HARD, mask, val); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic enum drbd_state_rv 51762306a36Sopenharmony_ci_req_st_cond(struct drbd_device *device, union drbd_state mask, 51862306a36Sopenharmony_ci union drbd_state val) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci union drbd_state os, ns; 52162306a36Sopenharmony_ci unsigned long flags; 52262306a36Sopenharmony_ci enum drbd_state_rv rv; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &device->flags)) 52562306a36Sopenharmony_ci return SS_CW_SUCCESS; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (test_and_clear_bit(CL_ST_CHG_FAIL, &device->flags)) 52862306a36Sopenharmony_ci return SS_CW_FAILED_BY_PEER; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 53162306a36Sopenharmony_ci os = drbd_read_state(device); 53262306a36Sopenharmony_ci ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); 53362306a36Sopenharmony_ci rv = is_valid_transition(os, ns); 53462306a36Sopenharmony_ci if (rv >= SS_SUCCESS) 53562306a36Sopenharmony_ci rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (!cl_wide_st_chg(device, os, ns)) 53862306a36Sopenharmony_ci rv = SS_CW_NO_NEED; 53962306a36Sopenharmony_ci if (rv == SS_UNKNOWN_ERROR) { 54062306a36Sopenharmony_ci rv = is_valid_state(device, ns); 54162306a36Sopenharmony_ci if (rv >= SS_SUCCESS) { 54262306a36Sopenharmony_ci rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection); 54362306a36Sopenharmony_ci if (rv >= SS_SUCCESS) 54462306a36Sopenharmony_ci rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return rv; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/** 55362306a36Sopenharmony_ci * drbd_req_state() - Perform an eventually cluster wide state change 55462306a36Sopenharmony_ci * @device: DRBD device. 55562306a36Sopenharmony_ci * @mask: mask of state bits to change. 55662306a36Sopenharmony_ci * @val: value of new state bits. 55762306a36Sopenharmony_ci * @f: flags 55862306a36Sopenharmony_ci * 55962306a36Sopenharmony_ci * Should not be called directly, use drbd_request_state() or 56062306a36Sopenharmony_ci * _drbd_request_state(). 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_cistatic enum drbd_state_rv 56362306a36Sopenharmony_cidrbd_req_state(struct drbd_device *device, union drbd_state mask, 56462306a36Sopenharmony_ci union drbd_state val, enum chg_state_flags f) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct completion done; 56762306a36Sopenharmony_ci unsigned long flags; 56862306a36Sopenharmony_ci union drbd_state os, ns; 56962306a36Sopenharmony_ci enum drbd_state_rv rv; 57062306a36Sopenharmony_ci void *buffer = NULL; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci init_completion(&done); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (f & CS_SERIALIZE) 57562306a36Sopenharmony_ci mutex_lock(device->state_mutex); 57662306a36Sopenharmony_ci if (f & CS_INHIBIT_MD_IO) 57762306a36Sopenharmony_ci buffer = drbd_md_get_buffer(device, __func__); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 58062306a36Sopenharmony_ci os = drbd_read_state(device); 58162306a36Sopenharmony_ci ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); 58262306a36Sopenharmony_ci rv = is_valid_transition(os, ns); 58362306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 58462306a36Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 58562306a36Sopenharmony_ci goto abort; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (cl_wide_st_chg(device, os, ns)) { 58962306a36Sopenharmony_ci rv = is_valid_state(device, ns); 59062306a36Sopenharmony_ci if (rv == SS_SUCCESS) 59162306a36Sopenharmony_ci rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection); 59262306a36Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 59562306a36Sopenharmony_ci if (f & CS_VERBOSE) 59662306a36Sopenharmony_ci print_st_err(device, os, ns, rv); 59762306a36Sopenharmony_ci goto abort; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (drbd_send_state_req(first_peer_device(device), mask, val)) { 60162306a36Sopenharmony_ci rv = SS_CW_FAILED_BY_PEER; 60262306a36Sopenharmony_ci if (f & CS_VERBOSE) 60362306a36Sopenharmony_ci print_st_err(device, os, ns, rv); 60462306a36Sopenharmony_ci goto abort; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci wait_event(device->state_wait, 60862306a36Sopenharmony_ci (rv = _req_st_cond(device, mask, val))); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 61162306a36Sopenharmony_ci if (f & CS_VERBOSE) 61262306a36Sopenharmony_ci print_st_err(device, os, ns, rv); 61362306a36Sopenharmony_ci goto abort; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 61662306a36Sopenharmony_ci ns = apply_mask_val(drbd_read_state(device), mask, val); 61762306a36Sopenharmony_ci rv = _drbd_set_state(device, ns, f, &done); 61862306a36Sopenharmony_ci } else { 61962306a36Sopenharmony_ci rv = _drbd_set_state(device, ns, f, &done); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) { 62562306a36Sopenharmony_ci D_ASSERT(device, current != first_peer_device(device)->connection->worker.task); 62662306a36Sopenharmony_ci wait_for_completion(&done); 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ciabort: 63062306a36Sopenharmony_ci if (buffer) 63162306a36Sopenharmony_ci drbd_md_put_buffer(device); 63262306a36Sopenharmony_ci if (f & CS_SERIALIZE) 63362306a36Sopenharmony_ci mutex_unlock(device->state_mutex); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return rv; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci/** 63962306a36Sopenharmony_ci * _drbd_request_state() - Request a state change (with flags) 64062306a36Sopenharmony_ci * @device: DRBD device. 64162306a36Sopenharmony_ci * @mask: mask of state bits to change. 64262306a36Sopenharmony_ci * @val: value of new state bits. 64362306a36Sopenharmony_ci * @f: flags 64462306a36Sopenharmony_ci * 64562306a36Sopenharmony_ci * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE 64662306a36Sopenharmony_ci * flag, or when logging of failed state change requests is not desired. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cienum drbd_state_rv 64962306a36Sopenharmony_ci_drbd_request_state(struct drbd_device *device, union drbd_state mask, 65062306a36Sopenharmony_ci union drbd_state val, enum chg_state_flags f) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci enum drbd_state_rv rv; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci wait_event(device->state_wait, 65562306a36Sopenharmony_ci (rv = drbd_req_state(device, mask, val, f)) != SS_IN_TRANSIENT_STATE); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return rv; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci/* 66162306a36Sopenharmony_ci * We grab drbd_md_get_buffer(), because we don't want to "fail" the disk while 66262306a36Sopenharmony_ci * there is IO in-flight: the transition into D_FAILED for detach purposes 66362306a36Sopenharmony_ci * may get misinterpreted as actual IO error in a confused endio function. 66462306a36Sopenharmony_ci * 66562306a36Sopenharmony_ci * We wrap it all into wait_event(), to retry in case the drbd_req_state() 66662306a36Sopenharmony_ci * returns SS_IN_TRANSIENT_STATE. 66762306a36Sopenharmony_ci * 66862306a36Sopenharmony_ci * To avoid potential deadlock with e.g. the receiver thread trying to grab 66962306a36Sopenharmony_ci * drbd_md_get_buffer() while trying to get out of the "transient state", we 67062306a36Sopenharmony_ci * need to grab and release the meta data buffer inside of that wait_event loop. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_cistatic enum drbd_state_rv 67362306a36Sopenharmony_cirequest_detach(struct drbd_device *device) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci return drbd_req_state(device, NS(disk, D_FAILED), 67662306a36Sopenharmony_ci CS_VERBOSE | CS_ORDERED | CS_INHIBIT_MD_IO); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ciint drbd_request_detach_interruptible(struct drbd_device *device) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci int ret, rv; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci drbd_suspend_io(device); /* so no-one is stuck in drbd_al_begin_io */ 68462306a36Sopenharmony_ci wait_event_interruptible(device->state_wait, 68562306a36Sopenharmony_ci (rv = request_detach(device)) != SS_IN_TRANSIENT_STATE); 68662306a36Sopenharmony_ci drbd_resume_io(device); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci ret = wait_event_interruptible(device->misc_wait, 68962306a36Sopenharmony_ci device->state.disk != D_FAILED); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (rv == SS_IS_DISKLESS) 69262306a36Sopenharmony_ci rv = SS_NOTHING_TO_DO; 69362306a36Sopenharmony_ci if (ret) 69462306a36Sopenharmony_ci rv = ERR_INTR; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return rv; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cienum drbd_state_rv 70062306a36Sopenharmony_ci_drbd_request_state_holding_state_mutex(struct drbd_device *device, union drbd_state mask, 70162306a36Sopenharmony_ci union drbd_state val, enum chg_state_flags f) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci enum drbd_state_rv rv; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci BUG_ON(f & CS_SERIALIZE); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci wait_event_cmd(device->state_wait, 70862306a36Sopenharmony_ci (rv = drbd_req_state(device, mask, val, f)) != SS_IN_TRANSIENT_STATE, 70962306a36Sopenharmony_ci mutex_unlock(device->state_mutex), 71062306a36Sopenharmony_ci mutex_lock(device->state_mutex)); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return rv; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic void print_st(struct drbd_device *device, const char *name, union drbd_state ns) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci drbd_err(device, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n", 71862306a36Sopenharmony_ci name, 71962306a36Sopenharmony_ci drbd_conn_str(ns.conn), 72062306a36Sopenharmony_ci drbd_role_str(ns.role), 72162306a36Sopenharmony_ci drbd_role_str(ns.peer), 72262306a36Sopenharmony_ci drbd_disk_str(ns.disk), 72362306a36Sopenharmony_ci drbd_disk_str(ns.pdsk), 72462306a36Sopenharmony_ci is_susp(ns) ? 's' : 'r', 72562306a36Sopenharmony_ci ns.aftr_isp ? 'a' : '-', 72662306a36Sopenharmony_ci ns.peer_isp ? 'p' : '-', 72762306a36Sopenharmony_ci ns.user_isp ? 'u' : '-', 72862306a36Sopenharmony_ci ns.susp_fen ? 'F' : '-', 72962306a36Sopenharmony_ci ns.susp_nod ? 'N' : '-' 73062306a36Sopenharmony_ci ); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_civoid print_st_err(struct drbd_device *device, union drbd_state os, 73462306a36Sopenharmony_ci union drbd_state ns, enum drbd_state_rv err) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci if (err == SS_IN_TRANSIENT_STATE) 73762306a36Sopenharmony_ci return; 73862306a36Sopenharmony_ci drbd_err(device, "State change failed: %s\n", drbd_set_st_err_str(err)); 73962306a36Sopenharmony_ci print_st(device, " state", os); 74062306a36Sopenharmony_ci print_st(device, "wanted", ns); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic long print_state_change(char *pb, union drbd_state os, union drbd_state ns, 74462306a36Sopenharmony_ci enum chg_state_flags flags) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci char *pbp; 74762306a36Sopenharmony_ci pbp = pb; 74862306a36Sopenharmony_ci *pbp = 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (ns.role != os.role && flags & CS_DC_ROLE) 75162306a36Sopenharmony_ci pbp += sprintf(pbp, "role( %s -> %s ) ", 75262306a36Sopenharmony_ci drbd_role_str(os.role), 75362306a36Sopenharmony_ci drbd_role_str(ns.role)); 75462306a36Sopenharmony_ci if (ns.peer != os.peer && flags & CS_DC_PEER) 75562306a36Sopenharmony_ci pbp += sprintf(pbp, "peer( %s -> %s ) ", 75662306a36Sopenharmony_ci drbd_role_str(os.peer), 75762306a36Sopenharmony_ci drbd_role_str(ns.peer)); 75862306a36Sopenharmony_ci if (ns.conn != os.conn && flags & CS_DC_CONN) 75962306a36Sopenharmony_ci pbp += sprintf(pbp, "conn( %s -> %s ) ", 76062306a36Sopenharmony_ci drbd_conn_str(os.conn), 76162306a36Sopenharmony_ci drbd_conn_str(ns.conn)); 76262306a36Sopenharmony_ci if (ns.disk != os.disk && flags & CS_DC_DISK) 76362306a36Sopenharmony_ci pbp += sprintf(pbp, "disk( %s -> %s ) ", 76462306a36Sopenharmony_ci drbd_disk_str(os.disk), 76562306a36Sopenharmony_ci drbd_disk_str(ns.disk)); 76662306a36Sopenharmony_ci if (ns.pdsk != os.pdsk && flags & CS_DC_PDSK) 76762306a36Sopenharmony_ci pbp += sprintf(pbp, "pdsk( %s -> %s ) ", 76862306a36Sopenharmony_ci drbd_disk_str(os.pdsk), 76962306a36Sopenharmony_ci drbd_disk_str(ns.pdsk)); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return pbp - pb; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic void drbd_pr_state_change(struct drbd_device *device, union drbd_state os, union drbd_state ns, 77562306a36Sopenharmony_ci enum chg_state_flags flags) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci char pb[300]; 77862306a36Sopenharmony_ci char *pbp = pb; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci pbp += print_state_change(pbp, os, ns, flags ^ CS_DC_MASK); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (ns.aftr_isp != os.aftr_isp) 78362306a36Sopenharmony_ci pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", 78462306a36Sopenharmony_ci os.aftr_isp, 78562306a36Sopenharmony_ci ns.aftr_isp); 78662306a36Sopenharmony_ci if (ns.peer_isp != os.peer_isp) 78762306a36Sopenharmony_ci pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", 78862306a36Sopenharmony_ci os.peer_isp, 78962306a36Sopenharmony_ci ns.peer_isp); 79062306a36Sopenharmony_ci if (ns.user_isp != os.user_isp) 79162306a36Sopenharmony_ci pbp += sprintf(pbp, "user_isp( %d -> %d ) ", 79262306a36Sopenharmony_ci os.user_isp, 79362306a36Sopenharmony_ci ns.user_isp); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (pbp != pb) 79662306a36Sopenharmony_ci drbd_info(device, "%s\n", pb); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic void conn_pr_state_change(struct drbd_connection *connection, union drbd_state os, union drbd_state ns, 80062306a36Sopenharmony_ci enum chg_state_flags flags) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci char pb[300]; 80362306a36Sopenharmony_ci char *pbp = pb; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci pbp += print_state_change(pbp, os, ns, flags); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (is_susp(ns) != is_susp(os) && flags & CS_DC_SUSP) 80862306a36Sopenharmony_ci pbp += sprintf(pbp, "susp( %d -> %d ) ", 80962306a36Sopenharmony_ci is_susp(os), 81062306a36Sopenharmony_ci is_susp(ns)); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (pbp != pb) 81362306a36Sopenharmony_ci drbd_info(connection, "%s\n", pb); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/** 81862306a36Sopenharmony_ci * is_valid_state() - Returns an SS_ error code if ns is not valid 81962306a36Sopenharmony_ci * @device: DRBD device. 82062306a36Sopenharmony_ci * @ns: State to consider. 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_cistatic enum drbd_state_rv 82362306a36Sopenharmony_ciis_valid_state(struct drbd_device *device, union drbd_state ns) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci /* See drbd_state_sw_errors in drbd_strings.c */ 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci enum drbd_fencing_p fp; 82862306a36Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 82962306a36Sopenharmony_ci struct net_conf *nc; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci rcu_read_lock(); 83262306a36Sopenharmony_ci fp = FP_DONT_CARE; 83362306a36Sopenharmony_ci if (get_ldev(device)) { 83462306a36Sopenharmony_ci fp = rcu_dereference(device->ldev->disk_conf)->fencing; 83562306a36Sopenharmony_ci put_ldev(device); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci nc = rcu_dereference(first_peer_device(device)->connection->net_conf); 83962306a36Sopenharmony_ci if (nc) { 84062306a36Sopenharmony_ci if (!nc->two_primaries && ns.role == R_PRIMARY) { 84162306a36Sopenharmony_ci if (ns.peer == R_PRIMARY) 84262306a36Sopenharmony_ci rv = SS_TWO_PRIMARIES; 84362306a36Sopenharmony_ci else if (conn_highest_peer(first_peer_device(device)->connection) == R_PRIMARY) 84462306a36Sopenharmony_ci rv = SS_O_VOL_PEER_PRI; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (rv <= 0) 84962306a36Sopenharmony_ci goto out; /* already found a reason to abort */ 85062306a36Sopenharmony_ci else if (ns.role == R_SECONDARY && device->open_cnt) 85162306a36Sopenharmony_ci rv = SS_DEVICE_IN_USE; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE) 85462306a36Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci else if (fp >= FP_RESOURCE && 85762306a36Sopenharmony_ci ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN) 85862306a36Sopenharmony_ci rv = SS_PRIMARY_NOP; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT) 86162306a36Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT) 86462306a36Sopenharmony_ci rv = SS_NO_LOCAL_DISK; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT) 86762306a36Sopenharmony_ci rv = SS_NO_REMOTE_DISK; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci else if (ns.conn > C_CONNECTED && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) 87062306a36Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci else if ((ns.conn == C_CONNECTED || 87362306a36Sopenharmony_ci ns.conn == C_WF_BITMAP_S || 87462306a36Sopenharmony_ci ns.conn == C_SYNC_SOURCE || 87562306a36Sopenharmony_ci ns.conn == C_PAUSED_SYNC_S) && 87662306a36Sopenharmony_ci ns.disk == D_OUTDATED) 87762306a36Sopenharmony_ci rv = SS_CONNECTED_OUTDATES; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && 88062306a36Sopenharmony_ci (nc->verify_alg[0] == 0)) 88162306a36Sopenharmony_ci rv = SS_NO_VERIFY_ALG; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && 88462306a36Sopenharmony_ci first_peer_device(device)->connection->agreed_pro_version < 88) 88562306a36Sopenharmony_ci rv = SS_NOT_SUPPORTED; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci else if (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) 88862306a36Sopenharmony_ci rv = SS_NO_UP_TO_DATE_DISK; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci else if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) && 89162306a36Sopenharmony_ci ns.pdsk == D_UNKNOWN) 89262306a36Sopenharmony_ci rv = SS_NEED_CONNECTION; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN) 89562306a36Sopenharmony_ci rv = SS_CONNECTED_OUTDATES; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ciout: 89862306a36Sopenharmony_ci rcu_read_unlock(); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return rv; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci/** 90462306a36Sopenharmony_ci * is_valid_soft_transition() - Returns an SS_ error code if the state transition is not possible 90562306a36Sopenharmony_ci * This function limits state transitions that may be declined by DRBD. I.e. 90662306a36Sopenharmony_ci * user requests (aka soft transitions). 90762306a36Sopenharmony_ci * @os: old state. 90862306a36Sopenharmony_ci * @ns: new state. 90962306a36Sopenharmony_ci * @connection: DRBD connection. 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_cistatic enum drbd_state_rv 91262306a36Sopenharmony_ciis_valid_soft_transition(union drbd_state os, union drbd_state ns, struct drbd_connection *connection) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && 91762306a36Sopenharmony_ci os.conn > C_CONNECTED) 91862306a36Sopenharmony_ci rv = SS_RESYNC_RUNNING; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE) 92162306a36Sopenharmony_ci rv = SS_ALREADY_STANDALONE; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS) 92462306a36Sopenharmony_ci rv = SS_IS_DISKLESS; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED) 92762306a36Sopenharmony_ci rv = SS_NO_NET_CONFIG; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING) 93062306a36Sopenharmony_ci rv = SS_LOWER_THAN_OUTDATED; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED) 93362306a36Sopenharmony_ci rv = SS_IN_TRANSIENT_STATE; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* While establishing a connection only allow cstate to change. 93662306a36Sopenharmony_ci Delay/refuse role changes, detach attach etc... (they do not touch cstate) */ 93762306a36Sopenharmony_ci if (test_bit(STATE_SENT, &connection->flags) && 93862306a36Sopenharmony_ci !((ns.conn == C_WF_REPORT_PARAMS && os.conn == C_WF_CONNECTION) || 93962306a36Sopenharmony_ci (ns.conn >= C_CONNECTED && os.conn == C_WF_REPORT_PARAMS))) 94062306a36Sopenharmony_ci rv = SS_IN_TRANSIENT_STATE; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* Do not promote during resync handshake triggered by "force primary". 94362306a36Sopenharmony_ci * This is a hack. It should really be rejected by the peer during the 94462306a36Sopenharmony_ci * cluster wide state change request. */ 94562306a36Sopenharmony_ci if (os.role != R_PRIMARY && ns.role == R_PRIMARY 94662306a36Sopenharmony_ci && ns.pdsk == D_UP_TO_DATE 94762306a36Sopenharmony_ci && ns.disk != D_UP_TO_DATE && ns.disk != D_DISKLESS 94862306a36Sopenharmony_ci && (ns.conn <= C_WF_SYNC_UUID || ns.conn != os.conn)) 94962306a36Sopenharmony_ci rv = SS_IN_TRANSIENT_STATE; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) 95262306a36Sopenharmony_ci rv = SS_NEED_CONNECTION; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && 95562306a36Sopenharmony_ci ns.conn != os.conn && os.conn > C_CONNECTED) 95662306a36Sopenharmony_ci rv = SS_RESYNC_RUNNING; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) && 95962306a36Sopenharmony_ci os.conn < C_CONNECTED) 96062306a36Sopenharmony_ci rv = SS_NEED_CONNECTION; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE) 96362306a36Sopenharmony_ci && os.conn < C_WF_REPORT_PARAMS) 96462306a36Sopenharmony_ci rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (ns.conn == C_DISCONNECTING && ns.pdsk == D_OUTDATED && 96762306a36Sopenharmony_ci os.conn < C_CONNECTED && os.pdsk > D_OUTDATED) 96862306a36Sopenharmony_ci rv = SS_OUTDATE_WO_CONN; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci return rv; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic enum drbd_state_rv 97462306a36Sopenharmony_ciis_valid_conn_transition(enum drbd_conns oc, enum drbd_conns nc) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci /* no change -> nothing to do, at least for the connection part */ 97762306a36Sopenharmony_ci if (oc == nc) 97862306a36Sopenharmony_ci return SS_NOTHING_TO_DO; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* disconnect of an unconfigured connection does not make sense */ 98162306a36Sopenharmony_ci if (oc == C_STANDALONE && nc == C_DISCONNECTING) 98262306a36Sopenharmony_ci return SS_ALREADY_STANDALONE; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci /* from C_STANDALONE, we start with C_UNCONNECTED */ 98562306a36Sopenharmony_ci if (oc == C_STANDALONE && nc != C_UNCONNECTED) 98662306a36Sopenharmony_ci return SS_NEED_CONNECTION; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* When establishing a connection we need to go through WF_REPORT_PARAMS! 98962306a36Sopenharmony_ci Necessary to do the right thing upon invalidate-remote on a disconnected resource */ 99062306a36Sopenharmony_ci if (oc < C_WF_REPORT_PARAMS && nc >= C_CONNECTED) 99162306a36Sopenharmony_ci return SS_NEED_CONNECTION; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* After a network error only C_UNCONNECTED or C_DISCONNECTING may follow. */ 99462306a36Sopenharmony_ci if (oc >= C_TIMEOUT && oc <= C_TEAR_DOWN && nc != C_UNCONNECTED && nc != C_DISCONNECTING) 99562306a36Sopenharmony_ci return SS_IN_TRANSIENT_STATE; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* After C_DISCONNECTING only C_STANDALONE may follow */ 99862306a36Sopenharmony_ci if (oc == C_DISCONNECTING && nc != C_STANDALONE) 99962306a36Sopenharmony_ci return SS_IN_TRANSIENT_STATE; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci return SS_SUCCESS; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci/** 100662306a36Sopenharmony_ci * is_valid_transition() - Returns an SS_ error code if the state transition is not possible 100762306a36Sopenharmony_ci * This limits hard state transitions. Hard state transitions are facts there are 100862306a36Sopenharmony_ci * imposed on DRBD by the environment. E.g. disk broke or network broke down. 100962306a36Sopenharmony_ci * But those hard state transitions are still not allowed to do everything. 101062306a36Sopenharmony_ci * @ns: new state. 101162306a36Sopenharmony_ci * @os: old state. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_cistatic enum drbd_state_rv 101462306a36Sopenharmony_ciis_valid_transition(union drbd_state os, union drbd_state ns) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci enum drbd_state_rv rv; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci rv = is_valid_conn_transition(os.conn, ns.conn); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* we cannot fail (again) if we already detached */ 102162306a36Sopenharmony_ci if (ns.disk == D_FAILED && os.disk == D_DISKLESS) 102262306a36Sopenharmony_ci rv = SS_IS_DISKLESS; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return rv; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic void print_sanitize_warnings(struct drbd_device *device, enum sanitize_state_warnings warn) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci static const char *msg_table[] = { 103062306a36Sopenharmony_ci [NO_WARNING] = "", 103162306a36Sopenharmony_ci [ABORTED_ONLINE_VERIFY] = "Online-verify aborted.", 103262306a36Sopenharmony_ci [ABORTED_RESYNC] = "Resync aborted.", 103362306a36Sopenharmony_ci [CONNECTION_LOST_NEGOTIATING] = "Connection lost while negotiating, no data!", 103462306a36Sopenharmony_ci [IMPLICITLY_UPGRADED_DISK] = "Implicitly upgraded disk", 103562306a36Sopenharmony_ci [IMPLICITLY_UPGRADED_PDSK] = "Implicitly upgraded pdsk", 103662306a36Sopenharmony_ci }; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (warn != NO_WARNING) 103962306a36Sopenharmony_ci drbd_warn(device, "%s\n", msg_table[warn]); 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci/** 104362306a36Sopenharmony_ci * sanitize_state() - Resolves implicitly necessary additional changes to a state transition 104462306a36Sopenharmony_ci * @device: DRBD device. 104562306a36Sopenharmony_ci * @os: old state. 104662306a36Sopenharmony_ci * @ns: new state. 104762306a36Sopenharmony_ci * @warn: placeholder for returned state warning. 104862306a36Sopenharmony_ci * 104962306a36Sopenharmony_ci * When we loose connection, we have to set the state of the peers disk (pdsk) 105062306a36Sopenharmony_ci * to D_UNKNOWN. This rule and many more along those lines are in this function. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_cistatic union drbd_state sanitize_state(struct drbd_device *device, union drbd_state os, 105362306a36Sopenharmony_ci union drbd_state ns, enum sanitize_state_warnings *warn) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci enum drbd_fencing_p fp; 105662306a36Sopenharmony_ci enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci if (warn) 105962306a36Sopenharmony_ci *warn = NO_WARNING; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci fp = FP_DONT_CARE; 106262306a36Sopenharmony_ci if (get_ldev(device)) { 106362306a36Sopenharmony_ci rcu_read_lock(); 106462306a36Sopenharmony_ci fp = rcu_dereference(device->ldev->disk_conf)->fencing; 106562306a36Sopenharmony_ci rcu_read_unlock(); 106662306a36Sopenharmony_ci put_ldev(device); 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci /* Implications from connection to peer and peer_isp */ 107062306a36Sopenharmony_ci if (ns.conn < C_CONNECTED) { 107162306a36Sopenharmony_ci ns.peer_isp = 0; 107262306a36Sopenharmony_ci ns.peer = R_UNKNOWN; 107362306a36Sopenharmony_ci if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT) 107462306a36Sopenharmony_ci ns.pdsk = D_UNKNOWN; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* Clear the aftr_isp when becoming unconfigured */ 107862306a36Sopenharmony_ci if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY) 107962306a36Sopenharmony_ci ns.aftr_isp = 0; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* An implication of the disk states onto the connection state */ 108262306a36Sopenharmony_ci /* Abort resync if a disk fails/detaches */ 108362306a36Sopenharmony_ci if (ns.conn > C_CONNECTED && (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { 108462306a36Sopenharmony_ci if (warn) 108562306a36Sopenharmony_ci *warn = ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T ? 108662306a36Sopenharmony_ci ABORTED_ONLINE_VERIFY : ABORTED_RESYNC; 108762306a36Sopenharmony_ci ns.conn = C_CONNECTED; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci /* Connection breaks down before we finished "Negotiating" */ 109162306a36Sopenharmony_ci if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && 109262306a36Sopenharmony_ci get_ldev_if_state(device, D_NEGOTIATING)) { 109362306a36Sopenharmony_ci if (device->ed_uuid == device->ldev->md.uuid[UI_CURRENT]) { 109462306a36Sopenharmony_ci ns.disk = device->new_state_tmp.disk; 109562306a36Sopenharmony_ci ns.pdsk = device->new_state_tmp.pdsk; 109662306a36Sopenharmony_ci } else { 109762306a36Sopenharmony_ci if (warn) 109862306a36Sopenharmony_ci *warn = CONNECTION_LOST_NEGOTIATING; 109962306a36Sopenharmony_ci ns.disk = D_DISKLESS; 110062306a36Sopenharmony_ci ns.pdsk = D_UNKNOWN; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci put_ldev(device); 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* D_CONSISTENT and D_OUTDATED vanish when we get connected */ 110662306a36Sopenharmony_ci if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) { 110762306a36Sopenharmony_ci if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) 110862306a36Sopenharmony_ci ns.disk = D_UP_TO_DATE; 110962306a36Sopenharmony_ci if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED) 111062306a36Sopenharmony_ci ns.pdsk = D_UP_TO_DATE; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* Implications of the connection state on the disk states */ 111462306a36Sopenharmony_ci disk_min = D_DISKLESS; 111562306a36Sopenharmony_ci disk_max = D_UP_TO_DATE; 111662306a36Sopenharmony_ci pdsk_min = D_INCONSISTENT; 111762306a36Sopenharmony_ci pdsk_max = D_UNKNOWN; 111862306a36Sopenharmony_ci switch ((enum drbd_conns)ns.conn) { 111962306a36Sopenharmony_ci case C_WF_BITMAP_T: 112062306a36Sopenharmony_ci case C_PAUSED_SYNC_T: 112162306a36Sopenharmony_ci case C_STARTING_SYNC_T: 112262306a36Sopenharmony_ci case C_WF_SYNC_UUID: 112362306a36Sopenharmony_ci case C_BEHIND: 112462306a36Sopenharmony_ci disk_min = D_INCONSISTENT; 112562306a36Sopenharmony_ci disk_max = D_OUTDATED; 112662306a36Sopenharmony_ci pdsk_min = D_UP_TO_DATE; 112762306a36Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci case C_VERIFY_S: 113062306a36Sopenharmony_ci case C_VERIFY_T: 113162306a36Sopenharmony_ci disk_min = D_UP_TO_DATE; 113262306a36Sopenharmony_ci disk_max = D_UP_TO_DATE; 113362306a36Sopenharmony_ci pdsk_min = D_UP_TO_DATE; 113462306a36Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci case C_CONNECTED: 113762306a36Sopenharmony_ci disk_min = D_DISKLESS; 113862306a36Sopenharmony_ci disk_max = D_UP_TO_DATE; 113962306a36Sopenharmony_ci pdsk_min = D_DISKLESS; 114062306a36Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci case C_WF_BITMAP_S: 114362306a36Sopenharmony_ci case C_PAUSED_SYNC_S: 114462306a36Sopenharmony_ci case C_STARTING_SYNC_S: 114562306a36Sopenharmony_ci case C_AHEAD: 114662306a36Sopenharmony_ci disk_min = D_UP_TO_DATE; 114762306a36Sopenharmony_ci disk_max = D_UP_TO_DATE; 114862306a36Sopenharmony_ci pdsk_min = D_INCONSISTENT; 114962306a36Sopenharmony_ci pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/ 115062306a36Sopenharmony_ci break; 115162306a36Sopenharmony_ci case C_SYNC_TARGET: 115262306a36Sopenharmony_ci disk_min = D_INCONSISTENT; 115362306a36Sopenharmony_ci disk_max = D_INCONSISTENT; 115462306a36Sopenharmony_ci pdsk_min = D_UP_TO_DATE; 115562306a36Sopenharmony_ci pdsk_max = D_UP_TO_DATE; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci case C_SYNC_SOURCE: 115862306a36Sopenharmony_ci disk_min = D_UP_TO_DATE; 115962306a36Sopenharmony_ci disk_max = D_UP_TO_DATE; 116062306a36Sopenharmony_ci pdsk_min = D_INCONSISTENT; 116162306a36Sopenharmony_ci pdsk_max = D_INCONSISTENT; 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci case C_STANDALONE: 116462306a36Sopenharmony_ci case C_DISCONNECTING: 116562306a36Sopenharmony_ci case C_UNCONNECTED: 116662306a36Sopenharmony_ci case C_TIMEOUT: 116762306a36Sopenharmony_ci case C_BROKEN_PIPE: 116862306a36Sopenharmony_ci case C_NETWORK_FAILURE: 116962306a36Sopenharmony_ci case C_PROTOCOL_ERROR: 117062306a36Sopenharmony_ci case C_TEAR_DOWN: 117162306a36Sopenharmony_ci case C_WF_CONNECTION: 117262306a36Sopenharmony_ci case C_WF_REPORT_PARAMS: 117362306a36Sopenharmony_ci case C_MASK: 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci if (ns.disk > disk_max) 117762306a36Sopenharmony_ci ns.disk = disk_max; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (ns.disk < disk_min) { 118062306a36Sopenharmony_ci if (warn) 118162306a36Sopenharmony_ci *warn = IMPLICITLY_UPGRADED_DISK; 118262306a36Sopenharmony_ci ns.disk = disk_min; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci if (ns.pdsk > pdsk_max) 118562306a36Sopenharmony_ci ns.pdsk = pdsk_max; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (ns.pdsk < pdsk_min) { 118862306a36Sopenharmony_ci if (warn) 118962306a36Sopenharmony_ci *warn = IMPLICITLY_UPGRADED_PDSK; 119062306a36Sopenharmony_ci ns.pdsk = pdsk_min; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (fp == FP_STONITH && 119462306a36Sopenharmony_ci (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && 119562306a36Sopenharmony_ci !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) 119662306a36Sopenharmony_ci ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (device->resource->res_opts.on_no_data == OND_SUSPEND_IO && 119962306a36Sopenharmony_ci (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && 120062306a36Sopenharmony_ci !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) 120162306a36Sopenharmony_ci ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */ 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { 120462306a36Sopenharmony_ci if (ns.conn == C_SYNC_SOURCE) 120562306a36Sopenharmony_ci ns.conn = C_PAUSED_SYNC_S; 120662306a36Sopenharmony_ci if (ns.conn == C_SYNC_TARGET) 120762306a36Sopenharmony_ci ns.conn = C_PAUSED_SYNC_T; 120862306a36Sopenharmony_ci } else { 120962306a36Sopenharmony_ci if (ns.conn == C_PAUSED_SYNC_S) 121062306a36Sopenharmony_ci ns.conn = C_SYNC_SOURCE; 121162306a36Sopenharmony_ci if (ns.conn == C_PAUSED_SYNC_T) 121262306a36Sopenharmony_ci ns.conn = C_SYNC_TARGET; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci return ns; 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_civoid drbd_resume_al(struct drbd_device *device) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci if (test_and_clear_bit(AL_SUSPENDED, &device->flags)) 122162306a36Sopenharmony_ci drbd_info(device, "Resumed AL updates\n"); 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci/* helper for _drbd_set_state */ 122562306a36Sopenharmony_cistatic void set_ov_position(struct drbd_peer_device *peer_device, enum drbd_conns cs) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (peer_device->connection->agreed_pro_version < 90) 123062306a36Sopenharmony_ci device->ov_start_sector = 0; 123162306a36Sopenharmony_ci device->rs_total = drbd_bm_bits(device); 123262306a36Sopenharmony_ci device->ov_position = 0; 123362306a36Sopenharmony_ci if (cs == C_VERIFY_T) { 123462306a36Sopenharmony_ci /* starting online verify from an arbitrary position 123562306a36Sopenharmony_ci * does not fit well into the existing protocol. 123662306a36Sopenharmony_ci * on C_VERIFY_T, we initialize ov_left and friends 123762306a36Sopenharmony_ci * implicitly in receive_DataRequest once the 123862306a36Sopenharmony_ci * first P_OV_REQUEST is received */ 123962306a36Sopenharmony_ci device->ov_start_sector = ~(sector_t)0; 124062306a36Sopenharmony_ci } else { 124162306a36Sopenharmony_ci unsigned long bit = BM_SECT_TO_BIT(device->ov_start_sector); 124262306a36Sopenharmony_ci if (bit >= device->rs_total) { 124362306a36Sopenharmony_ci device->ov_start_sector = 124462306a36Sopenharmony_ci BM_BIT_TO_SECT(device->rs_total - 1); 124562306a36Sopenharmony_ci device->rs_total = 1; 124662306a36Sopenharmony_ci } else 124762306a36Sopenharmony_ci device->rs_total -= bit; 124862306a36Sopenharmony_ci device->ov_position = device->ov_start_sector; 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci device->ov_left = device->rs_total; 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci/** 125462306a36Sopenharmony_ci * _drbd_set_state() - Set a new DRBD state 125562306a36Sopenharmony_ci * @device: DRBD device. 125662306a36Sopenharmony_ci * @ns: new state. 125762306a36Sopenharmony_ci * @flags: Flags 125862306a36Sopenharmony_ci * @done: Optional completion, that will get completed after the after_state_ch() finished 125962306a36Sopenharmony_ci * 126062306a36Sopenharmony_ci * Caller needs to hold req_lock. Do not call directly. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_cienum drbd_state_rv 126362306a36Sopenharmony_ci_drbd_set_state(struct drbd_device *device, union drbd_state ns, 126462306a36Sopenharmony_ci enum chg_state_flags flags, struct completion *done) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci struct drbd_peer_device *peer_device = first_peer_device(device); 126762306a36Sopenharmony_ci struct drbd_connection *connection = peer_device ? peer_device->connection : NULL; 126862306a36Sopenharmony_ci union drbd_state os; 126962306a36Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 127062306a36Sopenharmony_ci enum sanitize_state_warnings ssw; 127162306a36Sopenharmony_ci struct after_state_chg_work *ascw; 127262306a36Sopenharmony_ci struct drbd_state_change *state_change; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci os = drbd_read_state(device); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci ns = sanitize_state(device, os, ns, &ssw); 127762306a36Sopenharmony_ci if (ns.i == os.i) 127862306a36Sopenharmony_ci return SS_NOTHING_TO_DO; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci rv = is_valid_transition(os, ns); 128162306a36Sopenharmony_ci if (rv < SS_SUCCESS) 128262306a36Sopenharmony_ci return rv; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (!(flags & CS_HARD)) { 128562306a36Sopenharmony_ci /* pre-state-change checks ; only look at ns */ 128662306a36Sopenharmony_ci /* See drbd_state_sw_errors in drbd_strings.c */ 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci rv = is_valid_state(device, ns); 128962306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 129062306a36Sopenharmony_ci /* If the old state was illegal as well, then let 129162306a36Sopenharmony_ci this happen...*/ 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (is_valid_state(device, os) == rv) 129462306a36Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 129562306a36Sopenharmony_ci } else 129662306a36Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 130062306a36Sopenharmony_ci if (flags & CS_VERBOSE) 130162306a36Sopenharmony_ci print_st_err(device, os, ns, rv); 130262306a36Sopenharmony_ci return rv; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci print_sanitize_warnings(device, ssw); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci drbd_pr_state_change(device, os, ns, flags); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* Display changes to the susp* flags that where caused by the call to 131062306a36Sopenharmony_ci sanitize_state(). Only display it here if we where not called from 131162306a36Sopenharmony_ci _conn_request_state() */ 131262306a36Sopenharmony_ci if (!(flags & CS_DC_SUSP)) 131362306a36Sopenharmony_ci conn_pr_state_change(connection, os, ns, 131462306a36Sopenharmony_ci (flags & ~CS_DC_MASK) | CS_DC_SUSP); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference 131762306a36Sopenharmony_ci * on the ldev here, to be sure the transition -> D_DISKLESS resp. 131862306a36Sopenharmony_ci * drbd_ldev_destroy() won't happen before our corresponding 131962306a36Sopenharmony_ci * after_state_ch works run, where we put_ldev again. */ 132062306a36Sopenharmony_ci if ((os.disk != D_FAILED && ns.disk == D_FAILED) || 132162306a36Sopenharmony_ci (os.disk != D_DISKLESS && ns.disk == D_DISKLESS)) 132262306a36Sopenharmony_ci atomic_inc(&device->local_cnt); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (!is_sync_state(os.conn) && is_sync_state(ns.conn)) 132562306a36Sopenharmony_ci clear_bit(RS_DONE, &device->flags); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* FIXME: Have any flags been set earlier in this function already? */ 132862306a36Sopenharmony_ci state_change = remember_old_state(device->resource, GFP_ATOMIC); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* changes to local_cnt and device flags should be visible before 133162306a36Sopenharmony_ci * changes to state, which again should be visible before anything else 133262306a36Sopenharmony_ci * depending on that change happens. */ 133362306a36Sopenharmony_ci smp_wmb(); 133462306a36Sopenharmony_ci device->state.i = ns.i; 133562306a36Sopenharmony_ci device->resource->susp = ns.susp; 133662306a36Sopenharmony_ci device->resource->susp_nod = ns.susp_nod; 133762306a36Sopenharmony_ci device->resource->susp_fen = ns.susp_fen; 133862306a36Sopenharmony_ci smp_wmb(); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci remember_new_state(state_change); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* put replicated vs not-replicated requests in seperate epochs */ 134362306a36Sopenharmony_ci if (drbd_should_do_remote((union drbd_dev_state)os.i) != 134462306a36Sopenharmony_ci drbd_should_do_remote((union drbd_dev_state)ns.i)) 134562306a36Sopenharmony_ci start_new_tl_epoch(connection); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) 134862306a36Sopenharmony_ci drbd_print_uuids(device, "attached to UUIDs"); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* Wake up role changes, that were delayed because of connection establishing */ 135162306a36Sopenharmony_ci if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS && 135262306a36Sopenharmony_ci no_peer_wf_report_params(connection)) { 135362306a36Sopenharmony_ci clear_bit(STATE_SENT, &connection->flags); 135462306a36Sopenharmony_ci wake_up_all_devices(connection); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci wake_up(&device->misc_wait); 135862306a36Sopenharmony_ci wake_up(&device->state_wait); 135962306a36Sopenharmony_ci wake_up(&connection->ping_wait); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci /* Aborted verify run, or we reached the stop sector. 136262306a36Sopenharmony_ci * Log the last position, unless end-of-device. */ 136362306a36Sopenharmony_ci if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && 136462306a36Sopenharmony_ci ns.conn <= C_CONNECTED) { 136562306a36Sopenharmony_ci device->ov_start_sector = 136662306a36Sopenharmony_ci BM_BIT_TO_SECT(drbd_bm_bits(device) - device->ov_left); 136762306a36Sopenharmony_ci if (device->ov_left) 136862306a36Sopenharmony_ci drbd_info(device, "Online Verify reached sector %llu\n", 136962306a36Sopenharmony_ci (unsigned long long)device->ov_start_sector); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) && 137362306a36Sopenharmony_ci (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) { 137462306a36Sopenharmony_ci drbd_info(device, "Syncer continues.\n"); 137562306a36Sopenharmony_ci device->rs_paused += (long)jiffies 137662306a36Sopenharmony_ci -(long)device->rs_mark_time[device->rs_last_mark]; 137762306a36Sopenharmony_ci if (ns.conn == C_SYNC_TARGET) 137862306a36Sopenharmony_ci mod_timer(&device->resync_timer, jiffies); 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) && 138262306a36Sopenharmony_ci (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) { 138362306a36Sopenharmony_ci drbd_info(device, "Resync suspended\n"); 138462306a36Sopenharmony_ci device->rs_mark_time[device->rs_last_mark] = jiffies; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (os.conn == C_CONNECTED && 138862306a36Sopenharmony_ci (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) { 138962306a36Sopenharmony_ci unsigned long now = jiffies; 139062306a36Sopenharmony_ci int i; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci set_ov_position(peer_device, ns.conn); 139362306a36Sopenharmony_ci device->rs_start = now; 139462306a36Sopenharmony_ci device->rs_last_sect_ev = 0; 139562306a36Sopenharmony_ci device->ov_last_oos_size = 0; 139662306a36Sopenharmony_ci device->ov_last_oos_start = 0; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci for (i = 0; i < DRBD_SYNC_MARKS; i++) { 139962306a36Sopenharmony_ci device->rs_mark_left[i] = device->ov_left; 140062306a36Sopenharmony_ci device->rs_mark_time[i] = now; 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci drbd_rs_controller_reset(peer_device); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (ns.conn == C_VERIFY_S) { 140662306a36Sopenharmony_ci drbd_info(device, "Starting Online Verify from sector %llu\n", 140762306a36Sopenharmony_ci (unsigned long long)device->ov_position); 140862306a36Sopenharmony_ci mod_timer(&device->resync_timer, jiffies); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (get_ldev(device)) { 141362306a36Sopenharmony_ci u32 mdf = device->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND| 141462306a36Sopenharmony_ci MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE| 141562306a36Sopenharmony_ci MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci mdf &= ~MDF_AL_CLEAN; 141862306a36Sopenharmony_ci if (test_bit(CRASHED_PRIMARY, &device->flags)) 141962306a36Sopenharmony_ci mdf |= MDF_CRASHED_PRIMARY; 142062306a36Sopenharmony_ci if (device->state.role == R_PRIMARY || 142162306a36Sopenharmony_ci (device->state.pdsk < D_INCONSISTENT && device->state.peer == R_PRIMARY)) 142262306a36Sopenharmony_ci mdf |= MDF_PRIMARY_IND; 142362306a36Sopenharmony_ci if (device->state.conn > C_WF_REPORT_PARAMS) 142462306a36Sopenharmony_ci mdf |= MDF_CONNECTED_IND; 142562306a36Sopenharmony_ci if (device->state.disk > D_INCONSISTENT) 142662306a36Sopenharmony_ci mdf |= MDF_CONSISTENT; 142762306a36Sopenharmony_ci if (device->state.disk > D_OUTDATED) 142862306a36Sopenharmony_ci mdf |= MDF_WAS_UP_TO_DATE; 142962306a36Sopenharmony_ci if (device->state.pdsk <= D_OUTDATED && device->state.pdsk >= D_INCONSISTENT) 143062306a36Sopenharmony_ci mdf |= MDF_PEER_OUT_DATED; 143162306a36Sopenharmony_ci if (mdf != device->ldev->md.flags) { 143262306a36Sopenharmony_ci device->ldev->md.flags = mdf; 143362306a36Sopenharmony_ci drbd_md_mark_dirty(device); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT) 143662306a36Sopenharmony_ci drbd_set_ed_uuid(device, device->ldev->md.uuid[UI_CURRENT]); 143762306a36Sopenharmony_ci put_ldev(device); 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */ 144162306a36Sopenharmony_ci if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT && 144262306a36Sopenharmony_ci os.peer == R_SECONDARY && ns.peer == R_PRIMARY) 144362306a36Sopenharmony_ci set_bit(CONSIDER_RESYNC, &device->flags); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* Receiver should clean up itself */ 144662306a36Sopenharmony_ci if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING) 144762306a36Sopenharmony_ci drbd_thread_stop_nowait(&connection->receiver); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* Now the receiver finished cleaning up itself, it should die */ 145062306a36Sopenharmony_ci if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE) 145162306a36Sopenharmony_ci drbd_thread_stop_nowait(&connection->receiver); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* Upon network failure, we need to restart the receiver. */ 145462306a36Sopenharmony_ci if (os.conn > C_WF_CONNECTION && 145562306a36Sopenharmony_ci ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) 145662306a36Sopenharmony_ci drbd_thread_restart_nowait(&connection->receiver); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* Resume AL writing if we get a connection */ 145962306a36Sopenharmony_ci if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { 146062306a36Sopenharmony_ci drbd_resume_al(device); 146162306a36Sopenharmony_ci connection->connect_cnt++; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci /* remember last attach time so request_timer_fn() won't 146562306a36Sopenharmony_ci * kill newly established sessions while we are still trying to thaw 146662306a36Sopenharmony_ci * previously frozen IO */ 146762306a36Sopenharmony_ci if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) && 146862306a36Sopenharmony_ci ns.disk > D_NEGOTIATING) 146962306a36Sopenharmony_ci device->last_reattach_jif = jiffies; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); 147262306a36Sopenharmony_ci if (ascw) { 147362306a36Sopenharmony_ci ascw->os = os; 147462306a36Sopenharmony_ci ascw->ns = ns; 147562306a36Sopenharmony_ci ascw->flags = flags; 147662306a36Sopenharmony_ci ascw->w.cb = w_after_state_ch; 147762306a36Sopenharmony_ci ascw->device = device; 147862306a36Sopenharmony_ci ascw->done = done; 147962306a36Sopenharmony_ci ascw->state_change = state_change; 148062306a36Sopenharmony_ci drbd_queue_work(&connection->sender_work, 148162306a36Sopenharmony_ci &ascw->w); 148262306a36Sopenharmony_ci } else { 148362306a36Sopenharmony_ci drbd_err(device, "Could not kmalloc an ascw\n"); 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci return rv; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic int w_after_state_ch(struct drbd_work *w, int unused) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct after_state_chg_work *ascw = 149262306a36Sopenharmony_ci container_of(w, struct after_state_chg_work, w); 149362306a36Sopenharmony_ci struct drbd_device *device = ascw->device; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci after_state_ch(device, ascw->os, ascw->ns, ascw->flags, ascw->state_change); 149662306a36Sopenharmony_ci forget_state_change(ascw->state_change); 149762306a36Sopenharmony_ci if (ascw->flags & CS_WAIT_COMPLETE) 149862306a36Sopenharmony_ci complete(ascw->done); 149962306a36Sopenharmony_ci kfree(ascw); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return 0; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic void abw_start_sync(struct drbd_device *device, int rv) 150562306a36Sopenharmony_ci{ 150662306a36Sopenharmony_ci if (rv) { 150762306a36Sopenharmony_ci drbd_err(device, "Writing the bitmap failed not starting resync.\n"); 150862306a36Sopenharmony_ci _drbd_request_state(device, NS(conn, C_CONNECTED), CS_VERBOSE); 150962306a36Sopenharmony_ci return; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci switch (device->state.conn) { 151362306a36Sopenharmony_ci case C_STARTING_SYNC_T: 151462306a36Sopenharmony_ci _drbd_request_state(device, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); 151562306a36Sopenharmony_ci break; 151662306a36Sopenharmony_ci case C_STARTING_SYNC_S: 151762306a36Sopenharmony_ci drbd_start_resync(device, C_SYNC_SOURCE); 151862306a36Sopenharmony_ci break; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ciint drbd_bitmap_io_from_worker(struct drbd_device *device, 152362306a36Sopenharmony_ci int (*io_fn)(struct drbd_device *, struct drbd_peer_device *), 152462306a36Sopenharmony_ci char *why, enum bm_flag flags, 152562306a36Sopenharmony_ci struct drbd_peer_device *peer_device) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci int rv; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci D_ASSERT(device, current == first_peer_device(device)->connection->worker.task); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci /* open coded non-blocking drbd_suspend_io(device); */ 153262306a36Sopenharmony_ci atomic_inc(&device->suspend_cnt); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci drbd_bm_lock(device, why, flags); 153562306a36Sopenharmony_ci rv = io_fn(device, peer_device); 153662306a36Sopenharmony_ci drbd_bm_unlock(device); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci drbd_resume_io(device); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return rv; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ciint notify_resource_state_change(struct sk_buff *skb, 154462306a36Sopenharmony_ci unsigned int seq, 154562306a36Sopenharmony_ci struct drbd_resource_state_change *resource_state_change, 154662306a36Sopenharmony_ci enum drbd_notification_type type) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci struct drbd_resource *resource = resource_state_change->resource; 154962306a36Sopenharmony_ci struct resource_info resource_info = { 155062306a36Sopenharmony_ci .res_role = resource_state_change->role[NEW], 155162306a36Sopenharmony_ci .res_susp = resource_state_change->susp[NEW], 155262306a36Sopenharmony_ci .res_susp_nod = resource_state_change->susp_nod[NEW], 155362306a36Sopenharmony_ci .res_susp_fen = resource_state_change->susp_fen[NEW], 155462306a36Sopenharmony_ci }; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci return notify_resource_state(skb, seq, resource, &resource_info, type); 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ciint notify_connection_state_change(struct sk_buff *skb, 156062306a36Sopenharmony_ci unsigned int seq, 156162306a36Sopenharmony_ci struct drbd_connection_state_change *connection_state_change, 156262306a36Sopenharmony_ci enum drbd_notification_type type) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci struct drbd_connection *connection = connection_state_change->connection; 156562306a36Sopenharmony_ci struct connection_info connection_info = { 156662306a36Sopenharmony_ci .conn_connection_state = connection_state_change->cstate[NEW], 156762306a36Sopenharmony_ci .conn_role = connection_state_change->peer_role[NEW], 156862306a36Sopenharmony_ci }; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci return notify_connection_state(skb, seq, connection, &connection_info, type); 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ciint notify_device_state_change(struct sk_buff *skb, 157462306a36Sopenharmony_ci unsigned int seq, 157562306a36Sopenharmony_ci struct drbd_device_state_change *device_state_change, 157662306a36Sopenharmony_ci enum drbd_notification_type type) 157762306a36Sopenharmony_ci{ 157862306a36Sopenharmony_ci struct drbd_device *device = device_state_change->device; 157962306a36Sopenharmony_ci struct device_info device_info = { 158062306a36Sopenharmony_ci .dev_disk_state = device_state_change->disk_state[NEW], 158162306a36Sopenharmony_ci }; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci return notify_device_state(skb, seq, device, &device_info, type); 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ciint notify_peer_device_state_change(struct sk_buff *skb, 158762306a36Sopenharmony_ci unsigned int seq, 158862306a36Sopenharmony_ci struct drbd_peer_device_state_change *p, 158962306a36Sopenharmony_ci enum drbd_notification_type type) 159062306a36Sopenharmony_ci{ 159162306a36Sopenharmony_ci struct drbd_peer_device *peer_device = p->peer_device; 159262306a36Sopenharmony_ci struct peer_device_info peer_device_info = { 159362306a36Sopenharmony_ci .peer_repl_state = p->repl_state[NEW], 159462306a36Sopenharmony_ci .peer_disk_state = p->disk_state[NEW], 159562306a36Sopenharmony_ci .peer_resync_susp_user = p->resync_susp_user[NEW], 159662306a36Sopenharmony_ci .peer_resync_susp_peer = p->resync_susp_peer[NEW], 159762306a36Sopenharmony_ci .peer_resync_susp_dependency = p->resync_susp_dependency[NEW], 159862306a36Sopenharmony_ci }; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type); 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic void broadcast_state_change(struct drbd_state_change *state_change) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct drbd_resource_state_change *resource_state_change = &state_change->resource[0]; 160662306a36Sopenharmony_ci bool resource_state_has_changed; 160762306a36Sopenharmony_ci unsigned int n_device, n_connection, n_peer_device, n_peer_devices; 160862306a36Sopenharmony_ci int (*last_func)(struct sk_buff *, unsigned int, void *, 160962306a36Sopenharmony_ci enum drbd_notification_type) = NULL; 161062306a36Sopenharmony_ci void *last_arg = NULL; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci#define HAS_CHANGED(state) ((state)[OLD] != (state)[NEW]) 161362306a36Sopenharmony_ci#define FINAL_STATE_CHANGE(type) \ 161462306a36Sopenharmony_ci ({ if (last_func) \ 161562306a36Sopenharmony_ci last_func(NULL, 0, last_arg, type); \ 161662306a36Sopenharmony_ci }) 161762306a36Sopenharmony_ci#define REMEMBER_STATE_CHANGE(func, arg, type) \ 161862306a36Sopenharmony_ci ({ FINAL_STATE_CHANGE(type | NOTIFY_CONTINUES); \ 161962306a36Sopenharmony_ci last_func = (typeof(last_func))func; \ 162062306a36Sopenharmony_ci last_arg = arg; \ 162162306a36Sopenharmony_ci }) 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci mutex_lock(¬ification_mutex); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci resource_state_has_changed = 162662306a36Sopenharmony_ci HAS_CHANGED(resource_state_change->role) || 162762306a36Sopenharmony_ci HAS_CHANGED(resource_state_change->susp) || 162862306a36Sopenharmony_ci HAS_CHANGED(resource_state_change->susp_nod) || 162962306a36Sopenharmony_ci HAS_CHANGED(resource_state_change->susp_fen); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci if (resource_state_has_changed) 163262306a36Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_resource_state_change, 163362306a36Sopenharmony_ci resource_state_change, NOTIFY_CHANGE); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci for (n_connection = 0; n_connection < state_change->n_connections; n_connection++) { 163662306a36Sopenharmony_ci struct drbd_connection_state_change *connection_state_change = 163762306a36Sopenharmony_ci &state_change->connections[n_connection]; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (HAS_CHANGED(connection_state_change->peer_role) || 164062306a36Sopenharmony_ci HAS_CHANGED(connection_state_change->cstate)) 164162306a36Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_connection_state_change, 164262306a36Sopenharmony_ci connection_state_change, NOTIFY_CHANGE); 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci for (n_device = 0; n_device < state_change->n_devices; n_device++) { 164662306a36Sopenharmony_ci struct drbd_device_state_change *device_state_change = 164762306a36Sopenharmony_ci &state_change->devices[n_device]; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci if (HAS_CHANGED(device_state_change->disk_state)) 165062306a36Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_device_state_change, 165162306a36Sopenharmony_ci device_state_change, NOTIFY_CHANGE); 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci n_peer_devices = state_change->n_devices * state_change->n_connections; 165562306a36Sopenharmony_ci for (n_peer_device = 0; n_peer_device < n_peer_devices; n_peer_device++) { 165662306a36Sopenharmony_ci struct drbd_peer_device_state_change *p = 165762306a36Sopenharmony_ci &state_change->peer_devices[n_peer_device]; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci if (HAS_CHANGED(p->disk_state) || 166062306a36Sopenharmony_ci HAS_CHANGED(p->repl_state) || 166162306a36Sopenharmony_ci HAS_CHANGED(p->resync_susp_user) || 166262306a36Sopenharmony_ci HAS_CHANGED(p->resync_susp_peer) || 166362306a36Sopenharmony_ci HAS_CHANGED(p->resync_susp_dependency)) 166462306a36Sopenharmony_ci REMEMBER_STATE_CHANGE(notify_peer_device_state_change, 166562306a36Sopenharmony_ci p, NOTIFY_CHANGE); 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci FINAL_STATE_CHANGE(NOTIFY_CHANGE); 166962306a36Sopenharmony_ci mutex_unlock(¬ification_mutex); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci#undef HAS_CHANGED 167262306a36Sopenharmony_ci#undef FINAL_STATE_CHANGE 167362306a36Sopenharmony_ci#undef REMEMBER_STATE_CHANGE 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci/* takes old and new peer disk state */ 167762306a36Sopenharmony_cistatic bool lost_contact_to_peer_data(enum drbd_disk_state os, enum drbd_disk_state ns) 167862306a36Sopenharmony_ci{ 167962306a36Sopenharmony_ci if ((os >= D_INCONSISTENT && os != D_UNKNOWN && os != D_OUTDATED) 168062306a36Sopenharmony_ci && (ns < D_INCONSISTENT || ns == D_UNKNOWN || ns == D_OUTDATED)) 168162306a36Sopenharmony_ci return true; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci /* Scenario, starting with normal operation 168462306a36Sopenharmony_ci * Connected Primary/Secondary UpToDate/UpToDate 168562306a36Sopenharmony_ci * NetworkFailure Primary/Unknown UpToDate/DUnknown (frozen) 168662306a36Sopenharmony_ci * ... 168762306a36Sopenharmony_ci * Connected Primary/Secondary UpToDate/Diskless (resumed; needs to bump uuid!) 168862306a36Sopenharmony_ci */ 168962306a36Sopenharmony_ci if (os == D_UNKNOWN 169062306a36Sopenharmony_ci && (ns == D_DISKLESS || ns == D_FAILED || ns == D_OUTDATED)) 169162306a36Sopenharmony_ci return true; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci return false; 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci/** 169762306a36Sopenharmony_ci * after_state_ch() - Perform after state change actions that may sleep 169862306a36Sopenharmony_ci * @device: DRBD device. 169962306a36Sopenharmony_ci * @os: old state. 170062306a36Sopenharmony_ci * @ns: new state. 170162306a36Sopenharmony_ci * @flags: Flags 170262306a36Sopenharmony_ci * @state_change: state change to broadcast 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_cistatic void after_state_ch(struct drbd_device *device, union drbd_state os, 170562306a36Sopenharmony_ci union drbd_state ns, enum chg_state_flags flags, 170662306a36Sopenharmony_ci struct drbd_state_change *state_change) 170762306a36Sopenharmony_ci{ 170862306a36Sopenharmony_ci struct drbd_resource *resource = device->resource; 170962306a36Sopenharmony_ci struct drbd_peer_device *peer_device = first_peer_device(device); 171062306a36Sopenharmony_ci struct drbd_connection *connection = peer_device ? peer_device->connection : NULL; 171162306a36Sopenharmony_ci struct sib_info sib; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci broadcast_state_change(state_change); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci sib.sib_reason = SIB_STATE_CHANGE; 171662306a36Sopenharmony_ci sib.os = os; 171762306a36Sopenharmony_ci sib.ns = ns; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if ((os.disk != D_UP_TO_DATE || os.pdsk != D_UP_TO_DATE) 172062306a36Sopenharmony_ci && (ns.disk == D_UP_TO_DATE && ns.pdsk == D_UP_TO_DATE)) { 172162306a36Sopenharmony_ci clear_bit(CRASHED_PRIMARY, &device->flags); 172262306a36Sopenharmony_ci if (device->p_uuid) 172362306a36Sopenharmony_ci device->p_uuid[UI_FLAGS] &= ~((u64)2); 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci /* Inform userspace about the change... */ 172762306a36Sopenharmony_ci drbd_bcast_event(device, &sib); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) && 173062306a36Sopenharmony_ci (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE)) 173162306a36Sopenharmony_ci drbd_khelper(device, "pri-on-incon-degr"); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci /* Here we have the actions that are performed after a 173462306a36Sopenharmony_ci state change. This function might sleep */ 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (ns.susp_nod) { 173762306a36Sopenharmony_ci enum drbd_req_event what = NOTHING; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 174062306a36Sopenharmony_ci if (os.conn < C_CONNECTED && conn_lowest_conn(connection) >= C_CONNECTED) 174162306a36Sopenharmony_ci what = RESEND; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) && 174462306a36Sopenharmony_ci conn_lowest_disk(connection) == D_UP_TO_DATE) 174562306a36Sopenharmony_ci what = RESTART_FROZEN_DISK_IO; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci if (resource->susp_nod && what != NOTHING) { 174862306a36Sopenharmony_ci _tl_restart(connection, what); 174962306a36Sopenharmony_ci _conn_request_state(connection, 175062306a36Sopenharmony_ci (union drbd_state) { { .susp_nod = 1 } }, 175162306a36Sopenharmony_ci (union drbd_state) { { .susp_nod = 0 } }, 175262306a36Sopenharmony_ci CS_VERBOSE); 175362306a36Sopenharmony_ci } 175462306a36Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci if (ns.susp_fen) { 175862306a36Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 175962306a36Sopenharmony_ci if (resource->susp_fen && conn_lowest_conn(connection) >= C_CONNECTED) { 176062306a36Sopenharmony_ci /* case2: The connection was established again: */ 176162306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 176262306a36Sopenharmony_ci int vnr; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci rcu_read_lock(); 176562306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 176662306a36Sopenharmony_ci clear_bit(NEW_CUR_UUID, &peer_device->device->flags); 176762306a36Sopenharmony_ci rcu_read_unlock(); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci /* We should actively create a new uuid, _before_ 177062306a36Sopenharmony_ci * we resume/resent, if the peer is diskless 177162306a36Sopenharmony_ci * (recovery from a multiple error scenario). 177262306a36Sopenharmony_ci * Currently, this happens with a slight delay 177362306a36Sopenharmony_ci * below when checking lost_contact_to_peer_data() ... 177462306a36Sopenharmony_ci */ 177562306a36Sopenharmony_ci _tl_restart(connection, RESEND); 177662306a36Sopenharmony_ci _conn_request_state(connection, 177762306a36Sopenharmony_ci (union drbd_state) { { .susp_fen = 1 } }, 177862306a36Sopenharmony_ci (union drbd_state) { { .susp_fen = 0 } }, 177962306a36Sopenharmony_ci CS_VERBOSE); 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci /* Became sync source. With protocol >= 96, we still need to send out 178562306a36Sopenharmony_ci * the sync uuid now. Need to do that before any drbd_send_state, or 178662306a36Sopenharmony_ci * the other side may go "paused sync" before receiving the sync uuids, 178762306a36Sopenharmony_ci * which is unexpected. */ 178862306a36Sopenharmony_ci if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && 178962306a36Sopenharmony_ci (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && 179062306a36Sopenharmony_ci connection->agreed_pro_version >= 96 && get_ldev(device)) { 179162306a36Sopenharmony_ci drbd_gen_and_send_sync_uuid(peer_device); 179262306a36Sopenharmony_ci put_ldev(device); 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci /* Do not change the order of the if above and the two below... */ 179662306a36Sopenharmony_ci if (os.pdsk == D_DISKLESS && 179762306a36Sopenharmony_ci ns.pdsk > D_DISKLESS && ns.pdsk != D_UNKNOWN) { /* attach on the peer */ 179862306a36Sopenharmony_ci /* we probably will start a resync soon. 179962306a36Sopenharmony_ci * make sure those things are properly reset. */ 180062306a36Sopenharmony_ci device->rs_total = 0; 180162306a36Sopenharmony_ci device->rs_failed = 0; 180262306a36Sopenharmony_ci atomic_set(&device->rs_pending_cnt, 0); 180362306a36Sopenharmony_ci drbd_rs_cancel_all(device); 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci drbd_send_uuids(peer_device); 180662306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci /* No point in queuing send_bitmap if we don't have a connection 180962306a36Sopenharmony_ci * anymore, so check also the _current_ state, not only the new state 181062306a36Sopenharmony_ci * at the time this work was queued. */ 181162306a36Sopenharmony_ci if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && 181262306a36Sopenharmony_ci device->state.conn == C_WF_BITMAP_S) 181362306a36Sopenharmony_ci drbd_queue_bitmap_io(device, &drbd_send_bitmap, NULL, 181462306a36Sopenharmony_ci "send_bitmap (WFBitMapS)", 181562306a36Sopenharmony_ci BM_LOCKED_TEST_ALLOWED, peer_device); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci /* Lost contact to peer's copy of the data */ 181862306a36Sopenharmony_ci if (lost_contact_to_peer_data(os.pdsk, ns.pdsk)) { 181962306a36Sopenharmony_ci if (get_ldev(device)) { 182062306a36Sopenharmony_ci if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) && 182162306a36Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { 182262306a36Sopenharmony_ci if (drbd_suspended(device)) { 182362306a36Sopenharmony_ci set_bit(NEW_CUR_UUID, &device->flags); 182462306a36Sopenharmony_ci } else { 182562306a36Sopenharmony_ci drbd_uuid_new_current(device); 182662306a36Sopenharmony_ci drbd_send_uuids(peer_device); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci put_ldev(device); 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (ns.pdsk < D_INCONSISTENT && get_ldev(device)) { 183462306a36Sopenharmony_ci if (os.peer != R_PRIMARY && ns.peer == R_PRIMARY && 183562306a36Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { 183662306a36Sopenharmony_ci drbd_uuid_new_current(device); 183762306a36Sopenharmony_ci drbd_send_uuids(peer_device); 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci /* D_DISKLESS Peer becomes secondary */ 184062306a36Sopenharmony_ci if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) 184162306a36Sopenharmony_ci /* We may still be Primary ourselves. 184262306a36Sopenharmony_ci * No harm done if the bitmap still changes, 184362306a36Sopenharmony_ci * redirtied pages will follow later. */ 184462306a36Sopenharmony_ci drbd_bitmap_io_from_worker(device, &drbd_bm_write, 184562306a36Sopenharmony_ci "demote diskless peer", BM_LOCKED_SET_ALLOWED, peer_device); 184662306a36Sopenharmony_ci put_ldev(device); 184762306a36Sopenharmony_ci } 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci /* Write out all changed bits on demote. 185062306a36Sopenharmony_ci * Though, no need to da that just yet 185162306a36Sopenharmony_ci * if there is a resync going on still */ 185262306a36Sopenharmony_ci if (os.role == R_PRIMARY && ns.role == R_SECONDARY && 185362306a36Sopenharmony_ci device->state.conn <= C_CONNECTED && get_ldev(device)) { 185462306a36Sopenharmony_ci /* No changes to the bitmap expected this time, so assert that, 185562306a36Sopenharmony_ci * even though no harm was done if it did change. */ 185662306a36Sopenharmony_ci drbd_bitmap_io_from_worker(device, &drbd_bm_write, 185762306a36Sopenharmony_ci "demote", BM_LOCKED_TEST_ALLOWED, peer_device); 185862306a36Sopenharmony_ci put_ldev(device); 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci /* Last part of the attaching process ... */ 186262306a36Sopenharmony_ci if (ns.conn >= C_CONNECTED && 186362306a36Sopenharmony_ci os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) { 186462306a36Sopenharmony_ci drbd_send_sizes(peer_device, 0, 0); /* to start sync... */ 186562306a36Sopenharmony_ci drbd_send_uuids(peer_device); 186662306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci /* We want to pause/continue resync, tell peer. */ 187062306a36Sopenharmony_ci if (ns.conn >= C_CONNECTED && 187162306a36Sopenharmony_ci ((os.aftr_isp != ns.aftr_isp) || 187262306a36Sopenharmony_ci (os.user_isp != ns.user_isp))) 187362306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci /* In case one of the isp bits got set, suspend other devices. */ 187662306a36Sopenharmony_ci if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) && 187762306a36Sopenharmony_ci (ns.aftr_isp || ns.peer_isp || ns.user_isp)) 187862306a36Sopenharmony_ci suspend_other_sg(device); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci /* Make sure the peer gets informed about eventual state 188162306a36Sopenharmony_ci changes (ISP bits) while we were in WFReportParams. */ 188262306a36Sopenharmony_ci if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) 188362306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci if (os.conn != C_AHEAD && ns.conn == C_AHEAD) 188662306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci /* We are in the progress to start a full sync... */ 188962306a36Sopenharmony_ci if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || 189062306a36Sopenharmony_ci (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) 189162306a36Sopenharmony_ci /* no other bitmap changes expected during this phase */ 189262306a36Sopenharmony_ci drbd_queue_bitmap_io(device, 189362306a36Sopenharmony_ci &drbd_bmio_set_n_write, &abw_start_sync, 189462306a36Sopenharmony_ci "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED, 189562306a36Sopenharmony_ci peer_device); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci /* first half of local IO error, failure to attach, 189862306a36Sopenharmony_ci * or administrative detach */ 189962306a36Sopenharmony_ci if (os.disk != D_FAILED && ns.disk == D_FAILED) { 190062306a36Sopenharmony_ci enum drbd_io_error_p eh = EP_PASS_ON; 190162306a36Sopenharmony_ci int was_io_error = 0; 190262306a36Sopenharmony_ci /* corresponding get_ldev was in _drbd_set_state, to serialize 190362306a36Sopenharmony_ci * our cleanup here with the transition to D_DISKLESS. 190462306a36Sopenharmony_ci * But is is still not save to dreference ldev here, since 190562306a36Sopenharmony_ci * we might come from an failed Attach before ldev was set. */ 190662306a36Sopenharmony_ci if (device->ldev) { 190762306a36Sopenharmony_ci rcu_read_lock(); 190862306a36Sopenharmony_ci eh = rcu_dereference(device->ldev->disk_conf)->on_io_error; 190962306a36Sopenharmony_ci rcu_read_unlock(); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci was_io_error = test_and_clear_bit(WAS_IO_ERROR, &device->flags); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci /* Intentionally call this handler first, before drbd_send_state(). 191462306a36Sopenharmony_ci * See: 2932204 drbd: call local-io-error handler early 191562306a36Sopenharmony_ci * People may chose to hard-reset the box from this handler. 191662306a36Sopenharmony_ci * It is useful if this looks like a "regular node crash". */ 191762306a36Sopenharmony_ci if (was_io_error && eh == EP_CALL_HELPER) 191862306a36Sopenharmony_ci drbd_khelper(device, "local-io-error"); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci /* Immediately allow completion of all application IO, 192162306a36Sopenharmony_ci * that waits for completion from the local disk, 192262306a36Sopenharmony_ci * if this was a force-detach due to disk_timeout 192362306a36Sopenharmony_ci * or administrator request (drbdsetup detach --force). 192462306a36Sopenharmony_ci * Do NOT abort otherwise. 192562306a36Sopenharmony_ci * Aborting local requests may cause serious problems, 192662306a36Sopenharmony_ci * if requests are completed to upper layers already, 192762306a36Sopenharmony_ci * and then later the already submitted local bio completes. 192862306a36Sopenharmony_ci * This can cause DMA into former bio pages that meanwhile 192962306a36Sopenharmony_ci * have been re-used for other things. 193062306a36Sopenharmony_ci * So aborting local requests may cause crashes, 193162306a36Sopenharmony_ci * or even worse, silent data corruption. 193262306a36Sopenharmony_ci */ 193362306a36Sopenharmony_ci if (test_and_clear_bit(FORCE_DETACH, &device->flags)) 193462306a36Sopenharmony_ci tl_abort_disk_io(device); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* current state still has to be D_FAILED, 193762306a36Sopenharmony_ci * there is only one way out: to D_DISKLESS, 193862306a36Sopenharmony_ci * and that may only happen after our put_ldev below. */ 193962306a36Sopenharmony_ci if (device->state.disk != D_FAILED) 194062306a36Sopenharmony_ci drbd_err(device, 194162306a36Sopenharmony_ci "ASSERT FAILED: disk is %s during detach\n", 194262306a36Sopenharmony_ci drbd_disk_str(device->state.disk)); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (ns.conn >= C_CONNECTED) 194562306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci drbd_rs_cancel_all(device); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci /* In case we want to get something to stable storage still, 195062306a36Sopenharmony_ci * this may be the last chance. 195162306a36Sopenharmony_ci * Following put_ldev may transition to D_DISKLESS. */ 195262306a36Sopenharmony_ci drbd_md_sync(device); 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci put_ldev(device); 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* second half of local IO error, failure to attach, 195862306a36Sopenharmony_ci * or administrative detach, 195962306a36Sopenharmony_ci * after local_cnt references have reached zero again */ 196062306a36Sopenharmony_ci if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) { 196162306a36Sopenharmony_ci /* We must still be diskless, 196262306a36Sopenharmony_ci * re-attach has to be serialized with this! */ 196362306a36Sopenharmony_ci if (device->state.disk != D_DISKLESS) 196462306a36Sopenharmony_ci drbd_err(device, 196562306a36Sopenharmony_ci "ASSERT FAILED: disk is %s while going diskless\n", 196662306a36Sopenharmony_ci drbd_disk_str(device->state.disk)); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci if (ns.conn >= C_CONNECTED) 196962306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 197062306a36Sopenharmony_ci /* corresponding get_ldev in __drbd_set_state 197162306a36Sopenharmony_ci * this may finally trigger drbd_ldev_destroy. */ 197262306a36Sopenharmony_ci put_ldev(device); 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci /* Notify peer that I had a local IO error, and did not detached.. */ 197662306a36Sopenharmony_ci if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT && ns.conn >= C_CONNECTED) 197762306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci /* Disks got bigger while they were detached */ 198062306a36Sopenharmony_ci if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING && 198162306a36Sopenharmony_ci test_and_clear_bit(RESYNC_AFTER_NEG, &device->flags)) { 198262306a36Sopenharmony_ci if (ns.conn == C_CONNECTED) 198362306a36Sopenharmony_ci resync_after_online_grow(device); 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci /* A resync finished or aborted, wake paused devices... */ 198762306a36Sopenharmony_ci if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) || 198862306a36Sopenharmony_ci (os.peer_isp && !ns.peer_isp) || 198962306a36Sopenharmony_ci (os.user_isp && !ns.user_isp)) 199062306a36Sopenharmony_ci resume_next_sg(device); 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci /* sync target done with resync. Explicitly notify peer, even though 199362306a36Sopenharmony_ci * it should (at least for non-empty resyncs) already know itself. */ 199462306a36Sopenharmony_ci if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) 199562306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci /* Verify finished, or reached stop sector. Peer did not know about 199862306a36Sopenharmony_ci * the stop sector, and we may even have changed the stop sector during 199962306a36Sopenharmony_ci * verify to interrupt/stop early. Send the new state. */ 200062306a36Sopenharmony_ci if (os.conn == C_VERIFY_S && ns.conn == C_CONNECTED 200162306a36Sopenharmony_ci && verify_can_do_stop_sector(device)) 200262306a36Sopenharmony_ci drbd_send_state(peer_device, ns); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* This triggers bitmap writeout of potentially still unwritten pages 200562306a36Sopenharmony_ci * if the resync finished cleanly, or aborted because of peer disk 200662306a36Sopenharmony_ci * failure, or on transition from resync back to AHEAD/BEHIND. 200762306a36Sopenharmony_ci * 200862306a36Sopenharmony_ci * Connection loss is handled in drbd_disconnected() by the receiver. 200962306a36Sopenharmony_ci * 201062306a36Sopenharmony_ci * For resync aborted because of local disk failure, we cannot do 201162306a36Sopenharmony_ci * any bitmap writeout anymore. 201262306a36Sopenharmony_ci * 201362306a36Sopenharmony_ci * No harm done if some bits change during this phase. 201462306a36Sopenharmony_ci */ 201562306a36Sopenharmony_ci if ((os.conn > C_CONNECTED && os.conn < C_AHEAD) && 201662306a36Sopenharmony_ci (ns.conn == C_CONNECTED || ns.conn >= C_AHEAD) && get_ldev(device)) { 201762306a36Sopenharmony_ci drbd_queue_bitmap_io(device, &drbd_bm_write_copy_pages, NULL, 201862306a36Sopenharmony_ci "write from resync_finished", BM_LOCKED_CHANGE_ALLOWED, 201962306a36Sopenharmony_ci peer_device); 202062306a36Sopenharmony_ci put_ldev(device); 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci if (ns.disk == D_DISKLESS && 202462306a36Sopenharmony_ci ns.conn == C_STANDALONE && 202562306a36Sopenharmony_ci ns.role == R_SECONDARY) { 202662306a36Sopenharmony_ci if (os.aftr_isp != ns.aftr_isp) 202762306a36Sopenharmony_ci resume_next_sg(device); 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci drbd_md_sync(device); 203162306a36Sopenharmony_ci} 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_cistruct after_conn_state_chg_work { 203462306a36Sopenharmony_ci struct drbd_work w; 203562306a36Sopenharmony_ci enum drbd_conns oc; 203662306a36Sopenharmony_ci union drbd_state ns_min; 203762306a36Sopenharmony_ci union drbd_state ns_max; /* new, max state, over all devices */ 203862306a36Sopenharmony_ci enum chg_state_flags flags; 203962306a36Sopenharmony_ci struct drbd_connection *connection; 204062306a36Sopenharmony_ci struct drbd_state_change *state_change; 204162306a36Sopenharmony_ci}; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_cistatic int w_after_conn_state_ch(struct drbd_work *w, int unused) 204462306a36Sopenharmony_ci{ 204562306a36Sopenharmony_ci struct after_conn_state_chg_work *acscw = 204662306a36Sopenharmony_ci container_of(w, struct after_conn_state_chg_work, w); 204762306a36Sopenharmony_ci struct drbd_connection *connection = acscw->connection; 204862306a36Sopenharmony_ci enum drbd_conns oc = acscw->oc; 204962306a36Sopenharmony_ci union drbd_state ns_max = acscw->ns_max; 205062306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 205162306a36Sopenharmony_ci int vnr; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci broadcast_state_change(acscw->state_change); 205462306a36Sopenharmony_ci forget_state_change(acscw->state_change); 205562306a36Sopenharmony_ci kfree(acscw); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* Upon network configuration, we need to start the receiver */ 205862306a36Sopenharmony_ci if (oc == C_STANDALONE && ns_max.conn == C_UNCONNECTED) 205962306a36Sopenharmony_ci drbd_thread_start(&connection->receiver); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci if (oc == C_DISCONNECTING && ns_max.conn == C_STANDALONE) { 206262306a36Sopenharmony_ci struct net_conf *old_conf; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci mutex_lock(¬ification_mutex); 206562306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) 206662306a36Sopenharmony_ci notify_peer_device_state(NULL, 0, peer_device, NULL, 206762306a36Sopenharmony_ci NOTIFY_DESTROY | NOTIFY_CONTINUES); 206862306a36Sopenharmony_ci notify_connection_state(NULL, 0, connection, NULL, NOTIFY_DESTROY); 206962306a36Sopenharmony_ci mutex_unlock(¬ification_mutex); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci mutex_lock(&connection->resource->conf_update); 207262306a36Sopenharmony_ci old_conf = connection->net_conf; 207362306a36Sopenharmony_ci connection->my_addr_len = 0; 207462306a36Sopenharmony_ci connection->peer_addr_len = 0; 207562306a36Sopenharmony_ci RCU_INIT_POINTER(connection->net_conf, NULL); 207662306a36Sopenharmony_ci conn_free_crypto(connection); 207762306a36Sopenharmony_ci mutex_unlock(&connection->resource->conf_update); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci kvfree_rcu_mightsleep(old_conf); 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci if (ns_max.susp_fen) { 208362306a36Sopenharmony_ci /* case1: The outdate peer handler is successful: */ 208462306a36Sopenharmony_ci if (ns_max.pdsk <= D_OUTDATED) { 208562306a36Sopenharmony_ci rcu_read_lock(); 208662306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 208762306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 208862306a36Sopenharmony_ci if (test_bit(NEW_CUR_UUID, &device->flags)) { 208962306a36Sopenharmony_ci drbd_uuid_new_current(device); 209062306a36Sopenharmony_ci clear_bit(NEW_CUR_UUID, &device->flags); 209162306a36Sopenharmony_ci } 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci rcu_read_unlock(); 209462306a36Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 209562306a36Sopenharmony_ci _tl_restart(connection, CONNECTION_LOST_WHILE_PENDING); 209662306a36Sopenharmony_ci _conn_request_state(connection, 209762306a36Sopenharmony_ci (union drbd_state) { { .susp_fen = 1 } }, 209862306a36Sopenharmony_ci (union drbd_state) { { .susp_fen = 0 } }, 209962306a36Sopenharmony_ci CS_VERBOSE); 210062306a36Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 210162306a36Sopenharmony_ci } 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci conn_md_sync(connection); 210462306a36Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci return 0; 210762306a36Sopenharmony_ci} 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_cistatic void conn_old_common_state(struct drbd_connection *connection, union drbd_state *pcs, enum chg_state_flags *pf) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci enum chg_state_flags flags = ~0; 211262306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 211362306a36Sopenharmony_ci int vnr, first_vol = 1; 211462306a36Sopenharmony_ci union drbd_dev_state os, cs = { 211562306a36Sopenharmony_ci { .role = R_SECONDARY, 211662306a36Sopenharmony_ci .peer = R_UNKNOWN, 211762306a36Sopenharmony_ci .conn = connection->cstate, 211862306a36Sopenharmony_ci .disk = D_DISKLESS, 211962306a36Sopenharmony_ci .pdsk = D_UNKNOWN, 212062306a36Sopenharmony_ci } }; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci rcu_read_lock(); 212362306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 212462306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 212562306a36Sopenharmony_ci os = device->state; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci if (first_vol) { 212862306a36Sopenharmony_ci cs = os; 212962306a36Sopenharmony_ci first_vol = 0; 213062306a36Sopenharmony_ci continue; 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci if (cs.role != os.role) 213462306a36Sopenharmony_ci flags &= ~CS_DC_ROLE; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci if (cs.peer != os.peer) 213762306a36Sopenharmony_ci flags &= ~CS_DC_PEER; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (cs.conn != os.conn) 214062306a36Sopenharmony_ci flags &= ~CS_DC_CONN; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (cs.disk != os.disk) 214362306a36Sopenharmony_ci flags &= ~CS_DC_DISK; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (cs.pdsk != os.pdsk) 214662306a36Sopenharmony_ci flags &= ~CS_DC_PDSK; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci rcu_read_unlock(); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci *pf |= CS_DC_MASK; 215162306a36Sopenharmony_ci *pf &= flags; 215262306a36Sopenharmony_ci (*pcs).i = cs.i; 215362306a36Sopenharmony_ci} 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_cistatic enum drbd_state_rv 215662306a36Sopenharmony_ciconn_is_valid_transition(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 215762306a36Sopenharmony_ci enum chg_state_flags flags) 215862306a36Sopenharmony_ci{ 215962306a36Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 216062306a36Sopenharmony_ci union drbd_state ns, os; 216162306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 216262306a36Sopenharmony_ci int vnr; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci rcu_read_lock(); 216562306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 216662306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 216762306a36Sopenharmony_ci os = drbd_read_state(device); 216862306a36Sopenharmony_ci ns = sanitize_state(device, os, apply_mask_val(os, mask, val), NULL); 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED) 217162306a36Sopenharmony_ci ns.disk = os.disk; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci if (ns.i == os.i) 217462306a36Sopenharmony_ci continue; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci rv = is_valid_transition(os, ns); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci if (rv >= SS_SUCCESS && !(flags & CS_HARD)) { 217962306a36Sopenharmony_ci rv = is_valid_state(device, ns); 218062306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 218162306a36Sopenharmony_ci if (is_valid_state(device, os) == rv) 218262306a36Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 218362306a36Sopenharmony_ci } else 218462306a36Sopenharmony_ci rv = is_valid_soft_transition(os, ns, connection); 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci if (rv < SS_SUCCESS) { 218862306a36Sopenharmony_ci if (flags & CS_VERBOSE) 218962306a36Sopenharmony_ci print_st_err(device, os, ns, rv); 219062306a36Sopenharmony_ci break; 219162306a36Sopenharmony_ci } 219262306a36Sopenharmony_ci } 219362306a36Sopenharmony_ci rcu_read_unlock(); 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci return rv; 219662306a36Sopenharmony_ci} 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_cistatic void 219962306a36Sopenharmony_ciconn_set_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 220062306a36Sopenharmony_ci union drbd_state *pns_min, union drbd_state *pns_max, enum chg_state_flags flags) 220162306a36Sopenharmony_ci{ 220262306a36Sopenharmony_ci union drbd_state ns, os, ns_max = { }; 220362306a36Sopenharmony_ci union drbd_state ns_min = { 220462306a36Sopenharmony_ci { .role = R_MASK, 220562306a36Sopenharmony_ci .peer = R_MASK, 220662306a36Sopenharmony_ci .conn = val.conn, 220762306a36Sopenharmony_ci .disk = D_MASK, 220862306a36Sopenharmony_ci .pdsk = D_MASK 220962306a36Sopenharmony_ci } }; 221062306a36Sopenharmony_ci struct drbd_peer_device *peer_device; 221162306a36Sopenharmony_ci enum drbd_state_rv rv; 221262306a36Sopenharmony_ci int vnr, number_of_volumes = 0; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci if (mask.conn == C_MASK) { 221562306a36Sopenharmony_ci /* remember last connect time so request_timer_fn() won't 221662306a36Sopenharmony_ci * kill newly established sessions while we are still trying to thaw 221762306a36Sopenharmony_ci * previously frozen IO */ 221862306a36Sopenharmony_ci if (connection->cstate != C_WF_REPORT_PARAMS && val.conn == C_WF_REPORT_PARAMS) 221962306a36Sopenharmony_ci connection->last_reconnect_jif = jiffies; 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci connection->cstate = val.conn; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci rcu_read_lock(); 222562306a36Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 222662306a36Sopenharmony_ci struct drbd_device *device = peer_device->device; 222762306a36Sopenharmony_ci number_of_volumes++; 222862306a36Sopenharmony_ci os = drbd_read_state(device); 222962306a36Sopenharmony_ci ns = apply_mask_val(os, mask, val); 223062306a36Sopenharmony_ci ns = sanitize_state(device, os, ns, NULL); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci if (flags & CS_IGN_OUTD_FAIL && ns.disk == D_OUTDATED && os.disk < D_OUTDATED) 223362306a36Sopenharmony_ci ns.disk = os.disk; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci rv = _drbd_set_state(device, ns, flags, NULL); 223662306a36Sopenharmony_ci BUG_ON(rv < SS_SUCCESS); 223762306a36Sopenharmony_ci ns.i = device->state.i; 223862306a36Sopenharmony_ci ns_max.role = max_role(ns.role, ns_max.role); 223962306a36Sopenharmony_ci ns_max.peer = max_role(ns.peer, ns_max.peer); 224062306a36Sopenharmony_ci ns_max.conn = max_t(enum drbd_conns, ns.conn, ns_max.conn); 224162306a36Sopenharmony_ci ns_max.disk = max_t(enum drbd_disk_state, ns.disk, ns_max.disk); 224262306a36Sopenharmony_ci ns_max.pdsk = max_t(enum drbd_disk_state, ns.pdsk, ns_max.pdsk); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci ns_min.role = min_role(ns.role, ns_min.role); 224562306a36Sopenharmony_ci ns_min.peer = min_role(ns.peer, ns_min.peer); 224662306a36Sopenharmony_ci ns_min.conn = min_t(enum drbd_conns, ns.conn, ns_min.conn); 224762306a36Sopenharmony_ci ns_min.disk = min_t(enum drbd_disk_state, ns.disk, ns_min.disk); 224862306a36Sopenharmony_ci ns_min.pdsk = min_t(enum drbd_disk_state, ns.pdsk, ns_min.pdsk); 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci rcu_read_unlock(); 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci if (number_of_volumes == 0) { 225362306a36Sopenharmony_ci ns_min = ns_max = (union drbd_state) { { 225462306a36Sopenharmony_ci .role = R_SECONDARY, 225562306a36Sopenharmony_ci .peer = R_UNKNOWN, 225662306a36Sopenharmony_ci .conn = val.conn, 225762306a36Sopenharmony_ci .disk = D_DISKLESS, 225862306a36Sopenharmony_ci .pdsk = D_UNKNOWN 225962306a36Sopenharmony_ci } }; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci ns_min.susp = ns_max.susp = connection->resource->susp; 226362306a36Sopenharmony_ci ns_min.susp_nod = ns_max.susp_nod = connection->resource->susp_nod; 226462306a36Sopenharmony_ci ns_min.susp_fen = ns_max.susp_fen = connection->resource->susp_fen; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci *pns_min = ns_min; 226762306a36Sopenharmony_ci *pns_max = ns_max; 226862306a36Sopenharmony_ci} 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_cistatic enum drbd_state_rv 227162306a36Sopenharmony_ci_conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union drbd_state val) 227262306a36Sopenharmony_ci{ 227362306a36Sopenharmony_ci enum drbd_state_rv err, rv = SS_UNKNOWN_ERROR; /* continue waiting */; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &connection->flags)) 227662306a36Sopenharmony_ci rv = SS_CW_SUCCESS; 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &connection->flags)) 227962306a36Sopenharmony_ci rv = SS_CW_FAILED_BY_PEER; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci err = conn_is_valid_transition(connection, mask, val, 0); 228262306a36Sopenharmony_ci if (err == SS_SUCCESS && connection->cstate == C_WF_REPORT_PARAMS) 228362306a36Sopenharmony_ci return rv; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci return err; 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_cienum drbd_state_rv 228962306a36Sopenharmony_ci_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 229062306a36Sopenharmony_ci enum chg_state_flags flags) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci enum drbd_state_rv rv = SS_SUCCESS; 229362306a36Sopenharmony_ci struct after_conn_state_chg_work *acscw; 229462306a36Sopenharmony_ci enum drbd_conns oc = connection->cstate; 229562306a36Sopenharmony_ci union drbd_state ns_max, ns_min, os; 229662306a36Sopenharmony_ci bool have_mutex = false; 229762306a36Sopenharmony_ci struct drbd_state_change *state_change; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci if (mask.conn) { 230062306a36Sopenharmony_ci rv = is_valid_conn_transition(oc, val.conn); 230162306a36Sopenharmony_ci if (rv < SS_SUCCESS) 230262306a36Sopenharmony_ci goto abort; 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci rv = conn_is_valid_transition(connection, mask, val, flags); 230662306a36Sopenharmony_ci if (rv < SS_SUCCESS) 230762306a36Sopenharmony_ci goto abort; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING && 231062306a36Sopenharmony_ci !(flags & (CS_LOCAL_ONLY | CS_HARD))) { 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci /* This will be a cluster-wide state change. 231362306a36Sopenharmony_ci * Need to give up the spinlock, grab the mutex, 231462306a36Sopenharmony_ci * then send the state change request, ... */ 231562306a36Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 231662306a36Sopenharmony_ci mutex_lock(&connection->cstate_mutex); 231762306a36Sopenharmony_ci have_mutex = true; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci set_bit(CONN_WD_ST_CHG_REQ, &connection->flags); 232062306a36Sopenharmony_ci if (conn_send_state_req(connection, mask, val)) { 232162306a36Sopenharmony_ci /* sending failed. */ 232262306a36Sopenharmony_ci clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags); 232362306a36Sopenharmony_ci rv = SS_CW_FAILED_BY_PEER; 232462306a36Sopenharmony_ci /* need to re-aquire the spin lock, though */ 232562306a36Sopenharmony_ci goto abort_unlocked; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci if (val.conn == C_DISCONNECTING) 232962306a36Sopenharmony_ci set_bit(DISCONNECT_SENT, &connection->flags); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci /* ... and re-aquire the spinlock. 233262306a36Sopenharmony_ci * If _conn_rq_cond() returned >= SS_SUCCESS, we must call 233362306a36Sopenharmony_ci * conn_set_state() within the same spinlock. */ 233462306a36Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 233562306a36Sopenharmony_ci wait_event_lock_irq(connection->ping_wait, 233662306a36Sopenharmony_ci (rv = _conn_rq_cond(connection, mask, val)), 233762306a36Sopenharmony_ci connection->resource->req_lock); 233862306a36Sopenharmony_ci clear_bit(CONN_WD_ST_CHG_REQ, &connection->flags); 233962306a36Sopenharmony_ci if (rv < SS_SUCCESS) 234062306a36Sopenharmony_ci goto abort; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci state_change = remember_old_state(connection->resource, GFP_ATOMIC); 234462306a36Sopenharmony_ci conn_old_common_state(connection, &os, &flags); 234562306a36Sopenharmony_ci flags |= CS_DC_SUSP; 234662306a36Sopenharmony_ci conn_set_state(connection, mask, val, &ns_min, &ns_max, flags); 234762306a36Sopenharmony_ci conn_pr_state_change(connection, os, ns_max, flags); 234862306a36Sopenharmony_ci remember_new_state(state_change); 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC); 235162306a36Sopenharmony_ci if (acscw) { 235262306a36Sopenharmony_ci acscw->oc = os.conn; 235362306a36Sopenharmony_ci acscw->ns_min = ns_min; 235462306a36Sopenharmony_ci acscw->ns_max = ns_max; 235562306a36Sopenharmony_ci acscw->flags = flags; 235662306a36Sopenharmony_ci acscw->w.cb = w_after_conn_state_ch; 235762306a36Sopenharmony_ci kref_get(&connection->kref); 235862306a36Sopenharmony_ci acscw->connection = connection; 235962306a36Sopenharmony_ci acscw->state_change = state_change; 236062306a36Sopenharmony_ci drbd_queue_work(&connection->sender_work, &acscw->w); 236162306a36Sopenharmony_ci } else { 236262306a36Sopenharmony_ci drbd_err(connection, "Could not kmalloc an acscw\n"); 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci abort: 236662306a36Sopenharmony_ci if (have_mutex) { 236762306a36Sopenharmony_ci /* mutex_unlock() "... must not be used in interrupt context.", 236862306a36Sopenharmony_ci * so give up the spinlock, then re-aquire it */ 236962306a36Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 237062306a36Sopenharmony_ci abort_unlocked: 237162306a36Sopenharmony_ci mutex_unlock(&connection->cstate_mutex); 237262306a36Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci if (rv < SS_SUCCESS && flags & CS_VERBOSE) { 237562306a36Sopenharmony_ci drbd_err(connection, "State change failed: %s\n", drbd_set_st_err_str(rv)); 237662306a36Sopenharmony_ci drbd_err(connection, " mask = 0x%x val = 0x%x\n", mask.i, val.i); 237762306a36Sopenharmony_ci drbd_err(connection, " old_conn:%s wanted_conn:%s\n", drbd_conn_str(oc), drbd_conn_str(val.conn)); 237862306a36Sopenharmony_ci } 237962306a36Sopenharmony_ci return rv; 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cienum drbd_state_rv 238362306a36Sopenharmony_ciconn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, 238462306a36Sopenharmony_ci enum chg_state_flags flags) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci enum drbd_state_rv rv; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 238962306a36Sopenharmony_ci rv = _conn_request_state(connection, mask, val, flags); 239062306a36Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci return rv; 239362306a36Sopenharmony_ci} 2394