aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/stack_user.c
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2008-02-20 18:39:44 -0500
committerMark Fasheh <mfasheh@suse.com>2008-04-18 11:56:07 -0400
commitd4b95eef4dc4a59bcd42bdf783638a2eaa57b4c8 (patch)
treeb09a20940c6089bf7b8c297fa618bd03183857e6 /fs/ocfs2/stack_user.c
parent3cfd4ab6b6b4bee2035b62e1c293801c3d257502 (diff)
ocfs2: Add the 'set version' message to the ocfs2_control device.
The "SETV" message sets the filesystem locking protocol version as negotiated by the client. The client negotiates based on the maximum version advertised in /sys/fs/ocfs2/max_locking_protocol. Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/stack_user.c')
-rw-r--r--fs/ocfs2/stack_user.c131
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> */
129struct 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> */
111struct ocfs2_control_message_down { 139struct 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 {
120union ocfs2_control_message { 148union 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
126static atomic_t ocfs2_control_opened; 155static atomic_t ocfs2_control_opened;
127static int ocfs2_control_this_node = -1; 156static int ocfs2_control_this_node = -1;
157static struct ocfs2_protocol_version running_proto;
128 158
129static LIST_HEAD(ocfs2_live_connection_list); 159static LIST_HEAD(ocfs2_live_connection_list);
130static LIST_HEAD(ocfs2_control_private_list); 160static 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 */
270static int ocfs2_control_install_private(struct file *file) 301static 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
334out_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
378static 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
330static int ocfs2_control_do_down_msg(struct file *file, 428static 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
478out: 585out: