[libvirt] [PATCHv3 0/4] phyp: add storage management

Here's my promised refactoring of the patches. Eduardo Otubo (2): phyp: add rudimentary storage driver phyp: add storage management driver Eric Blake (2): phyp: reduce scope of driver functions phyp: optimize use of sed src/phyp/phyp_driver.c | 3542 +++++++++++++++++++++++++++++++++++------------- src/phyp/phyp_driver.h | 76 +- 2 files changed, 2621 insertions(+), 997 deletions(-)

Several phyp functions are not namespace clean, and had no reason to be exported since no one outside the phyp driver needed to use them. Rather than do lots of forward declarations, I was able to topologically sort the file. So, this patch looks huge, but is really just a matter of marking things static and dealing with the compiler fallout. * src/phyp/phyp_driver.h (PHYP_DRIVER_H): Add include guard. (phypCheckSPFreeSapce): Delete unused declaration. (phypGetSystemType, phypGetVIOSPartitionID, phypCapsInit) (phypBuildLpar, phypUUIDTable_WriteFile, phypUUIDTable_ReadFile) (phypUUIDTable_AddLpar, phypUUIDTable_RemLpar, phypUUIDTable_Pull) (phypUUIDTable_Push, phypUUIDTable_Init, phypUUIDTable_Free) (escape_specialcharacters, waitsocket, phypGetLparUUID) (phypGetLparMem, phypGetLparCPU, phypGetLparCPUGeneric) (phypGetRemoteSlot, phypGetBackingDevice, phypDiskType) (openSSHSession): Move declarations to phyp_driver.c and make static. * src/phyp/phyp_driver.c: Rearrange file contents to provide topological sorting of newly-static funtions (no semantic changes other than reduced scope). (phypGetBackingDevice, phypDiskType): Mark unused, for now. --- New patch - reduce scope where possible, and rearrange everything into topological order. There is no significant code changes beyond marking a few things 'static', so although it looks big, you don't have to worry about the guts of any command changing. src/phyp/phyp_driver.c | 2030 ++++++++++++++++++++++++------------------------ src/phyp/phyp_driver.h | 75 +-- 2 files changed, 1029 insertions(+), 1076 deletions(-) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index dfa31c7..0912f90 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -66,181 +66,881 @@ virReportErrorHelper(NULL, VIR_FROM_PHYP, code, __FILE__, __FUNCTION__, \ __LINE__, __VA_ARGS__) -static unsigned const int HMC = 0; -static unsigned const int IVM = 127; - /* * URI: phyp://user@[hmc|ivm]/managed_system * */ -static virDrvOpenStatus -phypOpen(virConnectPtr conn, - virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) +static unsigned const int HMC = 0; +static unsigned const int IVM = 127; + +static int +waitsocket(int socket_fd, LIBSSH2_SESSION * session) { - LIBSSH2_SESSION *session = NULL; - ConnectionData *connection_data = NULL; - char *string = NULL; - size_t len = 0; - int internal_socket; - uuid_tablePtr uuid_table = NULL; - phyp_driverPtr phyp_driver = NULL; - char *char_ptr; - char *managed_system = NULL; + struct timeval timeout; + int rc; + fd_set fd; + fd_set *writefd = NULL; + fd_set *readfd = NULL; + int dir; - if (!conn || !conn->uri) - return VIR_DRV_OPEN_DECLINED; + timeout.tv_sec = 0; + timeout.tv_usec = 1000; - if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "phyp")) - return VIR_DRV_OPEN_DECLINED; + FD_ZERO(&fd); - if (conn->uri->server == NULL) { - PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing server name in phyp:// URI")); - return VIR_DRV_OPEN_ERROR; + FD_SET(socket_fd, &fd); + + /* now make sure we wait in the correct direction */ + dir = libssh2_session_block_directions(session); + + if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) + readfd = &fd; + + if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) + writefd = &fd; + + rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout); + + return rc; +} + +/* this function is the layer that manipulates the ssh channel itself + * and executes the commands on the remote machine */ +static char * +phypExec(LIBSSH2_SESSION * session, char *cmd, int *exit_status, + virConnectPtr conn) +{ + LIBSSH2_CHANNEL *channel; + ConnectionData *connection_data = conn->networkPrivateData; + virBuffer tex_ret = VIR_BUFFER_INITIALIZER; + char buffer[0x4000] = { 0 }; + int exitcode; + int bytecount = 0; + int sock = connection_data->sock; + int rc = 0; + + /* Exec non-blocking on the remove host */ + while ((channel = libssh2_channel_open_session(session)) == NULL && + libssh2_session_last_error(session, NULL, NULL, 0) == + LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); } - if (VIR_ALLOC(phyp_driver) < 0) { + if (channel == NULL) { + goto err; + } + + while ((rc = libssh2_channel_exec(channel, cmd)) == + LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); + } + + if (rc != 0) { + goto err; + } + + for (;;) { + /* loop until we block */ + do { + rc = libssh2_channel_read(channel, buffer, sizeof(buffer)); + if (rc > 0) { + bytecount += rc; + virBufferVSprintf(&tex_ret, "%s", buffer); + } + } + while (rc > 0); + + /* this is due to blocking that would occur otherwise so we loop on + * this condition */ + if (rc == LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); + } else { + break; + } + } + + exitcode = 127; + + while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) { + waitsocket(sock, session); + } + + if (rc == 0) { + exitcode = libssh2_channel_get_exit_status(channel); + } + + (*exit_status) = exitcode; + libssh2_channel_free(channel); + channel = NULL; + goto exit; + + err: + (*exit_status) = SSH_CMD_ERR; + virBufferFreeAndReset(&tex_ret); + return NULL; + + exit: + if (virBufferError(&tex_ret)) { + virBufferFreeAndReset(&tex_ret); virReportOOMError(); - goto failure; + return NULL; } + return virBufferContentAndReset(&tex_ret); +} - if (VIR_ALLOC(uuid_table) < 0) { +static int +phypGetSystemType(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + LIBSSH2_SESSION *session = connection_data->session; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + + if (virAsprintf(&cmd, "lshmc -V") < 0) { virReportOOMError(); - goto failure; + exit_status = -1; } + ret = phypExec(session, cmd, &exit_status, conn); - if (VIR_ALLOC(connection_data) < 0) { + VIR_FREE(cmd); + VIR_FREE(ret); + return exit_status; +} + +static int +phypGetVIOSPartitionID(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + int id = -1; + char *char_ptr; + char *managed_system = phyp_driver->managed_system; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&buf, "lssyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env|grep " + "vioserver|sed -s 's/,.*$//'"); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); virReportOOMError(); - goto failure; + return -1; } + cmd = virBufferContentAndReset(&buf); - if (conn->uri->path) { - len = strlen(conn->uri->path) + 1; + ret = phypExec(session, cmd, &exit_status, conn); - if (VIR_ALLOC_N(string, len) < 0) { - virReportOOMError(); - goto failure; - } + if (exit_status < 0 || ret == NULL) + goto err; - /* need to shift one byte in order to remove the first "/" of URI component */ - if (conn->uri->path[0] == '/') - managed_system = strdup(conn->uri->path + 1); - else - managed_system = strdup(conn->uri->path); + if (virStrToLong_i(ret, &char_ptr, 10, &id) == -1) + goto err; - if (!managed_system) { - virReportOOMError(); - goto failure; + VIR_FREE(cmd); + VIR_FREE(ret); + return id; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static virCapsPtr +phypCapsInit(void) +{ + struct utsname utsname; + virCapsPtr caps; + virCapsGuestPtr guest; + + uname(&utsname); + + if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) + goto no_memory; + + /* Some machines have problematic NUMA toplogy causing + * unexpected failures. We don't want to break the QEMU + * driver in this scenario, so log errors & carry on + */ + if (nodeCapsInitNUMA(caps) < 0) { + virCapabilitiesFreeNUMAInfo(caps); + VIR_WARN0 + ("Failed to query host NUMA topology, disabling NUMA capabilities"); + } + + /* XXX shouldn't 'borrow' KVM's prefix */ + virCapabilitiesSetMacPrefix(caps, (unsigned char[]) { + 0x52, 0x54, 0x00}); + + if ((guest = virCapabilitiesAddGuest(caps, + "linux", + utsname.machine, + sizeof(int) == 4 ? 32 : 8, + NULL, NULL, 0, NULL)) == NULL) + goto no_memory; + + if (virCapabilitiesAddGuestDomain(guest, + "phyp", NULL, NULL, 0, NULL) == NULL) + goto no_memory; + + return caps; + + no_memory: + virCapabilitiesFree(caps); + return NULL; +} + +/* This is a generic function that won't be used directly by + * libvirt api. The function returns the number of domains + * in different states: Running, Not Activated and all: + * + * type: 0 - Running + * 1 - Not Activated + * * - All + * */ +static int +phypNumDomainsGeneric(virConnectPtr conn, unsigned int type) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + int exit_status = 0; + int ndom = 0; + char *char_ptr; + char *cmd = NULL; + char *ret = NULL; + char *managed_system = phyp_driver->managed_system; + const char *state; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (type == 0) + state = "|grep Running"; + else if (type == 1) { + if (system_type == HMC) { + state = "|grep \"Not Activated\""; + } else { + state = "|grep \"Open Firmware\""; } + } else + state = " "; - /* here we are handling only the first component of the path, - * so skipping the second: - * */ - char_ptr = strchr(managed_system, '/'); + virBufferAddLit(&buf, "lssyscfg -r lpar"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9]*'", + state); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); - if (char_ptr) - *char_ptr = '\0'; + ret = phypExec(session, cmd, &exit_status, conn); - if (escape_specialcharacters(conn->uri->path, string, len) == -1) { - PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, - "%s", - _("Error parsing 'path'. Invalid characters.")); - goto failure; + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &ndom) == -1) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return ndom; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +/* This is a generic function that won't be used directly by + * libvirt api. The function returns the ids of domains + * in different states: Running, and all: + * + * type: 0 - Running + * 1 - all + * */ +static int +phypListDomainsGeneric(virConnectPtr conn, int *ids, int nids, + unsigned int type) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + char *managed_system = phyp_driver->managed_system; + int exit_status = 0; + int got = 0; + char *char_ptr; + unsigned int i = 0, j = 0; + char id_c[10]; + char *cmd = NULL; + char *ret = NULL; + const char *state; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (type == 0) + state = "|grep Running"; + else + state = " "; + + memset(id_c, 0, 10); + + virBufferAddLit(&buf, "lssyscfg -r lpar"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'", + state); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + /* I need to parse the textual return in order to get the ret */ + if (exit_status < 0 || ret == NULL) + goto err; + else { + while (got < nids) { + if (ret[i] == '\0') + break; + else if (ret[i] == '\n') { + if (virStrToLong_i(id_c, &char_ptr, 10, &ids[got]) == -1) { + VIR_ERROR(_("Cannot parse number from '%s'"), id_c); + goto err; + } + memset(id_c, 0, 10); + j = 0; + got++; + } else { + id_c[j] = ret[i]; + j++; + } + i++; } } - if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) { - PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, - "%s", _("Error while opening SSH session.")); - goto failure; + VIR_FREE(cmd); + VIR_FREE(ret); + return got; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypUUIDTable_WriteFile(virConnectPtr conn) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + unsigned int i = 0; + int fd = -1; + char local_file[] = "./uuid_table"; + + if ((fd = creat(local_file, 0755)) == -1) + goto err; + + for (i = 0; i < uuid_table->nlpars; i++) { + if (safewrite(fd, &uuid_table->lpars[i]->id, + sizeof(uuid_table->lpars[i]->id)) != + sizeof(uuid_table->lpars[i]->id)) { + VIR_ERROR0(_("Unable to write information to local file.")); + goto err; + } + + if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) != + VIR_UUID_BUFLEN) { + VIR_ERROR0(_("Unable to write information to local file.")); + goto err; + } } - connection_data->session = session; + close(fd); + return 0; - uuid_table->nlpars = 0; - uuid_table->lpars = NULL; + err: + close(fd); + return -1; +} - if (conn->uri->path) - phyp_driver->managed_system = managed_system; +static int +phypUUIDTable_Push(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + LIBSSH2_SESSION *session = connection_data->session; + LIBSSH2_CHANNEL *channel = NULL; + virBuffer username = VIR_BUFFER_INITIALIZER; + struct stat local_fileinfo; + char buffer[1024]; + int rc = 0; + FILE *fd; + size_t nread, sent; + char *ptr; + char local_file[] = "./uuid_table"; + char *remote_file = NULL; - phyp_driver->uuid_table = uuid_table; - if ((phyp_driver->caps = phypCapsInit()) == NULL) { + if (conn->uri->user != NULL) { + virBufferVSprintf(&username, "%s", conn->uri->user); + + if (virBufferError(&username)) { + virBufferFreeAndReset(&username); + virReportOOMError(); + goto err; + } + } + + if (virAsprintf + (&remote_file, "/home/%s/libvirt_uuid_table", + virBufferContentAndReset(&username)) + < 0) { virReportOOMError(); - goto failure; + goto err; } - conn->privateData = phyp_driver; - conn->networkPrivateData = connection_data; + if (stat(local_file, &local_fileinfo) == -1) { + VIR_WARN0("Unable to stat local file."); + goto err; + } - if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1) - goto failure; + if (!(fd = fopen(local_file, "rb"))) { + VIR_WARN0("Unable to open local file."); + goto err; + } - if (phypUUIDTable_Init(conn) == -1) - goto failure; + do { + channel = + libssh2_scp_send(session, remote_file, + 0x1FF & local_fileinfo.st_mode, + (unsigned long) local_fileinfo.st_size); - if (phyp_driver->system_type == HMC) { - if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1) - goto failure; + if ((!channel) && (libssh2_session_last_errno(session) != + LIBSSH2_ERROR_EAGAIN)) + goto err; + } while (!channel); + + do { + nread = fread(buffer, 1, sizeof(buffer), fd); + if (nread <= 0) { + if (feof(fd)) { + /* end of file */ + break; + } else { + VIR_ERROR(_("Failed to read from %s"), local_file); + goto err; + } + } + ptr = buffer; + sent = 0; + + do { + /* write the same data over and over, until error or completion */ + rc = libssh2_channel_write(channel, ptr, nread); + if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */ + continue; + } else if (rc > 0) { + /* rc indicates how many bytes were written this time */ + sent += rc; + } + ptr += sent; + nread -= sent; + } while (rc > 0 && sent < nread); + } while (1); + + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; } + virBufferFreeAndReset(&username); + return 0; - return VIR_DRV_OPEN_SUCCESS; + err: + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + return -1; +} - failure: - if (phyp_driver != NULL) { - virCapabilitiesFree(phyp_driver->caps); - VIR_FREE(phyp_driver->managed_system); - VIR_FREE(phyp_driver); +static int +phypUUIDTable_RemLpar(virConnectPtr conn, int id) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + unsigned int i = 0; + + for (i = 0; i <= uuid_table->nlpars; i++) { + if (uuid_table->lpars[i]->id == id) { + uuid_table->lpars[i]->id = -1; + memset(uuid_table->lpars[i]->uuid, 0, VIR_UUID_BUFLEN); + } } - phypUUIDTable_Free(uuid_table); + if (phypUUIDTable_WriteFile(conn) == -1) + goto err; - if (session != NULL) { - libssh2_session_disconnect(session, "Disconnecting..."); - libssh2_session_free(session); + if (phypUUIDTable_Push(conn) == -1) + goto err; + + return 0; + + err: + return -1; +} + +static int +phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id) +{ + phyp_driverPtr phyp_driver = conn->privateData; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + + uuid_table->nlpars++; + unsigned int i = uuid_table->nlpars; + i--; + + if (VIR_REALLOC_N(uuid_table->lpars, uuid_table->nlpars) < 0) { + virReportOOMError(); + goto err; } - VIR_FREE(connection_data); - VIR_FREE(string); + if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { + virReportOOMError(); + goto err; + } - return VIR_DRV_OPEN_ERROR; + uuid_table->lpars[i]->id = id; + memmove(uuid_table->lpars[i]->uuid, uuid, VIR_UUID_BUFLEN); + + if (phypUUIDTable_WriteFile(conn) == -1) + goto err; + + if (phypUUIDTable_Push(conn) == -1) + goto err; + + return 0; + + err: + return -1; } static int -phypClose(virConnectPtr conn) +phypUUIDTable_ReadFile(virConnectPtr conn) { - ConnectionData *connection_data = conn->networkPrivateData; phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; + uuid_tablePtr uuid_table = phyp_driver->uuid_table; + unsigned int i = 0; + int fd = -1; + char local_file[] = "./uuid_table"; + int rc = 0; + int id; - libssh2_session_disconnect(session, "Disconnecting..."); - libssh2_session_free(session); + if ((fd = open(local_file, O_RDONLY)) == -1) { + VIR_WARN0("Unable to write information to local file."); + goto err; + } - virCapabilitiesFree(phyp_driver->caps); - phypUUIDTable_Free(phyp_driver->uuid_table); - VIR_FREE(phyp_driver->managed_system); - VIR_FREE(phyp_driver); - VIR_FREE(connection_data); + /* Creating a new data base and writing to local file */ + if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { + for (i = 0; i < uuid_table->nlpars; i++) { + + rc = read(fd, &id, sizeof(int)); + if (rc == sizeof(int)) { + if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { + virReportOOMError(); + goto err; + } + uuid_table->lpars[i]->id = id; + } else { + VIR_WARN0 + ("Unable to read from information to local file."); + goto err; + } + + rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN); + if (rc != VIR_UUID_BUFLEN) { + VIR_WARN0("Unable to read information to local file."); + goto err; + } + } + } else + virReportOOMError(); + + close(fd); return 0; + + err: + close(fd); + return -1; } +static int +phypUUIDTable_Pull(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + LIBSSH2_SESSION *session = connection_data->session; + LIBSSH2_CHANNEL *channel = NULL; + virBuffer username = VIR_BUFFER_INITIALIZER; + struct stat fileinfo; + char buffer[1024]; + int rc = 0; + int fd; + int got = 0; + int amount = 0; + int total = 0; + int sock = 0; + char local_file[] = "./uuid_table"; + char *remote_file = NULL; + + if (conn->uri->user != NULL) { + virBufferVSprintf(&username, "%s", conn->uri->user); + + if (virBufferError(&username)) { + virBufferFreeAndReset(&username); + virReportOOMError(); + goto err; + } + } + + if (virAsprintf + (&remote_file, "/home/%s/libvirt_uuid_table", + virBufferContentAndReset(&username)) + < 0) { + virReportOOMError(); + goto err; + } + + /* Trying to stat the remote file. */ + do { + channel = libssh2_scp_recv(session, remote_file, &fileinfo); + + if (!channel) { + if (libssh2_session_last_errno(session) != + LIBSSH2_ERROR_EAGAIN) { + goto err;; + } else { + waitsocket(sock, session); + } + } + } while (!channel); + + /* Creating a new data base based on remote file */ + if ((fd = creat(local_file, 0755)) == -1) + goto err; + + /* Request a file via SCP */ + while (got < fileinfo.st_size) { + do { + amount = sizeof(buffer); + + if ((fileinfo.st_size - got) < amount) { + amount = fileinfo.st_size - got; + } + + rc = libssh2_channel_read(channel, buffer, amount); + if (rc > 0) { + if (safewrite(fd, buffer, rc) != rc) + VIR_WARN0 + ("Unable to write information to local file."); + + got += rc; + total += rc; + } + } while (rc > 0); + + if ((rc == LIBSSH2_ERROR_EAGAIN) + && (got < fileinfo.st_size)) { + /* this is due to blocking that would occur otherwise + * so we loop on this condition */ + + waitsocket(sock, session); /* now we wait */ + continue; + } + break; + } + close(fd); + goto exit; + + exit: + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + virBufferFreeAndReset(&username); + return 0; + + err: + if (channel) { + libssh2_channel_send_eof(channel); + libssh2_channel_wait_eof(channel); + libssh2_channel_wait_closed(channel); + libssh2_channel_free(channel); + channel = NULL; + } + return -1; +} static int -phypIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) +phypUUIDTable_Init(virConnectPtr conn) { - /* Phyp uses an SSH tunnel, so is always encrypted */ - return 1; + uuid_tablePtr uuid_table; + phyp_driverPtr phyp_driver; + int nids_numdomains = 0; + int nids_listdomains = 0; + int *ids = NULL; + unsigned int i = 0; + + if ((nids_numdomains = phypNumDomainsGeneric(conn, 2)) < 0) + goto err; + + if (VIR_ALLOC_N(ids, nids_numdomains) < 0) { + virReportOOMError(); + goto err; + } + + if ((nids_listdomains = + phypListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0) + goto err; + + /* exit early if there are no domains */ + if (nids_numdomains == 0 && nids_listdomains == 0) + goto exit; + else if (nids_numdomains != nids_listdomains) { + VIR_ERROR0(_("Unable to determine number of domains.")); + goto err; + } + + phyp_driver = conn->privateData; + uuid_table = phyp_driver->uuid_table; + uuid_table->nlpars = nids_listdomains; + + /* try to get the table from server */ + if (phypUUIDTable_Pull(conn) == -1) { + /* file not found in the server, creating a new one */ + if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { + for (i = 0; i < uuid_table->nlpars; i++) { + if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { + virReportOOMError(); + goto err; + } + uuid_table->lpars[i]->id = ids[i]; + + if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0) + VIR_WARN("Unable to generate UUID for domain %d", + ids[i]); + } + } else { + virReportOOMError(); + goto err; + } + + if (phypUUIDTable_WriteFile(conn) == -1) + goto err; + + if (phypUUIDTable_Push(conn) == -1) + goto err; + } else { + if (phypUUIDTable_ReadFile(conn) == -1) + goto err; + goto exit; + } + + exit: + VIR_FREE(ids); + return 0; + + err: + VIR_FREE(ids); + return -1; } +static void +phypUUIDTable_Free(uuid_tablePtr uuid_table) +{ + int i; + + if (uuid_table == NULL) + return; + + for (i = 0; i < uuid_table->nlpars; i++) + VIR_FREE(uuid_table->lpars[i]); + + VIR_FREE(uuid_table->lpars); + VIR_FREE(uuid_table); +} static int -phypIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) +escape_specialcharacters(char *src, char *dst, size_t dstlen) { - /* Phyp uses an SSH tunnel, so is always secure */ - return 1; -} + size_t len = strlen(src); + char temp_buffer[len]; + unsigned int i = 0, j = 0; + if (len == 0) + return -1; + for (i = 0; i < len; i++) { + switch (src[i]) { + case '&': + case ';': + case '`': + case '@': + case '"': + case '|': + case '*': + case '?': + case '~': + case '<': + case '>': + case '^': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '$': + case '%': + case '#': + case '\\': + case '\n': + case '\r': + case '\t': + continue; + default: + temp_buffer[j] = src[i]; + j++; + } + } + temp_buffer[j] = '\0'; + + if (virStrcpy(dst, temp_buffer, dstlen) == NULL) + return -1; + + return 0; +} -LIBSSH2_SESSION * +static LIBSSH2_SESSION * openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, int *internal_socket) { @@ -414,108 +1114,170 @@ openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, return session; } -/* this functions is the layer that manipulates the ssh channel itself - * and executes the commands on the remote machine */ -static char * -phypExec(LIBSSH2_SESSION * session, char *cmd, int *exit_status, - virConnectPtr conn) +static virDrvOpenStatus +phypOpen(virConnectPtr conn, + virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) { - LIBSSH2_CHANNEL *channel; - ConnectionData *connection_data = conn->networkPrivateData; - virBuffer tex_ret = VIR_BUFFER_INITIALIZER; - char buffer[0x4000] = { 0 }; - int exitcode; - int bytecount = 0; - int sock = connection_data->sock; - int rc = 0; + LIBSSH2_SESSION *session = NULL; + ConnectionData *connection_data = NULL; + char *string = NULL; + size_t len = 0; + int internal_socket; + uuid_tablePtr uuid_table = NULL; + phyp_driverPtr phyp_driver = NULL; + char *char_ptr; + char *managed_system = NULL; - /* Exec non-blocking on the remove host */ - while ((channel = libssh2_channel_open_session(session)) == NULL && - libssh2_session_last_error(session, NULL, NULL, 0) == - LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); + if (!conn || !conn->uri) + return VIR_DRV_OPEN_DECLINED; + + if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "phyp")) + return VIR_DRV_OPEN_DECLINED; + + if (conn->uri->server == NULL) { + PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing server name in phyp:// URI")); + return VIR_DRV_OPEN_ERROR; } - if (channel == NULL) { - goto err; + if (VIR_ALLOC(phyp_driver) < 0) { + virReportOOMError(); + goto failure; } - while ((rc = libssh2_channel_exec(channel, cmd)) == - LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); + if (VIR_ALLOC(uuid_table) < 0) { + virReportOOMError(); + goto failure; } - if (rc != 0) { - goto err; + if (VIR_ALLOC(connection_data) < 0) { + virReportOOMError(); + goto failure; } - for (;;) { - /* loop until we block */ - do { - rc = libssh2_channel_read(channel, buffer, sizeof(buffer)); - if (rc > 0) { - bytecount += rc; - virBufferVSprintf(&tex_ret, "%s", buffer); - } + if (conn->uri->path) { + len = strlen(conn->uri->path) + 1; + + if (VIR_ALLOC_N(string, len) < 0) { + virReportOOMError(); + goto failure; } - while (rc > 0); - /* this is due to blocking that would occur otherwise so we loop on - * this condition */ - if (rc == LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); - } else { - break; + /* need to shift one byte in order to remove the first "/" of URI component */ + if (conn->uri->path[0] == '/') + managed_system = strdup(conn->uri->path + 1); + else + managed_system = strdup(conn->uri->path); + + if (!managed_system) { + virReportOOMError(); + goto failure; } - } - exitcode = 127; + /* here we are handling only the first component of the path, + * so skipping the second: + * */ + char_ptr = strchr(managed_system, '/'); - while ((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN) { - waitsocket(sock, session); + if (char_ptr) + *char_ptr = '\0'; + + if (escape_specialcharacters(conn->uri->path, string, len) == -1) { + PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Error parsing 'path'. Invalid characters.")); + goto failure; + } } - if (rc == 0) { - exitcode = libssh2_channel_get_exit_status(channel); + if ((session = openSSHSession(conn, auth, &internal_socket)) == NULL) { + PHYP_ERROR(VIR_ERR_INTERNAL_ERROR, + "%s", _("Error while opening SSH session.")); + goto failure; } - (*exit_status) = exitcode; - libssh2_channel_free(channel); - channel = NULL; - goto exit; + connection_data->session = session; - err: - (*exit_status) = SSH_CMD_ERR; - virBufferFreeAndReset(&tex_ret); - return NULL; + uuid_table->nlpars = 0; + uuid_table->lpars = NULL; - exit: - if (virBufferError(&tex_ret)) { - virBufferFreeAndReset(&tex_ret); + if (conn->uri->path) + phyp_driver->managed_system = managed_system; + + phyp_driver->uuid_table = uuid_table; + if ((phyp_driver->caps = phypCapsInit()) == NULL) { virReportOOMError(); - return NULL; + goto failure; } - return virBufferContentAndReset(&tex_ret); + + conn->privateData = phyp_driver; + conn->networkPrivateData = connection_data; + + if ((phyp_driver->system_type = phypGetSystemType(conn)) == -1) + goto failure; + + if (phypUUIDTable_Init(conn) == -1) + goto failure; + + if (phyp_driver->system_type == HMC) { + if ((phyp_driver->vios_id = phypGetVIOSPartitionID(conn)) == -1) + goto failure; + } + + return VIR_DRV_OPEN_SUCCESS; + + failure: + if (phyp_driver != NULL) { + virCapabilitiesFree(phyp_driver->caps); + VIR_FREE(phyp_driver->managed_system); + VIR_FREE(phyp_driver); + } + + phypUUIDTable_Free(uuid_table); + + if (session != NULL) { + libssh2_session_disconnect(session, "Disconnecting..."); + libssh2_session_free(session); + } + + VIR_FREE(connection_data); + VIR_FREE(string); + + return VIR_DRV_OPEN_ERROR; } -int -phypGetSystemType(virConnectPtr conn) +static int +phypClose(virConnectPtr conn) { ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; LIBSSH2_SESSION *session = connection_data->session; - char *cmd = NULL; - char *ret = NULL; - int exit_status = 0; - if (virAsprintf(&cmd, "lshmc -V") < 0) { - virReportOOMError(); - exit_status = -1; - } - ret = phypExec(session, cmd, &exit_status, conn); + libssh2_session_disconnect(session, "Disconnecting..."); + libssh2_session_free(session); - VIR_FREE(cmd); - VIR_FREE(ret); - return exit_status; + virCapabilitiesFree(phyp_driver->caps); + phypUUIDTable_Free(phyp_driver->uuid_table); + VIR_FREE(phyp_driver->managed_system); + VIR_FREE(phyp_driver); + VIR_FREE(connection_data); + return 0; +} + + +static int +phypIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + /* Phyp uses an SSH tunnel, so is always encrypted */ + return 1; +} + + +static int +phypIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + /* Phyp uses an SSH tunnel, so is always secure */ + return 1; } @@ -611,7 +1373,7 @@ phypGetLparNAME(LIBSSH2_SESSION * session, const char *managed_system, * return: 0 - record found * -1 - not found * */ -int +static int phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn) { phyp_driverPtr phyp_driver = conn->privateData; @@ -634,7 +1396,7 @@ phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn) * 0 - maxmem * 1 - memory * */ -unsigned long +static unsigned long phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id, int type) { @@ -689,22 +1451,7 @@ phypGetLparMem(virConnectPtr conn, const char *managed_system, int lpar_id, } -unsigned long -phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id) -{ - return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0); -} - -static int -phypGetLparCPUMAX(virDomainPtr dom) -{ - phyp_driverPtr phyp_driver = dom->conn->privateData; - char *managed_system = phyp_driver->managed_system; - - return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1); -} - -unsigned long +static unsigned long phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system, int lpar_id, int type) { @@ -755,7 +1502,22 @@ phypGetLparCPUGeneric(virConnectPtr conn, const char *managed_system, return 0; } -int +static unsigned long +phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id) +{ + return phypGetLparCPUGeneric(conn, managed_system, lpar_id, 0); +} + +static int +phypGetLparCPUMAX(virDomainPtr dom) +{ + phyp_driverPtr phyp_driver = dom->conn->privateData; + char *managed_system = phyp_driver->managed_system; + + return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1); +} + +static int phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, const char *lpar_name) { @@ -805,7 +1567,10 @@ phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, return -1; } -char * +/* XXX - is this needed? */ +static char *phypGetBackingDevice(virConnectPtr, const char *, char *) + ATTRIBUTE_UNUSED; +static char * phypGetBackingDevice(virConnectPtr conn, const char *managed_system, char *lpar_name) { @@ -885,7 +1650,7 @@ phypGetBackingDevice(virConnectPtr conn, const char *managed_system, } -int +static int phypGetLparState(virConnectPtr conn, unsigned int lpar_id) { ConnectionData *connection_data = conn->networkPrivateData; @@ -934,52 +1699,9 @@ phypGetLparState(virConnectPtr conn, unsigned int lpar_id) return state; } -int -phypGetVIOSPartitionID(virConnectPtr conn) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - char *cmd = NULL; - char *ret = NULL; - int exit_status = 0; - int id = -1; - char *char_ptr; - char *managed_system = phyp_driver->managed_system; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - virBufferAddLit(&buf, "lssyscfg"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env|grep " - "vioserver|sed -s 's/,.*$//'"); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - if (exit_status < 0 || ret == NULL) - goto err; - - if (virStrToLong_i(ret, &char_ptr, 10, &id) == -1) - goto err; - - VIR_FREE(cmd); - VIR_FREE(ret); - return id; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - -int +/* XXX - is this needed? */ +static int phypDiskType(virConnectPtr, char *) ATTRIBUTE_UNUSED; +static int phypDiskType(virConnectPtr conn, char *backing_device) { phyp_driverPtr phyp_driver = conn->privateData; @@ -1029,71 +1751,6 @@ phypDiskType(virConnectPtr conn, char *backing_device) return disk_type; } -/* This is a generic function that won't be used directly by - * libvirt api. The function returns the number of domains - * in different states: Running, Not Activated and all: - * - * type: 0 - Running - * 1 - Not Activated - * * - All - * */ -static int -phypNumDomainsGeneric(virConnectPtr conn, unsigned int type) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - int exit_status = 0; - int ndom = 0; - char *char_ptr; - char *cmd = NULL; - char *ret = NULL; - char *managed_system = phyp_driver->managed_system; - const char *state; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (type == 0) - state = "|grep Running"; - else if (type == 1) { - if (system_type == HMC) { - state = "|grep \"Not Activated\""; - } else { - state = "|grep \"Open Firmware\""; - } - } else - state = " "; - - virBufferAddLit(&buf, "lssyscfg -r lpar"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -F lpar_id,state %s |grep -c '^[0-9]*'", - state); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - if (exit_status < 0 || ret == NULL) - goto err; - - if (virStrToLong_i(ret, &char_ptr, 10, &ndom) == -1) - goto err; - - VIR_FREE(cmd); - VIR_FREE(ret); - return ndom; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - static int phypNumDefinedDomains(virConnectPtr conn) { @@ -1106,86 +1763,6 @@ phypNumDomains(virConnectPtr conn) return phypNumDomainsGeneric(conn, 0); } -/* This is a generic function that won't be used directly by - * libvirt api. The function returns the ids of domains - * in different states: Running, and all: - * - * type: 0 - Running - * 1 - all - * */ -static int -phypListDomainsGeneric(virConnectPtr conn, int *ids, int nids, - unsigned int type) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - char *managed_system = phyp_driver->managed_system; - int exit_status = 0; - int got = 0; - char *char_ptr; - unsigned int i = 0, j = 0; - char id_c[10]; - char *cmd = NULL; - char *ret = NULL; - const char *state; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (type == 0) - state = "|grep Running"; - else - state = " "; - - memset(id_c, 0, 10); - - virBufferAddLit(&buf, "lssyscfg -r lpar"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -F lpar_id,state %s | sed -e 's/,.*$//'", - state); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - /* I need to parse the textual return in order to get the ret */ - if (exit_status < 0 || ret == NULL) - goto err; - else { - while (got < nids) { - if (ret[i] == '\0') - break; - else if (ret[i] == '\n') { - if (virStrToLong_i(id_c, &char_ptr, 10, &ids[got]) == -1) { - VIR_ERROR(_("Cannot parse number from '%s'"), id_c); - goto err; - } - memset(id_c, 0, 10); - j = 0; - got++; - } else { - id_c[j] = ret[i]; - j++; - } - i++; - } - } - - VIR_FREE(cmd); - VIR_FREE(ret); - return got; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - static int phypListDomains(virConnectPtr conn, int *ids, int nids) { @@ -1513,6 +2090,55 @@ phypDomainDestroy(virDomainPtr dom) } +static int +phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + char *managed_system = phyp_driver->managed_system; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&buf, "mksyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -r lpar -p %s -i min_mem=%d,desired_mem=%d," + "max_mem=%d,desired_procs=%d,virtual_scsi_adapters=%s", + def->name, (int) def->memory, (int) def->memory, + (int) def->maxmem, (int) def->vcpus, def->disks[0]->src); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0) { + VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), ret); + goto err; + } + + if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) { + VIR_ERROR0(_("Unable to add LPAR to the table")); + goto err; + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + static virDomainPtr phypDomainCreateAndStart(virConnectPtr conn, const char *xml, unsigned int flags) @@ -1578,50 +2204,6 @@ phypConnectGetCapabilities(virConnectPtr conn) return xml; } -virCapsPtr -phypCapsInit(void) -{ - struct utsname utsname; - virCapsPtr caps; - virCapsGuestPtr guest; - - uname(&utsname); - - if ((caps = virCapabilitiesNew(utsname.machine, 0, 0)) == NULL) - goto no_memory; - - /* Some machines have problematic NUMA toplogy causing - * unexpected failures. We don't want to break the QEMU - * driver in this scenario, so log errors & carry on - */ - if (nodeCapsInitNUMA(caps) < 0) { - virCapabilitiesFreeNUMAInfo(caps); - VIR_WARN0 - ("Failed to query host NUMA topology, disabling NUMA capabilities"); - } - - /* XXX shouldn't 'borrow' KVM's prefix */ - virCapabilitiesSetMacPrefix(caps, (unsigned char[]) { - 0x52, 0x54, 0x00}); - - if ((guest = virCapabilitiesAddGuest(caps, - "linux", - utsname.machine, - sizeof(int) == 4 ? 32 : 8, - NULL, NULL, 0, NULL)) == NULL) - goto no_memory; - - if (virCapabilitiesAddGuestDomain(guest, - "phyp", NULL, NULL, 0, NULL) == NULL) - goto no_memory; - - return caps; - - no_memory: - virCapabilitiesFree(caps); - return NULL; -} - static int phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) { @@ -1683,7 +2265,7 @@ phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) } -virDriver phypDriver = { +static virDriver phypDriver = { VIR_DRV_PHYP, "PHYP", phypOpen, /* open */ phypClose, /* close */ NULL, /* supports_feature */ @@ -1783,584 +2365,6 @@ virDriver phypDriver = { }; int -phypBuildLpar(virConnectPtr conn, virDomainDefPtr def) -{ - ConnectionData *connection_data = conn->networkPrivateData; - phyp_driverPtr phyp_driver = conn->privateData; - LIBSSH2_SESSION *session = connection_data->session; - int system_type = phyp_driver->system_type; - char *managed_system = phyp_driver->managed_system; - char *cmd = NULL; - char *ret = NULL; - int exit_status = 0; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - virBufferAddLit(&buf, "mksyscfg"); - if (system_type == HMC) - virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -r lpar -p %s -i min_mem=%d,desired_mem=%d," - "max_mem=%d,desired_procs=%d,virtual_scsi_adapters=%s", - def->name, (int) def->memory, (int) def->memory, - (int) def->maxmem, (int) def->vcpus, def->disks[0]->src); - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - cmd = virBufferContentAndReset(&buf); - - ret = phypExec(session, cmd, &exit_status, conn); - - if (exit_status < 0) { - VIR_ERROR(_("Unable to create LPAR. Reason: '%s'"), ret); - goto err; - } - - if (phypUUIDTable_AddLpar(conn, def->uuid, def->id) == -1) { - VIR_ERROR0(_("Unable to add LPAR to the table")); - goto err; - } - - VIR_FREE(cmd); - VIR_FREE(ret); - return 0; - - err: - VIR_FREE(cmd); - VIR_FREE(ret); - return -1; -} - -int -phypUUIDTable_RemLpar(virConnectPtr conn, int id) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - unsigned int i = 0; - - for (i = 0; i <= uuid_table->nlpars; i++) { - if (uuid_table->lpars[i]->id == id) { - uuid_table->lpars[i]->id = -1; - memset(uuid_table->lpars[i]->uuid, 0, VIR_UUID_BUFLEN); - } - } - - if (phypUUIDTable_WriteFile(conn) == -1) - goto err; - - if (phypUUIDTable_Push(conn) == -1) - goto err; - - return 0; - - err: - return -1; -} - -int -phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - - uuid_table->nlpars++; - unsigned int i = uuid_table->nlpars; - i--; - - if (VIR_REALLOC_N(uuid_table->lpars, uuid_table->nlpars) < 0) { - virReportOOMError(); - goto err; - } - - if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { - virReportOOMError(); - goto err; - } - - uuid_table->lpars[i]->id = id; - memmove(uuid_table->lpars[i]->uuid, uuid, VIR_UUID_BUFLEN); - - if (phypUUIDTable_WriteFile(conn) == -1) - goto err; - - if (phypUUIDTable_Push(conn) == -1) - goto err; - - return 0; - - err: - return -1; -} - -int -phypUUIDTable_ReadFile(virConnectPtr conn) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - unsigned int i = 0; - int fd = -1; - char local_file[] = "./uuid_table"; - int rc = 0; - int id; - - if ((fd = open(local_file, O_RDONLY)) == -1) { - VIR_WARN0("Unable to write information to local file."); - goto err; - } - - /* Creating a new data base and writing to local file */ - if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { - for (i = 0; i < uuid_table->nlpars; i++) { - - rc = read(fd, &id, sizeof(int)); - if (rc == sizeof(int)) { - if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { - virReportOOMError(); - goto err; - } - uuid_table->lpars[i]->id = id; - } else { - VIR_WARN0 - ("Unable to read from information to local file."); - goto err; - } - - rc = read(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN); - if (rc != VIR_UUID_BUFLEN) { - VIR_WARN0("Unable to read information to local file."); - goto err; - } - } - } else - virReportOOMError(); - - close(fd); - return 0; - - err: - close(fd); - return -1; -} - -int -phypUUIDTable_WriteFile(virConnectPtr conn) -{ - phyp_driverPtr phyp_driver = conn->privateData; - uuid_tablePtr uuid_table = phyp_driver->uuid_table; - unsigned int i = 0; - int fd = -1; - char local_file[] = "./uuid_table"; - - if ((fd = creat(local_file, 0755)) == -1) - goto err; - - for (i = 0; i < uuid_table->nlpars; i++) { - if (safewrite(fd, &uuid_table->lpars[i]->id, - sizeof(uuid_table->lpars[i]->id)) != - sizeof(uuid_table->lpars[i]->id)) { - VIR_ERROR0(_("Unable to write information to local file.")); - goto err; - } - - if (safewrite(fd, uuid_table->lpars[i]->uuid, VIR_UUID_BUFLEN) != - VIR_UUID_BUFLEN) { - VIR_ERROR0(_("Unable to write information to local file.")); - goto err; - } - } - - close(fd); - return 0; - - err: - close(fd); - return -1; -} - -int -phypUUIDTable_Init(virConnectPtr conn) -{ - uuid_tablePtr uuid_table; - phyp_driverPtr phyp_driver; - int nids_numdomains = 0; - int nids_listdomains = 0; - int *ids = NULL; - unsigned int i = 0; - - if ((nids_numdomains = phypNumDomainsGeneric(conn, 2)) < 0) - goto err; - - if (VIR_ALLOC_N(ids, nids_numdomains) < 0) { - virReportOOMError(); - goto err; - } - - if ((nids_listdomains = - phypListDomainsGeneric(conn, ids, nids_numdomains, 1)) < 0) - goto err; - - /* exit early if there are no domains */ - if (nids_numdomains == 0 && nids_listdomains == 0) - goto exit; - else if (nids_numdomains != nids_listdomains) { - VIR_ERROR0(_("Unable to determine number of domains.")); - goto err; - } - - phyp_driver = conn->privateData; - uuid_table = phyp_driver->uuid_table; - uuid_table->nlpars = nids_listdomains; - - /* try to get the table from server */ - if (phypUUIDTable_Pull(conn) == -1) { - /* file not found in the server, creating a new one */ - if (VIR_ALLOC_N(uuid_table->lpars, uuid_table->nlpars) >= 0) { - for (i = 0; i < uuid_table->nlpars; i++) { - if (VIR_ALLOC(uuid_table->lpars[i]) < 0) { - virReportOOMError(); - goto err; - } - uuid_table->lpars[i]->id = ids[i]; - - if (virUUIDGenerate(uuid_table->lpars[i]->uuid) < 0) - VIR_WARN("Unable to generate UUID for domain %d", - ids[i]); - } - } else { - virReportOOMError(); - goto err; - } - - if (phypUUIDTable_WriteFile(conn) == -1) - goto err; - - if (phypUUIDTable_Push(conn) == -1) - goto err; - } else { - if (phypUUIDTable_ReadFile(conn) == -1) - goto err; - goto exit; - } - - exit: - VIR_FREE(ids); - return 0; - - err: - VIR_FREE(ids); - return -1; -} - -void -phypUUIDTable_Free(uuid_tablePtr uuid_table) -{ - int i; - - if (uuid_table == NULL) - return; - - for (i = 0; i < uuid_table->nlpars; i++) - VIR_FREE(uuid_table->lpars[i]); - - VIR_FREE(uuid_table->lpars); - VIR_FREE(uuid_table); -} - -int -phypUUIDTable_Push(virConnectPtr conn) -{ - ConnectionData *connection_data = conn->networkPrivateData; - LIBSSH2_SESSION *session = connection_data->session; - LIBSSH2_CHANNEL *channel = NULL; - virBuffer username = VIR_BUFFER_INITIALIZER; - struct stat local_fileinfo; - char buffer[1024]; - int rc = 0; - FILE *fd; - size_t nread, sent; - char *ptr; - char local_file[] = "./uuid_table"; - char *remote_file = NULL; - - if (conn->uri->user != NULL) { - virBufferVSprintf(&username, "%s", conn->uri->user); - - if (virBufferError(&username)) { - virBufferFreeAndReset(&username); - virReportOOMError(); - goto err; - } - } - - if (virAsprintf - (&remote_file, "/home/%s/libvirt_uuid_table", - virBufferContentAndReset(&username)) - < 0) { - virReportOOMError(); - goto err; - } - - if (stat(local_file, &local_fileinfo) == -1) { - VIR_WARN0("Unable to stat local file."); - goto err; - } - - if (!(fd = fopen(local_file, "rb"))) { - VIR_WARN0("Unable to open local file."); - goto err; - } - - do { - channel = - libssh2_scp_send(session, remote_file, - 0x1FF & local_fileinfo.st_mode, - (unsigned long) local_fileinfo.st_size); - - if ((!channel) && (libssh2_session_last_errno(session) != - LIBSSH2_ERROR_EAGAIN)) - goto err; - } while (!channel); - - do { - nread = fread(buffer, 1, sizeof(buffer), fd); - if (nread <= 0) { - if (feof(fd)) { - /* end of file */ - break; - } else { - VIR_ERROR(_("Failed to read from %s"), local_file); - goto err; - } - } - ptr = buffer; - sent = 0; - - do { - /* write the same data over and over, until error or completion */ - rc = libssh2_channel_write(channel, ptr, nread); - if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */ - continue; - } else if (rc > 0) { - /* rc indicates how many bytes were written this time */ - sent += rc; - } - ptr += sent; - nread -= sent; - } while (rc > 0 && sent < nread); - } while (1); - - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - virBufferFreeAndReset(&username); - return 0; - - err: - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - return -1; -} - -int -phypUUIDTable_Pull(virConnectPtr conn) -{ - ConnectionData *connection_data = conn->networkPrivateData; - LIBSSH2_SESSION *session = connection_data->session; - LIBSSH2_CHANNEL *channel = NULL; - virBuffer username = VIR_BUFFER_INITIALIZER; - struct stat fileinfo; - char buffer[1024]; - int rc = 0; - int fd; - int got = 0; - int amount = 0; - int total = 0; - int sock = 0; - char local_file[] = "./uuid_table"; - char *remote_file = NULL; - - if (conn->uri->user != NULL) { - virBufferVSprintf(&username, "%s", conn->uri->user); - - if (virBufferError(&username)) { - virBufferFreeAndReset(&username); - virReportOOMError(); - goto err; - } - } - - if (virAsprintf - (&remote_file, "/home/%s/libvirt_uuid_table", - virBufferContentAndReset(&username)) - < 0) { - virReportOOMError(); - goto err; - } - - /* Trying to stat the remote file. */ - do { - channel = libssh2_scp_recv(session, remote_file, &fileinfo); - - if (!channel) { - if (libssh2_session_last_errno(session) != - LIBSSH2_ERROR_EAGAIN) { - goto err;; - } else { - waitsocket(sock, session); - } - } - } while (!channel); - - /* Creating a new data base based on remote file */ - if ((fd = creat(local_file, 0755)) == -1) - goto err; - - /* Request a file via SCP */ - while (got < fileinfo.st_size) { - do { - amount = sizeof(buffer); - - if ((fileinfo.st_size - got) < amount) { - amount = fileinfo.st_size - got; - } - - rc = libssh2_channel_read(channel, buffer, amount); - if (rc > 0) { - if (safewrite(fd, buffer, rc) != rc) - VIR_WARN0 - ("Unable to write information to local file."); - - got += rc; - total += rc; - } - } while (rc > 0); - - if ((rc == LIBSSH2_ERROR_EAGAIN) - && (got < fileinfo.st_size)) { - /* this is due to blocking that would occur otherwise - * so we loop on this condition */ - - waitsocket(sock, session); /* now we wait */ - continue; - } - break; - } - close(fd); - goto exit; - - exit: - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - virBufferFreeAndReset(&username); - return 0; - - err: - if (channel) { - libssh2_channel_send_eof(channel); - libssh2_channel_wait_eof(channel); - libssh2_channel_wait_closed(channel); - libssh2_channel_free(channel); - channel = NULL; - } - return -1; -} - -int -escape_specialcharacters(char *src, char *dst, size_t dstlen) -{ - size_t len = strlen(src); - char temp_buffer[len]; - unsigned int i = 0, j = 0; - if (len == 0) - return -1; - - for (i = 0; i < len; i++) { - switch (src[i]) { - case '&': - case ';': - case '`': - case '@': - case '"': - case '|': - case '*': - case '?': - case '~': - case '<': - case '>': - case '^': - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case '$': - case '%': - case '#': - case '\\': - case '\n': - case '\r': - case '\t': - continue; - default: - temp_buffer[j] = src[i]; - j++; - } - } - temp_buffer[j] = '\0'; - - if (virStrcpy(dst, temp_buffer, dstlen) == NULL) - return -1; - - return 0; -} - -int -waitsocket(int socket_fd, LIBSSH2_SESSION * session) -{ - struct timeval timeout; - int rc; - fd_set fd; - fd_set *writefd = NULL; - fd_set *readfd = NULL; - int dir; - - timeout.tv_sec = 0; - timeout.tv_usec = 1000; - - FD_ZERO(&fd); - - FD_SET(socket_fd, &fd); - - /* now make sure we wait in the correct direction */ - dir = libssh2_session_block_directions(session); - - if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) - readfd = &fd; - - if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) - writefd = &fd; - - rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout); - - return rc; -} - -int phypRegister(void) { virRegisterDriver(&phypDriver); diff --git a/src/phyp/phyp_driver.h b/src/phyp/phyp_driver.h index 80ff0c3..a22156c 100644 --- a/src/phyp/phyp_driver.h +++ b/src/phyp/phyp_driver.h @@ -1,5 +1,5 @@ - /* + * Copyright (C) 2010 Red Hat, Inc. * Copyright IBM Corp. 2009 * * phyp_driver.c: ssh layer to access Power Hypervisors @@ -22,14 +22,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "conf/capabilities.h" -#include "conf/domain_conf.h" -#include <config.h> -#include <libssh2.h> +#ifndef PHYP_DRIVER_H +# define PHYP_DRIVER_H + +# include "conf/capabilities.h" +# include "conf/domain_conf.h" +# include <config.h> +# include <libssh2.h> -#define LPAR_EXEC_ERR -1 -#define SSH_CONN_ERR -2 /* error while trying to connect to remote host */ -#define SSH_CMD_ERR -3 /* error while trying to execute the remote cmd */ +# define LPAR_EXEC_ERR -1 +# define SSH_CONN_ERR -2 /* error while trying to connect to remote host */ +# define SSH_CMD_ERR -3 /* error while trying to execute the remote cmd */ typedef struct _ConnectionData ConnectionData; typedef ConnectionData *ConnectionDataPtr; @@ -75,60 +78,6 @@ struct _phyp_driver { char *managed_system; }; -int phypCheckSPFreeSapce(virConnectPtr conn, int required_size, char *sp); - -int phypGetSystemType(virConnectPtr conn); - -int phypGetVIOSPartitionID(virConnectPtr conn); - -virCapsPtr phypCapsInit(void); - -int phypBuildLpar(virConnectPtr conn, virDomainDefPtr def); - -int phypUUIDTable_WriteFile(virConnectPtr conn); - -int phypUUIDTable_ReadFile(virConnectPtr conn); - -int phypUUIDTable_AddLpar(virConnectPtr conn, unsigned char *uuid, int id); - -int phypUUIDTable_RemLpar(virConnectPtr conn, int id); - -int phypUUIDTable_Pull(virConnectPtr conn); - -int phypUUIDTable_Push(virConnectPtr conn); - -int phypUUIDTable_Init(virConnectPtr conn); - -void phypUUIDTable_Free(uuid_tablePtr uuid_table); - -int escape_specialcharacters(char *src, char *dst, size_t dstlen); - -int waitsocket(int socket_fd, LIBSSH2_SESSION * session); - -int phypGetLparUUID(unsigned char *uuid, int lpar_id, virConnectPtr conn); - int phypRegister(void); -int phypGetLparState(virConnectPtr conn, unsigned int lpar_id); - -unsigned long phypGetLparMem(virConnectPtr conn, - const char *managed_system, int lpar_id, - int type); - -unsigned long phypGetLparCPU(virConnectPtr conn, - const char *managed_system, int lpar_id); - -unsigned long phypGetLparCPUGeneric(virConnectPtr conn, - const char *managed_system, - int lpar_id, int type); - -int phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, - const char *lpar_name); - -char *phypGetBackingDevice(virConnectPtr conn, const char *managed_system, - char *lpar_name); - -int phypDiskType(virConnectPtr conn, char *backing_device); - -LIBSSH2_SESSION *openSSHSession(virConnectPtr conn, virConnectAuthPtr auth, - int *internal_socket); +#endif /* PHYP_DRIVER_H */ -- 1.7.0.1

On 06/24/2010 07:32 PM, Eric Blake wrote:
Several phyp functions are not namespace clean, and had no reason to be exported since no one outside the phyp driver needed to use them. Rather than do lots of forward declarations, I was able to topologically sort the file. So, this patch looks huge, but is really just a matter of marking things static and dealing with the compiler fallout.
* src/phyp/phyp_driver.h (PHYP_DRIVER_H): Add include guard. (phypCheckSPFreeSapce): Delete unused declaration. (phypGetSystemType, phypGetVIOSPartitionID, phypCapsInit) (phypBuildLpar, phypUUIDTable_WriteFile, phypUUIDTable_ReadFile) (phypUUIDTable_AddLpar, phypUUIDTable_RemLpar, phypUUIDTable_Pull) (phypUUIDTable_Push, phypUUIDTable_Init, phypUUIDTable_Free) (escape_specialcharacters, waitsocket, phypGetLparUUID) (phypGetLparMem, phypGetLparCPU, phypGetLparCPUGeneric) (phypGetRemoteSlot, phypGetBackingDevice, phypDiskType) (openSSHSession): Move declarations to phyp_driver.c and make static. * src/phyp/phyp_driver.c: Rearrange file contents to provide topological sorting of newly-static funtions (no semantic changes other than reduced scope). (phypGetBackingDevice, phypDiskType): Mark unused, for now. ---
New patch - reduce scope where possible, and rearrange everything into topological order. There is no significant code changes beyond marking a few things 'static', so although it looks big, you don't have to worry about the guts of any command changing.
Yes, I was aware of that and was planning a future patch with these changes. If you thought that would be better to clean these up early it's ok too. Thank you very much. The patch seems ok. I tested the commands with my HMC/VIOS and IVM and everything is still working. Thanks. ACK. []'s -- Eduardo Otubo Software Engineer Linux Technology Center IBM Systems & Technology Group Mobile: +55 19 8135 0885 eotubo@linux.vnet.ibm.com

From: Eduardo Otubo <otubo@linux.vnet.ibm.com> * src/phyp/phyp_driver.c (phypStorageDriver): New driver. (phypStorageOpen, phypStorageClose): New functions. (phypRegister): Register it. Signed-off-by: Eric Blake <eblake@redhat.com> --- For my sanity, I split out the creation/registration of the driver from the addition of all the methods in the driver. src/phyp/phyp_driver.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 63 insertions(+), 1 deletions(-) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 0912f90..341ee99 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -56,6 +56,7 @@ #include "virterror_internal.h" #include "uuid.h" #include "domain_conf.h" +#include "storage_conf.h" #include "nodeinfo.h" #include "phyp_driver.h" @@ -2265,6 +2266,22 @@ phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) } +static virDrvOpenStatus +phypStorageOpen(virConnectPtr conn ATTRIBUTE_UNUSED, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags) +{ + virCheckFlags(0, VIR_DRV_OPEN_ERROR); + + return VIR_DRV_OPEN_SUCCESS; +} + +static int +phypStorageClose(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return 0; +} + static virDriver phypDriver = { VIR_DRV_PHYP, "PHYP", phypOpen, /* open */ phypClose, /* close */ @@ -2364,9 +2381,54 @@ static virDriver phypDriver = { NULL, /* domainSnapshotDelete */ }; +static virStorageDriver phypStorageDriver = { + .name = "PHYP", + .open = phypStorageOpen, + .close = phypStorageClose, + + .numOfPools = NULL, + .listPools = NULL, + .numOfDefinedPools = NULL, + .listDefinedPools = NULL, + .findPoolSources = NULL, + .poolLookupByName = NULL, + .poolLookupByUUID = NULL, + .poolLookupByVolume = NULL, + .poolCreateXML = NULL, + .poolDefineXML = NULL, + .poolBuild = NULL, + .poolUndefine = NULL, + .poolCreate = NULL, + .poolDestroy = NULL, + .poolDelete = NULL, + .poolRefresh = NULL, + .poolGetInfo = NULL, + .poolGetXMLDesc = NULL, + .poolGetAutostart = NULL, + .poolSetAutostart = NULL, + .poolNumOfVolumes = NULL, + .poolListVolumes = NULL, + + .volLookupByName = NULL, + .volLookupByKey = NULL, + .volLookupByPath = NULL, + .volCreateXML = NULL, + .volCreateXMLFrom = NULL, + .volDelete = NULL, + .volGetInfo = NULL, + .volGetXMLDesc = NULL, + .volGetPath = NULL, + .poolIsActive = NULL, + .poolIsPersistent = NULL +}; + int phypRegister(void) { - virRegisterDriver(&phypDriver); + if (virRegisterDriver(&phypDriver) < 0) + return -1; + if (virRegisterStorageDriver(&phypStorageDriver) < 0) + return -1; + return 0; } -- 1.7.0.1

On 06/24/2010 07:32 PM, Eric Blake wrote:
From: Eduardo Otubo<otubo@linux.vnet.ibm.com>
* src/phyp/phyp_driver.c (phypStorageDriver): New driver. (phypStorageOpen, phypStorageClose): New functions. (phypRegister): Register it.
Signed-off-by: Eric Blake<eblake@redhat.com> ---
For my sanity, I split out the creation/registration of the driver from the addition of all the methods in the driver.
src/phyp/phyp_driver.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 63 insertions(+), 1 deletions(-)
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 0912f90..341ee99 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -56,6 +56,7 @@ #include "virterror_internal.h" #include "uuid.h" #include "domain_conf.h" +#include "storage_conf.h" #include "nodeinfo.h"
#include "phyp_driver.h" @@ -2265,6 +2266,22 @@ phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus)
}
+static virDrvOpenStatus +phypStorageOpen(virConnectPtr conn ATTRIBUTE_UNUSED, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags) +{ + virCheckFlags(0, VIR_DRV_OPEN_ERROR); + + return VIR_DRV_OPEN_SUCCESS; +} + +static int +phypStorageClose(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + return 0; +} + static virDriver phypDriver = { VIR_DRV_PHYP, "PHYP", phypOpen, /* open */ phypClose, /* close */ @@ -2364,9 +2381,54 @@ static virDriver phypDriver = { NULL, /* domainSnapshotDelete */ };
+static virStorageDriver phypStorageDriver = { + .name = "PHYP", + .open = phypStorageOpen, + .close = phypStorageClose, + + .numOfPools = NULL, + .listPools = NULL, + .numOfDefinedPools = NULL, + .listDefinedPools = NULL, + .findPoolSources = NULL, + .poolLookupByName = NULL, + .poolLookupByUUID = NULL, + .poolLookupByVolume = NULL, + .poolCreateXML = NULL, + .poolDefineXML = NULL, + .poolBuild = NULL, + .poolUndefine = NULL, + .poolCreate = NULL, + .poolDestroy = NULL, + .poolDelete = NULL, + .poolRefresh = NULL, + .poolGetInfo = NULL, + .poolGetXMLDesc = NULL, + .poolGetAutostart = NULL, + .poolSetAutostart = NULL, + .poolNumOfVolumes = NULL, + .poolListVolumes = NULL, + + .volLookupByName = NULL, + .volLookupByKey = NULL, + .volLookupByPath = NULL, + .volCreateXML = NULL, + .volCreateXMLFrom = NULL, + .volDelete = NULL, + .volGetInfo = NULL, + .volGetXMLDesc = NULL, + .volGetPath = NULL, + .poolIsActive = NULL, + .poolIsPersistent = NULL +}; + int phypRegister(void) { - virRegisterDriver(&phypDriver); + if (virRegisterDriver(&phypDriver)< 0) + return -1; + if (virRegisterStorageDriver(&phypStorageDriver)< 0) + return -1; + return 0; }
ACK. -- Eduardo Otubo Software Engineer Linux Technology Center IBM Systems & Technology Group Mobile: +55 19 8135 0885 eotubo@linux.vnet.ibm.com

From: Eduardo Otubo <otubo@linux.vnet.ibm.com> Add the storage management driver to the Power Hypervisor driver. This is a big but simple patch, it's just a new set of functions. This patch includes: * Storage driver: The set of pool-* and vol-* functions. * attach-disk function. * Support for IVM on the new functions. Signed-off-by: Eric Blake <eblake@redhat.com> --- This is more or less Eduardo's v2 2/2 patch, but reorganized in topological order and converted to static functions, and with a lot of cleanups (such as from v2 1/2) squashed in. I tested that it compiles, but I did _not_ test that it works for HVM - Eduardo, you'll need to give this a once-over. src/phyp/phyp_driver.c | 1638 +++++++++++++++++++++++++++++++++++++++++++++++- src/phyp/phyp_driver.h | 1 + 2 files changed, 1624 insertions(+), 15 deletions(-) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 341ee99..df6d10c 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1648,7 +1648,1615 @@ phypGetBackingDevice(virConnectPtr conn, const char *managed_system, VIR_FREE(cmd); VIR_FREE(ret); return NULL; +} + +static char * +phypGetLparProfile(virConnectPtr conn, int lpar_id) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&buf, "lssyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, + " -r prof --filter lpar_ids=%d -F name|head -n 1", + lpar_id); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + char *char_ptr = strchr(ret, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + VIR_FREE(cmd); + return ret; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return NULL; +} + +static int +phypGetVIOSNextSlotNumber(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *char_ptr; + char *cmd = NULL; + char *ret = NULL; + char *profile = NULL; + int slot = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!(profile = phypGetLparProfile(conn, vios_id))) { + VIR_ERROR0(_("Unable to get VIOS profile name.")); + goto err; + } + + virBufferAddLit(&buf, "lssyscfg"); + + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + + virBufferVSprintf(&buf, " -r prof --filter " + "profile_names=%s -F virtual_eth_adapters," + "virtual_opti_pool_id,virtual_scsi_adapters," + "virtual_serial_adapters|sed -e 's/\"//g' -e " + "'s/,/\\n/g'|sed -e 's/\\(^[0-9][0-9]\\*\\).*$/\\1/'" + "|sort|tail -n 1", profile); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &slot) == -1) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return slot + 1; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypCreateServerSCSIAdapter(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + char *profile = NULL; + int slot = 0; + char *vios_name = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (! + (vios_name = + phypGetLparNAME(session, managed_system, vios_id, conn))) { + VIR_ERROR0(_("Unable to get VIOS name")); + goto err; + } + + if (!(profile = phypGetLparProfile(conn, vios_id))) { + VIR_ERROR0(_("Unable to get VIOS profile name.")); + goto err; + } + + if ((slot = phypGetVIOSNextSlotNumber(conn)) == -1) { + VIR_ERROR0(_("Unable to get free slot number")); + goto err; + } + + /* Listing all the virtual_scsi_adapter interfaces, the new adapter must + * be appended to this list + * */ + virBufferAddLit(&buf, "lssyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -r prof --filter lpar_ids=%d,profile_names=%s" + " -F virtual_scsi_adapters|sed -e s/\\\"//g", + vios_id, profile); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + /* Here I change the VIOS configuration to append the new adapter + * with the free slot I got with phypGetVIOSNextSlotNumber. + * */ + virBufferAddLit(&buf, "chsyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, " -r prof -i 'name=%s,lpar_id=%d," + "\"virtual_scsi_adapters=%s,%d/server/any/any/1\"'", + vios_name, vios_id, ret, slot); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + /* Finally I add the new scsi adapter to VIOS using the same slot + * I used in the VIOS configuration. + * */ + virBufferAddLit(&buf, "chhwres -r virtualio --rsubtype scsi"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, + " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"", + vios_name, slot); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + VIR_FREE(profile); + VIR_FREE(vios_name); + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(profile); + VIR_FREE(vios_name); + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static char * +phypGetVIOSFreeSCSIAdapter(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lsmap -all -field svsa backing -fmt , "); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|grep -v ',[^.*]'|head -n 1|sed -e 's/,//g'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + char *char_ptr = strchr(ret, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + VIR_FREE(cmd); + return ret; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return NULL; +} + + +static int +phypAttachDevice(virDomainPtr domain, const char *xml) +{ + + virConnectPtr conn = domain->conn; + ConnectionData *connection_data = domain->conn->networkPrivateData; + phyp_driverPtr phyp_driver = domain->conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *char_ptr = NULL; + char *cmd = NULL; + char *ret = NULL; + char *scsi_adapter = NULL; + int slot = 0; + char *vios_name = NULL; + char *profile = NULL; + virDomainDeviceDefPtr dev = NULL; + virDomainDefPtr def = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *domain_name = NULL; + + if (VIR_ALLOC_N(domain_name, sizeof(domain->name)) < 0) { + virReportOOMError(); + goto err; + } + + if (escape_specialcharacters + (domain->name, domain_name, strlen(domain->name)) == -1) { + virReportOOMError(); + goto err; + } + + def->os.type = strdup("aix"); + + if (def->os.type == NULL) { + virReportOOMError(); + goto err; + } + + dev = virDomainDeviceDefParse(phyp_driver->caps, def, xml, + VIR_DOMAIN_XML_INACTIVE); + if (!dev) { + virReportOOMError(); + goto err; + } + + if (! + (vios_name = + phypGetLparNAME(session, managed_system, vios_id, conn))) { + VIR_ERROR0(_("Unable to get VIOS name")); + goto err; + } + + /* First, let's look for a free SCSI Adapter + * */ + if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) { + /* If not found, let's create one. + * */ + if (phypCreateServerSCSIAdapter(conn) == -1) { + VIR_ERROR0(_("Unable to create new virtual adapter")); + goto err; + } else { + if (!(scsi_adapter = phypGetVIOSFreeSCSIAdapter(conn))) { + VIR_ERROR0(_("Unable to create new virtual adapter")); + goto err; + } + } + } + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "mkvdev -vdev %s -vadapter %s", + dev->data.disk->src, scsi_adapter); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (!(profile = phypGetLparProfile(conn, domain->id))) { + VIR_ERROR0(_("Unable to get VIOS profile name.")); + goto err; + } + + /* Let's get the slot number for the adapter we just created + * */ + virBufferAddLit(&buf, "lshwres -r virtualio --rsubtype scsi"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, + " slot_num,backing_device|grep %s|cut -d, -f1", + dev->data.disk->src); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &slot) == -1) + goto err; + + /* Listing all the virtual_scsi_adapter interfaces, the new adapter must + * be appended to this list + * */ + virBufferAddLit(&buf, "lssyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, + " -r prof --filter lpar_ids=%d,profile_names=%s" + " -F virtual_scsi_adapters|sed -e 's/\"//g'", + vios_id, profile); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + /* Here I change the LPAR configuration to append the new adapter + * with the new slot we just created + * */ + virBufferAddLit(&buf, "chsyscfg"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, + " -r prof -i 'name=%s,lpar_id=%d," + "\"virtual_scsi_adapters=%s,%d/client/%d/%s/0\"'", + domain_name, domain->id, ret, slot, + vios_id, vios_name); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (virStrToLong_i(ret, &char_ptr, 10, &slot) == -1) + goto err; + + /* Finally I add the new scsi adapter to VIOS using the same slot + * I used in the VIOS configuration. + * */ + virBufferAddLit(&buf, "chhwres -r virtualio --rsubtype scsi"); + if (system_type == HMC) + virBufferVSprintf(&buf, " -m %s", managed_system); + virBufferVSprintf(&buf, + " -p %s -o a -s %d -d 0 -a \"adapter_type=server\"", + domain_name, slot); + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) { + VIR_ERROR0(_ + ("Possibly you don't have IBM Tools installed in your LPAR." + "Contact your support to enable this feature.")); + goto err; + } + + VIR_FREE(cmd); + VIR_FREE(ret); + VIR_FREE(def); + VIR_FREE(dev); + VIR_FREE(vios_name); + VIR_FREE(scsi_adapter); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + VIR_FREE(def); + VIR_FREE(dev); + VIR_FREE(vios_name); + VIR_FREE(scsi_adapter); + return -1; +} + +static int +phypVolumeGetKey(virConnectPtr conn, char *key, const char *name) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lslv %s -field lvid", name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed -e 's/^LV IDENTIFIER://' -e 's/ //g'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + char *char_ptr = strchr(ret, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + if (memcpy(key, ret, MAX_KEY_SIZE) == NULL) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static char * +phypGetStoragePoolDevice(virConnectPtr conn, char *name) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lssp -detail -sp %s -field name", name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed '1d; s/ //g'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + char *char_ptr = strchr(ret, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + VIR_FREE(cmd); + return ret; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return NULL; +} + +static unsigned long int +phypGetStoragePoolSize(virConnectPtr conn, char *name) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int exit_status = 0; + int vios_id = phyp_driver->vios_id; + char *cmd = NULL; + char *ret = NULL; + int sp_size = 0; + char *char_ptr; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lssp -detail -sp %s -field size", name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed '1d; s/ //g'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &sp_size) == -1) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return sp_size; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypBuildVolume(virConnectPtr conn, const char *lvname, const char *spname, + unsigned int capacity, char *key) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int vios_id = phyp_driver->vios_id; + int system_type = phyp_driver->system_type; + char *managed_system = phyp_driver->managed_system; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "mklv -lv %s %s %d", lvname, spname, capacity); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0) { + VIR_ERROR(_("Unable to create Volume: %s"), ret); + goto err; + } + + if (phypVolumeGetKey(conn, key, lvname) == -1) + goto err;; + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static virStorageVolPtr +phypVolumeLookupByName(virStoragePoolPtr pool, const char *volname) +{ + + char key[MAX_KEY_SIZE]; + + if (phypVolumeGetKey(pool->conn, key, volname) == -1) + return NULL; + + return virGetStorageVol(pool->conn, pool->name, volname, key); +} + +static virStorageVolPtr +phypStorageVolCreateXML(virStoragePoolPtr pool, + const char *xml, unsigned int flags) +{ + virCheckFlags(0, NULL); + + virStorageVolDefPtr voldef = NULL; + virStoragePoolDefPtr spdef = NULL; + virStorageVolPtr vol = NULL; + char *key = NULL; + + if (VIR_ALLOC(spdef) < 0) { + virReportOOMError(); + return NULL; + } + + if (VIR_ALLOC_N(key, MAX_KEY_SIZE) < 0) { + virReportOOMError(); + return NULL; + } + + /* Filling spdef manually + * */ + if (pool->name != NULL) { + spdef->name = pool->name; + } else { + VIR_ERROR0(_("Unable to determine storage pool's name.")); + goto err; + } + + if (memcpy(spdef->uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) { + VIR_ERROR0(_("Unable to determine storage pool's uuid.")); + goto err; + } + + if ((spdef->capacity = + phypGetStoragePoolSize(pool->conn, pool->name)) == -1) { + VIR_ERROR0(_("Unable to determine storage pools's size.")); + goto err; + } + + /* Information not avaliable */ + spdef->allocation = 0; + spdef->available = 0; + + spdef->source.ndevice = 1; + + /*XXX source adapter not working properly, should show hdiskX */ + if ((spdef->source.adapter = + phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) { + VIR_ERROR0(_("Unable to determine storage pools's source adapter.")); + goto err; + } + + if ((voldef = virStorageVolDefParseString(spdef, xml)) == NULL) { + VIR_ERROR0(_("Error parsing volume XML.")); + goto err; + } + + /* checking if this name already exists on this system */ + if (phypVolumeLookupByName(pool, voldef->name) != NULL) { + VIR_ERROR0(_("StoragePool name already exists.")); + goto err; + } + + /* The key must be NULL, the Power Hypervisor creates a key + * in the moment you create the volume. + * */ + if (voldef->key) { + VIR_ERROR0(_("Key must be empty, Power Hypervisor will create one for you.")); + goto err; + } + + if (voldef->capacity) { + VIR_ERROR0(_("Capacity cannot be empty.")); + goto err; + } + + if (phypBuildVolume + (pool->conn, voldef->name, spdef->name, voldef->capacity, + key) == -1) + goto err; + + if ((vol = + virGetStorageVol(pool->conn, pool->name, voldef->name, + key)) == NULL) + goto err; + + return vol; + + err: + virStorageVolDefFree(voldef); + virStoragePoolDefFree(spdef); + if (vol) + virUnrefStorageVol(vol); + return NULL; +} + +static char * +phypVolumeGetPhysicalVolumeByStoragePool(virStorageVolPtr vol, char *sp) +{ + virConnectPtr conn = vol->conn; + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lssp -detail -sp %s -field pvname", sp); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed 1d"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + char *char_ptr = strchr(ret, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + VIR_FREE(cmd); + return ret; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return NULL; + +} + +static virStorageVolPtr +phypVolumeLookupByPath(virConnectPtr conn, const char *volname) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *spname = NULL; + char *key = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lslv %s -field vgname", volname); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + cmd = virBufferContentAndReset(&buf); + + spname = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || spname == NULL) + return NULL; + + char *char_ptr = strchr(spname, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + if (VIR_ALLOC_N(key, MAX_KEY_SIZE) < 0) { + virReportOOMError(); + return NULL; + } + + if (phypVolumeGetKey(conn, key, volname) == -1) + return NULL; + + return virGetStorageVol(conn, spname, volname, key); +} + +static int +phypGetStoragePoolUUID(virConnectPtr conn, unsigned char *uuid, + const char *name) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *ret = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lsdev -dev %s -attr vgserial_id", name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed '1,2d'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (memmove(uuid, ret, VIR_UUID_BUFLEN) == NULL) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static virStoragePoolPtr +phypStoragePoolLookupByName(virConnectPtr conn, const char *name) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + + if (phypGetStoragePoolUUID(conn, uuid, name) == -1) + return NULL; + + return virGetStoragePool(conn, name, uuid); +} + +static char * +phypVolumeGetXMLDesc(virStorageVolPtr vol, unsigned int flags) +{ + virCheckFlags(0, NULL); + + virStorageVolDef voldef; + memset(&voldef, 0, sizeof(virStorageVolDef)); + + virStoragePoolPtr sp = + phypStoragePoolLookupByName(vol->conn, vol->pool); + + if (!sp) + goto err; + + virStoragePoolDef pool; + memset(&pool, 0, sizeof(virStoragePoolDef)); + + if (VIR_ALLOC_N(voldef.key, MAX_KEY_SIZE) < 0) { + virReportOOMError(); + return NULL; + } + + if (sp->name != NULL) { + pool.name = sp->name; + } else { + VIR_ERROR0(_("Unable to determine storage sp's name.")); + goto err; + } + + if (memmove(pool.uuid, sp->uuid, VIR_UUID_BUFLEN) == NULL) { + VIR_ERROR0(_("Unable to determine storage sp's uuid.")); + goto err; + } + + if ((pool.capacity = phypGetStoragePoolSize(sp->conn, sp->name)) == -1) { + VIR_ERROR0(_("Unable to determine storage sps's size.")); + goto err; + } + + /* Information not avaliable */ + pool.allocation = 0; + pool.available = 0; + + pool.source.ndevice = 1; + + if ((pool.source.adapter = + phypGetStoragePoolDevice(sp->conn, sp->name)) == NULL) { + VIR_ERROR0(_("Unable to determine storage sps's source adapter.")); + goto err; + } + + if (vol->name != NULL) + voldef.name = vol->name; + else { + VIR_ERROR0(_("Unable to determine storage pool's name.")); + goto err; + } + + if (memmove(voldef.key, vol->key, PATH_MAX) == NULL) { + VIR_ERROR0(_("Unable to determine volume's key.")); + goto err; + } + + voldef.type = VIR_STORAGE_POOL_LOGICAL; + + return virStorageVolDefFormat(&pool, &voldef); + + err: + return NULL; +} + +/* The Volume Group path here will be treated as suggested in the + * email on the libvirt mailling list. As soon as I can't get the + * path for every volume, the path will be a representation in + * the form: + * + * /physical_volume/storage_pool/logical_volume + * + * */ +static char * +phypVolumeGetPath(virStorageVolPtr vol) +{ + virConnectPtr conn = vol->conn; + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + char *cmd = NULL; + char *sp = NULL; + char *path = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lslv %s -field vgname", vol->name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, + "|sed -e 's/^VOLUME GROUP://g' -e 's/ //g'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + cmd = virBufferContentAndReset(&buf); + + sp = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || sp == NULL) + goto err; + + char *char_ptr = strchr(sp, '\n'); + + if (char_ptr) + *char_ptr = '\0'; + + char *pv = phypVolumeGetPhysicalVolumeByStoragePool(vol, sp); + + if (pv) { + if (virAsprintf(&path, "/%s/%s/%s", pv, sp, vol->name) < 0) { + virReportOOMError(); + goto err; + } + } else { + goto err; + } + + VIR_FREE(cmd); + return path; + + err: + VIR_FREE(cmd); + VIR_FREE(sp); + VIR_FREE(path); + return NULL; + +} + +static int +phypStoragePoolListVolumes(virStoragePoolPtr pool, char **const volumes, + int nvolumes) +{ + virConnectPtr conn = pool->conn; + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + int got = 0; + int i; + char *cmd = NULL; + char *ret = NULL; + char *volumes_list = NULL; + char *char_ptr2 = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lsvg -lv %s -field lvname", pool->name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|sed '1,2d'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + /* I need to parse the textual return in order to get the volumes */ + if (exit_status < 0 || ret == NULL) + goto err; + else { + volumes_list = ret; + + while (got < nvolumes) { + char_ptr2 = strchr(volumes_list, '\n'); + + if (char_ptr2) { + *char_ptr2 = '\0'; + if ((volumes[got++] = strdup(volumes_list)) == NULL) { + virReportOOMError(); + goto err; + } + char_ptr2++; + volumes_list = char_ptr2; + } else + break; + } + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return got; + + err: + for (i = 0; i < got; i++) + VIR_FREE(volumes[i]); + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypStoragePoolNumOfVolumes(virStoragePoolPtr pool) +{ + virConnectPtr conn = pool->conn; + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + int exit_status = 0; + int nvolumes = 0; + char *cmd = NULL; + char *ret = NULL; + char *managed_system = phyp_driver->managed_system; + int vios_id = phyp_driver->vios_id; + char *char_ptr; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + virBufferVSprintf(&buf, "lsvg -lv %s -field lvname", pool->name); + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + virBufferVSprintf(&buf, "|grep -c '^.*$'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &nvolumes) == -1) + goto err; + + /* We need to remove 2 line from the header text output */ + nvolumes -= 2; + + VIR_FREE(cmd); + VIR_FREE(ret); + return nvolumes; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypDestroyStoragePool(virStoragePoolPtr pool) +{ + virConnectPtr conn = pool->conn; + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int vios_id = phyp_driver->vios_id; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "rmsp %s", pool->name); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + if (virAsprintf(&cmd, + "viosvrcmd -m %s --id %d -c " + "'rmsp %s'", managed_system, vios_id, + pool->name) < 0) { + virReportOOMError(); + goto err; + } + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0) { + VIR_ERROR(_("Unable to create Storage Pool: %s"), ret); + goto err; + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypBuildStoragePool(virConnectPtr conn, virStoragePoolDefPtr def) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + virStoragePoolSource source = def->source; + int vios_id = phyp_driver->vios_id; + int system_type = phyp_driver->system_type; + char *managed_system = phyp_driver->managed_system; + char *cmd = NULL; + char *ret = NULL; + int exit_status = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "mksp -f %schild %s", def->name, + source.adapter); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0) { + VIR_ERROR(_("Unable to create Storage Pool: %s"), ret); + goto err; + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return 0; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; + +} + +static int +phypNumOfStoragePools(virConnectPtr conn) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + int system_type = phyp_driver->system_type; + int exit_status = 0; + int nsp = 0; + char *cmd = NULL; + char *ret = NULL; + char *managed_system = phyp_driver->managed_system; + int vios_id = phyp_driver->vios_id; + char *char_ptr; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lsvg"); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + virBufferVSprintf(&buf, "|grep -c '^.*$'"); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + if (exit_status < 0 || ret == NULL) + goto err; + + if (virStrToLong_i(ret, &char_ptr, 10, &nsp) == -1) + goto err; + + VIR_FREE(cmd); + VIR_FREE(ret); + return nsp; + + err: + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static int +phypListStoragePools(virConnectPtr conn, char **const pools, int npools) +{ + ConnectionData *connection_data = conn->networkPrivateData; + phyp_driverPtr phyp_driver = conn->privateData; + LIBSSH2_SESSION *session = connection_data->session; + char *managed_system = phyp_driver->managed_system; + int system_type = phyp_driver->system_type; + int vios_id = phyp_driver->vios_id; + int exit_status = 0; + int got = 0; + int i; + char *cmd = NULL; + char *ret = NULL; + char *storage_pools = NULL; + char *char_ptr2 = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (system_type == HMC) + virBufferVSprintf(&buf, "viosvrcmd -m %s --id %d -c '", + managed_system, vios_id); + + virBufferVSprintf(&buf, "lsvg"); + + if (system_type == HMC) + virBufferAddChar(&buf, '\''); + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + cmd = virBufferContentAndReset(&buf); + + ret = phypExec(session, cmd, &exit_status, conn); + + /* I need to parse the textual return in order to get the storage pools */ + if (exit_status < 0 || ret == NULL) + goto err; + else { + storage_pools = ret; + + while (got < npools) { + char_ptr2 = strchr(storage_pools, '\n'); + + if (char_ptr2) { + *char_ptr2 = '\0'; + if ((pools[got++] = strdup(storage_pools)) == NULL) { + virReportOOMError(); + goto err; + } + char_ptr2++; + storage_pools = char_ptr2; + } else + break; + } + } + + VIR_FREE(cmd); + VIR_FREE(ret); + return got; + + err: + for (i = 0; i < got; i++) + VIR_FREE(pools[i]); + VIR_FREE(cmd); + VIR_FREE(ret); + return -1; +} + +static virStoragePoolPtr +phypGetStoragePoolLookUpByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + virStoragePoolPtr sp = NULL; + int npools = 0; + int gotpools = 0; + char **pools = NULL; + unsigned int i = 0; + unsigned char *local_uuid = NULL; + + if (VIR_ALLOC_N(local_uuid, VIR_UUID_BUFLEN) < 0) { + virReportOOMError(); + goto err; + } + + if ((npools = phypNumOfStoragePools(conn)) == -1) { + virReportOOMError(); + goto err; + } + + if (VIR_ALLOC_N(pools, npools) < 0) { + virReportOOMError(); + goto err; + } + + if ((gotpools = phypListStoragePools(conn, pools, npools)) == -1) { + virReportOOMError(); + goto err; + } + + if (gotpools != npools) { + virReportOOMError(); + goto err; + } + + for (i = 0; i < gotpools; i++) { + if (phypGetStoragePoolUUID(conn, local_uuid, pools[i]) == -1) + continue; + + if (!memcmp(local_uuid, uuid, VIR_UUID_BUFLEN)) { + sp = virGetStoragePool(conn, pools[i], uuid); + VIR_FREE(local_uuid); + VIR_FREE(pools); + + if (sp) + return sp; + else + goto err; + } + } + + err: + VIR_FREE(local_uuid); + VIR_FREE(pools); + return NULL; +} + +static virStoragePoolPtr +phypStoragePoolCreateXML(virConnectPtr conn, + const char *xml, unsigned int flags) +{ + virCheckFlags(0, NULL); + + virStoragePoolDefPtr def = NULL; + virStoragePoolPtr sp = NULL; + + if (!(def = virStoragePoolDefParseString(xml))) + goto err; + + /* checking if this name already exists on this system */ + if (phypStoragePoolLookupByName(conn, def->name) != NULL) { + VIR_WARN0("StoragePool name already exists."); + goto err; + } + + /* checking if ID or UUID already exists on this system */ + if (phypGetStoragePoolLookUpByUUID(conn, def->uuid) != NULL) { + VIR_WARN0("StoragePool uuid already exists."); + goto err; + } + + if ((sp = virGetStoragePool(conn, def->name, def->uuid)) == NULL) + goto err; + + if (phypBuildStoragePool(conn, def) == -1) + goto err; + + return sp; + + err: + virStoragePoolDefFree(def); + if (sp) + virUnrefStoragePool(sp); + return NULL; +} + +static char * +phypGetStoragePoolXMLDesc(virStoragePoolPtr pool, unsigned int flags) +{ + virCheckFlags(0, NULL); + + virStoragePoolDef def; + memset(&def, 0, sizeof(virStoragePoolDef)); + + if (pool->name != NULL) + def.name = pool->name; + else { + VIR_ERROR0(_("Unable to determine storage pool's name.")); + goto err; + } + + if (memmove(def.uuid, pool->uuid, VIR_UUID_BUFLEN) == NULL) { + VIR_ERROR0(_("Unable to determine storage pool's uuid.")); + goto err; + } + + if ((def.capacity = + phypGetStoragePoolSize(pool->conn, pool->name)) == -1) { + VIR_ERROR0(_("Unable to determine storage pools's size.")); + goto err; + } + + /* Information not avaliable */ + def.allocation = 0; + def.available = 0; + + def.source.ndevice = 1; + + /*XXX source adapter not working properly, should show hdiskX */ + if ((def.source.adapter = + phypGetStoragePoolDevice(pool->conn, pool->name)) == NULL) { + VIR_ERROR0(_("Unable to determine storage pools's source adapter.")); + goto err; + } + + return virStoragePoolDefFormat(&def); + + err: + return NULL; } static int @@ -2327,7 +3935,7 @@ static virDriver phypDriver = { NULL, /* domainCreateWithFlags */ NULL, /* domainDefineXML */ NULL, /* domainUndefine */ - NULL, /* domainAttachDevice */ + phypAttachDevice, /* domainAttachDevice */ NULL, /* domainAttachDeviceFlags */ NULL, /* domainDetachDevice */ NULL, /* domainDetachDeviceFlags */ @@ -2386,38 +3994,38 @@ static virStorageDriver phypStorageDriver = { .open = phypStorageOpen, .close = phypStorageClose, - .numOfPools = NULL, - .listPools = NULL, + .numOfPools = phypNumOfStoragePools, + .listPools = phypListStoragePools, .numOfDefinedPools = NULL, .listDefinedPools = NULL, .findPoolSources = NULL, - .poolLookupByName = NULL, - .poolLookupByUUID = NULL, + .poolLookupByName = phypStoragePoolLookupByName, + .poolLookupByUUID = phypGetStoragePoolLookUpByUUID, .poolLookupByVolume = NULL, - .poolCreateXML = NULL, + .poolCreateXML = phypStoragePoolCreateXML, .poolDefineXML = NULL, .poolBuild = NULL, .poolUndefine = NULL, .poolCreate = NULL, - .poolDestroy = NULL, + .poolDestroy = phypDestroyStoragePool, .poolDelete = NULL, .poolRefresh = NULL, .poolGetInfo = NULL, - .poolGetXMLDesc = NULL, + .poolGetXMLDesc = phypGetStoragePoolXMLDesc, .poolGetAutostart = NULL, .poolSetAutostart = NULL, - .poolNumOfVolumes = NULL, - .poolListVolumes = NULL, + .poolNumOfVolumes = phypStoragePoolNumOfVolumes, + .poolListVolumes = phypStoragePoolListVolumes, - .volLookupByName = NULL, + .volLookupByName = phypVolumeLookupByName, .volLookupByKey = NULL, - .volLookupByPath = NULL, - .volCreateXML = NULL, + .volLookupByPath = phypVolumeLookupByPath, + .volCreateXML = phypStorageVolCreateXML, .volCreateXMLFrom = NULL, .volDelete = NULL, .volGetInfo = NULL, - .volGetXMLDesc = NULL, - .volGetPath = NULL, + .volGetXMLDesc = phypVolumeGetXMLDesc, + .volGetPath = phypVolumeGetPath, .poolIsActive = NULL, .poolIsPersistent = NULL }; diff --git a/src/phyp/phyp_driver.h b/src/phyp/phyp_driver.h index a22156c..bc8e003 100644 --- a/src/phyp/phyp_driver.h +++ b/src/phyp/phyp_driver.h @@ -30,6 +30,7 @@ # include <config.h> # include <libssh2.h> +# define MAX_KEY_SIZE (1024*4) # define LPAR_EXEC_ERR -1 # define SSH_CONN_ERR -2 /* error while trying to connect to remote host */ # define SSH_CMD_ERR -3 /* error while trying to execute the remote cmd */ -- 1.7.0.1

On 06/24/2010 07:32 PM, Eric Blake wrote:
From: Eduardo Otubo<otubo@linux.vnet.ibm.com>
Add the storage management driver to the Power Hypervisor driver. This is a big but simple patch, it's just a new set of functions.
This patch includes: * Storage driver: The set of pool-* and vol-* functions. * attach-disk function. * Support for IVM on the new functions.
Signed-off-by: Eric Blake<eblake@redhat.com> ---
This is more or less Eduardo's v2 2/2 patch, but reorganized in topological order and converted to static functions, and with a lot of cleanups (such as from v2 1/2) squashed in.
I tested that it compiles, but I did _not_ test that it works for HVM - Eduardo, you'll need to give this a once-over.
I tested all the new functions and they are working properly on the HMC/VIOs and IVM. ACK. -- Eduardo Otubo Software Engineer Linux Technology Center IBM Systems & Technology Group Mobile: +55 19 8135 0885 eotubo@linux.vnet.ibm.com

On 06/25/2010 08:32 AM, Eric Blake wrote:
From: Eduardo Otubo<otubo@linux.vnet.ibm.com>
Add the storage management driver to the Power Hypervisor driver. This is a big but simple patch, it's just a new set of functions.
This patch includes: * Storage driver: The set of pool-* and vol-* functions. * attach-disk function. * Support for IVM on the new functions.
Signed-off-by: Eric Blake<eblake@redhat.com> <snip>
Hi guys, This commit is causing a segfault here. virConnectNumOfStoragePools() calls phypNumOfStoragePools(), which calls phypExec(). In this case with session equaling NULL. That's flowing through to libssh2_channel_open_ex(), which tries to access data in the (NULL) session structure and segfaults. Unsure if this mailing list accepts attachments. I'll try sending 4 screenshots, that illustrates the problem session variable at each point in the backtrace. (Note the "Target request failed: Cannot access memory at address 0x4700." in the bottom right of the attached screenshot0001.png file, when it attempts to access the session->open_state value.) Rolling git back 2 commits to this entry, and the above segfault doesn't occur: 8914453 phyp: reduce scope of driver functions Hope that helps. Regards and best wishes, Justin Clift -- Salasaga - Open Source eLearning IDE http://www.salasaga.org

On 06/25/2010 08:32 AM, Eric Blake wrote:
From: Eduardo Otubo<otubo@linux.vnet.ibm.com>
Add the storage management driver to the Power Hypervisor driver. This is a big but simple patch, it's just a new set of functions.
This patch includes: * Storage driver: The set of pool-* and vol-* functions. * attach-disk function. * Support for IVM on the new functions.
Signed-off-by: Eric Blake<eblake@redhat.com> <snip>
This commit is causing a segfault here when running "pool-list" in unmodified virsh. virConnectNumOfStoragePools() calls phypNumOfStoragePools(), which calls phypExec(). In this case with session equaling NULL. That's flowing through to libssh2_channel_open_ex(), which tries to access data in the (NULL) session structure and segfaults. Screenshots here, illustrating the problem session variable at each point in the backtrace: http://justinclift.fedorapeople.org/screenshots/screenshot0001.png http://justinclift.fedorapeople.org/screenshots/screenshot0002.png http://justinclift.fedorapeople.org/screenshots/screenshot0003.png http://justinclift.fedorapeople.org/screenshots/screenshot0004.png Note the "Target request failed: Cannot access memory at address 0x4700." in the bottom right of the screenshot0001.png file. That's when it attempts to access the session->open_state value, causing the segfault. Rolling back 2 commits to this entry, makes the above segfault go away: 8914453 phyp: reduce scope of driver functions Hope that helps. Regards and best wishes, Justin Clift -- Salasaga - Open Source eLearning IDE http://www.salasaga.org

On 06/27/2010 09:17 AM, Justin Clift wrote:
On 06/25/2010 08:32 AM, Eric Blake wrote:
From: Eduardo Otubo<otubo@linux.vnet.ibm.com>
Add the storage management driver to the Power Hypervisor driver. This is a big but simple patch, it's just a new set of functions.
This patch includes: * Storage driver: The set of pool-* and vol-* functions. * attach-disk function. * Support for IVM on the new functions.
Signed-off-by: Eric Blake<eblake@redhat.com> <snip>
This commit is causing a segfault here when running "pool-list" in unmodified virsh.
virConnectNumOfStoragePools() calls phypNumOfStoragePools(), which calls phypExec(). In this case with session equaling NULL.
virConnectNumOfStoragePools should not call successfully phypNumOfStoragePools unless the connection URI is for phyp. Does this patch clean up the mess? https://www.redhat.com/archives/libvir-list/2010-June/msg00707.html -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On 06/29/2010 03:50 AM, Eric Blake wrote: <snip>
virConnectNumOfStoragePools should not call successfully phypNumOfStoragePools unless the connection URI is for phyp. Does this patch clean up the mess? https://www.redhat.com/archives/libvir-list/2010-June/msg00707.html
Yep, just applied that and recompiled. No segfault in virsh now. I'll test your v2 version when you submit it as well, just let me know. :) Regards and best wishes, Justin Clift -- Salasaga - Open Source eLearning IDE http://www.salasaga.org

Minor speedups by using the full power of sed. * src/phyp/phyp_driver.c (phypGetVIOSFreeSCSIAdapter) (phypDiskType, phypListDefinedDomains): Use fewer processes, by folding other work into sed. (phypGetVIOSPartitionID): Likewise. Also avoid non-portable use of 'sed -s'. --- src/phyp/phyp_driver.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index df6d10c..3692f2c 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -227,8 +227,8 @@ phypGetVIOSPartitionID(virConnectPtr conn) virBufferAddLit(&buf, "lssyscfg"); if (system_type == HMC) virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env|grep " - "vioserver|sed -s 's/,.*$//'"); + virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env" + "|sed -n '/vioserver/ {\n s/,.*$//\n p\n}'"); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); @@ -1889,7 +1889,7 @@ phypGetVIOSFreeSCSIAdapter(virConnectPtr conn) if (system_type == HMC) virBufferAddChar(&buf, '\''); - virBufferVSprintf(&buf, "|grep -v ',[^.*]'|head -n 1|sed -e 's/,//g'"); + virBufferVSprintf(&buf, "|sed '/,[^.*]/d; s/,//g; q'"); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); @@ -3330,7 +3330,7 @@ phypDiskType(virConnectPtr conn, char *backing_device) if (system_type == HMC) virBufferVSprintf(&buf, " -m %s", managed_system); virBufferVSprintf(&buf, " -p %d -c \"lssp -field name type " - "-fmt , -all|grep %s|sed -e 's/^.*,//'\"", + "-fmt , -all|sed -n '/%s/ {\n s/^.*,//\n p\n}'\"", vios_id, backing_device); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); @@ -3398,8 +3398,8 @@ phypListDefinedDomains(virConnectPtr conn, char **const names, int nnames) virBufferAddLit(&buf, "lssyscfg -r lpar"); if (system_type == HMC) virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -F name,state | grep \"Not Activated\" | " - "sed -e 's/,.*$//'"); + virBufferVSprintf(&buf, " -F name,state" + "|sed -n '/Not Activated/ {\n s/,.*$//\n p\n}'"); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); -- 1.7.0.1

On 06/24/2010 07:32 PM, Eric Blake wrote:
Minor speedups by using the full power of sed.
* src/phyp/phyp_driver.c (phypGetVIOSFreeSCSIAdapter) (phypDiskType, phypListDefinedDomains): Use fewer processes, by folding other work into sed. (phypGetVIOSPartitionID): Likewise. Also avoid non-portable use of 'sed -s'. --- src/phyp/phyp_driver.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index df6d10c..3692f2c 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -227,8 +227,8 @@ phypGetVIOSPartitionID(virConnectPtr conn) virBufferAddLit(&buf, "lssyscfg"); if (system_type == HMC) virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env|grep " - "vioserver|sed -s 's/,.*$//'"); + virBufferAddLit(&buf, " -r lpar -F lpar_id,lpar_env" + "|sed -n '/vioserver/ {\n s/,.*$//\n p\n}'"); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); @@ -1889,7 +1889,7 @@ phypGetVIOSFreeSCSIAdapter(virConnectPtr conn) if (system_type == HMC) virBufferAddChar(&buf, '\'');
- virBufferVSprintf(&buf, "|grep -v ',[^.*]'|head -n 1|sed -e 's/,//g'"); + virBufferVSprintf(&buf, "|sed '/,[^.*]/d; s/,//g; q'");
if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); @@ -3330,7 +3330,7 @@ phypDiskType(virConnectPtr conn, char *backing_device) if (system_type == HMC) virBufferVSprintf(&buf, " -m %s", managed_system); virBufferVSprintf(&buf, " -p %d -c \"lssp -field name type " - "-fmt , -all|grep %s|sed -e 's/^.*,//'\"", + "-fmt , -all|sed -n '/%s/ {\n s/^.*,//\n p\n}'\"", vios_id, backing_device); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); @@ -3398,8 +3398,8 @@ phypListDefinedDomains(virConnectPtr conn, char **const names, int nnames) virBufferAddLit(&buf, "lssyscfg -r lpar"); if (system_type == HMC) virBufferVSprintf(&buf, " -m %s", managed_system); - virBufferVSprintf(&buf, " -F name,state | grep \"Not Activated\" | " - "sed -e 's/,.*$//'"); + virBufferVSprintf(&buf, " -F name,state" + "|sed -n '/Not Activated/ {\n s/,.*$//\n p\n}'"); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError();
I tested each sed expression on HMC shell, all of them are working fine. Eric, again, thank you very much for all the help to complete this driver. It's been a great lesson to discuss all these patches. I Hope I can improve the quality of them in the future. -- Eduardo Otubo Software Engineer Linux Technology Center IBM Systems & Technology Group Mobile: +55 19 8135 0885 eotubo@linux.vnet.ibm.com

On 06/25/2010 12:02 AM, Eduardo Otubo wrote:
I tested each sed expression on HMC shell, all of them are working fine.
Eric, again, thank you very much for all the help to complete this driver. It's been a great lesson to discuss all these patches. I Hope I can improve the quality of them in the future.
And thank you for persisting, and for reviewing my cleanup. Your series is now pushed. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (3)
-
Eduardo Otubo
-
Eric Blake
-
Justin Clift