1 /*
2  * Copyright (c) 2015-2017 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Jan Friesse (jfriesse@redhat.com)
7  *
8  * This software licensed under BSD license, the text of which follows:
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  * - Neither the name of the Red Hat, Inc. nor the names of its
19  *   contributors may be used to endorse or promote products derived from this
20  *   software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "qnet-config.h"
36 #include "qdevice-log.h"
37 #include "qdevice-net-cast-vote-timer.h"
38 #include "qdevice-votequorum.h"
39 
40 static int
qdevice_net_cast_vote_timer_callback(void * data1,void * data2)41 qdevice_net_cast_vote_timer_callback(void *data1, void *data2)
42 {
43 	struct qdevice_net_instance *instance;
44 	int cast_vote;
45 	int case_processed;
46 
47 	instance = (struct qdevice_net_instance *)data1;
48 
49 	if (instance->cast_vote_timer_paused) {
50 		return (-1);
51 	}
52 
53 	case_processed = 0;
54 
55 	switch (instance->cast_vote_timer_vote) {
56 	case TLV_VOTE_ACK:
57 		case_processed = 1;
58 		cast_vote = 1;
59 		break;
60 	case TLV_VOTE_NACK:
61 		case_processed = 1;
62 		cast_vote = 0;
63 		break;
64 	case TLV_VOTE_ASK_LATER:
65 	case TLV_VOTE_WAIT_FOR_REPLY:
66 	case TLV_VOTE_NO_CHANGE:
67 	case TLV_VOTE_UNDEFINED:
68 		/*
69 		 * Shouldn't happen
70 		 */
71 		break;
72 	/*
73 	 * Default is not defined intentionally. Compiler shows warning when
74 	 * new tlv_vote is added.
75 	 */
76 	}
77 
78 	if (!case_processed) {
79 		qdevice_log(LOG_CRIT, "qdevice_net_timer_cast_vote: Unhandled cast_vote_timer_vote %u\n",
80 		    instance->cast_vote_timer_vote);
81 		exit(1);
82 	}
83 
84 	if (qdevice_votequorum_poll(instance->qdevice_instance_ptr, cast_vote) != 0) {
85 		instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER;
86 		instance->schedule_disconnect = 1;
87 		instance->cast_vote_timer = NULL;
88 		return (0);
89 	}
90 
91 	/*
92 	 * Schedule this function callback again
93 	 */
94 	return (-1);
95 }
96 
97 int
qdevice_net_cast_vote_timer_update(struct qdevice_net_instance * instance,enum tlv_vote vote)98 qdevice_net_cast_vote_timer_update(struct qdevice_net_instance *instance, enum tlv_vote vote)
99 {
100 	int timer_needs_running;
101 	int case_processed;
102 
103 	case_processed = 0;
104 
105 	switch (vote) {
106 	case TLV_VOTE_UNDEFINED:
107 		break;
108 	case TLV_VOTE_ACK:
109 	case TLV_VOTE_NACK:
110 		case_processed = 1;
111 		timer_needs_running = 1;
112 		break;
113 	case TLV_VOTE_WAIT_FOR_REPLY:
114 	case TLV_VOTE_ASK_LATER:
115 		case_processed = 1;
116 		timer_needs_running = 0;
117 		break;
118 	case TLV_VOTE_NO_CHANGE:
119 		case_processed = 1;
120 		return (0);
121 
122 		break;
123 	/*
124 	 * Default is not defined intentionally. Compiler shows warning when
125 	 * new tlv_vote is added.
126 	 */
127 	}
128 
129 	if (!case_processed) {
130 		qdevice_log(LOG_CRIT, "qdevice_net_cast_vote_timer_update_vote: Unhandled vote parameter %u\n",
131 		    vote);
132 		exit(1);
133 	}
134 
135 	instance->cast_vote_timer_vote = vote;
136 
137 	if (timer_needs_running) {
138 		if (instance->cast_vote_timer == NULL) {
139 			instance->cast_vote_timer = timer_list_add(&instance->main_timer_list,
140 			    instance->cast_vote_timer_interval,
141 			    qdevice_net_cast_vote_timer_callback, (void *)instance, NULL);
142 
143 			if (instance->cast_vote_timer == NULL) {
144 				qdevice_log(LOG_ERR, "Can't schedule sending of "
145 				    "votequorum poll");
146 
147 				return (-1);
148 			} else {
149 				qdevice_log(LOG_DEBUG, "Cast vote timer is now scheduled every "
150 				    "%"PRIu32"ms voting %s.", instance->cast_vote_timer_interval,
151 				    tlv_vote_to_str(instance->cast_vote_timer_vote));
152 			}
153 		} else {
154 			qdevice_log(LOG_DEBUG, "Cast vote timer remains scheduled every "
155 			    "%"PRIu32"ms voting %s.", instance->cast_vote_timer_interval,
156 			    tlv_vote_to_str(instance->cast_vote_timer_vote));
157 		}
158 
159 		if (qdevice_net_cast_vote_timer_callback((void *)instance, NULL) != -1) {
160 			return (-1);
161 		}
162 	} else {
163 		if (instance->cast_vote_timer != NULL) {
164 			timer_list_delete(&instance->main_timer_list, instance->cast_vote_timer);
165 			instance->cast_vote_timer = NULL;
166 			qdevice_log(LOG_DEBUG, "Cast vote timer is now stopped.");
167 		} else {
168 			qdevice_log(LOG_DEBUG, "Cast vote timer remains stopped.");
169 		}
170 	}
171 
172 	return (0);
173 }
174 
175 void
qdevice_net_cast_vote_timer_set_paused(struct qdevice_net_instance * instance,int paused)176 qdevice_net_cast_vote_timer_set_paused(struct qdevice_net_instance *instance, int paused)
177 {
178 
179 	if (paused != instance->cast_vote_timer_paused) {
180 		instance->cast_vote_timer_paused = paused;
181 
182 		if (instance->cast_vote_timer_paused) {
183 			qdevice_log(LOG_DEBUG, "Cast vote timer is now paused.");
184 		} else {
185 			qdevice_log(LOG_DEBUG, "Cast vote timer is no longer paused.");
186 		}
187 	}
188 }
189