build: Remove special case for the build farm
[nivanova/samba-autobuild/.git] / source3 / modules / vfs_aio_fork.c
1 /*
2  * Simulate the Posix AIO using mmap/fork
3  *
4  * Copyright (C) Volker Lendecke 2008
5  * Copyright (C) Jeremy Allison 2010
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "system/shmem.h"
25 #include "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "lib/async_req/async_sock.h"
28 #include "lib/util/tevent_unix.h"
29
30 #undef recvmsg
31
32 #ifndef MAP_FILE
33 #define MAP_FILE 0
34 #endif
35
36 struct mmap_area {
37         size_t size;
38         volatile void *ptr;
39 };
40
41 static int mmap_area_destructor(struct mmap_area *area)
42 {
43         munmap((void *)area->ptr, area->size);
44         return 0;
45 }
46
47 static struct mmap_area *mmap_area_init(TALLOC_CTX *mem_ctx, size_t size)
48 {
49         struct mmap_area *result;
50         int fd;
51
52         result = talloc(mem_ctx, struct mmap_area);
53         if (result == NULL) {
54                 DEBUG(0, ("talloc failed\n"));
55                 goto fail;
56         }
57
58         fd = open("/dev/zero", O_RDWR);
59         if (fd == -1) {
60                 DEBUG(3, ("open(\"/dev/zero\") failed: %s\n",
61                           strerror(errno)));
62                 goto fail;
63         }
64
65         result->ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
66                            MAP_SHARED|MAP_FILE, fd, 0);
67         if (result->ptr == MAP_FAILED) {
68                 DEBUG(1, ("mmap failed: %s\n", strerror(errno)));
69                 goto fail;
70         }
71
72         close(fd);
73
74         result->size = size;
75         talloc_set_destructor(result, mmap_area_destructor);
76
77         return result;
78
79 fail:
80         TALLOC_FREE(result);
81         return NULL;
82 }
83
84 enum cmd_type {
85         READ_CMD,
86         WRITE_CMD,
87         FSYNC_CMD
88 };
89
90 static const char *cmd_type_str(enum cmd_type cmd)
91 {
92         const char *result;
93
94         switch (cmd) {
95         case READ_CMD:
96                 result = "READ";
97                 break;
98         case WRITE_CMD:
99                 result = "WRITE";
100                 break;
101         case FSYNC_CMD:
102                 result = "FSYNC";
103                 break;
104         default:
105                 result = "<UNKNOWN>";
106                 break;
107         }
108         return result;
109 }
110
111 struct rw_cmd {
112         size_t n;
113         off_t offset;
114         enum cmd_type cmd;
115 };
116
117 struct rw_ret {
118         ssize_t size;
119         int ret_errno;
120 };
121
122 struct aio_child_list;
123
124 struct aio_child {
125         struct aio_child *prev, *next;
126         struct aio_child_list *list;
127         pid_t pid;
128         int sockfd;
129         struct mmap_area *map;
130         bool dont_delete;       /* Marked as in use since last cleanup */
131         bool busy;
132 };
133
134 struct aio_child_list {
135         struct aio_child *children;
136         struct timed_event *cleanup_event;
137 };
138
139 static void free_aio_children(void **p)
140 {
141         TALLOC_FREE(*p);
142 }
143
144 static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
145 {
146         struct msghdr msg;
147         struct iovec iov[1];
148         ssize_t n;
149 #ifndef HAVE_MSGHDR_MSG_CONTROL
150         int newfd;
151 #endif
152
153 #ifdef  HAVE_MSGHDR_MSG_CONTROL
154         union {
155           struct cmsghdr        cm;
156           char                          control[CMSG_SPACE(sizeof(int))];
157         } control_un;
158         struct cmsghdr  *cmptr;
159
160         msg.msg_control = control_un.control;
161         msg.msg_controllen = sizeof(control_un.control);
162 #else
163 #if HAVE_MSGHDR_MSG_ACCTRIGHTS
164         msg.msg_accrights = (caddr_t) &newfd;
165         msg.msg_accrightslen = sizeof(int);
166 #else
167 #error Can not pass file descriptors
168 #endif
169 #endif
170
171         msg.msg_name = NULL;
172         msg.msg_namelen = 0;
173         msg.msg_flags = 0;
174
175         iov[0].iov_base = (void *)ptr;
176         iov[0].iov_len = nbytes;
177         msg.msg_iov = iov;
178         msg.msg_iovlen = 1;
179
180         if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
181                 return(n);
182         }
183
184 #ifdef  HAVE_MSGHDR_MSG_CONTROL
185         if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
186             && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
187                 if (cmptr->cmsg_level != SOL_SOCKET) {
188                         DEBUG(10, ("control level != SOL_SOCKET"));
189                         errno = EINVAL;
190                         return -1;
191                 }
192                 if (cmptr->cmsg_type != SCM_RIGHTS) {
193                         DEBUG(10, ("control type != SCM_RIGHTS"));
194                         errno = EINVAL;
195                         return -1;
196                 }
197                 memcpy(recvfd, CMSG_DATA(cmptr), sizeof(*recvfd));
198         } else {
199                 *recvfd = -1;           /* descriptor was not passed */
200         }
201 #else
202         if (msg.msg_accrightslen == sizeof(int)) {
203                 *recvfd = newfd;
204         }
205         else {
206                 *recvfd = -1;           /* descriptor was not passed */
207         }
208 #endif
209
210         return(n);
211 }
212
213 static ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
214 {
215         struct msghdr   msg;
216         struct iovec    iov[1];
217
218 #ifdef  HAVE_MSGHDR_MSG_CONTROL
219         union {
220                 struct cmsghdr  cm;
221                 char control[CMSG_SPACE(sizeof(int))];
222         } control_un;
223         struct cmsghdr  *cmptr;
224
225         ZERO_STRUCT(msg);
226         ZERO_STRUCT(control_un);
227
228         msg.msg_control = control_un.control;
229         msg.msg_controllen = sizeof(control_un.control);
230
231         cmptr = CMSG_FIRSTHDR(&msg);
232         cmptr->cmsg_len = CMSG_LEN(sizeof(int));
233         cmptr->cmsg_level = SOL_SOCKET;
234         cmptr->cmsg_type = SCM_RIGHTS;
235         memcpy(CMSG_DATA(cmptr), &sendfd, sizeof(sendfd));
236 #else
237         ZERO_STRUCT(msg);
238         msg.msg_accrights = (caddr_t) &sendfd;
239         msg.msg_accrightslen = sizeof(int);
240 #endif
241
242         msg.msg_name = NULL;
243         msg.msg_namelen = 0;
244
245         ZERO_STRUCT(iov);
246         iov[0].iov_base = (void *)ptr;
247         iov[0].iov_len = nbytes;
248         msg.msg_iov = iov;
249         msg.msg_iovlen = 1;
250
251         return (sendmsg(fd, &msg, 0));
252 }
253
254 static void aio_child_cleanup(struct event_context *event_ctx,
255                               struct timed_event *te,
256                               struct timeval now,
257                               void *private_data)
258 {
259         struct aio_child_list *list = talloc_get_type_abort(
260                 private_data, struct aio_child_list);
261         struct aio_child *child, *next;
262
263         TALLOC_FREE(list->cleanup_event);
264
265         for (child = list->children; child != NULL; child = next) {
266                 next = child->next;
267
268                 if (child->busy) {
269                         DEBUG(10, ("child %d currently active\n",
270                                    (int)child->pid));
271                         continue;
272                 }
273
274                 if (child->dont_delete) {
275                         DEBUG(10, ("Child %d was active since last cleanup\n",
276                                    (int)child->pid));
277                         child->dont_delete = false;
278                         continue;
279                 }
280
281                 DEBUG(10, ("Child %d idle for more than 30 seconds, "
282                            "deleting\n", (int)child->pid));
283
284                 TALLOC_FREE(child);
285                 child = next;
286         }
287
288         if (list->children != NULL) {
289                 /*
290                  * Re-schedule the next cleanup round
291                  */
292                 list->cleanup_event = event_add_timed(server_event_context(), list,
293                                                       timeval_add(&now, 30, 0),
294                                                       aio_child_cleanup, list);
295
296         }
297 }
298
299 static struct aio_child_list *init_aio_children(struct vfs_handle_struct *handle)
300 {
301         struct aio_child_list *data = NULL;
302
303         if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
304                 SMB_VFS_HANDLE_GET_DATA(handle, data, struct aio_child_list,
305                                         return NULL);
306         }
307
308         if (data == NULL) {
309                 data = talloc_zero(NULL, struct aio_child_list);
310                 if (data == NULL) {
311                         return NULL;
312                 }
313         }
314
315         /*
316          * Regardless of whether the child_list had been around or not, make
317          * sure that we have a cleanup timed event. This timed event will
318          * delete itself when it finds that no children are around anymore.
319          */
320
321         if (data->cleanup_event == NULL) {
322                 data->cleanup_event = event_add_timed(server_event_context(), data,
323                                                       timeval_current_ofs(30, 0),
324                                                       aio_child_cleanup, data);
325                 if (data->cleanup_event == NULL) {
326                         TALLOC_FREE(data);
327                         return NULL;
328                 }
329         }
330
331         if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
332                 SMB_VFS_HANDLE_SET_DATA(handle, data, free_aio_children,
333                                         struct aio_child_list, return False);
334         }
335
336         return data;
337 }
338
339 static void aio_child_loop(int sockfd, struct mmap_area *map)
340 {
341         while (true) {
342                 int fd = -1;
343                 ssize_t ret;
344                 struct rw_cmd cmd_struct;
345                 struct rw_ret ret_struct;
346
347                 ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
348                 if (ret != sizeof(cmd_struct)) {
349                         DEBUG(10, ("read_fd returned %d: %s\n", (int)ret,
350                                    strerror(errno)));
351                         exit(1);
352                 }
353
354                 DEBUG(10, ("aio_child_loop: %s %d bytes at %d from fd %d\n",
355                            cmd_type_str(cmd_struct.cmd),
356                            (int)cmd_struct.n, (int)cmd_struct.offset, fd));
357
358 #ifdef DEVELOPER
359                 {
360                         /*
361                          * For developer testing, we want erratic behaviour for
362                          * async I/O times
363                          */
364                         uint8_t randval;
365                         unsigned msecs;
366                         /*
367                          * use generate_random_buffer, we just forked from a
368                          * common parent state
369                          */
370                         generate_random_buffer(&randval, sizeof(randval));
371                         msecs = randval + 20;
372                         DEBUG(10, ("delaying for %u msecs\n", msecs));
373                         smb_msleep(msecs);
374                 }
375 #endif
376
377
378                 ZERO_STRUCT(ret_struct);
379
380                 switch (cmd_struct.cmd) {
381                 case READ_CMD:
382                         ret_struct.size = sys_pread(
383                                 fd, (void *)map->ptr, cmd_struct.n,
384                                 cmd_struct.offset);
385 #if 0
386 /* This breaks "make test" when run with aio_fork module. */
387 #ifdef DEVELOPER
388                         ret_struct.size = MAX(1, ret_struct.size * 0.9);
389 #endif
390 #endif
391                         break;
392                 case WRITE_CMD:
393                         ret_struct.size = sys_pwrite(
394                                 fd, (void *)map->ptr, cmd_struct.n,
395                                 cmd_struct.offset);
396                         break;
397                 case FSYNC_CMD:
398                         ret_struct.size = fsync(fd);
399                         break;
400                 default:
401                         ret_struct.size = -1;
402                         errno = EINVAL;
403                 }
404
405                 DEBUG(10, ("aio_child_loop: syscall returned %d\n",
406                            (int)ret_struct.size));
407
408                 if (ret_struct.size == -1) {
409                         ret_struct.ret_errno = errno;
410                 }
411
412                 /*
413                  * Close the fd before telling our parent we're done. The
414                  * parent might close and re-open the file very quickly, and
415                  * with system-level share modes (GPFS) we would get an
416                  * unjustified SHARING_VIOLATION.
417                  */
418                 close(fd);
419
420                 ret = write_data(sockfd, (char *)&ret_struct,
421                                  sizeof(ret_struct));
422                 if (ret != sizeof(ret_struct)) {
423                         DEBUG(10, ("could not write ret_struct: %s\n",
424                                    strerror(errno)));
425                         exit(2);
426                 }
427         }
428 }
429
430 static int aio_child_destructor(struct aio_child *child)
431 {
432         char c=0;
433
434         SMB_ASSERT(!child->busy);
435
436         DEBUG(10, ("aio_child_destructor: removing child %d on fd %d\n",
437                         child->pid, child->sockfd));
438
439         /*
440          * closing the sockfd makes the child not return from recvmsg() on RHEL
441          * 5.5 so instead force the child to exit by writing bad data to it
442          */
443         write(child->sockfd, &c, sizeof(c));
444         close(child->sockfd);
445         DLIST_REMOVE(child->list->children, child);
446         return 0;
447 }
448
449 /*
450  * We have to close all fd's in open files, we might incorrectly hold a system
451  * level share mode on a file.
452  */
453
454 static struct files_struct *close_fsp_fd(struct files_struct *fsp,
455                                          void *private_data)
456 {
457         if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
458                 close(fsp->fh->fd);
459                 fsp->fh->fd = -1;
460         }
461         return NULL;
462 }
463
464 static int create_aio_child(struct smbd_server_connection *sconn,
465                             struct aio_child_list *children,
466                             size_t map_size,
467                             struct aio_child **presult)
468 {
469         struct aio_child *result;
470         int fdpair[2];
471         int ret;
472
473         fdpair[0] = fdpair[1] = -1;
474
475         result = talloc_zero(children, struct aio_child);
476         if (result == NULL) {
477                 return ENOMEM;
478         }
479
480         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
481                 ret = errno;
482                 DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
483                 goto fail;
484         }
485
486         DEBUG(10, ("fdpair = %d/%d\n", fdpair[0], fdpair[1]));
487
488         result->map = mmap_area_init(result, map_size);
489         if (result->map == NULL) {
490                 ret = errno;
491                 DEBUG(0, ("Could not create mmap area\n"));
492                 goto fail;
493         }
494
495         result->pid = fork();
496         if (result->pid == -1) {
497                 ret = errno;
498                 DEBUG(0, ("fork failed: %s\n", strerror(errno)));
499                 goto fail;
500         }
501
502         if (result->pid == 0) {
503                 close(fdpair[0]);
504                 result->sockfd = fdpair[1];
505                 files_forall(sconn, close_fsp_fd, NULL);
506                 aio_child_loop(result->sockfd, result->map);
507         }
508
509         DEBUG(10, ("Child %d created with sockfd %d\n",
510                         result->pid, fdpair[0]));
511
512         result->sockfd = fdpair[0];
513         close(fdpair[1]);
514
515         result->list = children;
516         DLIST_ADD(children->children, result);
517
518         talloc_set_destructor(result, aio_child_destructor);
519
520         *presult = result;
521
522         return 0;
523
524  fail:
525         if (fdpair[0] != -1) close(fdpair[0]);
526         if (fdpair[1] != -1) close(fdpair[1]);
527         TALLOC_FREE(result);
528
529         return ret;
530 }
531
532 static int get_idle_child(struct vfs_handle_struct *handle,
533                           struct aio_child **pchild)
534 {
535         struct aio_child_list *children;
536         struct aio_child *child;
537
538         children = init_aio_children(handle);
539         if (children == NULL) {
540                 return ENOMEM;
541         }
542
543         for (child = children->children; child != NULL; child = child->next) {
544                 if (!child->busy) {
545                         break;
546                 }
547         }
548
549         if (child == NULL) {
550                 int ret;
551
552                 DEBUG(10, ("no idle child found, creating new one\n"));
553
554                 ret = create_aio_child(handle->conn->sconn, children,
555                                           128*1024, &child);
556                 if (ret != 0) {
557                         DEBUG(10, ("create_aio_child failed: %s\n",
558                                    strerror(errno)));
559                         return ret;
560                 }
561         }
562
563         child->dont_delete = true;
564         child->busy = true;
565
566         *pchild = child;
567         return 0;
568 }
569
570 struct aio_fork_pread_state {
571         struct aio_child *child;
572         ssize_t ret;
573         int err;
574 };
575
576 static void aio_fork_pread_done(struct tevent_req *subreq);
577
578 static struct tevent_req *aio_fork_pread_send(struct vfs_handle_struct *handle,
579                                               TALLOC_CTX *mem_ctx,
580                                               struct tevent_context *ev,
581                                               struct files_struct *fsp,
582                                               void *data,
583                                               size_t n, off_t offset)
584 {
585         struct tevent_req *req, *subreq;
586         struct aio_fork_pread_state *state;
587         struct rw_cmd cmd;
588         ssize_t written;
589         int err;
590
591         req = tevent_req_create(mem_ctx, &state, struct aio_fork_pread_state);
592         if (req == NULL) {
593                 return NULL;
594         }
595
596         if (n > 128*1024) {
597                 /* TODO: support variable buffers */
598                 tevent_req_error(req, EINVAL);
599                 return tevent_req_post(req, ev);
600         }
601
602         err = get_idle_child(handle, &state->child);
603         if (err != 0) {
604                 tevent_req_error(req, err);
605                 return tevent_req_post(req, ev);
606         }
607
608         ZERO_STRUCT(cmd);
609         cmd.n = n;
610         cmd.offset = offset;
611         cmd.cmd = READ_CMD;
612
613         DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
614                    (int)state->child->pid));
615
616         /*
617          * Not making this async. We're writing into an empty unix
618          * domain socket. This should never block.
619          */
620         written = write_fd(state->child->sockfd, &cmd, sizeof(cmd),
621                            fsp->fh->fd);
622         if (written == -1) {
623                 err = errno;
624
625                 TALLOC_FREE(state->child);
626
627                 DEBUG(10, ("write_fd failed: %s\n", strerror(err)));
628                 tevent_req_error(req, err);
629                 return tevent_req_post(req, ev);
630         }
631
632         subreq = read_packet_send(state, ev, state->child->sockfd,
633                                   sizeof(struct rw_ret), NULL, NULL);
634         if (tevent_req_nomem(subreq, req)) {
635                 TALLOC_FREE(state->child); /* we sent sth down */
636                 return tevent_req_post(req, ev);
637         }
638         tevent_req_set_callback(subreq, aio_fork_pread_done, req);
639         return req;
640 }
641
642 static void aio_fork_pread_done(struct tevent_req *subreq)
643 {
644         struct tevent_req *req = tevent_req_callback_data(
645                 subreq, struct tevent_req);
646         struct aio_fork_pread_state *state = tevent_req_data(
647                 req, struct aio_fork_pread_state);
648         ssize_t nread;
649         uint8_t *buf;
650         int err;
651         struct rw_ret *retbuf;
652
653         nread = read_packet_recv(subreq, talloc_tos(), &buf, &err);
654         TALLOC_FREE(subreq);
655         if (nread == -1) {
656                 TALLOC_FREE(state->child);
657                 tevent_req_error(req, err);
658                 return;
659         }
660
661         state->child->busy = false;
662
663         retbuf = (struct rw_ret *)buf;
664         state->ret = retbuf->size;
665         state->err = retbuf->ret_errno;
666         tevent_req_done(req);
667 }
668
669 static ssize_t aio_fork_pread_recv(struct tevent_req *req, int *err)
670 {
671         struct aio_fork_pread_state *state = tevent_req_data(
672                 req, struct aio_fork_pread_state);
673
674         if (tevent_req_is_unix_error(req, err)) {
675                 return -1;
676         }
677         if (state->ret == -1) {
678                 *err = state->err;
679         }
680         return state->ret;
681 }
682
683 struct aio_fork_pwrite_state {
684         struct aio_child *child;
685         ssize_t ret;
686         int err;
687 };
688
689 static void aio_fork_pwrite_done(struct tevent_req *subreq);
690
691 static struct tevent_req *aio_fork_pwrite_send(
692         struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
693         struct tevent_context *ev, struct files_struct *fsp,
694         const void *data, size_t n, off_t offset)
695 {
696         struct tevent_req *req, *subreq;
697         struct aio_fork_pwrite_state *state;
698         struct rw_cmd cmd;
699         ssize_t written;
700         int err;
701
702         req = tevent_req_create(mem_ctx, &state, struct aio_fork_pwrite_state);
703         if (req == NULL) {
704                 return NULL;
705         }
706
707         if (n > 128*1024) {
708                 /* TODO: support variable buffers */
709                 tevent_req_error(req, EINVAL);
710                 return tevent_req_post(req, ev);
711         }
712
713         err = get_idle_child(handle, &state->child);
714         if (err != 0) {
715                 tevent_req_error(req, err);
716                 return tevent_req_post(req, ev);
717         }
718
719         ZERO_STRUCT(cmd);
720         cmd.n = n;
721         cmd.offset = offset;
722         cmd.cmd = WRITE_CMD;
723
724         DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
725                    (int)state->child->pid));
726
727         /*
728          * Not making this async. We're writing into an empty unix
729          * domain socket. This should never block.
730          */
731         written = write_fd(state->child->sockfd, &cmd, sizeof(cmd),
732                            fsp->fh->fd);
733         if (written == -1) {
734                 err = errno;
735
736                 TALLOC_FREE(state->child);
737
738                 DEBUG(10, ("write_fd failed: %s\n", strerror(err)));
739                 tevent_req_error(req, err);
740                 return tevent_req_post(req, ev);
741         }
742
743         subreq = read_packet_send(state, ev, state->child->sockfd,
744                                   sizeof(struct rw_ret), NULL, NULL);
745         if (tevent_req_nomem(subreq, req)) {
746                 TALLOC_FREE(state->child); /* we sent sth down */
747                 return tevent_req_post(req, ev);
748         }
749         tevent_req_set_callback(subreq, aio_fork_pwrite_done, req);
750         return req;
751 }
752
753 static void aio_fork_pwrite_done(struct tevent_req *subreq)
754 {
755         struct tevent_req *req = tevent_req_callback_data(
756                 subreq, struct tevent_req);
757         struct aio_fork_pwrite_state *state = tevent_req_data(
758                 req, struct aio_fork_pwrite_state);
759         ssize_t nread;
760         uint8_t *buf;
761         int err;
762         struct rw_ret *retbuf;
763
764         nread = read_packet_recv(subreq, talloc_tos(), &buf, &err);
765         TALLOC_FREE(subreq);
766         if (nread == -1) {
767                 TALLOC_FREE(state->child);
768                 tevent_req_error(req, err);
769                 return;
770         }
771
772         state->child->busy = false;
773
774         retbuf = (struct rw_ret *)buf;
775         state->ret = retbuf->size;
776         state->err = retbuf->ret_errno;
777         tevent_req_done(req);
778 }
779
780 static ssize_t aio_fork_pwrite_recv(struct tevent_req *req, int *err)
781 {
782         struct aio_fork_pwrite_state *state = tevent_req_data(
783                 req, struct aio_fork_pwrite_state);
784
785         if (tevent_req_is_unix_error(req, err)) {
786                 return -1;
787         }
788         if (state->ret == -1) {
789                 *err = state->err;
790         }
791         return state->ret;
792 }
793
794 struct aio_fork_fsync_state {
795         struct aio_child *child;
796         ssize_t ret;
797         int err;
798 };
799
800 static void aio_fork_fsync_done(struct tevent_req *subreq);
801
802 static struct tevent_req *aio_fork_fsync_send(
803         struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
804         struct tevent_context *ev, struct files_struct *fsp)
805 {
806         struct tevent_req *req, *subreq;
807         struct aio_fork_fsync_state *state;
808         struct rw_cmd cmd;
809         ssize_t written;
810         int err;
811
812         req = tevent_req_create(mem_ctx, &state, struct aio_fork_fsync_state);
813         if (req == NULL) {
814                 return NULL;
815         }
816
817         err = get_idle_child(handle, &state->child);
818         if (err != 0) {
819                 tevent_req_error(req, err);
820                 return tevent_req_post(req, ev);
821         }
822
823         ZERO_STRUCT(cmd);
824         cmd.cmd = FSYNC_CMD;
825
826         DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
827                    (int)state->child->pid));
828
829         /*
830          * Not making this async. We're writing into an empty unix
831          * domain socket. This should never block.
832          */
833         written = write_fd(state->child->sockfd, &cmd, sizeof(cmd),
834                            fsp->fh->fd);
835         if (written == -1) {
836                 err = errno;
837
838                 TALLOC_FREE(state->child);
839
840                 DEBUG(10, ("write_fd failed: %s\n", strerror(err)));
841                 tevent_req_error(req, err);
842                 return tevent_req_post(req, ev);
843         }
844
845         subreq = read_packet_send(state, ev, state->child->sockfd,
846                                   sizeof(struct rw_ret), NULL, NULL);
847         if (tevent_req_nomem(subreq, req)) {
848                 TALLOC_FREE(state->child); /* we sent sth down */
849                 return tevent_req_post(req, ev);
850         }
851         tevent_req_set_callback(subreq, aio_fork_fsync_done, req);
852         return req;
853 }
854
855 static void aio_fork_fsync_done(struct tevent_req *subreq)
856 {
857         struct tevent_req *req = tevent_req_callback_data(
858                 subreq, struct tevent_req);
859         struct aio_fork_fsync_state *state = tevent_req_data(
860                 req, struct aio_fork_fsync_state);
861         ssize_t nread;
862         uint8_t *buf;
863         int err;
864         struct rw_ret *retbuf;
865
866         nread = read_packet_recv(subreq, talloc_tos(), &buf, &err);
867         TALLOC_FREE(subreq);
868         if (nread == -1) {
869                 TALLOC_FREE(state->child);
870                 tevent_req_error(req, err);
871                 return;
872         }
873
874         state->child->busy = false;
875
876         retbuf = (struct rw_ret *)buf;
877         state->ret = retbuf->size;
878         state->err = retbuf->ret_errno;
879         tevent_req_done(req);
880 }
881
882 static int aio_fork_fsync_recv(struct tevent_req *req, int *err)
883 {
884         struct aio_fork_fsync_state *state = tevent_req_data(
885                 req, struct aio_fork_fsync_state);
886
887         if (tevent_req_is_unix_error(req, err)) {
888                 return -1;
889         }
890         if (state->ret == -1) {
891                 *err = state->err;
892         }
893         return state->ret;
894 }
895
896 static int aio_fork_connect(vfs_handle_struct *handle, const char *service,
897                             const char *user)
898 {
899         /*********************************************************************
900          * How many threads to initialize ?
901          * 100 per process seems insane as a default until you realize that
902          * (a) Threads terminate after 1 second when idle.
903          * (b) Throttling is done in SMB2 via the crediting algorithm.
904          * (c) SMB1 clients are limited to max_mux (50) outstanding
905          *     requests and Windows clients don't use this anyway.
906          * Essentially we want this to be unlimited unless smb.conf
907          * says different.
908          *********************************************************************/
909         aio_pending_size = 100;
910         return SMB_VFS_NEXT_CONNECT(handle, service, user);
911 }
912
913 static struct vfs_fn_pointers vfs_aio_fork_fns = {
914         .connect_fn = aio_fork_connect,
915         .pread_send_fn = aio_fork_pread_send,
916         .pread_recv_fn = aio_fork_pread_recv,
917         .pwrite_send_fn = aio_fork_pwrite_send,
918         .pwrite_recv_fn = aio_fork_pwrite_recv,
919         .fsync_send_fn = aio_fork_fsync_send,
920         .fsync_recv_fn = aio_fork_fsync_recv,
921 };
922
923 NTSTATUS vfs_aio_fork_init(void);
924 NTSTATUS vfs_aio_fork_init(void)
925 {
926         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
927                                 "aio_fork", &vfs_aio_fork_fns);
928 }