|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2] tools/xenstore: Do not abort xenstore-ls if a node disappears while iterating
On Wed, 2019-08-07 at 16:37 +0100, Ian Jackson wrote:
> I think it is not safe to continue if we get a permissions error. I
> think that would mean "we were not able to determine whether this node
> exists", not "this node does not exist".
Either way, I interpreted it more as "haha screw you, now I'm not going
to tell you whether any *other* node exists".
This is the test case I actually started with:
(dom0) # for a in `seq 1 1000` ; do xenstore-write /local/domain/2/foo/$a $a ;
done
Now simultaneously:
(dom0) # for a in `seq 1 999` ; do xenstore-rm /local/domain/2/foo/$a ; done
(dom2) # while true ; do ./xenstore-ls -p /local/domain/2/foo | grep -c 1000;
done
I do expect to see node 1000, every time. With my patch, that works.
> So with a permissions error silently ignored, xenstore-ls might
> silently produce partial output.
Even without the race condition, we get partial output. In this test
case, observe that node four is absent from what dom2 reports, and we
get *two* error messages about node three.
(dom0) # xenstore-ls -p /local/domain/2/foo
one = "one" . . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
two = "two" . . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
three = "three" . . . . . . . . . . . . . . . . . . . . . . (n0)
four = "four" . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
(dom2) # xenstore-ls -p /local/domain/2/foo
one = "one" . . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
two = "two" . . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
three:
xenstore-ls:
could not access permissions for three: Permission denied
xenstore-ls: xs_directory (/local/domain/2/foo/three): Permission denied
The tool actually makes three calls for each node it touches. If the
xs_read() fails, it silently prints ":\n" and doesn't report the errno.
If the (optional) xs_get_permissions() fails, it *warns* but continues,
attempting to recurse into the node in question.
If the xs_directory() fails, it aborts and doesn't even continue.
My v2 patch makes the third case (xs_directory()) behave like the first
(xs_read()), and silently continue. It gives me:
(dom2) # ./xenstore-ls -p /local/domain/2/foo
one = "one" . . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
two = "two" . . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
three:
xenstore-ls:
could not access permissions for three: Permission denied
four = "four" . . . . . . . . . . . . . . . . . . . . . . . (n0,r2)
(dom2) # ./xenstore-ls /local/domain/2/foo
one = "one"
two = "two"
three:
four = "four"
> Given that the code doesn't have a way to print an error message and
> record the error code or exit status for later, I think the best
> approach is probably exactly David's patch only without the mention of
> EACCES.
Well... here's an incremental straw man patch based on the existing v2,
which will print an error for the *first* operation that fails, and
should cope with race conditions too.
Tested with
(dom0) # while true; do xenstore-chmod /local/domain/2/foo/three n0;
xenstore-chmod /local/domain/2/foo/three n0 r2 ; done
(dom2) # while true ; do echo ================= ; sudo ./xenstore-ls -p
/local/domain/2/foo; done
diff --git a/tools/xenstore/xenstore_client.c b/tools/xenstore/xenstore_client.c
index 9fcd3d2f9e..c5d0b18106 100644
--- a/tools/xenstore/xenstore_client.c
+++ b/tools/xenstore/xenstore_client.c
@@ -140,7 +140,7 @@ static int show_whole_path = 0;
#define MIN(a, b) (((a) < (b))? (a) : (b))
-static void do_ls(struct xs_handle *h, char *path, int cur_depth, int
show_perms)
+static void do_ls(struct xs_handle *h, char *path, int cur_depth, int
show_perms, int ignore_errors)
{
char **e;
char *newpath, *val;
@@ -151,7 +151,13 @@ static void do_ls(struct xs_handle *h, char *path, int
cur_depth, int show_perms
e = xs_directory(h, XBT_NULL, path, &num);
if (e == NULL) {
if (cur_depth && (errno == ENOENT || errno == EACCES)) {
- /* If a node disappears while recursing, silently move on. */
+ /*
+ * If a node disappears or becomes inaccessible while traversing,
+ * only print an error if previous operations on this node haven't
+ * done do. Then move on.
+ */
+ if (!ignore_errors)
+ warn("xs_directory (%s)", path);
return;
}
@@ -197,7 +203,7 @@ static void do_ls(struct xs_handle *h, char *path, int
cur_depth, int show_perms
/* Print value */
if (val == NULL) {
- printf(":\n");
+ printf(": (%s)", strerror(errno));
}
else {
if (max_width < (linewid + len + TAG_LEN)) {
@@ -222,7 +228,10 @@ static void do_ls(struct xs_handle *h, char *path, int
cur_depth, int show_perms
if (show_perms) {
perms = xs_get_permissions(h, XBT_NULL, newpath, &nperms);
if (perms == NULL) {
- warn("\ncould not access permissions for %s", e[i]);
+ /* Don't repeat an error message if xs_read() already failed */
+ if (val)
+ warn("could not access permissions for %s", e[i]);
+ val = NULL;
}
else {
int i;
@@ -239,7 +248,7 @@ static void do_ls(struct xs_handle *h, char *path, int
cur_depth, int show_perms
putchar('\n');
- do_ls(h, newpath, cur_depth+1, show_perms);
+ do_ls(h, newpath, cur_depth+1, show_perms, !val);
}
free(e);
free(newpath);
@@ -448,7 +457,7 @@ perform(enum mode mode, int optind, int argc, char **argv,
struct xs_handle *xsh
break;
}
case MODE_ls: {
- do_ls(xsh, argv[optind], 0, prefix);
+ do_ls(xsh, argv[optind], 0, prefix, 0);
optind++;
break;
}
Attachment:
smime.p7s _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |