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