LCOV - code coverage report
Current view: top level - spdk/module/bdev/aio - bdev_aio.c (source / functions) Hit Total Coverage
Test: Combined Lines: 356 560 63.6 %
Date: 2024-11-20 12:56:55 Functions: 38 44 86.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 132 1212 10.9 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  *   Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "bdev_aio.h"
       8                 :            : 
       9                 :            : #include "spdk/stdinc.h"
      10                 :            : 
      11                 :            : #include "spdk/barrier.h"
      12                 :            : #include "spdk/bdev.h"
      13                 :            : #include "spdk/bdev_module.h"
      14                 :            : #include "spdk/env.h"
      15                 :            : #include "spdk/fd.h"
      16                 :            : #include "spdk/likely.h"
      17                 :            : #include "spdk/thread.h"
      18                 :            : #include "spdk/json.h"
      19                 :            : #include "spdk/util.h"
      20                 :            : #include "spdk/string.h"
      21                 :            : 
      22                 :            : #include "spdk/log.h"
      23                 :            : 
      24                 :            : #include <sys/eventfd.h>
      25                 :            : 
      26                 :            : #ifndef __FreeBSD__
      27                 :            : #include <libaio.h>
      28                 :            : #endif
      29                 :            : 
      30                 :            : struct bdev_aio_io_channel {
      31                 :            :         uint64_t                                io_inflight;
      32                 :            : #ifdef __FreeBSD__
      33                 :            :         int                                     kqfd;
      34                 :            : #else
      35                 :            :         io_context_t                            io_ctx;
      36                 :            : #endif
      37                 :            :         struct bdev_aio_group_channel           *group_ch;
      38                 :            :         TAILQ_ENTRY(bdev_aio_io_channel)        link;
      39                 :            : };
      40                 :            : 
      41                 :            : struct bdev_aio_group_channel {
      42                 :            :         /* eventfd for io completion notification in interrupt mode.
      43                 :            :          * Negative value like '-1' indicates it is invalid or unused.
      44                 :            :          */
      45                 :            :         int                                     efd;
      46                 :            :         struct spdk_interrupt                   *intr;
      47                 :            :         struct spdk_poller                      *poller;
      48                 :            :         TAILQ_HEAD(, bdev_aio_io_channel)       io_ch_head;
      49                 :            : };
      50                 :            : 
      51                 :            : struct bdev_aio_task {
      52                 :            : #ifdef __FreeBSD__
      53                 :            :         struct aiocb                    aiocb;
      54                 :            : #else
      55                 :            :         struct iocb                     iocb;
      56                 :            : #endif
      57                 :            :         uint64_t                        len;
      58                 :            :         struct bdev_aio_io_channel      *ch;
      59                 :            : };
      60                 :            : 
      61                 :            : struct file_disk {
      62                 :            :         struct bdev_aio_task    *reset_task;
      63                 :            :         struct spdk_poller      *reset_retry_timer;
      64                 :            :         struct spdk_bdev        disk;
      65                 :            :         char                    *filename;
      66                 :            :         int                     fd;
      67                 :            : #ifdef RWF_NOWAIT
      68                 :            :         bool                    use_nowait;
      69                 :            : #endif
      70                 :            :         TAILQ_ENTRY(file_disk)  link;
      71                 :            :         bool                    block_size_override;
      72                 :            :         bool                    readonly;
      73                 :            :         bool                    fallocate;
      74                 :            : };
      75                 :            : 
      76                 :            : /* For user space reaping of completions */
      77                 :            : struct spdk_aio_ring {
      78                 :            :         uint32_t id;
      79                 :            :         uint32_t size;
      80                 :            :         uint32_t head;
      81                 :            :         uint32_t tail;
      82                 :            : 
      83                 :            :         uint32_t version;
      84                 :            :         uint32_t compat_features;
      85                 :            :         uint32_t incompat_features;
      86                 :            :         uint32_t header_length;
      87                 :            : };
      88                 :            : 
      89                 :            : #define SPDK_AIO_RING_VERSION   0xa10a10a1
      90                 :            : 
      91                 :            : static int bdev_aio_initialize(void);
      92                 :            : static void bdev_aio_fini(void);
      93                 :            : static void aio_free_disk(struct file_disk *fdisk);
      94                 :            : static TAILQ_HEAD(, file_disk) g_aio_disk_head = TAILQ_HEAD_INITIALIZER(g_aio_disk_head);
      95                 :            : 
      96                 :            : #define SPDK_AIO_QUEUE_DEPTH 128
      97                 :            : #define MAX_EVENTS_PER_POLL 32
      98                 :            : 
      99                 :            : static int
     100                 :       2137 : bdev_aio_get_ctx_size(void)
     101                 :            : {
     102                 :       2137 :         return sizeof(struct bdev_aio_task);
     103                 :            : }
     104                 :            : 
     105                 :            : static struct spdk_bdev_module aio_if = {
     106                 :            :         .name           = "aio",
     107                 :            :         .module_init    = bdev_aio_initialize,
     108                 :            :         .module_fini    = bdev_aio_fini,
     109                 :            :         .get_ctx_size   = bdev_aio_get_ctx_size,
     110                 :            : };
     111                 :            : 
     112                 :       2174 : SPDK_BDEV_MODULE_REGISTER(aio, &aio_if)
     113                 :            : 
     114                 :            : static int
     115                 :        162 : bdev_aio_open(struct file_disk *disk)
     116                 :            : {
     117                 :            :         int fd;
     118   [ -  +  -  +  :        162 :         int io_flag = disk->readonly ? O_RDONLY : O_RDWR;
                   #  # ]
     119                 :            : #ifdef RWF_NOWAIT
     120                 :        114 :         struct stat st;
     121                 :            : #endif
     122                 :            : 
     123   [ -  +  #  #  :        162 :         fd = open(disk->filename, io_flag | O_DIRECT);
                   #  # ]
     124         [ +  + ]:        162 :         if (fd < 0) {
     125                 :            :                 /* Try without O_DIRECT for non-disk files */
     126   [ #  #  #  #  :          0 :                 fd = open(disk->filename, io_flag);
                   #  # ]
     127         [ #  # ]:          0 :                 if (fd < 0) {
     128   [ #  #  #  #  :          0 :                         SPDK_ERRLOG("open() failed (file:%s), errno %d: %s\n",
             #  #  #  # ]
     129                 :            :                                     disk->filename, errno, spdk_strerror(errno));
     130   [ #  #  #  # ]:          0 :                         disk->fd = -1;
     131                 :          0 :                         return -1;
     132                 :            :                 }
     133                 :          0 :         }
     134                 :            : 
     135   [ #  #  #  # ]:        162 :         disk->fd = fd;
     136                 :            : 
     137                 :            : #ifdef RWF_NOWAIT
     138                 :            :         /* Some aio operations can block, for example if number outstanding
     139                 :            :          * I/O exceeds number of block layer tags. But not all files can
     140                 :            :          * support RWF_NOWAIT flag. So use RWF_NOWAIT on block devices only.
     141                 :            :          */
     142   [ +  -  -  +  :        152 :         disk->use_nowait = fstat(fd, &st) == 0 && S_ISBLK(st.st_mode);
          #  #  #  #  #  
                      # ]
     143                 :            : #endif
     144                 :            : 
     145                 :        162 :         return 0;
     146                 :         10 : }
     147                 :            : 
     148                 :            : static int
     149                 :        162 : bdev_aio_close(struct file_disk *disk)
     150                 :            : {
     151                 :            :         int rc;
     152                 :            : 
     153   [ +  +  #  #  :        162 :         if (disk->fd == -1) {
                   #  # ]
     154                 :          0 :                 return 0;
     155                 :            :         }
     156                 :            : 
     157   [ #  #  #  # ]:        162 :         rc = close(disk->fd);
     158         [ -  + ]:        162 :         if (rc < 0) {
     159   [ #  #  #  #  :          0 :                 SPDK_ERRLOG("close() failed (fd=%d), errno %d: %s\n",
             #  #  #  # ]
     160                 :            :                             disk->fd, errno, spdk_strerror(errno));
     161                 :          0 :                 return -1;
     162                 :            :         }
     163                 :            : 
     164   [ #  #  #  # ]:        162 :         disk->fd = -1;
     165                 :            : 
     166                 :        162 :         return 0;
     167                 :         10 : }
     168                 :            : 
     169                 :            : #ifdef __FreeBSD__
     170                 :            : static int
     171                 :      35849 : bdev_aio_submit_io(enum spdk_bdev_io_type type, struct file_disk *fdisk,
     172                 :            :                    struct spdk_io_channel *ch, struct bdev_aio_task *aio_task,
     173                 :            :                    struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t offset)
     174                 :            : {
     175                 :      35849 :         struct aiocb *aiocb = &aio_task->aiocb;
     176                 :      35849 :         struct bdev_aio_io_channel *aio_ch = spdk_io_channel_get_ctx(ch);
     177                 :            : 
     178                 :      35849 :         memset(aiocb, 0, sizeof(struct aiocb));
     179                 :      35849 :         aiocb->aio_fildes = fdisk->fd;
     180                 :      35849 :         aiocb->aio_iov = iov;
     181                 :      35849 :         aiocb->aio_iovcnt = iovcnt;
     182                 :      35849 :         aiocb->aio_offset = offset;
     183                 :      35849 :         aiocb->aio_sigevent.sigev_notify_kqueue = aio_ch->kqfd;
     184                 :      35849 :         aiocb->aio_sigevent.sigev_value.sival_ptr = aio_task;
     185                 :      35849 :         aiocb->aio_sigevent.sigev_notify = SIGEV_KEVENT;
     186                 :            : 
     187                 :      35849 :         aio_task->len = nbytes;
     188                 :      35849 :         aio_task->ch = aio_ch;
     189                 :            : 
     190         [ +  + ]:      35849 :         if (type == SPDK_BDEV_IO_TYPE_READ) {
     191                 :      15471 :                 return aio_readv(aiocb);
     192                 :            :         }
     193                 :            : 
     194                 :      20378 :         return aio_writev(aiocb);
     195                 :      35849 : }
     196                 :            : #else
     197                 :            : static int
     198                 :    1764756 : bdev_aio_submit_io(enum spdk_bdev_io_type type, struct file_disk *fdisk,
     199                 :            :                    struct spdk_io_channel *ch, struct bdev_aio_task *aio_task,
     200                 :            :                    struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t offset)
     201                 :            : {
     202         [ #  # ]:    1764756 :         struct iocb *iocb = &aio_task->iocb;
     203                 :    1764756 :         struct bdev_aio_io_channel *aio_ch = spdk_io_channel_get_ctx(ch);
     204                 :            : 
     205         [ +  + ]:    1764756 :         if (type == SPDK_BDEV_IO_TYPE_READ) {
     206   [ #  #  #  # ]:     735976 :                 io_prep_preadv(iocb, fdisk->fd, iov, iovcnt, offset);
     207                 :          0 :         } else {
     208   [ #  #  #  # ]:    1028780 :                 io_prep_pwritev(iocb, fdisk->fd, iov, iovcnt, offset);
     209                 :            :         }
     210                 :            : 
     211   [ +  +  #  #  :    1764756 :         if (aio_ch->group_ch->efd >= 0) {
          #  #  #  #  #  
                      # ]
     212   [ #  #  #  #  :     499447 :                 io_set_eventfd(iocb, aio_ch->group_ch->efd);
             #  #  #  # ]
     213                 :          0 :         }
     214   [ #  #  #  # ]:    1764756 :         iocb->data = aio_task;
     215                 :            : #ifdef RWF_NOWAIT
     216   [ -  +  -  +  :    1764756 :         if (fdisk->use_nowait) {
             #  #  #  # ]
     217   [ #  #  #  # ]:          0 :                 iocb->aio_rw_flags = RWF_NOWAIT;
     218                 :          0 :         }
     219                 :            : #endif
     220   [ #  #  #  # ]:    1764756 :         aio_task->len = nbytes;
     221   [ #  #  #  # ]:    1764756 :         aio_task->ch = aio_ch;
     222                 :            : 
     223   [ #  #  #  # ]:    1764756 :         return io_submit(aio_ch->io_ctx, 1, &iocb);
     224                 :            : }
     225                 :            : #endif
     226                 :            : 
     227                 :            : static void
     228                 :    1800609 : bdev_aio_rw(enum spdk_bdev_io_type type, struct file_disk *fdisk,
     229                 :            :             struct spdk_io_channel *ch, struct bdev_aio_task *aio_task,
     230                 :            :             struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t offset)
     231                 :            : {
     232                 :    1800609 :         struct bdev_aio_io_channel *aio_ch = spdk_io_channel_get_ctx(ch);
     233                 :            :         int rc;
     234                 :            : 
     235         [ +  + ]:    1800609 :         if (type == SPDK_BDEV_IO_TYPE_READ) {
     236   [ +  +  -  +  :     751452 :                 SPDK_DEBUGLOG(aio, "read %d iovs size %lu to off: %#lx\n",
                   #  # ]
     237                 :            :                               iovcnt, nbytes, offset);
     238                 :      15476 :         } else {
     239   [ +  +  -  +  :    1049157 :                 SPDK_DEBUGLOG(aio, "write %d iovs size %lu from off: %#lx\n",
                   #  # ]
     240                 :            :                               iovcnt, nbytes, offset);
     241                 :            :         }
     242                 :            : 
     243                 :    1800609 :         rc = bdev_aio_submit_io(type, fdisk, ch, aio_task, iov, iovcnt, nbytes, offset);
     244         [ -  + ]:    1800609 :         if (spdk_unlikely(rc < 0)) {
     245         [ #  # ]:          0 :                 if (rc == -EAGAIN) {
     246                 :          0 :                         spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_NOMEM);
     247                 :          0 :                 } else {
     248                 :          0 :                         spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), rc);
     249                 :          0 :                         SPDK_ERRLOG("%s: io_submit returned %d\n", __func__, rc);
     250                 :            :                 }
     251                 :          0 :         } else {
     252         [ #  # ]:    1800609 :                 aio_ch->io_inflight++;
     253                 :            :         }
     254                 :    1800609 : }
     255                 :            : 
     256                 :            : static void
     257                 :          0 : bdev_aio_flush(struct file_disk *fdisk, struct bdev_aio_task *aio_task)
     258                 :            : {
     259   [ #  #  #  # ]:          0 :         int rc = fsync(fdisk->fd);
     260                 :            : 
     261         [ #  # ]:          0 :         if (rc == 0) {
     262                 :          0 :                 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_SUCCESS);
     263                 :          0 :         } else {
     264   [ #  #  #  # ]:          0 :                 spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), -errno);
     265                 :            :         }
     266                 :          0 : }
     267                 :            : 
     268                 :            : #ifndef __FreeBSD__
     269                 :            : static void
     270                 :          0 : bdev_aio_fallocate(struct spdk_bdev_io *bdev_io, int mode)
     271                 :            : {
     272   [ #  #  #  #  :          0 :         struct file_disk *fdisk = (struct file_disk *)bdev_io->bdev->ctxt;
             #  #  #  # ]
     273         [ #  # ]:          0 :         struct bdev_aio_task *aio_task = (struct bdev_aio_task *)bdev_io->driver_ctx;
     274   [ #  #  #  #  :          0 :         uint64_t offset_bytes = bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     275   [ #  #  #  #  :          0 :         uint64_t length_bytes = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     276                 :            :         int rc;
     277                 :            : 
     278   [ #  #  #  #  :          0 :         if (!fdisk->fallocate) {
             #  #  #  # ]
     279                 :          0 :                 spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), -ENOTSUP);
     280                 :          0 :                 return;
     281                 :            :         }
     282                 :            : 
     283   [ #  #  #  # ]:          0 :         rc = fallocate(fdisk->fd, mode, offset_bytes, length_bytes);
     284         [ #  # ]:          0 :         if (rc == 0) {
     285                 :          0 :                 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_SUCCESS);
     286                 :          0 :         } else {
     287   [ #  #  #  # ]:          0 :                 spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), -errno);
     288                 :            :         }
     289                 :          0 : }
     290                 :            : 
     291                 :            : static void
     292                 :          0 : bdev_aio_unmap(struct spdk_bdev_io *bdev_io)
     293                 :            : {
     294                 :          0 :         int mode = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE;
     295                 :            : 
     296                 :          0 :         bdev_aio_fallocate(bdev_io, mode);
     297                 :          0 : }
     298                 :            : 
     299                 :            : 
     300                 :            : static void
     301                 :          0 : bdev_aio_write_zeros(struct spdk_bdev_io *bdev_io)
     302                 :            : {
     303                 :          0 :         int mode = FALLOC_FL_ZERO_RANGE;
     304                 :            : 
     305                 :          0 :         bdev_aio_fallocate(bdev_io, mode);
     306                 :          0 : }
     307                 :            : #endif
     308                 :            : 
     309                 :            : static void
     310                 :        162 : bdev_aio_destruct_cb(void *io_device)
     311                 :            : {
     312                 :        162 :         struct file_disk *fdisk = io_device;
     313                 :        162 :         int rc = 0;
     314                 :            : 
     315   [ +  +  #  #  :        162 :         TAILQ_REMOVE(&g_aio_disk_head, fdisk, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     316                 :        162 :         rc = bdev_aio_close(fdisk);
     317         [ -  + ]:        162 :         if (rc < 0) {
     318                 :          0 :                 SPDK_ERRLOG("bdev_aio_close() failed\n");
     319                 :          0 :         }
     320                 :        162 :         aio_free_disk(fdisk);
     321                 :        162 : }
     322                 :            : 
     323                 :            : static int
     324                 :        162 : bdev_aio_destruct(void *ctx)
     325                 :            : {
     326                 :        162 :         struct file_disk *fdisk = ctx;
     327                 :            : 
     328                 :        162 :         spdk_io_device_unregister(fdisk, bdev_aio_destruct_cb);
     329                 :            : 
     330                 :        162 :         return 0;
     331                 :            : }
     332                 :            : 
     333                 :            : #ifdef __FreeBSD__
     334                 :            : static int
     335                 :    1536744 : bdev_user_io_getevents(int kq, unsigned int max, struct kevent *events)
     336                 :            : {
     337                 :            :         struct timespec ts;
     338                 :            :         int count;
     339                 :            : 
     340                 :    1536744 :         memset(events, 0, max * sizeof(struct kevent));
     341                 :    1536744 :         memset(&ts, 0, sizeof(ts));
     342                 :            : 
     343                 :    1536744 :         count = kevent(kq, NULL, 0, events, max, &ts);
     344         [ -  + ]:    1536744 :         if (count < 0) {
     345                 :          0 :                 SPDK_ERRLOG("failed to get kevents: %s.\n", spdk_strerror(errno));
     346                 :          0 :                 return -errno;
     347                 :            :         }
     348                 :            : 
     349                 :    1536744 :         return count;
     350                 :    1536744 : }
     351                 :            : 
     352                 :            : static int
     353                 :    1536751 : bdev_aio_io_channel_poll(struct bdev_aio_io_channel *io_ch)
     354                 :            : {
     355                 :    1536751 :         int nr, i, res = 0;
     356                 :            :         struct bdev_aio_task *aio_task;
     357                 :            :         struct kevent events[SPDK_AIO_QUEUE_DEPTH];
     358                 :            : 
     359                 :    1536751 :         nr = bdev_user_io_getevents(io_ch->kqfd, SPDK_AIO_QUEUE_DEPTH, events);
     360         [ +  - ]:    1536751 :         if (nr < 0) {
     361                 :          0 :                 return 0;
     362                 :            :         }
     363                 :            : 
     364         [ +  + ]:    1572603 :         for (i = 0; i < nr; i++) {
     365                 :      35852 :                 aio_task = events[i].udata;
     366                 :      35852 :                 aio_task->ch->io_inflight--;
     367         [ -  + ]:      35852 :                 if (aio_task == NULL) {
     368                 :          0 :                         spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_FAILED);
     369                 :          0 :                         break;
     370         [ +  - ]:      35852 :                 } else if ((uint64_t)aio_return(&aio_task->aiocb) == aio_task->len) {
     371                 :      35852 :                         spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_SUCCESS);
     372                 :      35852 :                 } else {
     373                 :          0 :                         SPDK_ERRLOG("failed to complete aio: rc %d\n", aio_error(&aio_task->aiocb));
     374                 :          0 :                         res = aio_error(&aio_task->aiocb);
     375         [ #  # ]:          0 :                         if (res != 0) {
     376                 :          0 :                                 spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), res);
     377                 :          0 :                         } else {
     378                 :          0 :                                 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_FAILED);
     379                 :            :                         }
     380                 :            :                 }
     381                 :      35852 :         }
     382                 :            : 
     383                 :    1536751 :         return nr;
     384                 :    1536751 : }
     385                 :            : #else
     386                 :            : static int
     387                 :   13627328 : bdev_user_io_getevents(io_context_t io_ctx, unsigned int max, struct io_event *uevents)
     388                 :            : {
     389                 :            :         uint32_t head, tail, count;
     390                 :            :         struct spdk_aio_ring *ring;
     391                 :    7929728 :         struct timespec timeout;
     392                 :            :         struct io_event *kevents;
     393                 :            : 
     394                 :   13627328 :         ring = (struct spdk_aio_ring *)io_ctx;
     395                 :            : 
     396   [ +  -  -  +  :   13627328 :         if (spdk_unlikely(ring->version != SPDK_AIO_RING_VERSION || ring->incompat_features != 0)) {
          #  #  #  #  #  
                #  #  # ]
     397                 :          0 :                 timeout.tv_sec = 0;
     398         [ #  # ]:          0 :                 timeout.tv_nsec = 0;
     399                 :            : 
     400                 :          0 :                 return io_getevents(io_ctx, 0, max, uevents, &timeout);
     401                 :            :         }
     402                 :            : 
     403                 :            :         /* Read the current state out of the ring */
     404   [ #  #  #  # ]:   13627328 :         head = ring->head;
     405   [ #  #  #  # ]:   13627328 :         tail = ring->tail;
     406                 :            : 
     407                 :            :         /* This memory barrier is required to prevent the loads above
     408                 :            :          * from being re-ordered with stores to the events array
     409                 :            :          * potentially occurring on other threads. */
     410                 :   13627328 :         spdk_smp_rmb();
     411                 :            : 
     412                 :            :         /* Calculate how many items are in the circular ring */
     413                 :   13627328 :         count = tail - head;
     414         [ +  + ]:   13627328 :         if (tail < head) {
     415   [ #  #  #  # ]:       3587 :                 count += ring->size;
     416                 :          0 :         }
     417                 :            : 
     418                 :            :         /* Reduce the count to the limit provided by the user */
     419         [ #  # ]:   13627328 :         count = spdk_min(max, count);
     420                 :            : 
     421                 :            :         /* Grab the memory location of the event array */
     422   [ #  #  #  # ]:   13627328 :         kevents = (struct io_event *)((uintptr_t)ring + ring->header_length);
     423                 :            : 
     424                 :            :         /* Copy the events out of the ring. */
     425   [ +  +  #  #  :   13627328 :         if ((head + count) <= ring->size) {
                   #  # ]
     426                 :            :                 /* Only one copy is required */
     427   [ -  +  -  +  :   13624230 :                 memcpy(uevents, &kevents[head], count * sizeof(struct io_event));
                   #  # ]
     428                 :          0 :         } else {
     429   [ #  #  #  # ]:       3098 :                 uint32_t first_part = ring->size - head;
     430                 :            :                 /* Two copies are required */
     431   [ -  +  -  +  :       3098 :                 memcpy(uevents, &kevents[head], first_part * sizeof(struct io_event));
                   #  # ]
     432   [ -  +  -  +  :       3098 :                 memcpy(&uevents[first_part], &kevents[0], (count - first_part) * sizeof(struct io_event));
             #  #  #  # ]
     433                 :            :         }
     434                 :            : 
     435                 :            :         /* Update the head pointer. On x86, stores will not be reordered with older loads,
     436                 :            :          * so the copies out of the event array will always be complete prior to this
     437                 :            :          * update becoming visible. On other architectures this is not guaranteed, so
     438                 :            :          * add a barrier. */
     439                 :            : #if defined(__i386__) || defined(__x86_64__)
     440                 :   13627328 :         spdk_compiler_barrier();
     441                 :            : #else
     442                 :            :         spdk_smp_mb();
     443                 :            : #endif
     444   [ -  +  #  #  :   13627328 :         ring->head = (head + count) % ring->size;
          #  #  #  #  #  
                      # ]
     445                 :            : 
     446                 :   13627328 :         return count;
     447                 :          0 : }
     448                 :            : 
     449                 :            : static int
     450                 :   13627328 : bdev_aio_io_channel_poll(struct bdev_aio_io_channel *io_ch)
     451                 :            : {
     452                 :   13627328 :         int nr, i, res = 0;
     453                 :            :         struct bdev_aio_task *aio_task;
     454                 :    7929728 :         struct io_event events[SPDK_AIO_QUEUE_DEPTH];
     455                 :            : 
     456   [ #  #  #  # ]:   13627328 :         nr = bdev_user_io_getevents(io_ch->io_ctx, SPDK_AIO_QUEUE_DEPTH, events);
     457         [ -  + ]:   13627328 :         if (nr < 0) {
     458                 :          0 :                 return 0;
     459                 :            :         }
     460                 :            : 
     461   [ +  +  #  # ]:   15392084 :         for (i = 0; i < nr; i++) {
     462   [ #  #  #  #  :    1764756 :                 aio_task = events[i].data;
             #  #  #  # ]
     463   [ #  #  #  #  :    1764756 :                 aio_task->ch->io_inflight--;
                   #  # ]
     464   [ +  -  #  #  :    1764756 :                 if (events[i].res == aio_task->len) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     465                 :    1764756 :                         spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_SUCCESS);
     466                 :          0 :                 } else {
     467                 :            :                         /* From aio_abi.h, io_event.res is defined __s64, negative errno
     468                 :            :                          * will be assigned to io_event.res for error situation.
     469                 :            :                          * But from libaio.h, io_event.res is defined unsigned long, so
     470                 :            :                          * convert it to signed value for error detection.
     471                 :            :                          */
     472   [ #  #  #  #  :          0 :                         res = (int)events[i].res;
             #  #  #  # ]
     473         [ #  # ]:          0 :                         if (res < 0) {
     474         [ #  # ]:          0 :                                 if (res == -EAGAIN) {
     475                 :          0 :                                         spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_NOMEM);
     476                 :          0 :                                 } else {
     477   [ #  #  #  #  :          0 :                                         SPDK_ERRLOG("failed to complete aio: rc %"PRId64"\n", events[i].res);
             #  #  #  # ]
     478                 :          0 :                                         spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), res);
     479                 :            :                                 }
     480                 :          0 :                         } else {
     481   [ #  #  #  #  :          0 :                                 SPDK_ERRLOG("failed to complete aio: rc %"PRId64"\n", events[i].res);
             #  #  #  # ]
     482                 :          0 :                                 spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_FAILED);
     483                 :            :                         }
     484                 :            :                 }
     485                 :          0 :         }
     486                 :            : 
     487                 :   13627328 :         return nr;
     488                 :          0 : }
     489                 :            : #endif
     490                 :            : 
     491                 :            : static int
     492                 :   13968576 : bdev_aio_group_poll(void *arg)
     493                 :            : {
     494                 :   13968576 :         struct bdev_aio_group_channel *group_ch = arg;
     495                 :            :         struct bdev_aio_io_channel *io_ch;
     496                 :   13968576 :         int nr = 0;
     497                 :            : 
     498   [ +  +  #  #  :   29132650 :         TAILQ_FOREACH(io_ch, &group_ch->io_ch_head, link) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     499         [ #  # ]:   15164074 :                 nr += bdev_aio_io_channel_poll(io_ch);
     500                 :    1536746 :         }
     501                 :            : 
     502                 :   13968576 :         return nr > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
     503                 :            : }
     504                 :            : 
     505                 :            : static int
     506                 :      25432 : bdev_aio_group_interrupt(void *arg)
     507                 :            : {
     508                 :      25432 :         struct bdev_aio_group_channel *group_ch = arg;
     509                 :            :         int rc;
     510                 :         11 :         uint64_t num_events;
     511                 :            : 
     512   [ -  +  #  #  :      25432 :         assert(group_ch->efd >= 0);
             #  #  #  # ]
     513                 :            : 
     514                 :            :         /* if completed IO number is larger than SPDK_AIO_QUEUE_DEPTH,
     515                 :            :          * io_getevent should be called again to ensure all completed IO are processed.
     516                 :            :          */
     517   [ #  #  #  # ]:      25432 :         rc = read(group_ch->efd, &num_events, sizeof(num_events));
     518         [ -  + ]:      25432 :         if (rc < 0) {
     519         [ #  # ]:          0 :                 SPDK_ERRLOG("failed to acknowledge aio group: %s.\n", spdk_strerror(errno));
     520   [ #  #  #  # ]:          0 :                 return -errno;
     521                 :            :         }
     522                 :            : 
     523         [ -  + ]:      25432 :         if (num_events > SPDK_AIO_QUEUE_DEPTH) {
     524                 :          0 :                 num_events -= SPDK_AIO_QUEUE_DEPTH;
     525   [ #  #  #  # ]:          0 :                 rc = write(group_ch->efd, &num_events, sizeof(num_events));
     526         [ #  # ]:          0 :                 if (rc < 0) {
     527         [ #  # ]:          0 :                         SPDK_ERRLOG("failed to notify aio group: %s.\n", spdk_strerror(errno));
     528                 :          0 :                 }
     529                 :          0 :         }
     530                 :            : 
     531                 :      25432 :         return bdev_aio_group_poll(group_ch);
     532                 :          0 : }
     533                 :            : 
     534                 :            : static void
     535                 :          5 : _bdev_aio_get_io_inflight(struct spdk_io_channel_iter *i)
     536                 :            : {
     537                 :          5 :         struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
     538                 :          5 :         struct bdev_aio_io_channel *aio_ch = spdk_io_channel_get_ctx(ch);
     539                 :            : 
     540   [ -  +  #  #  :          5 :         if (aio_ch->io_inflight) {
                   #  # ]
     541                 :          0 :                 spdk_for_each_channel_continue(i, -1);
     542                 :          0 :                 return;
     543                 :            :         }
     544                 :            : 
     545                 :          5 :         spdk_for_each_channel_continue(i, 0);
     546                 :          1 : }
     547                 :            : 
     548                 :            : static int bdev_aio_reset_retry_timer(void *arg);
     549                 :            : 
     550                 :            : static void
     551                 :          5 : _bdev_aio_get_io_inflight_done(struct spdk_io_channel_iter *i, int status)
     552                 :            : {
     553                 :          5 :         struct file_disk *fdisk = spdk_io_channel_iter_get_ctx(i);
     554                 :            : 
     555         [ -  + ]:          5 :         if (status == -1) {
     556   [ #  #  #  # ]:          0 :                 fdisk->reset_retry_timer = SPDK_POLLER_REGISTER(bdev_aio_reset_retry_timer, fdisk, 500);
     557                 :          0 :                 return;
     558                 :            :         }
     559                 :            : 
     560   [ #  #  #  # ]:          5 :         spdk_bdev_io_complete(spdk_bdev_io_from_ctx(fdisk->reset_task), SPDK_BDEV_IO_STATUS_SUCCESS);
     561                 :          1 : }
     562                 :            : 
     563                 :            : static int
     564                 :          5 : bdev_aio_reset_retry_timer(void *arg)
     565                 :            : {
     566                 :          5 :         struct file_disk *fdisk = arg;
     567                 :            : 
     568   [ -  +  #  #  :          5 :         if (fdisk->reset_retry_timer) {
                   #  # ]
     569         [ #  # ]:          0 :                 spdk_poller_unregister(&fdisk->reset_retry_timer);
     570                 :          0 :         }
     571                 :            : 
     572                 :          6 :         spdk_for_each_channel(fdisk,
     573                 :            :                               _bdev_aio_get_io_inflight,
     574                 :          1 :                               fdisk,
     575                 :            :                               _bdev_aio_get_io_inflight_done);
     576                 :            : 
     577                 :          5 :         return SPDK_POLLER_BUSY;
     578                 :            : }
     579                 :            : 
     580                 :            : static void
     581                 :          5 : bdev_aio_reset(struct file_disk *fdisk, struct bdev_aio_task *aio_task)
     582                 :            : {
     583   [ #  #  #  # ]:          5 :         fdisk->reset_task = aio_task;
     584                 :            : 
     585                 :          5 :         bdev_aio_reset_retry_timer(fdisk);
     586                 :          5 : }
     587                 :            : 
     588                 :            : static void
     589                 :    1800604 : bdev_aio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
     590                 :            :                     bool success)
     591                 :            : {
     592   [ -  +  #  # ]:    1800604 :         if (!success) {
     593                 :          0 :                 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
     594                 :          0 :                 return;
     595                 :            :         }
     596                 :            : 
     597   [ +  +  #  #  :    1800604 :         switch (bdev_io->type) {
                   #  # ]
     598                 :    1764756 :         case SPDK_BDEV_IO_TYPE_READ:
     599                 :            :         case SPDK_BDEV_IO_TYPE_WRITE:
     600   [ #  #  #  # ]:    3295656 :                 bdev_aio_rw(bdev_io->type,
     601   [ #  #  #  #  :    1800604 :                             (struct file_disk *)bdev_io->bdev->ctxt,
             #  #  #  # ]
     602                 :      35848 :                             ch,
     603         [ #  # ]:    1800604 :                             (struct bdev_aio_task *)bdev_io->driver_ctx,
     604   [ #  #  #  #  :      35848 :                             bdev_io->u.bdev.iovs,
             #  #  #  # ]
     605   [ #  #  #  #  :      35848 :                             bdev_io->u.bdev.iovcnt,
             #  #  #  # ]
     606   [ #  #  #  #  :    1800604 :                             bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     607   [ #  #  #  #  :    1800604 :                             bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     608                 :    1800604 :                 break;
     609                 :          0 :         default:
     610                 :          0 :                 SPDK_ERRLOG("Wrong io type\n");
     611                 :          0 :                 break;
     612                 :            :         }
     613                 :      35848 : }
     614                 :            : 
     615                 :            : static int
     616                 :    1800611 : _bdev_aio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
     617                 :            : {
     618   [ #  #  #  #  :    1800611 :         struct file_disk *fdisk = (struct file_disk *)bdev_io->bdev->ctxt;
             #  #  #  # ]
     619                 :            : 
     620   [ +  +  +  +  :    1800611 :         switch (bdev_io->type) {
          -  -  -  #  #  
                   #  # ]
     621                 :            :         /* Read and write operations must be performed on buffers aligned to
     622                 :            :          * bdev->required_alignment. If user specified unaligned buffers,
     623                 :            :          * get the aligned buffer from the pool by calling spdk_bdev_io_get_buf. */
     624                 :     735976 :         case SPDK_BDEV_IO_TYPE_READ:
     625                 :     766918 :                 spdk_bdev_io_get_buf(bdev_io, bdev_aio_get_buf_cb,
     626   [ #  #  #  #  :     751447 :                                      bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     627                 :     751447 :                 return 0;
     628                 :    1028780 :         case SPDK_BDEV_IO_TYPE_WRITE:
     629   [ -  +  -  +  :    1049159 :                 if (fdisk->readonly) {
             #  #  #  # ]
     630                 :          0 :                         spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
     631                 :          0 :                 } else {
     632                 :    1069538 :                         spdk_bdev_io_get_buf(bdev_io, bdev_aio_get_buf_cb,
     633   [ #  #  #  #  :    1049159 :                                              bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     634                 :            :                 }
     635                 :    1049159 :                 return 0;
     636                 :            : 
     637                 :          0 :         case SPDK_BDEV_IO_TYPE_FLUSH:
     638   [ #  #  #  #  :          0 :                 bdev_aio_flush((struct file_disk *)bdev_io->bdev->ctxt,
             #  #  #  # ]
     639         [ #  # ]:          0 :                                (struct bdev_aio_task *)bdev_io->driver_ctx);
     640                 :          0 :                 return 0;
     641                 :            : 
     642                 :          4 :         case SPDK_BDEV_IO_TYPE_RESET:
     643   [ #  #  #  #  :          6 :                 bdev_aio_reset((struct file_disk *)bdev_io->bdev->ctxt,
             #  #  #  # ]
     644         [ #  # ]:          5 :                                (struct bdev_aio_task *)bdev_io->driver_ctx);
     645                 :          5 :                 return 0;
     646                 :            : 
     647                 :            : #ifndef __FreeBSD__
     648                 :          0 :         case SPDK_BDEV_IO_TYPE_UNMAP:
     649                 :          0 :                 bdev_aio_unmap(bdev_io);
     650                 :          0 :                 return 0;
     651                 :            : 
     652                 :          0 :         case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
     653                 :          0 :                 bdev_aio_write_zeros(bdev_io);
     654                 :          0 :                 return 0;
     655                 :            : #endif
     656                 :            : 
     657                 :          0 :         default:
     658                 :          0 :                 return -1;
     659                 :            :         }
     660                 :      35851 : }
     661                 :            : 
     662                 :            : static void
     663                 :    1800610 : bdev_aio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
     664                 :            : {
     665         [ -  + ]:    1800610 :         if (_bdev_aio_submit_request(ch, bdev_io) < 0) {
     666                 :          0 :                 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
     667                 :          0 :         }
     668                 :    1800610 : }
     669                 :            : 
     670                 :            : static bool
     671                 :     244234 : bdev_aio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
     672                 :            : {
     673                 :     244234 :         struct file_disk *fdisk = ctx;
     674                 :            : 
     675      [ +  +  + ]:     244234 :         switch (io_type) {
     676                 :      38298 :         case SPDK_BDEV_IO_TYPE_READ:
     677                 :            :         case SPDK_BDEV_IO_TYPE_WRITE:
     678                 :            :         case SPDK_BDEV_IO_TYPE_FLUSH:
     679                 :            :         case SPDK_BDEV_IO_TYPE_RESET:
     680                 :      41407 :                 return true;
     681                 :            : 
     682                 :     176008 :         case SPDK_BDEV_IO_TYPE_UNMAP:
     683                 :            :         case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
     684   [ -  +  #  #  :     182198 :                 return fdisk->fallocate;
                   #  # ]
     685                 :            : 
     686                 :      20573 :         default:
     687                 :      20629 :                 return false;
     688                 :            :         }
     689                 :       9355 : }
     690                 :            : 
     691                 :            : #ifdef __FreeBSD__
     692                 :            : static int
     693                 :         17 : bdev_aio_create_io(struct bdev_aio_io_channel *ch)
     694                 :            : {
     695                 :         17 :         ch->kqfd = kqueue();
     696         [ -  + ]:         17 :         if (ch->kqfd < 0) {
     697                 :          0 :                 SPDK_ERRLOG("async I/O context setup failure: %s.\n", spdk_strerror(errno));
     698                 :          0 :                 return -1;
     699                 :            :         }
     700                 :            : 
     701                 :         17 :         return 0;
     702                 :         17 : }
     703                 :            : 
     704                 :            : static void
     705                 :         17 : bdev_aio_destroy_io(struct bdev_aio_io_channel *ch)
     706                 :            : {
     707                 :         17 :         close(ch->kqfd);
     708                 :         17 : }
     709                 :            : #else
     710                 :            : static int
     711                 :        236 : bdev_aio_create_io(struct bdev_aio_io_channel *ch)
     712                 :            : {
     713   [ -  +  #  # ]:        236 :         if (io_setup(SPDK_AIO_QUEUE_DEPTH, &ch->io_ctx) < 0) {
     714                 :          0 :                 SPDK_ERRLOG("Async I/O context setup failure, likely due to exceeding kernel limit.\n");
     715                 :          0 :                 SPDK_ERRLOG("This limit may be increased using 'sysctl -w fs.aio-max-nr'.\n");
     716                 :          0 :                 return -1;
     717                 :            :         }
     718                 :            : 
     719                 :        236 :         return 0;
     720                 :          0 : }
     721                 :            : 
     722                 :            : static void
     723                 :        236 : bdev_aio_destroy_io(struct bdev_aio_io_channel *ch)
     724                 :            : {
     725   [ #  #  #  # ]:        236 :         io_destroy(ch->io_ctx);
     726                 :        236 : }
     727                 :            : #endif
     728                 :            : 
     729                 :            : static int
     730                 :        253 : bdev_aio_create_cb(void *io_device, void *ctx_buf)
     731                 :            : {
     732                 :        253 :         struct bdev_aio_io_channel *ch = ctx_buf;
     733                 :            :         int rc;
     734                 :            : 
     735                 :        253 :         rc = bdev_aio_create_io(ch);
     736         [ -  + ]:        253 :         if (rc < 0) {
     737                 :          0 :                 return rc;
     738                 :            :         }
     739                 :            : 
     740   [ #  #  #  # ]:        253 :         ch->group_ch = spdk_io_channel_get_ctx(spdk_get_io_channel(&aio_if));
     741   [ #  #  #  #  :        253 :         TAILQ_INSERT_TAIL(&ch->group_ch->io_ch_head, ch, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     742                 :            : 
     743                 :        253 :         return 0;
     744                 :         17 : }
     745                 :            : 
     746                 :            : static void
     747                 :        253 : bdev_aio_destroy_cb(void *io_device, void *ctx_buf)
     748                 :            : {
     749                 :        253 :         struct bdev_aio_io_channel *ch = ctx_buf;
     750                 :            : 
     751                 :        253 :         bdev_aio_destroy_io(ch);
     752                 :            : 
     753   [ +  +  #  #  :        253 :         assert(ch->group_ch);
             #  #  #  # ]
     754   [ +  +  #  #  :        253 :         TAILQ_REMOVE(&ch->group_ch->io_ch_head, ch, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     755                 :            : 
     756   [ #  #  #  # ]:        253 :         spdk_put_io_channel(spdk_io_channel_from_ctx(ch->group_ch));
     757                 :        253 : }
     758                 :            : 
     759                 :            : static struct spdk_io_channel *
     760                 :        253 : bdev_aio_get_io_channel(void *ctx)
     761                 :            : {
     762                 :        253 :         struct file_disk *fdisk = ctx;
     763                 :            : 
     764                 :        253 :         return spdk_get_io_channel(fdisk);
     765                 :            : }
     766                 :            : 
     767                 :            : 
     768                 :            : static int
     769                 :       1445 : bdev_aio_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
     770                 :            : {
     771                 :       1445 :         struct file_disk *fdisk = ctx;
     772                 :            : 
     773                 :       1445 :         spdk_json_write_named_object_begin(w, "aio");
     774                 :            : 
     775   [ #  #  #  # ]:       1445 :         spdk_json_write_named_string(w, "filename", fdisk->filename);
     776                 :            : 
     777   [ -  +  #  #  :       1445 :         spdk_json_write_named_bool(w, "block_size_override", fdisk->block_size_override);
                   #  # ]
     778                 :            : 
     779   [ -  +  #  #  :       1445 :         spdk_json_write_named_bool(w, "readonly", fdisk->readonly);
                   #  # ]
     780                 :            : 
     781   [ -  +  #  #  :       1445 :         spdk_json_write_named_bool(w, "fallocate", fdisk->fallocate);
                   #  # ]
     782                 :            : 
     783                 :       1445 :         spdk_json_write_object_end(w);
     784                 :            : 
     785                 :       1445 :         return 0;
     786                 :            : }
     787                 :            : 
     788                 :            : static void
     789                 :         34 : bdev_aio_write_json_config(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
     790                 :            : {
     791   [ #  #  #  # ]:         34 :         struct file_disk *fdisk = bdev->ctxt;
     792                 :         34 :         const struct spdk_uuid *uuid = spdk_bdev_get_uuid(bdev);
     793                 :            : 
     794                 :         34 :         spdk_json_write_object_begin(w);
     795                 :            : 
     796                 :         34 :         spdk_json_write_named_string(w, "method", "bdev_aio_create");
     797                 :            : 
     798                 :         34 :         spdk_json_write_named_object_begin(w, "params");
     799   [ #  #  #  # ]:         34 :         spdk_json_write_named_string(w, "name", bdev->name);
     800   [ +  +  +  -  :         34 :         if (fdisk->block_size_override) {
             #  #  #  # ]
     801   [ #  #  #  # ]:         34 :                 spdk_json_write_named_uint32(w, "block_size", bdev->blocklen);
     802                 :          5 :         }
     803   [ #  #  #  # ]:         34 :         spdk_json_write_named_string(w, "filename", fdisk->filename);
     804   [ -  +  #  #  :         34 :         spdk_json_write_named_bool(w, "readonly", fdisk->readonly);
                   #  # ]
     805   [ -  +  #  #  :         34 :         spdk_json_write_named_bool(w, "fallocate", fdisk->fallocate);
                   #  # ]
     806         [ +  + ]:         34 :         if (!spdk_uuid_is_null(uuid)) {
     807                 :         34 :                 spdk_json_write_named_uuid(w, "uuid", uuid);
     808                 :          5 :         }
     809                 :         34 :         spdk_json_write_object_end(w);
     810                 :            : 
     811                 :         34 :         spdk_json_write_object_end(w);
     812                 :         34 : }
     813                 :            : 
     814                 :            : static const struct spdk_bdev_fn_table aio_fn_table = {
     815                 :            :         .destruct               = bdev_aio_destruct,
     816                 :            :         .submit_request         = bdev_aio_submit_request,
     817                 :            :         .io_type_supported      = bdev_aio_io_type_supported,
     818                 :            :         .get_io_channel         = bdev_aio_get_io_channel,
     819                 :            :         .dump_info_json         = bdev_aio_dump_info_json,
     820                 :            :         .write_config_json      = bdev_aio_write_json_config,
     821                 :            : };
     822                 :            : 
     823                 :            : static void
     824                 :        162 : aio_free_disk(struct file_disk *fdisk)
     825                 :            : {
     826         [ -  + ]:        162 :         if (fdisk == NULL) {
     827                 :          0 :                 return;
     828                 :            :         }
     829   [ #  #  #  # ]:        162 :         free(fdisk->filename);
     830   [ #  #  #  #  :        162 :         free(fdisk->disk.name);
                   #  # ]
     831                 :        162 :         free(fdisk);
     832                 :         10 : }
     833                 :            : 
     834                 :            : static int
     835                 :         22 : bdev_aio_register_interrupt(struct bdev_aio_group_channel *ch)
     836                 :            : {
     837                 :            :         int efd;
     838                 :            : 
     839                 :         22 :         efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
     840         [ -  + ]:         22 :         if (efd < 0) {
     841                 :          0 :                 return -1;
     842                 :            :         }
     843                 :            : 
     844   [ #  #  #  # ]:         22 :         ch->intr = SPDK_INTERRUPT_REGISTER(efd, bdev_aio_group_interrupt, ch);
     845   [ -  +  #  #  :         22 :         if (ch->intr == NULL) {
                   #  # ]
     846                 :          0 :                 close(efd);
     847                 :          0 :                 return -1;
     848                 :            :         }
     849   [ #  #  #  # ]:         22 :         ch->efd = efd;
     850                 :            : 
     851                 :         22 :         return 0;
     852                 :          0 : }
     853                 :            : 
     854                 :            : static void
     855                 :         22 : bdev_aio_unregister_interrupt(struct bdev_aio_group_channel *ch)
     856                 :            : {
     857         [ #  # ]:         22 :         spdk_interrupt_unregister(&ch->intr);
     858   [ #  #  #  # ]:         22 :         close(ch->efd);
     859   [ #  #  #  # ]:         22 :         ch->efd = -1;
     860                 :         22 : }
     861                 :            : 
     862                 :            : static int
     863                 :        250 : bdev_aio_group_create_cb(void *io_device, void *ctx_buf)
     864                 :            : {
     865                 :        250 :         struct bdev_aio_group_channel *ch = ctx_buf;
     866                 :            :         int rc;
     867                 :            : 
     868   [ #  #  #  #  :        250 :         TAILQ_INIT(&ch->io_ch_head);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     869                 :            :         /* Initialize ch->efd to be invalid and unused. */
     870   [ #  #  #  # ]:        250 :         ch->efd = -1;
     871         [ +  + ]:        250 :         if (spdk_interrupt_mode_is_enabled()) {
     872                 :         22 :                 rc = bdev_aio_register_interrupt(ch);
     873         [ -  + ]:         22 :                 if (rc < 0) {
     874                 :          0 :                         SPDK_ERRLOG("Failed to prepare intr resource to bdev_aio\n");
     875                 :          0 :                         return rc;
     876                 :            :                 }
     877                 :          0 :         }
     878                 :            : 
     879   [ #  #  #  # ]:        250 :         ch->poller = SPDK_POLLER_REGISTER(bdev_aio_group_poll, ch, 0);
     880   [ #  #  #  # ]:        250 :         spdk_poller_register_interrupt(ch->poller, NULL, NULL);
     881                 :            : 
     882                 :        250 :         return 0;
     883                 :         17 : }
     884                 :            : 
     885                 :            : static void
     886                 :        250 : bdev_aio_group_destroy_cb(void *io_device, void *ctx_buf)
     887                 :            : {
     888                 :        250 :         struct bdev_aio_group_channel *ch = ctx_buf;
     889                 :            : 
     890   [ +  +  #  #  :        250 :         if (!TAILQ_EMPTY(&ch->io_ch_head)) {
             #  #  #  # ]
     891                 :          0 :                 SPDK_ERRLOG("Group channel of bdev aio has uncleared io channel\n");
     892                 :          0 :         }
     893                 :            : 
     894         [ #  # ]:        250 :         spdk_poller_unregister(&ch->poller);
     895         [ +  + ]:        250 :         if (spdk_interrupt_mode_is_enabled()) {
     896                 :         22 :                 bdev_aio_unregister_interrupt(ch);
     897                 :          0 :         }
     898                 :        250 : }
     899                 :            : 
     900                 :            : int
     901                 :        162 : create_aio_bdev(const char *name, const char *filename, uint32_t block_size, bool readonly,
     902                 :            :                 bool fallocate, const struct spdk_uuid *uuid)
     903                 :            : {
     904                 :            :         struct file_disk *fdisk;
     905                 :            :         uint32_t detected_block_size;
     906                 :            :         uint64_t disk_size;
     907                 :            :         int rc;
     908                 :            : 
     909                 :            : #ifdef __FreeBSD__
     910         [ -  + ]:         10 :         if (fallocate) {
     911                 :          0 :                 SPDK_ERRLOG("Unable to support fallocate on this platform\n");
     912                 :          0 :                 return -ENOTSUP;
     913                 :            :         }
     914                 :            : #endif
     915                 :            : 
     916                 :        162 :         fdisk = calloc(1, sizeof(*fdisk));
     917         [ +  + ]:        162 :         if (!fdisk) {
     918                 :          0 :                 SPDK_ERRLOG("Unable to allocate enough memory for aio backend\n");
     919                 :          0 :                 return -ENOMEM;
     920                 :            :         }
     921   [ #  #  #  #  :        162 :         fdisk->readonly = readonly;
                   #  # ]
     922   [ #  #  #  #  :        162 :         fdisk->fallocate = fallocate;
                   #  # ]
     923                 :            : 
     924   [ -  +  #  #  :        162 :         fdisk->filename = strdup(filename);
                   #  # ]
     925   [ +  +  #  #  :        162 :         if (!fdisk->filename) {
                   #  # ]
     926                 :          0 :                 rc = -ENOMEM;
     927                 :          0 :                 goto error_return;
     928                 :            :         }
     929                 :            : 
     930         [ -  + ]:        162 :         if (bdev_aio_open(fdisk)) {
     931   [ #  #  #  #  :          0 :                 SPDK_ERRLOG("Unable to open file %s. fd: %d errno: %d\n", filename, fdisk->fd, errno);
                   #  # ]
     932   [ #  #  #  # ]:          0 :                 rc = -errno;
     933                 :          0 :                 goto error_return;
     934                 :            :         }
     935                 :            : 
     936   [ #  #  #  # ]:        162 :         disk_size = spdk_fd_get_size(fdisk->fd);
     937                 :            : 
     938   [ -  +  #  #  :        162 :         fdisk->disk.name = strdup(name);
             #  #  #  # ]
     939   [ +  +  #  #  :        162 :         if (!fdisk->disk.name) {
             #  #  #  # ]
     940                 :          0 :                 rc = -ENOMEM;
     941                 :          0 :                 goto error_return;
     942                 :            :         }
     943   [ #  #  #  #  :        162 :         fdisk->disk.product_name = "AIO disk";
                   #  # ]
     944   [ #  #  #  #  :        162 :         fdisk->disk.module = &aio_if;
                   #  # ]
     945                 :            : 
     946   [ #  #  #  #  :        162 :         fdisk->disk.write_cache = 1;
                   #  # ]
     947                 :            : 
     948   [ #  #  #  # ]:        162 :         detected_block_size = spdk_fd_get_blocklen(fdisk->fd);
     949         [ +  + ]:        162 :         if (block_size == 0) {
     950                 :            :                 /* User did not specify block size - use autodetected block size. */
     951         [ #  # ]:          0 :                 if (detected_block_size == 0) {
     952                 :          0 :                         SPDK_ERRLOG("Block size could not be auto-detected\n");
     953                 :          0 :                         rc = -EINVAL;
     954                 :          0 :                         goto error_return;
     955                 :            :                 }
     956   [ #  #  #  # ]:          0 :                 fdisk->block_size_override = false;
     957                 :          0 :                 block_size = detected_block_size;
     958                 :          0 :         } else {
     959         [ -  + ]:        162 :                 if (block_size < detected_block_size) {
     960                 :          0 :                         SPDK_ERRLOG("Specified block size %" PRIu32 " is smaller than "
     961                 :            :                                     "auto-detected block size %" PRIu32 "\n",
     962                 :            :                                     block_size, detected_block_size);
     963                 :          0 :                         rc = -EINVAL;
     964                 :          0 :                         goto error_return;
     965   [ -  +  -  - ]:        162 :                 } else if (detected_block_size != 0 && block_size != detected_block_size) {
     966                 :          0 :                         SPDK_WARNLOG("Specified block size %" PRIu32 " does not match "
     967                 :            :                                      "auto-detected block size %" PRIu32 "\n",
     968                 :            :                                      block_size, detected_block_size);
     969                 :          0 :                 }
     970   [ #  #  #  # ]:        162 :                 fdisk->block_size_override = true;
     971                 :            :         }
     972                 :            : 
     973         [ -  + ]:        162 :         if (block_size < 512) {
     974                 :          0 :                 SPDK_ERRLOG("Invalid block size %" PRIu32 " (must be at least 512).\n", block_size);
     975                 :          0 :                 rc = -EINVAL;
     976                 :          0 :                 goto error_return;
     977                 :            :         }
     978                 :            : 
     979         [ +  + ]:        162 :         if (!spdk_u32_is_pow2(block_size)) {
     980                 :          0 :                 SPDK_ERRLOG("Invalid block size %" PRIu32 " (must be a power of 2.)\n", block_size);
     981                 :          0 :                 rc = -EINVAL;
     982                 :          0 :                 goto error_return;
     983                 :            :         }
     984                 :            : 
     985   [ #  #  #  #  :        162 :         fdisk->disk.blocklen = block_size;
                   #  # ]
     986   [ +  +  +  +  :        162 :         if (fdisk->block_size_override && detected_block_size) {
          -  +  #  #  #  
                      # ]
     987   [ #  #  #  #  :          0 :                 fdisk->disk.required_alignment = spdk_u32log2(detected_block_size);
                   #  # ]
     988                 :          0 :         } else {
     989   [ #  #  #  #  :        162 :                 fdisk->disk.required_alignment = spdk_u32log2(block_size);
                   #  # ]
     990                 :            :         }
     991                 :            : 
     992   [ -  +  -  +  :        162 :         if (disk_size % fdisk->disk.blocklen != 0) {
          #  #  #  #  #  
                      # ]
     993   [ #  #  #  #  :          0 :                 SPDK_ERRLOG("Disk size %" PRIu64 " is not a multiple of block size %" PRIu32 "\n",
                   #  # ]
     994                 :            :                             disk_size, fdisk->disk.blocklen);
     995                 :          0 :                 rc = -EINVAL;
     996                 :          0 :                 goto error_return;
     997                 :            :         }
     998                 :            : 
     999   [ -  +  #  #  :        162 :         fdisk->disk.blockcnt = disk_size / fdisk->disk.blocklen;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1000   [ #  #  #  #  :        162 :         fdisk->disk.ctxt = fdisk;
                   #  # ]
    1001   [ #  #  #  # ]:        162 :         spdk_uuid_copy(&fdisk->disk.uuid, uuid);
    1002                 :            : 
    1003   [ #  #  #  #  :        162 :         fdisk->disk.fn_table = &aio_fn_table;
                   #  # ]
    1004                 :            : 
    1005                 :        172 :         spdk_io_device_register(fdisk, bdev_aio_create_cb, bdev_aio_destroy_cb,
    1006                 :            :                                 sizeof(struct bdev_aio_io_channel),
    1007   [ #  #  #  #  :        162 :                                 fdisk->disk.name);
                   #  # ]
    1008         [ #  # ]:        162 :         rc = spdk_bdev_register(&fdisk->disk);
    1009         [ +  + ]:        162 :         if (rc) {
    1010                 :          0 :                 spdk_io_device_unregister(fdisk, NULL);
    1011                 :          0 :                 goto error_return;
    1012                 :            :         }
    1013                 :            : 
    1014   [ #  #  #  #  :        162 :         TAILQ_INSERT_TAIL(&g_aio_disk_head, fdisk, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1015                 :        162 :         return 0;
    1016                 :            : 
    1017                 :          0 : error_return:
    1018                 :          0 :         bdev_aio_close(fdisk);
    1019                 :          0 :         aio_free_disk(fdisk);
    1020                 :          0 :         return rc;
    1021                 :         10 : }
    1022                 :            : 
    1023                 :            : static void
    1024                 :          0 : dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
    1025                 :            : {
    1026                 :          0 : }
    1027                 :            : 
    1028                 :            : int
    1029                 :          0 : bdev_aio_rescan(const char *name)
    1030                 :            : {
    1031                 :          0 :         struct spdk_bdev_desc *desc;
    1032                 :            :         struct spdk_bdev *bdev;
    1033                 :            :         struct file_disk *fdisk;
    1034                 :            :         uint64_t disk_size, blockcnt;
    1035                 :            :         int rc;
    1036                 :            : 
    1037                 :          0 :         rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &desc);
    1038         [ #  # ]:          0 :         if (rc != 0) {
    1039                 :          0 :                 return rc;
    1040                 :            :         }
    1041                 :            : 
    1042                 :          0 :         bdev = spdk_bdev_desc_get_bdev(desc);
    1043   [ #  #  #  #  :          0 :         if (bdev->module != &aio_if) {
                   #  # ]
    1044                 :          0 :                 rc = -ENODEV;
    1045                 :          0 :                 goto exit;
    1046                 :            :         }
    1047                 :            : 
    1048                 :          0 :         fdisk = SPDK_CONTAINEROF(bdev, struct file_disk, disk);
    1049   [ #  #  #  # ]:          0 :         disk_size = spdk_fd_get_size(fdisk->fd);
    1050   [ #  #  #  #  :          0 :         blockcnt = disk_size / bdev->blocklen;
                   #  # ]
    1051                 :            : 
    1052   [ #  #  #  #  :          0 :         if (bdev->blockcnt != blockcnt) {
                   #  # ]
    1053   [ #  #  #  #  :          0 :                 SPDK_NOTICELOG("AIO device is resized: bdev name %s, old block count %" PRIu64 ", new block count %"
             #  #  #  # ]
    1054                 :            :                                PRIu64 "\n",
    1055                 :            :                                fdisk->filename,
    1056                 :            :                                bdev->blockcnt,
    1057                 :            :                                blockcnt);
    1058                 :          0 :                 rc = spdk_bdev_notify_blockcnt_change(bdev, blockcnt);
    1059         [ #  # ]:          0 :                 if (rc != 0) {
    1060   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("Could not change num blocks for aio bdev: name %s, errno: %d.\n",
    1061                 :            :                                     fdisk->filename, rc);
    1062                 :          0 :                         goto exit;
    1063                 :            :                 }
    1064                 :          0 :         }
    1065                 :            : 
    1066                 :          0 : exit:
    1067                 :          0 :         spdk_bdev_close(desc);
    1068                 :          0 :         return rc;
    1069                 :          0 : }
    1070                 :            : 
    1071                 :            : struct delete_aio_bdev_ctx {
    1072                 :            :         delete_aio_bdev_complete cb_fn;
    1073                 :            :         void *cb_arg;
    1074                 :            : };
    1075                 :            : 
    1076                 :            : static void
    1077                 :         47 : aio_bdev_unregister_cb(void *arg, int bdeverrno)
    1078                 :            : {
    1079                 :         47 :         struct delete_aio_bdev_ctx *ctx = arg;
    1080                 :            : 
    1081   [ #  #  #  #  :         47 :         ctx->cb_fn(ctx->cb_arg, bdeverrno);
          #  #  #  #  #  
                #  #  # ]
    1082                 :         47 :         free(ctx);
    1083                 :         47 : }
    1084                 :            : 
    1085                 :            : void
    1086                 :         47 : bdev_aio_delete(const char *name, delete_aio_bdev_complete cb_fn, void *cb_arg)
    1087                 :            : {
    1088                 :            :         struct delete_aio_bdev_ctx *ctx;
    1089                 :            :         int rc;
    1090                 :            : 
    1091                 :         47 :         ctx = calloc(1, sizeof(*ctx));
    1092         [ -  + ]:         47 :         if (ctx == NULL) {
    1093   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    1094                 :          0 :                 return;
    1095                 :            :         }
    1096                 :            : 
    1097   [ #  #  #  # ]:         47 :         ctx->cb_fn = cb_fn;
    1098   [ #  #  #  # ]:         47 :         ctx->cb_arg = cb_arg;
    1099                 :         47 :         rc = spdk_bdev_unregister_by_name(name, &aio_if, aio_bdev_unregister_cb, ctx);
    1100         [ +  + ]:         47 :         if (rc != 0) {
    1101                 :          0 :                 aio_bdev_unregister_cb(ctx, rc);
    1102                 :          0 :         }
    1103                 :          1 : }
    1104                 :            : 
    1105                 :            : static int
    1106                 :       2052 : bdev_aio_initialize(void)
    1107                 :            : {
    1108                 :       2052 :         spdk_io_device_register(&aio_if, bdev_aio_group_create_cb, bdev_aio_group_destroy_cb,
    1109                 :            :                                 sizeof(struct bdev_aio_group_channel), "aio_module");
    1110                 :            : 
    1111                 :       2052 :         return 0;
    1112                 :            : }
    1113                 :            : 
    1114                 :            : static void
    1115                 :       2052 : bdev_aio_fini(void)
    1116                 :            : {
    1117                 :       2052 :         spdk_io_device_unregister(&aio_if, NULL);
    1118                 :       2052 : }
    1119                 :            : 
    1120                 :       2174 : SPDK_LOG_REGISTER_COMPONENT(aio)

Generated by: LCOV version 1.15