ia64/xen-unstable

changeset 5478:dda0c275d413

bitkeeper revision 1.1713.3.5 (42b2a4e2r6SNlC_nq2hAkXEQjEFAmA)

Many files:
- watch now takes a token, returned when reading watch
- More tests
- Fix domain shared page communication (flush output)
- Add "home" path for domains
- More permissions checks in various functions
- Simplify watch acknowledgement code and fix occasional bug
xs_watch_stress.c, 12readonly.sh, 11domain-watch.sh, 10domain-homedir.sh:
new file
xs_stress.c, xs_lib.h, xs_lib.c:
Cleanup whitespace.
ignore:
Add tools/xenstore/xs_watch_stress
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Fri Jun 17 10:24:34 2005 +0000 (2005-06-17)
parents 632206427a75
children ebef9f2fb49f
files .rootkeys BitKeeper/etc/ignore tools/python/xen/lowlevel/xs/xs.c tools/xenstore/Makefile tools/xenstore/testsuite/07watch.sh tools/xenstore/testsuite/10domain-homedir.sh tools/xenstore/testsuite/11domain-watch.sh tools/xenstore/testsuite/12readonly.sh tools/xenstore/testsuite/test.sh tools/xenstore/xenstored_core.c tools/xenstore/xenstored_core.h tools/xenstore/xenstored_domain.c tools/xenstore/xenstored_domain.h tools/xenstore/xenstored_transaction.c tools/xenstore/xenstored_watch.c tools/xenstore/xenstored_watch.h tools/xenstore/xs.c tools/xenstore/xs.h tools/xenstore/xs_lib.c tools/xenstore/xs_lib.h tools/xenstore/xs_stress.c tools/xenstore/xs_test.c tools/xenstore/xs_watch_stress.c
line diff
     1.1 --- a/.rootkeys	Fri Jun 17 09:58:14 2005 +0000
     1.2 +++ b/.rootkeys	Fri Jun 17 10:24:34 2005 +0000
     1.3 @@ -1066,6 +1066,9 @@ 42a57d98YGCLyTDSGmoyFqRqQUlagQ tools/xen
     1.4  42a57d98fdO519YyATk4_Zwr1STNfQ tools/xenstore/testsuite/07watch.sh
     1.5  42a57d98zZUtvirUMjmHxFphJjmO7Q tools/xenstore/testsuite/08transaction.sh
     1.6  42a57d98sn9RbpBgHRv1D99Kt7LwYA tools/xenstore/testsuite/09domain.sh
     1.7 +42b2a4bfxAwHlRgd31SJBgFnj8g3MA tools/xenstore/testsuite/10domain-homedir.sh
     1.8 +42b2a4bfHbUp4IB8tfNIa8j37S27fw tools/xenstore/testsuite/11domain-watch.sh
     1.9 +42b2a4bfhrB5v6uYKPj6jSO_Ng0PAA tools/xenstore/testsuite/12readonly.sh
    1.10  42a57d98tSuoFCHnnM2GgENXJrRQmw tools/xenstore/testsuite/test.sh
    1.11  42a57d98zxDP2Ti7dTznGROi66rUGw tools/xenstore/utils.c
    1.12  42a57d98SDvOYCEjmCjwHSk6390GLA tools/xenstore/utils.h
    1.13 @@ -1087,6 +1090,7 @@ 42a57d99L2pYeMFyjQ_4Rnb17xTSMg tools/xen
    1.14  42a57d99Kl6Ba8oCHv2fggl7QN9QZA tools/xenstore/xs_random.c
    1.15  42a57d99SHYR1lQOD0shuErPDg9NKQ tools/xenstore/xs_stress.c
    1.16  42a57d996aBawpkQNOWkNWXD6LrhPg tools/xenstore/xs_test.c
    1.17 +42b2a4bfp-lhxBfenUyHlvw7bPcVgA tools/xenstore/xs_watch_stress.c
    1.18  403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
    1.19  40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
    1.20  420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c
     2.1 --- a/BitKeeper/etc/ignore	Fri Jun 17 09:58:14 2005 +0000
     2.2 +++ b/BitKeeper/etc/ignore	Fri Jun 17 10:24:34 2005 +0000
     2.3 @@ -148,6 +148,7 @@ tools/xenstore/xs_dom0_test
     2.4  tools/xenstore/xs_random
     2.5  tools/xenstore/xs_stress
     2.6  tools/xenstore/xs_test
     2.7 +tools/xenstore/xs_watch_stress
     2.8  tools/xentrace/xentrace
     2.9  tools/xfrd/xfrd
    2.10  xen/BLOG
     3.1 --- a/tools/python/xen/lowlevel/xs/xs.c	Fri Jun 17 09:58:14 2005 +0000
     3.2 +++ b/tools/python/xen/lowlevel/xs/xs.c	Fri Jun 17 10:24:34 2005 +0000
     3.3 @@ -277,10 +277,11 @@ static PyObject *xspy_set_permissions(Py
     3.4  
     3.5  static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
     3.6  {
     3.7 -    static char *kwd_spec[] = { "path", "priority", NULL };
     3.8 -    static char *arg_spec = "s|i";
     3.9 +    static char *kwd_spec[] = { "path", "priority", "token", NULL };
    3.10 +    static char *arg_spec = "s|is";
    3.11      char *path = NULL;
    3.12      int priority = 0;
    3.13 +    char *token;
    3.14  
    3.15      struct xs_handle *xh = xshandle(self);
    3.16      PyObject *val = NULL;
    3.17 @@ -289,9 +290,9 @@ static PyObject *xspy_watch(PyObject *se
    3.18      if (!xh)
    3.19  	goto exit;
    3.20      if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 
    3.21 -                                     &path, &priority))
    3.22 +                                     &path, &priority, &token))
    3.23          goto exit;
    3.24 -    xsval = xs_watch(xh, path, priority);
    3.25 +    xsval = xs_watch(xh, path, token, priority);
    3.26      val = pyvalue_int(xsval);
    3.27   exit:
    3.28      return val;
    3.29 @@ -305,14 +306,19 @@ static PyObject *xspy_read_watch(PyObjec
    3.30  
    3.31      struct xs_handle *xh = xshandle(self);
    3.32      PyObject *val = NULL;
    3.33 -    char *xsval = NULL;
    3.34 +    char **xsval = NULL;
    3.35  
    3.36      if (!xh)
    3.37  	goto exit;
    3.38      if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
    3.39          goto exit;
    3.40      xsval = xs_read_watch(xh);
    3.41 -    val = pyvalue_str(xsval);
    3.42 +    if(!xsval){
    3.43 +            val = PyErr_SetFromErrno(PyExc_RuntimeError);
    3.44 +            goto exit;
    3.45 +    }
    3.46 +    /* Create tuple (path, token). */
    3.47 +    val = Py_BuildValue("(ss)", xsval[0], xsval[1]);
    3.48   exit:
    3.49      if (xsval)
    3.50  	free(xsval);
    3.51 @@ -323,7 +329,8 @@ static PyObject *xspy_acknowledge_watch(
    3.52  					PyObject *kwds)
    3.53  {
    3.54      static char *kwd_spec[] = { NULL };
    3.55 -    static char *arg_spec = "";
    3.56 +    static char *arg_spec = "s";
    3.57 +    char *token = "";
    3.58  
    3.59      struct xs_handle *xh = xshandle(self);
    3.60      PyObject *val = NULL;
    3.61 @@ -331,9 +338,9 @@ static PyObject *xspy_acknowledge_watch(
    3.62  
    3.63      if (!xh)
    3.64  	goto exit;
    3.65 -    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
    3.66 +    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token))
    3.67          goto exit;
    3.68 -    xsval = xs_acknowledge_watch(xh);
    3.69 +    xsval = xs_acknowledge_watch(xh, token);
    3.70      val = pyvalue_int(xsval);
    3.71   exit:
    3.72      return val;
    3.73 @@ -341,9 +348,10 @@ static PyObject *xspy_acknowledge_watch(
    3.74  
    3.75  static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
    3.76  {
    3.77 -    static char *kwd_spec[] = { "path", NULL };
    3.78 -    static char *arg_spec = "s|";
    3.79 +    static char *kwd_spec[] = { "path", "token", NULL };
    3.80 +    static char *arg_spec = "s|s";
    3.81      char *path = NULL;
    3.82 +    char *token = "";
    3.83  
    3.84      struct xs_handle *xh = xshandle(self);
    3.85      PyObject *val = NULL;
    3.86 @@ -351,9 +359,10 @@ static PyObject *xspy_unwatch(PyObject *
    3.87  
    3.88      if (!xh)
    3.89  	goto exit;
    3.90 -    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
    3.91 +    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path,
    3.92 +				     &token))
    3.93          goto exit;
    3.94 -    xsval = xs_unwatch(xh, path);
    3.95 +    xsval = xs_unwatch(xh, path, token);
    3.96      val = pyvalue_int(xsval);
    3.97   exit:
    3.98      return val;
     4.1 --- a/tools/xenstore/Makefile	Fri Jun 17 09:58:14 2005 +0000
     4.2 +++ b/tools/xenstore/Makefile	Fri Jun 17 10:24:34 2005 +0000
     4.3 @@ -41,8 +41,9 @@ xenstored_test: xenstored_core_test.o xe
     4.4  xs_test: xs_test.o xs_lib.o utils.o
     4.5  xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o
     4.6  xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
     4.7 +xs_watch_stress: xs_watch_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
     4.8  
     4.9 -xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
    4.10 +xs_test.o xs_stress.o xs_watch_stress.o xenstored_core_test.o xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
    4.11  
    4.12  xenstored_%_test.o: xenstored_%.c
    4.13  	$(COMPILE.c) -o $@ $<
    4.14 @@ -63,8 +64,9 @@ libxenstore.a: $(LIB_OBJS_A)
    4.15  libxenstore-pic.a: $(LIB_OBJS_PIC)
    4.16  
    4.17  clean: testsuite-clean
    4.18 -	rm -f *.o *.opic *.a xen
    4.19 -	rm -f xs_test xenstored xenstored_test xs_random xs_stress xs_dom0_test
    4.20 +	rm -f *.o *.opic *.a
    4.21 +	rm -f xen xenstored xs_random xs_stress xs_watch_stress
    4.22 +	rm -f xs_test xenstored_test xs_dom0_test
    4.23  	-$(RM) $(PROG_DEP)
    4.24  
    4.25  check: testsuite-run randomcheck stresstest
    4.26 @@ -83,9 +85,11 @@ randomcheck: xs_random xenstored_test
    4.27  	$(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED)
    4.28  	$(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
    4.29  
    4.30 -stresstest: xs_stress xenstored_test
    4.31 +stresstest: xs_stress xs_watch_stress xenstored_test
    4.32  	rm -rf $(TESTDIR)/store
    4.33 -	export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 10000; ret=$$?; kill $$PID; exit $$ret
    4.34 +	export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret
    4.35 +	rm -rf $(TESTDIR)/store
    4.36 +	export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret
    4.37  
    4.38  xs_dom0_test: xs_dom0_test.o utils.o
    4.39  	$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@
     5.1 --- a/tools/xenstore/testsuite/07watch.sh	Fri Jun 17 09:58:14 2005 +0000
     5.2 +++ b/tools/xenstore/testsuite/07watch.sh	Fri Jun 17 10:24:34 2005 +0000
     5.3 @@ -3,30 +3,118 @@
     5.4  # Watch something, write to it, check watch has fired.
     5.5  [ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ]
     5.6  
     5.7 -[ "`echo -e '1 watch /test 100\n2 write /test create contents2\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/test" ]
     5.8 +[ "`echo -e '1 watch /test token 100
     5.9 +2 write /test create contents2
    5.10 +1 waitwatch
    5.11 +1 ackwatch token' | ./xs_test 2>&1`" = "1:/test:token" ]
    5.12  
    5.13  # Check that reads don't set it off.
    5.14 -[ "`echo -e '1 watch /test 100\n2 read /test\n1 waitwatch' | ./xs_test 2>&1`" = "2:contents2
    5.15 +[ "`echo -e '1 watch /test token 100
    5.16 +2 read /test
    5.17 +1 waitwatch' | ./xs_test 2>&1`" = "2:contents2
    5.18  1:waitwatch timeout" ]
    5.19  
    5.20 -# mkdir, setperm and rm should (also /tests watching dirs)
    5.21 +# mkdir, setperm and rm should (also tests watching dirs)
    5.22  [ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
    5.23 -[ "`echo -e '1 watch /dir 100\n2 mkdir /dir/newdir\n1 waitwatch\n1 ackwatch\n2 setperm /dir/newdir 0 READ\n1 waitwatch\n1 ackwatch\n2 rm /dir/newdir\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/newdir
    5.24 -1:/dir/newdir
    5.25 -1:/dir/newdir" ]
    5.26 +[ "`echo -e '1 watch /dir token 100
    5.27 +2 mkdir /dir/newdir
    5.28 +1 waitwatch
    5.29 +1 ackwatch token
    5.30 +2 setperm /dir/newdir 0 READ
    5.31 +1 waitwatch
    5.32 +1 ackwatch token
    5.33 +2 rm /dir/newdir
    5.34 +1 waitwatch
    5.35 +1 ackwatch token' | ./xs_test 2>&1`" = "1:/dir/newdir:token
    5.36 +1:/dir/newdir:token
    5.37 +1:/dir/newdir:token" ]
    5.38  
    5.39  # ignore watches while doing commands, should work.
    5.40 -[ "`echo -e 'watch /dir 100\nwrite /dir/test create contents\nread /dir/test\nwaitwatch\nackwatch' | ./xs_test 2>&1`" = "contents
    5.41 -/dir/test" ]
    5.42 +[ "`echo -e 'watch /dir token 100
    5.43 +write /dir/test create contents
    5.44 +read /dir/test
    5.45 +waitwatch
    5.46 +ackwatch token' | ./xs_test 2>&1`" = "contents
    5.47 +/dir/test:token" ]
    5.48  
    5.49  # watch priority /test.
    5.50 -[ "`echo -e '1 watch /dir 1\n3 watch /dir 3\n2 watch /dir 2\nwrite /dir/test create contents\n3 waitwatch\n3 ackwatch\n2 waitwatch\n2 ackwatch\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "3:/dir/test
    5.51 -2:/dir/test
    5.52 -1:/dir/test" ]
    5.53 +[ "`echo -e '1 watch /dir token1 1
    5.54 +3 watch /dir token3 3
    5.55 +2 watch /dir token2 2
    5.56 +write /dir/test create contents
    5.57 +3 waitwatch
    5.58 +3 ackwatch token3
    5.59 +2 waitwatch
    5.60 +2 ackwatch token2
    5.61 +1 waitwatch
    5.62 +1 ackwatch token1' | ./xs_test 2>&1`" = "3:/dir/test:token3
    5.63 +2:/dir/test:token2
    5.64 +1:/dir/test:token1" ]
    5.65  
    5.66  # If one dies (without acking), the other should still get ack.
    5.67 -[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 waitwatch\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "2:/dir/test
    5.68 -1:/dir/test" ]
    5.69 +[ "`echo -e '1 watch /dir token1 0
    5.70 +2 watch /dir token2 1
    5.71 +write /dir/test create contents
    5.72 +2 waitwatch
    5.73 +2 close
    5.74 +1 waitwatch
    5.75 +1 ackwatch token1' | ./xs_test 2>&1`" = "2:/dir/test:token2
    5.76 +1:/dir/test:token1" ]
    5.77  
    5.78  # If one dies (without reading at all), the other should still get ack.
    5.79 -[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/test" ]
    5.80 +[ "`echo -e '1 watch /dir token1 0
    5.81 +2 watch /dir token2 1
    5.82 +write /dir/test create contents
    5.83 +2 close
    5.84 +1 waitwatch
    5.85 +1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
    5.86 +
    5.87 +# unwatch
    5.88 +[ "`echo -e '1 watch /dir token1 0
    5.89 +1 unwatch /dir token1
    5.90 +1 watch /dir token2 0
    5.91 +2 write /dir/test2 create contents
    5.92 +1 waitwatch
    5.93 +1 unwatch /dir token2' | ./xs_test 2>&1`" = "1:/dir/test2:token2" ]
    5.94 +
    5.95 +# unwatch while watch pending.
    5.96 +[ "`echo -e '1 watch /dir token1 0
    5.97 +2 watch /dir token2 1
    5.98 +write /dir/test create contents
    5.99 +2 unwatch /dir token2
   5.100 +1 waitwatch
   5.101 +1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
   5.102 +
   5.103 +# check we only get notified once.
   5.104 +[ "`echo -e '1 watch /test token 100
   5.105 +2 write /test create contents2
   5.106 +1 waitwatch
   5.107 +1 ackwatch token
   5.108 +1 waitwatch' | ./xs_test 2>&1`" = "1:/test:token
   5.109 +1:waitwatch timeout" ]
   5.110 +
   5.111 +# watches are queued in order.
   5.112 +[ "`echo -e '1 watch / token 100
   5.113 +2 write /test1 create contents
   5.114 +2 write /test2 create contents
   5.115 +2 write /test3 create contents
   5.116 +1 waitwatch
   5.117 +1 ackwatch token
   5.118 +1 waitwatch
   5.119 +1 ackwatch token
   5.120 +1 waitwatch
   5.121 +1 ackwatch token' | ./xs_test 2>&1`" = "1:/test1:token
   5.122 +1:/test2:token
   5.123 +1:/test3:token" ]
   5.124 +
   5.125 +# Creation of subpaths should be covered correctly.
   5.126 +[ "`echo -e '1 watch / token 100
   5.127 +2 write /test/subnode create contents2
   5.128 +2 write /test/subnode/subnode create contents2
   5.129 +1 waitwatch
   5.130 +1 ackwatch token
   5.131 +1 waitwatch
   5.132 +1 ackwatch token
   5.133 +1 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
   5.134 +1:/test/subnode/subnode:token
   5.135 +1:waitwatch timeout" ]
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/xenstore/testsuite/10domain-homedir.sh	Fri Jun 17 10:24:34 2005 +0000
     6.3 @@ -0,0 +1,12 @@
     6.4 +#! /bin/sh
     6.5 +# Test domain "implicit" paths.
     6.6 +
     6.7 +# Create a domain, write an entry using implicit path, read using implicit
     6.8 +[ "`echo -e 'mkdir /home
     6.9 +introduce 1 100 7 /home
    6.10 +1 write entry1 create contents
    6.11 +read /home/entry1
    6.12 +dir /home' | ./xs_test 2>&1`" = "handle is 1
    6.13 +contents
    6.14 +entry1" ]
    6.15 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/xenstore/testsuite/11domain-watch.sh	Fri Jun 17 10:24:34 2005 +0000
     7.3 @@ -0,0 +1,51 @@
     7.4 +#! /bin/sh
     7.5 +# Test watching from a domain.
     7.6 +
     7.7 +# Watch something, write to it, check watch has fired.
     7.8 +[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ]
     7.9 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
    7.10 +
    7.11 +[ "`echo -e 'introduce 1 100 7 /my/home
    7.12 +1 watch /test token 100
    7.13 +write /test create contents2
    7.14 +1 waitwatch
    7.15 +1 ackwatch token
    7.16 +1 unwatch /test token
    7.17 +release 1' | ./xs_test 2>&1`" = "handle is 1
    7.18 +1:/test:token" ]
    7.19 +
    7.20 +# ignore watches while doing commands, should work.
    7.21 +[ "`echo -e 'introduce 1 100 7 /my/home
    7.22 +1 watch /dir token 100
    7.23 +1 write /dir/test create contents
    7.24 +1 read /dir/test
    7.25 +1 waitwatch
    7.26 +1 ackwatch token
    7.27 +release 1' | ./xs_test 2>&1`" = "handle is 1
    7.28 +1:contents
    7.29 +1:/dir/test:token" ]
    7.30 +
    7.31 +# unwatch
    7.32 +[ "`echo -e 'introduce 1 100 7 /my/home
    7.33 +1 watch /dir token1 0
    7.34 +1 unwatch /dir token1
    7.35 +1 watch /dir token2 0
    7.36 +2 write /dir/test2 create contents
    7.37 +1 waitwatch
    7.38 +1 unwatch /dir token2
    7.39 +release 1' | ./xs_test 2>&1`" = "handle is 1
    7.40 +1:/dir/test2:token2" ]
    7.41 +
    7.42 +# unwatch while watch pending.
    7.43 +[ "`echo -e 'introduce 1 100 7 /my/home
    7.44 +introduce 2 101 8 /my/secondhome
    7.45 +1 watch /dir token1 0
    7.46 +2 watch /dir token2 1
    7.47 +write /dir/test create contents
    7.48 +2 unwatch /dir token2
    7.49 +1 waitwatch
    7.50 +1 ackwatch token1
    7.51 +release 1
    7.52 +release 2' | ./xs_test 2>&1`" = "handle is 1
    7.53 +handle is 2
    7.54 +1:/dir/test:token1" ]
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/xenstore/testsuite/12readonly.sh	Fri Jun 17 10:24:34 2005 +0000
     8.3 @@ -0,0 +1,40 @@
     8.4 +#! /bin/sh
     8.5 +# Test that read only connection can't alter store.
     8.6 +
     8.7 +[ "`echo 'write /test create contents' | ./xs_test 2>&1`" = "" ]
     8.8 +
     8.9 +# These are all valid.
    8.10 +[ "`echo 'dir /
    8.11 +read /test
    8.12 +getperm /test
    8.13 +watch /test token 0
    8.14 +unwatch /test token 
    8.15 +start /
    8.16 +commit
    8.17 +start /
    8.18 +abort' | ./xs_test --readonly 2>&1`" = "test
    8.19 +contents
    8.20 +0 NONE" ]
    8.21 +
    8.22 +# These don't work
    8.23 +[ "`echo 'write /test2 create contents' | ./xs_test --readonly 2>&1`" = "FATAL: write: Read-only file system" ]
    8.24 +[ "`echo 'write /test create contents' | ./xs_test --readonly 2>&1`" = "FATAL: write: Read-only file system" ]
    8.25 +[ "`echo 'setperm /test 100 NONE' | ./xs_test --readonly 2>&1`" = "FATAL: setperm: Read-only file system" ]
    8.26 +[ "`echo 'setperm /test 100 NONE' | ./xs_test --readonly 2>&1`" = "FATAL: setperm: Read-only file system" ]
    8.27 +[ "`echo 'shutdown' | ./xs_test --readonly 2>&1`" = "FATAL: shutdown: Read-only file system" ]
    8.28 +[ "`echo 'introduce 1 100 7 /home' | ./xs_test --readonly 2>&1`" = "FATAL: introduce: Read-only file system" ]
    8.29 +
    8.30 +# Check that watches work like normal.
    8.31 +set -m
    8.32 +[ "`echo 'watch / token 0
    8.33 +waitwatch
    8.34 +ackwatch token' | ./xs_test --readonly 2>&1`" = "/test:token" ] &
    8.35 +
    8.36 +[ "`echo 'write /test create contents' | ./xs_test 2>&1`" = "" ]
    8.37 +if wait; then :; else
    8.38 +    echo Readonly wait test failed: $?
    8.39 +    exit 1
    8.40 +fi
    8.41 +    
    8.42 +    
    8.43 +
     9.1 --- a/tools/xenstore/testsuite/test.sh	Fri Jun 17 09:58:14 2005 +0000
     9.2 +++ b/tools/xenstore/testsuite/test.sh	Fri Jun 17 10:24:34 2005 +0000
     9.3 @@ -9,7 +9,7 @@ run_test()
     9.4      mkdir $XENSTORED_ROOTDIR
     9.5  # Weird failures with this.
     9.6      if type valgrind >/dev/null 2>&1; then
     9.7 -	valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid &
     9.8 +	valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid 2> testsuite/tmp/xenstored_errors &
     9.9  	while [ ! -s /tmp/pid ]; do sleep 0; done
    9.10  	PID=`cat /tmp/pid`
    9.11  	rm /tmp/pid
    10.1 --- a/tools/xenstore/xenstored_core.c	Fri Jun 17 09:58:14 2005 +0000
    10.2 +++ b/tools/xenstore/xenstored_core.c	Fri Jun 17 10:24:34 2005 +0000
    10.3 @@ -122,6 +122,33 @@ void __attribute__((noreturn)) corrupt(s
    10.4  	_exit(2);
    10.5  }
    10.6  
    10.7 +static char *sockmsg_string(enum xsd_sockmsg_type type)
    10.8 +{
    10.9 +	switch (type) {
   10.10 +	case XS_DEBUG: return "DEBUG";
   10.11 +	case XS_SHUTDOWN: return "SHUTDOWN";
   10.12 +	case XS_DIRECTORY: return "DIRECTORY";
   10.13 +	case XS_READ: return "READ";
   10.14 +	case XS_GET_PERMS: return "GET_PERMS";
   10.15 +	case XS_WATCH: return "WATCH";
   10.16 +	case XS_WATCH_ACK: return "WATCH_ACK";
   10.17 +	case XS_UNWATCH: return "UNWATCH";
   10.18 +	case XS_TRANSACTION_START: return "TRANSACTION_START";
   10.19 +	case XS_TRANSACTION_END: return "TRANSACTION_END";
   10.20 +	case XS_INTRODUCE: return "INTRODUCE";
   10.21 +	case XS_RELEASE: return "RELEASE";
   10.22 +	case XS_GETDOMAINPATH: return "GETDOMAINPATH";
   10.23 +	case XS_WRITE: return "WRITE";
   10.24 +	case XS_MKDIR: return "MKDIR";
   10.25 +	case XS_RM: return "RM";
   10.26 +	case XS_SET_PERMS: return "SET_PERMS";
   10.27 +	case XS_WATCH_EVENT: return "WATCH_EVENT";
   10.28 +	case XS_ERROR: return "ERROR";
   10.29 +	default:
   10.30 +		return "**UNKNOWN**";
   10.31 +	}
   10.32 +}
   10.33 +
   10.34  static bool write_message(struct connection *conn)
   10.35  {
   10.36  	int ret;
   10.37 @@ -129,8 +156,9 @@ static bool write_message(struct connect
   10.38  
   10.39  	if (out->inhdr) {
   10.40  		if (verbose)
   10.41 -			xprintf("Writing msg %i out to %p\n",
   10.42 -				out->hdr.msg.type, conn);
   10.43 +			xprintf("Writing msg %s (%s) out to %p\n",
   10.44 +				sockmsg_string(out->hdr.msg.type),
   10.45 +				out->buffer, conn);
   10.46  		ret = conn->write(conn, out->hdr.raw + out->used,
   10.47  				  sizeof(out->hdr) - out->used);
   10.48  		if (ret < 0)
   10.49 @@ -148,9 +176,6 @@ static bool write_message(struct connect
   10.50  			return true;
   10.51  	}
   10.52  
   10.53 -	if (verbose)
   10.54 -		xprintf("Writing data len %i out to %p\n",
   10.55 -			out->hdr.msg.len, conn);
   10.56  	ret = conn->write(conn, out->buffer + out->used,
   10.57  			  out->hdr.msg.len - out->used);
   10.58  
   10.59 @@ -162,10 +187,7 @@ static bool write_message(struct connect
   10.60  		return true;
   10.61  
   10.62  	conn->out = NULL;
   10.63 -
   10.64 -	/* If this was an event, we wait for ack, otherwise we're done. */
   10.65 -	if (!is_watch_event(conn, out))
   10.66 -		talloc_free(out);
   10.67 +	talloc_free(out);
   10.68  
   10.69  	queue_next_event(conn);
   10.70  	return true;
   10.71 @@ -402,7 +424,7 @@ static bool valid_chars(const char *node
   10.72  		       "0123456789-/_@") == strlen(node));
   10.73  }
   10.74  
   10.75 -static bool is_valid_nodename(const char *node)
   10.76 +bool is_valid_nodename(const char *node)
   10.77  {
   10.78  	/* Must start in /. */
   10.79  	if (!strstarts(node, "/"))
   10.80 @@ -601,17 +623,24 @@ static int check_with_parents(struct con
   10.81  	return errnum;
   10.82  }
   10.83  
   10.84 +char *canonicalize(struct connection *conn, const char *node)
   10.85 +{
   10.86 +	const char *prefix;
   10.87 +
   10.88 +	if (!node || strstarts(node, "/"))
   10.89 +		return (char *)node;
   10.90 +	prefix = get_implicit_path(conn);
   10.91 +	if (prefix)
   10.92 +		return talloc_asprintf(node, "%s/%s", prefix, node);
   10.93 +	return (char *)node;
   10.94 +}
   10.95 +
   10.96  bool check_node_perms(struct connection *conn, const char *node,
   10.97  		      enum xs_perm_type perm)
   10.98  {
   10.99  	struct xs_permissions *perms;
  10.100  	unsigned int num;
  10.101  
  10.102 -	if (!node) {
  10.103 -		errno = EINVAL;
  10.104 -		return false;
  10.105 -	}
  10.106 -
  10.107  	if (!node || !is_valid_nodename(node)) {
  10.108  		errno = EINVAL;
  10.109  		return false;
  10.110 @@ -651,6 +680,7 @@ static bool send_directory(struct connec
  10.111  	DIR *dir;
  10.112  	struct dirent *dirent;
  10.113  
  10.114 +	node = canonicalize(conn, node);
  10.115  	if (!check_node_perms(conn, node, XS_PERM_READ))
  10.116  		return send_error(conn, errno);
  10.117  
  10.118 @@ -680,6 +710,7 @@ static bool do_read(struct connection *c
  10.119  	unsigned int size;
  10.120  	int *fd;
  10.121  
  10.122 +	node = canonicalize(conn, node);
  10.123  	if (!check_node_perms(conn, node, XS_PERM_READ))
  10.124  		return send_error(conn, errno);
  10.125  
  10.126 @@ -750,7 +781,7 @@ static bool do_write(struct connection *
  10.127  	if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
  10.128  		return send_error(conn, EINVAL);
  10.129  
  10.130 -	node = vec[0];
  10.131 +	node = canonicalize(conn, vec[0]);
  10.132  	if (!within_transaction(conn->transaction, node))
  10.133  		return send_error(conn, EROFS);
  10.134  
  10.135 @@ -804,6 +835,7 @@ static bool do_write(struct connection *
  10.136  
  10.137  static bool do_mkdir(struct connection *conn, const char *node)
  10.138  {
  10.139 +	node = canonicalize(conn, node);
  10.140  	if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE))
  10.141  		return send_error(conn, errno);
  10.142  
  10.143 @@ -826,6 +858,7 @@ static bool do_rm(struct connection *con
  10.144  {
  10.145  	char *tmppath, *path;
  10.146  
  10.147 +	node = canonicalize(conn, node);
  10.148  	if (!check_node_perms(conn, node, XS_PERM_WRITE))
  10.149  		return send_error(conn, errno);
  10.150  
  10.151 @@ -848,6 +881,7 @@ static bool do_rm(struct connection *con
  10.152  
  10.153  	add_change_node(conn->transaction, node);
  10.154  	send_ack(conn, XS_RM);
  10.155 +	/* FIXME: traverse and fire watches for ALL of them! */
  10.156  	fire_watches(conn->transaction, node);
  10.157  	return false;
  10.158  }
  10.159 @@ -858,6 +892,7 @@ static bool do_get_perms(struct connecti
  10.160  	char *strings;
  10.161  	unsigned int len, num;
  10.162  
  10.163 +	node = canonicalize(conn, node);
  10.164  	if (!check_node_perms(conn, node, XS_PERM_READ))
  10.165  		return send_error(conn, errno);
  10.166  
  10.167 @@ -883,7 +918,7 @@ static bool do_set_perms(struct connecti
  10.168  		return send_error(conn, EINVAL);
  10.169  
  10.170  	/* First arg is node name. */
  10.171 -	node = in->buffer;
  10.172 +	node = canonicalize(conn, in->buffer);
  10.173  	in->buffer += strlen(in->buffer) + 1;
  10.174  	num--;
  10.175  
  10.176 @@ -968,10 +1003,10 @@ static bool process_message(struct conne
  10.177  		return do_watch(conn, in);
  10.178  
  10.179  	case XS_WATCH_ACK:
  10.180 -		return do_watch_ack(conn);
  10.181 +		return do_watch_ack(conn, onearg(in));
  10.182  
  10.183  	case XS_UNWATCH:
  10.184 -		return do_unwatch(conn, onearg(in));
  10.185 +		return do_unwatch(conn, in);
  10.186  
  10.187  	case XS_TRANSACTION_START:
  10.188  		return do_transaction_start(conn, onearg(in));
  10.189 @@ -1015,13 +1050,13 @@ static void consider_message(struct conn
  10.190  	}
  10.191  
  10.192  	if (verbose)
  10.193 -		xprintf("Got message %i len %i from %p\n",
  10.194 -			type, conn->in->hdr.msg.len, conn);
  10.195 +		xprintf("Got message %s len %i from %p\n",
  10.196 +			sockmsg_string(type), conn->in->hdr.msg.len, conn);
  10.197  
  10.198  	/* We might get a command while waiting for an ack: this means
  10.199  	 * the other end discarded it: we will re-transmit. */
  10.200  	if (type != XS_WATCH_ACK)
  10.201 -		reset_watch_event(conn);
  10.202 +		conn->waiting_for_ack = false;
  10.203  
  10.204  	/* Careful: process_message may free connection.  We detach
  10.205  	 * "in" beforehand and allocate the new buffer to avoid
  10.206 @@ -1136,7 +1171,6 @@ struct connection *new_connection(connwr
  10.207  
  10.208  	new->blocked = false;
  10.209  	new->out = new->waiting_reply = NULL;
  10.210 -	new->event = NULL;
  10.211  	new->fd = -1;
  10.212  	new->id = 0;
  10.213  	new->domain = NULL;
  10.214 @@ -1203,6 +1237,42 @@ static void time_relative_to_now(struct 
  10.215  	}
  10.216  }
  10.217  
  10.218 +#ifdef TESTING
  10.219 +/* Useful for running under debugger. */
  10.220 +void dump_connection(void)
  10.221 +{
  10.222 +	struct connection *i;
  10.223 +
  10.224 +	list_for_each_entry(i, &connections, list) {
  10.225 +		printf("Connection %p:\n", i);
  10.226 +		if (i->id)
  10.227 +			printf("    id = %i\n", i->id);
  10.228 +		if (i->blocked)
  10.229 +			printf("    blocked on = %s\n", i->blocked);
  10.230 +		if (i->waiting_for_ack)
  10.231 +			printf("    waiting_for_ack TRUE\n");
  10.232 +		if (!i->in->inhdr || i->in->used)
  10.233 +			printf("    got %i bytes of %s\n",
  10.234 +			       i->in->used, i->in->inhdr ? "header" : "data");
  10.235 +		if (i->out)
  10.236 +			printf("    sending message %s (%s) out\n",
  10.237 +			       sockmsg_string(i->out->hdr.msg.type),
  10.238 +			       i->out->buffer);
  10.239 +		if (i->waiting_reply)
  10.240 +			printf("    ... and behind is queued %s (%s)\n",
  10.241 +			       sockmsg_string(i->waiting_reply->hdr.msg.type),
  10.242 +			       i->waiting_reply->buffer);
  10.243 +#if 0
  10.244 +		if (i->transaction)
  10.245 +			dump_transaction(i);
  10.246 +		if (i->domain)
  10.247 +			dump_domain(i);
  10.248 +#endif
  10.249 +		dump_watches(i);
  10.250 +	}
  10.251 +}
  10.252 +#endif
  10.253 +
  10.254  static struct option options[] = { { "no-fork", 0, NULL, 'N' },
  10.255  				   { "verbose", 0, NULL, 'V' },
  10.256  				   { "output-pid", 0, NULL, 'P' },
  10.257 @@ -1314,6 +1384,7 @@ int main(int argc, char *argv[])
  10.258  
  10.259  		timerclear(&tv);
  10.260  		shortest_transaction_timeout(&tv);
  10.261 +		shortest_watch_ack_timeout(&tv);
  10.262  		if (timerisset(&tv)) {
  10.263  			time_relative_to_now(&tv);
  10.264  			tvp = &tv;
  10.265 @@ -1351,8 +1422,15 @@ int main(int argc, char *argv[])
  10.266  			}
  10.267  		}
  10.268  
  10.269 -		if (tvp)
  10.270 +		/* Flush output for domain connections,  */
  10.271 +		list_for_each_entry(i, &connections, list)
  10.272 +			if (i->domain && i->out)
  10.273 +				handle_output(i);
  10.274 +
  10.275 +		if (tvp) {
  10.276  			check_transaction_timeout();
  10.277 +			check_watch_ack_timeout();
  10.278 +		}
  10.279  
  10.280  		/* If transactions ended, we might be able to do more work. */
  10.281  		unblock_connections();
    11.1 --- a/tools/xenstore/xenstored_core.h	Fri Jun 17 09:58:14 2005 +0000
    11.2 +++ b/tools/xenstore/xenstored_core.h	Fri Jun 17 10:24:34 2005 +0000
    11.3 @@ -16,8 +16,10 @@
    11.4      along with this program; if not, write to the Free Software
    11.5      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    11.6  */
    11.7 -#ifndef _XENSTORED_INTERNAL_H
    11.8 -#define _XENSTORED_INTERNAL_H
    11.9 +
   11.10 +#ifndef _XENSTORED_CORE_H
   11.11 +#define _XENSTORED_CORE_H
   11.12 +
   11.13  #include <stdbool.h>
   11.14  #include <stdint.h>
   11.15  #include <errno.h>
   11.16 @@ -59,8 +61,8 @@ struct connection
   11.17  	/* Is this a read-only connection? */
   11.18  	bool can_write;
   11.19  
   11.20 -	/* Our current event.  If all used, we're waiting for ack. */
   11.21 -	struct watch_event *event;
   11.22 +	/* Are we waiting for a watch event ack? */
   11.23 +	bool waiting_for_ack;
   11.24  
   11.25  	/* Buffered incoming data. */
   11.26  	struct buffered_data *in;
   11.27 @@ -105,6 +107,9 @@ bool send_ack(struct connection *conn, e
   11.28  /* Send an error: error is usually "errno". */
   11.29  bool send_error(struct connection *conn, int error);
   11.30  
   11.31 +/* Canonicalize this path if possible. */
   11.32 +char *canonicalize(struct connection *conn, const char *node);
   11.33 +
   11.34  /* Check permissions on this node. */
   11.35  bool check_node_perms(struct connection *conn, const char *node,
   11.36  		      enum xs_perm_type perm);
   11.37 @@ -121,6 +126,10 @@ struct connection *new_connection(connwr
   11.38  void handle_input(struct connection *conn);
   11.39  void handle_output(struct connection *conn);
   11.40  
   11.41 +/* Is this a valid node name? */
   11.42 +bool is_valid_nodename(const char *node);
   11.43 +
   11.44  /* Convenient talloc-style destructor for paths. */
   11.45  int destroy_path(void *path);
   11.46 -#endif /* _XENSTORED_INTERNAL_H */
   11.47 +
   11.48 +#endif /* _XENSTORED_CORE_H */
    12.1 --- a/tools/xenstore/xenstored_domain.c	Fri Jun 17 09:58:14 2005 +0000
    12.2 +++ b/tools/xenstore/xenstored_domain.c	Fri Jun 17 10:24:34 2005 +0000
    12.3 @@ -65,11 +65,6 @@ struct domain
    12.4  
    12.5  static LIST_HEAD(domains);
    12.6  
    12.7 -void domain_set_conn(struct domain *domain, struct connection *conn)
    12.8 -{
    12.9 -	domain->conn = conn;
   12.10 -}
   12.11 -
   12.12  struct ringbuf_head
   12.13  {
   12.14  	u32 write; /* Next place to write to */
   12.15 @@ -268,6 +263,9 @@ bool do_introduce(struct connection *con
   12.16  	if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
   12.17  		return send_error(conn, EINVAL);
   12.18  
   12.19 +	if (conn->id != 0)
   12.20 +		return send_error(conn, EACCES);
   12.21 +
   12.22  	if (!conn->can_write)
   12.23  		return send_error(conn, EROFS);
   12.24  
   12.25 @@ -275,10 +273,9 @@ bool do_introduce(struct connection *con
   12.26  	domain = talloc(in, struct domain);
   12.27  	domain->domid = atoi(vec[0]);
   12.28  	domain->port = atoi(vec[2]);
   12.29 +	if (!domain->port || !domain->domid || !is_valid_nodename(vec[3]))
   12.30 +		return send_error(conn, EINVAL);
   12.31  	domain->path = talloc_strdup(domain, vec[3]);
   12.32 -	talloc_set_destructor(domain, destroy_domain);
   12.33 -	if (!domain->port || !domain->domid)
   12.34 -		return send_error(conn, EINVAL);
   12.35  	domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
   12.36  					    getpagesize(),
   12.37  					    PROT_READ|PROT_WRITE,
   12.38 @@ -286,6 +283,9 @@ bool do_introduce(struct connection *con
   12.39  	if (!domain->page)
   12.40  		return send_error(conn, errno);
   12.41  
   12.42 +	list_add(&domain->list, &domains);
   12.43 +	talloc_set_destructor(domain, destroy_domain);
   12.44 +
   12.45  	/* One in each half of page. */
   12.46  	domain->input = domain->page;
   12.47  	domain->output = domain->page + getpagesize()/2;
   12.48 @@ -298,7 +298,6 @@ bool do_introduce(struct connection *con
   12.49  	domain->conn->domain = domain;
   12.50  
   12.51  	talloc_steal(domain->conn, domain);
   12.52 -	list_add(&domain->list, &domains);
   12.53  
   12.54  	return send_ack(conn, XS_INTRODUCE);
   12.55  }
   12.56 @@ -327,6 +326,9 @@ bool do_release(struct connection *conn,
   12.57  	if (!domid)
   12.58  		return send_error(conn, EINVAL);
   12.59  
   12.60 +	if (conn->id != 0)
   12.61 +		return send_error(conn, EACCES);
   12.62 +
   12.63  	domain = find_domain_by_domid(domid);
   12.64  	if (!domain)
   12.65  		return send_error(conn, ENOENT);
   12.66 @@ -365,6 +367,14 @@ static int close_xc_handle(void *_handle
   12.67  	return 0;
   12.68  }
   12.69  
   12.70 +/* Returns the implicit path of a connection (only domains have this) */
   12.71 +const char *get_implicit_path(const struct connection *conn)
   12.72 +{
   12.73 +	if (!conn->domain)
   12.74 +		return NULL;
   12.75 +	return conn->domain->path;
   12.76 +}
   12.77 +
   12.78  /* Returns the event channel handle. */
   12.79  int domain_init(void)
   12.80  {
    13.1 --- a/tools/xenstore/xenstored_domain.h	Fri Jun 17 09:58:14 2005 +0000
    13.2 +++ b/tools/xenstore/xenstored_domain.h	Fri Jun 17 10:24:34 2005 +0000
    13.3 @@ -16,6 +16,7 @@
    13.4      along with this program; if not, write to the Free Software
    13.5      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    13.6  */
    13.7 +
    13.8  #ifndef _XENSTORED_DOMAIN_H
    13.9  #define _XENSTORED_DOMAIN_H
   13.10  
   13.11 @@ -33,6 +34,7 @@ bool do_get_domain_path(struct connectio
   13.12  /* Returns the event channel handle */
   13.13  int domain_init(void);
   13.14  
   13.15 -void domain_set_conn(struct domain *domain, struct connection *conn);
   13.16 +/* Returns the implicit path of a connection (only domains have this) */
   13.17 +const char *get_implicit_path(const struct connection *conn);
   13.18  
   13.19  #endif /* _XENSTORED_DOMAIN_H */
    14.1 --- a/tools/xenstore/xenstored_transaction.c	Fri Jun 17 09:58:14 2005 +0000
    14.2 +++ b/tools/xenstore/xenstored_transaction.c	Fri Jun 17 10:24:34 2005 +0000
    14.3 @@ -201,6 +201,7 @@ bool do_transaction_start(struct connect
    14.4  	if (conn->transaction)
    14.5  		return send_error(conn, EBUSY);
    14.6  
    14.7 +	node = canonicalize(conn, node);
    14.8  	if (!check_node_perms(conn, node, XS_PERM_READ))
    14.9  		return send_error(conn, errno);
   14.10  
    15.1 --- a/tools/xenstore/xenstored_watch.c	Fri Jun 17 09:58:14 2005 +0000
    15.2 +++ b/tools/xenstore/xenstored_watch.c	Fri Jun 17 10:24:34 2005 +0000
    15.3 @@ -21,6 +21,8 @@
    15.4  #include <sys/types.h>
    15.5  #include <stdarg.h>
    15.6  #include <stdlib.h>
    15.7 +#include <sys/time.h>
    15.8 +#include <time.h>
    15.9  #include "talloc.h"
   15.10  #include "list.h"
   15.11  #include "xenstored_watch.h"
   15.12 @@ -28,6 +30,8 @@
   15.13  #include "utils.h"
   15.14  #include "xenstored_test.h"
   15.15  
   15.16 +/* FIXME: time out unacked watches. */
   15.17 +
   15.18  /* We create this if anyone is interested "node", then we pass it from
   15.19   * watch to watch as each connection acks it.
   15.20   */
   15.21 @@ -39,7 +43,10 @@ struct watch_event
   15.22  	/* Watch we are currently attached to. */
   15.23  	struct watch *watch;
   15.24  
   15.25 -	struct buffered_data *data;
   15.26 +	struct timeval timeout;
   15.27 +
   15.28 +	/* Name of node which changed. */
   15.29 +	char *node;
   15.30  };
   15.31  
   15.32  struct watch
   15.33 @@ -50,72 +57,63 @@ struct watch
   15.34  	/* Current outstanding events applying to this watch. */
   15.35  	struct list_head events;
   15.36  
   15.37 +	char *token;
   15.38  	char *node;
   15.39  	struct connection *conn;
   15.40  };
   15.41  static LIST_HEAD(watches);
   15.42  
   15.43 -static void reset_event(struct watch_event *event)
   15.44 +static struct watch_event *get_first_event(struct connection *conn)
   15.45  {
   15.46 -	event->data->inhdr = true;
   15.47 -	event->data->used = 0;
   15.48 -}
   15.49 -
   15.50 -/* We received a non-ACK response: re-queue any watch we just sent. */
   15.51 -void reset_watch_event(struct connection *conn)
   15.52 -{
   15.53 -	if (waiting_for_ack(conn))
   15.54 -		reset_event(conn->event);
   15.55 -}
   15.56 +	struct watch *watch;
   15.57 +	struct watch_event *event;
   15.58  
   15.59 -/* We're waiting if we have an event and we sent it all. */
   15.60 -bool waiting_for_ack(struct connection *conn)
   15.61 -{
   15.62 -	if (!conn->event)
   15.63 -		return false;
   15.64 +	/* Find first watch with an event. */
   15.65 +	list_for_each_entry(watch, &watches, list) {
   15.66 +		if (watch->conn != conn)
   15.67 +			continue;
   15.68  
   15.69 -	if (conn->event->data->inhdr)
   15.70 -		return false;
   15.71 -	return conn->event->data->used == conn->event->data->hdr.msg.len;
   15.72 -}
   15.73 -
   15.74 -bool is_watch_event(struct connection *conn, struct buffered_data *out)
   15.75 -{
   15.76 -	return (conn->event && out == conn->event->data);
   15.77 +		event = list_top(&watch->events, struct watch_event, list);
   15.78 +		if (event)
   15.79 +			return event;
   15.80 +	}
   15.81 +	return NULL;
   15.82  }
   15.83  
   15.84  /* Look through our watches: if any of them have an event, queue it. */
   15.85  void queue_next_event(struct connection *conn)
   15.86  {
   15.87 -	struct watch *watch;
   15.88 +	struct watch_event *event;
   15.89 +	char *buffer;
   15.90 +	unsigned int len;
   15.91  
   15.92 -	/* We had a reply queued already?  Send it. */
   15.93 +	/* We had a reply queued already?  Send it: other end will
   15.94 +	 * discard watch. */
   15.95  	if (conn->waiting_reply) {
   15.96  		conn->out = conn->waiting_reply;
   15.97  		conn->waiting_reply = NULL;
   15.98 +		conn->waiting_for_ack = false;
   15.99  		return;
  15.100  	}
  15.101  
  15.102 -	/* If we're waiting for ack, don't queue more. */
  15.103 -	if (waiting_for_ack(conn))
  15.104 +	/* If we're already waiting for ack, don't queue more. */
  15.105 +	if (conn->waiting_for_ack)
  15.106 +		return;
  15.107 +
  15.108 +	event = get_first_event(conn);
  15.109 +	if (!event)
  15.110  		return;
  15.111  
  15.112 -	/* Find a good event to send. */
  15.113 -	if (!conn->event) {
  15.114 -		list_for_each_entry(watch, &watches, list) {
  15.115 -			if (watch->conn != conn)
  15.116 -				continue;
  15.117 +	/* If we decide to cancel, we will reset this. */
  15.118 +	conn->waiting_for_ack = true;
  15.119  
  15.120 -			conn->event = list_top(&watch->events,
  15.121 -					       struct watch_event, list);
  15.122 -			if (conn->event)
  15.123 -				break;
  15.124 -		}
  15.125 -		if (!conn->event)
  15.126 -			return;
  15.127 -	}
  15.128 -
  15.129 -	conn->out = conn->event->data;
  15.130 +	/* Create reply from path and token */
  15.131 +	len = strlen(event->node) + 1 + strlen(event->watch->token) + 1;
  15.132 +	buffer = talloc_array(conn, char, len);
  15.133 +	strcpy(buffer, event->node);
  15.134 +	strcpy(buffer+strlen(event->node)+1, event->watch->token);
  15.135 +	send_reply(conn, XS_WATCH_EVENT, buffer, len);
  15.136 +	talloc_free(buffer);
  15.137  }
  15.138  
  15.139  /* Watch on DIR applies to DIR, DIR/FILE, but not DIRLONG. */
  15.140 @@ -160,14 +158,15 @@ void fire_watches(struct transaction *tr
  15.141  
  15.142  	/* Create and fill in info about event. */
  15.143  	event = talloc(talloc_autofree_context(), struct watch_event);
  15.144 -	event->data = new_buffer(event);
  15.145 -	event->data->hdr.msg.type = XS_WATCH_EVENT;
  15.146 -	event->data->hdr.msg.len = strlen(node) + 1;
  15.147 -	event->data->buffer = talloc_strdup(event->data, node);
  15.148 +	event->node = talloc_strdup(event, node);
  15.149  
  15.150  	/* Tie event to this watch. */
  15.151  	event->watch = watch;
  15.152 -	list_add(&event->list, &watch->events);
  15.153 +	list_add_tail(&event->list, &watch->events);
  15.154 +
  15.155 +	/* Warn if not finished after thirty seconds. */
  15.156 +	gettimeofday(&event->timeout, NULL);
  15.157 +	event->timeout.tv_sec += 30;
  15.158  
  15.159  	/* If connection not doing anything, queue this. */
  15.160  	if (!watch->conn->out)
  15.161 @@ -178,16 +177,15 @@ void fire_watches(struct transaction *tr
  15.162  static void move_event_onwards(struct watch_event *event)
  15.163  {
  15.164  	list_del(&event->list);
  15.165 -	reset_event(event);
  15.166  
  15.167  	/* Remove from this watch, and find next watch to put this on. */
  15.168 -	event->watch = find_next_watch(event->watch, event->data->buffer);
  15.169 +	event->watch = find_next_watch(event->watch, event->node);
  15.170  	if (!event->watch) {
  15.171  		talloc_free(event);
  15.172  		return;
  15.173  	}
  15.174  
  15.175 -	list_add(&event->list, &event->watch->events);
  15.176 +	list_add_tail(&event->list, &event->watch->events);
  15.177  
  15.178  	/* If connection not doing anything, queue this. */
  15.179  	if (!event->watch->conn->out)
  15.180 @@ -199,10 +197,6 @@ static int destroy_watch(void *_watch)
  15.181  	struct watch *watch = _watch;
  15.182  	struct watch_event *event;
  15.183  
  15.184 -	/* Forget about sending out or waiting for acks for this watch.  */
  15.185 -	if (watch->conn->event && watch->conn->event->watch == watch)
  15.186 -		watch->conn->event = NULL;
  15.187 -
  15.188  	/* If we have pending events, pass them on to others. */
  15.189  	while ((event = list_top(&watch->events, struct watch_event, list)))
  15.190  		move_event_onwards(event);
  15.191 @@ -227,21 +221,59 @@ static void insert_watch(struct watch *w
  15.192  	list_add_tail(&watch->list, &watches);
  15.193  }
  15.194  
  15.195 +void shortest_watch_ack_timeout(struct timeval *tv)
  15.196 +{
  15.197 +	struct watch *watch;
  15.198 +
  15.199 +	list_for_each_entry(watch, &watches, list) {
  15.200 +		struct watch_event *i;
  15.201 +		list_for_each_entry(i, &watch->events, list) {
  15.202 +			if (!timerisset(&i->timeout))
  15.203 +				continue;
  15.204 +			if (!timerisset(tv) || timercmp(&i->timeout, tv, <))
  15.205 +				*tv = i->timeout;
  15.206 +		}
  15.207 +	}
  15.208 +}	
  15.209 +
  15.210 +void check_watch_ack_timeout(void)
  15.211 +{
  15.212 +	struct watch *watch;
  15.213 +	struct timeval now;
  15.214 +
  15.215 +	gettimeofday(&now, NULL);
  15.216 +	list_for_each_entry(watch, &watches, list) {
  15.217 +		struct watch_event *i, *tmp;
  15.218 +		list_for_each_entry_safe(i, tmp, &watch->events, list) {
  15.219 +			if (!timerisset(&i->timeout))
  15.220 +				continue;
  15.221 +			if (timercmp(&i->timeout, &now, <)) {
  15.222 +				xprintf("Warning: timeout on watch event %s"
  15.223 +					" token %s\n",
  15.224 +					i->node, watch->token);
  15.225 +				timerclear(&i->timeout);
  15.226 +			}
  15.227 +		}
  15.228 +	}
  15.229 +}
  15.230 +
  15.231  bool do_watch(struct connection *conn, struct buffered_data *in)
  15.232  {
  15.233  	struct watch *watch;
  15.234 -	char *vec[2];
  15.235 +	char *vec[3];
  15.236  
  15.237  	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
  15.238  		return send_error(conn, EINVAL);
  15.239  
  15.240 +	vec[0] = canonicalize(conn, vec[0]);
  15.241  	if (!check_node_perms(conn, vec[0], XS_PERM_READ))
  15.242  		return send_error(conn, errno);
  15.243  
  15.244  	watch = talloc(conn, struct watch);
  15.245  	watch->node = talloc_strdup(watch, vec[0]);
  15.246 +	watch->token = talloc_strdup(watch, vec[1]);
  15.247  	watch->conn = conn;
  15.248 -	watch->priority = strtoul(vec[1], NULL, 0);
  15.249 +	watch->priority = strtoul(vec[2], NULL, 0);
  15.250  	INIT_LIST_HEAD(&watch->events);
  15.251  
  15.252  	insert_watch(watch);
  15.253 @@ -249,31 +281,58 @@ bool do_watch(struct connection *conn, s
  15.254  	return send_ack(conn, XS_WATCH);
  15.255  }
  15.256  
  15.257 -bool do_watch_ack(struct connection *conn)
  15.258 +bool do_watch_ack(struct connection *conn, const char *token)
  15.259  {
  15.260  	struct watch_event *event;
  15.261  
  15.262 -	if (!waiting_for_ack(conn))
  15.263 +	if (!conn->waiting_for_ack)
  15.264  		return send_error(conn, ENOENT);
  15.265  
  15.266 -	/* Remove this watch event. */
  15.267 -	event = conn->event;
  15.268 -	conn->event = NULL;
  15.269 +	event = get_first_event(conn);
  15.270 +	if (!streq(event->watch->token, token))
  15.271 +		return send_error(conn, EINVAL);
  15.272  
  15.273  	move_event_onwards(event);
  15.274 +	conn->waiting_for_ack = false;
  15.275  	return send_ack(conn, XS_WATCH_ACK);
  15.276  }
  15.277  
  15.278 -bool do_unwatch(struct connection *conn, const char *node)
  15.279 +bool do_unwatch(struct connection *conn, struct buffered_data *in)
  15.280  {
  15.281  	struct watch *watch;
  15.282 +	char *node, *vec[2];
  15.283  
  15.284 +	if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
  15.285 +		return send_error(conn, EINVAL);
  15.286 +
  15.287 +	node = canonicalize(conn, vec[0]);
  15.288  	list_for_each_entry(watch, &watches, list) {
  15.289 -		if (watch->conn == conn
  15.290 -		    && streq(watch->node, node)) {
  15.291 +		if (watch->conn != conn)
  15.292 +			continue;
  15.293 +
  15.294 +		if (streq(watch->node, node) && streq(watch->token, vec[1])) {
  15.295  			talloc_free(watch);
  15.296  			return send_ack(conn, XS_UNWATCH);
  15.297  		}
  15.298  	}
  15.299  	return send_error(conn, ENOENT);
  15.300  }
  15.301 +
  15.302 +#ifdef TESTING
  15.303 +void dump_watches(struct connection *conn)
  15.304 +{
  15.305 +	struct watch *watch;
  15.306 +	struct watch_event *event;
  15.307 +
  15.308 +	/* Find first watch with an event. */
  15.309 +	list_for_each_entry(watch, &watches, list) {
  15.310 +		if (watch->conn != conn)
  15.311 +			continue;
  15.312 +
  15.313 +		printf("    watch on %s token %s prio %i\n",
  15.314 +		       watch->node, watch->token, watch->priority);
  15.315 +		list_for_each_entry(event, &watch->events, list)
  15.316 +			printf("        event: %s\n", event->node);
  15.317 +	}
  15.318 +}
  15.319 +#endif
    16.1 --- a/tools/xenstore/xenstored_watch.h	Fri Jun 17 09:58:14 2005 +0000
    16.2 +++ b/tools/xenstore/xenstored_watch.h	Fri Jun 17 10:24:34 2005 +0000
    16.3 @@ -16,13 +16,15 @@
    16.4      along with this program; if not, write to the Free Software
    16.5      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    16.6  */
    16.7 +
    16.8  #ifndef _XENSTORED_WATCH_H
    16.9  #define _XENSTORED_WATCH_H
   16.10 +
   16.11  #include "xenstored_core.h"
   16.12  
   16.13  bool do_watch(struct connection *conn, struct buffered_data *in);
   16.14 -bool do_watch_ack(struct connection *conn);
   16.15 -bool do_unwatch(struct connection *conn, const char *node);
   16.16 +bool do_watch_ack(struct connection *conn, const char *token);
   16.17 +bool do_unwatch(struct connection *conn, struct buffered_data *in);
   16.18  
   16.19  /* Is this a watch event message for this connection? */
   16.20  bool is_watch_event(struct connection *conn, struct buffered_data *out);
   16.21 @@ -30,13 +32,15 @@ bool is_watch_event(struct connection *c
   16.22  /* Look through our watches: if any of them have an event, queue it. */
   16.23  void queue_next_event(struct connection *conn);
   16.24  
   16.25 -/* Is this connection waiting for a watch acknowledgement? */
   16.26 -bool waiting_for_ack(struct connection *conn);
   16.27 -
   16.28 -/* Reset event if we were sending one */
   16.29 -void reset_watch_event(struct connection *conn);
   16.30 -
   16.31  /* Fire all watches. */
   16.32  void fire_watches(struct transaction *trans, const char *node);
   16.33  
   16.34 +/* Find shortest timeout: if any, reduce tv (may already be set). */
   16.35 +void shortest_watch_ack_timeout(struct timeval *tv);
   16.36 +
   16.37 +/* Check for watches which may have timed out. */
   16.38 +void check_watch_ack_timeout(void);
   16.39 +
   16.40 +void dump_watches(struct connection *conn);
   16.41 +
   16.42  #endif /* _XENSTORED_WATCH_H */
    17.1 --- a/tools/xenstore/xs.c	Fri Jun 17 09:58:14 2005 +0000
    17.2 +++ b/tools/xenstore/xs.c	Fri Jun 17 10:24:34 2005 +0000
    17.3 @@ -159,8 +159,7 @@ static void *read_reply(int fd, enum xsd
    17.4  
    17.5  /* Send message to xs, get malloc'ed reply.  NULL and set errno on error. */
    17.6  static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type,
    17.7 -		      const struct iovec *iovec,
    17.8 -		      unsigned int num_vecs,
    17.9 +		      const struct iovec *iovec, unsigned int num_vecs,
   17.10  		      unsigned int *len)
   17.11  {
   17.12  	struct xsd_sockmsg msg;
   17.13 @@ -330,8 +329,7 @@ bool xs_rm(struct xs_handle *h, const ch
   17.14   * Returns malloced array, or NULL: call free() after use.
   17.15   */
   17.16  struct xs_permissions *xs_get_permissions(struct xs_handle *h,
   17.17 -					  const char *path,
   17.18 -					  unsigned int *num)
   17.19 +					  const char *path, unsigned int *num)
   17.20  {
   17.21  	char *strings;
   17.22  	unsigned int len;
   17.23 @@ -400,61 +398,75 @@ unwind:
   17.24  
   17.25  /* Watch a node for changes (poll on fd to detect, or call read_watch()).
   17.26   * When the node (or any child) changes, fd will become readable.
   17.27 + * Token is returned when watch is read, to allow matching.
   17.28   * Priority indicates order if multiple watchers: higher is first.
   17.29   * Returns false on failure.
   17.30   */
   17.31 -bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority)
   17.32 +bool xs_watch(struct xs_handle *h, const char *path, const char *token,
   17.33 +	      unsigned int priority)
   17.34  {
   17.35  	char prio[MAX_STRLEN(priority)];
   17.36 -	struct iovec iov[2];
   17.37 +	struct iovec iov[3];
   17.38  
   17.39  	sprintf(prio, "%u", priority);
   17.40  	iov[0].iov_base = (void *)path;
   17.41  	iov[0].iov_len = strlen(path) + 1;
   17.42 -	iov[1].iov_base = prio;
   17.43 -	iov[1].iov_len = strlen(prio) + 1;
   17.44 +	iov[1].iov_base = (void *)token;
   17.45 +	iov[1].iov_len = strlen(token) + 1;
   17.46 +	iov[2].iov_base = prio;
   17.47 +	iov[2].iov_len = strlen(prio) + 1;
   17.48  
   17.49  	return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
   17.50  }
   17.51  
   17.52  /* Find out what node change was on (will block if nothing pending).
   17.53 - * Returns malloced path, or NULL: call free() after use.
   17.54 + * Returns array of two pointers: path and token, or NULL.
   17.55 + * Call free() after use.
   17.56   */
   17.57 -char *xs_read_watch(struct xs_handle *h)
   17.58 +char **xs_read_watch(struct xs_handle *h)
   17.59  {
   17.60  	struct xsd_sockmsg msg;
   17.61 -	char *path;
   17.62 +	char **ret;
   17.63  
   17.64  	if (!read_all(h->fd, &msg, sizeof(msg)))
   17.65  		return NULL;
   17.66  
   17.67  	assert(msg.type == XS_WATCH_EVENT);
   17.68 -	path = malloc(msg.len);
   17.69 -	if (!path)
   17.70 +	ret = malloc(sizeof(char *)*2 + msg.len);
   17.71 +	if (!ret)
   17.72  		return NULL;
   17.73  
   17.74 -	if (!read_all(h->fd, path, msg.len)) {
   17.75 -		free_no_errno(path);
   17.76 +	ret[0] = (char *)(ret + 2);
   17.77 +	if (!read_all(h->fd, ret[0], msg.len)) {
   17.78 +		free_no_errno(ret);
   17.79  		return NULL;
   17.80  	}
   17.81 -	return path;
   17.82 +	ret[1] = ret[0] + strlen(ret[0]) + 1;
   17.83 +	return ret;
   17.84  }
   17.85  
   17.86  /* Acknowledge watch on node.  Watches must be acknowledged before
   17.87   * any other watches can be read.
   17.88   * Returns false on failure.
   17.89   */
   17.90 -bool xs_acknowledge_watch(struct xs_handle *h)
   17.91 +bool xs_acknowledge_watch(struct xs_handle *h, const char *token)
   17.92  {
   17.93 -	return xs_bool(xs_single(h, XS_WATCH_ACK, "OK", NULL));
   17.94 +	return xs_bool(xs_single(h, XS_WATCH_ACK, token, NULL));
   17.95  }
   17.96  
   17.97  /* Remove a watch on a node.
   17.98   * Returns false on failure (no watch on that node).
   17.99   */
  17.100 -bool xs_unwatch(struct xs_handle *h, const char *path)
  17.101 +bool xs_unwatch(struct xs_handle *h, const char *path, const char *token)
  17.102  {
  17.103 -	return xs_bool(xs_single(h, XS_UNWATCH, path, NULL));
  17.104 +	struct iovec iov[2];
  17.105 +
  17.106 +	iov[0].iov_base = (char *)path;
  17.107 +	iov[0].iov_len = strlen(path) + 1;
  17.108 +	iov[1].iov_base = (char *)token;
  17.109 +	iov[1].iov_len = strlen(token) + 1;
  17.110 +
  17.111 +	return xs_bool(xs_talkv(h, XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
  17.112  }
  17.113  
  17.114  /* Start a transaction: changes by others will not be seen during this
  17.115 @@ -488,11 +500,8 @@ bool xs_transaction_end(struct xs_handle
  17.116   * This tells the store daemon about a shared memory page and event channel
  17.117   * associated with a domain: the domain uses these to communicate.
  17.118   */
  17.119 -bool xs_introduce_domain(struct xs_handle *h,
  17.120 -			 domid_t domid,
  17.121 -			 unsigned long mfn,
  17.122 -			 unsigned int eventchn,
  17.123 -			 const char *path)
  17.124 +bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn,
  17.125 +			 unsigned int eventchn, const char *path)
  17.126  {
  17.127  	char domid_str[MAX_STRLEN(domid)];
  17.128  	char mfn_str[MAX_STRLEN(mfn)];
  17.129 @@ -515,8 +524,7 @@ bool xs_introduce_domain(struct xs_handl
  17.130  	return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL));
  17.131  }
  17.132  
  17.133 -bool xs_release_domain(struct xs_handle *h,
  17.134 -		       domid_t domid)
  17.135 +bool xs_release_domain(struct xs_handle *h, domid_t domid)
  17.136  {
  17.137  	char domid_str[MAX_STRLEN(domid)];
  17.138  
    18.1 --- a/tools/xenstore/xs.h	Fri Jun 17 09:58:14 2005 +0000
    18.2 +++ b/tools/xenstore/xs.h	Fri Jun 17 10:24:34 2005 +0000
    18.3 @@ -1,5 +1,3 @@
    18.4 -#ifndef _XS_H
    18.5 -#define _XS_H
    18.6  /* 
    18.7      Xen Store Daemon providing simple tree-like database.
    18.8      Copyright (C) 2005 Rusty Russell IBM Corporation
    18.9 @@ -19,11 +17,15 @@
   18.10      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   18.11  */
   18.12  
   18.13 -/* On failure, these routines set errno. */
   18.14 +#ifndef _XS_H
   18.15 +#define _XS_H
   18.16 +
   18.17  #include "xs_lib.h"
   18.18  
   18.19  struct xs_handle;
   18.20  
   18.21 +/* On failure, these routines set errno. */
   18.22 +
   18.23  /* Connect to the xs daemon.
   18.24   * Returns a handle or NULL.
   18.25   */
   18.26 @@ -52,8 +54,8 @@ void *xs_read(struct xs_handle *h, const
   18.27  /* Write the value of a single file.
   18.28   * Returns false on failure.  createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
   18.29   */
   18.30 -bool xs_write(struct xs_handle *h, const char *path, const void *data, unsigned int len,
   18.31 -	      int createflags);
   18.32 +bool xs_write(struct xs_handle *h, const char *path, const void *data,
   18.33 +	      unsigned int len, int createflags);
   18.34  
   18.35  /* Create a new directory.
   18.36   * Returns false on failure.
   18.37 @@ -69,42 +71,42 @@ bool xs_rm(struct xs_handle *h, const ch
   18.38   * Returns malloced array, or NULL: call free() after use.
   18.39   */
   18.40  struct xs_permissions *xs_get_permissions(struct xs_handle *h,
   18.41 -					  const char *path,
   18.42 -					  unsigned int *num);
   18.43 +					  const char *path, unsigned int *num);
   18.44  
   18.45  /* Set permissions of node (must be owner).
   18.46   * Returns false on failure.
   18.47   */
   18.48 -bool xs_set_permissions(struct xs_handle *h,
   18.49 -			const char *path,
   18.50 -			struct xs_permissions *perms,
   18.51 -			unsigned int num_perms);
   18.52 +bool xs_set_permissions(struct xs_handle *h, const char *path,
   18.53 +			struct xs_permissions *perms, unsigned int num_perms);
   18.54  
   18.55  /* Watch a node for changes (poll on fd to detect, or call read_watch()).
   18.56   * When the node (or any child) changes, fd will become readable.
   18.57 + * Token is returned when watch is read, to allow matching.
   18.58   * Priority indicates order if multiple watchers: higher is first.
   18.59   * Returns false on failure.
   18.60   */
   18.61 -bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority);
   18.62 +bool xs_watch(struct xs_handle *h, const char *path, const char *token,
   18.63 +	      unsigned int priority);
   18.64  
   18.65  /* Return the FD to poll on to see if a watch has fired. */
   18.66  int xs_fileno(struct xs_handle *h);
   18.67  
   18.68  /* Find out what node change was on (will block if nothing pending).
   18.69 - * Returns malloced path, or NULL: call free() after use.
   18.70 + * Returns array of two pointers: path and token, or NULL.
   18.71 + * Call free() after use.
   18.72   */
   18.73 -char *xs_read_watch(struct xs_handle *h);
   18.74 +char **xs_read_watch(struct xs_handle *h);
   18.75  
   18.76  /* Acknowledge watch on node.  Watches must be acknowledged before
   18.77   * any other watches can be read.
   18.78   * Returns false on failure.
   18.79   */
   18.80 -bool xs_acknowledge_watch(struct xs_handle *h);
   18.81 +bool xs_acknowledge_watch(struct xs_handle *h, const char *token);
   18.82  
   18.83  /* Remove a watch on a node.
   18.84   * Returns false on failure (no watch on that node).
   18.85   */
   18.86 -bool xs_unwatch(struct xs_handle *h, const char *path);
   18.87 +bool xs_unwatch(struct xs_handle *h, const char *path, const char *token);
   18.88  
   18.89  /* Start a transaction: changes by others will not be seen during this
   18.90   * transaction, and changes will not be visible to others until end.
   18.91 @@ -125,11 +127,8 @@ bool xs_transaction_end(struct xs_handle
   18.92   * This tells the store daemon about a shared memory page, event channel
   18.93   * and store path associated with a domain: the domain uses these to communicate.
   18.94   */
   18.95 -bool xs_introduce_domain(struct xs_handle *h,
   18.96 -                         domid_t domid,
   18.97 -                         unsigned long mfn,
   18.98 -                         unsigned int eventchn,
   18.99 -                         const char *path);
  18.100 +bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn,
  18.101 +                         unsigned int eventchn, const char *path);
  18.102  
  18.103  /* Release a domain.
  18.104   * Tells the store domain to release the memory page to the domain.
    19.1 --- a/tools/xenstore/xs_lib.c	Fri Jun 17 09:58:14 2005 +0000
    19.2 +++ b/tools/xenstore/xs_lib.c	Fri Jun 17 10:24:34 2005 +0000
    19.3 @@ -67,7 +67,7 @@ bool xs_write_all(int fd, const void *da
    19.4  
    19.5  /* Convert strings to permissions.  False if a problem. */
    19.6  bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num,
    19.7 -		      const char *strings)
    19.8 +			 const char *strings)
    19.9  {
   19.10  	const char *p;
   19.11  	char *end;
   19.12 @@ -138,4 +138,3 @@ unsigned int xs_count_strings(const char
   19.13  
   19.14  	return num;
   19.15  }
   19.16 -	
    20.1 --- a/tools/xenstore/xs_lib.h	Fri Jun 17 09:58:14 2005 +0000
    20.2 +++ b/tools/xenstore/xs_lib.h	Fri Jun 17 10:24:34 2005 +0000
    20.3 @@ -1,5 +1,3 @@
    20.4 -#ifndef _XR_LIB_H
    20.5 -#define _XR_LIB_H
    20.6  /* 
    20.7      Common routines between Xen store user library and daemon.
    20.8      Copyright (C) 2005 Rusty Russell IBM Corporation
    20.9 @@ -18,6 +16,10 @@
   20.10      along with this program; if not, write to the Free Software
   20.11      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   20.12  */
   20.13 +
   20.14 +#ifndef _XS_LIB_H
   20.15 +#define _XS_LIB_H
   20.16 +
   20.17  #include <stdbool.h>
   20.18  #include <limits.h>
   20.19  #include <xc.h>
   20.20 @@ -52,7 +54,7 @@ bool xs_write_all(int fd, const void *da
   20.21  
   20.22  /* Convert strings to permissions.  False if a problem. */
   20.23  bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num,
   20.24 -		      const char *strings);
   20.25 +			 const char *strings);
   20.26  
   20.27  /* Convert permissions to a string (up to len MAX_STRLEN(domid_t)+1). */
   20.28  bool xs_perm_to_string(const struct xs_permissions *perm, char *buffer);
    21.1 --- a/tools/xenstore/xs_stress.c	Fri Jun 17 09:58:14 2005 +0000
    21.2 +++ b/tools/xenstore/xs_stress.c	Fri Jun 17 10:24:34 2005 +0000
    21.3 @@ -50,7 +50,7 @@ static void work(unsigned int cycles, un
    21.4  		}
    21.5  		if (streq(lockdir, ""))
    21.6  			strcpy(lockdir, "/");
    21.7 -		
    21.8 +
    21.9  		if (!xs_transaction_start(h, lockdir))
   21.10  			barf_perror("%i: starting transaction %i on %s",
   21.11  				    childnum, i, lockdir);
    22.1 --- a/tools/xenstore/xs_test.c	Fri Jun 17 09:58:14 2005 +0000
    22.2 +++ b/tools/xenstore/xs_test.c	Fri Jun 17 10:24:34 2005 +0000
    22.3 @@ -173,9 +173,9 @@ static void __attribute__((noreturn)) us
    22.4  	     "  getperm <path>\n"
    22.5  	     "  setperm <path> <id> <flags> ...\n"
    22.6  	     "  shutdown\n"
    22.7 -	     "  watch <path> <prio>\n"
    22.8 +	     "  watch <path> <token> <prio>\n"
    22.9  	     "  waitwatch\n"
   22.10 -	     "  ackwatch\n"
   22.11 +	     "  ackwatch <token>\n"
   22.12  	     "  unwatch <path> <token>\n"
   22.13  	     "  close\n"
   22.14  	     "  start <node>\n"
   22.15 @@ -358,36 +358,37 @@ static void do_shutdown(unsigned int han
   22.16  		failed(handle);
   22.17  }
   22.18  
   22.19 -static void do_watch(unsigned int handle, const char *node, const char *pri)
   22.20 +static void do_watch(unsigned int handle, const char *node, const char *token,
   22.21 +		     const char *pri)
   22.22  {
   22.23 -	if (!xs_watch(handles[handle], node, atoi(pri)))
   22.24 +	if (!xs_watch(handles[handle], node, token, atoi(pri)))
   22.25  		failed(handle);
   22.26  }
   22.27  
   22.28  static void do_waitwatch(unsigned int handle)
   22.29  {
   22.30 -	char *node;
   22.31 +	char **vec;
   22.32  
   22.33 -	node = xs_read_watch(handles[handle]);
   22.34 -	if (!node)
   22.35 +	vec = xs_read_watch(handles[handle]);
   22.36 +	if (!vec)
   22.37  		failed(handle);
   22.38  
   22.39  	if (handle)
   22.40 -		printf("%i:%s\n", handle, node);
   22.41 +		printf("%i:%s:%s\n", handle, vec[0], vec[1]);
   22.42  	else
   22.43 -		printf("%s\n", node);
   22.44 -	free(node);
   22.45 +		printf("%s:%s\n", vec[0], vec[1]);
   22.46 +	free(vec);
   22.47  }
   22.48  
   22.49 -static void do_ackwatch(unsigned int handle)
   22.50 +static void do_ackwatch(unsigned int handle, const char *token)
   22.51  {
   22.52 -	if (!xs_acknowledge_watch(handles[handle]))
   22.53 +	if (!xs_acknowledge_watch(handles[handle], token))
   22.54  		failed(handle);
   22.55  }
   22.56  
   22.57 -static void do_unwatch(unsigned int handle, const char *node)
   22.58 +static void do_unwatch(unsigned int handle, const char *node, const char *token)
   22.59  {
   22.60 -	if (!xs_unwatch(handles[handle], node))
   22.61 +	if (!xs_unwatch(handles[handle], node, token))
   22.62  		failed(handle);
   22.63  }
   22.64  
   22.65 @@ -613,13 +614,13 @@ int main(int argc, char *argv[])
   22.66  		else if (streq(command, "shutdown"))
   22.67  			do_shutdown(handle);
   22.68  		else if (streq(command, "watch"))
   22.69 -			do_watch(handle, arg(line, 1), arg(line, 2));
   22.70 +			do_watch(handle, arg(line, 1), arg(line, 2), arg(line, 3));
   22.71  		else if (streq(command, "waitwatch"))
   22.72  			do_waitwatch(handle);
   22.73  		else if (streq(command, "ackwatch"))
   22.74 -			do_ackwatch(handle);
   22.75 +			do_ackwatch(handle, arg(line, 1));
   22.76  		else if (streq(command, "unwatch"))
   22.77 -			do_unwatch(handle, arg(line, 1));
   22.78 +			do_unwatch(handle, arg(line, 1), arg(line, 2));
   22.79  		else if (streq(command, "close")) {
   22.80  			xs_daemon_close(handles[handle]);
   22.81  			handles[handle] = NULL;
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tools/xenstore/xs_watch_stress.c	Fri Jun 17 10:24:34 2005 +0000
    23.3 @@ -0,0 +1,120 @@
    23.4 +/* Stress test for watch code: two processes communicating by watches */
    23.5 +#include "xs.h"
    23.6 +#include "utils.h"
    23.7 +#include <stdlib.h>
    23.8 +#include <stdio.h>
    23.9 +#include <sys/types.h>
   23.10 +#include <sys/wait.h>
   23.11 +#include <sys/stat.h>
   23.12 +#include <fcntl.h>
   23.13 +#include <unistd.h>
   23.14 +
   23.15 +int main(int argc __attribute__((unused)), char *argv[])
   23.16 +{
   23.17 +	int childpid, status, fds[2];
   23.18 +	bool parent;
   23.19 +	unsigned int i, acks = 0;
   23.20 +	struct xs_handle *h;
   23.21 +	char *data;
   23.22 +	unsigned int len;
   23.23 +	const char *path, *otherpath;
   23.24 +
   23.25 +	pipe(fds);
   23.26 +	childpid = fork();
   23.27 +	if (childpid == -1)
   23.28 +		barf_perror("Failed fork");
   23.29 +	parent = (childpid != 0);
   23.30 +
   23.31 +	h = xs_daemon_open();
   23.32 +	if (!h)
   23.33 +		barf_perror("Could not connect to daemon");
   23.34 +
   23.35 +	if (!xs_watch(h, "/", "token", 0))
   23.36 +		barf_perror("Could not set watch");
   23.37 +
   23.38 +	if (parent) {
   23.39 +		char c;
   23.40 +
   23.41 +		if (read(fds[0], &c, 1) != 1)
   23.42 +			barf("Child exited");
   23.43 +
   23.44 +		path = "/parent";
   23.45 +		otherpath = "/child";
   23.46 +		/* Create initial node. */
   23.47 +		if (!xs_write(h, path, "0", 2, O_CREAT))
   23.48 +			barf_perror("Write to %s failed", path);
   23.49 +	} else {
   23.50 +		path = "/child";
   23.51 +		otherpath = "/parent";
   23.52 +
   23.53 +		if (write(fds[1], "", 1) != 1)
   23.54 +			barf_perror("Write to parent failed");
   23.55 +	}
   23.56 +
   23.57 +	for (i = 0; i < (argv[1] ? (unsigned)atoi(argv[1]) : 100);) {
   23.58 +		char **vec;
   23.59 +
   23.60 +		vec = xs_read_watch(h);
   23.61 +		if (!vec)
   23.62 +			barf_perror("Read watch failed");
   23.63 +
   23.64 +		if (!streq(vec[1], "token"))
   23.65 +			barf("Watch token %s bad", vec[1]);
   23.66 +		if (streq(vec[0], otherpath)) {
   23.67 +			char number[32];
   23.68 +
   23.69 +			data = xs_read(h, otherpath, &len);
   23.70 +			if (!data)
   23.71 +				barf_perror("reading %s", otherpath);
   23.72 +			sprintf(number, "%i", atoi(data) + 1);
   23.73 +			free(data);
   23.74 +			if (!xs_write(h, path, number, strlen(number) + 1,
   23.75 +				      O_CREAT))
   23.76 +				barf_perror("writing %s", path);
   23.77 +			i++;
   23.78 +		} else if (!streq(vec[0], path))
   23.79 +			barf_perror("Watch fired on unknown path %s", vec[0]);
   23.80 +		xs_acknowledge_watch(h, vec[1]);
   23.81 +		acks++;
   23.82 +		free(vec);
   23.83 +	}
   23.84 +
   23.85 +	if (!parent) {
   23.86 +		while (acks != 2 * i - 1) {
   23.87 +			char **vec;
   23.88 +			vec = xs_read_watch(h);
   23.89 +			if (!vec)
   23.90 +				barf_perror("Watch failed");
   23.91 +			if (!streq(vec[0], path))
   23.92 +				barf_perror("Watch fired path %s", vec[0]);
   23.93 +			if (!streq(vec[1], "token"))
   23.94 +				barf("Watch token %s bad", vec[1]);
   23.95 +			free(vec);
   23.96 +
   23.97 +			printf("Expect %i events, only got %i\n",
   23.98 +			       2 * i - 1, acks);
   23.99 +			acks++;
  23.100 +		}
  23.101 +		exit(0);
  23.102 +	}
  23.103 +
  23.104 +	if (acks != 2 * i)
  23.105 +		barf("Parent got %i watch events\n", acks);
  23.106 +
  23.107 +	printf("Waiting for %i\n", childpid);
  23.108 +	if (waitpid(childpid, &status, 0) != childpid)
  23.109 +		barf_perror("Child wait failed");
  23.110 +	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
  23.111 +		barf_perror("Child status %i", status);
  23.112 +
  23.113 +	data = xs_read(h, path, &len);
  23.114 +	if (atoi(data) != 2 * (int)i)
  23.115 +		barf("%s count is %s\n", path, data);
  23.116 +	free(data);
  23.117 +	data = xs_read(h, otherpath, &len);
  23.118 +	if (atoi(data) != 2 * (int)i - 1)
  23.119 +		barf("%s count is %s\n", otherpath, data);
  23.120 +	free(data);
  23.121 +	printf("Success!\n");
  23.122 +	exit(0);
  23.123 +}