7ed2691cfbff48d79bc3dea336880afece0c72b2
[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/smbd.h"
23 #include "smbd/globals.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "../lib/util/tevent_unix.h"
26
27 /****************************************************************************
28  The buffer we keep around whilst an aio request is in process.
29 *****************************************************************************/
30
31 struct aio_extra {
32         files_struct *fsp;
33         struct smb_request *smbreq;
34         DATA_BLOB outbuf;
35         struct lock_struct lock;
36         size_t nbyte;
37         off_t offset;
38         bool write_through;
39 };
40
41 /****************************************************************************
42  Accessor function to return write_through state.
43 *****************************************************************************/
44
45 bool aio_write_through_requested(struct aio_extra *aio_ex)
46 {
47         return aio_ex->write_through;
48 }
49
50 /****************************************************************************
51  Create the extended aio struct we must keep around for the lifetime
52  of the aio call.
53 *****************************************************************************/
54
55 static struct aio_extra *create_aio_extra(TALLOC_CTX *mem_ctx,
56                                         files_struct *fsp,
57                                         size_t buflen)
58 {
59         struct aio_extra *aio_ex = talloc_zero(mem_ctx, struct aio_extra);
60
61         if (!aio_ex) {
62                 return NULL;
63         }
64
65         /* The output buffer stored in the aio_ex is the start of
66            the smb return buffer. The buffer used in the acb
67            is the start of the reply data portion of that buffer. */
68
69         if (buflen) {
70                 aio_ex->outbuf = data_blob_talloc(aio_ex, NULL, buflen);
71                 if (!aio_ex->outbuf.data) {
72                         TALLOC_FREE(aio_ex);
73                         return NULL;
74                 }
75         }
76         aio_ex->fsp = fsp;
77         return aio_ex;
78 }
79
80 struct aio_req_fsp_link {
81         files_struct *fsp;
82         struct tevent_req *req;
83 };
84
85 static int aio_del_req_from_fsp(struct aio_req_fsp_link *lnk)
86 {
87         unsigned i;
88         files_struct *fsp = lnk->fsp;
89         struct tevent_req *req = lnk->req;
90
91         for (i=0; i<fsp->num_aio_requests; i++) {
92                 if (fsp->aio_requests[i] == req) {
93                         break;
94                 }
95         }
96         if (i == fsp->num_aio_requests) {
97                 DEBUG(1, ("req %p not found in fsp %p\n", req, fsp));
98                 return 0;
99         }
100         fsp->num_aio_requests -= 1;
101         fsp->aio_requests[i] = fsp->aio_requests[fsp->num_aio_requests];
102
103         if (fsp->num_aio_requests == 0) {
104                 TALLOC_FREE(fsp->aio_requests);
105         }
106         return 0;
107 }
108
109 bool aio_add_req_to_fsp(files_struct *fsp, struct tevent_req *req)
110 {
111         size_t array_len;
112         struct aio_req_fsp_link *lnk;
113
114         lnk = talloc(req, struct aio_req_fsp_link);
115         if (lnk == NULL) {
116                 return false;
117         }
118
119         array_len = talloc_array_length(fsp->aio_requests);
120         if (array_len <= fsp->num_aio_requests) {
121                 struct tevent_req **tmp;
122
123                 if (fsp->num_aio_requests + 10 < 10) {
124                         /* Integer wrap. */
125                         TALLOC_FREE(lnk);
126                         return false;
127                 }
128
129                 /*
130                  * Allocate in blocks of 10 so we don't allocate
131                  * on every aio request.
132                  */
133                 tmp = talloc_realloc(
134                         fsp, fsp->aio_requests, struct tevent_req *,
135                         fsp->num_aio_requests+10);
136                 if (tmp == NULL) {
137                         TALLOC_FREE(lnk);
138                         return false;
139                 }
140                 fsp->aio_requests = tmp;
141         }
142         fsp->aio_requests[fsp->num_aio_requests] = req;
143         fsp->num_aio_requests += 1;
144
145         lnk->fsp = fsp;
146         lnk->req = req;
147         talloc_set_destructor(lnk, aio_del_req_from_fsp);
148
149         return true;
150 }
151
152 static void aio_pread_smb1_done(struct tevent_req *req);
153
154 /****************************************************************************
155  Set up an aio request from a SMBreadX call.
156 *****************************************************************************/
157
158 NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
159                              struct smb_request *smbreq,
160                              files_struct *fsp, off_t startpos,
161                              size_t smb_maxcnt)
162 {
163         struct aio_extra *aio_ex;
164         size_t bufsize;
165         size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
166         struct tevent_req *req;
167
168         if (fsp->base_fsp != NULL) {
169                 /* No AIO on streams yet */
170                 DEBUG(10, ("AIO on streams not yet supported\n"));
171                 return NT_STATUS_RETRY;
172         }
173
174         if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
175             && !SMB_VFS_AIO_FORCE(fsp)) {
176                 /* Too small a read for aio request. */
177                 DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
178                           "for minimum aio_read of %u\n",
179                           (unsigned int)smb_maxcnt,
180                           (unsigned int)min_aio_read_size ));
181                 return NT_STATUS_RETRY;
182         }
183
184         /* Only do this on non-chained and non-chaining reads */
185         if (req_is_in_chain(smbreq)) {
186                 return NT_STATUS_RETRY;
187         }
188
189         /* The following is safe from integer wrap as we've already checked
190            smb_maxcnt is 128k or less. Wct is 12 for read replies */
191
192         bufsize = smb_size + 12 * 2 + smb_maxcnt + 1 /* padding byte */;
193
194         if ((aio_ex = create_aio_extra(NULL, fsp, bufsize)) == NULL) {
195                 DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
196                 return NT_STATUS_NO_MEMORY;
197         }
198
199         construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
200         srv_set_message((char *)aio_ex->outbuf.data, 12, 0, True);
201         SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
202         SCVAL(smb_buf(aio_ex->outbuf.data), 0, 0); /* padding byte */
203
204         init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
205                 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
206                 &aio_ex->lock);
207
208         /* Take the lock until the AIO completes. */
209         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
210                 TALLOC_FREE(aio_ex);
211                 return NT_STATUS_FILE_LOCK_CONFLICT;
212         }
213
214         aio_ex->nbyte = smb_maxcnt;
215         aio_ex->offset = startpos;
216
217         req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx,
218                                  fsp,
219                                  smb_buf(aio_ex->outbuf.data) + 1 /* pad */,
220                                  smb_maxcnt, startpos);
221         if (req == NULL) {
222                 DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
223                          "Error %s\n", strerror(errno) ));
224                 TALLOC_FREE(aio_ex);
225                 return NT_STATUS_RETRY;
226         }
227         tevent_req_set_callback(req, aio_pread_smb1_done, aio_ex);
228
229         if (!aio_add_req_to_fsp(fsp, req)) {
230                 DEBUG(1, ("Could not add req to fsp\n"));
231                 TALLOC_FREE(aio_ex);
232                 return NT_STATUS_RETRY;
233         }
234
235         aio_ex->smbreq = talloc_move(aio_ex, &smbreq);
236
237         DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, "
238                   "offset %.0f, len = %u (mid = %u)\n",
239                   fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
240                   (unsigned int)aio_ex->smbreq->mid ));
241
242         return NT_STATUS_OK;
243 }
244
245 static void aio_pread_smb1_done(struct tevent_req *req)
246 {
247         struct aio_extra *aio_ex = tevent_req_callback_data(
248                 req, struct aio_extra);
249         files_struct *fsp = aio_ex->fsp;
250         size_t outsize;
251         char *outbuf = (char *)aio_ex->outbuf.data;
252         ssize_t nread;
253         struct vfs_aio_state vfs_aio_state;
254
255         nread = SMB_VFS_PREAD_RECV(req, &vfs_aio_state);
256         TALLOC_FREE(req);
257
258         DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
259                    (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
260
261         if (fsp == NULL) {
262                 DEBUG( 3, ("aio_pread_smb1_done: file closed whilst "
263                            "aio outstanding (mid[%llu]).\n",
264                            (unsigned long long)aio_ex->smbreq->mid));
265                 TALLOC_FREE(aio_ex);
266                 return;
267         }
268
269         if (nread < 0) {
270                 DEBUG( 3, ("handle_aio_read_complete: file %s nread == %d. "
271                            "Error = %s\n", fsp_str_dbg(fsp), (int)nread,
272                            strerror(vfs_aio_state.error)));
273
274                 ERROR_NT(map_nt_error_from_unix(vfs_aio_state.error));
275                 outsize = srv_set_message(outbuf,0,0,true);
276         } else {
277                 outsize = setup_readX_header(outbuf, nread);
278
279                 aio_ex->fsp->fh->pos = aio_ex->offset + nread;
280                 aio_ex->fsp->fh->position_information = aio_ex->fsp->fh->pos;
281
282                 DEBUG( 3, ("handle_aio_read_complete file %s max=%d "
283                            "nread=%d\n", fsp_str_dbg(fsp),
284                            (int)aio_ex->nbyte, (int)nread ) );
285
286         }
287
288         if (outsize <= 4) {
289                 DBG_INFO("Invalid outsize (%zu)\n", outsize);
290                 TALLOC_FREE(aio_ex);
291                 return;
292         }
293         outsize -= 4;
294         _smb_setlen_large(outbuf, outsize);
295
296         show_msg(outbuf);
297         if (!srv_send_smb(aio_ex->smbreq->xconn, outbuf,
298                           true, aio_ex->smbreq->seqnum+1,
299                           IS_CONN_ENCRYPTED(fsp->conn), NULL)) {
300                 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
301                                     "failed.");
302         }
303
304         DEBUG(10, ("handle_aio_read_complete: scheduled aio_read completed "
305                    "for file %s, offset %.0f, len = %u\n",
306                    fsp_str_dbg(fsp), (double)aio_ex->offset,
307                    (unsigned int)nread));
308
309         TALLOC_FREE(aio_ex);
310 }
311
312 struct pwrite_fsync_state {
313         struct tevent_context *ev;
314         files_struct *fsp;
315         bool write_through;
316         ssize_t nwritten;
317 };
318
319 static void pwrite_fsync_write_done(struct tevent_req *subreq);
320 static void pwrite_fsync_sync_done(struct tevent_req *subreq);
321
322 static struct tevent_req *pwrite_fsync_send(TALLOC_CTX *mem_ctx,
323                                             struct tevent_context *ev,
324                                             struct files_struct *fsp,
325                                             const void *data,
326                                             size_t n, off_t offset,
327                                             bool write_through)
328 {
329         struct tevent_req *req, *subreq;
330         struct pwrite_fsync_state *state;
331
332         req = tevent_req_create(mem_ctx, &state, struct pwrite_fsync_state);
333         if (req == NULL) {
334                 return NULL;
335         }
336         state->ev = ev;
337         state->fsp = fsp;
338         state->write_through = write_through;
339
340         subreq = SMB_VFS_PWRITE_SEND(state, ev, fsp, data, n, offset);
341         if (tevent_req_nomem(subreq, req)) {
342                 return tevent_req_post(req, ev);
343         }
344         tevent_req_set_callback(subreq, pwrite_fsync_write_done, req);
345         return req;
346 }
347
348 static void pwrite_fsync_write_done(struct tevent_req *subreq)
349 {
350         struct tevent_req *req = tevent_req_callback_data(
351                 subreq, struct tevent_req);
352         struct pwrite_fsync_state *state = tevent_req_data(
353                 req, struct pwrite_fsync_state);
354         connection_struct *conn = state->fsp->conn;
355         bool do_sync;
356         struct vfs_aio_state vfs_aio_state;
357
358         state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &vfs_aio_state);
359         TALLOC_FREE(subreq);
360         if (state->nwritten == -1) {
361                 tevent_req_error(req, vfs_aio_state.error);
362                 return;
363         }
364
365         do_sync = (lp_strict_sync(SNUM(conn)) &&
366                    (lp_sync_always(SNUM(conn)) || state->write_through));
367         if (!do_sync) {
368                 tevent_req_done(req);
369                 return;
370         }
371
372         subreq = SMB_VFS_FSYNC_SEND(state, state->ev, state->fsp);
373         if (tevent_req_nomem(subreq, req)) {
374                 return;
375         }
376         tevent_req_set_callback(subreq, pwrite_fsync_sync_done, req);
377 }
378
379 static void pwrite_fsync_sync_done(struct tevent_req *subreq)
380 {
381         struct tevent_req *req = tevent_req_callback_data(
382                 subreq, struct tevent_req);
383         int ret;
384         struct vfs_aio_state vfs_aio_state;
385
386         ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
387         TALLOC_FREE(subreq);
388         if (ret == -1) {
389                 tevent_req_error(req, vfs_aio_state.error);
390                 return;
391         }
392         tevent_req_done(req);
393 }
394
395 static ssize_t pwrite_fsync_recv(struct tevent_req *req, int *perr)
396 {
397         struct pwrite_fsync_state *state = tevent_req_data(
398                 req, struct pwrite_fsync_state);
399
400         if (tevent_req_is_unix_error(req, perr)) {
401                 return -1;
402         }
403         return state->nwritten;
404 }
405
406 static void aio_pwrite_smb1_done(struct tevent_req *req);
407
408 /****************************************************************************
409  Set up an aio request from a SMBwriteX call.
410 *****************************************************************************/
411
412 NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
413                               struct smb_request *smbreq,
414                               files_struct *fsp, const char *data,
415                               off_t startpos,
416                               size_t numtowrite)
417 {
418         struct aio_extra *aio_ex;
419         size_t bufsize;
420         size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
421         struct tevent_req *req;
422
423         if (fsp->base_fsp != NULL) {
424                 /* No AIO on streams yet */
425                 DEBUG(10, ("AIO on streams not yet supported\n"));
426                 return NT_STATUS_RETRY;
427         }
428
429         if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
430             && !SMB_VFS_AIO_FORCE(fsp)) {
431                 /* Too small a write for aio request. */
432                 DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
433                           "small for minimum aio_write of %u\n",
434                           (unsigned int)numtowrite,
435                           (unsigned int)min_aio_write_size ));
436                 return NT_STATUS_RETRY;
437         }
438
439         /* Only do this on non-chained and non-chaining writes */
440         if (req_is_in_chain(smbreq)) {
441                 return NT_STATUS_RETRY;
442         }
443
444         bufsize = smb_size + 6*2;
445
446         if (!(aio_ex = create_aio_extra(NULL, fsp, bufsize))) {
447                 DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
448                 return NT_STATUS_NO_MEMORY;
449         }
450         aio_ex->write_through = BITSETW(smbreq->vwv+7,0);
451
452         construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
453         srv_set_message((char *)aio_ex->outbuf.data, 6, 0, True);
454         SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
455
456         init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
457                 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
458                 &aio_ex->lock);
459
460         /* Take the lock until the AIO completes. */
461         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
462                 TALLOC_FREE(aio_ex);
463                 return NT_STATUS_FILE_LOCK_CONFLICT;
464         }
465
466         aio_ex->nbyte = numtowrite;
467         aio_ex->offset = startpos;
468
469         req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
470                                 data, numtowrite, startpos,
471                                 aio_ex->write_through);
472         if (req == NULL) {
473                 DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
474                          "Error %s\n", strerror(errno) ));
475                 TALLOC_FREE(aio_ex);
476                 return NT_STATUS_RETRY;
477         }
478         tevent_req_set_callback(req, aio_pwrite_smb1_done, aio_ex);
479
480         if (!aio_add_req_to_fsp(fsp, req)) {
481                 DEBUG(1, ("Could not add req to fsp\n"));
482                 TALLOC_FREE(aio_ex);
483                 return NT_STATUS_RETRY;
484         }
485
486         aio_ex->smbreq = talloc_move(aio_ex, &smbreq);
487
488         /* This should actually be improved to span the write. */
489         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
490         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
491
492         if (!aio_ex->write_through && !lp_sync_always(SNUM(fsp->conn))
493             && fsp->fsp_flags.aio_write_behind)
494         {
495                 /* Lie to the client and immediately claim we finished the
496                  * write. */
497                 SSVAL(aio_ex->outbuf.data,smb_vwv2,numtowrite);
498                 SSVAL(aio_ex->outbuf.data,smb_vwv4,(numtowrite>>16)&1);
499                 show_msg((char *)aio_ex->outbuf.data);
500                 if (!srv_send_smb(aio_ex->smbreq->xconn,
501                                 (char *)aio_ex->outbuf.data,
502                                 true, aio_ex->smbreq->seqnum+1,
503                                 IS_CONN_ENCRYPTED(fsp->conn),
504                                 &aio_ex->smbreq->pcd)) {
505                         exit_server_cleanly("schedule_aio_write_and_X: "
506                                             "srv_send_smb failed.");
507                 }
508                 DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
509                           "behind for file %s\n", fsp_str_dbg(fsp)));
510         }
511
512         DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file "
513                   "%s, offset %.0f, len = %u (mid = %u)\n",
514                   fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
515                   (unsigned int)aio_ex->smbreq->mid));
516
517         return NT_STATUS_OK;
518 }
519
520 static void aio_pwrite_smb1_done(struct tevent_req *req)
521 {
522         struct aio_extra *aio_ex = tevent_req_callback_data(
523                 req, struct aio_extra);
524         files_struct *fsp = aio_ex->fsp;
525         char *outbuf = (char *)aio_ex->outbuf.data;
526         ssize_t numtowrite = aio_ex->nbyte;
527         ssize_t nwritten;
528         int err;
529
530         nwritten = pwrite_fsync_recv(req, &err);
531         TALLOC_FREE(req);
532
533         DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
534                    (nwritten == -1) ? strerror(err) : "no error"));
535
536         if (fsp == NULL) {
537                 DEBUG( 3, ("aio_pwrite_smb1_done: file closed whilst "
538                            "aio outstanding (mid[%llu]).\n",
539                            (unsigned long long)aio_ex->smbreq->mid));
540                 TALLOC_FREE(aio_ex);
541                 return;
542         }
543
544         mark_file_modified(fsp);
545
546         if (fsp->fsp_flags.aio_write_behind) {
547
548                 if (nwritten != numtowrite) {
549                         if (nwritten == -1) {
550                                 DEBUG(5,("handle_aio_write_complete: "
551                                          "aio_write_behind failed ! File %s "
552                                          "is corrupt ! Error %s\n",
553                                          fsp_str_dbg(fsp), strerror(err)));
554                         } else {
555                                 DEBUG(0,("handle_aio_write_complete: "
556                                          "aio_write_behind failed ! File %s "
557                                          "is corrupt ! Wanted %u bytes but "
558                                          "only wrote %d\n", fsp_str_dbg(fsp),
559                                          (unsigned int)numtowrite,
560                                          (int)nwritten ));
561                         }
562                 } else {
563                         DEBUG(10,("handle_aio_write_complete: "
564                                   "aio_write_behind completed for file %s\n",
565                                   fsp_str_dbg(fsp)));
566                 }
567                 /* TODO: should no return success in case of an error !!! */
568                 TALLOC_FREE(aio_ex);
569                 return;
570         }
571
572         /* We don't need outsize or set_message here as we've already set the
573            fixed size length when we set up the aio call. */
574
575         if (nwritten == -1) {
576                 DEBUG(3, ("handle_aio_write: file %s wanted %u bytes. "
577                           "nwritten == %d. Error = %s\n",
578                           fsp_str_dbg(fsp), (unsigned int)numtowrite,
579                           (int)nwritten, strerror(err)));
580
581                 ERROR_NT(map_nt_error_from_unix(err));
582                 srv_set_message(outbuf,0,0,true);
583         } else {
584                 SSVAL(outbuf,smb_vwv2,nwritten);
585                 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
586                 if (nwritten < (ssize_t)numtowrite) {
587                         SCVAL(outbuf,smb_rcls,ERRHRD);
588                         SSVAL(outbuf,smb_err,ERRdiskfull);
589                 }
590
591                 DEBUG(3,("handle_aio_write: %s, num=%d wrote=%d\n",
592                          fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
593
594                 aio_ex->fsp->fh->pos = aio_ex->offset + nwritten;
595         }
596
597         show_msg(outbuf);
598         if (!srv_send_smb(aio_ex->smbreq->xconn, outbuf,
599                           true, aio_ex->smbreq->seqnum+1,
600                           IS_CONN_ENCRYPTED(fsp->conn),
601                           NULL)) {
602                 exit_server_cleanly("handle_aio_write_complete: "
603                                     "srv_send_smb failed.");
604         }
605
606         DEBUG(10, ("handle_aio_write_complete: scheduled aio_write completed "
607                    "for file %s, offset %.0f, requested %u, written = %u\n",
608                    fsp_str_dbg(fsp), (double)aio_ex->offset,
609                    (unsigned int)numtowrite, (unsigned int)nwritten));
610
611         TALLOC_FREE(aio_ex);
612 }
613
614 bool cancel_smb2_aio(struct smb_request *smbreq)
615 {
616         struct smbd_smb2_request *smb2req = smbreq->smb2req;
617         struct aio_extra *aio_ex = NULL;
618
619         if (smb2req) {
620                 aio_ex = talloc_get_type(smbreq->async_priv,
621                                          struct aio_extra);
622         }
623
624         if (aio_ex == NULL) {
625                 return false;
626         }
627
628         if (aio_ex->fsp == NULL) {
629                 return false;
630         }
631
632         /*
633          * We let the aio request run and don't try to cancel it which means
634          * processing of the SMB2 request must continue as normal, cf MS-SMB2
635          * 3.3.5.16:
636          *
637          *   If the target request is not successfully canceled, processing of
638          *   the target request MUST continue and no response is sent to the
639          *   cancel request.
640          */
641
642         return false;
643 }
644
645 static void aio_pread_smb2_done(struct tevent_req *req);
646
647 /****************************************************************************
648  Set up an aio request from a SMB2 read call.
649 *****************************************************************************/
650
651 NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
652                                 struct smb_request *smbreq,
653                                 files_struct *fsp,
654                                 TALLOC_CTX *ctx,
655                                 DATA_BLOB *preadbuf,
656                                 off_t startpos,
657                                 size_t smb_maxcnt)
658 {
659         struct aio_extra *aio_ex;
660         size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
661         struct tevent_req *req;
662
663         if (fsp->base_fsp != NULL) {
664                 /* No AIO on streams yet */
665                 DEBUG(10, ("AIO on streams not yet supported\n"));
666                 return NT_STATUS_RETRY;
667         }
668
669         if (fsp->op == NULL) {
670                 /* No AIO on internal opens. */
671                 return NT_STATUS_RETRY;
672         }
673
674         if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
675             && !SMB_VFS_AIO_FORCE(fsp)) {
676                 /* Too small a read for aio request. */
677                 DEBUG(10,("smb2: read size (%u) too small "
678                         "for minimum aio_read of %u\n",
679                         (unsigned int)smb_maxcnt,
680                         (unsigned int)min_aio_read_size ));
681                 return NT_STATUS_RETRY;
682         }
683
684         if (smbd_smb2_is_compound(smbreq->smb2req)) {
685                 return NT_STATUS_RETRY;
686         }
687
688         /* Create the out buffer. */
689         *preadbuf = data_blob_talloc(ctx, NULL, smb_maxcnt);
690         if (preadbuf->data == NULL) {
691                 return NT_STATUS_NO_MEMORY;
692         }
693
694         if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
695                 return NT_STATUS_NO_MEMORY;
696         }
697
698         init_strict_lock_struct(fsp, fsp->op->global->open_persistent_id,
699                 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
700                 &aio_ex->lock);
701
702         /* Take the lock until the AIO completes. */
703         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
704                 TALLOC_FREE(aio_ex);
705                 return NT_STATUS_FILE_LOCK_CONFLICT;
706         }
707
708         aio_ex->nbyte = smb_maxcnt;
709         aio_ex->offset = startpos;
710
711         req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
712                                  preadbuf->data, smb_maxcnt, startpos);
713         if (req == NULL) {
714                 DEBUG(0, ("smb2: SMB_VFS_PREAD_SEND failed. "
715                           "Error %s\n", strerror(errno)));
716                 TALLOC_FREE(aio_ex);
717                 return NT_STATUS_RETRY;
718         }
719         tevent_req_set_callback(req, aio_pread_smb2_done, aio_ex);
720
721         if (!aio_add_req_to_fsp(fsp, req)) {
722                 DEBUG(1, ("Could not add req to fsp\n"));
723                 TALLOC_FREE(aio_ex);
724                 return NT_STATUS_RETRY;
725         }
726
727         /* We don't need talloc_move here as both aio_ex and
728          * smbreq are children of smbreq->smb2req. */
729         aio_ex->smbreq = smbreq;
730         smbreq->async_priv = aio_ex;
731
732         DEBUG(10,("smb2: scheduled aio_read for file %s, "
733                 "offset %.0f, len = %u (mid = %u)\n",
734                 fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
735                 (unsigned int)aio_ex->smbreq->mid ));
736
737         return NT_STATUS_OK;
738 }
739
740 static void aio_pread_smb2_done(struct tevent_req *req)
741 {
742         struct aio_extra *aio_ex = tevent_req_callback_data(
743                 req, struct aio_extra);
744         struct tevent_req *subreq = aio_ex->smbreq->smb2req->subreq;
745         files_struct *fsp = aio_ex->fsp;
746         NTSTATUS status;
747         ssize_t nread;
748         struct vfs_aio_state vfs_aio_state = { 0 };
749
750         nread = SMB_VFS_PREAD_RECV(req, &vfs_aio_state);
751         TALLOC_FREE(req);
752
753         DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
754                    (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
755
756         /* Common error or success code processing for async or sync
757            read returns. */
758
759         status = smb2_read_complete(subreq, nread, vfs_aio_state.error);
760
761         if (nread > 0) {
762                 fsp->fh->pos = aio_ex->offset + nread;
763                 fsp->fh->position_information = fsp->fh->pos;
764         }
765
766         DEBUG(10, ("smb2: scheduled aio_read completed "
767                    "for file %s, offset %.0f, len = %u "
768                    "(errcode = %d, NTSTATUS = %s)\n",
769                    fsp_str_dbg(aio_ex->fsp),
770                    (double)aio_ex->offset,
771                    (unsigned int)nread,
772                    vfs_aio_state.error, nt_errstr(status)));
773
774         if (!NT_STATUS_IS_OK(status)) {
775                 tevent_req_nterror(subreq, status);
776                 return;
777         }
778         tevent_req_done(subreq);
779 }
780
781 static void aio_pwrite_smb2_done(struct tevent_req *req);
782
783 /****************************************************************************
784  Set up an aio request from a SMB2write call.
785 *****************************************************************************/
786
787 NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
788                                 struct smb_request *smbreq,
789                                 files_struct *fsp,
790                                 uint64_t in_offset,
791                                 DATA_BLOB in_data,
792                                 bool write_through)
793 {
794         struct aio_extra *aio_ex = NULL;
795         size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
796         struct tevent_req *req;
797
798         if (fsp->base_fsp != NULL) {
799                 /* No AIO on streams yet */
800                 DEBUG(10, ("AIO on streams not yet supported\n"));
801                 return NT_STATUS_RETRY;
802         }
803
804         if (fsp->op == NULL) {
805                 /* No AIO on internal opens. */
806                 return NT_STATUS_RETRY;
807         }
808
809         if ((!min_aio_write_size || (in_data.length < min_aio_write_size))
810             && !SMB_VFS_AIO_FORCE(fsp)) {
811                 /* Too small a write for aio request. */
812                 DEBUG(10,("smb2: write size (%u) too "
813                         "small for minimum aio_write of %u\n",
814                         (unsigned int)in_data.length,
815                         (unsigned int)min_aio_write_size ));
816                 return NT_STATUS_RETRY;
817         }
818
819         if (smbd_smb2_is_compound(smbreq->smb2req)) {
820                 return NT_STATUS_RETRY;
821         }
822
823         if (smbreq->unread_bytes) {
824                 /* Can't do async with recvfile. */
825                 return NT_STATUS_RETRY;
826         }
827
828         if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
829                 return NT_STATUS_NO_MEMORY;
830         }
831
832         aio_ex->write_through = write_through;
833
834         init_strict_lock_struct(fsp, fsp->op->global->open_persistent_id,
835                 in_offset, (uint64_t)in_data.length, WRITE_LOCK,
836                 &aio_ex->lock);
837
838         /* Take the lock until the AIO completes. */
839         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
840                 TALLOC_FREE(aio_ex);
841                 return NT_STATUS_FILE_LOCK_CONFLICT;
842         }
843
844         aio_ex->nbyte = in_data.length;
845         aio_ex->offset = in_offset;
846
847         req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
848                                 in_data.data, in_data.length, in_offset,
849                                 write_through);
850         if (req == NULL) {
851                 DEBUG(3, ("smb2: SMB_VFS_PWRITE_SEND failed. "
852                           "Error %s\n", strerror(errno)));
853                 TALLOC_FREE(aio_ex);
854                 return NT_STATUS_RETRY;
855         }
856         tevent_req_set_callback(req, aio_pwrite_smb2_done, aio_ex);
857
858         if (!aio_add_req_to_fsp(fsp, req)) {
859                 DEBUG(1, ("Could not add req to fsp\n"));
860                 TALLOC_FREE(aio_ex);
861                 return NT_STATUS_RETRY;
862         }
863
864         /* We don't need talloc_move here as both aio_ex and
865         * smbreq are children of smbreq->smb2req. */
866         aio_ex->smbreq = smbreq;
867         smbreq->async_priv = aio_ex;
868
869         /* This should actually be improved to span the write. */
870         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
871         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
872
873         /*
874          * We don't want to do write behind due to ownership
875          * issues of the request structs. Maybe add it if I
876          * figure those out. JRA.
877          */
878
879         DEBUG(10,("smb2: scheduled aio_write for file "
880                 "%s, offset %.0f, len = %u (mid = %u)\n",
881                 fsp_str_dbg(fsp),
882                 (double)in_offset,
883                 (unsigned int)in_data.length,
884                 (unsigned int)aio_ex->smbreq->mid));
885
886         return NT_STATUS_OK;
887 }
888
889 static void aio_pwrite_smb2_done(struct tevent_req *req)
890 {
891         struct aio_extra *aio_ex = tevent_req_callback_data(
892                 req, struct aio_extra);
893         ssize_t numtowrite = aio_ex->nbyte;
894         struct tevent_req *subreq = aio_ex->smbreq->smb2req->subreq;
895         files_struct *fsp = aio_ex->fsp;
896         NTSTATUS status;
897         ssize_t nwritten;
898         int err = 0;
899
900         nwritten = pwrite_fsync_recv(req, &err);
901         TALLOC_FREE(req);
902
903         DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
904                    (nwritten == -1) ? strerror(err) : "no error"));
905
906         mark_file_modified(fsp);
907
908         status = smb2_write_complete_nosync(subreq, nwritten, err);
909
910         DEBUG(10, ("smb2: scheduled aio_write completed "
911                    "for file %s, offset %.0f, requested %u, "
912                    "written = %u (errcode = %d, NTSTATUS = %s)\n",
913                    fsp_str_dbg(fsp),
914                    (double)aio_ex->offset,
915                    (unsigned int)numtowrite,
916                    (unsigned int)nwritten,
917                    err, nt_errstr(status)));
918
919         if (!NT_STATUS_IS_OK(status)) {
920                 tevent_req_nterror(subreq, status);
921                 return;
922         }
923         tevent_req_done(subreq);
924 }