Fix issue with aio where r/w lock wasn't kept across aio read operations.
[garming/samba-autobuild/.git] / source3 / smbd / aio.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    async_io read handling using POSIX async io.
5    Copyright (C) Jeremy Allison 2005.
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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/globals.h"
23
24 #if defined(WITH_AIO)
25
26 /* The signal we'll use to signify aio done. */
27 #ifndef RT_SIGNAL_AIO
28 #define RT_SIGNAL_AIO   (SIGRTMIN+3)
29 #endif
30
31 #ifndef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIVAL_PTR
32 #ifdef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIGVAL_PTR
33 #define sival_int       sigval_int
34 #define sival_ptr       sigval_ptr
35 #endif
36 #endif
37
38 /****************************************************************************
39  Initialize the signal handler for aio read/write.
40 *****************************************************************************/
41
42 static void smbd_aio_signal_handler(struct tevent_context *ev_ctx,
43                                     struct tevent_signal *se,
44                                     int signum, int count,
45                                     void *_info, void *private_data)
46 {
47         siginfo_t *info = (siginfo_t *)_info;
48         unsigned int mid = (unsigned int)info->si_value.sival_int;
49
50         smbd_aio_complete_mid(mid);
51 }
52
53
54 static void initialize_async_io_handler(void)
55 {
56         if (aio_signal_event) {
57                 return;
58         }
59
60         aio_signal_event = tevent_add_signal(smbd_event_context(),
61                                              smbd_event_context(),
62                                              RT_SIGNAL_AIO, SA_SIGINFO,
63                                              smbd_aio_signal_handler,
64                                              NULL);
65         if (!aio_signal_event) {
66                 exit_server("Failed to setup RT_SIGNAL_AIO handler");
67         }
68
69         /* tevent supports 100 signal with SA_SIGINFO */
70         aio_pending_size = 100;
71 }
72
73
74 /****************************************************************************
75  The buffer we keep around whilst an aio request is in process.
76 *****************************************************************************/
77
78 struct aio_extra {
79         struct aio_extra *next, *prev;
80         SMB_STRUCT_AIOCB acb;
81         files_struct *fsp;
82         struct smb_request *req;
83         char *outbuf;
84         struct lock_struct lock;
85         int (*handle_completion)(struct aio_extra *ex, int errcode);
86 };
87
88 static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode);
89 static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode);
90
91 static int aio_extra_destructor(struct aio_extra *aio_ex)
92 {
93         DLIST_REMOVE(aio_list_head, aio_ex);
94         return 0;
95 }
96
97 /****************************************************************************
98  Create the extended aio struct we must keep around for the lifetime
99  of the aio call.
100 *****************************************************************************/
101
102 static struct aio_extra *create_aio_extra(files_struct *fsp, size_t buflen)
103 {
104         struct aio_extra *aio_ex = TALLOC_ZERO_P(NULL, struct aio_extra);
105
106         if (!aio_ex) {
107                 return NULL;
108         }
109
110         /* The output buffer stored in the aio_ex is the start of
111            the smb return buffer. The buffer used in the acb
112            is the start of the reply data portion of that buffer. */
113
114         aio_ex->outbuf = TALLOC_ARRAY(aio_ex, char, buflen);
115         if (!aio_ex->outbuf) {
116                 TALLOC_FREE(aio_ex);
117                 return NULL;
118         }
119         DLIST_ADD(aio_list_head, aio_ex);
120         talloc_set_destructor(aio_ex, aio_extra_destructor);
121         aio_ex->fsp = fsp;
122         return aio_ex;
123 }
124
125 /****************************************************************************
126  Given the mid find the extended aio struct containing it.
127 *****************************************************************************/
128
129 static struct aio_extra *find_aio_ex(uint16 mid)
130 {
131         struct aio_extra *p;
132
133         for( p = aio_list_head; p; p = p->next) {
134                 if (mid == p->req->mid) {
135                         return p;
136                 }
137         }
138         return NULL;
139 }
140
141 /****************************************************************************
142  We can have these many aio buffers in flight.
143 *****************************************************************************/
144
145 /****************************************************************************
146  Set up an aio request from a SMBreadX call.
147 *****************************************************************************/
148
149 NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
150                              struct smb_request *req,
151                              files_struct *fsp, SMB_OFF_T startpos,
152                              size_t smb_maxcnt)
153 {
154         struct aio_extra *aio_ex;
155         SMB_STRUCT_AIOCB *a;
156         size_t bufsize;
157         size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
158         int ret;
159
160         if (fsp->base_fsp != NULL) {
161                 /* No AIO on streams yet */
162                 DEBUG(10, ("AIO on streams not yet supported\n"));
163                 return NT_STATUS_RETRY;
164         }
165
166         if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
167             && !SMB_VFS_AIO_FORCE(fsp)) {
168                 /* Too small a read for aio request. */
169                 DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
170                           "for minimum aio_read of %u\n",
171                           (unsigned int)smb_maxcnt,
172                           (unsigned int)min_aio_read_size ));
173                 return NT_STATUS_RETRY;
174         }
175
176         /* Only do this on non-chained and non-chaining reads not using the
177          * write cache. */
178         if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) {
179                 return NT_STATUS_RETRY;
180         }
181
182         if (outstanding_aio_calls >= aio_pending_size) {
183                 DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
184                           "activities outstanding.\n",
185                           outstanding_aio_calls ));
186                 return NT_STATUS_RETRY;
187         }
188
189         /* The following is safe from integer wrap as we've already checked
190            smb_maxcnt is 128k or less. Wct is 12 for read replies */
191
192         bufsize = smb_size + 12 * 2 + smb_maxcnt;
193
194         /* Ensure aio is initialized. */
195         initialize_async_io_handler();
196
197         if ((aio_ex = create_aio_extra(fsp, bufsize)) == NULL) {
198                 DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
199                 return NT_STATUS_NO_MEMORY;
200         }
201         aio_ex->handle_completion = handle_aio_read_complete;
202
203         construct_reply_common_req(req, aio_ex->outbuf);
204         srv_set_message(aio_ex->outbuf, 12, 0, True);
205         SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
206
207         init_strict_lock_struct(fsp, (uint32)req->smbpid,
208                 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
209                 &aio_ex->lock);
210
211         /* Take the lock until the AIO completes. */
212         if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
213                 TALLOC_FREE(aio_ex);
214                 return NT_STATUS_FILE_LOCK_CONFLICT;
215         }
216
217         a = &aio_ex->acb;
218
219         /* Now set up the aio record for the read call. */
220
221         a->aio_fildes = fsp->fh->fd;
222         a->aio_buf = smb_buf(aio_ex->outbuf);
223         a->aio_nbytes = smb_maxcnt;
224         a->aio_offset = startpos;
225         a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
226         a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
227         a->aio_sigevent.sigev_value.sival_int = req->mid;
228
229         ret = SMB_VFS_AIO_READ(fsp, a);
230         if (ret == -1) {
231                 DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
232                          "Error %s\n", strerror(errno) ));
233                 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
234                 TALLOC_FREE(aio_ex);
235                 return NT_STATUS_RETRY;
236         }
237
238         outstanding_aio_calls++;
239         aio_ex->req = talloc_move(aio_ex, &req);
240
241         DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, "
242                   "offset %.0f, len = %u (mid = %u)\n",
243                   fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
244                   (unsigned int)aio_ex->req->mid ));
245
246         return NT_STATUS_OK;
247 }
248
249 /****************************************************************************
250  Set up an aio request from a SMBwriteX call.
251 *****************************************************************************/
252
253 NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
254                               struct smb_request *req,
255                               files_struct *fsp, char *data,
256                               SMB_OFF_T startpos,
257                               size_t numtowrite)
258 {
259         struct aio_extra *aio_ex;
260         SMB_STRUCT_AIOCB *a;
261         size_t bufsize;
262         bool write_through = BITSETW(req->vwv+7,0);
263         size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
264         int ret;
265
266         if (fsp->base_fsp != NULL) {
267                 /* No AIO on streams yet */
268                 DEBUG(10, ("AIO on streams not yet supported\n"));
269                 return NT_STATUS_RETRY;
270         }
271
272         if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
273             && !SMB_VFS_AIO_FORCE(fsp)) {
274                 /* Too small a write for aio request. */
275                 DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
276                           "small for minimum aio_write of %u\n",
277                           (unsigned int)numtowrite,
278                           (unsigned int)min_aio_write_size ));
279                 return NT_STATUS_RETRY;
280         }
281
282         /* Only do this on non-chained and non-chaining reads not using the
283          * write cache. */
284         if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) {
285                 return NT_STATUS_RETRY;
286         }
287
288         if (outstanding_aio_calls >= aio_pending_size) {
289                 DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
290                          "activities outstanding.\n",
291                           outstanding_aio_calls ));
292                 DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
293                           "aio_write for file %s, offset %.0f, len = %u "
294                           "(mid = %u)\n",
295                           fsp_str_dbg(fsp), (double)startpos,
296                           (unsigned int)numtowrite,
297                           (unsigned int)req->mid ));
298                 return NT_STATUS_RETRY;
299         }
300
301         /* Ensure aio is initialized. */
302         initialize_async_io_handler();
303
304         bufsize = smb_size + 6*2;
305
306         if (!(aio_ex = create_aio_extra(fsp, bufsize))) {
307                 DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
308                 return NT_STATUS_NO_MEMORY;
309         }
310         aio_ex->handle_completion = handle_aio_write_complete;
311
312         construct_reply_common_req(req, aio_ex->outbuf);
313         srv_set_message(aio_ex->outbuf, 6, 0, True);
314         SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
315
316         init_strict_lock_struct(fsp, (uint32)req->smbpid,
317                 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
318                 &aio_ex->lock);
319
320         /* Take the lock until the AIO completes. */
321         if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
322                 TALLOC_FREE(aio_ex);
323                 return NT_STATUS_FILE_LOCK_CONFLICT;
324         }
325
326         a = &aio_ex->acb;
327
328         /* Now set up the aio record for the write call. */
329
330         a->aio_fildes = fsp->fh->fd;
331         a->aio_buf = data;
332         a->aio_nbytes = numtowrite;
333         a->aio_offset = startpos;
334         a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
335         a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
336         a->aio_sigevent.sigev_value.sival_int = req->mid;
337
338         ret = SMB_VFS_AIO_WRITE(fsp, a);
339         if (ret == -1) {
340                 DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
341                          "Error %s\n", strerror(errno) ));
342                 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
343                 TALLOC_FREE(aio_ex);
344                 return NT_STATUS_RETRY;
345         }
346
347         outstanding_aio_calls++;
348         aio_ex->req = talloc_move(aio_ex, &req);
349
350         /* This should actually be improved to span the write. */
351         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
352         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
353
354         if (!write_through && !lp_syncalways(SNUM(fsp->conn))
355             && fsp->aio_write_behind) {
356                 /* Lie to the client and immediately claim we finished the
357                  * write. */
358                 SSVAL(aio_ex->outbuf,smb_vwv2,numtowrite);
359                 SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1);
360                 show_msg(aio_ex->outbuf);
361                 if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf,
362                                 true, aio_ex->req->seqnum+1,
363                                 IS_CONN_ENCRYPTED(fsp->conn),
364                                 &aio_ex->req->pcd)) {
365                         exit_server_cleanly("handle_aio_write: srv_send_smb "
366                                             "failed.");
367                 }
368                 DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
369                           "behind for file %s\n", fsp_str_dbg(fsp)));
370         }
371
372         DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file "
373                   "%s, offset %.0f, len = %u (mid = %u) "
374                   "outstanding_aio_calls = %d\n",
375                   fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
376                   (unsigned int)aio_ex->req->mid, outstanding_aio_calls ));
377
378         return NT_STATUS_OK;
379 }
380
381 /****************************************************************************
382  Complete the read and return the data or error back to the client.
383  Returns errno or zero if all ok.
384 *****************************************************************************/
385
386 static int handle_aio_read_complete(struct aio_extra *aio_ex, int errcode)
387 {
388         int outsize;
389         char *outbuf = aio_ex->outbuf;
390         char *data = smb_buf(outbuf);
391         ssize_t nread = SMB_VFS_AIO_RETURN(aio_ex->fsp,&aio_ex->acb);
392
393         if (nread < 0) {
394                 /* We're relying here on the fact that if the fd is
395                    closed then the aio will complete and aio_return
396                    will return an error. Hopefully this is
397                    true.... JRA. */
398
399                 DEBUG( 3,( "handle_aio_read_complete: file %s nread == %d. "
400                            "Error = %s\n",
401                            fsp_str_dbg(aio_ex->fsp), (int)nread, strerror(errcode)));
402
403                 ERROR_NT(map_nt_error_from_unix(errcode));
404                 outsize = srv_set_message(outbuf,0,0,true);
405         } else {
406                 outsize = srv_set_message(outbuf,12,nread,False);
407                 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be * -1. */
408                 SSVAL(outbuf,smb_vwv5,nread);
409                 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
410                 SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
411                 SSVAL(smb_buf(outbuf),-2,nread);
412
413                 aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nread;
414                 aio_ex->fsp->fh->position_information = aio_ex->fsp->fh->pos;
415
416                 DEBUG( 3, ( "handle_aio_read_complete file %s max=%d "
417                             "nread=%d\n",
418                             fsp_str_dbg(aio_ex->fsp),
419                             (int)aio_ex->acb.aio_nbytes, (int)nread ) );
420
421         }
422         smb_setlen(outbuf,outsize - 4);
423         show_msg(outbuf);
424         if (!srv_send_smb(smbd_server_fd(),outbuf,
425                         true, aio_ex->req->seqnum+1,
426                         IS_CONN_ENCRYPTED(aio_ex->fsp->conn), NULL)) {
427                 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
428                                     "failed.");
429         }
430
431         DEBUG(10,("handle_aio_read_complete: scheduled aio_read completed "
432                   "for file %s, offset %.0f, len = %u\n",
433                   fsp_str_dbg(aio_ex->fsp), (double)aio_ex->acb.aio_offset,
434                   (unsigned int)nread ));
435
436         return errcode;
437 }
438
439 /****************************************************************************
440  Complete the write and return the data or error back to the client.
441  Returns error code or zero if all ok.
442 *****************************************************************************/
443
444 static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode)
445 {
446         files_struct *fsp = aio_ex->fsp;
447         char *outbuf = aio_ex->outbuf;
448         ssize_t numtowrite = aio_ex->acb.aio_nbytes;
449         ssize_t nwritten = SMB_VFS_AIO_RETURN(fsp,&aio_ex->acb);
450
451         if (fsp->aio_write_behind) {
452                 if (nwritten != numtowrite) {
453                         if (nwritten == -1) {
454                                 DEBUG(5,("handle_aio_write_complete: "
455                                          "aio_write_behind failed ! File %s "
456                                          "is corrupt ! Error %s\n",
457                                          fsp_str_dbg(fsp), strerror(errcode)));
458                         } else {
459                                 DEBUG(0,("handle_aio_write_complete: "
460                                          "aio_write_behind failed ! File %s "
461                                          "is corrupt ! Wanted %u bytes but "
462                                          "only wrote %d\n", fsp_str_dbg(fsp),
463                                          (unsigned int)numtowrite,
464                                          (int)nwritten ));
465                                 errcode = EIO;
466                         }
467                 } else {
468                         DEBUG(10,("handle_aio_write_complete: "
469                                   "aio_write_behind completed for file %s\n",
470                                   fsp_str_dbg(fsp)));
471                 }
472                 /* TODO: should no return 0 in case of an error !!! */
473                 return 0;
474         }
475
476         /* We don't need outsize or set_message here as we've already set the
477            fixed size length when we set up the aio call. */
478
479         if(nwritten == -1) {
480                 DEBUG( 3,( "handle_aio_write: file %s wanted %u bytes. "
481                            "nwritten == %d. Error = %s\n",
482                            fsp_str_dbg(fsp), (unsigned int)numtowrite,
483                            (int)nwritten, strerror(errcode) ));
484
485                 ERROR_NT(map_nt_error_from_unix(errcode));
486                 srv_set_message(outbuf,0,0,true);
487         } else {
488                 bool write_through = BITSETW(aio_ex->req->vwv+7,0);
489                 NTSTATUS status;
490
491                 SSVAL(outbuf,smb_vwv2,nwritten);
492                 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
493                 if (nwritten < (ssize_t)numtowrite) {
494                         SCVAL(outbuf,smb_rcls,ERRHRD);
495                         SSVAL(outbuf,smb_err,ERRdiskfull);
496                 }
497
498                 DEBUG(3,("handle_aio_write: fnum=%d num=%d wrote=%d\n",
499                          fsp->fnum, (int)numtowrite, (int)nwritten));
500                 status = sync_file(fsp->conn,fsp, write_through);
501                 if (!NT_STATUS_IS_OK(status)) {
502                         errcode = errno;
503                         ERROR_BOTH(map_nt_error_from_unix(errcode),
504                                    ERRHRD, ERRdiskfull);
505                         srv_set_message(outbuf,0,0,true);
506                         DEBUG(5,("handle_aio_write: sync_file for %s returned %s\n",
507                                  fsp_str_dbg(fsp), nt_errstr(status)));
508                 }
509
510                 aio_ex->fsp->fh->pos = aio_ex->acb.aio_offset + nwritten;
511         }
512
513         show_msg(outbuf);
514         if (!srv_send_smb(smbd_server_fd(),outbuf,
515                           true, aio_ex->req->seqnum+1,
516                           IS_CONN_ENCRYPTED(fsp->conn),
517                           NULL)) {
518                 exit_server_cleanly("handle_aio_write: srv_send_smb failed.");
519         }
520
521         DEBUG(10,("handle_aio_write_complete: scheduled aio_write completed "
522                   "for file %s, offset %.0f, requested %u, written = %u\n",
523                   fsp_str_dbg(fsp), (double)aio_ex->acb.aio_offset,
524                   (unsigned int)numtowrite, (unsigned int)nwritten ));
525
526         return errcode;
527 }
528
529 /****************************************************************************
530  Handle any aio completion. Returns True if finished (and sets *perr if err
531  was non-zero), False if not.
532 *****************************************************************************/
533
534 static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr)
535 {
536         files_struct *fsp = NULL;
537         int err;
538
539         if(!aio_ex) {
540                 DEBUG(3, ("handle_aio_completed: Non-existing aio_ex passed\n"));
541                 return false;
542         }
543
544         fsp = aio_ex->fsp;
545
546         /* Ensure the operation has really completed. */
547         err = SMB_VFS_AIO_ERROR(fsp, &aio_ex->acb);
548         if (err == EINPROGRESS) {
549                 DEBUG(10,( "handle_aio_completed: operation mid %u still in "
550                            "process for file %s\n",
551                            aio_ex->req->mid, fsp_str_dbg(aio_ex->fsp)));
552                 return False;
553         }
554
555         /* Unlock now we're done. */
556         SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
557
558         if (err == ECANCELED) {
559                 /* If error is ECANCELED then don't return anything to the
560                  * client. */
561                 DEBUG(10,( "handle_aio_completed: operation mid %u"
562                            " canceled\n", aio_ex->req->mid));
563                 return True;
564         }
565
566         err = aio_ex->handle_completion(aio_ex, err);
567         if (err) {
568                 *perr = err; /* Only save non-zero errors. */
569         }
570
571         return True;
572 }
573
574 /****************************************************************************
575  Handle any aio completion inline.
576 *****************************************************************************/
577
578 void smbd_aio_complete_mid(unsigned int mid)
579 {
580         files_struct *fsp = NULL;
581         struct aio_extra *aio_ex = find_aio_ex(mid);
582         int ret = 0;
583
584         outstanding_aio_calls--;
585
586         DEBUG(10,("smbd_aio_complete_mid: mid[%u]\n", mid));
587
588         if (!aio_ex) {
589                 DEBUG(3,("smbd_aio_complete_mid: Can't find record to "
590                          "match mid %u.\n", mid));
591                 return;
592         }
593
594         fsp = aio_ex->fsp;
595         if (fsp == NULL) {
596                 /* file was closed whilst I/O was outstanding. Just
597                  * ignore. */
598                 DEBUG( 3,( "smbd_aio_complete_mid: file closed whilst "
599                            "aio outstanding (mid[%u]).\n", mid));
600                 return;
601         }
602
603         if (!handle_aio_completed(aio_ex, &ret)) {
604                 return;
605         }
606
607         TALLOC_FREE(aio_ex);
608 }
609
610 /****************************************************************************
611  We're doing write behind and the client closed the file. Wait up to 30
612  seconds (my arbitrary choice) for the aio to complete. Return 0 if all writes
613  completed, errno to return if not.
614 *****************************************************************************/
615
616 #define SMB_TIME_FOR_AIO_COMPLETE_WAIT 29
617
618 int wait_for_aio_completion(files_struct *fsp)
619 {
620         struct aio_extra *aio_ex;
621         const SMB_STRUCT_AIOCB **aiocb_list;
622         int aio_completion_count = 0;
623         time_t start_time = time(NULL);
624         int seconds_left;
625
626         for (seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT;
627              seconds_left >= 0;) {
628                 int err = 0;
629                 int i;
630                 struct timespec ts;
631
632                 aio_completion_count = 0;
633                 for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
634                         if (aio_ex->fsp == fsp) {
635                                 aio_completion_count++;
636                         }
637                 }
638
639                 if (!aio_completion_count) {
640                         return 0;
641                 }
642
643                 DEBUG(3,("wait_for_aio_completion: waiting for %d aio events "
644                          "to complete.\n", aio_completion_count ));
645
646                 aiocb_list = SMB_MALLOC_ARRAY(const SMB_STRUCT_AIOCB *,
647                                               aio_completion_count);
648                 if (!aiocb_list) {
649                         return ENOMEM;
650                 }
651
652                 for( i = 0, aio_ex = aio_list_head;
653                      aio_ex;
654                      aio_ex = aio_ex->next) {
655                         if (aio_ex->fsp == fsp) {
656                                 aiocb_list[i++] = &aio_ex->acb;
657                         }
658                 }
659
660                 /* Now wait up to seconds_left for completion. */
661                 ts.tv_sec = seconds_left;
662                 ts.tv_nsec = 0;
663
664                 DEBUG(10,("wait_for_aio_completion: %d events, doing a wait "
665                           "of %d seconds.\n",
666                           aio_completion_count, seconds_left ));
667
668                 err = SMB_VFS_AIO_SUSPEND(fsp, aiocb_list,
669                                           aio_completion_count, &ts);
670
671                 DEBUG(10,("wait_for_aio_completion: returned err = %d, "
672                           "errno = %s\n", err, strerror(errno) ));
673
674                 if (err == -1 && errno == EAGAIN) {
675                         DEBUG(0,("wait_for_aio_completion: aio_suspend timed "
676                                  "out waiting for %d events after a wait of "
677                                  "%d seconds\n", aio_completion_count,
678                                  seconds_left));
679                         /* Timeout. */
680                         cancel_aio_by_fsp(fsp);
681                         SAFE_FREE(aiocb_list);
682                         return EIO;
683                 }
684
685                 /* One or more events might have completed - process them if
686                  * so. */
687                 for( i = 0; i < aio_completion_count; i++) {
688                         uint16 mid = aiocb_list[i]->aio_sigevent.sigev_value.sival_int;
689
690                         aio_ex = find_aio_ex(mid);
691
692                         if (!aio_ex) {
693                                 DEBUG(0, ("wait_for_aio_completion: mid %u "
694                                           "doesn't match an aio record\n",
695                                           (unsigned int)mid ));
696                                 continue;
697                         }
698
699                         if (!handle_aio_completed(aio_ex, &err)) {
700                                 continue;
701                         }
702                         TALLOC_FREE(aio_ex);
703                 }
704
705                 SAFE_FREE(aiocb_list);
706                 seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT
707                         - (time(NULL) - start_time);
708         }
709
710         /* We timed out - we don't know why. Return ret if already an error,
711          * else EIO. */
712         DEBUG(10,("wait_for_aio_completion: aio_suspend timed out waiting "
713                   "for %d events\n",
714                   aio_completion_count));
715
716         return EIO;
717 }
718
719 /****************************************************************************
720  Cancel any outstanding aio requests. The client doesn't care about the reply.
721 *****************************************************************************/
722
723 void cancel_aio_by_fsp(files_struct *fsp)
724 {
725         struct aio_extra *aio_ex;
726
727         for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
728                 if (aio_ex->fsp == fsp) {
729                         /* Unlock now we're done. */
730                         SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
731
732                         /* Don't delete the aio_extra record as we may have
733                            completed and don't yet know it. Just do the
734                            aio_cancel call and return. */
735                         SMB_VFS_AIO_CANCEL(fsp, &aio_ex->acb);
736                         aio_ex->fsp = NULL; /* fsp will be closed when we
737                                              * return. */
738                 }
739         }
740 }
741
742 #else
743 NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
744                              struct smb_request *req,
745                              files_struct *fsp, SMB_OFF_T startpos,
746                              size_t smb_maxcnt)
747 {
748         return NT_STATUS_RETRY;
749 }
750
751 NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
752                               struct smb_request *req,
753                               files_struct *fsp, char *data,
754                               SMB_OFF_T startpos,
755                               size_t numtowrite)
756 {
757         return NT_STATUS_RETRY;
758 }
759
760 void cancel_aio_by_fsp(files_struct *fsp)
761 {
762 }
763
764 int wait_for_aio_completion(files_struct *fsp)
765 {
766         return ENOSYS;
767 }
768
769 void smbd_aio_complete_mid(unsigned int mid);
770
771 #endif