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