aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/stack_user.c94
1 files changed, 89 insertions, 5 deletions
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index ff8d30757924..a5e58e2b9d59 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -35,9 +35,21 @@
35 * of output is a supported protocol tag. All protocol tags are a single 35 * of output is a supported protocol tag. All protocol tags are a single
36 * character followed by a two hex digit version number. Currently the 36 * character followed by a two hex digit version number. Currently the
37 * only things supported is T01, for "Text-base version 0x01". Next, the 37 * only things supported is T01, for "Text-base version 0x01". Next, the
38 * client writes the version they would like to use. If the version tag 38 * client writes the version they would like to use, including the newline.
39 * written is unknown, -EINVAL is returned. Once the negotiation is 39 * Thus, the protocol tag is 'T01\n'. If the version tag written is
40 * complete, the client can start sending messages. 40 * unknown, -EINVAL is returned. Once the negotiation is complete, the
41 * client can start sending messages.
42 *
43 * The T01 protocol only has one message, "DOWN". It has the following
44 * syntax:
45 *
46 * DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline>
47 *
48 * eg:
49 *
50 * DOWN 632A924FDD844190BDA93C0DF6B94899 00000001\n
51 *
52 * This is 47 characters.
41 */ 53 */
42 54
43/* 55/*
@@ -49,6 +61,11 @@
49#define OCFS2_CONTROL_HANDSHAKE_INVALID (0) 61#define OCFS2_CONTROL_HANDSHAKE_INVALID (0)
50#define OCFS2_CONTROL_HANDSHAKE_READ (1) 62#define OCFS2_CONTROL_HANDSHAKE_READ (1)
51#define OCFS2_CONTROL_HANDSHAKE_VALID (2) 63#define OCFS2_CONTROL_HANDSHAKE_VALID (2)
64#define OCFS2_CONTROL_MESSAGE_DOWN "DOWN"
65#define OCFS2_CONTROL_MESSAGE_DOWN_LEN 4
66#define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN 47
67#define OCFS2_TEXT_UUID_LEN 32
68#define OCFS2_CONTROL_MESSAGE_NODENUM_LEN 8
52 69
53/* 70/*
54 * ocfs2_live_connection is refcounted because the filesystem and 71 * ocfs2_live_connection is refcounted because the filesystem and
@@ -149,7 +166,7 @@ static void ocfs2_live_connection_drop(struct ocfs2_live_connection *c)
149 kfree(c); 166 kfree(c);
150} 167}
151 168
152static ssize_t ocfs2_control_cfu(char *target, size_t target_len, 169static ssize_t ocfs2_control_cfu(void *target, size_t target_len,
153 const char __user *buf, size_t count) 170 const char __user *buf, size_t count)
154{ 171{
155 /* The T01 expects write(2) calls to have exactly one command */ 172 /* The T01 expects write(2) calls to have exactly one command */
@@ -185,6 +202,73 @@ static ssize_t ocfs2_control_validate_handshake(struct file *file,
185 return count; 202 return count;
186} 203}
187 204
205static void ocfs2_control_send_down(const char *uuid,
206 int nodenum)
207{
208 struct ocfs2_live_connection *c;
209
210 mutex_lock(&ocfs2_control_lock);
211
212 c = ocfs2_connection_find(uuid);
213 if (c) {
214 BUG_ON(c->oc_conn == NULL);
215 c->oc_conn->cc_recovery_handler(nodenum,
216 c->oc_conn->cc_recovery_data);
217 }
218
219 mutex_unlock(&ocfs2_control_lock);
220}
221
222/* DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> */
223struct ocfs2_control_message_down {
224 char tag[OCFS2_CONTROL_MESSAGE_DOWN_LEN];
225 char space1;
226 char uuid[OCFS2_TEXT_UUID_LEN];
227 char space2;
228 char nodestr[OCFS2_CONTROL_MESSAGE_NODENUM_LEN];
229 char newline;
230};
231
232static ssize_t ocfs2_control_message(struct file *file,
233 const char __user *buf,
234 size_t count)
235{
236 ssize_t ret;
237 char *p = NULL;
238 long nodenum;
239 struct ocfs2_control_message_down msg;
240
241 /* Try to catch padding issues */
242 WARN_ON(offsetof(struct ocfs2_control_message_down, uuid) !=
243 (sizeof(msg.tag) + sizeof(msg.space1)));
244
245 memset(&msg, 0, sizeof(struct ocfs2_control_message_down));
246 ret = ocfs2_control_cfu(&msg, OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN,
247 buf, count);
248 if (ret != count)
249 return ret;
250
251 if (strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_DOWN,
252 strlen(OCFS2_CONTROL_MESSAGE_DOWN)))
253 return -EINVAL;
254
255 if ((msg.space1 != ' ') || (msg.space2 != ' ') ||
256 (msg.newline != '\n'))
257 return -EINVAL;
258 msg.space1 = msg.space2 = msg.newline = '\0';
259
260 nodenum = simple_strtol(msg.nodestr, &p, 16);
261 if (!p || *p)
262 return -EINVAL;
263
264 if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
265 (nodenum > INT_MAX) || (nodenum < 0))
266 return -ERANGE;
267
268 ocfs2_control_send_down(msg.uuid, nodenum);
269
270 return count;
271}
188 272
189static ssize_t ocfs2_control_write(struct file *file, 273static ssize_t ocfs2_control_write(struct file *file,
190 const char __user *buf, 274 const char __user *buf,
@@ -204,7 +288,7 @@ static ssize_t ocfs2_control_write(struct file *file,
204 break; 288 break;
205 289
206 case OCFS2_CONTROL_HANDSHAKE_VALID: 290 case OCFS2_CONTROL_HANDSHAKE_VALID:
207 ret = count; /* XXX */ 291 ret = ocfs2_control_message(file, buf, count);
208 break; 292 break;
209 293
210 default: 294 default: