e3265fb0e8dfccf6e4c2ba3ebb42c9627cb8e42d
[abartlet/samba.git/.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  The buffer we keep around whilst an aio request is in process.
40 *****************************************************************************/
41
42 struct aio_extra {
43         struct aio_extra *next, *prev;
44         SMB_STRUCT_AIOCB acb;
45         files_struct *fsp;
46         struct smb_request *req;
47         char *outbuf;
48         struct lock_struct lock;
49         int (*handle_completion)(struct aio_extra *ex, int errcode);
50 };
51
52 /****************************************************************************
53  Initialize the signal handler for aio read/write.
54 *****************************************************************************/
55
56 static void smbd_aio_signal_handler(struct tevent_context *ev_ctx,
57                                     struct tevent_signal *se,
58                                     int signum, int count,
59                                     void *_info, void *private_data)
60 {
61         siginfo_t *info = (siginfo_t *)_info;
62         struct aio_extra *aio_ex = (struct aio_extra *)
63                                 info->si_value.sival_ptr;
64
65         smbd_aio_complete_mid(aio_ex->req->mid);
66 }
67
68
69 static void initialize_async_io_handler(void)
70 {
71         if (aio_signal_event) {
72                 return;
73         }
74
75         aio_signal_event = tevent_add_signal(smbd_event_context(),
76                                              smbd_event_context(),
77                                              RT_SIGNAL_AIO, SA_SIGINFO,
78                                              smbd_aio_signal_handler,
79                                              NULL);
80         if (!aio_signal_event) {
81                 exit_server("Failed to setup RT_SIGNAL_AIO handler");
82         }
83
84         /* tevent supports 100 signal with SA_SIGINFO */
85         aio_pending_size = 100;
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(uint64_t 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         /* Ensure aio is initialized. */
161         initialize_async_io_handler();
162
163         if (fsp->base_fsp != NULL) {
164                 /* No AIO on streams yet */
165                 DEBUG(10, ("AIO on streams not yet supported\n"));
166                 return NT_STATUS_RETRY;
167         }
168
169         if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
170             && !SMB_VFS_AIO_FORCE(fsp)) {
171                 /* Too small a read for aio request. */
172                 DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
173                           "for minimum aio_read of %u\n",
174                           (unsigned int)smb_maxcnt,
175                           (unsigned int)min_aio_read_size ));
176                 return NT_STATUS_RETRY;
177         }
178
179         /* Only do this on non-chained and non-chaining reads not using the
180          * write cache. */
181         if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) {
182                 return NT_STATUS_RETRY;
183         }
184
185         if (outstanding_aio_calls >= aio_pending_size) {
186                 DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
187                           "activities outstanding.\n",
188                           outstanding_aio_calls ));
189                 return NT_STATUS_RETRY;
190         }
191
192         /* The following is safe from integer wrap as we've already checked
193            smb_maxcnt is 128k or less. Wct is 12 for read replies */
194
195         bufsize = smb_size + 12 * 2 + smb_maxcnt;
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, (uint64_t)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_ptr = aio_ex;
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         /* Ensure aio is initialized. */
267         initialize_async_io_handler();
268
269         if (fsp->base_fsp != NULL) {
270                 /* No AIO on streams yet */
271                 DEBUG(10, ("AIO on streams not yet supported\n"));
272                 return NT_STATUS_RETRY;
273         }
274
275         if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
276             && !SMB_VFS_AIO_FORCE(fsp)) {
277                 /* Too small a write for aio request. */
278                 DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
279                           "small for minimum aio_write of %u\n",
280                           (unsigned int)numtowrite,
281                           (unsigned int)min_aio_write_size ));
282                 return NT_STATUS_RETRY;
283         }
284
285         /* Only do this on non-chained and non-chaining reads not using the
286          * write cache. */
287         if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) {
288                 return NT_STATUS_RETRY;
289         }
290
291         if (outstanding_aio_calls >= aio_pending_size) {
292                 DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
293                          "activities outstanding.\n",
294                           outstanding_aio_calls ));
295                 DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
296                           "aio_write for file %s, offset %.0f, len = %u "
297                           "(mid = %u)\n",
298                           fsp_str_dbg(fsp), (double)startpos,
299                           (unsigned int)numtowrite,
300                           (unsigned int)req->mid ));
301                 return NT_STATUS_RETRY;
302         }
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, (uint64_t)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_ptr = aio_ex;
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 %llu still in "
550                         "process for file %s\n",
551                         (unsigned long long)aio_ex->req->mid,
552                         fsp_str_dbg(aio_ex->fsp)));
553                 return False;
554         }
555
556         /* Unlock now we're done. */
557         SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
558
559         if (err == ECANCELED) {
560                 /* If error is ECANCELED then don't return anything to the
561                  * client. */
562                 DEBUG(10,( "handle_aio_completed: operation mid %llu"
563                         " canceled\n",
564                         (unsigned long long)aio_ex->req->mid));
565                 return True;
566         }
567
568         err = aio_ex->handle_completion(aio_ex, err);
569         if (err) {
570                 *perr = err; /* Only save non-zero errors. */
571         }
572
573         return True;
574 }
575
576 /****************************************************************************
577  Handle any aio completion inline.
578 *****************************************************************************/
579
580 void smbd_aio_complete_mid(uint64_t mid)
581 {
582         files_struct *fsp = NULL;
583         struct aio_extra *aio_ex = find_aio_ex(mid);
584         int ret = 0;
585
586         outstanding_aio_calls--;
587
588         DEBUG(10,("smbd_aio_complete_mid: mid[%llu]\n",
589                 (unsigned long long)mid));
590
591         if (!aio_ex) {
592                 DEBUG(3,("smbd_aio_complete_mid: Can't find record to "
593                         "match mid %llu.\n",
594                         (unsigned long long)mid));
595                 return;
596         }
597
598         fsp = aio_ex->fsp;
599         if (fsp == NULL) {
600                 /* file was closed whilst I/O was outstanding. Just
601                  * ignore. */
602                 DEBUG( 3,( "smbd_aio_complete_mid: file closed whilst "
603                         "aio outstanding (mid[%llu]).\n",
604                         (unsigned long long)mid));
605                 return;
606         }
607
608         if (!handle_aio_completed(aio_ex, &ret)) {
609                 return;
610         }
611
612         TALLOC_FREE(aio_ex);
613 }
614
615 /****************************************************************************
616  We're doing write behind and the client closed the file. Wait up to 30
617  seconds (my arbitrary choice) for the aio to complete. Return 0 if all writes
618  completed, errno to return if not.
619 *****************************************************************************/
620
621 #define SMB_TIME_FOR_AIO_COMPLETE_WAIT 29
622
623 int wait_for_aio_completion(files_struct *fsp)
624 {
625         struct aio_extra *aio_ex;
626         const SMB_STRUCT_AIOCB **aiocb_list;
627         int aio_completion_count = 0;
628         time_t start_time = time(NULL);
629         int seconds_left;
630
631         for (seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT;
632              seconds_left >= 0;) {
633                 int err = 0;
634                 int i;
635                 struct timespec ts;
636
637                 aio_completion_count = 0;
638                 for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
639                         if (aio_ex->fsp == fsp) {
640                                 aio_completion_count++;
641                         }
642                 }
643
644                 if (!aio_completion_count) {
645                         return 0;
646                 }
647
648                 DEBUG(3,("wait_for_aio_completion: waiting for %d aio events "
649                          "to complete.\n", aio_completion_count ));
650
651                 aiocb_list = SMB_MALLOC_ARRAY(const SMB_STRUCT_AIOCB *,
652                                               aio_completion_count);
653                 if (!aiocb_list) {
654                         return ENOMEM;
655                 }
656
657                 for( i = 0, aio_ex = aio_list_head;
658                      aio_ex;
659                      aio_ex = aio_ex->next) {
660                         if (aio_ex->fsp == fsp) {
661                                 aiocb_list[i++] = &aio_ex->acb;
662                         }
663                 }
664
665                 /* Now wait up to seconds_left for completion. */
666                 ts.tv_sec = seconds_left;
667                 ts.tv_nsec = 0;
668
669                 DEBUG(10,("wait_for_aio_completion: %d events, doing a wait "
670                           "of %d seconds.\n",
671                           aio_completion_count, seconds_left ));
672
673                 err = SMB_VFS_AIO_SUSPEND(fsp, aiocb_list,
674                                           aio_completion_count, &ts);
675
676                 DEBUG(10,("wait_for_aio_completion: returned err = %d, "
677                           "errno = %s\n", err, strerror(errno) ));
678
679                 if (err == -1 && errno == EAGAIN) {
680                         DEBUG(0,("wait_for_aio_completion: aio_suspend timed "
681                                  "out waiting for %d events after a wait of "
682                                  "%d seconds\n", aio_completion_count,
683                                  seconds_left));
684                         /* Timeout. */
685                         cancel_aio_by_fsp(fsp);
686                         SAFE_FREE(aiocb_list);
687                         return EIO;
688                 }
689
690                 /* One or more events might have completed - process them if
691                  * so. */
692                 for( i = 0; i < aio_completion_count; i++) {
693                         aio_ex = (struct aio_extra *)aiocb_list[i]->aio_sigevent.sigev_value.sival_ptr;
694
695                         if (!handle_aio_completed(aio_ex, &err)) {
696                                 continue;
697                         }
698                         TALLOC_FREE(aio_ex);
699                 }
700
701                 SAFE_FREE(aiocb_list);
702                 seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT
703                         - (time(NULL) - start_time);
704         }
705
706         /* We timed out - we don't know why. Return ret if already an error,
707          * else EIO. */
708         DEBUG(10,("wait_for_aio_completion: aio_suspend timed out waiting "
709                   "for %d events\n",
710                   aio_completion_count));
711
712         return EIO;
713 }
714
715 /****************************************************************************
716  Cancel any outstanding aio requests. The client doesn't care about the reply.
717 *****************************************************************************/
718
719 void cancel_aio_by_fsp(files_struct *fsp)
720 {
721         struct aio_extra *aio_ex;
722
723         for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
724                 if (aio_ex->fsp == fsp) {
725                         /* Unlock now we're done. */
726                         SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
727
728                         /* Don't delete the aio_extra record as we may have
729                            completed and don't yet know it. Just do the
730                            aio_cancel call and return. */
731                         SMB_VFS_AIO_CANCEL(fsp, &aio_ex->acb);
732                         aio_ex->fsp = NULL; /* fsp will be closed when we
733                                              * return. */
734                 }
735         }
736 }
737
738 #else
739 NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
740                              struct smb_request *req,
741                              files_struct *fsp, SMB_OFF_T startpos,
742                              size_t smb_maxcnt)
743 {
744         return NT_STATUS_RETRY;
745 }
746
747 NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
748                               struct smb_request *req,
749                               files_struct *fsp, char *data,
750                               SMB_OFF_T startpos,
751                               size_t numtowrite)
752 {
753         return NT_STATUS_RETRY;
754 }
755
756 void cancel_aio_by_fsp(files_struct *fsp)
757 {
758 }
759
760 int wait_for_aio_completion(files_struct *fsp)
761 {
762         return ENOSYS;
763 }
764
765 void smbd_aio_complete_mid(uint64_t mid);
766
767 #endif