Roger Pau Monne
2012-Mar-21 01:53 UTC
[PATCH v3] libxl: Atomicaly check backend state and set it to 5 at device_remove
libxl__initiate_device_remove was setting backend state to 5, which
could create a race condition, since the previous check for state != 4
and setting state to 5 was not done inside the same transaction, so
the kernel could change the state to 6 in the space between the check
for state != 4 and setting it to 5.
The state != 4 check and setting it to 5 should happen in the same
transaction, to assure that nobody is modifying it behind our back.
Changes since v2:
* Updated to match current tree, plus Ian Jackson "libxl child
process handling" series.
* Moved xs_transaction_end to out_ok section.
Changes since v1:
* Do the check and set in the same transaction, instead of removing
the set state to 5.
Signed-off-by: Roger Pau Monne <roger.pau@entel.upc.edu>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
---
tools/libxl/libxl_device.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index c7e057d..d5cb722 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -381,23 +381,25 @@ int libxl__initiate_device_remove(libxl__egc *egc,
libxl__ao *ao,
{
AO_GC;
libxl_ctx *ctx = libxl__gc_owner(gc);
- xs_transaction_t t;
+ xs_transaction_t t = 0;
char *be_path = libxl__device_backend_path(gc, dev);
char *state_path = libxl__sprintf(gc, "%s/state", be_path);
- char *state = libxl__xs_read(gc, XBT_NULL, state_path);
+ char *state;
int rc = 0;
libxl__ao_device_remove *aorm = 0;
- if (!state)
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ state = libxl__xs_read(gc, t, state_path);
+ if (!state) {
goto out_ok;
+ }
if (atoi(state) != 4) {
libxl__device_destroy_tapdisk(gc, be_path);
xs_rm(ctx->xsh, XBT_NULL, be_path);
goto out_ok;
}
-retry_transaction:
- t = xs_transaction_start(ctx->xsh);
xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/online",
be_path), "0", strlen("0"));
xs_write(ctx->xsh, t, state_path, "5", strlen("5"));
if (!xs_transaction_end(ctx->xsh, t, 0)) {
@@ -408,6 +410,8 @@ retry_transaction:
goto out_fail;
}
}
+ /* mark transaction as ended, to prevent double closing it on out_ok */
+ t = 0;
libxl__device_destroy_tapdisk(gc, be_path);
@@ -428,6 +432,7 @@ retry_transaction:
return rc;
out_ok:
+ if (t) xs_transaction_end(ctx->xsh, t, 0);
libxl__ao_complete(egc, ao, 0);
return 0;
}
--
1.7.2.5
Ian Jackson
2012-Mar-22 12:26 UTC
Re: [PATCH v3] libxl: Atomicaly check backend state and set it to 5 at device_remove
Roger Pau Monne writes ("[PATCH v3] libxl: Atomicaly check backend state
and set it to 5 at device_remove"):> libxl__initiate_device_remove was setting backend state to 5, which
> could create a race condition, since the previous check for state != 4
> and setting state to 5 was not done inside the same transaction, so
> the kernel could change the state to 6 in the space between the check
> for state != 4 and setting it to 5.
>
> The state != 4 check and setting it to 5 should happen in the same
> transaction, to assure that nobody is modifying it behind our back.
>
> Changes since v2:
>
> * Updated to match current tree, plus Ian Jackson "libxl child
> process handling" series.
>
> * Moved xs_transaction_end to out_ok section.
>
> Changes since v1:
>
> * Do the check and set in the same transaction, instead of removing
> the set state to 5.
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Do you want me to push it onto the end of my series or will you
repost it after mine''s applied ?
Ian.