s3: Make us survive base-delaywrite with aio enabled
[Samba/gebeck_regimport.git] / source3 / smbd / aio.c
blob9cb690d892f6f3ad51514e8a44d2e9d5f538704d
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.
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.
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.
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/>.
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../lib/util/tevent_ntstatus.h"
26 /****************************************************************************
27 The buffer we keep around whilst an aio request is in process.
28 *****************************************************************************/
30 struct aio_extra {
31 files_struct *fsp;
32 struct smb_request *smbreq;
33 DATA_BLOB outbuf;
34 struct lock_struct lock;
35 size_t nbyte;
36 off_t offset;
37 bool write_through;
40 /****************************************************************************
41 Accessor function to return write_through state.
42 *****************************************************************************/
44 bool aio_write_through_requested(struct aio_extra *aio_ex)
46 return aio_ex->write_through;
49 static int aio_extra_destructor(struct aio_extra *aio_ex)
51 outstanding_aio_calls--;
52 return 0;
55 /****************************************************************************
56 Create the extended aio struct we must keep around for the lifetime
57 of the aio call.
58 *****************************************************************************/
60 static struct aio_extra *create_aio_extra(TALLOC_CTX *mem_ctx,
61 files_struct *fsp,
62 size_t buflen)
64 struct aio_extra *aio_ex = talloc_zero(mem_ctx, struct aio_extra);
66 if (!aio_ex) {
67 return NULL;
70 /* The output buffer stored in the aio_ex is the start of
71 the smb return buffer. The buffer used in the acb
72 is the start of the reply data portion of that buffer. */
74 if (buflen) {
75 aio_ex->outbuf = data_blob_talloc(aio_ex, NULL, buflen);
76 if (!aio_ex->outbuf.data) {
77 TALLOC_FREE(aio_ex);
78 return NULL;
81 talloc_set_destructor(aio_ex, aio_extra_destructor);
82 aio_ex->fsp = fsp;
83 outstanding_aio_calls++;
84 return aio_ex;
87 struct aio_req_fsp_link {
88 files_struct *fsp;
89 struct tevent_req *req;
92 static int aio_del_req_from_fsp(struct aio_req_fsp_link *lnk)
94 unsigned i;
95 files_struct *fsp = lnk->fsp;
96 struct tevent_req *req = lnk->req;
98 for (i=0; i<fsp->num_aio_requests; i++) {
99 if (fsp->aio_requests[i] == req) {
100 break;
103 if (i == fsp->num_aio_requests) {
104 DEBUG(1, ("req %p not found in fsp %p\n", req, fsp));
105 return 0;
107 fsp->num_aio_requests -= 1;
108 fsp->aio_requests[i] = fsp->aio_requests[fsp->num_aio_requests];
109 return 0;
112 static bool aio_add_req_to_fsp(files_struct *fsp, struct tevent_req *req)
114 size_t array_len;
115 struct aio_req_fsp_link *lnk;
117 lnk = talloc(req, struct aio_req_fsp_link);
118 if (lnk == NULL) {
119 return false;
122 array_len = talloc_array_length(fsp->aio_requests);
123 if (array_len <= fsp->num_aio_requests) {
124 struct tevent_req **tmp;
126 tmp = talloc_realloc(
127 fsp, fsp->aio_requests, struct tevent_req *,
128 fsp->num_aio_requests+1);
129 if (tmp == NULL) {
130 TALLOC_FREE(lnk);
131 return false;
133 fsp->aio_requests = tmp;
135 fsp->aio_requests[fsp->num_aio_requests] = req;
136 fsp->num_aio_requests += 1;
138 lnk->fsp = fsp;
139 lnk->req = req;
140 talloc_set_destructor(lnk, aio_del_req_from_fsp);
142 return true;
145 static void aio_pread_smb1_done(struct tevent_req *req);
147 /****************************************************************************
148 Set up an aio request from a SMBreadX call.
149 *****************************************************************************/
151 NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
152 struct smb_request *smbreq,
153 files_struct *fsp, off_t startpos,
154 size_t smb_maxcnt)
156 struct aio_extra *aio_ex;
157 size_t bufsize;
158 size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
159 struct tevent_req *req;
161 if (fsp->base_fsp != NULL) {
162 /* No AIO on streams yet */
163 DEBUG(10, ("AIO on streams not yet supported\n"));
164 return NT_STATUS_RETRY;
167 if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
168 && !SMB_VFS_AIO_FORCE(fsp)) {
169 /* Too small a read for aio request. */
170 DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
171 "for minimum aio_read of %u\n",
172 (unsigned int)smb_maxcnt,
173 (unsigned int)min_aio_read_size ));
174 return NT_STATUS_RETRY;
177 /* Only do this on non-chained and non-chaining reads not using the
178 * write cache. */
179 if (req_is_in_chain(smbreq) || (lp_write_cache_size(SNUM(conn)) != 0)) {
180 return NT_STATUS_RETRY;
183 if (outstanding_aio_calls >= aio_pending_size) {
184 DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
185 "activities outstanding.\n",
186 outstanding_aio_calls ));
187 return NT_STATUS_RETRY;
190 /* The following is safe from integer wrap as we've already checked
191 smb_maxcnt is 128k or less. Wct is 12 for read replies */
193 bufsize = smb_size + 12 * 2 + smb_maxcnt;
195 if ((aio_ex = create_aio_extra(NULL, fsp, bufsize)) == NULL) {
196 DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
197 return NT_STATUS_NO_MEMORY;
200 construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
201 srv_set_message((char *)aio_ex->outbuf.data, 12, 0, True);
202 SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
204 init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
205 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
206 &aio_ex->lock);
208 /* Take the lock until the AIO completes. */
209 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
210 TALLOC_FREE(aio_ex);
211 return NT_STATUS_FILE_LOCK_CONFLICT;
214 aio_ex->nbyte = smb_maxcnt;
215 aio_ex->offset = startpos;
217 req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx,
218 fsp, smb_buf(aio_ex->outbuf.data),
219 smb_maxcnt, startpos);
220 if (req == NULL) {
221 DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
222 "Error %s\n", strerror(errno) ));
223 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
224 TALLOC_FREE(aio_ex);
225 return NT_STATUS_RETRY;
227 tevent_req_set_callback(req, aio_pread_smb1_done, aio_ex);
229 if (!aio_add_req_to_fsp(fsp, req)) {
230 DEBUG(1, ("Could not add req to fsp\n"));
231 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
232 TALLOC_FREE(aio_ex);
233 return NT_STATUS_RETRY;
236 aio_ex->smbreq = talloc_move(aio_ex, &smbreq);
238 DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, "
239 "offset %.0f, len = %u (mid = %u)\n",
240 fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
241 (unsigned int)aio_ex->smbreq->mid ));
243 return NT_STATUS_OK;
246 static void aio_pread_smb1_done(struct tevent_req *req)
248 struct aio_extra *aio_ex = tevent_req_callback_data(
249 req, struct aio_extra);
250 files_struct *fsp = aio_ex->fsp;
251 int outsize;
252 char *outbuf = (char *)aio_ex->outbuf.data;
253 char *data = smb_buf(outbuf);
254 ssize_t nread;
255 int err;
257 nread = SMB_VFS_PREAD_RECV(req, &err);
258 TALLOC_FREE(req);
260 DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
261 (nread == -1) ? strerror(err) : "no error"));
263 if (fsp == NULL) {
264 DEBUG( 3, ("aio_pread_smb1_done: file closed whilst "
265 "aio outstanding (mid[%llu]).\n",
266 (unsigned long long)aio_ex->smbreq->mid));
267 TALLOC_FREE(aio_ex);
268 return;
271 /* Unlock now we're done. */
272 SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
274 if (nread < 0) {
275 DEBUG( 3, ("handle_aio_read_complete: file %s nread == %d. "
276 "Error = %s\n", fsp_str_dbg(fsp), (int)nread,
277 strerror(err)));
279 ERROR_NT(map_nt_error_from_unix(err));
280 outsize = srv_set_message(outbuf,0,0,true);
281 } else {
282 outsize = srv_set_message(outbuf, 12, nread, False);
283 SSVAL(outbuf,smb_vwv2, 0xFFFF); /* Remaining - must be * -1. */
284 SSVAL(outbuf,smb_vwv5, nread);
285 SSVAL(outbuf,smb_vwv6, smb_offset(data,outbuf));
286 SSVAL(outbuf,smb_vwv7, ((nread >> 16) & 1));
287 SSVAL(smb_buf(outbuf), -2, nread);
289 aio_ex->fsp->fh->pos = aio_ex->offset + nread;
290 aio_ex->fsp->fh->position_information = aio_ex->fsp->fh->pos;
292 DEBUG( 3, ("handle_aio_read_complete file %s max=%d "
293 "nread=%d\n", fsp_str_dbg(fsp),
294 (int)aio_ex->nbyte, (int)nread ) );
297 smb_setlen(outbuf, outsize - 4);
298 show_msg(outbuf);
299 if (!srv_send_smb(aio_ex->smbreq->sconn, outbuf,
300 true, aio_ex->smbreq->seqnum+1,
301 IS_CONN_ENCRYPTED(fsp->conn), NULL)) {
302 exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
303 "failed.");
306 DEBUG(10, ("handle_aio_read_complete: scheduled aio_read completed "
307 "for file %s, offset %.0f, len = %u\n",
308 fsp_str_dbg(fsp), (double)aio_ex->offset,
309 (unsigned int)nread));
311 TALLOC_FREE(aio_ex);
314 static void aio_pwrite_smb1_done(struct tevent_req *req);
316 /****************************************************************************
317 Set up an aio request from a SMBwriteX call.
318 *****************************************************************************/
320 NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
321 struct smb_request *smbreq,
322 files_struct *fsp, const char *data,
323 off_t startpos,
324 size_t numtowrite)
326 struct aio_extra *aio_ex;
327 size_t bufsize;
328 size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
329 struct tevent_req *req;
331 if (fsp->base_fsp != NULL) {
332 /* No AIO on streams yet */
333 DEBUG(10, ("AIO on streams not yet supported\n"));
334 return NT_STATUS_RETRY;
337 if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
338 && !SMB_VFS_AIO_FORCE(fsp)) {
339 /* Too small a write for aio request. */
340 DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
341 "small for minimum aio_write of %u\n",
342 (unsigned int)numtowrite,
343 (unsigned int)min_aio_write_size ));
344 return NT_STATUS_RETRY;
347 /* Only do this on non-chained and non-chaining writes not using the
348 * write cache. */
349 if (req_is_in_chain(smbreq) || (lp_write_cache_size(SNUM(conn)) != 0)) {
350 return NT_STATUS_RETRY;
353 if (outstanding_aio_calls >= aio_pending_size) {
354 DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
355 "activities outstanding.\n",
356 outstanding_aio_calls ));
357 DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
358 "aio_write for file %s, offset %.0f, len = %u "
359 "(mid = %u)\n",
360 fsp_str_dbg(fsp), (double)startpos,
361 (unsigned int)numtowrite,
362 (unsigned int)smbreq->mid ));
363 return NT_STATUS_RETRY;
366 bufsize = smb_size + 6*2;
368 if (!(aio_ex = create_aio_extra(NULL, fsp, bufsize))) {
369 DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
370 return NT_STATUS_NO_MEMORY;
372 aio_ex->write_through = BITSETW(smbreq->vwv+7,0);
374 construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
375 srv_set_message((char *)aio_ex->outbuf.data, 6, 0, True);
376 SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
378 init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
379 (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
380 &aio_ex->lock);
382 /* Take the lock until the AIO completes. */
383 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
384 TALLOC_FREE(aio_ex);
385 return NT_STATUS_FILE_LOCK_CONFLICT;
388 aio_ex->nbyte = numtowrite;
389 aio_ex->offset = startpos;
391 req = SMB_VFS_PWRITE_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
392 data, numtowrite, startpos);
393 if (req == NULL) {
394 DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
395 "Error %s\n", strerror(errno) ));
396 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
397 TALLOC_FREE(aio_ex);
398 return NT_STATUS_RETRY;
400 tevent_req_set_callback(req, aio_pwrite_smb1_done, aio_ex);
402 if (!aio_add_req_to_fsp(fsp, req)) {
403 DEBUG(1, ("Could not add req to fsp\n"));
404 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
405 TALLOC_FREE(aio_ex);
406 return NT_STATUS_RETRY;
409 aio_ex->smbreq = talloc_move(aio_ex, &smbreq);
411 /* This should actually be improved to span the write. */
412 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
413 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
415 if (!aio_ex->write_through && !lp_syncalways(SNUM(fsp->conn))
416 && fsp->aio_write_behind) {
417 /* Lie to the client and immediately claim we finished the
418 * write. */
419 SSVAL(aio_ex->outbuf.data,smb_vwv2,numtowrite);
420 SSVAL(aio_ex->outbuf.data,smb_vwv4,(numtowrite>>16)&1);
421 show_msg((char *)aio_ex->outbuf.data);
422 if (!srv_send_smb(aio_ex->smbreq->sconn,
423 (char *)aio_ex->outbuf.data,
424 true, aio_ex->smbreq->seqnum+1,
425 IS_CONN_ENCRYPTED(fsp->conn),
426 &aio_ex->smbreq->pcd)) {
427 exit_server_cleanly("schedule_aio_write_and_X: "
428 "srv_send_smb failed.");
430 DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
431 "behind for file %s\n", fsp_str_dbg(fsp)));
434 DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file "
435 "%s, offset %.0f, len = %u (mid = %u) "
436 "outstanding_aio_calls = %d\n",
437 fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
438 (unsigned int)aio_ex->smbreq->mid, outstanding_aio_calls ));
440 return NT_STATUS_OK;
443 static void aio_pwrite_smb1_done(struct tevent_req *req)
445 struct aio_extra *aio_ex = tevent_req_callback_data(
446 req, struct aio_extra);
447 files_struct *fsp = aio_ex->fsp;
448 char *outbuf = (char *)aio_ex->outbuf.data;
449 ssize_t numtowrite = aio_ex->nbyte;
450 ssize_t nwritten;
451 int err;
453 nwritten = SMB_VFS_PWRITE_RECV(req, &err);
454 TALLOC_FREE(req);
456 DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
457 (nwritten == -1) ? strerror(err) : "no error"));
459 if (fsp == NULL) {
460 DEBUG( 3, ("aio_pwrite_smb1_done: file closed whilst "
461 "aio outstanding (mid[%llu]).\n",
462 (unsigned long long)aio_ex->smbreq->mid));
463 TALLOC_FREE(aio_ex);
464 return;
467 /* Unlock now we're done. */
468 SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
470 mark_file_modified(fsp);
472 if (fsp->aio_write_behind) {
474 if (nwritten != numtowrite) {
475 if (nwritten == -1) {
476 DEBUG(5,("handle_aio_write_complete: "
477 "aio_write_behind failed ! File %s "
478 "is corrupt ! Error %s\n",
479 fsp_str_dbg(fsp), strerror(err)));
480 } else {
481 DEBUG(0,("handle_aio_write_complete: "
482 "aio_write_behind failed ! File %s "
483 "is corrupt ! Wanted %u bytes but "
484 "only wrote %d\n", fsp_str_dbg(fsp),
485 (unsigned int)numtowrite,
486 (int)nwritten ));
488 } else {
489 DEBUG(10,("handle_aio_write_complete: "
490 "aio_write_behind completed for file %s\n",
491 fsp_str_dbg(fsp)));
493 /* TODO: should no return success in case of an error !!! */
494 TALLOC_FREE(aio_ex);
495 return;
498 /* We don't need outsize or set_message here as we've already set the
499 fixed size length when we set up the aio call. */
501 if (nwritten == -1) {
502 DEBUG(3, ("handle_aio_write: file %s wanted %u bytes. "
503 "nwritten == %d. Error = %s\n",
504 fsp_str_dbg(fsp), (unsigned int)numtowrite,
505 (int)nwritten, strerror(err)));
507 ERROR_NT(map_nt_error_from_unix(err));
508 srv_set_message(outbuf,0,0,true);
509 } else {
510 NTSTATUS status;
512 SSVAL(outbuf,smb_vwv2,nwritten);
513 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
514 if (nwritten < (ssize_t)numtowrite) {
515 SCVAL(outbuf,smb_rcls,ERRHRD);
516 SSVAL(outbuf,smb_err,ERRdiskfull);
519 DEBUG(3,("handle_aio_write: %s, num=%d wrote=%d\n",
520 fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
521 status = sync_file(fsp->conn,fsp, aio_ex->write_through);
522 if (!NT_STATUS_IS_OK(status)) {
523 ERROR_BOTH(map_nt_error_from_unix(errno),
524 ERRHRD, ERRdiskfull);
525 srv_set_message(outbuf,0,0,true);
526 DEBUG(5, ("handle_aio_write: sync_file for %s "
527 "returned %s\n",
528 fsp_str_dbg(fsp), nt_errstr(status)));
531 aio_ex->fsp->fh->pos = aio_ex->offset + nwritten;
534 show_msg(outbuf);
535 if (!srv_send_smb(aio_ex->smbreq->sconn, outbuf,
536 true, aio_ex->smbreq->seqnum+1,
537 IS_CONN_ENCRYPTED(fsp->conn),
538 NULL)) {
539 exit_server_cleanly("handle_aio_write_complete: "
540 "srv_send_smb failed.");
543 DEBUG(10, ("handle_aio_write_complete: scheduled aio_write completed "
544 "for file %s, offset %.0f, requested %u, written = %u\n",
545 fsp_str_dbg(fsp), (double)aio_ex->offset,
546 (unsigned int)numtowrite, (unsigned int)nwritten));
548 TALLOC_FREE(aio_ex);
551 bool cancel_smb2_aio(struct smb_request *smbreq)
553 struct smbd_smb2_request *smb2req = smbreq->smb2req;
554 struct aio_extra *aio_ex = NULL;
556 if (smb2req) {
557 aio_ex = talloc_get_type(smbreq->async_priv,
558 struct aio_extra);
561 if (aio_ex == NULL) {
562 return false;
565 if (aio_ex->fsp == NULL) {
566 return false;
570 * We let the aio request run. Setting fsp to NULL has the
571 * effect that the _done routines don't send anything out.
574 aio_ex->fsp = NULL;
575 return true;
578 static void aio_pread_smb2_done(struct tevent_req *req);
580 /****************************************************************************
581 Set up an aio request from a SMB2 read call.
582 *****************************************************************************/
584 NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
585 struct smb_request *smbreq,
586 files_struct *fsp,
587 TALLOC_CTX *ctx,
588 DATA_BLOB *preadbuf,
589 off_t startpos,
590 size_t smb_maxcnt)
592 struct aio_extra *aio_ex;
593 size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
594 struct tevent_req *req;
596 if (fsp->base_fsp != NULL) {
597 /* No AIO on streams yet */
598 DEBUG(10, ("AIO on streams not yet supported\n"));
599 return NT_STATUS_RETRY;
602 if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
603 && !SMB_VFS_AIO_FORCE(fsp)) {
604 /* Too small a read for aio request. */
605 DEBUG(10,("smb2: read size (%u) too small "
606 "for minimum aio_read of %u\n",
607 (unsigned int)smb_maxcnt,
608 (unsigned int)min_aio_read_size ));
609 return NT_STATUS_RETRY;
612 /* Only do this on reads not using the write cache. */
613 if (lp_write_cache_size(SNUM(conn)) != 0) {
614 return NT_STATUS_RETRY;
617 if (outstanding_aio_calls >= aio_pending_size) {
618 DEBUG(10,("smb2: Already have %d aio "
619 "activities outstanding.\n",
620 outstanding_aio_calls ));
621 return NT_STATUS_RETRY;
624 /* Create the out buffer. */
625 *preadbuf = data_blob_talloc(ctx, NULL, smb_maxcnt);
626 if (preadbuf->data == NULL) {
627 return NT_STATUS_NO_MEMORY;
630 if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
631 return NT_STATUS_NO_MEMORY;
634 init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
635 (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
636 &aio_ex->lock);
638 /* Take the lock until the AIO completes. */
639 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
640 TALLOC_FREE(aio_ex);
641 return NT_STATUS_FILE_LOCK_CONFLICT;
644 aio_ex->nbyte = smb_maxcnt;
645 aio_ex->offset = startpos;
647 req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
648 preadbuf->data, smb_maxcnt, startpos);
649 if (req == NULL) {
650 DEBUG(0, ("smb2: SMB_VFS_PREAD_SEND failed. "
651 "Error %s\n", strerror(errno)));
652 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
653 TALLOC_FREE(aio_ex);
654 return NT_STATUS_RETRY;
656 tevent_req_set_callback(req, aio_pread_smb2_done, aio_ex);
658 if (!aio_add_req_to_fsp(fsp, req)) {
659 DEBUG(1, ("Could not add req to fsp\n"));
660 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
661 TALLOC_FREE(aio_ex);
662 return NT_STATUS_RETRY;
665 /* We don't need talloc_move here as both aio_ex and
666 * smbreq are children of smbreq->smb2req. */
667 aio_ex->smbreq = smbreq;
668 smbreq->async_priv = aio_ex;
670 DEBUG(10,("smb2: scheduled aio_read for file %s, "
671 "offset %.0f, len = %u (mid = %u)\n",
672 fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
673 (unsigned int)aio_ex->smbreq->mid ));
675 return NT_STATUS_OK;
678 static void aio_pread_smb2_done(struct tevent_req *req)
680 struct aio_extra *aio_ex = tevent_req_callback_data(
681 req, struct aio_extra);
682 struct tevent_req *subreq = aio_ex->smbreq->smb2req->subreq;
683 files_struct *fsp = aio_ex->fsp;
684 NTSTATUS status;
685 ssize_t nread;
686 int err = 0;
688 nread = SMB_VFS_PREAD_RECV(req, &err);
689 TALLOC_FREE(req);
691 DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
692 (nread == -1) ? strerror(err) : "no error"));
694 if (fsp == NULL) {
695 DEBUG( 3, ("aio_pread_smb2_done: file closed whilst "
696 "aio outstanding (mid[%llu]).\n",
697 (unsigned long long)aio_ex->smbreq->mid));
698 TALLOC_FREE(aio_ex);
699 return;
702 /* Unlock now we're done. */
703 SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
705 mark_file_modified(fsp);
707 /* Common error or success code processing for async or sync
708 read returns. */
710 status = smb2_read_complete(subreq, nread, err);
712 if (nread > 0) {
713 fsp->fh->pos = aio_ex->offset + nread;
714 fsp->fh->position_information = fsp->fh->pos;
717 DEBUG(10, ("smb2: scheduled aio_read completed "
718 "for file %s, offset %.0f, len = %u "
719 "(errcode = %d, NTSTATUS = %s)\n",
720 fsp_str_dbg(aio_ex->fsp),
721 (double)aio_ex->offset,
722 (unsigned int)nread,
723 err, nt_errstr(status)));
725 if (!NT_STATUS_IS_OK(status)) {
726 tevent_req_nterror(subreq, status);
727 return;
729 tevent_req_done(subreq);
732 static void aio_pwrite_smb2_done(struct tevent_req *req);
734 /****************************************************************************
735 Set up an aio request from a SMB2write call.
736 *****************************************************************************/
738 NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
739 struct smb_request *smbreq,
740 files_struct *fsp,
741 uint64_t in_offset,
742 DATA_BLOB in_data,
743 bool write_through)
745 struct aio_extra *aio_ex = NULL;
746 size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
747 struct tevent_req *req;
749 if (fsp->base_fsp != NULL) {
750 /* No AIO on streams yet */
751 DEBUG(10, ("AIO on streams not yet supported\n"));
752 return NT_STATUS_RETRY;
755 if ((!min_aio_write_size || (in_data.length < min_aio_write_size))
756 && !SMB_VFS_AIO_FORCE(fsp)) {
757 /* Too small a write for aio request. */
758 DEBUG(10,("smb2: write size (%u) too "
759 "small for minimum aio_write of %u\n",
760 (unsigned int)in_data.length,
761 (unsigned int)min_aio_write_size ));
762 return NT_STATUS_RETRY;
765 /* Only do this on writes not using the write cache. */
766 if (lp_write_cache_size(SNUM(conn)) != 0) {
767 return NT_STATUS_RETRY;
770 if (outstanding_aio_calls >= aio_pending_size) {
771 DEBUG(3,("smb2: Already have %d aio "
772 "activities outstanding.\n",
773 outstanding_aio_calls ));
774 return NT_STATUS_RETRY;
777 if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
778 return NT_STATUS_NO_MEMORY;
781 aio_ex->write_through = write_through;
783 init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
784 in_offset, (uint64_t)in_data.length, WRITE_LOCK,
785 &aio_ex->lock);
787 /* Take the lock until the AIO completes. */
788 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
789 TALLOC_FREE(aio_ex);
790 return NT_STATUS_FILE_LOCK_CONFLICT;
793 aio_ex->nbyte = in_data.length;
794 aio_ex->offset = in_offset;
796 req = SMB_VFS_PWRITE_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
797 in_data.data, in_data.length, in_offset);
798 if (req == NULL) {
799 DEBUG(3, ("smb2: SMB_VFS_PWRITE_SEND failed. "
800 "Error %s\n", strerror(errno)));
801 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
802 TALLOC_FREE(aio_ex);
803 return NT_STATUS_RETRY;
805 tevent_req_set_callback(req, aio_pwrite_smb2_done, aio_ex);
807 if (!aio_add_req_to_fsp(fsp, req)) {
808 DEBUG(1, ("Could not add req to fsp\n"));
809 SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
810 TALLOC_FREE(aio_ex);
811 return NT_STATUS_RETRY;
814 /* We don't need talloc_move here as both aio_ex and
815 * smbreq are children of smbreq->smb2req. */
816 aio_ex->smbreq = smbreq;
817 smbreq->async_priv = aio_ex;
819 /* This should actually be improved to span the write. */
820 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
821 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
824 * We don't want to do write behind due to ownership
825 * issues of the request structs. Maybe add it if I
826 * figure those out. JRA.
829 DEBUG(10,("smb2: scheduled aio_write for file "
830 "%s, offset %.0f, len = %u (mid = %u) "
831 "outstanding_aio_calls = %d\n",
832 fsp_str_dbg(fsp),
833 (double)in_offset,
834 (unsigned int)in_data.length,
835 (unsigned int)aio_ex->smbreq->mid,
836 outstanding_aio_calls ));
838 return NT_STATUS_OK;
841 static void aio_pwrite_smb2_done(struct tevent_req *req)
843 struct aio_extra *aio_ex = tevent_req_callback_data(
844 req, struct aio_extra);
845 ssize_t numtowrite = aio_ex->nbyte;
846 struct tevent_req *subreq = aio_ex->smbreq->smb2req->subreq;
847 files_struct *fsp = aio_ex->fsp;
848 NTSTATUS status;
849 ssize_t nwritten;
850 int err = 0;
852 nwritten = SMB_VFS_PWRITE_RECV(req, &err);
853 TALLOC_FREE(req);
855 DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
856 (nwritten == -1) ? strerror(err) : "no error"));
858 if (fsp == NULL) {
859 DEBUG( 3, ("aio_pwrite_smb2_done: file closed whilst "
860 "aio outstanding (mid[%llu]).\n",
861 (unsigned long long)aio_ex->smbreq->mid));
862 TALLOC_FREE(aio_ex);
863 return;
866 /* Unlock now we're done. */
867 SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
869 status = smb2_write_complete(subreq, nwritten, err);
871 DEBUG(10, ("smb2: scheduled aio_write completed "
872 "for file %s, offset %.0f, requested %u, "
873 "written = %u (errcode = %d, NTSTATUS = %s)\n",
874 fsp_str_dbg(fsp),
875 (double)aio_ex->offset,
876 (unsigned int)numtowrite,
877 (unsigned int)nwritten,
878 err, nt_errstr(status)));
880 if (!NT_STATUS_IS_OK(status)) {
881 tevent_req_nterror(subreq, status);
882 return;
884 tevent_req_done(subreq);
887 /****************************************************************************
888 Handle any aio completion inline.
889 *****************************************************************************/
891 void aio_fsp_close(files_struct *fsp)
893 unsigned i;
895 for (i=0; i<fsp->num_aio_requests; i++) {
896 struct tevent_req *req = fsp->aio_requests[i];
897 struct aio_extra *aio_ex = tevent_req_callback_data(
898 req, struct aio_extra);
899 aio_ex->fsp = NULL;