"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-aio.c" (15 Mar 2019, 6836 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-aio.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.50_vs_0.09.51.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #if defined(HAVE_LIB_RT) && \
   28     defined(HAVE_AIO_H) && \
   29     NEED_GLIBC(2,1,0)
   30 
   31 #define BUFFER_SZ   (16)
   32 
   33 /* per request async I/O data */
   34 typedef struct {
   35     int     request;        /* Request slot */
   36     int     status;         /* AIO error status */
   37     struct aiocb    aiocb;          /* AIO cb */
   38     uint8_t     buffer[BUFFER_SZ];  /* Associated read/write buffer */
   39     volatile uint64_t count;        /* Signal handled count */
   40 } io_req_t;
   41 
   42 static volatile bool do_accounting = true;
   43 #endif
   44 
   45 int stress_set_aio_requests(const char *opt)
   46 {
   47     uint64_t aio_requests;
   48 
   49     aio_requests = get_uint64(opt);
   50     check_range("aio-requests", aio_requests,
   51         MIN_AIO_REQUESTS, MAX_AIO_REQUESTS);
   52     return set_setting("aio-requests", TYPE_ID_UINT64, &aio_requests);
   53 }
   54 
   55 #if defined(HAVE_LIB_RT) && \
   56     defined(HAVE_AIO_H) && \
   57     NEED_GLIBC(2,1,0)
   58 /*
   59  *  aio_fill_buffer()
   60  *  fill buffer with some known pattern
   61  */
   62 static inline void aio_fill_buffer(
   63     const int request,
   64     uint8_t *const buffer,
   65     const size_t size)
   66 {
   67     register size_t i;
   68 
   69     for (i = 0; i < size; i++)
   70         buffer[i] = (uint8_t)(request + i);
   71 }
   72 
   73 /*
   74  *  aio_signal_handler()
   75  *  handle an async I/O signal
   76  */
   77 static void MLOCKED_TEXT aio_signal_handler(int sig, siginfo_t *si, void *ucontext)
   78 {
   79     io_req_t *io_req = (io_req_t *)si->si_value.sival_ptr;
   80 
   81     (void)sig;
   82     (void)si;
   83     (void)ucontext;
   84 
   85     if (do_accounting && io_req)
   86         io_req->count++;
   87 }
   88 
   89 /*
   90  *  aio_issue_cancel()
   91  *  cancel an in-progress async I/O request
   92  */
   93 static void aio_issue_cancel(const char *name, io_req_t *io_req)
   94 {
   95     int ret;
   96 
   97     if (io_req->status != EINPROGRESS)
   98         return;
   99 
  100     ret = aio_cancel(io_req->aiocb.aio_fildes,
  101         &io_req->aiocb);
  102     switch (ret) {
  103     case AIO_CANCELED:
  104     case AIO_ALLDONE:
  105         break;
  106     case AIO_NOTCANCELED:
  107         pr_dbg("%s: async I/O request %d not cancelled\n",
  108             name, io_req->request);
  109         break;
  110     default:
  111         pr_err("%s: %d error: %d %s\n",
  112             name, io_req->request,
  113             errno, strerror(errno));
  114     }
  115 }
  116 
  117 /*
  118  *  issue_aio_request()
  119  *  construct an AIO request and action it
  120  */
  121 static int issue_aio_request(
  122     const char *name,
  123     const int fd,
  124     const off_t offset,
  125     io_req_t *const io_req,
  126     const int request,
  127     int (*aio_func)(struct aiocb *aiocbp) )
  128 {
  129     while (g_keep_stressing_flag) {
  130         int ret;
  131 
  132         io_req->request = request;
  133         io_req->status = EINPROGRESS;
  134         io_req->aiocb.aio_fildes = fd;
  135         io_req->aiocb.aio_buf = io_req->buffer;
  136         io_req->aiocb.aio_nbytes = BUFFER_SZ;
  137         io_req->aiocb.aio_reqprio = 0;
  138         io_req->aiocb.aio_offset = offset;
  139         io_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  140         io_req->aiocb.aio_sigevent.sigev_signo = SIGUSR1;
  141         io_req->aiocb.aio_sigevent.sigev_value.sival_ptr = io_req;
  142 
  143         ret = aio_func(&io_req->aiocb);
  144         if (ret < 0) {
  145             if ((errno == EAGAIN) || (errno == EINTR))
  146                 continue;
  147             pr_err("%s: failed to issue aio request: %d (%s)\n",
  148                 name, errno, strerror(errno));
  149         }
  150         return ret;
  151     }
  152     /* Given up */
  153     return 1;
  154 }
  155 
  156 /*
  157  *  stress_aio
  158  *  stress asynchronous I/O
  159  */
  160 static int stress_aio(const args_t *args)
  161 {
  162     int ret, fd, rc = EXIT_FAILURE;
  163     io_req_t *io_reqs;
  164     struct sigaction sa, sa_old;
  165     char filename[PATH_MAX];
  166     uint64_t total = 0, i, opt_aio_requests = DEFAULT_AIO_REQUESTS;
  167 
  168     if (!get_setting("aio-requests", &opt_aio_requests)) {
  169         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  170             opt_aio_requests = MAX_AIO_REQUESTS;
  171         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  172             opt_aio_requests = MIN_AIO_REQUESTS;
  173     }
  174 
  175     if ((io_reqs = calloc(opt_aio_requests, sizeof(*io_reqs))) == NULL) {
  176         pr_err("%s: cannot allocate io request structures\n", args->name);
  177         return EXIT_NO_RESOURCE;
  178     }
  179 
  180     ret = stress_temp_dir_mk_args(args);
  181     if (ret < 0) {
  182         free(io_reqs);
  183         return exit_status(-ret);
  184     }
  185 
  186     (void)stress_temp_filename_args(args,
  187         filename, sizeof(filename), mwc32());
  188 
  189     if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
  190         rc = exit_status(errno);
  191         pr_fail_err("open");
  192         goto finish;
  193     }
  194     (void)unlink(filename);
  195 
  196     (void)sigemptyset(&sa.sa_mask);
  197     sa.sa_flags = SA_RESTART | SA_SIGINFO;
  198     sa.sa_sigaction = aio_signal_handler;
  199     if (sigaction(SIGUSR1, &sa, &sa_old) < 0)
  200         pr_fail_err("sigaction");
  201 
  202     /* Kick off requests */
  203     for (i = 0; i < opt_aio_requests; i++) {
  204         aio_fill_buffer(i, io_reqs[i].buffer, BUFFER_SZ);
  205         ret = issue_aio_request(args->name, fd, (off_t)i * BUFFER_SZ,
  206             &io_reqs[i], i, aio_write);
  207         if (ret < 0)
  208             goto cancel;
  209         if (ret > 0) {
  210             rc = EXIT_SUCCESS;
  211             goto cancel;
  212         }
  213     }
  214 
  215     do {
  216         (void)shim_usleep(250000); /* wait until a signal occurs */
  217 
  218         for (i = 0; keep_stressing() && (i < opt_aio_requests); i++) {
  219             if (io_reqs[i].status != EINPROGRESS)
  220                 continue;
  221 
  222             io_reqs[i].status = aio_error(&io_reqs[i].aiocb);
  223             switch (io_reqs[i].status) {
  224             case ECANCELED:
  225             case 0:
  226                 /* Succeeded or cancelled, so redo another */
  227                 inc_counter(args);
  228                 if (issue_aio_request(args->name, fd,
  229                     (off_t)i * BUFFER_SZ, &io_reqs[i], i,
  230                     mwc1() ? aio_read : aio_write) < 0)
  231                     goto cancel;
  232                 break;
  233             case EINPROGRESS:
  234                 break;
  235             default:
  236                 /* Something went wrong */
  237                 pr_fail_errno("aio_error",
  238                     io_reqs[i].status);
  239                 goto cancel;
  240             }
  241         }
  242     } while (keep_stressing());
  243 
  244     rc = EXIT_SUCCESS;
  245 
  246 cancel:
  247     /* Stop accounting */
  248     do_accounting = false;
  249     /* Cancel pending AIO requests */
  250     for (i = 0; i < opt_aio_requests; i++) {
  251         aio_issue_cancel(args->name, &io_reqs[i]);
  252         total += io_reqs[i].count;
  253     }
  254     (void)close(fd);
  255 finish:
  256     free(io_reqs);
  257 
  258     pr_dbg("%s: total of %" PRIu64 " async I/O signals "
  259         "caught (instance %d)\n",
  260         args->name, total, args->instance);
  261     (void)stress_temp_dir_rm_args(args);
  262     return rc;
  263 }
  264 
  265 stressor_info_t stress_aio_info = {
  266     .stressor = stress_aio,
  267     .class = CLASS_IO | CLASS_INTERRUPT | CLASS_OS
  268 };
  269 #else
  270 stressor_info_t stress_aio_info = {
  271     .stressor = stress_not_implemented,
  272     .class = CLASS_IO | CLASS_INTERRUPT | CLASS_OS
  273 };
  274 #endif