mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
util: Introduce virStorageFileGetNPIVKey
The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
8bf89dc837
commit
5f9e211c93
@ -2863,6 +2863,7 @@ virStorageFileGetMetadata;
|
|||||||
virStorageFileGetMetadataFromBuf;
|
virStorageFileGetMetadataFromBuf;
|
||||||
virStorageFileGetMetadataFromFD;
|
virStorageFileGetMetadataFromFD;
|
||||||
virStorageFileGetMetadataInternal;
|
virStorageFileGetMetadataInternal;
|
||||||
|
virStorageFileGetNPIVKey;
|
||||||
virStorageFileGetRelativeBackingPath;
|
virStorageFileGetRelativeBackingPath;
|
||||||
virStorageFileGetSCSIKey;
|
virStorageFileGetSCSIKey;
|
||||||
virStorageFileGetUniqueIdentifier;
|
virStorageFileGetUniqueIdentifier;
|
||||||
|
@ -1492,6 +1492,85 @@ int virStorageFileGetSCSIKey(const char *path,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_UDEV
|
||||||
|
/* virStorageFileGetNPIVKey
|
||||||
|
* @path: Path to the NPIV device
|
||||||
|
* @key: Unique key to be returned
|
||||||
|
*
|
||||||
|
* Using a udev specific function, query the @path to get and return a
|
||||||
|
* unique @key for the caller to use. Unlike the GetSCSIKey method, an
|
||||||
|
* NPIV LUN is uniquely identified by its ID_TARGET_PORT value.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 On success, with the @key filled in or @key=NULL if the
|
||||||
|
* returned output string didn't have the data we need to
|
||||||
|
* formulate a unique key value
|
||||||
|
* -1 When WITH_UDEV is undefined and a system error is reported
|
||||||
|
* -2 When WITH_UDEV is defined, but calling virCommandRun fails
|
||||||
|
*/
|
||||||
|
# define ID_SERIAL "ID_SERIAL="
|
||||||
|
# define ID_TARGET_PORT "ID_TARGET_PORT="
|
||||||
|
int
|
||||||
|
virStorageFileGetNPIVKey(const char *path,
|
||||||
|
char **key)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
VIR_AUTOFREE(char *) outbuf = NULL;
|
||||||
|
const char *serial;
|
||||||
|
const char *port;
|
||||||
|
virCommandPtr cmd = virCommandNewArgList("/lib/udev/scsi_id",
|
||||||
|
"--replace-whitespace",
|
||||||
|
"--whitelisted",
|
||||||
|
"--export",
|
||||||
|
"--device", path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
int ret = -2;
|
||||||
|
|
||||||
|
*key = NULL;
|
||||||
|
|
||||||
|
/* Run the program and capture its output */
|
||||||
|
virCommandSetOutputBuffer(cmd, &outbuf);
|
||||||
|
if (virCommandRun(cmd, &status) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Explicitly check status == 0, rather than passing NULL
|
||||||
|
* to virCommandRun because we don't want to raise an actual
|
||||||
|
* error in this scenario, just return a NULL key.
|
||||||
|
*/
|
||||||
|
if (status == 0 && *outbuf &&
|
||||||
|
(serial = strstr(outbuf, ID_SERIAL)) &&
|
||||||
|
(port = strstr(outbuf, ID_TARGET_PORT))) {
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
serial += strlen(ID_SERIAL);
|
||||||
|
port += strlen(ID_TARGET_PORT);
|
||||||
|
|
||||||
|
if ((tmp = strchr(serial, '\n')))
|
||||||
|
*tmp = '\0';
|
||||||
|
|
||||||
|
if ((tmp = strchr(port, '\n')))
|
||||||
|
*tmp = '\0';
|
||||||
|
|
||||||
|
if (*serial != '\0' && *port != '\0')
|
||||||
|
ignore_value(virAsprintf(key, "%s_PORT%s", serial, port));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virCommandFree(cmd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int virStorageFileGetNPIVKey(const char *path,
|
||||||
|
char **key ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virStorageFileParseBackingStoreStr:
|
* virStorageFileParseBackingStoreStr:
|
||||||
* @str: backing store specifier string to parse
|
* @str: backing store specifier string to parse
|
||||||
|
@ -392,6 +392,8 @@ int virStorageFileGetLVMKey(const char *path,
|
|||||||
int virStorageFileGetSCSIKey(const char *path,
|
int virStorageFileGetSCSIKey(const char *path,
|
||||||
char **key,
|
char **key,
|
||||||
bool ignoreError);
|
bool ignoreError);
|
||||||
|
int virStorageFileGetNPIVKey(const char *path,
|
||||||
|
char **key);
|
||||||
|
|
||||||
void virStorageAuthDefFree(virStorageAuthDefPtr def);
|
void virStorageAuthDefFree(virStorageAuthDefPtr def);
|
||||||
virStorageAuthDefPtr virStorageAuthDefCopy(const virStorageAuthDef *src);
|
virStorageAuthDefPtr virStorageAuthDefCopy(const virStorageAuthDef *src);
|
||||||
|
Loading…
Reference in New Issue
Block a user