source: trunk/packages/xen-3.1/xen-3.1/extras/mini-os/xenbus/xenbus.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 16.4 KB
Line 
1/*
2 ****************************************************************************
3 * (C) 2006 - Cambridge University
4 ****************************************************************************
5 *
6 *        File: xenbus.c
7 *      Author: Steven Smith (sos22@cam.ac.uk)
8 *     Changes: Grzegorz Milos (gm281@cam.ac.uk)
9 *     Changes: John D. Ramsdell
10 *             
11 *        Date: Jun 2006, chages Aug 2005
12 *
13 * Environment: Xen Minimal OS
14 * Description: Minimal implementation of xenbus
15 *
16 ****************************************************************************
17 **/
18#include <os.h>
19#include <mm.h>
20#include <traps.h>
21#include <lib.h>
22#include <xenbus.h>
23#include <events.h>
24#include <errno.h>
25#include <sched.h>
26#include <wait.h>
27#include <xen/io/xs_wire.h>
28#include <spinlock.h>
29#include <xmalloc.h>
30
31#define BUG_ON(x) do { \
32    if (x) {printk("BUG at %s:%d\n", __FILE__, __LINE__); BUG(); } \
33} while (0)
34
35#define min(x,y) ({                       \
36        typeof(x) tmpx = (x);                 \
37        typeof(y) tmpy = (y);                 \
38        tmpx < tmpy ? tmpx : tmpy;            \
39        })
40
41#ifdef XENBUS_DEBUG
42#define DEBUG(_f, _a...) \
43    printk("MINI_OS(file=xenbus.c, line=%d) " _f , __LINE__, ## _a)
44#else
45#define DEBUG(_f, _a...)    ((void)0)
46#endif
47
48static struct xenstore_domain_interface *xenstore_buf;
49static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
50static DECLARE_WAIT_QUEUE_HEAD(watch_queue);
51struct xenbus_req_info
52{
53    int in_use:1;
54    struct wait_queue_head waitq;
55    void *reply;
56};
57
58#define NR_REQS 32
59static struct xenbus_req_info req_info[NR_REQS];
60
61static void memcpy_from_ring(const void *Ring,
62        void *Dest,
63        int off,
64        int len)
65{
66    int c1, c2;
67    const char *ring = Ring;
68    char *dest = Dest;
69    c1 = min(len, XENSTORE_RING_SIZE - off);
70    c2 = len - c1;
71    memcpy(dest, ring + off, c1);
72    memcpy(dest + c1, ring, c2);
73}
74
75void wait_for_watch(void)
76{
77    DEFINE_WAIT(w);
78    add_waiter(w,watch_queue);
79    schedule();
80    remove_waiter(w);
81    wake(current);
82}
83
84char* xenbus_wait_for_value(const char* path,const char* value)
85{
86    for(;;)
87    {
88        char *res, *msg;
89        int r;
90
91        msg = xenbus_read(XBT_NIL, path, &res);
92        if(msg) return msg;
93
94        r = strcmp(value,res);
95        free(res);
96
97        if(r==0) break;
98        else wait_for_watch();
99    }
100    return NULL;
101}
102
103
104static void xenbus_thread_func(void *ign)
105{
106    struct xsd_sockmsg msg;
107    unsigned prod = 0;
108
109    for (;;) 
110    {
111        wait_event(xb_waitq, prod != xenstore_buf->rsp_prod);
112        while (1) 
113        {
114            prod = xenstore_buf->rsp_prod;
115            DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
116                    xenstore_buf->rsp_prod);
117            if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
118                break;
119            rmb();
120            memcpy_from_ring(xenstore_buf->rsp,
121                    &msg,
122                    MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
123                    sizeof(msg));
124            DEBUG("Msg len %d, %d avail, id %d.\n",
125                    msg.len + sizeof(msg),
126                    xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
127                    msg.req_id);
128            if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
129                    sizeof(msg) + msg.len)
130                break;
131
132            DEBUG("Message is good.\n");
133
134            if(msg.type == XS_WATCH_EVENT)
135            {
136                char* payload = (char*)malloc(sizeof(msg) + msg.len);
137                char *path,*token;
138
139                memcpy_from_ring(xenstore_buf->rsp,
140                    payload,
141                    MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
142                    msg.len + sizeof(msg));
143
144                path = payload + sizeof(msg);
145                token = path + strlen(path) + 1;
146
147                xenstore_buf->rsp_cons += msg.len + sizeof(msg);
148                free(payload);
149                wake_up(&watch_queue);
150            }
151
152            else
153            {
154                req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len);
155                memcpy_from_ring(xenstore_buf->rsp,
156                    req_info[msg.req_id].reply,
157                    MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
158                    msg.len + sizeof(msg));
159                xenstore_buf->rsp_cons += msg.len + sizeof(msg);
160                wake_up(&req_info[msg.req_id].waitq);
161            }
162        }
163    }
164}
165
166static void xenbus_evtchn_handler(evtchn_port_t port, struct pt_regs *regs,
167                                  void *ign)
168{
169    wake_up(&xb_waitq);
170}
171
172static int nr_live_reqs;
173static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
174static DECLARE_WAIT_QUEUE_HEAD(req_wq);
175
176/* Release a xenbus identifier */
177static void release_xenbus_id(int id)
178{
179    BUG_ON(!req_info[id].in_use);
180    spin_lock(&req_lock);
181    req_info[id].in_use = 0;
182    nr_live_reqs--;
183    req_info[id].in_use = 0;
184    if (nr_live_reqs == NR_REQS - 1)
185        wake_up(&req_wq);
186    spin_unlock(&req_lock);
187}
188
189/* Allocate an identifier for a xenbus request.  Blocks if none are
190   available. */
191static int allocate_xenbus_id(void)
192{
193    static int probe;
194    int o_probe;
195
196    while (1) 
197    {
198        spin_lock(&req_lock);
199        if (nr_live_reqs < NR_REQS)
200            break;
201        spin_unlock(&req_lock);
202        wait_event(req_wq, (nr_live_reqs < NR_REQS));
203    }
204
205    o_probe = probe;
206    for (;;) 
207    {
208        if (!req_info[o_probe].in_use)
209            break;
210        o_probe = (o_probe + 1) % NR_REQS;
211        BUG_ON(o_probe == probe);
212    }
213    nr_live_reqs++;
214    req_info[o_probe].in_use = 1;
215    probe = (o_probe + 1) % NR_REQS;
216    spin_unlock(&req_lock);
217    init_waitqueue_head(&req_info[o_probe].waitq);
218
219    return o_probe;
220}
221
222/* Initialise xenbus. */
223void init_xenbus(void)
224{
225    int err;
226    printk("Initialising xenbus\n");
227    DEBUG("init_xenbus called.\n");
228    xenstore_buf = mfn_to_virt(start_info.store_mfn);
229    create_thread("xenstore", xenbus_thread_func, NULL);
230    DEBUG("buf at %p.\n", xenstore_buf);
231    err = bind_evtchn(start_info.store_evtchn,
232                      xenbus_evtchn_handler,
233              NULL);
234    DEBUG("xenbus on irq %d\n", err);
235}
236
237struct write_req {
238    const void *data;
239    unsigned len;
240};
241
242/* Send data to xenbus.  This can block.  All of the requests are seen
243   by xenbus as if sent atomically.  The header is added
244   automatically, using type %type, req_id %req_id, and trans_id
245   %trans_id. */
246static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
247                     const struct write_req *req, int nr_reqs)
248{
249    XENSTORE_RING_IDX prod;
250    int r;
251    int len = 0;
252    const struct write_req *cur_req;
253    int req_off;
254    int total_off;
255    int this_chunk;
256    struct xsd_sockmsg m = {.type = type, .req_id = req_id,
257        .tx_id = trans_id };
258    struct write_req header_req = { &m, sizeof(m) };
259
260    for (r = 0; r < nr_reqs; r++)
261        len += req[r].len;
262    m.len = len;
263    len += sizeof(m);
264
265    cur_req = &header_req;
266
267    BUG_ON(len > XENSTORE_RING_SIZE);
268    /* Wait for the ring to drain to the point where we can send the
269       message. */
270    prod = xenstore_buf->req_prod;
271    if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE) 
272    {
273        /* Wait for there to be space on the ring */
274        DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
275                prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
276        wait_event(xb_waitq,
277                xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
278                XENSTORE_RING_SIZE);
279        DEBUG("Back from wait.\n");
280        prod = xenstore_buf->req_prod;
281    }
282
283    /* We're now guaranteed to be able to send the message without
284       overflowing the ring.  Do so. */
285    total_off = 0;
286    req_off = 0;
287    while (total_off < len) 
288    {
289        this_chunk = min(cur_req->len - req_off,
290                XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
291        memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
292                (char *)cur_req->data + req_off, this_chunk);
293        prod += this_chunk;
294        req_off += this_chunk;
295        total_off += this_chunk;
296        if (req_off == cur_req->len) 
297        {
298            req_off = 0;
299            if (cur_req == &header_req)
300                cur_req = req;
301            else
302                cur_req++;
303        }
304    }
305
306    DEBUG("Complete main loop of xb_write.\n");
307    BUG_ON(req_off != 0);
308    BUG_ON(total_off != len);
309    BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
310
311    /* Remote must see entire message before updating indexes */
312    wmb();
313
314    xenstore_buf->req_prod += len;
315
316    /* Send evtchn to notify remote */
317    notify_remote_via_evtchn(start_info.store_evtchn);
318}
319
320/* Send a mesasge to xenbus, in the same fashion as xb_write, and
321   block waiting for a reply.  The reply is malloced and should be
322   freed by the caller. */
323static struct xsd_sockmsg *
324xenbus_msg_reply(int type,
325                 xenbus_transaction_t trans,
326                 struct write_req *io,
327                 int nr_reqs)
328{
329    int id;
330    DEFINE_WAIT(w);
331    struct xsd_sockmsg *rep;
332
333    id = allocate_xenbus_id();
334    add_waiter(w, req_info[id].waitq);
335
336    xb_write(type, id, trans, io, nr_reqs);
337
338    schedule();
339    remove_waiter(w);
340    wake(current);
341
342    rep = req_info[id].reply;
343    BUG_ON(rep->req_id != id);
344    release_xenbus_id(id);
345    return rep;
346}
347
348static char *errmsg(struct xsd_sockmsg *rep)
349{
350    if (!rep) {
351        char msg[] = "No reply";
352        size_t len = strlen(msg) + 1;
353        return memcpy(malloc(len), msg, len);
354    }
355    if (rep->type != XS_ERROR)
356        return NULL;
357    char *res = malloc(rep->len + 1);
358    memcpy(res, rep + 1, rep->len);
359    res[rep->len] = 0;
360    free(rep);
361    return res;
362}       
363
364/* Send a debug message to xenbus.  Can block. */
365static void xenbus_debug_msg(const char *msg)
366{
367    int len = strlen(msg);
368    struct write_req req[] = {
369        { "print", sizeof("print") },
370        { msg, len },
371        { "", 1 }};
372    struct xsd_sockmsg *reply;
373
374    reply = xenbus_msg_reply(XS_DEBUG, 0, req, ARRAY_SIZE(req));
375    DEBUG("Got a reply, type %d, id %d, len %d.\n",
376            reply->type, reply->req_id, reply->len);
377}
378
379/* List the contents of a directory.  Returns a malloc()ed array of
380   pointers to malloc()ed strings.  The array is NULL terminated.  May
381   block. */
382char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
383{
384    struct xsd_sockmsg *reply, *repmsg;
385    struct write_req req[] = { { pre, strlen(pre)+1 } };
386    int nr_elems, x, i;
387    char **res;
388
389    repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
390    char *msg = errmsg(repmsg);
391    if (msg) {
392        *contents = NULL;
393        return msg;
394    }
395    reply = repmsg + 1;
396    for (x = nr_elems = 0; x < repmsg->len; x++)
397        nr_elems += (((char *)reply)[x] == 0);
398    res = malloc(sizeof(res[0]) * (nr_elems + 1));
399    for (x = i = 0; i < nr_elems; i++) {
400        int l = strlen((char *)reply + x);
401        res[i] = malloc(l + 1);
402        memcpy(res[i], (char *)reply + x, l + 1);
403        x += l + 1;
404    }
405    res[i] = NULL;
406    free(repmsg);
407    *contents = res;
408    return NULL;
409}
410
411char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
412{
413    struct write_req req[] = { {path, strlen(path) + 1} };
414    struct xsd_sockmsg *rep;
415    char *res;
416    rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
417    char *msg = errmsg(rep);
418    if (msg) {
419        *value = NULL;
420        return msg;
421    }
422    res = malloc(rep->len + 1);
423    memcpy(res, rep + 1, rep->len);
424    res[rep->len] = 0;
425    free(rep);
426    *value = res;
427    return NULL;
428}
429
430char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value)
431{
432    struct write_req req[] = { 
433        {path, strlen(path) + 1},
434        {value, strlen(value) + 1},
435    };
436    struct xsd_sockmsg *rep;
437    rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
438    char *msg = errmsg(rep);
439    if (msg) return msg;
440    free(rep);
441    return NULL;
442}
443
444char* xenbus_watch_path( xenbus_transaction_t xbt, const char *path)
445{
446        /* in the future one could have multiple watch queues, and use
447         * the token for demuxing. For now the token is 0. */
448
449    struct xsd_sockmsg *rep;
450
451    struct write_req req[] = { 
452        {path, strlen(path) + 1},
453        {"0",2 },
454    };
455
456    rep = xenbus_msg_reply(XS_WATCH, xbt, req, ARRAY_SIZE(req));
457
458    char *msg = errmsg(rep);
459    if (msg) return msg;
460    free(rep);
461
462    return NULL;
463}
464
465char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
466{
467    struct write_req req[] = { {path, strlen(path) + 1} };
468    struct xsd_sockmsg *rep;
469    rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
470    char *msg = errmsg(rep);
471    if (msg)
472        return msg;
473    free(rep);
474    return NULL;
475}
476
477char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
478{
479    struct write_req req[] = { {path, strlen(path) + 1} };
480    struct xsd_sockmsg *rep;
481    char *res;
482    rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
483    char *msg = errmsg(rep);
484    if (msg) {
485        *value = NULL;
486        return msg;
487    }
488    res = malloc(rep->len + 1);
489    memcpy(res, rep + 1, rep->len);
490    res[rep->len] = 0;
491    free(rep);
492    *value = res;
493    return NULL;
494}
495
496#define PERM_MAX_SIZE 32
497char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm)
498{
499    char value[PERM_MAX_SIZE];
500    snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
501    struct write_req req[] = { 
502        {path, strlen(path) + 1},
503        {value, strlen(value) + 1},
504    };
505    struct xsd_sockmsg *rep;
506    rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
507    char *msg = errmsg(rep);
508    if (msg)
509        return msg;
510    free(rep);
511    return NULL;
512}
513
514char *xenbus_transaction_start(xenbus_transaction_t *xbt)
515{
516    /* xenstored becomes angry if you send a length 0 message, so just
517       shove a nul terminator on the end */
518    struct write_req req = { "", 1};
519    struct xsd_sockmsg *rep;
520    char *err;
521
522    rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
523    err = errmsg(rep);
524    if (err)
525        return err;
526    sscanf((char *)(rep + 1), "%u", xbt);
527    free(rep);
528    return NULL;
529}
530
531char *
532xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
533{
534    struct xsd_sockmsg *rep;
535    struct write_req req;
536    char *err;
537
538    *retry = 0;
539
540    req.data = abort ? "F" : "T";
541    req.len = 2;
542    rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
543    err = errmsg(rep);
544    if (err) {
545        if (!strcmp(err, "EAGAIN")) {
546            *retry = 1;
547            free(err);
548            return NULL;
549        } else {
550            return err;
551        }
552    }
553    free(rep);
554    return NULL;
555}
556
557int xenbus_read_integer(char *path)
558{
559    char *res, *buf;
560    int t;
561
562    res = xenbus_read(XBT_NIL, path, &buf);
563    if (res) {
564        printk("Failed to read %s.\n", path);
565        free(res);
566        return -1;
567    }
568    sscanf(buf, "%d", &t);
569    free(buf);
570    return t;
571}
572
573static void do_ls_test(const char *pre)
574{
575    char **dirs;
576    int x;
577
578    DEBUG("ls %s...\n", pre);
579    char *msg = xenbus_ls(XBT_NIL, pre, &dirs);
580    if (msg) {
581        DEBUG("Error in xenbus ls: %s\n", msg);
582        free(msg);
583        return;
584    }
585    for (x = 0; dirs[x]; x++) 
586    {
587        DEBUG("ls %s[%d] -> %s\n", pre, x, dirs[x]);
588        free(dirs[x]);
589    }
590    free(dirs);
591}
592
593static void do_read_test(const char *path)
594{
595    char *res;
596    DEBUG("Read %s...\n", path);
597    char *msg = xenbus_read(XBT_NIL, path, &res);
598    if (msg) {
599        DEBUG("Error in xenbus read: %s\n", msg);
600        free(msg);
601        return;
602    }
603    DEBUG("Read %s -> %s.\n", path, res);
604    free(res);
605}
606
607static void do_write_test(const char *path, const char *val)
608{
609    DEBUG("Write %s to %s...\n", val, path);
610    char *msg = xenbus_write(XBT_NIL, path, val);
611    if (msg) {
612        DEBUG("Result %s\n", msg);
613        free(msg);
614    } else {
615        DEBUG("Success.\n");
616    }
617}
618
619static void do_rm_test(const char *path)
620{
621    DEBUG("rm %s...\n", path);
622    char *msg = xenbus_rm(XBT_NIL, path);
623    if (msg) {
624        DEBUG("Result %s\n", msg);
625        free(msg);
626    } else {
627        DEBUG("Success.\n");
628    }
629}
630
631/* Simple testing thing */
632void test_xenbus(void)
633{
634    DEBUG("Doing xenbus test.\n");
635    xenbus_debug_msg("Testing xenbus...\n");
636
637    DEBUG("Doing ls test.\n");
638    do_ls_test("device");
639    do_ls_test("device/vif");
640    do_ls_test("device/vif/0");
641
642    DEBUG("Doing read test.\n");
643    do_read_test("device/vif/0/mac");
644    do_read_test("device/vif/0/backend");
645
646    DEBUG("Doing write test.\n");
647    do_write_test("device/vif/0/flibble", "flobble");
648    do_read_test("device/vif/0/flibble");
649    do_write_test("device/vif/0/flibble", "widget");
650    do_read_test("device/vif/0/flibble");
651
652    DEBUG("Doing rm test.\n");
653    do_rm_test("device/vif/0/flibble");
654    do_read_test("device/vif/0/flibble");
655    DEBUG("(Should have said ENOENT)\n");
656}
657
658/*
659 * Local variables:
660 * mode: C
661 * c-basic-offset: 4
662 * End:
663 */
Note: See TracBrowser for help on using the repository browser.