LCOV - code coverage report
Current view: top level - source3/smbd - smb2_aio.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 211 260 81.2 %
Date: 2024-04-21 15:09:00 Functions: 12 13 92.3 %

          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             :  Accessor function to return write_through state.
      29             : *****************************************************************************/
      30             : 
      31           0 : bool aio_write_through_requested(struct aio_extra *aio_ex)
      32             : {
      33           0 :         return aio_ex->write_through;
      34             : }
      35             : 
      36             : /****************************************************************************
      37             :  Create the extended aio struct we must keep around for the lifetime
      38             :  of the aio call.
      39             : *****************************************************************************/
      40             : 
      41      199513 : struct aio_extra *create_aio_extra(TALLOC_CTX *mem_ctx,
      42             :                                    files_struct *fsp,
      43             :                                    size_t buflen)
      44             : {
      45      199513 :         struct aio_extra *aio_ex = talloc_zero(mem_ctx, struct aio_extra);
      46             : 
      47      199513 :         if (!aio_ex) {
      48           0 :                 return NULL;
      49             :         }
      50             : 
      51             :         /* The output buffer stored in the aio_ex is the start of
      52             :            the smb return buffer. The buffer used in the acb
      53             :            is the start of the reply data portion of that buffer. */
      54             : 
      55      199513 :         if (buflen) {
      56      142019 :                 aio_ex->outbuf = data_blob_talloc(aio_ex, NULL, buflen);
      57      142019 :                 if (!aio_ex->outbuf.data) {
      58           0 :                         TALLOC_FREE(aio_ex);
      59           0 :                         return NULL;
      60             :                 }
      61             :         }
      62      199513 :         aio_ex->fsp = fsp;
      63      199513 :         return aio_ex;
      64             : }
      65             : 
      66             : struct aio_req_fsp_link {
      67             : #ifdef DEVELOPER
      68             :         struct smbd_server_connection *sconn;
      69             : #endif
      70             :         files_struct *fsp;
      71             :         struct tevent_req *req;
      72             : };
      73             : 
      74      532196 : static int aio_del_req_from_fsp(struct aio_req_fsp_link *lnk)
      75             : {
      76        7212 :         unsigned i;
      77      532196 :         files_struct *fsp = lnk->fsp;
      78      532196 :         struct tevent_req *req = lnk->req;
      79             : 
      80             : #ifdef DEVELOPER
      81      532196 :         struct files_struct *ifsp = NULL;
      82      532196 :         bool found = false;
      83             : 
      84             :         /*
      85             :          * When this is called, lnk->fsp must still exist
      86             :          * on the files list for this connection. Panic if not.
      87             :          */
      88     1134598 :         for (ifsp = lnk->sconn->files; ifsp; ifsp = ifsp->next) {
      89      602402 :                 if (ifsp == fsp) {
      90      532196 :                         found = true;
      91             :                 }
      92             :         }
      93      532196 :         if (!found) {
      94           0 :                 smb_panic("orphaned lnk on fsp aio list.\n");
      95             :         }
      96             : #endif
      97             : 
      98      532795 :         for (i=0; i<fsp->num_aio_requests; i++) {
      99      532795 :                 if (fsp->aio_requests[i] == req) {
     100      524984 :                         break;
     101             :                 }
     102             :         }
     103      532196 :         if (i == fsp->num_aio_requests) {
     104           0 :                 DEBUG(1, ("req %p not found in fsp %p\n", req, fsp));
     105           0 :                 return 0;
     106             :         }
     107      532196 :         fsp->num_aio_requests -= 1;
     108      532196 :         fsp->aio_requests[i] = fsp->aio_requests[fsp->num_aio_requests];
     109             : 
     110      532196 :         if (fsp->num_aio_requests == 0) {
     111      527309 :                 TALLOC_FREE(fsp->aio_requests);
     112             :         }
     113      524984 :         return 0;
     114             : }
     115             : 
     116      532196 : bool aio_add_req_to_fsp(files_struct *fsp, struct tevent_req *req)
     117             : {
     118        7212 :         size_t array_len;
     119        7212 :         struct aio_req_fsp_link *lnk;
     120             : 
     121      532196 :         lnk = talloc(req, struct aio_req_fsp_link);
     122      532196 :         if (lnk == NULL) {
     123           0 :                 return false;
     124             :         }
     125             : 
     126      532196 :         array_len = talloc_array_length(fsp->aio_requests);
     127      532196 :         if (array_len <= fsp->num_aio_requests) {
     128        7212 :                 struct tevent_req **tmp;
     129             : 
     130      527311 :                 if (fsp->num_aio_requests + 10 < 10) {
     131             :                         /* Integer wrap. */
     132           0 :                         TALLOC_FREE(lnk);
     133           0 :                         return false;
     134             :                 }
     135             : 
     136             :                 /*
     137             :                  * Allocate in blocks of 10 so we don't allocate
     138             :                  * on every aio request.
     139             :                  */
     140      527311 :                 tmp = talloc_realloc(
     141             :                         fsp, fsp->aio_requests, struct tevent_req *,
     142             :                         fsp->num_aio_requests+10);
     143      527311 :                 if (tmp == NULL) {
     144           0 :                         TALLOC_FREE(lnk);
     145           0 :                         return false;
     146             :                 }
     147      527311 :                 fsp->aio_requests = tmp;
     148             :         }
     149      532196 :         fsp->aio_requests[fsp->num_aio_requests] = req;
     150      532196 :         fsp->num_aio_requests += 1;
     151             : 
     152      532196 :         lnk->fsp = fsp;
     153      532196 :         lnk->req = req;
     154             : #ifdef DEVELOPER
     155      532196 :         lnk->sconn = fsp->conn->sconn;
     156             : #endif
     157      532196 :         talloc_set_destructor(lnk, aio_del_req_from_fsp);
     158             : 
     159      532196 :         return true;
     160             : }
     161             : 
     162             : struct pwrite_fsync_state {
     163             :         struct tevent_context *ev;
     164             :         files_struct *fsp;
     165             :         bool write_through;
     166             :         ssize_t nwritten;
     167             : };
     168             : 
     169             : static void pwrite_fsync_write_done(struct tevent_req *subreq);
     170             : static void pwrite_fsync_sync_done(struct tevent_req *subreq);
     171             : 
     172      185711 : struct tevent_req *pwrite_fsync_send(TALLOC_CTX *mem_ctx,
     173             :                                      struct tevent_context *ev,
     174             :                                      struct files_struct *fsp,
     175             :                                      const void *data,
     176             :                                      size_t n, off_t offset,
     177             :                                      bool write_through)
     178             : {
     179          52 :         struct tevent_req *req, *subreq;
     180          52 :         struct pwrite_fsync_state *state;
     181          52 :         bool ok;
     182             : 
     183      185711 :         req = tevent_req_create(mem_ctx, &state, struct pwrite_fsync_state);
     184      185711 :         if (req == NULL) {
     185           0 :                 return NULL;
     186             :         }
     187      185711 :         state->ev = ev;
     188      185711 :         state->fsp = fsp;
     189      185711 :         state->write_through = write_through;
     190             : 
     191      185711 :         ok = vfs_valid_pwrite_range(offset, n);
     192      185711 :         if (!ok) {
     193          30 :                 tevent_req_error(req, EINVAL);
     194          30 :                 return tevent_req_post(req, ev);
     195             :         }
     196             : 
     197      185681 :         if (n == 0) {
     198           0 :                 tevent_req_done(req);
     199           0 :                 return tevent_req_post(req, ev);
     200             :         }
     201             : 
     202      185681 :         subreq = SMB_VFS_PWRITE_SEND(state, ev, fsp, data, n, offset);
     203      185681 :         if (tevent_req_nomem(subreq, req)) {
     204           0 :                 return tevent_req_post(req, ev);
     205             :         }
     206      185681 :         tevent_req_set_callback(subreq, pwrite_fsync_write_done, req);
     207      185681 :         return req;
     208             : }
     209             : 
     210      185677 : static void pwrite_fsync_write_done(struct tevent_req *subreq)
     211             : {
     212      185677 :         struct tevent_req *req = tevent_req_callback_data(
     213             :                 subreq, struct tevent_req);
     214      185677 :         struct pwrite_fsync_state *state = tevent_req_data(
     215             :                 req, struct pwrite_fsync_state);
     216      185677 :         connection_struct *conn = state->fsp->conn;
     217          52 :         bool do_sync;
     218          52 :         struct vfs_aio_state vfs_aio_state;
     219             : 
     220      185677 :         state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &vfs_aio_state);
     221      185677 :         TALLOC_FREE(subreq);
     222      185677 :         if (state->nwritten == -1) {
     223           0 :                 tevent_req_error(req, vfs_aio_state.error);
     224      185604 :                 return;
     225             :         }
     226             : 
     227      556979 :         do_sync = (lp_strict_sync(SNUM(conn)) &&
     228      371354 :                    (lp_sync_always(SNUM(conn)) || state->write_through));
     229      185677 :         if (!do_sync) {
     230      185604 :                 tevent_req_done(req);
     231      185604 :                 return;
     232             :         }
     233             : 
     234          73 :         subreq = SMB_VFS_FSYNC_SEND(state, state->ev, state->fsp);
     235          73 :         if (tevent_req_nomem(subreq, req)) {
     236           0 :                 return;
     237             :         }
     238          73 :         tevent_req_set_callback(subreq, pwrite_fsync_sync_done, req);
     239             : }
     240             : 
     241          73 : static void pwrite_fsync_sync_done(struct tevent_req *subreq)
     242             : {
     243          73 :         struct tevent_req *req = tevent_req_callback_data(
     244             :                 subreq, struct tevent_req);
     245           1 :         int ret;
     246           1 :         struct vfs_aio_state vfs_aio_state;
     247             : 
     248          73 :         ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
     249          73 :         TALLOC_FREE(subreq);
     250          73 :         if (ret == -1) {
     251           0 :                 tevent_req_error(req, vfs_aio_state.error);
     252           0 :                 return;
     253             :         }
     254          73 :         tevent_req_done(req);
     255             : }
     256             : 
     257      185707 : ssize_t pwrite_fsync_recv(struct tevent_req *req, int *perr)
     258             : {
     259      185707 :         struct pwrite_fsync_state *state = tevent_req_data(
     260             :                 req, struct pwrite_fsync_state);
     261             : 
     262      185707 :         if (tevent_req_is_unix_error(req, perr)) {
     263          30 :                 return -1;
     264             :         }
     265      185677 :         return state->nwritten;
     266             : }
     267             : 
     268           2 : bool cancel_smb2_aio(struct smb_request *smbreq)
     269             : {
     270           2 :         struct smbd_smb2_request *smb2req = smbreq->smb2req;
     271           2 :         struct aio_extra *aio_ex = NULL;
     272             : 
     273           2 :         if (smb2req) {
     274           2 :                 aio_ex = talloc_get_type(smbreq->async_priv,
     275             :                                          struct aio_extra);
     276             :         }
     277             : 
     278           2 :         if (aio_ex == NULL) {
     279           0 :                 return false;
     280             :         }
     281             : 
     282           2 :         if (aio_ex->fsp == NULL) {
     283           0 :                 return false;
     284             :         }
     285             : 
     286             :         /*
     287             :          * We let the aio request run and don't try to cancel it which means
     288             :          * processing of the SMB2 request must continue as normal, cf MS-SMB2
     289             :          * 3.3.5.16:
     290             :          *
     291             :          *   If the target request is not successfully canceled, processing of
     292             :          *   the target request MUST continue and no response is sent to the
     293             :          *   cancel request.
     294             :          */
     295             : 
     296           2 :         return false;
     297             : }
     298             : 
     299             : static void aio_pread_smb2_done(struct tevent_req *req);
     300             : 
     301             : /****************************************************************************
     302             :  Set up an aio request from a SMB2 read call.
     303             : *****************************************************************************/
     304             : 
     305        5011 : NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
     306             :                                 struct smb_request *smbreq,
     307             :                                 files_struct *fsp,
     308             :                                 TALLOC_CTX *ctx,
     309             :                                 DATA_BLOB *preadbuf,
     310             :                                 off_t startpos,
     311             :                                 size_t smb_maxcnt)
     312             : {
     313           0 :         struct aio_extra *aio_ex;
     314        5011 :         size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
     315           0 :         struct tevent_req *req;
     316        5011 :         bool is_compound = false;
     317        5011 :         bool is_last_in_compound = false;
     318           0 :         bool ok;
     319             : 
     320        5011 :         ok = vfs_valid_pread_range(startpos, smb_maxcnt);
     321        5011 :         if (!ok) {
     322          36 :                 return NT_STATUS_INVALID_PARAMETER;
     323             :         }
     324             : 
     325        4975 :         if (fsp_is_alternate_stream(fsp)) {
     326         703 :                 DEBUG(10, ("AIO on streams not yet supported\n"));
     327         703 :                 return NT_STATUS_RETRY;
     328             :         }
     329             : 
     330        4272 :         if (fsp->op == NULL) {
     331             :                 /* No AIO on internal opens. */
     332           0 :                 return NT_STATUS_RETRY;
     333             :         }
     334             : 
     335        4272 :         if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
     336          38 :             && !SMB_VFS_AIO_FORCE(fsp)) {
     337             :                 /* Too small a read for aio request. */
     338          38 :                 DEBUG(10,("smb2: read size (%u) too small "
     339             :                         "for minimum aio_read of %u\n",
     340             :                         (unsigned int)smb_maxcnt,
     341             :                         (unsigned int)min_aio_read_size ));
     342          38 :                 return NT_STATUS_RETRY;
     343             :         }
     344             : 
     345        4234 :         is_compound = smbd_smb2_is_compound(smbreq->smb2req);
     346        4234 :         is_last_in_compound = smbd_smb2_is_last_in_compound(smbreq->smb2req);
     347             : 
     348        4234 :         if (is_compound && !is_last_in_compound) {
     349             :                 /*
     350             :                  * Only allow going async if this is the last
     351             :                  * request in a compound.
     352             :                  */
     353          26 :                 return NT_STATUS_RETRY;
     354             :         }
     355             : 
     356             :         /* Create the out buffer. */
     357        4208 :         *preadbuf = data_blob_talloc(ctx, NULL, smb_maxcnt);
     358        4208 :         if (preadbuf->data == NULL) {
     359           0 :                 return NT_STATUS_NO_MEMORY;
     360             :         }
     361             : 
     362        4208 :         if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
     363           0 :                 return NT_STATUS_NO_MEMORY;
     364             :         }
     365             : 
     366        4208 :         init_strict_lock_struct(fsp,
     367        4208 :                         fsp->op->global->open_persistent_id,
     368             :                         (uint64_t)startpos,
     369             :                         (uint64_t)smb_maxcnt,
     370             :                         READ_LOCK,
     371             :                         lp_posix_cifsu_locktype(fsp),
     372             :                         &aio_ex->lock);
     373             : 
     374             :         /* Take the lock until the AIO completes. */
     375        4208 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
     376           4 :                 TALLOC_FREE(aio_ex);
     377           4 :                 return NT_STATUS_FILE_LOCK_CONFLICT;
     378             :         }
     379             : 
     380        4204 :         aio_ex->nbyte = smb_maxcnt;
     381        4204 :         aio_ex->offset = startpos;
     382             : 
     383        4204 :         req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
     384             :                                  preadbuf->data, smb_maxcnt, startpos);
     385        4204 :         if (req == NULL) {
     386           0 :                 DEBUG(0, ("smb2: SMB_VFS_PREAD_SEND failed. "
     387             :                           "Error %s\n", strerror(errno)));
     388           0 :                 TALLOC_FREE(aio_ex);
     389           0 :                 return NT_STATUS_RETRY;
     390             :         }
     391        4204 :         tevent_req_set_callback(req, aio_pread_smb2_done, aio_ex);
     392             : 
     393        4204 :         if (!aio_add_req_to_fsp(fsp, req)) {
     394           0 :                 DEBUG(1, ("Could not add req to fsp\n"));
     395           0 :                 TALLOC_FREE(aio_ex);
     396           0 :                 return NT_STATUS_RETRY;
     397             :         }
     398             : 
     399             :         /* We don't need talloc_move here as both aio_ex and
     400             :          * smbreq are children of smbreq->smb2req. */
     401        4204 :         aio_ex->smbreq = smbreq;
     402        4204 :         smbreq->async_priv = aio_ex;
     403             : 
     404        4204 :         DEBUG(10,("smb2: scheduled aio_read for file %s, "
     405             :                 "offset %.0f, len = %u (mid = %u)\n",
     406             :                 fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
     407             :                 (unsigned int)aio_ex->smbreq->mid ));
     408             : 
     409        4204 :         return NT_STATUS_OK;
     410             : }
     411             : 
     412        4204 : static void aio_pread_smb2_done(struct tevent_req *req)
     413             : {
     414        4204 :         struct aio_extra *aio_ex = tevent_req_callback_data(
     415             :                 req, struct aio_extra);
     416        4204 :         struct tevent_req *subreq = aio_ex->smbreq->smb2req->subreq;
     417        4204 :         files_struct *fsp = aio_ex->fsp;
     418           0 :         NTSTATUS status;
     419           0 :         ssize_t nread;
     420        4204 :         struct vfs_aio_state vfs_aio_state = { 0 };
     421             : 
     422        4204 :         nread = SMB_VFS_PREAD_RECV(req, &vfs_aio_state);
     423        4204 :         TALLOC_FREE(req);
     424             : 
     425        4204 :         DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
     426             :                    (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
     427             : 
     428             :         /* Common error or success code processing for async or sync
     429             :            read returns. */
     430             : 
     431        4204 :         status = smb2_read_complete(subreq, nread, vfs_aio_state.error);
     432             : 
     433        4204 :         if (nread > 0) {
     434        3858 :                 fh_set_pos(fsp->fh, aio_ex->offset + nread);
     435        3858 :                 fh_set_position_information(fsp->fh,
     436        3858 :                                                 fh_get_pos(fsp->fh));
     437             :         }
     438             : 
     439        4204 :         DEBUG(10, ("smb2: scheduled aio_read completed "
     440             :                    "for file %s, offset %.0f, len = %u "
     441             :                    "(errcode = %d, NTSTATUS = %s)\n",
     442             :                    fsp_str_dbg(aio_ex->fsp),
     443             :                    (double)aio_ex->offset,
     444             :                    (unsigned int)nread,
     445             :                    vfs_aio_state.error, nt_errstr(status)));
     446             : 
     447        4204 :         if (tevent_req_nterror(subreq, status)) {
     448         362 :                 return;
     449             :         }
     450        3842 :         tevent_req_done(subreq);
     451             : }
     452             : 
     453             : static void aio_pwrite_smb2_done(struct tevent_req *req);
     454             : 
     455             : /****************************************************************************
     456             :  Set up an aio request from a SMB2write call.
     457             : *****************************************************************************/
     458             : 
     459       56426 : NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
     460             :                                 struct smb_request *smbreq,
     461             :                                 files_struct *fsp,
     462             :                                 uint64_t in_offset,
     463             :                                 DATA_BLOB in_data,
     464             :                                 bool write_through)
     465             : {
     466       56426 :         struct aio_extra *aio_ex = NULL;
     467       56426 :         size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
     468           0 :         struct tevent_req *req;
     469       56426 :         bool is_compound = false;
     470       56426 :         bool is_last_in_compound = false;
     471             : 
     472       56426 :         if (fsp_is_alternate_stream(fsp)) {
     473             :                 /* No AIO on streams yet */
     474        3108 :                 DEBUG(10, ("AIO on streams not yet supported\n"));
     475        3108 :                 return NT_STATUS_RETRY;
     476             :         }
     477             : 
     478       53318 :         if (fsp->op == NULL) {
     479             :                 /* No AIO on internal opens. */
     480           0 :                 return NT_STATUS_RETRY;
     481             :         }
     482             : 
     483       53318 :         if ((!min_aio_write_size || (in_data.length < min_aio_write_size))
     484          24 :             && !SMB_VFS_AIO_FORCE(fsp)) {
     485             :                 /* Too small a write for aio request. */
     486          24 :                 DEBUG(10,("smb2: write size (%u) too "
     487             :                         "small for minimum aio_write of %u\n",
     488             :                         (unsigned int)in_data.length,
     489             :                         (unsigned int)min_aio_write_size ));
     490          24 :                 return NT_STATUS_RETRY;
     491             :         }
     492             : 
     493       53294 :         is_compound = smbd_smb2_is_compound(smbreq->smb2req);
     494       53294 :         is_last_in_compound = smbd_smb2_is_last_in_compound(smbreq->smb2req);
     495             : 
     496       53294 :         if (is_compound && !is_last_in_compound) {
     497             :                 /*
     498             :                  * Only allow going async if this is the last
     499             :                  * request in a compound.
     500             :                  */
     501           8 :                 return NT_STATUS_RETRY;
     502             :         }
     503             : 
     504       53286 :         if (smbreq->unread_bytes) {
     505             :                 /* Can't do async with recvfile. */
     506           0 :                 return NT_STATUS_RETRY;
     507             :         }
     508             : 
     509       53286 :         if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
     510           0 :                 return NT_STATUS_NO_MEMORY;
     511             :         }
     512             : 
     513       53286 :         aio_ex->write_through = write_through;
     514             : 
     515       53286 :         init_strict_lock_struct(fsp,
     516       53286 :                         fsp->op->global->open_persistent_id,
     517             :                         in_offset,
     518       53286 :                         (uint64_t)in_data.length,
     519             :                         WRITE_LOCK,
     520             :                         lp_posix_cifsu_locktype(fsp),
     521             :                         &aio_ex->lock);
     522             : 
     523             :         /* Take the lock until the AIO completes. */
     524       53286 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
     525          12 :                 TALLOC_FREE(aio_ex);
     526          12 :                 return NT_STATUS_FILE_LOCK_CONFLICT;
     527             :         }
     528             : 
     529       53274 :         aio_ex->nbyte = in_data.length;
     530       53274 :         aio_ex->offset = in_offset;
     531             : 
     532       53274 :         req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
     533       53274 :                                 in_data.data, in_data.length, in_offset,
     534             :                                 write_through);
     535       53274 :         if (req == NULL) {
     536           0 :                 DEBUG(3, ("smb2: SMB_VFS_PWRITE_SEND failed. "
     537             :                           "Error %s\n", strerror(errno)));
     538           0 :                 TALLOC_FREE(aio_ex);
     539           0 :                 return NT_STATUS_RETRY;
     540             :         }
     541       53274 :         tevent_req_set_callback(req, aio_pwrite_smb2_done, aio_ex);
     542             : 
     543       53274 :         if (!aio_add_req_to_fsp(fsp, req)) {
     544           0 :                 DEBUG(1, ("Could not add req to fsp\n"));
     545           0 :                 TALLOC_FREE(aio_ex);
     546           0 :                 return NT_STATUS_RETRY;
     547             :         }
     548             : 
     549             :         /* We don't need talloc_move here as both aio_ex and
     550             :         * smbreq are children of smbreq->smb2req. */
     551       53274 :         aio_ex->smbreq = smbreq;
     552       53274 :         smbreq->async_priv = aio_ex;
     553             : 
     554             :         /* This should actually be improved to span the write. */
     555       53274 :         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
     556       53274 :         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
     557             : 
     558             :         /*
     559             :          * We don't want to do write behind due to ownership
     560             :          * issues of the request structs. Maybe add it if I
     561             :          * figure those out. JRA.
     562             :          */
     563             : 
     564       53274 :         DEBUG(10,("smb2: scheduled aio_write for file "
     565             :                 "%s, offset %.0f, len = %u (mid = %u)\n",
     566             :                 fsp_str_dbg(fsp),
     567             :                 (double)in_offset,
     568             :                 (unsigned int)in_data.length,
     569             :                 (unsigned int)aio_ex->smbreq->mid));
     570             : 
     571       53274 :         return NT_STATUS_OK;
     572             : }
     573             : 
     574       53270 : static void aio_pwrite_smb2_done(struct tevent_req *req)
     575             : {
     576       53270 :         struct aio_extra *aio_ex = tevent_req_callback_data(
     577             :                 req, struct aio_extra);
     578       53270 :         ssize_t numtowrite = aio_ex->nbyte;
     579       53270 :         struct tevent_req *subreq = aio_ex->smbreq->smb2req->subreq;
     580       53270 :         files_struct *fsp = aio_ex->fsp;
     581           0 :         NTSTATUS status;
     582           0 :         ssize_t nwritten;
     583       53270 :         int err = 0;
     584             : 
     585       53270 :         nwritten = pwrite_fsync_recv(req, &err);
     586       53270 :         TALLOC_FREE(req);
     587             : 
     588       53270 :         DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
     589             :                    (nwritten == -1) ? strerror(err) : "no error"));
     590             : 
     591       53270 :         mark_file_modified(fsp);
     592             : 
     593       53270 :         status = smb2_write_complete_nosync(subreq, nwritten, err);
     594             : 
     595       53270 :         DEBUG(10, ("smb2: scheduled aio_write completed "
     596             :                    "for file %s, offset %.0f, requested %u, "
     597             :                    "written = %u (errcode = %d, NTSTATUS = %s)\n",
     598             :                    fsp_str_dbg(fsp),
     599             :                    (double)aio_ex->offset,
     600             :                    (unsigned int)numtowrite,
     601             :                    (unsigned int)nwritten,
     602             :                    err, nt_errstr(status)));
     603             : 
     604       53270 :         if (tevent_req_nterror(subreq, status)) {
     605          30 :                 return;
     606             :         }
     607       53240 :         tevent_req_done(subreq);
     608             : }

Generated by: LCOV version 1.14