diff options
Diffstat (limited to 'fs/ocfs2/stack_user.c')
-rw-r--r-- | fs/ocfs2/stack_user.c | 131 |
1 files changed, 119 insertions, 12 deletions
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 43e6105369c6..de982c11e69b 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -40,7 +40,7 @@ | |||
40 | * unknown, -EINVAL is returned. Once the negotiation is complete, the | 40 | * unknown, -EINVAL is returned. Once the negotiation is complete, the |
41 | * client can start sending messages. | 41 | * client can start sending messages. |
42 | * | 42 | * |
43 | * The T01 protocol only has two messages. First is the "SETN" message. | 43 | * The T01 protocol has three messages. First is the "SETN" message. |
44 | * It has the following syntax: | 44 | * It has the following syntax: |
45 | * | 45 | * |
46 | * SETN<space><8-char-hex-nodenum><newline> | 46 | * SETN<space><8-char-hex-nodenum><newline> |
@@ -50,8 +50,22 @@ | |||
50 | * The "SETN" message must be the first message following the protocol. | 50 | * The "SETN" message must be the first message following the protocol. |
51 | * It tells ocfs2_control the local node number. | 51 | * It tells ocfs2_control the local node number. |
52 | * | 52 | * |
53 | * Once the local node number has been set, the "DOWN" message can be | 53 | * Next comes the "SETV" message. It has the following syntax: |
54 | * sent for node down notification. It has the following syntax: | 54 | * |
55 | * SETV<space><2-char-hex-major><space><2-char-hex-minor><newline> | ||
56 | * | ||
57 | * This is 11 characters. | ||
58 | * | ||
59 | * The "SETV" message sets the filesystem locking protocol version as | ||
60 | * negotiated by the client. The client negotiates based on the maximum | ||
61 | * version advertised in /sys/fs/ocfs2/max_locking_protocol. The major | ||
62 | * number from the "SETV" message must match | ||
63 | * user_stack.sp_proto->lp_max_version.pv_major, and the minor number | ||
64 | * must be less than or equal to ...->lp_max_version.pv_minor. | ||
65 | * | ||
66 | * Once this information has been set, mounts will be allowed. From this | ||
67 | * point on, the "DOWN" message can be sent for node down notification. | ||
68 | * It has the following syntax: | ||
55 | * | 69 | * |
56 | * DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> | 70 | * DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> |
57 | * | 71 | * |
@@ -79,9 +93,12 @@ | |||
79 | #define OCFS2_CONTROL_MESSAGE_OP_LEN 4 | 93 | #define OCFS2_CONTROL_MESSAGE_OP_LEN 4 |
80 | #define OCFS2_CONTROL_MESSAGE_SETNODE_OP "SETN" | 94 | #define OCFS2_CONTROL_MESSAGE_SETNODE_OP "SETN" |
81 | #define OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN 14 | 95 | #define OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN 14 |
96 | #define OCFS2_CONTROL_MESSAGE_SETVERSION_OP "SETV" | ||
97 | #define OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN 11 | ||
82 | #define OCFS2_CONTROL_MESSAGE_DOWN_OP "DOWN" | 98 | #define OCFS2_CONTROL_MESSAGE_DOWN_OP "DOWN" |
83 | #define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN 47 | 99 | #define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN 47 |
84 | #define OCFS2_TEXT_UUID_LEN 32 | 100 | #define OCFS2_TEXT_UUID_LEN 32 |
101 | #define OCFS2_CONTROL_MESSAGE_VERNUM_LEN 2 | ||
85 | #define OCFS2_CONTROL_MESSAGE_NODENUM_LEN 8 | 102 | #define OCFS2_CONTROL_MESSAGE_NODENUM_LEN 8 |
86 | 103 | ||
87 | /* | 104 | /* |
@@ -97,6 +114,7 @@ struct ocfs2_control_private { | |||
97 | struct list_head op_list; | 114 | struct list_head op_list; |
98 | int op_state; | 115 | int op_state; |
99 | int op_this_node; | 116 | int op_this_node; |
117 | struct ocfs2_protocol_version op_proto; | ||
100 | }; | 118 | }; |
101 | 119 | ||
102 | /* SETN<space><8-char-hex-nodenum><newline> */ | 120 | /* SETN<space><8-char-hex-nodenum><newline> */ |
@@ -107,6 +125,16 @@ struct ocfs2_control_message_setn { | |||
107 | char newline; | 125 | char newline; |
108 | }; | 126 | }; |
109 | 127 | ||
128 | /* SETV<space><2-char-hex-major><space><2-char-hex-minor><newline> */ | ||
129 | struct ocfs2_control_message_setv { | ||
130 | char tag[OCFS2_CONTROL_MESSAGE_OP_LEN]; | ||
131 | char space1; | ||
132 | char major[OCFS2_CONTROL_MESSAGE_VERNUM_LEN]; | ||
133 | char space2; | ||
134 | char minor[OCFS2_CONTROL_MESSAGE_VERNUM_LEN]; | ||
135 | char newline; | ||
136 | }; | ||
137 | |||
110 | /* DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> */ | 138 | /* DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> */ |
111 | struct ocfs2_control_message_down { | 139 | struct ocfs2_control_message_down { |
112 | char tag[OCFS2_CONTROL_MESSAGE_OP_LEN]; | 140 | char tag[OCFS2_CONTROL_MESSAGE_OP_LEN]; |
@@ -120,11 +148,13 @@ struct ocfs2_control_message_down { | |||
120 | union ocfs2_control_message { | 148 | union ocfs2_control_message { |
121 | char tag[OCFS2_CONTROL_MESSAGE_OP_LEN]; | 149 | char tag[OCFS2_CONTROL_MESSAGE_OP_LEN]; |
122 | struct ocfs2_control_message_setn u_setn; | 150 | struct ocfs2_control_message_setn u_setn; |
151 | struct ocfs2_control_message_setv u_setv; | ||
123 | struct ocfs2_control_message_down u_down; | 152 | struct ocfs2_control_message_down u_down; |
124 | }; | 153 | }; |
125 | 154 | ||
126 | static atomic_t ocfs2_control_opened; | 155 | static atomic_t ocfs2_control_opened; |
127 | static int ocfs2_control_this_node = -1; | 156 | static int ocfs2_control_this_node = -1; |
157 | static struct ocfs2_protocol_version running_proto; | ||
128 | 158 | ||
129 | static LIST_HEAD(ocfs2_live_connection_list); | 159 | static LIST_HEAD(ocfs2_live_connection_list); |
130 | static LIST_HEAD(ocfs2_control_private_list); | 160 | static LIST_HEAD(ocfs2_control_private_list); |
@@ -264,8 +294,9 @@ static void ocfs2_control_send_down(const char *uuid, | |||
264 | /* | 294 | /* |
265 | * Called whenever configuration elements are sent to /dev/ocfs2_control. | 295 | * Called whenever configuration elements are sent to /dev/ocfs2_control. |
266 | * If all configuration elements are present, try to set the global | 296 | * If all configuration elements are present, try to set the global |
267 | * values. If not, return -EAGAIN. If there is a problem, return a | 297 | * values. If there is a problem, return an error. Skip any missing |
268 | * different error. | 298 | * elements, and only bump ocfs2_control_opened when we have all elements |
299 | * and are successful. | ||
269 | */ | 300 | */ |
270 | static int ocfs2_control_install_private(struct file *file) | 301 | static int ocfs2_control_install_private(struct file *file) |
271 | { | 302 | { |
@@ -275,15 +306,32 @@ static int ocfs2_control_install_private(struct file *file) | |||
275 | 306 | ||
276 | BUG_ON(p->op_state != OCFS2_CONTROL_HANDSHAKE_PROTOCOL); | 307 | BUG_ON(p->op_state != OCFS2_CONTROL_HANDSHAKE_PROTOCOL); |
277 | 308 | ||
278 | if (p->op_this_node < 0) | 309 | mutex_lock(&ocfs2_control_lock); |
310 | |||
311 | if (p->op_this_node < 0) { | ||
279 | set_p = 0; | 312 | set_p = 0; |
313 | } else if ((ocfs2_control_this_node >= 0) && | ||
314 | (ocfs2_control_this_node != p->op_this_node)) { | ||
315 | rc = -EINVAL; | ||
316 | goto out_unlock; | ||
317 | } | ||
280 | 318 | ||
281 | mutex_lock(&ocfs2_control_lock); | 319 | if (!p->op_proto.pv_major) { |
282 | if (ocfs2_control_this_node < 0) { | 320 | set_p = 0; |
283 | if (set_p) | 321 | } else if (!list_empty(&ocfs2_live_connection_list) && |
284 | ocfs2_control_this_node = p->op_this_node; | 322 | ((running_proto.pv_major != p->op_proto.pv_major) || |
285 | } else if (ocfs2_control_this_node != p->op_this_node) | 323 | (running_proto.pv_minor != p->op_proto.pv_minor))) { |
286 | rc = -EINVAL; | 324 | rc = -EINVAL; |
325 | goto out_unlock; | ||
326 | } | ||
327 | |||
328 | if (set_p) { | ||
329 | ocfs2_control_this_node = p->op_this_node; | ||
330 | running_proto.pv_major = p->op_proto.pv_major; | ||
331 | running_proto.pv_minor = p->op_proto.pv_minor; | ||
332 | } | ||
333 | |||
334 | out_unlock: | ||
287 | mutex_unlock(&ocfs2_control_lock); | 335 | mutex_unlock(&ocfs2_control_lock); |
288 | 336 | ||
289 | if (!rc && set_p) { | 337 | if (!rc && set_p) { |
@@ -327,6 +375,56 @@ static int ocfs2_control_do_setnode_msg(struct file *file, | |||
327 | return ocfs2_control_install_private(file); | 375 | return ocfs2_control_install_private(file); |
328 | } | 376 | } |
329 | 377 | ||
378 | static int ocfs2_control_do_setversion_msg(struct file *file, | ||
379 | struct ocfs2_control_message_setv *msg) | ||
380 | { | ||
381 | long major, minor; | ||
382 | char *ptr = NULL; | ||
383 | struct ocfs2_control_private *p = file->private_data; | ||
384 | struct ocfs2_protocol_version *max = | ||
385 | &user_stack.sp_proto->lp_max_version; | ||
386 | |||
387 | if (ocfs2_control_get_handshake_state(file) != | ||
388 | OCFS2_CONTROL_HANDSHAKE_PROTOCOL) | ||
389 | return -EINVAL; | ||
390 | |||
391 | if (strncmp(msg->tag, OCFS2_CONTROL_MESSAGE_SETVERSION_OP, | ||
392 | OCFS2_CONTROL_MESSAGE_OP_LEN)) | ||
393 | return -EINVAL; | ||
394 | |||
395 | if ((msg->space1 != ' ') || (msg->space2 != ' ') || | ||
396 | (msg->newline != '\n')) | ||
397 | return -EINVAL; | ||
398 | msg->space1 = msg->space2 = msg->newline = '\0'; | ||
399 | |||
400 | major = simple_strtol(msg->major, &ptr, 16); | ||
401 | if (!ptr || *ptr) | ||
402 | return -EINVAL; | ||
403 | minor = simple_strtol(msg->minor, &ptr, 16); | ||
404 | if (!ptr || *ptr) | ||
405 | return -EINVAL; | ||
406 | |||
407 | /* | ||
408 | * The major must be between 1 and 255, inclusive. The minor | ||
409 | * must be between 0 and 255, inclusive. The version passed in | ||
410 | * must be within the maximum version supported by the filesystem. | ||
411 | */ | ||
412 | if ((major == LONG_MIN) || (major == LONG_MAX) || | ||
413 | (major > (u8)-1) || (major < 1)) | ||
414 | return -ERANGE; | ||
415 | if ((minor == LONG_MIN) || (minor == LONG_MAX) || | ||
416 | (minor > (u8)-1) || (minor < 0)) | ||
417 | return -ERANGE; | ||
418 | if ((major != max->pv_major) || | ||
419 | (minor > max->pv_minor)) | ||
420 | return -EINVAL; | ||
421 | |||
422 | p->op_proto.pv_major = major; | ||
423 | p->op_proto.pv_minor = minor; | ||
424 | |||
425 | return ocfs2_control_install_private(file); | ||
426 | } | ||
427 | |||
330 | static int ocfs2_control_do_down_msg(struct file *file, | 428 | static int ocfs2_control_do_down_msg(struct file *file, |
331 | struct ocfs2_control_message_down *msg) | 429 | struct ocfs2_control_message_down *msg) |
332 | { | 430 | { |
@@ -379,6 +477,10 @@ static ssize_t ocfs2_control_message(struct file *file, | |||
379 | !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_SETNODE_OP, | 477 | !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_SETNODE_OP, |
380 | OCFS2_CONTROL_MESSAGE_OP_LEN)) | 478 | OCFS2_CONTROL_MESSAGE_OP_LEN)) |
381 | ret = ocfs2_control_do_setnode_msg(file, &msg.u_setn); | 479 | ret = ocfs2_control_do_setnode_msg(file, &msg.u_setn); |
480 | else if ((count == OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN) && | ||
481 | !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_SETVERSION_OP, | ||
482 | OCFS2_CONTROL_MESSAGE_OP_LEN)) | ||
483 | ret = ocfs2_control_do_setversion_msg(file, &msg.u_setv); | ||
382 | else if ((count == OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN) && | 484 | else if ((count == OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN) && |
383 | !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_DOWN_OP, | 485 | !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_DOWN_OP, |
384 | OCFS2_CONTROL_MESSAGE_OP_LEN)) | 486 | OCFS2_CONTROL_MESSAGE_OP_LEN)) |
@@ -471,8 +573,13 @@ static int ocfs2_control_release(struct inode *inode, struct file *file) | |||
471 | "an emergency restart!\n"); | 573 | "an emergency restart!\n"); |
472 | emergency_restart(); | 574 | emergency_restart(); |
473 | } | 575 | } |
474 | /* Last valid close clears the node number */ | 576 | /* |
577 | * Last valid close clears the node number and resets | ||
578 | * the locking protocol version | ||
579 | */ | ||
475 | ocfs2_control_this_node = -1; | 580 | ocfs2_control_this_node = -1; |
581 | running_proto.pv_major = 0; | ||
582 | running_proto.pv_major = 0; | ||
476 | } | 583 | } |
477 | 584 | ||
478 | out: | 585 | out: |