Annotation of Gnu-Mach/xen/store.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  *  Copyright (C) 2006-2009 Free Software Foundation
                      3:  *
                      4:  * This program is free software ; you can redistribute it and/or modify
                      5:  * it under the terms of the GNU General Public License as published by
                      6:  * the Free Software Foundation ; either version 2 of the License, or
                      7:  * (at your option) any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful,
                     10:  * but WITHOUT ANY WARRANTY ; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
                     12:  * GNU General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with the program ; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: #include <sys/types.h>
                     20: #include <mach/mig_support.h>
                     21: #include <machine/pmap.h>
                     22: #include <machine/ipl.h>
                     23: #include <kern/kalloc.h>
                     24: #include <stdarg.h>
                     25: #include <string.h>
                     26: #include <alloca.h>
                     27: #include <xen/public/xen.h>
                     28: #include <xen/public/io/xs_wire.h>
                     29: #include <util/atoi.h>
                     30: #include "store.h"
                     31: #include "ring.h"
                     32: #include "evt.h"
                     33: #include "xen.h"
                     34: 
                     35: /* TODO use events instead of just yielding */
                     36: 
                     37: /* Hypervisor part */
                     38: 
                     39: decl_simple_lock_data(static, lock);
                     40: 
                     41: static struct xenstore_domain_interface *store;
                     42: 
                     43: struct store_req {
                     44:        const char *data;
                     45:        unsigned len;
                     46: };
                     47: 
                     48: /* Send a request */
1.1.1.2 ! root       49: static void store_put(hyp_store_transaction_t t, uint32_t type, struct store_req *req, unsigned nr_reqs) {
1.1       root       50:        struct xsd_sockmsg head = {
                     51:                .type = type,
                     52:                .req_id = 0,
                     53:                .tx_id = t,
                     54:        };
                     55:        unsigned totlen, len;
                     56:        unsigned i;
                     57: 
                     58:        totlen = 0;
                     59:        for (i = 0; i < nr_reqs; i++)
                     60:                totlen += req[i].len;
                     61:        head.len = totlen;
                     62:        totlen += sizeof(head);
                     63: 
                     64:        if (totlen > sizeof(store->req) - 1)
                     65:                panic("too big store message %d, max %d", totlen, sizeof(store->req));
                     66: 
                     67:        while (hyp_ring_available(store->req, store->req_prod, store->req_cons) < totlen)
                     68:                hyp_yield();
                     69: 
                     70:        mb();
                     71:        hyp_ring_store(&hyp_ring_cell(store->req, store->req_prod), &head, sizeof(head), store->req, store->req + sizeof(store->req));
                     72:        len = sizeof(head);
                     73:        for (i=0; i<nr_reqs; i++) {
                     74:                hyp_ring_store(&hyp_ring_cell(store->req, store->req_prod + len), req[i].data, req[i].len, store->req, store->req + sizeof(store->req));
                     75:                len += req[i].len;
                     76:        }
                     77: 
                     78:        wmb();
                     79:        store->req_prod += totlen;
                     80:        hyp_event_channel_send(boot_info.store_evtchn);
                     81: }
                     82: 
                     83: static const char *errors[] = {
                     84:        "EINVAL",
                     85:        "EACCES",
                     86:        "EEXIST",
                     87:        "EISDIR",
                     88:        "ENOENT",
                     89:        "ENOMEM",
                     90:        "ENOSPC",
                     91:        "EIO",
                     92:        "ENOTEMPTY",
                     93:        "ENOSYS",
                     94:        "EROFS",
                     95:        "EBUSY",
                     96:        "EAGAIN",
                     97:        "EISCONN",
                     98:        NULL,
                     99: };
                    100: 
                    101: /* Send a request and wait for a reply, whose header is put in head, and
                    102:  * data is returned (beware, that's in the ring !)
                    103:  * On error, returns NULL.  Else takes the lock and return pointer on data and
                    104:  * store_put_wait_end shall be called after reading it.  */
                    105: static struct xsd_sockmsg head;
                    106: const char *hyp_store_error;
                    107: 
1.1.1.2 ! root      108: static void *store_put_wait(hyp_store_transaction_t t, uint32_t type, struct store_req *req, unsigned nr_reqs) {
1.1       root      109:        unsigned len;
                    110:        const char **error;
                    111:        void *data;
                    112: 
                    113:        simple_lock(&lock);
                    114:        store_put(t, type, req, nr_reqs);
                    115: again:
                    116:        while (store->rsp_prod - store->rsp_cons < sizeof(head))
                    117:                hyp_yield();
                    118:        rmb();
                    119:        hyp_ring_fetch(&head, &hyp_ring_cell(store->rsp, store->rsp_cons), sizeof(head), store->rsp, store->rsp + sizeof(store->rsp));
                    120:        len = sizeof(head) + head.len;
                    121:        while (store->rsp_prod - store->rsp_cons < len)
                    122:                hyp_yield();
                    123:        rmb();
                    124:        if (head.type == XS_WATCH_EVENT) {
                    125:                /* Spurious watch event, drop */
                    126:                store->rsp_cons += sizeof(head) + head.len;
                    127:                hyp_event_channel_send(boot_info.store_evtchn);
                    128:                goto again;
                    129:        }
                    130:        data = &hyp_ring_cell(store->rsp, store->rsp_cons + sizeof(head));
                    131:        if (head.len <= 10) {
                    132:                char c[10];
                    133:                hyp_ring_fetch(c, data, head.len, store->rsp, store->rsp + sizeof(store->rsp));
                    134:                for (error = errors; *error; error++) {
                    135:                        if (head.len == strlen(*error) + 1 && !memcmp(*error, c, head.len)) {
                    136:                                hyp_store_error = *error;
                    137:                                store->rsp_cons += len;
                    138:                                hyp_event_channel_send(boot_info.store_evtchn);
                    139:                                simple_unlock(&lock);
                    140:                                return NULL;
                    141:                        }
                    142:                }
                    143:        }
                    144:        return data;
                    145: }
                    146: 
                    147: /* Must be called after each store_put_wait.  Releases lock.  */
                    148: static void store_put_wait_end(void) {
                    149:        mb();
                    150:        store->rsp_cons += sizeof(head) + head.len;
                    151:        hyp_event_channel_send(boot_info.store_evtchn);
                    152:        simple_unlock(&lock);
                    153: }
                    154: 
                    155: /* Start a transaction.  */
                    156: hyp_store_transaction_t hyp_store_transaction_start(void) {
                    157:        struct store_req req = {
                    158:                .data = "",
                    159:                .len = 1,
                    160:        };
                    161:        char *rep;
                    162:        char *s;
                    163:        int i;
                    164: 
                    165:        rep = store_put_wait(0, XS_TRANSACTION_START, &req, 1);
                    166:        if (!rep)
                    167:                panic("couldn't start transaction (%s)", hyp_store_error);
                    168:        s = alloca(head.len);
                    169:        hyp_ring_fetch(s, rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
                    170:        mach_atoi((u_char*) s, &i);
                    171:        if (i == MACH_ATOI_DEFAULT)
                    172:                panic("bogus transaction id len %d '%s'", head.len, s);
                    173:        store_put_wait_end();
                    174:        return i;
                    175: }
                    176: 
                    177: /* Stop a transaction.  */
                    178: int hyp_store_transaction_stop(hyp_store_transaction_t t) {
                    179:        struct store_req req = {
                    180:                .data = "T",
                    181:                .len = 2,
                    182:        };
                    183:        int ret = 1;
                    184:        void *rep;
                    185:        rep = store_put_wait(t, XS_TRANSACTION_END, &req, 1);
                    186:        if (!rep)
                    187:                return 0;
                    188:        store_put_wait_end();
                    189:        return ret;
                    190: }
                    191: 
                    192: /* List a directory: returns an array to file names, terminated by NULL.  Free
                    193:  * with kfree.  */
                    194: char **hyp_store_ls(hyp_store_transaction_t t, int n, ...) {
                    195:        struct store_req req[n];
                    196:        va_list listp;
                    197:        int i;
                    198:        char *rep;
                    199:        char *c;
                    200:        char **res, **rsp;
                    201: 
                    202:        va_start (listp, n);
                    203:        for (i = 0; i < n; i++) {
                    204:                req[i].data = va_arg(listp, char *);
                    205:                req[i].len = strlen(req[i].data);
                    206:        }
                    207:        req[n - 1].len++;
                    208:        va_end (listp);
                    209: 
                    210:        rep = store_put_wait(t, XS_DIRECTORY, req, n);
                    211:        if (!rep)
                    212:                return NULL;
                    213:        i = 0;
                    214:        for (   c = rep, n = 0;
                    215:                n < head.len;
                    216:                n += hyp_ring_next_word(&c, store->rsp, store->rsp + sizeof(store->rsp)) + 1)
                    217:                i++;
                    218:        res = (void*) kalloc((i + 1) * sizeof(char*) + head.len);
                    219:        if (!res)
                    220:                hyp_store_error = "ENOMEM";
                    221:        else {
                    222:                hyp_ring_fetch(res + (i + 1), rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
                    223:                rsp = res;
                    224:                for (c = (char*) (res + (i + 1)); i; i--, c += strlen(c) + 1)
                    225:                        *rsp++ = c;
                    226:                *rsp = NULL;
                    227:        }
                    228:        store_put_wait_end();
                    229:        return res;
                    230: }
                    231: 
                    232: /* Get the value of an entry, va version.  */
                    233: static void *hyp_store_read_va(hyp_store_transaction_t t, int n, va_list listp) {
                    234:        struct store_req req[n];
                    235:        int i;
                    236:        void *rep;
                    237:        char *res;
                    238: 
                    239:        for (i = 0; i < n; i++) {
                    240:                req[i].data = va_arg(listp, char *);
                    241:                req[i].len = strlen(req[i].data);
                    242:        }
                    243:        req[n - 1].len++;
                    244: 
                    245:        rep = store_put_wait(t, XS_READ, req, n);
                    246:        if (!rep)
                    247:                return NULL;
                    248:        res = (void*) kalloc(head.len + 1);
                    249:        if (!res)
                    250:                hyp_store_error = "ENOMEM";
                    251:        else {
                    252:                hyp_ring_fetch(res, rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
                    253:                res[head.len] = 0;
                    254:        }
                    255:        store_put_wait_end();
                    256:        return res;
                    257: }
                    258: 
                    259: /* Get the value of an entry.  Free with kfree.  */
                    260: void *hyp_store_read(hyp_store_transaction_t t, int n, ...) {
                    261:        va_list listp;
                    262:        char *res;
                    263: 
                    264:        va_start(listp, n);
                    265:        res = hyp_store_read_va(t, n, listp);
                    266:        va_end(listp);
                    267:        return res;
                    268: }
                    269: 
                    270: /* Get the integer value of an entry, -1 on error.  */
                    271: int hyp_store_read_int(hyp_store_transaction_t t, int n, ...) {
                    272:        va_list listp;
                    273:        char *res;
                    274:        int i;
                    275: 
                    276:        va_start(listp, n);
                    277:        res = hyp_store_read_va(t, n, listp);
                    278:        va_end(listp);
                    279:        if (!res)
                    280:                return -1;
                    281:        mach_atoi((u_char *) res, &i);
                    282:        if (i == MACH_ATOI_DEFAULT)
                    283:                printf("bogus integer '%s'\n", res);
                    284:        kfree((vm_offset_t) res, strlen(res)+1);
                    285:        return i;
                    286: }
                    287: 
                    288: /* Set the value of an entry.  */
                    289: char *hyp_store_write(hyp_store_transaction_t t, const char *data, int n, ...) {
                    290:        struct store_req req[n + 1];
                    291:        va_list listp;
                    292:        int i;
                    293:        void *rep;
                    294:        char *res;
                    295: 
                    296:        va_start (listp, n);
                    297:        for (i = 0; i < n; i++) {
                    298:                req[i].data = va_arg(listp, char *);
                    299:                req[i].len = strlen(req[i].data);
                    300:        }
                    301:        req[n - 1].len++;
                    302:        req[n].data = data;
                    303:        req[n].len = strlen (data);
                    304:        va_end (listp);
                    305: 
                    306:        rep = store_put_wait (t, XS_WRITE, req, n + 1);
                    307:        if (!rep)
                    308:                return NULL;
                    309:        res = (void*) kalloc(head.len + 1);
                    310:        if (!res)
                    311:                hyp_store_error = NULL;
                    312:        else {
                    313:                hyp_ring_fetch(res, rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
                    314:                res[head.len] = 0;
                    315:        }
                    316:        store_put_wait_end();
                    317:        return res;
                    318: }
                    319: 
                    320: static void hyp_store_handler(int unit)
                    321: {
                    322:        thread_wakeup(&boot_info.store_evtchn);
                    323: }
                    324: 
                    325: /* Map store's shared page.  */
                    326: void hyp_store_init(void)
                    327: {
                    328:        if (store)
                    329:                return;
                    330:        simple_lock_init(&lock);
                    331:        store = (void*) mfn_to_kv(boot_info.store_mfn);
                    332: #ifdef MACH_PV_PAGETABLES
                    333:        pmap_set_page_readwrite(store);
                    334: #endif /* MACH_PV_PAGETABLES */
                    335:        /* SPL sched */
                    336:        hyp_evt_handler(boot_info.store_evtchn, hyp_store_handler, 0, SPL7);
                    337: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.