提交 1dc5dea7 编写于 作者: M Michal Privoznik

qemu: Handle huge number of queues correctly

Currently, kernel supports up to 8 queues for a multiqueue tap device.
However, if user tries to enter a huge number (e.g. one million) the tap
allocation fails, as expected. But what is not expected is the log full
of warnings:

    warning : virFileClose:83 : Tried to close invalid fd 0

The problem is, upon error we iterate over an array of FDs (handlers to
queues) and VIR_FORCE_CLOSE() over each item. However, the array is
pre-filled with zeros. Hence, we repeatedly close stdin. Ouch.
But there's more. The queues allocation is done in virNetDevTapCreate()
which cleans up the FDs in case of error. Then, its caller, the
virNetDevTapCreateInBridgePort() iterates over the FD array and tries to
close them too. And so does qemuNetworkIfaceConnect() and
qemuBuildInterfaceCommandLine().
上级 41813766
...@@ -406,7 +406,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, ...@@ -406,7 +406,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
cleanup: cleanup:
if (ret < 0) { if (ret < 0) {
size_t i; size_t i;
for (i = 0; i < *tapfdSize; i++) for (i = 0; i < *tapfdSize && tapfd[i] >= 0; i++)
VIR_FORCE_CLOSE(tapfd[i]); VIR_FORCE_CLOSE(tapfd[i]);
if (template_ifname) if (template_ifname)
VIR_FREE(net->ifname); VIR_FREE(net->ifname);
...@@ -7338,6 +7338,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -7338,6 +7338,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
VIR_ALLOC_N(tapfdName, tapfdSize) < 0) VIR_ALLOC_N(tapfdName, tapfdSize) < 0)
goto cleanup; goto cleanup;
memset(tapfd, -1, tapfdSize * sizeof(tapfd[0]));
if (qemuNetworkIfaceConnect(def, conn, driver, net, if (qemuNetworkIfaceConnect(def, conn, driver, net,
qemuCaps, tapfd, &tapfdSize) < 0) qemuCaps, tapfd, &tapfdSize) < 0)
goto cleanup; goto cleanup;
...@@ -7365,6 +7367,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -7365,6 +7367,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
VIR_ALLOC_N(vhostfdName, vhostfdSize)) VIR_ALLOC_N(vhostfdName, vhostfdSize))
goto cleanup; goto cleanup;
memset(vhostfd, -1, vhostfdSize * sizeof(vhostfd[0]));
if (qemuOpenVhostNet(def, net, qemuCaps, vhostfd, &vhostfdSize) < 0) if (qemuOpenVhostNet(def, net, qemuCaps, vhostfd, &vhostfdSize) < 0)
goto cleanup; goto cleanup;
} }
...@@ -7424,13 +7428,13 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, ...@@ -7424,13 +7428,13 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
cleanup: cleanup:
if (ret < 0) if (ret < 0)
virDomainConfNWFilterTeardown(net); virDomainConfNWFilterTeardown(net);
for (i = 0; tapfd && i < tapfdSize; i++) { for (i = 0; tapfd && i < tapfdSize && tapfd[i] >= 0; i++) {
if (ret < 0) if (ret < 0)
VIR_FORCE_CLOSE(tapfd[i]); VIR_FORCE_CLOSE(tapfd[i]);
if (tapfdName) if (tapfdName)
VIR_FREE(tapfdName[i]); VIR_FREE(tapfdName[i]);
} }
for (i = 0; vhostfd && i < vhostfdSize; i++) { for (i = 0; vhostfd && i < vhostfdSize && vhostfd[i] >= 0; i++) {
if (ret < 0) if (ret < 0)
VIR_FORCE_CLOSE(vhostfd[i]); VIR_FORCE_CLOSE(vhostfd[i]);
if (vhostfdName) if (vhostfdName)
......
...@@ -445,6 +445,7 @@ int virNetDevTapCreateInBridgePort(const char *brname, ...@@ -445,6 +445,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
{ {
virMacAddr tapmac; virMacAddr tapmac;
char macaddrstr[VIR_MAC_STRING_BUFLEN]; char macaddrstr[VIR_MAC_STRING_BUFLEN];
size_t i;
if (virNetDevTapCreate(ifname, tapfd, tapfdSize, flags) < 0) if (virNetDevTapCreate(ifname, tapfd, tapfdSize, flags) < 0)
return -1; return -1;
...@@ -498,8 +499,8 @@ int virNetDevTapCreateInBridgePort(const char *brname, ...@@ -498,8 +499,8 @@ int virNetDevTapCreateInBridgePort(const char *brname,
return 0; return 0;
error: error:
while (tapfdSize) for (i = 0; i < tapfdSize && tapfd[i] >= 0; i++)
VIR_FORCE_CLOSE(tapfd[--tapfdSize]); VIR_FORCE_CLOSE(tapfd[i]);
return -1; return -1;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册