Commit d4b95eef4dc4a59bcd42bdf783638a2eaa57b4c8

Authored by Joel Becker
Committed by Mark Fasheh
1 parent 3cfd4ab6b6

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>

Showing 1 changed file with 119 additions and 12 deletions Side-by-side Diff

fs/ocfs2/stack_user.c
... ... @@ -40,7 +40,7 @@
40 40 * unknown, -EINVAL is returned. Once the negotiation is complete, the
41 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 44 * It has the following syntax:
45 45 *
46 46 * SETN<space><8-char-hex-nodenum><newline>
47 47  
... ... @@ -50,9 +50,23 @@
50 50 * The "SETN" message must be the first message following the protocol.
51 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
54   - * sent for node down notification. It has the following syntax:
  53 + * Next comes the "SETV" message. It has the following syntax:
55 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:
  69 + *
56 70 * DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline>
57 71 *
58 72 * eg:
59 73  
... ... @@ -79,9 +93,12 @@
79 93 #define OCFS2_CONTROL_MESSAGE_OP_LEN 4
80 94 #define OCFS2_CONTROL_MESSAGE_SETNODE_OP "SETN"
81 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 98 #define OCFS2_CONTROL_MESSAGE_DOWN_OP "DOWN"
83 99 #define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN 47
84 100 #define OCFS2_TEXT_UUID_LEN 32
  101 +#define OCFS2_CONTROL_MESSAGE_VERNUM_LEN 2
85 102 #define OCFS2_CONTROL_MESSAGE_NODENUM_LEN 8
86 103  
87 104 /*
... ... @@ -97,6 +114,7 @@
97 114 struct list_head op_list;
98 115 int op_state;
99 116 int op_this_node;
  117 + struct ocfs2_protocol_version op_proto;
100 118 };
101 119  
102 120 /* SETN<space><8-char-hex-nodenum><newline> */
... ... @@ -107,6 +125,16 @@
107 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 138 /* DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> */
111 139 struct ocfs2_control_message_down {
112 140 char tag[OCFS2_CONTROL_MESSAGE_OP_LEN];
113 141  
... ... @@ -120,11 +148,13 @@
120 148 union ocfs2_control_message {
121 149 char tag[OCFS2_CONTROL_MESSAGE_OP_LEN];
122 150 struct ocfs2_control_message_setn u_setn;
  151 + struct ocfs2_control_message_setv u_setv;
123 152 struct ocfs2_control_message_down u_down;
124 153 };
125 154  
126 155 static atomic_t ocfs2_control_opened;
127 156 static int ocfs2_control_this_node = -1;
  157 +static struct ocfs2_protocol_version running_proto;
128 158  
129 159 static LIST_HEAD(ocfs2_live_connection_list);
130 160 static LIST_HEAD(ocfs2_control_private_list);
... ... @@ -264,8 +294,9 @@
264 294 /*
265 295 * Called whenever configuration elements are sent to /dev/ocfs2_control.
266 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
268   - * different error.
  297 + * values. If there is a problem, return an error. Skip any missing
  298 + * elements, and only bump ocfs2_control_opened when we have all elements
  299 + * and are successful.
269 300 */
270 301 static int ocfs2_control_install_private(struct file *file)
271 302 {
272 303  
273 304  
274 305  
... ... @@ -275,15 +306,32 @@
275 306  
276 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 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);
282   - if (ocfs2_control_this_node < 0) {
283   - if (set_p)
284   - ocfs2_control_this_node = p->op_this_node;
285   - } else if (ocfs2_control_this_node != p->op_this_node)
  319 + if (!p->op_proto.pv_major) {
  320 + set_p = 0;
  321 + } else if (!list_empty(&ocfs2_live_connection_list) &&
  322 + ((running_proto.pv_major != p->op_proto.pv_major) ||
  323 + (running_proto.pv_minor != p->op_proto.pv_minor))) {
286 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 335 mutex_unlock(&ocfs2_control_lock);
288 336  
289 337 if (!rc && set_p) {
... ... @@ -327,6 +375,56 @@
327 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 428 static int ocfs2_control_do_down_msg(struct file *file,
331 429 struct ocfs2_control_message_down *msg)
332 430 {
... ... @@ -379,6 +477,10 @@
379 477 !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_SETNODE_OP,
380 478 OCFS2_CONTROL_MESSAGE_OP_LEN))
381 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 484 else if ((count == OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN) &&
383 485 !strncmp(msg.tag, OCFS2_CONTROL_MESSAGE_DOWN_OP,
384 486 OCFS2_CONTROL_MESSAGE_OP_LEN))
385 487  
... ... @@ -471,8 +573,13 @@
471 573 "an emergency restart!\n");
472 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 580 ocfs2_control_this_node = -1;
  581 + running_proto.pv_major = 0;
  582 + running_proto.pv_major = 0;
476 583 }
477 584  
478 585 out: