diff --git a/src/control.c b/src/control.c index 84215af..4c1c899 100644 --- a/src/control.c +++ b/src/control.c @@ -310,7 +310,6 @@ enum mirror_state control_client_mirror_wait( return mirror_state; } - #define write_socket(msg) write(client->socket, (msg "\n"), strlen((msg))+1) /** Command parser to start mirror process from socket input */ int control_mirror(struct control_client* client, int linesc, char** lines) @@ -437,8 +436,41 @@ int control_mirror(struct control_client* client, int linesc, char** lines) return 0; } -#undef write_socket +int control_mirror_max_bps( struct control_client* client, int linesc, char** lines ) +{ + NULLCHECK( client ); + NULLCHECK( client->flexnbd ); + struct server* serve = flexnbd_server( client->flexnbd ); + uint64_t max_Bps; + + if ( !serve->mirror_super ) { + write_socket( "1: Not currently mirroring" ); + return -1; + } + + if ( linesc != 1 ) { + write_socket( "1: Bad format" ); + return -1; + } + + errno = 0; + max_Bps = strtoull( lines[0], NULL, 10 ); + if ( errno == ERANGE ) { + write_socket( "1: max_bps out of range" ); + return -1; + } else if ( errno != 0 ) { + write_socket( "1: max_bps couldn't be parsed" ); + return -1; + } + + serve->mirror->max_bytes_per_second = max_Bps; + write_socket( "0: updated" ); + + return 0; +} + +#undef write_socket /** Command parser to alter access control list from socket input */ int control_acl(struct control_client* client, int linesc, char** lines) @@ -581,6 +613,11 @@ void control_respond(struct control_client * client) if (control_status(client, linesc-1, lines+1) < 0) { debug("status command failed"); } + } else if ( strcmp( lines[0], "mirror_max_bps" ) == 0 ) { + info( "mirror_max_bps command received" ); + if( control_mirror_max_bps( client, linesc-1, lines+1 ) < 0 ) { + debug( "mirror_max_bps command failed" ); + } } else { write(client->socket, "10: unknown command\n", 23); diff --git a/src/mode.c b/src/mode.c index eae6fc7..7254b30 100644 --- a/src/mode.c +++ b/src/mode.c @@ -113,6 +113,24 @@ static char acl_help_text[] = VERBOSE_LINE QUIET_LINE; +static struct option mirror_speed_options[] = { + GETOPT_HELP, + GETOPT_SOCK, + GETOPT_MAX_SPEED, + GETOPT_QUIET, + GETOPT_VERBOSE, + {0} +}; +static char mirror_speed_short_options[] = "hs:m:" SOPT_QUIET SOPT_VERBOSE; +static char mirror_speed_help_text[] = + "Usage: flexnbd " CMD_MIRROR_SPEED " \n\n" + "Set the maximum speed of a migration from a mirring server listening on SOCK.\n\n" + HELP_LINE + SOCK_LINE + MAX_SPEED_LINE + VERBOSE_LINE + QUIET_LINE; + static struct option mirror_options[] = { GETOPT_HELP, GETOPT_SOCK, @@ -179,6 +197,7 @@ char help_help_text_arr[] = "\tflexnbd write\n" "\tflexnbd acl\n" "\tflexnbd mirror\n" + "\tflexnbd mirror-speed\n" "\tflexnbd break\n" "\tflexnbd status\n" "\tflexnbd help\n\n" @@ -333,6 +352,36 @@ void read_acl_param( int c, char **sock ) read_sock_param( c, sock, acl_help_text ); } +void read_mirror_speed_param( + int c, + char **sock, + char **max_speed +) +{ + switch( c ) { + case 'h': + fprintf( stdout, "%s\n", mirror_speed_help_text ); + exit( 0 ); + break; + case 's': + *sock = optarg; + break; + case 'm': + *max_speed = optarg; + break; + case 'q': + log_level = QUIET_LOG_LEVEL; + break; + case 'v': + log_level = VERBOSE_LOG_LEVEL; + break; + default: + exit_err( mirror_speed_help_text ); + break; + + } +} + void read_mirror_param( int c, char **sock, @@ -655,6 +704,33 @@ int mode_acl( int argc, char *argv[] ) } +int mode_mirror_speed( int argc, char *argv[] ) +{ + int c; + char *sock = NULL; + char *speed = NULL; + + while( 1 ) { + c = getopt_long( argc, argv, mirror_speed_short_options, mirror_speed_options, NULL ); + if ( -1 == c ) { break; } + read_mirror_speed_param( c, &sock, &speed ); + } + + if ( NULL == sock ) { + fprintf( stderr, "--sock is required.\n" ); + exit_err( mirror_speed_help_text ); + } + + if ( NULL == speed ) { + fprintf( stderr, "--max-speed is required.\n"); + exit_err( mirror_speed_help_text ); + } + + do_remote_command( "mirror_max_bps", sock, 1, &speed ); + return 0; +} + + int mode_mirror( int argc, char *argv[] ) { int c; @@ -787,6 +863,8 @@ void mode(char* mode, int argc, char **argv) } else if ( IS_CMD( CMD_ACL, mode ) ) { mode_acl( argc, argv ); + } else if ( IS_CMD ( CMD_MIRROR_SPEED, mode ) ) { + mode_mirror_speed( argc, argv ); } else if ( IS_CMD( CMD_MIRROR, mode ) ) { mode_mirror( argc, argv ); diff --git a/src/mode.h b/src/mode.h index 1f902ff..c895483 100644 --- a/src/mode.h +++ b/src/mode.h @@ -23,6 +23,7 @@ void mode(char* mode, int argc, char **argv); #define OPT_CONNECT_ADDR "conn-addr" #define OPT_CONNECT_PORT "conn-port" #define OPT_KILLSWITCH "killswitch" +#define OPT_MAX_SPEED "max-speed" #define CMD_SERVE "serve" #define CMD_LISTEN "listen" @@ -30,10 +31,11 @@ void mode(char* mode, int argc, char **argv); #define CMD_WRITE "write" #define CMD_ACL "acl" #define CMD_MIRROR "mirror" +#define CMD_MIRROR_SPEED "mirror-speed" #define CMD_BREAK "break" #define CMD_STATUS "status" #define CMD_HELP "help" -#define LEN_CMD_MAX 7 +#define LEN_CMD_MAX 13 #define PATH_LEN_MAX 1024 #define ADDR_LEN_MAX 64 @@ -54,6 +56,7 @@ void mode(char* mode, int argc, char **argv); #define GETOPT_CONNECT_ADDR GETOPT_ARG( OPT_CONNECT_ADDR, 'C' ) #define GETOPT_CONNECT_PORT GETOPT_ARG( OPT_CONNECT_PORT, 'P' ) #define GETOPT_KILLSWITCH GETOPT_ARG( OPT_KILLSWITCH, 'k' ) +#define GETOPT_MAX_SPEED GETOPT_ARG( OPT_MAX_SPEED, 'm' ) #define OPT_VERBOSE "verbose" #define SOPT_VERBOSE "v" @@ -82,7 +85,8 @@ void mode(char* mode, int argc, char **argv); "\t--" OPT_SOCK ",-s \tPath to the control socket.\n" #define BIND_LINE \ "\t--" OPT_BIND ",-b \tBind the local socket to a particular IP address.\n" - +#define MAX_SPEED_LINE \ + "\t--" OPT_MAX_SPEED ",-m \tMaximum speed of the migration, in bytes/sec.\n" char * help_help_text; diff --git a/src/remote.c b/src/remote.c index ee714ff..8accb39 100644 --- a/src/remote.c +++ b/src/remote.c @@ -17,7 +17,7 @@ void print_response( const char * response ) exit_status = atoi(response); response_text = strchr( response, ':' ); - FATAL_IF_NULL( response_text, + FATAL_IF_NULL( response_text, "Error parsing server response: '%s'", response ); out = exit_status > 0 ? stderr : stdout; @@ -32,19 +32,19 @@ void do_remote_command(char* command, char* socket_name, int argc, char** argv) int remote = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un address; char response[max_response]; - + memset(&address, 0, sizeof(address)); - + FATAL_IF_NEGATIVE(remote, "Couldn't create client socket"); - + address.sun_family = AF_UNIX; strncpy(address.sun_path, socket_name, sizeof(address.sun_path)); - + FATAL_IF_NEGATIVE( connect(remote, (struct sockaddr*) &address, sizeof(address)), "Couldn't connect to %s", socket_name ); - + write(remote, command, strlen(command)); write(remote, &newline, 1); for (i=0; i