ia64/xen-unstable

view tools/fs-back/fs-ops.c @ 17022:fbbc0523779e

ioemu stubdom: make daemonize optional
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 11 10:03:48 2008 +0000 (2008-02-11)
parents a1a3fe600ef3
children e5c9c8e6e726
line source
1 #undef NDEBUG
2 #include <stdio.h>
3 #include <aio.h>
4 #include <string.h>
5 #include <assert.h>
6 #include <fcntl.h>
7 #include <dirent.h>
8 #include <inttypes.h>
9 #include <xenctrl.h>
10 #include <sys/mman.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/vfs.h>
14 #include <sys/mount.h>
15 #include <unistd.h>
16 #include "fs-backend.h"
18 /* For debugging only */
19 #include <sys/time.h>
20 #include <time.h>
23 #define BUFFER_SIZE 1024
26 unsigned short get_request(struct mount *mount, struct fsif_request *req)
27 {
28 unsigned short id = get_id_from_freelist(mount->freelist);
30 printf("Private Request id: %d\n", id);
31 memcpy(&mount->requests[id].req_shadow, req, sizeof(struct fsif_request));
32 mount->requests[id].active = 1;
34 return id;
35 }
38 void dispatch_file_open(struct mount *mount, struct fsif_request *req)
39 {
40 char *file_name, full_path[BUFFER_SIZE];
41 int fd;
42 struct timeval tv1, tv2;
43 RING_IDX rsp_idx;
44 fsif_response_t *rsp;
45 uint16_t req_id;
47 printf("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
48 /* Read the request, and open file */
49 file_name = xc_gnttab_map_grant_ref(mount->gnth,
50 mount->dom_id,
51 req->u.fopen.gref,
52 PROT_READ);
54 req_id = req->id;
55 printf("File open issued for %s\n", file_name);
56 assert(BUFFER_SIZE >
57 strlen(file_name) + strlen(mount->export->export_path) + 1);
58 sprintf(full_path, "%s/%s", mount->export->export_path, file_name);
59 assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
60 printf("Issuing open for %s\n", full_path);
61 fd = open(full_path, O_RDWR);
62 printf("Got FD: %d\n", fd);
63 /* We can advance the request consumer index, from here on, the request
64 * should not be used (it may be overrinden by a response) */
65 mount->ring.req_cons++;
68 /* Get a response from the ring */
69 rsp_idx = mount->ring.rsp_prod_pvt++;
70 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
71 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
72 rsp->id = req_id;
73 rsp->ret_val = (uint64_t)fd;
74 }
76 void dispatch_file_close(struct mount *mount, struct fsif_request *req)
77 {
78 int ret;
79 RING_IDX rsp_idx;
80 fsif_response_t *rsp;
81 uint16_t req_id;
83 printf("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
85 req_id = req->id;
86 ret = close(req->u.fclose.fd);
87 printf("Got ret: %d\n", ret);
88 /* We can advance the request consumer index, from here on, the request
89 * should not be used (it may be overrinden by a response) */
90 mount->ring.req_cons++;
93 /* Get a response from the ring */
94 rsp_idx = mount->ring.rsp_prod_pvt++;
95 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
96 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
97 rsp->id = req_id;
98 rsp->ret_val = (uint64_t)ret;
99 }
100 void dispatch_file_read(struct mount *mount, struct fsif_request *req)
101 {
102 void *buf;
103 int fd;
104 uint16_t req_id;
105 unsigned short priv_id;
106 struct fs_request *priv_req;
108 /* Read the request */
109 buf = xc_gnttab_map_grant_ref(mount->gnth,
110 mount->dom_id,
111 req->u.fread.gref,
112 PROT_WRITE);
114 req_id = req->id;
115 printf("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
116 req->u.fread.fd, req->u.fread.len, req->u.fread.offset);
118 priv_id = get_request(mount, req);
119 printf("Private id is: %d\n", priv_id);
120 priv_req = &mount->requests[priv_id];
121 priv_req->page = buf;
123 /* Dispatch AIO read request */
124 bzero(&priv_req->aiocb, sizeof(struct aiocb));
125 priv_req->aiocb.aio_fildes = req->u.fread.fd;
126 priv_req->aiocb.aio_nbytes = req->u.fread.len;
127 priv_req->aiocb.aio_offset = req->u.fread.offset;
128 priv_req->aiocb.aio_buf = buf;
129 assert(aio_read(&priv_req->aiocb) >= 0);
132 /* We can advance the request consumer index, from here on, the request
133 * should not be used (it may be overrinden by a response) */
134 mount->ring.req_cons++;
135 }
137 void end_file_read(struct mount *mount, struct fs_request *priv_req)
138 {
139 RING_IDX rsp_idx;
140 fsif_response_t *rsp;
141 uint16_t req_id;
143 /* Release the grant */
144 assert(xc_gnttab_munmap(mount->gnth, priv_req->page, 1) == 0);
146 /* Get a response from the ring */
147 rsp_idx = mount->ring.rsp_prod_pvt++;
148 req_id = priv_req->req_shadow.id;
149 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
150 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
151 rsp->id = req_id;
152 rsp->ret_val = (uint64_t)aio_return(&priv_req->aiocb);
153 }
155 void dispatch_file_write(struct mount *mount, struct fsif_request *req)
156 {
157 void *buf;
158 int fd;
159 uint16_t req_id;
160 unsigned short priv_id;
161 struct fs_request *priv_req;
163 /* Read the request */
164 buf = xc_gnttab_map_grant_ref(mount->gnth,
165 mount->dom_id,
166 req->u.fwrite.gref,
167 PROT_READ);
169 req_id = req->id;
170 printf("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
171 req->u.fwrite.fd, req->u.fwrite.len, req->u.fwrite.offset);
173 priv_id = get_request(mount, req);
174 printf("Private id is: %d\n", priv_id);
175 priv_req = &mount->requests[priv_id];
176 priv_req->page = buf;
178 /* Dispatch AIO write request */
179 bzero(&priv_req->aiocb, sizeof(struct aiocb));
180 priv_req->aiocb.aio_fildes = req->u.fwrite.fd;
181 priv_req->aiocb.aio_nbytes = req->u.fwrite.len;
182 priv_req->aiocb.aio_offset = req->u.fwrite.offset;
183 priv_req->aiocb.aio_buf = buf;
184 assert(aio_write(&priv_req->aiocb) >= 0);
187 /* We can advance the request consumer index, from here on, the request
188 * should not be used (it may be overrinden by a response) */
189 mount->ring.req_cons++;
190 }
192 void end_file_write(struct mount *mount, struct fs_request *priv_req)
193 {
194 RING_IDX rsp_idx;
195 fsif_response_t *rsp;
196 uint16_t req_id;
198 /* Release the grant */
199 assert(xc_gnttab_munmap(mount->gnth, priv_req->page, 1) == 0);
201 /* Get a response from the ring */
202 rsp_idx = mount->ring.rsp_prod_pvt++;
203 req_id = priv_req->req_shadow.id;
204 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
205 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
206 rsp->id = req_id;
207 rsp->ret_val = (uint64_t)aio_return(&priv_req->aiocb);
208 }
210 void dispatch_stat(struct mount *mount, struct fsif_request *req)
211 {
212 struct fsif_stat_response *buf;
213 struct stat stat;
214 int fd, ret;
215 uint16_t req_id;
216 RING_IDX rsp_idx;
217 fsif_response_t *rsp;
219 /* Read the request */
220 buf = xc_gnttab_map_grant_ref(mount->gnth,
221 mount->dom_id,
222 req->u.fstat.gref,
223 PROT_WRITE);
225 req_id = req->id;
226 fd = req->u.fstat.fd;
227 printf("File stat issued for FD=%d\n", fd);
229 /* We can advance the request consumer index, from here on, the request
230 * should not be used (it may be overrinden by a response) */
231 mount->ring.req_cons++;
233 /* Stat, and create the response */
234 ret = fstat(fd, &stat);
235 printf("Mode=%o, uid=%d, a_time=%ld\n",
236 stat.st_mode, stat.st_uid, stat.st_atime);
237 buf->stat_mode = stat.st_mode;
238 buf->stat_uid = stat.st_uid;
239 buf->stat_gid = stat.st_gid;
240 #ifdef BLKGETSIZE
241 if (S_ISBLK(stat.st_mode)) {
242 int sectors;
243 if (ioctl(fd, BLKGETSIZE, &sectors)) {
244 perror("getting device size\n");
245 buf->stat_size = 0;
246 } else
247 buf->stat_size = sectors << 9;
248 } else
249 #endif
250 buf->stat_size = stat.st_size;
251 buf->stat_atime = stat.st_atime;
252 buf->stat_mtime = stat.st_mtime;
253 buf->stat_ctime = stat.st_ctime;
255 /* Release the grant */
256 assert(xc_gnttab_munmap(mount->gnth, buf, 1) == 0);
258 /* Get a response from the ring */
259 rsp_idx = mount->ring.rsp_prod_pvt++;
260 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
261 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
262 rsp->id = req_id;
263 rsp->ret_val = (uint64_t)ret;
264 }
267 void dispatch_truncate(struct mount *mount, struct fsif_request *req)
268 {
269 int fd, ret;
270 uint16_t req_id;
271 RING_IDX rsp_idx;
272 fsif_response_t *rsp;
273 int64_t length;
275 req_id = req->id;
276 fd = req->u.ftruncate.fd;
277 length = req->u.ftruncate.length;
278 printf("File truncate issued for FD=%d, length=%"PRId64"\n", fd, length);
280 /* We can advance the request consumer index, from here on, the request
281 * should not be used (it may be overrinden by a response) */
282 mount->ring.req_cons++;
284 /* Stat, and create the response */
285 ret = ftruncate(fd, length);
287 /* Get a response from the ring */
288 rsp_idx = mount->ring.rsp_prod_pvt++;
289 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
290 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
291 rsp->id = req_id;
292 rsp->ret_val = (uint64_t)ret;
293 }
295 void dispatch_remove(struct mount *mount, struct fsif_request *req)
296 {
297 char *file_name, full_path[BUFFER_SIZE];
298 int ret;
299 RING_IDX rsp_idx;
300 fsif_response_t *rsp;
301 uint16_t req_id;
303 printf("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
304 /* Read the request, and open file */
305 file_name = xc_gnttab_map_grant_ref(mount->gnth,
306 mount->dom_id,
307 req->u.fremove.gref,
308 PROT_READ);
310 req_id = req->id;
311 printf("File remove issued for %s\n", file_name);
312 assert(BUFFER_SIZE >
313 strlen(file_name) + strlen(mount->export->export_path) + 1);
314 sprintf(full_path, "%s/%s", mount->export->export_path, file_name);
315 assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
316 printf("Issuing remove for %s\n", full_path);
317 ret = remove(full_path);
318 printf("Got ret: %d\n", ret);
319 /* We can advance the request consumer index, from here on, the request
320 * should not be used (it may be overrinden by a response) */
321 mount->ring.req_cons++;
324 /* Get a response from the ring */
325 rsp_idx = mount->ring.rsp_prod_pvt++;
326 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
327 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
328 rsp->id = req_id;
329 rsp->ret_val = (uint64_t)ret;
330 }
333 void dispatch_rename(struct mount *mount, struct fsif_request *req)
334 {
335 char *buf, *old_file_name, *new_file_name;
336 char old_full_path[BUFFER_SIZE], new_full_path[BUFFER_SIZE];
337 int ret;
338 RING_IDX rsp_idx;
339 fsif_response_t *rsp;
340 uint16_t req_id;
342 printf("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
343 /* Read the request, and open file */
344 buf = xc_gnttab_map_grant_ref(mount->gnth,
345 mount->dom_id,
346 req->u.frename.gref,
347 PROT_READ);
349 req_id = req->id;
350 old_file_name = buf + req->u.frename.old_name_offset;
351 new_file_name = buf + req->u.frename.new_name_offset;
352 printf("File rename issued for %s -> %s (buf=%s)\n",
353 old_file_name, new_file_name, buf);
354 assert(BUFFER_SIZE >
355 strlen(old_file_name) + strlen(mount->export->export_path) + 1);
356 assert(BUFFER_SIZE >
357 strlen(new_file_name) + strlen(mount->export->export_path) + 1);
358 sprintf(old_full_path, "%s/%s", mount->export->export_path, old_file_name);
359 sprintf(new_full_path, "%s/%s", mount->export->export_path, new_file_name);
360 assert(xc_gnttab_munmap(mount->gnth, buf, 1) == 0);
361 printf("Issuing rename for %s -> %s\n", old_full_path, new_full_path);
362 ret = rename(old_full_path, new_full_path);
363 printf("Got ret: %d\n", ret);
364 /* We can advance the request consumer index, from here on, the request
365 * should not be used (it may be overrinden by a response) */
366 mount->ring.req_cons++;
369 /* Get a response from the ring */
370 rsp_idx = mount->ring.rsp_prod_pvt++;
371 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
372 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
373 rsp->id = req_id;
374 rsp->ret_val = (uint64_t)ret;
375 }
378 void dispatch_create(struct mount *mount, struct fsif_request *req)
379 {
380 char *file_name, full_path[BUFFER_SIZE];
381 int ret;
382 int8_t directory;
383 int32_t mode;
384 RING_IDX rsp_idx;
385 fsif_response_t *rsp;
386 uint16_t req_id;
388 printf("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
389 /* Read the request, and create file/directory */
390 mode = req->u.fcreate.mode;
391 directory = req->u.fcreate.directory;
392 file_name = xc_gnttab_map_grant_ref(mount->gnth,
393 mount->dom_id,
394 req->u.fcreate.gref,
395 PROT_READ);
397 req_id = req->id;
398 printf("File create issued for %s\n", file_name);
399 assert(BUFFER_SIZE >
400 strlen(file_name) + strlen(mount->export->export_path) + 1);
401 sprintf(full_path, "%s/%s", mount->export->export_path, file_name);
402 assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
403 /* We can advance the request consumer index, from here on, the request
404 * should not be used (it may be overrinden by a response) */
405 mount->ring.req_cons++;
407 if(directory)
408 {
409 printf("Issuing create for directory: %s\n", full_path);
410 ret = mkdir(full_path, mode);
411 }
412 else
413 {
414 printf("Issuing create for file: %s\n", full_path);
415 ret = creat(full_path, mode);
416 }
417 printf("Got ret %d (errno=%d)\n", ret, errno);
419 /* Get a response from the ring */
420 rsp_idx = mount->ring.rsp_prod_pvt++;
421 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
422 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
423 rsp->id = req_id;
424 rsp->ret_val = (uint64_t)ret;
425 }
427 void dispatch_list(struct mount *mount, struct fsif_request *req)
428 {
429 char *file_name, *buf, full_path[BUFFER_SIZE];
430 uint32_t offset, nr_files, error_code;
431 uint64_t ret_val;
432 RING_IDX rsp_idx;
433 fsif_response_t *rsp;
434 uint16_t req_id;
435 DIR *dir;
436 struct dirent *dirent = NULL;
438 printf("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
439 /* Read the request, and list directory */
440 offset = req->u.flist.offset;
441 buf = file_name = xc_gnttab_map_grant_ref(mount->gnth,
442 mount->dom_id,
443 req->u.flist.gref,
444 PROT_READ | PROT_WRITE);
446 req_id = req->id;
447 printf("Dir list issued for %s\n", file_name);
448 assert(BUFFER_SIZE >
449 strlen(file_name) + strlen(mount->export->export_path) + 1);
450 sprintf(full_path, "%s/%s", mount->export->export_path, file_name);
451 /* We can advance the request consumer index, from here on, the request
452 * should not be used (it may be overrinden by a response) */
453 mount->ring.req_cons++;
455 ret_val = 0;
456 nr_files = 0;
457 dir = opendir(full_path);
458 if(dir == NULL)
459 {
460 error_code = errno;
461 goto error_out;
462 }
463 /* Skip offset dirs */
464 dirent = readdir(dir);
465 while(offset-- > 0 && dirent != NULL)
466 dirent = readdir(dir);
467 /* If there was any error with reading the directory, errno will be set */
468 error_code = errno;
469 /* Copy file names of the remaining non-NULL dirents into buf */
470 assert(NAME_MAX < PAGE_SIZE >> 1);
471 while(dirent != NULL &&
472 (PAGE_SIZE - ((unsigned long)buf & PAGE_MASK) > NAME_MAX))
473 {
474 int curr_length = strlen(dirent->d_name) + 1;
476 memcpy(buf, dirent->d_name, curr_length);
477 buf += curr_length;
478 dirent = readdir(dir);
479 error_code = errno;
480 nr_files++;
481 }
482 error_out:
483 ret_val = ((nr_files << NR_FILES_SHIFT) & NR_FILES_MASK) |
484 ((error_code << ERROR_SHIFT) & ERROR_MASK) |
485 (dirent != NULL ? HAS_MORE_FLAG : 0);
486 assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
488 /* Get a response from the ring */
489 rsp_idx = mount->ring.rsp_prod_pvt++;
490 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
491 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
492 rsp->id = req_id;
493 rsp->ret_val = ret_val;
494 }
496 void dispatch_chmod(struct mount *mount, struct fsif_request *req)
497 {
498 int fd, ret;
499 RING_IDX rsp_idx;
500 fsif_response_t *rsp;
501 uint16_t req_id;
502 int32_t mode;
504 printf("Dispatching file chmod operation (fd=%d, mode=%o).\n",
505 req->u.fchmod.fd, req->u.fchmod.mode);
506 req_id = req->id;
507 fd = req->u.fchmod.fd;
508 mode = req->u.fchmod.mode;
509 /* We can advance the request consumer index, from here on, the request
510 * should not be used (it may be overrinden by a response) */
511 mount->ring.req_cons++;
513 ret = fchmod(fd, mode);
515 /* Get a response from the ring */
516 rsp_idx = mount->ring.rsp_prod_pvt++;
517 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
518 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
519 rsp->id = req_id;
520 rsp->ret_val = (uint64_t)ret;
521 }
523 void dispatch_fs_space(struct mount *mount, struct fsif_request *req)
524 {
525 char *file_name, full_path[BUFFER_SIZE];
526 RING_IDX rsp_idx;
527 fsif_response_t *rsp;
528 uint16_t req_id;
529 struct statfs stat;
530 int64_t ret;
532 printf("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
533 /* Read the request, and open file */
534 file_name = xc_gnttab_map_grant_ref(mount->gnth,
535 mount->dom_id,
536 req->u.fspace.gref,
537 PROT_READ);
539 req_id = req->id;
540 printf("Fs space issued for %s\n", file_name);
541 assert(BUFFER_SIZE >
542 strlen(file_name) + strlen(mount->export->export_path) + 1);
543 sprintf(full_path, "%s/%s", mount->export->export_path, file_name);
544 assert(xc_gnttab_munmap(mount->gnth, file_name, 1) == 0);
545 printf("Issuing fs space for %s\n", full_path);
546 ret = statfs(full_path, &stat);
547 if(ret >= 0)
548 ret = stat.f_bsize * stat.f_bfree;
550 /* We can advance the request consumer index, from here on, the request
551 * should not be used (it may be overrinden by a response) */
552 mount->ring.req_cons++;
555 /* Get a response from the ring */
556 rsp_idx = mount->ring.rsp_prod_pvt++;
557 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
558 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
559 rsp->id = req_id;
560 rsp->ret_val = (uint64_t)ret;
561 }
563 void dispatch_file_sync(struct mount *mount, struct fsif_request *req)
564 {
565 int fd;
566 uint16_t req_id;
567 unsigned short priv_id;
568 struct fs_request *priv_req;
570 req_id = req->id;
571 fd = req->u.fsync.fd;
572 printf("File sync issued for FD=%d\n", fd);
574 priv_id = get_request(mount, req);
575 printf("Private id is: %d\n", priv_id);
576 priv_req = &mount->requests[priv_id];
578 /* Dispatch AIO read request */
579 bzero(&priv_req->aiocb, sizeof(struct aiocb));
580 priv_req->aiocb.aio_fildes = fd;
581 assert(aio_fsync(O_SYNC, &priv_req->aiocb) >= 0);
584 /* We can advance the request consumer index, from here on, the request
585 * should not be used (it may be overrinden by a response) */
586 mount->ring.req_cons++;
587 }
589 void end_file_sync(struct mount *mount, struct fs_request *priv_req)
590 {
591 RING_IDX rsp_idx;
592 fsif_response_t *rsp;
593 uint16_t req_id;
595 /* Get a response from the ring */
596 rsp_idx = mount->ring.rsp_prod_pvt++;
597 req_id = priv_req->req_shadow.id;
598 printf("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
599 rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
600 rsp->id = req_id;
601 rsp->ret_val = (uint64_t)aio_return(&priv_req->aiocb);
602 }
604 struct fs_op fopen_op = {.type = REQ_FILE_OPEN,
605 .dispatch_handler = dispatch_file_open,
606 .response_handler = NULL};
607 struct fs_op fclose_op = {.type = REQ_FILE_CLOSE,
608 .dispatch_handler = dispatch_file_close,
609 .response_handler = NULL};
610 struct fs_op fread_op = {.type = REQ_FILE_READ,
611 .dispatch_handler = dispatch_file_read,
612 .response_handler = end_file_read};
613 struct fs_op fwrite_op = {.type = REQ_FILE_WRITE,
614 .dispatch_handler = dispatch_file_write,
615 .response_handler = end_file_write};
616 struct fs_op fstat_op = {.type = REQ_STAT,
617 .dispatch_handler = dispatch_stat,
618 .response_handler = NULL};
619 struct fs_op ftruncate_op = {.type = REQ_FILE_TRUNCATE,
620 .dispatch_handler = dispatch_truncate,
621 .response_handler = NULL};
622 struct fs_op fremove_op = {.type = REQ_REMOVE,
623 .dispatch_handler = dispatch_remove,
624 .response_handler = NULL};
625 struct fs_op frename_op = {.type = REQ_RENAME,
626 .dispatch_handler = dispatch_rename,
627 .response_handler = NULL};
628 struct fs_op fcreate_op = {.type = REQ_CREATE,
629 .dispatch_handler = dispatch_create,
630 .response_handler = NULL};
631 struct fs_op flist_op = {.type = REQ_DIR_LIST,
632 .dispatch_handler = dispatch_list,
633 .response_handler = NULL};
634 struct fs_op fchmod_op = {.type = REQ_CHMOD,
635 .dispatch_handler = dispatch_chmod,
636 .response_handler = NULL};
637 struct fs_op fspace_op = {.type = REQ_FS_SPACE,
638 .dispatch_handler = dispatch_fs_space,
639 .response_handler = NULL};
640 struct fs_op fsync_op = {.type = REQ_FILE_SYNC,
641 .dispatch_handler = dispatch_file_sync,
642 .response_handler = end_file_sync};
645 struct fs_op *fsops[] = {&fopen_op,
646 &fclose_op,
647 &fread_op,
648 &fwrite_op,
649 &fstat_op,
650 &ftruncate_op,
651 &fremove_op,
652 &frename_op,
653 &fcreate_op,
654 &flist_op,
655 &fchmod_op,
656 &fspace_op,
657 &fsync_op,
658 NULL};