debuggers.hg

view tools/fs-back/fs-backend.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents 243614f8360c
children 779c0ef9682c
line source
1 #undef NDEBUG
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <assert.h>
6 #include <malloc.h>
7 #include <xenctrl.h>
8 #include <aio.h>
9 #include <sys/mman.h>
10 #include <sys/select.h>
11 #include <sys/socket.h>
12 #include <xen/io/ring.h>
13 #include <xc_private.h>
14 #include <err.h>
15 #include "sys-queue.h"
16 #include "fs-backend.h"
17 #include "fs-debug.h"
19 struct xs_handle *xsh = NULL;
20 static struct fs_export *fs_exports = NULL;
21 static int export_id = 0;
22 static int mount_id = 0;
23 static int pipefds[2];
24 static LIST_HEAD(mount_requests_head, fs_mount) mount_requests_head;
26 static void free_mount_request(struct fs_mount *mount);
28 static void dispatch_response(struct fs_request *request)
29 {
30 int i;
31 struct fs_op *op;
33 for(i=0;;i++)
34 {
35 op = fsops[i];
36 /* We should dispatch a response before reaching the end of the array */
37 assert(op != NULL);
38 if(op->type == request->req_shadow.type)
39 {
40 FS_DEBUG("Found op for type=%d\n", op->type);
41 /* There needs to be a response handler */
42 assert(op->response_handler != NULL);
43 op->response_handler(request->mount, request);
44 break;
45 }
46 }
48 request->active = 0;
49 add_id_to_freelist(request->id, request->mount->freelist);
50 }
52 static void handle_aio_event(struct fs_request *request)
53 {
54 int ret, notify;
56 FS_DEBUG("handle_aio_event: mount %s request %d\n", request->mount->frontend, request->id);
57 if (request->active < 0) {
58 request->mount->nr_entries++;
59 if (!request->mount->nr_entries)
60 free_mount_request(request->mount);
61 return;
62 }
64 ret = aio_error(&request->aiocb);
65 if(ret != EINPROGRESS && ret != ECANCELED)
66 dispatch_response(request);
68 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&request->mount->ring, notify);
69 FS_DEBUG("Pushed responces and notify=%d\n", notify);
70 if(notify)
71 xc_evtchn_notify(request->mount->evth, request->mount->local_evtchn);
72 }
74 static void allocate_request_array(struct fs_mount *mount)
75 {
76 int i, nr_entries = mount->nr_entries;
77 struct fs_request *requests;
78 unsigned short *freelist;
80 requests = malloc(sizeof(struct fs_request) *nr_entries);
81 freelist = malloc(sizeof(unsigned short) * (nr_entries + 1));
82 memset(requests, 0, sizeof(struct fs_request) * nr_entries);
83 memset(freelist, 0, sizeof(unsigned short) * (nr_entries + 1));
84 for(i=0; i< nr_entries; i++)
85 {
86 requests[i].active = 0;
87 requests[i].mount = mount;
88 add_id_to_freelist(i, freelist);
89 }
90 mount->requests = requests;
91 mount->freelist = freelist;
92 }
95 static void handle_mount(struct fs_mount *mount)
96 {
97 int more, notify;
98 int nr_consumed=0;
99 RING_IDX cons, rp;
100 struct fsif_request *req;
102 moretodo:
103 rp = mount->ring.sring->req_prod;
104 xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
106 while ((cons = mount->ring.req_cons) != rp)
107 {
108 int i;
109 struct fs_op *op;
111 FS_DEBUG("Got a request at %d (of %d)\n",
112 cons, RING_SIZE(&mount->ring));
113 req = RING_GET_REQUEST(&mount->ring, cons);
114 FS_DEBUG("Request type=%d\n", req->type);
115 for(i=0;;i++)
116 {
117 op = fsops[i];
118 if(op == NULL)
119 {
120 /* We've reached the end of the array, no appropirate
121 * handler found. Warn, ignore and continue. */
122 FS_DEBUG("WARN: Unknown request type: %d\n", req->type);
123 mount->ring.req_cons++;
124 break;
125 }
126 if(op->type == req->type)
127 {
128 /* There needs to be a dispatch handler */
129 assert(op->dispatch_handler != NULL);
130 op->dispatch_handler(mount, req);
131 break;
132 }
133 }
135 nr_consumed++;
136 }
137 FS_DEBUG("Backend consumed: %d requests\n", nr_consumed);
138 RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more);
139 if(more) goto moretodo;
141 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify);
142 FS_DEBUG("Pushed responces and notify=%d\n", notify);
143 if(notify)
144 xc_evtchn_notify(mount->evth, mount->local_evtchn);
145 }
147 void terminate_mount_request(struct fs_mount *mount)
148 {
149 int count = 0, i;
151 FS_DEBUG("terminate_mount_request %s\n", mount->frontend);
152 xenbus_write_backend_state(mount, STATE_CLOSING);
154 for(i=0; i<mount->nr_entries; i++)
155 if(mount->requests[i].active) {
156 mount->requests[i].active = -1;
157 aio_cancel(mount->requests[i].aiocb.aio_fildes, &mount->requests[i].aiocb);
158 count--;
159 }
160 mount->nr_entries = count;
162 /* wait for the frontend to shut down but don't wait more than 3
163 * seconds */
164 i = 0;
165 while (!xenbus_frontend_state_changed(mount, STATE_CLOSING) && i < 3) {
166 sleep(1);
167 i++;
168 }
169 xenbus_write_backend_state(mount, STATE_CLOSED);
171 xc_gnttab_munmap(mount->gnth, mount->ring.sring, mount->shared_ring_size);
172 xc_gnttab_close(mount->gnth);
173 xc_evtchn_unbind(mount->evth, mount->local_evtchn);
174 xc_evtchn_close(mount->evth);
176 if (!count)
177 free_mount_request(mount);
178 }
180 static void free_mount_request(struct fs_mount *mount) {
181 FS_DEBUG("free_mount_request %s\n", mount->frontend);
182 xenbus_free_backend_node(mount);
183 free(mount->frontend);
184 free(mount->requests);
185 free(mount->freelist);
186 LIST_REMOVE (mount, entries);
187 free(mount);
188 }
190 static void handle_connection(int frontend_dom_id, int export_id, char *frontend)
191 {
192 struct fs_mount *mount;
193 struct fs_export *export;
194 struct fsif_sring *sring = NULL;
195 uint32_t dom_ids[MAX_RING_SIZE];
196 int i;
198 FS_DEBUG("Handling connection from dom=%d, for export=%d\n",
199 frontend_dom_id, export_id);
200 /* Try to find the export on the list */
201 export = fs_exports;
202 while(export)
203 {
204 if(export->export_id == export_id)
205 break;
206 export = export->next;
207 }
208 if(!export)
209 {
210 FS_DEBUG("Could not find the export (the id is unknown).\n");
211 return;
212 }
214 mount = (struct fs_mount*)malloc(sizeof(struct fs_mount));
215 memset(mount, 0, sizeof(struct fs_mount));
216 mount->dom_id = frontend_dom_id;
217 mount->export = export;
218 mount->mount_id = mount_id++;
219 if (xenbus_read_mount_request(mount, frontend) < 0)
220 goto error;
221 FS_DEBUG("Frontend found at: %s (gref=%d, evtchn=%d)\n",
222 mount->frontend, mount->grefs[0], mount->remote_evtchn);
223 if (!xenbus_write_backend_node(mount)) {
224 FS_DEBUG("ERROR: failed to write backend node on xenbus\n");
225 goto error;
226 }
227 mount->evth = -1;
228 mount->evth = xc_evtchn_open();
229 if (mount->evth < 0) {
230 FS_DEBUG("ERROR: Couldn't open evtchn!\n");
231 goto error;
232 }
233 mount->local_evtchn = -1;
234 mount->local_evtchn = xc_evtchn_bind_interdomain(mount->evth,
235 mount->dom_id,
236 mount->remote_evtchn);
237 if (mount->local_evtchn < 0) {
238 FS_DEBUG("ERROR: Couldn't bind evtchn!\n");
239 goto error;
240 }
241 mount->gnth = -1;
242 mount->gnth = xc_gnttab_open();
243 if (mount->gnth < 0) {
244 FS_DEBUG("ERROR: Couldn't open gnttab!\n");
245 goto error;
246 }
247 for(i=0; i<mount->shared_ring_size; i++)
248 dom_ids[i] = mount->dom_id;
249 sring = xc_gnttab_map_grant_refs(mount->gnth,
250 mount->shared_ring_size,
251 dom_ids,
252 mount->grefs,
253 PROT_READ | PROT_WRITE);
255 if (!sring) {
256 FS_DEBUG("ERROR: Couldn't amp grant refs!\n");
257 goto error;
258 }
260 BACK_RING_INIT(&mount->ring, sring, mount->shared_ring_size * XC_PAGE_SIZE);
261 mount->nr_entries = mount->ring.nr_ents;
262 for (i = 0; i < MAX_FDS; i++)
263 mount->fds[i] = -1;
265 LIST_INSERT_HEAD(&mount_requests_head, mount, entries);
266 if (!xenbus_watch_frontend_state(mount)) {
267 FS_DEBUG("ERROR: failed to watch frontend state on xenbus\n");
268 goto error;
269 }
270 if (!xenbus_write_backend_state(mount, STATE_READY)) {
271 FS_DEBUG("ERROR: failed to write backend state to xenbus\n");
272 goto error;
273 }
275 allocate_request_array(mount);
277 return;
279 error:
280 xenbus_write_backend_state(mount, STATE_CLOSED);
281 if (sring)
282 xc_gnttab_munmap(mount->gnth, mount->ring.sring, mount->shared_ring_size);
283 if (mount->gnth > 0)
284 xc_gnttab_close(mount->gnth);
285 if (mount->local_evtchn > 0)
286 xc_evtchn_unbind(mount->evth, mount->local_evtchn);
287 if (mount->evth > 0)
288 xc_evtchn_close(mount->evth);
289 }
291 static void await_connections(void)
292 {
293 int fd, max_fd, ret, dom_id, export_id;
294 fd_set fds;
295 char **watch_paths;
296 unsigned int len;
297 char d;
298 struct fs_mount *pointer;
300 LIST_INIT (&mount_requests_head);
302 assert(xsh != NULL);
303 if ((fd = xenbus_get_watch_fd()) == -1)
304 err(1, "xenbus_get_watch_fd: could not setup watch");
305 /* Infinite watch loop */
306 do {
307 FD_ZERO(&fds);
308 FD_SET(fd, &fds);
309 FD_SET(pipefds[0], &fds);
310 max_fd = fd > pipefds[0] ? fd : pipefds[0];
311 LIST_FOREACH(pointer, &mount_requests_head, entries) {
312 int tfd = xc_evtchn_fd(pointer->evth);
313 FD_SET(tfd, &fds);
314 if (tfd > max_fd) max_fd = tfd;
315 }
316 ret = select(max_fd+1, &fds, NULL, NULL, NULL);
317 if (ret < 0) {
318 if (errno == EINTR) continue;
319 /* try to recover */
320 else if (errno == EBADF) {
321 struct timeval timeout;
322 memset(&timeout, 0x00, sizeof(timeout));
323 FD_ZERO(&fds);
324 FD_SET(fd, &fds);
325 FD_SET(pipefds[0], &fds);
326 max_fd = fd > pipefds[0] ? fd : pipefds[0];
327 ret = select(max_fd + 1, &fds, NULL, NULL, &timeout);
328 if (ret < 0)
329 err(1, "select: unrecoverable error occurred: %d\n", errno);
331 /* trying to find the bogus fd among the open event channels */
332 LIST_FOREACH(pointer, &mount_requests_head, entries) {
333 int tfd = xc_evtchn_fd(pointer->evth);
334 memset(&timeout, 0x00, sizeof(timeout));
335 FD_ZERO(&fds);
336 FD_SET(tfd, &fds);
337 ret = select(tfd + 1, &fds, NULL, NULL, &timeout);
338 if (ret < 0) {
339 FS_DEBUG("fd %d is bogus, closing the related connection\n", tfd);
340 pointer->evth = fd;
341 terminate_mount_request(pointer);
342 continue;
343 }
344 }
345 continue;
346 } else
347 err(1, "select: unrecoverable error occurred: %d\n", errno);
348 }
349 if (FD_ISSET(fd, &fds)) {
350 watch_paths = xs_read_watch(xsh, &len);
351 if (!strcmp(watch_paths[XS_WATCH_TOKEN], "conn-watch")) {
352 dom_id = -1;
353 export_id = -1;
354 d = 0;
355 FS_DEBUG("Path changed %s\n", watch_paths[0]);
356 sscanf(watch_paths[XS_WATCH_PATH], WATCH_NODE"/%d/%d/fronten%c",
357 &dom_id, &export_id, &d);
358 if((dom_id >= 0) && (export_id >= 0) && d == 'd') {
359 char *frontend = xs_read(xsh, XBT_NULL, watch_paths[XS_WATCH_PATH], NULL);
360 if (frontend) {
361 char *p, *wp = strdup(watch_paths[XS_WATCH_PATH]);
362 handle_connection(dom_id, export_id, frontend);
363 xs_rm(xsh, XBT_NULL, wp);
364 p = strrchr(wp, '/');
365 if (p) {
366 *p = '\0';
367 p = strrchr(wp, '/');
368 if (p) {
369 *p = '\0';
370 xs_rm(xsh, XBT_NULL, wp);
371 }
372 }
373 free(wp);
374 }
375 }
376 } else if (!strcmp(watch_paths[XS_WATCH_TOKEN], "frontend-state")) {
377 LIST_FOREACH(pointer, &mount_requests_head, entries) {
378 if (!strncmp(pointer->frontend, watch_paths[XS_WATCH_PATH], strlen(pointer->frontend))) {
379 char *state = xenbus_read_frontend_state(pointer);
380 if (!state || strcmp(state, STATE_READY)) {
381 xenbus_unwatch_frontend_state(pointer);
382 terminate_mount_request(pointer);
383 }
384 free(state);
385 break;
386 }
387 }
388 } else {
389 FS_DEBUG("xenstore watch event unrecognized\n");
390 }
391 FS_DEBUG("Awaiting next connection.\n");
392 /* TODO - we need to figure out what to free */
393 free(watch_paths);
394 }
395 if (FD_ISSET(pipefds[0], &fds)) {
396 struct fs_request *request;
397 if (read_exact(pipefds[0], &request, sizeof(struct fs_request *)) < 0)
398 err(1, "read request failed\n");
399 handle_aio_event(request);
400 }
401 LIST_FOREACH(pointer, &mount_requests_head, entries) {
402 if (FD_ISSET(xc_evtchn_fd(pointer->evth), &fds)) {
403 evtchn_port_t port;
404 port = xc_evtchn_pending(pointer->evth);
405 if (port != -1) {
406 handle_mount(pointer);
407 xc_evtchn_unmask(pointer->evth, port);
408 }
409 }
410 }
411 } while (1);
412 }
414 static struct fs_export* create_export(char *name, char *export_path)
415 {
416 struct fs_export *curr_export, **last_export;
418 /* Create export structure */
419 curr_export = (struct fs_export *)malloc(sizeof(struct fs_export));
420 curr_export->name = name;
421 curr_export->export_path = export_path;
422 curr_export->export_id = export_id++;
423 /* Thread it onto the list */
424 curr_export->next = NULL;
425 last_export = &fs_exports;
426 while(*last_export)
427 last_export = &((*last_export)->next);
428 *last_export = curr_export;
430 return curr_export;
431 }
433 static void aio_signal_handler(int signo, siginfo_t *info, void *context)
434 {
435 struct fs_request *request = (struct fs_request*) info->si_value.sival_ptr;
436 int saved_errno = errno;
437 if (write_exact(pipefds[1], &request, sizeof(struct fs_request *)) < 0)
438 err(1, "write request filed\n");
439 errno = saved_errno;
440 }
442 int main(void)
443 {
444 struct fs_export *export;
445 struct sigaction act;
446 sigset_t enable;
448 sigemptyset(&enable);
449 sigaddset(&enable, SIGUSR2);
450 pthread_sigmask(SIG_UNBLOCK, &enable, NULL);
452 sigfillset(&act.sa_mask);
453 act.sa_flags = SA_SIGINFO; /* do not restart syscalls to interrupt select(); use sa_sigaction */
454 act.sa_sigaction = aio_signal_handler;
455 sigaction(SIGUSR2, &act, NULL);
457 /* Open the connection to XenStore first */
458 xsh = xs_domain_open();
459 assert(xsh != NULL);
460 xs_rm(xsh, XBT_NULL, ROOT_NODE);
461 /* Create watch node */
462 xenbus_create_request_node();
464 /* Create & register the default export */
465 export = create_export("default", "/var/lib/xen");
466 xenbus_register_export(export);
468 if (socketpair(PF_UNIX,SOCK_STREAM, 0, pipefds) == -1)
469 err(1, "failed to create pipe\n");
471 await_connections();
472 /* Close the connection to XenStore when we are finished with everything */
473 xs_daemon_close(xsh);
474 #if 0
475 int xc_handle;
476 char *shared_page;
477 int prot = PROT_READ | PROT_WRITE;
479 xc_handle = xc_gnttab_open();
480 printf("Main fn.\n");
482 shared_page = xc_gnttab_map_grant_ref(xc_handle,
483 7,
484 2047,
485 prot);
487 shared_page[20] = '\0';
488 printf("Current content of the page = %s\n", shared_page);
489 sprintf(shared_page, "%s", "Haha dirty page now! Very bad page.");
490 xc_gnttab_munmap(xc_handle, shared_page, 1);
491 xc_gnttab_close(xc_handle);
492 unrelated next line, saved for later convinience
493 xc_evtchn_notify(mount->evth, mount->local_evtchn);
494 #endif
495 }