LCOV - code coverage report
Current view: top level - source3/modules - vfs_aio_fork.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 273 386 70.7 %
Date: 2024-02-28 12:06:22 Functions: 23 24 95.8 %

          Line data    Source code
       1             : /*
       2             :  * Simulate the Posix AIO using mmap/fork
       3             :  *
       4             :  * Copyright (C) Volker Lendecke 2008
       5             :  * Copyright (C) Jeremy Allison 2010
       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 2 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, write to the Free Software
      19             :  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      20             :  */
      21             : 
      22             : #include "includes.h"
      23             : #include "system/filesys.h"
      24             : #include "system/shmem.h"
      25             : #include "smbd/smbd.h"
      26             : #include "smbd/globals.h"
      27             : #include "lib/async_req/async_sock.h"
      28             : #include "lib/util/tevent_unix.h"
      29             : #include "lib/util/sys_rw.h"
      30             : #include "lib/util/sys_rw_data.h"
      31             : #include "lib/util/msghdr.h"
      32             : #include "smbprofile.h"
      33             : #include "lib/global_contexts.h"
      34             : 
      35             : #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
      36             : # error Can not pass file descriptors
      37             : #endif
      38             : 
      39             : #undef recvmsg
      40             : 
      41             : #ifndef MAP_FILE
      42             : #define MAP_FILE 0
      43             : #endif
      44             : 
      45             : struct aio_child_list;
      46             : 
      47             : struct aio_fork_config {
      48             :         bool erratic_testing_mode;
      49             :         struct aio_child_list *children;
      50             : };
      51             : 
      52             : struct mmap_area {
      53             :         size_t size;
      54             :         void *ptr;
      55             : };
      56             : 
      57          17 : static int mmap_area_destructor(struct mmap_area *area)
      58             : {
      59          17 :         munmap(discard_const(area->ptr), area->size);
      60          17 :         return 0;
      61             : }
      62             : 
      63          17 : static struct mmap_area *mmap_area_init(TALLOC_CTX *mem_ctx, size_t size)
      64             : {
      65             :         struct mmap_area *result;
      66             :         int fd;
      67             : 
      68          17 :         result = talloc(mem_ctx, struct mmap_area);
      69          17 :         if (result == NULL) {
      70           0 :                 DEBUG(0, ("talloc failed\n"));
      71           0 :                 goto fail;
      72             :         }
      73             : 
      74          17 :         fd = open("/dev/zero", O_RDWR);
      75          17 :         if (fd == -1) {
      76           0 :                 DEBUG(3, ("open(\"/dev/zero\") failed: %s\n",
      77             :                           strerror(errno)));
      78           0 :                 goto fail;
      79             :         }
      80             : 
      81          17 :         result->ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
      82             :                            MAP_SHARED|MAP_FILE, fd, 0);
      83          17 :         close(fd);
      84          17 :         if (result->ptr == MAP_FAILED) {
      85           0 :                 DEBUG(1, ("mmap failed: %s\n", strerror(errno)));
      86           0 :                 goto fail;
      87             :         }
      88             : 
      89          17 :         result->size = size;
      90          17 :         talloc_set_destructor(result, mmap_area_destructor);
      91             : 
      92          17 :         return result;
      93             : 
      94           0 : fail:
      95           0 :         TALLOC_FREE(result);
      96           0 :         return NULL;
      97             : }
      98             : 
      99             : enum cmd_type {
     100             :         READ_CMD,
     101             :         WRITE_CMD,
     102             :         FSYNC_CMD
     103             : };
     104             : 
     105           0 : static const char *cmd_type_str(enum cmd_type cmd)
     106             : {
     107             :         const char *result;
     108             : 
     109           0 :         switch (cmd) {
     110           0 :         case READ_CMD:
     111           0 :                 result = "READ";
     112           0 :                 break;
     113           0 :         case WRITE_CMD:
     114           0 :                 result = "WRITE";
     115           0 :                 break;
     116           0 :         case FSYNC_CMD:
     117           0 :                 result = "FSYNC";
     118           0 :                 break;
     119           0 :         default:
     120           0 :                 result = "<UNKNOWN>";
     121           0 :                 break;
     122             :         }
     123           0 :         return result;
     124             : }
     125             : 
     126             : struct rw_cmd {
     127             :         size_t n;
     128             :         off_t offset;
     129             :         enum cmd_type cmd;
     130             :         bool erratic_testing_mode;
     131             : };
     132             : 
     133             : struct rw_ret {
     134             :         ssize_t size;
     135             :         int ret_errno;
     136             :         uint64_t duration;
     137             : };
     138             : 
     139             : struct aio_child_list;
     140             : 
     141             : struct aio_child {
     142             :         struct aio_child *prev, *next;
     143             :         struct aio_child_list *list;
     144             :         pid_t pid;
     145             :         int sockfd;
     146             :         struct mmap_area *map;
     147             :         bool dont_delete;       /* Marked as in use since last cleanup */
     148             :         bool busy;
     149             : };
     150             : 
     151             : struct aio_child_list {
     152             :         struct aio_child *children;
     153             :         struct tevent_timer *cleanup_event;
     154             : };
     155             : 
     156       25981 : static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
     157       25981 : {
     158             :         struct iovec iov[1];
     159       25981 :         struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 };
     160             :         ssize_t n;
     161       25981 :         size_t bufsize = msghdr_prep_recv_fds(NULL, NULL, 0, 1);
     162       25981 :         uint8_t buf[bufsize];
     163             : 
     164       25981 :         msghdr_prep_recv_fds(&msg, buf, bufsize, 1);
     165             : 
     166       25981 :         iov[0].iov_base = (void *)ptr;
     167       25981 :         iov[0].iov_len = nbytes;
     168             : 
     169             :         do {
     170       25981 :                 n = recvmsg(fd, &msg, 0);
     171       25981 :         } while ((n == -1) && (errno == EINTR));
     172             : 
     173       25981 :         if (n <= 0) {
     174           0 :                 return n;
     175             :         }
     176             : 
     177       25981 :         {
     178       25981 :                 size_t num_fds = msghdr_extract_fds(&msg, NULL, 0);
     179       25981 :                 int fds[num_fds];
     180             : 
     181       25981 :                 msghdr_extract_fds(&msg, fds, num_fds);
     182             : 
     183       25981 :                 if (num_fds != 1) {
     184             :                         size_t i;
     185             : 
     186          17 :                         for (i=0; i<num_fds; i++) {
     187           0 :                                 close(fds[i]);
     188             :                         }
     189             : 
     190          17 :                         *recvfd = -1;
     191          17 :                         return n;
     192             :                 }
     193             : 
     194       25964 :                 *recvfd = fds[0];
     195             :         }
     196             : 
     197       25964 :         return(n);
     198             : }
     199             : 
     200       25964 : static ssize_t write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
     201       25964 : {
     202       25964 :         struct msghdr msg = {0};
     203       25964 :         size_t bufsize = msghdr_prep_fds(NULL, NULL, 0, &sendfd, 1);
     204       25964 :         uint8_t buf[bufsize];
     205             :         struct iovec iov;
     206             :         ssize_t sent;
     207             : 
     208       25964 :         msghdr_prep_fds(&msg, buf, bufsize, &sendfd, 1);
     209             : 
     210       25964 :         iov.iov_base = (void *)ptr;
     211       25964 :         iov.iov_len = nbytes;
     212       25964 :         msg.msg_iov = &iov;
     213       25964 :         msg.msg_iovlen = 1;
     214             : 
     215             :         do {
     216       25964 :                 sent = sendmsg(fd, &msg, 0);
     217       25964 :         } while ((sent == -1) && (errno == EINTR));
     218             : 
     219       25964 :         return sent;
     220             : }
     221             : 
     222           8 : static void aio_child_cleanup(struct tevent_context *event_ctx,
     223             :                               struct tevent_timer *te,
     224             :                               struct timeval now,
     225             :                               void *private_data)
     226             : {
     227           8 :         struct aio_child_list *list = talloc_get_type_abort(
     228             :                 private_data, struct aio_child_list);
     229             :         struct aio_child *child, *next;
     230             : 
     231           8 :         TALLOC_FREE(list->cleanup_event);
     232             : 
     233          16 :         for (child = list->children; child != NULL; child = next) {
     234           8 :                 next = child->next;
     235             : 
     236           8 :                 if (child->busy) {
     237           8 :                         DEBUG(10, ("child %d currently active\n",
     238             :                                    (int)child->pid));
     239           8 :                         continue;
     240             :                 }
     241             : 
     242           0 :                 if (child->dont_delete) {
     243           0 :                         DEBUG(10, ("Child %d was active since last cleanup\n",
     244             :                                    (int)child->pid));
     245           0 :                         child->dont_delete = false;
     246           0 :                         continue;
     247             :                 }
     248             : 
     249           0 :                 DEBUG(10, ("Child %d idle for more than 30 seconds, "
     250             :                            "deleting\n", (int)child->pid));
     251             : 
     252           0 :                 TALLOC_FREE(child);
     253           0 :                 child = next;
     254             :         }
     255             : 
     256           8 :         if (list->children != NULL) {
     257             :                 /*
     258             :                  * Re-schedule the next cleanup round
     259             :                  */
     260           8 :                 list->cleanup_event = tevent_add_timer(global_event_context(), list,
     261             :                                                       timeval_add(&now, 30, 0),
     262             :                                                       aio_child_cleanup, list);
     263             : 
     264             :         }
     265           8 : }
     266             : 
     267       25964 : static struct aio_child_list *init_aio_children(struct vfs_handle_struct *handle)
     268             : {
     269             :         struct aio_fork_config *config;
     270             :         struct aio_child_list *children;
     271             : 
     272       25964 :         SMB_VFS_HANDLE_GET_DATA(handle, config, struct aio_fork_config,
     273             :                                 return NULL);
     274             : 
     275       25964 :         if (config->children == NULL) {
     276          10 :                 config->children = talloc_zero(config, struct aio_child_list);
     277          10 :                 if (config->children == NULL) {
     278           0 :                         return NULL;
     279             :                 }
     280             :         }
     281       25964 :         children = config->children;
     282             : 
     283             :         /*
     284             :          * Regardless of whether the child_list had been around or not, make
     285             :          * sure that we have a cleanup timed event. This timed event will
     286             :          * delete itself when it finds that no children are around anymore.
     287             :          */
     288             : 
     289       25964 :         if (children->cleanup_event == NULL) {
     290          10 :                 children->cleanup_event =
     291          10 :                         tevent_add_timer(global_event_context(), children,
     292             :                                          timeval_current_ofs(30, 0),
     293             :                                          aio_child_cleanup, children);
     294          10 :                 if (children->cleanup_event == NULL) {
     295           0 :                         TALLOC_FREE(config->children);
     296           0 :                         return NULL;
     297             :                 }
     298             :         }
     299             : 
     300       25964 :         return children;
     301             : }
     302             : 
     303       25981 : static void aio_child_loop(int sockfd, struct mmap_area *map)
     304             : {
     305       25964 :         while (true) {
     306       25981 :                 int fd = -1;
     307             :                 ssize_t ret;
     308             :                 struct rw_cmd cmd_struct;
     309             :                 struct rw_ret ret_struct;
     310             :                 struct timespec start, end;
     311             : 
     312       25981 :                 ret = read_fd(sockfd, &cmd_struct, sizeof(cmd_struct), &fd);
     313       25981 :                 if (ret != sizeof(cmd_struct)) {
     314          17 :                         DEBUG(10, ("read_fd returned %d: %s\n", (int)ret,
     315             :                                    strerror(errno)));
     316          17 :                         exit(1);
     317             :                 }
     318             : 
     319       25964 :                 DEBUG(10, ("aio_child_loop: %s %d bytes at %d from fd %d\n",
     320             :                            cmd_type_str(cmd_struct.cmd),
     321             :                            (int)cmd_struct.n, (int)cmd_struct.offset, fd));
     322             : 
     323       25964 :                 if (cmd_struct.erratic_testing_mode) {
     324             :                         /*
     325             :                          * For developer testing, we want erratic behaviour for
     326             :                          * async I/O times
     327             :                          */
     328             :                         uint8_t randval;
     329             :                         unsigned msecs;
     330             :                         /*
     331             :                          * use generate_random_buffer, we just forked from a
     332             :                          * common parent state
     333             :                          */
     334       25964 :                         generate_random_buffer(&randval, sizeof(randval));
     335       25964 :                         msecs = (randval%20)+1;
     336       25964 :                         DEBUG(10, ("delaying for %u msecs\n", msecs));
     337       25964 :                         smb_msleep(msecs);
     338             :                 }
     339             : 
     340       25964 :                 ZERO_STRUCT(ret_struct);
     341             : 
     342       25964 :                 PROFILE_TIMESTAMP(&start);
     343             : 
     344       25964 :                 switch (cmd_struct.cmd) {
     345         628 :                 case READ_CMD:
     346         628 :                         ret_struct.size = sys_pread_full(
     347             :                                 fd, discard_const(map->ptr), cmd_struct.n,
     348             :                                 cmd_struct.offset);
     349             : #if 0
     350             : /* This breaks "make test" when run with aio_fork module. */
     351             : #ifdef DEVELOPER
     352             :                         ret_struct.size = MAX(1, ret_struct.size * 0.9);
     353             : #endif
     354             : #endif
     355         628 :                         break;
     356       25334 :                 case WRITE_CMD:
     357       50668 :                         ret_struct.size = sys_pwrite_full(
     358       25334 :                                 fd, discard_const(map->ptr), cmd_struct.n,
     359             :                                 cmd_struct.offset);
     360       25334 :                         break;
     361           2 :                 case FSYNC_CMD:
     362           2 :                         ret_struct.size = fsync(fd);
     363           2 :                         break;
     364           0 :                 default:
     365           0 :                         ret_struct.size = -1;
     366           0 :                         errno = EINVAL;
     367             :                 }
     368             : 
     369       25964 :                 PROFILE_TIMESTAMP(&end);
     370       25964 :                 ret_struct.duration = nsec_time_diff(&end, &start);
     371       25964 :                 DEBUG(10, ("aio_child_loop: syscall returned %d\n",
     372             :                            (int)ret_struct.size));
     373             : 
     374       25964 :                 if (ret_struct.size == -1) {
     375           0 :                         ret_struct.ret_errno = errno;
     376             :                 }
     377             : 
     378             :                 /*
     379             :                  * Close the fd before telling our parent we're done. The
     380             :                  * parent might close and re-open the file very quickly, and
     381             :                  * with system-level share modes (GPFS) we would get an
     382             :                  * unjustified SHARING_VIOLATION.
     383             :                  */
     384       25964 :                 close(fd);
     385             : 
     386       25964 :                 ret = write_data(sockfd, (char *)&ret_struct,
     387             :                                  sizeof(ret_struct));
     388       25964 :                 if (ret != sizeof(ret_struct)) {
     389           0 :                         DEBUG(10, ("could not write ret_struct: %s\n",
     390             :                                    strerror(errno)));
     391           0 :                         exit(2);
     392             :                 }
     393             :         }
     394             : }
     395             : 
     396          17 : static int aio_child_destructor(struct aio_child *child)
     397             : {
     398          17 :         char c=0;
     399             : 
     400          17 :         SMB_ASSERT(!child->busy);
     401             : 
     402          17 :         DEBUG(10, ("aio_child_destructor: removing child %d on fd %d\n",
     403             :                    (int)child->pid, child->sockfd));
     404             : 
     405             :         /*
     406             :          * closing the sockfd makes the child not return from recvmsg() on RHEL
     407             :          * 5.5 so instead force the child to exit by writing bad data to it
     408             :          */
     409          17 :         sys_write_v(child->sockfd, &c, sizeof(c));
     410          17 :         close(child->sockfd);
     411          17 :         DLIST_REMOVE(child->list->children, child);
     412          17 :         return 0;
     413             : }
     414             : 
     415             : /*
     416             :  * We have to close all fd's in open files, we might incorrectly hold a system
     417             :  * level share mode on a file.
     418             :  */
     419             : 
     420          21 : static struct files_struct *close_fsp_fd(struct files_struct *fsp,
     421             :                                          void *private_data)
     422             : {
     423          21 :         if ((fsp->fh != NULL) && (fsp_get_pathref_fd(fsp) != -1)) {
     424          21 :                 close(fsp_get_pathref_fd(fsp));
     425          21 :                 fsp_set_fd(fsp, -1);
     426             :         }
     427          21 :         return NULL;
     428             : }
     429             : 
     430          17 : static int create_aio_child(struct smbd_server_connection *sconn,
     431             :                             struct aio_child_list *children,
     432             :                             size_t map_size,
     433             :                             struct aio_child **presult)
     434             : {
     435             :         struct aio_child *result;
     436             :         int fdpair[2];
     437             :         int ret;
     438             : 
     439          17 :         fdpair[0] = fdpair[1] = -1;
     440             : 
     441          17 :         result = talloc_zero(children, struct aio_child);
     442          17 :         if (result == NULL) {
     443           0 :                 return ENOMEM;
     444             :         }
     445             : 
     446          17 :         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) == -1) {
     447           0 :                 ret = errno;
     448           0 :                 DEBUG(10, ("socketpair() failed: %s\n", strerror(errno)));
     449           0 :                 goto fail;
     450             :         }
     451             : 
     452          17 :         DEBUG(10, ("fdpair = %d/%d\n", fdpair[0], fdpair[1]));
     453             : 
     454          17 :         result->map = mmap_area_init(result, map_size);
     455          17 :         if (result->map == NULL) {
     456           0 :                 ret = errno;
     457           0 :                 DEBUG(0, ("Could not create mmap area\n"));
     458           0 :                 goto fail;
     459             :         }
     460             : 
     461          17 :         result->pid = fork();
     462          34 :         if (result->pid == -1) {
     463           0 :                 ret = errno;
     464           0 :                 DEBUG(0, ("fork failed: %s\n", strerror(errno)));
     465           0 :                 goto fail;
     466             :         }
     467             : 
     468          34 :         if (result->pid == 0) {
     469          17 :                 close(fdpair[0]);
     470          17 :                 result->sockfd = fdpair[1];
     471          17 :                 files_forall(sconn, close_fsp_fd, NULL);
     472          17 :                 aio_child_loop(result->sockfd, result->map);
     473             :         }
     474             : 
     475          17 :         DEBUG(10, ("Child %d created with sockfd %d\n",
     476             :                    (int)result->pid, fdpair[0]));
     477             : 
     478          17 :         result->sockfd = fdpair[0];
     479          17 :         close(fdpair[1]);
     480             : 
     481          17 :         result->list = children;
     482          17 :         DLIST_ADD(children->children, result);
     483             : 
     484          17 :         talloc_set_destructor(result, aio_child_destructor);
     485             : 
     486          17 :         *presult = result;
     487             : 
     488          17 :         return 0;
     489             : 
     490           0 :  fail:
     491           0 :         if (fdpair[0] != -1) close(fdpair[0]);
     492           0 :         if (fdpair[1] != -1) close(fdpair[1]);
     493           0 :         TALLOC_FREE(result);
     494             : 
     495           0 :         return ret;
     496             : }
     497             : 
     498       25964 : static int get_idle_child(struct vfs_handle_struct *handle,
     499             :                           struct aio_child **pchild)
     500             : {
     501             :         struct aio_child_list *children;
     502             :         struct aio_child *child;
     503             : 
     504       25964 :         children = init_aio_children(handle);
     505       25964 :         if (children == NULL) {
     506           0 :                 return ENOMEM;
     507             :         }
     508             : 
     509       26196 :         for (child = children->children; child != NULL; child = child->next) {
     510       26179 :                 if (!child->busy) {
     511       25947 :                         break;
     512             :                 }
     513             :         }
     514             : 
     515       25964 :         if (child == NULL) {
     516             :                 int ret;
     517             : 
     518          17 :                 DEBUG(10, ("no idle child found, creating new one\n"));
     519             : 
     520          17 :                 ret = create_aio_child(handle->conn->sconn, children,
     521             :                                           128*1024, &child);
     522          17 :                 if (ret != 0) {
     523           0 :                         DEBUG(10, ("create_aio_child failed: %s\n",
     524             :                                    strerror(errno)));
     525           0 :                         return ret;
     526             :                 }
     527             :         }
     528             : 
     529       25964 :         child->dont_delete = true;
     530       25964 :         child->busy = true;
     531             : 
     532       25964 :         *pchild = child;
     533       25964 :         return 0;
     534             : }
     535             : 
     536             : struct aio_fork_pread_state {
     537             :         struct aio_child *child;
     538             :         size_t n;
     539             :         void *data;
     540             :         ssize_t ret;
     541             :         struct vfs_aio_state vfs_aio_state;
     542             : };
     543             : 
     544             : static void aio_fork_pread_done(struct tevent_req *subreq);
     545             : 
     546         628 : static struct tevent_req *aio_fork_pread_send(struct vfs_handle_struct *handle,
     547             :                                               TALLOC_CTX *mem_ctx,
     548             :                                               struct tevent_context *ev,
     549             :                                               struct files_struct *fsp,
     550             :                                               void *data,
     551             :                                               size_t n, off_t offset)
     552             : {
     553             :         struct tevent_req *req, *subreq;
     554             :         struct aio_fork_pread_state *state;
     555             :         struct rw_cmd cmd;
     556             :         ssize_t written;
     557             :         int err;
     558             :         struct aio_fork_config *config;
     559             : 
     560         628 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
     561             :                                 struct aio_fork_config,
     562             :                                 return NULL);
     563             : 
     564         628 :         req = tevent_req_create(mem_ctx, &state, struct aio_fork_pread_state);
     565         628 :         if (req == NULL) {
     566           0 :                 return NULL;
     567             :         }
     568         628 :         state->n = n;
     569         628 :         state->data = data;
     570             : 
     571         628 :         if (n > 128*1024) {
     572             :                 /* TODO: support variable buffers */
     573           0 :                 tevent_req_error(req, EINVAL);
     574           0 :                 return tevent_req_post(req, ev);
     575             :         }
     576             : 
     577         628 :         err = get_idle_child(handle, &state->child);
     578         628 :         if (err != 0) {
     579           0 :                 tevent_req_error(req, err);
     580           0 :                 return tevent_req_post(req, ev);
     581             :         }
     582             : 
     583         628 :         ZERO_STRUCT(cmd);
     584         628 :         cmd.n = n;
     585         628 :         cmd.offset = offset;
     586         628 :         cmd.cmd = READ_CMD;
     587         628 :         cmd.erratic_testing_mode = config->erratic_testing_mode;
     588             : 
     589         628 :         DEBUG(10, ("sending fd %d to child %d\n", fsp_get_io_fd(fsp),
     590             :                    (int)state->child->pid));
     591             : 
     592             :         /*
     593             :          * Not making this async. We're writing into an empty unix
     594             :          * domain socket. This should never block.
     595             :          */
     596         628 :         written = write_fd(state->child->sockfd, &cmd, sizeof(cmd),
     597             :                            fsp_get_io_fd(fsp));
     598         628 :         if (written == -1) {
     599           0 :                 err = errno;
     600             : 
     601           0 :                 TALLOC_FREE(state->child);
     602             : 
     603           0 :                 DEBUG(10, ("write_fd failed: %s\n", strerror(err)));
     604           0 :                 tevent_req_error(req, err);
     605           0 :                 return tevent_req_post(req, ev);
     606             :         }
     607             : 
     608         628 :         subreq = read_packet_send(state, ev, state->child->sockfd,
     609             :                                   sizeof(struct rw_ret), NULL, NULL);
     610         628 :         if (tevent_req_nomem(subreq, req)) {
     611           0 :                 TALLOC_FREE(state->child); /* we sent sth down */
     612           0 :                 return tevent_req_post(req, ev);
     613             :         }
     614         628 :         tevent_req_set_callback(subreq, aio_fork_pread_done, req);
     615         628 :         return req;
     616             : }
     617             : 
     618         628 : static void aio_fork_pread_done(struct tevent_req *subreq)
     619             : {
     620         628 :         struct tevent_req *req = tevent_req_callback_data(
     621             :                 subreq, struct tevent_req);
     622         628 :         struct aio_fork_pread_state *state = tevent_req_data(
     623             :                 req, struct aio_fork_pread_state);
     624             :         ssize_t nread;
     625             :         uint8_t *buf;
     626             :         int err;
     627             :         struct rw_ret *retbuf;
     628             : 
     629         628 :         nread = read_packet_recv(subreq, talloc_tos(), &buf, &err);
     630         628 :         TALLOC_FREE(subreq);
     631         628 :         if (nread == -1) {
     632           0 :                 TALLOC_FREE(state->child);
     633           0 :                 tevent_req_error(req, err);
     634           0 :                 return;
     635             :         }
     636             : 
     637         628 :         retbuf = (struct rw_ret *)buf;
     638         628 :         state->ret = retbuf->size;
     639         628 :         state->vfs_aio_state.error = retbuf->ret_errno;
     640         628 :         state->vfs_aio_state.duration = retbuf->duration;
     641             : 
     642         628 :         if ((size_t)state->ret > state->n) {
     643           0 :                 tevent_req_error(req, EIO);
     644           0 :                 state->child->busy = false;
     645           0 :                 return;
     646             :         }
     647         628 :         memcpy(state->data, state->child->map->ptr, state->ret);
     648             : 
     649         628 :         state->child->busy = false;
     650             : 
     651         628 :         tevent_req_done(req);
     652             : }
     653             : 
     654         628 : static ssize_t aio_fork_pread_recv(struct tevent_req *req,
     655             :                                    struct vfs_aio_state *vfs_aio_state)
     656             : {
     657         628 :         struct aio_fork_pread_state *state = tevent_req_data(
     658             :                 req, struct aio_fork_pread_state);
     659             : 
     660         628 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
     661           0 :                 return -1;
     662             :         }
     663         628 :         *vfs_aio_state = state->vfs_aio_state;
     664         628 :         return state->ret;
     665             : }
     666             : 
     667             : struct aio_fork_pwrite_state {
     668             :         struct aio_child *child;
     669             :         ssize_t ret;
     670             :         struct vfs_aio_state vfs_aio_state;
     671             : };
     672             : 
     673             : static void aio_fork_pwrite_done(struct tevent_req *subreq);
     674             : 
     675       25334 : static struct tevent_req *aio_fork_pwrite_send(
     676             :         struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
     677             :         struct tevent_context *ev, struct files_struct *fsp,
     678             :         const void *data, size_t n, off_t offset)
     679             : {
     680             :         struct tevent_req *req, *subreq;
     681             :         struct aio_fork_pwrite_state *state;
     682             :         struct rw_cmd cmd;
     683             :         ssize_t written;
     684             :         int err;
     685             :         struct aio_fork_config *config;
     686       25334 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
     687             :                                 struct aio_fork_config,
     688             :                                 return NULL);
     689             : 
     690       25334 :         req = tevent_req_create(mem_ctx, &state, struct aio_fork_pwrite_state);
     691       25334 :         if (req == NULL) {
     692           0 :                 return NULL;
     693             :         }
     694             : 
     695       25334 :         if (n > 128*1024) {
     696             :                 /* TODO: support variable buffers */
     697           0 :                 tevent_req_error(req, EINVAL);
     698           0 :                 return tevent_req_post(req, ev);
     699             :         }
     700             : 
     701       25334 :         err = get_idle_child(handle, &state->child);
     702       25334 :         if (err != 0) {
     703           0 :                 tevent_req_error(req, err);
     704           0 :                 return tevent_req_post(req, ev);
     705             :         }
     706             : 
     707       25334 :         memcpy(state->child->map->ptr, data, n);
     708             : 
     709       25334 :         ZERO_STRUCT(cmd);
     710       25334 :         cmd.n = n;
     711       25334 :         cmd.offset = offset;
     712       25334 :         cmd.cmd = WRITE_CMD;
     713       25334 :         cmd.erratic_testing_mode = config->erratic_testing_mode;
     714             : 
     715       25334 :         DEBUG(10, ("sending fd %d to child %d\n", fsp_get_io_fd(fsp),
     716             :                    (int)state->child->pid));
     717             : 
     718             :         /*
     719             :          * Not making this async. We're writing into an empty unix
     720             :          * domain socket. This should never block.
     721             :          */
     722       25334 :         written = write_fd(state->child->sockfd, &cmd, sizeof(cmd),
     723             :                            fsp_get_io_fd(fsp));
     724       25334 :         if (written == -1) {
     725           0 :                 err = errno;
     726             : 
     727           0 :                 TALLOC_FREE(state->child);
     728             : 
     729           0 :                 DEBUG(10, ("write_fd failed: %s\n", strerror(err)));
     730           0 :                 tevent_req_error(req, err);
     731           0 :                 return tevent_req_post(req, ev);
     732             :         }
     733             : 
     734       25334 :         subreq = read_packet_send(state, ev, state->child->sockfd,
     735             :                                   sizeof(struct rw_ret), NULL, NULL);
     736       25334 :         if (tevent_req_nomem(subreq, req)) {
     737           0 :                 TALLOC_FREE(state->child); /* we sent sth down */
     738           0 :                 return tevent_req_post(req, ev);
     739             :         }
     740       25334 :         tevent_req_set_callback(subreq, aio_fork_pwrite_done, req);
     741       25334 :         return req;
     742             : }
     743             : 
     744       25334 : static void aio_fork_pwrite_done(struct tevent_req *subreq)
     745             : {
     746       25334 :         struct tevent_req *req = tevent_req_callback_data(
     747             :                 subreq, struct tevent_req);
     748       25334 :         struct aio_fork_pwrite_state *state = tevent_req_data(
     749             :                 req, struct aio_fork_pwrite_state);
     750             :         ssize_t nread;
     751             :         uint8_t *buf;
     752             :         int err;
     753             :         struct rw_ret *retbuf;
     754             : 
     755       25334 :         nread = read_packet_recv(subreq, talloc_tos(), &buf, &err);
     756       25334 :         TALLOC_FREE(subreq);
     757       25334 :         if (nread == -1) {
     758           0 :                 TALLOC_FREE(state->child);
     759           0 :                 tevent_req_error(req, err);
     760           0 :                 return;
     761             :         }
     762             : 
     763       25334 :         state->child->busy = false;
     764             : 
     765       25334 :         retbuf = (struct rw_ret *)buf;
     766       25334 :         state->ret = retbuf->size;
     767       25334 :         state->vfs_aio_state.error = retbuf->ret_errno;
     768       25334 :         state->vfs_aio_state.duration = retbuf->duration;
     769       25334 :         tevent_req_done(req);
     770             : }
     771             : 
     772       25334 : static ssize_t aio_fork_pwrite_recv(struct tevent_req *req,
     773             :                                     struct vfs_aio_state *vfs_aio_state)
     774             : {
     775       25334 :         struct aio_fork_pwrite_state *state = tevent_req_data(
     776             :                 req, struct aio_fork_pwrite_state);
     777             : 
     778       25334 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
     779           0 :                 return -1;
     780             :         }
     781       25334 :         *vfs_aio_state = state->vfs_aio_state;
     782       25334 :         return state->ret;
     783             : }
     784             : 
     785             : struct aio_fork_fsync_state {
     786             :         struct aio_child *child;
     787             :         ssize_t ret;
     788             :         struct vfs_aio_state vfs_aio_state;
     789             : };
     790             : 
     791             : static void aio_fork_fsync_done(struct tevent_req *subreq);
     792             : 
     793           2 : static struct tevent_req *aio_fork_fsync_send(
     794             :         struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
     795             :         struct tevent_context *ev, struct files_struct *fsp)
     796             : {
     797             :         struct tevent_req *req, *subreq;
     798             :         struct aio_fork_fsync_state *state;
     799             :         struct rw_cmd cmd;
     800             :         ssize_t written;
     801             :         int err;
     802             :         struct aio_fork_config *config;
     803             : 
     804           2 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
     805             :                                 struct aio_fork_config,
     806             :                                 return NULL);
     807             : 
     808           2 :         req = tevent_req_create(mem_ctx, &state, struct aio_fork_fsync_state);
     809           2 :         if (req == NULL) {
     810           0 :                 return NULL;
     811             :         }
     812             : 
     813           2 :         err = get_idle_child(handle, &state->child);
     814           2 :         if (err != 0) {
     815           0 :                 tevent_req_error(req, err);
     816           0 :                 return tevent_req_post(req, ev);
     817             :         }
     818             : 
     819           2 :         ZERO_STRUCT(cmd);
     820           2 :         cmd.cmd = FSYNC_CMD;
     821           2 :         cmd.erratic_testing_mode = config->erratic_testing_mode;
     822             : 
     823           2 :         DEBUG(10, ("sending fd %d to child %d\n", fsp_get_io_fd(fsp),
     824             :                    (int)state->child->pid));
     825             : 
     826             :         /*
     827             :          * Not making this async. We're writing into an empty unix
     828             :          * domain socket. This should never block.
     829             :          */
     830           2 :         written = write_fd(state->child->sockfd, &cmd, sizeof(cmd),
     831             :                            fsp_get_io_fd(fsp));
     832           2 :         if (written == -1) {
     833           0 :                 err = errno;
     834             : 
     835           0 :                 TALLOC_FREE(state->child);
     836             : 
     837           0 :                 DEBUG(10, ("write_fd failed: %s\n", strerror(err)));
     838           0 :                 tevent_req_error(req, err);
     839           0 :                 return tevent_req_post(req, ev);
     840             :         }
     841             : 
     842           2 :         subreq = read_packet_send(state, ev, state->child->sockfd,
     843             :                                   sizeof(struct rw_ret), NULL, NULL);
     844           2 :         if (tevent_req_nomem(subreq, req)) {
     845           0 :                 TALLOC_FREE(state->child); /* we sent sth down */
     846           0 :                 return tevent_req_post(req, ev);
     847             :         }
     848           2 :         tevent_req_set_callback(subreq, aio_fork_fsync_done, req);
     849           2 :         return req;
     850             : }
     851             : 
     852           2 : static void aio_fork_fsync_done(struct tevent_req *subreq)
     853             : {
     854           2 :         struct tevent_req *req = tevent_req_callback_data(
     855             :                 subreq, struct tevent_req);
     856           2 :         struct aio_fork_fsync_state *state = tevent_req_data(
     857             :                 req, struct aio_fork_fsync_state);
     858             :         ssize_t nread;
     859             :         uint8_t *buf;
     860             :         int err;
     861             :         struct rw_ret *retbuf;
     862             : 
     863           2 :         nread = read_packet_recv(subreq, talloc_tos(), &buf, &err);
     864           2 :         TALLOC_FREE(subreq);
     865           2 :         if (nread == -1) {
     866           0 :                 TALLOC_FREE(state->child);
     867           0 :                 tevent_req_error(req, err);
     868           0 :                 return;
     869             :         }
     870             : 
     871           2 :         state->child->busy = false;
     872             : 
     873           2 :         retbuf = (struct rw_ret *)buf;
     874           2 :         state->ret = retbuf->size;
     875           2 :         state->vfs_aio_state.error = retbuf->ret_errno;
     876           2 :         state->vfs_aio_state.duration = retbuf->duration;
     877           2 :         tevent_req_done(req);
     878             : }
     879             : 
     880           2 : static int aio_fork_fsync_recv(struct tevent_req *req,
     881             :                                struct vfs_aio_state *vfs_aio_state)
     882             : {
     883           2 :         struct aio_fork_fsync_state *state = tevent_req_data(
     884             :                 req, struct aio_fork_fsync_state);
     885             : 
     886           2 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
     887           0 :                 return -1;
     888             :         }
     889           2 :         *vfs_aio_state = state->vfs_aio_state;
     890           2 :         return state->ret;
     891             : }
     892             : 
     893          10 : static int aio_fork_connect(vfs_handle_struct *handle, const char *service,
     894             :                             const char *user)
     895             : {
     896             :         int ret;
     897             :         struct aio_fork_config *config;
     898          10 :         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
     899             : 
     900          10 :         if (ret < 0) {
     901           0 :                 return ret;
     902             :         }
     903             : 
     904          10 :         config = talloc_zero(handle->conn, struct aio_fork_config);
     905          10 :         if (!config) {
     906           0 :                 SMB_VFS_NEXT_DISCONNECT(handle);
     907           0 :                 DEBUG(0, ("talloc_zero() failed\n"));
     908           0 :                 return -1;
     909             :         }
     910             : 
     911          10 :         config->erratic_testing_mode = lp_parm_bool(SNUM(handle->conn), "vfs_aio_fork",
     912             :                                                     "erratic_testing_mode", false);
     913             :         
     914          10 :         SMB_VFS_HANDLE_SET_DATA(handle, config,
     915             :                                 NULL, struct aio_fork_config,
     916             :                                 return -1);
     917             : 
     918          10 :         return 0;
     919             : }
     920             : 
     921             : static struct vfs_fn_pointers vfs_aio_fork_fns = {
     922             :         .connect_fn = aio_fork_connect,
     923             :         .pread_send_fn = aio_fork_pread_send,
     924             :         .pread_recv_fn = aio_fork_pread_recv,
     925             :         .pwrite_send_fn = aio_fork_pwrite_send,
     926             :         .pwrite_recv_fn = aio_fork_pwrite_recv,
     927             :         .fsync_send_fn = aio_fork_fsync_send,
     928             :         .fsync_recv_fn = aio_fork_fsync_recv,
     929             : };
     930             : 
     931             : static_decl_vfs;
     932          37 : NTSTATUS vfs_aio_fork_init(TALLOC_CTX *ctx)
     933             : {
     934          37 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
     935             :                                 "aio_fork", &vfs_aio_fork_fns);
     936             : }

Generated by: LCOV version 1.14