added speer skeletor
[archipelago] / xseg / peers / user / mapperd.c
1 /*
2  * The Mapper
3  */
4
5 #define _GNU_SOURCE
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <aio.h>
15 #include <signal.h>
16 #include <limits.h>
17 #include <xseg/xseg.h>
18 #include <pthread.h>
19
20 #include <xseg/protocol.h>
21
22 #include "common.h"  /* Please fix me */
23
24 #define MAX_PATH_SIZE 255
25 #define MAX_FILENAME_SIZE 255
26
27 #define DEFAULT_NR_OPS 16
28
29 #define MAPPER_SANITY_CHECKS 1
30
31 /*
32  * Globals, holding command-line arguments
33  */
34 long cmdline_mportno = -1;
35 long cmdline_bportno = -1;
36 char *cmdline_xseg_spec = NULL;
37 long cmdline_nr_ops = DEFAULT_NR_OPS;
38
39 struct mapperd {
40         struct xseg *xseg;
41         struct xseg_port *mport;
42         uint32_t mportno, bportno;
43 };
44
45 static int usage(char *argv0)
46 {
47         fprintf(stderr,
48                 "Usage: %s [-p MAPPERD_PORT]"
49                         "[-b BLOCKD_POART] [-g XSEG_SPEC] [-n NR_OPS]\n\n"
50                 "where:\n"
51                 "\tMAPPERD_PORT: xseg port to listen for requests on\n"
52                 "\tBLOCKD_PORT: xseg port where blockd/filed/sosd lives\n"
53                 "\tXSEG_SPEC: xseg spec as 'type:name:nr_ports:nr_requests:"
54                         "request_size:extra_size:page_shift'\n"
55                 "\tNR_OPS: number of outstanding xseg requests\n",
56                 argv0);
57
58         return 1;
59 }
60
61 static int safe_atoi(char *s)
62 {
63         long l;
64         char *endp;
65
66         l = strtol(s, &endp, 10);
67         if (s != endp && *endp == '\0')
68                 return l;
69         else
70                 return -1;
71 }
72
73 static void parse_cmdline(int argc, char **argv)
74 {
75         for (;;) {
76                 int c;
77
78                 opterr = 0;
79                 c = getopt(argc, argv, "+:hp:b:n:g:");
80                 if (c == -1)
81                         break;
82                 
83                 switch(c) {
84                         case '?':
85                                 perr(PFE, 0, "Unknown option: -%c", optopt);
86                                 break;
87                         case ':':
88                                 perr(PFE, 0, "Option -%c requires an argument",
89                                         optopt);
90                                 break;
91                         case 'h':
92                                 usage(argv[0]);
93                                 exit(0);
94                                 break;
95                         case 'p':
96                                 cmdline_mportno = safe_atoi(optarg);
97                                 break;
98                         case 'b':
99                                 cmdline_bportno = safe_atoi(optarg);
100                                 break;
101                         case 'n':
102                                 cmdline_nr_ops = safe_atoi(optarg);
103                                 break;
104                         case 'g':
105                                 /* FIXME: Max length of spec? strdup, eww */
106                                 cmdline_xseg_spec = strdup(optarg);
107                                 if (!cmdline_xseg_spec)
108                                         perr(PFE, 0, "out of memory");
109                                 break;
110                 }
111         }
112
113         argc -= optind;
114         argv += optind;
115
116         /* Sanity check for all arguments */
117         if (cmdline_mportno < 0)
118                 perr(PFE, 0, "no or invalid port specified for mapperd");
119         if (cmdline_bportno != -1)
120                 perr(PFE, 0, "This is a no-op 1-1 mapper. Cannot specify a blocker port");
121                 //no or invalid port specified for blockd/filed/sosd");
122         if (cmdline_nr_ops < 1)
123                 perr(PFE, 0, "specified outstanding request count is invalid");
124         if (!cmdline_xseg_spec)
125                 perr(PFE, 0, "xseg specification is mandatory");
126
127         if (argc)
128                 perr(PFE, 0, "Non-option arguments specified on command line");
129 }
130
131 static struct xseg *join_or_create(char *spec)
132 {
133         struct xseg_config config;
134         struct xseg *xseg;
135
136         (void)xseg_parse_spec(spec, &config);
137         xseg = xseg_join(config.type, config.name, "posix", NULL);
138         if (xseg)
139                 return xseg;
140
141         (void)xseg_create(&config);
142         return xseg_join(config.type, config.name, "posix", NULL);
143 }
144
145 static int mapperd_loop(struct mapperd *mapperd)
146 {
147         int ret;
148         struct xseg_request *xreq;
149         struct xseg *xseg = mapperd->xseg;
150         uint32_t mportno = mapperd->mportno;
151         char *target, buf[MAX_FILENAME_SIZE];
152         xport p;
153
154         always_assert(xseg);
155
156         for (;;) {
157                 ret = xseg_prepare_wait(xseg, mportno);
158                 always_assert(ret == 0);
159
160                 xreq = xseg_accept(xseg, mportno, 0);
161                 if (xreq) {
162                         xseg_cancel_wait(xseg, mportno);
163                         /*
164                          * Construct a 1-1 reply immediately, make sure it fits
165                          * Verify the initiator has allocated enough space for
166                          * the reply and the target name fits in the map reply.
167                          */
168                         size_t s = sizeof(struct xseg_reply_map) +
169                                 2 * sizeof(struct xseg_reply_map_scatterlist);
170                         target = xseg_get_target(xseg, xreq);
171                         strncpy(buf, target, xreq->targetlen);
172                         xseg_resize_request(xseg, xreq, xreq->targetlen, s);
173                         target = xseg_get_target(xseg, xreq);
174                         strncpy(target, buf, xreq->targetlen);
175
176                         struct xseg_reply_map *mreply = (void *)xseg_get_data(xseg, xreq);
177                         mreply->cnt = 2;
178                         mreply->segs[0].offset = xreq->offset;
179                         mreply->segs[0].size = xreq->size/2;
180                         /* FIXME: strlcpy() would work nicely here */
181                         strncpy(mreply->segs[0].target, target, xreq->targetlen);
182                         mreply->segs[0].target[xreq->targetlen] = '_';
183                         mreply->segs[0].target[xreq->targetlen + 1] = '1';
184                         mreply->segs[0].target[xreq->targetlen + 2] = '\0';
185                         
186                         mreply->segs[1].offset = xreq->offset;
187                         mreply->segs[1].size = xreq->size/2;
188                         /* FIXME: strlcpy() would work nicely here */
189                         strncpy(mreply->segs[1].target, target, xreq->targetlen);
190                         mreply->segs[1].target[xreq->targetlen] = '_';
191                         mreply->segs[1].target[xreq->targetlen + 1] = '2';
192                         mreply->segs[1].target[xreq->targetlen + 2] = '\0';
193
194                         /* Respond to the initiator, signal the source port */
195 //                      perr(PI, 0, "completed io");
196                         xreq->state |= XS_SERVED;
197                         p = xseg_respond(xseg, xreq, mportno, X_ALLOC);
198                         ret = xseg_signal(xseg, p);
199 //                      always_assert(ret == 1);
200                 } else {
201                         /*
202                          * If things are OK, no timeout should ever be needed.
203                          * Otherwise, it's a mapperd or xseg bug.
204                          */
205                         xseg_wait_signal(xseg, 1000000UL);
206                 }
207         }
208         
209         /* Shouldn't reach this point */
210         always_assert(0);
211         return 0;
212 }
213
214 /*
215  * FIXME: Initialize the mapperd struct based on cmdline_* vars
216  */
217 static int mapperd_init(struct mapperd *mapperd)
218 {
219         int ret;
220
221         mapperd->mportno = cmdline_mportno;
222         mapperd->bportno = cmdline_bportno;
223
224         /* FIXME: If xseg library fails, is errno set? */
225         if (xseg_initialize()) {
226                 perr(PE, 0, "could not initialize xseg library");
227                 ret = -EIO;
228                 goto out;
229         }
230
231         if (! (mapperd->xseg = join_or_create(cmdline_xseg_spec))) {
232                 perr(PE, 0, "could not join or create xseg with spec '%s'\n",
233                         cmdline_xseg_spec);
234                 ret = -EIO;
235                 goto out_with_xseginit;
236         }
237
238         if (! (mapperd->mport = xseg_bind_port(mapperd->xseg, mapperd->mportno, NULL))) {
239                 perr(PE, 0, "cannot bind to xseg port %ld", (long)mapperd->mportno);
240                 ret = -EIO;
241                 goto out_with_xsegjoin;
242         }
243
244         mapperd->mportno = xseg_portno(mapperd->xseg, mapperd->mport);
245         xseg_init_local_signal(mapperd->xseg, mapperd->mportno);
246         perr(PI, 0, "mapperd on port %u of %u",
247                 mapperd->mportno, mapperd->xseg->config.nr_ports);
248
249         ret = 0;
250         goto out;
251
252 out_with_xsegjoin:
253         xseg_leave(mapperd->xseg);
254 out_with_xseginit:
255         xseg_finalize();
256 out:
257         return ret;
258 }
259
260 int main(int argc, char *argv[])
261 {
262         struct mapperd mapper;
263
264         init_perr("mapperd");
265         parse_cmdline(argc, argv);
266
267         perr(PI, 0, "v = %ld, m = %ld, b = %ld, nr_ops = %lu\n",
268                 cmdline_mportno, cmdline_mportno, cmdline_bportno, cmdline_nr_ops);
269
270         if (mapperd_init(&mapper) < 0) {
271                 perr(PFE, 0, "failed to initialize mapperd.");
272                 exit(1); /* This is just to quiesce gcc's control flow analysis */
273         }
274
275         return mapperd_loop(&mapper);
276 }
277