On Fri, Nov 22, 2013 at 15:41:28 +0100, Martin Kletzander wrote:
On Fri, Nov 22, 2013 at 10:24:17AM +0000, Daniel P. Berrange wrote:
> On Fri, Nov 22, 2013 at 06:01:44AM +0100, Martin Kletzander wrote:
> > There are few places where we know about port getting opened even
> > though it was not allocated on any virPortAllocator (or we know it was
> > reserved like this). We cannot notify the virPortAllocator that the
> > port is open because of that (since the port may be out of range) and
> > in that case, we are stuck with old data.
> >
> > This also fixes the issue that if you have autoport='no' and
> > port='-1', the port never gets returned (introduced by 7b4a630484);
> > the case when we don't know whether to release the port or not.
> >
> > There may be also other places where the port is being released even
> > though it might have been set statically out of range by the user. In
> > that case we report an error, but that shouldn't stop APIs releasing
> > ports (e.g. destroy). Moreover, the return value is not checked
> > sometimes and we're stuck with an error in the logs and also set as a
> > lastError.
> >
> > To make this behave the best I can imagine, we'd have to have a single
> > virPortAllocator with configurable ranges (ports shared between
> > allocators), but that's an idea for another day. In this patch, I'm
> > modifyping the virPortAllocatorRelease() function to be safe for all
> > kinds of parameters, making it a no-op in case of out-of-range ports
> > and warning in case virBitmapClearBit() returns an error (which is
> > just a sanity code in combination with the range check).
> >
> > Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
> > ---
> > src/libxl/libxl_driver.c | 13 ++++---------
> > src/qemu/qemu_process.c | 32 +++++++++++++++++++++-----------
> > src/util/virportallocator.c | 33 +++++++++------------------------
> > src/util/virportallocator.h | 4 ++--
> > tests/virportallocatortest.c | 5 +----
> > 5 files changed, 37 insertions(+), 50 deletions(-)
> >
> > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
> > index 1b42f14..26e2d3a 100644
> > --- a/src/libxl/libxl_driver.c
> > +++ b/src/libxl/libxl_driver.c
> > @@ -279,15 +279,10 @@ libxlVmCleanup(libxlDriverPrivatePtr driver,
> > if (virAtomicIntDecAndTest(&driver->nactive) &&
driver->inhibitCallback)
> > driver->inhibitCallback(false, driver->inhibitOpaque);
> >
> > - if ((vm->def->ngraphics == 1) &&
> > - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC
&&
> > - vm->def->graphics[0]->data.vnc.autoport) {
> > - vnc_port = vm->def->graphics[0]->data.vnc.port;
> > - if (vnc_port >= LIBXL_VNC_PORT_MIN) {
> > - if (virPortAllocatorRelease(driver->reservedVNCPorts,
> > - vnc_port) < 0)
> > - VIR_DEBUG("Could not mark port %d as unused",
vnc_port);
> > - }
> > + if (vm->def->ngraphics == 1 &&
> > + vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC)
{
> > + virPortAllocatorRelease(driver->reservedVNCPorts,
> > +
vm->def->graphics[0]->data.vnc.port);
> > }
>
> I don't think this change or the others that follow are safe.
>
> Consider we have guests, A & B.
>
> Start A which is using autoport and it gets given port 5900
> and this is recorded in the port allocator database.
>
> Now start B which has static port, also 5900, and this is
> *not* recorded in the port allocator database.
>
> Now B tries to start up and fails, due to clashing port, so now
> we run the cleanup code. Your change means we release port 5900,
> which is the port belonging to A, not B.
>
Oh, this is a case I haven't considered, right. So I think I'll need
to come up with the shared port allocator and it will have a hint to
who it currently using the code (in order to know whether to release
it or not).
However, we sometimes (during incoming migration) allocate a port in one
thread and release it in another thread... :-)
Jirka