LCOV - code coverage report
Current view: top level - source3/smbd - smb1_aio.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 168 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 4 0.0 %

          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             : static void aio_pread_smb1_done(struct tevent_req *req);
      28             : 
      29             : /****************************************************************************
      30             :  Set up an aio request from a SMBreadX call.
      31             : *****************************************************************************/
      32             : 
      33           0 : NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
      34             :                              struct smb_request *smbreq,
      35             :                              files_struct *fsp, off_t startpos,
      36             :                              size_t smb_maxcnt)
      37             : {
      38             :         struct aio_extra *aio_ex;
      39             :         size_t bufsize;
      40           0 :         size_t min_aio_read_size = lp_aio_read_size(SNUM(conn));
      41             :         struct tevent_req *req;
      42             :         bool ok;
      43             : 
      44           0 :         ok = vfs_valid_pread_range(startpos, smb_maxcnt);
      45           0 :         if (!ok) {
      46           0 :                 return NT_STATUS_INVALID_PARAMETER;
      47             :         }
      48             : 
      49           0 :         if (fsp_is_alternate_stream(fsp)) {
      50           0 :                 DEBUG(10, ("AIO on streams not yet supported\n"));
      51           0 :                 return NT_STATUS_RETRY;
      52             :         }
      53             : 
      54           0 :         if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
      55           0 :             && !SMB_VFS_AIO_FORCE(fsp)) {
      56             :                 /* Too small a read for aio request. */
      57           0 :                 DEBUG(10,("schedule_aio_read_and_X: read size (%u) too small "
      58             :                           "for minimum aio_read of %u\n",
      59             :                           (unsigned int)smb_maxcnt,
      60             :                           (unsigned int)min_aio_read_size ));
      61           0 :                 return NT_STATUS_RETRY;
      62             :         }
      63             : 
      64             :         /* Only do this on non-chained and non-chaining reads */
      65           0 :         if (req_is_in_chain(smbreq)) {
      66           0 :                 return NT_STATUS_RETRY;
      67             :         }
      68             : 
      69             :         /* The following is safe from integer wrap as we've already checked
      70             :            smb_maxcnt is 128k or less. Wct is 12 for read replies */
      71             : 
      72           0 :         bufsize = smb_size + 12 * 2 + smb_maxcnt + 1 /* padding byte */;
      73             : 
      74           0 :         if ((aio_ex = create_aio_extra(NULL, fsp, bufsize)) == NULL) {
      75           0 :                 DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
      76           0 :                 return NT_STATUS_NO_MEMORY;
      77             :         }
      78             : 
      79           0 :         construct_smb1_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
      80           0 :         srv_smb1_set_message((char *)aio_ex->outbuf.data, 12, 0, True);
      81           0 :         SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
      82           0 :         SCVAL(smb_buf(aio_ex->outbuf.data), 0, 0); /* padding byte */
      83             : 
      84           0 :         init_strict_lock_struct(fsp,
      85           0 :                         (uint64_t)smbreq->smbpid,
      86             :                         (uint64_t)startpos,
      87             :                         (uint64_t)smb_maxcnt,
      88             :                         READ_LOCK,
      89             :                         lp_posix_cifsu_locktype(fsp),
      90             :                         &aio_ex->lock);
      91             : 
      92             :         /* Take the lock until the AIO completes. */
      93           0 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
      94           0 :                 TALLOC_FREE(aio_ex);
      95           0 :                 return NT_STATUS_FILE_LOCK_CONFLICT;
      96             :         }
      97             : 
      98           0 :         aio_ex->nbyte = smb_maxcnt;
      99           0 :         aio_ex->offset = startpos;
     100             : 
     101           0 :         req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx,
     102             :                                  fsp,
     103             :                                  smb_buf(aio_ex->outbuf.data) + 1 /* pad */,
     104             :                                  smb_maxcnt, startpos);
     105           0 :         if (req == NULL) {
     106           0 :                 DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
     107             :                          "Error %s\n", strerror(errno) ));
     108           0 :                 TALLOC_FREE(aio_ex);
     109           0 :                 return NT_STATUS_RETRY;
     110             :         }
     111           0 :         tevent_req_set_callback(req, aio_pread_smb1_done, aio_ex);
     112             : 
     113           0 :         if (!aio_add_req_to_fsp(fsp, req)) {
     114           0 :                 DEBUG(1, ("Could not add req to fsp\n"));
     115           0 :                 TALLOC_FREE(aio_ex);
     116           0 :                 return NT_STATUS_RETRY;
     117             :         }
     118             : 
     119           0 :         aio_ex->smbreq = talloc_move(aio_ex, &smbreq);
     120             : 
     121           0 :         DEBUG(10,("schedule_aio_read_and_X: scheduled aio_read for file %s, "
     122             :                   "offset %.0f, len = %u (mid = %u)\n",
     123             :                   fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
     124             :                   (unsigned int)aio_ex->smbreq->mid ));
     125             : 
     126           0 :         return NT_STATUS_OK;
     127             : }
     128             : 
     129           0 : static void aio_pread_smb1_done(struct tevent_req *req)
     130             : {
     131           0 :         struct aio_extra *aio_ex = tevent_req_callback_data(
     132             :                 req, struct aio_extra);
     133           0 :         files_struct *fsp = aio_ex->fsp;
     134             :         size_t outsize;
     135           0 :         char *outbuf = (char *)aio_ex->outbuf.data;
     136             :         ssize_t nread;
     137             :         struct vfs_aio_state vfs_aio_state;
     138             : 
     139           0 :         nread = SMB_VFS_PREAD_RECV(req, &vfs_aio_state);
     140           0 :         TALLOC_FREE(req);
     141             : 
     142           0 :         DEBUG(10, ("pread_recv returned %d, err = %s\n", (int)nread,
     143             :                    (nread == -1) ? strerror(vfs_aio_state.error) : "no error"));
     144             : 
     145           0 :         if (fsp == NULL) {
     146           0 :                 DEBUG( 3, ("aio_pread_smb1_done: file closed whilst "
     147             :                            "aio outstanding (mid[%llu]).\n",
     148             :                            (unsigned long long)aio_ex->smbreq->mid));
     149           0 :                 TALLOC_FREE(aio_ex);
     150           0 :                 return;
     151             :         }
     152             : 
     153           0 :         if (nread < 0) {
     154           0 :                 DEBUG( 3, ("handle_aio_read_complete: file %s nread == %d. "
     155             :                            "Error = %s\n", fsp_str_dbg(fsp), (int)nread,
     156             :                            strerror(vfs_aio_state.error)));
     157             : 
     158           0 :                 ERROR_NT(map_nt_error_from_unix(vfs_aio_state.error));
     159           0 :                 outsize = srv_smb1_set_message(outbuf,0,0,true);
     160             :         } else {
     161           0 :                 outsize = setup_readX_header(outbuf, nread);
     162             : 
     163           0 :                 fh_set_pos(aio_ex->fsp->fh, aio_ex->offset + nread);
     164           0 :                 fh_set_position_information(aio_ex->fsp->fh,
     165           0 :                                             fh_get_pos(aio_ex->fsp->fh));
     166             : 
     167           0 :                 DEBUG( 3, ("handle_aio_read_complete file %s max=%d "
     168             :                            "nread=%d\n", fsp_str_dbg(fsp),
     169             :                            (int)aio_ex->nbyte, (int)nread ) );
     170             : 
     171             :         }
     172             : 
     173           0 :         if (outsize <= 4) {
     174           0 :                 DBG_INFO("Invalid outsize (%zu)\n", outsize);
     175           0 :                 TALLOC_FREE(aio_ex);
     176           0 :                 return;
     177             :         }
     178           0 :         outsize -= 4;
     179           0 :         _smb_setlen_large(outbuf, outsize);
     180             : 
     181           0 :         show_msg(outbuf);
     182           0 :         if (!smb1_srv_send(aio_ex->smbreq->xconn, outbuf,
     183           0 :                           true, aio_ex->smbreq->seqnum+1,
     184           0 :                           IS_CONN_ENCRYPTED(fsp->conn), NULL)) {
     185           0 :                 exit_server_cleanly("handle_aio_read_complete: smb1_srv_send "
     186             :                                     "failed.");
     187             :         }
     188             : 
     189           0 :         DEBUG(10, ("handle_aio_read_complete: scheduled aio_read completed "
     190             :                    "for file %s, offset %.0f, len = %u\n",
     191             :                    fsp_str_dbg(fsp), (double)aio_ex->offset,
     192             :                    (unsigned int)nread));
     193             : 
     194           0 :         TALLOC_FREE(aio_ex);
     195             : }
     196             : 
     197             : static void aio_pwrite_smb1_done(struct tevent_req *req);
     198             : 
     199             : /****************************************************************************
     200             :  Set up an aio request from a SMBwriteX call.
     201             : *****************************************************************************/
     202             : 
     203           0 : NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
     204             :                               struct smb_request *smbreq,
     205             :                               files_struct *fsp, const char *data,
     206             :                               off_t startpos,
     207             :                               size_t numtowrite)
     208             : {
     209             :         struct aio_extra *aio_ex;
     210             :         size_t bufsize;
     211           0 :         size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
     212             :         struct tevent_req *req;
     213             : 
     214           0 :         if (fsp_is_alternate_stream(fsp)) {
     215           0 :                 DEBUG(10, ("AIO on streams not yet supported\n"));
     216           0 :                 return NT_STATUS_RETRY;
     217             :         }
     218             : 
     219           0 :         if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
     220           0 :             && !SMB_VFS_AIO_FORCE(fsp)) {
     221             :                 /* Too small a write for aio request. */
     222           0 :                 DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
     223             :                           "small for minimum aio_write of %u\n",
     224             :                           (unsigned int)numtowrite,
     225             :                           (unsigned int)min_aio_write_size ));
     226           0 :                 return NT_STATUS_RETRY;
     227             :         }
     228             : 
     229             :         /* Only do this on non-chained and non-chaining writes */
     230           0 :         if (req_is_in_chain(smbreq)) {
     231           0 :                 return NT_STATUS_RETRY;
     232             :         }
     233             : 
     234           0 :         bufsize = smb_size + 6*2;
     235             : 
     236           0 :         if (!(aio_ex = create_aio_extra(NULL, fsp, bufsize))) {
     237           0 :                 DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
     238           0 :                 return NT_STATUS_NO_MEMORY;
     239             :         }
     240           0 :         aio_ex->write_through = BITSETW(smbreq->vwv+7,0);
     241             : 
     242           0 :         construct_smb1_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
     243           0 :         srv_smb1_set_message((char *)aio_ex->outbuf.data, 6, 0, True);
     244           0 :         SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */
     245             : 
     246           0 :         init_strict_lock_struct(fsp,
     247           0 :                         (uint64_t)smbreq->smbpid,
     248             :                         (uint64_t)startpos,
     249             :                         (uint64_t)numtowrite,
     250             :                         WRITE_LOCK,
     251             :                         lp_posix_cifsu_locktype(fsp),
     252             :                         &aio_ex->lock);
     253             : 
     254             :         /* Take the lock until the AIO completes. */
     255           0 :         if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &aio_ex->lock)) {
     256           0 :                 TALLOC_FREE(aio_ex);
     257           0 :                 return NT_STATUS_FILE_LOCK_CONFLICT;
     258             :         }
     259             : 
     260           0 :         aio_ex->nbyte = numtowrite;
     261           0 :         aio_ex->offset = startpos;
     262             : 
     263           0 :         req = pwrite_fsync_send(aio_ex, fsp->conn->sconn->ev_ctx, fsp,
     264             :                                 data, numtowrite, startpos,
     265           0 :                                 aio_ex->write_through);
     266           0 :         if (req == NULL) {
     267           0 :                 DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
     268             :                          "Error %s\n", strerror(errno) ));
     269           0 :                 TALLOC_FREE(aio_ex);
     270           0 :                 return NT_STATUS_RETRY;
     271             :         }
     272           0 :         tevent_req_set_callback(req, aio_pwrite_smb1_done, aio_ex);
     273             : 
     274           0 :         if (!aio_add_req_to_fsp(fsp, req)) {
     275           0 :                 DEBUG(1, ("Could not add req to fsp\n"));
     276           0 :                 TALLOC_FREE(aio_ex);
     277           0 :                 return NT_STATUS_RETRY;
     278             :         }
     279             : 
     280           0 :         aio_ex->smbreq = talloc_move(aio_ex, &smbreq);
     281             : 
     282             :         /* This should actually be improved to span the write. */
     283           0 :         contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
     284           0 :         contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
     285             : 
     286           0 :         if (!aio_ex->write_through && !lp_sync_always(SNUM(fsp->conn))
     287           0 :             && fsp->fsp_flags.aio_write_behind)
     288             :         {
     289             :                 /* Lie to the client and immediately claim we finished the
     290             :                  * write. */
     291           0 :                 SSVAL(aio_ex->outbuf.data,smb_vwv2,numtowrite);
     292           0 :                 SSVAL(aio_ex->outbuf.data,smb_vwv4,(numtowrite>>16)&1);
     293           0 :                 show_msg((char *)aio_ex->outbuf.data);
     294           0 :                 if (!smb1_srv_send(aio_ex->smbreq->xconn,
     295           0 :                                 (char *)aio_ex->outbuf.data,
     296           0 :                                 true, aio_ex->smbreq->seqnum+1,
     297           0 :                                 IS_CONN_ENCRYPTED(fsp->conn),
     298           0 :                                 &aio_ex->smbreq->pcd)) {
     299           0 :                         exit_server_cleanly("schedule_aio_write_and_X: "
     300             :                                             "smb1_srv_send failed.");
     301             :                 }
     302           0 :                 DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
     303             :                           "behind for file %s\n", fsp_str_dbg(fsp)));
     304             :         }
     305             : 
     306           0 :         DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write for file "
     307             :                   "%s, offset %.0f, len = %u (mid = %u)\n",
     308             :                   fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
     309             :                   (unsigned int)aio_ex->smbreq->mid));
     310             : 
     311           0 :         return NT_STATUS_OK;
     312             : }
     313             : 
     314           0 : static void aio_pwrite_smb1_done(struct tevent_req *req)
     315             : {
     316           0 :         struct aio_extra *aio_ex = tevent_req_callback_data(
     317             :                 req, struct aio_extra);
     318           0 :         files_struct *fsp = aio_ex->fsp;
     319           0 :         char *outbuf = (char *)aio_ex->outbuf.data;
     320           0 :         ssize_t numtowrite = aio_ex->nbyte;
     321             :         ssize_t nwritten;
     322             :         int err;
     323             : 
     324           0 :         nwritten = pwrite_fsync_recv(req, &err);
     325           0 :         TALLOC_FREE(req);
     326             : 
     327           0 :         DEBUG(10, ("pwrite_recv returned %d, err = %s\n", (int)nwritten,
     328             :                    (nwritten == -1) ? strerror(err) : "no error"));
     329             : 
     330           0 :         if (fsp == NULL) {
     331           0 :                 DEBUG( 3, ("aio_pwrite_smb1_done: file closed whilst "
     332             :                            "aio outstanding (mid[%llu]).\n",
     333             :                            (unsigned long long)aio_ex->smbreq->mid));
     334           0 :                 TALLOC_FREE(aio_ex);
     335           0 :                 return;
     336             :         }
     337             : 
     338           0 :         mark_file_modified(fsp);
     339             : 
     340           0 :         if (fsp->fsp_flags.aio_write_behind) {
     341             : 
     342           0 :                 if (nwritten != numtowrite) {
     343           0 :                         if (nwritten == -1) {
     344           0 :                                 DEBUG(5,("handle_aio_write_complete: "
     345             :                                          "aio_write_behind failed ! File %s "
     346             :                                          "is corrupt ! Error %s\n",
     347             :                                          fsp_str_dbg(fsp), strerror(err)));
     348             :                         } else {
     349           0 :                                 DEBUG(0,("handle_aio_write_complete: "
     350             :                                          "aio_write_behind failed ! File %s "
     351             :                                          "is corrupt ! Wanted %u bytes but "
     352             :                                          "only wrote %d\n", fsp_str_dbg(fsp),
     353             :                                          (unsigned int)numtowrite,
     354             :                                          (int)nwritten ));
     355             :                         }
     356             :                 } else {
     357           0 :                         DEBUG(10,("handle_aio_write_complete: "
     358             :                                   "aio_write_behind completed for file %s\n",
     359             :                                   fsp_str_dbg(fsp)));
     360             :                 }
     361             :                 /* TODO: should no return success in case of an error !!! */
     362           0 :                 TALLOC_FREE(aio_ex);
     363           0 :                 return;
     364             :         }
     365             : 
     366             :         /* We don't need outsize or set_message here as we've already set the
     367             :            fixed size length when we set up the aio call. */
     368             : 
     369           0 :         if (nwritten == -1) {
     370           0 :                 DEBUG(3, ("handle_aio_write: file %s wanted %u bytes. "
     371             :                           "nwritten == %d. Error = %s\n",
     372             :                           fsp_str_dbg(fsp), (unsigned int)numtowrite,
     373             :                           (int)nwritten, strerror(err)));
     374             : 
     375           0 :                 ERROR_NT(map_nt_error_from_unix(err));
     376           0 :                 srv_smb1_set_message(outbuf,0,0,true);
     377             :         } else {
     378           0 :                 SSVAL(outbuf,smb_vwv2,nwritten);
     379           0 :                 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
     380           0 :                 if (nwritten < (ssize_t)numtowrite) {
     381           0 :                         SCVAL(outbuf,smb_rcls,ERRHRD);
     382           0 :                         SSVAL(outbuf,smb_err,ERRdiskfull);
     383             :                 }
     384             : 
     385           0 :                 DEBUG(3,("handle_aio_write: %s, num=%d wrote=%d\n",
     386             :                          fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
     387             : 
     388           0 :                 fh_set_pos(aio_ex->fsp->fh, aio_ex->offset + nwritten);
     389             :         }
     390             : 
     391           0 :         show_msg(outbuf);
     392           0 :         if (!smb1_srv_send(aio_ex->smbreq->xconn, outbuf,
     393           0 :                           true, aio_ex->smbreq->seqnum+1,
     394           0 :                           IS_CONN_ENCRYPTED(fsp->conn),
     395             :                           NULL)) {
     396           0 :                 exit_server_cleanly("handle_aio_write_complete: "
     397             :                                     "smb1_srv_send failed.");
     398             :         }
     399             : 
     400           0 :         DEBUG(10, ("handle_aio_write_complete: scheduled aio_write completed "
     401             :                    "for file %s, offset %.0f, requested %u, written = %u\n",
     402             :                    fsp_str_dbg(fsp), (double)aio_ex->offset,
     403             :                    (unsigned int)numtowrite, (unsigned int)nwritten));
     404             : 
     405           0 :         TALLOC_FREE(aio_ex);
     406             : }

Generated by: LCOV version 1.13