s3-includes: only include system/shmem.h when needed.
[samba.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/shmem.h"
24
25 struct mmap_area {
26         size_t size;
27         volatile void *ptr;
28 };
29
30 static int mmap_area_destructor(struct mmap_area *area)
31 {
32         munmap((void *)area->ptr, area->size);
33         return 0;
34 }
35
36 static struct mmap_area *mmap_area_init(TALLOC_CTX *mem_ctx, size_t size)
37 {
38         struct mmap_area *result;
39         int fd;
40
41         result = talloc(mem_ctx, struct mmap_area);
42         if (result == NULL) {
43                 DEBUG(0, ("talloc failed\n"));
44                 goto fail;
45         }
46
47         fd = open("/dev/zero", O_RDWR);
48         if (fd == -1) {
49                 DEBUG(3, ("open(\"/dev/zero\") failed: %s\n",
50                           strerror(errno)));
51                 goto fail;
52         }
53
54         result->ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
55                            MAP_SHARED|MAP_FILE, fd, 0);
56         if (result->ptr == MAP_FAILED) {
57                 DEBUG(1, ("mmap failed: %s\n", strerror(errno)));
58                 goto fail;
59         }
60
61         close(fd);
62
63         result->size = size;
64         talloc_set_destructor(result, mmap_area_destructor);
65
66         return result;
67
68 fail:
69         TALLOC_FREE(result);
70         return NULL;
71 }
72
73 struct rw_cmd {
74         size_t n;
75         SMB_OFF_T offset;
76         bool read_cmd;
77 };
78
79 struct rw_ret {
80         ssize_t size;
81         int ret_errno;
82 };
83
84 struct aio_child_list;
85
86 struct aio_child {
87         struct aio_child *prev, *next;
88         struct aio_child_list *list;
89         SMB_STRUCT_AIOCB *aiocb;
90         pid_t pid;
91         int sockfd;
92         struct fd_event *sock_event;
93         struct rw_ret retval;
94         struct mmap_area *map;  /* ==NULL means write request */
95         bool dont_delete;       /* Marked as in use since last cleanup */
96         bool cancelled;
97         bool read_cmd;
98 };
99
100 struct aio_child_list {
101         struct aio_child *children;
102         struct timed_event *cleanup_event;
103 };
104
105 static void free_aio_children(void **p)
106 {
107         TALLOC_FREE(*p);
108 }
109
110 static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
111 {
112         struct msghdr msg;
113         struct iovec iov[1];
114         ssize_t n;
115 #ifndef HAVE_MSGHDR_MSG_CONTROL
116         int newfd;
117 #endif
118
119 #ifdef  HAVE_MSGHDR_MSG_CONTROL
120         union {
121           struct cmsghdr        cm;
122           char                          control[CMSG_SPACE(sizeof(int))];
123         } control_un;
124         struct cmsghdr  *cmptr;
125
126         msg.msg_control = control_un.control;
127         msg.msg_controllen = sizeof(control_un.control);
128 #else
129 #if HAVE_MSGHDR_MSG_ACCTRIGHTS
130         msg.msg_accrights = (caddr_t) &newfd;
131         msg.msg_accrightslen = sizeof(int);
132 #else
133 #error Can not pass file descriptors
134 #endif
135 #endif
136
137         msg.msg_name = NULL;
138         msg.msg_namelen = 0;
139
140         iov[0].iov_base = (void *)ptr;
141         iov[0].iov_len = nbytes;
142         msg.msg_iov = iov;
143         msg.msg_iovlen = 1;
144
145         if ( (n = recvmsg(fd, &msg, 0)) <= 0) {
146                 return(n);
147         }
148
149 #ifdef  HAVE_MSGHDR_MSG_CONTROL
150         if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
151             && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
152                 if (cmptr->cmsg_level != SOL_SOCKET) {
153                         DEBUG(10, ("control level != SOL_SOCKET"));
154                         errno = EINVAL;
155                         return -1;
156                 }
157                 if (cmptr->cmsg_type != SCM_RIGHTS) {
158                         DEBUG(10, ("control type != SCM_RIGHTS"));
159                         errno = EINVAL;
160                         return -1;
161                 }
162                 *recvfd = *((int *) CMSG_DATA(cmptr));
163         } else {
164                 *recvfd = -1;           /* descriptor was not passed */
165         }
166 #else
167         if (msg.msg_accrightslen == sizeof(int)) {
168                 *recvfd = newfd;
169         }
170         else {
171                 *recvfd = -1;           /* descriptor was not passed */
172         }
173 #endif
174
175         return(n);
176 }
177
178 static ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
179 {
180         struct msghdr   msg;
181         struct iovec    iov[1];
182
183 #ifdef  HAVE_MSGHDR_MSG_CONTROL
184         union {
185                 struct cmsghdr  cm;
186                 char control[CMSG_SPACE(sizeof(int))];
187         } control_un;
188         struct cmsghdr  *cmptr;
189
190         ZERO_STRUCT(msg);
191         ZERO_STRUCT(control_un);
192
193         msg.msg_control = control_un.control;
194         msg.msg_controllen = sizeof(control_un.control);
195
196         cmptr = CMSG_FIRSTHDR(&msg);
197         cmptr->cmsg_len = CMSG_LEN(sizeof(int));
198         cmptr->cmsg_level = SOL_SOCKET;
199         cmptr->cmsg_type = SCM_RIGHTS;
200         *((int *) CMSG_DATA(cmptr)) = sendfd;
201 #else
202         ZERO_STRUCT(msg);
203         msg.msg_accrights = (caddr_t) &sendfd;
204         msg.msg_accrightslen = sizeof(int);
205 #endif
206
207         msg.msg_name = NULL;
208         msg.msg_namelen = 0;
209
210         ZERO_STRUCT(iov);
211         iov[0].iov_base = (void *)ptr;
212         iov[0].iov_len = nbytes;
213         msg.msg_iov = iov;
214         msg.msg_iovlen = 1;
215
216         return (sendmsg(fd, &msg, 0));
217 }
218
219 static void aio_child_cleanup(struct event_context *event_ctx,
220                               struct timed_event *te,
221                               struct timeval now,
222                               void *private_data)
223 {
224         struct aio_child_list *list = talloc_get_type_abort(
225                 private_data, struct aio_child_list);
226         struct aio_child *child, *next;
227
228         TALLOC_FREE(list->cleanup_event);
229
230         for (child = list->children; child != NULL; child = next) {
231                 next = child->next;
232
233                 if (child->aiocb != NULL) {
234                         DEBUG(10, ("child %d currently active\n",
235                                    (int)child->pid));
236                         continue;
237                 }
238
239                 if (child->dont_delete) {
240                         DEBUG(10, ("Child %d was active since last cleanup\n",
241                                    (int)child->pid));
242                         child->dont_delete = false;
243                         continue;
244                 }
245
246                 DEBUG(10, ("Child %d idle for more than 30 seconds, "
247                            "deleting\n", (int)child->pid));
248
249                 TALLOC_FREE(child);
250                 child = next;
251         }
252
253         if (list->children != NULL) {
254                 /*
255                  * Re-schedule the next cleanup round
256                  */
257                 list->cleanup_event = event_add_timed(smbd_event_context(), list,
258                                                       timeval_add(&now, 30, 0),
259                                                       aio_child_cleanup, list);
260
261         }
262 }
263
264 static struct aio_child_list *init_aio_children(struct vfs_handle_struct *handle)
265 {
266         struct aio_child_list *data = NULL;
267
268         if (SMB_VFS_HANDLE_TEST_DATA(handle)) {
269                 SMB_VFS_HANDLE_GET_DATA(handle, data, struct aio_child_list,
270                                         return NULL);
271         }
272
273         if (data == NULL) {
274                 data = TALLOC_ZERO_P(NULL, struct aio_child_list);
275                 if (data == NULL) {
276                         return NULL;
277                 }
278         }
279
280         /*
281          * Regardless of whether the child_list had been around or not, make
282          * sure that we have a cleanup timed event. This timed event will
283          * delete itself when it finds that no children are around anymore.
284          */
285
286         if (data->cleanup_event == NULL) {
287                 data->cleanup_event = event_add_timed(smbd_event_context(), data,
288                                                       timeval_current_ofs(30, 0),
289                                                       aio_child_cleanup, data);
290                 if (data->cleanup_event == NULL) {
291                         TALLOC_FREE(data);
292                         return NULL;
293                 }
294         }
295
296         if (!SMB_VFS_HANDLE_TEST_DATA(handle)) {
297                 SMB_VFS_HANDLE_SET_DATA(handle, data, free_aio_children,
298                                         struct aio_child_list, return False);
299         }
300
301         return data;
302 }
303
304 static void aio_child_loop(int sockfd, struct mmap_area *map)
305 {
306         while (true) {
307                 int fd = -1;
308                 ssize_t ret;
309                 struct rw_cmd cmd_struct;
310                 struct rw_ret ret_struct;
311
312                 ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
313                 if (ret != sizeof(cmd_struct)) {
314                         DEBUG(10, ("read_fd returned %d: %s\n", (int)ret,
315                                    strerror(errno)));
316                         exit(1);
317                 }
318
319                 DEBUG(10, ("aio_child_loop: %s %d bytes at %d from fd %d\n",
320                            cmd_struct.read_cmd ? "read" : "write",
321                            (int)cmd_struct.n, (int)cmd_struct.offset, fd));
322
323 #ifdef ENABLE_BUILD_FARM_HACKS
324                 {
325                         /*
326                          * In the build farm, we want erratic behaviour for
327                          * async I/O times
328                          */
329                         uint8_t randval;
330                         unsigned msecs;
331                         /*
332                          * use generate_random_buffer, we just forked from a
333                          * common parent state
334                          */
335                         generate_random_buffer(&randval, sizeof(randval));
336                         msecs = randval + 20;
337                         DEBUG(10, ("delaying for %u msecs\n", msecs));
338                         smb_msleep(msecs);
339                 }
340 #endif
341
342
343                 ZERO_STRUCT(ret_struct);
344
345                 if (cmd_struct.read_cmd) {
346                         ret_struct.size = sys_pread(
347                                 fd, (void *)map->ptr, cmd_struct.n,
348                                 cmd_struct.offset);
349 #if 0
350 /* This breaks "make test" when run with aio_fork module. */
351 #ifdef ENABLE_BUILD_FARM_HACKS
352                         ret_struct.size = MAX(1, ret_struct.size * 0.9);
353 #endif
354 #endif
355                 }
356                 else {
357                         ret_struct.size = sys_pwrite(
358                                 fd, (void *)map->ptr, cmd_struct.n,
359                                 cmd_struct.offset);
360                 }
361
362                 DEBUG(10, ("aio_child_loop: syscall returned %d\n",
363                            (int)ret_struct.size));
364
365                 if (ret_struct.size == -1) {
366                         ret_struct.ret_errno = errno;
367                 }
368
369                 /*
370                  * Close the fd before telling our parent we're done. The
371                  * parent might close and re-open the file very quickly, and
372                  * with system-level share modes (GPFS) we would get an
373                  * unjustified SHARING_VIOLATION.
374                  */
375                 close(fd);
376
377                 ret = write_data(sockfd, (char *)&ret_struct,
378                                  sizeof(ret_struct));
379                 if (ret != sizeof(ret_struct)) {
380                         DEBUG(10, ("could not write ret_struct: %s\n",
381                                    strerror(errno)));
382                         exit(2);
383                 }
384         }
385 }
386
387 static void handle_aio_completion(struct event_context *event_ctx,
388                                   struct fd_event *event, uint16 flags,
389                                   void *p)
390 {
391         struct aio_extra *aio_ex = NULL;
392         struct aio_child *child = (struct aio_child *)p;
393         NTSTATUS status;
394
395         DEBUG(10, ("handle_aio_completion called with flags=%d\n", flags));
396
397         if ((flags & EVENT_FD_READ) == 0) {
398                 return;
399         }
400
401         status = read_data(child->sockfd, (char *)&child->retval,
402                            sizeof(child->retval));
403
404         if (!NT_STATUS_IS_OK(status)) {
405                 DEBUG(1, ("aio child %d died: %s\n", (int)child->pid,
406                           nt_errstr(status)));
407                 child->retval.size = -1;
408                 child->retval.ret_errno = EIO;
409         }
410
411         if (child->aiocb == NULL) {
412                 DEBUG(1, ("Inactive child died\n"));
413                 TALLOC_FREE(child);
414                 return;
415         }
416
417         if (child->cancelled) {
418                 child->aiocb = NULL;
419                 child->cancelled = false;
420                 return;
421         }
422
423         if (child->read_cmd && (child->retval.size > 0)) {
424                 SMB_ASSERT(child->retval.size <= child->aiocb->aio_nbytes);
425                 memcpy((void *)child->aiocb->aio_buf, (void *)child->map->ptr,
426                        child->retval.size);
427         }
428
429         aio_ex = (struct aio_extra *)child->aiocb->aio_sigevent.sigev_value.sival_ptr;
430         smbd_aio_complete_aio_ex(aio_ex);
431 }
432
433 static int aio_child_destructor(struct aio_child *child)
434 {
435         char c=0;
436
437         SMB_ASSERT((child->aiocb == NULL) || child->cancelled);
438
439         DEBUG(10, ("aio_child_destructor: removing child %d on fd %d\n",
440                         child->pid, child->sockfd));
441
442         /*
443          * closing the sockfd makes the child not return from recvmsg() on RHEL
444          * 5.5 so instead force the child to exit by writing bad data to it
445          */
446         write(child->sockfd, &c, sizeof(c));
447         close(child->sockfd);
448         DLIST_REMOVE(child->list->children, child);
449         return 0;
450 }
451
452 /*
453  * We have to close all fd's in open files, we might incorrectly hold a system
454  * level share mode on a file.
455  */
456
457 static struct files_struct *close_fsp_fd(struct files_struct *fsp,
458                                          void *private_data)
459 {
460         if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
461                 close(fsp->fh->fd);
462                 fsp->fh->fd = -1;
463         }
464         return NULL;
465 }
466
467 static NTSTATUS create_aio_child(struct smbd_server_connection *sconn,
468                                  struct aio_child_list *children,
469                                  size_t map_size,
470                                  struct aio_child **presult)
471 {
472         struct aio_child *result;
473         int fdpair[2];
474         NTSTATUS status;
475
476         fdpair[0] = fdpair[1] = -1;
477
478         result = TALLOC_ZERO_P(children, struct aio_child);
479         NT_STATUS_HAVE_NO_MEMORY(result);
480
481         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
482                 status = map_nt_error_from_unix(errno);
483                 DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
484                 goto fail;
485         }
486
487         DEBUG(10, ("fdpair = %d/%d\n", fdpair[0], fdpair[1]));
488
489         result->map = mmap_area_init(result, map_size);
490         if (result->map == NULL) {
491                 status = map_nt_error_from_unix(errno);
492                 DEBUG(0, ("Could not create mmap area\n"));
493                 goto fail;
494         }
495
496         result->pid = sys_fork();
497         if (result->pid == -1) {
498                 status = map_nt_error_from_unix(errno);
499                 DEBUG(0, ("fork failed: %s\n", strerror(errno)));
500                 goto fail;
501         }
502
503         if (result->pid == 0) {
504                 close(fdpair[0]);
505                 result->sockfd = fdpair[1];
506                 files_forall(sconn, close_fsp_fd, NULL);
507                 aio_child_loop(result->sockfd, result->map);
508         }
509
510         DEBUG(10, ("Child %d created with sockfd %d\n",
511                         result->pid, fdpair[0]));
512
513         result->sockfd = fdpair[0];
514         close(fdpair[1]);
515
516         result->sock_event = event_add_fd(smbd_event_context(), result,
517                                           result->sockfd, EVENT_FD_READ,
518                                           handle_aio_completion,
519                                           result);
520         if (result->sock_event == NULL) {
521                 status = NT_STATUS_NO_MEMORY;
522                 DEBUG(0, ("event_add_fd failed\n"));
523                 goto fail;
524         }
525
526         result->list = children;
527         DLIST_ADD(children->children, result);
528
529         talloc_set_destructor(result, aio_child_destructor);
530
531         *presult = result;
532
533         return NT_STATUS_OK;
534
535  fail:
536         if (fdpair[0] != -1) close(fdpair[0]);
537         if (fdpair[1] != -1) close(fdpair[1]);
538         TALLOC_FREE(result);
539
540         return status;
541 }
542
543 static NTSTATUS get_idle_child(struct vfs_handle_struct *handle,
544                                struct aio_child **pchild)
545 {
546         struct aio_child_list *children;
547         struct aio_child *child;
548         NTSTATUS status;
549
550         children = init_aio_children(handle);
551         if (children == NULL) {
552                 return NT_STATUS_NO_MEMORY;
553         }
554
555         for (child = children->children; child != NULL; child = child->next) {
556                 if (child->aiocb == NULL) {
557                         /* idle */
558                         break;
559                 }
560         }
561
562         if (child == NULL) {
563                 DEBUG(10, ("no idle child found, creating new one\n"));
564
565                 status = create_aio_child(handle->conn->sconn, children,
566                                           128*1024, &child);
567                 if (!NT_STATUS_IS_OK(status)) {
568                         DEBUG(10, ("create_aio_child failed: %s\n",
569                                    nt_errstr(status)));
570                         return status;
571                 }
572         }
573
574         child->dont_delete = true;
575
576         *pchild = child;
577         return NT_STATUS_OK;
578 }
579
580 static int aio_fork_read(struct vfs_handle_struct *handle,
581                          struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
582 {
583         struct aio_child *child;
584         struct rw_cmd cmd;
585         ssize_t ret;
586         NTSTATUS status;
587
588         if (aiocb->aio_nbytes > 128*1024) {
589                 /* TODO: support variable buffers */
590                 errno = EINVAL;
591                 return -1;
592         }
593
594         status = get_idle_child(handle, &child);
595         if (!NT_STATUS_IS_OK(status)) {
596                 DEBUG(10, ("Could not get an idle child\n"));
597                 return -1;
598         }
599
600         child->read_cmd = true;
601         child->aiocb = aiocb;
602         child->retval.ret_errno = EINPROGRESS;
603
604         ZERO_STRUCT(cmd);
605         cmd.n = aiocb->aio_nbytes;
606         cmd.offset = aiocb->aio_offset;
607         cmd.read_cmd = child->read_cmd;
608
609         DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
610                    (int)child->pid));
611
612         ret = write_fd(child->sockfd, &cmd, sizeof(cmd), fsp->fh->fd);
613         if (ret == -1) {
614                 DEBUG(10, ("write_fd failed: %s\n", strerror(errno)));
615                 return -1;
616         }
617
618         return 0;
619 }
620
621 static int aio_fork_write(struct vfs_handle_struct *handle,
622                           struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
623 {
624         struct aio_child *child;
625         struct rw_cmd cmd;
626         ssize_t ret;
627         NTSTATUS status;
628
629         if (aiocb->aio_nbytes > 128*1024) {
630                 /* TODO: support variable buffers */
631                 errno = EINVAL;
632                 return -1;
633         }
634
635         status = get_idle_child(handle, &child);
636         if (!NT_STATUS_IS_OK(status)) {
637                 DEBUG(10, ("Could not get an idle child\n"));
638                 return -1;
639         }
640
641         child->read_cmd = false;
642         child->aiocb = aiocb;
643         child->retval.ret_errno = EINPROGRESS;
644
645         memcpy((void *)child->map->ptr, (void *)aiocb->aio_buf,
646                aiocb->aio_nbytes);
647
648         ZERO_STRUCT(cmd);
649         cmd.n = aiocb->aio_nbytes;
650         cmd.offset = aiocb->aio_offset;
651         cmd.read_cmd = child->read_cmd;
652
653         DEBUG(10, ("sending fd %d to child %d\n", fsp->fh->fd,
654                    (int)child->pid));
655
656         ret = write_fd(child->sockfd, &cmd, sizeof(cmd), fsp->fh->fd);
657         if (ret == -1) {
658                 DEBUG(10, ("write_fd failed: %s\n", strerror(errno)));
659                 return -1;
660         }
661
662         return 0;
663 }
664
665 static struct aio_child *aio_fork_find_child(struct vfs_handle_struct *handle,
666                                              SMB_STRUCT_AIOCB *aiocb)
667 {
668         struct aio_child_list *children;
669         struct aio_child *child;
670
671         children = init_aio_children(handle);
672         if (children == NULL) {
673                 return NULL;
674         }
675
676         for (child = children->children; child != NULL; child = child->next) {
677                 if (child->aiocb == aiocb) {
678                         return child;
679                 }
680         }
681
682         return NULL;
683 }
684
685 static ssize_t aio_fork_return_fn(struct vfs_handle_struct *handle,
686                                   struct files_struct *fsp,
687                                   SMB_STRUCT_AIOCB *aiocb)
688 {
689         struct aio_child *child = aio_fork_find_child(handle, aiocb);
690
691         if (child == NULL) {
692                 errno = EINVAL;
693                 DEBUG(0, ("returning EINVAL\n"));
694                 return -1;
695         }
696
697         child->aiocb = NULL;
698
699         if (child->retval.size == -1) {
700                 errno = child->retval.ret_errno;
701         }
702
703         return child->retval.size;
704 }
705
706 static int aio_fork_cancel(struct vfs_handle_struct *handle,
707                            struct files_struct *fsp,
708                            SMB_STRUCT_AIOCB *aiocb)
709 {
710         struct aio_child_list *children;
711         struct aio_child *child;
712
713         children = init_aio_children(handle);
714         if (children == NULL) {
715                 errno = EINVAL;
716                 return -1;
717         }
718
719         for (child = children->children; child != NULL; child = child->next) {
720                 if (child->aiocb == NULL) {
721                         continue;
722                 }
723                 if (child->aiocb->aio_fildes != fsp->fh->fd) {
724                         continue;
725                 }
726                 if ((aiocb != NULL) && (child->aiocb != aiocb)) {
727                         continue;
728                 }
729
730                 /*
731                  * We let the child do its job, but we discard the result when
732                  * it's finished.
733                  */
734
735                 child->cancelled = true;
736         }
737
738         return AIO_CANCELED;
739 }
740
741 static int aio_fork_error_fn(struct vfs_handle_struct *handle,
742                              struct files_struct *fsp,
743                              SMB_STRUCT_AIOCB *aiocb)
744 {
745         struct aio_child *child = aio_fork_find_child(handle, aiocb);
746
747         if (child == NULL) {
748                 errno = EINVAL;
749                 return -1;
750         }
751
752         return child->retval.ret_errno;
753 }
754
755 static void aio_fork_suspend_timed_out(struct tevent_context *event_ctx,
756                                         struct tevent_timer *te,
757                                         struct timeval now,
758                                         void *private_data)
759 {
760         bool *timed_out = (bool *)private_data;
761         /* Remove this timed event handler. */
762         TALLOC_FREE(te);
763         *timed_out = true;
764 }
765
766 static int aio_fork_suspend(struct vfs_handle_struct *handle,
767                         struct files_struct *fsp,
768                         const SMB_STRUCT_AIOCB * const aiocb_array[],
769                         int n,
770                         const struct timespec *timeout)
771 {
772         struct aio_child_list *children = NULL;
773         TALLOC_CTX *frame = talloc_stackframe();
774         struct event_context *ev = NULL;
775         int i;
776         int ret = -1;
777         bool timed_out = false;
778
779         children = init_aio_children(handle);
780         if (children == NULL) {
781                 errno = EINVAL;
782                 goto out;
783         }
784
785         /* This is a blocking call, and has to use a sub-event loop. */
786         ev = event_context_init(frame);
787         if (ev == NULL) {
788                 errno = ENOMEM;
789                 goto out;
790         }
791
792         if (timeout) {
793                 struct timeval tv = convert_timespec_to_timeval(*timeout);
794                 struct tevent_timer *te = tevent_add_timer(ev,
795                                                 frame,
796                                                 timeval_current_ofs(tv.tv_sec,
797                                                                     tv.tv_usec),
798                                                 aio_fork_suspend_timed_out,
799                                                 &timed_out);
800                 if (!te) {
801                         errno = ENOMEM;
802                         goto out;
803                 }
804         }
805
806         for (i = 0; i < n; i++) {
807                 struct aio_child *child = NULL;
808                 const SMB_STRUCT_AIOCB *aiocb = aiocb_array[i];
809
810                 if (!aiocb) {
811                         continue;
812                 }
813
814                 /*
815                  * We're going to cheat here. We know that smbd/aio.c
816                  * only calls this when it's waiting for every single
817                  * outstanding call to finish on a close, so just wait
818                  * individually for each IO to complete. We don't care
819                  * what order they finish - only that they all do. JRA.
820                  */
821
822                 for (child = children->children; child != NULL; child = child->next) {
823                         if (child->aiocb == NULL) {
824                                 continue;
825                         }
826                         if (child->aiocb->aio_fildes != fsp->fh->fd) {
827                                 continue;
828                         }
829                         if (child->aiocb != aiocb) {
830                                 continue;
831                         }
832
833                         if (child->aiocb->aio_sigevent.sigev_value.sival_ptr == NULL) {
834                                 continue;
835                         }
836
837                         /* We're never using this event on the
838                          * main event context again... */
839                         TALLOC_FREE(child->sock_event);
840
841                         child->sock_event = event_add_fd(ev,
842                                                 child,
843                                                 child->sockfd,
844                                                 EVENT_FD_READ,
845                                                 handle_aio_completion,
846                                                 child);
847
848                         while (1) {
849                                 if (tevent_loop_once(ev) == -1) {
850                                         goto out;
851                                 }
852
853                                 if (timed_out) {
854                                         errno = EAGAIN;
855                                         goto out;
856                                 }
857
858                                 /* We set child->aiocb to NULL in our hooked
859                                  * AIO_RETURN(). */
860                                 if (child->aiocb == NULL) {
861                                         break;
862                                 }
863                         }
864                 }
865         }
866
867         ret = 0;
868
869   out:
870
871         TALLOC_FREE(frame);
872         return ret;
873 }
874
875 static struct vfs_fn_pointers vfs_aio_fork_fns = {
876         .aio_read = aio_fork_read,
877         .aio_write = aio_fork_write,
878         .aio_return_fn = aio_fork_return_fn,
879         .aio_cancel = aio_fork_cancel,
880         .aio_error_fn = aio_fork_error_fn,
881         .aio_suspend = aio_fork_suspend,
882 };
883
884 NTSTATUS vfs_aio_fork_init(void);
885 NTSTATUS vfs_aio_fork_init(void)
886 {
887         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
888                                 "aio_fork", &vfs_aio_fork_fns);
889 }