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

Generated by: LCOV version 1.14