LCOV - code coverage report
Current view: top level - source3/smbd - smb2_aio.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 146 227 64.3 %
Date: 2024-06-13 04:01:37 Functions: 10 13 76.9 %

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

Generated by: LCOV version 1.13