LCOV - code coverage report
Current view: top level - source3/smbd - aio.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 295 391 75.4 %
Date: 2021-09-23 10:06:22 Functions: 16 17 94.1 %

          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             : }

Generated by: LCOV version 1.13