remove obsolete peer blockd
[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
152         always_assert(xseg);
153
154         for (;;) {
155                 ret = xseg_prepare_wait(xseg, mportno);
156                 always_assert(ret == 0);
157
158                 xreq = xseg_accept(xseg, mportno);
159                 if (xreq) {
160                         xseg_cancel_wait(xseg, mportno);
161                         /*
162                          * Construct a 1-1 reply immediately, make sure it fits
163                          * Verify the initiator has allocated enough space for
164                          * the reply and the target name fits in the map reply.
165                          */
166                         size_t s = sizeof(struct xseg_reply_map) +
167                                 sizeof(struct xseg_reply_map_scatterlist);
168                         always_assert(xreq->datalen >= s);
169                         always_assert(xreq->targetlen <= XSEG_MAX_TARGETLEN);
170
171                         struct xseg_reply_map *mreply = (void *)xreq->data;
172                         mreply->cnt = 1;
173                         mreply->segs[0].offset = xreq->offset;
174                         mreply->segs[0].size = xreq->size;
175                         /* FIXME: strlcpy() would work nicely here */
176                         strncpy(mreply->segs[0].target, xreq->target, xreq->targetlen);
177                         mreply->segs[0].target[xreq->targetlen] = '\0';
178
179                         /* Respond to the initiator, signal the source port */
180 //                      perr(PI, 0, "completed io");
181                         xreq->state |= XS_SERVED;
182                         ret = xseg_respond(xseg, xreq->portno, xreq);
183                         always_assert(ret != NoSerial);
184                         ret = xseg_signal(xseg, xreq->portno);
185 //                      always_assert(ret == 1);
186                 } else {
187                         /*
188                          * If things are OK, no timeout should ever be needed.
189                          * Otherwise, it's a mapperd or xseg bug.
190                          */
191                         xseg_wait_signal(xseg, 1000000UL);
192                 }
193         }
194         
195         /* Shouldn't reach this point */
196         always_assert(0);
197         return 0;
198 }
199
200 /*
201  * FIXME: Initialize the mapperd struct based on cmdline_* vars
202  */
203 static int mapperd_init(struct mapperd *mapperd)
204 {
205         int ret;
206
207         mapperd->mportno = cmdline_mportno;
208         mapperd->bportno = cmdline_bportno;
209
210         /* FIXME: If xseg library fails, is errno set? */
211         if (xseg_initialize()) {
212                 perr(PE, 0, "could not initialize xseg library");
213                 ret = -EIO;
214                 goto out;
215         }
216
217         if (! (mapperd->xseg = join_or_create(cmdline_xseg_spec))) {
218                 perr(PE, 0, "could not join or create xseg with spec '%s'\n",
219                         cmdline_xseg_spec);
220                 ret = -EIO;
221                 goto out_with_xseginit;
222         }
223
224         if (! (mapperd->mport = xseg_bind_port(mapperd->xseg, mapperd->mportno))) {
225                 perr(PE, 0, "cannot bind to xseg port %ld", (long)mapperd->mportno);
226                 ret = -EIO;
227                 goto out_with_xsegjoin;
228         }
229
230         mapperd->mportno = xseg_portno(mapperd->xseg, mapperd->mport);
231         
232         perr(PI, 0, "mapperd on port %u of %u",
233                 mapperd->mportno, mapperd->xseg->config.nr_ports);
234
235         ret = 0;
236         goto out;
237
238 out_with_xsegjoin:
239         xseg_leave(mapperd->xseg);
240 out_with_xseginit:
241         xseg_finalize();
242 out:
243         return ret;
244 }
245
246 int main(int argc, char *argv[])
247 {
248         struct mapperd mapper;
249
250         init_perr("mapperd");
251         parse_cmdline(argc, argv);
252
253         perr(PI, 0, "v = %ld, m = %ld, b = %ld, nr_ops = %lu\n",
254                 cmdline_mportno, cmdline_mportno, cmdline_bportno, cmdline_nr_ops);
255
256         if (mapperd_init(&mapper) < 0) {
257                 perr(PFE, 0, "failed to initialize mapperd.");
258                 exit(1); /* This is just to quiesce gcc's control flow analysis */
259         }
260
261         return mapperd_loop(&mapper);
262 }
263