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