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