📄 dlmdomain.c
字号:
ret = dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN; spin_unlock(&dlm->spinlock); return ret;}static void dlm_mark_domain_leaving(struct dlm_ctxt *dlm){ /* Yikes, a double spinlock! I need domain_lock for the dlm * state and the dlm spinlock for join state... Sorry! */again: spin_lock(&dlm_domain_lock); spin_lock(&dlm->spinlock); if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { mlog(0, "Node %d is joining, we wait on it.\n", dlm->joining_node); spin_unlock(&dlm->spinlock); spin_unlock(&dlm_domain_lock); wait_event(dlm->dlm_join_events, dlm_no_joining_node(dlm)); goto again; } dlm->dlm_state = DLM_CTXT_LEAVING; spin_unlock(&dlm->spinlock); spin_unlock(&dlm_domain_lock);}static void __dlm_print_nodes(struct dlm_ctxt *dlm){ int node = -1; assert_spin_locked(&dlm->spinlock); printk(KERN_INFO "ocfs2_dlm: Nodes in domain (\"%s\"): ", dlm->name); while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, node + 1)) < O2NM_MAX_NODES) { printk("%d ", node); } printk("\n");}static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data){ struct dlm_ctxt *dlm = data; unsigned int node; struct dlm_exit_domain *exit_msg = (struct dlm_exit_domain *) msg->buf; mlog_entry("%p %u %p", msg, len, data); if (!dlm_grab(dlm)) return 0; node = exit_msg->node_idx; printk(KERN_INFO "ocfs2_dlm: Node %u leaves domain %s\n", node, dlm->name); spin_lock(&dlm->spinlock); clear_bit(node, dlm->domain_map); __dlm_print_nodes(dlm); /* notify anything attached to the heartbeat events */ dlm_hb_event_notify_attached(dlm, node, 0); spin_unlock(&dlm->spinlock); dlm_put(dlm); return 0;}static int dlm_send_one_domain_exit(struct dlm_ctxt *dlm, unsigned int node){ int status; struct dlm_exit_domain leave_msg; mlog(0, "Asking node %u if we can leave the domain %s me = %u\n", node, dlm->name, dlm->node_num); memset(&leave_msg, 0, sizeof(leave_msg)); leave_msg.node_idx = dlm->node_num; status = o2net_send_message(DLM_EXIT_DOMAIN_MSG, dlm->key, &leave_msg, sizeof(leave_msg), node, NULL); mlog(0, "status return %d from o2net_send_message\n", status); return status;}static void dlm_leave_domain(struct dlm_ctxt *dlm){ int node, clear_node, status; /* At this point we've migrated away all our locks and won't * accept mastership of new ones. The dlm is responsible for * almost nothing now. We make sure not to confuse any joining * nodes and then commence shutdown procedure. */ spin_lock(&dlm->spinlock); /* Clear ourselves from the domain map */ clear_bit(dlm->node_num, dlm->domain_map); while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, 0)) < O2NM_MAX_NODES) { /* Drop the dlm spinlock. This is safe wrt the domain_map. * -nodes cannot be added now as the * query_join_handlers knows to respond with OK_NO_MAP * -we catch the right network errors if a node is * removed from the map while we're sending him the * exit message. */ spin_unlock(&dlm->spinlock); clear_node = 1; status = dlm_send_one_domain_exit(dlm, node); if (status < 0 && status != -ENOPROTOOPT && status != -ENOTCONN) { mlog(ML_NOTICE, "Error %d sending domain exit message " "to node %d\n", status, node); /* Not sure what to do here but lets sleep for * a bit in case this was a transient * error... */ msleep(DLM_DOMAIN_BACKOFF_MS); clear_node = 0; } spin_lock(&dlm->spinlock); /* If we're not clearing the node bit then we intend * to loop back around to try again. */ if (clear_node) clear_bit(node, dlm->domain_map); } spin_unlock(&dlm->spinlock);}int dlm_joined(struct dlm_ctxt *dlm){ int ret = 0; spin_lock(&dlm_domain_lock); if (dlm->dlm_state == DLM_CTXT_JOINED) ret = 1; spin_unlock(&dlm_domain_lock); return ret;}int dlm_shutting_down(struct dlm_ctxt *dlm){ int ret = 0; spin_lock(&dlm_domain_lock); if (dlm->dlm_state == DLM_CTXT_IN_SHUTDOWN) ret = 1; spin_unlock(&dlm_domain_lock); return ret;}void dlm_unregister_domain(struct dlm_ctxt *dlm){ int leave = 0; struct dlm_lock_resource *res; spin_lock(&dlm_domain_lock); BUG_ON(dlm->dlm_state != DLM_CTXT_JOINED); BUG_ON(!dlm->num_joins); dlm->num_joins--; if (!dlm->num_joins) { /* We mark it "in shutdown" now so new register * requests wait until we've completely left the * domain. Don't use DLM_CTXT_LEAVING yet as we still * want new domain joins to communicate with us at * least until we've completed migration of our * resources. */ dlm->dlm_state = DLM_CTXT_IN_SHUTDOWN; leave = 1; } spin_unlock(&dlm_domain_lock); if (leave) { mlog(0, "shutting down domain %s\n", dlm->name); /* We changed dlm state, notify the thread */ dlm_kick_thread(dlm, NULL); while (dlm_migrate_all_locks(dlm)) { /* Give dlm_thread time to purge the lockres' */ msleep(500); mlog(0, "%s: more migration to do\n", dlm->name); } /* This list should be empty. If not, print remaining lockres */ if (!list_empty(&dlm->tracking_list)) { mlog(ML_ERROR, "Following lockres' are still on the " "tracking list:\n"); list_for_each_entry(res, &dlm->tracking_list, tracking) dlm_print_one_lock_resource(res); } dlm_mark_domain_leaving(dlm); dlm_leave_domain(dlm); dlm_complete_dlm_shutdown(dlm); } dlm_put(dlm);}EXPORT_SYMBOL_GPL(dlm_unregister_domain);static int dlm_query_join_proto_check(char *proto_type, int node, struct dlm_protocol_version *ours, struct dlm_protocol_version *request){ int rc; struct dlm_protocol_version proto = *request; if (!dlm_protocol_compare(ours, &proto)) { mlog(0, "node %u wanted to join with %s locking protocol " "%u.%u, we respond with %u.%u\n", node, proto_type, request->pv_major, request->pv_minor, proto.pv_major, proto.pv_minor); request->pv_minor = proto.pv_minor; rc = 0; } else { mlog(ML_NOTICE, "Node %u wanted to join with %s locking " "protocol %u.%u, but we have %u.%u, disallowing\n", node, proto_type, request->pv_major, request->pv_minor, ours->pv_major, ours->pv_minor); rc = 1; } return rc;}/* * struct dlm_query_join_packet is made up of four one-byte fields. They * are effectively in big-endian order already. However, little-endian * machines swap them before putting the packet on the wire (because * query_join's response is a status, and that status is treated as a u32 * on the wire). Thus, a big-endian and little-endian machines will treat * this structure differently. * * The solution is to have little-endian machines swap the structure when * converting from the structure to the u32 representation. This will * result in the structure having the correct format on the wire no matter * the host endian format. */static void dlm_query_join_packet_to_wire(struct dlm_query_join_packet *packet, u32 *wire){ union dlm_query_join_response response; response.packet = *packet; *wire = cpu_to_be32(response.intval);}static void dlm_query_join_wire_to_packet(u32 wire, struct dlm_query_join_packet *packet){ union dlm_query_join_response response; response.intval = cpu_to_be32(wire); *packet = response.packet;}static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data){ struct dlm_query_join_request *query; struct dlm_query_join_packet packet = { .code = JOIN_DISALLOW, }; struct dlm_ctxt *dlm = NULL; u32 response; u8 nodenum; query = (struct dlm_query_join_request *) msg->buf; mlog(0, "node %u wants to join domain %s\n", query->node_idx, query->domain); /* * If heartbeat doesn't consider the node live, tell it * to back off and try again. This gives heartbeat a chance * to catch up. */ if (!o2hb_check_node_heartbeating(query->node_idx)) { mlog(0, "node %u is not in our live map yet\n", query->node_idx); packet.code = JOIN_DISALLOW; goto respond; } packet.code = JOIN_OK_NO_MAP; spin_lock(&dlm_domain_lock); dlm = __dlm_lookup_domain_full(query->domain, query->name_len); if (!dlm) goto unlock_respond; /* * There is a small window where the joining node may not see the * node(s) that just left but still part of the cluster. DISALLOW * join request if joining node has different node map. */ nodenum=0; while (nodenum < O2NM_MAX_NODES) { if (test_bit(nodenum, dlm->domain_map)) { if (!byte_test_bit(nodenum, query->node_map)) { mlog(0, "disallow join as node %u does not " "have node %u in its nodemap\n", query->node_idx, nodenum); packet.code = JOIN_DISALLOW; goto unlock_respond; } } nodenum++; } /* Once the dlm ctxt is marked as leaving then we don't want * to be put in someone's domain map. * Also, explicitly disallow joining at certain troublesome * times (ie. during recovery). */ if (dlm && dlm->dlm_state != DLM_CTXT_LEAVING) { int bit = query->node_idx; spin_lock(&dlm->spinlock); if (dlm->dlm_state == DLM_CTXT_NEW && dlm->joining_node == DLM_LOCK_RES_OWNER_UNKNOWN) { /*If this is a brand new context and we * haven't started our join process yet, then * the other node won the race. */ packet.code = JOIN_OK_NO_MAP; } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { /* Disallow parallel joins. */ packet.code = JOIN_DISALLOW; } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { mlog(0, "node %u trying to join, but recovery " "is ongoing.\n", bit); packet.code = JOIN_DISALLOW; } else if (test_bit(bit, dlm->recovery_map)) { mlog(0, "node %u trying to join, but it " "still needs recovery.\n", bit); packet.code = JOIN_DISALLOW; } else if (test_bit(bit, dlm->domain_map)) { mlog(0, "node %u trying to join, but it " "is still in the domain! needs recovery?\n", bit); packet.code = JOIN_DISALLOW; } else { /* Alright we're fully a part of this domain * so we keep some state as to who's joining * and indicate to him that needs to be fixed * up. */ /* Make sure we speak compatible locking protocols. */ if (dlm_query_join_proto_check("DLM", bit, &dlm->dlm_locking_proto, &query->dlm_proto)) { packet.code = JOIN_PROTOCOL_MISMATCH; } else if (dlm_query_join_proto_check("fs", bit, &dlm->fs_locking_proto, &query->fs_proto)) { packet.code = JOIN_PROTOCOL_MISMATCH; } else { packet.dlm_minor = query->dlm_proto.pv_minor; packet.fs_minor = query->fs_proto.pv_minor; packet.code = JOIN_OK; __dlm_set_joining_node(dlm, query->node_idx); } } spin_unlock(&dlm->spinlock); }unlock_respond: spin_unlock(&dlm_domain_lock);respond: mlog(0, "We respond with %u\n", packet.code); dlm_query_join_packet_to_wire(&packet, &response); return response;}static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data){ struct dlm_assert_joined *assert; struct dlm_ctxt *dlm = NULL; assert = (struct dlm_assert_joined *) msg->buf; mlog(0, "node %u asserts join on domain %s\n", assert->node_idx, assert->domain); spin_lock(&dlm_domain_lock); dlm = __dlm_lookup_domain_full(assert->domain, assert->name_len); /* XXX should we consider no dlm ctxt an error? */ if (dlm) { spin_lock(&dlm->spinlock); /* Alright, this node has officially joined our * domain. Set him in the map and clean up our * leftover join state. */ BUG_ON(dlm->joining_node != assert->node_idx); set_bit(assert->node_idx, dlm->domain_map); __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); printk(KERN_INFO "ocfs2_dlm: Node %u joins domain %s\n", assert->node_idx, dlm->name); __dlm_print_nodes(dlm); /* notify anything attached to the heartbeat events */ dlm_hb_event_notify_attached(dlm, assert->node_idx, 1); spin_unlock(&dlm->spinlock); } spin_unlock(&dlm_domain_lock); return 0;}static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data){ struct dlm_cancel_join *cancel; struct dlm_ctxt *dlm = NULL; cancel = (struct dlm_cancel_join *) msg->buf; mlog(0, "node %u cancels join on domain %s\n", cancel->node_idx, cancel->domain); spin_lock(&dlm_domain_lock); dlm = __dlm_lookup_domain_full(cancel->domain, cancel->name_len); if (dlm) { spin_lock(&dlm->spinlock); /* Yikes, this guy wants to cancel his join. No * problem, we simply cleanup our join state. */ BUG_ON(dlm->joining_node != cancel->node_idx); __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); spin_unlock(&dlm->spinlock); } spin_unlock(&dlm_domain_lock); return 0;}static int dlm_send_one_join_cancel(struct dlm_ctxt *dlm, unsigned int node){ int status; struct dlm_cancel_join cancel_msg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -